/* * get_pcmu_properties * * This function is called from the attach routine to get the key * properties of the pci nodes. * * used by: pcmu_attach() * * return value: DDI_FAILURE on failure */ int get_pcmu_properties(pcmu_t *pcmu_p, dev_info_t *dip) { int i; /* * Get the device's port id. */ if ((pcmu_p->pcmu_id = (uint32_t)pcmu_get_portid(dip)) == -1u) { cmn_err(CE_WARN, "%s%d: no portid property\n", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } /* * Get the bus-ranges property. */ i = sizeof (pcmu_p->pcmu_bus_range); if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "bus-range", (caddr_t)&pcmu_p->pcmu_bus_range, &i) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: no bus-range property\n", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } PCMU_DBG2(PCMU_DBG_ATTACH, dip, "get_pcmu_properties: bus-range (%x,%x)\n", pcmu_p->pcmu_bus_range.lo, pcmu_p->pcmu_bus_range.hi); /* * Get the ranges property. */ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&pcmu_p->pcmu_ranges, &pcmu_p->pcmu_ranges_length) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: no ranges property\n", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } pcmu_fix_ranges(pcmu_p->pcmu_ranges, pcmu_p->pcmu_ranges_length / sizeof (pcmu_ranges_t)); /* * Determine the number upa slot interrupts. */ pcmu_p->pcmu_numproxy = pcmu_get_numproxy(pcmu_p->pcmu_dip); PCMU_DBG1(PCMU_DBG_ATTACH, dip, "get_pcmu_properties: numproxy=%d\n", pcmu_p->pcmu_numproxy); return (DDI_SUCCESS); }
/* * If the device is a PCI bus device (i.e bus-range property exists) then * claim the bus numbers used by the device from the specified bus * resource map. */ static int claim_pci_busnum(dev_info_t *dip, void *arg) { struct bus_range pci_bus_range; struct busnum_ctrl *ctrl; ndi_ra_request_t req; char bus_type[16] = "(unknown)"; int len; uint64_t base; uint64_t retlen; ctrl = (struct busnum_ctrl *)arg; /* check if this is a PCI bus node */ len = sizeof (bus_type); if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type", (caddr_t)&bus_type, &len) != DDI_SUCCESS) return (DDI_WALK_PRUNECHILD); /* it is not a pci/pci-ex bus type */ if ((strcmp(bus_type, "pci") != 0) && (strcmp(bus_type, "pciex") != 0)) return (DDI_WALK_PRUNECHILD); /* look for the bus-range property */ len = sizeof (struct bus_range); if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) { if ((pci_bus_range.lo >= ctrl->range->lo) && (pci_bus_range.hi <= ctrl->range->hi)) { /* claim the bus range from the bus resource map */ bzero((caddr_t)&req, sizeof (req)); req.ra_addr = (uint64_t)pci_bus_range.lo; req.ra_flags |= NDI_RA_ALLOC_SPECIFIED; req.ra_len = (uint64_t)pci_bus_range.hi - (uint64_t)pci_bus_range.lo + 1; if (ndi_ra_alloc(ctrl->dip, &req, &base, &retlen, NDI_RA_TYPE_PCI_BUSNUM, 0) == NDI_SUCCESS) return (DDI_WALK_PRUNECHILD); } } /* * Error return. */ ctrl->rv = DDI_FAILURE; return (DDI_WALK_TERMINATE); }
/* * Get boot property value for fastreboot_onpanic. * * NOTE: If fastreboot_onpanic is set to non-zero in /etc/system, * new setting passed in via "-B fastreboot_onpanic" is ignored. * This order of precedence is to enable developers debugging panics * that occur early in boot to utilize Fast Reboot on panic. */ static void fastboot_get_bootprop(void) { int val = 0xaa, len, ret; dev_info_t *devi; char *propstr = NULL; devi = ddi_root_node(); ret = ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, FASTREBOOT_ONPANIC, &propstr); if (ret == DDI_PROP_SUCCESS) { if (FASTREBOOT_ONPANIC_NOTSET(propstr)) val = 0; else if (FASTREBOOT_ONPANIC_ISSET(propstr)) val = UA_FASTREBOOT_ONPANIC; /* * Only set fastreboot_onpanic to the value passed in * if it's not already set to non-zero, and the value * has indeed been passed in via command line. */ if (!fastreboot_onpanic && val != 0xaa) fastreboot_onpanic = val; ddi_prop_free(propstr); } else if (ret != DDI_PROP_NOT_FOUND && ret != DDI_PROP_UNDEFINED) { cmn_err(CE_NOTE, "!%s value is invalid, will be ignored", FASTREBOOT_ONPANIC); } len = sizeof (fastreboot_onpanic_cmdline); ret = ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, FASTREBOOT_ONPANIC_CMDLINE, fastreboot_onpanic_cmdline, &len); if (ret == DDI_PROP_BUF_TOO_SMALL) cmn_err(CE_NOTE, "!%s value is too long, will be ignored", FASTREBOOT_ONPANIC_CMDLINE); }
/* * Setup resource map for the pci bus node based on the "available" * property and "bus-range" property. */ int pci_resource_setup(dev_info_t *dip) { pci_regspec_t *regs; int rlen, rcount, i; char bus_type[16] = "(unknown)"; int len; struct busnum_ctrl ctrl; int circular_count; int rval = NDI_SUCCESS; /* * If this is a pci bus node then look for "available" property * to find the available resources on this bus. */ len = sizeof (bus_type); if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "device_type", (caddr_t)&bus_type, &len) != DDI_SUCCESS) return (NDI_FAILURE); /* it is not a pci/pci-ex bus type */ if ((strcmp(bus_type, "pci") != 0) && (strcmp(bus_type, "pciex") != 0)) return (NDI_FAILURE); /* * The pci-hotplug project addresses adding the call * to pci_resource_setup from pci nexus driver. * However that project would initially be only for x86, * so for sparc pcmcia-pci support we still need to call * pci_resource_setup in pcic driver. Once all pci nexus drivers * are updated to call pci_resource_setup this portion of the * code would really become an assert to make sure this * function is not called for the same dip twice. */ { if (ra_map_exist(dip, NDI_RA_TYPE_MEM) == NDI_SUCCESS) { return (NDI_FAILURE); } } /* * Create empty resource maps first. * * NOTE: If all the allocated resources are already assigned to * device(s) in the hot plug slot then "available" property may not * be present. But, subsequent hot plug operation may unconfigure * the device in the slot and try to free up it's resources. So, * at the minimum we should create empty maps here. */ if (ndi_ra_map_setup(dip, NDI_RA_TYPE_MEM) == NDI_FAILURE) { return (NDI_FAILURE); } if (ndi_ra_map_setup(dip, NDI_RA_TYPE_IO) == NDI_FAILURE) { return (NDI_FAILURE); } if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM) == NDI_FAILURE) { return (NDI_FAILURE); } if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_PREFETCH_MEM) == NDI_FAILURE) { return (NDI_FAILURE); } /* read the "available" property if it is available */ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "available", (caddr_t)®s, &rlen) == DDI_SUCCESS) { /* * create the available resource list for both memory and * io space */ rcount = rlen / sizeof (pci_regspec_t); for (i = 0; i < rcount; i++) { switch (PCI_REG_ADDR_G(regs[i].pci_phys_hi)) { case PCI_REG_ADDR_G(PCI_ADDR_MEM32): (void) ndi_ra_free(dip, (uint64_t)regs[i].pci_phys_low, (uint64_t)regs[i].pci_size_low, (regs[i].pci_phys_hi & PCI_REG_PF_M) ? NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM, 0); break; case PCI_REG_ADDR_G(PCI_ADDR_MEM64): (void) ndi_ra_free(dip, ((uint64_t)(regs[i].pci_phys_mid) << 32) | ((uint64_t)(regs[i].pci_phys_low)), ((uint64_t)(regs[i].pci_size_hi) << 32) | ((uint64_t)(regs[i].pci_size_low)), (regs[i].pci_phys_hi & PCI_REG_PF_M) ? NDI_RA_TYPE_PCI_PREFETCH_MEM : NDI_RA_TYPE_MEM, 0); break; case PCI_REG_ADDR_G(PCI_ADDR_IO): (void) ndi_ra_free(dip, (uint64_t)regs[i].pci_phys_low, (uint64_t)regs[i].pci_size_low, NDI_RA_TYPE_IO, 0); break; case PCI_REG_ADDR_G(PCI_ADDR_CONFIG): break; default: cmn_err(CE_WARN, "pci_resource_setup: bad addr type: %x\n", PCI_REG_ADDR_G(regs[i].pci_phys_hi)); break; } } kmem_free((caddr_t)regs, rlen); } /* * update resource map for available bus numbers if the node * has available-bus-range or bus-range property. */ len = sizeof (struct bus_range); if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "available-bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) { /* * Add bus numbers in the range to the free list. */ (void) ndi_ra_free(dip, (uint64_t)pci_bus_range.lo, (uint64_t)pci_bus_range.hi - (uint64_t)pci_bus_range.lo + 1, NDI_RA_TYPE_PCI_BUSNUM, 0); } else { /* * We don't have an available-bus-range property. If, instead, * we have a bus-range property we add all the bus numbers * in that range to the free list but we must then scan * for pci-pci bridges on this bus to find out the if there * are any of those bus numbers already in use. If so, we can * reclaim them. */ len = sizeof (struct bus_range); if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) { if (pci_bus_range.lo != pci_bus_range.hi) { /* * Add bus numbers other than the secondary * bus number to the free list. */ (void) ndi_ra_free(dip, (uint64_t)pci_bus_range.lo + 1, (uint64_t)pci_bus_range.hi - (uint64_t)pci_bus_range.lo, NDI_RA_TYPE_PCI_BUSNUM, 0); /* scan for pci-pci bridges */ ctrl.rv = DDI_SUCCESS; ctrl.dip = dip; ctrl.range = &pci_bus_range; ndi_devi_enter(dip, &circular_count); ddi_walk_devs(ddi_get_child(dip), claim_pci_busnum, (void *)&ctrl); ndi_devi_exit(dip, circular_count); if (ctrl.rv != DDI_SUCCESS) { /* failed to create the map */ (void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_BUSNUM); rval = NDI_FAILURE; } } } } #ifdef BUSRA_DEBUG if (busra_debug) { (void) ra_dump_all(NULL, dip); } #endif return (rval); }
/*ARGSUSED*/ static int xen_uppc_translate_irq(dev_info_t *dip, int irqno) { char dev_type[16]; int dev_len, pci_irq, devid, busid; ddi_acc_handle_t cfg_handle; uchar_t ipin, iline; iflag_t intr_flag; if (dip == NULL) { XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: irqno = %d" " dip = NULL\n", irqno)); return (irqno); } if (!xen_uppc_enable_acpi) { return (irqno); } dev_len = sizeof (dev_type); if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ddi_get_parent(dip), DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type, &dev_len) != DDI_PROP_SUCCESS) { XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: irqno %d" " device %s instance %d no device_type\n", irqno, ddi_get_name(dip), ddi_get_instance(dip))); return (irqno); } if ((strcmp(dev_type, "pci") == 0) || (strcmp(dev_type, "pciex") == 0)) { /* pci device */ if (acpica_get_bdf(dip, &busid, &devid, NULL) != 0) return (irqno); if (pci_config_setup(dip, &cfg_handle) != DDI_SUCCESS) return (irqno); ipin = pci_config_get8(cfg_handle, PCI_CONF_IPIN) - PCI_INTA; iline = pci_config_get8(cfg_handle, PCI_CONF_ILINE); if (xen_uppc_acpi_translate_pci_irq(dip, busid, devid, ipin, &pci_irq, &intr_flag) == ACPI_PSM_SUCCESS) { XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: [ACPI] " "new irq %d old irq %d device %s, instance %d\n", pci_irq, irqno, ddi_get_name(dip), ddi_get_instance(dip))); /* * Make sure pci_irq is within range. * Otherwise, fall through and return irqno. */ if (pci_irq <= MAX_ISA_IRQ) { if (iline != pci_irq) { /* * Update the device's ILINE byte, * in case uppc_acpi_translate_pci_irq * has choosen a different pci_irq * than the BIOS has configured. * Some chipsets use the value in * ILINE to control interrupt routing, * in conflict with the PCI spec. */ pci_config_put8(cfg_handle, PCI_CONF_ILINE, pci_irq); } pci_config_teardown(&cfg_handle); return (pci_irq); } } pci_config_teardown(&cfg_handle); /* FALLTHRU to common case - returning irqno */ } else { /* non-PCI; assumes ISA-style edge-triggered */ psm_set_elcr(irqno, 0); /* set IRQ to ISA mode */ XEN_UPPC_VERBOSE_IRQ((CE_CONT, "!xVM_uppc: non-pci," "irqno %d device %s instance %d\n", irqno, ddi_get_name(dip), ddi_get_instance(dip))); } return (irqno); }