Some fixes, some warning fixed, added a lot of code for the MII handling (almost completely "stolen" from Axel's sis900 driver), not yet working.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6988 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -67,14 +67,13 @@ wb840_open(const char *name, uint32 flags, void** cookie)
|
|||||||
LOG(("wb840: reg_base=%x\n", (int)data->reg_base));
|
LOG(("wb840: reg_base=%x\n", (int)data->reg_base));
|
||||||
|
|
||||||
wb_read_eeprom(data, &data->myaddr, 0, 3, 0);
|
wb_read_eeprom(data, &data->myaddr, 0, 3, 0);
|
||||||
print_address((void*)&data->myaddr);
|
|
||||||
|
|
||||||
data->wb_cachesize = gPci->read_pci_config(data->pciInfo->bus, data->pciInfo->device,
|
data->wb_cachesize = gPci->read_pci_config(data->pciInfo->bus, data->pciInfo->device,
|
||||||
data->pciInfo->function, PCI_line_size, sizeof (PCI_line_size)) & 0xff;
|
data->pciInfo->function, PCI_line_size, sizeof (PCI_line_size)) & 0xff;
|
||||||
|
|
||||||
if (wb_create_semaphores(data) == B_OK) {
|
if (wb_create_semaphores(data) == B_OK) {
|
||||||
/* reset the card */
|
wb_initPHYs(data);
|
||||||
wb_reset(data);
|
wb_init(data);
|
||||||
|
|
||||||
/* Setup interrupts */
|
/* Setup interrupts */
|
||||||
data->irq = data->pciInfo->u.h0.interrupt_line;
|
data->irq = data->pciInfo->u.h0.interrupt_line;
|
||||||
@@ -87,15 +86,9 @@ wb840_open(const char *name, uint32 flags, void** cookie)
|
|||||||
WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_RX_ON);
|
WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_RX_ON);
|
||||||
write32(data->reg_base + WB_RXSTART, 0xFFFFFFFF);
|
write32(data->reg_base + WB_RXSTART, 0xFFFFFFFF);
|
||||||
WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_TX_ON);
|
WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_TX_ON);
|
||||||
//write32(data->reg_base + WB_TXSTART, 0xFFFFFFFF);
|
|
||||||
|
|
||||||
//dump_registers(data);
|
|
||||||
|
|
||||||
add_timer(&data->timer, wb_tick, 1000000LL, B_PERIODIC_TIMER);
|
add_timer(&data->timer, wb_tick, 1000000LL, B_PERIODIC_TIMER);
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
dump_registers(data);
|
|
||||||
#endif
|
|
||||||
return B_OK; // Everything after this line is an error
|
return B_OK; // Everything after this line is an error
|
||||||
|
|
||||||
} else
|
} else
|
||||||
@@ -149,11 +142,13 @@ wb840_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
|
|||||||
*num_bytes = 0;
|
*num_bytes = 0;
|
||||||
} else {
|
} else {
|
||||||
size = WB_RXBYTES(check);
|
size = WB_RXBYTES(check);
|
||||||
|
size -= CRC_SIZE;
|
||||||
LOG((DEVICE_NAME": received %d bytes\n", (int)size));
|
LOG((DEVICE_NAME": received %d bytes\n", (int)size));
|
||||||
if (size > WB_MAX_FRAMELEN || size > *num_bytes) {
|
if (size > WB_MAX_FRAMELEN || size > *num_bytes) {
|
||||||
LOG(("ERROR: Bad frame size: %d", (int)size));
|
LOG(("ERROR: Bad frame size: %d", (int)size));
|
||||||
size = *num_bytes;
|
size = *num_bytes;
|
||||||
}
|
}
|
||||||
|
*num_bytes = size;
|
||||||
memcpy(buf, (void *)device->rxBuffer[current], size);
|
memcpy(buf, (void *)device->rxBuffer[current], size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,42 +52,6 @@
|
|||||||
#define MII_DELAY(x) read32(x->reg_base + WB_SIO)
|
#define MII_DELAY(x) read32(x->reg_base + WB_SIO)
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
wb_eeprom_putbyte(wb_device *device, int addr)
|
|
||||||
{
|
|
||||||
int d, i;
|
|
||||||
int delay;
|
|
||||||
|
|
||||||
d = addr | WB_EECMD_READ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Feed in each bit and strobe the clock.
|
|
||||||
*/
|
|
||||||
for (i = 0x400; i; i >>= 1) {
|
|
||||||
if (d & i) {
|
|
||||||
SIO_SET(WB_SIO_EE_DATAIN);
|
|
||||||
} else {
|
|
||||||
SIO_CLR(WB_SIO_EE_DATAIN);
|
|
||||||
}
|
|
||||||
for (delay = 0; delay < 100; delay++)
|
|
||||||
MII_DELAY(device);
|
|
||||||
|
|
||||||
SIO_SET(WB_SIO_EE_CLK);
|
|
||||||
|
|
||||||
for (delay = 0; delay < 150; delay++)
|
|
||||||
MII_DELAY(device);
|
|
||||||
|
|
||||||
SIO_CLR(WB_SIO_EE_CLK);
|
|
||||||
|
|
||||||
for (delay = 0; delay < 100; delay++)
|
|
||||||
MII_DELAY(device);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mii_sync(struct wb_device *device)
|
mii_sync(struct wb_device *device)
|
||||||
{
|
{
|
||||||
@@ -269,7 +233,7 @@ wb_miibus_readreg(wb_device *device, int phy, int reg)
|
|||||||
frame.mii_regaddr = reg;
|
frame.mii_regaddr = reg;
|
||||||
wb_mii_readreg(device, &frame);
|
wb_mii_readreg(device, &frame);
|
||||||
|
|
||||||
return(frame.mii_data);
|
return frame.mii_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -299,6 +263,42 @@ wb_miibus_statchg(wb_device *device)
|
|||||||
|
|
||||||
#define EEPROM_DELAY(x) read32(x->reg_base + WB_SIO)
|
#define EEPROM_DELAY(x) read32(x->reg_base + WB_SIO)
|
||||||
|
|
||||||
|
void
|
||||||
|
wb_eeprom_putbyte(wb_device *device, int addr)
|
||||||
|
{
|
||||||
|
int d, i;
|
||||||
|
int delay;
|
||||||
|
|
||||||
|
d = addr | WB_EECMD_READ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Feed in each bit and strobe the clock.
|
||||||
|
*/
|
||||||
|
for (i = 0x400; i; i >>= 1) {
|
||||||
|
if (d & i) {
|
||||||
|
SIO_SET(WB_SIO_EE_DATAIN);
|
||||||
|
} else {
|
||||||
|
SIO_CLR(WB_SIO_EE_DATAIN);
|
||||||
|
}
|
||||||
|
for (delay = 0; delay < 100; delay++)
|
||||||
|
MII_DELAY(device);
|
||||||
|
|
||||||
|
SIO_SET(WB_SIO_EE_CLK);
|
||||||
|
|
||||||
|
for (delay = 0; delay < 150; delay++)
|
||||||
|
MII_DELAY(device);
|
||||||
|
|
||||||
|
SIO_CLR(WB_SIO_EE_CLK);
|
||||||
|
|
||||||
|
for (delay = 0; delay < 100; delay++)
|
||||||
|
MII_DELAY(device);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wb_eeprom_askdata(wb_device *device, int addr)
|
wb_eeprom_askdata(wb_device *device, int addr)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
#include "wb840.h"
|
#include "wb840.h"
|
||||||
|
|
||||||
extern void wb_read_eeprom(struct wb_device *, void* dest, int offset, int count, int swap);
|
extern void wb_read_eeprom(struct wb_device *, void* dest, int offset, int count, int swap);
|
||||||
extern uint16 mii_read(struct wb_device *, int phy_id, int location);
|
extern int wb_miibus_readreg(struct wb_device *, int phy_id, int location);
|
||||||
|
extern void wb_miibus_writereg(struct wb_device *, int phy, int location, int data);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,6 +18,40 @@
|
|||||||
|
|
||||||
#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
|
#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
|
||||||
|
|
||||||
|
// MII chip info table
|
||||||
|
|
||||||
|
#define PHY_ID0_WB840_INTERNAL 0x0181
|
||||||
|
#define PHY_ID1_WB840_INTERNAL 0xb800
|
||||||
|
#define MII_HOME 0x0001
|
||||||
|
#define MII_LAN 0x0002
|
||||||
|
|
||||||
|
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},
|
||||||
|
{NULL,0,0,0}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
mii_readstatus(wb_device *device)
|
||||||
|
{
|
||||||
|
// status bit has to be retrieved 2 times
|
||||||
|
int i = 0;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
while (i++ < 2)
|
||||||
|
status = wb_miibus_readreg(device, device->phy, MII_STATUS);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint32
|
static uint32
|
||||||
physicalAddress(volatile void *addr, uint32 length)
|
physicalAddress(volatile void *addr, uint32 length)
|
||||||
{
|
{
|
||||||
@@ -85,35 +119,117 @@ wb_disable_interrupts(struct wb_device *device)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
wb_reset(wb_device *device)
|
wb_selectPHY(wb_device *device)
|
||||||
{
|
{
|
||||||
int i = 0;
|
uint16 status;
|
||||||
cpu_status status;
|
|
||||||
|
|
||||||
LOG((DEVICE_NAME": reset()\n"));
|
// ToDo: need to be changed, select PHY in relation to the link mode
|
||||||
|
device->currentPHY = device->firstPHY;
|
||||||
|
device->phy = device->currentPHY->address;
|
||||||
|
status = wb_miibus_readreg(device, device->phy, MII_CONTROL);
|
||||||
|
status &= ~MII_CONTROL_ISOLATE;
|
||||||
|
|
||||||
status = disable_interrupts();
|
wb_miibus_writereg(device, device->phy, MII_CONTROL, status);
|
||||||
|
}
|
||||||
|
|
||||||
device->wb_txthresh = WB_TXTHRESH_INIT;
|
|
||||||
|
|
||||||
write32(device->reg_base + WB_NETCFG, 0L);
|
uint16
|
||||||
write32(device->reg_base + WB_BUSCTL, 0L);
|
wb_resetPHY(wb_device *device)
|
||||||
write32(device->reg_base + WB_TXADDR, 0L);
|
{
|
||||||
write32(device->reg_base + WB_RXADDR, 0L);
|
uint16 status = mii_readstatus(device);
|
||||||
|
dprintf("wb_resetPHY: %d\n", status);
|
||||||
|
wb_miibus_writereg(device, device->phy, MII_CONTROL, MII_CONTROL_RESET);
|
||||||
|
|
||||||
WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET);
|
return status;
|
||||||
WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET);
|
}
|
||||||
|
|
||||||
for (i = 0; i < WB_TIMEOUT; i++) {
|
|
||||||
if (!(read32(device->reg_base + WB_BUSCTL) & WB_BUSCTL_RESET))
|
status_t
|
||||||
break;
|
wb_initPHYs(wb_device *device)
|
||||||
|
{
|
||||||
|
uint16 phy;
|
||||||
|
// search for total of 32 possible MII PHY addresses
|
||||||
|
for (phy = 0; phy < 32; phy++) {
|
||||||
|
struct mii_phy *mii;
|
||||||
|
uint16 status;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
status = wb_miibus_readreg(device, phy, MII_STATUS);
|
||||||
|
status = wb_miibus_readreg(device, phy, MII_STATUS);
|
||||||
|
|
||||||
|
if (status == 0xffff || status == 0x0000)
|
||||||
|
// this MII is not accessable
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mii = (struct mii_phy *)malloc(sizeof(struct mii_phy));
|
||||||
|
if (mii == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
mii->address = phy;
|
||||||
|
mii->id0 = wb_miibus_readreg(device, phy, MII_PHY_ID0);
|
||||||
|
mii->id1 = wb_miibus_readreg(device, phy, MII_PHY_ID1);
|
||||||
|
mii->types = MII_HOME;
|
||||||
|
mii->next = device->firstPHY;
|
||||||
|
device->firstPHY = mii;
|
||||||
|
|
||||||
|
while (gMIIChips[i].name != NULL) {
|
||||||
|
if (gMIIChips[i].id0 == mii->id0 && gMIIChips[i].id1 == (mii->id1 & 0xfff0)) {
|
||||||
|
dprintf("Found MII PHY: %s\n", gMIIChips[i].name);
|
||||||
|
mii->types = gMIIChips[i].types;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (gMIIChips[i].name == NULL)
|
||||||
|
dprintf("Unknown MII PHY transceiver: id = (%x, %x).\n",mii->id0, mii->id1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == WB_TIMEOUT)
|
if (device->firstPHY == NULL) {
|
||||||
LOG(("reset hasn't completed!!!"));
|
dprintf("No MII PHY transceiver found!\n");
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
write32(device->reg_base + WB_BUSCTL, WB_BUSCTL_MUSTBEONE|WB_BUSCTL_ARBITRATION);
|
wb_selectPHY(device);
|
||||||
WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BURSTLEN_16LONG);
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
wb_init(wb_device *device)
|
||||||
|
{
|
||||||
|
LOG((DEVICE_NAME": init()\n"));
|
||||||
|
|
||||||
|
wb_reset(device);
|
||||||
|
|
||||||
|
device->wb_txthresh = WB_TXTHRESH_INIT;
|
||||||
|
|
||||||
switch(device->wb_cachesize) {
|
switch(device->wb_cachesize) {
|
||||||
case 32:
|
case 32:
|
||||||
@@ -131,6 +247,9 @@ wb_reset(wb_device *device)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write32(device->reg_base + WB_BUSCTL, WB_BUSCTL_MUSTBEONE|WB_BUSCTL_ARBITRATION);
|
||||||
|
WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BURSTLEN_16LONG);
|
||||||
|
|
||||||
write32(device->reg_base + WB_BUSCTL_SKIPLEN, WB_SKIPLEN_4LONG);
|
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; doesn't tend to work too well at 100Mbps */
|
||||||
@@ -150,6 +269,35 @@ wb_reset(wb_device *device)
|
|||||||
|
|
||||||
//Disable capture broadcast
|
//Disable capture broadcast
|
||||||
WB_CLRBIT(device->reg_base + WB_NETCFG, WB_NETCFG_RX_BROAD);
|
WB_CLRBIT(device->reg_base + WB_NETCFG, WB_NETCFG_RX_BROAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
write32(device->reg_base + WB_RXADDR, 0L);
|
||||||
|
|
||||||
|
WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET);
|
||||||
|
WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET);
|
||||||
|
|
||||||
|
for (i = 0; i < WB_TIMEOUT; i++) {
|
||||||
|
if (!(read32(device->reg_base + WB_BUSCTL) & WB_BUSCTL_RESET))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == WB_TIMEOUT)
|
||||||
|
LOG(("reset hasn't completed!!!"));
|
||||||
|
|
||||||
restore_interrupts(status);
|
restore_interrupts(status);
|
||||||
|
|
||||||
@@ -159,9 +307,42 @@ wb_reset(wb_device *device)
|
|||||||
//XXX Initialize MII interface
|
//XXX Initialize MII interface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
wb_updateLink(struct wb_device *device)
|
wb_updateLink(struct wb_device *device)
|
||||||
{
|
{
|
||||||
|
if (!device->autoNegotiationComplete) {
|
||||||
|
int32 mode = wb_read_mode(device);
|
||||||
|
if (mode)
|
||||||
|
wb_set_mode(device, mode);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device->link) { // link lost
|
||||||
|
uint16 status = mii_readstatus(device);
|
||||||
|
|
||||||
|
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
|
||||||
|
uint16 status;
|
||||||
|
|
||||||
|
wb_selectPHY(device);
|
||||||
|
|
||||||
|
status = mii_readstatus(device);
|
||||||
|
if (status & MII_STATUS_LINK) {
|
||||||
|
//sis900_checkMode(device);
|
||||||
|
device->link = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -362,17 +543,19 @@ wb_create_semaphores(struct wb_device *device)
|
|||||||
{
|
{
|
||||||
device->rxSem = create_sem(0, "wb840 receive");
|
device->rxSem = create_sem(0, "wb840 receive");
|
||||||
if (device->rxSem < B_OK) {
|
if (device->rxSem < B_OK) {
|
||||||
LOG(("Couldn't create sem, sem_id %d\n", (int)device->rxSem));
|
LOG(("Couldn't create sem, sem_id %ld\n", device->rxSem));
|
||||||
return device->rxSem;
|
return device->rxSem;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_sem_owner(device->rxSem, B_SYSTEM_TEAM);
|
set_sem_owner(device->rxSem, B_SYSTEM_TEAM);
|
||||||
|
|
||||||
device->txSem = create_sem(WB_TX_LIST_CNT, "wb840 transmit");
|
device->txSem = create_sem(WB_TX_LIST_CNT, "wb840 transmit");
|
||||||
if (device->txSem < B_OK) {
|
if (device->txSem < B_OK) {
|
||||||
LOG(("Couldn't create sem, sem_id %d\n", (int)device->txSem));
|
LOG(("Couldn't create sem, sem_id %ld\n", device->txSem));
|
||||||
delete_sem(device->rxSem);
|
delete_sem(device->rxSem);
|
||||||
return device->txSem;
|
return device->txSem;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_sem_owner(device->txSem, B_SYSTEM_TEAM);
|
set_sem_owner(device->txSem, B_SYSTEM_TEAM);
|
||||||
|
|
||||||
device->rxLock = 0;
|
device->rxLock = 0;
|
||||||
@@ -387,9 +570,10 @@ wb_create_rings(struct wb_device *device)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if ((device->rxArea = create_area("wb840 rx buffer", (void **)&device->rxBuffer[0],
|
device->rxArea = create_area("wb840 rx buffer", (void **)&device->rxBuffer[0],
|
||||||
B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(WB_BUFBYTES * WB_RX_LIST_CNT),
|
B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(WB_BUFBYTES * WB_RX_LIST_CNT),
|
||||||
B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA)) < B_OK)
|
B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
|
||||||
|
if (device->rxArea < B_OK)
|
||||||
return device->rxArea;
|
return device->rxArea;
|
||||||
|
|
||||||
for (i = 1; i < WB_RX_LIST_CNT; i++)
|
for (i = 1; i < WB_RX_LIST_CNT; i++)
|
||||||
@@ -404,9 +588,10 @@ wb_create_rings(struct wb_device *device)
|
|||||||
device->rxFree = WB_RX_LIST_CNT;
|
device->rxFree = WB_RX_LIST_CNT;
|
||||||
device->rxDescriptor[WB_RX_LIST_CNT - 1].wb_ctl |= WB_RXCTL_RLAST;
|
device->rxDescriptor[WB_RX_LIST_CNT - 1].wb_ctl |= WB_RXCTL_RLAST;
|
||||||
|
|
||||||
if ((device->txArea = create_area("wb840 tx buffer", (void **)&device->txBuffer[0],
|
device->txArea = create_area("wb840 tx buffer", (void **)&device->txBuffer[0],
|
||||||
B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(WB_BUFBYTES * WB_TX_LIST_CNT),
|
B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(WB_BUFBYTES * WB_TX_LIST_CNT),
|
||||||
B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA)) < B_OK) {
|
B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
|
||||||
|
if (device->txArea < B_OK) {
|
||||||
delete_area(device->rxArea);
|
delete_area(device->rxArea);
|
||||||
return device->txArea;
|
return device->txArea;
|
||||||
}
|
}
|
||||||
@@ -444,3 +629,79 @@ wb_delete_rings(struct wb_device *device)
|
|||||||
delete_area(device->rxArea);
|
delete_area(device->rxArea);
|
||||||
delete_area(device->txArea);
|
delete_area(device->txArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
wb_read_mode(wb_device *info)
|
||||||
|
{
|
||||||
|
uint16 autoAdv, autoLinkPartner;
|
||||||
|
int32 speed, duplex;
|
||||||
|
|
||||||
|
uint16 status = mii_readstatus(info);
|
||||||
|
if (!(status & MII_STATUS_LINK)) {
|
||||||
|
//dprintf(DEVICE_NAME ": no link detected (status = %x)\n", status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// auto negotiation completed
|
||||||
|
autoAdv = wb_miibus_readreg(info, info->phy, MII_AUTONEG_ADV);
|
||||||
|
autoLinkPartner = wb_miibus_readreg(info, info->phy, MII_AUTONEG_LINK_PARTNER);
|
||||||
|
status = autoAdv & autoLinkPartner;
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
return speed | duplex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
int32 speed = mode & LINK_SPEED_MASK;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|||||||
@@ -197,17 +197,13 @@ enum interruptMaskBits {
|
|||||||
WB_IMR_ABNORMAL = 0x00008000,
|
WB_IMR_ABNORMAL = 0x00008000,
|
||||||
WB_IMR_NORMAL = 0x00010000,
|
WB_IMR_NORMAL = 0x00010000,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WB_INTRS \
|
#define WB_INTRS \
|
||||||
(WB_IMR_RX_OK|WB_IMR_RX_IDLE|WB_IMR_RX_ERR|WB_IMR_TX_OK| \
|
(WB_IMR_RX_OK|WB_IMR_RX_IDLE|WB_IMR_RX_ERR|WB_IMR_TX_OK| \
|
||||||
WB_IMR_RX_NOBUF|WB_IMR_RX_ERR|WB_IMR_RX_EARLY| \
|
WB_IMR_RX_NOBUF|WB_IMR_RX_ERR|WB_IMR_RX_EARLY| \
|
||||||
WB_IMR_TX_NOBUF|WB_IMR_TX_UNDERRUN|WB_IMR_BUS_ERR| \
|
WB_IMR_TX_NOBUF|WB_IMR_TX_UNDERRUN|WB_IMR_BUS_ERR| \
|
||||||
WB_IMR_ABNORMAL|WB_IMR_NORMAL|WB_IMR_TX_EARLY)
|
WB_IMR_ABNORMAL|WB_IMR_NORMAL|WB_IMR_TX_EARLY)
|
||||||
|
|
||||||
/*#define WB_INTRS \
|
|
||||||
(WB_IMR_RX_OK|WB_IMR_TX_OK|WB_IMR_RX_ERR| \
|
|
||||||
WB_IMR_TX_UNDERRUN|WB_IMR_BUS_ERR| \
|
|
||||||
WB_IMR_ABNORMAL|WB_IMR_NORMAL|WB_IMR_TX_EARLY)
|
|
||||||
*/
|
|
||||||
/*
|
/*
|
||||||
* Serial I/O (EEPROM/ROM) bits.
|
* Serial I/O (EEPROM/ROM) bits.
|
||||||
*/
|
*/
|
||||||
@@ -300,11 +296,12 @@ struct wb_desc {
|
|||||||
#define WB_MAX_FRAMELEN 1536
|
#define WB_MAX_FRAMELEN 1536
|
||||||
|
|
||||||
#define WB_UNSENT 0x1234
|
#define WB_UNSENT 0x1234
|
||||||
#define WB_BUFBYTES (1024 * sizeof(uint32))
|
#define WB_BUFBYTES 2048
|
||||||
|
|
||||||
/* Ethernet defines */
|
/* Ethernet defines */
|
||||||
#define CRC_SIZE 4
|
#define CRC_SIZE 4
|
||||||
#define ETHER_TRANSMIT_TIMEOUT ((bigtime_t)5000000) /* five seconds */
|
#define ETHER_TRANSMIT_TIMEOUT ((bigtime_t)5000000) /* five seconds */
|
||||||
|
#define WB_TIMEOUT 1000
|
||||||
|
|
||||||
typedef struct wb_mii_frame wb_mii_frame;
|
typedef struct wb_mii_frame wb_mii_frame;
|
||||||
struct wb_mii_frame {
|
struct wb_mii_frame {
|
||||||
@@ -355,9 +352,15 @@ struct wb_device {
|
|||||||
int16 txInterruptIndex;
|
int16 txInterruptIndex;
|
||||||
int16 txSent;
|
int16 txSent;
|
||||||
|
|
||||||
|
struct mii_phy *firstPHY;
|
||||||
|
struct mii_phy *currentPHY;
|
||||||
|
uint16 phy;
|
||||||
|
bool autoNegotiationComplete;
|
||||||
|
bool link;
|
||||||
|
uint16 fixedMode;
|
||||||
|
|
||||||
volatile int32 blockFlag;
|
volatile int32 blockFlag;
|
||||||
ether_address_t myaddr; /* my ethernet address */
|
ether_address_t myaddr;
|
||||||
//volatile int interrupted; /* interrupted system call */
|
|
||||||
|
|
||||||
spinlock intLock;
|
spinlock intLock;
|
||||||
const char* deviceName;
|
const char* deviceName;
|
||||||
@@ -366,7 +369,99 @@ struct wb_device {
|
|||||||
int wb_cachesize;
|
int wb_cachesize;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WB_TIMEOUT 1000
|
|
||||||
|
|
||||||
|
|
||||||
|
/* MII Interface */
|
||||||
|
|
||||||
|
struct mii_phy {
|
||||||
|
struct mii_phy *next;
|
||||||
|
uint16 id0, id1;
|
||||||
|
uint16 address;
|
||||||
|
uint8 types;
|
||||||
|
};
|
||||||
|
|
||||||
|
// taken from Axel's Sis900 driver
|
||||||
|
enum MII_address {
|
||||||
|
// standard registers
|
||||||
|
MII_CONTROL = 0x00,
|
||||||
|
MII_STATUS = 0x01,
|
||||||
|
MII_PHY_ID0 = 0x02,
|
||||||
|
MII_PHY_ID1 = 0x03,
|
||||||
|
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 {
|
||||||
|
MII_CONTROL_RESET = 0x8000,
|
||||||
|
MII_CONTROL_RESET_AUTONEG = 0x0200,
|
||||||
|
MII_CONTROL_AUTO = 0x1000,
|
||||||
|
MII_CONTROL_FULL_DUPLEX = 0x0100,
|
||||||
|
MII_CONTROL_ISOLATE = 0x0400
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MII_commands {
|
||||||
|
MII_CMD_READ = 0x6000,
|
||||||
|
MII_CMD_WRITE = 0x5002,
|
||||||
|
|
||||||
|
MII_PHY_SHIFT = 7,
|
||||||
|
MII_REG_SHIFT = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MII_status_bits {
|
||||||
|
MII_STATUS_EXT = 0x0001,
|
||||||
|
MII_STATUS_JAB = 0x0002,
|
||||||
|
MII_STATUS_LINK = 0x0004,
|
||||||
|
MII_STATUS_CAN_AUTO = 0x0008,
|
||||||
|
MII_STATUS_FAULT = 0x0010,
|
||||||
|
MII_STATUS_AUTO_DONE = 0x0020,
|
||||||
|
MII_STATUS_CAN_T = 0x0800,
|
||||||
|
MII_STATUS_CAN_T_FDX = 0x1000,
|
||||||
|
MII_STATUS_CAN_TX = 0x2000,
|
||||||
|
MII_STATUS_CAN_TX_FDX = 0x4000,
|
||||||
|
MII_STATUS_CAN_T4 = 0x8000
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MII_auto_negotiation {
|
||||||
|
MII_NWAY_NODE_SEL = 0x001f,
|
||||||
|
MII_NWAY_CSMA_CD = 0x0001,
|
||||||
|
MII_NWAY_T = 0x0020,
|
||||||
|
MII_NWAY_T_FDX = 0x0040,
|
||||||
|
MII_NWAY_TX = 0x0080,
|
||||||
|
MII_NWAY_TX_FDX = 0x0100,
|
||||||
|
MII_NWAY_T4 = 0x0200,
|
||||||
|
MII_NWAY_PAUSE = 0x0400,
|
||||||
|
MII_NWAY_RF = 0x2000,
|
||||||
|
MII_NWAY_ACK = 0x4000,
|
||||||
|
MII_NWAY_NP = 0x8000
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum MII_link_status {
|
||||||
|
MII_LINK_FAIL = 0x4000,
|
||||||
|
MII_LINK_100_MBIT = 0x0080,
|
||||||
|
MII_LINK_FULL_DUPLEX = 0x0040
|
||||||
|
};
|
||||||
|
|
||||||
|
enum link_modes {
|
||||||
|
LINK_HALF_DUPLEX = 0x0100,
|
||||||
|
LINK_FULL_DUPLEX = 0x0200,
|
||||||
|
LINK_DUPLEX_MASK = 0xff00,
|
||||||
|
|
||||||
|
LINK_SPEED_HOME = 1,
|
||||||
|
LINK_SPEED_10_MBIT = 10,
|
||||||
|
LINK_SPEED_100_MBIT = 100,
|
||||||
|
LINK_SPEED_DEFAULT = LINK_SPEED_100_MBIT,
|
||||||
|
LINK_SPEED_MASK = 0x00ff
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Vendor and Card IDs
|
* Vendor and Card IDs
|
||||||
@@ -387,13 +482,24 @@ struct wb_device {
|
|||||||
|
|
||||||
// Prototypes
|
// Prototypes
|
||||||
extern int32 wb_interrupt(void *arg);
|
extern int32 wb_interrupt(void *arg);
|
||||||
extern status_t wb_create_semaphores(struct wb_device *device);
|
extern status_t wb_create_semaphores(wb_device *device);
|
||||||
extern status_t wb_create_rings(struct wb_device *device);
|
extern status_t wb_create_rings(wb_device *device);
|
||||||
extern void wb_delete_rings(wb_device *device);
|
extern void wb_delete_rings(wb_device *device);
|
||||||
|
|
||||||
|
extern void wb_init(wb_device *device);
|
||||||
extern void wb_reset(wb_device *device);
|
extern void wb_reset(wb_device *device);
|
||||||
|
|
||||||
|
extern status_t wb_initPHYs(wb_device *device);
|
||||||
|
|
||||||
extern void wb_disable_interrupts(wb_device *device);
|
extern void wb_disable_interrupts(wb_device *device);
|
||||||
extern void wb_enable_interrupts(wb_device *device);
|
extern void wb_enable_interrupts(wb_device *device);
|
||||||
|
|
||||||
|
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 int32 wb_tick(timer *arg);
|
||||||
extern void wb_free_rx_descriptor(wb_desc *desc);
|
extern void wb_free_rx_descriptor(wb_desc *desc);
|
||||||
|
|
||||||
|
extern void print_address(ether_address_t *addr);
|
||||||
|
|
||||||
#endif //__WB840_H
|
#endif //__WB840_H
|
||||||
|
|||||||
Reference in New Issue
Block a user