Almost completely rewritten the interrupt handler, some cleanups

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7164 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini
2004-04-05 07:06:26 +00:00
parent 0029e79802
commit 85bbb77938
4 changed files with 71 additions and 107 deletions
@@ -4,9 +4,9 @@
#define ARGS (const char *, ...) #define ARGS (const char *, ...)
#ifdef DEBUG #ifdef DEBUG
#define LOG(ARGS) dprintf ARGS #define LOG(ARGS) dprintf ARGS
#else #else
#define LOG(ARGS) ; #define LOG(ARGS)
#endif // DEBUG #endif // DEBUG
#endif //__MYDEBUG_H #endif //__MYDEBUG_H
@@ -319,13 +319,15 @@ wb840_free(void* cookie)
gOpenMask &= ~(1L << device->devId); gOpenMask &= ~(1L << device->devId);
wb_delete_rings(device); wb_delete_rings(device);
free(device->firstPHY);
free(device); free(device);
return B_OK; return B_OK;
} }
device_hooks gDeviceHooks = { device_hooks
gDeviceHooks = {
wb840_open, /* -> open entry point */ wb840_open, /* -> open entry point */
wb840_close, /* -> close entry point */ wb840_close, /* -> close entry point */
wb840_free, /* -> free cookie */ wb840_free, /* -> free cookie */
@@ -22,6 +22,7 @@ pci_module_info *gPci;
char* gDevNameList[MAX_CARDS + 1]; char* gDevNameList[MAX_CARDS + 1];
pci_info *gDevList[MAX_CARDS]; pci_info *gDevList[MAX_CARDS];
static bool static bool
probe(pci_info *item) probe(pci_info *item)
{ {
@@ -120,8 +121,8 @@ publish_devices()
device_hooks* device_hooks*
find_device(const char* name) find_device(const char* name)
{ {
int32 i; int32 i;
char *item; char *item;
LOG((DEVICE_NAME ": find_device()\n")); LOG((DEVICE_NAME ": find_device()\n"));
// Find device name // Find device name
+63 -102
View File
@@ -1,7 +1,8 @@
/* Copyright (c) 2003-2004 /* Copyright (c) 2003-2004
* Stefano Ceccherini <[email protected]>. All rights reserved. * Stefano Ceccherini <[email protected]>. All rights reserved.
*/ */
#define DEBUG 1
#include "device.h" #include "device.h"
#include "driver.h" #include "driver.h"
#include "debug.h" #include "debug.h"
@@ -19,20 +20,22 @@
#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 // MII chip info table
#define PHY_ID0_DAVICOM_DM9101 0x0181 #define PHY_ID0_DAVICOM_DM9101 0x0181
#define PHY_ID1_DAVICOM_DM9101 0xb800 #define PHY_ID1_DAVICOM_DM9101 0xb800
#define MII_HOME 0x0001 #define MII_HOME 0x0001
#define MII_LAN 0x0002 #define MII_LAN 0x0002
const static struct mii_chip_info struct mii_chip_info
{ {
const char *name; const char *name;
uint16 id0, id1; uint16 id0, id1;
uint8 types; uint8 types;
} };
const static struct mii_chip_info
gMIIChips[] = { gMIIChips[] = {
{"DAVICOM_DM9101 MII PHY", PHY_ID0_DAVICOM_DM9101, PHY_ID1_DAVICOM_DM9101, MII_LAN}, {"DAVICOM_DM9101", PHY_ID0_DAVICOM_DM9101, PHY_ID1_DAVICOM_DM9101, MII_LAN},
{NULL,0,0,0} {NULL,0,0,0}
}; };
@@ -62,36 +65,6 @@ physicalAddress(volatile void *addr, uint32 length)
} }
#if DEBUG
static void
dump_registers(wb_device *device)
{
LOG(("Registers dump:\n"));
LOG(("WB_BUSCTL: %x\n", (int)read32(device->reg_base + WB_BUSCTL)));
LOG(("WB_TXSTART: %x\n", (int)read32(device->reg_base + WB_TXSTART)));
LOG(("WB_RXSTART: %x\n", (int)read32(device->reg_base + WB_RXSTART)));
LOG(("WB_RXADDR: %x\n", (int)read32(device->reg_base + WB_RXADDR)));
LOG(("WB_TXADDR: %x\n", (int)read32(device->reg_base + WB_TXADDR)));
LOG(("WB_ISR: %x\n", (int)read32(device->reg_base + WB_ISR)));
LOG(("WB_NETCFG: %x\n", (int)read32(device->reg_base + WB_NETCFG)));
LOG(("WB_IMR: %x\n", (int)read32(device->reg_base + WB_IMR)));
LOG(("WB_FRAMESDISCARDED: %x\n", (int)read32(device->reg_base + WB_FRAMESDISCARDED)));
LOG(("WB_SIO: %x\n", (int)read32(device->reg_base + WB_SIO)));
LOG(("WB_BOOTROMADDR: %x\n", (int)read32(device->reg_base + WB_BOOTROMADDR)));
LOG(("WB_TIMER: %x\n", (int)read32(device->reg_base + WB_TIMER)));
LOG(("WB_CURRXCTL: %x\n", (int)read32(device->reg_base + WB_CURRXCTL)));
LOG(("WB_CURRXBUF: %x\n", (int)read32(device->reg_base + WB_CURRXBUF)));
LOG(("WB_MAR0: %x\n", (int)read32(device->reg_base + WB_MAR0)));
LOG(("WB_MAR1: %x\n", (int)read32(device->reg_base + WB_MAR1)));
LOG(("WB_NODE0: %x\n", (int)read32(device->reg_base + WB_NODE0)));
LOG(("WB_NODE1: %x\n", (int)read32(device->reg_base + WB_NODE1)));
LOG(("WB_BOOTROMSIZE: %x\n", (int)read32(device->reg_base + WB_BOOTROMSIZE)));
LOG(("WB_CURTXCTL: %x\n", (int)read32(device->reg_base + WB_CURTXCTL)));
LOG(("WB_CURTXBUF: %x\n", (int)read32(device->reg_base + WB_CURTXBUF)));
}
#endif
// Prepares a RX descriptor to be used by the chip // Prepares a RX descriptor to be used by the chip
void void
wb_put_rx_descriptor(wb_desc *descriptor) wb_put_rx_descriptor(wb_desc *descriptor)
@@ -216,18 +189,9 @@ wb_init(wb_device *device)
write32(device->reg_base + WB_BUSCTL_SKIPLEN, WB_SKIPLEN_4LONG); write32(device->reg_base + WB_BUSCTL_SKIPLEN, WB_SKIPLEN_4LONG);
// Early TX interrupt // Enable early TX/RX interrupt
WB_SETBIT(device->reg_base + WB_NETCFG, (WB_NETCFG_TX_EARLY_ON|WB_NETCFG_RX_EARLY_ON)); 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);
//100 MBits
//WB_SETBIT(device->reg_base + WB_NETCFG, WB_NETCFG_100MBPS);
/* Program the multicast filter, if necessary */
//wb_setmulti(device);
//Disable promiscuos mode //Disable promiscuos mode
WB_CLRBIT(device->reg_base + WB_NETCFG, WB_NETCFG_RX_ALLPHYS); WB_CLRBIT(device->reg_base + WB_NETCFG, WB_NETCFG_RX_ALLPHYS);
@@ -257,7 +221,7 @@ wb_reset(wb_device *device)
} }
if (i == WB_TIMEOUT) if (i == WB_TIMEOUT)
LOG(("reset hasn't completed!!!")); LOG((DEVICE_NAME": reset hasn't completed!!!"));
/* Wait a bit while the chip reorders his toughts */ /* Wait a bit while the chip reorders his toughts */
snooze(1000); snooze(1000);
@@ -275,17 +239,17 @@ wb_updateLink(struct wb_device *device)
return; return;
} }
if (device->link) { // link lost if (device->link) {
uint16 status = mii_readstatus(device); uint16 status = mii_readstatus(device);
// Check if link lost
if ((status & MII_STATUS_LINK) == 0) if ((status & MII_STATUS_LINK) == 0)
device->link = false; device->link = false;
} } else {
if (!device->link) { // new link established
uint16 status; uint16 status;
wb_selectPHY(device); wb_selectPHY(device);
// Check if we have a new link
status = mii_readstatus(device); status = mii_readstatus(device);
if (status & MII_STATUS_LINK) if (status & MII_STATUS_LINK)
device->link = true; device->link = true;
@@ -304,12 +268,11 @@ wb_tick(timer *arg)
} }
/***************** Interrupt handling ******************************/ /***************** Interrupt handling ******************************/
status_t static status_t
wb_rxok(struct wb_device *device) wb_rxok(struct wb_device *device)
{ {
uint32 releaseRxSem = 0; uint32 releaseRxSem = 0;
int16 limit; int16 limit;
LOG(("Rx interrupt\n"));
acquire_spinlock(&device->rxSpinlock); acquire_spinlock(&device->rxSpinlock);
@@ -327,10 +290,8 @@ wb_rxok(struct wb_device *device)
write32(device->reg_base + WB_RXSTART, 0xFFFFFFFF); write32(device->reg_base + WB_RXSTART, 0xFFFFFFFF);
release_spinlock(&device->rxSpinlock); release_spinlock(&device->rxSpinlock);
if (releaseRxSem > 0) { if (releaseRxSem > 0) {
//dprintf("releasing read sem %d times\n", releaseRxSem);
release_sem_etc(device->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE); release_sem_etc(device->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE);
return B_INVOKE_SCHEDULER; return B_INVOKE_SCHEDULER;
} }
@@ -339,7 +300,7 @@ wb_rxok(struct wb_device *device)
} }
status_t static status_t
wb_tx_nobuf(struct wb_device *info) wb_tx_nobuf(struct wb_device *info)
{ {
int16 releaseTxSem = 0; int16 releaseTxSem = 0;
@@ -350,16 +311,20 @@ wb_tx_nobuf(struct wb_device *info)
for (limit = info->txSent; limit > 0; limit--) { for (limit = info->txSent; limit > 0; limit--) {
status = info->txDescriptor[info->txInterruptIndex].wb_status; status = info->txDescriptor[info->txInterruptIndex].wb_status;
LOG(("wb_tx_nobuf, status: %lx\n", status));
if (status & WB_TXSTAT_TXERR) { if (status & WB_TXSTAT_TXERR) {
LOG(("TX_STAT_ERR\n")); LOG(("TX_STAT_ERR\n"));
break; break;
} else if (status & WB_UNSENT) { } else if (status & WB_UNSENT) {
LOG(("TX_STAT_UNSENT\n")); LOG(("TX_STAT_UNSENT\n"));
break; break;
} else { } else if (status & WB_TXSTAT_OWN) {
LOG((DEVICE_NAME": Device still owns the descriptor\n"));
break;
} else
info->txDescriptor[info->txInterruptIndex].wb_status = 0; info->txDescriptor[info->txInterruptIndex].wb_status = 0;
}
releaseTxSem++; // this many buffers are free releaseTxSem++; // this many buffers are free
info->txInterruptIndex = (info->txInterruptIndex + 1) & WB_TX_CNT_MASK; info->txInterruptIndex = (info->txInterruptIndex + 1) & WB_TX_CNT_MASK;
info->txSent--; info->txSent--;
@@ -384,78 +349,76 @@ wb_interrupt(void *arg)
{ {
struct wb_device *device = (wb_device*)arg; struct wb_device *device = (wb_device*)arg;
int32 retval = B_UNHANDLED_INTERRUPT; int32 retval = B_UNHANDLED_INTERRUPT;
int16 worklimit = 20;
uint32 status; uint32 status;
acquire_spinlock(&device->intLock); acquire_spinlock(&device->intLock);
wb_disable_interrupts(device); wb_disable_interrupts(device);
while (worklimit-- > 0) { status = read32(device->reg_base + WB_ISR);
status = read32(device->reg_base + WB_ISR);
/* Is our card the one which requested the interrupt ? */ // Did this card request the interrupt ?
if (!(status & WB_INTRS)) { if (status & WB_INTRS) {
/* No, bail out. */ // Clean all the interrupts bits
break;
}
// Clean all the interrupts
if (status) if (status)
write32(device->reg_base + WB_ISR, status); write32(device->reg_base + WB_ISR, status);
LOG((DEVICE_NAME":*** Interrupt received ***\n")); if (status & WB_ISR_ABNORMAL)
LOG((DEVICE_NAME": *** Abnormal Interrupt received ***\n"));
else
LOG((DEVICE_NAME": interrupt received: \n"));
if (status & WB_ISR_RX_EARLY) {
LOG(("WB_ISR_RX_EARLY\n"));
}
if (status & WB_ISR_RX_NOBUF) { if (status & WB_ISR_RX_NOBUF) {
LOG((DEVICE_NAME ": WB_ISR_RX_NOBUF\n")); LOG(("WB_ISR_RX_NOBUF\n"));
//retval = wb_rx_nobuf(device); // Something is screwed
continue;
} }
if (status & WB_ISR_RX_ERR) { if (status & WB_ISR_RX_ERR) {
LOG((DEVICE_NAME": WB_ISR_RX_ERR\n")); LOG(("WB_ISR_RX_ERR\n"));
continue; // TODO: Do something useful
} }
if (status & WB_ISR_RX_OK) { if (status & WB_ISR_RX_OK) {
LOG((DEVICE_NAME": WB_ISR_RX_OK\n")); LOG(("WB_ISR_RX_OK\n"));
retval = wb_rxok(device); retval = wb_rxok(device);
continue;
} }
if (status & WB_ISR_RX_IDLE) { if (status & WB_ISR_RX_IDLE) {
LOG((DEVICE_NAME": WB_ISR_RX_IDLE\n")); LOG(("WB_ISR_RX_IDLE\n"));
continue; // ???
} }
if (status & WB_ISR_TX_NOBUF) { if (status & (WB_ISR_TX_NOBUF | WB_ISR_TX_EARLY)) {
LOG((DEVICE_NAME ": WB_ISR_TX_NOBUF\n")); LOG(("WB_ISR_TX_NOBUF/TX_EARLY\n"));
retval = wb_tx_nobuf(device); retval = wb_tx_nobuf(device);
continue;
} }
if (status & WB_ISR_TX_UNDERRUN) { if (status & WB_ISR_TX_UNDERRUN) {
LOG((DEVICE_NAME ": WB_ISR_TX_UNDERRUN\n")); LOG(("WB_ISR_TX_UNDERRUN\n"));
// TODO: Jack up TX Threshold // TODO: Jack up TX Threshold
continue;
} }
if (status & WB_ISR_TX_IDLE) { if (status & WB_ISR_TX_IDLE) {
LOG((DEVICE_NAME ": WB_ISR_TX_IDLE\n")); LOG(("WB_ISR_TX_IDLE\n"));
continue;
} }
if (status & WB_ISR_TX_OK) { if (status & WB_ISR_TX_OK) {
LOG((DEVICE_NAME": WB_ISR_TX_OK\n")); LOG(("WB_ISR_TX_OK\n"));
continue; // So what ?
} }
if (status & WB_ISR_BUS_ERR) { if (status & WB_ISR_BUS_ERR) {
LOG((DEVICE_NAME": BUS_ERROR: %x\n", (int)(status & WB_ISR_BUSERRTYPE) >> 4)); LOG(("WB_ISR_BUS_ERROR: %lx\n", (status & WB_ISR_BUSERRTYPE) >> 4));
//wb_reset(device); //wb_reset(device);
continue;
} }
LOG((DEVICE_NAME ": unknown interrupt received\n")); if (status & WB_ISR_TIMER_EXPIRED) {
LOG(("WB_ISR_TIMER_EXPIRED\n"));
// ??
}
} }
wb_enable_interrupts(device); wb_enable_interrupts(device);
@@ -491,8 +454,6 @@ wb_create_semaphores(struct wb_device *device)
return device->rxSem; return device->rxSem;
} }
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 %ld\n", device->txSem)); LOG(("Couldn't create sem, sem_id %ld\n", device->txSem));
@@ -500,6 +461,7 @@ wb_create_semaphores(struct wb_device *device)
return device->txSem; return device->txSem;
} }
set_sem_owner(device->rxSem, B_SYSTEM_TEAM);
set_sem_owner(device->txSem, B_SYSTEM_TEAM); set_sem_owner(device->txSem, B_SYSTEM_TEAM);
device->rxLock = 0; device->rxLock = 0;
@@ -617,11 +579,10 @@ wb_set_mode(wb_device *info, int mode)
// Stop TX and RX queue. // Stop TX and RX queue.
if (read32(cfgAddress) & (WB_NETCFG_TX_ON|WB_NETCFG_RX_ON)) { if (read32(cfgAddress) & (WB_NETCFG_TX_ON|WB_NETCFG_RX_ON)) {
restart = 1; restart = true;
WB_CLRBIT(cfgAddress, (WB_NETCFG_TX_ON|WB_NETCFG_RX_ON)); WB_CLRBIT(cfgAddress, (WB_NETCFG_TX_ON|WB_NETCFG_RX_ON));
for (i = 0; i < WB_TIMEOUT; i++) { for (i = 0; i < WB_TIMEOUT; i++) {
//delay(10)
if ((read32(info->reg_base + WB_ISR) & WB_ISR_TX_IDLE) && if ((read32(info->reg_base + WB_ISR) & WB_ISR_TX_IDLE) &&
(read32(info->reg_base + WB_ISR) & WB_ISR_RX_IDLE)) (read32(info->reg_base + WB_ISR) & WB_ISR_RX_IDLE))
break; break;