2 * ADM5120 built in ethernet switch driver
4 * Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
6 * Inspiration for this driver came from the original ADMtek 2.4
7 * driver, Copyright ADMtek Inc.
9 #include <linux/autoconf.h>
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/netdevice.h>
13 #include <linux/etherdevice.h>
14 #include <linux/skbuff.h>
15 #include <linux/errno.h>
16 #include <linux/interrupt.h>
17 #include <linux/ioport.h>
18 #include <asm/mipsregs.h>
21 #include "adm5120sw.h"
23 MODULE_AUTHOR("Jeroen Vreeken (pe1rxq@amsat.org)");
24 MODULE_DESCRIPTION("ADM5120 ethernet switch driver");
25 MODULE_LICENSE("GPL");
28 * The ADM5120 uses an internal matrix to determine which ports
29 * belong to which VLAN.
30 * The default generates a VLAN (and device) for each port
31 * (including MII port) and the CPU port is part of all of them.
33 * Another example, one big switch and everything mapped to eth0:
34 * 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00
36 static unsigned char vlan_matrix
[SW_DEVS
] = {
37 0x41, 0x42, 0x44, 0x48, 0x50, 0x60
40 static int adm5120_nrdevs
;
42 static struct net_device
*adm5120_devs
[SW_DEVS
];
43 static struct adm5120_dma
44 adm5120_dma_txh_v
[ADM5120_DMA_TXH
] __attribute__((aligned(16))),
45 adm5120_dma_txl_v
[ADM5120_DMA_TXL
] __attribute__((aligned(16))),
46 adm5120_dma_rxh_v
[ADM5120_DMA_RXH
] __attribute__((aligned(16))),
47 adm5120_dma_rxl_v
[ADM5120_DMA_RXL
] __attribute__((aligned(16))),
53 *adm5120_skb_rxh
[ADM5120_DMA_RXH
],
54 *adm5120_skb_rxl
[ADM5120_DMA_RXL
],
55 *adm5120_skb_txh
[ADM5120_DMA_TXH
],
56 *adm5120_skb_txl
[ADM5120_DMA_TXL
];
57 static int adm5120_rxhi
= 0;
58 static int adm5120_rxli
= 0;
59 /* We don't use high priority tx for now */
60 /*static int adm5120_txhi = 0;*/
61 static int adm5120_txli
= 0;
62 static int adm5120_txhit
= 0;
63 static int adm5120_txlit
= 0;
64 static int adm5120_if_open
= 0;
66 static inline void adm5120_set_reg(unsigned int reg
, unsigned long val
)
68 *(volatile unsigned long*)(SW_BASE
+reg
) = val
;
71 static inline unsigned long adm5120_get_reg(unsigned int reg
)
73 return *(volatile unsigned long*)(SW_BASE
+reg
);
76 static inline void adm5120_rxfixup(struct adm5120_dma
*dma
,
77 struct sk_buff
**skbl
, int num
)
81 /* Resubmit the entire ring */
82 for (i
=0; i
<num
; i
++) {
85 dma
[i
].len
= ADM5120_DMA_RXSIZE
;
86 dma
[i
].data
= ADM5120_DMA_ADDR(skbl
[i
]->data
) |
87 ADM5120_DMA_OWN
| (i
==num
-1 ? ADM5120_DMA_RINGEND
: 0);
91 static inline void adm5120_rx(struct adm5120_dma
*dma
, struct sk_buff
**skbl
,
94 struct sk_buff
*skb
, *skbn
;
95 struct adm5120_sw
*priv
;
96 struct net_device
*dev
;
99 while (!(dma
[*index
].data
& ADM5120_DMA_OWN
)) {
100 port
= (dma
[*index
].status
& ADM5120_DMA_PORTID
);
101 port
>>= ADM5120_DMA_PORTSHIFT
;
102 for (vlan
= 0; vlan
< adm5120_nrdevs
; vlan
++) {
103 if ((1<<port
) & vlan_matrix
[vlan
])
106 if (vlan
== adm5120_nrdevs
)
108 dev
= adm5120_devs
[vlan
];
110 len
= (dma
[*index
].status
& ADM5120_DMA_LEN
);
111 len
>>= ADM5120_DMA_LENSHIFT
;
114 priv
= netdev_priv(dev
);
115 if (len
<= 0 || len
> ADM5120_DMA_RXSIZE
||
116 dma
[*index
].status
& ADM5120_DMA_FCSERR
) {
117 priv
->stats
.rx_errors
++;
120 skbn
= dev_alloc_skb(ADM5120_DMA_RXSIZE
+16);
124 skb
->protocol
= eth_type_trans(skb
, dev
);
125 skb
->ip_summed
= CHECKSUM_UNNECESSARY
;
126 dev
->last_rx
= jiffies
;
127 priv
->stats
.rx_packets
++;
128 priv
->stats
.rx_bytes
+=len
;
129 skb_reserve(skbn
, 2);
132 printk(KERN_INFO
"%s recycling!\n", dev
->name
);
136 dma
[*index
].status
= 0;
137 dma
[*index
].cntl
= 0;
138 dma
[*index
].len
= ADM5120_DMA_RXSIZE
;
139 dma
[*index
].data
= ADM5120_DMA_ADDR(skbl
[*index
]->data
) |
141 (num
-1==*index
? ADM5120_DMA_RINGEND
: 0);
149 static inline void adm5120_tx(struct adm5120_dma
*dma
, struct sk_buff
**skbl
,
152 while((dma
[*index
].data
& ADM5120_DMA_OWN
) == 0 && skbl
[*index
]) {
153 dev_kfree_skb_irq(skbl
[*index
]);
160 irqreturn_t
adm5120_sw_irq(int irq
, void *dev_id
, struct pt_regs
*regs
)
162 unsigned long intreg
;
164 adm5120_set_reg(ADM5120_INT_MASK
,
165 adm5120_get_reg(ADM5120_INT_MASK
) | ADM5120_INTHANDLE
);
167 intreg
= adm5120_get_reg(ADM5120_INT_ST
);
168 adm5120_set_reg(ADM5120_INT_ST
, intreg
);
170 if (intreg
& ADM5120_INT_RXH
)
171 adm5120_rx(adm5120_dma_rxh
, adm5120_skb_rxh
, &adm5120_rxhi
,
173 if (intreg
& ADM5120_INT_HFULL
)
174 adm5120_rxfixup(adm5120_dma_rxh
, adm5120_skb_rxh
,
176 if (intreg
& ADM5120_INT_RXL
)
177 adm5120_rx(adm5120_dma_rxl
, adm5120_skb_rxl
, &adm5120_rxli
,
179 if (intreg
& ADM5120_INT_LFULL
)
180 adm5120_rxfixup(adm5120_dma_rxl
, adm5120_skb_rxl
,
182 if (intreg
& ADM5120_INT_TXH
)
183 adm5120_tx(adm5120_dma_txh
, adm5120_skb_txh
, &adm5120_txhit
,
185 if (intreg
& ADM5120_INT_TXL
)
186 adm5120_tx(adm5120_dma_txl
, adm5120_skb_txl
, &adm5120_txlit
,
189 adm5120_set_reg(ADM5120_INT_MASK
,
190 adm5120_get_reg(ADM5120_INT_MASK
) & ~ADM5120_INTHANDLE
);
195 static void adm5120_set_vlan(char *matrix
)
199 val
= matrix
[0] + (matrix
[1]<<8) + (matrix
[2]<<16) + (matrix
[3]<<24);
200 adm5120_set_reg(ADM5120_VLAN_GI
, val
);
201 val
= matrix
[4] + (matrix
[5]<<8);
202 adm5120_set_reg(ADM5120_VLAN_GII
, val
);
205 static int adm5120_sw_open(struct net_device
*dev
)
207 if (!adm5120_if_open
++)
208 adm5120_set_reg(ADM5120_INT_MASK
,
209 adm5120_get_reg(ADM5120_INT_MASK
) & ~ADM5120_INTHANDLE
);
210 netif_start_queue(dev
);
214 static int adm5120_sw_stop(struct net_device
*dev
)
216 netif_stop_queue(dev
);
217 if (!--adm5120_if_open
)
218 adm5120_set_reg(ADM5120_INT_MASK
,
219 adm5120_get_reg(ADM5120_INT_MASK
) | ADM5120_INTMASKALL
);
223 static int adm5120_sw_tx(struct sk_buff
*skb
, struct net_device
*dev
)
225 struct adm5120_dma
*dma
= adm5120_dma_txl
;
226 struct sk_buff
**skbl
= adm5120_skb_txl
;
227 struct adm5120_sw
*priv
= netdev_priv(dev
);
228 int *index
= &adm5120_txli
;
229 int num
= ADM5120_DMA_TXL
;
230 int trigger
= ADM5120_SEND_TRIG_L
;
232 dev
->trans_start
= jiffies
;
233 if (dma
[*index
].data
& ADM5120_DMA_OWN
) {
235 priv
->stats
.tx_dropped
++;
239 dma
[*index
].data
= ADM5120_DMA_ADDR(skb
->data
) | ADM5120_DMA_OWN
;
241 dma
[*index
].data
|= ADM5120_DMA_RINGEND
;
243 ((skb
->len
<ETH_ZLEN
?ETH_ZLEN
:skb
->len
) << ADM5120_DMA_LENSHIFT
) |
245 dma
[*index
].len
= skb
->len
< ETH_ZLEN
? ETH_ZLEN
: skb
->len
;
246 priv
->stats
.tx_packets
++;
247 priv
->stats
.tx_bytes
+= skb
->len
;
252 adm5120_set_reg(ADM5120_SEND_TRIG
, trigger
);
257 static void adm5120_tx_timeout(struct net_device
*dev
)
259 netif_wake_queue(dev
);
262 static struct net_device_stats
*adm5120_sw_stats(struct net_device
*dev
)
264 return &((struct adm5120_sw
*)netdev_priv(dev
))->stats
;
267 static void adm5120_set_multicast_list(struct net_device
*dev
)
269 struct adm5120_sw
*priv
= netdev_priv(dev
);
272 portmask
= vlan_matrix
[priv
->port
] & 0x3f;
274 if (dev
->flags
& IFF_PROMISC
)
275 adm5120_set_reg(ADM5120_CPUP_CONF
,
276 adm5120_get_reg(ADM5120_CPUP_CONF
) &
277 ~((portmask
<< ADM5120_DISUNSHIFT
) & ADM5120_DISUNALL
));
279 adm5120_set_reg(ADM5120_CPUP_CONF
,
280 adm5120_get_reg(ADM5120_CPUP_CONF
) |
281 (portmask
<< ADM5120_DISUNSHIFT
));
283 if (dev
->flags
& IFF_PROMISC
|| dev
->flags
& IFF_ALLMULTI
||
285 adm5120_set_reg(ADM5120_CPUP_CONF
,
286 adm5120_get_reg(ADM5120_CPUP_CONF
) &
287 ~((portmask
<< ADM5120_DISMCSHIFT
) & ADM5120_DISMCALL
));
289 adm5120_set_reg(ADM5120_CPUP_CONF
,
290 adm5120_get_reg(ADM5120_CPUP_CONF
) |
291 (portmask
<< ADM5120_DISMCSHIFT
));
294 static void adm5120_write_mac(struct net_device
*dev
)
296 struct adm5120_sw
*priv
= netdev_priv(dev
);
297 unsigned char *mac
= dev
->dev_addr
;
299 adm5120_set_reg(ADM5120_MAC_WT1
,
300 mac
[2] | (mac
[3]<<8) | (mac
[4]<<16) | (mac
[5]<<24));
301 adm5120_set_reg(ADM5120_MAC_WT0
, (priv
->port
<<3) |
302 (mac
[0]<<16) | (mac
[1]<<24) | ADM5120_MAC_WRITE
| ADM5120_VLAN_EN
);
304 while (!(adm5120_get_reg(ADM5120_MAC_WT0
) & ADM5120_MAC_WRITE_DONE
));
307 static int adm5120_sw_set_mac_address(struct net_device
*dev
, void *p
)
309 struct sockaddr
*addr
= p
;
311 memcpy(dev
->dev_addr
, addr
->sa_data
, dev
->addr_len
);
312 adm5120_write_mac(dev
);
316 static int adm5120_do_ioctl(struct net_device
*dev
, struct ifreq
*rq
, int cmd
)
319 struct adm5120_info info
;
320 struct adm5120_sw
*priv
= netdev_priv(dev
);
325 info
.ports
= adm5120_nrdevs
;
326 info
.vlan
= priv
->port
;
327 err
= copy_to_user(rq
->ifr_data
, &info
, sizeof(info
));
332 if (!capable(CAP_NET_ADMIN
))
334 err
= copy_from_user(vlan_matrix
, rq
->ifr_data
,
335 sizeof(vlan_matrix
));
338 adm5120_set_vlan(vlan_matrix
);
341 err
= copy_to_user(rq
->ifr_data
, vlan_matrix
,
342 sizeof(vlan_matrix
));
352 static void adm5120_dma_tx_init(struct adm5120_dma
*dma
, struct sk_buff
**skb
,
355 memset(dma
, 0, sizeof(struct adm5120_dma
)*num
);
356 dma
[num
-1].data
|= ADM5120_DMA_RINGEND
;
357 memset(skb
, 0, sizeof(struct skb
*)*num
);
360 static void adm5120_dma_rx_init(struct adm5120_dma
*dma
, struct sk_buff
**skb
,
365 memset(dma
, 0, sizeof(struct adm5120_dma
)*num
);
366 for (i
=0; i
<num
; i
++) {
367 skb
[i
] = dev_alloc_skb(ADM5120_DMA_RXSIZE
+16);
372 skb_reserve(skb
[i
], 2);
373 dma
[i
].data
= ADM5120_DMA_ADDR(skb
[i
]->data
) | ADM5120_DMA_OWN
;
375 dma
[i
].len
= ADM5120_DMA_RXSIZE
;
378 dma
[i
-1].data
|= ADM5120_DMA_RINGEND
;
381 static int __init
adm5120_sw_init(void)
384 struct net_device
*dev
;
386 err
= request_irq(SW_IRQ
, adm5120_sw_irq
, 0, "ethernet switch", NULL
);
391 if (adm5120_get_reg(ADM5120_CODE
) & ADM5120_CODE_PQFP
)
393 /* CFE based devices only have two enet ports */
394 else if (boot_loader_type
== CFE
)
399 adm5120_set_reg(ADM5120_CPUP_CONF
,
400 ADM5120_DISCCPUPORT
| ADM5120_CRC_PADDING
|
401 ADM5120_DISUNALL
| ADM5120_DISMCALL
);
402 adm5120_set_reg(ADM5120_PORT_CONF0
, ADM5120_ENMC
| ADM5120_ENBP
);
404 adm5120_set_reg(ADM5120_PHY_CNTL2
, adm5120_get_reg(ADM5120_PHY_CNTL2
) |
405 ADM5120_AUTONEG
| ADM5120_NORMAL
| ADM5120_AUTOMDIX
);
406 adm5120_set_reg(ADM5120_PHY_CNTL3
, adm5120_get_reg(ADM5120_PHY_CNTL3
) |
409 adm5120_set_reg(ADM5120_INT_MASK
, ADM5120_INTMASKALL
);
410 adm5120_set_reg(ADM5120_INT_ST
, ADM5120_INTMASKALL
);
412 adm5120_dma_txh
= (void *)KSEG1ADDR((u32
)adm5120_dma_txh_v
);
413 adm5120_dma_txl
= (void *)KSEG1ADDR((u32
)adm5120_dma_txl_v
);
414 adm5120_dma_rxh
= (void *)KSEG1ADDR((u32
)adm5120_dma_rxh_v
);
415 adm5120_dma_rxl
= (void *)KSEG1ADDR((u32
)adm5120_dma_rxl_v
);
417 adm5120_dma_tx_init(adm5120_dma_txh
, adm5120_skb_txh
, ADM5120_DMA_TXH
);
418 adm5120_dma_tx_init(adm5120_dma_txl
, adm5120_skb_txl
, ADM5120_DMA_TXL
);
419 adm5120_dma_rx_init(adm5120_dma_rxh
, adm5120_skb_rxh
, ADM5120_DMA_RXH
);
420 adm5120_dma_rx_init(adm5120_dma_rxl
, adm5120_skb_rxl
, ADM5120_DMA_RXL
);
421 adm5120_set_reg(ADM5120_SEND_HBADDR
, KSEG1ADDR(adm5120_dma_txh
));
422 adm5120_set_reg(ADM5120_SEND_LBADDR
, KSEG1ADDR(adm5120_dma_txl
));
423 adm5120_set_reg(ADM5120_RECEIVE_HBADDR
, KSEG1ADDR(adm5120_dma_rxh
));
424 adm5120_set_reg(ADM5120_RECEIVE_LBADDR
, KSEG1ADDR(adm5120_dma_rxl
));
426 adm5120_set_vlan(vlan_matrix
);
428 for (i
=0; i
<adm5120_nrdevs
; i
++) {
429 adm5120_devs
[i
] = alloc_etherdev(sizeof(struct adm5120_sw
));
430 if (!adm5120_devs
[i
]) {
435 dev
= adm5120_devs
[i
];
436 SET_MODULE_OWNER(dev
);
437 memset(netdev_priv(dev
), 0, sizeof(struct adm5120_sw
));
438 ((struct adm5120_sw
*)netdev_priv(dev
))->port
= i
;
439 dev
->base_addr
= SW_BASE
;
441 dev
->open
= adm5120_sw_open
;
442 dev
->hard_start_xmit
= adm5120_sw_tx
;
443 dev
->stop
= adm5120_sw_stop
;
444 dev
->get_stats
= adm5120_sw_stats
;
445 dev
->set_multicast_list
= adm5120_set_multicast_list
;
446 dev
->do_ioctl
= adm5120_do_ioctl
;
447 dev
->tx_timeout
= adm5120_tx_timeout
;
448 dev
->watchdog_timeo
= ETH_TX_TIMEOUT
;
449 dev
->set_mac_address
= adm5120_sw_set_mac_address
;
450 /* HACK alert!!! In the original admtek driver it is asumed
451 that you can read the MAC addressess from flash, but edimax
452 decided to leave that space intentionally blank...
454 memcpy(dev
->dev_addr
, "\x00\x50\xfc\x11\x22\x01", 6);
455 dev
->dev_addr
[5] += i
;
456 adm5120_write_mac(dev
);
458 if ((err
= register_netdev(dev
))) {
462 printk(KERN_INFO
"%s: ADM5120 switch port%d\n", dev
->name
, i
);
464 adm5120_set_reg(ADM5120_CPUP_CONF
,
465 ADM5120_CRC_PADDING
| ADM5120_DISUNALL
| ADM5120_DISMCALL
);
470 /* Undo everything that did succeed */
472 unregister_netdev(adm5120_devs
[i
-1]);
473 free_netdev(adm5120_devs
[i
-1]);
475 free_irq(SW_IRQ
, NULL
);
477 printk(KERN_ERR
"ADM5120 Ethernet switch init failed\n");
481 static void __exit
adm5120_sw_exit(void)
485 for (i
= 0; i
< adm5120_nrdevs
; i
++) {
486 unregister_netdev(adm5120_devs
[i
]);
487 free_netdev(adm5120_devs
[i
-1]);
490 free_irq(SW_IRQ
, NULL
);
492 for (i
= 0; i
< ADM5120_DMA_RXH
; i
++) {
493 if (!adm5120_skb_rxh
[i
])
495 kfree_skb(adm5120_skb_rxh
[i
]);
497 for (i
= 0; i
< ADM5120_DMA_RXL
; i
++) {
498 if (!adm5120_skb_rxl
[i
])
500 kfree_skb(adm5120_skb_rxl
[i
]);
504 module_init(adm5120_sw_init
);
505 module_exit(adm5120_sw_exit
);