Rewrite of the bootloader runtime detection (Gabor Juhos)
[openwrt.git] / target / linux / adm5120-2.6 / files / drivers / net / adm5120sw.c
1 /*
2 * ADM5120 built in ethernet switch driver
3 *
4 * Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
5 *
6 * Inspiration for this driver came from the original ADMtek 2.4
7 * driver, Copyright ADMtek Inc.
8 */
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>
19 #include <asm/irq.h>
20 #include <asm/io.h>
21 #include "adm5120sw.h"
22
23 #include "adm5120_info.h"
24
25 MODULE_AUTHOR("Jeroen Vreeken (pe1rxq@amsat.org)");
26 MODULE_DESCRIPTION("ADM5120 ethernet switch driver");
27 MODULE_LICENSE("GPL");
28
29 /*
30 * The ADM5120 uses an internal matrix to determine which ports
31 * belong to which VLAN.
32 * The default generates a VLAN (and device) for each port
33 * (including MII port) and the CPU port is part of all of them.
34 *
35 * Another example, one big switch and everything mapped to eth0:
36 * 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00
37 */
38 static unsigned char vlan_matrix[SW_DEVS] = {
39 0x41, 0x42, 0x44, 0x48, 0x50, 0x60
40 };
41
42 static int adm5120_nrdevs;
43
44 static struct net_device *adm5120_devs[SW_DEVS];
45 static struct adm5120_dma
46 adm5120_dma_txh_v[ADM5120_DMA_TXH] __attribute__((aligned(16))),
47 adm5120_dma_txl_v[ADM5120_DMA_TXL] __attribute__((aligned(16))),
48 adm5120_dma_rxh_v[ADM5120_DMA_RXH] __attribute__((aligned(16))),
49 adm5120_dma_rxl_v[ADM5120_DMA_RXL] __attribute__((aligned(16))),
50 *adm5120_dma_txh,
51 *adm5120_dma_txl,
52 *adm5120_dma_rxh,
53 *adm5120_dma_rxl;
54 static struct sk_buff
55 *adm5120_skb_rxh[ADM5120_DMA_RXH],
56 *adm5120_skb_rxl[ADM5120_DMA_RXL],
57 *adm5120_skb_txh[ADM5120_DMA_TXH],
58 *adm5120_skb_txl[ADM5120_DMA_TXL];
59 static int adm5120_rxhi = 0;
60 static int adm5120_rxli = 0;
61 /* We don't use high priority tx for now */
62 /*static int adm5120_txhi = 0;*/
63 static int adm5120_txli = 0;
64 static int adm5120_txhit = 0;
65 static int adm5120_txlit = 0;
66 static int adm5120_if_open = 0;
67
68 static inline void adm5120_set_reg(unsigned int reg, unsigned long val)
69 {
70 *(volatile unsigned long*)(SW_BASE+reg) = val;
71 }
72
73 static inline unsigned long adm5120_get_reg(unsigned int reg)
74 {
75 return *(volatile unsigned long*)(SW_BASE+reg);
76 }
77
78 static inline void adm5120_rxfixup(struct adm5120_dma *dma,
79 struct sk_buff **skbl, int num)
80 {
81 int i;
82
83 /* Resubmit the entire ring */
84 for (i=0; i<num; i++) {
85 dma[i].status = 0;
86 dma[i].cntl = 0;
87 dma[i].len = ADM5120_DMA_RXSIZE;
88 dma[i].data = ADM5120_DMA_ADDR(skbl[i]->data) |
89 ADM5120_DMA_OWN | (i==num-1 ? ADM5120_DMA_RINGEND : 0);
90 }
91 }
92
93 static inline void adm5120_rx(struct adm5120_dma *dma, struct sk_buff **skbl,
94 int *index, int num)
95 {
96 struct sk_buff *skb, *skbn;
97 struct adm5120_sw *priv;
98 struct net_device *dev;
99 int port, vlan, len;
100
101 while (!(dma[*index].data & ADM5120_DMA_OWN)) {
102 port = (dma[*index].status & ADM5120_DMA_PORTID);
103 port >>= ADM5120_DMA_PORTSHIFT;
104 for (vlan = 0; vlan < adm5120_nrdevs; vlan++) {
105 if ((1<<port) & vlan_matrix[vlan])
106 break;
107 }
108 if (vlan == adm5120_nrdevs)
109 vlan = 0;
110 dev = adm5120_devs[vlan];
111 skb = skbl[*index];
112 len = (dma[*index].status & ADM5120_DMA_LEN);
113 len >>= ADM5120_DMA_LENSHIFT;
114 len -= ETH_FCS;
115
116 priv = netdev_priv(dev);
117 if (len <= 0 || len > ADM5120_DMA_RXSIZE ||
118 dma[*index].status & ADM5120_DMA_FCSERR) {
119 priv->stats.rx_errors++;
120 skbn = NULL;
121 } else {
122 skbn = dev_alloc_skb(ADM5120_DMA_RXSIZE+16);
123 if (skbn) {
124 skb_put(skb, len);
125 skb->dev = dev;
126 skb->protocol = eth_type_trans(skb, dev);
127 skb->ip_summed = CHECKSUM_UNNECESSARY;
128 dev->last_rx = jiffies;
129 priv->stats.rx_packets++;
130 priv->stats.rx_bytes+=len;
131 skb_reserve(skbn, 2);
132 skbl[*index] = skbn;
133 } else {
134 printk(KERN_INFO "%s recycling!\n", dev->name);
135 }
136 }
137
138 dma[*index].status = 0;
139 dma[*index].cntl = 0;
140 dma[*index].len = ADM5120_DMA_RXSIZE;
141 dma[*index].data = ADM5120_DMA_ADDR(skbl[*index]->data) |
142 ADM5120_DMA_OWN |
143 (num-1==*index ? ADM5120_DMA_RINGEND : 0);
144 if (num == ++*index)
145 *index = 0;
146 if (skbn)
147 netif_rx(skb);
148 }
149 }
150
151 static inline void adm5120_tx(struct adm5120_dma *dma, struct sk_buff **skbl,
152 int *index, int num)
153 {
154 while((dma[*index].data & ADM5120_DMA_OWN) == 0 && skbl[*index]) {
155 dev_kfree_skb_irq(skbl[*index]);
156 skbl[*index] = NULL;
157 if (++*index == num)
158 *index = 0;
159 }
160 }
161
162 irqreturn_t adm5120_sw_irq(int irq, void *dev_id, struct pt_regs *regs)
163 {
164 unsigned long intreg;
165
166 adm5120_set_reg(ADM5120_INT_MASK,
167 adm5120_get_reg(ADM5120_INT_MASK) | ADM5120_INTHANDLE);
168
169 intreg = adm5120_get_reg(ADM5120_INT_ST);
170 adm5120_set_reg(ADM5120_INT_ST, intreg);
171
172 if (intreg & ADM5120_INT_RXH)
173 adm5120_rx(adm5120_dma_rxh, adm5120_skb_rxh, &adm5120_rxhi,
174 ADM5120_DMA_RXH);
175 if (intreg & ADM5120_INT_HFULL)
176 adm5120_rxfixup(adm5120_dma_rxh, adm5120_skb_rxh,
177 ADM5120_DMA_RXH);
178 if (intreg & ADM5120_INT_RXL)
179 adm5120_rx(adm5120_dma_rxl, adm5120_skb_rxl, &adm5120_rxli,
180 ADM5120_DMA_RXL);
181 if (intreg & ADM5120_INT_LFULL)
182 adm5120_rxfixup(adm5120_dma_rxl, adm5120_skb_rxl,
183 ADM5120_DMA_RXL);
184 if (intreg & ADM5120_INT_TXH)
185 adm5120_tx(adm5120_dma_txh, adm5120_skb_txh, &adm5120_txhit,
186 ADM5120_DMA_TXH);
187 if (intreg & ADM5120_INT_TXL)
188 adm5120_tx(adm5120_dma_txl, adm5120_skb_txl, &adm5120_txlit,
189 ADM5120_DMA_TXL);
190
191 adm5120_set_reg(ADM5120_INT_MASK,
192 adm5120_get_reg(ADM5120_INT_MASK) & ~ADM5120_INTHANDLE);
193
194 return IRQ_HANDLED;
195 }
196
197 static void adm5120_set_vlan(char *matrix)
198 {
199 unsigned long val;
200
201 val = matrix[0] + (matrix[1]<<8) + (matrix[2]<<16) + (matrix[3]<<24);
202 adm5120_set_reg(ADM5120_VLAN_GI, val);
203 val = matrix[4] + (matrix[5]<<8);
204 adm5120_set_reg(ADM5120_VLAN_GII, val);
205 }
206
207 static int adm5120_sw_open(struct net_device *dev)
208 {
209 if (!adm5120_if_open++)
210 adm5120_set_reg(ADM5120_INT_MASK,
211 adm5120_get_reg(ADM5120_INT_MASK) & ~ADM5120_INTHANDLE);
212 netif_start_queue(dev);
213 return 0;
214 }
215
216 static int adm5120_sw_stop(struct net_device *dev)
217 {
218 netif_stop_queue(dev);
219 if (!--adm5120_if_open)
220 adm5120_set_reg(ADM5120_INT_MASK,
221 adm5120_get_reg(ADM5120_INT_MASK) | ADM5120_INTMASKALL);
222 return 0;
223 }
224
225 static int adm5120_sw_tx(struct sk_buff *skb, struct net_device *dev)
226 {
227 struct adm5120_dma *dma = adm5120_dma_txl;
228 struct sk_buff **skbl = adm5120_skb_txl;
229 struct adm5120_sw *priv = netdev_priv(dev);
230 int *index = &adm5120_txli;
231 int num = ADM5120_DMA_TXL;
232 int trigger = ADM5120_SEND_TRIG_L;
233
234 dev->trans_start = jiffies;
235 if (dma[*index].data & ADM5120_DMA_OWN) {
236 dev_kfree_skb(skb);
237 priv->stats.tx_dropped++;
238 return 0;
239 }
240
241 dma[*index].data = ADM5120_DMA_ADDR(skb->data) | ADM5120_DMA_OWN;
242 if (*index == num-1)
243 dma[*index].data |= ADM5120_DMA_RINGEND;
244 dma[*index].status =
245 ((skb->len<ETH_ZLEN?ETH_ZLEN:skb->len) << ADM5120_DMA_LENSHIFT) |
246 (0x1 << priv->port);
247 dma[*index].len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
248 priv->stats.tx_packets++;
249 priv->stats.tx_bytes += skb->len;
250 skbl[*index]=skb;
251
252 if (++*index == num)
253 *index = 0;
254 adm5120_set_reg(ADM5120_SEND_TRIG, trigger);
255
256 return 0;
257 }
258
259 static void adm5120_tx_timeout(struct net_device *dev)
260 {
261 netif_wake_queue(dev);
262 }
263
264 static struct net_device_stats *adm5120_sw_stats(struct net_device *dev)
265 {
266 return &((struct adm5120_sw *)netdev_priv(dev))->stats;
267 }
268
269 static void adm5120_set_multicast_list(struct net_device *dev)
270 {
271 struct adm5120_sw *priv = netdev_priv(dev);
272 int portmask;
273
274 portmask = vlan_matrix[priv->port] & 0x3f;
275
276 if (dev->flags & IFF_PROMISC)
277 adm5120_set_reg(ADM5120_CPUP_CONF,
278 adm5120_get_reg(ADM5120_CPUP_CONF) &
279 ~((portmask << ADM5120_DISUNSHIFT) & ADM5120_DISUNALL));
280 else
281 adm5120_set_reg(ADM5120_CPUP_CONF,
282 adm5120_get_reg(ADM5120_CPUP_CONF) |
283 (portmask << ADM5120_DISUNSHIFT));
284
285 if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI ||
286 dev->mc_count)
287 adm5120_set_reg(ADM5120_CPUP_CONF,
288 adm5120_get_reg(ADM5120_CPUP_CONF) &
289 ~((portmask << ADM5120_DISMCSHIFT) & ADM5120_DISMCALL));
290 else
291 adm5120_set_reg(ADM5120_CPUP_CONF,
292 adm5120_get_reg(ADM5120_CPUP_CONF) |
293 (portmask << ADM5120_DISMCSHIFT));
294 }
295
296 static void adm5120_write_mac(struct net_device *dev)
297 {
298 struct adm5120_sw *priv = netdev_priv(dev);
299 unsigned char *mac = dev->dev_addr;
300
301 adm5120_set_reg(ADM5120_MAC_WT1,
302 mac[2] | (mac[3]<<8) | (mac[4]<<16) | (mac[5]<<24));
303 adm5120_set_reg(ADM5120_MAC_WT0, (priv->port<<3) |
304 (mac[0]<<16) | (mac[1]<<24) | ADM5120_MAC_WRITE | ADM5120_VLAN_EN);
305
306 while (!(adm5120_get_reg(ADM5120_MAC_WT0) & ADM5120_MAC_WRITE_DONE));
307 }
308
309 static int adm5120_sw_set_mac_address(struct net_device *dev, void *p)
310 {
311 struct sockaddr *addr = p;
312
313 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
314 adm5120_write_mac(dev);
315 return 0;
316 }
317
318 static int adm5120_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
319 {
320 int err;
321 struct adm5120_sw_info info;
322 struct adm5120_sw *priv = netdev_priv(dev);
323
324 switch(cmd) {
325 case SIOCGADMINFO:
326 info.magic = 0x5120;
327 info.ports = adm5120_nrdevs;
328 info.vlan = priv->port;
329 err = copy_to_user(rq->ifr_data, &info, sizeof(info));
330 if (err)
331 return -EFAULT;
332 break;
333 case SIOCSMATRIX:
334 if (!capable(CAP_NET_ADMIN))
335 return -EPERM;
336 err = copy_from_user(vlan_matrix, rq->ifr_data,
337 sizeof(vlan_matrix));
338 if (err)
339 return -EFAULT;
340 adm5120_set_vlan(vlan_matrix);
341 break;
342 case SIOCGMATRIX:
343 err = copy_to_user(rq->ifr_data, vlan_matrix,
344 sizeof(vlan_matrix));
345 if (err)
346 return -EFAULT;
347 break;
348 default:
349 return -EOPNOTSUPP;
350 }
351 return 0;
352 }
353
354 static void adm5120_dma_tx_init(struct adm5120_dma *dma, struct sk_buff **skb,
355 int num)
356 {
357 memset(dma, 0, sizeof(struct adm5120_dma)*num);
358 dma[num-1].data |= ADM5120_DMA_RINGEND;
359 memset(skb, 0, sizeof(struct skb*)*num);
360 }
361
362 static void adm5120_dma_rx_init(struct adm5120_dma *dma, struct sk_buff **skb,
363 int num)
364 {
365 int i;
366
367 memset(dma, 0, sizeof(struct adm5120_dma)*num);
368 for (i=0; i<num; i++) {
369 skb[i] = dev_alloc_skb(ADM5120_DMA_RXSIZE+16);
370 if (!skb[i]) {
371 i=num;
372 break;
373 }
374 skb_reserve(skb[i], 2);
375 dma[i].data = ADM5120_DMA_ADDR(skb[i]->data) | ADM5120_DMA_OWN;
376 dma[i].cntl = 0;
377 dma[i].len = ADM5120_DMA_RXSIZE;
378 dma[i].status = 0;
379 }
380 dma[i-1].data |= ADM5120_DMA_RINGEND;
381 }
382
383 static int __init adm5120_sw_init(void)
384 {
385 int i, err;
386 struct net_device *dev;
387
388 err = request_irq(SW_IRQ, adm5120_sw_irq, 0, "ethernet switch", NULL);
389 if (err)
390 goto out;
391
392 /* MII port? */
393 if (adm5120_get_reg(ADM5120_CODE) & ADM5120_CODE_PQFP)
394 adm5120_nrdevs = 5;
395 /* CFE based devices only have two enet ports */
396 else if (adm5120_info.boot_loader == BOOT_LOADER_CFE)
397 adm5120_nrdevs = 2;
398 else
399 adm5120_nrdevs = 6;
400
401 adm5120_set_reg(ADM5120_CPUP_CONF,
402 ADM5120_DISCCPUPORT | ADM5120_CRC_PADDING |
403 ADM5120_DISUNALL | ADM5120_DISMCALL);
404 adm5120_set_reg(ADM5120_PORT_CONF0, ADM5120_ENMC | ADM5120_ENBP);
405
406 adm5120_set_reg(ADM5120_PHY_CNTL2, adm5120_get_reg(ADM5120_PHY_CNTL2) |
407 ADM5120_AUTONEG | ADM5120_NORMAL | ADM5120_AUTOMDIX);
408 adm5120_set_reg(ADM5120_PHY_CNTL3, adm5120_get_reg(ADM5120_PHY_CNTL3) |
409 ADM5120_PHY_NTH);
410
411 adm5120_set_reg(ADM5120_INT_MASK, ADM5120_INTMASKALL);
412 adm5120_set_reg(ADM5120_INT_ST, ADM5120_INTMASKALL);
413
414 adm5120_dma_txh = (void *)KSEG1ADDR((u32)adm5120_dma_txh_v);
415 adm5120_dma_txl = (void *)KSEG1ADDR((u32)adm5120_dma_txl_v);
416 adm5120_dma_rxh = (void *)KSEG1ADDR((u32)adm5120_dma_rxh_v);
417 adm5120_dma_rxl = (void *)KSEG1ADDR((u32)adm5120_dma_rxl_v);
418
419 adm5120_dma_tx_init(adm5120_dma_txh, adm5120_skb_txh, ADM5120_DMA_TXH);
420 adm5120_dma_tx_init(adm5120_dma_txl, adm5120_skb_txl, ADM5120_DMA_TXL);
421 adm5120_dma_rx_init(adm5120_dma_rxh, adm5120_skb_rxh, ADM5120_DMA_RXH);
422 adm5120_dma_rx_init(adm5120_dma_rxl, adm5120_skb_rxl, ADM5120_DMA_RXL);
423 adm5120_set_reg(ADM5120_SEND_HBADDR, KSEG1ADDR(adm5120_dma_txh));
424 adm5120_set_reg(ADM5120_SEND_LBADDR, KSEG1ADDR(adm5120_dma_txl));
425 adm5120_set_reg(ADM5120_RECEIVE_HBADDR, KSEG1ADDR(adm5120_dma_rxh));
426 adm5120_set_reg(ADM5120_RECEIVE_LBADDR, KSEG1ADDR(adm5120_dma_rxl));
427
428 adm5120_set_vlan(vlan_matrix);
429
430 for (i=0; i<adm5120_nrdevs; i++) {
431 adm5120_devs[i] = alloc_etherdev(sizeof(struct adm5120_sw));
432 if (!adm5120_devs[i]) {
433 err = -ENOMEM;
434 goto out_int;
435 }
436
437 dev = adm5120_devs[i];
438 SET_MODULE_OWNER(dev);
439 memset(netdev_priv(dev), 0, sizeof(struct adm5120_sw));
440 ((struct adm5120_sw*)netdev_priv(dev))->port = i;
441 dev->base_addr = SW_BASE;
442 dev->irq = SW_IRQ;
443 dev->open = adm5120_sw_open;
444 dev->hard_start_xmit = adm5120_sw_tx;
445 dev->stop = adm5120_sw_stop;
446 dev->get_stats = adm5120_sw_stats;
447 dev->set_multicast_list = adm5120_set_multicast_list;
448 dev->do_ioctl = adm5120_do_ioctl;
449 dev->tx_timeout = adm5120_tx_timeout;
450 dev->watchdog_timeo = ETH_TX_TIMEOUT;
451 dev->set_mac_address = adm5120_sw_set_mac_address;
452 /* HACK alert!!! In the original admtek driver it is asumed
453 that you can read the MAC addressess from flash, but edimax
454 decided to leave that space intentionally blank...
455 */
456 memcpy(dev->dev_addr, "\x00\x50\xfc\x11\x22\x01", 6);
457 dev->dev_addr[5] += i;
458 adm5120_write_mac(dev);
459
460 if ((err = register_netdev(dev))) {
461 free_netdev(dev);
462 goto out_int;
463 }
464 printk(KERN_INFO "%s: ADM5120 switch port%d\n", dev->name, i);
465 }
466 adm5120_set_reg(ADM5120_CPUP_CONF,
467 ADM5120_CRC_PADDING | ADM5120_DISUNALL | ADM5120_DISMCALL);
468
469 return 0;
470
471 out_int:
472 /* Undo everything that did succeed */
473 for (; i; i--) {
474 unregister_netdev(adm5120_devs[i-1]);
475 free_netdev(adm5120_devs[i-1]);
476 }
477 free_irq(SW_IRQ, NULL);
478 out:
479 printk(KERN_ERR "ADM5120 Ethernet switch init failed\n");
480 return err;
481 }
482
483 static void __exit adm5120_sw_exit(void)
484 {
485 int i;
486
487 for (i = 0; i < adm5120_nrdevs; i++) {
488 unregister_netdev(adm5120_devs[i]);
489 free_netdev(adm5120_devs[i-1]);
490 }
491
492 free_irq(SW_IRQ, NULL);
493
494 for (i = 0; i < ADM5120_DMA_RXH; i++) {
495 if (!adm5120_skb_rxh[i])
496 break;
497 kfree_skb(adm5120_skb_rxh[i]);
498 }
499 for (i = 0; i < ADM5120_DMA_RXL; i++) {
500 if (!adm5120_skb_rxl[i])
501 break;
502 kfree_skb(adm5120_skb_rxl[i]);
503 }
504 }
505
506 module_init(adm5120_sw_init);
507 module_exit(adm5120_sw_exit);
This page took 0.075566 seconds and 5 git commands to generate.