diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/sunbmac.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/net/sunbmac.c')
-rw-r--r-- | drivers/net/sunbmac.c | 1324 |
1 files changed, 1324 insertions, 0 deletions
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c new file mode 100644 index 000000000000..025dcd867eaa --- /dev/null +++ b/drivers/net/sunbmac.c | |||
@@ -0,0 +1,1324 @@ | |||
1 | /* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $ | ||
2 | * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. | ||
3 | * | ||
4 | * Copyright (C) 1997, 1998, 1999, 2003 David S. Miller (davem@redhat.com) | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/fcntl.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/ioport.h> | ||
14 | #include <linux/in.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/crc32.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/ethtool.h> | ||
22 | #include <linux/netdevice.h> | ||
23 | #include <linux/etherdevice.h> | ||
24 | #include <linux/skbuff.h> | ||
25 | #include <linux/bitops.h> | ||
26 | |||
27 | #include <asm/auxio.h> | ||
28 | #include <asm/byteorder.h> | ||
29 | #include <asm/dma.h> | ||
30 | #include <asm/idprom.h> | ||
31 | #include <asm/io.h> | ||
32 | #include <asm/openprom.h> | ||
33 | #include <asm/oplib.h> | ||
34 | #include <asm/pgtable.h> | ||
35 | #include <asm/sbus.h> | ||
36 | #include <asm/system.h> | ||
37 | |||
38 | #include "sunbmac.h" | ||
39 | |||
40 | static char version[] __initdata = | ||
41 | "sunbmac.c:v2.0 24/Nov/03 David S. Miller (davem@redhat.com)\n"; | ||
42 | |||
43 | #undef DEBUG_PROBE | ||
44 | #undef DEBUG_TX | ||
45 | #undef DEBUG_IRQ | ||
46 | |||
47 | #ifdef DEBUG_PROBE | ||
48 | #define DP(x) printk x | ||
49 | #else | ||
50 | #define DP(x) | ||
51 | #endif | ||
52 | |||
53 | #ifdef DEBUG_TX | ||
54 | #define DTX(x) printk x | ||
55 | #else | ||
56 | #define DTX(x) | ||
57 | #endif | ||
58 | |||
59 | #ifdef DEBUG_IRQ | ||
60 | #define DIRQ(x) printk x | ||
61 | #else | ||
62 | #define DIRQ(x) | ||
63 | #endif | ||
64 | |||
65 | static struct bigmac *root_bigmac_dev; | ||
66 | |||
67 | #define DEFAULT_JAMSIZE 4 /* Toe jam */ | ||
68 | |||
69 | #define QEC_RESET_TRIES 200 | ||
70 | |||
71 | static int qec_global_reset(void __iomem *gregs) | ||
72 | { | ||
73 | int tries = QEC_RESET_TRIES; | ||
74 | |||
75 | sbus_writel(GLOB_CTRL_RESET, gregs + GLOB_CTRL); | ||
76 | while (--tries) { | ||
77 | if (sbus_readl(gregs + GLOB_CTRL) & GLOB_CTRL_RESET) { | ||
78 | udelay(20); | ||
79 | continue; | ||
80 | } | ||
81 | break; | ||
82 | } | ||
83 | if (tries) | ||
84 | return 0; | ||
85 | printk(KERN_ERR "BigMAC: Cannot reset the QEC.\n"); | ||
86 | return -1; | ||
87 | } | ||
88 | |||
89 | static void qec_init(struct bigmac *bp) | ||
90 | { | ||
91 | void __iomem *gregs = bp->gregs; | ||
92 | struct sbus_dev *qec_sdev = bp->qec_sdev; | ||
93 | u8 bsizes = bp->bigmac_bursts; | ||
94 | u32 regval; | ||
95 | |||
96 | /* 64byte bursts do not work at the moment, do | ||
97 | * not even try to enable them. -DaveM | ||
98 | */ | ||
99 | if (bsizes & DMA_BURST32) | ||
100 | regval = GLOB_CTRL_B32; | ||
101 | else | ||
102 | regval = GLOB_CTRL_B16; | ||
103 | sbus_writel(regval | GLOB_CTRL_BMODE, gregs + GLOB_CTRL); | ||
104 | sbus_writel(GLOB_PSIZE_2048, gregs + GLOB_PSIZE); | ||
105 | |||
106 | /* All of memsize is given to bigmac. */ | ||
107 | sbus_writel(qec_sdev->reg_addrs[1].reg_size, | ||
108 | gregs + GLOB_MSIZE); | ||
109 | |||
110 | /* Half to the transmitter, half to the receiver. */ | ||
111 | sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1, | ||
112 | gregs + GLOB_TSIZE); | ||
113 | sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1, | ||
114 | gregs + GLOB_RSIZE); | ||
115 | } | ||
116 | |||
117 | #define TX_RESET_TRIES 32 | ||
118 | #define RX_RESET_TRIES 32 | ||
119 | |||
120 | static void bigmac_tx_reset(void __iomem *bregs) | ||
121 | { | ||
122 | int tries = TX_RESET_TRIES; | ||
123 | |||
124 | sbus_writel(0, bregs + BMAC_TXCFG); | ||
125 | |||
126 | /* The fifo threshold bit is read-only and does | ||
127 | * not clear. -DaveM | ||
128 | */ | ||
129 | while ((sbus_readl(bregs + BMAC_TXCFG) & ~(BIGMAC_TXCFG_FIFO)) != 0 && | ||
130 | --tries != 0) | ||
131 | udelay(20); | ||
132 | |||
133 | if (!tries) { | ||
134 | printk(KERN_ERR "BIGMAC: Transmitter will not reset.\n"); | ||
135 | printk(KERN_ERR "BIGMAC: tx_cfg is %08x\n", | ||
136 | sbus_readl(bregs + BMAC_TXCFG)); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | static void bigmac_rx_reset(void __iomem *bregs) | ||
141 | { | ||
142 | int tries = RX_RESET_TRIES; | ||
143 | |||
144 | sbus_writel(0, bregs + BMAC_RXCFG); | ||
145 | while (sbus_readl(bregs + BMAC_RXCFG) && --tries) | ||
146 | udelay(20); | ||
147 | |||
148 | if (!tries) { | ||
149 | printk(KERN_ERR "BIGMAC: Receiver will not reset.\n"); | ||
150 | printk(KERN_ERR "BIGMAC: rx_cfg is %08x\n", | ||
151 | sbus_readl(bregs + BMAC_RXCFG)); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | /* Reset the transmitter and receiver. */ | ||
156 | static void bigmac_stop(struct bigmac *bp) | ||
157 | { | ||
158 | bigmac_tx_reset(bp->bregs); | ||
159 | bigmac_rx_reset(bp->bregs); | ||
160 | } | ||
161 | |||
162 | static void bigmac_get_counters(struct bigmac *bp, void __iomem *bregs) | ||
163 | { | ||
164 | struct net_device_stats *stats = &bp->enet_stats; | ||
165 | |||
166 | stats->rx_crc_errors += sbus_readl(bregs + BMAC_RCRCECTR); | ||
167 | sbus_writel(0, bregs + BMAC_RCRCECTR); | ||
168 | |||
169 | stats->rx_frame_errors += sbus_readl(bregs + BMAC_UNALECTR); | ||
170 | sbus_writel(0, bregs + BMAC_UNALECTR); | ||
171 | |||
172 | stats->rx_length_errors += sbus_readl(bregs + BMAC_GLECTR); | ||
173 | sbus_writel(0, bregs + BMAC_GLECTR); | ||
174 | |||
175 | stats->tx_aborted_errors += sbus_readl(bregs + BMAC_EXCTR); | ||
176 | |||
177 | stats->collisions += | ||
178 | (sbus_readl(bregs + BMAC_EXCTR) + | ||
179 | sbus_readl(bregs + BMAC_LTCTR)); | ||
180 | sbus_writel(0, bregs + BMAC_EXCTR); | ||
181 | sbus_writel(0, bregs + BMAC_LTCTR); | ||
182 | } | ||
183 | |||
184 | static void bigmac_clean_rings(struct bigmac *bp) | ||
185 | { | ||
186 | int i; | ||
187 | |||
188 | for (i = 0; i < RX_RING_SIZE; i++) { | ||
189 | if (bp->rx_skbs[i] != NULL) { | ||
190 | dev_kfree_skb_any(bp->rx_skbs[i]); | ||
191 | bp->rx_skbs[i] = NULL; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | for (i = 0; i < TX_RING_SIZE; i++) { | ||
196 | if (bp->tx_skbs[i] != NULL) { | ||
197 | dev_kfree_skb_any(bp->tx_skbs[i]); | ||
198 | bp->tx_skbs[i] = NULL; | ||
199 | } | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static void bigmac_init_rings(struct bigmac *bp, int from_irq) | ||
204 | { | ||
205 | struct bmac_init_block *bb = bp->bmac_block; | ||
206 | struct net_device *dev = bp->dev; | ||
207 | int i, gfp_flags = GFP_KERNEL; | ||
208 | |||
209 | if (from_irq || in_interrupt()) | ||
210 | gfp_flags = GFP_ATOMIC; | ||
211 | |||
212 | bp->rx_new = bp->rx_old = bp->tx_new = bp->tx_old = 0; | ||
213 | |||
214 | /* Free any skippy bufs left around in the rings. */ | ||
215 | bigmac_clean_rings(bp); | ||
216 | |||
217 | /* Now get new skbufs for the receive ring. */ | ||
218 | for (i = 0; i < RX_RING_SIZE; i++) { | ||
219 | struct sk_buff *skb; | ||
220 | |||
221 | skb = big_mac_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags); | ||
222 | if (!skb) | ||
223 | continue; | ||
224 | |||
225 | bp->rx_skbs[i] = skb; | ||
226 | skb->dev = dev; | ||
227 | |||
228 | /* Because we reserve afterwards. */ | ||
229 | skb_put(skb, ETH_FRAME_LEN); | ||
230 | skb_reserve(skb, 34); | ||
231 | |||
232 | bb->be_rxd[i].rx_addr = | ||
233 | sbus_map_single(bp->bigmac_sdev, skb->data, | ||
234 | RX_BUF_ALLOC_SIZE - 34, | ||
235 | SBUS_DMA_FROMDEVICE); | ||
236 | bb->be_rxd[i].rx_flags = | ||
237 | (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); | ||
238 | } | ||
239 | |||
240 | for (i = 0; i < TX_RING_SIZE; i++) | ||
241 | bb->be_txd[i].tx_flags = bb->be_txd[i].tx_addr = 0; | ||
242 | } | ||
243 | |||
244 | #define MGMT_CLKON (MGMT_PAL_INT_MDIO|MGMT_PAL_EXT_MDIO|MGMT_PAL_OENAB|MGMT_PAL_DCLOCK) | ||
245 | #define MGMT_CLKOFF (MGMT_PAL_INT_MDIO|MGMT_PAL_EXT_MDIO|MGMT_PAL_OENAB) | ||
246 | |||
247 | static void idle_transceiver(void __iomem *tregs) | ||
248 | { | ||
249 | int i = 20; | ||
250 | |||
251 | while (i--) { | ||
252 | sbus_writel(MGMT_CLKOFF, tregs + TCVR_MPAL); | ||
253 | sbus_readl(tregs + TCVR_MPAL); | ||
254 | sbus_writel(MGMT_CLKON, tregs + TCVR_MPAL); | ||
255 | sbus_readl(tregs + TCVR_MPAL); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | static void write_tcvr_bit(struct bigmac *bp, void __iomem *tregs, int bit) | ||
260 | { | ||
261 | if (bp->tcvr_type == internal) { | ||
262 | bit = (bit & 1) << 3; | ||
263 | sbus_writel(bit | (MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO), | ||
264 | tregs + TCVR_MPAL); | ||
265 | sbus_readl(tregs + TCVR_MPAL); | ||
266 | sbus_writel(bit | MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK, | ||
267 | tregs + TCVR_MPAL); | ||
268 | sbus_readl(tregs + TCVR_MPAL); | ||
269 | } else if (bp->tcvr_type == external) { | ||
270 | bit = (bit & 1) << 2; | ||
271 | sbus_writel(bit | MGMT_PAL_INT_MDIO | MGMT_PAL_OENAB, | ||
272 | tregs + TCVR_MPAL); | ||
273 | sbus_readl(tregs + TCVR_MPAL); | ||
274 | sbus_writel(bit | MGMT_PAL_INT_MDIO | MGMT_PAL_OENAB | MGMT_PAL_DCLOCK, | ||
275 | tregs + TCVR_MPAL); | ||
276 | sbus_readl(tregs + TCVR_MPAL); | ||
277 | } else { | ||
278 | printk(KERN_ERR "write_tcvr_bit: No transceiver type known!\n"); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | static int read_tcvr_bit(struct bigmac *bp, void __iomem *tregs) | ||
283 | { | ||
284 | int retval = 0; | ||
285 | |||
286 | if (bp->tcvr_type == internal) { | ||
287 | sbus_writel(MGMT_PAL_EXT_MDIO, tregs + TCVR_MPAL); | ||
288 | sbus_readl(tregs + TCVR_MPAL); | ||
289 | sbus_writel(MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK, | ||
290 | tregs + TCVR_MPAL); | ||
291 | sbus_readl(tregs + TCVR_MPAL); | ||
292 | retval = (sbus_readl(tregs + TCVR_MPAL) & MGMT_PAL_INT_MDIO) >> 3; | ||
293 | } else if (bp->tcvr_type == external) { | ||
294 | sbus_writel(MGMT_PAL_INT_MDIO, tregs + TCVR_MPAL); | ||
295 | sbus_readl(tregs + TCVR_MPAL); | ||
296 | sbus_writel(MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK, tregs + TCVR_MPAL); | ||
297 | sbus_readl(tregs + TCVR_MPAL); | ||
298 | retval = (sbus_readl(tregs + TCVR_MPAL) & MGMT_PAL_EXT_MDIO) >> 2; | ||
299 | } else { | ||
300 | printk(KERN_ERR "read_tcvr_bit: No transceiver type known!\n"); | ||
301 | } | ||
302 | return retval; | ||
303 | } | ||
304 | |||
305 | static int read_tcvr_bit2(struct bigmac *bp, void __iomem *tregs) | ||
306 | { | ||
307 | int retval = 0; | ||
308 | |||
309 | if (bp->tcvr_type == internal) { | ||
310 | sbus_writel(MGMT_PAL_EXT_MDIO, tregs + TCVR_MPAL); | ||
311 | sbus_readl(tregs + TCVR_MPAL); | ||
312 | retval = (sbus_readl(tregs + TCVR_MPAL) & MGMT_PAL_INT_MDIO) >> 3; | ||
313 | sbus_writel(MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK, tregs + TCVR_MPAL); | ||
314 | sbus_readl(tregs + TCVR_MPAL); | ||
315 | } else if (bp->tcvr_type == external) { | ||
316 | sbus_writel(MGMT_PAL_INT_MDIO, tregs + TCVR_MPAL); | ||
317 | sbus_readl(tregs + TCVR_MPAL); | ||
318 | retval = (sbus_readl(tregs + TCVR_MPAL) & MGMT_PAL_EXT_MDIO) >> 2; | ||
319 | sbus_writel(MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK, tregs + TCVR_MPAL); | ||
320 | sbus_readl(tregs + TCVR_MPAL); | ||
321 | } else { | ||
322 | printk(KERN_ERR "read_tcvr_bit2: No transceiver type known!\n"); | ||
323 | } | ||
324 | return retval; | ||
325 | } | ||
326 | |||
327 | static void put_tcvr_byte(struct bigmac *bp, | ||
328 | void __iomem *tregs, | ||
329 | unsigned int byte) | ||
330 | { | ||
331 | int shift = 4; | ||
332 | |||
333 | do { | ||
334 | write_tcvr_bit(bp, tregs, ((byte >> shift) & 1)); | ||
335 | shift -= 1; | ||
336 | } while (shift >= 0); | ||
337 | } | ||
338 | |||
339 | static void bigmac_tcvr_write(struct bigmac *bp, void __iomem *tregs, | ||
340 | int reg, unsigned short val) | ||
341 | { | ||
342 | int shift; | ||
343 | |||
344 | reg &= 0xff; | ||
345 | val &= 0xffff; | ||
346 | switch(bp->tcvr_type) { | ||
347 | case internal: | ||
348 | case external: | ||
349 | break; | ||
350 | |||
351 | default: | ||
352 | printk(KERN_ERR "bigmac_tcvr_read: Whoops, no known transceiver type.\n"); | ||
353 | return; | ||
354 | }; | ||
355 | |||
356 | idle_transceiver(tregs); | ||
357 | write_tcvr_bit(bp, tregs, 0); | ||
358 | write_tcvr_bit(bp, tregs, 1); | ||
359 | write_tcvr_bit(bp, tregs, 0); | ||
360 | write_tcvr_bit(bp, tregs, 1); | ||
361 | |||
362 | put_tcvr_byte(bp, tregs, | ||
363 | ((bp->tcvr_type == internal) ? | ||
364 | BIGMAC_PHY_INTERNAL : BIGMAC_PHY_EXTERNAL)); | ||
365 | |||
366 | put_tcvr_byte(bp, tregs, reg); | ||
367 | |||
368 | write_tcvr_bit(bp, tregs, 1); | ||
369 | write_tcvr_bit(bp, tregs, 0); | ||
370 | |||
371 | shift = 15; | ||
372 | do { | ||
373 | write_tcvr_bit(bp, tregs, (val >> shift) & 1); | ||
374 | shift -= 1; | ||
375 | } while (shift >= 0); | ||
376 | } | ||
377 | |||
378 | static unsigned short bigmac_tcvr_read(struct bigmac *bp, | ||
379 | void __iomem *tregs, | ||
380 | int reg) | ||
381 | { | ||
382 | unsigned short retval = 0; | ||
383 | |||
384 | reg &= 0xff; | ||
385 | switch(bp->tcvr_type) { | ||
386 | case internal: | ||
387 | case external: | ||
388 | break; | ||
389 | |||
390 | default: | ||
391 | printk(KERN_ERR "bigmac_tcvr_read: Whoops, no known transceiver type.\n"); | ||
392 | return 0xffff; | ||
393 | }; | ||
394 | |||
395 | idle_transceiver(tregs); | ||
396 | write_tcvr_bit(bp, tregs, 0); | ||
397 | write_tcvr_bit(bp, tregs, 1); | ||
398 | write_tcvr_bit(bp, tregs, 1); | ||
399 | write_tcvr_bit(bp, tregs, 0); | ||
400 | |||
401 | put_tcvr_byte(bp, tregs, | ||
402 | ((bp->tcvr_type == internal) ? | ||
403 | BIGMAC_PHY_INTERNAL : BIGMAC_PHY_EXTERNAL)); | ||
404 | |||
405 | put_tcvr_byte(bp, tregs, reg); | ||
406 | |||
407 | if (bp->tcvr_type == external) { | ||
408 | int shift = 15; | ||
409 | |||
410 | (void) read_tcvr_bit2(bp, tregs); | ||
411 | (void) read_tcvr_bit2(bp, tregs); | ||
412 | |||
413 | do { | ||
414 | int tmp; | ||
415 | |||
416 | tmp = read_tcvr_bit2(bp, tregs); | ||
417 | retval |= ((tmp & 1) << shift); | ||
418 | shift -= 1; | ||
419 | } while (shift >= 0); | ||
420 | |||
421 | (void) read_tcvr_bit2(bp, tregs); | ||
422 | (void) read_tcvr_bit2(bp, tregs); | ||
423 | (void) read_tcvr_bit2(bp, tregs); | ||
424 | } else { | ||
425 | int shift = 15; | ||
426 | |||
427 | (void) read_tcvr_bit(bp, tregs); | ||
428 | (void) read_tcvr_bit(bp, tregs); | ||
429 | |||
430 | do { | ||
431 | int tmp; | ||
432 | |||
433 | tmp = read_tcvr_bit(bp, tregs); | ||
434 | retval |= ((tmp & 1) << shift); | ||
435 | shift -= 1; | ||
436 | } while (shift >= 0); | ||
437 | |||
438 | (void) read_tcvr_bit(bp, tregs); | ||
439 | (void) read_tcvr_bit(bp, tregs); | ||
440 | (void) read_tcvr_bit(bp, tregs); | ||
441 | } | ||
442 | return retval; | ||
443 | } | ||
444 | |||
445 | static void bigmac_tcvr_init(struct bigmac *bp) | ||
446 | { | ||
447 | void __iomem *tregs = bp->tregs; | ||
448 | u32 mpal; | ||
449 | |||
450 | idle_transceiver(tregs); | ||
451 | sbus_writel(MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK, | ||
452 | tregs + TCVR_MPAL); | ||
453 | sbus_readl(tregs + TCVR_MPAL); | ||
454 | |||
455 | /* Only the bit for the present transceiver (internal or | ||
456 | * external) will stick, set them both and see what stays. | ||
457 | */ | ||
458 | sbus_writel(MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO, tregs + TCVR_MPAL); | ||
459 | sbus_readl(tregs + TCVR_MPAL); | ||
460 | udelay(20); | ||
461 | |||
462 | mpal = sbus_readl(tregs + TCVR_MPAL); | ||
463 | if (mpal & MGMT_PAL_EXT_MDIO) { | ||
464 | bp->tcvr_type = external; | ||
465 | sbus_writel(~(TCVR_PAL_EXTLBACK | TCVR_PAL_MSENSE | TCVR_PAL_LTENABLE), | ||
466 | tregs + TCVR_TPAL); | ||
467 | sbus_readl(tregs + TCVR_TPAL); | ||
468 | } else if (mpal & MGMT_PAL_INT_MDIO) { | ||
469 | bp->tcvr_type = internal; | ||
470 | sbus_writel(~(TCVR_PAL_SERIAL | TCVR_PAL_EXTLBACK | | ||
471 | TCVR_PAL_MSENSE | TCVR_PAL_LTENABLE), | ||
472 | tregs + TCVR_TPAL); | ||
473 | sbus_readl(tregs + TCVR_TPAL); | ||
474 | } else { | ||
475 | printk(KERN_ERR "BIGMAC: AIEEE, neither internal nor " | ||
476 | "external MDIO available!\n"); | ||
477 | printk(KERN_ERR "BIGMAC: mgmt_pal[%08x] tcvr_pal[%08x]\n", | ||
478 | sbus_readl(tregs + TCVR_MPAL), | ||
479 | sbus_readl(tregs + TCVR_TPAL)); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | static int bigmac_init(struct bigmac *, int); | ||
484 | |||
485 | static int try_next_permutation(struct bigmac *bp, void __iomem *tregs) | ||
486 | { | ||
487 | if (bp->sw_bmcr & BMCR_SPEED100) { | ||
488 | int timeout; | ||
489 | |||
490 | /* Reset the PHY. */ | ||
491 | bp->sw_bmcr = (BMCR_ISOLATE | BMCR_PDOWN | BMCR_LOOPBACK); | ||
492 | bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); | ||
493 | bp->sw_bmcr = (BMCR_RESET); | ||
494 | bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); | ||
495 | |||
496 | timeout = 64; | ||
497 | while (--timeout) { | ||
498 | bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); | ||
499 | if ((bp->sw_bmcr & BMCR_RESET) == 0) | ||
500 | break; | ||
501 | udelay(20); | ||
502 | } | ||
503 | if (timeout == 0) | ||
504 | printk(KERN_ERR "%s: PHY reset failed.\n", bp->dev->name); | ||
505 | |||
506 | bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); | ||
507 | |||
508 | /* Now we try 10baseT. */ | ||
509 | bp->sw_bmcr &= ~(BMCR_SPEED100); | ||
510 | bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | /* We've tried them all. */ | ||
515 | return -1; | ||
516 | } | ||
517 | |||
518 | static void bigmac_timer(unsigned long data) | ||
519 | { | ||
520 | struct bigmac *bp = (struct bigmac *) data; | ||
521 | void __iomem *tregs = bp->tregs; | ||
522 | int restart_timer = 0; | ||
523 | |||
524 | bp->timer_ticks++; | ||
525 | if (bp->timer_state == ltrywait) { | ||
526 | bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMSR); | ||
527 | bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); | ||
528 | if (bp->sw_bmsr & BMSR_LSTATUS) { | ||
529 | printk(KERN_INFO "%s: Link is now up at %s.\n", | ||
530 | bp->dev->name, | ||
531 | (bp->sw_bmcr & BMCR_SPEED100) ? | ||
532 | "100baseT" : "10baseT"); | ||
533 | bp->timer_state = asleep; | ||
534 | restart_timer = 0; | ||
535 | } else { | ||
536 | if (bp->timer_ticks >= 4) { | ||
537 | int ret; | ||
538 | |||
539 | ret = try_next_permutation(bp, tregs); | ||
540 | if (ret == -1) { | ||
541 | printk(KERN_ERR "%s: Link down, cable problem?\n", | ||
542 | bp->dev->name); | ||
543 | ret = bigmac_init(bp, 0); | ||
544 | if (ret) { | ||
545 | printk(KERN_ERR "%s: Error, cannot re-init the " | ||
546 | "BigMAC.\n", bp->dev->name); | ||
547 | } | ||
548 | return; | ||
549 | } | ||
550 | bp->timer_ticks = 0; | ||
551 | restart_timer = 1; | ||
552 | } else { | ||
553 | restart_timer = 1; | ||
554 | } | ||
555 | } | ||
556 | } else { | ||
557 | /* Can't happens.... */ | ||
558 | printk(KERN_ERR "%s: Aieee, link timer is asleep but we got one anyways!\n", | ||
559 | bp->dev->name); | ||
560 | restart_timer = 0; | ||
561 | bp->timer_ticks = 0; | ||
562 | bp->timer_state = asleep; /* foo on you */ | ||
563 | } | ||
564 | |||
565 | if (restart_timer != 0) { | ||
566 | bp->bigmac_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */ | ||
567 | add_timer(&bp->bigmac_timer); | ||
568 | } | ||
569 | } | ||
570 | |||
571 | /* Well, really we just force the chip into 100baseT then | ||
572 | * 10baseT, each time checking for a link status. | ||
573 | */ | ||
574 | static void bigmac_begin_auto_negotiation(struct bigmac *bp) | ||
575 | { | ||
576 | void __iomem *tregs = bp->tregs; | ||
577 | int timeout; | ||
578 | |||
579 | /* Grab new software copies of PHY registers. */ | ||
580 | bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMSR); | ||
581 | bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); | ||
582 | |||
583 | /* Reset the PHY. */ | ||
584 | bp->sw_bmcr = (BMCR_ISOLATE | BMCR_PDOWN | BMCR_LOOPBACK); | ||
585 | bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); | ||
586 | bp->sw_bmcr = (BMCR_RESET); | ||
587 | bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); | ||
588 | |||
589 | timeout = 64; | ||
590 | while (--timeout) { | ||
591 | bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); | ||
592 | if ((bp->sw_bmcr & BMCR_RESET) == 0) | ||
593 | break; | ||
594 | udelay(20); | ||
595 | } | ||
596 | if (timeout == 0) | ||
597 | printk(KERN_ERR "%s: PHY reset failed.\n", bp->dev->name); | ||
598 | |||
599 | bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR); | ||
600 | |||
601 | /* First we try 100baseT. */ | ||
602 | bp->sw_bmcr |= BMCR_SPEED100; | ||
603 | bigmac_tcvr_write(bp, tregs, BIGMAC_BMCR, bp->sw_bmcr); | ||
604 | |||
605 | bp->timer_state = ltrywait; | ||
606 | bp->timer_ticks = 0; | ||
607 | bp->bigmac_timer.expires = jiffies + (12 * HZ) / 10; | ||
608 | bp->bigmac_timer.data = (unsigned long) bp; | ||
609 | bp->bigmac_timer.function = &bigmac_timer; | ||
610 | add_timer(&bp->bigmac_timer); | ||
611 | } | ||
612 | |||
613 | static int bigmac_init(struct bigmac *bp, int from_irq) | ||
614 | { | ||
615 | void __iomem *gregs = bp->gregs; | ||
616 | void __iomem *cregs = bp->creg; | ||
617 | void __iomem *bregs = bp->bregs; | ||
618 | unsigned char *e = &bp->dev->dev_addr[0]; | ||
619 | |||
620 | /* Latch current counters into statistics. */ | ||
621 | bigmac_get_counters(bp, bregs); | ||
622 | |||
623 | /* Reset QEC. */ | ||
624 | qec_global_reset(gregs); | ||
625 | |||
626 | /* Init QEC. */ | ||
627 | qec_init(bp); | ||
628 | |||
629 | /* Alloc and reset the tx/rx descriptor chains. */ | ||
630 | bigmac_init_rings(bp, from_irq); | ||
631 | |||
632 | /* Initialize the PHY. */ | ||
633 | bigmac_tcvr_init(bp); | ||
634 | |||
635 | /* Stop transmitter and receiver. */ | ||
636 | bigmac_stop(bp); | ||
637 | |||
638 | /* Set hardware ethernet address. */ | ||
639 | sbus_writel(((e[4] << 8) | e[5]), bregs + BMAC_MACADDR2); | ||
640 | sbus_writel(((e[2] << 8) | e[3]), bregs + BMAC_MACADDR1); | ||
641 | sbus_writel(((e[0] << 8) | e[1]), bregs + BMAC_MACADDR0); | ||
642 | |||
643 | /* Clear the hash table until mc upload occurs. */ | ||
644 | sbus_writel(0, bregs + BMAC_HTABLE3); | ||
645 | sbus_writel(0, bregs + BMAC_HTABLE2); | ||
646 | sbus_writel(0, bregs + BMAC_HTABLE1); | ||
647 | sbus_writel(0, bregs + BMAC_HTABLE0); | ||
648 | |||
649 | /* Enable Big Mac hash table filter. */ | ||
650 | sbus_writel(BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_FIFO, | ||
651 | bregs + BMAC_RXCFG); | ||
652 | udelay(20); | ||
653 | |||
654 | /* Ok, configure the Big Mac transmitter. */ | ||
655 | sbus_writel(BIGMAC_TXCFG_FIFO, bregs + BMAC_TXCFG); | ||
656 | |||
657 | /* The HME docs recommend to use the 10LSB of our MAC here. */ | ||
658 | sbus_writel(((e[5] | e[4] << 8) & 0x3ff), | ||
659 | bregs + BMAC_RSEED); | ||
660 | |||
661 | /* Enable the output drivers no matter what. */ | ||
662 | sbus_writel(BIGMAC_XCFG_ODENABLE | BIGMAC_XCFG_RESV, | ||
663 | bregs + BMAC_XIFCFG); | ||
664 | |||
665 | /* Tell the QEC where the ring descriptors are. */ | ||
666 | sbus_writel(bp->bblock_dvma + bib_offset(be_rxd, 0), | ||
667 | cregs + CREG_RXDS); | ||
668 | sbus_writel(bp->bblock_dvma + bib_offset(be_txd, 0), | ||
669 | cregs + CREG_TXDS); | ||
670 | |||
671 | /* Setup the FIFO pointers into QEC local memory. */ | ||
672 | sbus_writel(0, cregs + CREG_RXRBUFPTR); | ||
673 | sbus_writel(0, cregs + CREG_RXWBUFPTR); | ||
674 | sbus_writel(sbus_readl(gregs + GLOB_RSIZE), | ||
675 | cregs + CREG_TXRBUFPTR); | ||
676 | sbus_writel(sbus_readl(gregs + GLOB_RSIZE), | ||
677 | cregs + CREG_TXWBUFPTR); | ||
678 | |||
679 | /* Tell bigmac what interrupts we don't want to hear about. */ | ||
680 | sbus_writel(BIGMAC_IMASK_GOTFRAME | BIGMAC_IMASK_SENTFRAME, | ||
681 | bregs + BMAC_IMASK); | ||
682 | |||
683 | /* Enable the various other irq's. */ | ||
684 | sbus_writel(0, cregs + CREG_RIMASK); | ||
685 | sbus_writel(0, cregs + CREG_TIMASK); | ||
686 | sbus_writel(0, cregs + CREG_QMASK); | ||
687 | sbus_writel(0, cregs + CREG_BMASK); | ||
688 | |||
689 | /* Set jam size to a reasonable default. */ | ||
690 | sbus_writel(DEFAULT_JAMSIZE, bregs + BMAC_JSIZE); | ||
691 | |||
692 | /* Clear collision counter. */ | ||
693 | sbus_writel(0, cregs + CREG_CCNT); | ||
694 | |||
695 | /* Enable transmitter and receiver. */ | ||
696 | sbus_writel(sbus_readl(bregs + BMAC_TXCFG) | BIGMAC_TXCFG_ENABLE, | ||
697 | bregs + BMAC_TXCFG); | ||
698 | sbus_writel(sbus_readl(bregs + BMAC_RXCFG) | BIGMAC_RXCFG_ENABLE, | ||
699 | bregs + BMAC_RXCFG); | ||
700 | |||
701 | /* Ok, start detecting link speed/duplex. */ | ||
702 | bigmac_begin_auto_negotiation(bp); | ||
703 | |||
704 | /* Success. */ | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | /* Error interrupts get sent here. */ | ||
709 | static void bigmac_is_medium_rare(struct bigmac *bp, u32 qec_status, u32 bmac_status) | ||
710 | { | ||
711 | printk(KERN_ERR "bigmac_is_medium_rare: "); | ||
712 | if (qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) { | ||
713 | if (qec_status & GLOB_STAT_ER) | ||
714 | printk("QEC_ERROR, "); | ||
715 | if (qec_status & GLOB_STAT_BM) | ||
716 | printk("QEC_BMAC_ERROR, "); | ||
717 | } | ||
718 | if (bmac_status & CREG_STAT_ERRORS) { | ||
719 | if (bmac_status & CREG_STAT_BERROR) | ||
720 | printk("BMAC_ERROR, "); | ||
721 | if (bmac_status & CREG_STAT_TXDERROR) | ||
722 | printk("TXD_ERROR, "); | ||
723 | if (bmac_status & CREG_STAT_TXLERR) | ||
724 | printk("TX_LATE_ERROR, "); | ||
725 | if (bmac_status & CREG_STAT_TXPERR) | ||
726 | printk("TX_PARITY_ERROR, "); | ||
727 | if (bmac_status & CREG_STAT_TXSERR) | ||
728 | printk("TX_SBUS_ERROR, "); | ||
729 | |||
730 | if (bmac_status & CREG_STAT_RXDROP) | ||
731 | printk("RX_DROP_ERROR, "); | ||
732 | |||
733 | if (bmac_status & CREG_STAT_RXSMALL) | ||
734 | printk("RX_SMALL_ERROR, "); | ||
735 | if (bmac_status & CREG_STAT_RXLERR) | ||
736 | printk("RX_LATE_ERROR, "); | ||
737 | if (bmac_status & CREG_STAT_RXPERR) | ||
738 | printk("RX_PARITY_ERROR, "); | ||
739 | if (bmac_status & CREG_STAT_RXSERR) | ||
740 | printk("RX_SBUS_ERROR, "); | ||
741 | } | ||
742 | |||
743 | printk(" RESET\n"); | ||
744 | bigmac_init(bp, 1); | ||
745 | } | ||
746 | |||
747 | /* BigMAC transmit complete service routines. */ | ||
748 | static void bigmac_tx(struct bigmac *bp) | ||
749 | { | ||
750 | struct be_txd *txbase = &bp->bmac_block->be_txd[0]; | ||
751 | struct net_device *dev = bp->dev; | ||
752 | int elem; | ||
753 | |||
754 | spin_lock(&bp->lock); | ||
755 | |||
756 | elem = bp->tx_old; | ||
757 | DTX(("bigmac_tx: tx_old[%d] ", elem)); | ||
758 | while (elem != bp->tx_new) { | ||
759 | struct sk_buff *skb; | ||
760 | struct be_txd *this = &txbase[elem]; | ||
761 | |||
762 | DTX(("this(%p) [flags(%08x)addr(%08x)]", | ||
763 | this, this->tx_flags, this->tx_addr)); | ||
764 | |||
765 | if (this->tx_flags & TXD_OWN) | ||
766 | break; | ||
767 | skb = bp->tx_skbs[elem]; | ||
768 | bp->enet_stats.tx_packets++; | ||
769 | bp->enet_stats.tx_bytes += skb->len; | ||
770 | sbus_unmap_single(bp->bigmac_sdev, | ||
771 | this->tx_addr, skb->len, | ||
772 | SBUS_DMA_TODEVICE); | ||
773 | |||
774 | DTX(("skb(%p) ", skb)); | ||
775 | bp->tx_skbs[elem] = NULL; | ||
776 | dev_kfree_skb_irq(skb); | ||
777 | |||
778 | elem = NEXT_TX(elem); | ||
779 | } | ||
780 | DTX((" DONE, tx_old=%d\n", elem)); | ||
781 | bp->tx_old = elem; | ||
782 | |||
783 | if (netif_queue_stopped(dev) && | ||
784 | TX_BUFFS_AVAIL(bp) > 0) | ||
785 | netif_wake_queue(bp->dev); | ||
786 | |||
787 | spin_unlock(&bp->lock); | ||
788 | } | ||
789 | |||
790 | /* BigMAC receive complete service routines. */ | ||
791 | static void bigmac_rx(struct bigmac *bp) | ||
792 | { | ||
793 | struct be_rxd *rxbase = &bp->bmac_block->be_rxd[0]; | ||
794 | struct be_rxd *this; | ||
795 | int elem = bp->rx_new, drops = 0; | ||
796 | u32 flags; | ||
797 | |||
798 | this = &rxbase[elem]; | ||
799 | while (!((flags = this->rx_flags) & RXD_OWN)) { | ||
800 | struct sk_buff *skb; | ||
801 | int len = (flags & RXD_LENGTH); /* FCS not included */ | ||
802 | |||
803 | /* Check for errors. */ | ||
804 | if (len < ETH_ZLEN) { | ||
805 | bp->enet_stats.rx_errors++; | ||
806 | bp->enet_stats.rx_length_errors++; | ||
807 | |||
808 | drop_it: | ||
809 | /* Return it to the BigMAC. */ | ||
810 | bp->enet_stats.rx_dropped++; | ||
811 | this->rx_flags = | ||
812 | (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); | ||
813 | goto next; | ||
814 | } | ||
815 | skb = bp->rx_skbs[elem]; | ||
816 | if (len > RX_COPY_THRESHOLD) { | ||
817 | struct sk_buff *new_skb; | ||
818 | |||
819 | /* Now refill the entry, if we can. */ | ||
820 | new_skb = big_mac_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); | ||
821 | if (new_skb == NULL) { | ||
822 | drops++; | ||
823 | goto drop_it; | ||
824 | } | ||
825 | sbus_unmap_single(bp->bigmac_sdev, | ||
826 | this->rx_addr, | ||
827 | RX_BUF_ALLOC_SIZE - 34, | ||
828 | SBUS_DMA_FROMDEVICE); | ||
829 | bp->rx_skbs[elem] = new_skb; | ||
830 | new_skb->dev = bp->dev; | ||
831 | skb_put(new_skb, ETH_FRAME_LEN); | ||
832 | skb_reserve(new_skb, 34); | ||
833 | this->rx_addr = sbus_map_single(bp->bigmac_sdev, | ||
834 | new_skb->data, | ||
835 | RX_BUF_ALLOC_SIZE - 34, | ||
836 | SBUS_DMA_FROMDEVICE); | ||
837 | this->rx_flags = | ||
838 | (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); | ||
839 | |||
840 | /* Trim the original skb for the netif. */ | ||
841 | skb_trim(skb, len); | ||
842 | } else { | ||
843 | struct sk_buff *copy_skb = dev_alloc_skb(len + 2); | ||
844 | |||
845 | if (copy_skb == NULL) { | ||
846 | drops++; | ||
847 | goto drop_it; | ||
848 | } | ||
849 | copy_skb->dev = bp->dev; | ||
850 | skb_reserve(copy_skb, 2); | ||
851 | skb_put(copy_skb, len); | ||
852 | sbus_dma_sync_single_for_cpu(bp->bigmac_sdev, | ||
853 | this->rx_addr, len, | ||
854 | SBUS_DMA_FROMDEVICE); | ||
855 | eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0); | ||
856 | sbus_dma_sync_single_for_device(bp->bigmac_sdev, | ||
857 | this->rx_addr, len, | ||
858 | SBUS_DMA_FROMDEVICE); | ||
859 | |||
860 | /* Reuse original ring buffer. */ | ||
861 | this->rx_flags = | ||
862 | (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); | ||
863 | |||
864 | skb = copy_skb; | ||
865 | } | ||
866 | |||
867 | /* No checksums done by the BigMAC ;-( */ | ||
868 | skb->protocol = eth_type_trans(skb, bp->dev); | ||
869 | netif_rx(skb); | ||
870 | bp->dev->last_rx = jiffies; | ||
871 | bp->enet_stats.rx_packets++; | ||
872 | bp->enet_stats.rx_bytes += len; | ||
873 | next: | ||
874 | elem = NEXT_RX(elem); | ||
875 | this = &rxbase[elem]; | ||
876 | } | ||
877 | bp->rx_new = elem; | ||
878 | if (drops) | ||
879 | printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", bp->dev->name); | ||
880 | } | ||
881 | |||
882 | static irqreturn_t bigmac_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
883 | { | ||
884 | struct bigmac *bp = (struct bigmac *) dev_id; | ||
885 | u32 qec_status, bmac_status; | ||
886 | |||
887 | DIRQ(("bigmac_interrupt: ")); | ||
888 | |||
889 | /* Latch status registers now. */ | ||
890 | bmac_status = sbus_readl(bp->creg + CREG_STAT); | ||
891 | qec_status = sbus_readl(bp->gregs + GLOB_STAT); | ||
892 | |||
893 | DIRQ(("qec_status=%08x bmac_status=%08x\n", qec_status, bmac_status)); | ||
894 | if ((qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) || | ||
895 | (bmac_status & CREG_STAT_ERRORS)) | ||
896 | bigmac_is_medium_rare(bp, qec_status, bmac_status); | ||
897 | |||
898 | if (bmac_status & CREG_STAT_TXIRQ) | ||
899 | bigmac_tx(bp); | ||
900 | |||
901 | if (bmac_status & CREG_STAT_RXIRQ) | ||
902 | bigmac_rx(bp); | ||
903 | |||
904 | return IRQ_HANDLED; | ||
905 | } | ||
906 | |||
907 | static int bigmac_open(struct net_device *dev) | ||
908 | { | ||
909 | struct bigmac *bp = (struct bigmac *) dev->priv; | ||
910 | int ret; | ||
911 | |||
912 | ret = request_irq(dev->irq, &bigmac_interrupt, SA_SHIRQ, dev->name, bp); | ||
913 | if (ret) { | ||
914 | printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq); | ||
915 | return ret; | ||
916 | } | ||
917 | init_timer(&bp->bigmac_timer); | ||
918 | ret = bigmac_init(bp, 0); | ||
919 | if (ret) | ||
920 | free_irq(dev->irq, bp); | ||
921 | return ret; | ||
922 | } | ||
923 | |||
924 | static int bigmac_close(struct net_device *dev) | ||
925 | { | ||
926 | struct bigmac *bp = (struct bigmac *) dev->priv; | ||
927 | |||
928 | del_timer(&bp->bigmac_timer); | ||
929 | bp->timer_state = asleep; | ||
930 | bp->timer_ticks = 0; | ||
931 | |||
932 | bigmac_stop(bp); | ||
933 | bigmac_clean_rings(bp); | ||
934 | free_irq(dev->irq, bp); | ||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | static void bigmac_tx_timeout(struct net_device *dev) | ||
939 | { | ||
940 | struct bigmac *bp = (struct bigmac *) dev->priv; | ||
941 | |||
942 | bigmac_init(bp, 0); | ||
943 | netif_wake_queue(dev); | ||
944 | } | ||
945 | |||
946 | /* Put a packet on the wire. */ | ||
947 | static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
948 | { | ||
949 | struct bigmac *bp = (struct bigmac *) dev->priv; | ||
950 | int len, entry; | ||
951 | u32 mapping; | ||
952 | |||
953 | len = skb->len; | ||
954 | mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE); | ||
955 | |||
956 | /* Avoid a race... */ | ||
957 | spin_lock_irq(&bp->lock); | ||
958 | entry = bp->tx_new; | ||
959 | DTX(("bigmac_start_xmit: len(%d) entry(%d)\n", len, entry)); | ||
960 | bp->bmac_block->be_txd[entry].tx_flags = TXD_UPDATE; | ||
961 | bp->tx_skbs[entry] = skb; | ||
962 | bp->bmac_block->be_txd[entry].tx_addr = mapping; | ||
963 | bp->bmac_block->be_txd[entry].tx_flags = | ||
964 | (TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH)); | ||
965 | bp->tx_new = NEXT_TX(entry); | ||
966 | if (TX_BUFFS_AVAIL(bp) <= 0) | ||
967 | netif_stop_queue(dev); | ||
968 | spin_unlock_irq(&bp->lock); | ||
969 | |||
970 | /* Get it going. */ | ||
971 | sbus_writel(CREG_CTRL_TWAKEUP, bp->creg + CREG_CTRL); | ||
972 | |||
973 | |||
974 | dev->trans_start = jiffies; | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | static struct net_device_stats *bigmac_get_stats(struct net_device *dev) | ||
980 | { | ||
981 | struct bigmac *bp = (struct bigmac *) dev->priv; | ||
982 | |||
983 | bigmac_get_counters(bp, bp->bregs); | ||
984 | return &bp->enet_stats; | ||
985 | } | ||
986 | |||
987 | static void bigmac_set_multicast(struct net_device *dev) | ||
988 | { | ||
989 | struct bigmac *bp = (struct bigmac *) dev->priv; | ||
990 | void __iomem *bregs = bp->bregs; | ||
991 | struct dev_mc_list *dmi = dev->mc_list; | ||
992 | char *addrs; | ||
993 | int i; | ||
994 | u32 tmp, crc; | ||
995 | |||
996 | /* Disable the receiver. The bit self-clears when | ||
997 | * the operation is complete. | ||
998 | */ | ||
999 | tmp = sbus_readl(bregs + BMAC_RXCFG); | ||
1000 | tmp &= ~(BIGMAC_RXCFG_ENABLE); | ||
1001 | sbus_writel(tmp, bregs + BMAC_RXCFG); | ||
1002 | while ((sbus_readl(bregs + BMAC_RXCFG) & BIGMAC_RXCFG_ENABLE) != 0) | ||
1003 | udelay(20); | ||
1004 | |||
1005 | if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { | ||
1006 | sbus_writel(0xffff, bregs + BMAC_HTABLE0); | ||
1007 | sbus_writel(0xffff, bregs + BMAC_HTABLE1); | ||
1008 | sbus_writel(0xffff, bregs + BMAC_HTABLE2); | ||
1009 | sbus_writel(0xffff, bregs + BMAC_HTABLE3); | ||
1010 | } else if (dev->flags & IFF_PROMISC) { | ||
1011 | tmp = sbus_readl(bregs + BMAC_RXCFG); | ||
1012 | tmp |= BIGMAC_RXCFG_PMISC; | ||
1013 | sbus_writel(tmp, bregs + BMAC_RXCFG); | ||
1014 | } else { | ||
1015 | u16 hash_table[4]; | ||
1016 | |||
1017 | for (i = 0; i < 4; i++) | ||
1018 | hash_table[i] = 0; | ||
1019 | |||
1020 | for (i = 0; i < dev->mc_count; i++) { | ||
1021 | addrs = dmi->dmi_addr; | ||
1022 | dmi = dmi->next; | ||
1023 | |||
1024 | if (!(*addrs & 1)) | ||
1025 | continue; | ||
1026 | |||
1027 | crc = ether_crc_le(6, addrs); | ||
1028 | crc >>= 26; | ||
1029 | hash_table[crc >> 4] |= 1 << (crc & 0xf); | ||
1030 | } | ||
1031 | sbus_writel(hash_table[0], bregs + BMAC_HTABLE0); | ||
1032 | sbus_writel(hash_table[1], bregs + BMAC_HTABLE1); | ||
1033 | sbus_writel(hash_table[2], bregs + BMAC_HTABLE2); | ||
1034 | sbus_writel(hash_table[3], bregs + BMAC_HTABLE3); | ||
1035 | } | ||
1036 | |||
1037 | /* Re-enable the receiver. */ | ||
1038 | tmp = sbus_readl(bregs + BMAC_RXCFG); | ||
1039 | tmp |= BIGMAC_RXCFG_ENABLE; | ||
1040 | sbus_writel(tmp, bregs + BMAC_RXCFG); | ||
1041 | } | ||
1042 | |||
1043 | /* Ethtool support... */ | ||
1044 | static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | ||
1045 | { | ||
1046 | struct bigmac *bp = dev->priv; | ||
1047 | |||
1048 | strcpy(info->driver, "sunbmac"); | ||
1049 | strcpy(info->version, "2.0"); | ||
1050 | sprintf(info->bus_info, "SBUS:%d", | ||
1051 | bp->qec_sdev->slot); | ||
1052 | } | ||
1053 | |||
1054 | static u32 bigmac_get_link(struct net_device *dev) | ||
1055 | { | ||
1056 | struct bigmac *bp = dev->priv; | ||
1057 | |||
1058 | spin_lock_irq(&bp->lock); | ||
1059 | bp->sw_bmsr = bigmac_tcvr_read(bp, bp->tregs, BIGMAC_BMSR); | ||
1060 | spin_unlock_irq(&bp->lock); | ||
1061 | |||
1062 | return (bp->sw_bmsr & BMSR_LSTATUS); | ||
1063 | } | ||
1064 | |||
1065 | static struct ethtool_ops bigmac_ethtool_ops = { | ||
1066 | .get_drvinfo = bigmac_get_drvinfo, | ||
1067 | .get_link = bigmac_get_link, | ||
1068 | }; | ||
1069 | |||
1070 | static int __init bigmac_ether_init(struct sbus_dev *qec_sdev) | ||
1071 | { | ||
1072 | struct net_device *dev; | ||
1073 | static int version_printed; | ||
1074 | struct bigmac *bp; | ||
1075 | u8 bsizes, bsizes_more; | ||
1076 | int i; | ||
1077 | |||
1078 | /* Get a new device struct for this interface. */ | ||
1079 | dev = alloc_etherdev(sizeof(struct bigmac)); | ||
1080 | if (!dev) | ||
1081 | return -ENOMEM; | ||
1082 | SET_MODULE_OWNER(dev); | ||
1083 | |||
1084 | if (version_printed++ == 0) | ||
1085 | printk(KERN_INFO "%s", version); | ||
1086 | |||
1087 | dev->base_addr = (long) qec_sdev; | ||
1088 | for (i = 0; i < 6; i++) | ||
1089 | dev->dev_addr[i] = idprom->id_ethaddr[i]; | ||
1090 | |||
1091 | /* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */ | ||
1092 | bp = dev->priv; | ||
1093 | bp->qec_sdev = qec_sdev; | ||
1094 | bp->bigmac_sdev = qec_sdev->child; | ||
1095 | |||
1096 | spin_lock_init(&bp->lock); | ||
1097 | |||
1098 | /* Verify the registers we expect, are actually there. */ | ||
1099 | if ((bp->bigmac_sdev->num_registers != 3) || | ||
1100 | (bp->qec_sdev->num_registers != 2)) { | ||
1101 | printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n", | ||
1102 | bp->qec_sdev->num_registers, | ||
1103 | bp->bigmac_sdev->num_registers); | ||
1104 | printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n"); | ||
1105 | goto fail_and_cleanup; | ||
1106 | } | ||
1107 | |||
1108 | /* Map in QEC global control registers. */ | ||
1109 | bp->gregs = sbus_ioremap(&bp->qec_sdev->resource[0], 0, | ||
1110 | GLOB_REG_SIZE, "BigMAC QEC GLobal Regs"); | ||
1111 | if (!bp->gregs) { | ||
1112 | printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n"); | ||
1113 | goto fail_and_cleanup; | ||
1114 | } | ||
1115 | |||
1116 | /* Make sure QEC is in BigMAC mode. */ | ||
1117 | if ((sbus_readl(bp->gregs + GLOB_CTRL) & 0xf0000000) != GLOB_CTRL_BMODE) { | ||
1118 | printk(KERN_ERR "BigMAC: AIEEE, QEC is not in BigMAC mode!\n"); | ||
1119 | goto fail_and_cleanup; | ||
1120 | } | ||
1121 | |||
1122 | /* Reset the QEC. */ | ||
1123 | if (qec_global_reset(bp->gregs)) | ||
1124 | goto fail_and_cleanup; | ||
1125 | |||
1126 | /* Get supported SBUS burst sizes. */ | ||
1127 | bsizes = prom_getintdefault(bp->qec_sdev->prom_node, | ||
1128 | "burst-sizes", | ||
1129 | 0xff); | ||
1130 | |||
1131 | bsizes_more = prom_getintdefault(bp->qec_sdev->bus->prom_node, | ||
1132 | "burst-sizes", | ||
1133 | 0xff); | ||
1134 | |||
1135 | bsizes &= 0xff; | ||
1136 | if (bsizes_more != 0xff) | ||
1137 | bsizes &= bsizes_more; | ||
1138 | if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 || | ||
1139 | (bsizes & DMA_BURST32) == 0) | ||
1140 | bsizes = (DMA_BURST32 - 1); | ||
1141 | bp->bigmac_bursts = bsizes; | ||
1142 | |||
1143 | /* Perform QEC initialization. */ | ||
1144 | qec_init(bp); | ||
1145 | |||
1146 | /* Map in the BigMAC channel registers. */ | ||
1147 | bp->creg = sbus_ioremap(&bp->bigmac_sdev->resource[0], 0, | ||
1148 | CREG_REG_SIZE, "BigMAC QEC Channel Regs"); | ||
1149 | if (!bp->creg) { | ||
1150 | printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n"); | ||
1151 | goto fail_and_cleanup; | ||
1152 | } | ||
1153 | |||
1154 | /* Map in the BigMAC control registers. */ | ||
1155 | bp->bregs = sbus_ioremap(&bp->bigmac_sdev->resource[1], 0, | ||
1156 | BMAC_REG_SIZE, "BigMAC Primary Regs"); | ||
1157 | if (!bp->bregs) { | ||
1158 | printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n"); | ||
1159 | goto fail_and_cleanup; | ||
1160 | } | ||
1161 | |||
1162 | /* Map in the BigMAC transceiver registers, this is how you poke at | ||
1163 | * the BigMAC's PHY. | ||
1164 | */ | ||
1165 | bp->tregs = sbus_ioremap(&bp->bigmac_sdev->resource[2], 0, | ||
1166 | TCVR_REG_SIZE, "BigMAC Transceiver Regs"); | ||
1167 | if (!bp->tregs) { | ||
1168 | printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n"); | ||
1169 | goto fail_and_cleanup; | ||
1170 | } | ||
1171 | |||
1172 | /* Stop the BigMAC. */ | ||
1173 | bigmac_stop(bp); | ||
1174 | |||
1175 | /* Allocate transmit/receive descriptor DVMA block. */ | ||
1176 | bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev, | ||
1177 | PAGE_SIZE, | ||
1178 | &bp->bblock_dvma); | ||
1179 | if (bp->bmac_block == NULL || bp->bblock_dvma == 0) { | ||
1180 | printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n"); | ||
1181 | goto fail_and_cleanup; | ||
1182 | } | ||
1183 | |||
1184 | /* Get the board revision of this BigMAC. */ | ||
1185 | bp->board_rev = prom_getintdefault(bp->bigmac_sdev->prom_node, | ||
1186 | "board-version", 1); | ||
1187 | |||
1188 | /* Init auto-negotiation timer state. */ | ||
1189 | init_timer(&bp->bigmac_timer); | ||
1190 | bp->timer_state = asleep; | ||
1191 | bp->timer_ticks = 0; | ||
1192 | |||
1193 | /* Backlink to generic net device struct. */ | ||
1194 | bp->dev = dev; | ||
1195 | |||
1196 | /* Set links to our BigMAC open and close routines. */ | ||
1197 | dev->open = &bigmac_open; | ||
1198 | dev->stop = &bigmac_close; | ||
1199 | dev->hard_start_xmit = &bigmac_start_xmit; | ||
1200 | dev->ethtool_ops = &bigmac_ethtool_ops; | ||
1201 | |||
1202 | /* Set links to BigMAC statistic and multi-cast loading code. */ | ||
1203 | dev->get_stats = &bigmac_get_stats; | ||
1204 | dev->set_multicast_list = &bigmac_set_multicast; | ||
1205 | |||
1206 | dev->tx_timeout = &bigmac_tx_timeout; | ||
1207 | dev->watchdog_timeo = 5*HZ; | ||
1208 | |||
1209 | /* Finish net device registration. */ | ||
1210 | dev->irq = bp->bigmac_sdev->irqs[0]; | ||
1211 | dev->dma = 0; | ||
1212 | |||
1213 | if (register_netdev(dev)) { | ||
1214 | printk(KERN_ERR "BIGMAC: Cannot register device.\n"); | ||
1215 | goto fail_and_cleanup; | ||
1216 | } | ||
1217 | |||
1218 | /* Put us into the list of instances attached for later driver | ||
1219 | * exit. | ||
1220 | */ | ||
1221 | bp->next_module = root_bigmac_dev; | ||
1222 | root_bigmac_dev = bp; | ||
1223 | |||
1224 | printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name); | ||
1225 | for (i = 0; i < 6; i++) | ||
1226 | printk("%2.2x%c", dev->dev_addr[i], | ||
1227 | i == 5 ? ' ' : ':'); | ||
1228 | printk("\n"); | ||
1229 | |||
1230 | return 0; | ||
1231 | |||
1232 | fail_and_cleanup: | ||
1233 | /* Something went wrong, undo whatever we did so far. */ | ||
1234 | /* Free register mappings if any. */ | ||
1235 | if (bp->gregs) | ||
1236 | sbus_iounmap(bp->gregs, GLOB_REG_SIZE); | ||
1237 | if (bp->creg) | ||
1238 | sbus_iounmap(bp->creg, CREG_REG_SIZE); | ||
1239 | if (bp->bregs) | ||
1240 | sbus_iounmap(bp->bregs, BMAC_REG_SIZE); | ||
1241 | if (bp->tregs) | ||
1242 | sbus_iounmap(bp->tregs, TCVR_REG_SIZE); | ||
1243 | |||
1244 | if (bp->bmac_block) | ||
1245 | sbus_free_consistent(bp->bigmac_sdev, | ||
1246 | PAGE_SIZE, | ||
1247 | bp->bmac_block, | ||
1248 | bp->bblock_dvma); | ||
1249 | |||
1250 | /* This also frees the co-located 'dev->priv' */ | ||
1251 | free_netdev(dev); | ||
1252 | return -ENODEV; | ||
1253 | } | ||
1254 | |||
1255 | /* QEC can be the parent of either QuadEthernet or | ||
1256 | * a BigMAC. We want the latter. | ||
1257 | */ | ||
1258 | static int __init bigmac_match(struct sbus_dev *sdev) | ||
1259 | { | ||
1260 | struct sbus_dev *child = sdev->child; | ||
1261 | |||
1262 | if (strcmp(sdev->prom_name, "qec") != 0) | ||
1263 | return 0; | ||
1264 | |||
1265 | if (child == NULL) | ||
1266 | return 0; | ||
1267 | |||
1268 | if (strcmp(child->prom_name, "be") != 0) | ||
1269 | return 0; | ||
1270 | |||
1271 | return 1; | ||
1272 | } | ||
1273 | |||
1274 | static int __init bigmac_probe(void) | ||
1275 | { | ||
1276 | struct sbus_bus *sbus; | ||
1277 | struct sbus_dev *sdev = NULL; | ||
1278 | static int called; | ||
1279 | int cards = 0, v; | ||
1280 | |||
1281 | root_bigmac_dev = NULL; | ||
1282 | |||
1283 | if (called) | ||
1284 | return -ENODEV; | ||
1285 | called++; | ||
1286 | |||
1287 | for_each_sbus(sbus) { | ||
1288 | for_each_sbusdev(sdev, sbus) { | ||
1289 | if (bigmac_match(sdev)) { | ||
1290 | cards++; | ||
1291 | if ((v = bigmac_ether_init(sdev))) | ||
1292 | return v; | ||
1293 | } | ||
1294 | } | ||
1295 | } | ||
1296 | if (!cards) | ||
1297 | return -ENODEV; | ||
1298 | return 0; | ||
1299 | } | ||
1300 | |||
1301 | static void __exit bigmac_cleanup(void) | ||
1302 | { | ||
1303 | while (root_bigmac_dev) { | ||
1304 | struct bigmac *bp = root_bigmac_dev; | ||
1305 | struct bigmac *bp_nxt = root_bigmac_dev->next_module; | ||
1306 | |||
1307 | sbus_iounmap(bp->gregs, GLOB_REG_SIZE); | ||
1308 | sbus_iounmap(bp->creg, CREG_REG_SIZE); | ||
1309 | sbus_iounmap(bp->bregs, BMAC_REG_SIZE); | ||
1310 | sbus_iounmap(bp->tregs, TCVR_REG_SIZE); | ||
1311 | sbus_free_consistent(bp->bigmac_sdev, | ||
1312 | PAGE_SIZE, | ||
1313 | bp->bmac_block, | ||
1314 | bp->bblock_dvma); | ||
1315 | |||
1316 | unregister_netdev(bp->dev); | ||
1317 | free_netdev(bp->dev); | ||
1318 | root_bigmac_dev = bp_nxt; | ||
1319 | } | ||
1320 | } | ||
1321 | |||
1322 | module_init(bigmac_probe); | ||
1323 | module_exit(bigmac_cleanup); | ||
1324 | MODULE_LICENSE("GPL"); | ||