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