root/src/linux/brcm/linux.v24_2/drivers/net/et/et_linux.c

Revision 8761, 25.3 kB (checked in by BrainSlayer, 3 years ago)

commit newer linux.v24 kernel code (some parts missing, will be added in the next days)

Line 
1 /*
2  * Linux device driver for
3  * Broadcom BCM44XX and BCM47XX 10/100 Mbps Ethernet Controller
4  *
5  * Copyright 2004, Broadcom Corporation
6  * All Rights Reserved.               
7  *                                     
8  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;   
9  * the contents of this file may not be disclosed to third parties, copied
10  * or duplicated in any form, in whole or in part, without the prior     
11  * written permission of Broadcom Corporation.                           
12  *
13  * $Id$
14  */
15
16 #define __UNDEF_NO_VERSION__
17
18 #include <typedefs.h>
19
20 #include <linux/module.h>
21 #include <linuxver.h>
22 #include <linux_osl.h>
23
24 #include <linux/types.h>
25 #include <linux/errno.h>
26 #include <linux/pci.h>
27 #include <linux/init.h>
28 #include <linux/kernel.h>
29 #include <linux/netdevice.h>
30 #include <linux/etherdevice.h>
31 #include <linux/skbuff.h>
32 #include <linux/delay.h>
33 #include <linux/string.h>
34 #include <linux/sockios.h>
35 #ifdef SIOCETHTOOL
36 #include <linux/ethtool.h>
37 #endif
38 #include <linux/mii.h>
39 #include <linux/ip.h>
40
41 #include <asm/system.h>
42 #include <asm/io.h>
43 #include <asm/irq.h>
44 #include <asm/pgtable.h>
45 #include <asm/uaccess.h>
46
47 #include <epivers.h>
48 #include <bcmendian.h>
49 #include <proto/ethernet.h>
50 #include <proto/vlan.h>
51 #include <bcmdevs.h>
52 #include <bcmenetmib.h>
53 #include <bcmenetrxh.h>
54 #include <bcmenetphy.h>
55 #include <etsockio.h>
56 #include <bcmutils.h>
57 #include <et_dbg.h>
58 #include <etc.h>
59
60 typedef struct et_info {
61         etc_info_t      *etc;           /* pointer to common os-independent data */
62         struct net_device *dev;         /* backpoint to device */
63         struct pci_dev *pdev;           /* backpoint to pci_dev */
64         void            *osh;           /* pointer to os handle */
65         spinlock_t      lock;           /* per-device perimeter lock */
66         struct sk_buff_head txq;        /* send queue */
67         void *regsva;                   /* opaque chip registers virtual address */
68         struct timer_list timer;        /* one second watchdog timer */
69         struct net_device_stats stats;  /* stat counter reporting structure */
70         int events;                     /* bit channel between isr and dpc */
71         struct tasklet_struct tasklet;  /* dpc tasklet */
72         ulong flags;                    /* current irq flags */
73         struct et_info *next;           /* pointer to next et_info_t in chain */
74 } et_info_t;
75
76 static int et_found = 0;
77 static et_info_t *et_list = NULL;
78
79 /* defines */
80 #define ET_INFO(dev)    (et_info_t*)((dev)->priv)
81 #define DATAHIWAT       50              /* data msg txq hiwat mark */
82 #define ET_LOCK(et)     do { ulong flags; spin_lock_irqsave(&(et)->lock, flags); (et)->flags = flags; } while (0)
83 #define ET_UNLOCK(et)   do { ulong flags; flags = (et)->flags; spin_unlock_irqrestore(&(et)->lock, flags); } while (0)
84 #define ET_LOCKED(wl)   spin_is_locked(&(et)->lock)
85
86 #define ET_TASKLET (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,5))
87
88 /* prototypes called by etc.c */
89 void et_init(et_info_t *et);
90 void et_reset(et_info_t *et);
91 void et_link_up(et_info_t *et);
92 void et_link_down(et_info_t *et);
93 void et_up(et_info_t *et);
94 void et_down(et_info_t *et, int reset);
95 int et_dump(et_info_t *et, uchar *buf, uint len);
96
97 /* local prototypes */
98 static void et_free(et_info_t *et);
99 static int et_open(struct net_device *dev);
100 static int et_close(struct net_device *dev);
101 static int et_start(struct sk_buff *skb, struct net_device *dev);
102 static void et_sendnext(et_info_t *et);
103 static struct net_device_stats *et_get_stats(struct net_device *dev);
104 static int et_set_mac_address(struct net_device *dev, void *addr);
105 static void et_set_multicast_list(struct net_device *dev);
106 static void et_watchdog(ulong data);
107 static int et_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
108 static irqreturn_t et_isr(int irq, void *dev_id, struct pt_regs *ptregs);
109 static void et_dpc(ulong data);
110 static void et_sendup(et_info_t *et, struct sk_buff *skb);
111
112 /* recognized PCI IDs */
113 static struct pci_device_id et_id_table[] __devinitdata = {
114         { vendor: PCI_ANY_ID,
115           device: PCI_ANY_ID,
116           subvendor: PCI_ANY_ID,
117           subdevice: PCI_ANY_ID,
118           class: PCI_CLASS_NETWORK_ETHERNET << 8,
119           class_mask: 0xffff00,
120           driver_data: 0,
121         },
122         { 0, }
123 };
124 MODULE_DEVICE_TABLE(pci, et_id_table);
125
126
127 static int __devinit
128 et_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
129 {
130         struct net_device *dev;
131         et_info_t *et;
132         void *osh;
133         char name[128];
134         int unit = et_found;
135
136
137         ET_TRACE(("et%d: et_probe: bus %d slot %d func %d irq %d\n", unit,
138                   pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev->irq));
139
140         if (!etc_chipmatch(pdev->vendor, pdev->device))
141                 return -ENODEV;
142
143         osh = osl_attach(pdev);
144         ASSERT(osh);
145
146         pci_set_master(pdev);
147         pci_enable_device(pdev);
148
149         if (!(dev = (struct net_device *) MALLOC(osh, sizeof(struct net_device)))) {
150                 ET_ERROR(("et%d: et_probe: out of memory, malloced %d bytes\n", unit, MALLOCED(osh)));
151                 osl_detach(osh);
152                 return -ENOMEM;
153         }
154         bzero(dev, sizeof(struct net_device));
155
156         if (!init_etherdev(dev, 0)) {
157                 ET_ERROR(("et%d: et_probe: init_etherdev() failed\n", unit));
158                 MFREE(osh, dev, sizeof(struct net_device));
159                 osl_detach(osh);
160                 return -ENOMEM;
161         }
162
163         /* allocate private info */
164         if ((et = (et_info_t*) MALLOC(osh, sizeof (et_info_t))) == NULL) {
165                 ET_ERROR(("et%d: et_probe: out of memory, malloced %d bytes\n", unit, MALLOCED(osh)));
166                 MFREE(osh, dev, sizeof(et_info_t));
167                 osl_detach(osh);
168                 return -ENOMEM;
169         }
170         bzero(et, sizeof (et_info_t));
171         dev->priv = (void*) et;
172         et->dev = dev;
173         et->pdev = pdev;
174         et->osh = osh;
175         pci_set_drvdata(pdev, et);
176
177         /* map chip registers (47xx: and sprom) */     
178         dev->base_addr = pci_resource_start(pdev, 0);
179         if ((et->regsva = ioremap_nocache(dev->base_addr, 8192)) == NULL) {
180                 ET_ERROR(("et%d: ioremap() failed\n", unit));
181                 goto fail;
182         }
183
184         spin_lock_init(&et->lock);
185         skb_queue_head_init(&et->txq);
186
187         /* common load-time initialization */
188         if ((et->etc = etc_attach((void*)et, pdev->vendor, pdev->device, unit, osh, et->regsva)) == NULL) {
189                 ET_ERROR(("et%d: etc_attach() failed\n", unit));
190                 goto fail;
191         }
192
193         bcopy(&et->etc->cur_etheraddr, dev->dev_addr, ETHER_ADDR_LEN);
194
195         /* init 1 second watchdog timer */
196         init_timer(&et->timer);
197         et->timer.data = (ulong)dev;
198         et->timer.function = et_watchdog;
199
200 #if ET_TASKLET
201         /* setup the bottom half handler */
202         tasklet_init(&et->tasklet, et_dpc, (ulong)et);
203 #endif
204
205         /* register our interrupt handler */
206         if (request_irq(pdev->irq, et_isr, SA_SHIRQ | SA_NET_RANDOM, dev->name, et)) {
207                 ET_ERROR(("et%d: request_irq() failed\n", unit));
208                 goto fail;
209         }
210         dev->irq = pdev->irq;
211
212         /* add us to the global linked list */
213         et->next = et_list;
214         et_list = et;
215
216         /* print hello string */
217         (*et->etc->chops->longname)(et->etc->ch, name, sizeof (name));
218         printf("%s: %s %s\n", dev->name, name, EPI_VERSION_STR);
219
220         /* lastly, enable our entry points */
221         dev->open = et_open;
222         dev->stop = et_close;
223         dev->hard_start_xmit = et_start;
224         dev->get_stats = et_get_stats;
225         dev->set_mac_address = et_set_mac_address;
226         dev->set_multicast_list = et_set_multicast_list;
227         dev->do_ioctl = et_ioctl;
228
229         if (register_netdev(dev)) {
230                 ET_ERROR(("et%d: register_netdev() failed\n", unit));
231                 goto fail;
232         }
233
234         et_found++;
235         return (0);
236
237 fail:
238         et_free(et);
239         return (-ENODEV);
240 }
241
242 static int
243 et_suspend(struct pci_dev *pdev, u32 state)
244 {
245         et_info_t *et;
246        
247         if ((et = (et_info_t *) pci_get_drvdata(pdev))) {
248                 netif_device_detach(et->dev);
249                 ET_LOCK(et);
250                 et_down(et, 1);
251                 ET_UNLOCK(et);
252         }
253
254         return 0;
255 }       
256
257 static int
258 et_resume(struct pci_dev *pdev)
259 {
260         et_info_t *et;
261                
262         if ((et = (et_info_t *) pci_get_drvdata(pdev))) {
263                 ET_LOCK(et);
264                 et_up(et);
265                 ET_UNLOCK(et);
266                 netif_device_attach(et->dev);
267         }
268
269         return 0;
270 }
271
272 /* Compatibility routines */
273 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6)
274 static void
275 _et_suspend(struct pci_dev *pdev)
276 {
277         et_suspend(pdev, 0);
278 }
279
280 static void
281 _et_resume(struct pci_dev *pdev)
282 {
283         et_resume(pdev);
284 }
285 #endif
286
287 static void __devexit
288 et_remove(struct pci_dev *pdev)
289 {
290         et_info_t *et;
291
292         if (!etc_chipmatch(pdev->vendor, pdev->device))
293                 return;
294
295         et_suspend(pdev, 0);
296
297         if ((et = (et_info_t *) pci_get_drvdata(pdev))) {
298                 et_free(et);
299                 pci_set_drvdata(pdev, NULL);
300         }
301 }
302
303 static struct pci_driver et_pci_driver = {
304         name:           "et",
305         probe:          et_probe,
306 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6)
307         suspend:        _et_suspend,
308         resume:         _et_resume,
309 #else
310         suspend:        et_suspend,
311         resume:         et_resume,
312 #endif
313         remove:         __devexit_p(et_remove),
314         id_table:       et_id_table,
315 };
316
317 static int __init
318 et_module_init(void)
319 {
320         return pci_module_init(&et_pci_driver);
321 }
322
323 static void __exit
324 et_module_exit(void)
325 {
326         pci_unregister_driver(&et_pci_driver);
327 }
328
329 module_init(et_module_init);
330 module_exit(et_module_exit);
331
332 static void
333 et_free(et_info_t *et)
334 {
335         et_info_t **prev;
336         void *osh;
337
338         if (et == NULL)
339                 return;
340
341         ET_TRACE(("et: et_free\n"));
342
343         if (et->dev && et->dev->irq)
344                 free_irq(et->dev->irq, et);
345
346         if (et->dev) {
347                 unregister_netdev(et->dev);
348                 MFREE(et->osh, et->dev, sizeof(struct net_device));
349                 et->dev = NULL;
350         }
351
352         /* free common resources */
353         if (et->etc) {
354                 etc_detach(et->etc);
355                 et->etc = NULL;
356         }
357
358         /*
359          * unregister_netdev() calls get_stats() which may read chip registers
360          * so we cannot unmap the chip registers until after calling unregister_netdev() .
361          */
362         if (et->regsva) {
363                 iounmap((void*)et->regsva);
364                 et->regsva = NULL;
365         }
366
367         /* remove us from the global linked list */
368         for (prev = &et_list; *prev; prev = &(*prev)->next)
369                 if (*prev == et) {
370                         *prev = et->next;
371                         break;
372                 }
373
374         osh = et->osh;
375         MFREE(et->osh, et, sizeof (et_info_t));
376
377         ASSERT(MALLOCED(osh) == 0);
378
379         osl_detach(osh);
380 }
381
382 static int
383 et_open(struct net_device *dev)
384 {
385         et_info_t *et;
386        
387         et = ET_INFO(dev);
388
389         ET_TRACE(("et%d: et_open\n", et->etc->unit));
390
391         et->etc->promisc = (dev->flags & IFF_PROMISC)? TRUE: FALSE;
392
393         ET_LOCK(et);
394         et_up(et);
395         ET_UNLOCK(et);
396
397         OLD_MOD_INC_USE_COUNT;
398
399         return (0);
400 }
401
402 static int
403 et_close(struct net_device *dev)
404 {
405         et_info_t *et;
406        
407         et = ET_INFO(dev);
408
409         ET_TRACE(("et%d: et_close\n", et->etc->unit));
410
411         et->etc->promisc = FALSE;
412
413         ET_LOCK(et);
414         et_down(et, 1);
415         ET_UNLOCK(et);
416
417         OLD_MOD_DEC_USE_COUNT;
418
419         return (0);
420 }
421
422 /*
423  * Yeah, queueing the packets on a tx queue instead of throwing them
424  * directly into the descriptor ring in the case of dma is kinda lame,
425  * but this results in a unified transmit path for both dma and pio
426  * and localizes/simplifies the netif_*_queue semantics, too.
427  */
428 static int
429 et_start(struct sk_buff *skb, struct net_device *dev)
430 {
431         et_info_t *et;
432
433         et = ET_INFO(dev);
434
435         ET_TRACE(("et%d: et_start: len %d\n", et->etc->unit, skb->len));
436         ET_LOG("et%d: et_start: len %d", et->etc->unit, skb->len);
437
438         ET_LOCK(et);
439
440         /* put it on the tx queue and call sendnext */
441         skb_queue_tail(&et->txq, skb);
442         et_sendnext(et);
443
444         ET_UNLOCK(et);
445
446         ET_LOG("et%d: et_start ret\n", et->etc->unit, 0);
447
448         return (0);
449 }
450
451 static void
452 et_sendnext(et_info_t *et)
453 {
454         etc_info_t *etc;
455         struct sk_buff *skb;
456
457         etc = et->etc;
458
459         ET_TRACE(("et%d: et_sendnext\n", etc->unit));
460         ET_LOG("et%d: et_sendnext", etc->unit, 0);
461
462         /* dequeue and send each packet */
463 #ifdef DMA
464         while (*etc->txavail > 0) {
465 #else
466         while (etc->pioactive == NULL) {
467 #endif
468                 if ((skb = skb_dequeue(&et->txq)) == NULL)
469                         break;
470
471                 ET_PRHDR("tx", (struct ether_header*) skb->data, skb->len, etc->unit);
472                 ET_PRPKT("txpkt", skb->data, skb->len, etc->unit);
473
474                 (*etc->chops->tx)(etc->ch, (void*)skb);
475
476                 etc->txframe++;
477                 etc->txbyte += skb->len;
478         }
479
480         /* stop the queue whenever txq fills */
481         if ((skb_queue_len(&et->txq) > DATAHIWAT) && !netif_queue_stopped(et->dev))
482                 netif_stop_queue(et->dev);
483         else if (netif_queue_stopped(et->dev) && (skb_queue_len(&et->txq) < (DATAHIWAT/2))) {
484                 netif_wake_queue(et->dev);
485         }
486 }
487
488 void
489 et_init(et_info_t *et)
490 {
491         ET_TRACE(("et%d: et_init\n", et->etc->unit));
492         ET_LOG("et%d: et_init", et->etc->unit, 0);
493
494         et_reset(et);
495
496         etc_init(et->etc);
497 }
498
499 void
500 et_reset(et_info_t *et)
501 {
502         ET_TRACE(("et%d: et_reset\n", et->etc->unit));
503
504         etc_reset(et->etc);
505
506         /* zap any pending dpc interrupt bits */
507         et->events = 0;
508 }
509
510 void
511 et_up(et_info_t *et)
512 {
513         etc_info_t *etc;
514
515         etc = et->etc;
516
517         if (etc->up)
518                 return;
519
520         ET_TRACE(("et%d: et_up\n", etc->unit));
521
522         etc_up(etc);
523
524         /* schedule one second watchdog timer */
525         et->timer.expires = jiffies + HZ;
526         add_timer(&et->timer);
527
528         netif_start_queue(et->dev);
529 }
530
531 void
532 et_down(et_info_t *et, int reset)
533 {
534         etc_info_t *etc;
535         struct sk_buff *skb;
536
537         etc = et->etc;
538
539         ET_TRACE(("et%d: et_down\n", etc->unit));
540
541         netif_down(et->dev);
542         netif_stop_queue(et->dev);
543
544         /* stop watchdog timer */
545         del_timer(&et->timer);
546
547         etc_down(etc, reset);
548
549         /* flush the txq */
550         while ((skb = skb_dequeue(&et->txq)))
551                 osl_pktfree(skb);
552
553 #if ET_TASKLET
554         /* kill dpc */
555         ET_UNLOCK(et);
556         tasklet_kill(&et->tasklet);
557         ET_LOCK(et);
558 #endif
559 }
560
561 static void
562 et_watchdog(ulong data)
563 {
564         et_info_t *et;
565
566         et = ET_INFO((struct net_device*)data);
567
568         ET_LOCK(et);
569
570         etc_watchdog(et->etc);
571
572         /* reschedule one second watchdog timer */
573         et->timer.expires = jiffies + HZ;
574         add_timer(&et->timer);
575
576         ET_UNLOCK(et);
577 }
578
579
580 #ifdef SIOCETHTOOL
581 static int
582 et_ethtool(et_info_t *et, struct ethtool_cmd *ecmd)
583 {
584         int ret = 0;
585         int speed;
586         struct ethtool_drvinfo *info;
587
588         ET_LOCK(et);
589
590         switch (ecmd->cmd) {
591         case ETHTOOL_GSET:
592                 ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
593                                    SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
594                                    SUPPORTED_Autoneg);
595                 ecmd->advertising = ADVERTISED_TP;
596                 ecmd->advertising |= (et->etc->advertise & ADV_10HALF) ? ADVERTISED_10baseT_Half : 0;
597                 ecmd->advertising |= (et->etc->advertise & ADV_10FULL) ? ADVERTISED_10baseT_Full : 0;
598                 ecmd->advertising |= (et->etc->advertise & ADV_100HALF) ? ADVERTISED_100baseT_Half : 0;
599                 ecmd->advertising |= (et->etc->advertise & ADV_100FULL) ? ADVERTISED_100baseT_Full : 0;
600                 if (et->etc->linkstate) {
601                         ecmd->speed = (et->etc->speed == 100) ? SPEED_100 : SPEED_10;
602                         ecmd->duplex = (et->etc->duplex == 1) ? DUPLEX_FULL : DUPLEX_HALF;
603                 } else {
604                         ecmd->speed = 0;
605                         ecmd->duplex = 0;
606                 }
607                 ecmd->port = PORT_TP;
608                 ecmd->phy_address = 0;
609                 ecmd->transceiver = XCVR_INTERNAL;
610                 ecmd->autoneg = (et->etc->forcespeed == ET_AUTO) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
611                 ecmd->maxtxpkt = 0;
612                 ecmd->maxrxpkt = 0;
613                 break;
614         case ETHTOOL_SSET:
615                 if(!capable(CAP_NET_ADMIN)) {
616                         ret = -EPERM;
617                         break;
618                 }
619                 else if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF)
620                         speed = ET_10HALF;
621                 else if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL)
622                         speed = ET_10FULL;
623                 else if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF)
624                         speed = ET_100HALF;
625                 else if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL)
626                         speed = ET_100FULL;
627                 else if (ecmd->autoneg == AUTONEG_ENABLE)
628                         speed = ET_AUTO;
629                 else {
630                         ret = -EINVAL;
631                         break;
632                 }
633                 ret = etc_ioctl(et->etc, ETCSPEED, &speed);
634                 break;
635         case ETHTOOL_GDRVINFO:
636                 info = (struct ethtool_drvinfo *)ecmd;
637                 bzero(info, sizeof(struct ethtool_drvinfo));
638                 info->cmd = ETHTOOL_GDRVINFO;
639                 sprintf(info->driver, "et%d", et->etc->unit);
640                 strcpy(info->version, EPI_VERSION_STR);
641                 break;
642         default:
643                 ret = -EINVAL;
644                 break;
645         }
646
647         ET_UNLOCK(et);
648
649         return (ret);
650 }
651 #endif
652
653 static int
654 et_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
655 {
656         et_info_t *et;
657         int error;
658         char *buf;
659         int size;
660         bool get, set;
661         struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
662
663         et = ET_INFO(dev);
664
665         ET_TRACE(("et%d: et_ioctl: cmd 0x%x\n", et->etc->unit, cmd));
666
667         switch (cmd) {
668 #ifdef SIOCETHTOOL
669         case SIOCETHTOOL:
670                 if (((struct ethtool_cmd *)ifr->ifr_data)->cmd == ETHTOOL_GDRVINFO)
671                         size = sizeof(struct ethtool_drvinfo);
672                 else
673                         size = sizeof (struct ethtool_cmd);
674                 get = TRUE; set = TRUE;
675                 break;
676 #endif
677         case SIOCGETCDUMP:
678                 size = 4096;
679                 get = TRUE; set = FALSE;
680                 break;
681         case SIOCGETCPHYRD:
682                 size = sizeof (int) * 2;
683                 get = TRUE; set = TRUE;
684                 break;
685         case SIOCSETCPHYWR:
686                 size = sizeof (int) * 2;
687                 get = FALSE; set = TRUE;
688                 break;
689         case SIOCGMIIPHY:
690                 data->phy_id = et->etc->phyaddr;
691         case SIOCGMIIREG:
692                 data->val_out = (*et->etc->chops->phyrd)(et->etc->ch, data->phy_id, data->reg_num);
693                 return 0;
694         case SIOCSMIIREG:
695                 (*et->etc->chops->phywr)(et->etc->ch, data->phy_id, data->reg_num, data->val_in);
696                 return 0;
697         default:
698                 size = sizeof (int);
699                 get = FALSE; set = TRUE;
700                 break;
701         }
702
703         if ((buf = MALLOC(et->osh, size)) == NULL) {
704                 ET_ERROR(("et: et_ioctl: out of memory, malloced %d bytes\n", MALLOCED(et->osh)));
705                 return (-ENOMEM);
706         }
707
708         if (set && copy_from_user(buf, ifr->ifr_data, size)) {
709                 MFREE(et->osh, buf, size);
710                 return (-EFAULT);
711         }
712
713         switch (cmd) {
714 #ifdef SIOCETHTOOL
715         case SIOCETHTOOL:
716                 error = et_ethtool(et, (struct ethtool_cmd*)buf);
717                 break;
718 #endif
719         default:
720                 ET_LOCK(et);           
721                 error = etc_ioctl(et->etc, cmd - SIOCSETCUP, buf) ? -EINVAL : 0;
722                 ET_UNLOCK(et);
723                 break;
724         }
725
726         if (!error && get)
727                 error = copy_to_user(ifr->ifr_data, buf, size);
728
729         MFREE(et->osh, buf, size);
730
731         return (error);
732 }
733
734 static struct net_device_stats*
735 et_get_stats(struct net_device *dev)
736 {
737         et_info_t *et;
738         etc_info_t *etc;
739         struct net_device_stats *stats;
740
741         et = ET_INFO(dev);
742
743         ET_TRACE(("et%d: et_get_stats\n", et->etc->unit));
744
745         ET_LOCK(et);
746
747         etc = et->etc;
748         stats = &et->stats;
749         bzero(stats, sizeof (struct net_device_stats));
750
751         /* refresh stats */
752         if (et->etc->up)
753                 (*etc->chops->statsupd)(etc->ch);
754
755         /* SWAG */
756         stats->rx_packets = etc->rxframe;
757         stats->tx_packets = etc->txframe;
758         stats->rx_bytes = etc->rxbyte;
759         stats->tx_bytes = etc->txbyte;
760         stats->rx_errors = etc->rxerror;
761         stats->tx_errors = etc->txerror;
762         stats->collisions = etc->mib.tx_total_cols;
763
764         stats->rx_length_errors = (etc->mib.rx_oversize_pkts + etc->mib.rx_undersize);
765         stats->rx_over_errors = etc->rxoflo;
766         stats->rx_crc_errors = etc->mib.rx_crc_errs;
767         stats->rx_frame_errors = etc->mib.rx_align_errs;
768         stats->rx_fifo_errors = etc->rxoflo;
769         stats->rx_missed_errors = etc->mib.rx_missed_pkts;
770
771         stats->tx_fifo_errors = etc->txuflo;
772
773         ET_UNLOCK(et);
774
775         return (stats);
776 }
777
778 static int
779 et_set_mac_address(struct net_device *dev, void *addr)
780 {
781         et_info_t *et;
782         struct sockaddr *sa = (struct sockaddr *) addr;
783
784         et = ET_INFO(dev);
785         ET_TRACE(("et%d: et_set_mac_address\n", et->etc->unit));
786
787         if (et->etc->up)
788                 return -EBUSY;
789
790         bcopy(sa->sa_data, dev->dev_addr, ETHER_ADDR_LEN);
791         bcopy(dev->dev_addr, &et->etc->cur_etheraddr, ETHER_ADDR_LEN);
792
793         return 0;
794 }
795
796 static void
797 et_set_multicast_list(struct net_device *dev)
798 {
799         et_info_t *et;
800         etc_info_t *etc;
801         struct dev_mc_list *mclist;
802         int i;
803
804         et = ET_INFO(dev);
805         etc = et->etc;
806
807         ET_TRACE(("et%d: et_set_multicast_list\n", etc->unit));
808
809         ET_LOCK(et);
810
811         if (etc->up) {
812                 etc->promisc = (dev->flags & IFF_PROMISC)? TRUE: FALSE;
813                 etc->allmulti = (dev->flags & IFF_ALLMULTI)? TRUE: FALSE;
814
815                 /* copy the list of multicasts into our private table */
816                 for (i = 0, mclist = dev->mc_list; mclist && (i < dev->mc_count);
817                         i++, mclist = mclist->next) {
818                         if (i >= MAXMULTILIST) {
819                                 etc->allmulti = TRUE;
820                                 i = 0;
821                                 break;
822                         }
823                         etc->multicast[i] = *((struct ether_addr*) mclist->dmi_addr);
824                 }
825                 etc->nmulticast = i;
826                
827                 et_init(et);
828         }
829
830         ET_UNLOCK(et);
831 }
832
833 static irqreturn_t
834 et_isr(int irq, void *dev_id, struct pt_regs *ptregs)
835 {
836         et_info_t *et;
837         struct chops *chops;
838         void *ch;
839         uint events = 0;
840
841         et = (et_info_t*) dev_id;
842         chops = et->etc->chops;
843         ch = et->etc->ch;
844
845         spin_lock(&et->lock);
846
847         /* guard against shared interrupts */
848         if (!et->etc->up)
849                 goto done;
850
851         /* get interrupt condition bits */
852         events = (*chops->getintrevents)(ch);
853
854         /* not for us */
855         if (!(events & INTR_NEW))
856                 goto done;
857
858         ET_TRACE(("et%d: et_isr: events 0x%x\n", et->etc->unit, events));
859         ET_LOG("et%d: et_isr: events 0x%x", et->etc->unit, events);
860
861         /* disable interrupts */
862         (*chops->intrsoff)(ch);
863
864         /* save intstatus bits */
865         ASSERT(et->events == 0);
866         et->events = events;
867
868 #if ET_TASKLET
869         /* schedule dpc */
870         tasklet_schedule(&et->tasklet);
871 #else
872         /* run dpc */
873         spin_unlock(&et->lock);
874         et_dpc((ulong) et);
875         spin_lock(&et->lock);
876 #endif
877
878  done:
879         spin_unlock(&et->lock);
880
881         ET_LOG("et%d: et_isr ret", et->etc->unit, 0);
882
883         return IRQ_RETVAL(events & INTR_NEW);
884 }
885
886 static void
887 et_dpc(ulong data)
888 {
889         et_info_t *et;
890         struct chops *chops;
891         void *ch;
892         struct sk_buff *skb;
893
894         et = (et_info_t*) data;
895         chops = et->etc->chops;
896         ch = et->etc->ch;
897
898         ET_TRACE(("et%d: et_dpc: events 0x%x\n", et->etc->unit, et->events));
899         ET_LOG("et%d: et_dpc: events 0x%x", et->etc->unit, et->events);
900
901         spin_lock(&et->lock);
902
903         if (!et->etc->up)
904                 goto done;
905
906         if (et->events & INTR_RX) {
907                 while ((skb = (struct sk_buff*) (*chops->rx)(ch)))
908                         et_sendup(et, skb);
909
910                 /* post more rx bufs */
911                 (*chops->rxfill)(ch);
912         }
913
914         if (et->events & INTR_TX)
915         {
916                 (*chops->txreclaim)(ch, FALSE);
917         }
918        
919         if (et->events & INTR_ERROR)
920                 if ((*chops->errors)(ch))
921                         et_init(et);
922
923         /* run the tx queue */
924         if (skb_queue_len(&et->txq) > 0)
925                 et_sendnext(et);
926
927  done: 
928         /* clear this before re-enabling interrupts */
929         et->events = 0;
930
931         spin_unlock(&et->lock);
932
933         /* re-enable interrupts */
934         if (et->etc->up)
935                 (*chops->intrson)(ch);
936
937         ET_LOG("et%d: et_dpc ret", et->etc->unit, 0);
938 }
939
940 /* Extract priority from VLAN tag or DSCP field */
941 void
942 et_set_rxprio(et_info_t *et, struct sk_buff *skb)
943 {
944         uint8 vlan_prio = 0;
945         uint16 vlan_id = 0;
946         struct ether_header *eh;
947         struct ethervlan_header *evh;
948         struct iphdr *ip = NULL;
949
950         eh = (struct ether_header*)skb->data;
951         ASSERT(ISALIGNED((uintptr)eh, sizeof(uint16)));
952
953         /* IP header follows ethernet header, or VLAN tags if present */
954         if (ntoh16(eh->ether_type) == ETHER_TYPE_IP)
955                 ip = (struct iphdr *)((uint)eh + ETHER_HDR_LEN);
956         else if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
957                 evh = (struct ethervlan_header*)eh;
958                 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP)
959                         ip = (struct iphdr *)&evh[1];
960
961 #ifdef REMOVE
962                 /* if ADMtek, single emac and ip pkt */
963                 if ((et->etc->boardflags & BFL_ENETADM) &&
964                         (et->etc->boardflags & BFL_ENETVLAN) && ip) {
965 #else
966                 if ((et->etc->boardflags & BFL_ENETVLAN) && ip) {
967 #endif
968                         /* always use DSCP priority overwrite VLAN priority, since VLAN priority
969                          * could be mapped incorrectly by the switch from an eight-level DSCP
970                          * priority value into a four-level value.
971                          */
972                         vlan_prio = ip->tos >> DSCP_WME_PRI_SHIFT;
973                         evh->vlan_tag &= hton16((uint16) ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT));
974                         evh->vlan_tag |= hton16(vlan_prio << VLAN_PRI_SHIFT);
975                 } else
976                         vlan_prio = ntoh16(evh->vlan_tag) >> VLAN_PRI_SHIFT;
977                 vlan_id = ntoh16(evh->vlan_tag) & VLAN_VID_MASK;
978         }
979
980         /*
981          * If a non-zero VLAN VID is present, and a non-zero VLAN user
982          * priority is set, set the skb->priority to the VLAN user
983          * priority.
984          */
985         if (vlan_id && vlan_prio)
986                 skb->priority = vlan_prio;
987         else if (ip && (ip->tos >> DSCP_WME_PRI_SHIFT))
988                 /*
989                  * If no VLAN tags are present, or the VLAN VID is zero,
990                  * and a non-zero DSCP priority is present,
991                  * set the skb->priority to the DSCP priority.
992                  */
993                 /* set skb priority according to DSCP priority */
994                 skb->priority = (ip->tos >> DSCP_WME_PRI_SHIFT);
995 }
996
997 void
998 et_sendup(et_info_t *et, struct sk_buff *skb)
999 {
1000         etc_info_t *etc;
1001         bcmenetrxh_t *rxh;
1002         uint16 flags;
1003         uchar eabuf[32];
1004
1005         etc = et->etc;
1006
1007         /* packet buffer starts with rxhdr */
1008         rxh = (bcmenetrxh_t*) skb->data;
1009                
1010         /* strip off rxhdr */
1011         skb_pull(skb, HWRXOFF);
1012
1013         ET_TRACE(("et%d: et_sendup: %d bytes\n", et->etc->unit, skb->len));
1014         ET_LOG("et%d: et_sendup: len %d", et->etc->unit, skb->len);
1015
1016         etc->rxframe++;
1017         etc->rxbyte += skb->len;
1018
1019         /* eh should now be aligned 2-mod-4 */
1020         ASSERT(((uint)skb->data & 3) == 2);
1021
1022         /* strip off crc32 */
1023         skb_trim(skb, skb->len - ETHER_CRC_LEN);
1024
1025         ET_PRHDR("rx", (struct ether_header*) skb->data, skb->len, etc->unit);
1026         ET_PRPKT("rxpkt", skb->data, skb->len, etc->unit);
1027
1028         /* check for reported frame errors */
1029         flags = ltoh16(rxh->flags);
1030         if (flags & (RXF_NO | RXF_RXER | RXF_CRC | RXF_OV))
1031                 goto err;
1032
1033         /* Extract priority from payload and send it up */
1034         if (et->etc->qos)
1035                 et_set_rxprio(et, skb);
1036
1037         skb->dev = et->dev;
1038         skb->protocol = eth_type_trans(skb, et->dev);
1039
1040         /* send it up */
1041         netif_rx(skb);
1042
1043         ET_LOG("et%d: et_sendup ret", et->etc->unit, 0);
1044
1045         return;
1046
1047 err:
1048         bcm_ether_ntoa(((struct ether_header*)skb->data)->ether_shost, eabuf);
1049         if (flags & RXF_NO) {
1050                 ET_ERROR(("et%d: rx: crc error (odd nibbles) from %s\n", etc->unit, eabuf));
1051         }
1052         if (flags & RXF_RXER) {
1053                 ET_ERROR(("et%d: rx: symbol error from %s\n", etc->unit, eabuf));
1054         }
1055         if ((flags & RXF_CRC) == RXF_CRC) {
1056                 ET_ERROR(("et%d: rx: crc error from %s\n", etc->unit, eabuf));
1057         }
1058         if (flags & RXF_OV) {
1059                 ET_ERROR(("et%d: rx: fifo overflow\n", etc->unit));
1060         }
1061         osl_pktfree(skb);                 
1062         return;
1063 }
1064
1065 int
1066 et_dump(et_info_t *et, uchar *buf, uint len)
1067 {
1068         /* big enough? */
1069         if (len < 4096)
1070                 return (4096);
1071
1072         sprintf(buf, "et%d: %s %s version %s\n", et->etc->unit,
1073                 __DATE__, __TIME__, EPI_VERSION_STR);
1074
1075
1076         return (strlen(buf));
1077 }
1078
1079
1080 void
1081 et_link_up(et_info_t *et)
1082 {
1083         ET_ERROR(("et%d: link up (%d%s)\n",
1084                 et->etc->unit, et->etc->speed, (et->etc->duplex? "FD" : "HD")));
1085 }
1086
1087 void
1088 et_link_down(et_info_t *et)
1089 {
1090         ET_ERROR(("et%d: link down\n", et->etc->unit));
1091 }
1092
1093 /*
1094  * 47XX-specific shared mdc/mdio contortion:
1095  * Find the et associated with the same chip as <et>
1096  * and coreunit matching <coreunit>.
1097  */
1098 void*
1099 et_phyfind(et_info_t *et, uint coreunit)
1100 {
1101         et_info_t *tmp;
1102         uint bus, slot;
1103
1104         bus = et->pdev->bus->number;
1105         slot = PCI_SLOT(et->pdev->devfn);
1106
1107         /* walk the list et's */
1108         for (tmp = et_list; tmp; tmp = tmp->next) {
1109                 if (et->etc == NULL)
1110                         continue;
1111                 if (tmp->pdev == NULL)
1112                         continue;
1113                 if (tmp->pdev->bus->number != bus)
1114                         continue;
1115                 if (tmp->etc->nicmode)
1116                         if (PCI_SLOT(tmp->pdev->devfn) != slot)
1117                                 continue;
1118                 if (tmp->etc->coreunit != coreunit)
1119                         continue;
1120                 break;
1121         }
1122         return (tmp);
1123 }
1124
1125 /* shared phy read entry point */
1126 uint16
1127 et_phyrd(et_info_t *et, uint phyaddr, uint reg)
1128 {
1129         uint16 val;
1130
1131         spin_lock(&et->lock);
1132         val = et->etc->chops->phyrd(et->etc->ch, phyaddr, reg);
1133         spin_unlock(&et->lock);
1134
1135         return (val);
1136 }
1137
1138 /* shared phy write entry point */
1139 void
1140 et_phywr(et_info_t *et, uint phyaddr, uint reg, uint16 val)
1141 {
1142         spin_lock(&et->lock);
1143         et->etc->chops->phywr(et->etc->ch, phyaddr, reg, val);
1144         spin_unlock(&et->lock);
1145 }
Note: See TracBrowser for help on using the browser.