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