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