summaryrefslogtreecommitdiff
path: root/usr/src/uts/sun4/os/ddi_impl.c
diff options
context:
space:
mode:
authorgovinda <none@none>2005-10-13 17:45:09 -0700
committergovinda <none@none>2005-10-13 17:45:09 -0700
commita195726fa33097e56cf1c25c31feddb827e140f0 (patch)
tree0d8a7063eb794f6d3697cb8cae5649c1363118a0 /usr/src/uts/sun4/os/ddi_impl.c
parent68ae3684389dbd334e0466478c9785b743f0b99b (diff)
downloadillumos-gate-a195726fa33097e56cf1c25c31feddb827e140f0.tar.gz
PSARC/2005/561 Obsolete DDI Interrupt Interfaces
6330182 Implement PSARC/2005/561 changes 6255855 ddi_intr_get_nintrs() returns DDI_SUCCESS for type = -1 6255872 ddi_intr_get_cap() returns 0 for capability structure 6256554 process_intr_ops() should check for pdip value 6280180 memory leaks in ddi_add_intr /ddi_intr_alloc 6320326 interrupt state should not be touched during interrupt re-routing 6320368 default px driver configuration should be MSIX 6320374 px driver should call ndi_ra_alloc() with proper arguments 6323264 px_err_reg_disable() access fire regsiters with incorrect csrbase 6328321 update sparc.fdbg for new DDI interrupt data structures --HG-- rename : usr/src/uts/common/sys/nexusintr.h => deleted_files/usr/src/uts/common/sys/nexusintr.h rename : usr/src/uts/sun4/sys/nexusintr_impl.h => deleted_files/usr/src/uts/sun4/sys/nexusintr_impl.h
Diffstat (limited to 'usr/src/uts/sun4/os/ddi_impl.c')
-rw-r--r--usr/src/uts/sun4/os/ddi_impl.c940
1 files changed, 416 insertions, 524 deletions
diff --git a/usr/src/uts/sun4/os/ddi_impl.c b/usr/src/uts/sun4/os/ddi_impl.c
index 4ae424e12c..da2931ba5b 100644
--- a/usr/src/uts/sun4/os/ddi_impl.c
+++ b/usr/src/uts/sun4/os/ddi_impl.c
@@ -55,7 +55,7 @@
#include <sys/ddi_isa.h>
dev_info_t *get_intr_parent(dev_info_t *, dev_info_t *,
- ddi_ispec_t *, ddi_ispec_t **);
+ ddi_intr_handle_impl_t *);
#pragma weak get_intr_parent
int process_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
@@ -394,48 +394,349 @@ cells_1275_cmp(prop_1275_cell_t *cell1, prop_1275_cell_t *cell2, int32_t len)
}
/*
- * Wrapper functions used by New DDI interrupt framework.
+ * get_intr_parent() is a generic routine that process a 1275 interrupt
+ * map (imap) property. This function returns a dev_info_t structure
+ * which claims ownership of the interrupt domain.
+ * It also returns the new interrupt translation within this new domain.
+ * If an interrupt-parent or interrupt-map property are not found,
+ * then we fallback to using the device tree's parent.
+ *
+ * imap entry format:
+ * <reg>,<interrupt>,<phandle>,<translated interrupt>
+ * reg - The register specification in the interrupts domain
+ * interrupt - The interrupt specification
+ * phandle - PROM handle of the device that owns the xlated interrupt domain
+ * translated interrupt - interrupt specifier in the parents domain
+ * note: <reg>,<interrupt> - The reg and interrupt can be combined to create
+ * a unique entry called a unit interrupt specifier.
+ *
+ * Here's the processing steps:
+ * step1 - If the interrupt-parent property exists, create the ispec and
+ * return the dip of the interrupt parent.
+ * step2 - Extract the interrupt-map property and the interrupt-map-mask
+ * If these don't exist, just return the device tree parent.
+ * step3 - build up the unit interrupt specifier to match against the
+ * interrupt map property
+ * step4 - Scan the interrupt-map property until a match is found
+ * step4a - Extract the interrupt parent
+ * step4b - Compare the unit interrupt specifier
*/
+dev_info_t *
+get_intr_parent(dev_info_t *pdip, dev_info_t *dip, ddi_intr_handle_impl_t *hdlp)
+{
+ prop_1275_cell_t *imap, *imap_mask, *scan, *reg_p, *match_req;
+ int32_t imap_sz, imap_cells, imap_scan_cells, imap_mask_sz,
+ addr_cells, intr_cells, reg_len, i, j;
+ int32_t match_found = 0;
+ dev_info_t *intr_parent_dip = NULL;
+ uint32_t *intr = &hdlp->ih_vector;
+ uint32_t nodeid;
+#ifdef DEBUG
+ static int debug = 0;
+#endif
+
+ /*
+ * step1
+ * If we have an interrupt-parent property, this property represents
+ * the nodeid of our interrupt parent.
+ */
+ if ((nodeid = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+ "interrupt-parent", -1)) != -1) {
+ intr_parent_dip = e_ddi_nodeid_to_dip(nodeid);
+ ASSERT(intr_parent_dip);
+
+ /*
+ * Attach the interrupt parent.
+ *
+ * N.B. e_ddi_nodeid_to_dip() isn't safe under DR.
+ * Also, interrupt parent isn't held. This needs
+ * to be revisited if DR-capable platforms implement
+ * interrupt redirection.
+ */
+ if (i_ddi_attach_node_hierarchy(intr_parent_dip)
+ != DDI_SUCCESS) {
+ ndi_rele_devi(intr_parent_dip);
+ return (NULL);
+ }
+
+ return (intr_parent_dip);
+ }
+
+ /*
+ * step2
+ * Get interrupt map structure from PROM property
+ */
+ if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
+ "interrupt-map", (caddr_t)&imap, &imap_sz)
+ != DDI_PROP_SUCCESS) {
+ /*
+ * If we don't have an imap property, default to using the
+ * device tree.
+ */
+
+ ndi_hold_devi(pdip);
+ return (pdip);
+ }
+
+ /* Get the interrupt mask property */
+ if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
+ "interrupt-map-mask", (caddr_t)&imap_mask, &imap_mask_sz)
+ != DDI_PROP_SUCCESS) {
+ /*
+ * If we don't find this property, we have to fail the request
+ * because the 1275 imap property wasn't defined correctly.
+ */
+ ASSERT(intr_parent_dip == NULL);
+ goto exit2;
+ }
+
+ /* Get the address cell size */
+ addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
+ "#address-cells", 2);
+
+ /* Get the interrupts cell size */
+ intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
+ "#interrupt-cells", 1);
+
+ /*
+ * step3
+ * Now lets build up the unit interrupt specifier e.g. reg,intr
+ * and apply the imap mask. match_req will hold this when we're
+ * through.
+ */
+ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
+ (caddr_t)&reg_p, &reg_len) != DDI_SUCCESS) {
+ ASSERT(intr_parent_dip == NULL);
+ goto exit3;
+ }
+
+ match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) +
+ CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP);
+
+ for (i = 0; i < addr_cells; i++)
+ match_req[i] = (reg_p[i] & imap_mask[i]);
+
+ for (j = 0; j < intr_cells; i++, j++)
+ match_req[i] = (intr[j] & imap_mask[i]);
+
+ /* Calculate the imap size in cells */
+ imap_cells = BYTES_TO_1275_CELLS(imap_sz);
+
+#ifdef DEBUG
+ if (debug)
+ prom_printf("reg cell size 0x%x, intr cell size 0x%x, "
+ "match_request 0x%p, imap 0x%p\n", addr_cells, intr_cells,
+ match_req, imap);
+#endif
+
+ /*
+ * Scan the imap property looking for a match of the interrupt unit
+ * specifier. This loop is rather complex since the data within the
+ * imap property may vary in size.
+ */
+ for (scan = imap, imap_scan_cells = i = 0;
+ imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) {
+ int new_intr_cells;
+
+ /* Set the index to the nodeid field */
+ i = addr_cells + intr_cells;
+
+ /*
+ * step4a
+ * Translate the nodeid field to a dip
+ */
+ ASSERT(intr_parent_dip == NULL);
+ intr_parent_dip = e_ddi_nodeid_to_dip((uint_t)scan[i++]);
+
+ ASSERT(intr_parent_dip != 0);
+#ifdef DEBUG
+ if (debug)
+ prom_printf("scan 0x%p\n", scan);
+#endif
+ /*
+ * The tmp_dip describes the new domain, get it's interrupt
+ * cell size
+ */
+ new_intr_cells = ddi_getprop(DDI_DEV_T_ANY, intr_parent_dip, 0,
+ "#interrupts-cells", 1);
+
+ /*
+ * step4b
+ * See if we have a match on the interrupt unit specifier
+ */
+ if (cells_1275_cmp(match_req, scan, addr_cells + intr_cells)
+ == 0) {
+ uint32_t *intr;
+
+ match_found = 1;
+
+ /*
+ * If we have an imap parent whose not in our device
+ * tree path, we need to hold and install that driver.
+ */
+ if (i_ddi_attach_node_hierarchy(intr_parent_dip)
+ != DDI_SUCCESS) {
+ ndi_rele_devi(intr_parent_dip);
+ intr_parent_dip = (dev_info_t *)NULL;
+ goto exit4;
+ }
+
+ /*
+ * We need to handcraft an ispec along with a bus
+ * interrupt value, so we can dup it into our
+ * standard ispec structure.
+ */
+ /* Extract the translated interrupt information */
+ intr = kmem_alloc(
+ CELLS_1275_TO_BYTES(new_intr_cells), KM_SLEEP);
+
+ for (j = 0; j < new_intr_cells; j++, i++)
+ intr[j] = scan[i];
+
+ cells_1275_copy(intr, &hdlp->ih_vector, new_intr_cells);
+
+ kmem_free(intr, CELLS_1275_TO_BYTES(new_intr_cells));
+
+#ifdef DEBUG
+ if (debug)
+ prom_printf("dip 0x%p\n", intr_parent_dip);
+#endif
+ break;
+ } else {
+#ifdef DEBUG
+ if (debug)
+ prom_printf("dip 0x%p\n", intr_parent_dip);
+#endif
+ ndi_rele_devi(intr_parent_dip);
+ intr_parent_dip = NULL;
+ i += new_intr_cells;
+ }
+ }
+
+ /*
+ * If we haven't found our interrupt parent at this point, fallback
+ * to using the device tree.
+ */
+ if (!match_found) {
+ ndi_hold_devi(pdip);
+ ASSERT(intr_parent_dip == NULL);
+ intr_parent_dip = pdip;
+ }
+
+ ASSERT(intr_parent_dip != NULL);
+
+exit4:
+ kmem_free(reg_p, reg_len);
+ kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) +
+ CELLS_1275_TO_BYTES(intr_cells));
+
+exit3:
+ kmem_free(imap_mask, imap_mask_sz);
+
+exit2:
+ kmem_free(imap, imap_sz);
+
+ return (intr_parent_dip);
+}
/*
- * i_ddi_handle_intr_ops:
+ * process_intr_ops:
+ *
+ * Process the interrupt op via the interrupt parent.
*/
int
-i_ddi_handle_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
+process_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t op,
ddi_intr_handle_impl_t *hdlp, void *result)
{
- ddi_intrspec_t ispec;
- int ret;
+ int ret = DDI_FAILURE;
- if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
- return (i_ddi_intr_ops(dip, rdip, op, hdlp, result));
+ if (NEXUS_HAS_INTR_OP(pdip)) {
+ ret = (*(DEVI(pdip)->devi_ops->devo_bus_ops->
+ bus_intr_op)) (pdip, rdip, op, hdlp, result);
+ } else {
+ cmn_err(CE_WARN, "Failed to process interrupt "
+ "for %s%d due to down-rev nexus driver %s%d",
+ ddi_get_name(rdip), ddi_get_instance(rdip),
+ ddi_get_name(pdip), ddi_get_instance(pdip));
+ }
- i_ddi_alloc_ispec(dip, hdlp->ih_inum, &ispec);
- if ((ddi_ispec_t *)ispec == NULL)
- return (DDI_FAILURE);
+ return (ret);
+}
- hdlp->ih_private = (void *)ispec;
- ret = i_ddi_intr_ops(dip, rdip, op, hdlp, result);
- hdlp->ih_private = NULL;
+/*ARGSUSED*/
+uint_t
+softlevel1(caddr_t arg)
+{
+ softint();
+ return (1);
+}
- i_ddi_free_ispec(ispec);
- return (ret);
+/*
+ * indirection table, to save us some large switch statements
+ * NOTE: This must agree with "INTLEVEL_foo" constants in
+ * <sys/avintr.h>
+ */
+struct autovec *const vectorlist[] = { 0 };
+
+/*
+ * This value is exported here for the functions in avintr.c
+ */
+const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0]));
+
+/*
+ * Check for machine specific interrupt levels which cannot be reassigned by
+ * settrap(), sun4u version.
+ *
+ * sun4u does not support V8 SPARC "fast trap" handlers.
+ */
+/*ARGSUSED*/
+int
+exclude_settrap(int lvl)
+{
+ return (1);
}
/*
+ * Check for machine specific interrupt levels which cannot have interrupt
+ * handlers added. We allow levels 1 through 15; level 0 is nonsense.
+ */
+/*ARGSUSED*/
+int
+exclude_level(int lvl)
+{
+ return ((lvl < 1) || (lvl > 15));
+}
+
+/*
+ * Wrapper functions used by New DDI interrupt framework.
+ */
+
+/*
* i_ddi_intr_ops:
*/
int
i_ddi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
ddi_intr_handle_impl_t *hdlp, void *result)
{
- ddi_ispec_t *sav_ip, *ip = NULL;
dev_info_t *pdip = ddi_get_parent(dip);
int ret = DDI_FAILURE;
+ /*
+ * The following check is required to address
+ * one of the test case of ADDI test suite.
+ */
+ if (pdip == NULL)
+ return (DDI_FAILURE);
+
if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
return (process_intr_ops(pdip, rdip, op, hdlp, result));
+ if (hdlp->ih_vector == 0)
+ hdlp->ih_vector = i_ddi_get_inum(rdip, hdlp->ih_inum);
+
+ if (hdlp->ih_pri == 0)
+ hdlp->ih_pri = i_ddi_get_intr_pri(rdip, hdlp->ih_inum);
+
switch (op) {
case DDI_INTROP_ADDISR:
case DDI_INTROP_REMISR:
@@ -443,18 +744,11 @@ i_ddi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
case DDI_INTROP_DISABLE:
case DDI_INTROP_BLOCKENABLE:
case DDI_INTROP_BLOCKDISABLE:
- /* Save the ispec */
- sav_ip = (ddi_ispec_t *)hdlp->ih_private;
-
/*
- * If we have an ispec struct, try and determine our
- * parent and possibly an interrupt translation.
- * intr parent dip returned held
+ * Try and determine our parent and possibly an interrupt
+ * translation. intr parent dip returned held
*/
- if ((pdip = get_intr_parent(pdip, dip, sav_ip, &ip)) != NULL) {
- /* Insert the interrupt info structure */
- hdlp->ih_private = (void *)ip;
- } else
+ if ((pdip = get_intr_parent(pdip, dip, hdlp)) == NULL)
goto done;
}
@@ -471,42 +765,9 @@ done:
/* Release hold acquired in get_intr_parent() */
if (pdip)
ndi_rele_devi(pdip);
-
- if (ip) {
- /* Set the PIL according to what the parent did */
- sav_ip->is_pil = ip->is_pil;
-
- /* Free the stacked ispec structure */
- i_ddi_free_ispec((ddi_intrspec_t)ip);
- }
-
- /* Restore the interrupt info */
- hdlp->ih_private = (void *)sav_ip;
}
- return (ret);
-}
-
-/*
- * process_intr_ops:
- *
- * Process the interrupt op via the interrupt parent.
- */
-int
-process_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t op,
- ddi_intr_handle_impl_t *hdlp, void *result)
-{
- int ret = DDI_FAILURE;
-
- if (NEXUS_HAS_INTR_OP(pdip)) {
- ret = (*(DEVI(pdip)->devi_ops->devo_bus_ops->
- bus_intr_op)) (pdip, rdip, op, hdlp, result);
- } else {
- cmn_err(CE_WARN, "Failed to process interrupt "
- "for %s%d due to down-rev nexus driver %s%d",
- ddi_get_name(rdip), ddi_get_instance(rdip),
- ddi_get_name(pdip), ddi_get_instance(pdip));
- }
+ hdlp->ih_vector = 0;
return (ret);
}
@@ -548,6 +809,98 @@ i_ddi_rem_ivintr(ddi_intr_handle_impl_t *hdlp)
}
/*
+ * i_ddi_get_inum - Get the interrupt number property from the
+ * specified device. Note that this function is called only for
+ * the FIXED interrupt type.
+ */
+uint32_t
+i_ddi_get_inum(dev_info_t *dip, uint_t inumber)
+{
+ int32_t intrlen, intr_cells, max_intrs;
+ prop_1275_cell_t *ip, intr_sz;
+ uint32_t intr = 0;
+
+ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
+ DDI_PROP_CANSLEEP,
+ "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
+
+ intr_cells = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+ "#interrupt-cells", 1);
+
+ /* adjust for number of bytes */
+ intr_sz = CELLS_1275_TO_BYTES(intr_cells);
+
+ /* Calculate the number of interrupts */
+ max_intrs = intrlen / intr_sz;
+
+ if (inumber < max_intrs) {
+ prop_1275_cell_t *intrp = ip;
+
+ /* Index into interrupt property */
+ intrp += (inumber * intr_cells);
+
+ cells_1275_copy(intrp, &intr, intr_cells);
+ }
+
+ kmem_free(ip, intrlen);
+ }
+
+ return (intr);
+}
+
+/*
+ * i_ddi_get_intr_pri - Get the interrupt-priorities property from
+ * the specified device. Note that this function is called only for
+ * the FIXED interrupt type.
+ */
+uint32_t
+i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber)
+{
+ uint32_t *intr_prio_p;
+ uint32_t pri = 0;
+ int32_t i;
+
+ /*
+ * Use the "interrupt-priorities" property to determine the
+ * the pil/ipl for the interrupt handler.
+ */
+ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "interrupt-priorities", (caddr_t)&intr_prio_p,
+ &i) == DDI_SUCCESS) {
+ if (inumber < (i / sizeof (int32_t)))
+ pri = intr_prio_p[inumber];
+ kmem_free(intr_prio_p, i);
+ }
+
+ return (pri);
+}
+
+int
+i_ddi_get_nintrs(dev_info_t *dip)
+{
+ int32_t intrlen;
+ prop_1275_cell_t intr_sz;
+ prop_1275_cell_t *ip;
+ int32_t ret = 0;
+
+ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
+ DDI_PROP_CANSLEEP,
+ "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
+
+ intr_sz = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
+ "#interrupt-cells", 1);
+ /* adjust for number of bytes */
+ intr_sz = CELLS_1275_TO_BYTES(intr_sz);
+
+ ret = intrlen / intr_sz;
+
+ kmem_free(ip, intrlen);
+ }
+
+ return (ret);
+}
+
+/*
* i_ddi_add_softint - allocate and add a soft interrupt to the system
*/
int
@@ -574,8 +927,10 @@ i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp)
/* disable */
ASSERT(hdlp->ih_private != NULL);
+
/* use uintptr_t to suppress the gcc warning */
intr_id = (uint_t)(uintptr_t)hdlp->ih_private;
+
rem_softintr(intr_id);
hdlp->ih_private = NULL;
}
@@ -618,96 +973,6 @@ i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri)
}
/*
- * Support routine for allocating and initializing an interrupt specification.
- * The bus interrupt value will be allocated at the end of this structure, so
- * the corresponding routine i_ddi_free_ispec() should be used to free the
- * interrupt specification.
- */
-void
-i_ddi_alloc_ispec(dev_info_t *dip, uint_t inumber, ddi_intrspec_t *intrspecp)
-{
- int32_t intrlen, intr_cells, max_intrs;
- prop_1275_cell_t *ip;
- prop_1275_cell_t intr_sz;
- ddi_ispec_t **ispecp = (ddi_ispec_t **)intrspecp;
-
- *ispecp = NULL;
- if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
- DDI_PROP_CANSLEEP,
- "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
-
- intr_cells = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
- "#interrupt-cells", 1);
-
- /* adjust for number of bytes */
- intr_sz = CELLS_1275_TO_BYTES(intr_cells);
-
- /* Calculate the number of interrupts */
- max_intrs = intrlen / intr_sz;
-
- if (inumber < max_intrs) {
- prop_1275_cell_t *intrp = ip;
-
- *ispecp = kmem_zalloc(
- (sizeof (ddi_ispec_t) + intr_sz), KM_SLEEP);
-
- (*ispecp)->is_intr =
- (uint32_t *)(*ispecp + 1);
-
- /* Index into interrupt property */
- intrp += (inumber * intr_cells);
-
- cells_1275_copy(intrp,
- (*ispecp)->is_intr, intr_cells);
-
- (*ispecp)->is_intr_sz = intr_sz;
-
- (*ispecp)->is_pil = i_ddi_get_intr_pri(dip, inumber);
- }
-
- kmem_free(ip, intrlen);
- }
-}
-
-/*
- * Analog routine to i_ddi_alloc_ispec() used to free the interrupt
- * specification and the associated bus interrupt value.
- */
-void
-i_ddi_free_ispec(ddi_intrspec_t intrspecp)
-{
- ddi_ispec_t *ispecp = (ddi_ispec_t *)intrspecp;
-
- kmem_free(ispecp, sizeof (ddi_ispec_t) + (ispecp->is_intr_sz));
-}
-
-/*
- * i_ddi_get_intr_pri - Get the interrupt-priorities property from
- * the specified device.
- */
-uint32_t
-i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber)
-{
- uint32_t *intr_prio_p;
- uint32_t pri = 0;
- int32_t i;
-
- /*
- * Use the "interrupt-priorities" property to determine the
- * the pil/ipl for the interrupt handler.
- */
- if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
- "interrupt-priorities", (caddr_t)&intr_prio_p,
- &i) == DDI_SUCCESS) {
- if (inumber < (i / sizeof (int32_t)))
- pri = intr_prio_p[inumber];
- kmem_free(intr_prio_p, i);
- }
-
- return (pri);
-}
-
-/*
* SECTION: DDI Memory/DMA
*/
@@ -1369,379 +1634,6 @@ impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len,
}
/*
- * SECTION: DDI Interrupt
- */
-
-/*
- * get_intr_parent() is a generic routine that process a 1275 interrupt
- * map (imap) property. This function returns a dev_info_t structure
- * which claims ownership of the interrupt domain.
- * It also returns the new interrupt translation within this new domain.
- * If an interrupt-parent or interrupt-map property are not found,
- * then we fallback to using the device tree's parent.
- *
- * imap entry format:
- * <reg>,<interrupt>,<phandle>,<translated interrupt>
- * reg - The register specification in the interrupts domain
- * interrupt - The interrupt specification
- * phandle - PROM handle of the device that owns the xlated interrupt domain
- * translated interrupt - interrupt specifier in the parents domain
- * note: <reg>,<interrupt> - The reg and interrupt can be combined to create
- * a unique entry called a unit interrupt specifier.
- *
- * Here's the processing steps:
- * step1 - If the interrupt-parent property exists, create the ispec and
- * return the dip of the interrupt parent.
- * step2 - Extract the interrupt-map property and the interrupt-map-mask
- * If these don't exist, just return the device tree parent.
- * step3 - build up the unit interrupt specifier to match against the
- * interrupt map property
- * step4 - Scan the interrupt-map property until a match is found
- * step4a - Extract the interrupt parent
- * step4b - Compare the unit interrupt specifier
- */
-dev_info_t *
-get_intr_parent(dev_info_t *pdip, dev_info_t *dip,
- ddi_ispec_t *child_ispecp, ddi_ispec_t **new_ispecp)
-{
- prop_1275_cell_t *imap, *imap_mask, *scan, *reg_p, *match_req;
- int32_t imap_sz, imap_cells, imap_scan_cells, imap_mask_sz,
- addr_cells, intr_cells, reg_len, i, j;
- int32_t match_found = 0;
- dev_info_t *intr_parent_dip = NULL;
- ddi_ispec_t *ispecp;
- uint32_t *intr = child_ispecp->is_intr;
- uint32_t nodeid;
- static ddi_ispec_t *dup_ispec(ddi_ispec_t *ispecp);
-#ifdef DEBUG
- static int debug = 0;
-#endif
-
- *new_ispecp = (ddi_ispec_t *)NULL;
-
- /*
- * step1
- * If we have an interrupt-parent property, this property represents
- * the nodeid of our interrupt parent.
- */
- if ((nodeid = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
- "interrupt-parent", -1)) != -1) {
- intr_parent_dip = e_ddi_nodeid_to_dip(nodeid);
- ASSERT(intr_parent_dip);
- /*
- * Attach the interrupt parent.
- *
- * N.B. e_ddi_nodeid_to_dip() isn't safe under DR.
- * Also, interrupt parent isn't held. This needs
- * to be revisited if DR-capable platforms implement
- * interrupt redirection.
- */
- if (i_ddi_attach_node_hierarchy(intr_parent_dip)
- != DDI_SUCCESS) {
- ndi_rele_devi(intr_parent_dip);
- return (NULL);
- }
-
- /* Create a new interrupt info struct and initialize it. */
- ispecp = dup_ispec(child_ispecp);
-
- *new_ispecp = ispecp;
- return (intr_parent_dip);
- }
-
- /*
- * step2
- * Get interrupt map structure from PROM property
- */
- if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
- "interrupt-map", (caddr_t)&imap, &imap_sz)
- != DDI_PROP_SUCCESS) {
- /*
- * If we don't have an imap property, default to using the
- * device tree.
- */
- /* Create a new interrupt info struct and initialize it. */
- ispecp = dup_ispec(child_ispecp);
-
- *new_ispecp = ispecp;
- ndi_hold_devi(pdip);
- return (pdip);
- }
-
- /* Get the interrupt mask property */
- if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
- "interrupt-map-mask", (caddr_t)&imap_mask, &imap_mask_sz)
- != DDI_PROP_SUCCESS) {
- /*
- * If we don't find this property, we have to fail the request
- * because the 1275 imap property wasn't defined correctly.
- */
- ASSERT(intr_parent_dip == NULL);
- goto exit2;
- }
-
- /* Get the address cell size */
- addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
- "#address-cells", 2);
-
- /* Get the interrupts cell size */
- intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
- "#interrupt-cells", 1);
-
- /*
- * step3
- * Now lets build up the unit interrupt specifier e.g. reg,intr
- * and apply the imap mask. match_req will hold this when we're
- * through.
- */
- if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
- (caddr_t)&reg_p, &reg_len) != DDI_SUCCESS) {
- ASSERT(intr_parent_dip == NULL);
- goto exit3;
- }
-
- match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) +
- CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP);
-
- for (i = 0; i < addr_cells; i++)
- match_req[i] = (reg_p[i] & imap_mask[i]);
-
- for (j = 0; j < intr_cells; i++, j++)
- match_req[i] = (intr[j] & imap_mask[i]);
-
- /* Calculate the imap size in cells */
- imap_cells = BYTES_TO_1275_CELLS(imap_sz);
-
-#ifdef DEBUG
- if (debug)
- prom_printf("reg cell size 0x%x, intr cell size 0x%x, "
- "match_request 0x%p, imap 0x%p\n", addr_cells, intr_cells,
- match_req, imap);
-#endif
-
- /*
- * Scan the imap property looking for a match of the interrupt unit
- * specifier. This loop is rather complex since the data within the
- * imap property may vary in size.
- */
- for (scan = imap, imap_scan_cells = i = 0;
- imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) {
- int new_intr_cells;
-
- /* Set the index to the nodeid field */
- i = addr_cells + intr_cells;
-
- /*
- * step4a
- * Translate the nodeid field to a dip
- */
- ASSERT(intr_parent_dip == NULL);
- intr_parent_dip = e_ddi_nodeid_to_dip((uint_t)scan[i++]);
-
- ASSERT(intr_parent_dip != 0);
-#ifdef DEBUG
- if (debug)
- prom_printf("scan 0x%p\n", scan);
-#endif
- /*
- * The tmp_dip describes the new domain, get it's interrupt
- * cell size
- */
- new_intr_cells = ddi_getprop(DDI_DEV_T_ANY, intr_parent_dip, 0,
- "#interrupts-cells", 1);
-
- /*
- * step4b
- * See if we have a match on the interrupt unit specifier
- */
- if (cells_1275_cmp(match_req, scan, addr_cells + intr_cells)
- == 0) {
- ddi_ispec_t ispec;
- uint32_t *intr;
-
- /*
- * Copy The childs ispec info excluding the interrupt
- */
- ispec = *child_ispecp;
-
- match_found = 1;
-
- /*
- * If we have an imap parent whose not in our device
- * tree path, we need to hold and install that driver.
- */
- if (i_ddi_attach_node_hierarchy(intr_parent_dip)
- != DDI_SUCCESS) {
- ndi_rele_devi(intr_parent_dip);
- intr_parent_dip = (dev_info_t *)NULL;
- goto exit4;
- }
-
- /*
- * We need to handcraft an ispec along with a bus
- * interrupt value, so we can dup it into our
- * standard ispec structure.
- */
- /* Extract the translated interrupt information */
- intr = kmem_alloc(
- CELLS_1275_TO_BYTES(new_intr_cells), KM_SLEEP);
-
- for (j = 0; j < new_intr_cells; j++, i++)
- intr[j] = scan[i];
-
- ispec.is_intr_sz =
- CELLS_1275_TO_BYTES(new_intr_cells);
- ispec.is_intr = intr;
-
- ispecp = dup_ispec(&ispec);
-
- kmem_free(intr, CELLS_1275_TO_BYTES(new_intr_cells));
-
-#ifdef DEBUG
- if (debug)
- prom_printf("dip 0x%p, intr info 0x%p\n",
- intr_parent_dip, ispecp);
-#endif
-
- break;
- } else {
-#ifdef DEBUG
- if (debug)
- prom_printf("dip 0x%p\n", intr_parent_dip);
-#endif
- ndi_rele_devi(intr_parent_dip);
- intr_parent_dip = NULL;
- i += new_intr_cells;
- }
- }
-
- /*
- * If we haven't found our interrupt parent at this point, fallback
- * to using the device tree.
- */
- if (!match_found) {
- /* Create a new interrupt info struct and initialize it. */
- ispecp = dup_ispec(child_ispecp);
-
- ndi_hold_devi(pdip);
- ASSERT(intr_parent_dip == NULL);
- intr_parent_dip = pdip;
- }
-
- ASSERT(ispecp != NULL);
- ASSERT(intr_parent_dip != NULL);
- *new_ispecp = ispecp;
-
-exit4:
- kmem_free(reg_p, reg_len);
- kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) +
- CELLS_1275_TO_BYTES(intr_cells));
-
-exit3:
- kmem_free(imap_mask, imap_mask_sz);
-
-exit2:
- kmem_free(imap, imap_sz);
-
- return (intr_parent_dip);
-}
-
-/*
- * Support routine for duplicating and initializing an interrupt specification.
- * The bus interrupt value will be allocated at the end of this structure, so
- * the corresponding routine i_ddi_free_ispec() should be used to free the
- * interrupt specification.
- */
-static ddi_ispec_t *
-dup_ispec(ddi_ispec_t *ispecp)
-{
- ddi_ispec_t *new_ispecp;
-
- new_ispecp = kmem_alloc(sizeof (ddi_ispec_t) + ispecp->is_intr_sz,
- KM_SLEEP);
-
- /* Copy the contents of the ispec */
- *new_ispecp = *ispecp;
-
- /* Reset the intr pointer to the one just created */
- new_ispecp->is_intr = (uint32_t *)(new_ispecp + 1);
-
- cells_1275_copy(ispecp->is_intr, new_ispecp->is_intr,
- BYTES_TO_1275_CELLS(ispecp->is_intr_sz));
-
- return (new_ispecp);
-}
-
-int
-i_ddi_get_nintrs(dev_info_t *dip)
-{
- int32_t intrlen;
- prop_1275_cell_t intr_sz;
- prop_1275_cell_t *ip;
- int32_t ret = 0;
-
- if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
- DDI_PROP_CANSLEEP,
- "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
-
- intr_sz = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
- "#interrupt-cells", 1);
- /* adjust for number of bytes */
- intr_sz = CELLS_1275_TO_BYTES(intr_sz);
-
- ret = intrlen / intr_sz;
-
- kmem_free(ip, intrlen);
- }
-
- return (ret);
-}
-
-/*ARGSUSED*/
-uint_t
-softlevel1(caddr_t arg)
-{
- softint();
- return (1);
-}
-
-/*
- * indirection table, to save us some large switch statements
- * NOTE: This must agree with "INTLEVEL_foo" constants in
- * <sys/avintr.h>
- */
-struct autovec *const vectorlist[] = { 0 };
-
-/*
- * This value is exported here for the functions in avintr.c
- */
-const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0]));
-
-/*
- * Check for machine specific interrupt levels which cannot be reassigned by
- * settrap(), sun4u version.
- *
- * sun4u does not support V8 SPARC "fast trap" handlers.
- */
-/*ARGSUSED*/
-int
-exclude_settrap(int lvl)
-{
- return (1);
-}
-
-/*
- * Check for machine specific interrupt levels which cannot have interrupt
- * handlers added. We allow levels 1 through 15; level 0 is nonsense.
- */
-/*ARGSUSED*/
-int
-exclude_level(int lvl)
-{
- return ((lvl < 1) || (lvl > 15));
-}
-
-/*
* The following functions ready a cautious request to go up to the nexus
* driver. It is up to the nexus driver to decide how to process the request.
* It may choose to call i_ddi_do_caut_get/put in this file, or do it