|
|
1.1 ! root 1: /************************************************************************** ! 2: * ! 3: * sundance.c -- Etherboot device driver for the Sundance ST201 "Alta". ! 4: * Written 2002-2002 by Timothy Legge <[email protected]> ! 5: * ! 6: * This program is free software; you can redistribute it and/or modify ! 7: * it under the terms of the GNU General Public License as published by ! 8: * the Free Software Foundation; either version 2 of the License, or ! 9: * (at your option) any later version. ! 10: * ! 11: * This program is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: * GNU General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU General Public License ! 17: * along with this program; if not, write to the Free Software ! 18: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 19: * ! 20: * Portions of this code based on: ! 21: * sundance.c: A Linux device driver for the Sundance ST201 "Alta" ! 22: * Written 1999-2002 by Donald Becker ! 23: * ! 24: * tulip.c: Tulip and Clone Etherboot Driver ! 25: * By Marty Conner ! 26: * Copyright (C) 2001 Entity Cyber, Inc. ! 27: * ! 28: * Linux Driver Version LK1.09a, 10-Jul-2003 (2.4.25) ! 29: * ! 30: * REVISION HISTORY: ! 31: * ================ ! 32: * v1.1 01-01-2003 timlegge Initial implementation ! 33: * v1.7 04-10-2003 timlegge Transfers Linux Kernel (30 sec) ! 34: * v1.8 04-13-2003 timlegge Fix multiple transmission bug ! 35: * v1.9 08-19-2003 timlegge Support Multicast ! 36: * v1.10 01-17-2004 timlegge Initial driver output cleanup ! 37: * v1.11 03-21-2004 timlegge Remove unused variables ! 38: * v1.12 03-21-2004 timlegge Remove excess MII defines ! 39: * v1.13 03-24-2004 timlegge Update to Linux 2.4.25 driver ! 40: * ! 41: ****************************************************************************/ ! 42: ! 43: FILE_LICENCE ( GPL2_OR_LATER ); ! 44: ! 45: /* to get some global routines like printf */ ! 46: #include "etherboot.h" ! 47: /* to get the interface to the body of the program */ ! 48: #include "nic.h" ! 49: /* to get the PCI support functions, if this is a PCI NIC */ ! 50: #include <ipxe/pci.h> ! 51: #include "mii.h" ! 52: ! 53: #define drv_version "v1.12" ! 54: #define drv_date "2004-03-21" ! 55: ! 56: #define HZ 100 ! 57: ! 58: /* Condensed operations for readability. */ ! 59: #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) ! 60: #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) ! 61: ! 62: /* Set the mtu */ ! 63: static int mtu = 1514; ! 64: ! 65: /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). ! 66: The sundance uses a 64 element hash table based on the Ethernet CRC. */ ! 67: // static int multicast_filter_limit = 32; ! 68: ! 69: /* Set the copy breakpoint for the copy-only-tiny-frames scheme. ! 70: Setting to > 1518 effectively disables this feature. ! 71: This chip can receive into any byte alignment buffers, so word-oriented ! 72: archs do not need a copy-align of the IP header. */ ! 73: static int rx_copybreak = 0; ! 74: static int flowctrl = 1; ! 75: ! 76: /* Allow forcing the media type */ ! 77: /* media[] specifies the media type the NIC operates at. ! 78: autosense Autosensing active media. ! 79: 10mbps_hd 10Mbps half duplex. ! 80: 10mbps_fd 10Mbps full duplex. ! 81: 100mbps_hd 100Mbps half duplex. ! 82: 100mbps_fd 100Mbps full duplex. ! 83: */ ! 84: static char media[] = "autosense"; ! 85: ! 86: /* Operational parameters that are set at compile time. */ ! 87: ! 88: /* As Etherboot uses a Polling driver we can keep the number of rings ! 89: to the minimum number required. In general that is 1 transmit and 4 receive receive rings. However some cards require that ! 90: there be a minimum of 2 rings */ ! 91: #define TX_RING_SIZE 2 ! 92: #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ ! 93: #define RX_RING_SIZE 4 ! 94: ! 95: ! 96: /* Operational parameters that usually are not changed. */ ! 97: /* Time in jiffies before concluding the transmitter is hung. */ ! 98: #define TX_TIME_OUT (4*HZ) ! 99: #define PKT_BUF_SZ 1536 ! 100: ! 101: /* Offsets to the device registers. ! 102: Unlike software-only systems, device drivers interact with complex hardware. ! 103: It's not useful to define symbolic names for every register bit in the ! 104: device. The name can only partially document the semantics and make ! 105: the driver longer and more difficult to read. ! 106: In general, only the important configuration values or bits changed ! 107: multiple times should be defined symbolically. ! 108: */ ! 109: enum alta_offsets { ! 110: DMACtrl = 0x00, ! 111: TxListPtr = 0x04, ! 112: TxDMABurstThresh = 0x08, ! 113: TxDMAUrgentThresh = 0x09, ! 114: TxDMAPollPeriod = 0x0a, ! 115: RxDMAStatus = 0x0c, ! 116: RxListPtr = 0x10, ! 117: DebugCtrl0 = 0x1a, ! 118: DebugCtrl1 = 0x1c, ! 119: RxDMABurstThresh = 0x14, ! 120: RxDMAUrgentThresh = 0x15, ! 121: RxDMAPollPeriod = 0x16, ! 122: LEDCtrl = 0x1a, ! 123: ASICCtrl = 0x30, ! 124: EEData = 0x34, ! 125: EECtrl = 0x36, ! 126: TxStartThresh = 0x3c, ! 127: RxEarlyThresh = 0x3e, ! 128: FlashAddr = 0x40, ! 129: FlashData = 0x44, ! 130: TxStatus = 0x46, ! 131: TxFrameId = 0x47, ! 132: DownCounter = 0x18, ! 133: IntrClear = 0x4a, ! 134: IntrEnable = 0x4c, ! 135: IntrStatus = 0x4e, ! 136: MACCtrl0 = 0x50, ! 137: MACCtrl1 = 0x52, ! 138: StationAddr = 0x54, ! 139: MaxFrameSize = 0x5A, ! 140: RxMode = 0x5c, ! 141: MIICtrl = 0x5e, ! 142: MulticastFilter0 = 0x60, ! 143: MulticastFilter1 = 0x64, ! 144: RxOctetsLow = 0x68, ! 145: RxOctetsHigh = 0x6a, ! 146: TxOctetsLow = 0x6c, ! 147: TxOctetsHigh = 0x6e, ! 148: TxFramesOK = 0x70, ! 149: RxFramesOK = 0x72, ! 150: StatsCarrierError = 0x74, ! 151: StatsLateColl = 0x75, ! 152: StatsMultiColl = 0x76, ! 153: StatsOneColl = 0x77, ! 154: StatsTxDefer = 0x78, ! 155: RxMissed = 0x79, ! 156: StatsTxXSDefer = 0x7a, ! 157: StatsTxAbort = 0x7b, ! 158: StatsBcastTx = 0x7c, ! 159: StatsBcastRx = 0x7d, ! 160: StatsMcastTx = 0x7e, ! 161: StatsMcastRx = 0x7f, ! 162: /* Aliased and bogus values! */ ! 163: RxStatus = 0x0c, ! 164: }; ! 165: enum ASICCtrl_HiWord_bit { ! 166: GlobalReset = 0x0001, ! 167: RxReset = 0x0002, ! 168: TxReset = 0x0004, ! 169: DMAReset = 0x0008, ! 170: FIFOReset = 0x0010, ! 171: NetworkReset = 0x0020, ! 172: HostReset = 0x0040, ! 173: ResetBusy = 0x0400, ! 174: }; ! 175: ! 176: /* Bits in the interrupt status/mask registers. */ ! 177: enum intr_status_bits { ! 178: IntrSummary = 0x0001, IntrPCIErr = 0x0002, IntrMACCtrl = 0x0008, ! 179: IntrTxDone = 0x0004, IntrRxDone = 0x0010, IntrRxStart = 0x0020, ! 180: IntrDrvRqst = 0x0040, ! 181: StatsMax = 0x0080, LinkChange = 0x0100, ! 182: IntrTxDMADone = 0x0200, IntrRxDMADone = 0x0400, ! 183: }; ! 184: ! 185: /* Bits in the RxMode register. */ ! 186: enum rx_mode_bits { ! 187: AcceptAllIPMulti = 0x20, AcceptMultiHash = 0x10, AcceptAll = 0x08, ! 188: AcceptBroadcast = 0x04, AcceptMulticast = 0x02, AcceptMyPhys = ! 189: 0x01, ! 190: }; ! 191: /* Bits in MACCtrl. */ ! 192: enum mac_ctrl0_bits { ! 193: EnbFullDuplex = 0x20, EnbRcvLargeFrame = 0x40, ! 194: EnbFlowCtrl = 0x100, EnbPassRxCRC = 0x200, ! 195: }; ! 196: enum mac_ctrl1_bits { ! 197: StatsEnable = 0x0020, StatsDisable = 0x0040, StatsEnabled = 0x0080, ! 198: TxEnable = 0x0100, TxDisable = 0x0200, TxEnabled = 0x0400, ! 199: RxEnable = 0x0800, RxDisable = 0x1000, RxEnabled = 0x2000, ! 200: }; ! 201: ! 202: /* The Rx and Tx buffer descriptors. ! 203: Using only 32 bit fields simplifies software endian correction. ! 204: This structure must be aligned, and should avoid spanning cache lines. ! 205: */ ! 206: struct netdev_desc { ! 207: u32 next_desc; ! 208: u32 status; ! 209: u32 addr; ! 210: u32 length; ! 211: }; ! 212: ! 213: /* Bits in netdev_desc.status */ ! 214: enum desc_status_bits { ! 215: DescOwn = 0x8000, ! 216: DescEndPacket = 0x4000, ! 217: DescEndRing = 0x2000, ! 218: LastFrag = 0x80000000, ! 219: DescIntrOnTx = 0x8000, ! 220: DescIntrOnDMADone = 0x80000000, ! 221: DisableAlign = 0x00000001, ! 222: }; ! 223: ! 224: /********************************************** ! 225: * Descriptor Ring and Buffer defination ! 226: ***********************************************/ ! 227: /* Define the TX Descriptor */ ! 228: static struct netdev_desc tx_ring[TX_RING_SIZE]; ! 229: ! 230: /* Define the RX Descriptor */ ! 231: static struct netdev_desc rx_ring[RX_RING_SIZE]; ! 232: ! 233: /* Create a static buffer of size PKT_BUF_SZ for each RX and TX descriptor. ! 234: All descriptors point to a part of this buffer */ ! 235: struct { ! 236: unsigned char txb[PKT_BUF_SZ * TX_RING_SIZE]; ! 237: unsigned char rxb[RX_RING_SIZE * PKT_BUF_SZ]; ! 238: } rx_tx_buf __shared; ! 239: #define rxb rx_tx_buf.rxb ! 240: #define txb rx_tx_buf.txb ! 241: ! 242: /* FIXME: Move BASE to the private structure */ ! 243: static u32 BASE; ! 244: #define EEPROM_SIZE 128 ! 245: ! 246: enum pci_id_flags_bits { ! 247: PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4, ! 248: PCI_ADDR0 = 0 << 4, PCI_ADDR1 = 1 << 4, PCI_ADDR2 = ! 249: 2 << 4, PCI_ADDR3 = 3 << 4, ! 250: }; ! 251: ! 252: enum chip_capability_flags { CanHaveMII = 1, KendinPktDropBug = 2, }; ! 253: #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) ! 254: ! 255: #define MII_CNT 4 ! 256: static struct sundance_private { ! 257: const char *nic_name; ! 258: /* Frequently used values */ ! 259: ! 260: unsigned int cur_rx; /* Producer/consumer ring indicies */ ! 261: unsigned int mtu; ! 262: ! 263: /* These values keep track of the tranceiver/media in use */ ! 264: unsigned int flowctrl:1; ! 265: unsigned int an_enable:1; ! 266: ! 267: unsigned int speed; ! 268: ! 269: /* MII tranceiver section */ ! 270: struct mii_if_info mii_if; ! 271: int mii_preamble_required; ! 272: unsigned char phys[MII_CNT]; ! 273: unsigned char pci_rev_id; ! 274: } sdx; ! 275: ! 276: static struct sundance_private *sdc; ! 277: ! 278: /* Station Address location within the EEPROM */ ! 279: #define EEPROM_SA_OFFSET 0x10 ! 280: #define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \ ! 281: IntrDrvRqst | IntrTxDone | StatsMax | \ ! 282: LinkChange) ! 283: ! 284: static int eeprom_read(long ioaddr, int location); ! 285: static int mdio_read(struct nic *nic, int phy_id, unsigned int location); ! 286: static void mdio_write(struct nic *nic, int phy_id, unsigned int location, ! 287: int value); ! 288: static void set_rx_mode(struct nic *nic); ! 289: ! 290: static void check_duplex(struct nic *nic) ! 291: { ! 292: int mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA); ! 293: int negotiated = mii_lpa & sdc->mii_if.advertising; ! 294: int duplex; ! 295: ! 296: /* Force media */ ! 297: if (!sdc->an_enable || mii_lpa == 0xffff) { ! 298: if (sdc->mii_if.full_duplex) ! 299: outw(inw(BASE + MACCtrl0) | EnbFullDuplex, ! 300: BASE + MACCtrl0); ! 301: return; ! 302: } ! 303: ! 304: /* Autonegotiation */ ! 305: duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; ! 306: if (sdc->mii_if.full_duplex != duplex) { ! 307: sdc->mii_if.full_duplex = duplex; ! 308: DBG ("%s: Setting %s-duplex based on MII #%d " ! 309: "negotiated capability %4.4x.\n", sdc->nic_name, ! 310: duplex ? "full" : "half", sdc->phys[0], ! 311: negotiated ); ! 312: outw(inw(BASE + MACCtrl0) | duplex ? 0x20 : 0, ! 313: BASE + MACCtrl0); ! 314: } ! 315: } ! 316: ! 317: ! 318: /************************************************************************** ! 319: * init_ring - setup the tx and rx descriptors ! 320: *************************************************************************/ ! 321: static void init_ring(struct nic *nic __unused) ! 322: { ! 323: int i; ! 324: ! 325: sdc->cur_rx = 0; ! 326: ! 327: /* Initialize all the Rx descriptors */ ! 328: for (i = 0; i < RX_RING_SIZE; i++) { ! 329: rx_ring[i].next_desc = virt_to_le32desc(&rx_ring[i + 1]); ! 330: rx_ring[i].status = 0; ! 331: rx_ring[i].length = 0; ! 332: rx_ring[i].addr = 0; ! 333: } ! 334: ! 335: /* Mark the last entry as wrapping the ring */ ! 336: rx_ring[i - 1].next_desc = virt_to_le32desc(&rx_ring[0]); ! 337: ! 338: for (i = 0; i < RX_RING_SIZE; i++) { ! 339: rx_ring[i].addr = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]); ! 340: rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LastFrag); ! 341: } ! 342: ! 343: /* We only use one transmit buffer, but two ! 344: * descriptors so transmit engines have somewhere ! 345: * to point should they feel the need */ ! 346: tx_ring[0].status = 0x00000000; ! 347: tx_ring[0].addr = virt_to_bus(&txb[0]); ! 348: tx_ring[0].next_desc = 0; /* virt_to_bus(&tx_ring[1]); */ ! 349: ! 350: /* This descriptor is never used */ ! 351: tx_ring[1].status = 0x00000000; ! 352: tx_ring[1].addr = 0; /*virt_to_bus(&txb[0]); */ ! 353: tx_ring[1].next_desc = 0; ! 354: ! 355: /* Mark the last entry as wrapping the ring, ! 356: * though this should never happen */ ! 357: tx_ring[1].length = cpu_to_le32(LastFrag | PKT_BUF_SZ); ! 358: } ! 359: ! 360: /************************************************************************** ! 361: * RESET - Reset Adapter ! 362: * ***********************************************************************/ ! 363: static void sundance_reset(struct nic *nic) ! 364: { ! 365: int i; ! 366: ! 367: init_ring(nic); ! 368: ! 369: outl(virt_to_le32desc(&rx_ring[0]), BASE + RxListPtr); ! 370: /* The Tx List Pointer is written as packets are queued */ ! 371: ! 372: /* Initialize other registers. */ ! 373: /* __set_mac_addr(dev); */ ! 374: { ! 375: u16 addr16; ! 376: ! 377: addr16 = (nic->node_addr[0] | (nic->node_addr[1] << 8)); ! 378: outw(addr16, BASE + StationAddr); ! 379: addr16 = (nic->node_addr[2] | (nic->node_addr[3] << 8)); ! 380: outw(addr16, BASE + StationAddr + 2); ! 381: addr16 = (nic->node_addr[4] | (nic->node_addr[5] << 8)); ! 382: outw(addr16, BASE + StationAddr + 4); ! 383: } ! 384: ! 385: outw(sdc->mtu + 14, BASE + MaxFrameSize); ! 386: if (sdc->mtu > 2047) /* this will never happen with default options */ ! 387: outl(inl(BASE + ASICCtrl) | 0x0c, BASE + ASICCtrl); ! 388: ! 389: set_rx_mode(nic); ! 390: ! 391: outw(0, BASE + DownCounter); ! 392: /* Set the chip to poll every N*30nsec */ ! 393: outb(100, BASE + RxDMAPollPeriod); ! 394: ! 395: /* Fix DFE-580TX packet drop issue */ ! 396: if (sdc->pci_rev_id >= 0x14) ! 397: writeb(0x01, BASE + DebugCtrl1); ! 398: ! 399: outw(RxEnable | TxEnable, BASE + MACCtrl1); ! 400: ! 401: /* Construct a perfect filter frame with the mac address as first match ! 402: * and broadcast for all others */ ! 403: for (i = 0; i < 192; i++) ! 404: txb[i] = 0xFF; ! 405: ! 406: txb[0] = nic->node_addr[0]; ! 407: txb[1] = nic->node_addr[1]; ! 408: txb[2] = nic->node_addr[2]; ! 409: txb[3] = nic->node_addr[3]; ! 410: txb[4] = nic->node_addr[4]; ! 411: txb[5] = nic->node_addr[5]; ! 412: ! 413: DBG ( "%s: Done sundance_reset, status: Rx %hX Tx %hX " ! 414: "MAC Control %hX, %hX %hX\n", ! 415: sdc->nic_name, (int) inl(BASE + RxStatus), ! 416: (int) inw(BASE + TxStatus), (int) inl(BASE + MACCtrl0), ! 417: (int) inw(BASE + MACCtrl1), (int) inw(BASE + MACCtrl0) ); ! 418: } ! 419: ! 420: /************************************************************************** ! 421: IRQ - Wait for a frame ! 422: ***************************************************************************/ ! 423: static void sundance_irq ( struct nic *nic, irq_action_t action ) { ! 424: unsigned int intr_status; ! 425: ! 426: switch ( action ) { ! 427: case DISABLE : ! 428: case ENABLE : ! 429: intr_status = inw(nic->ioaddr + IntrStatus); ! 430: intr_status = intr_status & ~DEFAULT_INTR; ! 431: if ( action == ENABLE ) ! 432: intr_status = intr_status | DEFAULT_INTR; ! 433: outw(intr_status, nic->ioaddr + IntrEnable); ! 434: break; ! 435: case FORCE : ! 436: outw(0x0200, BASE + ASICCtrl); ! 437: break; ! 438: } ! 439: } ! 440: /************************************************************************** ! 441: POLL - Wait for a frame ! 442: ***************************************************************************/ ! 443: static int sundance_poll(struct nic *nic, int retreive) ! 444: { ! 445: /* return true if there's an ethernet packet ready to read */ ! 446: /* nic->packet should contain data on return */ ! 447: /* nic->packetlen should contain length of data */ ! 448: int entry = sdc->cur_rx % RX_RING_SIZE; ! 449: u32 frame_status = le32_to_cpu(rx_ring[entry].status); ! 450: int intr_status; ! 451: int pkt_len = 0; ! 452: ! 453: if (!(frame_status & DescOwn)) ! 454: return 0; ! 455: ! 456: /* There is a packet ready */ ! 457: if(!retreive) ! 458: return 1; ! 459: ! 460: intr_status = inw(nic->ioaddr + IntrStatus); ! 461: outw(intr_status, nic->ioaddr + IntrStatus); ! 462: ! 463: pkt_len = frame_status & 0x1fff; ! 464: ! 465: if (frame_status & 0x001f4000) { ! 466: DBG ( "Polling frame_status error\n" ); /* Do we really care about this */ ! 467: } else { ! 468: if (pkt_len < rx_copybreak) { ! 469: /* FIXME: What should happen Will this ever occur */ ! 470: printf("Poll Error: pkt_len < rx_copybreak"); ! 471: } else { ! 472: nic->packetlen = pkt_len; ! 473: memcpy(nic->packet, rxb + ! 474: (sdc->cur_rx * PKT_BUF_SZ), nic->packetlen); ! 475: ! 476: } ! 477: } ! 478: rx_ring[entry].length = cpu_to_le32(PKT_BUF_SZ | LastFrag); ! 479: rx_ring[entry].status = 0; ! 480: entry++; ! 481: sdc->cur_rx = entry % RX_RING_SIZE; ! 482: outw(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone), ! 483: nic->ioaddr + IntrStatus); ! 484: return 1; ! 485: } ! 486: ! 487: /************************************************************************** ! 488: TRANSMIT - Transmit a frame ! 489: ***************************************************************************/ ! 490: static void sundance_transmit(struct nic *nic, const char *d, /* Destination */ ! 491: unsigned int t, /* Type */ ! 492: unsigned int s, /* size */ ! 493: const char *p) ! 494: { /* Packet */ ! 495: u16 nstype; ! 496: u32 to; ! 497: ! 498: /* Disable the Tx */ ! 499: outw(TxDisable, BASE + MACCtrl1); ! 500: ! 501: memcpy(txb, d, ETH_ALEN); ! 502: memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN); ! 503: nstype = htons((u16) t); ! 504: memcpy(txb + 2 * ETH_ALEN, (u8 *) & nstype, 2); ! 505: memcpy(txb + ETH_HLEN, p, s); ! 506: ! 507: s += ETH_HLEN; ! 508: s &= 0x0FFF; ! 509: while (s < ETH_ZLEN) ! 510: txb[s++] = '\0'; ! 511: ! 512: /* Setup the transmit descriptor */ ! 513: tx_ring[0].length = cpu_to_le32(s | LastFrag); ! 514: tx_ring[0].status = cpu_to_le32(0x00000001); ! 515: ! 516: /* Point to transmit descriptor */ ! 517: outl(virt_to_le32desc(&tx_ring[0]), BASE + TxListPtr); ! 518: ! 519: /* Enable Tx */ ! 520: outw(TxEnable, BASE + MACCtrl1); ! 521: /* Trigger an immediate send */ ! 522: outw(0, BASE + TxStatus); ! 523: ! 524: to = currticks() + TX_TIME_OUT; ! 525: while (!(tx_ring[0].status & 0x00010000) && (currticks() < to)); /* wait */ ! 526: ! 527: if (currticks() >= to) { ! 528: printf("TX Time Out"); ! 529: } ! 530: /* Disable Tx */ ! 531: outw(TxDisable, BASE + MACCtrl1); ! 532: ! 533: } ! 534: ! 535: /************************************************************************** ! 536: DISABLE - Turn off ethernet interface ! 537: ***************************************************************************/ ! 538: static void sundance_disable ( struct nic *nic __unused ) { ! 539: /* put the card in its initial state */ ! 540: /* This function serves 3 purposes. ! 541: * This disables DMA and interrupts so we don't receive ! 542: * unexpected packets or interrupts from the card after ! 543: * etherboot has finished. ! 544: * This frees resources so etherboot may use ! 545: * this driver on another interface ! 546: * This allows etherboot to reinitialize the interface ! 547: * if something is something goes wrong. ! 548: */ ! 549: outw(0x0000, BASE + IntrEnable); ! 550: /* Stop the Chipchips Tx and Rx Status */ ! 551: outw(TxDisable | RxDisable | StatsDisable, BASE + MACCtrl1); ! 552: } ! 553: ! 554: static struct nic_operations sundance_operations = { ! 555: .connect = dummy_connect, ! 556: .poll = sundance_poll, ! 557: .transmit = sundance_transmit, ! 558: .irq = sundance_irq, ! 559: ! 560: }; ! 561: ! 562: /************************************************************************** ! 563: PROBE - Look for an adapter, this routine's visible to the outside ! 564: ***************************************************************************/ ! 565: static int sundance_probe ( struct nic *nic, struct pci_device *pci ) { ! 566: ! 567: u8 ee_data[EEPROM_SIZE]; ! 568: u16 mii_ctl; ! 569: int i; ! 570: int speed; ! 571: ! 572: if (pci->ioaddr == 0) ! 573: return 0; ! 574: ! 575: /* BASE is used throughout to address the card */ ! 576: BASE = pci->ioaddr; ! 577: printf(" sundance.c: Found %s Vendor=0x%hX Device=0x%hX\n", ! 578: pci->id->name, pci->vendor, pci->device); ! 579: ! 580: /* Get the MAC Address by reading the EEPROM */ ! 581: for (i = 0; i < 3; i++) { ! 582: ((u16 *) ee_data)[i] = ! 583: le16_to_cpu(eeprom_read(BASE, i + EEPROM_SA_OFFSET)); ! 584: } ! 585: /* Update the nic structure with the MAC Address */ ! 586: for (i = 0; i < ETH_ALEN; i++) { ! 587: nic->node_addr[i] = ee_data[i]; ! 588: } ! 589: ! 590: /* Set the card as PCI Bus Master */ ! 591: adjust_pci_device(pci); ! 592: ! 593: // sdc->mii_if.dev = pci; ! 594: // sdc->mii_if.phy_id_mask = 0x1f; ! 595: // sdc->mii_if.reg_num_mask = 0x1f; ! 596: ! 597: /* point to private storage */ ! 598: sdc = &sdx; ! 599: ! 600: sdc->nic_name = pci->id->name; ! 601: sdc->mtu = mtu; ! 602: ! 603: pci_read_config_byte(pci, PCI_REVISION_ID, &sdc->pci_rev_id); ! 604: ! 605: DBG ( "Device revision id: %hx\n", sdc->pci_rev_id ); ! 606: ! 607: /* Print out some hardware info */ ! 608: DBG ( "%s: %s at ioaddr %hX, ", ! 609: pci->id->name, nic->node_addr, (unsigned int) BASE); ! 610: ! 611: sdc->mii_preamble_required = 0; ! 612: if (1) { ! 613: int phy, phy_idx = 0; ! 614: sdc->phys[0] = 1; /* Default Setting */ ! 615: sdc->mii_preamble_required++; ! 616: for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { ! 617: int mii_status = mdio_read(nic, phy, MII_BMSR); ! 618: if (mii_status != 0xffff && mii_status != 0x0000) { ! 619: sdc->phys[phy_idx++] = phy; ! 620: sdc->mii_if.advertising = ! 621: mdio_read(nic, phy, MII_ADVERTISE); ! 622: if ((mii_status & 0x0040) == 0) ! 623: sdc->mii_preamble_required++; ! 624: DBG ! 625: ( "%s: MII PHY found at address %d, status " "%hX advertising %hX\n", sdc->nic_name, phy, mii_status, sdc->mii_if.advertising ); ! 626: } ! 627: } ! 628: sdc->mii_preamble_required--; ! 629: if (phy_idx == 0) ! 630: printf("%s: No MII transceiver found!\n", ! 631: sdc->nic_name); ! 632: sdc->mii_if.phy_id = sdc->phys[0]; ! 633: } ! 634: ! 635: /* Parse override configuration */ ! 636: sdc->an_enable = 1; ! 637: if (strcasecmp(media, "autosense") != 0) { ! 638: sdc->an_enable = 0; ! 639: if (strcasecmp(media, "100mbps_fd") == 0 || ! 640: strcasecmp(media, "4") == 0) { ! 641: sdc->speed = 100; ! 642: sdc->mii_if.full_duplex = 1; ! 643: } else if (strcasecmp(media, "100mbps_hd") == 0 ! 644: || strcasecmp(media, "3") == 0) { ! 645: sdc->speed = 100; ! 646: sdc->mii_if.full_duplex = 0; ! 647: } else if (strcasecmp(media, "10mbps_fd") == 0 || ! 648: strcasecmp(media, "2") == 0) { ! 649: sdc->speed = 10; ! 650: sdc->mii_if.full_duplex = 1; ! 651: } else if (strcasecmp(media, "10mbps_hd") == 0 || ! 652: strcasecmp(media, "1") == 0) { ! 653: sdc->speed = 10; ! 654: sdc->mii_if.full_duplex = 0; ! 655: } else { ! 656: sdc->an_enable = 1; ! 657: } ! 658: } ! 659: if (flowctrl == 1) ! 660: sdc->flowctrl = 1; ! 661: ! 662: /* Fibre PHY? */ ! 663: if (inl(BASE + ASICCtrl) & 0x80) { ! 664: /* Default 100Mbps Full */ ! 665: if (sdc->an_enable) { ! 666: sdc->speed = 100; ! 667: sdc->mii_if.full_duplex = 1; ! 668: sdc->an_enable = 0; ! 669: } ! 670: } ! 671: ! 672: /* The Linux driver uses flow control and resets the link here. This means the ! 673: mii section from above would need to be re done I believe. Since it serves ! 674: no real purpose leave it out. */ ! 675: ! 676: /* Force media type */ ! 677: if (!sdc->an_enable) { ! 678: mii_ctl = 0; ! 679: mii_ctl |= (sdc->speed == 100) ? BMCR_SPEED100 : 0; ! 680: mii_ctl |= (sdc->mii_if.full_duplex) ? BMCR_FULLDPLX : 0; ! 681: mdio_write(nic, sdc->phys[0], MII_BMCR, mii_ctl); ! 682: printf("Override speed=%d, %s duplex\n", ! 683: sdc->speed, ! 684: sdc->mii_if.full_duplex ? "Full" : "Half"); ! 685: } ! 686: ! 687: /* Reset the chip to erase previous misconfiguration */ ! 688: DBG ( "ASIC Control is %#x\n", inl(BASE + ASICCtrl) ); ! 689: outw(0x007f, BASE + ASICCtrl + 2); ! 690: ! 691: /* ! 692: * wait for reset to complete ! 693: * this is heavily inspired by the linux sundance driver ! 694: * according to the linux driver it can take up to 1ms for the reset ! 695: * to complete ! 696: */ ! 697: i = 0; ! 698: while(inl(BASE + ASICCtrl) & (ResetBusy << 16)) { ! 699: if(i++ >= 10) { ! 700: DBG("sundance: NIC reset did not complete.\n"); ! 701: break; ! 702: } ! 703: udelay(100); ! 704: } ! 705: ! 706: DBG ( "ASIC Control is now %#x.\n", inl(BASE + ASICCtrl) ); ! 707: ! 708: sundance_reset(nic); ! 709: if (sdc->an_enable) { ! 710: u16 mii_advertise, mii_lpa; ! 711: mii_advertise = ! 712: mdio_read(nic, sdc->phys[0], MII_ADVERTISE); ! 713: mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA); ! 714: mii_advertise &= mii_lpa; ! 715: if (mii_advertise & ADVERTISE_100FULL) ! 716: sdc->speed = 100; ! 717: else if (mii_advertise & ADVERTISE_100HALF) ! 718: sdc->speed = 100; ! 719: else if (mii_advertise & ADVERTISE_10FULL) ! 720: sdc->speed = 10; ! 721: else if (mii_advertise & ADVERTISE_10HALF) ! 722: sdc->speed = 10; ! 723: } else { ! 724: mii_ctl = mdio_read(nic, sdc->phys[0], MII_BMCR); ! 725: speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; ! 726: sdc->speed = speed; ! 727: printf("%s: Link changed: %dMbps ,", sdc->nic_name, speed); ! 728: printf("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ? ! 729: "full" : "half"); ! 730: } ! 731: check_duplex(nic); ! 732: if (sdc->flowctrl && sdc->mii_if.full_duplex) { ! 733: outw(inw(BASE + MulticastFilter1 + 2) | 0x0200, ! 734: BASE + MulticastFilter1 + 2); ! 735: outw(inw(BASE + MACCtrl0) | EnbFlowCtrl, BASE + MACCtrl0); ! 736: } ! 737: printf("%dMbps, %s-Duplex\n", sdc->speed, ! 738: sdc->mii_if.full_duplex ? "Full" : "Half"); ! 739: ! 740: /* point to NIC specific routines */ ! 741: nic->nic_op = &sundance_operations; ! 742: ! 743: nic->irqno = pci->irq; ! 744: nic->ioaddr = BASE; ! 745: ! 746: return 1; ! 747: } ! 748: ! 749: ! 750: /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */ ! 751: static int eeprom_read(long ioaddr, int location) ! 752: { ! 753: int boguscnt = 10000; /* Typical 1900 ticks */ ! 754: outw(0x0200 | (location & 0xff), ioaddr + EECtrl); ! 755: do { ! 756: if (!(inw(ioaddr + EECtrl) & 0x8000)) { ! 757: return inw(ioaddr + EEData); ! 758: } ! 759: } ! 760: while (--boguscnt > 0); ! 761: return 0; ! 762: } ! 763: ! 764: /* MII transceiver control section. ! 765: Read and write the MII registers using software-generated serial ! 766: MDIO protocol. See the MII specifications or DP83840A data sheet ! 767: for details. ! 768: ! 769: The maximum data clock rate is 2.5 Mhz. ! 770: The timing is decoupled from the processor clock by flushing the write ! 771: from the CPU write buffer with a following read, and using PCI ! 772: transaction time. */ ! 773: ! 774: #define mdio_in(mdio_addr) inb(mdio_addr) ! 775: #define mdio_out(value, mdio_addr) outb(value, mdio_addr) ! 776: #define mdio_delay(mdio_addr) inb(mdio_addr) ! 777: ! 778: enum mii_reg_bits { ! 779: MDIO_ShiftClk = 0x0001, MDIO_Data = 0x0002, MDIO_EnbOutput = ! 780: 0x0004, ! 781: }; ! 782: #define MDIO_EnbIn (0) ! 783: #define MDIO_WRITE0 (MDIO_EnbOutput) ! 784: #define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput) ! 785: ! 786: /* Generate the preamble required for initial synchronization and ! 787: a few older transceivers. */ ! 788: static void mdio_sync(long mdio_addr) ! 789: { ! 790: int bits = 32; ! 791: ! 792: /* Establish sync by sending at least 32 logic ones. */ ! 793: while (--bits >= 0) { ! 794: mdio_out(MDIO_WRITE1, mdio_addr); ! 795: mdio_delay(mdio_addr); ! 796: mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); ! 797: mdio_delay(mdio_addr); ! 798: } ! 799: } ! 800: ! 801: static int ! 802: mdio_read(struct nic *nic __unused, int phy_id, unsigned int location) ! 803: { ! 804: long mdio_addr = BASE + MIICtrl; ! 805: int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; ! 806: int i, retval = 0; ! 807: ! 808: if (sdc->mii_preamble_required) ! 809: mdio_sync(mdio_addr); ! 810: ! 811: /* Shift the read command bits out. */ ! 812: for (i = 15; i >= 0; i--) { ! 813: int dataval = ! 814: (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; ! 815: ! 816: mdio_out(dataval, mdio_addr); ! 817: mdio_delay(mdio_addr); ! 818: mdio_out(dataval | MDIO_ShiftClk, mdio_addr); ! 819: mdio_delay(mdio_addr); ! 820: } ! 821: /* Read the two transition, 16 data, and wire-idle bits. */ ! 822: for (i = 19; i > 0; i--) { ! 823: mdio_out(MDIO_EnbIn, mdio_addr); ! 824: mdio_delay(mdio_addr); ! 825: retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data) ! 826: ? 1 : 0); ! 827: mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); ! 828: mdio_delay(mdio_addr); ! 829: } ! 830: return (retval >> 1) & 0xffff; ! 831: } ! 832: ! 833: static void ! 834: mdio_write(struct nic *nic __unused, int phy_id, ! 835: unsigned int location, int value) ! 836: { ! 837: long mdio_addr = BASE + MIICtrl; ! 838: int mii_cmd = ! 839: (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; ! 840: int i; ! 841: ! 842: if (sdc->mii_preamble_required) ! 843: mdio_sync(mdio_addr); ! 844: ! 845: /* Shift the command bits out. */ ! 846: for (i = 31; i >= 0; i--) { ! 847: int dataval = ! 848: (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; ! 849: mdio_out(dataval, mdio_addr); ! 850: mdio_delay(mdio_addr); ! 851: mdio_out(dataval | MDIO_ShiftClk, mdio_addr); ! 852: mdio_delay(mdio_addr); ! 853: } ! 854: /* Clear out extra bits. */ ! 855: for (i = 2; i > 0; i--) { ! 856: mdio_out(MDIO_EnbIn, mdio_addr); ! 857: mdio_delay(mdio_addr); ! 858: mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); ! 859: mdio_delay(mdio_addr); ! 860: } ! 861: return; ! 862: } ! 863: ! 864: static void set_rx_mode(struct nic *nic __unused) ! 865: { ! 866: int i; ! 867: u16 mc_filter[4]; /* Multicast hash filter */ ! 868: u32 rx_mode; ! 869: ! 870: memset(mc_filter, 0xff, sizeof(mc_filter)); ! 871: rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; ! 872: ! 873: if (sdc->mii_if.full_duplex && sdc->flowctrl) ! 874: mc_filter[3] |= 0x0200; ! 875: for (i = 0; i < 4; i++) ! 876: outw(mc_filter[i], BASE + MulticastFilter0 + i * 2); ! 877: outb(rx_mode, BASE + RxMode); ! 878: return; ! 879: } ! 880: ! 881: static struct pci_device_id sundance_nics[] = { ! 882: PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor", 0), ! 883: PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)", 0), ! 884: PCI_ROM(0x13f0, 0x0200, "ip100a", "IC+ IP100A", 0), ! 885: }; ! 886: ! 887: PCI_DRIVER ( sundance_driver, sundance_nics, PCI_NO_CLASS ); ! 888: ! 889: DRIVER ( "SUNDANCE/PCI", nic_driver, pci_driver, sundance_driver, ! 890: sundance_probe, sundance_disable ); ! 891: ! 892: /* ! 893: * Local variables: ! 894: * c-basic-offset: 8 ! 895: * c-indent-level: 8 ! 896: * tab-width: 8 ! 897: * End: ! 898: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.