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 FILE_LICENCE ( GPL2_OR_LATER );
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 #define USE_IO_OPS
00081
00082 #include "etherboot.h"
00083 #include "nic.h"
00084 #include <gpxe/pci.h>
00085 #include <gpxe/ethernet.h>
00086
00087 static const char *w89c840_version = "driver Version 0.94 - December 12, 2003";
00088
00089
00090 #define virt_to_le32desc(addr) virt_to_bus(addr)
00091 #define le32desc_to_virt(addr) bus_to_virt(addr)
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 #define TX_RING_SIZE 2
00106 #define RX_RING_SIZE 2
00107
00108
00109
00110
00111
00112 #define TX_FIFO_SIZE (2048)
00113 #define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16)
00114
00115
00116
00117 #define TX_TIMEOUT (10*1000)
00118
00119 #define PKT_BUF_SZ 1536
00120
00121
00122
00123
00124
00125
00126
00127 #if !defined(__OPTIMIZE__)
00128 #warning You must compile this file with the correct options!
00129 #warning See the last lines of the source file.
00130 #error You must compile this driver with "-O".
00131 #endif
00132
00133 enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2};
00134
00135 #ifdef USE_IO_OPS
00136 #define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
00137 #else
00138 #define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
00139 #endif
00140
00141 static u32 driver_flags = CanHaveMII | HasBrokenTx;
00142
00143
00144
00145
00146
00147 #ifdef USE_IO_OPS
00148 #undef readb
00149 #undef readw
00150 #undef readl
00151 #undef writeb
00152 #undef writew
00153 #undef writel
00154 #define readb inb
00155 #define readw inw
00156 #define readl inl
00157 #define writeb outb
00158 #define writew outw
00159 #define writel outl
00160 #endif
00161
00162
00163
00164
00165
00166
00167
00168 enum w840_offsets {
00169 PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08,
00170 RxRingPtr=0x0C, TxRingPtr=0x10,
00171 IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C,
00172 RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C,
00173 CurRxDescAddr=0x30, CurRxBufAddr=0x34,
00174 MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40,
00175 CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
00176 };
00177
00178
00179
00180 enum intr_status_bits {
00181 NormalIntr=0x10000, AbnormalIntr=0x8000,
00182 IntrPCIErr=0x2000, TimerInt=0x800,
00183 IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
00184 TxFIFOUnderflow=0x20, RxErrIntr=0x10,
00185 TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
00186 };
00187
00188
00189 enum rx_mode_bits {
00190 AcceptErr=0x80, AcceptRunt=0x40,
00191 AcceptBroadcast=0x20, AcceptMulticast=0x10,
00192 AcceptAllPhys=0x08, AcceptMyPhys=0x02,
00193 };
00194
00195 enum mii_reg_bits {
00196 MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000,
00197 MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000,
00198 };
00199
00200
00201 struct w840_rx_desc {
00202 s32 status;
00203 s32 length;
00204 u32 buffer1;
00205 u32 next_desc;
00206 };
00207
00208 struct w840_tx_desc {
00209 s32 status;
00210 s32 length;
00211 u32 buffer1, buffer2;
00212 };
00213
00214
00215 enum desc_status_bits {
00216 DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
00217 DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
00218 DescIntr=0x80000000,
00219 };
00220 #define PRIV_ALIGN 15
00221 #define PRIV_ALIGN_BYTES 32
00222
00223 static struct winbond_private
00224 {
00225
00226 struct w840_rx_desc rx_ring[RX_RING_SIZE];
00227 struct w840_tx_desc tx_ring[TX_RING_SIZE];
00228 struct net_device *next_module;
00229 void *priv_addr;
00230 const char *product_name;
00231
00232 int chip_id, drv_flags;
00233 struct pci_dev *pci_dev;
00234 int csr6;
00235 struct w840_rx_desc *rx_head_desc;
00236 unsigned int cur_rx, dirty_rx;
00237 unsigned int rx_buf_sz;
00238 unsigned int cur_tx, dirty_tx;
00239 int tx_q_bytes;
00240 unsigned int tx_full:1;
00241
00242 unsigned int full_duplex:1;
00243 unsigned int duplex_lock:1;
00244 unsigned int medialock:1;
00245 unsigned int default_port:4;
00246
00247 int mii_cnt;
00248 u16 advertising;
00249 unsigned char phys[2];
00250 } w840private __attribute__ ((aligned (PRIV_ALIGN_BYTES)));
00251
00252
00253
00254 static int ioaddr;
00255 static unsigned short eeprom [0x40];
00256 struct {
00257 char rx_packet[PKT_BUF_SZ * RX_RING_SIZE];
00258 char tx_packet[PKT_BUF_SZ * TX_RING_SIZE];
00259 } w89c840_buf __shared;
00260
00261 static int eeprom_read(long ioaddr, int location);
00262 static int mdio_read(int base_address, int phy_id, int location);
00263 #if 0
00264 static void mdio_write(int base_address, int phy_id, int location, int value);
00265 #endif
00266
00267 static void check_duplex(void);
00268 static void set_rx_mode(void);
00269 static void init_ring(void);
00270
00271 #if defined(W89C840_DEBUG)
00272 static void decode_interrupt(u32 intr_status)
00273 {
00274 printf("Interrupt status: ");
00275
00276 #define TRACE_INTR(_intr_) \
00277 if (intr_status & (_intr_)) { printf (" " #_intr_); }
00278
00279 TRACE_INTR(NormalIntr);
00280 TRACE_INTR(AbnormalIntr);
00281 TRACE_INTR(IntrPCIErr);
00282 TRACE_INTR(TimerInt);
00283 TRACE_INTR(IntrRxDied);
00284 TRACE_INTR(RxNoBuf);
00285 TRACE_INTR(IntrRxDone);
00286 TRACE_INTR(TxFIFOUnderflow);
00287 TRACE_INTR(RxErrIntr);
00288 TRACE_INTR(TxIdle);
00289 TRACE_INTR(IntrTxStopped);
00290 TRACE_INTR(IntrTxDone);
00291
00292 printf("\n");
00293
00294 }
00295 #endif
00296
00297
00298
00299
00300 static void w89c840_reset(struct nic *nic)
00301 {
00302 int i;
00303
00304
00305
00306 writel(0x00000001, ioaddr + PCIBusCfg);
00307
00308 init_ring();
00309
00310 writel(virt_to_bus(w840private.rx_ring), ioaddr + RxRingPtr);
00311 writel(virt_to_bus(w840private.tx_ring), ioaddr + TxRingPtr);
00312
00313 for (i = 0; i < ETH_ALEN; i++)
00314 writeb(nic->node_addr[i], ioaddr + StationAddr + i);
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 writel(0xE010, ioaddr + PCIBusCfg);
00329
00330 writel(0, ioaddr + RxStartDemand);
00331 w840private.csr6 = 0x20022002;
00332 check_duplex();
00333 set_rx_mode();
00334
00335
00336
00337
00338
00339
00340 #if defined(W89C840_DEBUG)
00341 printf("winbond-840 : Done reset.\n");
00342 #endif
00343 }
00344
00345 #if 0
00346 static void handle_intr(u32 intr_stat)
00347 {
00348 if ((intr_stat & (NormalIntr|AbnormalIntr)) == 0) {
00349
00350
00351 } else {
00352
00353 writel(intr_stat & 0x001ffff, ioaddr + IntrStatus);
00354 }
00355
00356 if (intr_stat & AbnormalIntr) {
00357
00358 printf("\n-=- Abnormal interrupt.\n");
00359
00360 #if defined(W89C840_DEBUG)
00361 decode_interrupt(intr_stat);
00362 #endif
00363
00364 if (intr_stat & RxNoBuf) {
00365
00366 printf("-=- <=> No receive buffers available.\n");
00367 writel(0, ioaddr + RxStartDemand);
00368 }
00369 }
00370 }
00371 #endif
00372
00373
00374
00375
00376 static int w89c840_poll(struct nic *nic, int retrieve)
00377 {
00378
00379
00380
00381 int packet_received = 0;
00382
00383 #if defined(W89C840_DEBUG)
00384 u32 intr_status = readl(ioaddr + IntrStatus);
00385 #endif
00386
00387 do {
00388
00389
00390 int entry = w840private.cur_rx % RX_RING_SIZE;
00391
00392 struct w840_rx_desc *desc = w840private.rx_head_desc;
00393 s32 status = desc->status;
00394
00395 if (status & DescOwn) {
00396
00397 packet_received = 0;
00398 break;
00399 }
00400
00401 if ( !retrieve ) {
00402 packet_received = 1;
00403 break;
00404 }
00405
00406 if ((status & 0x38008300) != 0x0300) {
00407 if ((status & 0x38000300) != 0x0300) {
00408
00409 if ((status & 0xffff) != 0x7fff) {
00410 printf("winbond-840 : Oversized Ethernet frame spanned "
00411 "multiple buffers, entry %d status %X !\n",
00412 w840private.cur_rx, (unsigned int) status);
00413 }
00414 } else if (status & 0x8000) {
00415
00416 #if defined(W89C840_DEBUG)
00417 printf("winbond-840 : Receive error, Rx status %X :", status);
00418 if (status & 0x0890) {
00419 printf(" RXLEN_ERROR");
00420 }
00421 if (status & 0x004C) {
00422 printf(", FRAME_ERROR");
00423 }
00424 if (status & 0x0002) {
00425 printf(", CRC_ERROR");
00426 }
00427 printf("\n");
00428 #endif
00429
00430
00431 w89c840_reset(nic);
00432
00433 packet_received = 0;
00434 break;
00435 }
00436 } else {
00437
00438 int pkt_len = ((status >> 16) & 0x7ff) - 4;
00439
00440 #if defined(W89C840_DEBUG)
00441 printf(" netdev_rx() normal Rx pkt ring %d length %d status %X\n", entry, pkt_len, status);
00442 #endif
00443
00444 nic->packetlen = pkt_len;
00445
00446
00447
00448
00449 memcpy(nic->packet, le32desc_to_virt(w840private.rx_ring[entry].buffer1), pkt_len);
00450 packet_received = 1;
00451
00452
00453 w840private.rx_ring[entry].status = DescOwn;
00454
00455 #if defined(W89C840_DEBUG)
00456
00457 printf(" Rx data %hhX:%hhX:%hhX:%hhX:%hhX:"
00458 "%hhX %hhX:%hhX:%hhX:%hhX:%hhX:%hhX %hhX%hhX "
00459 "%hhX.%hhX.%hhX.%hhX.\n",
00460 nic->packet[0], nic->packet[1], nic->packet[2], nic->packet[3],
00461 nic->packet[4], nic->packet[5], nic->packet[6], nic->packet[7],
00462 nic->packet[8], nic->packet[9], nic->packet[10],
00463 nic->packet[11], nic->packet[12], nic->packet[13],
00464 nic->packet[14], nic->packet[15], nic->packet[16],
00465 nic->packet[17]);
00466 #endif
00467
00468 }
00469
00470 entry = (++w840private.cur_rx) % RX_RING_SIZE;
00471 w840private.rx_head_desc = &w840private.rx_ring[entry];
00472 } while (0);
00473
00474 return packet_received;
00475 }
00476
00477
00478
00479
00480
00481 static void w89c840_transmit(
00482 struct nic *nic,
00483 const char *d,
00484 unsigned int t,
00485 unsigned int s,
00486 const char *p)
00487 {
00488
00489 unsigned entry;
00490 int transmit_status;
00491 unsigned long ct;
00492
00493
00494
00495
00496
00497 entry = w840private.cur_tx % TX_RING_SIZE;
00498
00499 memcpy (w89c840_buf.tx_packet, d, ETH_ALEN);
00500 memcpy (w89c840_buf.tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN);
00501
00502 *((char *) w89c840_buf.tx_packet + 12) = t >> 8;
00503 *((char *) w89c840_buf.tx_packet + 13) = t;
00504
00505 memcpy (w89c840_buf.tx_packet + ETH_HLEN, p, s);
00506 s += ETH_HLEN;
00507
00508 while (s < ETH_ZLEN)
00509 *((char *) w89c840_buf.tx_packet + ETH_HLEN + (s++)) = 0;
00510
00511 w840private.tx_ring[entry].buffer1
00512 = virt_to_le32desc(w89c840_buf.tx_packet);
00513
00514 w840private.tx_ring[entry].length = (DescWholePkt | (u32) s);
00515 if (entry >= TX_RING_SIZE-1)
00516 w840private.tx_ring[entry].length |= (DescIntr | DescEndRing);
00517 w840private.tx_ring[entry].status = (DescOwn);
00518 w840private.cur_tx++;
00519
00520 w840private.tx_q_bytes = (u16) s;
00521 writel(0, ioaddr + TxStartDemand);
00522
00523
00524
00525
00526 if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) {
00527
00528
00529
00530 w840private.tx_full = 1;
00531 }
00532
00533 #if defined(W89C840_DEBUG)
00534 printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry);
00535 #endif
00536
00537
00538 transmit_status = w840private.tx_ring[entry].status;
00539
00540 ct = currticks();
00541 {
00542 #if defined W89C840_DEBUG
00543 u32 intr_stat = 0;
00544 #endif
00545 while (1) {
00546
00547 #if defined(W89C840_DEBUG)
00548 decode_interrupt(intr_stat);
00549 #endif
00550
00551 while ( (transmit_status & DescOwn) && ct + TX_TIMEOUT < currticks()) {
00552
00553 transmit_status = w840private.tx_ring[entry].status;
00554 }
00555
00556 break;
00557 }
00558 }
00559
00560 if ((transmit_status & DescOwn) == 0) {
00561
00562 #if defined(W89C840_DEBUG)
00563 printf("winbond-840 : transmission complete after wait loop iterations, status %X\n",
00564 w840private.tx_ring[entry].status);
00565 #endif
00566
00567 return;
00568 }
00569
00570
00571
00572 printf("winbond-840 : transmission TIMEOUT : status %X\n",
00573 (unsigned int) w840private.tx_ring[entry].status);
00574
00575 return;
00576 }
00577
00578
00579
00580
00581 static void w89c840_disable ( struct nic *nic ) {
00582
00583 w89c840_reset(nic);
00584
00585
00586
00587
00588 writel(w840private.csr6 &= ~0x20FA, ioaddr + NetworkConfig);
00589 }
00590
00591
00592
00593
00594 static void w89c840_irq(struct nic *nic __unused, irq_action_t action __unused)
00595 {
00596 switch ( action ) {
00597 case DISABLE :
00598 break;
00599 case ENABLE :
00600 break;
00601 case FORCE :
00602 break;
00603 }
00604 }
00605
00606 static struct nic_operations w89c840_operations = {
00607 .connect = dummy_connect,
00608 .poll = w89c840_poll,
00609 .transmit = w89c840_transmit,
00610 .irq = w89c840_irq,
00611
00612 };
00613
00614 static struct pci_device_id w89c840_nics[] = {
00615 PCI_ROM(0x1050, 0x0840, "winbond840", "Winbond W89C840F", 0),
00616 PCI_ROM(0x11f6, 0x2011, "compexrl100atx", "Compex RL100ATX", 0),
00617 };
00618
00619 PCI_DRIVER ( w89c840_driver, w89c840_nics, PCI_NO_CLASS );
00620
00621
00622
00623
00624 static int w89c840_probe ( struct nic *nic, struct pci_device *p ) {
00625
00626
00627 u16 sum = 0;
00628 int i, j;
00629 unsigned short value;
00630
00631 if (p->ioaddr == 0)
00632 return 0;
00633
00634 nic->ioaddr = p->ioaddr;
00635 nic->irqno = 0;
00636
00637 #if defined(W89C840_DEBUG)
00638 printf("winbond-840: PCI bus %hhX device function %hhX: I/O address: %hX\n", p->bus, p->devfn, ioaddr);
00639 #endif
00640
00641 ioaddr = ioaddr & ~3;
00642
00643 #define PCI_DEVICE_ID_WINBOND2_89C840 0x0840
00644 #define PCI_DEVICE_ID_COMPEX_RL100ATX 0x2011
00645
00646
00647 if (p->vendor == PCI_VENDOR_ID_WINBOND2
00648 && p->device == PCI_DEVICE_ID_WINBOND2_89C840) {
00649
00650
00651
00652 } else if ( p->vendor == PCI_VENDOR_ID_COMPEX
00653 && p->device == PCI_DEVICE_ID_COMPEX_RL100ATX) {
00654
00655
00656
00657 } else {
00658
00659 printf("device ID : %X - is not a Compex RL100ATX NIC.\n",
00660 p->device);
00661 return 0;
00662 }
00663
00664 printf(" %s\n", w89c840_version);
00665
00666 adjust_pci_device(p);
00667
00668
00669 for (j = 0, i = 0; i < 0x40; i++) {
00670 value = eeprom_read(ioaddr, i);
00671 eeprom[i] = value;
00672 sum += value;
00673 }
00674
00675 for (i=0;i<ETH_ALEN;i++) {
00676 nic->node_addr[i] = (eeprom[i/2] >> (8*(i&1))) & 0xff;
00677 }
00678
00679 DBG ( "Ethernet addr: %s\n", eth_ntoa ( nic->node_addr ) );
00680
00681 #if defined(W89C840_DEBUG)
00682 printf("winbond-840: EEPROM checksum %hX, got eeprom", sum);
00683 #endif
00684
00685
00686
00687 writel(0x00000001, ioaddr + PCIBusCfg);
00688
00689 if (driver_flags & CanHaveMII) {
00690 int phy, phy_idx = 0;
00691 for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
00692 int mii_status = mdio_read(ioaddr, phy, 1);
00693 if (mii_status != 0xffff && mii_status != 0x0000) {
00694 w840private.phys[phy_idx++] = phy;
00695 w840private.advertising = mdio_read(ioaddr, phy, 4);
00696
00697 #if defined(W89C840_DEBUG)
00698 printf("winbond-840 : MII PHY found at address %d, status "
00699 "%X advertising %hX.\n", phy, mii_status, w840private.advertising);
00700 #endif
00701
00702 }
00703 }
00704
00705 w840private.mii_cnt = phy_idx;
00706
00707 if (phy_idx == 0) {
00708 printf("winbond-840 : MII PHY not found -- this device may not operate correctly.\n");
00709 }
00710 }
00711
00712
00713 nic->nic_op = &w89c840_operations;
00714
00715 w89c840_reset(nic);
00716
00717 return 1;
00718 }
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731 #define eeprom_delay(ee_addr) readl(ee_addr)
00732
00733 enum EEPROM_Ctrl_Bits {
00734 EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,
00735 EE_ChipSelect=0x801, EE_DataIn=0x08,
00736 };
00737
00738
00739 enum EEPROM_Cmds {
00740 EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
00741 };
00742
00743 static int eeprom_read(long addr, int location)
00744 {
00745 int i;
00746 int retval = 0;
00747 int ee_addr = addr + EECtrl;
00748 int read_cmd = location | EE_ReadCmd;
00749 writel(EE_ChipSelect, ee_addr);
00750
00751
00752 for (i = 10; i >= 0; i--) {
00753 short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
00754 writel(dataval, ee_addr);
00755 eeprom_delay(ee_addr);
00756 writel(dataval | EE_ShiftClk, ee_addr);
00757 eeprom_delay(ee_addr);
00758 }
00759 writel(EE_ChipSelect, ee_addr);
00760
00761 for (i = 16; i > 0; i--) {
00762 writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
00763 eeprom_delay(ee_addr);
00764 retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
00765 writel(EE_ChipSelect, ee_addr);
00766 eeprom_delay(ee_addr);
00767 }
00768
00769
00770 writel(0, ee_addr);
00771 return retval;
00772 }
00773
00774
00775
00776
00777
00778
00779
00780
00781 #define mdio_delay(mdio_addr) readl(mdio_addr)
00782
00783
00784
00785
00786 static char mii_preamble_required = 1;
00787
00788 #define MDIO_WRITE0 (MDIO_EnbOutput)
00789 #define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)
00790
00791
00792
00793 static void mdio_sync(long mdio_addr)
00794 {
00795 int bits = 32;
00796
00797
00798 while (--bits >= 0) {
00799 writel(MDIO_WRITE1, mdio_addr);
00800 mdio_delay(mdio_addr);
00801 writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
00802 mdio_delay(mdio_addr);
00803 }
00804 }
00805
00806 static int mdio_read(int base_address, int phy_id, int location)
00807 {
00808 long mdio_addr = base_address + MIICtrl;
00809 int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
00810 int i, retval = 0;
00811
00812 if (mii_preamble_required)
00813 mdio_sync(mdio_addr);
00814
00815
00816 for (i = 15; i >= 0; i--) {
00817 int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
00818
00819 writel(dataval, mdio_addr);
00820 mdio_delay(mdio_addr);
00821 writel(dataval | MDIO_ShiftClk, mdio_addr);
00822 mdio_delay(mdio_addr);
00823 }
00824
00825 for (i = 20; i > 0; i--) {
00826 writel(MDIO_EnbIn, mdio_addr);
00827 mdio_delay(mdio_addr);
00828 retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0);
00829 writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
00830 mdio_delay(mdio_addr);
00831 }
00832 return (retval>>1) & 0xffff;
00833 }
00834
00835 #if 0
00836 static void mdio_write(int base_address, int phy_id, int location, int value)
00837 {
00838 long mdio_addr = base_address + MIICtrl;
00839 int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
00840 int i;
00841
00842 if (location == 4 && phy_id == w840private.phys[0])
00843 w840private.advertising = value;
00844
00845 if (mii_preamble_required)
00846 mdio_sync(mdio_addr);
00847
00848
00849 for (i = 31; i >= 0; i--) {
00850 int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
00851
00852 writel(dataval, mdio_addr);
00853 mdio_delay(mdio_addr);
00854 writel(dataval | MDIO_ShiftClk, mdio_addr);
00855 mdio_delay(mdio_addr);
00856 }
00857
00858 for (i = 2; i > 0; i--) {
00859 writel(MDIO_EnbIn, mdio_addr);
00860 mdio_delay(mdio_addr);
00861 writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
00862 mdio_delay(mdio_addr);
00863 }
00864 return;
00865 }
00866 #endif
00867
00868 static void check_duplex(void)
00869 {
00870 int mii_reg5 = mdio_read(ioaddr, w840private.phys[0], 5);
00871 int negotiated = mii_reg5 & w840private.advertising;
00872 int duplex;
00873
00874 if (w840private.duplex_lock || mii_reg5 == 0xffff)
00875 return;
00876
00877 duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
00878 if (w840private.full_duplex != duplex) {
00879 w840private.full_duplex = duplex;
00880
00881 #if defined(W89C840_DEBUG)
00882 printf("winbond-840 : Setting %s-duplex based on MII # %d negotiated capability %X\n",
00883 duplex ? "full" : "half", w840private.phys[0], negotiated);
00884 #endif
00885
00886 w840private.csr6 &= ~0x200;
00887 w840private.csr6 |= duplex ? 0x200 : 0;
00888 }
00889 }
00890
00891 static void set_rx_mode(void)
00892 {
00893 u32 mc_filter[2];
00894 u32 rx_mode;
00895
00896
00897 memset(mc_filter, 0xff, sizeof(mc_filter));
00898
00899
00900
00901
00902
00903 rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
00904
00905 writel(mc_filter[0], ioaddr + MulticastFilter0);
00906 writel(mc_filter[1], ioaddr + MulticastFilter1);
00907 w840private.csr6 &= ~0x00F8;
00908 w840private.csr6 |= rx_mode;
00909 writel(w840private.csr6, ioaddr + NetworkConfig);
00910
00911 #if defined(W89C840_DEBUG)
00912 printf("winbond-840 : Done setting RX mode.\n");
00913 #endif
00914 }
00915
00916
00917 static void init_ring(void)
00918 {
00919 int i;
00920 char * p;
00921
00922 w840private.tx_full = 0;
00923 w840private.tx_q_bytes = w840private.cur_rx = w840private.cur_tx = 0;
00924 w840private.dirty_rx = w840private.dirty_tx = 0;
00925
00926 w840private.rx_buf_sz = PKT_BUF_SZ;
00927 w840private.rx_head_desc = &w840private.rx_ring[0];
00928
00929
00930
00931 p = &w89c840_buf.rx_packet[0];
00932
00933 for (i = 0; i < RX_RING_SIZE; i++) {
00934 w840private.rx_ring[i].length = w840private.rx_buf_sz;
00935 w840private.rx_ring[i].status = 0;
00936 w840private.rx_ring[i].next_desc = virt_to_le32desc(&w840private.rx_ring[i+1]);
00937
00938 w840private.rx_ring[i].buffer1 = virt_to_le32desc(p + (PKT_BUF_SZ * i));
00939 w840private.rx_ring[i].status = DescOwn | DescIntr;
00940 }
00941
00942
00943 w840private.rx_ring[i-1].length |= DescEndRing;
00944 w840private.rx_ring[i-1].next_desc = virt_to_le32desc(&w840private.rx_ring[0]);
00945
00946 w840private.dirty_rx = (unsigned int)(i - RX_RING_SIZE);
00947
00948 for (i = 0; i < TX_RING_SIZE; i++) {
00949 w840private.tx_ring[i].status = 0;
00950 }
00951 return;
00952 }
00953
00954
00955 DRIVER ( "W89C840F", nic_driver, pci_driver, w89c840_driver,
00956 w89c840_probe, w89c840_disable );
00957
00958
00959
00960
00961
00962
00963
00964