blob: 185764ef5e96b7ab20dd79fd6dc474d5f3bc5fdf [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 Denk53677ef2008-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700131 char *name;
wdenkcc1c8a12002-11-02 22:58:18 +0000132} chip_rev[] = {
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700169 char *name;
wdenkcc1c8a12002-11-02 22:58:18 +0000170} board_info[] = {
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700271void *bcm570xPktAlloc (int u, int pksize)
wdenkcc1c8a12002-11-02 22:58:18 +0000272{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700280void bcm570xPktFree (int u, void *p)
wdenkcc1c8a12002-11-02 22:58:18 +0000281{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700282 free (p);
wdenkcc1c8a12002-11-02 22:58:18 +0000283}
284
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700285int bcm570xReplenishRxBuffers (PUM_DEVICE_BLOCK pUmDevice)
wdenkcc1c8a12002-11-02 22:58:18 +0000286{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700296 pPacket = (PLM_PACKET) pUmPacket;
wdenkcc1c8a12002-11-02 22:58:18 +0000297
Vadim Bendeburyf539edc2007-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 }
314
315 pUmPacket->skbuff = skb;
316 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
317 queue_rx = 1;
wdenkcc1c8a12002-11-02 22:58:18 +0000318 }
319
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700320 if (queue_rx) {
321 LM_QueueRxPackets (pDevice);
322 }
wdenkcc1c8a12002-11-02 22:58:18 +0000323
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700330int eth_init (bd_t * bis)
wdenkcc1c8a12002-11-02 22:58:18 +0000331{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 {
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;
wdenkcc1c8a12002-11-02 22:58:18 +0000405 } else {
406
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700407 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 Bendeburyf539edc2007-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 }
420
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700421 /* 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000428 }
wdenkcc1c8a12002-11-02 22:58:18 +0000429
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700430 /* Lock not needed */
431 pUmDevice->do_global_lock = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000432
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200442 pUmDevice->timer_interval = CONFIG_SYS_HZ;
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700443 } else {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200444 pUmDevice->timer_interval = CONFIG_SYS_HZ / 50;
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700445 }
wdenkcc1c8a12002-11-02 22:58:18 +0000446
Vadim Bendeburyf539edc2007-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
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700453 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;
wdenkcc1c8a12002-11-02 22:58:18 +0000459
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700460 /* delay for 4 seconds */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200463 pUmDevice->adaptive_expiry = CONFIG_SYS_HZ / pUmDevice->timer_interval;
wdenkcc1c8a12002-11-02 22:58:18 +0000464
Vadim Bendeburyf539edc2007-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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200469 (3 * CONFIG_SYS_HZ) / pUmDevice->timer_interval;
wdenkcc1c8a12002-11-02 22:58:18 +0000470
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700477 /* Enable chip ISR */
478 LM_EnableInterrupt (pDevice);
wdenkcc1c8a12002-11-02 22:58:18 +0000479
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700480 /* Clear MC table */
481 LM_MulticastClear (pDevice);
wdenkcc1c8a12002-11-02 22:58:18 +0000482
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700529 return 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000530}
531
532/* Ethernet Interrupt service routine */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700533void eth_isr (void)
wdenkcc1c8a12002-11-02 22:58:18 +0000534{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700535 LM_UINT32 oldtag, newtag;
536 int i;
wdenkcc1c8a12002-11-02 22:58:18 +0000537
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700538 pUmDevice->interrupt = 1;
wdenkcc1c8a12002-11-02 22:58:18 +0000539
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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;
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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000576 }
wdenkcc1c8a12002-11-02 22:58:18 +0000577
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700578 /* Allocate new RX buffers */
579 if (QQ_GetEntryCnt (&pUmDevice->rx_out_of_buf_q.Container)) {
580 bcm570xReplenishRxBuffers (pUmDevice);
wdenkcc1c8a12002-11-02 22:58:18 +0000581 }
wdenkcc1c8a12002-11-02 22:58:18 +0000582
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700583 /* Queue packets */
584 if (QQ_GetEntryCnt (&pDevice->RxPacketFreeQ.Container)) {
585 LM_QueueRxPackets (pDevice);
wdenkcc1c8a12002-11-02 22:58:18 +0000586 }
wdenkcc1c8a12002-11-02 22:58:18 +0000587
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700588 if (pUmDevice->tx_queued) {
589 pUmDevice->tx_queued = 0;
590 }
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 }
598 }
599
600 pUmDevice->interrupt = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000601
602}
603
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700604int eth_send (volatile void *packet, int length)
wdenkcc1c8a12002-11-02 22:58:18 +0000605{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700606 int status = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000607#if ET_DEBUG
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700608 unsigned char *ptr = (unsigned char *)packet;
wdenkcc1c8a12002-11-02 22:58:18 +0000609#endif
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700610 PLM_PACKET pPacket;
611 PUM_PACKET pUmPacket;
wdenkcc1c8a12002-11-02 22:58:18 +0000612
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700619 eth_isr ();
wdenkcc1c8a12002-11-02 22:58:18 +0000620
Vadim Bendeburyf539edc2007-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
wdenkcc1c8a12002-11-02 22:58:18 +0000624 }
625
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700626 /* Clear sent flag */
627 pUmDevice->tx_pkt = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000628
Vadim Bendeburyf539edc2007-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;
wdenkcc1c8a12002-11-02 22:58:18 +0000633 }
634
635 pPacket = (PLM_PACKET)
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700636 QQ_PopHead (&pDevice->TxPacketFreeQ.Container);
wdenkcc1c8a12002-11-02 22:58:18 +0000637
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700638 if (pPacket == 0) {
639 pUmDevice->tx_full = 1;
640 printf ("bcm570xEndSend: TX full!\n");
641 return 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000642 }
643
Vadim Bendeburyf539edc2007-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;
649 }
650
651 if (length <= 0) {
652 printf ("eth: bad packet size: %d\n", length);
653 goto out;
654 }
655
656 /* Get packet buffers and fragment list */
wdenkcc1c8a12002-11-02 22:58:18 +0000657 pUmPacket = (PUM_PACKET) pPacket;
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700658 /* Single DMA Descriptor transmit.
659 * Fragments may be provided, but one DMA descriptor max is
660 * used to send the packet.
661 */
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;
wdenkcc1c8a12002-11-02 22:58:18 +0000673 }
674
Vadim Bendeburyf539edc2007-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;
wdenkcc1c8a12002-11-02 22:58:18 +0000683
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700684 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 }
wdenkcc1c8a12002-11-02 22:58:18 +0000698
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700699 if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) == 0) {
700 printf ("TX: emptyQ!\n");
701 pUmDevice->tx_full = 1;
702 }
703 }
wdenkcc1c8a12002-11-02 22:58:18 +0000704
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700705 while (pUmDevice->tx_pkt == 0) {
706 /* Service TX */
707 eth_isr ();
708 }
709#if ET_DEBUG
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]);
716#endif
717 pUmDevice->tx_pkt = 0;
718 QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
wdenkcc1c8a12002-11-02 22:58:18 +0000719
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700720 /* Done with send */
721 out:
722 return status;
wdenkcc1c8a12002-11-02 22:58:18 +0000723}
724
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700725/* Ethernet receive */
726int eth_rx (void)
727{
728 PLM_PACKET pPacket = NULL;
729 PUM_PACKET pUmPacket = NULL;
730 void *skb;
731 int size = 0;
732
733 while (TRUE) {
734
735 bcm570x_service_isr:
736 /* Pull down packet if it is there */
737 eth_isr ();
738
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 }
747
748 pPacket = (PLM_PACKET)
749 QQ_PopHead (&pDevice->RxPacketReceivedQ.Container);
750
751 if (pPacket == 0) {
752 printf ("eth_rx: empty packet!\n");
753 goto bcm570x_service_isr;
754 }
755
756 pUmPacket = (PUM_PACKET) pPacket;
757#if ET_DEBUG
758 printf ("eth_rx: packet @0x%x\n", (int)pPacket);
759#endif
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 }
770
771 /* Set size and address */
772 skb = pUmPacket->skbuff;
773 size = pPacket->PacketSize;
774
775 /* Pass the packet up to the protocol
776 * layers.
777 */
778 NetReceive (skb, size);
779
780 /* Free packet buffer */
781 bcm570xPktFree (pUmDevice->index, skb);
782 pUmPacket->skbuff = NULL;
783
784 /* Reuse SKB */
785 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
786
787 return 0; /* Got a packet, bail ... */
788 }
789 return size;
790}
wdenkcc1c8a12002-11-02 22:58:18 +0000791
wdenkcc1c8a12002-11-02 22:58:18 +0000792/* Shut down device */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700793void eth_halt (void)
wdenkcc1c8a12002-11-02 22:58:18 +0000794{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700834int MM_Packet_Desc_Size = sizeof (UM_PACKET);
wdenkcc1c8a12002-11-02 22:58:18 +0000835
836LM_STATUS
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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
846LM_STATUS
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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
855LM_STATUS
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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;
872}
wdenkcc1c8a12002-11-02 22:58:18 +0000873
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700874LM_STATUS
875MM_AllocateSharedMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
876 PLM_VOID * pMemoryBlockVirt,
877 PLM_PHYSICAL_ADDRESS pMemoryBlockPhy, LM_BOOL Cached)
878{
879 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 Bendeburyf539edc2007-05-24 15:52:25 -0700883 pvirt = malloc (BlockSize);
884 mapping = (dma_addr_t) (pvirt);
885 if (!pvirt)
886 return LM_STATUS_FAILURE;
887
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);
892
893 *pMemoryBlockVirt = (PLM_VOID) pvirt;
894 MM_SetAddr (pMemoryBlockPhy, (dma_addr_t) mapping);
895
896 return LM_STATUS_SUCCESS;
897}
898
899LM_STATUS
900MM_AllocateMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
901 PLM_VOID * pMemoryBlockVirt)
902{
903 PLM_VOID pvirt;
904 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
905
906 pvirt = malloc (BlockSize);
907
908 if (!pvirt)
909 return LM_STATUS_FAILURE;
910
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;
916
917 return LM_STATUS_SUCCESS;
918}
919
920LM_STATUS MM_MapMemBase (PLM_DEVICE_BLOCK pDevice)
921{
922 printf ("BCM570x PCI Memory base address @0x%x\n",
923 (unsigned int)pDevice->pMappedMemBase);
924 return LM_STATUS_SUCCESS;
925}
926
927LM_STATUS MM_InitializeUmPackets (PLM_DEVICE_BLOCK pDevice)
928{
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 }
942
943 skb = bcm570xPktAlloc (pUmDevice->index,
944 pPacket->u.Rx.RxBufferSize + 2);
945
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 }
953
954 pUmPacket->skbuff = skb;
955 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
wdenkcc1c8a12002-11-02 22:58:18 +0000956 }
957
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700958 pUmDevice->rx_low_buf_thresh = pDevice->RxPacketDescCnt / 8;
wdenkcc1c8a12002-11-02 22:58:18 +0000959
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700960 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000961}
962
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700963LM_STATUS MM_GetConfig (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +0000964{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -0700968 if (auto_speed[index] == 0)
969 pDevice->DisableAutoNeg = TRUE;
970 else
wdenkcc1c8a12002-11-02 22:58:18 +0000971 pDevice->DisableAutoNeg = FALSE;
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700972
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
wdenkcc1c8a12002-11-02 22:58:18 +00001012 }
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001020 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 }
wdenkcc1c8a12002-11-02 22:58:18 +00001030 }
1031
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001044 pDevice->RxMtu = pUmDevice->mtu;
wdenkcc1c8a12002-11-02 22:58:18 +00001045#endif
1046
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001047 if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
1048 pDevice->UseTaggedStatus = TRUE;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001049 pUmDevice->timer_interval = CONFIG_SYS_HZ;
wdenkcc1c8a12002-11-02 22:58:18 +00001050 } else {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001051 pUmDevice->timer_interval = CONFIG_SYS_HZ / 50;
wdenkcc1c8a12002-11-02 22:58:18 +00001052 }
wdenkcc1c8a12002-11-02 22:58:18 +00001053
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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;
wdenkcc1c8a12002-11-02 22:58:18 +00001074 } else {
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001075 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 Bendeburyf539edc2007-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;
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;
1091
1092 /* Don't update status blocks during interrupt */
1093 pDevice->RxCoalescingTicksDuringInt = 0;
1094 pDevice->TxCoalescingTicksDuringInt = 0;
1095
1096 return LM_STATUS_SUCCESS;
1097
1098}
1099
1100LM_STATUS MM_StartTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1101{
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);
1105
1106 return LM_STATUS_SUCCESS;
1107}
1108
1109LM_STATUS MM_CompleteTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1110{
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;
1115}
1116
1117LM_STATUS MM_IndicateStatus (PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
1118{
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);
1181 }
wdenkcc1c8a12002-11-02 22:58:18 +00001182#if 0
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001183 sysLedDsply (lcd[0], lcd[1], lcd[2], lcd[3]);
wdenkcc1c8a12002-11-02 22:58:18 +00001184#endif
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001185 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001186}
1187
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001195 pUmPacket = (PUM_PACKET) pPacket;
wdenkcc1c8a12002-11-02 22:58:18 +00001196
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001197 if ((skb = pUmPacket->skbuff))
1198 bcm570xPktFree (pUmDevice->index, skb);
wdenkcc1c8a12002-11-02 22:58:18 +00001199
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001200 pUmPacket->skbuff = 0;
wdenkcc1c8a12002-11-02 22:58:18 +00001201
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001202 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001203}
1204
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001205unsigned long MM_AnGetCurrentTime_us (PAN_STATE_INFO pAnInfo)
wdenkcc1c8a12002-11-02 22:58:18 +00001206{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001220LM_STATUS MM_CoalesceTxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
wdenkcc1c8a12002-11-02 22:58:18 +00001221{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001227 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 }
1235
1236 skbnew = bcm570xPktAlloc (pUmDevice->index, MAX_PACKET_SIZE);
1237
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 }
1243
1244 /* New packet values */
1245 pUmPacket->skbuff = skbnew;
1246 pUmPacket->lm_packet.u.Tx.FragCount = 1;
1247
wdenk8bde7f72003-06-27 21:31:46 +00001248 return (LM_STATUS_SUCCESS);
wdenkcc1c8a12002-11-02 22:58:18 +00001249}
1250
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001251LM_STATUS MM_IndicateRxPackets (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +00001252{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001258LM_STATUS MM_IndicateTxPackets (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +00001259{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001266 pPacket = (PLM_PACKET)
1267 QQ_PopHead (&pDevice->TxPacketXmittedQ.Container);
wdenkcc1c8a12002-11-02 22:58:18 +00001268
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001269 if (pPacket == 0)
1270 break;
wdenkcc1c8a12002-11-02 22:58:18 +00001271
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001272 pUmPacket = (PUM_PACKET) pPacket;
1273 skb = (void *)pUmPacket->skbuff;
wdenkcc1c8a12002-11-02 22:58:18 +00001274
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001283 if (skb)
1284 bcm570xPktFree (pUmDevice->index, skb);
wdenkcc1c8a12002-11-02 22:58:18 +00001285
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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
wdenk8bde7f72003-06-27 21:31:46 +00001329 paddr->High = 0;
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001330 paddr->Low = (unsigned long)addr;
wdenkcc1c8a12002-11-02 22:58:18 +00001331#endif
1332}
1333
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001338 set_64bit_addr (paddr, baddr & 0xffffffff, baddr >> 32);
wdenkcc1c8a12002-11-02 22:58:18 +00001339#else
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001353void atomic_set (atomic_t * entry, int val)
wdenkcc1c8a12002-11-02 22:58:18 +00001354{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001355 entry->counter = val;
wdenkcc1c8a12002-11-02 22:58:18 +00001356}
1357
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001358int atomic_read (atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001359{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001360 return entry->counter;
wdenkcc1c8a12002-11-02 22:58:18 +00001361}
1362
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001363void atomic_inc (atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001364{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001365 if (entry)
1366 entry->counter++;
wdenkcc1c8a12002-11-02 22:58:18 +00001367}
1368
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001369void atomic_dec (atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001370{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001371 if (entry)
1372 entry->counter--;
1373}
1374
1375void atomic_sub (int a, atomic_t * entry)
1376{
1377 if (entry)
1378 entry->counter -= a;
1379}
1380
1381void atomic_add (int a, atomic_t * entry)
1382{
1383 if (entry)
1384 entry->counter += a;
wdenkcc1c8a12002-11-02 22:58:18 +00001385}
1386
1387/******************************************************************************/
1388/* Description: */
1389/* */
1390/* Return: */
1391/******************************************************************************/
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001405char QQ_Full (PQQ_CONTAINER pQueue)
1406{
1407 unsigned int NewHead;
wdenkcc1c8a12002-11-02 22:58:18 +00001408
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001409 NewHead = (pQueue->Head + 1) % pQueue->Size;
wdenkcc1c8a12002-11-02 22:58:18 +00001410
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001512 Head = pQueue->Head;
wdenkcc1c8a12002-11-02 22:58:18 +00001513
1514#if !defined(QQ_NO_UNDERFLOW_CHECK)
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001525 Entry = pQueue->Array[Head];
1526 membar ();
wdenkcc1c8a12002-11-02 22:58:18 +00001527
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001528 pQueue->Head = Head;
1529 atomic_dec (&pQueue->EntryCnt);
wdenkcc1c8a12002-11-02 22:58:18 +00001530
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001544 Tail = pQueue->Tail;
wdenkcc1c8a12002-11-02 22:58:18 +00001545
1546#if !defined(QQ_NO_UNDERFLOW_CHECK)
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001565PQQ_ENTRY QQ_GetHead (PQQ_CONTAINER pQueue, unsigned int Idx)
wdenkcc1c8a12002-11-02 22:58:18 +00001566{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001586PQQ_ENTRY QQ_GetTail (PQQ_CONTAINER pQueue, unsigned int Idx)
wdenkcc1c8a12002-11-02 22:58:18 +00001587{
Vadim Bendeburyf539edc2007-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 Bendeburyf539edc2007-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 Bendeburyf539edc2007-05-24 15:52:25 -07001597 return pQueue->Array[Idx];
wdenkcc1c8a12002-11-02 22:58:18 +00001598}