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:
parent
725c92923a
commit
684349b37a
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user