Implemented link detection and speed autonegotiation

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7098 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini 2004-03-29 06:36:33 +00:00
parent 725c92923a
commit 684349b37a
4 changed files with 55 additions and 130 deletions

View File

@ -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);

View File

@ -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.
*/

View File

@ -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);
}

View File

@ -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);