INTRNG: Rework handling with resources. Partially revert r301453.
- Read interrupt properties at bus enumeration time and store it into global mapping table. - At bus_activate_resource() time, given mapping entry is resolved and connected to real interrupt source. A copy of mapping entry is attached to given resource. - At bus_setup_intr() time, mapping entry stored in resource is used for delivery of requested interrupt configuration. - For MSI/MSIX interrupts, mapping entry is created within pci_alloc_msi()/pci_alloc_msix() call. - For legacy PCI interrupts, mapping entry must be created within pcib_route_interrupt() by pcib driver itself. Reviewed by: nwhitehorn, andrew Differential Revision: https://reviews.freebsd.org/D7493
This commit is contained in:
parent
5818149caf
commit
28257ccca8
@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef FDT
|
||||
#include <machine/fdt.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#include "ofw_bus_if.h"
|
||||
#endif
|
||||
|
||||
@ -379,6 +380,11 @@ nexus_activate_resource(device_t bus, device_t child, int type, int rid,
|
||||
#endif
|
||||
rman_set_virtual(r, (void *)vaddr);
|
||||
rman_set_bushandle(r, vaddr);
|
||||
return (0);
|
||||
} else if (type == SYS_RES_IRQ) {
|
||||
#ifdef INTRNG
|
||||
intr_activate_irq(child, r);
|
||||
#endif
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@ -390,17 +396,23 @@ nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
|
||||
bus_size_t psize;
|
||||
bus_space_handle_t vaddr;
|
||||
|
||||
psize = (bus_size_t)rman_get_size(r);
|
||||
vaddr = rman_get_bushandle(r);
|
||||
if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
|
||||
psize = (bus_size_t)rman_get_size(r);
|
||||
vaddr = rman_get_bushandle(r);
|
||||
|
||||
if (vaddr != 0) {
|
||||
if (vaddr != 0) {
|
||||
#ifdef FDT
|
||||
bus_space_unmap(fdtbus_bs_tag, vaddr, psize);
|
||||
bus_space_unmap(fdtbus_bs_tag, vaddr, psize);
|
||||
#else
|
||||
pmap_unmapdev((vm_offset_t)vaddr, (vm_size_t)psize);
|
||||
pmap_unmapdev((vm_offset_t)vaddr, (vm_size_t)psize);
|
||||
#endif
|
||||
rman_set_virtual(r, NULL);
|
||||
rman_set_bushandle(r, 0);
|
||||
}
|
||||
} else if (type == SYS_RES_IRQ) {
|
||||
#ifdef INTRNG
|
||||
intr_deactivate_irq(child, r);
|
||||
#endif
|
||||
rman_set_virtual(r, NULL);
|
||||
rman_set_bushandle(r, 0);
|
||||
}
|
||||
|
||||
return (rman_deactivate_resource(r));
|
||||
@ -411,11 +423,22 @@ static int
|
||||
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
|
||||
pcell_t *intr)
|
||||
{
|
||||
|
||||
#ifdef INTRNG
|
||||
return (INTR_IRQ_INVALID);
|
||||
#else
|
||||
#ifndef INTRNG
|
||||
return (intr_fdt_map_irq(iparent, intr, icells));
|
||||
#endif
|
||||
#else
|
||||
u_int irq;
|
||||
struct intr_map_data_fdt *fdt_data;
|
||||
size_t len;
|
||||
|
||||
len = sizeof(*fdt_data) + icells * sizeof(pcell_t);
|
||||
fdt_data = (struct intr_map_data_fdt *)intr_alloc_map_data(
|
||||
INTR_MAP_DATA_FDT, len, M_WAITOK | M_ZERO);
|
||||
fdt_data->iparent = iparent;
|
||||
fdt_data->ncells = icells;
|
||||
memcpy(fdt_data->cells, intr, icells * sizeof(pcell_t));
|
||||
irq = intr_map_irq(NULL, iparent, (struct intr_map_data *)fdt_data);
|
||||
return (irq);
|
||||
#endif /* INTRNG */
|
||||
}
|
||||
#endif
|
||||
#endif /* FDT */
|
||||
|
||||
|
@ -88,12 +88,12 @@ struct tegra_lic_sc {
|
||||
};
|
||||
|
||||
static int
|
||||
tegra_lic_alloc_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
tegra_lic_activate_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
struct resource *res, struct intr_map_data *data)
|
||||
{
|
||||
struct tegra_lic_sc *sc = device_get_softc(dev);
|
||||
|
||||
return (PIC_ALLOC_INTR(sc->parent, isrc, res, data));
|
||||
return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -122,12 +122,12 @@ tegra_lic_map_intr(device_t dev, struct intr_map_data *data,
|
||||
}
|
||||
|
||||
static int
|
||||
tegra_lic_release_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
tegra_lic_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
struct resource *res, struct intr_map_data *data)
|
||||
{
|
||||
struct tegra_lic_sc *sc = device_get_softc(dev);
|
||||
|
||||
return (PIC_RELEASE_INTR(sc->parent, isrc, res, data));
|
||||
return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -266,11 +266,11 @@ static device_method_t tegra_lic_methods[] = {
|
||||
DEVMETHOD(device_detach, tegra_lic_detach),
|
||||
|
||||
/* Interrupt controller interface */
|
||||
DEVMETHOD(pic_alloc_intr, tegra_lic_alloc_intr),
|
||||
DEVMETHOD(pic_activate_intr, tegra_lic_activate_intr),
|
||||
DEVMETHOD(pic_disable_intr, tegra_lic_disable_intr),
|
||||
DEVMETHOD(pic_enable_intr, tegra_lic_enable_intr),
|
||||
DEVMETHOD(pic_map_intr, tegra_lic_map_intr),
|
||||
DEVMETHOD(pic_release_intr, tegra_lic_release_intr),
|
||||
DEVMETHOD(pic_deactivate_intr, tegra_lic_deactivate_intr),
|
||||
DEVMETHOD(pic_setup_intr, tegra_lic_setup_intr),
|
||||
DEVMETHOD(pic_teardown_intr, tegra_lic_teardown_intr),
|
||||
DEVMETHOD(pic_pre_ithread, tegra_lic_pre_ithread),
|
||||
|
@ -57,12 +57,12 @@ struct omap4_wugen_sc {
|
||||
};
|
||||
|
||||
static int
|
||||
omap4_wugen_alloc_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
omap4_wugen_activate_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
struct resource *res, struct intr_map_data *data)
|
||||
{
|
||||
struct omap4_wugen_sc *sc = device_get_softc(dev);
|
||||
|
||||
return (PIC_ALLOC_INTR(sc->sc_parent, isrc, res, data));
|
||||
return (PIC_ACTIVATE_INTR(sc->sc_parent, isrc, res, data));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -91,12 +91,12 @@ omap4_wugen_map_intr(device_t dev, struct intr_map_data *data,
|
||||
}
|
||||
|
||||
static int
|
||||
omap4_wugen_release_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
omap4_wugen_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
struct resource *res, struct intr_map_data *data)
|
||||
{
|
||||
struct omap4_wugen_sc *sc = device_get_softc(dev);
|
||||
|
||||
return (PIC_RELEASE_INTR(sc->sc_parent, isrc, res, data));
|
||||
return (PIC_DEACTIVATE_INTR(sc->sc_parent, isrc, res, data));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -227,11 +227,11 @@ static device_method_t omap4_wugen_methods[] = {
|
||||
DEVMETHOD(device_detach, omap4_wugen_detach),
|
||||
|
||||
/* Interrupt controller interface */
|
||||
DEVMETHOD(pic_alloc_intr, omap4_wugen_alloc_intr),
|
||||
DEVMETHOD(pic_activate_intr, omap4_wugen_activate_intr),
|
||||
DEVMETHOD(pic_disable_intr, omap4_wugen_disable_intr),
|
||||
DEVMETHOD(pic_enable_intr, omap4_wugen_enable_intr),
|
||||
DEVMETHOD(pic_map_intr, omap4_wugen_map_intr),
|
||||
DEVMETHOD(pic_release_intr, omap4_wugen_release_intr),
|
||||
DEVMETHOD(pic_deactivate_intr, omap4_wugen_deactivate_intr),
|
||||
DEVMETHOD(pic_setup_intr, omap4_wugen_setup_intr),
|
||||
DEVMETHOD(pic_teardown_intr, omap4_wugen_teardown_intr),
|
||||
DEVMETHOD(pic_pre_ithread, omap4_wugen_pre_ithread),
|
||||
|
@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/intr.h>
|
||||
|
||||
#ifdef FDT
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include "ofw_bus_if.h"
|
||||
#endif
|
||||
@ -345,6 +346,8 @@ nexus_activate_resource(device_t bus, device_t child, int type, int rid,
|
||||
rman_set_bustag(r, &memmap_bus);
|
||||
rman_set_virtual(r, (void *)vaddr);
|
||||
rman_set_bushandle(r, vaddr);
|
||||
} else if (type == SYS_RES_IRQ) {
|
||||
intr_activate_irq(child, r);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@ -378,13 +381,17 @@ nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
|
||||
bus_size_t psize;
|
||||
bus_space_handle_t vaddr;
|
||||
|
||||
psize = (bus_size_t)rman_get_size(r);
|
||||
vaddr = rman_get_bushandle(r);
|
||||
if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
|
||||
psize = (bus_size_t)rman_get_size(r);
|
||||
vaddr = rman_get_bushandle(r);
|
||||
|
||||
if (vaddr != 0) {
|
||||
bus_space_unmap(&memmap_bus, vaddr, psize);
|
||||
rman_set_virtual(r, NULL);
|
||||
rman_set_bushandle(r, 0);
|
||||
if (vaddr != 0) {
|
||||
bus_space_unmap(&memmap_bus, vaddr, psize);
|
||||
rman_set_virtual(r, NULL);
|
||||
rman_set_bushandle(r, 0);
|
||||
}
|
||||
} else if (type == SYS_RES_IRQ) {
|
||||
intr_deactivate_irq(child, r);
|
||||
}
|
||||
|
||||
return (rman_deactivate_resource(r));
|
||||
@ -431,8 +438,18 @@ static int
|
||||
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
|
||||
pcell_t *intr)
|
||||
{
|
||||
u_int irq;
|
||||
struct intr_map_data_fdt *fdt_data;
|
||||
size_t len;
|
||||
|
||||
return (INTR_IRQ_INVALID);
|
||||
len = sizeof(*fdt_data) + icells * sizeof(pcell_t);
|
||||
fdt_data = (struct intr_map_data_fdt *)intr_alloc_map_data(
|
||||
INTR_MAP_DATA_FDT, len, M_WAITOK | M_ZERO);
|
||||
fdt_data->iparent = iparent;
|
||||
fdt_data->ncells = icells;
|
||||
memcpy(fdt_data->cells, intr, icells * sizeof(pcell_t));
|
||||
irq = intr_map_irq(NULL, iparent, (struct intr_map_data *)fdt_data);
|
||||
return (irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -251,9 +251,7 @@ simplebus_setup_dinfo(device_t dev, phandle_t node,
|
||||
|
||||
resource_list_init(&ndi->rl);
|
||||
ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, &ndi->rl);
|
||||
#ifndef INTRNG
|
||||
ofw_bus_intr_to_rl(dev, node, &ndi->rl, NULL);
|
||||
#endif
|
||||
|
||||
return (ndi);
|
||||
}
|
||||
|
@ -31,7 +31,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/gpio.h>
|
||||
#ifdef INTRNG
|
||||
#include <sys/intr.h>
|
||||
#endif
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
@ -79,43 +81,26 @@ static int gpiobus_pin_toggle(device_t, device_t, uint32_t);
|
||||
* data will be moved into struct resource.
|
||||
*/
|
||||
#ifdef INTRNG
|
||||
static void
|
||||
gpio_destruct_map_data(struct intr_map_data *map_data)
|
||||
{
|
||||
|
||||
KASSERT(map_data->type == INTR_MAP_DATA_GPIO,
|
||||
("%s: bad map_data type %d", __func__, map_data->type));
|
||||
|
||||
free(map_data, M_DEVBUF);
|
||||
}
|
||||
|
||||
struct resource *
|
||||
gpio_alloc_intr_resource(device_t consumer_dev, int *rid, u_int alloc_flags,
|
||||
gpio_pin_t pin, uint32_t intr_mode)
|
||||
{
|
||||
int rv;
|
||||
u_int irq;
|
||||
struct intr_map_data_gpio *gpio_data;
|
||||
struct resource *res;
|
||||
|
||||
gpio_data = malloc(sizeof(*gpio_data), M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
gpio_data->hdr.type = INTR_MAP_DATA_GPIO;
|
||||
gpio_data->hdr.destruct = gpio_destruct_map_data;
|
||||
gpio_data = (struct intr_map_data_gpio *)intr_alloc_map_data(
|
||||
INTR_MAP_DATA_GPIO, sizeof(*gpio_data), M_WAITOK | M_ZERO);
|
||||
gpio_data->gpio_pin_num = pin->pin;
|
||||
gpio_data->gpio_pin_flags = pin->flags;
|
||||
gpio_data->gpio_intr_mode = intr_mode;
|
||||
|
||||
rv = intr_map_irq(pin->dev, 0, (struct intr_map_data *)gpio_data,
|
||||
&irq);
|
||||
if (rv != 0) {
|
||||
gpio_destruct_map_data((struct intr_map_data *)gpio_data);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
irq = intr_map_irq(pin->dev, 0, (struct intr_map_data *)gpio_data);
|
||||
res = bus_alloc_resource(consumer_dev, SYS_RES_IRQ, rid, irq, irq, 1,
|
||||
alloc_flags);
|
||||
if (res == NULL) {
|
||||
gpio_destruct_map_data((struct intr_map_data *)gpio_data);
|
||||
intr_free_intr_map_data((struct intr_map_data *)gpio_data);
|
||||
return (NULL);
|
||||
}
|
||||
rman_set_virtual(res, gpio_data);
|
||||
|
@ -70,12 +70,14 @@ struct gpiobus_pin_data
|
||||
char *name; /* pin name. */
|
||||
};
|
||||
|
||||
#ifdef INTRNG
|
||||
struct intr_map_data_gpio {
|
||||
struct intr_map_data hdr;
|
||||
u_int gpio_pin_num;
|
||||
u_int gpio_pin_flags;
|
||||
u_int gpio_intr_mode;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct gpiobus_softc
|
||||
{
|
||||
|
@ -321,13 +321,11 @@ ofw_gpiobus_setup_devinfo(device_t bus, device_t child, phandle_t node)
|
||||
devi->pins[i] = pins[i].pin;
|
||||
}
|
||||
free(pins, M_DEVBUF);
|
||||
#ifndef INTRNG
|
||||
/* Parse the interrupt resources. */
|
||||
if (ofw_bus_intr_to_rl(bus, node, &dinfo->opd_dinfo.rl, NULL) != 0) {
|
||||
ofw_gpiobus_destroy_devinfo(bus, dinfo);
|
||||
return (NULL);
|
||||
}
|
||||
#endif
|
||||
device_set_ivars(child, dinfo);
|
||||
|
||||
return (dinfo);
|
||||
|
@ -187,10 +187,8 @@ ofw_iicbus_attach(device_t dev)
|
||||
|
||||
childdev = device_add_child(dev, NULL, -1);
|
||||
resource_list_init(&dinfo->opd_dinfo.rl);
|
||||
#ifndef INTRNG
|
||||
ofw_bus_intr_to_rl(childdev, child,
|
||||
&dinfo->opd_dinfo.rl, NULL);
|
||||
#endif
|
||||
device_set_ivars(childdev, dinfo);
|
||||
}
|
||||
|
||||
|
@ -516,7 +516,6 @@ ofw_bus_find_iparent(phandle_t node)
|
||||
return (iparent);
|
||||
}
|
||||
|
||||
#ifndef INTRNG
|
||||
int
|
||||
ofw_bus_intr_to_rl(device_t dev, phandle_t node,
|
||||
struct resource_list *rl, int *rlen)
|
||||
@ -582,7 +581,6 @@ ofw_bus_intr_to_rl(device_t dev, phandle_t node,
|
||||
free(intr, M_OFWPROP);
|
||||
return (err);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
ofw_bus_intr_by_rid(device_t dev, phandle_t node, int wanted_rid,
|
||||
|
@ -32,7 +32,9 @@
|
||||
#define _DEV_OFW_OFW_BUS_SUBR_H_
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
#ifdef INTRNG
|
||||
#include <sys/intr.h>
|
||||
#endif
|
||||
#include <dev/ofw/openfirm.h>
|
||||
|
||||
#include "ofw_bus_if.h"
|
||||
@ -52,12 +54,14 @@ struct ofw_compat_data {
|
||||
uintptr_t ocd_data;
|
||||
};
|
||||
|
||||
#ifdef INTRNG
|
||||
struct intr_map_data_fdt {
|
||||
struct intr_map_data hdr;
|
||||
phandle_t iparent;
|
||||
u_int ncells;
|
||||
pcell_t *cells;
|
||||
pcell_t cells[];
|
||||
};
|
||||
#endif
|
||||
|
||||
#define SIMPLEBUS_PNP_DESCR "Z:compat;P:private;"
|
||||
#define SIMPLEBUS_PNP_INFO(t) \
|
||||
@ -89,9 +93,7 @@ int ofw_bus_msimap(phandle_t, uint16_t, phandle_t *, uint32_t *);
|
||||
/* Routines for parsing device-tree data into resource lists. */
|
||||
int ofw_bus_reg_to_rl(device_t, phandle_t, pcell_t, pcell_t,
|
||||
struct resource_list *);
|
||||
#ifndef INTRNG
|
||||
int ofw_bus_intr_to_rl(device_t, phandle_t, struct resource_list *, int *);
|
||||
#endif
|
||||
int ofw_bus_intr_by_rid(device_t, phandle_t, int, phandle_t *, int *,
|
||||
pcell_t **);
|
||||
|
||||
|
@ -80,9 +80,6 @@ static device_attach_t ofwbus_attach;
|
||||
static bus_alloc_resource_t ofwbus_alloc_resource;
|
||||
static bus_adjust_resource_t ofwbus_adjust_resource;
|
||||
static bus_release_resource_t ofwbus_release_resource;
|
||||
#ifdef INTRNG
|
||||
static bus_map_intr_t ofwbus_map_intr;
|
||||
#endif
|
||||
|
||||
static device_method_t ofwbus_methods[] = {
|
||||
/* Device interface */
|
||||
@ -96,9 +93,6 @@ static device_method_t ofwbus_methods[] = {
|
||||
DEVMETHOD(bus_alloc_resource, ofwbus_alloc_resource),
|
||||
DEVMETHOD(bus_adjust_resource, ofwbus_adjust_resource),
|
||||
DEVMETHOD(bus_release_resource, ofwbus_release_resource),
|
||||
#ifdef INTRNG
|
||||
DEVMETHOD(bus_map_intr, ofwbus_map_intr),
|
||||
#endif
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
@ -299,53 +293,3 @@ ofwbus_release_resource(device_t bus, device_t child, int type,
|
||||
}
|
||||
return (rman_release_resource(r));
|
||||
}
|
||||
|
||||
#ifdef INTRNG
|
||||
static void
|
||||
ofwbus_destruct_map_data(struct intr_map_data *map_data)
|
||||
{
|
||||
struct intr_map_data_fdt *fdt_map_data;
|
||||
|
||||
KASSERT(map_data->type == INTR_MAP_DATA_FDT,
|
||||
("%s: bad map_data type %d", __func__, map_data->type));
|
||||
|
||||
fdt_map_data = (struct intr_map_data_fdt *)map_data;
|
||||
OF_prop_free(fdt_map_data->cells);
|
||||
free(fdt_map_data, M_OFWPROP);
|
||||
}
|
||||
|
||||
static int
|
||||
ofwbus_map_intr(device_t bus, device_t child, int *rid, rman_res_t *start,
|
||||
rman_res_t *end, rman_res_t *count, struct intr_map_data **imd)
|
||||
{
|
||||
phandle_t iparent, node;
|
||||
pcell_t *cells;
|
||||
int ncells, rv;
|
||||
u_int irq;
|
||||
struct intr_map_data_fdt *fdt_data;
|
||||
|
||||
node = ofw_bus_get_node(child);
|
||||
rv = ofw_bus_intr_by_rid(child, node, *rid, &iparent, &ncells, &cells);
|
||||
if (rv != 0)
|
||||
return (rv);
|
||||
|
||||
fdt_data = malloc(sizeof(*fdt_data), M_OFWPROP, M_WAITOK | M_ZERO);
|
||||
fdt_data->hdr.type = INTR_MAP_DATA_FDT;
|
||||
fdt_data->hdr.destruct = ofwbus_destruct_map_data;
|
||||
fdt_data->iparent = iparent;
|
||||
fdt_data->ncells = ncells;
|
||||
fdt_data->cells = cells;
|
||||
rv = intr_map_irq(NULL, iparent, (struct intr_map_data *)fdt_data,
|
||||
&irq);
|
||||
if (rv != 0) {
|
||||
ofwbus_destruct_map_data((struct intr_map_data *)fdt_data);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
*start = irq;
|
||||
*end = irq;
|
||||
*count = 1;
|
||||
*imd = (struct intr_map_data *)fdt_data;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
@ -939,9 +939,7 @@ generic_pcie_ofw_bus_attach(device_t dev)
|
||||
resource_list_init(&di->di_rl);
|
||||
ofw_bus_reg_to_rl(dev, node, addr_cells, size_cells,
|
||||
&di->di_rl);
|
||||
#ifndef INTRNG
|
||||
ofw_bus_intr_to_rl(dev, node, &di->di_rl, NULL);
|
||||
#endif
|
||||
|
||||
/* Add newbus device for this FDT node */
|
||||
child = device_add_child(dev, NULL, -1);
|
||||
|
@ -263,9 +263,7 @@ mrmlb_ofw_bus_attach(device_t dev)
|
||||
resource_list_init(&di->di_rl);
|
||||
ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells,
|
||||
&di->di_rl);
|
||||
#ifndef INTRNG
|
||||
ofw_bus_intr_to_rl(dev, node, &di->di_rl, NULL);
|
||||
#endif
|
||||
|
||||
/* Add newbus device for this FDT node */
|
||||
child = device_add_child(dev, NULL, -1);
|
||||
|
@ -271,9 +271,7 @@ mdionexus_ofw_bus_attach(device_t dev)
|
||||
resource_list_init(&di->di_rl);
|
||||
ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells,
|
||||
&di->di_rl);
|
||||
#ifndef INTRNG
|
||||
ofw_bus_intr_to_rl(dev, node, &di->di_rl, NULL);
|
||||
#endif
|
||||
|
||||
/* Add newbus device for this FDT node */
|
||||
child = device_add_child(dev, NULL, -1);
|
||||
|
@ -417,35 +417,6 @@ METHOD int release_resource {
|
||||
struct resource *_res;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Map an interrupt
|
||||
*
|
||||
* This method is used to get an interrupt mapping data according to provided
|
||||
* hints. The hints could be modified afterwards, but only if mapping data was
|
||||
* allocated. This method is intended to be called before BUS_ALLOC_RESOURCE().
|
||||
*
|
||||
* @param _dev the parent device of @p _child
|
||||
* @param _child the device which is requesting an allocation
|
||||
* @param _rid a pointer to the resource identifier
|
||||
* @param _start a pointer to the hint at the start of the resource
|
||||
* range - pass @c 0 for any start address
|
||||
* @param _end a pointer to the hint at the end of the resource
|
||||
* range - pass @c ~0 for any end address
|
||||
* @param _count a pointer to the hint at the size of resource
|
||||
* range required - pass @c 1 for any size
|
||||
* @param _imd a pointer to the interrupt mapping data which was
|
||||
* allocated
|
||||
*/
|
||||
METHOD int map_intr {
|
||||
device_t _dev;
|
||||
device_t _child;
|
||||
int *_rid;
|
||||
rman_res_t *_start;
|
||||
rman_res_t *_end;
|
||||
rman_res_t *_count;
|
||||
struct intr_map_data **_imd;
|
||||
} DEFAULT bus_generic_map_intr;
|
||||
|
||||
/**
|
||||
* @brief Install an interrupt handler
|
||||
*
|
||||
|
@ -43,7 +43,7 @@ CODE {
|
||||
}
|
||||
|
||||
static int
|
||||
null_pic_alloc_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
null_pic_activate_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
struct resource *res, struct intr_map_data *data)
|
||||
{
|
||||
|
||||
@ -51,7 +51,7 @@ CODE {
|
||||
}
|
||||
|
||||
static int
|
||||
null_pic_release_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
null_pic_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
|
||||
struct resource *res, struct intr_map_data *data)
|
||||
{
|
||||
|
||||
@ -92,12 +92,12 @@ CODE {
|
||||
}
|
||||
};
|
||||
|
||||
METHOD int alloc_intr {
|
||||
METHOD int activate_intr {
|
||||
device_t dev;
|
||||
struct intr_irqsrc *isrc;
|
||||
struct resource *res;
|
||||
struct intr_map_data *data;
|
||||
} DEFAULT null_pic_alloc_intr;
|
||||
} DEFAULT null_pic_activate_intr;
|
||||
|
||||
METHOD int bind_intr {
|
||||
device_t dev;
|
||||
@ -120,12 +120,12 @@ METHOD int map_intr {
|
||||
struct intr_irqsrc **isrcp;
|
||||
};
|
||||
|
||||
METHOD int release_intr {
|
||||
METHOD int deactivate_intr {
|
||||
device_t dev;
|
||||
struct intr_irqsrc *isrc;
|
||||
struct resource *res;
|
||||
struct intr_map_data *data;
|
||||
} DEFAULT null_pic_release_intr;
|
||||
} DEFAULT null_pic_deactivate_intr;
|
||||
|
||||
METHOD int setup_intr {
|
||||
device_t dev;
|
||||
|
@ -3950,23 +3950,6 @@ bus_generic_new_pass(device_t dev)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function for implementing BUS_MAP_INTR().
|
||||
*
|
||||
* This simple implementation of BUS_MAP_INTR() simply calls the
|
||||
* BUS_MAP_INTR() method of the parent of @p dev.
|
||||
*/
|
||||
int
|
||||
bus_generic_map_intr(device_t dev, device_t child, int *rid, rman_res_t *start,
|
||||
rman_res_t *end, rman_res_t *count, struct intr_map_data **imd)
|
||||
{
|
||||
/* Propagate up the bus hierarchy until someone handles it. */
|
||||
if (dev->parent)
|
||||
return (BUS_MAP_INTR(dev->parent, child, rid, start, end, count,
|
||||
imd));
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function for implementing BUS_SETUP_INTR().
|
||||
*
|
||||
@ -4422,41 +4405,6 @@ bus_release_resources(device_t dev, const struct resource_spec *rs,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INTRNG
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* This can be converted to bus method later. (XXX)
|
||||
*/
|
||||
static struct intr_map_data *
|
||||
bus_extend_resource(device_t dev, int type, int *rid, rman_res_t *start,
|
||||
rman_res_t *end, rman_res_t *count)
|
||||
{
|
||||
struct intr_map_data *imd;
|
||||
struct resource_list *rl;
|
||||
int rv;
|
||||
|
||||
if (dev->parent == NULL)
|
||||
return (NULL);
|
||||
if (type != SYS_RES_IRQ)
|
||||
return (NULL);
|
||||
|
||||
if (!RMAN_IS_DEFAULT_RANGE(*start, *end))
|
||||
return (NULL);
|
||||
rl = BUS_GET_RESOURCE_LIST(dev->parent, dev);
|
||||
if (rl != NULL) {
|
||||
if (resource_list_find(rl, type, *rid) != NULL)
|
||||
return (NULL);
|
||||
}
|
||||
rv = BUS_MAP_INTR(dev->parent, dev, rid, start, end, count, &imd);
|
||||
if (rv != 0)
|
||||
return (NULL);
|
||||
if (rl != NULL)
|
||||
resource_list_add(rl, type, *rid, *start, *end, *count);
|
||||
return (imd);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Wrapper function for BUS_ALLOC_RESOURCE().
|
||||
*
|
||||
@ -4468,26 +4416,11 @@ bus_alloc_resource(device_t dev, int type, int *rid, rman_res_t start,
|
||||
rman_res_t end, rman_res_t count, u_int flags)
|
||||
{
|
||||
struct resource *res;
|
||||
#ifdef INTRNG
|
||||
struct intr_map_data *imd;
|
||||
#endif
|
||||
|
||||
if (dev->parent == NULL)
|
||||
return (NULL);
|
||||
|
||||
#ifdef INTRNG
|
||||
imd = bus_extend_resource(dev, type, rid, &start, &end, &count);
|
||||
#endif
|
||||
res = BUS_ALLOC_RESOURCE(dev->parent, dev, type, rid, start, end,
|
||||
count, flags);
|
||||
#ifdef INTRNG
|
||||
if (imd != NULL) {
|
||||
if (res != NULL && rman_get_virtual(res) == NULL)
|
||||
rman_set_virtual(res, imd);
|
||||
else
|
||||
imd->destruct(imd);
|
||||
}
|
||||
#endif
|
||||
return (res);
|
||||
}
|
||||
|
||||
@ -4574,21 +4507,10 @@ int
|
||||
bus_release_resource(device_t dev, int type, int rid, struct resource *r)
|
||||
{
|
||||
int rv;
|
||||
#ifdef INTRNG
|
||||
struct intr_map_data *imd;
|
||||
#endif
|
||||
|
||||
if (dev->parent == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
#ifdef INTRNG
|
||||
imd = (type == SYS_RES_IRQ) ? rman_get_virtual(r) : NULL;
|
||||
#endif
|
||||
rv = BUS_RELEASE_RESOURCE(dev->parent, dev, type, rid, r);
|
||||
#ifdef INTRNG
|
||||
if (imd != NULL)
|
||||
imd->destruct(imd);
|
||||
#endif
|
||||
return (rv);
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,9 @@ __FBSDID("$FreeBSD$");
|
||||
/*
|
||||
* New-style Interrupt Framework
|
||||
*
|
||||
* TODO: - to support IPI (PPI) enabling on other CPUs if already started
|
||||
* - to complete things for removable PICs
|
||||
* TODO: - add support for disconnected PICs.
|
||||
* - to support IPI (PPI) enabling on other CPUs if already started.
|
||||
* - to complete things for removable PICs.
|
||||
*/
|
||||
|
||||
#include "opt_ddb.h"
|
||||
@ -142,6 +143,11 @@ size_t sintrcnt = sizeof(intrcnt);
|
||||
size_t sintrnames = sizeof(intrnames);
|
||||
static u_int intrcnt_index;
|
||||
|
||||
static struct intr_irqsrc *intr_map_get_isrc(u_int res_id);
|
||||
static void intr_map_set_isrc(u_int res_id, struct intr_irqsrc *isrc);
|
||||
static void intr_map_copy_map_data(u_int res_id, device_t *dev, intptr_t *xref,
|
||||
struct intr_map_data **data);
|
||||
|
||||
/*
|
||||
* Interrupt framework initialization routine.
|
||||
*/
|
||||
@ -413,18 +419,6 @@ isrc_free_irq(struct intr_irqsrc *isrc)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup interrupt source by interrupt number (resource handle).
|
||||
*/
|
||||
static inline struct intr_irqsrc *
|
||||
isrc_lookup(u_int irq)
|
||||
{
|
||||
|
||||
if (irq < nitems(irq_sources))
|
||||
return (irq_sources[irq]);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize interrupt source and register it into global interrupt table.
|
||||
*/
|
||||
@ -899,13 +893,12 @@ intr_pic_add_handler(device_t parent, struct intr_pic *pic,
|
||||
return (pic);
|
||||
}
|
||||
|
||||
int
|
||||
intr_map_irq(device_t dev, intptr_t xref, struct intr_map_data *data,
|
||||
u_int *irqp)
|
||||
static int
|
||||
intr_resolve_irq(device_t dev, intptr_t xref, struct intr_map_data *data,
|
||||
struct intr_irqsrc **isrc)
|
||||
{
|
||||
int error;
|
||||
struct intr_irqsrc *isrc;
|
||||
struct intr_pic *pic;
|
||||
struct intr_map_data_msi *msi;
|
||||
|
||||
if (data == NULL)
|
||||
return (EINVAL);
|
||||
@ -914,50 +907,79 @@ intr_map_irq(device_t dev, intptr_t xref, struct intr_map_data *data,
|
||||
if (pic == NULL)
|
||||
return (ESRCH);
|
||||
|
||||
KASSERT((pic->pic_flags & FLAG_PIC) != 0,
|
||||
("%s: Found a non-PIC controller: %s", __func__,
|
||||
device_get_name(pic->pic_dev)));
|
||||
switch (data->type) {
|
||||
case INTR_MAP_DATA_MSI:
|
||||
KASSERT((pic->pic_flags & FLAG_MSI) != 0,
|
||||
("%s: Found a non-MSI controller: %s", __func__,
|
||||
device_get_name(pic->pic_dev)));
|
||||
msi = (struct intr_map_data_msi *)data;
|
||||
*isrc = msi->isrc;
|
||||
return (0);
|
||||
|
||||
error = PIC_MAP_INTR(pic->pic_dev, data, &isrc);
|
||||
if (error == 0)
|
||||
*irqp = isrc->isrc_irq;
|
||||
default:
|
||||
KASSERT((pic->pic_flags & FLAG_PIC) != 0,
|
||||
("%s: Found a non-PIC controller: %s", __func__,
|
||||
device_get_name(pic->pic_dev)));
|
||||
return (PIC_MAP_INTR(pic->pic_dev, data, isrc));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
intr_activate_irq(device_t dev, struct resource *res)
|
||||
{
|
||||
device_t map_dev;
|
||||
intptr_t map_xref;
|
||||
struct intr_map_data *data;
|
||||
struct intr_irqsrc *isrc;
|
||||
u_int res_id;
|
||||
int error;
|
||||
|
||||
KASSERT(rman_get_start(res) == rman_get_end(res),
|
||||
("%s: more interrupts in resource", __func__));
|
||||
|
||||
res_id = (u_int)rman_get_start(res);
|
||||
if (intr_map_get_isrc(res_id) != NULL)
|
||||
panic("Attempt to double activation of resource id: %u\n",
|
||||
res_id);
|
||||
intr_map_copy_map_data(res_id, &map_dev, &map_xref, &data);
|
||||
error = intr_resolve_irq(map_dev, map_xref, data, &isrc);
|
||||
if (error != 0) {
|
||||
free(data, M_INTRNG);
|
||||
/* XXX TODO DISCONECTED PICs */
|
||||
/* if (error == EINVAL) return(0); */
|
||||
return (error);
|
||||
}
|
||||
intr_map_set_isrc(res_id, isrc);
|
||||
rman_set_virtual(res, data);
|
||||
return (PIC_ACTIVATE_INTR(isrc->isrc_dev, isrc, res, data));
|
||||
}
|
||||
|
||||
int
|
||||
intr_deactivate_irq(device_t dev, struct resource *res)
|
||||
{
|
||||
struct intr_map_data *data;
|
||||
struct intr_irqsrc *isrc;
|
||||
u_int res_id;
|
||||
int error;
|
||||
|
||||
KASSERT(rman_get_start(res) == rman_get_end(res),
|
||||
("%s: more interrupts in resource", __func__));
|
||||
|
||||
res_id = (u_int)rman_get_start(res);
|
||||
isrc = intr_map_get_isrc(res_id);
|
||||
if (isrc == NULL)
|
||||
panic("Attempt to deactivate non-active resource id: %u\n",
|
||||
res_id);
|
||||
|
||||
data = rman_get_virtual(res);
|
||||
error = PIC_DEACTIVATE_INTR(isrc->isrc_dev, isrc, res, data);
|
||||
intr_map_set_isrc(res_id, NULL);
|
||||
rman_set_virtual(res, NULL);
|
||||
free(data, M_INTRNG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
intr_alloc_irq(device_t dev, struct resource *res)
|
||||
{
|
||||
struct intr_map_data *data;
|
||||
struct intr_irqsrc *isrc;
|
||||
|
||||
KASSERT(rman_get_start(res) == rman_get_end(res),
|
||||
("%s: more interrupts in resource", __func__));
|
||||
|
||||
isrc = isrc_lookup(rman_get_start(res));
|
||||
if (isrc == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
data = rman_get_virtual(res);
|
||||
return (PIC_ALLOC_INTR(isrc->isrc_dev, isrc, res, data));
|
||||
}
|
||||
|
||||
int
|
||||
intr_release_irq(device_t dev, struct resource *res)
|
||||
{
|
||||
struct intr_map_data *data;
|
||||
struct intr_irqsrc *isrc;
|
||||
|
||||
KASSERT(rman_get_start(res) == rman_get_end(res),
|
||||
("%s: more interrupts in resource", __func__));
|
||||
|
||||
isrc = isrc_lookup(rman_get_start(res));
|
||||
if (isrc == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
data = rman_get_virtual(res);
|
||||
return (PIC_RELEASE_INTR(isrc->isrc_dev, isrc, res, data));
|
||||
}
|
||||
|
||||
int
|
||||
intr_setup_irq(device_t dev, struct resource *res, driver_filter_t filt,
|
||||
driver_intr_t hand, void *arg, int flags, void **cookiep)
|
||||
@ -966,13 +988,17 @@ intr_setup_irq(device_t dev, struct resource *res, driver_filter_t filt,
|
||||
struct intr_map_data *data;
|
||||
struct intr_irqsrc *isrc;
|
||||
const char *name;
|
||||
u_int res_id;
|
||||
|
||||
KASSERT(rman_get_start(res) == rman_get_end(res),
|
||||
("%s: more interrupts in resource", __func__));
|
||||
|
||||
isrc = isrc_lookup(rman_get_start(res));
|
||||
if (isrc == NULL)
|
||||
res_id = (u_int)rman_get_start(res);
|
||||
isrc = intr_map_get_isrc(res_id);
|
||||
if (isrc == NULL) {
|
||||
/* XXX TODO DISCONECTED PICs */
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
data = rman_get_virtual(res);
|
||||
name = device_get_nameunit(dev);
|
||||
@ -1027,11 +1053,13 @@ intr_teardown_irq(device_t dev, struct resource *res, void *cookie)
|
||||
int error;
|
||||
struct intr_map_data *data;
|
||||
struct intr_irqsrc *isrc;
|
||||
u_int res_id;
|
||||
|
||||
KASSERT(rman_get_start(res) == rman_get_end(res),
|
||||
("%s: more interrupts in resource", __func__));
|
||||
|
||||
isrc = isrc_lookup(rman_get_start(res));
|
||||
res_id = (u_int)rman_get_start(res);
|
||||
isrc = intr_map_get_isrc(res_id);
|
||||
if (isrc == NULL || isrc->isrc_handlers == 0)
|
||||
return (EINVAL);
|
||||
|
||||
@ -1075,11 +1103,13 @@ intr_describe_irq(device_t dev, struct resource *res, void *cookie,
|
||||
{
|
||||
int error;
|
||||
struct intr_irqsrc *isrc;
|
||||
u_int res_id;
|
||||
|
||||
KASSERT(rman_get_start(res) == rman_get_end(res),
|
||||
("%s: more interrupts in resource", __func__));
|
||||
|
||||
isrc = isrc_lookup(rman_get_start(res));
|
||||
res_id = (u_int)rman_get_start(res);
|
||||
isrc = intr_map_get_isrc(res_id);
|
||||
if (isrc == NULL || isrc->isrc_handlers == 0)
|
||||
return (EINVAL);
|
||||
#ifdef INTR_SOLO
|
||||
@ -1107,11 +1137,13 @@ int
|
||||
intr_bind_irq(device_t dev, struct resource *res, int cpu)
|
||||
{
|
||||
struct intr_irqsrc *isrc;
|
||||
u_int res_id;
|
||||
|
||||
KASSERT(rman_get_start(res) == rman_get_end(res),
|
||||
("%s: more interrupts in resource", __func__));
|
||||
|
||||
isrc = isrc_lookup(rman_get_start(res));
|
||||
res_id = (u_int)rman_get_start(res);
|
||||
isrc = intr_map_get_isrc(res_id);
|
||||
if (isrc == NULL || isrc->isrc_handlers == 0)
|
||||
return (EINVAL);
|
||||
#ifdef INTR_SOLO
|
||||
@ -1190,6 +1222,28 @@ intr_irq_next_cpu(u_int current_cpu, cpuset_t *cpumask)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate memory for new intr_map_data structure.
|
||||
* Initialize common fields.
|
||||
*/
|
||||
struct intr_map_data *
|
||||
intr_alloc_map_data(enum intr_map_data_type type, size_t len, int flags)
|
||||
{
|
||||
struct intr_map_data *data;
|
||||
|
||||
data = malloc(len, M_INTRNG, flags);
|
||||
data->type = type;
|
||||
data->len = len;
|
||||
return (data);
|
||||
}
|
||||
|
||||
void intr_free_intr_map_data(struct intr_map_data *data)
|
||||
{
|
||||
|
||||
free(data, M_INTRNG);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Register a MSI/MSI-X interrupt controller
|
||||
*/
|
||||
@ -1218,6 +1272,7 @@ intr_alloc_msi(device_t pci, device_t child, intptr_t xref, int count,
|
||||
struct intr_irqsrc **isrc;
|
||||
struct intr_pic *pic;
|
||||
device_t pdev;
|
||||
struct intr_map_data_msi *msi;
|
||||
int err, i;
|
||||
|
||||
pic = pic_lookup(NULL, xref);
|
||||
@ -1230,12 +1285,19 @@ intr_alloc_msi(device_t pci, device_t child, intptr_t xref, int count,
|
||||
|
||||
isrc = malloc(sizeof(*isrc) * count, M_INTRNG, M_WAITOK);
|
||||
err = MSI_ALLOC_MSI(pic->pic_dev, child, count, maxcount, &pdev, isrc);
|
||||
if (err == 0) {
|
||||
for (i = 0; i < count; i++) {
|
||||
irqs[i] = isrc[i]->isrc_irq;
|
||||
}
|
||||
if (err != 0) {
|
||||
free(isrc, M_INTRNG);
|
||||
return (err);
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
msi = (struct intr_map_data_msi *)intr_alloc_map_data(
|
||||
INTR_MAP_DATA_MSI, sizeof(*msi), M_WAITOK | M_ZERO);
|
||||
msi-> isrc = isrc[i];
|
||||
irqs[i] = intr_map_irq(pic->pic_dev, xref,
|
||||
(struct intr_map_data *)msi);
|
||||
|
||||
}
|
||||
free(isrc, M_INTRNG);
|
||||
|
||||
return (err);
|
||||
@ -1259,15 +1321,16 @@ intr_release_msi(device_t pci, device_t child, intptr_t xref, int count,
|
||||
|
||||
isrc = malloc(sizeof(*isrc) * count, M_INTRNG, M_WAITOK);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
isrc[i] = isrc_lookup(irqs[i]);
|
||||
if (isrc == NULL) {
|
||||
free(isrc, M_INTRNG);
|
||||
return (EINVAL);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < count; i++)
|
||||
isrc[i] = intr_map_get_isrc(irqs[i]);
|
||||
|
||||
err = MSI_RELEASE_MSI(pic->pic_dev, child, count, isrc);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (isrc[i] != NULL)
|
||||
intr_unmap_irq(irqs[i]);
|
||||
}
|
||||
|
||||
free(isrc, M_INTRNG);
|
||||
return (err);
|
||||
}
|
||||
@ -1278,6 +1341,7 @@ intr_alloc_msix(device_t pci, device_t child, intptr_t xref, int *irq)
|
||||
struct intr_irqsrc *isrc;
|
||||
struct intr_pic *pic;
|
||||
device_t pdev;
|
||||
struct intr_map_data_msi *msi;
|
||||
int err;
|
||||
|
||||
pic = pic_lookup(NULL, xref);
|
||||
@ -1288,11 +1352,15 @@ intr_alloc_msix(device_t pci, device_t child, intptr_t xref, int *irq)
|
||||
("%s: Found a non-MSI controller: %s", __func__,
|
||||
device_get_name(pic->pic_dev)));
|
||||
|
||||
|
||||
err = MSI_ALLOC_MSIX(pic->pic_dev, child, &pdev, &isrc);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
*irq = isrc->isrc_irq;
|
||||
msi = (struct intr_map_data_msi *)intr_alloc_map_data(
|
||||
INTR_MAP_DATA_MSI, sizeof(*msi), M_WAITOK | M_ZERO);
|
||||
msi->isrc = isrc;
|
||||
*irq = intr_map_irq(pic->pic_dev, xref, (struct intr_map_data *)msi);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1311,11 +1379,15 @@ intr_release_msix(device_t pci, device_t child, intptr_t xref, int irq)
|
||||
("%s: Found a non-MSI controller: %s", __func__,
|
||||
device_get_name(pic->pic_dev)));
|
||||
|
||||
isrc = isrc_lookup(irq);
|
||||
if (isrc == NULL)
|
||||
isrc = intr_map_get_isrc(irq);
|
||||
if (isrc == NULL) {
|
||||
intr_unmap_irq(irq);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
err = MSI_RELEASE_MSIX(pic->pic_dev, child, isrc);
|
||||
intr_unmap_irq(irq);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
@ -1335,7 +1407,7 @@ intr_map_msi(device_t pci, device_t child, intptr_t xref, int irq,
|
||||
("%s: Found a non-MSI controller: %s", __func__,
|
||||
device_get_name(pic->pic_dev)));
|
||||
|
||||
isrc = isrc_lookup(irq);
|
||||
isrc = intr_map_get_isrc(irq);
|
||||
if (isrc == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
@ -1390,3 +1462,161 @@ DB_SHOW_COMMAND(irqs, db_show_irqs)
|
||||
db_printf("irq total %u\n", irqsum);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interrupt mapping table functions.
|
||||
*
|
||||
* Please, keep this part separately, it can be transformed to
|
||||
* extension of standard resources.
|
||||
*/
|
||||
struct intr_map_entry
|
||||
{
|
||||
device_t dev;
|
||||
intptr_t xref;
|
||||
struct intr_map_data *map_data;
|
||||
struct intr_irqsrc *isrc;
|
||||
/* XXX TODO DISCONECTED PICs */
|
||||
/*int flags */
|
||||
};
|
||||
|
||||
/* XXX Convert irq_map[] to dynamicaly expandable one. */
|
||||
static struct intr_map_entry *irq_map[2 * NIRQ];
|
||||
static int irq_map_count = nitems(irq_map);
|
||||
static int irq_map_first_free_idx;
|
||||
static struct mtx irq_map_lock;
|
||||
|
||||
static struct intr_irqsrc *
|
||||
intr_map_get_isrc(u_int res_id)
|
||||
{
|
||||
struct intr_irqsrc *isrc;
|
||||
|
||||
mtx_lock(&irq_map_lock);
|
||||
if ((res_id >= irq_map_count) || (irq_map[res_id] == NULL)) {
|
||||
mtx_unlock(&irq_map_lock);
|
||||
return (NULL);
|
||||
}
|
||||
isrc = irq_map[res_id]->isrc;
|
||||
mtx_unlock(&irq_map_lock);
|
||||
return (isrc);
|
||||
}
|
||||
|
||||
static void
|
||||
intr_map_set_isrc(u_int res_id, struct intr_irqsrc *isrc)
|
||||
{
|
||||
|
||||
mtx_lock(&irq_map_lock);
|
||||
if ((res_id >= irq_map_count) || (irq_map[res_id] == NULL)) {
|
||||
mtx_unlock(&irq_map_lock);
|
||||
return;
|
||||
}
|
||||
irq_map[res_id]->isrc = isrc;
|
||||
mtx_unlock(&irq_map_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a copy of intr_map_entry data
|
||||
*/
|
||||
static void
|
||||
intr_map_copy_map_data(u_int res_id, device_t *map_dev, intptr_t *map_xref,
|
||||
struct intr_map_data **data)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = 0;
|
||||
mtx_lock(&irq_map_lock);
|
||||
if (res_id >= irq_map_count || irq_map[res_id] == NULL)
|
||||
panic("Attempt to copy invalid resource id: %u\n", res_id);
|
||||
if (irq_map[res_id]->map_data != NULL)
|
||||
len = irq_map[res_id]->map_data->len;
|
||||
mtx_unlock(&irq_map_lock);
|
||||
|
||||
if (len == 0)
|
||||
*data = NULL;
|
||||
else
|
||||
*data = malloc(len, M_INTRNG, M_WAITOK | M_ZERO);
|
||||
mtx_lock(&irq_map_lock);
|
||||
if (irq_map[res_id] == NULL)
|
||||
panic("Attempt to copy invalid resource id: %u\n", res_id);
|
||||
if (len != 0) {
|
||||
if (len != irq_map[res_id]->map_data->len)
|
||||
panic("Resource id: %u has changed.\n", res_id);
|
||||
memcpy(*data, irq_map[res_id]->map_data, len);
|
||||
}
|
||||
*map_dev = irq_map[res_id]->dev;
|
||||
*map_xref = irq_map[res_id]->xref;
|
||||
mtx_unlock(&irq_map_lock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate and fill new entry in irq_map table.
|
||||
*/
|
||||
u_int
|
||||
intr_map_irq(device_t dev, intptr_t xref, struct intr_map_data *data)
|
||||
{
|
||||
u_int i;
|
||||
struct intr_map_entry *entry;
|
||||
|
||||
/* Prepare new entry first. */
|
||||
entry = malloc(sizeof(*entry), M_INTRNG, M_WAITOK | M_ZERO);
|
||||
|
||||
entry->dev = dev;
|
||||
entry->xref = xref;
|
||||
entry->map_data = data;
|
||||
entry->isrc = NULL;
|
||||
|
||||
mtx_lock(&irq_map_lock);
|
||||
for (i = irq_map_first_free_idx; i < irq_map_count; i++) {
|
||||
if (irq_map[i] == NULL) {
|
||||
irq_map[i] = entry;
|
||||
irq_map_first_free_idx = i + 1;
|
||||
mtx_unlock(&irq_map_lock);
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&irq_map_lock);
|
||||
|
||||
/* XXX Expand irq_map table */
|
||||
panic("IRQ mapping table is full.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove and free mapping entry.
|
||||
*/
|
||||
void
|
||||
intr_unmap_irq(u_int res_id)
|
||||
{
|
||||
struct intr_map_entry *entry;
|
||||
|
||||
mtx_lock(&irq_map_lock);
|
||||
if ((res_id >= irq_map_count) || (irq_map[res_id] == NULL))
|
||||
panic("Attempt to unmap invalid resource id: %u\n", res_id);
|
||||
entry = irq_map[res_id];
|
||||
irq_map[res_id] = NULL;
|
||||
irq_map_first_free_idx = res_id;
|
||||
mtx_unlock(&irq_map_lock);
|
||||
intr_free_intr_map_data(entry->map_data);
|
||||
free(entry, M_INTRNG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clone mapping entry.
|
||||
*/
|
||||
u_int
|
||||
intr_map_clone_irq(u_int old_res_id)
|
||||
{
|
||||
device_t map_dev;
|
||||
intptr_t map_xref;
|
||||
struct intr_map_data *data;
|
||||
|
||||
intr_map_copy_map_data(old_res_id, &map_dev, &map_xref, &data);
|
||||
return (intr_map_irq(map_dev, map_xref, data));
|
||||
}
|
||||
|
||||
static void
|
||||
intr_map_init(void *dummy __unused)
|
||||
{
|
||||
|
||||
mtx_init(&irq_map_lock, "intr map table", NULL, MTX_DEF);
|
||||
}
|
||||
SYSINIT(intr_map_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_map_init, NULL);
|
||||
|
@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
|
||||
#ifdef FDT
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include "ofw_bus_if.h"
|
||||
#endif
|
||||
@ -429,6 +430,10 @@ nexus_activate_resource(device_t bus, device_t child, int type, int rid,
|
||||
}
|
||||
rman_set_virtual(r, vaddr);
|
||||
rman_set_bushandle(r, (bus_space_handle_t)(uintptr_t)vaddr);
|
||||
} else if (type == SYS_RES_IRQ) {
|
||||
#ifdef INTRNG
|
||||
intr_activate_irq(child, r);
|
||||
#endif
|
||||
}
|
||||
|
||||
return (rman_activate_resource(r));
|
||||
@ -448,6 +453,10 @@ nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
|
||||
bus_space_unmap(rman_get_bustag(r), vaddr, psize);
|
||||
rman_set_virtual(r, NULL);
|
||||
rman_set_bushandle(r, 0);
|
||||
} else if (type == SYS_RES_IRQ) {
|
||||
#ifdef INTRNG
|
||||
intr_deactivate_irq(child, r);
|
||||
#endif
|
||||
}
|
||||
|
||||
return (rman_deactivate_resource(r));
|
||||
@ -523,12 +532,18 @@ static int
|
||||
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
|
||||
pcell_t *intr)
|
||||
{
|
||||
u_int irq;
|
||||
struct intr_map_data_fdt *fdt_data;
|
||||
size_t len;
|
||||
|
||||
#ifdef INTRNG
|
||||
return (INTR_IRQ_INVALID);
|
||||
#else
|
||||
return (intr_fdt_map_irq(iparent, intr, icells));
|
||||
#endif
|
||||
len = sizeof(*fdt_data) + icells * sizeof(pcell_t);
|
||||
fdt_data = (struct intr_map_data_fdt *)intr_alloc_map_data(
|
||||
INTR_MAP_DATA_FDT, len, M_WAITOK | M_ZERO);
|
||||
fdt_data->iparent = iparent;
|
||||
fdt_data->ncells = icells;
|
||||
memcpy(fdt_data->cells, intr, icells * sizeof(pcell_t));
|
||||
irq = intr_map_irq(NULL, iparent, (struct intr_map_data *)fdt_data);
|
||||
return (irq);
|
||||
}
|
||||
#endif
|
||||
#endif /* INTRNG */
|
||||
|
@ -272,17 +272,6 @@ enum intr_polarity {
|
||||
INTR_POLARITY_LOW = 2
|
||||
};
|
||||
|
||||
enum intr_map_data_type {
|
||||
INTR_MAP_DATA_ACPI,
|
||||
INTR_MAP_DATA_FDT,
|
||||
INTR_MAP_DATA_GPIO,
|
||||
};
|
||||
|
||||
struct intr_map_data {
|
||||
enum intr_map_data_type type;
|
||||
void (*destruct)(struct intr_map_data *);
|
||||
};
|
||||
|
||||
/**
|
||||
* CPU sets supported by bus_get_cpus(). Note that not all sets may be
|
||||
* supported for a given device. If a request is not supported by a
|
||||
@ -459,9 +448,6 @@ int bus_generic_release_resource(device_t bus, device_t child,
|
||||
int type, int rid, struct resource *r);
|
||||
int bus_generic_resume(device_t dev);
|
||||
int bus_generic_resume_child(device_t dev, device_t child);
|
||||
int bus_generic_map_intr(device_t dev, device_t child, int *rid,
|
||||
rman_res_t *start, rman_res_t *end,
|
||||
rman_res_t *count, struct intr_map_data **imd);
|
||||
int bus_generic_setup_intr(device_t dev, device_t child,
|
||||
struct resource *irq, int flags,
|
||||
driver_filter_t *filter, driver_intr_t *intr,
|
||||
|
@ -29,11 +29,38 @@
|
||||
|
||||
#ifndef _SYS_INTR_H_
|
||||
#define _SYS_INTR_H_
|
||||
#ifndef INTRNG
|
||||
#error Need INTRNG for this file
|
||||
#endif
|
||||
|
||||
#include <sys/systm.h>
|
||||
|
||||
#define INTR_IRQ_INVALID 0xFFFFFFFF
|
||||
|
||||
enum intr_map_data_type {
|
||||
INTR_MAP_DATA_ACPI = 0,
|
||||
INTR_MAP_DATA_FDT,
|
||||
INTR_MAP_DATA_GPIO,
|
||||
INTR_MAP_DATA_MSI,
|
||||
|
||||
/* Placeholders for platform specific types */
|
||||
INTR_MAP_DATA_PLAT_1 = 1000,
|
||||
INTR_MAP_DATA_PLAT_2,
|
||||
INTR_MAP_DATA_PLAT_3,
|
||||
INTR_MAP_DATA_PLAT_4,
|
||||
INTR_MAP_DATA_PLAT_5,
|
||||
};
|
||||
|
||||
struct intr_map_data {
|
||||
size_t len;
|
||||
enum intr_map_data_type type;
|
||||
};
|
||||
|
||||
struct intr_map_data_msi {
|
||||
struct intr_map_data hdr;
|
||||
struct intr_irqsrc *isrc;
|
||||
};
|
||||
|
||||
#ifdef notyet
|
||||
#define INTR_SOLO INTR_MD1
|
||||
typedef int intr_irq_filter_t(void *arg, struct trapframe *tf);
|
||||
@ -88,10 +115,9 @@ struct intr_pic *intr_pic_add_handler(device_t, struct intr_pic *,
|
||||
extern device_t intr_irq_root_dev;
|
||||
|
||||
/* Intr interface for BUS. */
|
||||
int intr_map_irq(device_t, intptr_t, struct intr_map_data *, u_int *);
|
||||
|
||||
int intr_alloc_irq(device_t, struct resource *);
|
||||
int intr_release_irq(device_t, struct resource *);
|
||||
int intr_activate_irq(device_t, struct resource *);
|
||||
int intr_deactivate_irq(device_t, struct resource *);
|
||||
|
||||
int intr_setup_irq(device_t, struct resource *, driver_filter_t, driver_intr_t,
|
||||
void *, int, void **);
|
||||
@ -100,6 +126,13 @@ int intr_teardown_irq(device_t, struct resource *, void *);
|
||||
int intr_describe_irq(device_t, struct resource *, void *, const char *);
|
||||
int intr_child_irq_handler(struct intr_pic *, uintptr_t);
|
||||
|
||||
/* Intr resources mapping. */
|
||||
struct intr_map_data *intr_alloc_map_data(enum intr_map_data_type, size_t, int);
|
||||
void intr_free_intr_map_data(struct intr_map_data *);
|
||||
u_int intr_map_irq(device_t, intptr_t, struct intr_map_data *);
|
||||
void intr_unmap_irq(u_int );
|
||||
u_int intr_map_clone_irq(u_int );
|
||||
|
||||
/* MSI/MSI-X handling */
|
||||
int intr_msi_register(device_t, intptr_t);
|
||||
int intr_alloc_msi(device_t, device_t, intptr_t, int, int, int *);
|
||||
|
Loading…
Reference in New Issue
Block a user