From 684349b37ae4041dad0f1bd0bb7653f448c9ca9f Mon Sep 17 00:00:00 2001 From: Stefano Ceccherini Date: Mon, 29 Mar 2004 06:36:33 +0000 Subject: [PATCH] Implemented link detection and speed autonegotiation git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7098 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/network/wb840/device.c | 2 +- .../kernel/drivers/network/wb840/interface.c | 4 +- .../kernel/drivers/network/wb840/wb840.c | 165 ++++++------------ .../kernel/drivers/network/wb840/wb840.h | 14 +- 4 files changed, 55 insertions(+), 130 deletions(-) diff --git a/src/add-ons/kernel/drivers/network/wb840/device.c b/src/add-ons/kernel/drivers/network/wb840/device.c index c2ac267dc5..f6a8e47e0f 100644 --- a/src/add-ons/kernel/drivers/network/wb840/device.c +++ b/src/add-ons/kernel/drivers/network/wb840/device.c @@ -159,7 +159,7 @@ wb840_read(void* cookie, off_t position, void *buf, size_t* num_bytes) acquire_spinlock(&device->rxSpinlock); // release buffer to ring - wb_free_rx_descriptor(&device->rxDescriptor[current]); + wb_put_rx_descriptor(&device->rxDescriptor[current]); device->rxFree++; release_spinlock(&device->rxSpinlock); diff --git a/src/add-ons/kernel/drivers/network/wb840/interface.c b/src/add-ons/kernel/drivers/network/wb840/interface.c index 62f0ab216b..b8a7cdf62f 100644 --- a/src/add-ons/kernel/drivers/network/wb840/interface.c +++ b/src/add-ons/kernel/drivers/network/wb840/interface.c @@ -50,8 +50,7 @@ read32(device->reg_base + WB_SIO) & ~x) #define MII_DELAY(x) read32(x->reg_base + WB_SIO) - - + static void mii_sync(struct wb_device *device) { @@ -212,7 +211,6 @@ wb_mii_writereg(wb_device *device, wb_mii_frame *frame) SIO_CLR(WB_SIO_MII_CLK); MII_DELAY(device); - /* * Turn off xmit. */ diff --git a/src/add-ons/kernel/drivers/network/wb840/wb840.c b/src/add-ons/kernel/drivers/network/wb840/wb840.c index 96dec13cff..fa6305126c 100644 --- a/src/add-ons/kernel/drivers/network/wb840/wb840.c +++ b/src/add-ons/kernel/drivers/network/wb840/wb840.c @@ -20,8 +20,8 @@ // MII chip info table -#define PHY_ID0_WB840_INTERNAL 0x0181 -#define PHY_ID1_WB840_INTERNAL 0xb800 +#define PHY_ID0_DAVICOM_DM9101 0x0181 +#define PHY_ID1_DAVICOM_DM9101 0xb800 #define MII_HOME 0x0001 #define MII_LAN 0x0002 @@ -30,10 +30,9 @@ const static struct mii_chip_info const char *name; uint16 id0, id1; uint8 types; -} - +} gMIIChips[] = { - {"WB840 Internal MII PHY", PHY_ID0_WB840_INTERNAL, PHY_ID1_WB840_INTERNAL, MII_LAN}, + {"DAVICOM_DM9101 MII PHY", PHY_ID0_DAVICOM_DM9101, PHY_ID1_DAVICOM_DM9101, MII_LAN}, {NULL,0,0,0} }; @@ -95,7 +94,7 @@ dump_registers(wb_device *device) // Prepares a RX descriptor to be used by the chip void -wb_free_rx_descriptor(wb_desc *descriptor) +wb_put_rx_descriptor(wb_desc *descriptor) { descriptor->wb_status = WB_RXSTAT_OWN; descriptor->wb_ctl = WB_MAX_FRAMELEN | WB_RXCTL_RLINK; @@ -130,17 +129,8 @@ wb_selectPHY(wb_device *device) status &= ~MII_CONTROL_ISOLATE; wb_miibus_writereg(device, device->phy, MII_CONTROL, status); -} - - -uint16 -wb_resetPHY(wb_device *device) -{ - uint16 status = mii_readstatus(device); - dprintf("wb_resetPHY: %d\n", status); - wb_miibus_writereg(device, device->phy, MII_CONTROL, MII_CONTROL_RESET); - return status; + wb_read_mode(device); } @@ -190,32 +180,6 @@ wb_initPHYs(wb_device *device) } wb_selectPHY(device); - - // if the internal PHY is selected, reset it - if (device->currentPHY->id0 == PHY_ID0_WB840_INTERNAL - && (device->currentPHY->id1 & 0xfff0) == PHY_ID1_WB840_INTERNAL) { - if (wb_resetPHY(device) & MII_STATUS_LINK) { - uint16 poll = MII_STATUS_LINK; - while (poll) { - poll ^= wb_miibus_readreg(device, device->phy, MII_STATUS) & poll; - } - } - } -/* - // workaround for ICS1893 PHY - if (info->currentPHY->id0 == PHY_ID0_ICS_1893 - && (info->currentPHY->id1 & 0xfff0) == PHY_ID1_ICS_1893) - mdio_write(info, 0x0018, 0xD200); - - // SiS 630E has some bugs on default value of PHY registers - if (info->pciInfo->revision == SiS900_REVISION_SiS630E) { - mdio_write(info, MII_AUTONEG_ADV, 0x05e1); - mdio_write(info, MII_CONFIG1, 0x22); - mdio_write(info, MII_CONFIG2, 0xff00); - mdio_write(info, MII_MASK, 0xffc0); - } - */ - device->link = mii_readstatus(device) & MII_STATUS_LINK; return B_OK; @@ -252,14 +216,14 @@ wb_init(wb_device *device) write32(device->reg_base + WB_BUSCTL_SKIPLEN, WB_SKIPLEN_4LONG); - /* Early TX interrupt; doesn't tend to work too well at 100Mbps */ + // Early TX interrupt WB_SETBIT(device->reg_base + WB_NETCFG, (WB_NETCFG_TX_EARLY_ON|WB_NETCFG_RX_EARLY_ON)); // fullduplex - WB_SETBIT(device->reg_base + WB_NETCFG, WB_NETCFG_FULLDUPLEX); + //WB_SETBIT(device->reg_base + WB_NETCFG, WB_NETCFG_FULLDUPLEX); //100 MBits - WB_SETBIT(device->reg_base + WB_NETCFG, WB_NETCFG_100MBPS); + //WB_SETBIT(device->reg_base + WB_NETCFG, WB_NETCFG_100MBPS); /* Program the multicast filter, if necessary */ //wb_setmulti(device); @@ -276,13 +240,9 @@ void wb_reset(wb_device *device) { int i = 0; - cpu_status status; LOG((DEVICE_NAME": reset()\n")); - status = disable_interrupts(); - // XXX: What about a spinlock here ? - write32(device->reg_base + WB_NETCFG, 0L); write32(device->reg_base + WB_BUSCTL, 0L); write32(device->reg_base + WB_TXADDR, 0L); @@ -299,12 +259,8 @@ wb_reset(wb_device *device) if (i == WB_TIMEOUT) LOG(("reset hasn't completed!!!")); - restore_interrupts(status); - /* Wait a bit while the chip reorders his toughts */ snooze(1000); - - //XXX Initialize MII interface } @@ -315,33 +271,24 @@ wb_updateLink(struct wb_device *device) int32 mode = wb_read_mode(device); if (mode) wb_set_mode(device, mode); - + return; } - if (device->link) { // link lost + if (device->link) { // link lost uint16 status = mii_readstatus(device); - if ((status & MII_STATUS_LINK) == 0) { + if ((status & MII_STATUS_LINK) == 0) device->link = false; - dprintf(DEVICE_NAME ": link lost\n"); - - // if it's the internal SiS900 MII PHY, reset it - //if (device->currentPHY->id0 == PHY_ID0_SiS900_INTERNAL - // && (device->currentPHY->id1 & 0xfff0) == PHY_ID1_SiS900_INTERNAL) - // sis900_resetPHY(device); - } } - if (!device->link) { // new link established + + if (!device->link) { // new link established uint16 status; - wb_selectPHY(device); status = mii_readstatus(device); - if (status & MII_STATUS_LINK) { - //sis900_checkMode(device); + if (status & MII_STATUS_LINK) device->link = true; - } } } @@ -368,7 +315,6 @@ wb_rxok(struct wb_device *device) for (limit = device->rxFree; limit > 0; limit--) { if (device->rxDescriptor[device->rxInterruptIndex].wb_status & WB_RXSTAT_OWN) { - //LOG((DEVICE_NAME ": RX_STAT_OWN\n")); break; } @@ -377,12 +323,11 @@ wb_rxok(struct wb_device *device) device->rxFree--; } - //Re-enable receive queue + // Re-enable receive queue write32(device->reg_base + WB_RXSTART, 0xFFFFFFFF); release_spinlock(&device->rxSpinlock); - //LOG((DEVICE_NAME": RxCurrent = %d\n", device->rxInterruptIndex)); if (releaseRxSem > 0) { //dprintf("releasing read sem %d times\n", releaseRxSem); @@ -404,7 +349,7 @@ wb_tx_nobuf(struct wb_device *info) acquire_spinlock(&info->txSpinlock); for (limit = info->txSent; limit > 0; limit--) { - status =info->txDescriptor[info->txInterruptIndex].wb_status; + status = info->txDescriptor[info->txInterruptIndex].wb_status; if (status & WB_TXSTAT_TXERR) { LOG(("TX_STAT_ERR\n")); @@ -413,7 +358,6 @@ wb_tx_nobuf(struct wb_device *info) LOG(("TX_STAT_UNSENT\n")); break; } else { - //dprintf("releasing TX descriptor to the ring\n"); info->txDescriptor[info->txInterruptIndex].wb_status = 0; } releaseTxSem++; // this many buffers are free @@ -580,7 +524,7 @@ wb_create_rings(struct wb_device *device) device->rxBuffer[i] = (void *)(((uint32)device->rxBuffer[0]) + (i * WB_BUFBYTES)); for (i = 0; i < WB_RX_LIST_CNT; i++) { - wb_free_rx_descriptor(&device->rxDescriptor[i]); + wb_put_rx_descriptor(&device->rxDescriptor[i]); device->rxDescriptor[i].wb_data = physicalAddress(device->rxBuffer[i], WB_BUFBYTES); device->rxDescriptor[i].wb_next = physicalAddress(&device->rxDescriptor[(i + 1) & WB_RX_CNT_MASK], sizeof(struct wb_desc)); @@ -639,7 +583,7 @@ wb_read_mode(wb_device *info) uint16 status = mii_readstatus(info); if (!(status & MII_STATUS_LINK)) { - //dprintf(DEVICE_NAME ": no link detected (status = %x)\n", status); + dprintf(DEVICE_NAME ": no link detected (status = %x)\n", status); return 0; } @@ -651,20 +595,11 @@ wb_read_mode(wb_device *info) speed = status & (MII_NWAY_TX | MII_NWAY_TX_FDX) ? LINK_SPEED_100_MBIT : LINK_SPEED_10_MBIT; duplex = status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX) ? LINK_FULL_DUPLEX : LINK_HALF_DUPLEX; - dprintf("status: 0x%x\n", status); info->autoNegotiationComplete = true; - // workaround for Realtek RTL8201 PHY issue - /*if (phy->id0 == PHY_ID0_REALTEK_8201 && (phy->id1 & 0xFFF0) == PHY_ID1_REALTEK_8201) { - if (mdio_read(info, MII_CONTROL) & MII_CONTROL_FULL_DUPLEX) - duplex = LINK_FULL_DUPLEX; - if (mdio_read(info, 0x0019) & 0x01) - speed = LINK_SPEED_100_MBIT; - } -*/ - //dprintf(DEVICE_NAME ": linked, 10%s MBit, %s duplex\n", - // speed == LINK_SPEED_100_MBIT ? "0" : "", - // duplex == LINK_FULL_DUPLEX ? "full" : "half"); + dprintf(DEVICE_NAME ": linked, 10%s MBit, %s duplex\n", + speed == LINK_SPEED_100_MBIT ? "0" : "", + duplex == LINK_FULL_DUPLEX ? "full" : "half"); return speed | duplex; } @@ -673,35 +608,37 @@ wb_read_mode(wb_device *info) void wb_set_mode(wb_device *info, int mode) { - /*uint32 address = (uint32)info->registers + SiS900_MAC_CONFIG; - uint32 txFlags = SiS900_Tx_AUTO_PADDING | SiS900_Tx_FILL_THRES; - uint32 rxFlags = 0; + uint32 cfgAddress = (uint32)info->reg_base + WB_NETCFG; int32 speed = mode & LINK_SPEED_MASK; + uint32 configFlags = 0; + + bool restart = false; + int32 i = 0; + + // Stop TX and RX queue. + if (read32(cfgAddress) & (WB_NETCFG_TX_ON|WB_NETCFG_RX_ON)) { + restart = 1; + WB_CLRBIT(cfgAddress, (WB_NETCFG_TX_ON|WB_NETCFG_RX_ON)); - if (read32(address) & SiS900_MAC_CONFIG_EDB_MASTER) { - TRACE((DEVICE_NAME ": EDB master is set!\n")); - txFlags |= 5 << SiS900_DMA_SHIFT; - rxFlags = 5 << SiS900_DMA_SHIFT; + for (i = 0; i < WB_TIMEOUT; i++) { + //delay(10) + if ((read32(info->reg_base + WB_ISR) & WB_ISR_TX_IDLE) && + (read32(info->reg_base + WB_ISR) & WB_ISR_RX_IDLE)) + break; + } + + if (i == WB_TIMEOUT) + dprintf(DEVICE_NAME" Failed to put RX and TX in idle state\n"); } + + if ((mode & LINK_DUPLEX_MASK) == LINK_FULL_DUPLEX) + configFlags |= WB_NETCFG_FULLDUPLEX; + + if (speed == LINK_SPEED_100_MBIT) + configFlags |= WB_NETCFG_100MBPS; - // link speed FIFO thresholds - - if (speed == LINK_SPEED_HOME || speed == LINK_SPEED_10_MBIT) { - rxFlags |= SiS900_Rx_10_MBIT_DRAIN_THRES; - txFlags |= SiS900_Tx_10_MBIT_DRAIN_THRES; - } else { - rxFlags |= SiS900_Rx_100_MBIT_DRAIN_THRES; - txFlags |= SiS900_Tx_100_MBIT_DRAIN_THRES; - } - - // duplex mode - - if ((mode & LINK_DUPLEX_MASK) == LINK_FULL_DUPLEX) { - txFlags |= SiS900_Tx_CS_IGNORE | SiS900_Tx_HB_IGNORE; - rxFlags |= SiS900_Rx_ACCEPT_Tx_PACKETS; - } - - write32((uint32)info->registers + SiS900_MAC_Tx_CONFIG, txFlags); - write32((uint32)info->registers + SiS900_MAC_Rx_CONFIG, rxFlags); -*/ + write32(cfgAddress, configFlags); + + if (restart) + WB_SETBIT(cfgAddress, WB_NETCFG_TX_ON|WB_NETCFG_RX_ON); } diff --git a/src/add-ons/kernel/drivers/network/wb840/wb840.h b/src/add-ons/kernel/drivers/network/wb840/wb840.h index f4678d7a47..e1dd09e899 100644 --- a/src/add-ons/kernel/drivers/network/wb840/wb840.h +++ b/src/add-ons/kernel/drivers/network/wb840/wb840.h @@ -324,11 +324,11 @@ struct wb_mii_frame { typedef struct wb_device wb_device; struct wb_device { + timer timer; int32 devId; pci_info* pciInfo; uint16 irq; /* IRQ line */ volatile uint32 reg_base; /* hardware register base address */ - timer timer; // rx data volatile wb_desc rxDescriptor[WB_RX_LIST_CNT]; @@ -370,10 +370,7 @@ struct wb_device { }; - - /* MII Interface */ - struct mii_phy { struct mii_phy *next; uint16 id0, id1; @@ -391,13 +388,6 @@ enum MII_address { MII_AUTONEG_ADV = 0x04, MII_AUTONEG_LINK_PARTNER = 0x05, MII_AUTONEG_EXT = 0x06 - - // SiS900 specific registers - /*MII_CONFIG1 = 0x10, - MII_CONFIG2 = 0x11, - MII_LINK_STATUS = 0x12, - MII_MASK = 0x13, - MII_RESERVED = 0x14*/ }; enum MII_control { @@ -498,7 +488,7 @@ extern void wb_set_mode(wb_device *device, int mode); extern int32 wb_read_mode(wb_device *device); extern int32 wb_tick(timer *arg); -extern void wb_free_rx_descriptor(wb_desc *desc); +extern void wb_put_rx_descriptor(wb_desc *desc); extern void print_address(ether_address_t *addr);