ia64/linux-2.6.18-xen.hg

annotate drivers/net/sunbmac.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

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