Date: Mon, 5 Sep 2016 22:11:46 +0000 (UTC) From: "Landon J. Fuller" <landonf@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r305444 - in head/sys/dev: bhnd bhnd/bcma bhnd/bhndb bhnd/cores/pmu bhnd/siba bwn Message-ID: <201609052211.u85MBk4r003838@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: landonf Date: Mon Sep 5 22:11:46 2016 New Revision: 305444 URL: https://svnweb.freebsd.org/changeset/base/305444 Log: 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) Modified: head/sys/dev/bhnd/bcma/bcma.c head/sys/dev/bhnd/bcma/bcma_dmp.h head/sys/dev/bhnd/bcma/bcmavar.h head/sys/dev/bhnd/bhnd.c head/sys/dev/bhnd/bhnd.h head/sys/dev/bhnd/bhnd_bus_if.m head/sys/dev/bhnd/bhnd_nexus.c head/sys/dev/bhnd/bhndb/bhnd_bhndb.c head/sys/dev/bhnd/bhndb/bhndb.c head/sys/dev/bhnd/bhndb/bhndb_pci.c head/sys/dev/bhnd/bhndb/bhndb_pcivar.h head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c head/sys/dev/bhnd/siba/siba.c head/sys/dev/bhnd/siba/siba_bhndb.c head/sys/dev/bhnd/siba/sibareg.h head/sys/dev/bhnd/siba/sibavar.h head/sys/dev/bwn/bwn_mac.c Modified: head/sys/dev/bhnd/bcma/bcma.c ============================================================================== --- head/sys/dev/bhnd/bcma/bcma.c Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bcma/bcma.c Mon Sep 5 22:11:46 2016 (r305444) @@ -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, devic 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 }; Modified: head/sys/dev/bhnd/bcma/bcma_dmp.h ============================================================================== --- head/sys/dev/bhnd/bcma/bcma_dmp.h Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bcma/bcma_dmp.h Mon Sep 5 22:11:46 2016 (r305444) @@ -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 Modified: head/sys/dev/bhnd/bcma/bcmavar.h ============================================================================== --- head/sys/dev/bhnd/bcma/bcmavar.h Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bcma/bcmavar.h Mon Sep 5 22:11:46 2016 (r305444) @@ -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); Modified: head/sys/dev/bhnd/bhnd.c ============================================================================== --- head/sys/dev/bhnd/bhnd.c Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bhnd.c Mon Sep 5 22:11:46 2016 (r305444) @@ -925,9 +925,14 @@ bhnd_generic_print_child(device_t dev, d 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, 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)); Modified: head/sys/dev/bhnd/bhnd.h ============================================================================== --- head/sys/dev/bhnd/bhnd.h Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bhnd.h Mon Sep 5 22:11:46 2016 (r305444) @@ -550,6 +550,45 @@ bhnd_read_board_info(device_t dev, struc } /** + * 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. * * The region containing the core's PMU register block (if any) must be Modified: head/sys/dev/bhnd/bhnd_bus_if.m ============================================================================== --- head/sys/dev/bhnd/bhnd_bus_if.m Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bhnd_bus_if.m Mon Sep 5 22:11:46 2016 (r305444) @@ -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. * Modified: head/sys/dev/bhnd/bhnd_nexus.c ============================================================================== --- head/sys/dev/bhnd/bhnd_nexus.c Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bhnd_nexus.c Mon Sep 5 22:11:46 2016 (r305444) @@ -122,6 +122,13 @@ bhnd_nexus_deactivate_resource(device_t 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_method 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 }; Modified: head/sys/dev/bhnd/bhndb/bhnd_bhndb.c ============================================================================== --- head/sys/dev/bhnd/bhndb/bhnd_bhndb.c Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bhndb/bhnd_bhndb.c Mon Sep 5 22:11:46 2016 (r305444) @@ -93,6 +93,13 @@ bhnd_bhndb_find_hostb_device(device_t de 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_method 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), Modified: head/sys/dev/bhnd/bhndb/bhndb.c ============================================================================== --- head/sys/dev/bhnd/bhndb/bhndb.c Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bhndb/bhndb.c Mon Sep 5 22:11:46 2016 (r305444) @@ -993,7 +993,7 @@ bhndb_suspend_resource(device_t dev, dev 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, devi 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, devi 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, d 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, devic 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, devic /* 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, devi 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 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, de { 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, 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 de 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 ("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; @@ -2053,61 +2087,6 @@ bhndb_bus_barrier(device_t dev, device_t } /** - * 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(). */ static bus_dma_tag_t @@ -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), Modified: head/sys/dev/bhnd/bhndb/bhndb_pci.c ============================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pci.c Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bhndb/bhndb_pci.c Mon Sep 5 22:11:46 2016 (r305444) @@ -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_con 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 d 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), Modified: head/sys/dev/bhnd/bhndb/bhndb_pcivar.h ============================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pcivar.h Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/bhndb/bhndb_pcivar.h Mon Sep 5 22:11:46 2016 (r305444) @@ -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 */ }; Modified: head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c ============================================================================== --- head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c Mon Sep 5 22:11:46 2016 (r305444) @@ -3395,14 +3395,14 @@ bhnd_pmu_radio_enable(struct bhnd_pmu_so 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); Modified: head/sys/dev/bhnd/siba/siba.c ============================================================================== --- head/sys/dev/bhnd/siba/siba.c Mon Sep 5 21:55:27 2016 (r305443) +++ head/sys/dev/bhnd/siba/siba.c Mon Sep 5 22:11:46 2016 (r305444) @@ -373,6 +373,60 @@ siba_get_region_addr(device_t dev, devic 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)); + *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201609052211.u85MBk4r003838>