KIrkwood: Sheevaplug: kwimage configuration
[u-boot-kw.git] / drivers / net / bcm570x.c
blobc250d446f14528cea4a45ade0f972eccbc34956b
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 */
7 #include <common.h>
9 #ifdef CONFIG_BMW
10 #include <mpc824x.h>
11 #endif
12 #include <net.h>
13 #include "bcm570x_mm.h"
14 #include "bcm570x_autoneg.h"
15 #include <pci.h>
16 #include <malloc.h>
19 * PCI Registers and definitions.
21 #define PCI_CMD_MASK 0xffff0000 /* mask to save status bits */
22 #define PCI_ANY_ID (~0)
25 * PCI memory base for Ethernet device as well as device Interrupt.
27 #define BCM570X_MBAR 0x80100000
28 #define BCM570X_ILINE 1
30 #define SECOND_USEC 1000000
31 #define MAX_PACKET_SIZE 1600
32 #define MAX_UNITS 4
34 /* Globals to this module */
35 int initialized = 0;
36 unsigned int ioBase = 0;
37 volatile PLM_DEVICE_BLOCK pDevice = NULL; /* 570x softc */
38 volatile PUM_DEVICE_BLOCK pUmDevice = NULL;
40 /* Used to pass the full-duplex flag, etc. */
41 int line_speed[MAX_UNITS] = { 0, 0, 0, 0 };
42 static int full_duplex[MAX_UNITS] = { 1, 1, 1, 1 };
43 static int rx_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
44 static int tx_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
45 static int auto_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
46 static int tx_checksum[MAX_UNITS] = { 1, 1, 1, 1 };
47 static int rx_checksum[MAX_UNITS] = { 1, 1, 1, 1 };
48 static int auto_speed[MAX_UNITS] = { 1, 1, 1, 1 };
50 #if JUMBO_FRAMES
51 /* Jumbo MTU for interfaces. */
52 static int mtu[MAX_UNITS] = { 0, 0, 0, 0 };
53 #endif
55 /* Turn on Wake-on lan for a device unit */
56 static int enable_wol[MAX_UNITS] = { 0, 0, 0, 0 };
58 #define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNT
59 static unsigned int tx_pkt_desc_cnt[MAX_UNITS] =
60 { TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT };
62 #define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNT
63 static unsigned int rx_std_desc_cnt[MAX_UNITS] =
64 { RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT };
66 static unsigned int rx_adaptive_coalesce[MAX_UNITS] = { 1, 1, 1, 1 };
68 #if T3_JUMBO_RCV_RCB_ENTRY_COUNT
69 #define JBO_DESC_CNT DEFAULT_JUMBO_RCV_DESC_COUNT
70 static unsigned int rx_jumbo_desc_cnt[MAX_UNITS] =
71 { JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT };
72 #endif
73 #define RX_COAL_TK DEFAULT_RX_COALESCING_TICKS
74 static unsigned int rx_coalesce_ticks[MAX_UNITS] =
75 { RX_COAL_TK, RX_COAL_TK, RX_COAL_TK, RX_COAL_TK };
77 #define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMES
78 static unsigned int rx_max_coalesce_frames[MAX_UNITS] =
79 { RX_COAL_FM, RX_COAL_FM, RX_COAL_FM, RX_COAL_FM };
81 #define TX_COAL_TK DEFAULT_TX_COALESCING_TICKS
82 static unsigned int tx_coalesce_ticks[MAX_UNITS] =
83 { TX_COAL_TK, TX_COAL_TK, TX_COAL_TK, TX_COAL_TK };
85 #define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMES
86 static unsigned int tx_max_coalesce_frames[MAX_UNITS] =
87 { TX_COAL_FM, TX_COAL_FM, TX_COAL_FM, TX_COAL_FM };
89 #define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKS
90 static unsigned int stats_coalesce_ticks[MAX_UNITS] =
91 { ST_COAL_TK, ST_COAL_TK, ST_COAL_TK, ST_COAL_TK };
94 * Legitimate values for BCM570x device types
96 typedef enum {
97 BCM5700VIGIL = 0,
98 BCM5700A6,
99 BCM5700T6,
100 BCM5700A9,
101 BCM5700T9,
102 BCM5700,
103 BCM5701A5,
104 BCM5701T1,
105 BCM5701T8,
106 BCM5701A7,
107 BCM5701A10,
108 BCM5701A12,
109 BCM5701,
110 BCM5702,
111 BCM5703,
112 BCM5703A31,
113 TC996T,
114 TC996ST,
115 TC996SSX,
116 TC996SX,
117 TC996BT,
118 TC997T,
119 TC997SX,
120 TC1000T,
121 TC940BR01,
122 TC942BR01,
123 NC6770,
124 NC7760,
125 NC7770,
126 NC7780
127 } board_t;
129 /* Chip-Rev names for each device-type */
130 static struct {
131 char *name;
132 } chip_rev[] = {
134 "BCM5700VIGIL"}, {
135 "BCM5700A6"}, {
136 "BCM5700T6"}, {
137 "BCM5700A9"}, {
138 "BCM5700T9"}, {
139 "BCM5700"}, {
140 "BCM5701A5"}, {
141 "BCM5701T1"}, {
142 "BCM5701T8"}, {
143 "BCM5701A7"}, {
144 "BCM5701A10"}, {
145 "BCM5701A12"}, {
146 "BCM5701"}, {
147 "BCM5702"}, {
148 "BCM5703"}, {
149 "BCM5703A31"}, {
150 "TC996T"}, {
151 "TC996ST"}, {
152 "TC996SSX"}, {
153 "TC996SX"}, {
154 "TC996BT"}, {
155 "TC997T"}, {
156 "TC997SX"}, {
157 "TC1000T"}, {
158 "TC940BR01"}, {
159 "TC942BR01"}, {
160 "NC6770"}, {
161 "NC7760"}, {
162 "NC7770"}, {
163 "NC7780"}, {
167 /* indexed by board_t, above */
168 static struct {
169 char *name;
170 } board_info[] = {
172 "Broadcom Vigil B5700 1000Base-T"}, {
173 "Broadcom BCM5700 1000Base-T"}, {
174 "Broadcom BCM5700 1000Base-SX"}, {
175 "Broadcom BCM5700 1000Base-SX"}, {
176 "Broadcom BCM5700 1000Base-T"}, {
177 "Broadcom BCM5700"}, {
178 "Broadcom BCM5701 1000Base-T"}, {
179 "Broadcom BCM5701 1000Base-T"}, {
180 "Broadcom BCM5701 1000Base-T"}, {
181 "Broadcom BCM5701 1000Base-SX"}, {
182 "Broadcom BCM5701 1000Base-T"}, {
183 "Broadcom BCM5701 1000Base-T"}, {
184 "Broadcom BCM5701"}, {
185 "Broadcom BCM5702 1000Base-T"}, {
186 "Broadcom BCM5703 1000Base-T"}, {
187 "Broadcom BCM5703 1000Base-SX"}, {
188 "3Com 3C996 10/100/1000 Server NIC"}, {
189 "3Com 3C996 10/100/1000 Server NIC"}, {
190 "3Com 3C996 Gigabit Fiber-SX Server NIC"}, {
191 "3Com 3C996 Gigabit Fiber-SX Server NIC"}, {
192 "3Com 3C996B Gigabit Server NIC"}, {
193 "3Com 3C997 Gigabit Server NIC"}, {
194 "3Com 3C997 Gigabit Fiber-SX Server NIC"}, {
195 "3Com 3C1000 Gigabit NIC"}, {
196 "3Com 3C940 Gigabit LOM (21X21)"}, {
197 "3Com 3C942 Gigabit LOM (31X31)"}, {
198 "Compaq NC6770 Gigabit Server Adapter"}, {
199 "Compaq NC7760 Gigabit Server Adapter"}, {
200 "Compaq NC7770 Gigabit Server Adapter"}, {
201 "Compaq NC7780 Gigabit Server Adapter"}, {
202 0},};
204 /* PCI Devices which use the 570x chipset */
205 struct pci_device_table {
206 unsigned short vendor_id, device_id; /* Vendor/DeviceID */
207 unsigned short subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
208 unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
209 unsigned long board_id; /* Data private to the driver */
210 int io_size, min_latency;
211 } bcm570xDevices[] = {
213 0x14e4, 0x1644, 0x1014, 0x0277, 0, 0, BCM5700VIGIL, 128, 32}, {
214 0x14e4, 0x1644, 0x14e4, 0x1644, 0, 0, BCM5700A6, 128, 32}, {
215 0x14e4, 0x1644, 0x14e4, 0x2, 0, 0, BCM5700T6, 128, 32}, {
216 0x14e4, 0x1644, 0x14e4, 0x3, 0, 0, BCM5700A9, 128, 32}, {
217 0x14e4, 0x1644, 0x14e4, 0x4, 0, 0, BCM5700T9, 128, 32}, {
218 0x14e4, 0x1644, 0x1028, 0xd1, 0, 0, BCM5700, 128, 32}, {
219 0x14e4, 0x1644, 0x1028, 0x0106, 0, 0, BCM5700, 128, 32}, {
220 0x14e4, 0x1644, 0x1028, 0x0109, 0, 0, BCM5700, 128, 32}, {
221 0x14e4, 0x1644, 0x1028, 0x010a, 0, 0, BCM5700, 128, 32}, {
222 0x14e4, 0x1644, 0x10b7, 0x1000, 0, 0, TC996T, 128, 32}, {
223 0x14e4, 0x1644, 0x10b7, 0x1001, 0, 0, TC996ST, 128, 32}, {
224 0x14e4, 0x1644, 0x10b7, 0x1002, 0, 0, TC996SSX, 128, 32}, {
225 0x14e4, 0x1644, 0x10b7, 0x1003, 0, 0, TC997T, 128, 32}, {
226 0x14e4, 0x1644, 0x10b7, 0x1005, 0, 0, TC997SX, 128, 32}, {
227 0x14e4, 0x1644, 0x10b7, 0x1008, 0, 0, TC942BR01, 128, 32}, {
228 0x14e4, 0x1644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5700, 128, 32}, {
229 0x14e4, 0x1645, 0x14e4, 1, 0, 0, BCM5701A5, 128, 32}, {
230 0x14e4, 0x1645, 0x14e4, 5, 0, 0, BCM5701T1, 128, 32}, {
231 0x14e4, 0x1645, 0x14e4, 6, 0, 0, BCM5701T8, 128, 32}, {
232 0x14e4, 0x1645, 0x14e4, 7, 0, 0, BCM5701A7, 128, 32}, {
233 0x14e4, 0x1645, 0x14e4, 8, 0, 0, BCM5701A10, 128, 32}, {
234 0x14e4, 0x1645, 0x14e4, 0x8008, 0, 0, BCM5701A12, 128, 32}, {
235 0x14e4, 0x1645, 0x0e11, 0xc1, 0, 0, NC6770, 128, 32}, {
236 0x14e4, 0x1645, 0x0e11, 0x7c, 0, 0, NC7770, 128, 32}, {
237 0x14e4, 0x1645, 0x0e11, 0x85, 0, 0, NC7780, 128, 32}, {
238 0x14e4, 0x1645, 0x1028, 0x0121, 0, 0, BCM5701, 128, 32}, {
239 0x14e4, 0x1645, 0x10b7, 0x1004, 0, 0, TC996SX, 128, 32}, {
240 0x14e4, 0x1645, 0x10b7, 0x1006, 0, 0, TC996BT, 128, 32}, {
241 0x14e4, 0x1645, 0x10b7, 0x1007, 0, 0, TC1000T, 128, 32}, {
242 0x14e4, 0x1645, 0x10b7, 0x1008, 0, 0, TC940BR01, 128, 32}, {
243 0x14e4, 0x1645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5701, 128, 32}, {
244 0x14e4, 0x1646, 0x14e4, 0x8009, 0, 0, BCM5702, 128, 32}, {
245 0x14e4, 0x1646, 0x0e11, 0xbb, 0, 0, NC7760, 128, 32}, {
246 0x14e4, 0x1646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702, 128, 32}, {
247 0x14e4, 0x16a6, 0x14e4, 0x8009, 0, 0, BCM5702, 128, 32}, {
248 0x14e4, 0x16a6, 0x0e11, 0xbb, 0, 0, NC7760, 128, 32}, {
249 0x14e4, 0x16a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702, 128, 32}, {
250 0x14e4, 0x1647, 0x14e4, 0x0009, 0, 0, BCM5703, 128, 32}, {
251 0x14e4, 0x1647, 0x14e4, 0x000a, 0, 0, BCM5703A31, 128, 32}, {
252 0x14e4, 0x1647, 0x14e4, 0x000b, 0, 0, BCM5703, 128, 32}, {
253 0x14e4, 0x1647, 0x14e4, 0x800a, 0, 0, BCM5703, 128, 32}, {
254 0x14e4, 0x1647, 0x0e11, 0x9a, 0, 0, NC7770, 128, 32}, {
255 0x14e4, 0x1647, 0x0e11, 0x99, 0, 0, NC7780, 128, 32}, {
256 0x14e4, 0x1647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703, 128, 32}, {
257 0x14e4, 0x16a7, 0x14e4, 0x0009, 0, 0, BCM5703, 128, 32}, {
258 0x14e4, 0x16a7, 0x14e4, 0x000a, 0, 0, BCM5703A31, 128, 32}, {
259 0x14e4, 0x16a7, 0x14e4, 0x000b, 0, 0, BCM5703, 128, 32}, {
260 0x14e4, 0x16a7, 0x14e4, 0x800a, 0, 0, BCM5703, 128, 32}, {
261 0x14e4, 0x16a7, 0x0e11, 0x9a, 0, 0, NC7770, 128, 32}, {
262 0x14e4, 0x16a7, 0x0e11, 0x99, 0, 0, NC7780, 128, 32}, {
263 0x14e4, 0x16a7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703, 128, 32}
266 #define n570xDevices (sizeof(bcm570xDevices)/sizeof(bcm570xDevices[0]))
269 * Allocate a packet buffer from the bcm570x packet pool.
271 void *bcm570xPktAlloc (int u, int pksize)
273 return malloc (pksize);
277 * Free a packet previously allocated from the bcm570x packet
278 * buffer pool.
280 void bcm570xPktFree (int u, void *p)
282 free (p);
285 int bcm570xReplenishRxBuffers (PUM_DEVICE_BLOCK pUmDevice)
287 PLM_PACKET pPacket;
288 PUM_PACKET pUmPacket;
289 void *skb;
290 int queue_rx = 0;
291 int ret = 0;
293 while ((pUmPacket = (PUM_PACKET)
294 QQ_PopHead (&pUmDevice->rx_out_of_buf_q.Container)) != 0) {
296 pPacket = (PLM_PACKET) pUmPacket;
298 /* reuse an old skb */
299 if (pUmPacket->skbuff) {
300 QQ_PushTail (&pDevice->RxPacketFreeQ.Container,
301 pPacket);
302 queue_rx = 1;
303 continue;
305 if ((skb = bcm570xPktAlloc (pUmDevice->index,
306 pPacket->u.Rx.RxBufferSize + 2)) ==
307 0) {
308 QQ_PushHead (&pUmDevice->rx_out_of_buf_q.Container,
309 pPacket);
310 printf ("NOTICE: Out of RX memory.\n");
311 ret = 1;
312 break;
315 pUmPacket->skbuff = skb;
316 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
317 queue_rx = 1;
320 if (queue_rx) {
321 LM_QueueRxPackets (pDevice);
324 return ret;
328 * Probe, Map, and Init 570x device.
330 int eth_init (bd_t * bis)
332 int i, rv, devFound = FALSE;
333 pci_dev_t devbusfn;
334 unsigned short status;
336 /* Find PCI device, if it exists, configure ... */
337 for (i = 0; i < n570xDevices; i++) {
338 devbusfn = pci_find_device (bcm570xDevices[i].vendor_id,
339 bcm570xDevices[i].device_id, 0);
340 if (devbusfn == -1) {
341 continue; /* No device of that vendor/device ID */
342 } else {
344 /* Set ILINE */
345 pci_write_config_byte (devbusfn,
346 PCI_INTERRUPT_LINE,
347 BCM570X_ILINE);
350 * 0x10 - 0x14 define one 64-bit MBAR.
351 * 0x14 is the higher-order address bits of the BAR.
353 pci_write_config_dword (devbusfn,
354 PCI_BASE_ADDRESS_1, 0);
356 ioBase = BCM570X_MBAR;
358 pci_write_config_dword (devbusfn,
359 PCI_BASE_ADDRESS_0, ioBase);
362 * Enable PCI memory, IO, and Master -- don't
363 * reset any status bits in doing so.
365 pci_read_config_word (devbusfn, PCI_COMMAND, &status);
367 status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
369 pci_write_config_word (devbusfn, PCI_COMMAND, status);
371 printf
372 ("\n%s: bus %d, device %d, function %d: MBAR=0x%x\n",
373 board_info[bcm570xDevices[i].board_id].name,
374 PCI_BUS (devbusfn), PCI_DEV (devbusfn),
375 PCI_FUNC (devbusfn), ioBase);
377 /* Allocate once, but always clear on init */
378 if (!pDevice) {
379 pDevice = malloc (sizeof (UM_DEVICE_BLOCK));
380 pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
381 memset (pDevice, 0x0, sizeof (UM_DEVICE_BLOCK));
384 /* Configure pci dev structure */
385 pUmDevice->pdev = devbusfn;
386 pUmDevice->index = 0;
387 pUmDevice->tx_pkt = 0;
388 pUmDevice->rx_pkt = 0;
389 devFound = TRUE;
390 break;
394 if (!devFound) {
395 printf
396 ("eth_init: FAILURE: no BCM570x Ethernet devices found.\n");
397 return -1;
400 /* Setup defaults for chip */
401 pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
403 if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) {
404 pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
405 } else {
407 if (rx_checksum[i]) {
408 pDevice->TaskToOffload |=
409 LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
410 LM_TASK_OFFLOAD_RX_UDP_CHECKSUM;
413 if (tx_checksum[i]) {
414 pDevice->TaskToOffload |=
415 LM_TASK_OFFLOAD_TX_TCP_CHECKSUM |
416 LM_TASK_OFFLOAD_TX_UDP_CHECKSUM;
417 pDevice->NoTxPseudoHdrChksum = TRUE;
421 /* Set Device PCI Memory base address */
422 pDevice->pMappedMemBase = (PLM_UINT8) ioBase;
424 /* Pull down adapter info */
425 if ((rv = LM_GetAdapterInfo (pDevice)) != LM_STATUS_SUCCESS) {
426 printf ("bcm570xEnd: LM_GetAdapterInfo failed: rv=%d!\n", rv);
427 return -2;
430 /* Lock not needed */
431 pUmDevice->do_global_lock = 0;
433 if (T3_ASIC_REV (pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) {
434 /* The 5700 chip works best without interleaved register */
435 /* accesses on certain machines. */
436 pUmDevice->do_global_lock = 1;
439 /* Setup timer delays */
440 if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
441 pDevice->UseTaggedStatus = TRUE;
442 pUmDevice->timer_interval = CONFIG_SYS_HZ;
443 } else {
444 pUmDevice->timer_interval = CONFIG_SYS_HZ / 50;
447 /* Grab name .... */
448 pUmDevice->name =
449 (char *)malloc (strlen (board_info[bcm570xDevices[i].board_id].name)
450 + 1);
451 strcpy (pUmDevice->name, board_info[bcm570xDevices[i].board_id].name);
453 eth_getenv_enetaddr("ethaddr", pDevice->NodeAddress);
454 LM_SetMacAddress (pDevice);
455 /* Init queues .. */
456 QQ_InitQueue (&pUmDevice->rx_out_of_buf_q.Container,
457 MAX_RX_PACKET_DESC_COUNT);
458 pUmDevice->rx_last_cnt = pUmDevice->tx_last_cnt = 0;
460 /* delay for 4 seconds */
461 pUmDevice->delayed_link_ind = (4 * CONFIG_SYS_HZ) / pUmDevice->timer_interval;
463 pUmDevice->adaptive_expiry = CONFIG_SYS_HZ / pUmDevice->timer_interval;
465 /* Sometimes we get spurious ints. after reset when link is down. */
466 /* This field tells the isr to service the int. even if there is */
467 /* no status block update. */
468 pUmDevice->adapter_just_inited =
469 (3 * CONFIG_SYS_HZ) / pUmDevice->timer_interval;
471 /* Initialize 570x */
472 if (LM_InitializeAdapter (pDevice) != LM_STATUS_SUCCESS) {
473 printf ("ERROR: Adapter initialization failed.\n");
474 return ERROR;
477 /* Enable chip ISR */
478 LM_EnableInterrupt (pDevice);
480 /* Clear MC table */
481 LM_MulticastClear (pDevice);
483 /* Enable Multicast */
484 LM_SetReceiveMask (pDevice,
485 pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST);
487 pUmDevice->opened = 1;
488 pUmDevice->tx_full = 0;
489 pUmDevice->tx_pkt = 0;
490 pUmDevice->rx_pkt = 0;
491 printf ("eth%d: %s @0x%lx,",
492 pDevice->index, pUmDevice->name, (unsigned long)ioBase);
493 printf ("node addr ");
494 for (i = 0; i < 6; i++) {
495 printf ("%2.2x", pDevice->NodeAddress[i]);
497 printf ("\n");
499 printf ("eth%d: ", pDevice->index);
500 printf ("%s with ", chip_rev[bcm570xDevices[i].board_id].name);
502 if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5400_PHY_ID)
503 printf ("Broadcom BCM5400 Copper ");
504 else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID)
505 printf ("Broadcom BCM5401 Copper ");
506 else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5411_PHY_ID)
507 printf ("Broadcom BCM5411 Copper ");
508 else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5701_PHY_ID)
509 printf ("Broadcom BCM5701 Integrated Copper ");
510 else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5703_PHY_ID)
511 printf ("Broadcom BCM5703 Integrated Copper ");
512 else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM8002_PHY_ID)
513 printf ("Broadcom BCM8002 SerDes ");
514 else if (pDevice->EnableTbi)
515 printf ("Agilent HDMP-1636 SerDes ");
516 else
517 printf ("Unknown ");
518 printf ("transceiver found\n");
520 printf ("eth%d: %s, MTU: %d,",
521 pDevice->index, pDevice->BusSpeedStr, 1500);
523 if ((pDevice->ChipRevId != T3_CHIP_ID_5700_B0) && rx_checksum[i])
524 printf ("Rx Checksum ON\n");
525 else
526 printf ("Rx Checksum OFF\n");
527 initialized++;
529 return 0;
532 /* Ethernet Interrupt service routine */
533 void eth_isr (void)
535 LM_UINT32 oldtag, newtag;
536 int i;
538 pUmDevice->interrupt = 1;
540 if (pDevice->UseTaggedStatus) {
541 if ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) ||
542 pUmDevice->adapter_just_inited) {
543 MB_REG_WR (pDevice, Mailbox.Interrupt[0].Low, 1);
544 oldtag = pDevice->pStatusBlkVirt->StatusTag;
546 for (i = 0;; i++) {
547 pDevice->pStatusBlkVirt->Status &=
548 ~STATUS_BLOCK_UPDATED;
549 LM_ServiceInterrupts (pDevice);
550 newtag = pDevice->pStatusBlkVirt->StatusTag;
551 if ((newtag == oldtag) || (i > 50)) {
552 MB_REG_WR (pDevice,
553 Mailbox.Interrupt[0].Low,
554 newtag << 24);
555 if (pDevice->UndiFix) {
556 REG_WR (pDevice, Grc.LocalCtrl,
557 pDevice->
558 GrcLocalCtrl | 0x2);
560 break;
562 oldtag = newtag;
565 } else {
566 while (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) {
567 unsigned int dummy;
569 pDevice->pMemView->Mailbox.Interrupt[0].Low = 1;
570 pDevice->pStatusBlkVirt->Status &=
571 ~STATUS_BLOCK_UPDATED;
572 LM_ServiceInterrupts (pDevice);
573 pDevice->pMemView->Mailbox.Interrupt[0].Low = 0;
574 dummy = pDevice->pMemView->Mailbox.Interrupt[0].Low;
578 /* Allocate new RX buffers */
579 if (QQ_GetEntryCnt (&pUmDevice->rx_out_of_buf_q.Container)) {
580 bcm570xReplenishRxBuffers (pUmDevice);
583 /* Queue packets */
584 if (QQ_GetEntryCnt (&pDevice->RxPacketFreeQ.Container)) {
585 LM_QueueRxPackets (pDevice);
588 if (pUmDevice->tx_queued) {
589 pUmDevice->tx_queued = 0;
592 if (pUmDevice->tx_full) {
593 if (pDevice->LinkStatus != LM_STATUS_LINK_DOWN) {
594 printf
595 ("NOTICE: tx was previously blocked, restarting MUX\n");
596 pUmDevice->tx_full = 0;
600 pUmDevice->interrupt = 0;
604 int eth_send (volatile void *packet, int length)
606 int status = 0;
607 #if ET_DEBUG
608 unsigned char *ptr = (unsigned char *)packet;
609 #endif
610 PLM_PACKET pPacket;
611 PUM_PACKET pUmPacket;
613 /* Link down, return */
614 while (pDevice->LinkStatus == LM_STATUS_LINK_DOWN) {
615 #if 0
616 printf ("eth%d: link down - check cable or link partner.\n",
617 pUmDevice->index);
618 #endif
619 eth_isr ();
621 /* Wait to see link for one-half a second before sending ... */
622 udelay (1500000);
626 /* Clear sent flag */
627 pUmDevice->tx_pkt = 0;
629 /* Previously blocked */
630 if (pUmDevice->tx_full) {
631 printf ("eth%d: tx blocked.\n", pUmDevice->index);
632 return 0;
635 pPacket = (PLM_PACKET)
636 QQ_PopHead (&pDevice->TxPacketFreeQ.Container);
638 if (pPacket == 0) {
639 pUmDevice->tx_full = 1;
640 printf ("bcm570xEndSend: TX full!\n");
641 return 0;
644 if (pDevice->SendBdLeft.counter == 0) {
645 pUmDevice->tx_full = 1;
646 printf ("bcm570xEndSend: no more TX descriptors!\n");
647 QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
648 return 0;
651 if (length <= 0) {
652 printf ("eth: bad packet size: %d\n", length);
653 goto out;
656 /* Get packet buffers and fragment list */
657 pUmPacket = (PUM_PACKET) pPacket;
658 /* Single DMA Descriptor transmit.
659 * Fragments may be provided, but one DMA descriptor max is
660 * used to send the packet.
662 if (MM_CoalesceTxBuffer (pDevice, pPacket) != LM_STATUS_SUCCESS) {
663 if (pUmPacket->skbuff == NULL) {
664 /* Packet was discarded */
665 printf ("TX: failed (1)\n");
666 status = 1;
667 } else {
668 printf ("TX: failed (2)\n");
669 status = 2;
671 QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
672 return status;
675 /* Copy packet to DMA buffer */
676 memset (pUmPacket->skbuff, 0x0, MAX_PACKET_SIZE);
677 memcpy ((void *)pUmPacket->skbuff, (void *)packet, length);
678 pPacket->PacketSize = length;
679 pPacket->Flags |= SND_BD_FLAG_END | SND_BD_FLAG_COAL_NOW;
680 pPacket->u.Tx.FragCount = 1;
681 /* We've already provided a frame ready for transmission */
682 pPacket->Flags &= ~SND_BD_FLAG_TCP_UDP_CKSUM;
684 if (LM_SendPacket (pDevice, pPacket) == LM_STATUS_FAILURE) {
686 * A lower level send failure will push the packet descriptor back
687 * in the free queue, so just deal with the VxWorks clusters.
689 if (pUmPacket->skbuff == NULL) {
690 printf ("TX failed (1)!\n");
691 /* Packet was discarded */
692 status = 3;
693 } else {
694 /* A resource problem ... */
695 printf ("TX failed (2)!\n");
696 status = 4;
699 if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) == 0) {
700 printf ("TX: emptyQ!\n");
701 pUmDevice->tx_full = 1;
705 while (pUmDevice->tx_pkt == 0) {
706 /* Service TX */
707 eth_isr ();
709 #if ET_DEBUG
710 printf ("eth_send: 0x%x, %d bytes\n"
711 "[%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x] ...\n",
712 (int)pPacket, length,
713 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5],
714 ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12],
715 ptr[13], ptr[14], ptr[15]);
716 #endif
717 pUmDevice->tx_pkt = 0;
718 QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
720 /* Done with send */
721 out:
722 return status;
725 /* Ethernet receive */
726 int eth_rx (void)
728 PLM_PACKET pPacket = NULL;
729 PUM_PACKET pUmPacket = NULL;
730 void *skb;
731 int size = 0;
733 while (TRUE) {
735 bcm570x_service_isr:
736 /* Pull down packet if it is there */
737 eth_isr ();
739 /* Indicate RX packets called */
740 if (pUmDevice->rx_pkt) {
741 /* printf("eth_rx: got a packet...\n"); */
742 pUmDevice->rx_pkt = 0;
743 } else {
744 /* printf("eth_rx: waiting for packet...\n"); */
745 goto bcm570x_service_isr;
748 pPacket = (PLM_PACKET)
749 QQ_PopHead (&pDevice->RxPacketReceivedQ.Container);
751 if (pPacket == 0) {
752 printf ("eth_rx: empty packet!\n");
753 goto bcm570x_service_isr;
756 pUmPacket = (PUM_PACKET) pPacket;
757 #if ET_DEBUG
758 printf ("eth_rx: packet @0x%x\n", (int)pPacket);
759 #endif
760 /* If the packet generated an error, reuse buffer */
761 if ((pPacket->PacketStatus != LM_STATUS_SUCCESS) ||
762 ((size = pPacket->PacketSize) > pDevice->RxMtu)) {
764 /* reuse skb */
765 QQ_PushTail (&pDevice->RxPacketFreeQ.Container,
766 pPacket);
767 printf ("eth_rx: error in packet dma!\n");
768 goto bcm570x_service_isr;
771 /* Set size and address */
772 skb = pUmPacket->skbuff;
773 size = pPacket->PacketSize;
775 /* Pass the packet up to the protocol
776 * layers.
778 NetReceive (skb, size);
780 /* Free packet buffer */
781 bcm570xPktFree (pUmDevice->index, skb);
782 pUmPacket->skbuff = NULL;
784 /* Reuse SKB */
785 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
787 return 0; /* Got a packet, bail ... */
789 return size;
792 /* Shut down device */
793 void eth_halt (void)
795 int i;
796 if (initialized)
797 if (pDevice && pUmDevice && pUmDevice->opened) {
798 printf ("\neth%d:%s,", pUmDevice->index,
799 pUmDevice->name);
800 printf ("HALT,");
801 /* stop device */
802 LM_Halt (pDevice);
803 printf ("POWER DOWN,");
804 LM_SetPowerState (pDevice, LM_POWER_STATE_D3);
806 /* Free the memory allocated by the device in tigon3 */
807 for (i = 0; i < pUmDevice->mem_list_num; i++) {
808 if (pUmDevice->mem_list[i]) {
809 /* sanity check */
810 if (pUmDevice->dma_list[i]) { /* cache-safe memory */
811 free (pUmDevice->mem_list[i]);
812 } else {
813 free (pUmDevice->mem_list[i]); /* normal memory */
817 pUmDevice->opened = 0;
818 free (pDevice);
819 pDevice = NULL;
820 pUmDevice = NULL;
821 initialized = 0;
822 printf ("done - offline.\n");
828 * Middle Module: Interface between the HW driver (tigon3 modules) and
829 * the native (SENS) driver. These routines implement the system
830 * interface for tigon3 on VxWorks.
833 /* Middle module dependency - size of a packet descriptor */
834 int MM_Packet_Desc_Size = sizeof (UM_PACKET);
836 LM_STATUS
837 MM_ReadConfig32 (PLM_DEVICE_BLOCK pDevice,
838 LM_UINT32 Offset, LM_UINT32 * pValue32)
840 UM_DEVICE_BLOCK *pUmDevice;
841 pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
842 pci_read_config_dword (pUmDevice->pdev, Offset, (u32 *) pValue32);
843 return LM_STATUS_SUCCESS;
846 LM_STATUS
847 MM_WriteConfig32 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT32 Value32)
849 UM_DEVICE_BLOCK *pUmDevice;
850 pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
851 pci_write_config_dword (pUmDevice->pdev, Offset, Value32);
852 return LM_STATUS_SUCCESS;
855 LM_STATUS
856 MM_ReadConfig16 (PLM_DEVICE_BLOCK pDevice,
857 LM_UINT32 Offset, LM_UINT16 * pValue16)
859 UM_DEVICE_BLOCK *pUmDevice;
860 pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
861 pci_read_config_word (pUmDevice->pdev, Offset, (u16 *) pValue16);
862 return LM_STATUS_SUCCESS;
865 LM_STATUS
866 MM_WriteConfig16 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT16 Value16)
868 UM_DEVICE_BLOCK *pUmDevice;
869 pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
870 pci_write_config_word (pUmDevice->pdev, Offset, Value16);
871 return LM_STATUS_SUCCESS;
874 LM_STATUS
875 MM_AllocateSharedMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
876 PLM_VOID * pMemoryBlockVirt,
877 PLM_PHYSICAL_ADDRESS pMemoryBlockPhy, LM_BOOL Cached)
879 PLM_VOID pvirt;
880 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
881 dma_addr_t mapping;
883 pvirt = malloc (BlockSize);
884 mapping = (dma_addr_t) (pvirt);
885 if (!pvirt)
886 return LM_STATUS_FAILURE;
888 pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
889 pUmDevice->dma_list[pUmDevice->mem_list_num] = mapping;
890 pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
891 memset (pvirt, 0, BlockSize);
893 *pMemoryBlockVirt = (PLM_VOID) pvirt;
894 MM_SetAddr (pMemoryBlockPhy, (dma_addr_t) mapping);
896 return LM_STATUS_SUCCESS;
899 LM_STATUS
900 MM_AllocateMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
901 PLM_VOID * pMemoryBlockVirt)
903 PLM_VOID pvirt;
904 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
906 pvirt = malloc (BlockSize);
908 if (!pvirt)
909 return LM_STATUS_FAILURE;
911 pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
912 pUmDevice->dma_list[pUmDevice->mem_list_num] = 0;
913 pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
914 memset (pvirt, 0, BlockSize);
915 *pMemoryBlockVirt = pvirt;
917 return LM_STATUS_SUCCESS;
920 LM_STATUS MM_MapMemBase (PLM_DEVICE_BLOCK pDevice)
922 printf ("BCM570x PCI Memory base address @0x%x\n",
923 (unsigned int)pDevice->pMappedMemBase);
924 return LM_STATUS_SUCCESS;
927 LM_STATUS MM_InitializeUmPackets (PLM_DEVICE_BLOCK pDevice)
929 int i;
930 void *skb;
931 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
932 PUM_PACKET pUmPacket = NULL;
933 PLM_PACKET pPacket = NULL;
935 for (i = 0; i < pDevice->RxPacketDescCnt; i++) {
936 pPacket = QQ_PopHead (&pDevice->RxPacketFreeQ.Container);
937 pUmPacket = (PUM_PACKET) pPacket;
939 if (pPacket == 0) {
940 printf ("MM_InitializeUmPackets: Bad RxPacketFreeQ\n");
943 skb = bcm570xPktAlloc (pUmDevice->index,
944 pPacket->u.Rx.RxBufferSize + 2);
946 if (skb == 0) {
947 pUmPacket->skbuff = 0;
948 QQ_PushTail (&pUmDevice->rx_out_of_buf_q.Container,
949 pPacket);
950 printf ("MM_InitializeUmPackets: out of buffer.\n");
951 continue;
954 pUmPacket->skbuff = skb;
955 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
958 pUmDevice->rx_low_buf_thresh = pDevice->RxPacketDescCnt / 8;
960 return LM_STATUS_SUCCESS;
963 LM_STATUS MM_GetConfig (PLM_DEVICE_BLOCK pDevice)
965 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
966 int index = pDevice->index;
968 if (auto_speed[index] == 0)
969 pDevice->DisableAutoNeg = TRUE;
970 else
971 pDevice->DisableAutoNeg = FALSE;
973 if (line_speed[index] == 0) {
974 pDevice->RequestedMediaType = LM_REQUESTED_MEDIA_TYPE_AUTO;
975 pDevice->DisableAutoNeg = FALSE;
976 } else {
977 if (line_speed[index] == 1000) {
978 if (pDevice->EnableTbi) {
979 pDevice->RequestedMediaType =
980 LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX;
981 } else if (full_duplex[index]) {
982 pDevice->RequestedMediaType =
983 LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX;
984 } else {
985 pDevice->RequestedMediaType =
986 LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS;
988 if (!pDevice->EnableTbi)
989 pDevice->DisableAutoNeg = FALSE;
990 } else if (line_speed[index] == 100) {
991 if (full_duplex[index]) {
992 pDevice->RequestedMediaType =
993 LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX;
994 } else {
995 pDevice->RequestedMediaType =
996 LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS;
998 } else if (line_speed[index] == 10) {
999 if (full_duplex[index]) {
1000 pDevice->RequestedMediaType =
1001 LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX;
1002 } else {
1003 pDevice->RequestedMediaType =
1004 LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS;
1006 } else {
1007 pDevice->RequestedMediaType =
1008 LM_REQUESTED_MEDIA_TYPE_AUTO;
1009 pDevice->DisableAutoNeg = FALSE;
1013 pDevice->FlowControlCap = 0;
1014 if (rx_flow_control[index] != 0) {
1015 pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
1017 if (tx_flow_control[index] != 0) {
1018 pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
1020 if ((auto_flow_control[index] != 0) &&
1021 (pDevice->DisableAutoNeg == FALSE)) {
1023 pDevice->FlowControlCap |= LM_FLOW_CONTROL_AUTO_PAUSE;
1024 if ((tx_flow_control[index] == 0) &&
1025 (rx_flow_control[index] == 0)) {
1026 pDevice->FlowControlCap |=
1027 LM_FLOW_CONTROL_TRANSMIT_PAUSE |
1028 LM_FLOW_CONTROL_RECEIVE_PAUSE;
1032 /* Default MTU for now */
1033 pUmDevice->mtu = 1500;
1035 #if T3_JUMBO_RCV_RCB_ENTRY_COUNT
1036 if (pUmDevice->mtu > 1500) {
1037 pDevice->RxMtu = pUmDevice->mtu;
1038 pDevice->RxJumboDescCnt = DEFAULT_JUMBO_RCV_DESC_COUNT;
1039 } else {
1040 pDevice->RxJumboDescCnt = 0;
1042 pDevice->RxJumboDescCnt = rx_jumbo_desc_cnt[index];
1043 #else
1044 pDevice->RxMtu = pUmDevice->mtu;
1045 #endif
1047 if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
1048 pDevice->UseTaggedStatus = TRUE;
1049 pUmDevice->timer_interval = CONFIG_SYS_HZ;
1050 } else {
1051 pUmDevice->timer_interval = CONFIG_SYS_HZ / 50;
1054 pDevice->TxPacketDescCnt = tx_pkt_desc_cnt[index];
1055 pDevice->RxStdDescCnt = rx_std_desc_cnt[index];
1056 /* Note: adaptive coalescence really isn't adaptive in this driver */
1057 pUmDevice->rx_adaptive_coalesce = rx_adaptive_coalesce[index];
1058 if (!pUmDevice->rx_adaptive_coalesce) {
1059 pDevice->RxCoalescingTicks = rx_coalesce_ticks[index];
1060 if (pDevice->RxCoalescingTicks > MAX_RX_COALESCING_TICKS)
1061 pDevice->RxCoalescingTicks = MAX_RX_COALESCING_TICKS;
1062 pUmDevice->rx_curr_coalesce_ticks = pDevice->RxCoalescingTicks;
1064 pDevice->RxMaxCoalescedFrames = rx_max_coalesce_frames[index];
1065 if (pDevice->RxMaxCoalescedFrames > MAX_RX_MAX_COALESCED_FRAMES)
1066 pDevice->RxMaxCoalescedFrames =
1067 MAX_RX_MAX_COALESCED_FRAMES;
1068 pUmDevice->rx_curr_coalesce_frames =
1069 pDevice->RxMaxCoalescedFrames;
1070 pDevice->StatsCoalescingTicks = stats_coalesce_ticks[index];
1071 if (pDevice->StatsCoalescingTicks > MAX_STATS_COALESCING_TICKS)
1072 pDevice->StatsCoalescingTicks =
1073 MAX_STATS_COALESCING_TICKS;
1074 } else {
1075 pUmDevice->rx_curr_coalesce_frames =
1076 DEFAULT_RX_MAX_COALESCED_FRAMES;
1077 pUmDevice->rx_curr_coalesce_ticks = DEFAULT_RX_COALESCING_TICKS;
1079 pDevice->TxCoalescingTicks = tx_coalesce_ticks[index];
1080 if (pDevice->TxCoalescingTicks > MAX_TX_COALESCING_TICKS)
1081 pDevice->TxCoalescingTicks = MAX_TX_COALESCING_TICKS;
1082 pDevice->TxMaxCoalescedFrames = tx_max_coalesce_frames[index];
1083 if (pDevice->TxMaxCoalescedFrames > MAX_TX_MAX_COALESCED_FRAMES)
1084 pDevice->TxMaxCoalescedFrames = MAX_TX_MAX_COALESCED_FRAMES;
1086 if (enable_wol[index]) {
1087 pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET;
1088 pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET;
1090 pDevice->NicSendBd = TRUE;
1092 /* Don't update status blocks during interrupt */
1093 pDevice->RxCoalescingTicksDuringInt = 0;
1094 pDevice->TxCoalescingTicksDuringInt = 0;
1096 return LM_STATUS_SUCCESS;
1100 LM_STATUS MM_StartTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1102 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1103 printf ("Start TX DMA: dev=%d packet @0x%x\n",
1104 (int)pUmDevice->index, (unsigned int)pPacket);
1106 return LM_STATUS_SUCCESS;
1109 LM_STATUS MM_CompleteTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1111 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1112 printf ("Complete TX DMA: dev=%d packet @0x%x\n",
1113 (int)pUmDevice->index, (unsigned int)pPacket);
1114 return LM_STATUS_SUCCESS;
1117 LM_STATUS MM_IndicateStatus (PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
1119 char buf[128];
1120 char lcd[4];
1121 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1122 LM_FLOW_CONTROL flow_control;
1124 pUmDevice->delayed_link_ind = 0;
1125 memset (lcd, 0x0, 4);
1127 if (Status == LM_STATUS_LINK_DOWN) {
1128 sprintf (buf, "eth%d: %s: NIC Link is down\n",
1129 pUmDevice->index, pUmDevice->name);
1130 lcd[0] = 'L';
1131 lcd[1] = 'N';
1132 lcd[2] = 'K';
1133 lcd[3] = '?';
1134 } else if (Status == LM_STATUS_LINK_ACTIVE) {
1135 sprintf (buf, "eth%d:%s: ", pUmDevice->index, pUmDevice->name);
1137 if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) {
1138 strcat (buf, "1000 Mbps ");
1139 lcd[0] = '1';
1140 lcd[1] = 'G';
1141 lcd[2] = 'B';
1142 } else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS) {
1143 strcat (buf, "100 Mbps ");
1144 lcd[0] = '1';
1145 lcd[1] = '0';
1146 lcd[2] = '0';
1147 } else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) {
1148 strcat (buf, "10 Mbps ");
1149 lcd[0] = '1';
1150 lcd[1] = '0';
1151 lcd[2] = ' ';
1153 if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) {
1154 strcat (buf, "full duplex");
1155 lcd[3] = 'F';
1156 } else {
1157 strcat (buf, "half duplex");
1158 lcd[3] = 'H';
1160 strcat (buf, " link up");
1162 flow_control = pDevice->FlowControl &
1163 (LM_FLOW_CONTROL_RECEIVE_PAUSE |
1164 LM_FLOW_CONTROL_TRANSMIT_PAUSE);
1166 if (flow_control) {
1167 if (flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE) {
1168 strcat (buf, ", receive ");
1169 if (flow_control &
1170 LM_FLOW_CONTROL_TRANSMIT_PAUSE)
1171 strcat (buf, " & transmit ");
1172 } else {
1173 strcat (buf, ", transmit ");
1175 strcat (buf, "flow control ON");
1176 } else {
1177 strcat (buf, ", flow control OFF");
1179 strcat (buf, "\n");
1180 printf ("%s", buf);
1182 #if 0
1183 sysLedDsply (lcd[0], lcd[1], lcd[2], lcd[3]);
1184 #endif
1185 return LM_STATUS_SUCCESS;
1188 LM_STATUS MM_FreeRxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1191 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1192 PUM_PACKET pUmPacket;
1193 void *skb;
1195 pUmPacket = (PUM_PACKET) pPacket;
1197 if ((skb = pUmPacket->skbuff))
1198 bcm570xPktFree (pUmDevice->index, skb);
1200 pUmPacket->skbuff = 0;
1202 return LM_STATUS_SUCCESS;
1205 unsigned long MM_AnGetCurrentTime_us (PAN_STATE_INFO pAnInfo)
1207 return get_timer (0);
1211 * Transform an MBUF chain into a single MBUF.
1212 * This routine will fail if the amount of data in the
1213 * chain overflows a transmit buffer. In that case,
1214 * the incoming MBUF chain will be freed. This routine can
1215 * also fail by not being able to allocate a new MBUF (including
1216 * cluster and mbuf headers). In that case the failure is
1217 * non-fatal. The incoming cluster chain is not freed, giving
1218 * the caller the choice of whether to try a retransmit later.
1220 LM_STATUS MM_CoalesceTxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1222 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1223 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1224 void *skbnew;
1225 int len = 0;
1227 if (len == 0)
1228 return (LM_STATUS_SUCCESS);
1230 if (len > MAX_PACKET_SIZE) {
1231 printf ("eth%d: xmit frame discarded, too big!, size = %d\n",
1232 pUmDevice->index, len);
1233 return (LM_STATUS_FAILURE);
1236 skbnew = bcm570xPktAlloc (pUmDevice->index, MAX_PACKET_SIZE);
1238 if (skbnew == NULL) {
1239 pUmDevice->tx_full = 1;
1240 printf ("eth%d: out of transmit buffers", pUmDevice->index);
1241 return (LM_STATUS_FAILURE);
1244 /* New packet values */
1245 pUmPacket->skbuff = skbnew;
1246 pUmPacket->lm_packet.u.Tx.FragCount = 1;
1248 return (LM_STATUS_SUCCESS);
1251 LM_STATUS MM_IndicateRxPackets (PLM_DEVICE_BLOCK pDevice)
1253 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1254 pUmDevice->rx_pkt = 1;
1255 return LM_STATUS_SUCCESS;
1258 LM_STATUS MM_IndicateTxPackets (PLM_DEVICE_BLOCK pDevice)
1260 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1261 PLM_PACKET pPacket;
1262 PUM_PACKET pUmPacket;
1263 void *skb;
1264 while (TRUE) {
1266 pPacket = (PLM_PACKET)
1267 QQ_PopHead (&pDevice->TxPacketXmittedQ.Container);
1269 if (pPacket == 0)
1270 break;
1272 pUmPacket = (PUM_PACKET) pPacket;
1273 skb = (void *)pUmPacket->skbuff;
1276 * Free MBLK if we transmitted a fragmented packet or a
1277 * non-fragmented packet straight from the VxWorks
1278 * buffer pool. If packet was copied to a local transmit
1279 * buffer, then there's no MBUF to free, just free
1280 * the transmit buffer back to the cluster pool.
1283 if (skb)
1284 bcm570xPktFree (pUmDevice->index, skb);
1286 pUmPacket->skbuff = 0;
1287 QQ_PushTail (&pDevice->TxPacketFreeQ.Container, pPacket);
1288 pUmDevice->tx_pkt = 1;
1290 if (pUmDevice->tx_full) {
1291 if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) >=
1292 (QQ_GetSize (&pDevice->TxPacketFreeQ.Container) >> 1))
1293 pUmDevice->tx_full = 0;
1295 return LM_STATUS_SUCCESS;
1299 * Scan an MBUF chain until we reach fragment number "frag"
1300 * Return its length and physical address.
1302 void MM_MapTxDma
1303 (PLM_DEVICE_BLOCK pDevice,
1304 struct _LM_PACKET *pPacket,
1305 T3_64BIT_HOST_ADDR * paddr, LM_UINT32 * len, int frag) {
1306 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1307 *len = pPacket->PacketSize;
1308 MM_SetT3Addr (paddr, (dma_addr_t) pUmPacket->skbuff);
1312 * Convert an mbuf address, a CPU local virtual address,
1313 * to a physical address as seen from a PCI device. Store the
1314 * result at paddr.
1316 void MM_MapRxDma (PLM_DEVICE_BLOCK pDevice,
1317 struct _LM_PACKET *pPacket, T3_64BIT_HOST_ADDR * paddr)
1319 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1320 MM_SetT3Addr (paddr, (dma_addr_t) pUmPacket->skbuff);
1323 void MM_SetAddr (LM_PHYSICAL_ADDRESS * paddr, dma_addr_t addr)
1325 #if (BITS_PER_LONG == 64)
1326 paddr->High = ((unsigned long)addr) >> 32;
1327 paddr->Low = ((unsigned long)addr) & 0xffffffff;
1328 #else
1329 paddr->High = 0;
1330 paddr->Low = (unsigned long)addr;
1331 #endif
1334 void MM_SetT3Addr (T3_64BIT_HOST_ADDR * paddr, dma_addr_t addr)
1336 unsigned long baddr = (unsigned long)addr;
1337 #if (BITS_PER_LONG == 64)
1338 set_64bit_addr (paddr, baddr & 0xffffffff, baddr >> 32);
1339 #else
1340 set_64bit_addr (paddr, baddr, 0);
1341 #endif
1345 * This combination of `inline' and `extern' has almost the effect of a
1346 * macro. The way to use it is to put a function definition in a header
1347 * file with these keywords, and put another copy of the definition
1348 * (lacking `inline' and `extern') in a library file. The definition in
1349 * the header file will cause most calls to the function to be inlined.
1350 * If any uses of the function remain, they will refer to the single copy
1351 * in the library.
1353 void atomic_set (atomic_t * entry, int val)
1355 entry->counter = val;
1358 int atomic_read (atomic_t * entry)
1360 return entry->counter;
1363 void atomic_inc (atomic_t * entry)
1365 if (entry)
1366 entry->counter++;
1369 void atomic_dec (atomic_t * entry)
1371 if (entry)
1372 entry->counter--;
1375 void atomic_sub (int a, atomic_t * entry)
1377 if (entry)
1378 entry->counter -= a;
1381 void atomic_add (int a, atomic_t * entry)
1383 if (entry)
1384 entry->counter += a;
1387 /******************************************************************************/
1388 /* Description: */
1389 /* */
1390 /* Return: */
1391 /******************************************************************************/
1392 void QQ_InitQueue (PQQ_CONTAINER pQueue, unsigned int QueueSize)
1394 pQueue->Head = 0;
1395 pQueue->Tail = 0;
1396 pQueue->Size = QueueSize + 1;
1397 atomic_set (&pQueue->EntryCnt, 0);
1398 } /* QQ_InitQueue */
1400 /******************************************************************************/
1401 /* Description: */
1402 /* */
1403 /* Return: */
1404 /******************************************************************************/
1405 char QQ_Full (PQQ_CONTAINER pQueue)
1407 unsigned int NewHead;
1409 NewHead = (pQueue->Head + 1) % pQueue->Size;
1411 return (NewHead == pQueue->Tail);
1412 } /* QQ_Full */
1414 /******************************************************************************/
1415 /* Description: */
1416 /* */
1417 /* Return: */
1418 /******************************************************************************/
1419 char QQ_Empty (PQQ_CONTAINER pQueue)
1421 return (pQueue->Head == pQueue->Tail);
1422 } /* QQ_Empty */
1424 /******************************************************************************/
1425 /* Description: */
1426 /* */
1427 /* Return: */
1428 /******************************************************************************/
1429 unsigned int QQ_GetSize (PQQ_CONTAINER pQueue)
1431 return pQueue->Size;
1432 } /* QQ_GetSize */
1434 /******************************************************************************/
1435 /* Description: */
1436 /* */
1437 /* Return: */
1438 /******************************************************************************/
1439 unsigned int QQ_GetEntryCnt (PQQ_CONTAINER pQueue)
1441 return atomic_read (&pQueue->EntryCnt);
1442 } /* QQ_GetEntryCnt */
1444 /******************************************************************************/
1445 /* Description: */
1446 /* */
1447 /* Return: */
1448 /* TRUE entry was added successfully. */
1449 /* FALSE queue is full. */
1450 /******************************************************************************/
1451 char QQ_PushHead (PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)
1453 unsigned int Head;
1455 Head = (pQueue->Head + 1) % pQueue->Size;
1457 #if !defined(QQ_NO_OVERFLOW_CHECK)
1458 if (Head == pQueue->Tail) {
1459 return 0;
1460 } /* if */
1461 #endif /* QQ_NO_OVERFLOW_CHECK */
1463 pQueue->Array[pQueue->Head] = pEntry;
1464 wmb ();
1465 pQueue->Head = Head;
1466 atomic_inc (&pQueue->EntryCnt);
1468 return -1;
1469 } /* QQ_PushHead */
1471 /******************************************************************************/
1472 /* Description: */
1473 /* */
1474 /* Return: */
1475 /* TRUE entry was added successfully. */
1476 /* FALSE queue is full. */
1477 /******************************************************************************/
1478 char QQ_PushTail (PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)
1480 unsigned int Tail;
1482 Tail = pQueue->Tail;
1483 if (Tail == 0) {
1484 Tail = pQueue->Size;
1485 } /* if */
1486 Tail--;
1488 #if !defined(QQ_NO_OVERFLOW_CHECK)
1489 if (Tail == pQueue->Head) {
1490 return 0;
1491 } /* if */
1492 #endif /* QQ_NO_OVERFLOW_CHECK */
1494 pQueue->Array[Tail] = pEntry;
1495 wmb ();
1496 pQueue->Tail = Tail;
1497 atomic_inc (&pQueue->EntryCnt);
1499 return -1;
1500 } /* QQ_PushTail */
1502 /******************************************************************************/
1503 /* Description: */
1504 /* */
1505 /* Return: */
1506 /******************************************************************************/
1507 PQQ_ENTRY QQ_PopHead (PQQ_CONTAINER pQueue)
1509 unsigned int Head;
1510 PQQ_ENTRY Entry;
1512 Head = pQueue->Head;
1514 #if !defined(QQ_NO_UNDERFLOW_CHECK)
1515 if (Head == pQueue->Tail) {
1516 return (PQQ_ENTRY) 0;
1517 } /* if */
1518 #endif /* QQ_NO_UNDERFLOW_CHECK */
1520 if (Head == 0) {
1521 Head = pQueue->Size;
1522 } /* if */
1523 Head--;
1525 Entry = pQueue->Array[Head];
1526 membar ();
1528 pQueue->Head = Head;
1529 atomic_dec (&pQueue->EntryCnt);
1531 return Entry;
1532 } /* QQ_PopHead */
1534 /******************************************************************************/
1535 /* Description: */
1536 /* */
1537 /* Return: */
1538 /******************************************************************************/
1539 PQQ_ENTRY QQ_PopTail (PQQ_CONTAINER pQueue)
1541 unsigned int Tail;
1542 PQQ_ENTRY Entry;
1544 Tail = pQueue->Tail;
1546 #if !defined(QQ_NO_UNDERFLOW_CHECK)
1547 if (Tail == pQueue->Head) {
1548 return (PQQ_ENTRY) 0;
1549 } /* if */
1550 #endif /* QQ_NO_UNDERFLOW_CHECK */
1552 Entry = pQueue->Array[Tail];
1553 membar ();
1554 pQueue->Tail = (Tail + 1) % pQueue->Size;
1555 atomic_dec (&pQueue->EntryCnt);
1557 return Entry;
1558 } /* QQ_PopTail */
1560 /******************************************************************************/
1561 /* Description: */
1562 /* */
1563 /* Return: */
1564 /******************************************************************************/
1565 PQQ_ENTRY QQ_GetHead (PQQ_CONTAINER pQueue, unsigned int Idx)
1567 if (Idx >= atomic_read (&pQueue->EntryCnt)) {
1568 return (PQQ_ENTRY) 0;
1571 if (pQueue->Head > Idx) {
1572 Idx = pQueue->Head - Idx;
1573 } else {
1574 Idx = pQueue->Size - (Idx - pQueue->Head);
1576 Idx--;
1578 return pQueue->Array[Idx];
1581 /******************************************************************************/
1582 /* Description: */
1583 /* */
1584 /* Return: */
1585 /******************************************************************************/
1586 PQQ_ENTRY QQ_GetTail (PQQ_CONTAINER pQueue, unsigned int Idx)
1588 if (Idx >= atomic_read (&pQueue->EntryCnt)) {
1589 return (PQQ_ENTRY) 0;
1592 Idx += pQueue->Tail;
1593 if (Idx >= pQueue->Size) {
1594 Idx = Idx - pQueue->Size;
1597 return pQueue->Array[Idx];