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:
parent
5502e596dc
commit
e1a99f77d4
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user