diff --git a/src/libs/compat/freebsd_network/bus.c b/src/libs/compat/freebsd_network/bus.c index 24f0f111a6..8ac11f157b 100644 --- a/src/libs/compat/freebsd_network/bus.c +++ b/src/libs/compat/freebsd_network/bus.c @@ -8,9 +8,9 @@ * Some of this code is based on previous work by Marcus Overhagen. */ -#include +#include "device.h" -#include +#include #include #include @@ -34,9 +34,17 @@ struct internal_intr { driver_intr_t handler; void *arg; int irq; + + void *context; + + thread_id thread; + sem_id sem; }; +static int32 intr_wrapper(void *data); + + static area_id map_mem(void **virtualAddr, void *_phy, size_t size, uint32 protection, const char *name) @@ -111,6 +119,9 @@ bus_alloc_resource(device_t dev, int type, int *rid, unsigned long start, && type != SYS_RES_IOPORT) return NULL; + device_printf(dev, "bus_alloc_resource(%i, [%i], 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", + type, *rid, start, end, count, flags); + // maybe a local array of resources is enough res = malloc(sizeof(struct resource)); if (res == NULL) @@ -165,19 +176,66 @@ static int32 intr_wrapper(void *data) { struct internal_intr *intr = data; - intr->handler(intr->arg); + driver_printf("in interrupt handler.\n"); + + disable_io_interrupt_handler(intr->context, B_IN_INTERRUPT_CONTEXT); + release_sem_etc(intr->sem, 1, B_DO_NOT_RESCHEDULE); + + return B_INVOKE_SCHEDULER; +} + + +static int32 +intr_handler(void *data) +{ + struct internal_intr *intr = 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"); + + intr->handler(intr->arg); + } + + disable_io_interrupt_handler(intr->context, 0); + return 0; } +static void +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); +} + + int bus_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t handler, void *arg, void **cookiep) { + /* TODO check MPSAFE etc */ + struct internal_intr *intr = (struct internal_intr *)malloc( sizeof(struct internal_intr)); + char semName[64]; status_t status; + /* status_t status; */ + if (intr == NULL) return B_NO_MEMORY; @@ -185,12 +243,34 @@ bus_setup_intr(device_t dev, struct resource *res, int flags, intr->arg = arg; intr->irq = res->handle; - status = install_io_interrupt_handler(intr->irq, intr_wrapper, intr, 0); - if (status < B_OK) { + snprintf(semName, sizeof(semName), "%s intr", dev->dev_name); + + intr->sem = create_sem(0, semName); + if (intr->sem < B_OK) { free(intr); + return B_NO_MEMORY; + } + + snprintf(semName, sizeof(semName), "%s intr handler", dev->dev_name); + + intr->thread = spawn_kernel_thread(intr_handler, semName, + B_REAL_TIME_DISPLAY_PRIORITY, intr); + if (intr->thread < B_OK) { + delete_sem(intr->sem); + free(intr); + return B_NO_MEMORY; + } + + intr->context = NULL; + status = create_io_interrupt_handler(intr->irq, intr_wrapper, intr, + &intr->context); + if (status < B_OK) { + free_internal_intr(intr); return status; } + resume_thread(intr->thread); + *cookiep = intr; return 0; @@ -201,8 +281,8 @@ 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); - free(intr); + /* remove_io_interrupt_handler(intr->irq, intr_wrapper, intr); */ + free_internal_intr(intr); return 0; } @@ -215,3 +295,33 @@ bus_generic_detach(device_t dev) return B_ERROR; } + +#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) \ + { \ + type value; \ + if (tag == I386_BUS_SPACE_IO) \ + value = fun(handle + offset); \ + else \ + value = *(volatile type *)(handle + offset); \ + return value; \ + } + +#define BUS_SPACE_WRITE(size, type, fun) \ + void bus_space_write_##size(bus_space_tag_t tag, \ + bus_space_handle_t handle, bus_size_t offset, type value) \ + { \ + if (tag == I386_BUS_SPACE_IO) \ + fun(value, handle + offset); \ + else \ + *(volatile type *)(handle + offset) = value; \ + } + +BUS_SPACE_READ(1, uint8_t, in8) +BUS_SPACE_READ(2, uint16_t, in16) +BUS_SPACE_READ(4, uint32_t, in32) + +BUS_SPACE_WRITE(1, uint8_t, out8) +BUS_SPACE_WRITE(2, uint16_t, out16) +BUS_SPACE_WRITE(4, uint32_t, out32) diff --git a/src/libs/compat/freebsd_network/compat.c b/src/libs/compat/freebsd_network/compat.c index d9da749deb..bf89ad8a19 100644 --- a/src/libs/compat/freebsd_network/compat.c +++ b/src/libs/compat/freebsd_network/compat.c @@ -20,6 +20,14 @@ // TODO a lot. +#define DEBUG_PCI + +#ifdef DEBUG_PCI +#define TRACE_PCI(dev, format, args...) device_printf(dev, format , ##args) +#else +#define TRACE_PCI(dev, format, args...) do { } while (0) +#endif + status_t init_compat_layer(void); struct net_stack_module_info *gStack; @@ -28,14 +36,18 @@ pci_module_info *gPci; uint32_t pci_read_config(device_t dev, int offset, int size) { - return gPci->read_pci_config(dev->pci_info.bus, dev->pci_info.device, - dev->pci_info.function, offset, size); + uint32_t value = gPci->read_pci_config(dev->pci_info.bus, + dev->pci_info.device, dev->pci_info.function, offset, size); + TRACE_PCI(dev, "pci_read_config(%i, %i) = 0x%lx\n", offset, size, value); + return value; } void pci_write_config(device_t dev, int offset, uint32_t value, int size) { + TRACE_PCI(dev, "pci_write_config(%i, 0x%lx, %i)\n", offset, value, size); + gPci->write_pci_config(dev->pci_info.bus, dev->pci_info.device, dev->pci_info.function, offset, size, value); } @@ -119,16 +131,48 @@ pci_enable_io(device_t dev, int space) } +void +driver_printf(const char *format, ...) +{ + va_list vl; + va_start(vl, format); + driver_vprintf(format, vl); + va_end(vl); +} + + +static void +driver_vprintf_etc(const char *extra, const char *format, va_list vl) +{ + char buf[256]; + vsnprintf(buf, sizeof(buf), format, vl); + + if (extra) + dprintf("[%s] (%s) %s", gDriverName, extra, buf); + else + dprintf("[%s] %s", gDriverName, buf); +} + + +void +driver_vprintf(const char *format, va_list vl) +{ + driver_vprintf_etc(NULL, format, vl); +} + + int device_printf(device_t dev, const char *format, ...) { - char buf[256]; + char devDesc[32]; va_list vl; - va_start(vl, format); - vsnprintf(buf, sizeof(buf), format, vl); - va_end(vl); - dprintf("[%s...] %s", gDriverName, buf); + snprintf(devDesc, sizeof(devDesc), "%i:%i:%i", (int)dev->pci_info.bus, + (int)dev->pci_info.device, (int)dev->pci_info.function); + + va_start(vl, format); + driver_vprintf_etc(devDesc, format, vl); + va_end(vl); return 0; } @@ -180,13 +224,11 @@ device_delete_child(device_t dev, device_t child) int printf(const char *format, ...) { - char buf[256]; va_list vl; va_start(vl, format); - vsnprintf(buf, sizeof(buf), format, vl); + driver_vprintf(format, vl); va_end(vl); - dprintf(buf); return 0; } diff --git a/src/libs/compat/freebsd_network/compat/net/if.h b/src/libs/compat/freebsd_network/compat/net/if.h index 4476c3bbce..d33afe67e3 100644 --- a/src/libs/compat/freebsd_network/compat/net/if.h +++ b/src/libs/compat/freebsd_network/compat/net/if.h @@ -26,6 +26,7 @@ #define IFF_DRV_RUNNING 0x10000 #define IFF_DRV_OACTIVE 0x20000 #define IFF_LINK0 0x40000 +#define IFF_DEBUG 0x80000 #define LINK_STATE_UNKNOWN 0 diff --git a/src/libs/compat/freebsd_network/compat/sys/bus.h b/src/libs/compat/freebsd_network/compat/sys/bus.h index dfa0fcb0d8..aff36e231a 100644 --- a/src/libs/compat/freebsd_network/compat/sys/bus.h +++ b/src/libs/compat/freebsd_network/compat/sys/bus.h @@ -24,67 +24,18 @@ typedef unsigned int bus_space_handle_t; #define BUS_SPACE_MAXSIZE_32BIT 0xffffffff #define BUS_SPACE_MAXSIZE 0xffffffff -static inline uint8_t -bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle, - bus_size_t offset) -{ - if (tag == I386_BUS_SPACE_IO) - return in8(handle + offset); - return *(volatile uint8_t *)(handle + offset); -} - - -static inline void -bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t handle, - bus_size_t offset, uint8_t value) -{ - if (tag == I386_BUS_SPACE_IO) - out8(handle + offset, value); - else - *(volatile uint8_t *)(handle + offset) = value; -} - - -static inline uint16_t -bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle, - bus_size_t offset) -{ - if (tag == I386_BUS_SPACE_IO) - return in16(handle + offset); - return *(volatile uint16_t *)(handle + offset); -} - - -static inline void -bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t handle, - bus_size_t offset, uint16_t value) -{ - if (tag == I386_BUS_SPACE_IO) - out16(handle + offset, value); - else - *(volatile uint16_t *)(handle + offset) = value; -} - - -static inline uint32_t -bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle, - bus_size_t offset) -{ - if (tag == I386_BUS_SPACE_IO) - return in32(handle + offset); - return *(volatile uint32_t *)(handle + offset); -} - - -static inline void -bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t handle, - bus_size_t offset, uint32_t value) -{ - if (tag == I386_BUS_SPACE_IO) - out32(handle + offset, value); - else - *(volatile uint32_t *)(handle + offset) = value; -} +uint8_t bus_space_read_1(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset); +void bus_space_write_1(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset, uint8_t value); +uint16_t bus_space_read_2(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset); +void bus_space_write_2(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset, uint16_t value); +uint32_t bus_space_read_4(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset); +void bus_space_write_4(bus_space_tag_t tag, bus_space_handle_t handle, + bus_size_t offset, uint32_t value); #define BUS_SPACE_BARRIER_READ 1 diff --git a/src/libs/compat/freebsd_network/device.c b/src/libs/compat/freebsd_network/device.c index 1636798ca1..c322fd8d4e 100644 --- a/src/libs/compat/freebsd_network/device.c +++ b/src/libs/compat/freebsd_network/device.c @@ -58,6 +58,8 @@ allocate_device(driver_t *driver) return NULL; } + ifq_init(&dev->receive_queue, semName); + return dev; } @@ -66,6 +68,7 @@ static void free_device(device_t dev) { delete_sem(dev->receive_sem); + ifq_uninit(&dev->receive_queue); free(dev->softc); free(dev); } @@ -93,7 +96,7 @@ compat_open(const char *name, uint32 flags, void **cookie) device_t dev; int i; - dprintf("%s, compat_open(%s, 0x%lx)\n", gDriverName, name, flags); + driver_printf("compat_open(%s, 0x%lx)\n", name, flags); for (i = 0; gDevNameList[i] != NULL; i++) { if (strcmp(gDevNameList[i], name) == 0) @@ -112,6 +115,8 @@ compat_open(const char *name, uint32 flags, void **cookie) if (status != 0) dev->flags = 0; + driver_printf(" ... status = 0x%ld\n", status); + *cookie = dev; return status; @@ -123,7 +128,7 @@ compat_close(void *cookie) { device_t dev = cookie; - dprintf("%s, compat_close(%p)\n", gDriverName, dev); + device_printf(dev, "compat_close()\n"); return B_ERROR; } @@ -134,7 +139,7 @@ compat_free(void *cookie) { device_t dev = cookie; - dprintf("%s, compat_free(%p)\n", gDriverName, dev); + device_printf(dev, "compat_free()\n"); free_device(dev); return B_ERROR; @@ -150,6 +155,9 @@ compat_read(void *cookie, off_t position, void *buf, size_t *numBytes) struct mbuf *mb; size_t len; + driver_printf("compat_read(%p, %lld, %p, [%lu])\n", cookie, position, buf, + *numBytes); + if (dev->flags & DEVICE_CLOSED) return B_INTERRUPTED; @@ -193,6 +201,9 @@ compat_write(void *cookie, off_t position, const void *buffer, device_t dev = cookie; struct mbuf *mb; + driver_printf("compat_write(%p, %lld, %p, [%lu])\n", cookie, position, + buffer, *numBytes); + mb = m_getcl(0, MT_DATA, 0); if (mb == NULL) return ENOBUFS; diff --git a/src/libs/compat/freebsd_network/device.h b/src/libs/compat/freebsd_network/device.h index 20f4796a3e..34c61332e3 100644 --- a/src/libs/compat/freebsd_network/device.h +++ b/src/libs/compat/freebsd_network/device.h @@ -58,6 +58,12 @@ void uninit_mutexes(void); void init_bounce_pages(void); void uninit_bounce_pages(void); +void driver_printf(const char *format, ...) __attribute__ ((format (__printf__, 1, 2))); +void driver_vprintf(const char *format, va_list vl); + +void ifq_init(struct ifqueue *ifq, const char *name); +void ifq_uninit(struct ifqueue *ifq); + extern struct net_stack_module_info *gStack; extern pci_module_info *gPci; diff --git a/src/libs/compat/freebsd_network/if.c b/src/libs/compat/freebsd_network/if.c index e094d336a5..738804cfb2 100644 --- a/src/libs/compat/freebsd_network/if.c +++ b/src/libs/compat/freebsd_network/if.c @@ -72,6 +72,26 @@ if_initname(struct ifnet *ifp, const char *name, int unit) } +void +ifq_init(struct ifqueue *ifq, const char *name) +{ + ifq->ifq_head = NULL; + ifq->ifq_tail = NULL; + ifq->ifq_len = 0; + ifq->ifq_maxlen = IFQ_MAXLEN; + ifq->ifq_drops = 0; + + mtx_init(&ifq->ifq_mtx, name, NULL, MTX_DEF); +} + + +void +ifq_uninit(struct ifqueue *ifq) +{ + mtx_destroy(&ifq->ifq_mtx); +} + + void if_attach(struct ifnet *ifp) { @@ -79,14 +99,14 @@ if_attach(struct ifnet *ifp) TAILQ_INIT(&ifp->if_prefixhead); TAILQ_INIT(&ifp->if_multiaddrs); - mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_xname, NULL, MTX_DEF); + ifq_init((struct ifqueue *)&ifp->if_snd, ifp->if_xname); } void if_detach(struct ifnet *ifp) { - mtx_destroy(&ifp->if_snd.ifq_mtx); + ifq_uninit((struct ifqueue *)&ifp->if_snd); } @@ -97,7 +117,6 @@ if_start(struct ifnet *ifp) if (ifp->if_flags & IFF_NEEDSGIANT) panic("freebsd compat.: unsupported giant requirement"); #endif - ifp->if_start(ifp); } @@ -133,7 +152,7 @@ int ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt0) { - int error; + int error = 0; IFQ_HANDOFF(ifp, m, error); return error; } @@ -270,3 +289,13 @@ ether_ioctl(struct ifnet *ifp, int command, caddr_t data) return 0; } + +char * +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]); + return (etherbuf); +}