bhnd(4): Implement backplane interrupt handling.
This adds bhnd(4) bus-level support for querying backplane interrupt vector routing, and delegating machine/bridge-specific interrupt handling to the concrete bhnd(4) driver implementation. On bhndb(4) bridged PCI devices, we provide the PCI/MSI interrupt directly to attached cores. On MIPS devices, we report a backplane interrupt count of 0, effectively disabling the bus-level interrupt assignment. This allows mips/broadcom to temporarily continue using hard-coded MIPS IRQs until bhnd_mips PIC support is implemented. Reviewed by: mizhka Approved by: adrian (mentor, implicit)
This commit is contained in:
parent
bc0784fd1f
commit
47d8c9cde3
@ -41,8 +41,11 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "bcmavar.h"
|
||||
|
||||
#include "bcma_dmp.h"
|
||||
|
||||
#include "bcma_eromreg.h"
|
||||
#include "bcma_eromvar.h"
|
||||
|
||||
#include <dev/bhnd/bhnd_core.h>
|
||||
|
||||
/* RID used when allocating EROM table */
|
||||
@ -434,6 +437,70 @@ bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
|
||||
*
|
||||
* This implementation consults @p child's agent register block,
|
||||
* returning the number of interrupt output lines routed to @p child.
|
||||
*/
|
||||
int
|
||||
bcma_get_intr_count(device_t dev, device_t child)
|
||||
{
|
||||
struct bcma_devinfo *dinfo;
|
||||
uint32_t dmpcfg, oobw;
|
||||
|
||||
dinfo = device_get_ivars(child);
|
||||
|
||||
/* Agent block must be mapped */
|
||||
if (dinfo->res_agent == NULL)
|
||||
return (0);
|
||||
|
||||
/* Agent must support OOB */
|
||||
dmpcfg = bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_CONFIG);
|
||||
if (!BCMA_DMP_GET_FLAG(dmpcfg, BCMA_DMP_CFG_OOB))
|
||||
return (0);
|
||||
|
||||
/* Return OOB width as interrupt count */
|
||||
oobw = bhnd_bus_read_4(dinfo->res_agent,
|
||||
BCMA_DMP_OOB_OUTWIDTH(BCMA_OOB_BANK_INTR));
|
||||
if (oobw > BCMA_OOB_NUM_SEL) {
|
||||
device_printf(dev, "ignoring invalid OOBOUTWIDTH for core %u: "
|
||||
"%#x\n", BCMA_DINFO_COREIDX(dinfo), oobw);
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (oobw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bcma(4) bus driver implementation of BHND_BUS_GET_CORE_IVEC().
|
||||
*
|
||||
* This implementation consults @p child's agent register block,
|
||||
* returning the interrupt output line routed to @p child, at OOB selector
|
||||
* @p intr.
|
||||
*/
|
||||
int
|
||||
bcma_get_core_ivec(device_t dev, device_t child, u_int intr, uint32_t *ivec)
|
||||
{
|
||||
struct bcma_devinfo *dinfo;
|
||||
uint32_t oobsel;
|
||||
|
||||
dinfo = device_get_ivars(child);
|
||||
|
||||
/* Interrupt ID must be valid. */
|
||||
if (intr >= bcma_get_intr_count(dev, child))
|
||||
return (ENXIO);
|
||||
|
||||
/* Fetch OOBSEL busline value */
|
||||
KASSERT(dinfo->res_agent != NULL, ("missing agent registers"));
|
||||
oobsel = bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_OOBSELOUT(
|
||||
BCMA_OOB_BANK_INTR, intr));
|
||||
*ivec = (oobsel >> BCMA_DMP_OOBSEL_SHIFT(intr)) &
|
||||
BCMA_DMP_OOBSEL_BUSLINE_MASK;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct bhnd_devinfo *
|
||||
bcma_alloc_bhnd_dinfo(device_t dev)
|
||||
{
|
||||
@ -475,6 +542,8 @@ bcma_add_children(device_t bus)
|
||||
/* Add all cores. */
|
||||
bcma_erom = (struct bcma_erom *)erom;
|
||||
while ((error = bcma_erom_next_corecfg(bcma_erom, &corecfg)) == 0) {
|
||||
int nintr;
|
||||
|
||||
/* Add the child device */
|
||||
child = BUS_ADD_CHILD(bus, 0, NULL, -1);
|
||||
if (child == NULL) {
|
||||
@ -494,6 +563,17 @@ bcma_add_children(device_t bus)
|
||||
if ((error = bcma_dinfo_alloc_agent(bus, child, dinfo)))
|
||||
goto cleanup;
|
||||
|
||||
/* Assign interrupts */
|
||||
nintr = bhnd_get_intr_count(child);
|
||||
for (int rid = 0; rid < nintr; rid++) {
|
||||
error = BHND_BUS_ASSIGN_INTR(bus, child, rid);
|
||||
if (error) {
|
||||
device_printf(bus, "failed to assign interrupt "
|
||||
"%d to core %u: %d\n", rid,
|
||||
BCMA_DINFO_COREIDX(dinfo), error);
|
||||
}
|
||||
}
|
||||
|
||||
/* If pins are floating or the hardware is otherwise
|
||||
* unpopulated, the device shouldn't be used. */
|
||||
if (bhnd_is_hw_disabled(child))
|
||||
@ -544,6 +624,8 @@ static device_method_t bcma_methods[] = {
|
||||
DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid),
|
||||
DEVMETHOD(bhnd_bus_decode_port_rid, bcma_decode_port_rid),
|
||||
DEVMETHOD(bhnd_bus_get_region_addr, bcma_get_region_addr),
|
||||
DEVMETHOD(bhnd_bus_get_intr_count, bcma_get_intr_count),
|
||||
DEVMETHOD(bhnd_bus_get_core_ivec, bcma_get_core_ivec),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
@ -37,8 +37,18 @@
|
||||
* in the proprietary "NIC-301 Interconnect Device Management (PL368)"
|
||||
* errata publication, available to licensees as part of ARM's
|
||||
* CoreLink Controllers and Peripherals Engineering Errata.
|
||||
*
|
||||
* As such, the exact interpretation of these register definitions is
|
||||
* unconfirmed, and may be incorrect.
|
||||
*/
|
||||
|
||||
#define BCMA_DMP_GET_FLAG(_value, _flag) \
|
||||
(((_value) & _flag) != 0)
|
||||
#define BCMA_DMP_GET_BITS(_value, _field) \
|
||||
((_value & _field ## _MASK) >> _field ## _SHIFT)
|
||||
#define BHND_DMP_SET_BITS(_value, _field) \
|
||||
(((_value) << _field ## _SHIFT) & _field ## _MASK)
|
||||
|
||||
/* Out-of-band Router registers */
|
||||
#define BCMA_OOB_BUSCONFIG 0x020
|
||||
#define BCMA_OOB_STATUSA 0x100
|
||||
@ -71,23 +81,36 @@
|
||||
#define BCMA_OOB_ITOPOOBC 0xf38
|
||||
#define BCMA_OOB_ITOPOOBD 0xf3c
|
||||
|
||||
/* DMP wrapper registers */
|
||||
#define BCMA_DMP_OOBSELINA30 0x000
|
||||
#define BCMA_DMP_OOBSELINA74 0x004
|
||||
#define BCMA_DMP_OOBSELINB30 0x020
|
||||
#define BCMA_DMP_OOBSELINB74 0x024
|
||||
#define BCMA_DMP_OOBSELINC30 0x040
|
||||
#define BCMA_DMP_OOBSELINC74 0x044
|
||||
#define BCMA_DMP_OOBSELIND30 0x060
|
||||
#define BCMA_DMP_OOBSELIND74 0x064
|
||||
#define BCMA_DMP_OOBSELOUTA30 0x100
|
||||
#define BCMA_DMP_OOBSELOUTA74 0x104
|
||||
#define BCMA_DMP_OOBSELOUTB30 0x120
|
||||
#define BCMA_DMP_OOBSELOUTB74 0x124
|
||||
#define BCMA_DMP_OOBSELOUTC30 0x140
|
||||
#define BCMA_DMP_OOBSELOUTC74 0x144
|
||||
#define BCMA_DMP_OOBSELOUTD30 0x160
|
||||
#define BCMA_DMP_OOBSELOUTD74 0x164
|
||||
/* Common definitions */
|
||||
#define BCMA_OOB_NUM_BANKS 4 /**< number of OOB banks (A, B, C, D) */
|
||||
#define BCMA_OOB_NUM_SEL 8 /**< number of OOB selectors per bank */
|
||||
#define BCMA_OOB_NUM_BUSLINES 32 /**< number of bus lines managed by OOB core */
|
||||
|
||||
#define BCMA_OOB_BANKA 0 /**< bank A index */
|
||||
#define BCMA_OOB_BANKB 1 /**< bank B index */
|
||||
#define BCMA_OOB_BANKC 2 /**< bank C index */
|
||||
#define BCMA_OOB_BANKD 3 /**< bank D index */
|
||||
|
||||
/** OOB bank used for interrupt lines */
|
||||
#define BCMA_OOB_BANK_INTR BCMA_OOB_BANKA
|
||||
|
||||
/* DMP agent registers */
|
||||
#define BCMA_DMP_OOBSELINA30 0x000 /**< A0-A3 input selectors */
|
||||
#define BCMA_DMP_OOBSELINA74 0x004 /**< A4-A7 input selectors */
|
||||
#define BCMA_DMP_OOBSELINB30 0x020 /**< B0-B3 input selectors */
|
||||
#define BCMA_DMP_OOBSELINB74 0x024 /**< B4-B7 input selectors */
|
||||
#define BCMA_DMP_OOBSELINC30 0x040 /**< C0-C3 input selectors */
|
||||
#define BCMA_DMP_OOBSELINC74 0x044 /**< C4-C7 input selectors */
|
||||
#define BCMA_DMP_OOBSELIND30 0x060 /**< D0-D3 input selectors */
|
||||
#define BCMA_DMP_OOBSELIND74 0x064 /**< D4-D7 input selectors */
|
||||
#define BCMA_DMP_OOBSELOUTA30 0x100 /**< A0-A3 output selectors */
|
||||
#define BCMA_DMP_OOBSELOUTA74 0x104 /**< A4-A7 output selectors */
|
||||
#define BCMA_DMP_OOBSELOUTB30 0x120 /**< B0-B3 output selectors */
|
||||
#define BCMA_DMP_OOBSELOUTB74 0x124 /**< B4-B7 output selectors */
|
||||
#define BCMA_DMP_OOBSELOUTC30 0x140 /**< C0-C3 output selectors */
|
||||
#define BCMA_DMP_OOBSELOUTC74 0x144 /**< C4-C7 output selectors */
|
||||
#define BCMA_DMP_OOBSELOUTD30 0x160 /**< D0-D3 output selectors */
|
||||
#define BCMA_DMP_OOBSELOUTD74 0x164 /**< D4-D7 output selectors */
|
||||
#define BCMA_DMP_OOBSYNCA 0x200
|
||||
#define BCMA_DMP_OOBSELOUTAEN 0x204
|
||||
#define BCMA_DMP_OOBSYNCB 0x220
|
||||
@ -109,18 +132,20 @@
|
||||
#define BCMA_DMP_OOBDINWIDTH 0x364
|
||||
#define BCMA_DMP_OOBDOUTWIDTH 0x368
|
||||
|
||||
/* The exact interpretation of these bits is unverified; these
|
||||
* are our best guesses as to their use */
|
||||
#define BCMA_DMP_OOBSEL_MASK 0xFF /**< OOBSEL config mask */
|
||||
#define BCMA_DMP_OOBSEL_0_MASK BCMA_DMP_OOBSEL_MASK
|
||||
#define BCMA_DMP_OOBSEL_1_MASK BCMA_DMP_OOBSEL_MASK
|
||||
#define BCMA_DMP_OOBSEL_2_MASK BCMA_DMP_OOBSEL_MASK
|
||||
#define BCMA_DMP_OOBSEL_3_MASK BCMA_DMP_OOBSEL_MASK
|
||||
#define BCMA_DMP_OOBSEL_0_SHIFT 0 /**< first OOBSEL config */
|
||||
#define BCMA_DMP_OOBSEL_1_SHIFT 8 /**< second OOBSEL config */
|
||||
#define BCMA_DMP_OOBSEL_2_SHIFT 16 /**< third OOBSEL config */
|
||||
#define BCMA_DMP_OOBSEL_3_SHIFT 24 /**< fouth OOBSEL config */
|
||||
#define BCMA_DMP_OOBSEL_EN (1 << 7) /**< enable bit */
|
||||
#define BCMA_DMP_OOBSEL(_base, _bank, _sel) \
|
||||
(_base + (_bank * 8) + (_sel >= 4 ? 4 : 0))
|
||||
|
||||
#define BCMA_DMP_OOBSELIN(_bank, _sel) \
|
||||
BCMA_DMP_OOBSEL(BCMA_DMP_OOBSELINA30, _bank, _sel)
|
||||
|
||||
#define BCMA_DMP_OOBSELOUT(_bank, _sel) \
|
||||
BCMA_DMP_OOBSEL(BCMA_DMP_OOBSELOUTA30, _bank, _sel)
|
||||
|
||||
#define BCMA_DMP_OOBSYNC(_bank) (BCMA_DMP_OOBSYNCA + (_bank * 8))
|
||||
#define BCMA_DMP_OOBSELOUT_EN(_bank) (BCMA_DMP_OOBSELOUTAEN + (_bank * 8))
|
||||
#define BCMA_DMP_OOB_EXTWIDTH(_bank) (BCMA_DMP_OOBAEXTWIDTH + (_bank * 12))
|
||||
#define BCMA_DMP_OOB_INWIDTH(_bank) (BCMA_DMP_OOBAINWIDTH + (_bank * 12))
|
||||
#define BCMA_DMP_OOB_OUTWIDTH(_bank) (BCMA_DMP_OOBAOUTWIDTH + (_bank * 12))
|
||||
|
||||
// This was inherited from Broadcom's aidmp.h header
|
||||
// Is it required for any of our use-cases?
|
||||
@ -192,6 +217,34 @@
|
||||
#define BCMA_DMP_COMPONENTID2 0xff8
|
||||
#define BCMA_DMP_COMPONENTID3 0xffc
|
||||
|
||||
|
||||
/* OOBSEL(IN|OUT) */
|
||||
#define BCMA_DMP_OOBSEL_MASK 0xFF /**< OOB selector mask */
|
||||
#define BCMA_DMP_OOBSEL_EN (1<<7) /**< OOB selector enable bit */
|
||||
#define BCMA_DMP_OOBSEL_SHIFT(_sel) ((_sel % BCMA_OOB_NUM_SEL) * 8)
|
||||
#define BCMA_DMP_OOBSEL_BUSLINE_MASK 0x7F /**< OOB selector bus line mask */
|
||||
#define BCMA_DMP_OOBSEL_BUSLINE_SHIFT 0
|
||||
|
||||
#define BCMA_DMP_OOBSEL_0_MASK BCMA_DMP_OOBSEL_MASK
|
||||
#define BCMA_DMP_OOBSEL_1_MASK BCMA_DMP_OOBSEL_MASK
|
||||
#define BCMA_DMP_OOBSEL_2_MASK BCMA_DMP_OOBSEL_MASK
|
||||
#define BCMA_DMP_OOBSEL_3_MASK BCMA_DMP_OOBSEL_MASK
|
||||
|
||||
#define BCMA_DMP_OOBSEL_4_MASK BCMA_DMP_OOBSEL_MASK
|
||||
#define BCMA_DMP_OOBSEL_5_MASK BCMA_DMP_OOBSEL_MASK
|
||||
#define BCMA_DMP_OOBSEL_6_MASK BCMA_DMP_OOBSEL_MASK
|
||||
#define BCMA_DMP_OOBSEL_7_MASK BCMA_DMP_OOBSEL_MASK
|
||||
|
||||
#define BCMA_DMP_OOBSEL_0_SHIFT BCMA_DMP_OOBSEL_SHIFT(0)
|
||||
#define BCMA_DMP_OOBSEL_1_SHIFT BCMA_DMP_OOBSEL_SHIFT(1)
|
||||
#define BCMA_DMP_OOBSEL_2_SHIFT BCMA_DMP_OOBSEL_SHIFT(2)
|
||||
#define BCMA_DMP_OOBSEL_3_SHIFT BCMA_DMP_OOBSEL_SHIFT(3)
|
||||
|
||||
#define BCMA_DMP_OOBSEL_4_SHIFT BCMA_DMP_OOBSEL_0_SHIFT
|
||||
#define BCMA_DMP_OOBSEL_5_SHIFT BCMA_DMP_OOBSEL_1_SHIFT
|
||||
#define BCMA_DMP_OOBSEL_6_SHIFT BCMA_DMP_OOBSEL_2_SHIFT
|
||||
#define BCMA_DMP_OOBSEL_7_SHIFT BCMA_DMP_OOBSEL_3_SHIFT
|
||||
|
||||
/* resetctrl */
|
||||
#define BMCA_DMP_RC_RESET 1
|
||||
|
||||
|
@ -74,6 +74,9 @@ struct bcma_sport;
|
||||
int bcma_probe(device_t dev);
|
||||
int bcma_attach(device_t dev);
|
||||
int bcma_detach(device_t dev);
|
||||
int bcma_get_intr_count(device_t dev, device_t child);
|
||||
int bcma_get_core_ivec(device_t dev, device_t child,
|
||||
u_int intr, uint32_t *ivec);
|
||||
|
||||
int bcma_add_children(device_t bus);
|
||||
|
||||
|
@ -925,9 +925,14 @@ bhnd_generic_print_child(device_t dev, device_t child)
|
||||
retval += bus_print_child_header(dev, child);
|
||||
|
||||
rl = BUS_GET_RESOURCE_LIST(dev, child);
|
||||
|
||||
|
||||
if (rl != NULL) {
|
||||
retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
|
||||
"%#jx");
|
||||
|
||||
retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ,
|
||||
"%#jd");
|
||||
}
|
||||
|
||||
retval += printf(" at core %u", bhnd_get_core_index(child));
|
||||
@ -974,8 +979,10 @@ bhnd_generic_probe_nomatch(device_t dev, device_t child)
|
||||
bhnd_get_device_name(child));
|
||||
|
||||
rl = BUS_GET_RESOURCE_LIST(dev, child);
|
||||
if (rl != NULL)
|
||||
if (rl != NULL) {
|
||||
resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
|
||||
resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%#jd");
|
||||
}
|
||||
|
||||
printf(" at core %u (no driver attached)\n",
|
||||
bhnd_get_core_index(child));
|
||||
|
@ -549,6 +549,45 @@ bhnd_read_board_info(device_t dev, struct bhnd_board_info *info)
|
||||
return (BHND_BUS_READ_BOARD_INFO(device_get_parent(dev), dev, info));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of interrupts to be assigned to @p child via
|
||||
* BHND_BUS_ASSIGN_INTR().
|
||||
*
|
||||
* @param dev A bhnd bus child device.
|
||||
*/
|
||||
static inline int
|
||||
bhnd_get_intr_count(device_t dev)
|
||||
{
|
||||
return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), dev));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the backplane interrupt vector corresponding to @p dev's given
|
||||
* @p intr number.
|
||||
*
|
||||
* @param dev A bhnd bus child device.
|
||||
* @param intr The interrupt number being queried. This is equivalent to the
|
||||
* bus resource ID for the interrupt.
|
||||
* @param[out] ivec On success, the assigned hardware interrupt vector be
|
||||
* written to this pointer.
|
||||
*
|
||||
* On bcma(4) devices, this returns the OOB bus line assigned to the
|
||||
* interrupt.
|
||||
*
|
||||
* On siba(4) devices, this returns the target OCP slave flag number assigned
|
||||
* to the interrupt.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENXIO If @p intr exceeds the number of interrupts available
|
||||
* to @p child.
|
||||
*/
|
||||
static inline int
|
||||
bhnd_get_core_ivec(device_t dev, u_int intr, uint32_t *ivec)
|
||||
{
|
||||
return (BHND_BUS_GET_CORE_IVEC(device_get_parent(dev), dev, intr,
|
||||
ivec));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and enable per-core PMU request handling for @p child.
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
#-
|
||||
# Copyright (c) 2015 Landon Fuller <landon@landonf.org>
|
||||
# Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@ -96,7 +96,26 @@ CODE {
|
||||
{
|
||||
panic("bhnd_bus_read_boardinfo unimplemented");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
bhnd_bus_null_get_intr_count(device_t dev, device_t child)
|
||||
{
|
||||
panic("bhnd_bus_get_intr_count unimplemented");
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_bus_null_assign_intr(device_t dev, device_t child, int rid)
|
||||
{
|
||||
panic("bhnd_bus_assign_intr unimplemented");
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_bus_null_get_core_ivec(device_t dev, device_t child, u_int intr,
|
||||
uint32_t *ivec)
|
||||
{
|
||||
panic("bhnd_bus_get_core_ivec unimplemented");
|
||||
}
|
||||
|
||||
static void
|
||||
bhnd_bus_null_child_added(device_t dev, device_t child)
|
||||
{
|
||||
@ -349,6 +368,78 @@ METHOD void free_devinfo {
|
||||
struct bhnd_devinfo *dinfo;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of interrupts to be assigned to @p child via
|
||||
* BHND_BUS_ASSIGN_INTR().
|
||||
*
|
||||
* @param dev The bhnd bus parent of @p child.
|
||||
* @param child The bhnd device for which a count should be returned.
|
||||
*
|
||||
* @retval 0 If no interrupts should be assigned.
|
||||
* @retval non-zero The count of interrupt resource IDs to be
|
||||
* assigned, starting at rid 0.
|
||||
*/
|
||||
METHOD int get_intr_count {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
} DEFAULT bhnd_bus_null_get_intr_count;
|
||||
|
||||
/**
|
||||
* Assign an interrupt to @p child via bus_set_resource().
|
||||
*
|
||||
* The default bus implementation of this method should assign backplane
|
||||
* interrupt values to @p child.
|
||||
*
|
||||
* Bridge-attached bus implementations may instead override standard
|
||||
* interconnect IRQ assignment, providing IRQs inherited from the parent bus.
|
||||
*
|
||||
* TODO: Once we can depend on INTRNG, investigate replacing this with a
|
||||
* bridge-level interrupt controller.
|
||||
*
|
||||
* @param dev The bhnd bus parent of @p child.
|
||||
* @param child The bhnd device to which an interrupt should be assigned.
|
||||
* @param rid The interrupt resource ID to be assigned.
|
||||
*
|
||||
* @retval 0 If an interrupt was assigned.
|
||||
* @retval non-zero If assigning an interrupt otherwise fails, a regular
|
||||
* unix error code will be returned.
|
||||
*/
|
||||
METHOD int assign_intr {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
int rid;
|
||||
} DEFAULT bhnd_bus_null_assign_intr;
|
||||
|
||||
/**
|
||||
* Return the backplane interrupt vector corresponding to @p child's given
|
||||
* @p intr number.
|
||||
*
|
||||
* @param dev The bhnd bus parent of @p child.
|
||||
* @param child The bhnd device for which the assigned interrupt vector should
|
||||
* be queried.
|
||||
* @param intr The interrupt number being queried. This is equivalent to the
|
||||
* bus resource ID for the interrupt.
|
||||
* @param[out] ivec On success, the assigned hardware interrupt vector be
|
||||
* written to this pointer.
|
||||
*
|
||||
* On bcma(4) devices, this returns the OOB bus line assigned to the
|
||||
* interrupt.
|
||||
*
|
||||
* On siba(4) devices, this returns the target OCP slave flag number assigned
|
||||
* to the interrupt.
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENXIO If @p intr exceeds the number of interrupts available
|
||||
* to @p child.
|
||||
*/
|
||||
METHOD int get_core_ivec {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
u_int intr;
|
||||
uint32_t *ivec;
|
||||
} DEFAULT bhnd_bus_null_get_core_ivec;
|
||||
|
||||
/**
|
||||
* Notify a bhnd bus that a child was added.
|
||||
*
|
||||
|
@ -122,6 +122,13 @@ bhnd_nexus_deactivate_resource(device_t dev, device_t child,
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_nexus_get_intr_count(device_t dev, device_t child)
|
||||
{
|
||||
// TODO: arch-specific interrupt handling.
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t bhnd_nexus_methods[] = {
|
||||
/* bhnd interface */
|
||||
DEVMETHOD(bhnd_bus_activate_resource, bhnd_nexus_activate_resource),
|
||||
@ -129,6 +136,8 @@ static device_method_t bhnd_nexus_methods[] = {
|
||||
DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_nexus_is_hw_disabled),
|
||||
DEVMETHOD(bhnd_bus_get_attach_type, bhnd_nexus_get_attach_type),
|
||||
|
||||
DEVMETHOD(bhnd_bus_get_intr_count, bhnd_nexus_get_intr_count),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
|
@ -93,6 +93,13 @@ bhnd_bhndb_find_hostb_device(device_t dev)
|
||||
return (bhnd_match_child(dev, &md));
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_bhndb_assign_intr(device_t dev, device_t child, int rid)
|
||||
{
|
||||
/* Delegate to parent bridge */
|
||||
return (BHND_BUS_ASSIGN_INTR(device_get_parent(dev), child, rid));
|
||||
}
|
||||
|
||||
static bhnd_clksrc
|
||||
bhnd_bhndb_pwrctl_get_clksrc(device_t dev, device_t child,
|
||||
bhnd_clock clock)
|
||||
@ -126,6 +133,7 @@ static device_method_t bhnd_bhndb_methods[] = {
|
||||
DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bhndb_is_hw_disabled),
|
||||
DEVMETHOD(bhnd_bus_find_hostb_device, bhnd_bhndb_find_hostb_device),
|
||||
DEVMETHOD(bhnd_bus_read_board_info, bhnd_bhndb_read_board_info),
|
||||
DEVMETHOD(bhnd_bus_assign_intr, bhnd_bhndb_assign_intr),
|
||||
|
||||
DEVMETHOD(bhnd_bus_pwrctl_get_clksrc, bhnd_bhndb_pwrctl_get_clksrc),
|
||||
DEVMETHOD(bhnd_bus_pwrctl_gate_clock, bhnd_bhndb_pwrctl_gate_clock),
|
||||
|
@ -993,7 +993,7 @@ bhndb_suspend_resource(device_t dev, device_t child, int type,
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
// TODO: IRQs?
|
||||
/* Non-MMIO resources (e.g. IRQs) are handled solely by our parent */
|
||||
if (type != SYS_RES_MEMORY)
|
||||
return;
|
||||
|
||||
@ -1024,7 +1024,7 @@ bhndb_resume_resource(device_t dev, device_t child, int type,
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
// TODO: IRQs?
|
||||
/* Non-MMIO resources (e.g. IRQs) are handled solely by our parent */
|
||||
if (type != SYS_RES_MEMORY)
|
||||
return (0);
|
||||
|
||||
@ -1040,7 +1040,6 @@ bhndb_resume_resource(device_t dev, device_t child, int type,
|
||||
rman_get_rid(r), r, NULL));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default bhndb(4) implementation of BUS_READ_IVAR().
|
||||
*/
|
||||
@ -1109,8 +1108,6 @@ bhndb_get_rman(struct bhndb_softc *sc, device_t child, int type)
|
||||
case SYS_RES_MEMORY:
|
||||
return (&sc->bus_res->br_mem_rman);
|
||||
case SYS_RES_IRQ:
|
||||
// TODO
|
||||
// return &sc->irq_rman;
|
||||
return (NULL);
|
||||
default:
|
||||
return (NULL);
|
||||
@ -1233,6 +1230,15 @@ bhndb_alloc_resource(device_t dev, device_t child, int type,
|
||||
isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
|
||||
rle = NULL;
|
||||
|
||||
/* Fetch the resource manager */
|
||||
rm = bhndb_get_rman(sc, child, type);
|
||||
if (rm == NULL) {
|
||||
/* Delegate to our parent device's bus; the requested
|
||||
* resource type isn't handled locally. */
|
||||
return (BUS_ALLOC_RESOURCE(device_get_parent(sc->parent_dev),
|
||||
child, type, rid, start, end, count, flags));
|
||||
}
|
||||
|
||||
/* Populate defaults */
|
||||
if (!passthrough && isdefault) {
|
||||
/* Fetch the resource list entry. */
|
||||
@ -1263,11 +1269,6 @@ bhndb_alloc_resource(device_t dev, device_t child, int type,
|
||||
/* Validate resource addresses */
|
||||
if (start > end || count > ((end - start) + 1))
|
||||
return (NULL);
|
||||
|
||||
/* Fetch the resource manager */
|
||||
rm = bhndb_get_rman(sc, child, type);
|
||||
if (rm == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* Make our reservation */
|
||||
rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
|
||||
@ -1310,12 +1311,21 @@ static int
|
||||
bhndb_release_resource(device_t dev, device_t child, int type, int rid,
|
||||
struct resource *r)
|
||||
{
|
||||
struct bhndb_softc *sc;
|
||||
struct resource_list_entry *rle;
|
||||
bool passthrough;
|
||||
int error;
|
||||
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
passthrough = (device_get_parent(child) != dev);
|
||||
|
||||
/* Delegate to our parent device's bus if the requested resource type
|
||||
* isn't handled locally. */
|
||||
if (bhndb_get_rman(sc, child, type) == NULL) {
|
||||
return (BUS_RELEASE_RESOURCE(device_get_parent(sc->parent_dev),
|
||||
child, type, rid, r));
|
||||
}
|
||||
|
||||
/* Deactivate resources */
|
||||
if (rman_get_flags(r) & RF_ACTIVE) {
|
||||
error = BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r);
|
||||
@ -1352,15 +1362,18 @@ bhndb_adjust_resource(device_t dev, device_t child, int type,
|
||||
sc = device_get_softc(dev);
|
||||
error = 0;
|
||||
|
||||
/* Delegate to our parent device's bus if the requested resource type
|
||||
* isn't handled locally. */
|
||||
rm = bhndb_get_rman(sc, child, type);
|
||||
if (rm == NULL) {
|
||||
return (BUS_ADJUST_RESOURCE(device_get_parent(sc->parent_dev),
|
||||
child, type, r, start, end));
|
||||
}
|
||||
|
||||
/* Verify basic constraints */
|
||||
if (end <= start)
|
||||
return (EINVAL);
|
||||
|
||||
/* Fetch resource manager */
|
||||
rm = bhndb_get_rman(sc, child, type);
|
||||
if (rm == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
if (!rman_is_region_manager(r, rm))
|
||||
return (ENXIO);
|
||||
|
||||
@ -1567,7 +1580,7 @@ bhndb_try_activate_resource(struct bhndb_softc *sc, device_t child, int type,
|
||||
|
||||
BHNDB_LOCK_ASSERT(sc, MA_NOTOWNED);
|
||||
|
||||
// TODO - IRQs
|
||||
/* Only MMIO resources can be mapped via register windows */
|
||||
if (type != SYS_RES_MEMORY)
|
||||
return (ENXIO);
|
||||
|
||||
@ -1678,6 +1691,13 @@ bhndb_activate_resource(device_t dev, device_t child, int type, int rid,
|
||||
{
|
||||
struct bhndb_softc *sc = device_get_softc(dev);
|
||||
|
||||
/* Delegate directly to our parent device's bus if the requested
|
||||
* resource type isn't handled locally. */
|
||||
if (bhndb_get_rman(sc, child, type) == NULL) {
|
||||
return (BUS_ACTIVATE_RESOURCE(device_get_parent(sc->parent_dev),
|
||||
child, type, rid, r));
|
||||
}
|
||||
|
||||
return (bhndb_try_activate_resource(sc, child, type, rid, r, NULL));
|
||||
}
|
||||
|
||||
@ -1695,8 +1715,13 @@ bhndb_deactivate_resource(device_t dev, device_t child, int type,
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if ((rm = bhndb_get_rman(sc, child, type)) == NULL)
|
||||
return (EINVAL);
|
||||
/* Delegate directly to our parent device's bus if the requested
|
||||
* resource type isn't handled locally. */
|
||||
rm = bhndb_get_rman(sc, child, type);
|
||||
if (rm == NULL) {
|
||||
return (BUS_DEACTIVATE_RESOURCE(
|
||||
device_get_parent(sc->parent_dev), child, type, rid, r));
|
||||
}
|
||||
|
||||
/* Mark inactive */
|
||||
if ((error = rman_deactivate_resource(r)))
|
||||
@ -1752,6 +1777,15 @@ bhndb_activate_bhnd_resource(device_t dev, device_t child,
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
/* Delegate directly to BUS_ACTIVATE_RESOURCE() if the requested
|
||||
* resource type isn't handled locally. */
|
||||
if (bhndb_get_rman(sc, child, type) == NULL) {
|
||||
error = BUS_ACTIVATE_RESOURCE(dev, child, type, rid, r->res);
|
||||
if (error == 0)
|
||||
r->direct = true;
|
||||
return (error);
|
||||
}
|
||||
|
||||
r_start = rman_get_start(r->res);
|
||||
r_size = rman_get_size(r->res);
|
||||
|
||||
@ -1815,7 +1849,7 @@ bhndb_deactivate_bhnd_resource(device_t dev, device_t child,
|
||||
("RF_ACTIVE not set on direct resource"));
|
||||
|
||||
/* Perform deactivation */
|
||||
error = bus_deactivate_resource(child, type, rid, r->res);
|
||||
error = BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r->res);
|
||||
if (!error)
|
||||
r->direct = false;
|
||||
|
||||
@ -2052,61 +2086,6 @@ bhndb_bus_barrier(device_t dev, device_t child, struct bhnd_resource *r,
|
||||
BHNDB_IO_COMMON_TEARDOWN();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhndb(4) implementation of BUS_SETUP_INTR().
|
||||
*/
|
||||
static int
|
||||
bhndb_setup_intr(device_t dev, device_t child, struct resource *r,
|
||||
int flags, driver_filter_t filter, driver_intr_t handler, void *arg,
|
||||
void **cookiep)
|
||||
{
|
||||
// TODO
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhndb(4) implementation of BUS_TEARDOWN_INTR().
|
||||
*/
|
||||
static int
|
||||
bhndb_teardown_intr(device_t dev, device_t child, struct resource *r,
|
||||
void *cookie)
|
||||
{
|
||||
// TODO
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhndb(4) implementation of BUS_CONFIG_INTR().
|
||||
*/
|
||||
static int
|
||||
bhndb_config_intr(device_t dev, int irq, enum intr_trigger trig,
|
||||
enum intr_polarity pol)
|
||||
{
|
||||
// TODO
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhndb(4) implementation of BUS_BIND_INTR().
|
||||
*/
|
||||
static int
|
||||
bhndb_bind_intr(device_t dev, device_t child, struct resource *r, int cpu)
|
||||
{
|
||||
// TODO
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhndb(4) implementation of BUS_DESCRIBE_INTR().
|
||||
*/
|
||||
static int
|
||||
bhndb_describe_intr(device_t dev, device_t child, struct resource *irq, void *cookie,
|
||||
const char *descr)
|
||||
{
|
||||
// TODO
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default bhndb(4) implementation of BUS_GET_DMA_TAG().
|
||||
*/
|
||||
@ -2138,11 +2117,11 @@ static device_method_t bhndb_methods[] = {
|
||||
DEVMETHOD(bus_activate_resource, bhndb_activate_resource),
|
||||
DEVMETHOD(bus_deactivate_resource, bhndb_deactivate_resource),
|
||||
|
||||
DEVMETHOD(bus_setup_intr, bhndb_setup_intr),
|
||||
DEVMETHOD(bus_teardown_intr, bhndb_teardown_intr),
|
||||
DEVMETHOD(bus_config_intr, bhndb_config_intr),
|
||||
DEVMETHOD(bus_bind_intr, bhndb_bind_intr),
|
||||
DEVMETHOD(bus_describe_intr, bhndb_describe_intr),
|
||||
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
|
||||
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
|
||||
DEVMETHOD(bus_config_intr, bus_generic_config_intr),
|
||||
DEVMETHOD(bus_bind_intr, bus_generic_bind_intr),
|
||||
DEVMETHOD(bus_describe_intr, bus_generic_describe_intr),
|
||||
|
||||
DEVMETHOD(bus_get_dma_tag, bhndb_get_dma_tag),
|
||||
|
||||
|
@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include "bhndb_pcivar.h"
|
||||
#include "bhndb_private.h"
|
||||
|
||||
static int bhndb_pci_init_msi(struct bhndb_pci_softc *sc);
|
||||
static int bhndb_pci_add_children(struct bhndb_pci_softc *sc);
|
||||
|
||||
static int bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc);
|
||||
@ -78,6 +79,8 @@ static void bhndb_init_sromless_pci_config(
|
||||
static bus_addr_t bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc);
|
||||
static bus_size_t bhndb_pci_sprom_size(struct bhndb_pci_softc *sc);
|
||||
|
||||
#define BHNDB_PCI_MSI_COUNT 1
|
||||
|
||||
/**
|
||||
* Default bhndb_pci implementation of device_probe().
|
||||
*
|
||||
@ -103,6 +106,33 @@ bhndb_pci_probe(device_t dev)
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
/* Configure MSI interrupts */
|
||||
static int
|
||||
bhndb_pci_init_msi(struct bhndb_pci_softc *sc)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* Is MSI available? */
|
||||
if (pci_msi_count(sc->parent) < BHNDB_PCI_MSI_COUNT)
|
||||
return (ENXIO);
|
||||
|
||||
/* Allocate expected message count */
|
||||
sc->intr.msi_count = BHNDB_PCI_MSI_COUNT;
|
||||
if ((error = pci_alloc_msi(sc->parent, &sc->intr.msi_count))) {
|
||||
device_printf(sc->dev, "failed to allocate MSI interrupts: "
|
||||
"%d\n", error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (sc->intr.msi_count < BHNDB_PCI_MSI_COUNT)
|
||||
return (ENXIO);
|
||||
|
||||
/* MSI uses resource IDs starting at 1 */
|
||||
sc->intr.intr_rid = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhndb_pci_attach(device_t dev)
|
||||
{
|
||||
@ -114,6 +144,21 @@ bhndb_pci_attach(device_t dev)
|
||||
sc->parent = device_get_parent(dev);
|
||||
sc->set_regwin = bhndb_pci_compat_setregwin;
|
||||
|
||||
/* Enable PCI bus mastering */
|
||||
pci_enable_busmaster(sc->parent);
|
||||
|
||||
/* Set up interrupt handling */
|
||||
if (bhndb_pci_init_msi(sc) == 0) {
|
||||
device_printf(dev, "Using MSI interrupts on %s\n",
|
||||
device_get_nameunit(sc->parent));
|
||||
} else {
|
||||
device_printf(dev, "Using INTx interrupts on %s\n",
|
||||
device_get_nameunit(sc->parent));
|
||||
sc->intr.intr_rid = 0;
|
||||
}
|
||||
|
||||
/* Determine our bridge device class */
|
||||
sc->pci_devclass = BHND_DEVCLASS_PCI;
|
||||
if (pci_find_cap(sc->parent, PCIY_EXPRESS, ®) == 0)
|
||||
sc->pci_devclass = BHND_DEVCLASS_PCIE;
|
||||
else
|
||||
@ -153,6 +198,9 @@ bhndb_pci_attach(device_t dev)
|
||||
cleanup:
|
||||
device_delete_children(dev);
|
||||
bhndb_disable_pci_clocks(sc);
|
||||
if (sc->intr.msi_count > 0)
|
||||
pci_release_msi(dev);
|
||||
|
||||
pci_disable_busmaster(sc->parent);
|
||||
|
||||
return (error);
|
||||
@ -178,6 +226,10 @@ bhndb_pci_detach(device_t dev)
|
||||
if ((error = bhndb_disable_pci_clocks(sc)))
|
||||
return (error);
|
||||
|
||||
/* Release MSI interrupts */
|
||||
if (sc->intr.msi_count > 0)
|
||||
pci_release_msi(dev);
|
||||
|
||||
/* Disable PCI bus mastering */
|
||||
pci_disable_busmaster(sc->parent);
|
||||
|
||||
@ -679,6 +731,29 @@ bhndb_pci_pwrctl_ungate_clock(device_t dev, device_t child,
|
||||
return (bhndb_enable_pci_clocks(sc));
|
||||
}
|
||||
|
||||
static int
|
||||
bhndb_pci_assign_intr(device_t dev, device_t child, int rid)
|
||||
{
|
||||
struct bhndb_pci_softc *sc;
|
||||
rman_res_t start, count;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
/* Is the rid valid? */
|
||||
if (rid >= bhnd_get_intr_count(child))
|
||||
return (EINVAL);
|
||||
|
||||
/* Fetch our common PCI interrupt's start/count. */
|
||||
error = bus_get_resource(sc->parent, SYS_RES_IRQ, sc->intr.intr_rid,
|
||||
&start, &count);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Add to child's resource list */
|
||||
return (bus_set_resource(child, SYS_RES_IRQ, rid, start, count));
|
||||
}
|
||||
|
||||
static device_method_t bhndb_pci_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, bhndb_pci_probe),
|
||||
@ -688,6 +763,8 @@ static device_method_t bhndb_pci_methods[] = {
|
||||
DEVMETHOD(device_detach, bhndb_pci_detach),
|
||||
|
||||
/* BHND interface */
|
||||
DEVMETHOD(bhnd_bus_assign_intr, bhndb_pci_assign_intr),
|
||||
|
||||
DEVMETHOD(bhnd_bus_pwrctl_get_clksrc, bhndb_pci_pwrctl_get_clksrc),
|
||||
DEVMETHOD(bhnd_bus_pwrctl_gate_clock, bhndb_pci_pwrctl_gate_clock),
|
||||
DEVMETHOD(bhnd_bus_pwrctl_ungate_clock, bhndb_pci_pwrctl_ungate_clock),
|
||||
|
@ -48,11 +48,19 @@ struct bhndb_pci_softc;
|
||||
typedef int (*bhndb_pci_set_regwin_t)(struct bhndb_pci_softc *sc,
|
||||
const struct bhndb_regwin *rw, bhnd_addr_t addr);
|
||||
|
||||
/* bhndb_pci interrupt state */
|
||||
struct bhndb_pci_intr {
|
||||
int msi_count; /**< MSI count, or 0 */
|
||||
int intr_rid; /**< interrupt resource ID.*/
|
||||
};
|
||||
|
||||
struct bhndb_pci_softc {
|
||||
struct bhndb_softc bhndb; /**< parent softc */
|
||||
device_t dev; /**< bridge device */
|
||||
device_t parent; /**< parent PCI device */
|
||||
bhnd_devclass_t pci_devclass; /**< PCI core's devclass */
|
||||
struct bhndb_pci_intr intr; /**< PCI interrupt config */
|
||||
|
||||
bhndb_pci_set_regwin_t set_regwin; /**< regwin handler */
|
||||
};
|
||||
|
||||
|
@ -3395,14 +3395,14 @@ bhnd_pmu_radio_enable(struct bhnd_pmu_softc *sc, device_t d11core, bool enable)
|
||||
|
||||
if (enable) {
|
||||
oobsel |= BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
|
||||
BCMA_DMP_OOBSEL_1);
|
||||
BCMA_DMP_OOBSEL_5);
|
||||
oobsel |= BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
|
||||
BCMA_DMP_OOBSEL_2);
|
||||
BCMA_DMP_OOBSEL_6);
|
||||
} else {
|
||||
oobsel &= ~BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
|
||||
BCMA_DMP_OOBSEL_1);
|
||||
BCMA_DMP_OOBSEL_5);
|
||||
oobsel &= ~BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
|
||||
BCMA_DMP_OOBSEL_2);
|
||||
BCMA_DMP_OOBSEL_6);
|
||||
}
|
||||
|
||||
bhnd_write_config(d11core, BCMA_DMP_OOBSELOUTB74, oobsel, 4);
|
||||
|
@ -373,6 +373,60 @@ siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default siba(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
|
||||
*
|
||||
* This implementation consults @p child's configuration block mapping,
|
||||
* returning SIBA_CORE_NUM_INTR if a valid CFG0 block is mapped.
|
||||
*/
|
||||
int
|
||||
siba_get_intr_count(device_t dev, device_t child)
|
||||
{
|
||||
struct siba_devinfo *dinfo;
|
||||
|
||||
/* delegate non-bus-attached devices to our parent */
|
||||
if (device_get_parent(child) != dev)
|
||||
return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
|
||||
|
||||
dinfo = device_get_ivars(child);
|
||||
|
||||
/* We can get/set interrupt sbflags on any core with a valid cfg0
|
||||
* block; whether the core actually makes use of it is another matter
|
||||
* entirely */
|
||||
if (dinfo->cfg[0] == NULL)
|
||||
return (0);
|
||||
|
||||
return (SIBA_CORE_NUM_INTR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default siba(4) bus driver implementation of BHND_BUS_GET_CORE_IVEC().
|
||||
*
|
||||
* This implementation consults @p child's CFG0 register block,
|
||||
* returning the interrupt flag assigned to @p child.
|
||||
*/
|
||||
int
|
||||
siba_get_core_ivec(device_t dev, device_t child, u_int intr, uint32_t *ivec)
|
||||
{
|
||||
struct siba_devinfo *dinfo;
|
||||
uint32_t tpsflag;
|
||||
|
||||
/* delegate non-bus-attached devices to our parent */
|
||||
if (device_get_parent(child) != dev)
|
||||
return (BHND_BUS_GET_CORE_IVEC(device_get_parent(dev), child,
|
||||
intr, ivec));
|
||||
|
||||
/* Must be a valid interrupt ID */
|
||||
if (intr >= siba_get_intr_count(dev, child))
|
||||
return (ENXIO);
|
||||
|
||||
/* Fetch sbflag number */
|
||||
dinfo = device_get_ivars(child);
|
||||
tpsflag = bhnd_bus_read_4(dinfo->cfg[0], SIBA_CFG0_TPSFLAG);
|
||||
*ivec = SIBA_REG_GET(tpsflag, TPS_NUM0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all address space mappings for @p di.
|
||||
@ -538,6 +592,7 @@ siba_add_children(device_t dev)
|
||||
device_t child;
|
||||
uint32_t idhigh, idlow;
|
||||
rman_res_t r_count, r_end, r_start;
|
||||
int nintr;
|
||||
|
||||
/* Map the core's register block */
|
||||
rid = 0;
|
||||
@ -594,6 +649,16 @@ siba_add_children(device_t dev)
|
||||
if ((error = siba_map_cfg_resources(dev, dinfo)))
|
||||
goto cleanup;
|
||||
|
||||
/* Assign interrupts */
|
||||
nintr = bhnd_get_intr_count(child);
|
||||
for (int rid = 0; rid < nintr; rid++) {
|
||||
error = BHND_BUS_ASSIGN_INTR(dev, child, rid);
|
||||
if (error) {
|
||||
device_printf(dev, "failed to assign interrupt "
|
||||
"%d to core %u: %d\n", rid, i, error);
|
||||
}
|
||||
}
|
||||
|
||||
/* If pins are floating or the hardware is otherwise
|
||||
* unpopulated, the device shouldn't be used. */
|
||||
if (bhnd_is_hw_disabled(child))
|
||||
@ -639,6 +704,8 @@ static device_method_t siba_methods[] = {
|
||||
DEVMETHOD(bhnd_bus_get_port_rid, siba_get_port_rid),
|
||||
DEVMETHOD(bhnd_bus_decode_port_rid, siba_decode_port_rid),
|
||||
DEVMETHOD(bhnd_bus_get_region_addr, siba_get_region_addr),
|
||||
DEVMETHOD(bhnd_bus_get_intr_count, siba_get_intr_count),
|
||||
DEVMETHOD(bhnd_bus_get_core_ivec, siba_get_core_ivec),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
@ -273,7 +273,6 @@ siba_bhndb_wars_hwup(struct siba_softc *sc)
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static device_method_t siba_bhndb_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, siba_bhndb_probe),
|
||||
|
@ -48,6 +48,7 @@
|
||||
#define SIBA_ENUM_ADDR BHND_DEFAULT_CHIPC_ADDR /**< enumeration space */
|
||||
#define SIBA_ENUM_SIZE 0x00100000 /**< size of the enumeration space */
|
||||
#define SIBA_CORE_SIZE BHND_DEFAULT_CORE_SIZE /**< per-core register block size */
|
||||
#define SIBA_CORE_NUM_INTR 1 /**< number of per-core interrupt lines */
|
||||
#define SIBA_MAX_CORES \
|
||||
(SIBA_ENUM_SIZE/SIBA_CORE_SIZE) /**< Maximum number of cores */
|
||||
|
||||
@ -119,6 +120,7 @@
|
||||
|
||||
/* sbtpsflag */
|
||||
#define SIBA_TPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */
|
||||
#define SIBA_TPS_NUM0_SHIFT 0
|
||||
#define SIBA_TPS_F0EN0 0x40 /* interrupt is always sent on the backplane */
|
||||
|
||||
/* sbtmerrlog */
|
||||
|
@ -54,6 +54,9 @@ int siba_attach(device_t dev);
|
||||
int siba_detach(device_t dev);
|
||||
int siba_resume(device_t dev);
|
||||
int siba_suspend(device_t dev);
|
||||
int siba_get_intr_count(device_t dev, device_t child);
|
||||
int siba_get_core_ivec(device_t dev, device_t child,
|
||||
u_int intr, uint32_t *ivec);
|
||||
|
||||
uint16_t siba_get_bhnd_mfgid(uint16_t ocp_vendor);
|
||||
|
||||
|
@ -47,16 +47,12 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "bhnd_nvram_map.h"
|
||||
|
||||
static const struct resource_spec bwn_rspec[] = {
|
||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||
{ -1, -1, 0 }
|
||||
};
|
||||
|
||||
#define RSPEC_LEN (sizeof(bwn_rspec)/sizeof(bwn_rspec[0]))
|
||||
|
||||
struct bwn_softc {
|
||||
struct resource_spec rspec[RSPEC_LEN];
|
||||
struct bhnd_resource *res[RSPEC_LEN-1];
|
||||
int mem_rid;
|
||||
struct bhnd_resource *mem_res;
|
||||
|
||||
int intr_rid;
|
||||
struct resource *intr_res;
|
||||
};
|
||||
|
||||
static const struct bwn_device {
|
||||
@ -89,28 +85,50 @@ static int
|
||||
bwn_attach(device_t dev)
|
||||
{
|
||||
struct bwn_softc *sc;
|
||||
struct bhnd_resource *r;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
memcpy(sc->rspec, bwn_rspec, sizeof(bwn_rspec));
|
||||
if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res)))
|
||||
return (error);
|
||||
/* Allocate device resources */
|
||||
sc->mem_rid = 0;
|
||||
sc->mem_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY,
|
||||
&sc->mem_rid, RF_ACTIVE);
|
||||
if (sc->mem_res == NULL) {
|
||||
device_printf(dev, "failed to allocate device registers\n");
|
||||
error = ENXIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// XXX TODO
|
||||
r = sc->res[0];
|
||||
device_printf(dev, "got rid=%d res=%p\n", sc->rspec[0].rid, r);
|
||||
sc->intr_rid = 0;
|
||||
sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->intr_rid,
|
||||
RF_ACTIVE|RF_SHAREABLE);
|
||||
if (sc->intr_res == NULL) {
|
||||
device_printf(dev, "failed to allocate device interrupt\n");
|
||||
error = ENXIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// TODO
|
||||
uint8_t macaddr[6];
|
||||
error = bhnd_nvram_getvar_array(dev, BHND_NVAR_MACADDR, macaddr,
|
||||
sizeof(macaddr), BHND_NVRAM_TYPE_UINT8);
|
||||
if (error)
|
||||
return (error);
|
||||
device_printf(dev, "error fetching macaddr: %d\n", error);
|
||||
else
|
||||
device_printf(dev, "got macaddr %6D\n", macaddr, ":");
|
||||
|
||||
device_printf(dev, "got macaddr %6D\n", macaddr, ":");
|
||||
|
||||
return (0);
|
||||
|
||||
cleanup:
|
||||
if (sc->mem_res != NULL)
|
||||
bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
|
||||
sc->mem_res);
|
||||
|
||||
if (sc->intr_res != NULL)
|
||||
bus_release_resource(dev, SYS_RES_IRQ, sc->intr_rid,
|
||||
sc->intr_res);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -119,7 +137,9 @@ bwn_detach(device_t dev)
|
||||
struct bwn_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
bhnd_release_resources(dev, sc->rspec, sc->res);
|
||||
|
||||
bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res);
|
||||
bus_release_resource(dev, SYS_RES_IRQ, sc->intr_rid, sc->intr_res);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user