freebsd compat. layer: use a thread for deferred interrupt handling. fixed a issue with bus_space_write_N. init the receive queue on device creation.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21041 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos 2007-05-06 15:08:08 +00:00
parent 5502e596dc
commit e1a99f77d4
7 changed files with 235 additions and 85 deletions

View File

@ -8,9 +8,9 @@
* Some of this code is based on previous work by Marcus Overhagen.
*/
#include <malloc.h>
#include "device.h"
#include <drivers/PCI.h>
#include <malloc.h>
#include <compat/dev/pci/pcivar.h>
#include <compat/machine/resource.h>
@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);
}