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