void pcmu_pbm_create(pcmu_t *pcmu_p) { pcmu_pbm_t *pcbm_p; int len; dev_info_t *dip = pcmu_p->pcmu_dip; /* * Allocate a state structure for the PBM and cross-link it * to its per pci node state structure. */ pcbm_p = (pcmu_pbm_t *)kmem_zalloc(sizeof (pcmu_pbm_t), KM_SLEEP); pcmu_p->pcmu_pcbm_p = pcbm_p; pcbm_p->pcbm_pcmu_p = pcmu_p; len = snprintf(pcbm_p->pcbm_nameinst_str, sizeof (pcbm_p->pcbm_nameinst_str), "%s%d", NAMEINST(dip)); pcbm_p->pcbm_nameaddr_str = pcbm_p->pcbm_nameinst_str + ++len; (void) snprintf(pcbm_p->pcbm_nameaddr_str, sizeof (pcbm_p->pcbm_nameinst_str) - len, "%s@%s", NAMEADDR(dip)); pcmu_pbm_setup(pcbm_p); PCMU_DBG4(PCMU_DBG_ATTACH, dip, "pcmu_pbm_create: ctrl=%x, afsr=%x, afar=%x, diag=%x\n", pcbm_p->pcbm_ctrl_reg, pcbm_p->pcbm_async_flt_status_reg, pcbm_p->pcbm_async_flt_addr_reg, pcbm_p->pcbm_diag_reg); PCMU_DBG1(PCMU_DBG_ATTACH, dip, "pcmu_pbm_create: conf=%x\n", pcbm_p->pcbm_config_header); /* * Register a function to disable pbm error interrupts during a panic. */ bus_func_register(BF_TYPE_ERRDIS, (busfunc_t)pcmu_pbm_disable_errors, pcbm_p); /* * create the interrupt-priorities property if it doesn't * already exist to provide a hint as to the PIL level for * our interrupt. */ if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "interrupt-priorities", &len) != DDI_PROP_SUCCESS) { /* Create the interrupt-priorities property. */ (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "interrupt-priorities", (caddr_t)pcmu_pil, sizeof (pcmu_pil)); } pcmu_pbm_configure(pcbm_p); }
static int ppb_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result) { dev_info_t *cdip = rdip; pci_regspec_t *pci_rp; int reglen, len; uint32_t d, intr; if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) || (hdlp->ih_type != DDI_INTR_TYPE_FIXED)) goto done; /* * If the interrupt-map property is defined at this * node, it will have performed the interrupt * translation as part of the property, so no * rotation needs to be done. */ if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "interrupt-map", &len) == DDI_PROP_SUCCESS) goto done; cdip = get_my_childs_dip(dip, rdip); /* * Use the devices reg property to determine its * PCI bus number and device number. */ if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, ®len) != DDI_SUCCESS) return (DDI_FAILURE); intr = hdlp->ih_vector; /* Spin the interrupt */ d = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi); if ((intr >= PCI_INTA) && (intr <= PCI_INTD)) hdlp->ih_vector = ((intr - 1 + (d % 4)) % 4 + 1); else cmn_err(CE_WARN, "%s%d: %s: PCI intr=%x out of range", ddi_driver_name(rdip), ddi_get_instance(rdip), ddi_driver_name(dip), intr); kmem_free(pci_rp, reglen); done: /* Pass up the request to our parent. */ return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result)); }
/*ARGSUSED*/ static int fco_getproplen(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) { int proplen; int flags = 0; fc_phandle_t h; dev_info_t *dip; char *pnp; char propname[OBP_MAXPROPNAME]; if (strstr(fc_cell2ptr(cp->svc_name), "inherited") == NULL) flags |= DDI_PROP_DONTPASS; if (fc_cell2int(cp->nargs) != 2) return (fc_syntax_error(cp, "nargs must be 2")); if (fc_cell2int(cp->nresults) < 1) return (fc_syntax_error(cp, "nresults must be > 0")); /* * Make sure this is a handle we gave out ... */ h = fc_cell2phandle(fc_arg(cp, 0)); if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL) return (fc_priv_error(cp, "unknown handle")); /* * XXX: We should care if the string is longer than OBP_MAXPROPNAME */ pnp = fc_cell2ptr(fc_arg(cp, 1)); bzero(propname, OBP_MAXPROPNAME); if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL)) return (fc_priv_error(cp, "EFAULT copying in propname")); if (ddi_getproplen(DDI_DEV_T_ANY, dip, flags, propname, &proplen)) proplen = -1; fc_result(cp, 0) = fc_int2cell(proplen); cp->nresults = fc_int2cell(1); return (fc_success_op(ap, rp, cp)); }
/* * If we don't already have a master SBBC selected, * get the <sbbc> property from the /chosen node. If * the pathname matches, this is the master SBBC and * we set up the console/TOD SRAM mapping here. */ static void sbbc_chosen_init(sbbc_softstate_t *softsp) { char master_sbbc[MAXNAMELEN]; char pn[MAXNAMELEN]; int nodeid, len; pnode_t dnode; if (master_chosen != FALSE) { /* * We've got one already */ return; } /* * Get /chosen node info. prom interface will handle errors. */ dnode = prom_chosennode(); /* * Look for the "iosram" property on the chosen node with a prom * interface as ddi_find_devinfo() couldn't be used (calls * ddi_walk_devs() that creates one extra lock on the device tree). */ if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) { /* * No I/O Board SBBC set up as console, what to do ? */ SBBC_ERR(CE_PANIC, "No SBBC found for Console/TOD \n"); } if (prom_getprop(dnode, IOSRAM_TOC_PROP, (caddr_t)&softsp->sram_toc) <= 0) { /* * SRAM TOC Offset defaults to 0 */ SBBC_ERR(CE_WARN, "No SBBC TOC Offset found\n"); softsp->sram_toc = 0; } /* * get the full OBP pathname of this node */ if (prom_phandle_to_path((phandle_t)nodeid, master_sbbc, sizeof (master_sbbc)) < 0) { SBBC_ERR1(CE_PANIC, "prom_phandle_to_path(%d) failed\n", nodeid); } SGSBBC_DBG_ALL("chosen pathname : %s\n", master_sbbc); SGSBBC_DBG_ALL("device pathname : %s\n", ddi_pathname(softsp->dip, pn)); if (strcmp(master_sbbc, ddi_pathname(softsp->dip, pn)) == 0) { /* * map in the SBBC regs */ if (sbbc_map_regs(softsp) != DDI_SUCCESS) { SBBC_ERR(CE_PANIC, "Can't map the SBBC regs \n"); } /* * Only the 'chosen' node is used for iosram_read()/_write() * Must initialise the tunnel before the console/tod * */ if (iosram_tunnel_init(softsp) == DDI_FAILURE) { SBBC_ERR(CE_PANIC, "Can't create the SRAM <-> SC " "comm. tunnel \n"); } master_chosen = TRUE; /* * Verify that an 'interrupts' property * exists for this device */ if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip, DDI_PROP_DONTPASS, "interrupts", &len) != DDI_PROP_SUCCESS) { SBBC_ERR(CE_PANIC, "No 'interrupts' property for the " "'chosen' SBBC \n"); } /* * add the interrupt handler * NB * should this be a high-level interrupt ? * NB */ if (sbbc_add_intr(softsp) == DDI_FAILURE) { SBBC_ERR(CE_PANIC, "Can't add interrupt handler for " "'chosen' SBBC \n"); } sbbc_enable_intr(softsp); /* * Create the mailbox */ if (sbbc_mbox_create(softsp) != 0) { cmn_err(CE_WARN, "No IOSRAM MailBox created!\n"); } } }
static int sbbc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) { int instance; sbbc_softstate_t *softsp; uint32_t *pci_intr_enable_reg; int len; #ifdef DEBUG char name[8]; #endif /* DEBUG */ instance = ddi_get_instance(devi); switch (cmd) { case DDI_ATTACH: if (ddi_soft_state_zalloc(sbbcp, instance) != 0) return (DDI_FAILURE); softsp = ddi_get_soft_state(sbbcp, instance); softsp->sbbc_instance = instance; /* * Set the dip in the soft state * And get interrupt cookies and initialize the * per instance mutex. */ softsp_init(softsp, devi); /* * Verify that an 'interrupts' property exists for * this device. If not, this instance will be ignored. */ if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip, DDI_PROP_DONTPASS, "interrupts", &len) != DDI_PROP_SUCCESS) { SBBC_ERR1(CE_WARN, "No 'interrupts' property for the " "SBBC instance %d\n", instance); return (DDI_FAILURE); } /* * Add this instance to the sbbc chosen iosram list * so that it can be used for tunnel switch. */ mutex_enter(&chosen_lock); softsp->sbbc_state = SBBC_STATE_INIT; sbbc_add_instance(softsp); /* * If this is the chosen IOSRAM and there is no master IOSRAM * yet, then let's set this instance as the master. * if there is a master alreay due to the previous tunnel switch * then keep as is even though this is the chosen. */ if (sgsbbc_iosram_is_chosen(softsp)) { ASSERT(master_iosram); softsp->iosram = master_iosram; master_iosram->sgsbbc = softsp; /* Do 'chosen' init only */ sbbc_chosen_init(softsp); } mutex_exit(&chosen_lock); #ifdef DEBUG (void) sprintf(name, "sbbc%d", instance); if (ddi_create_minor_node(devi, name, S_IFCHR, instance, NULL, NULL) == DDI_FAILURE) { mutex_destroy(&softsp->sbbc_lock); ddi_remove_minor_node(devi, NULL); ddi_soft_state_free(sbbcp, instance); return (DDI_FAILURE); } #endif /* DEBUG */ ddi_report_dev(devi); return (DDI_SUCCESS); case DDI_RESUME: if (!(softsp = ddi_get_soft_state(sbbcp, instance))) return (DDI_FAILURE); mutex_enter(&softsp->sbbc_lock); if ((softsp->suspended == TRUE) && (softsp->chosen == TRUE)) { /* * Enable Interrupts now, turn on both INT#A lines */ pci_intr_enable_reg = (uint32_t *) ((char *)softsp->sbbc_regs + SBBC_PCI_INT_ENABLE); ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, (uint32_t)SBBC_PCI_ENABLE_INT_A); /* * Reset intr_in_enabled to the original value * so the SC can send us interrupt. */ if (iosram_write(SBBC_SC_INTR_ENABLED_KEY, 0, (caddr_t)&intr_in_enabled, sizeof (intr_in_enabled))) { mutex_exit(&softsp->sbbc_lock); return (DDI_FAILURE); } } softsp->suspended = FALSE; mutex_exit(&softsp->sbbc_lock); return (DDI_SUCCESS); default: return (DDI_FAILURE); } }