blob: c8f4064224dc1b2022dc4e2adc9e88fec8ee7b9d [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
Jon Loeliger07d38a12007-07-09 17:30:01 -05009#if defined(CONFIG_CMD_NET) \
Jon Loeligerd5be43d2007-06-11 19:02:10 -050010 && (!defined(CONFIG_NET_MULTI)) && defined(CONFIG_BCM570x)
wdenkcc1c8a12002-11-02 22:58:18 +000011
12#ifdef CONFIG_BMW
13#include <mpc824x.h>
14#endif
15#include <net.h>
16#include "bcm570x_mm.h"
17#include "bcm570x_autoneg.h"
18#include <pci.h>
19#include <malloc.h>
20
wdenkcc1c8a12002-11-02 22:58:18 +000021/*
22 * PCI Registers and definitions.
23 */
24#define PCI_CMD_MASK 0xffff0000 /* mask to save status bits */
25#define PCI_ANY_ID (~0)
26
27/*
28 * PCI memory base for Ethernet device as well as device Interrupt.
29 */
30#define BCM570X_MBAR 0x80100000
31#define BCM570X_ILINE 1
32
wdenkcc1c8a12002-11-02 22:58:18 +000033#define SECOND_USEC 1000000
34#define MAX_PACKET_SIZE 1600
35#define MAX_UNITS 4
36
37/* Globals to this module */
38int initialized = 0;
39unsigned int ioBase = 0;
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070040volatile PLM_DEVICE_BLOCK pDevice = NULL; /* 570x softc */
41volatile PUM_DEVICE_BLOCK pUmDevice = NULL;
wdenkcc1c8a12002-11-02 22:58:18 +000042
43/* Used to pass the full-duplex flag, etc. */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070044int line_speed[MAX_UNITS] = { 0, 0, 0, 0 };
45static int full_duplex[MAX_UNITS] = { 1, 1, 1, 1 };
46static int rx_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
47static int tx_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
48static int auto_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
49static int tx_checksum[MAX_UNITS] = { 1, 1, 1, 1 };
50static int rx_checksum[MAX_UNITS] = { 1, 1, 1, 1 };
51static int auto_speed[MAX_UNITS] = { 1, 1, 1, 1 };
wdenkcc1c8a12002-11-02 22:58:18 +000052
53#if JUMBO_FRAMES
54/* Jumbo MTU for interfaces. */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070055static int mtu[MAX_UNITS] = { 0, 0, 0, 0 };
wdenkcc1c8a12002-11-02 22:58:18 +000056#endif
57
58/* Turn on Wake-on lan for a device unit */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070059static int enable_wol[MAX_UNITS] = { 0, 0, 0, 0 };
wdenkcc1c8a12002-11-02 22:58:18 +000060
61#define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNT
62static unsigned int tx_pkt_desc_cnt[MAX_UNITS] =
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070063 { TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT };
wdenkcc1c8a12002-11-02 22:58:18 +000064
65#define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNT
66static unsigned int rx_std_desc_cnt[MAX_UNITS] =
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070067 { RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT };
wdenkcc1c8a12002-11-02 22:58:18 +000068
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070069static unsigned int rx_adaptive_coalesce[MAX_UNITS] = { 1, 1, 1, 1 };
wdenkcc1c8a12002-11-02 22:58:18 +000070
71#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
72#define JBO_DESC_CNT DEFAULT_JUMBO_RCV_DESC_COUNT
73static unsigned int rx_jumbo_desc_cnt[MAX_UNITS] =
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070074 { JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT };
wdenkcc1c8a12002-11-02 22:58:18 +000075#endif
76#define RX_COAL_TK DEFAULT_RX_COALESCING_TICKS
77static unsigned int rx_coalesce_ticks[MAX_UNITS] =
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070078 { RX_COAL_TK, RX_COAL_TK, RX_COAL_TK, RX_COAL_TK };
wdenkcc1c8a12002-11-02 22:58:18 +000079
80#define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMES
81static unsigned int rx_max_coalesce_frames[MAX_UNITS] =
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070082 { RX_COAL_FM, RX_COAL_FM, RX_COAL_FM, RX_COAL_FM };
wdenkcc1c8a12002-11-02 22:58:18 +000083
84#define TX_COAL_TK DEFAULT_TX_COALESCING_TICKS
85static unsigned int tx_coalesce_ticks[MAX_UNITS] =
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070086 { TX_COAL_TK, TX_COAL_TK, TX_COAL_TK, TX_COAL_TK };
wdenkcc1c8a12002-11-02 22:58:18 +000087
88#define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMES
89static unsigned int tx_max_coalesce_frames[MAX_UNITS] =
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070090 { TX_COAL_FM, TX_COAL_FM, TX_COAL_FM, TX_COAL_FM };
wdenkcc1c8a12002-11-02 22:58:18 +000091
92#define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKS
93static unsigned int stats_coalesce_ticks[MAX_UNITS] =
Vadim Bendeburyf539edc2007-05-24 15:52:25 -070094 { ST_COAL_TK, ST_COAL_TK, ST_COAL_TK, ST_COAL_TK };
wdenkcc1c8a12002-11-02 22:58:18 +000095
wdenkcc1c8a12002-11-02 22:58:18 +000096/*
97 * Legitimate values for BCM570x device types
98 */
99typedef enum {
100 BCM5700VIGIL = 0,
101 BCM5700A6,
102 BCM5700T6,
103 BCM5700A9,
104 BCM5700T9,
105 BCM5700,
106 BCM5701A5,
107 BCM5701T1,
108 BCM5701T8,
109 BCM5701A7,
110 BCM5701A10,
111 BCM5701A12,
112 BCM5701,
113 BCM5702,
114 BCM5703,
115 BCM5703A31,
116 TC996T,
117 TC996ST,
118 TC996SSX,
119 TC996SX,
120 TC996BT,
121 TC997T,
122 TC997SX,
123 TC1000T,
124 TC940BR01,
125 TC942BR01,
126 NC6770,
127 NC7760,
128 NC7770,
129 NC7780
130} board_t;
131
132/* Chip-Rev names for each device-type */
133static struct {
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700134 char *name;
wdenkcc1c8a12002-11-02 22:58:18 +0000135} chip_rev[] = {
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700136 {
137 "BCM5700VIGIL"}, {
138 "BCM5700A6"}, {
139 "BCM5700T6"}, {
140 "BCM5700A9"}, {
141 "BCM5700T9"}, {
142 "BCM5700"}, {
143 "BCM5701A5"}, {
144 "BCM5701T1"}, {
145 "BCM5701T8"}, {
146 "BCM5701A7"}, {
147 "BCM5701A10"}, {
148 "BCM5701A12"}, {
149 "BCM5701"}, {
150 "BCM5702"}, {
151 "BCM5703"}, {
152 "BCM5703A31"}, {
153 "TC996T"}, {
154 "TC996ST"}, {
155 "TC996SSX"}, {
156 "TC996SX"}, {
157 "TC996BT"}, {
158 "TC997T"}, {
159 "TC997SX"}, {
160 "TC1000T"}, {
161 "TC940BR01"}, {
162 "TC942BR01"}, {
163 "NC6770"}, {
164 "NC7760"}, {
165 "NC7770"}, {
166 "NC7780"}, {
167 0}
wdenkcc1c8a12002-11-02 22:58:18 +0000168};
169
wdenkcc1c8a12002-11-02 22:58:18 +0000170/* indexed by board_t, above */
171static struct {
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700172 char *name;
wdenkcc1c8a12002-11-02 22:58:18 +0000173} board_info[] = {
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700174 {
175 "Broadcom Vigil B5700 1000Base-T"}, {
176 "Broadcom BCM5700 1000Base-T"}, {
177 "Broadcom BCM5700 1000Base-SX"}, {
178 "Broadcom BCM5700 1000Base-SX"}, {
179 "Broadcom BCM5700 1000Base-T"}, {
180 "Broadcom BCM5700"}, {
181 "Broadcom BCM5701 1000Base-T"}, {
182 "Broadcom BCM5701 1000Base-T"}, {
183 "Broadcom BCM5701 1000Base-T"}, {
184 "Broadcom BCM5701 1000Base-SX"}, {
185 "Broadcom BCM5701 1000Base-T"}, {
186 "Broadcom BCM5701 1000Base-T"}, {
187 "Broadcom BCM5701"}, {
188 "Broadcom BCM5702 1000Base-T"}, {
189 "Broadcom BCM5703 1000Base-T"}, {
190 "Broadcom BCM5703 1000Base-SX"}, {
191 "3Com 3C996 10/100/1000 Server NIC"}, {
192 "3Com 3C996 10/100/1000 Server NIC"}, {
193 "3Com 3C996 Gigabit Fiber-SX Server NIC"}, {
194 "3Com 3C996 Gigabit Fiber-SX Server NIC"}, {
195 "3Com 3C996B Gigabit Server NIC"}, {
196 "3Com 3C997 Gigabit Server NIC"}, {
197 "3Com 3C997 Gigabit Fiber-SX Server NIC"}, {
198 "3Com 3C1000 Gigabit NIC"}, {
199 "3Com 3C940 Gigabit LOM (21X21)"}, {
200 "3Com 3C942 Gigabit LOM (31X31)"}, {
201 "Compaq NC6770 Gigabit Server Adapter"}, {
202 "Compaq NC7760 Gigabit Server Adapter"}, {
203 "Compaq NC7770 Gigabit Server Adapter"}, {
204 "Compaq NC7780 Gigabit Server Adapter"}, {
2050},};
wdenkcc1c8a12002-11-02 22:58:18 +0000206
207/* PCI Devices which use the 570x chipset */
208struct pci_device_table {
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700209 unsigned short vendor_id, device_id; /* Vendor/DeviceID */
210 unsigned short subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
211 unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
212 unsigned long board_id; /* Data private to the driver */
213 int io_size, min_latency;
wdenkcc1c8a12002-11-02 22:58:18 +0000214} bcm570xDevices[] = {
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700215 {
216 0x14e4, 0x1644, 0x1014, 0x0277, 0, 0, BCM5700VIGIL, 128, 32}, {
217 0x14e4, 0x1644, 0x14e4, 0x1644, 0, 0, BCM5700A6, 128, 32}, {
218 0x14e4, 0x1644, 0x14e4, 0x2, 0, 0, BCM5700T6, 128, 32}, {
219 0x14e4, 0x1644, 0x14e4, 0x3, 0, 0, BCM5700A9, 128, 32}, {
220 0x14e4, 0x1644, 0x14e4, 0x4, 0, 0, BCM5700T9, 128, 32}, {
221 0x14e4, 0x1644, 0x1028, 0xd1, 0, 0, BCM5700, 128, 32}, {
222 0x14e4, 0x1644, 0x1028, 0x0106, 0, 0, BCM5700, 128, 32}, {
223 0x14e4, 0x1644, 0x1028, 0x0109, 0, 0, BCM5700, 128, 32}, {
224 0x14e4, 0x1644, 0x1028, 0x010a, 0, 0, BCM5700, 128, 32}, {
225 0x14e4, 0x1644, 0x10b7, 0x1000, 0, 0, TC996T, 128, 32}, {
226 0x14e4, 0x1644, 0x10b7, 0x1001, 0, 0, TC996ST, 128, 32}, {
227 0x14e4, 0x1644, 0x10b7, 0x1002, 0, 0, TC996SSX, 128, 32}, {
228 0x14e4, 0x1644, 0x10b7, 0x1003, 0, 0, TC997T, 128, 32}, {
229 0x14e4, 0x1644, 0x10b7, 0x1005, 0, 0, TC997SX, 128, 32}, {
230 0x14e4, 0x1644, 0x10b7, 0x1008, 0, 0, TC942BR01, 128, 32}, {
231 0x14e4, 0x1644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5700, 128, 32}, {
232 0x14e4, 0x1645, 0x14e4, 1, 0, 0, BCM5701A5, 128, 32}, {
233 0x14e4, 0x1645, 0x14e4, 5, 0, 0, BCM5701T1, 128, 32}, {
234 0x14e4, 0x1645, 0x14e4, 6, 0, 0, BCM5701T8, 128, 32}, {
235 0x14e4, 0x1645, 0x14e4, 7, 0, 0, BCM5701A7, 128, 32}, {
236 0x14e4, 0x1645, 0x14e4, 8, 0, 0, BCM5701A10, 128, 32}, {
237 0x14e4, 0x1645, 0x14e4, 0x8008, 0, 0, BCM5701A12, 128, 32}, {
238 0x14e4, 0x1645, 0x0e11, 0xc1, 0, 0, NC6770, 128, 32}, {
239 0x14e4, 0x1645, 0x0e11, 0x7c, 0, 0, NC7770, 128, 32}, {
240 0x14e4, 0x1645, 0x0e11, 0x85, 0, 0, NC7780, 128, 32}, {
241 0x14e4, 0x1645, 0x1028, 0x0121, 0, 0, BCM5701, 128, 32}, {
242 0x14e4, 0x1645, 0x10b7, 0x1004, 0, 0, TC996SX, 128, 32}, {
243 0x14e4, 0x1645, 0x10b7, 0x1006, 0, 0, TC996BT, 128, 32}, {
244 0x14e4, 0x1645, 0x10b7, 0x1007, 0, 0, TC1000T, 128, 32}, {
245 0x14e4, 0x1645, 0x10b7, 0x1008, 0, 0, TC940BR01, 128, 32}, {
246 0x14e4, 0x1645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5701, 128, 32}, {
247 0x14e4, 0x1646, 0x14e4, 0x8009, 0, 0, BCM5702, 128, 32}, {
248 0x14e4, 0x1646, 0x0e11, 0xbb, 0, 0, NC7760, 128, 32}, {
249 0x14e4, 0x1646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702, 128, 32}, {
250 0x14e4, 0x16a6, 0x14e4, 0x8009, 0, 0, BCM5702, 128, 32}, {
251 0x14e4, 0x16a6, 0x0e11, 0xbb, 0, 0, NC7760, 128, 32}, {
252 0x14e4, 0x16a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702, 128, 32}, {
253 0x14e4, 0x1647, 0x14e4, 0x0009, 0, 0, BCM5703, 128, 32}, {
254 0x14e4, 0x1647, 0x14e4, 0x000a, 0, 0, BCM5703A31, 128, 32}, {
255 0x14e4, 0x1647, 0x14e4, 0x000b, 0, 0, BCM5703, 128, 32}, {
256 0x14e4, 0x1647, 0x14e4, 0x800a, 0, 0, BCM5703, 128, 32}, {
257 0x14e4, 0x1647, 0x0e11, 0x9a, 0, 0, NC7770, 128, 32}, {
258 0x14e4, 0x1647, 0x0e11, 0x99, 0, 0, NC7780, 128, 32}, {
259 0x14e4, 0x1647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703, 128, 32}, {
260 0x14e4, 0x16a7, 0x14e4, 0x0009, 0, 0, BCM5703, 128, 32}, {
261 0x14e4, 0x16a7, 0x14e4, 0x000a, 0, 0, BCM5703A31, 128, 32}, {
262 0x14e4, 0x16a7, 0x14e4, 0x000b, 0, 0, BCM5703, 128, 32}, {
263 0x14e4, 0x16a7, 0x14e4, 0x800a, 0, 0, BCM5703, 128, 32}, {
264 0x14e4, 0x16a7, 0x0e11, 0x9a, 0, 0, NC7770, 128, 32}, {
265 0x14e4, 0x16a7, 0x0e11, 0x99, 0, 0, NC7780, 128, 32}, {
266 0x14e4, 0x16a7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703, 128, 32}
wdenkcc1c8a12002-11-02 22:58:18 +0000267};
268
269#define n570xDevices (sizeof(bcm570xDevices)/sizeof(bcm570xDevices[0]))
270
wdenkcc1c8a12002-11-02 22:58:18 +0000271/*
272 * Allocate a packet buffer from the bcm570x packet pool.
273 */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700274void *bcm570xPktAlloc (int u, int pksize)
wdenkcc1c8a12002-11-02 22:58:18 +0000275{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700276 return malloc (pksize);
wdenkcc1c8a12002-11-02 22:58:18 +0000277}
278
279/*
280 * Free a packet previously allocated from the bcm570x packet
281 * buffer pool.
282 */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700283void bcm570xPktFree (int u, void *p)
wdenkcc1c8a12002-11-02 22:58:18 +0000284{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700285 free (p);
wdenkcc1c8a12002-11-02 22:58:18 +0000286}
287
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700288int bcm570xReplenishRxBuffers (PUM_DEVICE_BLOCK pUmDevice)
wdenkcc1c8a12002-11-02 22:58:18 +0000289{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700290 PLM_PACKET pPacket;
291 PUM_PACKET pUmPacket;
292 void *skb;
293 int queue_rx = 0;
294 int ret = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000295
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700296 while ((pUmPacket = (PUM_PACKET)
297 QQ_PopHead (&pUmDevice->rx_out_of_buf_q.Container)) != 0) {
wdenkcc1c8a12002-11-02 22:58:18 +0000298
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700299 pPacket = (PLM_PACKET) pUmPacket;
wdenkcc1c8a12002-11-02 22:58:18 +0000300
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700301 /* reuse an old skb */
302 if (pUmPacket->skbuff) {
303 QQ_PushTail (&pDevice->RxPacketFreeQ.Container,
304 pPacket);
305 queue_rx = 1;
306 continue;
307 }
308 if ((skb = bcm570xPktAlloc (pUmDevice->index,
309 pPacket->u.Rx.RxBufferSize + 2)) ==
310 0) {
311 QQ_PushHead (&pUmDevice->rx_out_of_buf_q.Container,
312 pPacket);
313 printf ("NOTICE: Out of RX memory.\n");
314 ret = 1;
315 break;
316 }
317
318 pUmPacket->skbuff = skb;
319 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
320 queue_rx = 1;
wdenkcc1c8a12002-11-02 22:58:18 +0000321 }
322
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700323 if (queue_rx) {
324 LM_QueueRxPackets (pDevice);
325 }
wdenkcc1c8a12002-11-02 22:58:18 +0000326
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700327 return ret;
wdenkcc1c8a12002-11-02 22:58:18 +0000328}
329
330/*
331 * Probe, Map, and Init 570x device.
332 */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700333int eth_init (bd_t * bis)
wdenkcc1c8a12002-11-02 22:58:18 +0000334{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700335 int i, rv, devFound = FALSE;
336 pci_dev_t devbusfn;
337 unsigned short status;
wdenkcc1c8a12002-11-02 22:58:18 +0000338
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700339 /* Find PCI device, if it exists, configure ... */
340 for (i = 0; i < n570xDevices; i++) {
341 devbusfn = pci_find_device (bcm570xDevices[i].vendor_id,
342 bcm570xDevices[i].device_id, 0);
343 if (devbusfn == -1) {
344 continue; /* No device of that vendor/device ID */
345 } else {
346
347 /* Set ILINE */
348 pci_write_config_byte (devbusfn,
349 PCI_INTERRUPT_LINE,
350 BCM570X_ILINE);
351
352 /*
353 * 0x10 - 0x14 define one 64-bit MBAR.
354 * 0x14 is the higher-order address bits of the BAR.
355 */
356 pci_write_config_dword (devbusfn,
357 PCI_BASE_ADDRESS_1, 0);
358
359 ioBase = BCM570X_MBAR;
360
361 pci_write_config_dword (devbusfn,
362 PCI_BASE_ADDRESS_0, ioBase);
363
364 /*
365 * Enable PCI memory, IO, and Master -- don't
366 * reset any status bits in doing so.
367 */
368 pci_read_config_word (devbusfn, PCI_COMMAND, &status);
369
370 status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
371
372 pci_write_config_word (devbusfn, PCI_COMMAND, status);
373
374 printf
375 ("\n%s: bus %d, device %d, function %d: MBAR=0x%x\n",
376 board_info[bcm570xDevices[i].board_id].name,
377 PCI_BUS (devbusfn), PCI_DEV (devbusfn),
378 PCI_FUNC (devbusfn), ioBase);
379
380 /* Allocate once, but always clear on init */
381 if (!pDevice) {
382 pDevice = malloc (sizeof (UM_DEVICE_BLOCK));
383 pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
384 memset (pDevice, 0x0, sizeof (UM_DEVICE_BLOCK));
385 }
386
387 /* Configure pci dev structure */
388 pUmDevice->pdev = devbusfn;
389 pUmDevice->index = 0;
390 pUmDevice->tx_pkt = 0;
391 pUmDevice->rx_pkt = 0;
392 devFound = TRUE;
393 break;
394 }
395 }
396
397 if (!devFound) {
398 printf
399 ("eth_init: FAILURE: no BCM570x Ethernet devices found.\n");
400 return -1;
401 }
402
403 /* Setup defaults for chip */
404 pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
405
406 if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) {
407 pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
wdenkcc1c8a12002-11-02 22:58:18 +0000408 } else {
409
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700410 if (rx_checksum[i]) {
411 pDevice->TaskToOffload |=
412 LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
413 LM_TASK_OFFLOAD_RX_UDP_CHECKSUM;
414 }
wdenkcc1c8a12002-11-02 22:58:18 +0000415
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700416 if (tx_checksum[i]) {
417 pDevice->TaskToOffload |=
418 LM_TASK_OFFLOAD_TX_TCP_CHECKSUM |
419 LM_TASK_OFFLOAD_TX_UDP_CHECKSUM;
420 pDevice->NoTxPseudoHdrChksum = TRUE;
421 }
wdenkcc1c8a12002-11-02 22:58:18 +0000422 }
423
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700424 /* Set Device PCI Memory base address */
425 pDevice->pMappedMemBase = (PLM_UINT8) ioBase;
426
427 /* Pull down adapter info */
428 if ((rv = LM_GetAdapterInfo (pDevice)) != LM_STATUS_SUCCESS) {
429 printf ("bcm570xEnd: LM_GetAdapterInfo failed: rv=%d!\n", rv);
430 return -2;
wdenkcc1c8a12002-11-02 22:58:18 +0000431 }
wdenkcc1c8a12002-11-02 22:58:18 +0000432
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700433 /* Lock not needed */
434 pUmDevice->do_global_lock = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000435
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700436 if (T3_ASIC_REV (pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) {
437 /* The 5700 chip works best without interleaved register */
438 /* accesses on certain machines. */
439 pUmDevice->do_global_lock = 1;
440 }
wdenkcc1c8a12002-11-02 22:58:18 +0000441
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700442 /* Setup timer delays */
443 if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
444 pDevice->UseTaggedStatus = TRUE;
445 pUmDevice->timer_interval = CFG_HZ;
446 } else {
447 pUmDevice->timer_interval = CFG_HZ / 50;
448 }
wdenkcc1c8a12002-11-02 22:58:18 +0000449
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700450 /* Grab name .... */
451 pUmDevice->name =
452 (char *)malloc (strlen (board_info[bcm570xDevices[i].board_id].name)
453 + 1);
454 strcpy (pUmDevice->name, board_info[bcm570xDevices[i].board_id].name);
wdenkcc1c8a12002-11-02 22:58:18 +0000455
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700456 memcpy (pDevice->NodeAddress, bis->bi_enetaddr, 6);
457 LM_SetMacAddress (pDevice, bis->bi_enetaddr);
458 /* Init queues .. */
459 QQ_InitQueue (&pUmDevice->rx_out_of_buf_q.Container,
460 MAX_RX_PACKET_DESC_COUNT);
461 pUmDevice->rx_last_cnt = pUmDevice->tx_last_cnt = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000462
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700463 /* delay for 4 seconds */
464 pUmDevice->delayed_link_ind = (4 * CFG_HZ) / pUmDevice->timer_interval;
wdenkcc1c8a12002-11-02 22:58:18 +0000465
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700466 pUmDevice->adaptive_expiry = CFG_HZ / pUmDevice->timer_interval;
wdenkcc1c8a12002-11-02 22:58:18 +0000467
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700468 /* Sometimes we get spurious ints. after reset when link is down. */
469 /* This field tells the isr to service the int. even if there is */
470 /* no status block update. */
471 pUmDevice->adapter_just_inited =
472 (3 * CFG_HZ) / pUmDevice->timer_interval;
wdenkcc1c8a12002-11-02 22:58:18 +0000473
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700474 /* Initialize 570x */
475 if (LM_InitializeAdapter (pDevice) != LM_STATUS_SUCCESS) {
476 printf ("ERROR: Adapter initialization failed.\n");
477 return ERROR;
478 }
wdenkcc1c8a12002-11-02 22:58:18 +0000479
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700480 /* Enable chip ISR */
481 LM_EnableInterrupt (pDevice);
wdenkcc1c8a12002-11-02 22:58:18 +0000482
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700483 /* Clear MC table */
484 LM_MulticastClear (pDevice);
wdenkcc1c8a12002-11-02 22:58:18 +0000485
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700486 /* Enable Multicast */
487 LM_SetReceiveMask (pDevice,
488 pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST);
wdenkcc1c8a12002-11-02 22:58:18 +0000489
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700490 pUmDevice->opened = 1;
491 pUmDevice->tx_full = 0;
492 pUmDevice->tx_pkt = 0;
493 pUmDevice->rx_pkt = 0;
494 printf ("eth%d: %s @0x%lx,",
495 pDevice->index, pUmDevice->name, (unsigned long)ioBase);
496 printf ("node addr ");
497 for (i = 0; i < 6; i++) {
498 printf ("%2.2x", pDevice->NodeAddress[i]);
499 }
500 printf ("\n");
wdenkcc1c8a12002-11-02 22:58:18 +0000501
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700502 printf ("eth%d: ", pDevice->index);
503 printf ("%s with ", chip_rev[bcm570xDevices[i].board_id].name);
wdenkcc1c8a12002-11-02 22:58:18 +0000504
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700505 if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5400_PHY_ID)
506 printf ("Broadcom BCM5400 Copper ");
507 else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID)
508 printf ("Broadcom BCM5401 Copper ");
509 else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5411_PHY_ID)
510 printf ("Broadcom BCM5411 Copper ");
511 else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5701_PHY_ID)
512 printf ("Broadcom BCM5701 Integrated Copper ");
513 else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5703_PHY_ID)
514 printf ("Broadcom BCM5703 Integrated Copper ");
515 else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM8002_PHY_ID)
516 printf ("Broadcom BCM8002 SerDes ");
517 else if (pDevice->EnableTbi)
518 printf ("Agilent HDMP-1636 SerDes ");
519 else
520 printf ("Unknown ");
521 printf ("transceiver found\n");
wdenkcc1c8a12002-11-02 22:58:18 +0000522
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700523 printf ("eth%d: %s, MTU: %d,",
524 pDevice->index, pDevice->BusSpeedStr, 1500);
wdenkcc1c8a12002-11-02 22:58:18 +0000525
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700526 if ((pDevice->ChipRevId != T3_CHIP_ID_5700_B0) && rx_checksum[i])
527 printf ("Rx Checksum ON\n");
528 else
529 printf ("Rx Checksum OFF\n");
530 initialized++;
wdenkcc1c8a12002-11-02 22:58:18 +0000531
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700532 return 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000533}
534
535/* Ethernet Interrupt service routine */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700536void eth_isr (void)
wdenkcc1c8a12002-11-02 22:58:18 +0000537{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700538 LM_UINT32 oldtag, newtag;
539 int i;
wdenkcc1c8a12002-11-02 22:58:18 +0000540
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700541 pUmDevice->interrupt = 1;
wdenkcc1c8a12002-11-02 22:58:18 +0000542
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700543 if (pDevice->UseTaggedStatus) {
544 if ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) ||
545 pUmDevice->adapter_just_inited) {
546 MB_REG_WR (pDevice, Mailbox.Interrupt[0].Low, 1);
547 oldtag = pDevice->pStatusBlkVirt->StatusTag;
wdenkcc1c8a12002-11-02 22:58:18 +0000548
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700549 for (i = 0;; i++) {
550 pDevice->pStatusBlkVirt->Status &=
551 ~STATUS_BLOCK_UPDATED;
552 LM_ServiceInterrupts (pDevice);
553 newtag = pDevice->pStatusBlkVirt->StatusTag;
554 if ((newtag == oldtag) || (i > 50)) {
555 MB_REG_WR (pDevice,
556 Mailbox.Interrupt[0].Low,
557 newtag << 24);
558 if (pDevice->UndiFix) {
559 REG_WR (pDevice, Grc.LocalCtrl,
560 pDevice->
561 GrcLocalCtrl | 0x2);
562 }
563 break;
564 }
565 oldtag = newtag;
566 }
567 }
568 } else {
569 while (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) {
570 unsigned int dummy;
571
572 pDevice->pMemView->Mailbox.Interrupt[0].Low = 1;
573 pDevice->pStatusBlkVirt->Status &=
574 ~STATUS_BLOCK_UPDATED;
575 LM_ServiceInterrupts (pDevice);
576 pDevice->pMemView->Mailbox.Interrupt[0].Low = 0;
577 dummy = pDevice->pMemView->Mailbox.Interrupt[0].Low;
578 }
wdenkcc1c8a12002-11-02 22:58:18 +0000579 }
wdenkcc1c8a12002-11-02 22:58:18 +0000580
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700581 /* Allocate new RX buffers */
582 if (QQ_GetEntryCnt (&pUmDevice->rx_out_of_buf_q.Container)) {
583 bcm570xReplenishRxBuffers (pUmDevice);
wdenkcc1c8a12002-11-02 22:58:18 +0000584 }
wdenkcc1c8a12002-11-02 22:58:18 +0000585
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700586 /* Queue packets */
587 if (QQ_GetEntryCnt (&pDevice->RxPacketFreeQ.Container)) {
588 LM_QueueRxPackets (pDevice);
wdenkcc1c8a12002-11-02 22:58:18 +0000589 }
wdenkcc1c8a12002-11-02 22:58:18 +0000590
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700591 if (pUmDevice->tx_queued) {
592 pUmDevice->tx_queued = 0;
593 }
594
595 if (pUmDevice->tx_full) {
596 if (pDevice->LinkStatus != LM_STATUS_LINK_DOWN) {
597 printf
598 ("NOTICE: tx was previously blocked, restarting MUX\n");
599 pUmDevice->tx_full = 0;
600 }
601 }
602
603 pUmDevice->interrupt = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000604
605}
606
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700607int eth_send (volatile void *packet, int length)
wdenkcc1c8a12002-11-02 22:58:18 +0000608{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700609 int status = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000610#if ET_DEBUG
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700611 unsigned char *ptr = (unsigned char *)packet;
wdenkcc1c8a12002-11-02 22:58:18 +0000612#endif
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700613 PLM_PACKET pPacket;
614 PUM_PACKET pUmPacket;
wdenkcc1c8a12002-11-02 22:58:18 +0000615
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700616 /* Link down, return */
617 while (pDevice->LinkStatus == LM_STATUS_LINK_DOWN) {
wdenkcc1c8a12002-11-02 22:58:18 +0000618#if 0
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700619 printf ("eth%d: link down - check cable or link partner.\n",
620 pUmDevice->index);
wdenkcc1c8a12002-11-02 22:58:18 +0000621#endif
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700622 eth_isr ();
wdenkcc1c8a12002-11-02 22:58:18 +0000623
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700624 /* Wait to see link for one-half a second before sending ... */
625 udelay (1500000);
wdenkcc1c8a12002-11-02 22:58:18 +0000626
wdenkcc1c8a12002-11-02 22:58:18 +0000627 }
628
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700629 /* Clear sent flag */
630 pUmDevice->tx_pkt = 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000631
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700632 /* Previously blocked */
633 if (pUmDevice->tx_full) {
634 printf ("eth%d: tx blocked.\n", pUmDevice->index);
635 return 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000636 }
637
638 pPacket = (PLM_PACKET)
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700639 QQ_PopHead (&pDevice->TxPacketFreeQ.Container);
wdenkcc1c8a12002-11-02 22:58:18 +0000640
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700641 if (pPacket == 0) {
642 pUmDevice->tx_full = 1;
643 printf ("bcm570xEndSend: TX full!\n");
644 return 0;
wdenkcc1c8a12002-11-02 22:58:18 +0000645 }
646
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700647 if (pDevice->SendBdLeft.counter == 0) {
648 pUmDevice->tx_full = 1;
649 printf ("bcm570xEndSend: no more TX descriptors!\n");
650 QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
651 return 0;
652 }
653
654 if (length <= 0) {
655 printf ("eth: bad packet size: %d\n", length);
656 goto out;
657 }
658
659 /* Get packet buffers and fragment list */
wdenkcc1c8a12002-11-02 22:58:18 +0000660 pUmPacket = (PUM_PACKET) pPacket;
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700661 /* Single DMA Descriptor transmit.
662 * Fragments may be provided, but one DMA descriptor max is
663 * used to send the packet.
664 */
665 if (MM_CoalesceTxBuffer (pDevice, pPacket) != LM_STATUS_SUCCESS) {
666 if (pUmPacket->skbuff == NULL) {
667 /* Packet was discarded */
668 printf ("TX: failed (1)\n");
669 status = 1;
670 } else {
671 printf ("TX: failed (2)\n");
672 status = 2;
673 }
674 QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
675 return status;
wdenkcc1c8a12002-11-02 22:58:18 +0000676 }
677
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700678 /* Copy packet to DMA buffer */
679 memset (pUmPacket->skbuff, 0x0, MAX_PACKET_SIZE);
680 memcpy ((void *)pUmPacket->skbuff, (void *)packet, length);
681 pPacket->PacketSize = length;
682 pPacket->Flags |= SND_BD_FLAG_END | SND_BD_FLAG_COAL_NOW;
683 pPacket->u.Tx.FragCount = 1;
684 /* We've already provided a frame ready for transmission */
685 pPacket->Flags &= ~SND_BD_FLAG_TCP_UDP_CKSUM;
wdenkcc1c8a12002-11-02 22:58:18 +0000686
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700687 if (LM_SendPacket (pDevice, pPacket) == LM_STATUS_FAILURE) {
688 /*
689 * A lower level send failure will push the packet descriptor back
690 * in the free queue, so just deal with the VxWorks clusters.
691 */
692 if (pUmPacket->skbuff == NULL) {
693 printf ("TX failed (1)!\n");
694 /* Packet was discarded */
695 status = 3;
696 } else {
697 /* A resource problem ... */
698 printf ("TX failed (2)!\n");
699 status = 4;
700 }
wdenkcc1c8a12002-11-02 22:58:18 +0000701
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700702 if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) == 0) {
703 printf ("TX: emptyQ!\n");
704 pUmDevice->tx_full = 1;
705 }
706 }
wdenkcc1c8a12002-11-02 22:58:18 +0000707
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700708 while (pUmDevice->tx_pkt == 0) {
709 /* Service TX */
710 eth_isr ();
711 }
712#if ET_DEBUG
713 printf ("eth_send: 0x%x, %d bytes\n"
714 "[%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x] ...\n",
715 (int)pPacket, length,
716 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5],
717 ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12],
718 ptr[13], ptr[14], ptr[15]);
719#endif
720 pUmDevice->tx_pkt = 0;
721 QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
wdenkcc1c8a12002-11-02 22:58:18 +0000722
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700723 /* Done with send */
724 out:
725 return status;
wdenkcc1c8a12002-11-02 22:58:18 +0000726}
727
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700728/* Ethernet receive */
729int eth_rx (void)
730{
731 PLM_PACKET pPacket = NULL;
732 PUM_PACKET pUmPacket = NULL;
733 void *skb;
734 int size = 0;
735
736 while (TRUE) {
737
738 bcm570x_service_isr:
739 /* Pull down packet if it is there */
740 eth_isr ();
741
742 /* Indicate RX packets called */
743 if (pUmDevice->rx_pkt) {
744 /* printf("eth_rx: got a packet...\n"); */
745 pUmDevice->rx_pkt = 0;
746 } else {
747 /* printf("eth_rx: waiting for packet...\n"); */
748 goto bcm570x_service_isr;
749 }
750
751 pPacket = (PLM_PACKET)
752 QQ_PopHead (&pDevice->RxPacketReceivedQ.Container);
753
754 if (pPacket == 0) {
755 printf ("eth_rx: empty packet!\n");
756 goto bcm570x_service_isr;
757 }
758
759 pUmPacket = (PUM_PACKET) pPacket;
760#if ET_DEBUG
761 printf ("eth_rx: packet @0x%x\n", (int)pPacket);
762#endif
763 /* If the packet generated an error, reuse buffer */
764 if ((pPacket->PacketStatus != LM_STATUS_SUCCESS) ||
765 ((size = pPacket->PacketSize) > pDevice->RxMtu)) {
766
767 /* reuse skb */
768 QQ_PushTail (&pDevice->RxPacketFreeQ.Container,
769 pPacket);
770 printf ("eth_rx: error in packet dma!\n");
771 goto bcm570x_service_isr;
772 }
773
774 /* Set size and address */
775 skb = pUmPacket->skbuff;
776 size = pPacket->PacketSize;
777
778 /* Pass the packet up to the protocol
779 * layers.
780 */
781 NetReceive (skb, size);
782
783 /* Free packet buffer */
784 bcm570xPktFree (pUmDevice->index, skb);
785 pUmPacket->skbuff = NULL;
786
787 /* Reuse SKB */
788 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
789
790 return 0; /* Got a packet, bail ... */
791 }
792 return size;
793}
wdenkcc1c8a12002-11-02 22:58:18 +0000794
wdenkcc1c8a12002-11-02 22:58:18 +0000795/* Shut down device */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700796void eth_halt (void)
wdenkcc1c8a12002-11-02 22:58:18 +0000797{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700798 int i;
799 if (initialized)
800 if (pDevice && pUmDevice && pUmDevice->opened) {
801 printf ("\neth%d:%s,", pUmDevice->index,
802 pUmDevice->name);
803 printf ("HALT,");
804 /* stop device */
805 LM_Halt (pDevice);
806 printf ("POWER DOWN,");
807 LM_SetPowerState (pDevice, LM_POWER_STATE_D3);
wdenkcc1c8a12002-11-02 22:58:18 +0000808
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700809 /* Free the memory allocated by the device in tigon3 */
810 for (i = 0; i < pUmDevice->mem_list_num; i++) {
811 if (pUmDevice->mem_list[i]) {
812 /* sanity check */
813 if (pUmDevice->dma_list[i]) { /* cache-safe memory */
814 free (pUmDevice->mem_list[i]);
815 } else {
816 free (pUmDevice->mem_list[i]); /* normal memory */
817 }
818 }
819 }
820 pUmDevice->opened = 0;
821 free (pDevice);
822 pDevice = NULL;
823 pUmDevice = NULL;
824 initialized = 0;
825 printf ("done - offline.\n");
wdenkcc1c8a12002-11-02 22:58:18 +0000826 }
wdenkcc1c8a12002-11-02 22:58:18 +0000827}
828
wdenkcc1c8a12002-11-02 22:58:18 +0000829/*
830 *
831 * Middle Module: Interface between the HW driver (tigon3 modules) and
832 * the native (SENS) driver. These routines implement the system
833 * interface for tigon3 on VxWorks.
834 */
835
836/* Middle module dependency - size of a packet descriptor */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700837int MM_Packet_Desc_Size = sizeof (UM_PACKET);
wdenkcc1c8a12002-11-02 22:58:18 +0000838
839LM_STATUS
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700840MM_ReadConfig32 (PLM_DEVICE_BLOCK pDevice,
841 LM_UINT32 Offset, LM_UINT32 * pValue32)
wdenkcc1c8a12002-11-02 22:58:18 +0000842{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700843 UM_DEVICE_BLOCK *pUmDevice;
844 pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
845 pci_read_config_dword (pUmDevice->pdev, Offset, (u32 *) pValue32);
846 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000847}
848
849LM_STATUS
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700850MM_WriteConfig32 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT32 Value32)
wdenkcc1c8a12002-11-02 22:58:18 +0000851{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700852 UM_DEVICE_BLOCK *pUmDevice;
853 pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
854 pci_write_config_dword (pUmDevice->pdev, Offset, Value32);
855 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000856}
857
858LM_STATUS
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700859MM_ReadConfig16 (PLM_DEVICE_BLOCK pDevice,
860 LM_UINT32 Offset, LM_UINT16 * pValue16)
wdenkcc1c8a12002-11-02 22:58:18 +0000861{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700862 UM_DEVICE_BLOCK *pUmDevice;
863 pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
864 pci_read_config_word (pUmDevice->pdev, Offset, (u16 *) pValue16);
865 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000866}
867
868LM_STATUS
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700869MM_WriteConfig16 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT16 Value16)
wdenkcc1c8a12002-11-02 22:58:18 +0000870{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700871 UM_DEVICE_BLOCK *pUmDevice;
872 pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
873 pci_write_config_word (pUmDevice->pdev, Offset, Value16);
874 return LM_STATUS_SUCCESS;
875}
wdenkcc1c8a12002-11-02 22:58:18 +0000876
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700877LM_STATUS
878MM_AllocateSharedMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
879 PLM_VOID * pMemoryBlockVirt,
880 PLM_PHYSICAL_ADDRESS pMemoryBlockPhy, LM_BOOL Cached)
881{
882 PLM_VOID pvirt;
883 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
884 dma_addr_t mapping;
wdenkcc1c8a12002-11-02 22:58:18 +0000885
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700886 pvirt = malloc (BlockSize);
887 mapping = (dma_addr_t) (pvirt);
888 if (!pvirt)
889 return LM_STATUS_FAILURE;
890
891 pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
892 pUmDevice->dma_list[pUmDevice->mem_list_num] = mapping;
893 pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
894 memset (pvirt, 0, BlockSize);
895
896 *pMemoryBlockVirt = (PLM_VOID) pvirt;
897 MM_SetAddr (pMemoryBlockPhy, (dma_addr_t) mapping);
898
899 return LM_STATUS_SUCCESS;
900}
901
902LM_STATUS
903MM_AllocateMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
904 PLM_VOID * pMemoryBlockVirt)
905{
906 PLM_VOID pvirt;
907 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
908
909 pvirt = malloc (BlockSize);
910
911 if (!pvirt)
912 return LM_STATUS_FAILURE;
913
914 pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
915 pUmDevice->dma_list[pUmDevice->mem_list_num] = 0;
916 pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
917 memset (pvirt, 0, BlockSize);
918 *pMemoryBlockVirt = pvirt;
919
920 return LM_STATUS_SUCCESS;
921}
922
923LM_STATUS MM_MapMemBase (PLM_DEVICE_BLOCK pDevice)
924{
925 printf ("BCM570x PCI Memory base address @0x%x\n",
926 (unsigned int)pDevice->pMappedMemBase);
927 return LM_STATUS_SUCCESS;
928}
929
930LM_STATUS MM_InitializeUmPackets (PLM_DEVICE_BLOCK pDevice)
931{
932 int i;
933 void *skb;
934 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
935 PUM_PACKET pUmPacket = NULL;
936 PLM_PACKET pPacket = NULL;
937
938 for (i = 0; i < pDevice->RxPacketDescCnt; i++) {
939 pPacket = QQ_PopHead (&pDevice->RxPacketFreeQ.Container);
940 pUmPacket = (PUM_PACKET) pPacket;
941
942 if (pPacket == 0) {
943 printf ("MM_InitializeUmPackets: Bad RxPacketFreeQ\n");
944 }
945
946 skb = bcm570xPktAlloc (pUmDevice->index,
947 pPacket->u.Rx.RxBufferSize + 2);
948
949 if (skb == 0) {
950 pUmPacket->skbuff = 0;
951 QQ_PushTail (&pUmDevice->rx_out_of_buf_q.Container,
952 pPacket);
953 printf ("MM_InitializeUmPackets: out of buffer.\n");
954 continue;
955 }
956
957 pUmPacket->skbuff = skb;
958 QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
wdenkcc1c8a12002-11-02 22:58:18 +0000959 }
960
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700961 pUmDevice->rx_low_buf_thresh = pDevice->RxPacketDescCnt / 8;
wdenkcc1c8a12002-11-02 22:58:18 +0000962
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700963 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +0000964}
965
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700966LM_STATUS MM_GetConfig (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +0000967{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700968 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
969 int index = pDevice->index;
wdenkcc1c8a12002-11-02 22:58:18 +0000970
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700971 if (auto_speed[index] == 0)
972 pDevice->DisableAutoNeg = TRUE;
973 else
wdenkcc1c8a12002-11-02 22:58:18 +0000974 pDevice->DisableAutoNeg = FALSE;
Vadim Bendeburyf539edc2007-05-24 15:52:25 -0700975
976 if (line_speed[index] == 0) {
977 pDevice->RequestedMediaType = LM_REQUESTED_MEDIA_TYPE_AUTO;
978 pDevice->DisableAutoNeg = FALSE;
979 } else {
980 if (line_speed[index] == 1000) {
981 if (pDevice->EnableTbi) {
982 pDevice->RequestedMediaType =
983 LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX;
984 } else if (full_duplex[index]) {
985 pDevice->RequestedMediaType =
986 LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX;
987 } else {
988 pDevice->RequestedMediaType =
989 LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS;
990 }
991 if (!pDevice->EnableTbi)
992 pDevice->DisableAutoNeg = FALSE;
993 } else if (line_speed[index] == 100) {
994 if (full_duplex[index]) {
995 pDevice->RequestedMediaType =
996 LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX;
997 } else {
998 pDevice->RequestedMediaType =
999 LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS;
1000 }
1001 } else if (line_speed[index] == 10) {
1002 if (full_duplex[index]) {
1003 pDevice->RequestedMediaType =
1004 LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX;
1005 } else {
1006 pDevice->RequestedMediaType =
1007 LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS;
1008 }
1009 } else {
1010 pDevice->RequestedMediaType =
1011 LM_REQUESTED_MEDIA_TYPE_AUTO;
1012 pDevice->DisableAutoNeg = FALSE;
1013 }
1014
wdenkcc1c8a12002-11-02 22:58:18 +00001015 }
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001016 pDevice->FlowControlCap = 0;
1017 if (rx_flow_control[index] != 0) {
1018 pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
wdenkcc1c8a12002-11-02 22:58:18 +00001019 }
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001020 if (tx_flow_control[index] != 0) {
1021 pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
wdenkcc1c8a12002-11-02 22:58:18 +00001022 }
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001023 if ((auto_flow_control[index] != 0) &&
1024 (pDevice->DisableAutoNeg == FALSE)) {
1025
1026 pDevice->FlowControlCap |= LM_FLOW_CONTROL_AUTO_PAUSE;
1027 if ((tx_flow_control[index] == 0) &&
1028 (rx_flow_control[index] == 0)) {
1029 pDevice->FlowControlCap |=
1030 LM_FLOW_CONTROL_TRANSMIT_PAUSE |
1031 LM_FLOW_CONTROL_RECEIVE_PAUSE;
1032 }
wdenkcc1c8a12002-11-02 22:58:18 +00001033 }
1034
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001035 /* Default MTU for now */
1036 pUmDevice->mtu = 1500;
wdenkcc1c8a12002-11-02 22:58:18 +00001037
1038#if T3_JUMBO_RCV_RCB_ENTRY_COUNT
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001039 if (pUmDevice->mtu > 1500) {
1040 pDevice->RxMtu = pUmDevice->mtu;
1041 pDevice->RxJumboDescCnt = DEFAULT_JUMBO_RCV_DESC_COUNT;
1042 } else {
1043 pDevice->RxJumboDescCnt = 0;
1044 }
1045 pDevice->RxJumboDescCnt = rx_jumbo_desc_cnt[index];
wdenkcc1c8a12002-11-02 22:58:18 +00001046#else
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001047 pDevice->RxMtu = pUmDevice->mtu;
wdenkcc1c8a12002-11-02 22:58:18 +00001048#endif
1049
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001050 if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
1051 pDevice->UseTaggedStatus = TRUE;
1052 pUmDevice->timer_interval = CFG_HZ;
wdenkcc1c8a12002-11-02 22:58:18 +00001053 } else {
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001054 pUmDevice->timer_interval = CFG_HZ / 50;
wdenkcc1c8a12002-11-02 22:58:18 +00001055 }
wdenkcc1c8a12002-11-02 22:58:18 +00001056
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001057 pDevice->TxPacketDescCnt = tx_pkt_desc_cnt[index];
1058 pDevice->RxStdDescCnt = rx_std_desc_cnt[index];
1059 /* Note: adaptive coalescence really isn't adaptive in this driver */
1060 pUmDevice->rx_adaptive_coalesce = rx_adaptive_coalesce[index];
1061 if (!pUmDevice->rx_adaptive_coalesce) {
1062 pDevice->RxCoalescingTicks = rx_coalesce_ticks[index];
1063 if (pDevice->RxCoalescingTicks > MAX_RX_COALESCING_TICKS)
1064 pDevice->RxCoalescingTicks = MAX_RX_COALESCING_TICKS;
1065 pUmDevice->rx_curr_coalesce_ticks = pDevice->RxCoalescingTicks;
wdenkcc1c8a12002-11-02 22:58:18 +00001066
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001067 pDevice->RxMaxCoalescedFrames = rx_max_coalesce_frames[index];
1068 if (pDevice->RxMaxCoalescedFrames > MAX_RX_MAX_COALESCED_FRAMES)
1069 pDevice->RxMaxCoalescedFrames =
1070 MAX_RX_MAX_COALESCED_FRAMES;
1071 pUmDevice->rx_curr_coalesce_frames =
1072 pDevice->RxMaxCoalescedFrames;
1073 pDevice->StatsCoalescingTicks = stats_coalesce_ticks[index];
1074 if (pDevice->StatsCoalescingTicks > MAX_STATS_COALESCING_TICKS)
1075 pDevice->StatsCoalescingTicks =
1076 MAX_STATS_COALESCING_TICKS;
wdenkcc1c8a12002-11-02 22:58:18 +00001077 } else {
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001078 pUmDevice->rx_curr_coalesce_frames =
1079 DEFAULT_RX_MAX_COALESCED_FRAMES;
1080 pUmDevice->rx_curr_coalesce_ticks = DEFAULT_RX_COALESCING_TICKS;
wdenkcc1c8a12002-11-02 22:58:18 +00001081 }
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001082 pDevice->TxCoalescingTicks = tx_coalesce_ticks[index];
1083 if (pDevice->TxCoalescingTicks > MAX_TX_COALESCING_TICKS)
1084 pDevice->TxCoalescingTicks = MAX_TX_COALESCING_TICKS;
1085 pDevice->TxMaxCoalescedFrames = tx_max_coalesce_frames[index];
1086 if (pDevice->TxMaxCoalescedFrames > MAX_TX_MAX_COALESCED_FRAMES)
1087 pDevice->TxMaxCoalescedFrames = MAX_TX_MAX_COALESCED_FRAMES;
1088
1089 if (enable_wol[index]) {
1090 pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET;
1091 pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET;
1092 }
1093 pDevice->NicSendBd = TRUE;
1094
1095 /* Don't update status blocks during interrupt */
1096 pDevice->RxCoalescingTicksDuringInt = 0;
1097 pDevice->TxCoalescingTicksDuringInt = 0;
1098
1099 return LM_STATUS_SUCCESS;
1100
1101}
1102
1103LM_STATUS MM_StartTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1104{
1105 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1106 printf ("Start TX DMA: dev=%d packet @0x%x\n",
1107 (int)pUmDevice->index, (unsigned int)pPacket);
1108
1109 return LM_STATUS_SUCCESS;
1110}
1111
1112LM_STATUS MM_CompleteTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
1113{
1114 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1115 printf ("Complete TX DMA: dev=%d packet @0x%x\n",
1116 (int)pUmDevice->index, (unsigned int)pPacket);
1117 return LM_STATUS_SUCCESS;
1118}
1119
1120LM_STATUS MM_IndicateStatus (PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
1121{
1122 char buf[128];
1123 char lcd[4];
1124 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1125 LM_FLOW_CONTROL flow_control;
1126
1127 pUmDevice->delayed_link_ind = 0;
1128 memset (lcd, 0x0, 4);
1129
1130 if (Status == LM_STATUS_LINK_DOWN) {
1131 sprintf (buf, "eth%d: %s: NIC Link is down\n",
1132 pUmDevice->index, pUmDevice->name);
1133 lcd[0] = 'L';
1134 lcd[1] = 'N';
1135 lcd[2] = 'K';
1136 lcd[3] = '?';
1137 } else if (Status == LM_STATUS_LINK_ACTIVE) {
1138 sprintf (buf, "eth%d:%s: ", pUmDevice->index, pUmDevice->name);
1139
1140 if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) {
1141 strcat (buf, "1000 Mbps ");
1142 lcd[0] = '1';
1143 lcd[1] = 'G';
1144 lcd[2] = 'B';
1145 } else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS) {
1146 strcat (buf, "100 Mbps ");
1147 lcd[0] = '1';
1148 lcd[1] = '0';
1149 lcd[2] = '0';
1150 } else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) {
1151 strcat (buf, "10 Mbps ");
1152 lcd[0] = '1';
1153 lcd[1] = '0';
1154 lcd[2] = ' ';
1155 }
1156 if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) {
1157 strcat (buf, "full duplex");
1158 lcd[3] = 'F';
1159 } else {
1160 strcat (buf, "half duplex");
1161 lcd[3] = 'H';
1162 }
1163 strcat (buf, " link up");
1164
1165 flow_control = pDevice->FlowControl &
1166 (LM_FLOW_CONTROL_RECEIVE_PAUSE |
1167 LM_FLOW_CONTROL_TRANSMIT_PAUSE);
1168
1169 if (flow_control) {
1170 if (flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE) {
1171 strcat (buf, ", receive ");
1172 if (flow_control &
1173 LM_FLOW_CONTROL_TRANSMIT_PAUSE)
1174 strcat (buf, " & transmit ");
1175 } else {
1176 strcat (buf, ", transmit ");
1177 }
1178 strcat (buf, "flow control ON");
1179 } else {
1180 strcat (buf, ", flow control OFF");
1181 }
1182 strcat (buf, "\n");
1183 printf ("%s", buf);
1184 }
wdenkcc1c8a12002-11-02 22:58:18 +00001185#if 0
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001186 sysLedDsply (lcd[0], lcd[1], lcd[2], lcd[3]);
wdenkcc1c8a12002-11-02 22:58:18 +00001187#endif
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001188 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001189}
1190
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001191LM_STATUS MM_FreeRxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
wdenkcc1c8a12002-11-02 22:58:18 +00001192{
1193
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001194 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1195 PUM_PACKET pUmPacket;
1196 void *skb;
wdenkcc1c8a12002-11-02 22:58:18 +00001197
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001198 pUmPacket = (PUM_PACKET) pPacket;
wdenkcc1c8a12002-11-02 22:58:18 +00001199
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001200 if ((skb = pUmPacket->skbuff))
1201 bcm570xPktFree (pUmDevice->index, skb);
wdenkcc1c8a12002-11-02 22:58:18 +00001202
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001203 pUmPacket->skbuff = 0;
wdenkcc1c8a12002-11-02 22:58:18 +00001204
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001205 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001206}
1207
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001208unsigned long MM_AnGetCurrentTime_us (PAN_STATE_INFO pAnInfo)
wdenkcc1c8a12002-11-02 22:58:18 +00001209{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001210 return get_timer (0);
wdenkcc1c8a12002-11-02 22:58:18 +00001211}
1212
1213/*
1214 * Transform an MBUF chain into a single MBUF.
1215 * This routine will fail if the amount of data in the
1216 * chain overflows a transmit buffer. In that case,
1217 * the incoming MBUF chain will be freed. This routine can
1218 * also fail by not being able to allocate a new MBUF (including
1219 * cluster and mbuf headers). In that case the failure is
1220 * non-fatal. The incoming cluster chain is not freed, giving
1221 * the caller the choice of whether to try a retransmit later.
1222 */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001223LM_STATUS MM_CoalesceTxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
wdenkcc1c8a12002-11-02 22:58:18 +00001224{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001225 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1226 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1227 void *skbnew;
1228 int len = 0;
wdenkcc1c8a12002-11-02 22:58:18 +00001229
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001230 if (len == 0)
1231 return (LM_STATUS_SUCCESS);
1232
1233 if (len > MAX_PACKET_SIZE) {
1234 printf ("eth%d: xmit frame discarded, too big!, size = %d\n",
1235 pUmDevice->index, len);
1236 return (LM_STATUS_FAILURE);
1237 }
1238
1239 skbnew = bcm570xPktAlloc (pUmDevice->index, MAX_PACKET_SIZE);
1240
1241 if (skbnew == NULL) {
1242 pUmDevice->tx_full = 1;
1243 printf ("eth%d: out of transmit buffers", pUmDevice->index);
1244 return (LM_STATUS_FAILURE);
1245 }
1246
1247 /* New packet values */
1248 pUmPacket->skbuff = skbnew;
1249 pUmPacket->lm_packet.u.Tx.FragCount = 1;
1250
wdenk8bde7f72003-06-27 21:31:46 +00001251 return (LM_STATUS_SUCCESS);
wdenkcc1c8a12002-11-02 22:58:18 +00001252}
1253
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001254LM_STATUS MM_IndicateRxPackets (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +00001255{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001256 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1257 pUmDevice->rx_pkt = 1;
1258 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001259}
1260
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001261LM_STATUS MM_IndicateTxPackets (PLM_DEVICE_BLOCK pDevice)
wdenkcc1c8a12002-11-02 22:58:18 +00001262{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001263 PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
1264 PLM_PACKET pPacket;
1265 PUM_PACKET pUmPacket;
1266 void *skb;
1267 while (TRUE) {
wdenkcc1c8a12002-11-02 22:58:18 +00001268
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001269 pPacket = (PLM_PACKET)
1270 QQ_PopHead (&pDevice->TxPacketXmittedQ.Container);
wdenkcc1c8a12002-11-02 22:58:18 +00001271
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001272 if (pPacket == 0)
1273 break;
wdenkcc1c8a12002-11-02 22:58:18 +00001274
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001275 pUmPacket = (PUM_PACKET) pPacket;
1276 skb = (void *)pUmPacket->skbuff;
wdenkcc1c8a12002-11-02 22:58:18 +00001277
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001278 /*
1279 * Free MBLK if we transmitted a fragmented packet or a
1280 * non-fragmented packet straight from the VxWorks
1281 * buffer pool. If packet was copied to a local transmit
1282 * buffer, then there's no MBUF to free, just free
1283 * the transmit buffer back to the cluster pool.
1284 */
wdenkcc1c8a12002-11-02 22:58:18 +00001285
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001286 if (skb)
1287 bcm570xPktFree (pUmDevice->index, skb);
wdenkcc1c8a12002-11-02 22:58:18 +00001288
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001289 pUmPacket->skbuff = 0;
1290 QQ_PushTail (&pDevice->TxPacketFreeQ.Container, pPacket);
1291 pUmDevice->tx_pkt = 1;
1292 }
1293 if (pUmDevice->tx_full) {
1294 if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) >=
1295 (QQ_GetSize (&pDevice->TxPacketFreeQ.Container) >> 1))
1296 pUmDevice->tx_full = 0;
1297 }
1298 return LM_STATUS_SUCCESS;
wdenkcc1c8a12002-11-02 22:58:18 +00001299}
1300
1301/*
1302 * Scan an MBUF chain until we reach fragment number "frag"
1303 * Return its length and physical address.
1304 */
1305void MM_MapTxDma
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001306 (PLM_DEVICE_BLOCK pDevice,
1307 struct _LM_PACKET *pPacket,
1308 T3_64BIT_HOST_ADDR * paddr, LM_UINT32 * len, int frag) {
1309 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1310 *len = pPacket->PacketSize;
1311 MM_SetT3Addr (paddr, (dma_addr_t) pUmPacket->skbuff);
wdenkcc1c8a12002-11-02 22:58:18 +00001312}
1313
1314/*
1315 * Convert an mbuf address, a CPU local virtual address,
1316 * to a physical address as seen from a PCI device. Store the
1317 * result at paddr.
1318 */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001319void MM_MapRxDma (PLM_DEVICE_BLOCK pDevice,
1320 struct _LM_PACKET *pPacket, T3_64BIT_HOST_ADDR * paddr)
wdenkcc1c8a12002-11-02 22:58:18 +00001321{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001322 PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
1323 MM_SetT3Addr (paddr, (dma_addr_t) pUmPacket->skbuff);
wdenkcc1c8a12002-11-02 22:58:18 +00001324}
1325
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001326void MM_SetAddr (LM_PHYSICAL_ADDRESS * paddr, dma_addr_t addr)
wdenkcc1c8a12002-11-02 22:58:18 +00001327{
1328#if (BITS_PER_LONG == 64)
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001329 paddr->High = ((unsigned long)addr) >> 32;
1330 paddr->Low = ((unsigned long)addr) & 0xffffffff;
wdenkcc1c8a12002-11-02 22:58:18 +00001331#else
wdenk8bde7f72003-06-27 21:31:46 +00001332 paddr->High = 0;
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001333 paddr->Low = (unsigned long)addr;
wdenkcc1c8a12002-11-02 22:58:18 +00001334#endif
1335}
1336
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001337void MM_SetT3Addr (T3_64BIT_HOST_ADDR * paddr, dma_addr_t addr)
wdenkcc1c8a12002-11-02 22:58:18 +00001338{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001339 unsigned long baddr = (unsigned long)addr;
wdenkcc1c8a12002-11-02 22:58:18 +00001340#if (BITS_PER_LONG == 64)
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001341 set_64bit_addr (paddr, baddr & 0xffffffff, baddr >> 32);
wdenkcc1c8a12002-11-02 22:58:18 +00001342#else
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001343 set_64bit_addr (paddr, baddr, 0);
wdenkcc1c8a12002-11-02 22:58:18 +00001344#endif
1345}
1346
1347/*
1348 * This combination of `inline' and `extern' has almost the effect of a
1349 * macro. The way to use it is to put a function definition in a header
1350 * file with these keywords, and put another copy of the definition
1351 * (lacking `inline' and `extern') in a library file. The definition in
1352 * the header file will cause most calls to the function to be inlined.
1353 * If any uses of the function remain, they will refer to the single copy
1354 * in the library.
1355 */
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001356void atomic_set (atomic_t * entry, int val)
wdenkcc1c8a12002-11-02 22:58:18 +00001357{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001358 entry->counter = val;
wdenkcc1c8a12002-11-02 22:58:18 +00001359}
1360
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001361int atomic_read (atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001362{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001363 return entry->counter;
wdenkcc1c8a12002-11-02 22:58:18 +00001364}
1365
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001366void atomic_inc (atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001367{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001368 if (entry)
1369 entry->counter++;
wdenkcc1c8a12002-11-02 22:58:18 +00001370}
1371
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001372void atomic_dec (atomic_t * entry)
wdenkcc1c8a12002-11-02 22:58:18 +00001373{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001374 if (entry)
1375 entry->counter--;
1376}
1377
1378void atomic_sub (int a, atomic_t * entry)
1379{
1380 if (entry)
1381 entry->counter -= a;
1382}
1383
1384void atomic_add (int a, atomic_t * entry)
1385{
1386 if (entry)
1387 entry->counter += a;
wdenkcc1c8a12002-11-02 22:58:18 +00001388}
1389
1390/******************************************************************************/
1391/* Description: */
1392/* */
1393/* Return: */
1394/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001395void QQ_InitQueue (PQQ_CONTAINER pQueue, unsigned int QueueSize)
1396{
1397 pQueue->Head = 0;
1398 pQueue->Tail = 0;
1399 pQueue->Size = QueueSize + 1;
1400 atomic_set (&pQueue->EntryCnt, 0);
1401} /* QQ_InitQueue */
wdenkcc1c8a12002-11-02 22:58:18 +00001402
wdenkcc1c8a12002-11-02 22:58:18 +00001403/******************************************************************************/
1404/* Description: */
1405/* */
1406/* Return: */
1407/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001408char QQ_Full (PQQ_CONTAINER pQueue)
1409{
1410 unsigned int NewHead;
wdenkcc1c8a12002-11-02 22:58:18 +00001411
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001412 NewHead = (pQueue->Head + 1) % pQueue->Size;
wdenkcc1c8a12002-11-02 22:58:18 +00001413
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001414 return (NewHead == pQueue->Tail);
1415} /* QQ_Full */
wdenkcc1c8a12002-11-02 22:58:18 +00001416
wdenkcc1c8a12002-11-02 22:58:18 +00001417/******************************************************************************/
1418/* Description: */
1419/* */
1420/* Return: */
1421/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001422char QQ_Empty (PQQ_CONTAINER pQueue)
1423{
1424 return (pQueue->Head == pQueue->Tail);
1425} /* QQ_Empty */
wdenkcc1c8a12002-11-02 22:58:18 +00001426
wdenkcc1c8a12002-11-02 22:58:18 +00001427/******************************************************************************/
1428/* Description: */
1429/* */
1430/* Return: */
1431/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001432unsigned int QQ_GetSize (PQQ_CONTAINER pQueue)
1433{
1434 return pQueue->Size;
1435} /* QQ_GetSize */
wdenkcc1c8a12002-11-02 22:58:18 +00001436
wdenkcc1c8a12002-11-02 22:58:18 +00001437/******************************************************************************/
1438/* Description: */
1439/* */
1440/* Return: */
1441/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001442unsigned int QQ_GetEntryCnt (PQQ_CONTAINER pQueue)
1443{
1444 return atomic_read (&pQueue->EntryCnt);
1445} /* QQ_GetEntryCnt */
wdenkcc1c8a12002-11-02 22:58:18 +00001446
wdenkcc1c8a12002-11-02 22:58:18 +00001447/******************************************************************************/
1448/* Description: */
1449/* */
1450/* Return: */
1451/* TRUE entry was added successfully. */
1452/* FALSE queue is full. */
1453/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001454char QQ_PushHead (PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)
1455{
1456 unsigned int Head;
wdenkcc1c8a12002-11-02 22:58:18 +00001457
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001458 Head = (pQueue->Head + 1) % pQueue->Size;
wdenkcc1c8a12002-11-02 22:58:18 +00001459
1460#if !defined(QQ_NO_OVERFLOW_CHECK)
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001461 if (Head == pQueue->Tail) {
1462 return 0;
1463 } /* if */
1464#endif /* QQ_NO_OVERFLOW_CHECK */
wdenkcc1c8a12002-11-02 22:58:18 +00001465
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001466 pQueue->Array[pQueue->Head] = pEntry;
1467 wmb ();
1468 pQueue->Head = Head;
1469 atomic_inc (&pQueue->EntryCnt);
wdenkcc1c8a12002-11-02 22:58:18 +00001470
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001471 return -1;
1472} /* QQ_PushHead */
wdenkcc1c8a12002-11-02 22:58:18 +00001473
wdenkcc1c8a12002-11-02 22:58:18 +00001474/******************************************************************************/
1475/* Description: */
1476/* */
1477/* Return: */
1478/* TRUE entry was added successfully. */
1479/* FALSE queue is full. */
1480/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001481char QQ_PushTail (PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)
1482{
1483 unsigned int Tail;
wdenkcc1c8a12002-11-02 22:58:18 +00001484
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001485 Tail = pQueue->Tail;
1486 if (Tail == 0) {
1487 Tail = pQueue->Size;
1488 } /* if */
1489 Tail--;
wdenkcc1c8a12002-11-02 22:58:18 +00001490
1491#if !defined(QQ_NO_OVERFLOW_CHECK)
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001492 if (Tail == pQueue->Head) {
1493 return 0;
1494 } /* if */
1495#endif /* QQ_NO_OVERFLOW_CHECK */
wdenkcc1c8a12002-11-02 22:58:18 +00001496
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001497 pQueue->Array[Tail] = pEntry;
1498 wmb ();
1499 pQueue->Tail = Tail;
1500 atomic_inc (&pQueue->EntryCnt);
wdenkcc1c8a12002-11-02 22:58:18 +00001501
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001502 return -1;
1503} /* QQ_PushTail */
wdenkcc1c8a12002-11-02 22:58:18 +00001504
wdenkcc1c8a12002-11-02 22:58:18 +00001505/******************************************************************************/
1506/* Description: */
1507/* */
1508/* Return: */
1509/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001510PQQ_ENTRY QQ_PopHead (PQQ_CONTAINER pQueue)
1511{
1512 unsigned int Head;
1513 PQQ_ENTRY Entry;
wdenkcc1c8a12002-11-02 22:58:18 +00001514
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001515 Head = pQueue->Head;
wdenkcc1c8a12002-11-02 22:58:18 +00001516
1517#if !defined(QQ_NO_UNDERFLOW_CHECK)
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001518 if (Head == pQueue->Tail) {
1519 return (PQQ_ENTRY) 0;
1520 } /* if */
1521#endif /* QQ_NO_UNDERFLOW_CHECK */
wdenkcc1c8a12002-11-02 22:58:18 +00001522
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001523 if (Head == 0) {
1524 Head = pQueue->Size;
1525 } /* if */
1526 Head--;
wdenkcc1c8a12002-11-02 22:58:18 +00001527
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001528 Entry = pQueue->Array[Head];
1529 membar ();
wdenkcc1c8a12002-11-02 22:58:18 +00001530
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001531 pQueue->Head = Head;
1532 atomic_dec (&pQueue->EntryCnt);
wdenkcc1c8a12002-11-02 22:58:18 +00001533
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001534 return Entry;
1535} /* QQ_PopHead */
wdenkcc1c8a12002-11-02 22:58:18 +00001536
wdenkcc1c8a12002-11-02 22:58:18 +00001537/******************************************************************************/
1538/* Description: */
1539/* */
1540/* Return: */
1541/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001542PQQ_ENTRY QQ_PopTail (PQQ_CONTAINER pQueue)
1543{
1544 unsigned int Tail;
1545 PQQ_ENTRY Entry;
wdenkcc1c8a12002-11-02 22:58:18 +00001546
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001547 Tail = pQueue->Tail;
wdenkcc1c8a12002-11-02 22:58:18 +00001548
1549#if !defined(QQ_NO_UNDERFLOW_CHECK)
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001550 if (Tail == pQueue->Head) {
1551 return (PQQ_ENTRY) 0;
1552 } /* if */
1553#endif /* QQ_NO_UNDERFLOW_CHECK */
wdenkcc1c8a12002-11-02 22:58:18 +00001554
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001555 Entry = pQueue->Array[Tail];
1556 membar ();
1557 pQueue->Tail = (Tail + 1) % pQueue->Size;
1558 atomic_dec (&pQueue->EntryCnt);
wdenkcc1c8a12002-11-02 22:58:18 +00001559
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001560 return Entry;
1561} /* QQ_PopTail */
wdenkcc1c8a12002-11-02 22:58:18 +00001562
wdenkcc1c8a12002-11-02 22:58:18 +00001563/******************************************************************************/
1564/* Description: */
1565/* */
1566/* Return: */
1567/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001568PQQ_ENTRY QQ_GetHead (PQQ_CONTAINER pQueue, unsigned int Idx)
wdenkcc1c8a12002-11-02 22:58:18 +00001569{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001570 if (Idx >= atomic_read (&pQueue->EntryCnt)) {
1571 return (PQQ_ENTRY) 0;
1572 }
wdenkcc1c8a12002-11-02 22:58:18 +00001573
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001574 if (pQueue->Head > Idx) {
1575 Idx = pQueue->Head - Idx;
1576 } else {
1577 Idx = pQueue->Size - (Idx - pQueue->Head);
1578 }
1579 Idx--;
wdenkcc1c8a12002-11-02 22:58:18 +00001580
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001581 return pQueue->Array[Idx];
wdenkcc1c8a12002-11-02 22:58:18 +00001582}
1583
wdenkcc1c8a12002-11-02 22:58:18 +00001584/******************************************************************************/
1585/* Description: */
1586/* */
1587/* Return: */
1588/******************************************************************************/
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001589PQQ_ENTRY QQ_GetTail (PQQ_CONTAINER pQueue, unsigned int Idx)
wdenkcc1c8a12002-11-02 22:58:18 +00001590{
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001591 if (Idx >= atomic_read (&pQueue->EntryCnt)) {
1592 return (PQQ_ENTRY) 0;
1593 }
wdenkcc1c8a12002-11-02 22:58:18 +00001594
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001595 Idx += pQueue->Tail;
1596 if (Idx >= pQueue->Size) {
1597 Idx = Idx - pQueue->Size;
1598 }
wdenkcc1c8a12002-11-02 22:58:18 +00001599
Vadim Bendeburyf539edc2007-05-24 15:52:25 -07001600 return pQueue->Array[Idx];
wdenkcc1c8a12002-11-02 22:58:18 +00001601}
1602
Jon Loeligerddb5d862007-07-10 11:13:21 -05001603#endif