]> git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/net/bcm570x.c
c250d446f14528cea4a45ade0f972eccbc34956b
[people/ms/u-boot.git] / drivers / net / 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 #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>
17
18 /*
19 * PCI Registers and definitions.
20 */
21 #define PCI_CMD_MASK 0xffff0000 /* mask to save status bits */
22 #define PCI_ANY_ID (~0)
23
24 /*
25 * PCI memory base for Ethernet device as well as device Interrupt.
26 */
27 #define BCM570X_MBAR 0x80100000
28 #define BCM570X_ILINE 1
29
30 #define SECOND_USEC 1000000
31 #define MAX_PACKET_SIZE 1600
32 #define MAX_UNITS 4
33
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;
39
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 };
49
50 #if JUMBO_FRAMES
51 /* Jumbo MTU for interfaces. */
52 static int mtu[MAX_UNITS] = { 0, 0, 0, 0 };
53 #endif
54
55 /* Turn on Wake-on lan for a device unit */
56 static int enable_wol[MAX_UNITS] = { 0, 0, 0, 0 };
57
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 };
61
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 };
65
66 static unsigned int rx_adaptive_coalesce[MAX_UNITS] = { 1, 1, 1, 1 };
67
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 };
76
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 };
80
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 };
84
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 };
88
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 };
92
93 /*
94 * Legitimate values for BCM570x device types
95 */
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;
128
129 /* Chip-Rev names for each device-type */
130 static struct {
131 char *name;
132 } chip_rev[] = {
133 {
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"}, {
164 0}
165 };
166
167 /* indexed by board_t, above */
168 static struct {
169 char *name;
170 } board_info[] = {
171 {
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},};
203
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[] = {
212 {
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}
264 };
265
266 #define n570xDevices (sizeof(bcm570xDevices)/sizeof(bcm570xDevices[0]))
267
268 /*
269 * Allocate a packet buffer from the bcm570x packet pool.
270 */
271 void *bcm570xPktAlloc (int u, int pksize)
272 {
273 return malloc (pksize);
274 }
275
276 /*
277 * Free a packet previously allocated from the bcm570x packet
278 * buffer pool.
279 */
280 void bcm570xPktFree (int u, void *p)
281 {
282 free (p);
283 }
284
285 int bcm570xReplenishRxBuffers (PUM_DEVICE_BLOCK pUmDevice)
286 {
287 PLM_PACKET pPacket;
288 PUM_PACKET pUmPacket;
289 void *skb;
290 int queue_rx = 0;
291 int ret = 0;
292
293 while ((pUmPacket = (PUM_PACKET)
294 QQ_PopHead (&pUmDevice->rx_out_of_buf_q.Container)) != 0) {
295
296 pPacket = (PLM_PACKET) pUmPacket;
297
298 /* reuse an old skb */
299 if (pUmPacket->skbuff) {
300 QQ_PushTail (&pDevice->RxPacketFreeQ.Container,
301 pPacket);
302 queue_rx = 1;
303 continue;
304 }
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;
313 }
314
315 pUmPacket->skbuff = skb;
316 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
317 queue_rx = 1;
318 }
319
320 if (queue_rx) {
321 LM_QueueRxPackets (pDevice);
322 }
323
324 return ret;
325 }
326
327 /*
328 * Probe, Map, and Init 570x device.
329 */
330 int eth_init (bd_t * bis)
331 {
332 int i, rv, devFound = FALSE;
333 pci_dev_t devbusfn;
334 unsigned short status;
335
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 {
343
344 /* Set ILINE */
345 pci_write_config_byte (devbusfn,
346 PCI_INTERRUPT_LINE,
347 BCM570X_ILINE);
348
349 /*
350 * 0x10 - 0x14 define one 64-bit MBAR.
351 * 0x14 is the higher-order address bits of the BAR.
352 */
353 pci_write_config_dword (devbusfn,
354 PCI_BASE_ADDRESS_1, 0);
355
356 ioBase = BCM570X_MBAR;
357
358 pci_write_config_dword (devbusfn,
359 PCI_BASE_ADDRESS_0, ioBase);
360
361 /*
362 * Enable PCI memory, IO, and Master -- don't
363 * reset any status bits in doing so.
364 */
365 pci_read_config_word (devbusfn, PCI_COMMAND, &status);
366
367 status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
368
369 pci_write_config_word (devbusfn, PCI_COMMAND, status);
370
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);
376
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));
382 }
383
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;
391 }
392 }
393
394 if (!devFound) {
395 printf
396 ("eth_init: FAILURE: no BCM570x Ethernet devices found.\n");
397 return -1;
398 }
399
400 /* Setup defaults for chip */
401 pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
402
403 if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) {
404 pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
405 } else {
406
407 if (rx_checksum[i]) {
408 pDevice->TaskToOffload |=
409 LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
410 LM_TASK_OFFLOAD_RX_UDP_CHECKSUM;
411 }
412
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;
418 }
419 }
420
421 /* Set Device PCI Memory base address */
422 pDevice->pMappedMemBase = (PLM_UINT8) ioBase;
423
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;
428 }
429
430 /* Lock not needed */
431 pUmDevice->do_global_lock = 0;
432
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;
437 }
438
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;
445 }
446
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);
452
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;
459
460 /* delay for 4 seconds */
461 pUmDevice->delayed_link_ind = (4 * CONFIG_SYS_HZ) / pUmDevice->timer_interval;
462
463 pUmDevice->adaptive_expiry = CONFIG_SYS_HZ / pUmDevice->timer_interval;
464
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;
470
471 /* Initialize 570x */
472 if (LM_InitializeAdapter (pDevice) != LM_STATUS_SUCCESS) {
473 printf ("ERROR: Adapter initialization failed.\n");
474 return ERROR;
475 }
476
477 /* Enable chip ISR */
478 LM_EnableInterrupt (pDevice);
479
480 /* Clear MC table */
481 LM_MulticastClear (pDevice);
482
483 /* Enable Multicast */
484 LM_SetReceiveMask (pDevice,
485 pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST);
486
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]);
496 }
497 printf ("\n");
498
499 printf ("eth%d: ", pDevice->index);
500 printf ("%s with ", chip_rev[bcm570xDevices[i].board_id].name);
501
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");
519
520 printf ("eth%d: %s, MTU: %d,",
521 pDevice->index, pDevice->BusSpeedStr, 1500);
522
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++;
528
529 return 0;
530 }
531
532 /* Ethernet Interrupt service routine */
533 void eth_isr (void)
534 {
535 LM_UINT32 oldtag, newtag;
536 int i;
537
538 pUmDevice->interrupt = 1;
539
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;
545
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);
559 }
560 break;
561 }
562 oldtag = newtag;
563 }
564 }
565 } else {
566 while (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) {
567 unsigned int dummy;
568
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;
575 }
576 }
577
578 /* Allocate new RX buffers */
579 if (QQ_GetEntryCnt (&pUmDevice->rx_out_of_buf_q.Container)) {
580 bcm570xReplenishRxBuffers (pUmDevice);
581 }
582
583 /* Queue packets */
584 if (QQ_GetEntryCnt (&pDevice->RxPacketFreeQ.Container)) {
585 LM_QueueRxPackets (pDevice);
586 }
587
588 if (pUmDevice->tx_queued) {
589 pUmDevice->tx_queued = 0;
590 }
591
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;
597 }
598 }
599
600 pUmDevice->interrupt = 0;
601
602 }
603
604 int eth_send (volatile void *packet, int length)
605 {
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;
612
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 ();
620
621 /* Wait to see link for one-half a second before sending ... */
622 udelay (1500000);
623
624 }
625
626 /* Clear sent flag */
627 pUmDevice->tx_pkt = 0;
628
629 /* Previously blocked */
630 if (pUmDevice->tx_full) {
631 printf ("eth%d: tx blocked.\n", pUmDevice->index);
632 return 0;
633 }
634
635 pPacket = (PLM_PACKET)
636 QQ_PopHead (&pDevice->TxPacketFreeQ.Container);
637
638 if (pPacket == 0) {
639 pUmDevice->tx_full = 1;
640 printf ("bcm570xEndSend: TX full!\n");
641 return 0;
642 }
643
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;
649 }
650
651 if (length <= 0) {
652 printf ("eth: bad packet size: %d\n", length);
653 goto out;
654 }
655
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.
661 */
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;
670 }
671 QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
672 return status;
673 }
674
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;
683
684 if (LM_SendPacket (pDevice, pPacket) == LM_STATUS_FAILURE) {
685 /*
686 * A lower level send failure will push the packet descriptor back
687 * in the free queue, so just deal with the VxWorks clusters.
688 */
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;
697 }
698
699 if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) == 0) {
700 printf ("TX: emptyQ!\n");
701 pUmDevice->tx_full = 1;
702 }
703 }
704
705 while (pUmDevice->tx_pkt == 0) {
706 /* Service TX */
707 eth_isr ();
708 }
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);
719
720 /* Done with send */
721 out:
722 return status;
723 }
724
725 /* Ethernet receive */
726 int eth_rx (void)
727 {
728 PLM_PACKET pPacket = NULL;
729 PUM_PACKET pUmPacket = NULL;
730 void *skb;
731 int size = 0;
732
733 while (TRUE) {
734
735 bcm570x_service_isr:
736 /* Pull down packet if it is there */
737 eth_isr ();
738
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;
746 }
747
748 pPacket = (PLM_PACKET)
749 QQ_PopHead (&pDevice->RxPacketReceivedQ.Container);
750
751 if (pPacket == 0) {
752 printf ("eth_rx: empty packet!\n");
753 goto bcm570x_service_isr;
754 }
755
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)) {
763
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;
769 }
770
771 /* Set size and address */
772 skb = pUmPacket->skbuff;
773 size = pPacket->PacketSize;
774
775 /* Pass the packet up to the protocol
776 * layers.
777 */
778 NetReceive (skb, size);
779
780 /* Free packet buffer */
781 bcm570xPktFree (pUmDevice->index, skb);
782 pUmPacket->skbuff = NULL;
783
784 /* Reuse SKB */
785 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
786
787 return 0; /* Got a packet, bail ... */
788 }
789 return size;
790 }
791
792 /* Shut down device */
793 void eth_halt (void)
794 {
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);
805
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 */
814 }
815 }
816 }
817 pUmDevice->opened = 0;
818 free (pDevice);
819 pDevice = NULL;
820 pUmDevice = NULL;
821 initialized = 0;
822 printf ("done - offline.\n");
823 }
824 }
825
826 /*
827 *
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.
831 */
832
833 /* Middle module dependency - size of a packet descriptor */
834 int MM_Packet_Desc_Size = sizeof (UM_PACKET);
835
836 LM_STATUS
837 MM_ReadConfig32 (PLM_DEVICE_BLOCK pDevice,
838 LM_UINT32 Offset, LM_UINT32 * pValue32)
839 {
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;
844 }
845
846 LM_STATUS
847 MM_WriteConfig32 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT32 Value32)
848 {
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;
853 }
854
855 LM_STATUS
856 MM_ReadConfig16 (PLM_DEVICE_BLOCK pDevice,
857 LM_UINT32 Offset, LM_UINT16 * pValue16)
858 {
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;
863 }
864
865 LM_STATUS
866 MM_WriteConfig16 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT16 Value16)
867 {
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;
872 }
873
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)
878 {
879 PLM_VOID pvirt;
880 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
881 dma_addr_t mapping;
882
883 pvirt = malloc (BlockSize);
884 mapping = (dma_addr_t) (pvirt);
885 if (!pvirt)
886 return LM_STATUS_FAILURE;
887
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);
892
893 *pMemoryBlockVirt = (PLM_VOID) pvirt;
894 MM_SetAddr (pMemoryBlockPhy, (dma_addr_t) mapping);
895
896 return LM_STATUS_SUCCESS;
897 }
898
899 LM_STATUS
900 MM_AllocateMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
901 PLM_VOID * pMemoryBlockVirt)
902 {
903 PLM_VOID pvirt;
904 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
905
906 pvirt = malloc (BlockSize);
907
908 if (!pvirt)
909 return LM_STATUS_FAILURE;
910
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;
916
917 return LM_STATUS_SUCCESS;
918 }
919
920 LM_STATUS MM_MapMemBase (PLM_DEVICE_BLOCK pDevice)
921 {
922 printf ("BCM570x PCI Memory base address @0x%x\n",
923 (unsigned int)pDevice->pMappedMemBase);
924 return LM_STATUS_SUCCESS;
925 }
926
927 LM_STATUS MM_InitializeUmPackets (PLM_DEVICE_BLOCK pDevice)
928 {
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;
934
935 for (i = 0; i < pDevice->RxPacketDescCnt; i++) {
936 pPacket = QQ_PopHead (&pDevice->RxPacketFreeQ.Container);
937 pUmPacket = (PUM_PACKET) pPacket;
938
939 if (pPacket == 0) {
940 printf ("MM_InitializeUmPackets: Bad RxPacketFreeQ\n");
941 }
942
943 skb = bcm570xPktAlloc (pUmDevice->index,
944 pPacket->u.Rx.RxBufferSize + 2);
945
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;
952 }
953
954 pUmPacket->skbuff = skb;
955 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
956 }
957
958 pUmDevice->rx_low_buf_thresh = pDevice->RxPacketDescCnt / 8;
959
960 return LM_STATUS_SUCCESS;
961 }
962
963 LM_STATUS MM_GetConfig (PLM_DEVICE_BLOCK pDevice)
964 {
965 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
966 int index = pDevice->index;
967
968 if (auto_speed[index] == 0)
969 pDevice->DisableAutoNeg = TRUE;
970 else
971 pDevice->DisableAutoNeg = FALSE;
972
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;
987 }
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;
997 }
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;
1005 }
1006 } else {
1007 pDevice->RequestedMediaType =
1008 LM_REQUESTED_MEDIA_TYPE_AUTO;
1009 pDevice->DisableAutoNeg = FALSE;
1010 }
1011
1012 }
1013 pDevice->FlowControlCap = 0;
1014 if (rx_flow_control[index] != 0) {
1015 pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
1016 }
1017 if (tx_flow_control[index] != 0) {
1018 pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
1019 }
1020 if ((auto_flow_control[index] != 0) &&
1021 (pDevice->DisableAutoNeg == FALSE)) {
1022
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;
1029 }
1030 }
1031
1032 /* Default MTU for now */
1033 pUmDevice->mtu = 1500;
1034
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;
1041 }
1042 pDevice->RxJumboDescCnt = rx_jumbo_desc_cnt[index];
1043 #else
1044 pDevice->RxMtu = pUmDevice->mtu;
1045 #endif
1046
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;
1052 }
1053
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;
1063
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;
1078 }
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;
1085
1086 if (enable_wol[index]) {
1087 pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET;
1088 pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET;
1089 }
1090 pDevice->NicSendBd = TRUE;
1091
1092 /* Don't update status blocks during interrupt */
1093 pDevice->RxCoalescingTicksDuringInt = 0;
1094 pDevice->TxCoalescingTicksDuringInt = 0;
1095
1096 return LM_STATUS_SUCCESS;
1097
1098 }
1099
1100 LM_STATUS MM_StartTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1101 {
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);
1105
1106 return LM_STATUS_SUCCESS;
1107 }
1108
1109 LM_STATUS MM_CompleteTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1110 {
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;
1115 }
1116
1117 LM_STATUS MM_IndicateStatus (PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
1118 {
1119 char buf[128];
1120 char lcd[4];
1121 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1122 LM_FLOW_CONTROL flow_control;
1123
1124 pUmDevice->delayed_link_ind = 0;
1125 memset (lcd, 0x0, 4);
1126
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);
1136
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] = ' ';
1152 }
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';
1159 }
1160 strcat (buf, " link up");
1161
1162 flow_control = pDevice->FlowControl &
1163 (LM_FLOW_CONTROL_RECEIVE_PAUSE |
1164 LM_FLOW_CONTROL_TRANSMIT_PAUSE);
1165
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 ");
1174 }
1175 strcat (buf, "flow control ON");
1176 } else {
1177 strcat (buf, ", flow control OFF");
1178 }
1179 strcat (buf, "\n");
1180 printf ("%s", buf);
1181 }
1182 #if 0
1183 sysLedDsply (lcd[0], lcd[1], lcd[2], lcd[3]);
1184 #endif
1185 return LM_STATUS_SUCCESS;
1186 }
1187
1188 LM_STATUS MM_FreeRxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1189 {
1190
1191 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1192 PUM_PACKET pUmPacket;
1193 void *skb;
1194
1195 pUmPacket = (PUM_PACKET) pPacket;
1196
1197 if ((skb = pUmPacket->skbuff))
1198 bcm570xPktFree (pUmDevice->index, skb);
1199
1200 pUmPacket->skbuff = 0;
1201
1202 return LM_STATUS_SUCCESS;
1203 }
1204
1205 unsigned long MM_AnGetCurrentTime_us (PAN_STATE_INFO pAnInfo)
1206 {
1207 return get_timer (0);
1208 }
1209
1210 /*
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.
1219 */
1220 LM_STATUS MM_CoalesceTxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1221 {
1222 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1223 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1224 void *skbnew;
1225 int len = 0;
1226
1227 if (len == 0)
1228 return (LM_STATUS_SUCCESS);
1229
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);
1234 }
1235
1236 skbnew = bcm570xPktAlloc (pUmDevice->index, MAX_PACKET_SIZE);
1237
1238 if (skbnew == NULL) {
1239 pUmDevice->tx_full = 1;
1240 printf ("eth%d: out of transmit buffers", pUmDevice->index);
1241 return (LM_STATUS_FAILURE);
1242 }
1243
1244 /* New packet values */
1245 pUmPacket->skbuff = skbnew;
1246 pUmPacket->lm_packet.u.Tx.FragCount = 1;
1247
1248 return (LM_STATUS_SUCCESS);
1249 }
1250
1251 LM_STATUS MM_IndicateRxPackets (PLM_DEVICE_BLOCK pDevice)
1252 {
1253 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1254 pUmDevice->rx_pkt = 1;
1255 return LM_STATUS_SUCCESS;
1256 }
1257
1258 LM_STATUS MM_IndicateTxPackets (PLM_DEVICE_BLOCK pDevice)
1259 {
1260 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1261 PLM_PACKET pPacket;
1262 PUM_PACKET pUmPacket;
1263 void *skb;
1264 while (TRUE) {
1265
1266 pPacket = (PLM_PACKET)
1267 QQ_PopHead (&pDevice->TxPacketXmittedQ.Container);
1268
1269 if (pPacket == 0)
1270 break;
1271
1272 pUmPacket = (PUM_PACKET) pPacket;
1273 skb = (void *)pUmPacket->skbuff;
1274
1275 /*
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.
1281 */
1282
1283 if (skb)
1284 bcm570xPktFree (pUmDevice->index, skb);
1285
1286 pUmPacket->skbuff = 0;
1287 QQ_PushTail (&pDevice->TxPacketFreeQ.Container, pPacket);
1288 pUmDevice->tx_pkt = 1;
1289 }
1290 if (pUmDevice->tx_full) {
1291 if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) >=
1292 (QQ_GetSize (&pDevice->TxPacketFreeQ.Container) >> 1))
1293 pUmDevice->tx_full = 0;
1294 }
1295 return LM_STATUS_SUCCESS;
1296 }
1297
1298 /*
1299 * Scan an MBUF chain until we reach fragment number "frag"
1300 * Return its length and physical address.
1301 */
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);
1309 }
1310
1311 /*
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.
1315 */
1316 void MM_MapRxDma (PLM_DEVICE_BLOCK pDevice,
1317 struct _LM_PACKET *pPacket, T3_64BIT_HOST_ADDR * paddr)
1318 {
1319 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1320 MM_SetT3Addr (paddr, (dma_addr_t) pUmPacket->skbuff);
1321 }
1322
1323 void MM_SetAddr (LM_PHYSICAL_ADDRESS * paddr, dma_addr_t addr)
1324 {
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
1332 }
1333
1334 void MM_SetT3Addr (T3_64BIT_HOST_ADDR * paddr, dma_addr_t addr)
1335 {
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
1342 }
1343
1344 /*
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.
1352 */
1353 void atomic_set (atomic_t * entry, int val)
1354 {
1355 entry->counter = val;
1356 }
1357
1358 int atomic_read (atomic_t * entry)
1359 {
1360 return entry->counter;
1361 }
1362
1363 void atomic_inc (atomic_t * entry)
1364 {
1365 if (entry)
1366 entry->counter++;
1367 }
1368
1369 void atomic_dec (atomic_t * entry)
1370 {
1371 if (entry)
1372 entry->counter--;
1373 }
1374
1375 void atomic_sub (int a, atomic_t * entry)
1376 {
1377 if (entry)
1378 entry->counter -= a;
1379 }
1380
1381 void atomic_add (int a, atomic_t * entry)
1382 {
1383 if (entry)
1384 entry->counter += a;
1385 }
1386
1387 /******************************************************************************/
1388 /* Description: */
1389 /* */
1390 /* Return: */
1391 /******************************************************************************/
1392 void QQ_InitQueue (PQQ_CONTAINER pQueue, unsigned int QueueSize)
1393 {
1394 pQueue->Head = 0;
1395 pQueue->Tail = 0;
1396 pQueue->Size = QueueSize + 1;
1397 atomic_set (&pQueue->EntryCnt, 0);
1398 } /* QQ_InitQueue */
1399
1400 /******************************************************************************/
1401 /* Description: */
1402 /* */
1403 /* Return: */
1404 /******************************************************************************/
1405 char QQ_Full (PQQ_CONTAINER pQueue)
1406 {
1407 unsigned int NewHead;
1408
1409 NewHead = (pQueue->Head + 1) % pQueue->Size;
1410
1411 return (NewHead == pQueue->Tail);
1412 } /* QQ_Full */
1413
1414 /******************************************************************************/
1415 /* Description: */
1416 /* */
1417 /* Return: */
1418 /******************************************************************************/
1419 char QQ_Empty (PQQ_CONTAINER pQueue)
1420 {
1421 return (pQueue->Head == pQueue->Tail);
1422 } /* QQ_Empty */
1423
1424 /******************************************************************************/
1425 /* Description: */
1426 /* */
1427 /* Return: */
1428 /******************************************************************************/
1429 unsigned int QQ_GetSize (PQQ_CONTAINER pQueue)
1430 {
1431 return pQueue->Size;
1432 } /* QQ_GetSize */
1433
1434 /******************************************************************************/
1435 /* Description: */
1436 /* */
1437 /* Return: */
1438 /******************************************************************************/
1439 unsigned int QQ_GetEntryCnt (PQQ_CONTAINER pQueue)
1440 {
1441 return atomic_read (&pQueue->EntryCnt);
1442 } /* QQ_GetEntryCnt */
1443
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)
1452 {
1453 unsigned int Head;
1454
1455 Head = (pQueue->Head + 1) % pQueue->Size;
1456
1457 #if !defined(QQ_NO_OVERFLOW_CHECK)
1458 if (Head == pQueue->Tail) {
1459 return 0;
1460 } /* if */
1461 #endif /* QQ_NO_OVERFLOW_CHECK */
1462
1463 pQueue->Array[pQueue->Head] = pEntry;
1464 wmb ();
1465 pQueue->Head = Head;
1466 atomic_inc (&pQueue->EntryCnt);
1467
1468 return -1;
1469 } /* QQ_PushHead */
1470
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)
1479 {
1480 unsigned int Tail;
1481
1482 Tail = pQueue->Tail;
1483 if (Tail == 0) {
1484 Tail = pQueue->Size;
1485 } /* if */
1486 Tail--;
1487
1488 #if !defined(QQ_NO_OVERFLOW_CHECK)
1489 if (Tail == pQueue->Head) {
1490 return 0;
1491 } /* if */
1492 #endif /* QQ_NO_OVERFLOW_CHECK */
1493
1494 pQueue->Array[Tail] = pEntry;
1495 wmb ();
1496 pQueue->Tail = Tail;
1497 atomic_inc (&pQueue->EntryCnt);
1498
1499 return -1;
1500 } /* QQ_PushTail */
1501
1502 /******************************************************************************/
1503 /* Description: */
1504 /* */
1505 /* Return: */
1506 /******************************************************************************/
1507 PQQ_ENTRY QQ_PopHead (PQQ_CONTAINER pQueue)
1508 {
1509 unsigned int Head;
1510 PQQ_ENTRY Entry;
1511
1512 Head = pQueue->Head;
1513
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 */
1519
1520 if (Head == 0) {
1521 Head = pQueue->Size;
1522 } /* if */
1523 Head--;
1524
1525 Entry = pQueue->Array[Head];
1526 membar ();
1527
1528 pQueue->Head = Head;
1529 atomic_dec (&pQueue->EntryCnt);
1530
1531 return Entry;
1532 } /* QQ_PopHead */
1533
1534 /******************************************************************************/
1535 /* Description: */
1536 /* */
1537 /* Return: */
1538 /******************************************************************************/
1539 PQQ_ENTRY QQ_PopTail (PQQ_CONTAINER pQueue)
1540 {
1541 unsigned int Tail;
1542 PQQ_ENTRY Entry;
1543
1544 Tail = pQueue->Tail;
1545
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 */
1551
1552 Entry = pQueue->Array[Tail];
1553 membar ();
1554 pQueue->Tail = (Tail + 1) % pQueue->Size;
1555 atomic_dec (&pQueue->EntryCnt);
1556
1557 return Entry;
1558 } /* QQ_PopTail */
1559
1560 /******************************************************************************/
1561 /* Description: */
1562 /* */
1563 /* Return: */
1564 /******************************************************************************/
1565 PQQ_ENTRY QQ_GetHead (PQQ_CONTAINER pQueue, unsigned int Idx)
1566 {
1567 if (Idx >= atomic_read (&pQueue->EntryCnt)) {
1568 return (PQQ_ENTRY) 0;
1569 }
1570
1571 if (pQueue->Head > Idx) {
1572 Idx = pQueue->Head - Idx;
1573 } else {
1574 Idx = pQueue->Size - (Idx - pQueue->Head);
1575 }
1576 Idx--;
1577
1578 return pQueue->Array[Idx];
1579 }
1580
1581 /******************************************************************************/
1582 /* Description: */
1583 /* */
1584 /* Return: */
1585 /******************************************************************************/
1586 PQQ_ENTRY QQ_GetTail (PQQ_CONTAINER pQueue, unsigned int Idx)
1587 {
1588 if (Idx >= atomic_read (&pQueue->EntryCnt)) {
1589 return (PQQ_ENTRY) 0;
1590 }
1591
1592 Idx += pQueue->Tail;
1593 if (Idx >= pQueue->Size) {
1594 Idx = Idx - pQueue->Size;
1595 }
1596
1597 return pQueue->Array[Idx];
1598 }