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