From 0bdff52467a7c86f9d0e33f2b4eb79bbf65aa5bb Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Sun, 6 May 2007 22:40:19 +0000 Subject: [PATCH] freebsd compat. layer: instead of disabling the IRQ, disable the device's interrupts on real interrupt request as suggested by Travis. This solves potential issues with shared IRQs. The check & disable interrupts function is part of the required glue code. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21045 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../drivers/network/pcnet/dev/le/glue.c | 55 +++++++++++++++++++ .../drivers/network/pcnet/dev/le/if_le_pci.c | 15 ++++- src/libs/compat/freebsd_network/bus.c | 43 ++++++++------- src/libs/compat/freebsd_network/compat.c | 7 ++- .../freebsd_network/compat/sys/haiku-module.h | 15 +++++ src/libs/compat/freebsd_network/device.c | 3 + src/libs/compat/freebsd_network/device.h | 2 + src/libs/compat/freebsd_network/if.c | 5 +- 8 files changed, 120 insertions(+), 25 deletions(-) diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/le/glue.c b/src/add-ons/kernel/drivers/network/pcnet/dev/le/glue.c index 3ab33372b7..21c1bbe9f8 100644 --- a/src/add-ons/kernel/drivers/network/pcnet/dev/le/glue.c +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/le/glue.c @@ -1,3 +1,58 @@ #include +#include + +#include +#include +#include + +/* from if_le_pci.c */ +#define PCNET_PCI_RDP 0x10 +#define PCNET_PCI_RAP 0x12 + +struct le_pci_softc { + struct am79900_softc sc_am79900; /* glue to MI code */ + + int sc_rrid; + struct resource *sc_rres; + bus_space_tag_t sc_regt; + bus_space_handle_t sc_regh; + + int sc_irid; + struct resource *sc_ires; + void *sc_ih; + + bus_dma_tag_t sc_pdmat; + bus_dma_tag_t sc_dmat; + bus_dmamap_t sc_dmam; +}; + HAIKU_FBSD_DRIVER_GLUE(pcnet, le, pci) + +int HAIKU_CHECK_DISABLE_INTERRUPTS(device_t dev) { + struct le_pci_softc *lesc = (struct le_pci_softc *)device_get_softc(dev); + cpu_status status; + uint16_t value; + + HAIKU_INTR_REGISTER_ENTER(status); + + /* get current flags */ + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, LE_CSR0); + bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, + BUS_SPACE_BARRIER_WRITE); + value = bus_space_read_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RDP); + + /* is there a pending interrupt? */ + if (value & LE_C0_INTR) { + /* set the new flags, disable interrupts */ + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, LE_CSR0); + bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, + BUS_SPACE_BARRIER_WRITE); + bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RDP, + value & ~LE_C0_INEA); + } + + HAIKU_INTR_REGISTER_LEAVE(status); + + return value & LE_C0_INTR; +} diff --git a/src/add-ons/kernel/drivers/network/pcnet/dev/le/if_le_pci.c b/src/add-ons/kernel/drivers/network/pcnet/dev/le/if_le_pci.c index 6a9e94ccc6..09a43cb89e 100644 --- a/src/add-ons/kernel/drivers/network/pcnet/dev/le/if_le_pci.c +++ b/src/add-ons/kernel/drivers/network/pcnet/dev/le/if_le_pci.c @@ -195,22 +195,35 @@ static void le_pci_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) { struct le_pci_softc *lesc = (struct le_pci_softc *)sc; + cpu_status status = 0; + if (port == LE_CSR0) + HAIKU_INTR_REGISTER_ENTER(status); bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, port); bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RDP, val); + if (port == LE_CSR0) + HAIKU_INTR_REGISTER_LEAVE(status); } static uint16_t le_pci_rdcsr(struct lance_softc *sc, uint16_t port) { struct le_pci_softc *lesc = (struct le_pci_softc *)sc; + cpu_status status = 0; + uint16_t value; + if (port == LE_CSR0) + HAIKU_INTR_REGISTER_ENTER(status); bus_space_write_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, port); bus_space_barrier(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RAP, 2, BUS_SPACE_BARRIER_WRITE); - return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RDP)); + value = bus_space_read_2(lesc->sc_regt, lesc->sc_regh, PCNET_PCI_RDP); + if (port == LE_CSR0) + HAIKU_INTR_REGISTER_LEAVE(status); + + return value; } static int diff --git a/src/libs/compat/freebsd_network/bus.c b/src/libs/compat/freebsd_network/bus.c index 8ac11f157b..f08249eb9a 100644 --- a/src/libs/compat/freebsd_network/bus.c +++ b/src/libs/compat/freebsd_network/bus.c @@ -31,12 +31,11 @@ struct resource { struct internal_intr { + device_t dev; driver_intr_t handler; void *arg; int irq; - void *context; - thread_id thread; sem_id sem; }; @@ -176,11 +175,13 @@ static int32 intr_wrapper(void *data) { struct internal_intr *intr = data; - driver_printf("in interrupt handler.\n"); - disable_io_interrupt_handler(intr->context, B_IN_INTERRUPT_CONTEXT); + device_printf(intr->dev, "in interrupt handler.\n"); + + if (!HAIKU_CHECK_DISABLE_INTERRUPTS(intr->dev)) + return B_UNHANDLED_INTERRUPT; + release_sem_etc(intr->sem, 1, B_DO_NOT_RESCHEDULE); - return B_INVOKE_SCHEDULER; } @@ -192,19 +193,15 @@ intr_handler(void *data) status_t status; while (1) { - enable_io_interrupt_handler(intr->context); - status = acquire_sem(intr->sem); if (status < B_OK) break; - driver_printf("in soft interrupt handler.\n"); + device_printf(intr->dev, "in soft interrupt handler.\n"); intr->handler(intr->arg); } - disable_io_interrupt_handler(intr->context, 0); - return 0; } @@ -215,10 +212,6 @@ free_internal_intr(struct internal_intr *intr) status_t status; delete_sem(intr->sem); wait_for_thread(intr->thread, &status); - - if (intr->context) - delete_io_interrupt_handler(intr->context); - free(intr); } @@ -234,11 +227,10 @@ bus_setup_intr(device_t dev, struct resource *res, int flags, char semName[64]; status_t status; - /* status_t status; */ - if (intr == NULL) return B_NO_MEMORY; + intr->dev = dev; intr->handler = handler; intr->arg = arg; intr->irq = res->handle; @@ -261,9 +253,7 @@ bus_setup_intr(device_t dev, struct resource *res, int flags, return B_NO_MEMORY; } - intr->context = NULL; - status = create_io_interrupt_handler(intr->irq, intr_wrapper, intr, - &intr->context); + status = install_io_interrupt_handler(intr->irq, intr_wrapper, intr, 0); if (status < B_OK) { free_internal_intr(intr); return status; @@ -281,7 +271,7 @@ int bus_teardown_intr(device_t dev, struct resource *res, void *arg) { struct internal_intr *intr = arg; - /* remove_io_interrupt_handler(intr->irq, intr_wrapper, intr); */ + remove_io_interrupt_handler(intr->irq, intr_wrapper, intr); free_internal_intr(intr); return 0; } @@ -296,6 +286,15 @@ bus_generic_detach(device_t dev) } +#define DEBUG_BUS_SPACE_RW + +#ifdef DEBUG_BUS_SPACE_RW +#define TRACE_BUS_SPACE_RW(x) driver_printf x +#else +#define TRACE_BUS_SPACE_RW(x) +#endif + + #define BUS_SPACE_READ(size, type, fun) \ type bus_space_read_##size(bus_space_tag_t tag, \ bus_space_handle_t handle, bus_size_t offset) \ @@ -305,6 +304,8 @@ bus_generic_detach(device_t dev) value = fun(handle + offset); \ else \ value = *(volatile type *)(handle + offset); \ + TRACE_BUS_SPACE_RW(("bus_space_read_%s(0x%lx, 0x%lx, 0x%lx) = 0x%lx\n", \ + #size, (uint32)tag, (uint32)handle, (uint32)offset, (uint32)value)); \ return value; \ } @@ -312,6 +313,8 @@ bus_generic_detach(device_t dev) void bus_space_write_##size(bus_space_tag_t tag, \ bus_space_handle_t handle, bus_size_t offset, type value) \ { \ + TRACE_BUS_SPACE_RW(("bus_space_write_%s(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", \ + #size, (uint32)tag, (uint32)handle, (uint32)offset, (uint32)value)); \ if (tag == I386_BUS_SPACE_IO) \ fun(value, handle + offset); \ else \ diff --git a/src/libs/compat/freebsd_network/compat.c b/src/libs/compat/freebsd_network/compat.c index bf89ad8a19..9f34604d02 100644 --- a/src/libs/compat/freebsd_network/compat.c +++ b/src/libs/compat/freebsd_network/compat.c @@ -28,7 +28,7 @@ #define TRACE_PCI(dev, format, args...) do { } while (0) #endif -status_t init_compat_layer(void); +spinlock __haiku_intr_spinlock; struct net_stack_module_info *gStack; pci_module_info *gPci; @@ -224,10 +224,12 @@ device_delete_child(device_t dev, device_t child) int printf(const char *format, ...) { + char buf[256]; va_list vl; va_start(vl, format); - driver_vprintf(format, vl); + vsnprintf(buf, sizeof(buf), format, vl); va_end(vl); + dprintf(buf); return 0; } @@ -309,6 +311,7 @@ _kernel_contigfree(void *addr, size_t size) status_t init_compat_layer() { + __haiku_intr_spinlock = 0; return B_OK; } diff --git a/src/libs/compat/freebsd_network/compat/sys/haiku-module.h b/src/libs/compat/freebsd_network/compat/sys/haiku-module.h index 0d408ec168..cc9800366f 100644 --- a/src/libs/compat/freebsd_network/compat/sys/haiku-module.h +++ b/src/libs/compat/freebsd_network/compat/sys/haiku-module.h @@ -74,6 +74,21 @@ extern const char gDriverName[]; const char **publish_devices() { return (const char **)gDevNameList; } \ device_hooks *find_device(const char *name) { return &gDeviceHooks; } +extern spinlock __haiku_intr_spinlock; +extern int __haiku_disable_interrupts(device_t dev); + +#define HAIKU_CHECK_DISABLE_INTERRUPTS __haiku_disable_interrupts + +#define HAIKU_INTR_REGISTER_ENTER(status) do { \ + status = disable_interrupts(); \ + acquire_spinlock(&__haiku_intr_spinlock); \ +} while (0) + +#define HAIKU_INTR_REGISTER_LEAVE(status) do { \ + release_spinlock(&__haiku_intr_spinlock); \ + restore_interrupts(status); \ +} while (0) + #define DEFINE_CLASS_0(name, driver, methods, size) \ driver_t driver = { #name, methods, size } diff --git a/src/libs/compat/freebsd_network/device.c b/src/libs/compat/freebsd_network/device.c index c322fd8d4e..57309b839b 100644 --- a/src/libs/compat/freebsd_network/device.c +++ b/src/libs/compat/freebsd_network/device.c @@ -16,6 +16,7 @@ #include +#include #include #include @@ -326,6 +327,8 @@ _fbsd_init_driver(driver_t *driver) if (dev == NULL) return B_NO_MEMORY; + init_compat_layer(); + status = init_mutexes(); if (status < B_OK) { free_device(dev); diff --git a/src/libs/compat/freebsd_network/device.h b/src/libs/compat/freebsd_network/device.h index 34c61332e3..ea56015089 100644 --- a/src/libs/compat/freebsd_network/device.h +++ b/src/libs/compat/freebsd_network/device.h @@ -54,6 +54,8 @@ void uninit_mbufs(void); status_t init_mutexes(void); void uninit_mutexes(void); +status_t init_compat_layer(void); + /* busdma_machdep.c */ void init_bounce_pages(void); void uninit_bounce_pages(void); diff --git a/src/libs/compat/freebsd_network/if.c b/src/libs/compat/freebsd_network/if.c index 738804cfb2..c1b5df58db 100644 --- a/src/libs/compat/freebsd_network/if.c +++ b/src/libs/compat/freebsd_network/if.c @@ -295,7 +295,8 @@ ether_sprintf(const u_char *ap) { static char etherbuf[18]; snprintf(etherbuf, sizeof (etherbuf), - "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]); + "%02x:%02x:%02x:%02x:%02x:%02x", + (uint32)ap[0], (uint32)ap[1], (uint32)ap[2], (uint32)ap[3], + (uint32)ap[4], (uint32)ap[5]); return (etherbuf); }