* Patch by Paul Ruhland, 17 May 2004:
[platform/kernel/u-boot.git] / drivers / bcm570x.c
1 /*
2  * Broadcom BCM570x Ethernet Driver for U-Boot.
3  * Support 5701, 5702, 5703, and 5704. Single instance driver.
4  * Copyright (C) 2002 James F. Dougherty (jfd@broadcom.com)
5  */
6
7 #include <common.h>
8
9 #if (CONFIG_COMMANDS & CFG_CMD_NET) && (!defined(CONFIG_NET_MULTI)) && \
10         defined(CONFIG_BCM570x)
11
12 #ifdef CONFIG_BMW
13 #include <mpc824x.h>
14 #endif
15 #include <net.h>
16 #include "bcm570x_mm.h"
17 #include "bcm570x_autoneg.h"
18 #include <pci.h>
19 #include <malloc.h>
20
21
22 /*
23  * PCI Registers and definitions.
24  */
25 #define PCI_CMD_MASK    0xffff0000      /* mask to save status bits */
26 #define PCI_ANY_ID (~0)
27
28 /*
29  * PCI memory base for Ethernet device as well as device Interrupt.
30  */
31 #define BCM570X_MBAR    0x80100000
32 #define BCM570X_ILINE   1
33
34
35 #define SECOND_USEC     1000000
36 #define MAX_PACKET_SIZE 1600
37 #define MAX_UNITS       4
38
39 /* Globals to this module */
40 int initialized = 0;
41 unsigned int ioBase = 0;
42 volatile PLM_DEVICE_BLOCK    pDevice = NULL;        /* 570x softc */
43 volatile PUM_DEVICE_BLOCK    pUmDevice = NULL;
44
45 /* Used to pass the full-duplex flag, etc. */
46 int line_speed[MAX_UNITS] = {0,0,0,0};
47 static int full_duplex[MAX_UNITS] = {1,1,1,1};
48 static int rx_flow_control[MAX_UNITS] = {0,0,0,0};
49 static int tx_flow_control[MAX_UNITS] = {0,0,0,0};
50 static int auto_flow_control[MAX_UNITS] = {0,0,0,0};
51 static int tx_checksum[MAX_UNITS] = {1,1,1,1};
52 static int rx_checksum[MAX_UNITS] = {1,1,1,1};
53 static int auto_speed[MAX_UNITS] = {1,1,1,1};
54
55 #if JUMBO_FRAMES
56 /* Jumbo MTU for interfaces. */
57 static int mtu[MAX_UNITS] = {0,0,0,0};
58 #endif
59
60 /* Turn on Wake-on lan for a device unit */
61 static int enable_wol[MAX_UNITS] = {0,0,0,0};
62
63 #define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNT
64 static unsigned int tx_pkt_desc_cnt[MAX_UNITS] =
65         {TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT, TX_DESC_CNT};
66
67 #define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNT
68 static unsigned int rx_std_desc_cnt[MAX_UNITS] =
69         {RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT};
70
71 static unsigned int rx_adaptive_coalesce[MAX_UNITS] = {1,1,1,1};
72
73 #if T3_JUMBO_RCV_RCB_ENTRY_COUNT
74 #define JBO_DESC_CNT DEFAULT_JUMBO_RCV_DESC_COUNT
75 static unsigned int rx_jumbo_desc_cnt[MAX_UNITS] =
76         {JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT};
77 #endif
78 #define RX_COAL_TK DEFAULT_RX_COALESCING_TICKS
79 static unsigned int rx_coalesce_ticks[MAX_UNITS] =
80         {RX_COAL_TK, RX_COAL_TK, RX_COAL_TK, RX_COAL_TK};
81
82 #define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMES
83 static unsigned int rx_max_coalesce_frames[MAX_UNITS] =
84         {RX_COAL_FM, RX_COAL_FM, RX_COAL_FM, RX_COAL_FM};
85
86 #define TX_COAL_TK DEFAULT_TX_COALESCING_TICKS
87 static unsigned int tx_coalesce_ticks[MAX_UNITS] =
88         {TX_COAL_TK, TX_COAL_TK, TX_COAL_TK, TX_COAL_TK};
89
90 #define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMES
91 static unsigned int tx_max_coalesce_frames[MAX_UNITS] =
92         {TX_COAL_FM, TX_COAL_FM, TX_COAL_FM, TX_COAL_FM};
93
94 #define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKS
95 static unsigned int stats_coalesce_ticks[MAX_UNITS] =
96         {ST_COAL_TK, ST_COAL_TK, ST_COAL_TK, ST_COAL_TK};
97
98
99 /*
100  * Legitimate values for BCM570x device types
101  */
102 typedef enum {
103         BCM5700VIGIL = 0,
104         BCM5700A6,
105         BCM5700T6,
106         BCM5700A9,
107         BCM5700T9,
108         BCM5700,
109         BCM5701A5,
110         BCM5701T1,
111         BCM5701T8,
112         BCM5701A7,
113         BCM5701A10,
114         BCM5701A12,
115         BCM5701,
116         BCM5702,
117         BCM5703,
118         BCM5703A31,
119         TC996T,
120         TC996ST,
121         TC996SSX,
122         TC996SX,
123         TC996BT,
124         TC997T,
125         TC997SX,
126         TC1000T,
127         TC940BR01,
128         TC942BR01,
129         NC6770,
130         NC7760,
131         NC7770,
132         NC7780
133 } board_t;
134
135 /* Chip-Rev names for each device-type */
136 static struct {
137     char* name;
138 } chip_rev[] = {
139        {"BCM5700VIGIL"},
140        {"BCM5700A6"},
141        {"BCM5700T6"},
142        {"BCM5700A9"},
143        {"BCM5700T9"},
144        {"BCM5700"},
145        {"BCM5701A5"},
146        {"BCM5701T1"},
147        {"BCM5701T8"},
148        {"BCM5701A7"},
149        {"BCM5701A10"},
150        {"BCM5701A12"},
151        {"BCM5701"},
152        {"BCM5702"},
153        {"BCM5703"},
154        {"BCM5703A31"},
155        {"TC996T"},
156        {"TC996ST"},
157        {"TC996SSX"},
158        {"TC996SX"},
159        {"TC996BT"},
160        {"TC997T"},
161        {"TC997SX"},
162        {"TC1000T"},
163        {"TC940BR01"},
164        {"TC942BR01"},
165        {"NC6770"},
166        {"NC7760"},
167        {"NC7770"},
168        {"NC7780"},
169        {0}
170 };
171
172
173 /* indexed by board_t, above */
174 static struct {
175     char *name;
176 } board_info[] = {
177         { "Broadcom Vigil B5700 1000Base-T" },
178         { "Broadcom BCM5700 1000Base-T" },
179         { "Broadcom BCM5700 1000Base-SX" },
180         { "Broadcom BCM5700 1000Base-SX" },
181         { "Broadcom BCM5700 1000Base-T" },
182         { "Broadcom BCM5700" },
183         { "Broadcom BCM5701 1000Base-T" },
184         { "Broadcom BCM5701 1000Base-T" },
185         { "Broadcom BCM5701 1000Base-T" },
186         { "Broadcom BCM5701 1000Base-SX" },
187         { "Broadcom BCM5701 1000Base-T" },
188         { "Broadcom BCM5701 1000Base-T" },
189         { "Broadcom BCM5701" },
190         { "Broadcom BCM5702 1000Base-T" },
191         { "Broadcom BCM5703 1000Base-T" },
192         { "Broadcom BCM5703 1000Base-SX" },
193         { "3Com 3C996 10/100/1000 Server NIC" },
194         { "3Com 3C996 10/100/1000 Server NIC" },
195         { "3Com 3C996 Gigabit Fiber-SX Server NIC" },
196         { "3Com 3C996 Gigabit Fiber-SX Server NIC" },
197         { "3Com 3C996B Gigabit Server NIC" },
198         { "3Com 3C997 Gigabit Server NIC" },
199         { "3Com 3C997 Gigabit Fiber-SX Server NIC" },
200         { "3Com 3C1000 Gigabit NIC" },
201         { "3Com 3C940 Gigabit LOM (21X21)" },
202         { "3Com 3C942 Gigabit LOM (31X31)" },
203         { "Compaq NC6770 Gigabit Server Adapter" },
204         { "Compaq NC7760 Gigabit Server Adapter" },
205         { "Compaq NC7770 Gigabit Server Adapter" },
206         { "Compaq NC7780 Gigabit Server Adapter" },
207         { 0 },
208 };
209
210 /* PCI Devices which use the 570x chipset */
211 struct pci_device_table {
212     unsigned short vendor_id, device_id; /* Vendor/DeviceID */
213     unsigned short subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
214     unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
215     unsigned long board_id;         /* Data private to the driver */
216     int io_size, min_latency;
217 } bcm570xDevices[] = {
218         {0x14e4, 0x1644, 0x1014, 0x0277, 0, 0, BCM5700VIGIL ,128,32},
219         {0x14e4, 0x1644, 0x14e4, 0x1644, 0, 0, BCM5700A6 ,128,32},
220         {0x14e4, 0x1644, 0x14e4, 0x2, 0, 0, BCM5700T6 ,128,32},
221         {0x14e4, 0x1644, 0x14e4, 0x3, 0, 0, BCM5700A9 ,128,32},
222         {0x14e4, 0x1644, 0x14e4, 0x4, 0, 0, BCM5700T9 ,128,32},
223         {0x14e4, 0x1644, 0x1028, 0xd1, 0, 0, BCM5700 ,128,32},
224         {0x14e4, 0x1644, 0x1028, 0x0106, 0, 0, BCM5700 ,128,32},
225         {0x14e4, 0x1644, 0x1028, 0x0109, 0, 0, BCM5700 ,128,32},
226         {0x14e4, 0x1644, 0x1028, 0x010a, 0, 0, BCM5700 ,128,32},
227         {0x14e4, 0x1644, 0x10b7, 0x1000, 0, 0, TC996T ,128,32},
228         {0x14e4, 0x1644, 0x10b7, 0x1001, 0, 0, TC996ST ,128,32},
229         {0x14e4, 0x1644, 0x10b7, 0x1002, 0, 0, TC996SSX ,128,32},
230         {0x14e4, 0x1644, 0x10b7, 0x1003, 0, 0, TC997T ,128,32},
231         {0x14e4, 0x1644, 0x10b7, 0x1005, 0, 0, TC997SX ,128,32},
232         {0x14e4, 0x1644, 0x10b7, 0x1008, 0, 0, TC942BR01 ,128,32},
233         {0x14e4, 0x1644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5700 ,128,32},
234         {0x14e4, 0x1645, 0x14e4, 1, 0, 0, BCM5701A5 ,128,32},
235         {0x14e4, 0x1645, 0x14e4, 5, 0, 0, BCM5701T1 ,128,32},
236         {0x14e4, 0x1645, 0x14e4, 6, 0, 0, BCM5701T8 ,128,32},
237         {0x14e4, 0x1645, 0x14e4, 7, 0, 0, BCM5701A7 ,128,32},
238         {0x14e4, 0x1645, 0x14e4, 8, 0, 0, BCM5701A10 ,128,32},
239         {0x14e4, 0x1645, 0x14e4, 0x8008, 0, 0, BCM5701A12 ,128,32},
240         {0x14e4, 0x1645, 0x0e11, 0xc1, 0, 0, NC6770 ,128,32},
241         {0x14e4, 0x1645, 0x0e11, 0x7c, 0, 0, NC7770 ,128,32},
242         {0x14e4, 0x1645, 0x0e11, 0x85, 0, 0, NC7780 ,128,32},
243         {0x14e4, 0x1645, 0x1028, 0x0121, 0, 0, BCM5701 ,128,32},
244         {0x14e4, 0x1645, 0x10b7, 0x1004, 0, 0, TC996SX ,128,32},
245         {0x14e4, 0x1645, 0x10b7, 0x1006, 0, 0, TC996BT ,128,32},
246         {0x14e4, 0x1645, 0x10b7, 0x1007, 0, 0, TC1000T ,128,32},
247         {0x14e4, 0x1645, 0x10b7, 0x1008, 0, 0, TC940BR01 ,128,32},
248         {0x14e4, 0x1645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5701 ,128,32},
249         {0x14e4, 0x1646, 0x14e4, 0x8009, 0, 0, BCM5702 ,128,32},
250         {0x14e4, 0x1646, 0x0e11, 0xbb, 0, 0, NC7760 ,128,32},
251         {0x14e4, 0x1646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 ,128,32},
252         {0x14e4, 0x16a6, 0x14e4, 0x8009, 0, 0, BCM5702 ,128,32},
253         {0x14e4, 0x16a6, 0x0e11, 0xbb, 0, 0, NC7760 ,128,32},
254         {0x14e4, 0x16a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 ,128,32},
255         {0x14e4, 0x1647, 0x14e4, 0x0009, 0, 0, BCM5703 ,128,32},
256         {0x14e4, 0x1647, 0x14e4, 0x000a, 0, 0, BCM5703A31 ,128,32},
257         {0x14e4, 0x1647, 0x14e4, 0x000b, 0, 0, BCM5703 ,128,32},
258         {0x14e4, 0x1647, 0x14e4, 0x800a, 0, 0, BCM5703 ,128,32},
259         {0x14e4, 0x1647, 0x0e11, 0x9a, 0, 0, NC7770 ,128,32},
260         {0x14e4, 0x1647, 0x0e11, 0x99, 0, 0, NC7780 ,128,32},
261         {0x14e4, 0x1647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 ,128,32},
262         {0x14e4, 0x16a7, 0x14e4, 0x0009, 0, 0, BCM5703 ,128,32},
263         {0x14e4, 0x16a7, 0x14e4, 0x000a, 0, 0, BCM5703A31 ,128,32},
264         {0x14e4, 0x16a7, 0x14e4, 0x000b, 0, 0, BCM5703 ,128,32},
265         {0x14e4, 0x16a7, 0x14e4, 0x800a, 0, 0, BCM5703 ,128,32},
266         {0x14e4, 0x16a7, 0x0e11, 0x9a, 0, 0, NC7770 ,128,32},
267         {0x14e4, 0x16a7, 0x0e11, 0x99, 0, 0, NC7780 ,128,32},
268         {0x14e4, 0x16a7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 ,128,32}
269 };
270
271 #define n570xDevices   (sizeof(bcm570xDevices)/sizeof(bcm570xDevices[0]))
272
273
274 /*
275  * Allocate a packet buffer from the bcm570x packet pool.
276  */
277 void *
278 bcm570xPktAlloc(int u, int pksize)
279 {
280     return malloc(pksize);
281 }
282
283 /*
284  * Free a packet previously allocated from the bcm570x packet
285  * buffer pool.
286  */
287 void
288 bcm570xPktFree(int u, void *p)
289 {
290     free(p);
291 }
292
293 int
294 bcm570xReplenishRxBuffers(PUM_DEVICE_BLOCK pUmDevice)
295 {
296     PLM_PACKET pPacket;
297     PUM_PACKET pUmPacket;
298     void *skb;
299     int queue_rx = 0;
300     int ret = 0;
301
302     while ((pUmPacket = (PUM_PACKET)
303             QQ_PopHead(&pUmDevice->rx_out_of_buf_q.Container)) != 0) {
304
305         pPacket = (PLM_PACKET) pUmPacket;
306
307         /* reuse an old skb */
308         if (pUmPacket->skbuff) {
309             QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
310             queue_rx = 1;
311             continue;
312         }
313         if ( ( skb = bcm570xPktAlloc(pUmDevice->index,
314                                      pPacket->u.Rx.RxBufferSize + 2)) == 0) {
315             QQ_PushHead(&pUmDevice->rx_out_of_buf_q.Container,pPacket);
316             printf("NOTICE: Out of RX memory.\n");
317             ret = 1;
318             break;
319         }
320
321         pUmPacket->skbuff = skb;
322         QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
323         queue_rx = 1;
324     }
325
326     if (queue_rx) {
327         LM_QueueRxPackets(pDevice);
328     }
329
330     return ret;
331 }
332
333 /*
334  * Probe, Map, and Init 570x device.
335  */
336 int eth_init(bd_t *bis)
337 {
338     int i, rv, devFound = FALSE;
339     pci_dev_t  devbusfn;
340     unsigned short status;
341
342     /* Find PCI device, if it exists, configure ...  */
343     for( i = 0; i < n570xDevices; i++){
344         devbusfn = pci_find_device(bcm570xDevices[i].vendor_id,
345                                    bcm570xDevices[i].device_id, 0);
346         if(devbusfn == -1) {
347             continue; /* No device of that vendor/device ID */
348         } else {
349
350             /* Set ILINE */
351             pci_write_config_byte(devbusfn,
352                                   PCI_INTERRUPT_LINE, BCM570X_ILINE);
353
354             /*
355              * 0x10 - 0x14 define one 64-bit MBAR.
356              * 0x14 is the higher-order address bits of the BAR.
357              */
358             pci_write_config_dword(devbusfn,
359                                    PCI_BASE_ADDRESS_1, 0);
360
361             ioBase = BCM570X_MBAR;
362
363             pci_write_config_dword(devbusfn,
364                                    PCI_BASE_ADDRESS_0, ioBase);
365
366             /*
367              * Enable PCI memory, IO, and Master -- don't
368              * reset any status bits in doing so.
369              */
370             pci_read_config_word(devbusfn,
371                                  PCI_COMMAND, &status);
372
373             status |= PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER;
374
375             pci_write_config_word(devbusfn,
376                                   PCI_COMMAND, status);
377
378             printf("\n%s: bus %d, device %d, function %d: MBAR=0x%x\n",
379                    board_info[bcm570xDevices[i].board_id].name,
380                    PCI_BUS(devbusfn),
381                    PCI_DEV(devbusfn),
382                    PCI_FUNC(devbusfn),
383                    ioBase);
384
385             /* Allocate once, but always clear on init */
386             if (!pDevice) {
387                 pDevice = malloc(sizeof(UM_DEVICE_BLOCK));
388                 pUmDevice = (PUM_DEVICE_BLOCK)pDevice;
389                 memset(pDevice, 0x0, sizeof(UM_DEVICE_BLOCK));
390             }
391
392             /* Configure pci dev structure */
393             pUmDevice->pdev = devbusfn;
394             pUmDevice->index = 0;
395             pUmDevice->tx_pkt = 0;
396             pUmDevice->rx_pkt = 0;
397             devFound = TRUE;
398             break;
399         }
400     }
401
402     if(!devFound){
403         printf("eth_init: FAILURE: no BCM570x Ethernet devices found.\n");
404         return -1;
405     }
406
407     /* Setup defaults for chip */
408     pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
409
410     if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) {
411         pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
412     } else {
413
414         if (rx_checksum[i]) {
415             pDevice->TaskToOffload |=
416                 LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
417                 LM_TASK_OFFLOAD_RX_UDP_CHECKSUM;
418         }
419
420         if (tx_checksum[i]) {
421             pDevice->TaskToOffload |=
422                 LM_TASK_OFFLOAD_TX_TCP_CHECKSUM |
423                 LM_TASK_OFFLOAD_TX_UDP_CHECKSUM;
424             pDevice->NoTxPseudoHdrChksum = TRUE;
425         }
426     }
427
428     /* Set Device PCI Memory base address */
429     pDevice->pMappedMemBase = (PLM_UINT8) ioBase;
430
431     /* Pull down adapter info */
432     if ((rv = LM_GetAdapterInfo(pDevice)) != LM_STATUS_SUCCESS) {
433         printf("bcm570xEnd: LM_GetAdapterInfo failed: rv=%d!\n", rv );
434         return -2;
435     }
436
437     /* Lock not needed */
438     pUmDevice->do_global_lock = 0;
439
440     if (T3_ASIC_REV(pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) {
441         /* The 5700 chip works best without interleaved register */
442         /* accesses on certain machines. */
443         pUmDevice->do_global_lock = 1;
444     }
445
446     /* Setup timer delays */
447     if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) {
448         pDevice->UseTaggedStatus = TRUE;
449         pUmDevice->timer_interval = CFG_HZ;
450     }
451     else {
452         pUmDevice->timer_interval = CFG_HZ / 50;
453     }
454
455     /* Grab name .... */
456     pUmDevice->name =
457         (char*)malloc(strlen(board_info[bcm570xDevices[i].board_id].name)+1);
458     strcpy(pUmDevice->name,board_info[bcm570xDevices[i].board_id].name);
459
460     memcpy(pDevice->NodeAddress, bis->bi_enetaddr, 6);
461     LM_SetMacAddress(pDevice, bis->bi_enetaddr);
462     /* Init queues  .. */
463     QQ_InitQueue(&pUmDevice->rx_out_of_buf_q.Container,
464                  MAX_RX_PACKET_DESC_COUNT);
465     pUmDevice->rx_last_cnt = pUmDevice->tx_last_cnt = 0;
466
467     /* delay for 4 seconds */
468     pUmDevice->delayed_link_ind =
469         (4 * CFG_HZ) / pUmDevice->timer_interval;
470
471     pUmDevice->adaptive_expiry =
472         CFG_HZ / pUmDevice->timer_interval;
473
474     /* Sometimes we get spurious ints. after reset when link is down. */
475     /* This field tells the isr to service the int. even if there is */
476     /* no status block update. */
477     pUmDevice->adapter_just_inited =
478         (3 * CFG_HZ) / pUmDevice->timer_interval;
479
480     /* Initialize 570x */
481     if (LM_InitializeAdapter(pDevice) != LM_STATUS_SUCCESS) {
482         printf("ERROR: Adapter initialization failed.\n");
483         return ERROR;
484     }
485
486     /* Enable chip ISR */
487     LM_EnableInterrupt(pDevice);
488
489     /* Clear MC table */
490     LM_MulticastClear(pDevice);
491
492     /* Enable Multicast */
493     LM_SetReceiveMask(pDevice,
494                       pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST);
495
496     pUmDevice->opened = 1;
497     pUmDevice->tx_full = 0;
498     pUmDevice->tx_pkt = 0;
499     pUmDevice->rx_pkt = 0;
500     printf("eth%d: %s @0x%lx,",
501            pDevice->index, pUmDevice->name, (unsigned long)ioBase);
502     printf(     "node addr ");
503     for (i = 0; i < 6; i++) {
504         printf("%2.2x", pDevice->NodeAddress[i]);
505     }
506     printf("\n");
507
508     printf("eth%d: ", pDevice->index);
509     printf("%s with ",
510            chip_rev[bcm570xDevices[i].board_id].name);
511
512     if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5400_PHY_ID)
513         printf("Broadcom BCM5400 Copper ");
514     else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID)
515         printf("Broadcom BCM5401 Copper ");
516     else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5411_PHY_ID)
517         printf("Broadcom BCM5411 Copper ");
518     else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5701_PHY_ID)
519         printf("Broadcom BCM5701 Integrated Copper ");
520     else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5703_PHY_ID)
521         printf("Broadcom BCM5703 Integrated Copper ");
522     else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM8002_PHY_ID)
523         printf("Broadcom BCM8002 SerDes ");
524     else if (pDevice->EnableTbi)
525         printf("Agilent HDMP-1636 SerDes ");
526     else
527         printf("Unknown ");
528     printf("transceiver found\n");
529
530     printf("eth%d: %s, MTU: %d,",
531            pDevice->index, pDevice->BusSpeedStr, 1500);
532
533     if ((pDevice->ChipRevId != T3_CHIP_ID_5700_B0) &&
534         rx_checksum[i])
535         printf("Rx Checksum ON\n");
536     else
537         printf("Rx Checksum OFF\n");
538     initialized++;
539
540     return 0;
541 }
542
543 /* Ethernet Interrupt service routine */
544 void
545 eth_isr(void)
546 {
547     LM_UINT32 oldtag, newtag;
548     int i;
549
550     pUmDevice->interrupt = 1;
551
552     if (pDevice->UseTaggedStatus) {
553         if ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) ||
554             pUmDevice->adapter_just_inited) {
555             MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1);
556             oldtag = pDevice->pStatusBlkVirt->StatusTag;
557
558             for (i = 0; ; i++) {
559                 pDevice->pStatusBlkVirt->Status &= ~STATUS_BLOCK_UPDATED;
560                 LM_ServiceInterrupts(pDevice);
561                 newtag = pDevice->pStatusBlkVirt->StatusTag;
562                 if ((newtag == oldtag) || (i > 50)) {
563                     MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, newtag << 24);
564                     if (pDevice->UndiFix) {
565                         REG_WR(pDevice, Grc.LocalCtrl,
566                                pDevice->GrcLocalCtrl | 0x2);
567                     }
568                     break;
569                  }
570                 oldtag = newtag;
571             }
572         }
573     }
574     else {
575         while (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) {
576             unsigned int dummy;
577
578             pDevice->pMemView->Mailbox.Interrupt[0].Low = 1;
579             pDevice->pStatusBlkVirt->Status &= ~STATUS_BLOCK_UPDATED;
580             LM_ServiceInterrupts(pDevice);
581             pDevice->pMemView->Mailbox.Interrupt[0].Low = 0;
582             dummy = pDevice->pMemView->Mailbox.Interrupt[0].Low;
583         }
584     }
585
586     /* Allocate new RX buffers */
587     if (QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container)) {
588         bcm570xReplenishRxBuffers(pUmDevice);
589     }
590
591     /* Queue packets */
592     if (QQ_GetEntryCnt(&pDevice->RxPacketFreeQ.Container)) {
593         LM_QueueRxPackets(pDevice);
594     }
595
596     if (pUmDevice->tx_queued) {
597         pUmDevice->tx_queued = 0;
598     }
599
600     if(pUmDevice->tx_full){
601         if(pDevice->LinkStatus != LM_STATUS_LINK_DOWN){
602             printf("NOTICE: tx was previously blocked, restarting MUX\n");
603             pUmDevice->tx_full = 0;
604         }
605     }
606
607     pUmDevice->interrupt = 0;
608
609 }
610
611 int
612 eth_send(volatile void *packet, int length)
613 {
614     int status = 0;
615 #if ET_DEBUG
616     unsigned char* ptr = (unsigned char*)packet;
617 #endif
618     PLM_PACKET pPacket;
619     PUM_PACKET pUmPacket;
620
621     /* Link down, return */
622     while(pDevice->LinkStatus == LM_STATUS_LINK_DOWN) {
623 #if 0
624         printf("eth%d: link down - check cable or link partner.\n",
625                pUmDevice->index);
626 #endif
627         eth_isr();
628
629         /* Wait to see link for one-half a second before sending ... */
630         udelay(1500000);
631
632     }
633
634     /* Clear sent flag */
635     pUmDevice->tx_pkt = 0;
636
637     /* Previously blocked */
638     if(pUmDevice->tx_full){
639         printf("eth%d: tx blocked.\n", pUmDevice->index);
640         return 0;
641     }
642
643     pPacket = (PLM_PACKET)
644         QQ_PopHead(&pDevice->TxPacketFreeQ.Container);
645
646     if (pPacket == 0) {
647         pUmDevice->tx_full = 1;
648         printf("bcm570xEndSend: TX full!\n");
649         return 0;
650     }
651
652     if (pDevice->SendBdLeft.counter == 0) {
653         pUmDevice->tx_full = 1;
654         printf("bcm570xEndSend: no more TX descriptors!\n");
655         QQ_PushHead(&pDevice->TxPacketFreeQ.Container, pPacket);
656         return 0;
657     }
658
659     if (length <= 0){
660         printf("eth: bad packet size: %d\n", length);
661         goto out;
662     }
663
664     /* Get packet buffers and fragment list */
665     pUmPacket = (PUM_PACKET) pPacket;
666     /* Single DMA Descriptor transmit.
667      * Fragments may be provided, but one DMA descriptor max is
668      * used to send the packet.
669      */
670     if (MM_CoalesceTxBuffer (pDevice, pPacket) != LM_STATUS_SUCCESS) {
671         if (pUmPacket->skbuff == NULL){
672             /* Packet was discarded */
673             printf("TX: failed (1)\n");
674             status = 1;
675         } else{
676             printf("TX: failed (2)\n");
677             status = 2;
678         }
679         QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
680         return status;
681     }
682
683     /* Copy packet to DMA buffer */
684     memset(pUmPacket->skbuff, 0x0, MAX_PACKET_SIZE);
685     memcpy((void*)pUmPacket->skbuff, (void*)packet, length);
686     pPacket->PacketSize = length;
687     pPacket->Flags |= SND_BD_FLAG_END|SND_BD_FLAG_COAL_NOW;
688     pPacket->u.Tx.FragCount = 1;
689     /* We've already provided a frame ready for transmission */
690     pPacket->Flags &= ~SND_BD_FLAG_TCP_UDP_CKSUM;
691
692     if ( LM_SendPacket(pDevice, pPacket) == LM_STATUS_FAILURE){
693         /*
694          *  A lower level send failure will push the packet descriptor back
695          *  in the free queue, so just deal with the VxWorks clusters.
696          */
697         if (pUmPacket->skbuff == NULL){
698             printf("TX failed (1)!\n");
699             /* Packet was discarded */
700             status = 3;
701         } else {
702             /* A resource problem ... */
703             printf("TX failed (2)!\n");
704             status = 4;
705         }
706
707         if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) == 0) {
708             printf("TX: emptyQ!\n");
709             pUmDevice->tx_full = 1;
710         }
711     }
712
713     while(pUmDevice->tx_pkt == 0){
714         /* Service TX */
715         eth_isr();
716     }
717 #if ET_DEBUG
718     printf("eth_send: 0x%x, %d bytes\n"
719            "[%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x] ...\n",
720            (int)pPacket, length,
721            ptr[0],ptr[1],ptr[2],ptr[3],ptr[4],ptr[5],
722            ptr[6],ptr[7],ptr[8],ptr[9],ptr[10],ptr[11],ptr[12],
723            ptr[13],ptr[14],ptr[15]);
724 #endif
725     pUmDevice->tx_pkt = 0;
726     QQ_PushHead(&pDevice->TxPacketFreeQ.Container, pPacket);
727
728     /* Done with send */
729  out:
730     return status;
731 }
732
733
734 /* Ethernet receive */
735 int
736 eth_rx(void)
737 {
738     PLM_PACKET          pPacket = NULL;
739     PUM_PACKET          pUmPacket = NULL;
740     void *skb;
741     int size=0;
742
743     while(TRUE) {
744
745     bcm570x_service_isr:
746         /* Pull down packet if it is there */
747         eth_isr();
748
749         /* Indicate RX packets called */
750         if(pUmDevice->rx_pkt){
751             /* printf("eth_rx: got a packet...\n"); */
752             pUmDevice->rx_pkt = 0;
753         } else {
754             /* printf("eth_rx: waiting for packet...\n"); */
755             goto bcm570x_service_isr;
756         }
757
758         pPacket = (PLM_PACKET)
759             QQ_PopHead(&pDevice->RxPacketReceivedQ.Container);
760
761         if (pPacket == 0){
762             printf("eth_rx: empty packet!\n");
763             goto bcm570x_service_isr;
764         }
765
766         pUmPacket = (PUM_PACKET) pPacket;
767 #if ET_DEBUG
768         printf("eth_rx: packet @0x%x\n",
769                (int)pPacket);
770 #endif
771         /* If the packet generated an error, reuse buffer */
772         if ((pPacket->PacketStatus != LM_STATUS_SUCCESS) ||
773             ((size = pPacket->PacketSize) > pDevice->RxMtu)) {
774
775             /* reuse skb */
776             QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
777             printf("eth_rx: error in packet dma!\n");
778             goto bcm570x_service_isr;
779         }
780
781         /* Set size and address */
782         skb = pUmPacket->skbuff;
783         size = pPacket->PacketSize;
784
785         /* Pass the packet up to the protocol
786          * layers.
787          */
788         NetReceive(skb, size);
789
790         /* Free packet buffer */
791         bcm570xPktFree (pUmDevice->index, skb);
792         pUmPacket->skbuff = NULL;
793
794         /* Reuse SKB */
795         QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
796
797         return 0; /* Got a packet, bail ... */
798     }
799     return size;
800 }
801
802
803 /* Shut down device */
804 void
805 eth_halt(void)
806 {
807     int i;
808     if ( initialized)
809     if (pDevice && pUmDevice && pUmDevice->opened){
810         printf("\neth%d:%s,", pUmDevice->index, pUmDevice->name);
811         printf("HALT,");
812         /* stop device */
813         LM_Halt(pDevice);
814         printf("POWER DOWN,");
815         LM_SetPowerState(pDevice, LM_POWER_STATE_D3);
816
817         /* Free the memory allocated by the device in tigon3 */
818         for (i = 0; i < pUmDevice->mem_list_num; i++)  {
819             if (pUmDevice->mem_list[i])  {
820                 /* sanity check */
821                 if (pUmDevice->dma_list[i]) {  /* cache-safe memory */
822                     free(pUmDevice->mem_list[i]);
823                 } else {
824                     free(pUmDevice->mem_list[i]);  /* normal memory   */
825                 }
826             }
827         }
828         pUmDevice->opened = 0;
829         free(pDevice);
830         pDevice = NULL;
831         pUmDevice = NULL;
832         initialized = 0;
833         printf("done - offline.\n");
834     }
835 }
836
837
838 /*
839  *
840  * Middle Module: Interface between the HW driver (tigon3 modules) and
841  * the native (SENS) driver.  These routines implement the system
842  * interface for tigon3 on VxWorks.
843  */
844
845 /* Middle module dependency - size of a packet descriptor */
846 int MM_Packet_Desc_Size = sizeof(UM_PACKET);
847
848
849 LM_STATUS
850 MM_ReadConfig32(PLM_DEVICE_BLOCK pDevice,
851                 LM_UINT32 Offset,
852                 LM_UINT32 *pValue32)
853 {
854     UM_DEVICE_BLOCK *pUmDevice;
855     pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
856     pci_read_config_dword(pUmDevice->pdev,
857                           Offset, (u32 *) pValue32);
858     return LM_STATUS_SUCCESS;
859 }
860
861
862 LM_STATUS
863 MM_WriteConfig32(PLM_DEVICE_BLOCK pDevice,
864                  LM_UINT32 Offset,
865                  LM_UINT32 Value32)
866 {
867     UM_DEVICE_BLOCK *pUmDevice;
868     pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
869     pci_write_config_dword(pUmDevice->pdev,
870                            Offset, Value32);
871     return LM_STATUS_SUCCESS;
872 }
873
874
875 LM_STATUS
876 MM_ReadConfig16(PLM_DEVICE_BLOCK pDevice,
877                 LM_UINT32 Offset,
878                 LM_UINT16 *pValue16)
879 {
880     UM_DEVICE_BLOCK *pUmDevice;
881     pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
882     pci_read_config_word(pUmDevice->pdev,
883                          Offset, (u16*) pValue16);
884     return LM_STATUS_SUCCESS;
885 }
886
887 LM_STATUS
888 MM_WriteConfig16(PLM_DEVICE_BLOCK pDevice,
889                  LM_UINT32 Offset,
890                  LM_UINT16 Value16)
891 {
892     UM_DEVICE_BLOCK *pUmDevice;
893     pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
894     pci_write_config_word(pUmDevice->pdev,
895                           Offset, Value16);
896     return LM_STATUS_SUCCESS;
897 }
898
899
900 LM_STATUS
901 MM_AllocateSharedMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
902                         PLM_VOID *pMemoryBlockVirt,
903                         PLM_PHYSICAL_ADDRESS pMemoryBlockPhy,
904                         LM_BOOL Cached)
905 {
906     PLM_VOID pvirt;
907     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
908     dma_addr_t mapping;
909
910     pvirt = malloc(BlockSize);
911     mapping = (dma_addr_t)(pvirt);
912     if (!pvirt)
913         return LM_STATUS_FAILURE;
914
915     pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
916     pUmDevice->dma_list[pUmDevice->mem_list_num] = mapping;
917     pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
918     memset(pvirt, 0, BlockSize);
919
920     *pMemoryBlockVirt = (PLM_VOID) pvirt;
921     MM_SetAddr (pMemoryBlockPhy, (dma_addr_t) mapping);
922
923     return LM_STATUS_SUCCESS;
924 }
925
926
927 LM_STATUS
928 MM_AllocateMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
929         PLM_VOID *pMemoryBlockVirt)
930 {
931     PLM_VOID pvirt;
932     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
933
934     pvirt = malloc(BlockSize);
935
936     if (!pvirt)
937         return LM_STATUS_FAILURE;
938
939     pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
940     pUmDevice->dma_list[pUmDevice->mem_list_num] = 0;
941     pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
942     memset(pvirt, 0, BlockSize);
943     *pMemoryBlockVirt = pvirt;
944
945     return LM_STATUS_SUCCESS;
946 }
947
948 LM_STATUS
949 MM_MapMemBase(PLM_DEVICE_BLOCK pDevice)
950 {
951     printf("BCM570x PCI Memory base address @0x%x\n",
952            (unsigned int)pDevice->pMappedMemBase);
953     return LM_STATUS_SUCCESS;
954 }
955
956 LM_STATUS
957 MM_InitializeUmPackets(PLM_DEVICE_BLOCK pDevice)
958 {
959     int i;
960     void* skb;
961     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
962     PUM_PACKET pUmPacket = NULL;
963     PLM_PACKET pPacket = NULL;
964
965     for (i = 0; i < pDevice->RxPacketDescCnt; i++) {
966         pPacket = QQ_PopHead(&pDevice->RxPacketFreeQ.Container);
967         pUmPacket = (PUM_PACKET) pPacket;
968
969         if (pPacket == 0) {
970             printf("MM_InitializeUmPackets: Bad RxPacketFreeQ\n");
971         }
972
973         skb = bcm570xPktAlloc(pUmDevice->index,
974                               pPacket->u.Rx.RxBufferSize + 2);
975
976         if (skb == 0) {
977             pUmPacket->skbuff = 0;
978             QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket);
979             printf("MM_InitializeUmPackets: out of buffer.\n");
980             continue;
981         }
982
983         pUmPacket->skbuff = skb;
984         QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
985     }
986
987     pUmDevice->rx_low_buf_thresh = pDevice->RxPacketDescCnt / 8;
988
989     return LM_STATUS_SUCCESS;
990 }
991
992 LM_STATUS
993 MM_GetConfig(PLM_DEVICE_BLOCK pDevice)
994 {
995     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
996     int index = pDevice->index;
997
998     if (auto_speed[index] == 0)
999         pDevice->DisableAutoNeg = TRUE;
1000     else
1001         pDevice->DisableAutoNeg = FALSE;
1002
1003     if (line_speed[index] == 0) {
1004         pDevice->RequestedMediaType =
1005             LM_REQUESTED_MEDIA_TYPE_AUTO;
1006         pDevice->DisableAutoNeg = FALSE;
1007     }
1008     else {
1009         if (line_speed[index] == 1000) {
1010             if (pDevice->EnableTbi) {
1011                 pDevice->RequestedMediaType =
1012                     LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX;
1013             }
1014             else if (full_duplex[index]) {
1015                 pDevice->RequestedMediaType =
1016                     LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX;
1017             }
1018             else {
1019                 pDevice->RequestedMediaType =
1020                     LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS;
1021             }
1022             if (!pDevice->EnableTbi)
1023                 pDevice->DisableAutoNeg = FALSE;
1024         }
1025         else if (line_speed[index] == 100) {
1026             if (full_duplex[index]) {
1027                 pDevice->RequestedMediaType =
1028                     LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX;
1029             }
1030             else {
1031                 pDevice->RequestedMediaType =
1032                     LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS;
1033             }
1034         }
1035         else if (line_speed[index] == 10) {
1036             if (full_duplex[index]) {
1037                 pDevice->RequestedMediaType =
1038                     LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX;
1039             }
1040             else {
1041                 pDevice->RequestedMediaType =
1042                     LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS;
1043             }
1044         }
1045         else {
1046             pDevice->RequestedMediaType =
1047                 LM_REQUESTED_MEDIA_TYPE_AUTO;
1048             pDevice->DisableAutoNeg = FALSE;
1049         }
1050
1051     }
1052     pDevice->FlowControlCap = 0;
1053     if (rx_flow_control[index] != 0) {
1054         pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
1055     }
1056     if (tx_flow_control[index] != 0) {
1057         pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
1058     }
1059     if ((auto_flow_control[index] != 0) &&
1060         (pDevice->DisableAutoNeg == FALSE)) {
1061
1062         pDevice->FlowControlCap |= LM_FLOW_CONTROL_AUTO_PAUSE;
1063         if ((tx_flow_control[index] == 0) &&
1064             (rx_flow_control[index] == 0)) {
1065             pDevice->FlowControlCap |=
1066                 LM_FLOW_CONTROL_TRANSMIT_PAUSE |
1067                 LM_FLOW_CONTROL_RECEIVE_PAUSE;
1068         }
1069     }
1070
1071     /* Default MTU for now */
1072     pUmDevice->mtu = 1500;
1073
1074 #if T3_JUMBO_RCV_RCB_ENTRY_COUNT
1075     if (pUmDevice->mtu > 1500) {
1076         pDevice->RxMtu = pUmDevice->mtu;
1077         pDevice->RxJumboDescCnt = DEFAULT_JUMBO_RCV_DESC_COUNT;
1078     }
1079     else {
1080         pDevice->RxJumboDescCnt = 0;
1081     }
1082     pDevice->RxJumboDescCnt = rx_jumbo_desc_cnt[index];
1083 #else
1084     pDevice->RxMtu = pUmDevice->mtu;
1085 #endif
1086
1087     if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) {
1088         pDevice->UseTaggedStatus = TRUE;
1089         pUmDevice->timer_interval = CFG_HZ;
1090     }
1091     else {
1092         pUmDevice->timer_interval = CFG_HZ/50;
1093     }
1094
1095     pDevice->TxPacketDescCnt = tx_pkt_desc_cnt[index];
1096     pDevice->RxStdDescCnt = rx_std_desc_cnt[index];
1097     /* Note:  adaptive coalescence really isn't adaptive in this driver */
1098     pUmDevice->rx_adaptive_coalesce = rx_adaptive_coalesce[index];
1099     if (!pUmDevice->rx_adaptive_coalesce) {
1100         pDevice->RxCoalescingTicks = rx_coalesce_ticks[index];
1101         if (pDevice->RxCoalescingTicks > MAX_RX_COALESCING_TICKS)
1102             pDevice->RxCoalescingTicks = MAX_RX_COALESCING_TICKS;
1103         pUmDevice->rx_curr_coalesce_ticks =pDevice->RxCoalescingTicks;
1104
1105         pDevice->RxMaxCoalescedFrames = rx_max_coalesce_frames[index];
1106         if (pDevice->RxMaxCoalescedFrames>MAX_RX_MAX_COALESCED_FRAMES)
1107             pDevice->RxMaxCoalescedFrames =
1108                                 MAX_RX_MAX_COALESCED_FRAMES;
1109         pUmDevice->rx_curr_coalesce_frames =
1110             pDevice->RxMaxCoalescedFrames;
1111         pDevice->StatsCoalescingTicks = stats_coalesce_ticks[index];
1112         if (pDevice->StatsCoalescingTicks>MAX_STATS_COALESCING_TICKS)
1113             pDevice->StatsCoalescingTicks=
1114                 MAX_STATS_COALESCING_TICKS;
1115         }
1116         else {
1117             pUmDevice->rx_curr_coalesce_frames =
1118                 DEFAULT_RX_MAX_COALESCED_FRAMES;
1119             pUmDevice->rx_curr_coalesce_ticks =
1120                 DEFAULT_RX_COALESCING_TICKS;
1121         }
1122     pDevice->TxCoalescingTicks = tx_coalesce_ticks[index];
1123     if (pDevice->TxCoalescingTicks > MAX_TX_COALESCING_TICKS)
1124         pDevice->TxCoalescingTicks = MAX_TX_COALESCING_TICKS;
1125     pDevice->TxMaxCoalescedFrames = tx_max_coalesce_frames[index];
1126     if (pDevice->TxMaxCoalescedFrames > MAX_TX_MAX_COALESCED_FRAMES)
1127         pDevice->TxMaxCoalescedFrames = MAX_TX_MAX_COALESCED_FRAMES;
1128
1129     if (enable_wol[index]) {
1130         pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET;
1131         pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET;
1132     }
1133     pDevice->NicSendBd = TRUE;
1134
1135     /* Don't update status blocks during interrupt */
1136     pDevice->RxCoalescingTicksDuringInt = 0;
1137     pDevice->TxCoalescingTicksDuringInt = 0;
1138
1139     return LM_STATUS_SUCCESS;
1140
1141 }
1142
1143
1144 LM_STATUS
1145 MM_StartTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1146 {
1147     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1148     printf("Start TX DMA: dev=%d packet @0x%x\n",
1149            (int)pUmDevice->index, (unsigned int)pPacket);
1150
1151     return LM_STATUS_SUCCESS;
1152 }
1153
1154 LM_STATUS
1155 MM_CompleteTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1156 {
1157     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1158     printf("Complete TX DMA: dev=%d packet @0x%x\n",
1159            (int)pUmDevice->index, (unsigned int)pPacket);
1160     return LM_STATUS_SUCCESS;
1161 }
1162
1163
1164 LM_STATUS
1165 MM_IndicateStatus(PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
1166 {
1167     char buf[128];
1168     char lcd[4];
1169     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1170     LM_FLOW_CONTROL flow_control;
1171
1172     pUmDevice->delayed_link_ind = 0;
1173     memset(lcd, 0x0, 4);
1174
1175     if (Status == LM_STATUS_LINK_DOWN) {
1176         sprintf(buf,"eth%d: %s: NIC Link is down\n",
1177                 pUmDevice->index,pUmDevice->name);
1178         lcd[0] = 'L';lcd[1]='N';lcd[2]='K';lcd[3] = '?';
1179     } else if (Status == LM_STATUS_LINK_ACTIVE) {
1180         sprintf(buf,"eth%d:%s: ", pUmDevice->index, pUmDevice->name);
1181
1182         if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS){
1183             strcat(buf,"1000 Mbps ");
1184             lcd[0] = '1';lcd[1]='G';lcd[2]='B';
1185         } else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS){
1186             strcat(buf,"100 Mbps ");
1187             lcd[0] = '1';lcd[1]='0';lcd[2]='0';
1188         } else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS){
1189             strcat(buf,"10 Mbps ");
1190             lcd[0] = '1';lcd[1]='0';lcd[2]=' ';
1191         }
1192         if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL){
1193             strcat(buf, "full duplex");
1194             lcd[3] = 'F';
1195         } else {
1196             strcat(buf, "half duplex");
1197             lcd[3] = 'H';
1198         }
1199         strcat(buf, " link up");
1200
1201         flow_control = pDevice->FlowControl &
1202             (LM_FLOW_CONTROL_RECEIVE_PAUSE |
1203              LM_FLOW_CONTROL_TRANSMIT_PAUSE);
1204
1205         if (flow_control) {
1206             if (flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE) {
1207                 strcat(buf,", receive ");
1208                 if (flow_control & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
1209                     strcat(buf," & transmit ");
1210             }
1211             else {
1212                 strcat(buf,", transmit ");
1213             }
1214             strcat(buf,"flow control ON");
1215         } else {
1216             strcat(buf, ", flow control OFF");
1217         }
1218         strcat(buf,"\n");
1219         printf("%s",buf);
1220     }
1221 #if 0
1222     sysLedDsply(lcd[0],lcd[1],lcd[2],lcd[3]);
1223 #endif
1224     return LM_STATUS_SUCCESS;
1225 }
1226
1227 LM_STATUS
1228 MM_FreeRxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1229 {
1230
1231     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1232     PUM_PACKET pUmPacket;
1233     void *skb;
1234
1235     pUmPacket = (PUM_PACKET) pPacket;
1236
1237     if ((skb = pUmPacket->skbuff))
1238         bcm570xPktFree(pUmDevice->index, skb);
1239
1240     pUmPacket->skbuff = 0;
1241
1242     return LM_STATUS_SUCCESS;
1243 }
1244
1245 unsigned long
1246 MM_AnGetCurrentTime_us(PAN_STATE_INFO pAnInfo)
1247 {
1248     return get_timer(0);
1249 }
1250
1251 /*
1252  *   Transform an MBUF chain into a single MBUF.
1253  *   This routine will fail if the amount of data in the
1254  *   chain overflows a transmit buffer.  In that case,
1255  *   the incoming MBUF chain will be freed.  This routine can
1256  *   also fail by not being able to allocate a new MBUF (including
1257  *   cluster and mbuf headers).  In that case the failure is
1258  *   non-fatal.  The incoming cluster chain is not freed, giving
1259  *   the caller the choice of whether to try a retransmit later.
1260  */
1261 LM_STATUS
1262 MM_CoalesceTxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1263 {
1264     PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1265     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1266     void *skbnew;
1267     int len = 0;
1268
1269     if (len == 0)
1270         return (LM_STATUS_SUCCESS);
1271
1272     if (len > MAX_PACKET_SIZE){
1273         printf ("eth%d: xmit frame discarded, too big!, size = %d\n",
1274                 pUmDevice->index, len);
1275         return (LM_STATUS_FAILURE);
1276     }
1277
1278     skbnew = bcm570xPktAlloc(pUmDevice->index, MAX_PACKET_SIZE);
1279
1280     if (skbnew == NULL) {
1281         pUmDevice->tx_full = 1;
1282         printf ("eth%d: out of transmit buffers", pUmDevice->index);
1283         return (LM_STATUS_FAILURE);
1284     }
1285
1286     /* New packet values */
1287     pUmPacket->skbuff = skbnew;
1288     pUmPacket->lm_packet.u.Tx.FragCount = 1;
1289
1290     return (LM_STATUS_SUCCESS);
1291 }
1292
1293
1294 LM_STATUS
1295 MM_IndicateRxPackets(PLM_DEVICE_BLOCK pDevice)
1296 {
1297     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1298     pUmDevice->rx_pkt = 1;
1299     return LM_STATUS_SUCCESS;
1300 }
1301
1302 LM_STATUS
1303 MM_IndicateTxPackets(PLM_DEVICE_BLOCK pDevice)
1304 {
1305     PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1306     PLM_PACKET pPacket;
1307     PUM_PACKET pUmPacket;
1308     void *skb;
1309     while ( TRUE ) {
1310
1311         pPacket = (PLM_PACKET)
1312             QQ_PopHead(&pDevice->TxPacketXmittedQ.Container);
1313
1314         if (pPacket == 0)
1315             break;
1316
1317         pUmPacket = (PUM_PACKET) pPacket;
1318         skb = (void*)pUmPacket->skbuff;
1319
1320         /*
1321         * Free MBLK if we transmitted a fragmented packet or a
1322         * non-fragmented packet straight from the VxWorks
1323         * buffer pool. If packet was copied to a local transmit
1324         * buffer, then there's no MBUF to free, just free
1325         * the transmit buffer back to the cluster pool.
1326         */
1327
1328         if (skb)
1329             bcm570xPktFree (pUmDevice->index, skb);
1330
1331         pUmPacket->skbuff = 0;
1332         QQ_PushTail(&pDevice->TxPacketFreeQ.Container, pPacket);
1333         pUmDevice->tx_pkt = 1;
1334     }
1335     if (pUmDevice->tx_full) {
1336         if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) >=
1337             (QQ_GetSize(&pDevice->TxPacketFreeQ.Container) >> 1))
1338             pUmDevice->tx_full = 0;
1339     }
1340     return LM_STATUS_SUCCESS;
1341 }
1342
1343 /*
1344  *  Scan an MBUF chain until we reach fragment number "frag"
1345  *  Return its length and physical address.
1346  */
1347 void MM_MapTxDma
1348     (
1349     PLM_DEVICE_BLOCK pDevice,
1350     struct _LM_PACKET *pPacket,
1351     T3_64BIT_HOST_ADDR *paddr,
1352     LM_UINT32 *len,
1353     int frag)
1354 {
1355     PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1356     *len = pPacket->PacketSize;
1357     MM_SetT3Addr(paddr, (dma_addr_t) pUmPacket->skbuff);
1358 }
1359
1360 /*
1361  *  Convert an mbuf address, a CPU local virtual address,
1362  *  to a physical address as seen from a PCI device.  Store the
1363  *  result at paddr.
1364  */
1365 void MM_MapRxDma(
1366                  PLM_DEVICE_BLOCK pDevice,
1367                  struct _LM_PACKET *pPacket,
1368                  T3_64BIT_HOST_ADDR *paddr)
1369 {
1370     PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1371     MM_SetT3Addr(paddr, (dma_addr_t) pUmPacket->skbuff);
1372 }
1373
1374 void
1375 MM_SetAddr (LM_PHYSICAL_ADDRESS *paddr, dma_addr_t addr)
1376 {
1377 #if (BITS_PER_LONG == 64)
1378         paddr->High = ((unsigned long) addr) >> 32;
1379         paddr->Low = ((unsigned long) addr) & 0xffffffff;
1380 #else
1381         paddr->High = 0;
1382         paddr->Low = (unsigned long) addr;
1383 #endif
1384 }
1385
1386 void
1387 MM_SetT3Addr(T3_64BIT_HOST_ADDR *paddr, dma_addr_t addr)
1388 {
1389         unsigned long baddr = (unsigned long) addr;
1390 #if (BITS_PER_LONG == 64)
1391         set_64bit_addr(paddr, baddr & 0xffffffff, baddr >> 32);
1392 #else
1393         set_64bit_addr(paddr, baddr, 0);
1394 #endif
1395 }
1396
1397 /*
1398  * This combination of `inline' and `extern' has almost the effect of a
1399  * macro.  The way to use it is to put a function definition in a header
1400  * file with these keywords, and put another copy of the definition
1401  * (lacking `inline' and `extern') in a library file.  The definition in
1402  * the header file will cause most calls to the function to be inlined.
1403  * If any uses of the function remain, they will refer to the single copy
1404  * in the library.
1405  */
1406 void
1407 atomic_set(atomic_t* entry, int val)
1408 {
1409     entry->counter = val;
1410 }
1411 int
1412 atomic_read(atomic_t* entry)
1413 {
1414     return entry->counter;
1415 }
1416 void
1417 atomic_inc(atomic_t* entry)
1418 {
1419     if(entry)
1420         entry->counter++;
1421 }
1422
1423 void
1424 atomic_dec(atomic_t* entry)
1425 {
1426     if(entry)
1427         entry->counter--;
1428 }
1429
1430 void
1431 atomic_sub(int a, atomic_t* entry)
1432 {
1433     if(entry)
1434         entry->counter -= a;
1435 }
1436
1437 void
1438 atomic_add(int a, atomic_t* entry)
1439 {
1440     if(entry)
1441         entry->counter += a;
1442 }
1443
1444 /******************************************************************************/
1445 /* Description:                                                               */
1446 /*                                                                            */
1447 /* Return:                                                                    */
1448 /******************************************************************************/
1449 void
1450 QQ_InitQueue(
1451 PQQ_CONTAINER pQueue,
1452 unsigned int QueueSize) {
1453     pQueue->Head = 0;
1454     pQueue->Tail = 0;
1455     pQueue->Size = QueueSize+1;
1456     atomic_set(&pQueue->EntryCnt, 0);
1457 } /* QQ_InitQueue */
1458
1459
1460 /******************************************************************************/
1461 /* Description:                                                               */
1462 /*                                                                            */
1463 /* Return:                                                                    */
1464 /******************************************************************************/
1465 char
1466 QQ_Full(
1467 PQQ_CONTAINER pQueue) {
1468     unsigned int NewHead;
1469
1470     NewHead = (pQueue->Head + 1) % pQueue->Size;
1471
1472     return(NewHead == pQueue->Tail);
1473 } /* QQ_Full */
1474
1475
1476 /******************************************************************************/
1477 /* Description:                                                               */
1478 /*                                                                            */
1479 /* Return:                                                                    */
1480 /******************************************************************************/
1481 char
1482 QQ_Empty(
1483 PQQ_CONTAINER pQueue) {
1484     return(pQueue->Head == pQueue->Tail);
1485 } /* QQ_Empty */
1486
1487
1488 /******************************************************************************/
1489 /* Description:                                                               */
1490 /*                                                                            */
1491 /* Return:                                                                    */
1492 /******************************************************************************/
1493 unsigned int
1494 QQ_GetSize(
1495 PQQ_CONTAINER pQueue) {
1496     return pQueue->Size;
1497 } /* QQ_GetSize */
1498
1499
1500 /******************************************************************************/
1501 /* Description:                                                               */
1502 /*                                                                            */
1503 /* Return:                                                                    */
1504 /******************************************************************************/
1505 unsigned int
1506 QQ_GetEntryCnt(
1507 PQQ_CONTAINER pQueue) {
1508     return atomic_read(&pQueue->EntryCnt);
1509 } /* QQ_GetEntryCnt */
1510
1511
1512 /******************************************************************************/
1513 /* Description:                                                               */
1514 /*                                                                            */
1515 /* Return:                                                                    */
1516 /*    TRUE entry was added successfully.                                      */
1517 /*    FALSE queue is full.                                                    */
1518 /******************************************************************************/
1519 char
1520 QQ_PushHead(
1521 PQQ_CONTAINER pQueue,
1522 PQQ_ENTRY pEntry) {
1523     unsigned int Head;
1524
1525     Head = (pQueue->Head + 1) % pQueue->Size;
1526
1527 #if !defined(QQ_NO_OVERFLOW_CHECK)
1528     if(Head == pQueue->Tail) {
1529         return 0;
1530     } /* if */
1531 #endif /* QQ_NO_OVERFLOW_CHECK */
1532
1533     pQueue->Array[pQueue->Head] = pEntry;
1534     wmb();
1535     pQueue->Head = Head;
1536     atomic_inc(&pQueue->EntryCnt);
1537
1538     return -1;
1539 } /* QQ_PushHead */
1540
1541
1542 /******************************************************************************/
1543 /* Description:                                                               */
1544 /*                                                                            */
1545 /* Return:                                                                    */
1546 /*    TRUE entry was added successfully.                                      */
1547 /*    FALSE queue is full.                                                    */
1548 /******************************************************************************/
1549 char
1550 QQ_PushTail(
1551 PQQ_CONTAINER pQueue,
1552 PQQ_ENTRY pEntry) {
1553     unsigned int Tail;
1554
1555     Tail = pQueue->Tail;
1556     if(Tail == 0) {
1557         Tail = pQueue->Size;
1558     } /* if */
1559     Tail--;
1560
1561 #if !defined(QQ_NO_OVERFLOW_CHECK)
1562     if(Tail == pQueue->Head) {
1563         return 0;
1564     } /* if */
1565 #endif /* QQ_NO_OVERFLOW_CHECK */
1566
1567     pQueue->Array[Tail] = pEntry;
1568     wmb();
1569     pQueue->Tail = Tail;
1570     atomic_inc(&pQueue->EntryCnt);
1571
1572     return -1;
1573 } /* QQ_PushTail */
1574
1575
1576 /******************************************************************************/
1577 /* Description:                                                               */
1578 /*                                                                            */
1579 /* Return:                                                                    */
1580 /******************************************************************************/
1581 PQQ_ENTRY
1582 QQ_PopHead(
1583 PQQ_CONTAINER pQueue) {
1584     unsigned int Head;
1585     PQQ_ENTRY Entry;
1586
1587     Head = pQueue->Head;
1588
1589 #if !defined(QQ_NO_UNDERFLOW_CHECK)
1590     if(Head == pQueue->Tail) {
1591         return (PQQ_ENTRY) 0;
1592     } /* if */
1593 #endif /* QQ_NO_UNDERFLOW_CHECK */
1594
1595     if(Head == 0) {
1596         Head = pQueue->Size;
1597     } /* if */
1598     Head--;
1599
1600     Entry = pQueue->Array[Head];
1601     membar();
1602
1603     pQueue->Head = Head;
1604     atomic_dec(&pQueue->EntryCnt);
1605
1606     return Entry;
1607 } /* QQ_PopHead */
1608
1609
1610 /******************************************************************************/
1611 /* Description:                                                               */
1612 /*                                                                            */
1613 /* Return:                                                                    */
1614 /******************************************************************************/
1615 PQQ_ENTRY
1616 QQ_PopTail(
1617 PQQ_CONTAINER pQueue) {
1618     unsigned int Tail;
1619     PQQ_ENTRY Entry;
1620
1621     Tail = pQueue->Tail;
1622
1623 #if !defined(QQ_NO_UNDERFLOW_CHECK)
1624     if(Tail == pQueue->Head) {
1625         return (PQQ_ENTRY) 0;
1626     } /* if */
1627 #endif /* QQ_NO_UNDERFLOW_CHECK */
1628
1629     Entry = pQueue->Array[Tail];
1630     membar();
1631     pQueue->Tail = (Tail + 1) % pQueue->Size;
1632     atomic_dec(&pQueue->EntryCnt);
1633
1634     return Entry;
1635 } /* QQ_PopTail */
1636
1637
1638 /******************************************************************************/
1639 /* Description:                                                               */
1640 /*                                                                            */
1641 /* Return:                                                                    */
1642 /******************************************************************************/
1643 PQQ_ENTRY
1644 QQ_GetHead(
1645     PQQ_CONTAINER pQueue,
1646     unsigned int Idx)
1647 {
1648     if(Idx >= atomic_read(&pQueue->EntryCnt))
1649     {
1650         return (PQQ_ENTRY) 0;
1651     }
1652
1653     if(pQueue->Head > Idx)
1654     {
1655         Idx = pQueue->Head - Idx;
1656     }
1657     else
1658     {
1659         Idx = pQueue->Size - (Idx - pQueue->Head);
1660     }
1661     Idx--;
1662
1663     return pQueue->Array[Idx];
1664 }
1665
1666
1667 /******************************************************************************/
1668 /* Description:                                                               */
1669 /*                                                                            */
1670 /* Return:                                                                    */
1671 /******************************************************************************/
1672 PQQ_ENTRY
1673 QQ_GetTail(
1674     PQQ_CONTAINER pQueue,
1675     unsigned int Idx)
1676 {
1677     if(Idx >= atomic_read(&pQueue->EntryCnt))
1678     {
1679         return (PQQ_ENTRY) 0;
1680     }
1681
1682     Idx += pQueue->Tail;
1683     if(Idx >= pQueue->Size)
1684     {
1685         Idx = Idx - pQueue->Size;
1686     }
1687
1688     return pQueue->Array[Idx];
1689 }
1690
1691 #endif  /* CFG_CMD_NET, !CONFIG_NET_MULTI, CONFIG_BCM570x */