|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2008 Stefan Hajnoczi <[email protected]> ! 3: * Copyright (c) 2008 Pantelis Koukousoulas <[email protected]> ! 4: * ! 5: * This program is free software; you can redistribute it and/or ! 6: * modify it under the terms of the GNU General Public License as ! 7: * published by the Free Software Foundation; either version 2 of the ! 8: * License, or any later version. ! 9: * ! 10: * This program is distributed in the hope that it will be useful, but ! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 13: * General Public License for more details. ! 14: * ! 15: * You should have received a copy of the GNU General Public License ! 16: * along with this program; if not, write to the Free Software ! 17: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 18: * ! 19: * This driver is a port of the b44 linux driver version 1.01 ! 20: * ! 21: * Copyright (c) 2002 David S. Miller <[email protected]> ! 22: * Copyright (c) Pekka Pietikainen <[email protected]> ! 23: * Copyright (C) 2006 Broadcom Corporation. ! 24: * ! 25: * Some ssb bits copied from version 2.0 of the b44 driver ! 26: * Copyright (c) Michael Buesch ! 27: * ! 28: * Copyright (c) a lot of people too. Please respect their work. ! 29: */ ! 30: ! 31: FILE_LICENCE ( GPL2_OR_LATER ); ! 32: ! 33: #include <errno.h> ! 34: #include <assert.h> ! 35: #include <stdio.h> ! 36: #include <unistd.h> ! 37: #include <byteswap.h> ! 38: #include <ipxe/io.h> ! 39: #include <mii.h> ! 40: #include <ipxe/iobuf.h> ! 41: #include <ipxe/malloc.h> ! 42: #include <ipxe/pci.h> ! 43: #include <ipxe/netdevice.h> ! 44: #include <ipxe/ethernet.h> ! 45: #include <ipxe/if_ether.h> ! 46: #include "b44.h" ! 47: ! 48: ! 49: static inline int ring_next(int index) ! 50: { ! 51: /* B44_RING_SIZE is a power of 2 :) */ ! 52: return (index + 1) & (B44_RING_SIZE - 1); ! 53: } ! 54: ! 55: ! 56: /* Memory-mapped I/O wrappers */ ! 57: ! 58: static inline u32 br32(const struct b44_private *bp, u32 reg) ! 59: { ! 60: return readl(bp->regs + reg); ! 61: } ! 62: ! 63: ! 64: static inline void bw32(const struct b44_private *bp, u32 reg, u32 val) ! 65: { ! 66: writel(val, bp->regs + reg); ! 67: } ! 68: ! 69: ! 70: static inline void bflush(const struct b44_private *bp, u32 reg, u32 timeout) ! 71: { ! 72: readl(bp->regs + reg); ! 73: udelay(timeout); ! 74: } ! 75: ! 76: ! 77: #define VIRT_TO_B44(addr) ( virt_to_bus(addr) + SB_PCI_DMA ) ! 78: ! 79: ! 80: /** ! 81: * Return non-zero if the installed RAM is within ! 82: * the limit given and zero if it is outside. ! 83: * Hopefully will be removed soon. ! 84: */ ! 85: int phys_ram_within_limit(u64 limit) ! 86: { ! 87: struct memory_map memmap; ! 88: struct memory_region *highest = NULL; ! 89: get_memmap(&memmap); ! 90: ! 91: if (memmap.count == 0) ! 92: return 0; ! 93: highest = &memmap.regions[memmap.count - 1]; ! 94: ! 95: return (highest->end < limit); ! 96: } ! 97: ! 98: ! 99: /** ! 100: * Ring cells waiting to be processed are between 'tx_cur' and 'pending' ! 101: * indexes in the ring. ! 102: */ ! 103: static u32 pending_tx_index(struct b44_private *bp) ! 104: { ! 105: u32 pending = br32(bp, B44_DMATX_STAT); ! 106: pending &= DMATX_STAT_CDMASK; ! 107: ! 108: pending /= sizeof(struct dma_desc); ! 109: return pending & (B44_RING_SIZE - 1); ! 110: } ! 111: ! 112: ! 113: /** ! 114: * Ring cells waiting to be processed are between 'rx_cur' and 'pending' ! 115: * indexes in the ring. ! 116: */ ! 117: static u32 pending_rx_index(struct b44_private *bp) ! 118: { ! 119: u32 pending = br32(bp, B44_DMARX_STAT); ! 120: pending &= DMARX_STAT_CDMASK; ! 121: ! 122: pending /= sizeof(struct dma_desc); ! 123: return pending & (B44_RING_SIZE - 1); ! 124: } ! 125: ! 126: ! 127: /** ! 128: * Wait until the given bit is set/cleared. ! 129: */ ! 130: static int b44_wait_bit(struct b44_private *bp, unsigned long reg, u32 bit, ! 131: unsigned long timeout, const int clear) ! 132: { ! 133: unsigned long i; ! 134: ! 135: for (i = 0; i < timeout; i++) { ! 136: u32 val = br32(bp, reg); ! 137: ! 138: if (clear && !(val & bit)) ! 139: break; ! 140: ! 141: if (!clear && (val & bit)) ! 142: break; ! 143: ! 144: udelay(10); ! 145: } ! 146: if (i == timeout) { ! 147: return -ENODEV; ! 148: } ! 149: return 0; ! 150: } ! 151: ! 152: ! 153: /* ! 154: * Sonics Silicon Backplane support. SSB is a mini-bus interconnecting ! 155: * so-called IP Cores. One of those cores implements the Fast Ethernet ! 156: * functionality and another one the PCI engine. ! 157: * ! 158: * You need to switch to the core you want to talk to before actually ! 159: * sending commands. ! 160: * ! 161: * See: http://bcm-v4.sipsolutions.net/Backplane for (reverse-engineered) ! 162: * specs. ! 163: */ ! 164: ! 165: static inline u32 ssb_get_core_rev(struct b44_private *bp) ! 166: { ! 167: return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK); ! 168: } ! 169: ! 170: ! 171: static inline int ssb_is_core_up(struct b44_private *bp) ! 172: { ! 173: return ((br32(bp, B44_SBTMSLOW) & (SSB_CORE_DOWN | SBTMSLOW_CLOCK)) ! 174: == SBTMSLOW_CLOCK); ! 175: } ! 176: ! 177: ! 178: static u32 ssb_pci_setup(struct b44_private *bp, u32 cores) ! 179: { ! 180: u32 bar_orig, pci_rev, val; ! 181: ! 182: pci_read_config_dword(bp->pci, SSB_BAR0_WIN, &bar_orig); ! 183: pci_write_config_dword(bp->pci, SSB_BAR0_WIN, ! 184: BCM4400_PCI_CORE_ADDR); ! 185: pci_rev = ssb_get_core_rev(bp); ! 186: ! 187: val = br32(bp, B44_SBINTVEC); ! 188: val |= cores; ! 189: bw32(bp, B44_SBINTVEC, val); ! 190: ! 191: val = br32(bp, SSB_PCI_TRANS_2); ! 192: val |= SSB_PCI_PREF | SSB_PCI_BURST; ! 193: bw32(bp, SSB_PCI_TRANS_2, val); ! 194: ! 195: pci_write_config_dword(bp->pci, SSB_BAR0_WIN, bar_orig); ! 196: ! 197: return pci_rev; ! 198: } ! 199: ! 200: ! 201: static void ssb_core_disable(struct b44_private *bp) ! 202: { ! 203: if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET) ! 204: return; ! 205: ! 206: bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK)); ! 207: b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0); ! 208: b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1); ! 209: ! 210: bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK | ! 211: SSB_CORE_DOWN)); ! 212: bflush(bp, B44_SBTMSLOW, 1); ! 213: ! 214: bw32(bp, B44_SBTMSLOW, SSB_CORE_DOWN); ! 215: bflush(bp, B44_SBTMSLOW, 1); ! 216: } ! 217: ! 218: ! 219: static void ssb_core_reset(struct b44_private *bp) ! 220: { ! 221: u32 val; ! 222: const u32 mask = (SBTMSLOW_CLOCK | SBTMSLOW_FGC | SBTMSLOW_RESET); ! 223: ! 224: ssb_core_disable(bp); ! 225: ! 226: bw32(bp, B44_SBTMSLOW, mask); ! 227: bflush(bp, B44_SBTMSLOW, 1); ! 228: ! 229: /* Clear SERR if set, this is a hw bug workaround. */ ! 230: if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR) ! 231: bw32(bp, B44_SBTMSHIGH, 0); ! 232: ! 233: val = br32(bp, B44_SBIMSTATE); ! 234: if (val & (SBIMSTATE_BAD)) { ! 235: bw32(bp, B44_SBIMSTATE, val & ~SBIMSTATE_BAD); ! 236: } ! 237: ! 238: bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC)); ! 239: bflush(bp, B44_SBTMSLOW, 1); ! 240: ! 241: bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK)); ! 242: bflush(bp, B44_SBTMSLOW, 1); ! 243: } ! 244: ! 245: ! 246: /* ! 247: * Driver helper functions ! 248: */ ! 249: ! 250: /* ! 251: * Chip reset provides power to the b44 MAC & PCI cores, which ! 252: * is necessary for MAC register access. We only do a partial ! 253: * reset in case of transmit/receive errors (ISTAT_ERRORS) to ! 254: * avoid the chip being hung for an unnecessary long time in ! 255: * this case. ! 256: * ! 257: * Called-by: b44_close, b44_halt, b44_inithw(b44_open), b44_probe ! 258: */ ! 259: static void b44_chip_reset(struct b44_private *bp, int reset_kind) ! 260: { ! 261: if (ssb_is_core_up(bp)) { ! 262: bw32(bp, B44_RCV_LAZY, 0); ! 263: ! 264: bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); ! 265: ! 266: b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1); ! 267: ! 268: bw32(bp, B44_DMATX_CTRL, 0); ! 269: ! 270: bp->tx_dirty = bp->tx_cur = 0; ! 271: ! 272: if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK) ! 273: b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE, ! 274: 100, 0); ! 275: ! 276: bw32(bp, B44_DMARX_CTRL, 0); ! 277: ! 278: bp->rx_cur = 0; ! 279: } else { ! 280: ssb_pci_setup(bp, SBINTVEC_ENET0); ! 281: } ! 282: ! 283: ssb_core_reset(bp); ! 284: ! 285: /* Don't enable PHY if we are only doing a partial reset. */ ! 286: if (reset_kind == B44_CHIP_RESET_PARTIAL) ! 287: return; ! 288: ! 289: /* Make PHY accessible. */ ! 290: bw32(bp, B44_MDIO_CTRL, ! 291: (MDIO_CTRL_PREAMBLE | (0x0d & MDIO_CTRL_MAXF_MASK))); ! 292: bflush(bp, B44_MDIO_CTRL, 1); ! 293: ! 294: /* Enable internal or external PHY */ ! 295: if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) { ! 296: bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL); ! 297: bflush(bp, B44_ENET_CTRL, 1); ! 298: } else { ! 299: u32 val = br32(bp, B44_DEVCTRL); ! 300: if (val & DEVCTRL_EPR) { ! 301: bw32(bp, B44_DEVCTRL, (val & ~DEVCTRL_EPR)); ! 302: bflush(bp, B44_DEVCTRL, 100); ! 303: } ! 304: } ! 305: } ! 306: ! 307: ! 308: /** ! 309: * called by b44_poll in the error path ! 310: */ ! 311: static void b44_halt(struct b44_private *bp) ! 312: { ! 313: /* disable ints */ ! 314: bw32(bp, B44_IMASK, 0); ! 315: bflush(bp, B44_IMASK, 1); ! 316: ! 317: DBG("b44: powering down PHY\n"); ! 318: bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN); ! 319: ! 320: /* ! 321: * Now reset the chip, but without enabling ! 322: * the MAC&PHY part of it. ! 323: * This has to be done _after_ we shut down the PHY ! 324: */ ! 325: b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL); ! 326: } ! 327: ! 328: ! 329: ! 330: /* ! 331: * Called at device open time to get the chip ready for ! 332: * packet processing. ! 333: * ! 334: * Called-by: b44_open ! 335: */ ! 336: static void b44_init_hw(struct b44_private *bp, int reset_kind) ! 337: { ! 338: u32 val; ! 339: #define CTRL_MASK (DMARX_CTRL_ENABLE | (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT)) ! 340: ! 341: b44_chip_reset(bp, B44_CHIP_RESET_FULL); ! 342: if (reset_kind == B44_FULL_RESET) { ! 343: b44_phy_reset(bp); ! 344: } ! 345: ! 346: /* Enable CRC32, set proper LED modes and power on PHY */ ! 347: bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); ! 348: bw32(bp, B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT)); ! 349: ! 350: /* This sets the MAC address too. */ ! 351: b44_set_rx_mode(bp->netdev); ! 352: ! 353: /* MTU + eth header + possible VLAN tag + struct rx_header */ ! 354: bw32(bp, B44_RXMAXLEN, B44_MAX_MTU + ETH_HLEN + 8 + RX_HEADER_LEN); ! 355: bw32(bp, B44_TXMAXLEN, B44_MAX_MTU + ETH_HLEN + 8 + RX_HEADER_LEN); ! 356: ! 357: bw32(bp, B44_TX_HIWMARK, TX_HIWMARK_DEFLT); ! 358: if (reset_kind == B44_PARTIAL_RESET) { ! 359: bw32(bp, B44_DMARX_CTRL, CTRL_MASK); ! 360: } else { ! 361: bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE); ! 362: bw32(bp, B44_DMATX_ADDR, VIRT_TO_B44(bp->tx)); ! 363: ! 364: bw32(bp, B44_DMARX_CTRL, CTRL_MASK); ! 365: bw32(bp, B44_DMARX_ADDR, VIRT_TO_B44(bp->rx)); ! 366: bw32(bp, B44_DMARX_PTR, B44_RX_RING_LEN_BYTES); ! 367: ! 368: bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); ! 369: } ! 370: ! 371: val = br32(bp, B44_ENET_CTRL); ! 372: bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); ! 373: #undef CTRL_MASK ! 374: } ! 375: ! 376: ! 377: /*** Management of ring descriptors ***/ ! 378: ! 379: ! 380: static void b44_populate_rx_descriptor(struct b44_private *bp, u32 idx) ! 381: { ! 382: struct rx_header *rh; ! 383: u32 ctrl, addr; ! 384: ! 385: rh = bp->rx_iobuf[idx]->data; ! 386: rh->len = 0; ! 387: rh->flags = 0; ! 388: ctrl = DESC_CTRL_LEN & (RX_PKT_BUF_SZ - RX_PKT_OFFSET); ! 389: if (idx == B44_RING_LAST) { ! 390: ctrl |= DESC_CTRL_EOT; ! 391: } ! 392: addr = VIRT_TO_B44(bp->rx_iobuf[idx]->data); ! 393: ! 394: bp->rx[idx].ctrl = cpu_to_le32(ctrl); ! 395: bp->rx[idx].addr = cpu_to_le32(addr); ! 396: bw32(bp, B44_DMARX_PTR, idx * sizeof(struct dma_desc)); ! 397: } ! 398: ! 399: ! 400: /* ! 401: * Refill RX ring descriptors with buffers. This is needed ! 402: * because during rx we are passing ownership of descriptor ! 403: * buffers to the network stack. ! 404: */ ! 405: static void b44_rx_refill(struct b44_private *bp, u32 pending) ! 406: { ! 407: u32 i; ! 408: ! 409: // skip pending ! 410: for (i = pending + 1; i != bp->rx_cur; i = ring_next(i)) { ! 411: if (bp->rx_iobuf[i] != NULL) ! 412: continue; ! 413: ! 414: bp->rx_iobuf[i] = alloc_iob(RX_PKT_BUF_SZ); ! 415: if (!bp->rx_iobuf[i]) { ! 416: DBG("Refill rx ring failed!!\n"); ! 417: break; ! 418: } ! 419: ! 420: b44_populate_rx_descriptor(bp, i); ! 421: } ! 422: } ! 423: ! 424: ! 425: static void b44_free_rx_ring(struct b44_private *bp) ! 426: { ! 427: u32 i; ! 428: ! 429: if (bp->rx) { ! 430: for (i = 0; i < B44_RING_SIZE; i++) { ! 431: free_iob(bp->rx_iobuf[i]); ! 432: bp->rx_iobuf[i] = NULL; ! 433: } ! 434: free_dma(bp->rx, B44_RX_RING_LEN_BYTES); ! 435: bp->rx = NULL; ! 436: } ! 437: } ! 438: ! 439: ! 440: static int b44_init_rx_ring(struct b44_private *bp) ! 441: { ! 442: b44_free_rx_ring(bp); ! 443: ! 444: bp->rx = malloc_dma(B44_RX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); ! 445: if (!bp->rx) ! 446: return -ENOMEM; ! 447: ! 448: memset(bp->rx_iobuf, 0, sizeof(bp->rx_iobuf)); ! 449: ! 450: bp->rx_iobuf[0] = alloc_iob(RX_PKT_BUF_SZ); ! 451: b44_populate_rx_descriptor(bp, 0); ! 452: b44_rx_refill(bp, 0); ! 453: ! 454: DBG("Init RX rings: rx=0x%08lx\n", VIRT_TO_B44(bp->rx)); ! 455: return 0; ! 456: } ! 457: ! 458: ! 459: static void b44_free_tx_ring(struct b44_private *bp) ! 460: { ! 461: if (bp->tx) { ! 462: free_dma(bp->tx, B44_TX_RING_LEN_BYTES); ! 463: bp->tx = NULL; ! 464: } ! 465: } ! 466: ! 467: ! 468: static int b44_init_tx_ring(struct b44_private *bp) ! 469: { ! 470: b44_free_tx_ring(bp); ! 471: ! 472: bp->tx = malloc_dma(B44_TX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); ! 473: if (!bp->tx) ! 474: return -ENOMEM; ! 475: ! 476: memset(bp->tx, 0, B44_TX_RING_LEN_BYTES); ! 477: memset(bp->tx_iobuf, 0, sizeof(bp->tx_iobuf)); ! 478: ! 479: DBG("Init TX rings: tx=0x%08lx\n", VIRT_TO_B44(bp->tx)); ! 480: return 0; ! 481: } ! 482: ! 483: ! 484: /*** Interaction with the PHY ***/ ! 485: ! 486: ! 487: static int b44_phy_read(struct b44_private *bp, int reg, u32 * val) ! 488: { ! 489: int err; ! 490: ! 491: u32 arg1 = (MDIO_OP_READ << MDIO_DATA_OP_SHIFT); ! 492: u32 arg2 = (bp->phy_addr << MDIO_DATA_PMD_SHIFT); ! 493: u32 arg3 = (reg << MDIO_DATA_RA_SHIFT); ! 494: u32 arg4 = (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT); ! 495: u32 argv = arg1 | arg2 | arg3 | arg4; ! 496: ! 497: bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); ! 498: bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | argv)); ! 499: err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); ! 500: *val = br32(bp, B44_MDIO_DATA) & MDIO_DATA_DATA; ! 501: ! 502: return err; ! 503: } ! 504: ! 505: ! 506: static int b44_phy_write(struct b44_private *bp, int reg, u32 val) ! 507: { ! 508: u32 arg1 = (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT); ! 509: u32 arg2 = (bp->phy_addr << MDIO_DATA_PMD_SHIFT); ! 510: u32 arg3 = (reg << MDIO_DATA_RA_SHIFT); ! 511: u32 arg4 = (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT); ! 512: u32 arg5 = (val & MDIO_DATA_DATA); ! 513: u32 argv = arg1 | arg2 | arg3 | arg4 | arg5; ! 514: ! 515: ! 516: bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); ! 517: bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | argv)); ! 518: return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); ! 519: } ! 520: ! 521: ! 522: static int b44_phy_reset(struct b44_private *bp) ! 523: { ! 524: u32 val; ! 525: int err; ! 526: ! 527: err = b44_phy_write(bp, MII_BMCR, BMCR_RESET); ! 528: if (err) ! 529: return err; ! 530: ! 531: udelay(100); ! 532: err = b44_phy_read(bp, MII_BMCR, &val); ! 533: if (!err) { ! 534: if (val & BMCR_RESET) { ! 535: return -ENODEV; ! 536: } ! 537: } ! 538: ! 539: return 0; ! 540: } ! 541: ! 542: ! 543: /* ! 544: * The BCM44xx CAM (Content Addressable Memory) stores the MAC ! 545: * and PHY address. ! 546: */ ! 547: static void b44_cam_write(struct b44_private *bp, unsigned char *data, ! 548: int index) ! 549: { ! 550: u32 val; ! 551: ! 552: val = ((u32) data[2]) << 24; ! 553: val |= ((u32) data[3]) << 16; ! 554: val |= ((u32) data[4]) << 8; ! 555: val |= ((u32) data[5]) << 0; ! 556: bw32(bp, B44_CAM_DATA_LO, val); ! 557: ! 558: ! 559: val = (CAM_DATA_HI_VALID | ! 560: (((u32) data[0]) << 8) | (((u32) data[1]) << 0)); ! 561: ! 562: bw32(bp, B44_CAM_DATA_HI, val); ! 563: ! 564: val = CAM_CTRL_WRITE | (index << CAM_CTRL_INDEX_SHIFT); ! 565: bw32(bp, B44_CAM_CTRL, val); ! 566: ! 567: b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); ! 568: } ! 569: ! 570: ! 571: static void b44_set_mac_addr(struct b44_private *bp) ! 572: { ! 573: u32 val; ! 574: bw32(bp, B44_CAM_CTRL, 0); ! 575: b44_cam_write(bp, bp->netdev->ll_addr, 0); ! 576: val = br32(bp, B44_CAM_CTRL); ! 577: bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); ! 578: } ! 579: ! 580: ! 581: /* Read 128-bytes of EEPROM. */ ! 582: static void b44_read_eeprom(struct b44_private *bp, u8 * data) ! 583: { ! 584: long i; ! 585: u16 *ptr = (u16 *) data; ! 586: ! 587: for (i = 0; i < 128; i += 2) ! 588: ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); ! 589: } ! 590: ! 591: ! 592: static void b44_load_mac_and_phy_addr(struct b44_private *bp) ! 593: { ! 594: u8 eeprom[128]; ! 595: ! 596: /* Load MAC address, note byteswapping */ ! 597: b44_read_eeprom(bp, &eeprom[0]); ! 598: bp->netdev->hw_addr[0] = eeprom[79]; ! 599: bp->netdev->hw_addr[1] = eeprom[78]; ! 600: bp->netdev->hw_addr[2] = eeprom[81]; ! 601: bp->netdev->hw_addr[3] = eeprom[80]; ! 602: bp->netdev->hw_addr[4] = eeprom[83]; ! 603: bp->netdev->hw_addr[5] = eeprom[82]; ! 604: ! 605: /* Load PHY address */ ! 606: bp->phy_addr = eeprom[90] & 0x1f; ! 607: } ! 608: ! 609: ! 610: static void b44_set_rx_mode(struct net_device *netdev) ! 611: { ! 612: struct b44_private *bp = netdev_priv(netdev); ! 613: unsigned char zero[6] = { 0, 0, 0, 0, 0, 0 }; ! 614: u32 val; ! 615: int i; ! 616: ! 617: val = br32(bp, B44_RXCONFIG); ! 618: val &= ~RXCONFIG_PROMISC; ! 619: val |= RXCONFIG_ALLMULTI; ! 620: ! 621: b44_set_mac_addr(bp); ! 622: ! 623: for (i = 1; i < 64; i++) ! 624: b44_cam_write(bp, zero, i); ! 625: ! 626: bw32(bp, B44_RXCONFIG, val); ! 627: val = br32(bp, B44_CAM_CTRL); ! 628: bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); ! 629: } ! 630: ! 631: ! 632: /*** Implementation of iPXE driver callbacks ***/ ! 633: ! 634: /** ! 635: * Probe device ! 636: * ! 637: * @v pci PCI device ! 638: * @v id Matching entry in ID table ! 639: * @ret rc Return status code ! 640: */ ! 641: static int b44_probe(struct pci_device *pci) ! 642: { ! 643: struct net_device *netdev; ! 644: struct b44_private *bp; ! 645: int rc; ! 646: ! 647: /* ! 648: * Bail out if more than 1GB of physical RAM is installed. ! 649: * This limitation will be removed later when dma mapping ! 650: * is merged into mainline. ! 651: */ ! 652: if (!phys_ram_within_limit(B44_30BIT_DMA_MASK)) { ! 653: DBG("Sorry, this version of the driver does not\n" ! 654: "support systems with more than 1GB of RAM.\n"); ! 655: return -ENOMEM; ! 656: } ! 657: ! 658: /* Set up netdev */ ! 659: netdev = alloc_etherdev(sizeof(*bp)); ! 660: if (!netdev) ! 661: return -ENOMEM; ! 662: ! 663: netdev_init(netdev, &b44_operations); ! 664: pci_set_drvdata(pci, netdev); ! 665: netdev->dev = &pci->dev; ! 666: ! 667: /* Set up private data */ ! 668: bp = netdev_priv(netdev); ! 669: memset(bp, 0, sizeof(*bp)); ! 670: bp->netdev = netdev; ! 671: bp->pci = pci; ! 672: ! 673: /* Map device registers */ ! 674: bp->regs = ioremap(pci->membase, B44_REGS_SIZE); ! 675: if (!bp->regs) { ! 676: netdev_put(netdev); ! 677: return -ENOMEM; ! 678: } ! 679: ! 680: /* Enable PCI bus mastering */ ! 681: adjust_pci_device(pci); ! 682: ! 683: b44_load_mac_and_phy_addr(bp); ! 684: ! 685: rc = register_netdev(netdev); ! 686: if (rc != 0) { ! 687: iounmap(bp->regs); ! 688: netdev_put(netdev); ! 689: return rc; ! 690: } ! 691: ! 692: /* Link management currently not implemented */ ! 693: netdev_link_up(netdev); ! 694: ! 695: b44_chip_reset(bp, B44_CHIP_RESET_FULL); ! 696: ! 697: DBG("b44 %s (%04x:%04x) regs=%p MAC=%s\n", pci->id->name, ! 698: pci->id->vendor, pci->id->device, bp->regs, ! 699: eth_ntoa(netdev->ll_addr)); ! 700: ! 701: return 0; ! 702: } ! 703: ! 704: ! 705: /** ! 706: * Remove device ! 707: * ! 708: * @v pci PCI device ! 709: */ ! 710: static void b44_remove(struct pci_device *pci) ! 711: { ! 712: struct net_device *netdev = pci_get_drvdata(pci); ! 713: struct b44_private *bp = netdev_priv(netdev); ! 714: ! 715: ssb_core_disable(bp); ! 716: unregister_netdev(netdev); ! 717: iounmap(bp->regs); ! 718: netdev_nullify(netdev); ! 719: netdev_put(netdev); ! 720: } ! 721: ! 722: ! 723: /** Enable or disable interrupts ! 724: * ! 725: * @v netdev Network device ! 726: * @v enable Interrupts should be enabled ! 727: */ ! 728: static void b44_irq(struct net_device *netdev, int enable) ! 729: { ! 730: struct b44_private *bp = netdev_priv(netdev); ! 731: ! 732: /* Interrupt mask specifies which events generate interrupts */ ! 733: bw32(bp, B44_IMASK, enable ? IMASK_DEF : IMASK_DISABLE); ! 734: } ! 735: ! 736: ! 737: /** Open network device ! 738: * ! 739: * @v netdev Network device ! 740: * @ret rc Return status code ! 741: */ ! 742: static int b44_open(struct net_device *netdev) ! 743: { ! 744: struct b44_private *bp = netdev_priv(netdev); ! 745: int rc; ! 746: ! 747: rc = b44_init_tx_ring(bp); ! 748: if (rc != 0) ! 749: return rc; ! 750: ! 751: rc = b44_init_rx_ring(bp); ! 752: if (rc != 0) ! 753: return rc; ! 754: ! 755: b44_init_hw(bp, B44_FULL_RESET); ! 756: ! 757: /* Disable interrupts */ ! 758: b44_irq(netdev, 0); ! 759: ! 760: return 0; ! 761: } ! 762: ! 763: ! 764: /** Close network device ! 765: * ! 766: * @v netdev Network device ! 767: */ ! 768: static void b44_close(struct net_device *netdev) ! 769: { ! 770: struct b44_private *bp = netdev_priv(netdev); ! 771: ! 772: b44_chip_reset(bp, B44_FULL_RESET); ! 773: b44_free_tx_ring(bp); ! 774: b44_free_rx_ring(bp); ! 775: } ! 776: ! 777: ! 778: /** Transmit packet ! 779: * ! 780: * @v netdev Network device ! 781: * @v iobuf I/O buffer ! 782: * @ret rc Return status code ! 783: */ ! 784: static int b44_transmit(struct net_device *netdev, struct io_buffer *iobuf) ! 785: { ! 786: struct b44_private *bp = netdev_priv(netdev); ! 787: u32 cur = bp->tx_cur; ! 788: u32 ctrl; ! 789: ! 790: /* Check for TX ring overflow */ ! 791: if (bp->tx[cur].ctrl) { ! 792: DBG("tx overflow\n"); ! 793: return -ENOBUFS; ! 794: } ! 795: ! 796: /* Will call netdev_tx_complete() on the iobuf later */ ! 797: bp->tx_iobuf[cur] = iobuf; ! 798: ! 799: /* Set up TX descriptor */ ! 800: ctrl = (iob_len(iobuf) & DESC_CTRL_LEN) | ! 801: DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF; ! 802: ! 803: if (cur == B44_RING_LAST) ! 804: ctrl |= DESC_CTRL_EOT; ! 805: ! 806: bp->tx[cur].ctrl = cpu_to_le32(ctrl); ! 807: bp->tx[cur].addr = cpu_to_le32(VIRT_TO_B44(iobuf->data)); ! 808: ! 809: /* Update next available descriptor index */ ! 810: cur = ring_next(cur); ! 811: bp->tx_cur = cur; ! 812: wmb(); ! 813: ! 814: /* Tell card that a new TX descriptor is ready */ ! 815: bw32(bp, B44_DMATX_PTR, cur * sizeof(struct dma_desc)); ! 816: return 0; ! 817: } ! 818: ! 819: ! 820: /** Recycles sent TX descriptors and notifies network stack ! 821: * ! 822: * @v bp Driver state ! 823: */ ! 824: static void b44_tx_complete(struct b44_private *bp) ! 825: { ! 826: u32 cur, i; ! 827: ! 828: cur = pending_tx_index(bp); ! 829: ! 830: for (i = bp->tx_dirty; i != cur; i = ring_next(i)) { ! 831: /* Free finished frame */ ! 832: netdev_tx_complete(bp->netdev, bp->tx_iobuf[i]); ! 833: bp->tx_iobuf[i] = NULL; ! 834: ! 835: /* Clear TX descriptor */ ! 836: bp->tx[i].ctrl = 0; ! 837: bp->tx[i].addr = 0; ! 838: } ! 839: bp->tx_dirty = cur; ! 840: } ! 841: ! 842: ! 843: static void b44_process_rx_packets(struct b44_private *bp) ! 844: { ! 845: struct io_buffer *iob; /* received data */ ! 846: struct rx_header *rh; ! 847: u32 pending, i; ! 848: u16 len; ! 849: ! 850: pending = pending_rx_index(bp); ! 851: ! 852: for (i = bp->rx_cur; i != pending; i = ring_next(i)) { ! 853: iob = bp->rx_iobuf[i]; ! 854: if (iob == NULL) ! 855: break; ! 856: ! 857: rh = iob->data; ! 858: len = le16_to_cpu(rh->len); ! 859: ! 860: /* ! 861: * Guard against incompletely written RX descriptors. ! 862: * Without this, things can get really slow! ! 863: */ ! 864: if (len == 0) ! 865: break; ! 866: ! 867: /* Discard CRC that is generated by the card */ ! 868: len -= 4; ! 869: ! 870: /* Check for invalid packets and errors */ ! 871: if (len > RX_PKT_BUF_SZ - RX_PKT_OFFSET || ! 872: (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) { ! 873: DBG("rx error len=%d flags=%04x\n", len, ! 874: cpu_to_le16(rh->flags)); ! 875: rh->len = 0; ! 876: rh->flags = 0; ! 877: netdev_rx_err(bp->netdev, iob, -EINVAL); ! 878: continue; ! 879: } ! 880: ! 881: /* Clear RX descriptor */ ! 882: rh->len = 0; ! 883: rh->flags = 0; ! 884: bp->rx_iobuf[i] = NULL; ! 885: ! 886: /* Hand off the IO buffer to the network stack */ ! 887: iob_reserve(iob, RX_PKT_OFFSET); ! 888: iob_put(iob, len); ! 889: netdev_rx(bp->netdev, iob); ! 890: } ! 891: bp->rx_cur = i; ! 892: b44_rx_refill(bp, pending_rx_index(bp)); ! 893: } ! 894: ! 895: ! 896: /** Poll for completed and received packets ! 897: * ! 898: * @v netdev Network device ! 899: */ ! 900: static void b44_poll(struct net_device *netdev) ! 901: { ! 902: struct b44_private *bp = netdev_priv(netdev); ! 903: u32 istat; ! 904: ! 905: /* Interrupt status */ ! 906: istat = br32(bp, B44_ISTAT); ! 907: istat &= IMASK_DEF; /* only the events we care about */ ! 908: ! 909: if (!istat) ! 910: return; ! 911: if (istat & ISTAT_TX) ! 912: b44_tx_complete(bp); ! 913: if (istat & ISTAT_RX) ! 914: b44_process_rx_packets(bp); ! 915: if (istat & ISTAT_ERRORS) { ! 916: DBG("b44 error istat=0x%08x\n", istat); ! 917: ! 918: /* Reset B44 core partially to avoid long waits */ ! 919: b44_irq(bp->netdev, 0); ! 920: b44_halt(bp); ! 921: b44_init_tx_ring(bp); ! 922: b44_init_rx_ring(bp); ! 923: b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY); ! 924: } ! 925: ! 926: /* Acknowledge interrupt */ ! 927: bw32(bp, B44_ISTAT, 0); ! 928: bflush(bp, B44_ISTAT, 1); ! 929: } ! 930: ! 931: ! 932: static struct net_device_operations b44_operations = { ! 933: .open = b44_open, ! 934: .close = b44_close, ! 935: .transmit = b44_transmit, ! 936: .poll = b44_poll, ! 937: .irq = b44_irq, ! 938: }; ! 939: ! 940: ! 941: static struct pci_device_id b44_nics[] = { ! 942: PCI_ROM(0x14e4, 0x4401, "BCM4401", "BCM4401", 0), ! 943: PCI_ROM(0x14e4, 0x170c, "BCM4401-B0", "BCM4401-B0", 0), ! 944: PCI_ROM(0x14e4, 0x4402, "BCM4401-B1", "BCM4401-B1", 0), ! 945: }; ! 946: ! 947: ! 948: struct pci_driver b44_driver __pci_driver = { ! 949: .ids = b44_nics, ! 950: .id_count = sizeof b44_nics / sizeof b44_nics[0], ! 951: .probe = b44_probe, ! 952: .remove = b44_remove, ! 953: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.