From a195726fa33097e56cf1c25c31feddb827e140f0 Mon Sep 17 00:00:00 2001 From: govinda Date: Thu, 13 Oct 2005 17:45:09 -0700 Subject: 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 --- usr/src/uts/sun4/os/ddi_impl.c | 1456 +++++++++++++++++++--------------------- 1 file changed, 674 insertions(+), 782 deletions(-) (limited to 'usr/src/uts/sun4/os/ddi_impl.c') 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 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,244 +394,432 @@ cells_1275_cmp(prop_1275_cell_t *cell1, prop_1275_cell_t *cell2, int32_t len) } /* - * Wrapper functions used by New DDI interrupt framework. - */ - -/* - * i_ddi_handle_intr_ops: + * 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 - 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: , - 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 */ -int -i_ddi_handle_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op, - ddi_intr_handle_impl_t *hdlp, void *result) +dev_info_t * +get_intr_parent(dev_info_t *pdip, dev_info_t *dip, ddi_intr_handle_impl_t *hdlp) { - ddi_intrspec_t ispec; - int ret; - - if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) - return (i_ddi_intr_ops(dip, rdip, op, hdlp, result)); - - i_ddi_alloc_ispec(dip, hdlp->ih_inum, &ispec); - if ((ddi_ispec_t *)ispec == NULL) - return (DDI_FAILURE); + 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 - hdlp->ih_private = (void *)ispec; - ret = i_ddi_intr_ops(dip, rdip, op, hdlp, result); - hdlp->ih_private = 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); - i_ddi_free_ispec(ispec); - return (ret); -} + /* + * 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); + } -/* - * 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; + return (intr_parent_dip); + } - if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) - return (process_intr_ops(pdip, rdip, op, hdlp, result)); + /* + * 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. + */ - switch (op) { - case DDI_INTROP_ADDISR: - case DDI_INTROP_REMISR: - case DDI_INTROP_ENABLE: - case DDI_INTROP_DISABLE: - case DDI_INTROP_BLOCKENABLE: - case DDI_INTROP_BLOCKDISABLE: - /* Save the ispec */ - sav_ip = (ddi_ispec_t *)hdlp->ih_private; + 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 have an ispec struct, try and determine our - * parent and possibly an interrupt translation. - * intr parent dip returned held + * If we don't find this property, we have to fail the request + * because the 1275 imap property wasn't defined correctly. */ - if ((pdip = get_intr_parent(pdip, dip, sav_ip, &ip)) != NULL) { - /* Insert the interrupt info structure */ - hdlp->ih_private = (void *)ip; - } else - goto done; + ASSERT(intr_parent_dip == NULL); + goto exit2; } - ret = process_intr_ops(pdip, rdip, op, hdlp, result); - -done: - switch (op) { - case DDI_INTROP_ADDISR: - case DDI_INTROP_REMISR: - case DDI_INTROP_ENABLE: - case DDI_INTROP_DISABLE: - case DDI_INTROP_BLOCKENABLE: - case DDI_INTROP_BLOCKDISABLE: - /* 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; + /* Get the address cell size */ + addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0, + "#address-cells", 2); - /* Free the stacked ispec structure */ - i_ddi_free_ispec((ddi_intrspec_t)ip); - } + /* Get the interrupts cell size */ + intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0, + "#interrupt-cells", 1); - /* Restore the interrupt info */ - hdlp->ih_private = (void *)sav_ip; + /* + * 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)®_p, ®_len) != DDI_SUCCESS) { + ASSERT(intr_parent_dip == NULL); + goto exit3; } - return (ret); -} + match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) + + CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP); -/* - * 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; + for (i = 0; i < addr_cells; i++) + match_req[i] = (reg_p[i] & imap_mask[i]); - 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)); - } + for (j = 0; j < intr_cells; i++, j++) + match_req[i] = (intr[j] & imap_mask[i]); - return (ret); -} + /* Calculate the imap size in cells */ + imap_cells = BYTES_TO_1275_CELLS(imap_sz); -/* - * i_ddi_add_ivintr: - */ -/*ARGSUSED*/ -int -i_ddi_add_ivintr(ddi_intr_handle_impl_t *hdlp) -{ - /* Sanity check the entry we're about to add */ - if (GET_IVINTR(hdlp->ih_vector)) { - cmn_err(CE_WARN, "mondo 0x%x in use", hdlp->ih_vector); - return (DDI_FAILURE); - } +#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 /* - * If the PIL was set and is valid use it, otherwise - * default it to 1 + * 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. */ - if ((hdlp->ih_pri < 1) || (hdlp->ih_pri > PIL_MAX)) - hdlp->ih_pri = 1; - - VERIFY(add_ivintr(hdlp->ih_vector, hdlp->ih_pri, - (intrfunc)hdlp->ih_cb_func, hdlp->ih_cb_arg1, NULL) == 0); + for (scan = imap, imap_scan_cells = i = 0; + imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) { + int new_intr_cells; - return (DDI_SUCCESS); -} + /* Set the index to the nodeid field */ + i = addr_cells + intr_cells; -/* - * i_ddi_rem_ivintr: - */ -/*ARGSUSED*/ -void -i_ddi_rem_ivintr(ddi_intr_handle_impl_t *hdlp) -{ - rem_ivintr(hdlp->ih_vector, NULL); -} + /* + * 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++]); -/* - * i_ddi_add_softint - allocate and add a soft interrupt to the system - */ -int -i_ddi_add_softint(ddi_softint_hdl_impl_t *hdlp) -{ - uint_t rval; + 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); - if ((rval = add_softintr(hdlp->ih_pri, hdlp->ih_cb_func, - hdlp->ih_cb_arg1)) == 0) { + /* + * 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; - return (DDI_FAILURE); - } + match_found = 1; - /* use uintptr_t to suppress the gcc warning */ - hdlp->ih_private = (void *)(uintptr_t)rval; + /* + * 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; + } - return (DDI_SUCCESS); + /* + * 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); } -void -i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp) +/* + * 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) { - uint_t intr_id; + int ret = DDI_FAILURE; - /* 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; + 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)); + } + + return (ret); } -int -i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp, void *arg2) +/*ARGSUSED*/ +uint_t +softlevel1(caddr_t arg) { - uint_t intr_id; - int ret; + softint(); + return (1); +} - ASSERT(hdlp != NULL); - ASSERT(hdlp->ih_private != NULL); +/* + * indirection table, to save us some large switch statements + * NOTE: This must agree with "INTLEVEL_foo" constants in + * + */ +struct autovec *const vectorlist[] = { 0 }; - intr_id = (uint_t)hdlp->ih_private; +/* + * This value is exported here for the functions in avintr.c + */ +const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0])); - /* update the vector table for the 2nd arg */ - ret = update_softint_arg2(intr_id, arg2); - if (ret == DDI_SUCCESS) - setsoftint(intr_id); +/* + * 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); +} - return (ret); +/* + * 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)); } -/* ARGSUSED */ +/* + * Wrapper functions used by New DDI interrupt framework. + */ + +/* + * i_ddi_intr_ops: + */ int -i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri) +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) { - uint_t intr_id; - int ret; + dev_info_t *pdip = ddi_get_parent(dip); + int ret = DDI_FAILURE; - ASSERT(hdlp != NULL); - ASSERT(hdlp->ih_private != NULL); + /* + * The following check is required to address + * one of the test case of ADDI test suite. + */ + if (pdip == NULL) + return (DDI_FAILURE); - intr_id = (uint_t)hdlp->ih_private; + if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) + return (process_intr_ops(pdip, rdip, op, hdlp, result)); - /* update the vector table for the new priority */ - ret = update_softint_pri(intr_id, hdlp->ih_pri); + 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: + case DDI_INTROP_ENABLE: + case DDI_INTROP_DISABLE: + case DDI_INTROP_BLOCKENABLE: + case DDI_INTROP_BLOCKDISABLE: + /* + * Try and determine our parent and possibly an interrupt + * translation. intr parent dip returned held + */ + if ((pdip = get_intr_parent(pdip, dip, hdlp)) == NULL) + goto done; + } + + ret = process_intr_ops(pdip, rdip, op, hdlp, result); + +done: + switch (op) { + case DDI_INTROP_ADDISR: + case DDI_INTROP_REMISR: + case DDI_INTROP_ENABLE: + case DDI_INTROP_DISABLE: + case DDI_INTROP_BLOCKENABLE: + case DDI_INTROP_BLOCKDISABLE: + /* Release hold acquired in get_intr_parent() */ + if (pdip) + ndi_rele_devi(pdip); + } + + hdlp->ih_vector = 0; return (ret); } /* - * 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. + * i_ddi_add_ivintr: + */ +/*ARGSUSED*/ +int +i_ddi_add_ivintr(ddi_intr_handle_impl_t *hdlp) +{ + /* Sanity check the entry we're about to add */ + if (GET_IVINTR(hdlp->ih_vector)) { + cmn_err(CE_WARN, "mondo 0x%x in use", hdlp->ih_vector); + return (DDI_FAILURE); + } + + /* + * If the PIL was set and is valid use it, otherwise + * default it to 1 + */ + if ((hdlp->ih_pri < 1) || (hdlp->ih_pri > PIL_MAX)) + hdlp->ih_pri = 1; + + VERIFY(add_ivintr(hdlp->ih_vector, hdlp->ih_pri, + (intrfunc)hdlp->ih_cb_func, hdlp->ih_cb_arg1, NULL) == 0); + + return (DDI_SUCCESS); +} + +/* + * i_ddi_rem_ivintr: */ +/*ARGSUSED*/ void -i_ddi_alloc_ispec(dev_info_t *dip, uint_t inumber, ddi_intrspec_t *intrspecp) +i_ddi_rem_ivintr(ddi_intr_handle_impl_t *hdlp) { - 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; + rem_ivintr(hdlp->ih_vector, NULL); +} + +/* + * 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; - *ispecp = NULL; if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) { @@ -648,49 +836,29 @@ i_ddi_alloc_ispec(dev_info_t *dip, uint_t inumber, ddi_intrspec_t *intrspecp) 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); + cells_1275_copy(intrp, &intr, intr_cells); } 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)); + return (intr); } /* * i_ddi_get_intr_pri - Get the interrupt-priorities property from - * the specified device. + * 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; + uint32_t *intr_prio_p; + uint32_t pri = 0; + int32_t i; /* * Use the "interrupt-priorities" property to determine the @@ -707,13 +875,110 @@ i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber) return (pri); } -/* - * SECTION: DDI Memory/DMA - */ - -static vmem_t *little_endian_arena; -static vmem_t *big_endian_arena; - +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 +i_ddi_add_softint(ddi_softint_hdl_impl_t *hdlp) +{ + uint_t rval; + + if ((rval = add_softintr(hdlp->ih_pri, hdlp->ih_cb_func, + hdlp->ih_cb_arg1)) == 0) { + + return (DDI_FAILURE); + } + + /* use uintptr_t to suppress the gcc warning */ + hdlp->ih_private = (void *)(uintptr_t)rval; + + return (DDI_SUCCESS); +} + +void +i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp) +{ + uint_t intr_id; + + /* 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; +} + +int +i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp, void *arg2) +{ + uint_t intr_id; + int ret; + + ASSERT(hdlp != NULL); + ASSERT(hdlp->ih_private != NULL); + + intr_id = (uint_t)hdlp->ih_private; + + /* update the vector table for the 2nd arg */ + ret = update_softint_arg2(intr_id, arg2); + if (ret == DDI_SUCCESS) + setsoftint(intr_id); + + return (ret); +} + +/* ARGSUSED */ +int +i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri) +{ + uint_t intr_id; + int ret; + + ASSERT(hdlp != NULL); + ASSERT(hdlp->ih_private != NULL); + + intr_id = (uint_t)hdlp->ih_private; + + /* update the vector table for the new priority */ + ret = update_softint_pri(intr_id, hdlp->ih_pri); + + return (ret); +} + +/* + * SECTION: DDI Memory/DMA + */ + +static vmem_t *little_endian_arena; +static vmem_t *big_endian_arena; + static void * segkmem_alloc_le(vmem_t *vmp, size_t size, int flag) { @@ -1131,614 +1396,241 @@ int impl_free_instance(dev_info_t *dip) { return (DDI_FAILURE); -} - -/*ARGSUSED*/ -int -impl_check_cpu(dev_info_t *devi) -{ - return (DDI_SUCCESS); -} - - -static const char *nocopydevs[] = { - "SUNW,ffb", - "SUNW,afb", - NULL -}; - -/* - * Perform a copy from a memory mapped device (whose devinfo pointer is devi) - * separately mapped at devaddr in the kernel to a kernel buffer at kaddr. - */ -/*ARGSUSED*/ -int -e_ddi_copyfromdev(dev_info_t *devi, - off_t off, const void *devaddr, void *kaddr, size_t len) -{ - const char **argv; - - for (argv = nocopydevs; *argv; argv++) - if (strcmp(ddi_binding_name(devi), *argv) == 0) { - bzero(kaddr, len); - return (0); - } - - bcopy(devaddr, kaddr, len); - return (0); -} - -/* - * Perform a copy to a memory mapped device (whose devinfo pointer is devi) - * separately mapped at devaddr in the kernel from a kernel buffer at kaddr. - */ -/*ARGSUSED*/ -int -e_ddi_copytodev(dev_info_t *devi, - off_t off, const void *kaddr, void *devaddr, size_t len) -{ - const char **argv; - - for (argv = nocopydevs; *argv; argv++) - if (strcmp(ddi_binding_name(devi), *argv) == 0) - return (1); - - bcopy(kaddr, devaddr, len); - return (0); -} - -/* - * Boot Configuration - */ -idprom_t idprom; - -/* - * Configure the hardware on the system. - * Called before the rootfs is mounted - */ -void -configure(void) -{ - extern void i_ddi_init_root(); - - /* We better have released boot by this time! */ - ASSERT(!bootops); - - /* - * Determine whether or not to use the fpu, V9 SPARC cpus - * always have one. Could check for existence of a fp queue, - * Ultra I, II and IIa do not have a fp queue. - */ - if (fpu_exists) - fpu_probe(); - else - cmn_err(CE_CONT, "FPU not in use\n"); - -#if 0 /* XXXQ - not necessary for sun4u */ - /* - * This following line fixes bugid 1041296; we need to do a - * prom_nextnode(0) because this call ALSO patches the DMA+ - * bug in Campus-B and Phoenix. The prom uncaches the traptable - * page as a side-effect of devr_next(0) (which prom_nextnode calls), - * so this *must* be executed early on. (XXX This is untrue for sun4u) - */ - (void) prom_nextnode((dnode_t)0); -#endif - - /* - * Initialize devices on the machine. - * Uses configuration tree built by the PROMs to determine what - * is present, and builds a tree of prototype dev_info nodes - * corresponding to the hardware which identified itself. - */ - i_ddi_init_root(); - -#ifdef DDI_PROP_DEBUG - (void) ddi_prop_debug(1); /* Enable property debugging */ -#endif /* DDI_PROP_DEBUG */ -} - -/* - * The "status" property indicates the operational status of a device. - * If this property is present, the value is a string indicating the - * status of the device as follows: - * - * "okay" operational. - * "disabled" not operational, but might become operational. - * "fail" not operational because a fault has been detected, - * and it is unlikely that the device will become - * operational without repair. no additional details - * are available. - * "fail-xxx" not operational because a fault has been detected, - * and it is unlikely that the device will become - * operational without repair. "xxx" is additional - * human-readable information about the particular - * fault condition that was detected. - * - * The absence of this property means that the operational status is - * unknown or okay. - * - * This routine checks the status property of the specified device node - * and returns 0 if the operational status indicates failure, and 1 otherwise. - * - * The property may exist on plug-in cards the existed before IEEE 1275-1994. - * And, in that case, the property may not even be a string. So we carefully - * check for the value "fail", in the beginning of the string, noting - * the property length. - */ -int -status_okay(int id, char *buf, int buflen) -{ - char status_buf[OBP_MAXPROPNAME]; - char *bufp = buf; - int len = buflen; - int proplen; - static const char *status = "status"; - static const char *fail = "fail"; - size_t fail_len = strlen(fail); - - /* - * Get the proplen ... if it's smaller than "fail", - * or doesn't exist ... then we don't care, since - * the value can't begin with the char string "fail". - * - * NB: proplen, if it's a string, includes the NULL in the - * the size of the property, and fail_len does not. - */ - proplen = prom_getproplen((dnode_t)id, (caddr_t)status); - if (proplen <= fail_len) /* nonexistent or uninteresting len */ - return (1); - - /* - * if a buffer was provided, use it - */ - if ((buf == (char *)NULL) || (buflen <= 0)) { - bufp = status_buf; - len = sizeof (status_buf); - } - *bufp = (char)0; - - /* - * Get the property into the buffer, to the extent of the buffer, - * and in case the buffer is smaller than the property size, - * NULL terminate the buffer. (This handles the case where - * a buffer was passed in and the caller wants to print the - * value, but the buffer was too small). - */ - (void) prom_bounded_getprop((dnode_t)id, (caddr_t)status, - (caddr_t)bufp, len); - *(bufp + len - 1) = (char)0; - - /* - * If the value begins with the char string "fail", - * then it means the node is failed. We don't care - * about any other values. We assume the node is ok - * although it might be 'disabled'. - */ - if (strncmp(bufp, fail, fail_len) == 0) - return (0); - - return (1); -} - - -/* - * We set the cpu type from the idprom, if we can. - * Note that we just read out the contents of it, for the most part. - */ -void -setcputype(void) -{ - /* - * We cache the idprom info early on so that we don't - * rummage through the NVRAM unnecessarily later. - */ - (void) prom_getidprom((caddr_t)&idprom, sizeof (idprom)); -} - -/* - * Here is where we actually infer meanings to the members of idprom_t - */ -void -parse_idprom(void) -{ - if (idprom.id_format == IDFORM_1) { - uint_t i; - - (void) localetheraddr((struct ether_addr *)idprom.id_ether, - (struct ether_addr *)NULL); - - i = idprom.id_machine << 24; - i = i + idprom.id_serial; - numtos((ulong_t)i, hw_serial); - } else - prom_printf("Invalid format code in IDprom.\n"); -} - -/* - * Allow for implementation specific correction of PROM property values. - */ -/*ARGSUSED*/ -void -impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len, - caddr_t buffer) -{ - /* - * There are no adjustments needed in this implementation. - */ -} - -/* - * 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 - 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: , - 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)®_p, ®_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); +/*ARGSUSED*/ +int +impl_check_cpu(dev_info_t *devi) +{ + return (DDI_SUCCESS); +} - ndi_hold_devi(pdip); - ASSERT(intr_parent_dip == NULL); - intr_parent_dip = pdip; - } - ASSERT(ispecp != NULL); - ASSERT(intr_parent_dip != NULL); - *new_ispecp = ispecp; +static const char *nocopydevs[] = { + "SUNW,ffb", + "SUNW,afb", + NULL +}; -exit4: - kmem_free(reg_p, reg_len); - kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) + - CELLS_1275_TO_BYTES(intr_cells)); +/* + * Perform a copy from a memory mapped device (whose devinfo pointer is devi) + * separately mapped at devaddr in the kernel to a kernel buffer at kaddr. + */ +/*ARGSUSED*/ +int +e_ddi_copyfromdev(dev_info_t *devi, + off_t off, const void *devaddr, void *kaddr, size_t len) +{ + const char **argv; -exit3: - kmem_free(imap_mask, imap_mask_sz); + for (argv = nocopydevs; *argv; argv++) + if (strcmp(ddi_binding_name(devi), *argv) == 0) { + bzero(kaddr, len); + return (0); + } -exit2: - kmem_free(imap, imap_sz); + bcopy(devaddr, kaddr, len); + return (0); +} - return (intr_parent_dip); +/* + * Perform a copy to a memory mapped device (whose devinfo pointer is devi) + * separately mapped at devaddr in the kernel from a kernel buffer at kaddr. + */ +/*ARGSUSED*/ +int +e_ddi_copytodev(dev_info_t *devi, + off_t off, const void *kaddr, void *devaddr, size_t len) +{ + const char **argv; + + for (argv = nocopydevs; *argv; argv++) + if (strcmp(ddi_binding_name(devi), *argv) == 0) + return (1); + + bcopy(kaddr, devaddr, len); + return (0); } /* - * 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. + * Boot Configuration + */ +idprom_t idprom; + +/* + * Configure the hardware on the system. + * Called before the rootfs is mounted */ -static ddi_ispec_t * -dup_ispec(ddi_ispec_t *ispecp) +void +configure(void) { - ddi_ispec_t *new_ispecp; + extern void i_ddi_init_root(); - new_ispecp = kmem_alloc(sizeof (ddi_ispec_t) + ispecp->is_intr_sz, - KM_SLEEP); + /* We better have released boot by this time! */ + ASSERT(!bootops); - /* Copy the contents of the ispec */ - *new_ispecp = *ispecp; + /* + * Determine whether or not to use the fpu, V9 SPARC cpus + * always have one. Could check for existence of a fp queue, + * Ultra I, II and IIa do not have a fp queue. + */ + if (fpu_exists) + fpu_probe(); + else + cmn_err(CE_CONT, "FPU not in use\n"); - /* Reset the intr pointer to the one just created */ - new_ispecp->is_intr = (uint32_t *)(new_ispecp + 1); +#if 0 /* XXXQ - not necessary for sun4u */ + /* + * This following line fixes bugid 1041296; we need to do a + * prom_nextnode(0) because this call ALSO patches the DMA+ + * bug in Campus-B and Phoenix. The prom uncaches the traptable + * page as a side-effect of devr_next(0) (which prom_nextnode calls), + * so this *must* be executed early on. (XXX This is untrue for sun4u) + */ + (void) prom_nextnode((dnode_t)0); +#endif - cells_1275_copy(ispecp->is_intr, new_ispecp->is_intr, - BYTES_TO_1275_CELLS(ispecp->is_intr_sz)); + /* + * Initialize devices on the machine. + * Uses configuration tree built by the PROMs to determine what + * is present, and builds a tree of prototype dev_info nodes + * corresponding to the hardware which identified itself. + */ + i_ddi_init_root(); - return (new_ispecp); +#ifdef DDI_PROP_DEBUG + (void) ddi_prop_debug(1); /* Enable property debugging */ +#endif /* DDI_PROP_DEBUG */ } +/* + * The "status" property indicates the operational status of a device. + * If this property is present, the value is a string indicating the + * status of the device as follows: + * + * "okay" operational. + * "disabled" not operational, but might become operational. + * "fail" not operational because a fault has been detected, + * and it is unlikely that the device will become + * operational without repair. no additional details + * are available. + * "fail-xxx" not operational because a fault has been detected, + * and it is unlikely that the device will become + * operational without repair. "xxx" is additional + * human-readable information about the particular + * fault condition that was detected. + * + * The absence of this property means that the operational status is + * unknown or okay. + * + * This routine checks the status property of the specified device node + * and returns 0 if the operational status indicates failure, and 1 otherwise. + * + * The property may exist on plug-in cards the existed before IEEE 1275-1994. + * And, in that case, the property may not even be a string. So we carefully + * check for the value "fail", in the beginning of the string, noting + * the property length. + */ int -i_ddi_get_nintrs(dev_info_t *dip) +status_okay(int id, char *buf, int buflen) { - 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); + char status_buf[OBP_MAXPROPNAME]; + char *bufp = buf; + int len = buflen; + int proplen; + static const char *status = "status"; + static const char *fail = "fail"; + size_t fail_len = strlen(fail); - ret = intrlen / intr_sz; + /* + * Get the proplen ... if it's smaller than "fail", + * or doesn't exist ... then we don't care, since + * the value can't begin with the char string "fail". + * + * NB: proplen, if it's a string, includes the NULL in the + * the size of the property, and fail_len does not. + */ + proplen = prom_getproplen((dnode_t)id, (caddr_t)status); + if (proplen <= fail_len) /* nonexistent or uninteresting len */ + return (1); - kmem_free(ip, intrlen); + /* + * if a buffer was provided, use it + */ + if ((buf == (char *)NULL) || (buflen <= 0)) { + bufp = status_buf; + len = sizeof (status_buf); } + *bufp = (char)0; - return (ret); -} + /* + * Get the property into the buffer, to the extent of the buffer, + * and in case the buffer is smaller than the property size, + * NULL terminate the buffer. (This handles the case where + * a buffer was passed in and the caller wants to print the + * value, but the buffer was too small). + */ + (void) prom_bounded_getprop((dnode_t)id, (caddr_t)status, + (caddr_t)bufp, len); + *(bufp + len - 1) = (char)0; + + /* + * If the value begins with the char string "fail", + * then it means the node is failed. We don't care + * about any other values. We assume the node is ok + * although it might be 'disabled'. + */ + if (strncmp(bufp, fail, fail_len) == 0) + return (0); -/*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 - * - */ -struct autovec *const vectorlist[] = { 0 }; /* - * This value is exported here for the functions in avintr.c + * We set the cpu type from the idprom, if we can. + * Note that we just read out the contents of it, for the most part. */ -const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0])); +void +setcputype(void) +{ + /* + * We cache the idprom info early on so that we don't + * rummage through the NVRAM unnecessarily later. + */ + (void) prom_getidprom((caddr_t)&idprom, sizeof (idprom)); +} /* - * Check for machine specific interrupt levels which cannot be reassigned by - * settrap(), sun4u version. - * - * sun4u does not support V8 SPARC "fast trap" handlers. + * Here is where we actually infer meanings to the members of idprom_t */ -/*ARGSUSED*/ -int -exclude_settrap(int lvl) +void +parse_idprom(void) { - return (1); + if (idprom.id_format == IDFORM_1) { + uint_t i; + + (void) localetheraddr((struct ether_addr *)idprom.id_ether, + (struct ether_addr *)NULL); + + i = idprom.id_machine << 24; + i = i + idprom.id_serial; + numtos((ulong_t)i, hw_serial); + } else + prom_printf("Invalid format code in IDprom.\n"); } /* - * Check for machine specific interrupt levels which cannot have interrupt - * handlers added. We allow levels 1 through 15; level 0 is nonsense. + * Allow for implementation specific correction of PROM property values. */ /*ARGSUSED*/ -int -exclude_level(int lvl) +void +impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len, + caddr_t buffer) { - return ((lvl < 1) || (lvl > 15)); + /* + * There are no adjustments needed in this implementation. + */ } /* -- cgit v1.2.3