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
)
396 adm5120_set_reg(ADM5120_CPUP_CONF
,
397 ADM5120_DISCCPUPORT
| ADM5120_CRC_PADDING
|
398 ADM5120_DISUNALL
| ADM5120_DISMCALL
);
399 adm5120_set_reg(ADM5120_PORT_CONF0
, ADM5120_ENMC
| ADM5120_ENBP
);
401 adm5120_set_reg(ADM5120_PHY_CNTL2
, adm5120_get_reg(ADM5120_PHY_CNTL2
) |
402 ADM5120_AUTONEG
| ADM5120_NORMAL
| ADM5120_AUTOMDIX
);
403 adm5120_set_reg(ADM5120_PHY_CNTL3
, adm5120_get_reg(ADM5120_PHY_CNTL3
) |
406 adm5120_set_reg(ADM5120_INT_MASK
, ADM5120_INTMASKALL
);
407 adm5120_set_reg(ADM5120_INT_ST
, ADM5120_INTMASKALL
);
409 adm5120_dma_txh
= (void *)KSEG1ADDR((u32
)adm5120_dma_txh_v
);
410 adm5120_dma_txl
= (void *)KSEG1ADDR((u32
)adm5120_dma_txl_v
);
411 adm5120_dma_rxh
= (void *)KSEG1ADDR((u32
)adm5120_dma_rxh_v
);
412 adm5120_dma_rxl
= (void *)KSEG1ADDR((u32
)adm5120_dma_rxl_v
);
414 adm5120_dma_tx_init(adm5120_dma_txh
, adm5120_skb_txh
, ADM5120_DMA_TXH
);
415 adm5120_dma_tx_init(adm5120_dma_txl
, adm5120_skb_txl
, ADM5120_DMA_TXL
);
416 adm5120_dma_rx_init(adm5120_dma_rxh
, adm5120_skb_rxh
, ADM5120_DMA_RXH
);
417 adm5120_dma_rx_init(adm5120_dma_rxl
, adm5120_skb_rxl
, ADM5120_DMA_RXL
);
418 adm5120_set_reg(ADM5120_SEND_HBADDR
, KSEG1ADDR(adm5120_dma_txh
));
419 adm5120_set_reg(ADM5120_SEND_LBADDR
, KSEG1ADDR(adm5120_dma_txl
));
420 adm5120_set_reg(ADM5120_RECEIVE_HBADDR
, KSEG1ADDR(adm5120_dma_rxh
));
421 adm5120_set_reg(ADM5120_RECEIVE_LBADDR
, KSEG1ADDR(adm5120_dma_rxl
));
423 adm5120_set_vlan(vlan_matrix
);
425 for (i
=0; i
<adm5120_nrdevs
; i
++) {
426 adm5120_devs
[i
] = alloc_etherdev(sizeof(struct adm5120_sw
));
427 if (!adm5120_devs
[i
]) {
432 dev
= adm5120_devs
[i
];
433 SET_MODULE_OWNER(dev
);
434 memset(netdev_priv(dev
), 0, sizeof(struct adm5120_sw
));
435 ((struct adm5120_sw
*)netdev_priv(dev
))->port
= i
;
436 dev
->base_addr
= SW_BASE
;
438 dev
->open
= adm5120_sw_open
;
439 dev
->hard_start_xmit
= adm5120_sw_tx
;
440 dev
->stop
= adm5120_sw_stop
;
441 dev
->get_stats
= adm5120_sw_stats
;
442 dev
->set_multicast_list
= adm5120_set_multicast_list
;
443 dev
->do_ioctl
= adm5120_do_ioctl
;
444 dev
->tx_timeout
= adm5120_tx_timeout
;
445 dev
->watchdog_timeo
= ETH_TX_TIMEOUT
;
446 dev
->set_mac_address
= adm5120_sw_set_mac_address
;
447 /* HACK alert!!! In the original admtek driver it is asumed
448 that you can read the MAC addressess from flash, but edimax
449 decided to leave that space intentionally blank...
451 memcpy(dev
->dev_addr
, "\x00\x50\xfc\x11\x22\x01", 6);
452 dev
->dev_addr
[5] += i
;
453 adm5120_write_mac(dev
);
455 if ((err
= register_netdev(dev
))) {
459 printk(KERN_INFO
"%s: ADM5120 switch port%d\n", dev
->name
, i
);
461 adm5120_set_reg(ADM5120_CPUP_CONF
,
462 ADM5120_CRC_PADDING
| ADM5120_DISUNALL
| ADM5120_DISMCALL
);
467 /* Undo everything that did succeed */
469 unregister_netdev(adm5120_devs
[i
-1]);
470 free_netdev(adm5120_devs
[i
-1]);
472 free_irq(SW_IRQ
, NULL
);
474 printk(KERN_ERR
"ADM5120 Ethernet switch init failed\n");
478 static void __exit
adm5120_sw_exit(void)
482 for (i
= 0; i
< adm5120_nrdevs
; i
++) {
483 unregister_netdev(adm5120_devs
[i
]);
484 free_netdev(adm5120_devs
[i
-1]);
487 free_irq(SW_IRQ
, NULL
);
489 for (i
= 0; i
< ADM5120_DMA_RXH
; i
++) {
490 if (!adm5120_skb_rxh
[i
])
492 kfree_skb(adm5120_skb_rxh
[i
]);
494 for (i
= 0; i
< ADM5120_DMA_RXL
; i
++) {
495 if (!adm5120_skb_rxl
[i
])
497 kfree_skb(adm5120_skb_rxl
[i
]);
501 module_init(adm5120_sw_init
);
502 module_exit(adm5120_sw_exit
);