to make u-boot work for fat32 filesystem
[jz_uboot.git] / drivers / bcm570x.c
blob5f632a64692a8253482bc516d0eb859607d43527
1 /*
2 * Broadcom BCM570x Ethernet Driver for U-Boot.
3 * Support 5701, 5702, 5703, and 5704. Single instance driver.
4 * Copyright (C) 2002 James F. Dougherty (jfd@broadcom.com)
5 */
7 #include <common.h>
9 #if (CONFIG_COMMANDS & CFG_CMD_NET) && (!defined(CONFIG_NET_MULTI)) && \
10 defined(CONFIG_BCM570x)
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>
23 * PCI Registers and definitions.
25 #define PCI_CMD_MASK 0xffff0000 /* mask to save status bits */
26 #define PCI_ANY_ID (~0)
29 * PCI memory base for Ethernet device as well as device Interrupt.
31 #define BCM570X_MBAR 0x80100000
32 #define BCM570X_ILINE 1
35 #define SECOND_USEC 1000000
36 #define MAX_PACKET_SIZE 1600
37 #define MAX_UNITS 4
39 /* Globals to this module */
40 int initialized = 0;
41 unsigned int ioBase = 0;
42 volatile PLM_DEVICE_BLOCK pDevice = NULL; /* 570x softc */
43 volatile PUM_DEVICE_BLOCK pUmDevice = NULL;
45 /* Used to pass the full-duplex flag, etc. */
46 int line_speed[MAX_UNITS] = {0,0,0,0};
47 static int full_duplex[MAX_UNITS] = {1,1,1,1};
48 static int rx_flow_control[MAX_UNITS] = {0,0,0,0};
49 static int tx_flow_control[MAX_UNITS] = {0,0,0,0};
50 static int auto_flow_control[MAX_UNITS] = {0,0,0,0};
51 static int tx_checksum[MAX_UNITS] = {1,1,1,1};
52 static int rx_checksum[MAX_UNITS] = {1,1,1,1};
53 static int auto_speed[MAX_UNITS] = {1,1,1,1};
55 #if JUMBO_FRAMES
56 /* Jumbo MTU for interfaces. */
57 static int mtu[MAX_UNITS] = {0,0,0,0};
58 #endif
60 /* Turn on Wake-on lan for a device unit */
61 static int enable_wol[MAX_UNITS] = {0,0,0,0};
63 #define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNT
64 static unsigned int tx_pkt_desc_cnt[MAX_UNITS] =
65 {TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT, TX_DESC_CNT};
67 #define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNT
68 static unsigned int rx_std_desc_cnt[MAX_UNITS] =
69 {RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT};
71 static unsigned int rx_adaptive_coalesce[MAX_UNITS] = {1,1,1,1};
73 #if T3_JUMBO_RCV_RCB_ENTRY_COUNT
74 #define JBO_DESC_CNT DEFAULT_JUMBO_RCV_DESC_COUNT
75 static 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
79 static unsigned int rx_coalesce_ticks[MAX_UNITS] =
80 {RX_COAL_TK, RX_COAL_TK, RX_COAL_TK, RX_COAL_TK};
82 #define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMES
83 static unsigned int rx_max_coalesce_frames[MAX_UNITS] =
84 {RX_COAL_FM, RX_COAL_FM, RX_COAL_FM, RX_COAL_FM};
86 #define TX_COAL_TK DEFAULT_TX_COALESCING_TICKS
87 static unsigned int tx_coalesce_ticks[MAX_UNITS] =
88 {TX_COAL_TK, TX_COAL_TK, TX_COAL_TK, TX_COAL_TK};
90 #define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMES
91 static unsigned int tx_max_coalesce_frames[MAX_UNITS] =
92 {TX_COAL_FM, TX_COAL_FM, TX_COAL_FM, TX_COAL_FM};
94 #define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKS
95 static unsigned int stats_coalesce_ticks[MAX_UNITS] =
96 {ST_COAL_TK, ST_COAL_TK, ST_COAL_TK, ST_COAL_TK};
100 * Legitimate values for BCM570x device types
102 typedef 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;
135 /* Chip-Rev names for each device-type */
136 static 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"},
173 /* indexed by board_t, above */
174 static 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 },
210 /* PCI Devices which use the 570x chipset */
211 struct 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}
271 #define n570xDevices (sizeof(bcm570xDevices)/sizeof(bcm570xDevices[0]))
275 * Allocate a packet buffer from the bcm570x packet pool.
277 void *
278 bcm570xPktAlloc(int u, int pksize)
280 return malloc(pksize);
284 * Free a packet previously allocated from the bcm570x packet
285 * buffer pool.
287 void
288 bcm570xPktFree(int u, void *p)
290 free(p);
294 bcm570xReplenishRxBuffers(PUM_DEVICE_BLOCK pUmDevice)
296 PLM_PACKET pPacket;
297 PUM_PACKET pUmPacket;
298 void *skb;
299 int queue_rx = 0;
300 int ret = 0;
302 while ((pUmPacket = (PUM_PACKET)
303 QQ_PopHead(&pUmDevice->rx_out_of_buf_q.Container)) != 0) {
305 pPacket = (PLM_PACKET) pUmPacket;
307 /* reuse an old skb */
308 if (pUmPacket->skbuff) {
309 QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
310 queue_rx = 1;
311 continue;
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;
321 pUmPacket->skbuff = skb;
322 QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
323 queue_rx = 1;
326 if (queue_rx) {
327 LM_QueueRxPackets(pDevice);
330 return ret;
334 * Probe, Map, and Init 570x device.
336 int eth_init(bd_t *bis)
338 int i, rv, devFound = FALSE;
339 pci_dev_t devbusfn;
340 unsigned short status;
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 {
350 /* Set ILINE */
351 pci_write_config_byte(devbusfn,
352 PCI_INTERRUPT_LINE, BCM570X_ILINE);
355 * 0x10 - 0x14 define one 64-bit MBAR.
356 * 0x14 is the higher-order address bits of the BAR.
358 pci_write_config_dword(devbusfn,
359 PCI_BASE_ADDRESS_1, 0);
361 ioBase = BCM570X_MBAR;
363 pci_write_config_dword(devbusfn,
364 PCI_BASE_ADDRESS_0, ioBase);
367 * Enable PCI memory, IO, and Master -- don't
368 * reset any status bits in doing so.
370 pci_read_config_word(devbusfn,
371 PCI_COMMAND, &status);
373 status |= PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER;
375 pci_write_config_word(devbusfn,
376 PCI_COMMAND, status);
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);
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));
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;
402 if(!devFound){
403 printf("eth_init: FAILURE: no BCM570x Ethernet devices found.\n");
404 return -1;
407 /* Setup defaults for chip */
408 pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
410 if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) {
411 pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
412 } else {
414 if (rx_checksum[i]) {
415 pDevice->TaskToOffload |=
416 LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
417 LM_TASK_OFFLOAD_RX_UDP_CHECKSUM;
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;
428 /* Set Device PCI Memory base address */
429 pDevice->pMappedMemBase = (PLM_UINT8) ioBase;
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;
437 /* Lock not needed */
438 pUmDevice->do_global_lock = 0;
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;
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;
451 else {
452 pUmDevice->timer_interval = CFG_HZ / 50;
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);
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;
467 /* delay for 4 seconds */
468 pUmDevice->delayed_link_ind =
469 (4 * CFG_HZ) / pUmDevice->timer_interval;
471 pUmDevice->adaptive_expiry =
472 CFG_HZ / pUmDevice->timer_interval;
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;
480 /* Initialize 570x */
481 if (LM_InitializeAdapter(pDevice) != LM_STATUS_SUCCESS) {
482 printf("ERROR: Adapter initialization failed.\n");
483 return ERROR;
486 /* Enable chip ISR */
487 LM_EnableInterrupt(pDevice);
489 /* Clear MC table */
490 LM_MulticastClear(pDevice);
492 /* Enable Multicast */
493 LM_SetReceiveMask(pDevice,
494 pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST);
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]);
506 printf("\n");
508 printf("eth%d: ", pDevice->index);
509 printf("%s with ",
510 chip_rev[bcm570xDevices[i].board_id].name);
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)
521 printf("Broadcom BCM5703 Integrated Copper ");
522 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");
530 printf("eth%d: %s, MTU: %d,",
531 pDevice->index, pDevice->BusSpeedStr, 1500);
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++;
540 return 0;
543 /* Ethernet Interrupt service routine */
544 void
545 eth_isr(void)
547 LM_UINT32 oldtag, newtag;
548 int i;
550 pUmDevice->interrupt = 1;
552 if (pDevice->UseTaggedStatus) {
553 if ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) ||
554 pUmDevice->adapter_just_inited) {
555 MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1);
556 oldtag = pDevice->pStatusBlkVirt->StatusTag;
558 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,
566 pDevice->GrcLocalCtrl | 0x2);
568 break;
570 oldtag = newtag;
574 else {
575 while (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) {
576 unsigned int dummy;
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;
586 /* Allocate new RX buffers */
587 if (QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container)) {
588 bcm570xReplenishRxBuffers(pUmDevice);
591 /* Queue packets */
592 if (QQ_GetEntryCnt(&pDevice->RxPacketFreeQ.Container)) {
593 LM_QueueRxPackets(pDevice);
596 if (pUmDevice->tx_queued) {
597 pUmDevice->tx_queued = 0;
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;
607 pUmDevice->interrupt = 0;
612 eth_send(volatile void *packet, int length)
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;
621 /* Link down, return */
622 while(pDevice->LinkStatus == LM_STATUS_LINK_DOWN) {
623 #if 0
624 printf("eth%d: link down - check cable or link partner.\n",
625 pUmDevice->index);
626 #endif
627 eth_isr();
629 /* Wait to see link for one-half a second before sending ... */
630 udelay(1500000);
634 /* Clear sent flag */
635 pUmDevice->tx_pkt = 0;
637 /* Previously blocked */
638 if(pUmDevice->tx_full){
639 printf("eth%d: tx blocked.\n", pUmDevice->index);
640 return 0;
643 pPacket = (PLM_PACKET)
644 QQ_PopHead(&pDevice->TxPacketFreeQ.Container);
646 if (pPacket == 0) {
647 pUmDevice->tx_full = 1;
648 printf("bcm570xEndSend: TX full!\n");
649 return 0;
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;
659 if (length <= 0){
660 printf("eth: bad packet size: %d\n", length);
661 goto out;
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.
670 if (MM_CoalesceTxBuffer (pDevice, pPacket) != LM_STATUS_SUCCESS) {
671 if (pUmPacket->skbuff == NULL){
672 /* Packet was discarded */
673 printf("TX: failed (1)\n");
674 status = 1;
675 } else{
676 printf("TX: failed (2)\n");
677 status = 2;
679 QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
680 return status;
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;
692 if ( LM_SendPacket(pDevice, pPacket) == LM_STATUS_FAILURE){
694 * A lower level send failure will push the packet descriptor back
695 * in the free queue, so just deal with the VxWorks clusters.
697 if (pUmPacket->skbuff == NULL){
698 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;
707 if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) == 0) {
708 printf("TX: emptyQ!\n");
709 pUmDevice->tx_full = 1;
713 while(pUmDevice->tx_pkt == 0){
714 /* Service TX */
715 eth_isr();
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);
728 /* Done with send */
729 out:
730 return status;
734 /* Ethernet receive */
736 eth_rx(void)
738 PLM_PACKET pPacket = NULL;
739 PUM_PACKET pUmPacket = NULL;
740 void *skb;
741 int size=0;
743 while(TRUE) {
745 bcm570x_service_isr:
746 /* Pull down packet if it is there */
747 eth_isr();
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;
758 pPacket = (PLM_PACKET)
759 QQ_PopHead(&pDevice->RxPacketReceivedQ.Container);
761 if (pPacket == 0){
762 printf("eth_rx: empty packet!\n");
763 goto bcm570x_service_isr;
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)) {
775 /* reuse skb */
776 QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
777 printf("eth_rx: error in packet dma!\n");
778 goto bcm570x_service_isr;
781 /* Set size and address */
782 skb = pUmPacket->skbuff;
783 size = pPacket->PacketSize;
785 /* Pass the packet up to the protocol
786 * layers.
788 NetReceive(skb, size);
790 /* Free packet buffer */
791 bcm570xPktFree (pUmDevice->index, skb);
792 pUmPacket->skbuff = NULL;
794 /* Reuse SKB */
795 QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
797 return 0; /* Got a packet, bail ... */
799 return size;
803 /* Shut down device */
804 void
805 eth_halt(void)
807 int i;
808 if ( initialized)
809 if (pDevice && pUmDevice && pUmDevice->opened){
810 printf("\neth%d:%s,", pUmDevice->index, pUmDevice->name);
811 printf("HALT,");
812 /* stop device */
813 LM_Halt(pDevice);
814 printf("POWER DOWN,");
815 LM_SetPowerState(pDevice, LM_POWER_STATE_D3);
817 /* 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]) {
820 /* sanity check */
821 if (pUmDevice->dma_list[i]) { /* cache-safe memory */
822 free(pUmDevice->mem_list[i]);
823 } else {
824 free(pUmDevice->mem_list[i]); /* normal memory */
828 pUmDevice->opened = 0;
829 free(pDevice);
830 pDevice = NULL;
831 pUmDevice = NULL;
832 initialized = 0;
833 printf("done - offline.\n");
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.
845 /* Middle module dependency - size of a packet descriptor */
846 int MM_Packet_Desc_Size = sizeof(UM_PACKET);
849 LM_STATUS
850 MM_ReadConfig32(PLM_DEVICE_BLOCK pDevice,
851 LM_UINT32 Offset,
852 LM_UINT32 *pValue32)
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;
862 LM_STATUS
863 MM_WriteConfig32(PLM_DEVICE_BLOCK pDevice,
864 LM_UINT32 Offset,
865 LM_UINT32 Value32)
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;
875 LM_STATUS
876 MM_ReadConfig16(PLM_DEVICE_BLOCK pDevice,
877 LM_UINT32 Offset,
878 LM_UINT16 *pValue16)
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;
887 LM_STATUS
888 MM_WriteConfig16(PLM_DEVICE_BLOCK pDevice,
889 LM_UINT32 Offset,
890 LM_UINT16 Value16)
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;
900 LM_STATUS
901 MM_AllocateSharedMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
902 PLM_VOID *pMemoryBlockVirt,
903 PLM_PHYSICAL_ADDRESS pMemoryBlockPhy,
904 LM_BOOL Cached)
906 PLM_VOID pvirt;
907 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
908 dma_addr_t mapping;
910 pvirt = malloc(BlockSize);
911 mapping = (dma_addr_t)(pvirt);
912 if (!pvirt)
913 return LM_STATUS_FAILURE;
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);
920 *pMemoryBlockVirt = (PLM_VOID) pvirt;
921 MM_SetAddr (pMemoryBlockPhy, (dma_addr_t) mapping);
923 return LM_STATUS_SUCCESS;
927 LM_STATUS
928 MM_AllocateMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
929 PLM_VOID *pMemoryBlockVirt)
931 PLM_VOID pvirt;
932 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
934 pvirt = malloc(BlockSize);
936 if (!pvirt)
937 return LM_STATUS_FAILURE;
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;
945 return LM_STATUS_SUCCESS;
948 LM_STATUS
949 MM_MapMemBase(PLM_DEVICE_BLOCK pDevice)
951 printf("BCM570x PCI Memory base address @0x%x\n",
952 (unsigned int)pDevice->pMappedMemBase);
953 return LM_STATUS_SUCCESS;
956 LM_STATUS
957 MM_InitializeUmPackets(PLM_DEVICE_BLOCK pDevice)
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;
965 for (i = 0; i < pDevice->RxPacketDescCnt; i++) {
966 pPacket = QQ_PopHead(&pDevice->RxPacketFreeQ.Container);
967 pUmPacket = (PUM_PACKET) pPacket;
969 if (pPacket == 0) {
970 printf("MM_InitializeUmPackets: Bad RxPacketFreeQ\n");
973 skb = bcm570xPktAlloc(pUmDevice->index,
974 pPacket->u.Rx.RxBufferSize + 2);
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;
983 pUmPacket->skbuff = skb;
984 QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket);
987 pUmDevice->rx_low_buf_thresh = pDevice->RxPacketDescCnt / 8;
989 return LM_STATUS_SUCCESS;
992 LM_STATUS
993 MM_GetConfig(PLM_DEVICE_BLOCK pDevice)
995 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
996 int index = pDevice->index;
998 if (auto_speed[index] == 0)
999 pDevice->DisableAutoNeg = TRUE;
1000 else
1001 pDevice->DisableAutoNeg = FALSE;
1003 if (line_speed[index] == 0) {
1004 pDevice->RequestedMediaType =
1005 LM_REQUESTED_MEDIA_TYPE_AUTO;
1006 pDevice->DisableAutoNeg = FALSE;
1008 else {
1009 if (line_speed[index] == 1000) {
1010 if (pDevice->EnableTbi) {
1011 pDevice->RequestedMediaType =
1012 LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX;
1014 else if (full_duplex[index]) {
1015 pDevice->RequestedMediaType =
1016 LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX;
1018 else {
1019 pDevice->RequestedMediaType =
1020 LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS;
1022 if (!pDevice->EnableTbi)
1023 pDevice->DisableAutoNeg = FALSE;
1025 else if (line_speed[index] == 100) {
1026 if (full_duplex[index]) {
1027 pDevice->RequestedMediaType =
1028 LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX;
1030 else {
1031 pDevice->RequestedMediaType =
1032 LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS;
1035 else if (line_speed[index] == 10) {
1036 if (full_duplex[index]) {
1037 pDevice->RequestedMediaType =
1038 LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX;
1040 else {
1041 pDevice->RequestedMediaType =
1042 LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS;
1045 else {
1046 pDevice->RequestedMediaType =
1047 LM_REQUESTED_MEDIA_TYPE_AUTO;
1048 pDevice->DisableAutoNeg = FALSE;
1052 pDevice->FlowControlCap = 0;
1053 if (rx_flow_control[index] != 0) {
1054 pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
1056 if (tx_flow_control[index] != 0) {
1057 pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
1059 if ((auto_flow_control[index] != 0) &&
1060 (pDevice->DisableAutoNeg == FALSE)) {
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;
1071 /* Default MTU for now */
1072 pUmDevice->mtu = 1500;
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;
1079 else {
1080 pDevice->RxJumboDescCnt = 0;
1082 pDevice->RxJumboDescCnt = rx_jumbo_desc_cnt[index];
1083 #else
1084 pDevice->RxMtu = pUmDevice->mtu;
1085 #endif
1087 if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) {
1088 pDevice->UseTaggedStatus = TRUE;
1089 pUmDevice->timer_interval = CFG_HZ;
1091 else {
1092 pUmDevice->timer_interval = CFG_HZ/50;
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;
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;
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;
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;
1129 if (enable_wol[index]) {
1130 pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET;
1131 pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET;
1133 pDevice->NicSendBd = TRUE;
1135 /* Don't update status blocks during interrupt */
1136 pDevice->RxCoalescingTicksDuringInt = 0;
1137 pDevice->TxCoalescingTicksDuringInt = 0;
1139 return LM_STATUS_SUCCESS;
1144 LM_STATUS
1145 MM_StartTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
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);
1151 return LM_STATUS_SUCCESS;
1154 LM_STATUS
1155 MM_CompleteTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
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;
1164 LM_STATUS
1165 MM_IndicateStatus(PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
1167 char buf[128];
1168 char lcd[4];
1169 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1170 LM_FLOW_CONTROL flow_control;
1172 pUmDevice->delayed_link_ind = 0;
1173 memset(lcd, 0x0, 4);
1175 if (Status == LM_STATUS_LINK_DOWN) {
1176 sprintf(buf,"eth%d: %s: NIC Link is down\n",
1177 pUmDevice->index,pUmDevice->name);
1178 lcd[0] = 'L';lcd[1]='N';lcd[2]='K';lcd[3] = '?';
1179 } else if (Status == LM_STATUS_LINK_ACTIVE) {
1180 sprintf(buf,"eth%d:%s: ", pUmDevice->index, pUmDevice->name);
1182 if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS){
1183 strcat(buf,"1000 Mbps ");
1184 lcd[0] = '1';lcd[1]='G';lcd[2]='B';
1185 } else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS){
1186 strcat(buf,"100 Mbps ");
1187 lcd[0] = '1';lcd[1]='0';lcd[2]='0';
1188 } else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS){
1189 strcat(buf,"10 Mbps ");
1190 lcd[0] = '1';lcd[1]='0';lcd[2]=' ';
1192 if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL){
1193 strcat(buf, "full duplex");
1194 lcd[3] = 'F';
1195 } else {
1196 strcat(buf, "half duplex");
1197 lcd[3] = 'H';
1199 strcat(buf, " link up");
1201 flow_control = pDevice->FlowControl &
1202 (LM_FLOW_CONTROL_RECEIVE_PAUSE |
1203 LM_FLOW_CONTROL_TRANSMIT_PAUSE);
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 ");
1211 else {
1212 strcat(buf,", transmit ");
1214 strcat(buf,"flow control ON");
1215 } else {
1216 strcat(buf, ", flow control OFF");
1218 strcat(buf,"\n");
1219 printf("%s",buf);
1221 #if 0
1222 sysLedDsply(lcd[0],lcd[1],lcd[2],lcd[3]);
1223 #endif
1224 return LM_STATUS_SUCCESS;
1227 LM_STATUS
1228 MM_FreeRxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1231 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1232 PUM_PACKET pUmPacket;
1233 void *skb;
1235 pUmPacket = (PUM_PACKET) pPacket;
1237 if ((skb = pUmPacket->skbuff))
1238 bcm570xPktFree(pUmDevice->index, skb);
1240 pUmPacket->skbuff = 0;
1242 return LM_STATUS_SUCCESS;
1245 unsigned long
1246 MM_AnGetCurrentTime_us(PAN_STATE_INFO pAnInfo)
1248 return get_timer(0);
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.
1261 LM_STATUS
1262 MM_CoalesceTxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1264 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1265 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1266 void *skbnew;
1267 int len = 0;
1269 if (len == 0)
1270 return (LM_STATUS_SUCCESS);
1272 if (len > MAX_PACKET_SIZE){
1273 printf ("eth%d: xmit frame discarded, too big!, size = %d\n",
1274 pUmDevice->index, len);
1275 return (LM_STATUS_FAILURE);
1278 skbnew = bcm570xPktAlloc(pUmDevice->index, MAX_PACKET_SIZE);
1280 if (skbnew == NULL) {
1281 pUmDevice->tx_full = 1;
1282 printf ("eth%d: out of transmit buffers", pUmDevice->index);
1283 return (LM_STATUS_FAILURE);
1286 /* New packet values */
1287 pUmPacket->skbuff = skbnew;
1288 pUmPacket->lm_packet.u.Tx.FragCount = 1;
1290 return (LM_STATUS_SUCCESS);
1294 LM_STATUS
1295 MM_IndicateRxPackets(PLM_DEVICE_BLOCK pDevice)
1297 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1298 pUmDevice->rx_pkt = 1;
1299 return LM_STATUS_SUCCESS;
1302 LM_STATUS
1303 MM_IndicateTxPackets(PLM_DEVICE_BLOCK pDevice)
1305 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1306 PLM_PACKET pPacket;
1307 PUM_PACKET pUmPacket;
1308 void *skb;
1309 while ( TRUE ) {
1311 pPacket = (PLM_PACKET)
1312 QQ_PopHead(&pDevice->TxPacketXmittedQ.Container);
1314 if (pPacket == 0)
1315 break;
1317 pUmPacket = (PUM_PACKET) pPacket;
1318 skb = (void*)pUmPacket->skbuff;
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.
1328 if (skb)
1329 bcm570xPktFree (pUmDevice->index, skb);
1331 pUmPacket->skbuff = 0;
1332 QQ_PushTail(&pDevice->TxPacketFreeQ.Container, pPacket);
1333 pUmDevice->tx_pkt = 1;
1335 if (pUmDevice->tx_full) {
1336 if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) >=
1337 (QQ_GetSize(&pDevice->TxPacketFreeQ.Container) >> 1))
1338 pUmDevice->tx_full = 0;
1340 return LM_STATUS_SUCCESS;
1344 * Scan an MBUF chain until we reach fragment number "frag"
1345 * Return its length and physical address.
1347 void MM_MapTxDma
1349 PLM_DEVICE_BLOCK pDevice,
1350 struct _LM_PACKET *pPacket,
1351 T3_64BIT_HOST_ADDR *paddr,
1352 LM_UINT32 *len,
1353 int frag)
1355 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1356 *len = pPacket->PacketSize;
1357 MM_SetT3Addr(paddr, (dma_addr_t) pUmPacket->skbuff);
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.
1365 void MM_MapRxDma(
1366 PLM_DEVICE_BLOCK pDevice,
1367 struct _LM_PACKET *pPacket,
1368 T3_64BIT_HOST_ADDR *paddr)
1370 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1371 MM_SetT3Addr(paddr, (dma_addr_t) pUmPacket->skbuff);
1374 void
1375 MM_SetAddr (LM_PHYSICAL_ADDRESS *paddr, dma_addr_t addr)
1377 #if (BITS_PER_LONG == 64)
1378 paddr->High = ((unsigned long) addr) >> 32;
1379 paddr->Low = ((unsigned long) addr) & 0xffffffff;
1380 #else
1381 paddr->High = 0;
1382 paddr->Low = (unsigned long) addr;
1383 #endif
1386 void
1387 MM_SetT3Addr(T3_64BIT_HOST_ADDR *paddr, dma_addr_t addr)
1389 unsigned long baddr = (unsigned long) addr;
1390 #if (BITS_PER_LONG == 64)
1391 set_64bit_addr(paddr, baddr & 0xffffffff, baddr >> 32);
1392 #else
1393 set_64bit_addr(paddr, baddr, 0);
1394 #endif
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.
1406 void
1407 atomic_set(atomic_t* entry, int val)
1409 entry->counter = val;
1412 atomic_read(atomic_t* entry)
1414 return entry->counter;
1416 void
1417 atomic_inc(atomic_t* entry)
1419 if(entry)
1420 entry->counter++;
1423 void
1424 atomic_dec(atomic_t* entry)
1426 if(entry)
1427 entry->counter--;
1430 void
1431 atomic_sub(int a, atomic_t* entry)
1433 if(entry)
1434 entry->counter -= a;
1437 void
1438 atomic_add(int a, atomic_t* entry)
1440 if(entry)
1441 entry->counter += a;
1444 /******************************************************************************/
1445 /* Description: */
1446 /* */
1447 /* Return: */
1448 /******************************************************************************/
1449 void
1450 QQ_InitQueue(
1451 PQQ_CONTAINER pQueue,
1452 unsigned int QueueSize) {
1453 pQueue->Head = 0;
1454 pQueue->Tail = 0;
1455 pQueue->Size = QueueSize+1;
1456 atomic_set(&pQueue->EntryCnt, 0);
1457 } /* QQ_InitQueue */
1460 /******************************************************************************/
1461 /* Description: */
1462 /* */
1463 /* Return: */
1464 /******************************************************************************/
1465 char
1466 QQ_Full(
1467 PQQ_CONTAINER pQueue) {
1468 unsigned int NewHead;
1470 NewHead = (pQueue->Head + 1) % pQueue->Size;
1472 return(NewHead == pQueue->Tail);
1473 } /* QQ_Full */
1476 /******************************************************************************/
1477 /* Description: */
1478 /* */
1479 /* Return: */
1480 /******************************************************************************/
1481 char
1482 QQ_Empty(
1483 PQQ_CONTAINER pQueue) {
1484 return(pQueue->Head == pQueue->Tail);
1485 } /* QQ_Empty */
1488 /******************************************************************************/
1489 /* Description: */
1490 /* */
1491 /* Return: */
1492 /******************************************************************************/
1493 unsigned int
1494 QQ_GetSize(
1495 PQQ_CONTAINER pQueue) {
1496 return pQueue->Size;
1497 } /* QQ_GetSize */
1500 /******************************************************************************/
1501 /* Description: */
1502 /* */
1503 /* Return: */
1504 /******************************************************************************/
1505 unsigned int
1506 QQ_GetEntryCnt(
1507 PQQ_CONTAINER pQueue) {
1508 return atomic_read(&pQueue->EntryCnt);
1509 } /* QQ_GetEntryCnt */
1512 /******************************************************************************/
1513 /* Description: */
1514 /* */
1515 /* Return: */
1516 /* TRUE entry was added successfully. */
1517 /* FALSE queue is full. */
1518 /******************************************************************************/
1519 char
1520 QQ_PushHead(
1521 PQQ_CONTAINER pQueue,
1522 PQQ_ENTRY pEntry) {
1523 unsigned int Head;
1525 Head = (pQueue->Head + 1) % pQueue->Size;
1527 #if !defined(QQ_NO_OVERFLOW_CHECK)
1528 if(Head == pQueue->Tail) {
1529 return 0;
1530 } /* if */
1531 #endif /* QQ_NO_OVERFLOW_CHECK */
1533 pQueue->Array[pQueue->Head] = pEntry;
1534 wmb();
1535 pQueue->Head = Head;
1536 atomic_inc(&pQueue->EntryCnt);
1538 return -1;
1539 } /* QQ_PushHead */
1542 /******************************************************************************/
1543 /* Description: */
1544 /* */
1545 /* Return: */
1546 /* TRUE entry was added successfully. */
1547 /* FALSE queue is full. */
1548 /******************************************************************************/
1549 char
1550 QQ_PushTail(
1551 PQQ_CONTAINER pQueue,
1552 PQQ_ENTRY pEntry) {
1553 unsigned int Tail;
1555 Tail = pQueue->Tail;
1556 if(Tail == 0) {
1557 Tail = pQueue->Size;
1558 } /* if */
1559 Tail--;
1561 #if !defined(QQ_NO_OVERFLOW_CHECK)
1562 if(Tail == pQueue->Head) {
1563 return 0;
1564 } /* if */
1565 #endif /* QQ_NO_OVERFLOW_CHECK */
1567 pQueue->Array[Tail] = pEntry;
1568 wmb();
1569 pQueue->Tail = Tail;
1570 atomic_inc(&pQueue->EntryCnt);
1572 return -1;
1573 } /* QQ_PushTail */
1576 /******************************************************************************/
1577 /* Description: */
1578 /* */
1579 /* Return: */
1580 /******************************************************************************/
1581 PQQ_ENTRY
1582 QQ_PopHead(
1583 PQQ_CONTAINER pQueue) {
1584 unsigned int Head;
1585 PQQ_ENTRY Entry;
1587 Head = pQueue->Head;
1589 #if !defined(QQ_NO_UNDERFLOW_CHECK)
1590 if(Head == pQueue->Tail) {
1591 return (PQQ_ENTRY) 0;
1592 } /* if */
1593 #endif /* QQ_NO_UNDERFLOW_CHECK */
1595 if(Head == 0) {
1596 Head = pQueue->Size;
1597 } /* if */
1598 Head--;
1600 Entry = pQueue->Array[Head];
1601 membar();
1603 pQueue->Head = Head;
1604 atomic_dec(&pQueue->EntryCnt);
1606 return Entry;
1607 } /* QQ_PopHead */
1610 /******************************************************************************/
1611 /* Description: */
1612 /* */
1613 /* Return: */
1614 /******************************************************************************/
1615 PQQ_ENTRY
1616 QQ_PopTail(
1617 PQQ_CONTAINER pQueue) {
1618 unsigned int Tail;
1619 PQQ_ENTRY Entry;
1621 Tail = pQueue->Tail;
1623 #if !defined(QQ_NO_UNDERFLOW_CHECK)
1624 if(Tail == pQueue->Head) {
1625 return (PQQ_ENTRY) 0;
1626 } /* if */
1627 #endif /* QQ_NO_UNDERFLOW_CHECK */
1629 Entry = pQueue->Array[Tail];
1630 membar();
1631 pQueue->Tail = (Tail + 1) % pQueue->Size;
1632 atomic_dec(&pQueue->EntryCnt);
1634 return Entry;
1635 } /* QQ_PopTail */
1638 /******************************************************************************/
1639 /* Description: */
1640 /* */
1641 /* Return: */
1642 /******************************************************************************/
1643 PQQ_ENTRY
1644 QQ_GetHead(
1645 PQQ_CONTAINER pQueue,
1646 unsigned int Idx)
1648 if(Idx >= atomic_read(&pQueue->EntryCnt))
1650 return (PQQ_ENTRY) 0;
1653 if(pQueue->Head > Idx)
1655 Idx = pQueue->Head - Idx;
1657 else
1659 Idx = pQueue->Size - (Idx - pQueue->Head);
1661 Idx--;
1663 return pQueue->Array[Idx];
1667 /******************************************************************************/
1668 /* Description: */
1669 /* */
1670 /* Return: */
1671 /******************************************************************************/
1672 PQQ_ENTRY
1673 QQ_GetTail(
1674 PQQ_CONTAINER pQueue,
1675 unsigned int Idx)
1677 if(Idx >= atomic_read(&pQueue->EntryCnt))
1679 return (PQQ_ENTRY) 0;
1682 Idx += pQueue->Tail;
1683 if(Idx >= pQueue->Size)
1685 Idx = Idx - pQueue->Size;
1688 return pQueue->Array[Idx];
1691 #endif /* CFG_CMD_NET, !CONFIG_NET_MULTI, CONFIG_BCM570x */