blob: c250d446f14528cea4a45ade0f972eccbc34956b [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
wdenkcc1c8a12002-11-02 22:58:18 +00009#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
wdenkcc1c8a12002-11-02 22:58:18 +000018/*
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 */
Wolfgang Denka1be4762008-05-20 16:00:29 +020027#define BCM570X_MBAR 0x80100000
wdenkcc1c8a12002-11-02 22:58:18 +000028#define BCM570X_ILINE 1
29
wdenkcc1c8a12002-11-02 22:58:18 +000030#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;
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070037volatile PLM_DEVICE_BLOCK pDevice = NULL; /* 570x softc */
38volatile PUM_DEVICE_BLOCK pUmDevice = NULL;
wdenkcc1c8a12002-11-02 22:58:18 +000039
40/* Used to pass the full-duplex flag, etc. */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070041int 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 };
wdenkcc1c8a12002-11-02 22:58:18 +000049
50#if JUMBO_FRAMES
51/* Jumbo MTU for interfaces. */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070052static int mtu[MAX_UNITS] = { 0, 0, 0, 0 };
wdenkcc1c8a12002-11-02 22:58:18 +000053#endif
54
55/* Turn on Wake-on lan for a device unit */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070056static int enable_wol[MAX_UNITS] = { 0, 0, 0, 0 };
wdenkcc1c8a12002-11-02 22:58:18 +000057
58#define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNT
59static unsigned int tx_pkt_desc_cnt[MAX_UNITS] =
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070060 { TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT };
wdenkcc1c8a12002-11-02 22:58:18 +000061
62#define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNT
63static unsigned int rx_std_desc_cnt[MAX_UNITS] =
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070064 { RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT };
wdenkcc1c8a12002-11-02 22:58:18 +000065
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070066static unsigned int rx_adaptive_coalesce[MAX_UNITS] = { 1, 1, 1, 1 };
wdenkcc1c8a12002-11-02 22:58:18 +000067
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] =
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070071 { JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT };
wdenkcc1c8a12002-11-02 22:58:18 +000072#endif
73#define RX_COAL_TK DEFAULT_RX_COALESCING_TICKS
74static unsigned int rx_coalesce_ticks[MAX_UNITS] =
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070075 { RX_COAL_TK, RX_COAL_TK, RX_COAL_TK, RX_COAL_TK };
wdenkcc1c8a12002-11-02 22:58:18 +000076
77#define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMES
78static unsigned int rx_max_coalesce_frames[MAX_UNITS] =
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070079 { RX_COAL_FM, RX_COAL_FM, RX_COAL_FM, RX_COAL_FM };
wdenkcc1c8a12002-11-02 22:58:18 +000080
81#define TX_COAL_TK DEFAULT_TX_COALESCING_TICKS
82static unsigned int tx_coalesce_ticks[MAX_UNITS] =
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070083 { TX_COAL_TK, TX_COAL_TK, TX_COAL_TK, TX_COAL_TK };
wdenkcc1c8a12002-11-02 22:58:18 +000084
85#define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMES
86static unsigned int tx_max_coalesce_frames[MAX_UNITS] =
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070087 { TX_COAL_FM, TX_COAL_FM, TX_COAL_FM, TX_COAL_FM };
wdenkcc1c8a12002-11-02 22:58:18 +000088
89#define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKS
90static unsigned int stats_coalesce_ticks[MAX_UNITS] =
Vadim Bendebury6ddfee52007-05-24 15:52:25 -070091 { ST_COAL_TK, ST_COAL_TK, ST_COAL_TK, ST_COAL_TK };
wdenkcc1c8a12002-11-02 22:58:18 +000092
wdenkcc1c8a12002-11-02 22:58:18 +000093/*
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 {
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700131 char *name;
wdenkcc1c8a12002-11-02 22:58:18 +0000132} chip_rev[] = {
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700133 {
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}
wdenkcc1c8a12002-11-02 22:58:18 +0000165};
166
wdenkcc1c8a12002-11-02 22:58:18 +0000167/* indexed by board_t, above */
168static struct {
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700169 char *name;
wdenkcc1c8a12002-11-02 22:58:18 +0000170} board_info[] = {
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700171 {
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},};
wdenkcc1c8a12002-11-02 22:58:18 +0000203
204/* PCI Devices which use the 570x chipset */
205struct pci_device_table {
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700206 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000211} bcm570xDevices[] = {
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700212 {
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}
wdenkcc1c8a12002-11-02 22:58:18 +0000264};
265
266#define n570xDevices (sizeof(bcm570xDevices)/sizeof(bcm570xDevices[0]))
267
wdenkcc1c8a12002-11-02 22:58:18 +0000268/*
269 * Allocate a packet buffer from the bcm570x packet pool.
270 */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700271void *bcm570xPktAlloc (int u, int pksize)
wdenkcc1c8a12002-11-02 22:58:18 +0000272{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700273 return malloc (pksize);
wdenkcc1c8a12002-11-02 22:58:18 +0000274}
275
276/*
277 * Free a packet previously allocated from the bcm570x packet
278 * buffer pool.
279 */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700280void bcm570xPktFree (int u, void *p)
wdenkcc1c8a12002-11-02 22:58:18 +0000281{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700282 free (p);
wdenkcc1c8a12002-11-02 22:58:18 +0000283}
284
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700285int bcm570xReplenishRxBuffers (PUM_DEVICE_BLOCK pUmDevice)
wdenkcc1c8a12002-11-02 22:58:18 +0000286{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700287 PLM_PACKET pPacket;
288 PUM_PACKET pUmPacket;
289 void *skb;
290 int queue_rx = 0;
291 int ret = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000292
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700293 while ((pUmPacket = (PUM_PACKET)
294 QQ_PopHead (&pUmDevice->rx_out_of_buf_q.Container)) != 0) {
wdenkcc1c8a12002-11-02 22:58:18 +0000295
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700296 pPacket = (PLM_PACKET) pUmPacket;
wdenkcc1c8a12002-11-02 22:58:18 +0000297
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700298 /* 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000314
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700315 pUmPacket->skbuff = skb;
316 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
317 queue_rx = 1;
318 }
wdenkcc1c8a12002-11-02 22:58:18 +0000319
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700320 if (queue_rx) {
321 LM_QueueRxPackets (pDevice);
322 }
wdenkcc1c8a12002-11-02 22:58:18 +0000323
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700324 return ret;
wdenkcc1c8a12002-11-02 22:58:18 +0000325}
326
327/*
328 * Probe, Map, and Init 570x device.
329 */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700330int eth_init (bd_t * bis)
wdenkcc1c8a12002-11-02 22:58:18 +0000331{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700332 int i, rv, devFound = FALSE;
333 pci_dev_t devbusfn;
334 unsigned short status;
wdenkcc1c8a12002-11-02 22:58:18 +0000335
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700336 /* 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 {
wdenkcc1c8a12002-11-02 22:58:18 +0000343
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700344 /* Set ILINE */
345 pci_write_config_byte (devbusfn,
346 PCI_INTERRUPT_LINE,
347 BCM570X_ILINE);
wdenkcc1c8a12002-11-02 22:58:18 +0000348
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700349 /*
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);
wdenkcc1c8a12002-11-02 22:58:18 +0000355
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700356 ioBase = BCM570X_MBAR;
wdenkcc1c8a12002-11-02 22:58:18 +0000357
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700358 pci_write_config_dword (devbusfn,
359 PCI_BASE_ADDRESS_0, ioBase);
wdenkcc1c8a12002-11-02 22:58:18 +0000360
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700361 /*
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);
wdenkcc1c8a12002-11-02 22:58:18 +0000366
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700367 status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
wdenkcc1c8a12002-11-02 22:58:18 +0000368
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700369 pci_write_config_word (devbusfn, PCI_COMMAND, status);
wdenkcc1c8a12002-11-02 22:58:18 +0000370
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700371 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);
wdenkcc1c8a12002-11-02 22:58:18 +0000376
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700377 /* 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000383
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700384 /* 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000392 }
wdenkcc1c8a12002-11-02 22:58:18 +0000393
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700394 if (!devFound) {
395 printf
396 ("eth_init: FAILURE: no BCM570x Ethernet devices found.\n");
397 return -1;
398 }
wdenkcc1c8a12002-11-02 22:58:18 +0000399
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700400 /* Setup defaults for chip */
wdenkcc1c8a12002-11-02 22:58:18 +0000401 pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
wdenkcc1c8a12002-11-02 22:58:18 +0000402
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700403 if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) {
404 pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
405 } else {
406
407 if (rx_checksum[i]) {
408 pDevice->TaskToOffload |=
409 LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
410 LM_TASK_OFFLOAD_RX_UDP_CHECKSUM;
411 }
wdenkcc1c8a12002-11-02 22:58:18 +0000412
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700413 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000419 }
wdenkcc1c8a12002-11-02 22:58:18 +0000420
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700421 /* Set Device PCI Memory base address */
422 pDevice->pMappedMemBase = (PLM_UINT8) ioBase;
wdenkcc1c8a12002-11-02 22:58:18 +0000423
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700424 /* 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;
428 }
wdenkcc1c8a12002-11-02 22:58:18 +0000429
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700430 /* Lock not needed */
431 pUmDevice->do_global_lock = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000432
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700433 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000438
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700439 /* Setup timer delays */
440 if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
441 pDevice->UseTaggedStatus = TRUE;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200442 pUmDevice->timer_interval = CONFIG_SYS_HZ;
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700443 } else {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200444 pUmDevice->timer_interval = CONFIG_SYS_HZ / 50;
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700445 }
wdenkcc1c8a12002-11-02 22:58:18 +0000446
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700447 /* 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);
wdenkcc1c8a12002-11-02 22:58:18 +0000452
Mike Frysinger061af9d2009-02-11 19:04:25 -0500453 eth_getenv_enetaddr("ethaddr", pDevice->NodeAddress);
454 LM_SetMacAddress (pDevice);
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700455 /* 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000459
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700460 /* delay for 4 seconds */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200461 pUmDevice->delayed_link_ind = (4 * CONFIG_SYS_HZ) / pUmDevice->timer_interval;
wdenkcc1c8a12002-11-02 22:58:18 +0000462
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200463 pUmDevice->adaptive_expiry = CONFIG_SYS_HZ / pUmDevice->timer_interval;
wdenkcc1c8a12002-11-02 22:58:18 +0000464
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700465 /* 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 =
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200469 (3 * CONFIG_SYS_HZ) / pUmDevice->timer_interval;
wdenkcc1c8a12002-11-02 22:58:18 +0000470
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700471 /* Initialize 570x */
472 if (LM_InitializeAdapter (pDevice) != LM_STATUS_SUCCESS) {
473 printf ("ERROR: Adapter initialization failed.\n");
474 return ERROR;
475 }
wdenkcc1c8a12002-11-02 22:58:18 +0000476
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700477 /* Enable chip ISR */
478 LM_EnableInterrupt (pDevice);
wdenkcc1c8a12002-11-02 22:58:18 +0000479
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700480 /* Clear MC table */
481 LM_MulticastClear (pDevice);
wdenkcc1c8a12002-11-02 22:58:18 +0000482
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700483 /* Enable Multicast */
484 LM_SetReceiveMask (pDevice,
485 pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST);
wdenkcc1c8a12002-11-02 22:58:18 +0000486
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700487 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]);
496 }
497 printf ("\n");
wdenkcc1c8a12002-11-02 22:58:18 +0000498
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700499 printf ("eth%d: ", pDevice->index);
500 printf ("%s with ", chip_rev[bcm570xDevices[i].board_id].name);
wdenkcc1c8a12002-11-02 22:58:18 +0000501
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700502 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");
wdenkcc1c8a12002-11-02 22:58:18 +0000519
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700520 printf ("eth%d: %s, MTU: %d,",
521 pDevice->index, pDevice->BusSpeedStr, 1500);
wdenkcc1c8a12002-11-02 22:58:18 +0000522
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700523 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++;
wdenkcc1c8a12002-11-02 22:58:18 +0000528
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700529 return 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000530}
531
532/* Ethernet Interrupt service routine */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700533void eth_isr (void)
wdenkcc1c8a12002-11-02 22:58:18 +0000534{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700535 LM_UINT32 oldtag, newtag;
536 int i;
wdenkcc1c8a12002-11-02 22:58:18 +0000537
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700538 pUmDevice->interrupt = 1;
wdenkcc1c8a12002-11-02 22:58:18 +0000539
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700540 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000545
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700546 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000568
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700569 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000576 }
wdenkcc1c8a12002-11-02 22:58:18 +0000577
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700578 /* Allocate new RX buffers */
579 if (QQ_GetEntryCnt (&pUmDevice->rx_out_of_buf_q.Container)) {
580 bcm570xReplenishRxBuffers (pUmDevice);
581 }
wdenkcc1c8a12002-11-02 22:58:18 +0000582
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700583 /* Queue packets */
584 if (QQ_GetEntryCnt (&pDevice->RxPacketFreeQ.Container)) {
585 LM_QueueRxPackets (pDevice);
586 }
wdenkcc1c8a12002-11-02 22:58:18 +0000587
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700588 if (pUmDevice->tx_queued) {
589 pUmDevice->tx_queued = 0;
590 }
wdenkcc1c8a12002-11-02 22:58:18 +0000591
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700592 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000598 }
wdenkcc1c8a12002-11-02 22:58:18 +0000599
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700600 pUmDevice->interrupt = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000601
602}
603
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700604int eth_send (volatile void *packet, int length)
wdenkcc1c8a12002-11-02 22:58:18 +0000605{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700606 int status = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000607#if ET_DEBUG
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700608 unsigned char *ptr = (unsigned char *)packet;
wdenkcc1c8a12002-11-02 22:58:18 +0000609#endif
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700610 PLM_PACKET pPacket;
611 PUM_PACKET pUmPacket;
wdenkcc1c8a12002-11-02 22:58:18 +0000612
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700613 /* Link down, return */
614 while (pDevice->LinkStatus == LM_STATUS_LINK_DOWN) {
wdenkcc1c8a12002-11-02 22:58:18 +0000615#if 0
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700616 printf ("eth%d: link down - check cable or link partner.\n",
617 pUmDevice->index);
wdenkcc1c8a12002-11-02 22:58:18 +0000618#endif
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700619 eth_isr ();
wdenkcc1c8a12002-11-02 22:58:18 +0000620
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700621 /* Wait to see link for one-half a second before sending ... */
622 udelay (1500000);
wdenkcc1c8a12002-11-02 22:58:18 +0000623
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700624 }
wdenkcc1c8a12002-11-02 22:58:18 +0000625
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700626 /* Clear sent flag */
627 pUmDevice->tx_pkt = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000628
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700629 /* Previously blocked */
630 if (pUmDevice->tx_full) {
631 printf ("eth%d: tx blocked.\n", pUmDevice->index);
632 return 0;
633 }
wdenkcc1c8a12002-11-02 22:58:18 +0000634
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700635 pPacket = (PLM_PACKET)
636 QQ_PopHead (&pDevice->TxPacketFreeQ.Container);
wdenkcc1c8a12002-11-02 22:58:18 +0000637
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700638 if (pPacket == 0) {
639 pUmDevice->tx_full = 1;
640 printf ("bcm570xEndSend: TX full!\n");
641 return 0;
642 }
wdenkcc1c8a12002-11-02 22:58:18 +0000643
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700644 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000649 }
wdenkcc1c8a12002-11-02 22:58:18 +0000650
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700651 if (length <= 0) {
652 printf ("eth: bad packet size: %d\n", length);
653 goto out;
654 }
wdenkcc1c8a12002-11-02 22:58:18 +0000655
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700656 /* 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.
wdenk57b2d802003-06-27 21:31:46 +0000661 */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700662 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000673 }
674
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700675 /* 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000703 }
wdenkcc1c8a12002-11-02 22:58:18 +0000704
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700705 while (pUmDevice->tx_pkt == 0) {
706 /* Service TX */
707 eth_isr ();
708 }
wdenkcc1c8a12002-11-02 22:58:18 +0000709#if ET_DEBUG
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700710 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]);
wdenkcc1c8a12002-11-02 22:58:18 +0000716#endif
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700717 pUmDevice->tx_pkt = 0;
718 QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
wdenkcc1c8a12002-11-02 22:58:18 +0000719
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700720 /* Done with send */
721 out:
722 return status;
wdenkcc1c8a12002-11-02 22:58:18 +0000723}
724
wdenkcc1c8a12002-11-02 22:58:18 +0000725/* Ethernet receive */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700726int eth_rx (void)
wdenkcc1c8a12002-11-02 22:58:18 +0000727{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700728 PLM_PACKET pPacket = NULL;
729 PUM_PACKET pUmPacket = NULL;
730 void *skb;
731 int size = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000732
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700733 while (TRUE) {
wdenkcc1c8a12002-11-02 22:58:18 +0000734
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700735 bcm570x_service_isr:
736 /* Pull down packet if it is there */
737 eth_isr ();
wdenkcc1c8a12002-11-02 22:58:18 +0000738
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700739 /* 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000747
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700748 pPacket = (PLM_PACKET)
749 QQ_PopHead (&pDevice->RxPacketReceivedQ.Container);
wdenkcc1c8a12002-11-02 22:58:18 +0000750
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700751 if (pPacket == 0) {
752 printf ("eth_rx: empty packet!\n");
753 goto bcm570x_service_isr;
754 }
wdenkcc1c8a12002-11-02 22:58:18 +0000755
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700756 pUmPacket = (PUM_PACKET) pPacket;
wdenkcc1c8a12002-11-02 22:58:18 +0000757#if ET_DEBUG
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700758 printf ("eth_rx: packet @0x%x\n", (int)pPacket);
wdenkcc1c8a12002-11-02 22:58:18 +0000759#endif
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700760 /* If the packet generated an error, reuse buffer */
761 if ((pPacket->PacketStatus != LM_STATUS_SUCCESS) ||
762 ((size = pPacket->PacketSize) > pDevice->RxMtu)) {
wdenkcc1c8a12002-11-02 22:58:18 +0000763
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700764 /* 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000770
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700771 /* Set size and address */
772 skb = pUmPacket->skbuff;
773 size = pPacket->PacketSize;
wdenkcc1c8a12002-11-02 22:58:18 +0000774
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700775 /* Pass the packet up to the protocol
776 * layers.
777 */
778 NetReceive (skb, size);
wdenkcc1c8a12002-11-02 22:58:18 +0000779
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700780 /* Free packet buffer */
781 bcm570xPktFree (pUmDevice->index, skb);
782 pUmPacket->skbuff = NULL;
wdenkcc1c8a12002-11-02 22:58:18 +0000783
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700784 /* Reuse SKB */
785 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
wdenkcc1c8a12002-11-02 22:58:18 +0000786
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700787 return 0; /* Got a packet, bail ... */
788 }
789 return size;
wdenkcc1c8a12002-11-02 22:58:18 +0000790}
791
wdenkcc1c8a12002-11-02 22:58:18 +0000792/* Shut down device */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700793void eth_halt (void)
wdenkcc1c8a12002-11-02 22:58:18 +0000794{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700795 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);
wdenkcc1c8a12002-11-02 22:58:18 +0000805
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700806 /* 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");
wdenkcc1c8a12002-11-02 22:58:18 +0000823 }
wdenkcc1c8a12002-11-02 22:58:18 +0000824}
825
wdenkcc1c8a12002-11-02 22:58:18 +0000826/*
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 */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700834int MM_Packet_Desc_Size = sizeof (UM_PACKET);
wdenkcc1c8a12002-11-02 22:58:18 +0000835
836LM_STATUS
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700837MM_ReadConfig32 (PLM_DEVICE_BLOCK pDevice,
838 LM_UINT32 Offset, LM_UINT32 * pValue32)
wdenkcc1c8a12002-11-02 22:58:18 +0000839{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700840 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000844}
845
wdenkcc1c8a12002-11-02 22:58:18 +0000846LM_STATUS
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700847MM_WriteConfig32 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT32 Value32)
wdenkcc1c8a12002-11-02 22:58:18 +0000848{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700849 UM_DEVICE_BLOCK *pUmDevice;
850 pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
851 pci_write_config_dword (pUmDevice->pdev, Offset, Value32);
852 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000853}
854
wdenkcc1c8a12002-11-02 22:58:18 +0000855LM_STATUS
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700856MM_ReadConfig16 (PLM_DEVICE_BLOCK pDevice,
857 LM_UINT32 Offset, LM_UINT16 * pValue16)
wdenkcc1c8a12002-11-02 22:58:18 +0000858{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700859 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000863}
864
865LM_STATUS
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700866MM_WriteConfig16 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT16 Value16)
wdenkcc1c8a12002-11-02 22:58:18 +0000867{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700868 UM_DEVICE_BLOCK *pUmDevice;
869 pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
870 pci_write_config_word (pUmDevice->pdev, Offset, Value16);
871 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000872}
873
wdenkcc1c8a12002-11-02 22:58:18 +0000874LM_STATUS
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700875MM_AllocateSharedMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
876 PLM_VOID * pMemoryBlockVirt,
877 PLM_PHYSICAL_ADDRESS pMemoryBlockPhy, LM_BOOL Cached)
wdenkcc1c8a12002-11-02 22:58:18 +0000878{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700879 PLM_VOID pvirt;
880 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
881 dma_addr_t mapping;
wdenkcc1c8a12002-11-02 22:58:18 +0000882
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700883 pvirt = malloc (BlockSize);
884 mapping = (dma_addr_t) (pvirt);
885 if (!pvirt)
886 return LM_STATUS_FAILURE;
wdenkcc1c8a12002-11-02 22:58:18 +0000887
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700888 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);
wdenkcc1c8a12002-11-02 22:58:18 +0000892
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700893 *pMemoryBlockVirt = (PLM_VOID) pvirt;
894 MM_SetAddr (pMemoryBlockPhy, (dma_addr_t) mapping);
wdenkcc1c8a12002-11-02 22:58:18 +0000895
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700896 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000897}
898
wdenkcc1c8a12002-11-02 22:58:18 +0000899LM_STATUS
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700900MM_AllocateMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
901 PLM_VOID * pMemoryBlockVirt)
wdenkcc1c8a12002-11-02 22:58:18 +0000902{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700903 PLM_VOID pvirt;
904 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
wdenkcc1c8a12002-11-02 22:58:18 +0000905
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700906 pvirt = malloc (BlockSize);
wdenkcc1c8a12002-11-02 22:58:18 +0000907
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700908 if (!pvirt)
909 return LM_STATUS_FAILURE;
wdenkcc1c8a12002-11-02 22:58:18 +0000910
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700911 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000916
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700917 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000918}
919
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700920LM_STATUS MM_MapMemBase (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +0000921{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700922 printf ("BCM570x PCI Memory base address @0x%x\n",
923 (unsigned int)pDevice->pMappedMemBase);
924 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000925}
926
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700927LM_STATUS MM_InitializeUmPackets (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +0000928{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700929 int i;
930 void *skb;
931 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
932 PUM_PACKET pUmPacket = NULL;
933 PLM_PACKET pPacket = NULL;
wdenkcc1c8a12002-11-02 22:58:18 +0000934
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700935 for (i = 0; i < pDevice->RxPacketDescCnt; i++) {
936 pPacket = QQ_PopHead (&pDevice->RxPacketFreeQ.Container);
937 pUmPacket = (PUM_PACKET) pPacket;
wdenkcc1c8a12002-11-02 22:58:18 +0000938
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700939 if (pPacket == 0) {
940 printf ("MM_InitializeUmPackets: Bad RxPacketFreeQ\n");
941 }
wdenkcc1c8a12002-11-02 22:58:18 +0000942
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700943 skb = bcm570xPktAlloc (pUmDevice->index,
944 pPacket->u.Rx.RxBufferSize + 2);
wdenkcc1c8a12002-11-02 22:58:18 +0000945
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700946 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000953
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700954 pUmPacket->skbuff = skb;
955 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
956 }
wdenkcc1c8a12002-11-02 22:58:18 +0000957
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700958 pUmDevice->rx_low_buf_thresh = pDevice->RxPacketDescCnt / 8;
wdenkcc1c8a12002-11-02 22:58:18 +0000959
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700960 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000961}
962
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700963LM_STATUS MM_GetConfig (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +0000964{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700965 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
966 int index = pDevice->index;
wdenkcc1c8a12002-11-02 22:58:18 +0000967
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700968 if (auto_speed[index] == 0)
969 pDevice->DisableAutoNeg = TRUE;
970 else
971 pDevice->DisableAutoNeg = FALSE;
wdenkcc1c8a12002-11-02 22:58:18 +0000972
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700973 if (line_speed[index] == 0) {
974 pDevice->RequestedMediaType = LM_REQUESTED_MEDIA_TYPE_AUTO;
wdenkcc1c8a12002-11-02 22:58:18 +0000975 pDevice->DisableAutoNeg = FALSE;
Vadim Bendebury6ddfee52007-05-24 15:52:25 -0700976 } 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
wdenkcc1c8a12002-11-02 22:58:18 +00001012 }
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001013 pDevice->FlowControlCap = 0;
1014 if (rx_flow_control[index] != 0) {
1015 pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
wdenkcc1c8a12002-11-02 22:58:18 +00001016 }
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001017 if (tx_flow_control[index] != 0) {
1018 pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
wdenkcc1c8a12002-11-02 22:58:18 +00001019 }
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001020 if ((auto_flow_control[index] != 0) &&
1021 (pDevice->DisableAutoNeg == FALSE)) {
wdenkcc1c8a12002-11-02 22:58:18 +00001022
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001023 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 }
wdenkcc1c8a12002-11-02 22:58:18 +00001030 }
wdenkcc1c8a12002-11-02 22:58:18 +00001031
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001032 /* Default MTU for now */
1033 pUmDevice->mtu = 1500;
wdenkcc1c8a12002-11-02 22:58:18 +00001034
1035#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001036 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];
wdenkcc1c8a12002-11-02 22:58:18 +00001043#else
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001044 pDevice->RxMtu = pUmDevice->mtu;
wdenkcc1c8a12002-11-02 22:58:18 +00001045#endif
1046
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001047 if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
1048 pDevice->UseTaggedStatus = TRUE;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001049 pUmDevice->timer_interval = CONFIG_SYS_HZ;
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001050 } else {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001051 pUmDevice->timer_interval = CONFIG_SYS_HZ / 50;
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001052 }
wdenkcc1c8a12002-11-02 22:58:18 +00001053
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001054 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;
wdenkcc1c8a12002-11-02 22:58:18 +00001063
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001064 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;
wdenkcc1c8a12002-11-02 22:58:18 +00001078 }
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001079 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;
wdenkcc1c8a12002-11-02 22:58:18 +00001085
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001086 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;
wdenkcc1c8a12002-11-02 22:58:18 +00001091
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001092 /* Don't update status blocks during interrupt */
1093 pDevice->RxCoalescingTicksDuringInt = 0;
1094 pDevice->TxCoalescingTicksDuringInt = 0;
wdenkcc1c8a12002-11-02 22:58:18 +00001095
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001096 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001097
1098}
1099
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001100LM_STATUS MM_StartTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
wdenkcc1c8a12002-11-02 22:58:18 +00001101{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001102 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);
wdenkcc1c8a12002-11-02 22:58:18 +00001105
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001106 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001107}
1108
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001109LM_STATUS MM_CompleteTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
wdenkcc1c8a12002-11-02 22:58:18 +00001110{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001111 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;
wdenkcc1c8a12002-11-02 22:58:18 +00001115}
1116
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001117LM_STATUS MM_IndicateStatus (PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
wdenkcc1c8a12002-11-02 22:58:18 +00001118{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001119 char buf[128];
1120 char lcd[4];
1121 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1122 LM_FLOW_CONTROL flow_control;
wdenkcc1c8a12002-11-02 22:58:18 +00001123
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001124 pUmDevice->delayed_link_ind = 0;
1125 memset (lcd, 0x0, 4);
wdenkcc1c8a12002-11-02 22:58:18 +00001126
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001127 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);
wdenkcc1c8a12002-11-02 22:58:18 +00001136
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001137 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");
wdenkcc1c8a12002-11-02 22:58:18 +00001161
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001162 flow_control = pDevice->FlowControl &
1163 (LM_FLOW_CONTROL_RECEIVE_PAUSE |
1164 LM_FLOW_CONTROL_TRANSMIT_PAUSE);
wdenkcc1c8a12002-11-02 22:58:18 +00001165
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001166 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);
wdenkcc1c8a12002-11-02 22:58:18 +00001181 }
wdenkcc1c8a12002-11-02 22:58:18 +00001182#if 0
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001183 sysLedDsply (lcd[0], lcd[1], lcd[2], lcd[3]);
wdenkcc1c8a12002-11-02 22:58:18 +00001184#endif
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001185 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001186}
1187
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001188LM_STATUS MM_FreeRxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
wdenkcc1c8a12002-11-02 22:58:18 +00001189{
1190
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001191 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1192 PUM_PACKET pUmPacket;
1193 void *skb;
wdenkcc1c8a12002-11-02 22:58:18 +00001194
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001195 pUmPacket = (PUM_PACKET) pPacket;
wdenkcc1c8a12002-11-02 22:58:18 +00001196
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001197 if ((skb = pUmPacket->skbuff))
1198 bcm570xPktFree (pUmDevice->index, skb);
wdenkcc1c8a12002-11-02 22:58:18 +00001199
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001200 pUmPacket->skbuff = 0;
wdenkcc1c8a12002-11-02 22:58:18 +00001201
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001202 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001203}
1204
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001205unsigned long MM_AnGetCurrentTime_us (PAN_STATE_INFO pAnInfo)
wdenkcc1c8a12002-11-02 22:58:18 +00001206{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001207 return get_timer (0);
wdenkcc1c8a12002-11-02 22:58:18 +00001208}
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 */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001220LM_STATUS MM_CoalesceTxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
wdenkcc1c8a12002-11-02 22:58:18 +00001221{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001222 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1223 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1224 void *skbnew;
1225 int len = 0;
wdenkcc1c8a12002-11-02 22:58:18 +00001226
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001227 if (len == 0)
1228 return (LM_STATUS_SUCCESS);
wdenkcc1c8a12002-11-02 22:58:18 +00001229
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001230 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 }
wdenkcc1c8a12002-11-02 22:58:18 +00001235
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001236 skbnew = bcm570xPktAlloc (pUmDevice->index, MAX_PACKET_SIZE);
wdenkcc1c8a12002-11-02 22:58:18 +00001237
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001238 if (skbnew == NULL) {
1239 pUmDevice->tx_full = 1;
1240 printf ("eth%d: out of transmit buffers", pUmDevice->index);
1241 return (LM_STATUS_FAILURE);
1242 }
wdenkcc1c8a12002-11-02 22:58:18 +00001243
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001244 /* New packet values */
1245 pUmPacket->skbuff = skbnew;
1246 pUmPacket->lm_packet.u.Tx.FragCount = 1;
wdenkcc1c8a12002-11-02 22:58:18 +00001247
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001248 return (LM_STATUS_SUCCESS);
wdenkcc1c8a12002-11-02 22:58:18 +00001249}
1250
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001251LM_STATUS MM_IndicateRxPackets (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +00001252{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001253 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1254 pUmDevice->rx_pkt = 1;
1255 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001256}
1257
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001258LM_STATUS MM_IndicateTxPackets (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +00001259{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001260 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1261 PLM_PACKET pPacket;
1262 PUM_PACKET pUmPacket;
1263 void *skb;
1264 while (TRUE) {
wdenkcc1c8a12002-11-02 22:58:18 +00001265
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001266 pPacket = (PLM_PACKET)
1267 QQ_PopHead (&pDevice->TxPacketXmittedQ.Container);
wdenkcc1c8a12002-11-02 22:58:18 +00001268
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001269 if (pPacket == 0)
1270 break;
wdenkcc1c8a12002-11-02 22:58:18 +00001271
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001272 pUmPacket = (PUM_PACKET) pPacket;
1273 skb = (void *)pUmPacket->skbuff;
wdenkcc1c8a12002-11-02 22:58:18 +00001274
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001275 /*
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 */
wdenkcc1c8a12002-11-02 22:58:18 +00001282
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001283 if (skb)
1284 bcm570xPktFree (pUmDevice->index, skb);
wdenkcc1c8a12002-11-02 22:58:18 +00001285
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001286 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;
wdenkcc1c8a12002-11-02 22:58:18 +00001296}
1297
1298/*
1299 * Scan an MBUF chain until we reach fragment number "frag"
1300 * Return its length and physical address.
1301 */
1302void MM_MapTxDma
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001303 (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);
wdenkcc1c8a12002-11-02 22:58:18 +00001309}
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 */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001316void MM_MapRxDma (PLM_DEVICE_BLOCK pDevice,
1317 struct _LM_PACKET *pPacket, T3_64BIT_HOST_ADDR * paddr)
wdenkcc1c8a12002-11-02 22:58:18 +00001318{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001319 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1320 MM_SetT3Addr (paddr, (dma_addr_t) pUmPacket->skbuff);
wdenkcc1c8a12002-11-02 22:58:18 +00001321}
1322
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001323void MM_SetAddr (LM_PHYSICAL_ADDRESS * paddr, dma_addr_t addr)
wdenkcc1c8a12002-11-02 22:58:18 +00001324{
1325#if (BITS_PER_LONG == 64)
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001326 paddr->High = ((unsigned long)addr) >> 32;
1327 paddr->Low = ((unsigned long)addr) & 0xffffffff;
wdenkcc1c8a12002-11-02 22:58:18 +00001328#else
wdenk57b2d802003-06-27 21:31:46 +00001329 paddr->High = 0;
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001330 paddr->Low = (unsigned long)addr;
wdenkcc1c8a12002-11-02 22:58:18 +00001331#endif
1332}
1333
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001334void MM_SetT3Addr (T3_64BIT_HOST_ADDR * paddr, dma_addr_t addr)
wdenkcc1c8a12002-11-02 22:58:18 +00001335{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001336 unsigned long baddr = (unsigned long)addr;
wdenkcc1c8a12002-11-02 22:58:18 +00001337#if (BITS_PER_LONG == 64)
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001338 set_64bit_addr (paddr, baddr & 0xffffffff, baddr >> 32);
wdenkcc1c8a12002-11-02 22:58:18 +00001339#else
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001340 set_64bit_addr (paddr, baddr, 0);
wdenkcc1c8a12002-11-02 22:58:18 +00001341#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 */
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001353void atomic_set (atomic_t * entry, int val)
wdenkcc1c8a12002-11-02 22:58:18 +00001354{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001355 entry->counter = val;
wdenkcc1c8a12002-11-02 22:58:18 +00001356}
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001357
1358int atomic_read (atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001359{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001360 return entry->counter;
wdenkcc1c8a12002-11-02 22:58:18 +00001361}
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001362
1363void atomic_inc (atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001364{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001365 if (entry)
1366 entry->counter++;
wdenkcc1c8a12002-11-02 22:58:18 +00001367}
1368
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001369void atomic_dec (atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001370{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001371 if (entry)
1372 entry->counter--;
wdenkcc1c8a12002-11-02 22:58:18 +00001373}
1374
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001375void atomic_sub (int a, atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001376{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001377 if (entry)
1378 entry->counter -= a;
wdenkcc1c8a12002-11-02 22:58:18 +00001379}
1380
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001381void atomic_add (int a, atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001382{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001383 if (entry)
1384 entry->counter += a;
wdenkcc1c8a12002-11-02 22:58:18 +00001385}
1386
1387/******************************************************************************/
1388/* Description: */
1389/* */
1390/* Return: */
1391/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001392void 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 */
wdenkcc1c8a12002-11-02 22:58:18 +00001399
wdenkcc1c8a12002-11-02 22:58:18 +00001400/******************************************************************************/
1401/* Description: */
1402/* */
1403/* Return: */
1404/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001405char QQ_Full (PQQ_CONTAINER pQueue)
1406{
1407 unsigned int NewHead;
wdenkcc1c8a12002-11-02 22:58:18 +00001408
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001409 NewHead = (pQueue->Head + 1) % pQueue->Size;
wdenkcc1c8a12002-11-02 22:58:18 +00001410
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001411 return (NewHead == pQueue->Tail);
1412} /* QQ_Full */
wdenkcc1c8a12002-11-02 22:58:18 +00001413
wdenkcc1c8a12002-11-02 22:58:18 +00001414/******************************************************************************/
1415/* Description: */
1416/* */
1417/* Return: */
1418/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001419char QQ_Empty (PQQ_CONTAINER pQueue)
1420{
1421 return (pQueue->Head == pQueue->Tail);
1422} /* QQ_Empty */
wdenkcc1c8a12002-11-02 22:58:18 +00001423
wdenkcc1c8a12002-11-02 22:58:18 +00001424/******************************************************************************/
1425/* Description: */
1426/* */
1427/* Return: */
1428/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001429unsigned int QQ_GetSize (PQQ_CONTAINER pQueue)
1430{
1431 return pQueue->Size;
1432} /* QQ_GetSize */
wdenkcc1c8a12002-11-02 22:58:18 +00001433
wdenkcc1c8a12002-11-02 22:58:18 +00001434/******************************************************************************/
1435/* Description: */
1436/* */
1437/* Return: */
1438/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001439unsigned int QQ_GetEntryCnt (PQQ_CONTAINER pQueue)
1440{
1441 return atomic_read (&pQueue->EntryCnt);
1442} /* QQ_GetEntryCnt */
wdenkcc1c8a12002-11-02 22:58:18 +00001443
wdenkcc1c8a12002-11-02 22:58:18 +00001444/******************************************************************************/
1445/* Description: */
1446/* */
1447/* Return: */
1448/* TRUE entry was added successfully. */
1449/* FALSE queue is full. */
1450/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001451char QQ_PushHead (PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)
1452{
1453 unsigned int Head;
wdenkcc1c8a12002-11-02 22:58:18 +00001454
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001455 Head = (pQueue->Head + 1) % pQueue->Size;
wdenkcc1c8a12002-11-02 22:58:18 +00001456
1457#if !defined(QQ_NO_OVERFLOW_CHECK)
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001458 if (Head == pQueue->Tail) {
1459 return 0;
1460 } /* if */
1461#endif /* QQ_NO_OVERFLOW_CHECK */
wdenkcc1c8a12002-11-02 22:58:18 +00001462
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001463 pQueue->Array[pQueue->Head] = pEntry;
1464 wmb ();
1465 pQueue->Head = Head;
1466 atomic_inc (&pQueue->EntryCnt);
wdenkcc1c8a12002-11-02 22:58:18 +00001467
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001468 return -1;
1469} /* QQ_PushHead */
wdenkcc1c8a12002-11-02 22:58:18 +00001470
wdenkcc1c8a12002-11-02 22:58:18 +00001471/******************************************************************************/
1472/* Description: */
1473/* */
1474/* Return: */
1475/* TRUE entry was added successfully. */
1476/* FALSE queue is full. */
1477/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001478char QQ_PushTail (PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)
1479{
1480 unsigned int Tail;
wdenkcc1c8a12002-11-02 22:58:18 +00001481
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001482 Tail = pQueue->Tail;
1483 if (Tail == 0) {
1484 Tail = pQueue->Size;
1485 } /* if */
1486 Tail--;
wdenkcc1c8a12002-11-02 22:58:18 +00001487
1488#if !defined(QQ_NO_OVERFLOW_CHECK)
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001489 if (Tail == pQueue->Head) {
1490 return 0;
1491 } /* if */
1492#endif /* QQ_NO_OVERFLOW_CHECK */
wdenkcc1c8a12002-11-02 22:58:18 +00001493
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001494 pQueue->Array[Tail] = pEntry;
1495 wmb ();
1496 pQueue->Tail = Tail;
1497 atomic_inc (&pQueue->EntryCnt);
wdenkcc1c8a12002-11-02 22:58:18 +00001498
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001499 return -1;
1500} /* QQ_PushTail */
wdenkcc1c8a12002-11-02 22:58:18 +00001501
wdenkcc1c8a12002-11-02 22:58:18 +00001502/******************************************************************************/
1503/* Description: */
1504/* */
1505/* Return: */
1506/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001507PQQ_ENTRY QQ_PopHead (PQQ_CONTAINER pQueue)
1508{
1509 unsigned int Head;
1510 PQQ_ENTRY Entry;
wdenkcc1c8a12002-11-02 22:58:18 +00001511
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001512 Head = pQueue->Head;
wdenkcc1c8a12002-11-02 22:58:18 +00001513
1514#if !defined(QQ_NO_UNDERFLOW_CHECK)
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001515 if (Head == pQueue->Tail) {
1516 return (PQQ_ENTRY) 0;
1517 } /* if */
1518#endif /* QQ_NO_UNDERFLOW_CHECK */
wdenkcc1c8a12002-11-02 22:58:18 +00001519
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001520 if (Head == 0) {
1521 Head = pQueue->Size;
1522 } /* if */
1523 Head--;
wdenkcc1c8a12002-11-02 22:58:18 +00001524
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001525 Entry = pQueue->Array[Head];
1526 membar ();
wdenkcc1c8a12002-11-02 22:58:18 +00001527
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001528 pQueue->Head = Head;
1529 atomic_dec (&pQueue->EntryCnt);
wdenkcc1c8a12002-11-02 22:58:18 +00001530
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001531 return Entry;
1532} /* QQ_PopHead */
wdenkcc1c8a12002-11-02 22:58:18 +00001533
wdenkcc1c8a12002-11-02 22:58:18 +00001534/******************************************************************************/
1535/* Description: */
1536/* */
1537/* Return: */
1538/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001539PQQ_ENTRY QQ_PopTail (PQQ_CONTAINER pQueue)
1540{
1541 unsigned int Tail;
1542 PQQ_ENTRY Entry;
wdenkcc1c8a12002-11-02 22:58:18 +00001543
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001544 Tail = pQueue->Tail;
wdenkcc1c8a12002-11-02 22:58:18 +00001545
1546#if !defined(QQ_NO_UNDERFLOW_CHECK)
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001547 if (Tail == pQueue->Head) {
1548 return (PQQ_ENTRY) 0;
1549 } /* if */
1550#endif /* QQ_NO_UNDERFLOW_CHECK */
wdenkcc1c8a12002-11-02 22:58:18 +00001551
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001552 Entry = pQueue->Array[Tail];
1553 membar ();
1554 pQueue->Tail = (Tail + 1) % pQueue->Size;
1555 atomic_dec (&pQueue->EntryCnt);
wdenkcc1c8a12002-11-02 22:58:18 +00001556
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001557 return Entry;
1558} /* QQ_PopTail */
wdenkcc1c8a12002-11-02 22:58:18 +00001559
wdenkcc1c8a12002-11-02 22:58:18 +00001560/******************************************************************************/
1561/* Description: */
1562/* */
1563/* Return: */
1564/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001565PQQ_ENTRY QQ_GetHead (PQQ_CONTAINER pQueue, unsigned int Idx)
wdenkcc1c8a12002-11-02 22:58:18 +00001566{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001567 if (Idx >= atomic_read (&pQueue->EntryCnt)) {
1568 return (PQQ_ENTRY) 0;
1569 }
wdenkcc1c8a12002-11-02 22:58:18 +00001570
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001571 if (pQueue->Head > Idx) {
1572 Idx = pQueue->Head - Idx;
1573 } else {
1574 Idx = pQueue->Size - (Idx - pQueue->Head);
1575 }
1576 Idx--;
wdenkcc1c8a12002-11-02 22:58:18 +00001577
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001578 return pQueue->Array[Idx];
wdenkcc1c8a12002-11-02 22:58:18 +00001579}
1580
wdenkcc1c8a12002-11-02 22:58:18 +00001581/******************************************************************************/
1582/* Description: */
1583/* */
1584/* Return: */
1585/******************************************************************************/
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001586PQQ_ENTRY QQ_GetTail (PQQ_CONTAINER pQueue, unsigned int Idx)
wdenkcc1c8a12002-11-02 22:58:18 +00001587{
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001588 if (Idx >= atomic_read (&pQueue->EntryCnt)) {
1589 return (PQQ_ENTRY) 0;
1590 }
wdenkcc1c8a12002-11-02 22:58:18 +00001591
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001592 Idx += pQueue->Tail;
1593 if (Idx >= pQueue->Size) {
1594 Idx = Idx - pQueue->Size;
1595 }
wdenkcc1c8a12002-11-02 22:58:18 +00001596
Vadim Bendebury6ddfee52007-05-24 15:52:25 -07001597 return pQueue->Array[Idx];
wdenkcc1c8a12002-11-02 22:58:18 +00001598}