00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 FILE_LICENCE ( GPL2_OR_LATER );
00044
00045
00046 #include "etherboot.h"
00047
00048 #include "nic.h"
00049
00050 #include <gpxe/pci.h>
00051 #include "mii.h"
00052
00053 #define drv_version "v1.12"
00054 #define drv_date "2004-03-21"
00055
00056 #define HZ 100
00057
00058
00059 #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
00060 #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
00061
00062
00063 static int mtu = 1514;
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 static int rx_copybreak = 0;
00074 static int flowctrl = 1;
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 static char media[] = "autosense";
00085
00086
00087
00088
00089
00090
00091 #define TX_RING_SIZE 2
00092 #define TX_QUEUE_LEN 10
00093 #define RX_RING_SIZE 4
00094
00095
00096
00097
00098 #define TX_TIME_OUT (4*HZ)
00099 #define PKT_BUF_SZ 1536
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 enum alta_offsets {
00110 DMACtrl = 0x00,
00111 TxListPtr = 0x04,
00112 TxDMABurstThresh = 0x08,
00113 TxDMAUrgentThresh = 0x09,
00114 TxDMAPollPeriod = 0x0a,
00115 RxDMAStatus = 0x0c,
00116 RxListPtr = 0x10,
00117 DebugCtrl0 = 0x1a,
00118 DebugCtrl1 = 0x1c,
00119 RxDMABurstThresh = 0x14,
00120 RxDMAUrgentThresh = 0x15,
00121 RxDMAPollPeriod = 0x16,
00122 LEDCtrl = 0x1a,
00123 ASICCtrl = 0x30,
00124 EEData = 0x34,
00125 EECtrl = 0x36,
00126 TxStartThresh = 0x3c,
00127 RxEarlyThresh = 0x3e,
00128 FlashAddr = 0x40,
00129 FlashData = 0x44,
00130 TxStatus = 0x46,
00131 TxFrameId = 0x47,
00132 DownCounter = 0x18,
00133 IntrClear = 0x4a,
00134 IntrEnable = 0x4c,
00135 IntrStatus = 0x4e,
00136 MACCtrl0 = 0x50,
00137 MACCtrl1 = 0x52,
00138 StationAddr = 0x54,
00139 MaxFrameSize = 0x5A,
00140 RxMode = 0x5c,
00141 MIICtrl = 0x5e,
00142 MulticastFilter0 = 0x60,
00143 MulticastFilter1 = 0x64,
00144 RxOctetsLow = 0x68,
00145 RxOctetsHigh = 0x6a,
00146 TxOctetsLow = 0x6c,
00147 TxOctetsHigh = 0x6e,
00148 TxFramesOK = 0x70,
00149 RxFramesOK = 0x72,
00150 StatsCarrierError = 0x74,
00151 StatsLateColl = 0x75,
00152 StatsMultiColl = 0x76,
00153 StatsOneColl = 0x77,
00154 StatsTxDefer = 0x78,
00155 RxMissed = 0x79,
00156 StatsTxXSDefer = 0x7a,
00157 StatsTxAbort = 0x7b,
00158 StatsBcastTx = 0x7c,
00159 StatsBcastRx = 0x7d,
00160 StatsMcastTx = 0x7e,
00161 StatsMcastRx = 0x7f,
00162
00163 RxStatus = 0x0c,
00164 };
00165 enum ASICCtrl_HiWord_bit {
00166 GlobalReset = 0x0001,
00167 RxReset = 0x0002,
00168 TxReset = 0x0004,
00169 DMAReset = 0x0008,
00170 FIFOReset = 0x0010,
00171 NetworkReset = 0x0020,
00172 HostReset = 0x0040,
00173 ResetBusy = 0x0400,
00174 };
00175
00176
00177 enum intr_status_bits {
00178 IntrSummary = 0x0001, IntrPCIErr = 0x0002, IntrMACCtrl = 0x0008,
00179 IntrTxDone = 0x0004, IntrRxDone = 0x0010, IntrRxStart = 0x0020,
00180 IntrDrvRqst = 0x0040,
00181 StatsMax = 0x0080, LinkChange = 0x0100,
00182 IntrTxDMADone = 0x0200, IntrRxDMADone = 0x0400,
00183 };
00184
00185
00186 enum rx_mode_bits {
00187 AcceptAllIPMulti = 0x20, AcceptMultiHash = 0x10, AcceptAll = 0x08,
00188 AcceptBroadcast = 0x04, AcceptMulticast = 0x02, AcceptMyPhys =
00189 0x01,
00190 };
00191
00192 enum mac_ctrl0_bits {
00193 EnbFullDuplex = 0x20, EnbRcvLargeFrame = 0x40,
00194 EnbFlowCtrl = 0x100, EnbPassRxCRC = 0x200,
00195 };
00196 enum mac_ctrl1_bits {
00197 StatsEnable = 0x0020, StatsDisable = 0x0040, StatsEnabled = 0x0080,
00198 TxEnable = 0x0100, TxDisable = 0x0200, TxEnabled = 0x0400,
00199 RxEnable = 0x0800, RxDisable = 0x1000, RxEnabled = 0x2000,
00200 };
00201
00202
00203
00204
00205
00206 struct netdev_desc {
00207 u32 next_desc;
00208 u32 status;
00209 u32 addr;
00210 u32 length;
00211 };
00212
00213
00214 enum desc_status_bits {
00215 DescOwn = 0x8000,
00216 DescEndPacket = 0x4000,
00217 DescEndRing = 0x2000,
00218 LastFrag = 0x80000000,
00219 DescIntrOnTx = 0x8000,
00220 DescIntrOnDMADone = 0x80000000,
00221 DisableAlign = 0x00000001,
00222 };
00223
00224
00225
00226
00227
00228 static struct netdev_desc tx_ring[TX_RING_SIZE];
00229
00230
00231 static struct netdev_desc rx_ring[RX_RING_SIZE];
00232
00233
00234
00235 struct {
00236 unsigned char txb[PKT_BUF_SZ * TX_RING_SIZE];
00237 unsigned char rxb[RX_RING_SIZE * PKT_BUF_SZ];
00238 } rx_tx_buf __shared;
00239 #define rxb rx_tx_buf.rxb
00240 #define txb rx_tx_buf.txb
00241
00242
00243 static u32 BASE;
00244 #define EEPROM_SIZE 128
00245
00246 enum pci_id_flags_bits {
00247 PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4,
00248 PCI_ADDR0 = 0 << 4, PCI_ADDR1 = 1 << 4, PCI_ADDR2 =
00249 2 << 4, PCI_ADDR3 = 3 << 4,
00250 };
00251
00252 enum chip_capability_flags { CanHaveMII = 1, KendinPktDropBug = 2, };
00253 #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
00254
00255 #define MII_CNT 4
00256 static struct sundance_private {
00257 const char *nic_name;
00258
00259
00260 unsigned int cur_rx;
00261 unsigned int mtu;
00262
00263
00264 unsigned int flowctrl:1;
00265 unsigned int an_enable:1;
00266
00267 unsigned int speed;
00268
00269
00270 struct mii_if_info mii_if;
00271 int mii_preamble_required;
00272 unsigned char phys[MII_CNT];
00273 unsigned char pci_rev_id;
00274 } sdx;
00275
00276 static struct sundance_private *sdc;
00277
00278
00279 #define EEPROM_SA_OFFSET 0x10
00280 #define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \
00281 IntrDrvRqst | IntrTxDone | StatsMax | \
00282 LinkChange)
00283
00284 static int eeprom_read(long ioaddr, int location);
00285 static int mdio_read(struct nic *nic, int phy_id, unsigned int location);
00286 static void mdio_write(struct nic *nic, int phy_id, unsigned int location,
00287 int value);
00288 static void set_rx_mode(struct nic *nic);
00289
00290 static void check_duplex(struct nic *nic)
00291 {
00292 int mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA);
00293 int negotiated = mii_lpa & sdc->mii_if.advertising;
00294 int duplex;
00295
00296
00297 if (!sdc->an_enable || mii_lpa == 0xffff) {
00298 if (sdc->mii_if.full_duplex)
00299 outw(inw(BASE + MACCtrl0) | EnbFullDuplex,
00300 BASE + MACCtrl0);
00301 return;
00302 }
00303
00304
00305 duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
00306 if (sdc->mii_if.full_duplex != duplex) {
00307 sdc->mii_if.full_duplex = duplex;
00308 DBG ("%s: Setting %s-duplex based on MII #%d "
00309 "negotiated capability %4.4x.\n", sdc->nic_name,
00310 duplex ? "full" : "half", sdc->phys[0],
00311 negotiated );
00312 outw(inw(BASE + MACCtrl0) | duplex ? 0x20 : 0,
00313 BASE + MACCtrl0);
00314 }
00315 }
00316
00317
00318
00319
00320
00321 static void init_ring(struct nic *nic __unused)
00322 {
00323 int i;
00324
00325 sdc->cur_rx = 0;
00326
00327
00328 for (i = 0; i < RX_RING_SIZE; i++) {
00329 rx_ring[i].next_desc = virt_to_le32desc(&rx_ring[i + 1]);
00330 rx_ring[i].status = 0;
00331 rx_ring[i].length = 0;
00332 rx_ring[i].addr = 0;
00333 }
00334
00335
00336 rx_ring[i - 1].next_desc = virt_to_le32desc(&rx_ring[0]);
00337
00338 for (i = 0; i < RX_RING_SIZE; i++) {
00339 rx_ring[i].addr = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]);
00340 rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LastFrag);
00341 }
00342
00343
00344
00345
00346 tx_ring[0].status = 0x00000000;
00347 tx_ring[0].addr = virt_to_bus(&txb[0]);
00348 tx_ring[0].next_desc = 0;
00349
00350
00351 tx_ring[1].status = 0x00000000;
00352 tx_ring[1].addr = 0;
00353 tx_ring[1].next_desc = 0;
00354
00355
00356
00357 tx_ring[1].length = cpu_to_le32(LastFrag | PKT_BUF_SZ);
00358 }
00359
00360
00361
00362
00363 static void sundance_reset(struct nic *nic)
00364 {
00365 int i;
00366
00367 init_ring(nic);
00368
00369 outl(virt_to_le32desc(&rx_ring[0]), BASE + RxListPtr);
00370
00371
00372
00373
00374 {
00375 u16 addr16;
00376
00377 addr16 = (nic->node_addr[0] | (nic->node_addr[1] << 8));
00378 outw(addr16, BASE + StationAddr);
00379 addr16 = (nic->node_addr[2] | (nic->node_addr[3] << 8));
00380 outw(addr16, BASE + StationAddr + 2);
00381 addr16 = (nic->node_addr[4] | (nic->node_addr[5] << 8));
00382 outw(addr16, BASE + StationAddr + 4);
00383 }
00384
00385 outw(sdc->mtu + 14, BASE + MaxFrameSize);
00386 if (sdc->mtu > 2047)
00387 outl(inl(BASE + ASICCtrl) | 0x0c, BASE + ASICCtrl);
00388
00389 set_rx_mode(nic);
00390
00391 outw(0, BASE + DownCounter);
00392
00393 outb(100, BASE + RxDMAPollPeriod);
00394
00395
00396 if (sdc->pci_rev_id >= 0x14)
00397 writeb(0x01, BASE + DebugCtrl1);
00398
00399 outw(RxEnable | TxEnable, BASE + MACCtrl1);
00400
00401
00402
00403 for (i = 0; i < 192; i++)
00404 txb[i] = 0xFF;
00405
00406 txb[0] = nic->node_addr[0];
00407 txb[1] = nic->node_addr[1];
00408 txb[2] = nic->node_addr[2];
00409 txb[3] = nic->node_addr[3];
00410 txb[4] = nic->node_addr[4];
00411 txb[5] = nic->node_addr[5];
00412
00413 DBG ( "%s: Done sundance_reset, status: Rx %hX Tx %hX "
00414 "MAC Control %hX, %hX %hX\n",
00415 sdc->nic_name, (int) inl(BASE + RxStatus),
00416 (int) inw(BASE + TxStatus), (int) inl(BASE + MACCtrl0),
00417 (int) inw(BASE + MACCtrl1), (int) inw(BASE + MACCtrl0) );
00418 }
00419
00420
00421
00422
00423 static void sundance_irq ( struct nic *nic, irq_action_t action ) {
00424 unsigned int intr_status;
00425
00426 switch ( action ) {
00427 case DISABLE :
00428 case ENABLE :
00429 intr_status = inw(nic->ioaddr + IntrStatus);
00430 intr_status = intr_status & ~DEFAULT_INTR;
00431 if ( action == ENABLE )
00432 intr_status = intr_status | DEFAULT_INTR;
00433 outw(intr_status, nic->ioaddr + IntrEnable);
00434 break;
00435 case FORCE :
00436 outw(0x0200, BASE + ASICCtrl);
00437 break;
00438 }
00439 }
00440
00441
00442
00443 static int sundance_poll(struct nic *nic, int retreive)
00444 {
00445
00446
00447
00448 int entry = sdc->cur_rx % RX_RING_SIZE;
00449 u32 frame_status = le32_to_cpu(rx_ring[entry].status);
00450 int intr_status;
00451 int pkt_len = 0;
00452
00453 if (!(frame_status & DescOwn))
00454 return 0;
00455
00456
00457 if(!retreive)
00458 return 1;
00459
00460 intr_status = inw(nic->ioaddr + IntrStatus);
00461 outw(intr_status, nic->ioaddr + IntrStatus);
00462
00463 pkt_len = frame_status & 0x1fff;
00464
00465 if (frame_status & 0x001f4000) {
00466 DBG ( "Polling frame_status error\n" );
00467 } else {
00468 if (pkt_len < rx_copybreak) {
00469
00470 printf("Poll Error: pkt_len < rx_copybreak");
00471 } else {
00472 nic->packetlen = pkt_len;
00473 memcpy(nic->packet, rxb +
00474 (sdc->cur_rx * PKT_BUF_SZ), nic->packetlen);
00475
00476 }
00477 }
00478 rx_ring[entry].length = cpu_to_le32(PKT_BUF_SZ | LastFrag);
00479 rx_ring[entry].status = 0;
00480 entry++;
00481 sdc->cur_rx = entry % RX_RING_SIZE;
00482 outw(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone),
00483 nic->ioaddr + IntrStatus);
00484 return 1;
00485 }
00486
00487
00488
00489
00490 static void sundance_transmit(struct nic *nic, const char *d,
00491 unsigned int t,
00492 unsigned int s,
00493 const char *p)
00494 {
00495 u16 nstype;
00496 u32 to;
00497
00498
00499 outw(TxDisable, BASE + MACCtrl1);
00500
00501 memcpy(txb, d, ETH_ALEN);
00502 memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
00503 nstype = htons((u16) t);
00504 memcpy(txb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
00505 memcpy(txb + ETH_HLEN, p, s);
00506
00507 s += ETH_HLEN;
00508 s &= 0x0FFF;
00509 while (s < ETH_ZLEN)
00510 txb[s++] = '\0';
00511
00512
00513 tx_ring[0].length = cpu_to_le32(s | LastFrag);
00514 tx_ring[0].status = cpu_to_le32(0x00000001);
00515
00516
00517 outl(virt_to_le32desc(&tx_ring[0]), BASE + TxListPtr);
00518
00519
00520 outw(TxEnable, BASE + MACCtrl1);
00521
00522 outw(0, BASE + TxStatus);
00523
00524 to = currticks() + TX_TIME_OUT;
00525 while (!(tx_ring[0].status & 0x00010000) && (currticks() < to));
00526
00527 if (currticks() >= to) {
00528 printf("TX Time Out");
00529 }
00530
00531 outw(TxDisable, BASE + MACCtrl1);
00532
00533 }
00534
00535
00536
00537
00538 static void sundance_disable ( struct nic *nic __unused ) {
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549 outw(0x0000, BASE + IntrEnable);
00550
00551 outw(TxDisable | RxDisable | StatsDisable, BASE + MACCtrl1);
00552 }
00553
00554 static struct nic_operations sundance_operations = {
00555 .connect = dummy_connect,
00556 .poll = sundance_poll,
00557 .transmit = sundance_transmit,
00558 .irq = sundance_irq,
00559
00560 };
00561
00562
00563
00564
00565 static int sundance_probe ( struct nic *nic, struct pci_device *pci ) {
00566
00567 u8 ee_data[EEPROM_SIZE];
00568 u16 mii_ctl;
00569 int i;
00570 int speed;
00571
00572 if (pci->ioaddr == 0)
00573 return 0;
00574
00575
00576 BASE = pci->ioaddr;
00577 printf(" sundance.c: Found %s Vendor=0x%hX Device=0x%hX\n",
00578 pci->driver_name, pci->vendor, pci->device);
00579
00580
00581 for (i = 0; i < 3; i++) {
00582 ((u16 *) ee_data)[i] =
00583 le16_to_cpu(eeprom_read(BASE, i + EEPROM_SA_OFFSET));
00584 }
00585
00586 for (i = 0; i < ETH_ALEN; i++) {
00587 nic->node_addr[i] = ee_data[i];
00588 }
00589
00590
00591 adjust_pci_device(pci);
00592
00593
00594
00595
00596
00597
00598 sdc = &sdx;
00599
00600 sdc->nic_name = pci->driver_name;
00601 sdc->mtu = mtu;
00602
00603 pci_read_config_byte(pci, PCI_REVISION_ID, &sdc->pci_rev_id);
00604
00605 DBG ( "Device revision id: %hx\n", sdc->pci_rev_id );
00606
00607
00608 DBG ( "%s: %s at ioaddr %hX, ", pci->driver_name, nic->node_addr, (unsigned int) BASE);
00609
00610 sdc->mii_preamble_required = 0;
00611 if (1) {
00612 int phy, phy_idx = 0;
00613 sdc->phys[0] = 1;
00614 sdc->mii_preamble_required++;
00615 for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
00616 int mii_status = mdio_read(nic, phy, MII_BMSR);
00617 if (mii_status != 0xffff && mii_status != 0x0000) {
00618 sdc->phys[phy_idx++] = phy;
00619 sdc->mii_if.advertising =
00620 mdio_read(nic, phy, MII_ADVERTISE);
00621 if ((mii_status & 0x0040) == 0)
00622 sdc->mii_preamble_required++;
00623 DBG
00624 ( "%s: MII PHY found at address %d, status " "%hX advertising %hX\n", sdc->nic_name, phy, mii_status, sdc->mii_if.advertising );
00625 }
00626 }
00627 sdc->mii_preamble_required--;
00628 if (phy_idx == 0)
00629 printf("%s: No MII transceiver found!\n",
00630 sdc->nic_name);
00631 sdc->mii_if.phy_id = sdc->phys[0];
00632 }
00633
00634
00635 sdc->an_enable = 1;
00636 if (strcasecmp(media, "autosense") != 0) {
00637 sdc->an_enable = 0;
00638 if (strcasecmp(media, "100mbps_fd") == 0 ||
00639 strcasecmp(media, "4") == 0) {
00640 sdc->speed = 100;
00641 sdc->mii_if.full_duplex = 1;
00642 } else if (strcasecmp(media, "100mbps_hd") == 0
00643 || strcasecmp(media, "3") == 0) {
00644 sdc->speed = 100;
00645 sdc->mii_if.full_duplex = 0;
00646 } else if (strcasecmp(media, "10mbps_fd") == 0 ||
00647 strcasecmp(media, "2") == 0) {
00648 sdc->speed = 10;
00649 sdc->mii_if.full_duplex = 1;
00650 } else if (strcasecmp(media, "10mbps_hd") == 0 ||
00651 strcasecmp(media, "1") == 0) {
00652 sdc->speed = 10;
00653 sdc->mii_if.full_duplex = 0;
00654 } else {
00655 sdc->an_enable = 1;
00656 }
00657 }
00658 if (flowctrl == 1)
00659 sdc->flowctrl = 1;
00660
00661
00662 if (inl(BASE + ASICCtrl) & 0x80) {
00663
00664 if (sdc->an_enable) {
00665 sdc->speed = 100;
00666 sdc->mii_if.full_duplex = 1;
00667 sdc->an_enable = 0;
00668 }
00669 }
00670
00671
00672
00673
00674
00675
00676 if (!sdc->an_enable) {
00677 mii_ctl = 0;
00678 mii_ctl |= (sdc->speed == 100) ? BMCR_SPEED100 : 0;
00679 mii_ctl |= (sdc->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;
00680 mdio_write(nic, sdc->phys[0], MII_BMCR, mii_ctl);
00681 printf("Override speed=%d, %s duplex\n",
00682 sdc->speed,
00683 sdc->mii_if.full_duplex ? "Full" : "Half");
00684 }
00685
00686
00687 DBG ( "ASIC Control is %#x\n", inl(BASE + ASICCtrl) );
00688 outw(0x007f, BASE + ASICCtrl + 2);
00689
00690
00691
00692
00693
00694
00695
00696 i = 0;
00697 while(inl(BASE + ASICCtrl) & (ResetBusy << 16)) {
00698 if(i++ >= 10) {
00699 DBG("sundance: NIC reset did not complete.\n");
00700 break;
00701 }
00702 udelay(100);
00703 }
00704
00705 DBG ( "ASIC Control is now %#x.\n", inl(BASE + ASICCtrl) );
00706
00707 sundance_reset(nic);
00708 if (sdc->an_enable) {
00709 u16 mii_advertise, mii_lpa;
00710 mii_advertise =
00711 mdio_read(nic, sdc->phys[0], MII_ADVERTISE);
00712 mii_lpa = mdio_read(nic, sdc->phys[0], MII_LPA);
00713 mii_advertise &= mii_lpa;
00714 if (mii_advertise & ADVERTISE_100FULL)
00715 sdc->speed = 100;
00716 else if (mii_advertise & ADVERTISE_100HALF)
00717 sdc->speed = 100;
00718 else if (mii_advertise & ADVERTISE_10FULL)
00719 sdc->speed = 10;
00720 else if (mii_advertise & ADVERTISE_10HALF)
00721 sdc->speed = 10;
00722 } else {
00723 mii_ctl = mdio_read(nic, sdc->phys[0], MII_BMCR);
00724 speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
00725 sdc->speed = speed;
00726 printf("%s: Link changed: %dMbps ,", sdc->nic_name, speed);
00727 printf("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ?
00728 "full" : "half");
00729 }
00730 check_duplex(nic);
00731 if (sdc->flowctrl && sdc->mii_if.full_duplex) {
00732 outw(inw(BASE + MulticastFilter1 + 2) | 0x0200,
00733 BASE + MulticastFilter1 + 2);
00734 outw(inw(BASE + MACCtrl0) | EnbFlowCtrl, BASE + MACCtrl0);
00735 }
00736 printf("%dMbps, %s-Duplex\n", sdc->speed,
00737 sdc->mii_if.full_duplex ? "Full" : "Half");
00738
00739
00740 nic->nic_op = &sundance_operations;
00741
00742 nic->irqno = pci->irq;
00743 nic->ioaddr = BASE;
00744
00745 return 1;
00746 }
00747
00748
00749
00750 static int eeprom_read(long ioaddr, int location)
00751 {
00752 int boguscnt = 10000;
00753 outw(0x0200 | (location & 0xff), ioaddr + EECtrl);
00754 do {
00755 if (!(inw(ioaddr + EECtrl) & 0x8000)) {
00756 return inw(ioaddr + EEData);
00757 }
00758 }
00759 while (--boguscnt > 0);
00760 return 0;
00761 }
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773 #define mdio_in(mdio_addr) inb(mdio_addr)
00774 #define mdio_out(value, mdio_addr) outb(value, mdio_addr)
00775 #define mdio_delay(mdio_addr) inb(mdio_addr)
00776
00777 enum mii_reg_bits {
00778 MDIO_ShiftClk = 0x0001, MDIO_Data = 0x0002, MDIO_EnbOutput =
00779 0x0004,
00780 };
00781 #define MDIO_EnbIn (0)
00782 #define MDIO_WRITE0 (MDIO_EnbOutput)
00783 #define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)
00784
00785
00786
00787 static void mdio_sync(long mdio_addr)
00788 {
00789 int bits = 32;
00790
00791
00792 while (--bits >= 0) {
00793 mdio_out(MDIO_WRITE1, mdio_addr);
00794 mdio_delay(mdio_addr);
00795 mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
00796 mdio_delay(mdio_addr);
00797 }
00798 }
00799
00800 static int
00801 mdio_read(struct nic *nic __unused, int phy_id, unsigned int location)
00802 {
00803 long mdio_addr = BASE + MIICtrl;
00804 int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
00805 int i, retval = 0;
00806
00807 if (sdc->mii_preamble_required)
00808 mdio_sync(mdio_addr);
00809
00810
00811 for (i = 15; i >= 0; i--) {
00812 int dataval =
00813 (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
00814
00815 mdio_out(dataval, mdio_addr);
00816 mdio_delay(mdio_addr);
00817 mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
00818 mdio_delay(mdio_addr);
00819 }
00820
00821 for (i = 19; i > 0; i--) {
00822 mdio_out(MDIO_EnbIn, mdio_addr);
00823 mdio_delay(mdio_addr);
00824 retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data)
00825 ? 1 : 0);
00826 mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
00827 mdio_delay(mdio_addr);
00828 }
00829 return (retval >> 1) & 0xffff;
00830 }
00831
00832 static void
00833 mdio_write(struct nic *nic __unused, int phy_id,
00834 unsigned int location, int value)
00835 {
00836 long mdio_addr = BASE + MIICtrl;
00837 int mii_cmd =
00838 (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
00839 int i;
00840
00841 if (sdc->mii_preamble_required)
00842 mdio_sync(mdio_addr);
00843
00844
00845 for (i = 31; i >= 0; i--) {
00846 int dataval =
00847 (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
00848 mdio_out(dataval, mdio_addr);
00849 mdio_delay(mdio_addr);
00850 mdio_out(dataval | MDIO_ShiftClk, mdio_addr);
00851 mdio_delay(mdio_addr);
00852 }
00853
00854 for (i = 2; i > 0; i--) {
00855 mdio_out(MDIO_EnbIn, mdio_addr);
00856 mdio_delay(mdio_addr);
00857 mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
00858 mdio_delay(mdio_addr);
00859 }
00860 return;
00861 }
00862
00863 static void set_rx_mode(struct nic *nic __unused)
00864 {
00865 int i;
00866 u16 mc_filter[4];
00867 u32 rx_mode;
00868
00869 memset(mc_filter, 0xff, sizeof(mc_filter));
00870 rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
00871
00872 if (sdc->mii_if.full_duplex && sdc->flowctrl)
00873 mc_filter[3] |= 0x0200;
00874 for (i = 0; i < 4; i++)
00875 outw(mc_filter[i], BASE + MulticastFilter0 + i * 2);
00876 outb(rx_mode, BASE + RxMode);
00877 return;
00878 }
00879
00880 static struct pci_device_id sundance_nics[] = {
00881 PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor", 0),
00882 PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)", 0),
00883 PCI_ROM(0x13f0, 0x0200, "ip100a", "IC+ IP100A", 0),
00884 };
00885
00886 PCI_DRIVER ( sundance_driver, sundance_nics, PCI_NO_CLASS );
00887
00888 DRIVER ( "SUNDANCE/PCI", nic_driver, pci_driver, sundance_driver,
00889 sundance_probe, sundance_disable );
00890
00891
00892
00893
00894
00895
00896
00897