/*ARGSUSED*/ static void ppb_init_hotplug(ppb_devstate_t *ppb) { ppb->hotplug_capable = B_FALSE; if (ddi_prop_exists(DDI_DEV_T_ANY, ppb->dip, DDI_PROP_DONTPASS, "hotplug-capable")) { (void) modload("misc", "pcihp"); if (pcihp_init(ppb->dip) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s #%d: Failed setting hotplug framework", ddi_driver_name(ppb->dip), ddi_get_instance(ppb->dip)); } else ppb->hotplug_capable = B_TRUE; } if (ppb->hotplug_capable == B_FALSE) { /* * create minor node for devctl interfaces */ if (ddi_create_minor_node(ppb->dip, "devctl", S_IFCHR, PCI_MINOR_NUM(ddi_get_instance(ppb->dip), PCI_DEVCTL_MINOR), DDI_NT_NEXUS, 0) != DDI_SUCCESS) cmn_err(CE_WARN, "%s #%d: Failed to create a minor node", ddi_driver_name(ppb->dip), ddi_get_instance(ppb->dip)); } }
static int vboxUSBMonSolarisResetDevice(char *pszDevicePath, bool fReattach) { int rc = VERR_GENERAL_FAILURE; LogFunc((DEVICE_NAME ": vboxUSBMonSolarisResetDevice: pszDevicePath=%s fReattach=%d\n", pszDevicePath, fReattach)); /* * Try grabbing the dev_info_t. */ dev_info_t *pDeviceInfo = e_ddi_hold_devi_by_path(pszDevicePath, 0); if (pDeviceInfo) { ddi_release_devi(pDeviceInfo); /* * Grab the root device node from the parent hub for resetting. */ dev_info_t *pTmpDeviceInfo = NULL; for (;;) { pTmpDeviceInfo = ddi_get_parent(pDeviceInfo); if (!pTmpDeviceInfo) { LogRel((DEVICE_NAME ":vboxUSBMonSolarisResetDevice: Failed to get parent device info for %s\n", pszDevicePath)); return VERR_GENERAL_FAILURE; } if (ddi_prop_exists(DDI_DEV_T_ANY, pTmpDeviceInfo, DDI_PROP_DONTPASS, "usb-port-count")) /* parent hub */ break; pDeviceInfo = pTmpDeviceInfo; } /* * Try re-enumerating the device. */ rc = usb_reset_device(pDeviceInfo, fReattach ? USB_RESET_LVL_REATTACH : USB_RESET_LVL_DEFAULT); Log((DEVICE_NAME ": vboxUSBMonSolarisResetDevice: usb_reset_device for %s level=%s rc=%d\n", pszDevicePath, fReattach ? "ReAttach" : "Default", rc)); switch (rc) { case USB_SUCCESS: rc = VINF_SUCCESS; break; case USB_INVALID_PERM: rc = VERR_PERMISSION_DENIED; break; case USB_INVALID_ARGS: rc = VERR_INVALID_PARAMETER; break; case USB_BUSY: rc = VERR_RESOURCE_BUSY; break; case USB_INVALID_CONTEXT: rc = VERR_INVALID_CONTEXT; break; case USB_FAILURE: rc = VERR_GENERAL_FAILURE; break; default: rc = VERR_UNRESOLVED_ERROR; break; } } else { rc = VERR_INVALID_HANDLE; LogRel((DEVICE_NAME ": vboxUSBMonSolarisResetDevice: Cannot obtain device info for %s\n", pszDevicePath)); } return rc; }
static int pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags, char *name, caddr_t valuep, int *lengthp) { if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "hotplug-capable")) return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); }
void reset(void) { extern void acpi_reset_system(); #if !defined(__xpv) ushort_t *bios_memchk; /* * Can't use psm_map_phys or acpi_reset_system before the hat is * initialized. */ if (khat_running) { bios_memchk = (ushort_t *)psm_map_phys(0x472, sizeof (ushort_t), PROT_READ | PROT_WRITE); if (bios_memchk) *bios_memchk = 0x1234; /* bios memory check disable */ if (options_dip != NULL && ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), 0, "efi-systab")) { if (bootops == NULL) acpi_reset_system(); efi_reset(); } /* * The problem with using stubs is that we can call * acpi_reset_system only after the kernel is up and running. * * We should create a global state to keep track of how far * up the kernel is but for the time being we will depend on * bootops. bootops cleared in startup_end(). */ if (bootops == NULL) acpi_reset_system(); } pc_reset(); #else if (IN_XPV_PANIC()) { if (khat_running && bootops == NULL) { acpi_reset_system(); } pc_reset(); } (void) HYPERVISOR_shutdown(SHUTDOWN_reboot); panic("HYPERVISOR_shutdown() failed"); #endif /*NOTREACHED*/ }
void pcmu_child_cfg_save(dev_info_t *dip) { dev_info_t *cdip; int ret = DDI_SUCCESS; /* * Save the state of the configuration headers of child * nodes. */ for (cdip = ddi_get_child(dip); cdip != NULL; cdip = ddi_get_next_sibling(cdip)) { /* * Not interested in children who are not already * init'ed. They will be set up in pcmu_init_child(). */ if (i_ddi_node_state(cdip) < DS_INITIALIZED) { PCMU_DBG2(PCMU_DBG_DETACH, dip, "DDI_SUSPEND: skipping " "%s%d not in CF1\n", ddi_driver_name(cdip), ddi_get_instance(cdip)); continue; } /* * Only save config registers if not already saved by child. */ if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, SAVED_CONFIG_REGS) == 1) { continue; } /* * The nexus needs to save config registers. Create a property * so it knows to restore on resume. */ ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "nexus-saved-config-regs"); if (ret != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d can't update prop %s", ddi_driver_name(cdip), ddi_get_instance(cdip), "nexus-saved-config-regs"); } (void) pci_save_config_regs(cdip); } }
void pcmu_child_cfg_restore(dev_info_t *dip) { dev_info_t *cdip; /* * Restore config registers for children that did not save * their own registers. Children pwr states are UNKNOWN after * a resume since it is possible for the PM framework to call * resume without an actual power cycle. (ie if suspend fails). */ for (cdip = ddi_get_child(dip); cdip != NULL; cdip = ddi_get_next_sibling(cdip)) { /* * Not interested in children who are not already * init'ed. They will be set up by pcmu_init_child(). */ if (i_ddi_node_state(cdip) < DS_INITIALIZED) { PCMU_DBG2(PCMU_DBG_DETACH, dip, "DDI_RESUME: skipping %s%d not in CF1\n", ddi_driver_name(cdip), ddi_get_instance(cdip)); continue; } /* * Only restore config registers if saved by nexus. */ if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "nexus-saved-config-regs") == 1) { (void) pci_restore_config_regs(cdip); PCMU_DBG2(PCMU_DBG_PWR, dip, "DDI_RESUME: nexus restoring %s%d config regs\n", ddi_driver_name(cdip), ddi_get_instance(cdip)); if (ndi_prop_remove(DDI_DEV_T_NONE, cdip, "nexus-saved-config-regs") != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d can't remove prop %s", ddi_driver_name(cdip), ddi_get_instance(cdip), "nexus-saved-config-regs"); } } } }
/* * power management related initialization specific to px * called by px_attach() */ static int px_pwr_setup(dev_info_t *dip) { pcie_pwr_t *pwr_p; int instance = ddi_get_instance(dip); px_t *px_p = INST_TO_STATE(instance); ddi_intr_handle_impl_t hdl; ASSERT(PCIE_PMINFO(dip)); pwr_p = PCIE_NEXUS_PMINFO(dip); ASSERT(pwr_p); /* * indicate support LDI (Layered Driver Interface) * Create the property, if it is not already there */ if (!ddi_prop_exists(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, DDI_KERNEL_IOCTL)) { if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0) != DDI_PROP_SUCCESS) { DBG(DBG_PWR, dip, "can't create kernel ioctl prop\n"); return (DDI_FAILURE); } } /* No support for device PM. We are always at full power */ pwr_p->pwr_func_lvl = PM_LEVEL_D0; mutex_init(&px_p->px_l23ready_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(px_pwr_pil)); cv_init(&px_p->px_l23ready_cv, NULL, CV_DRIVER, NULL); /* Initialize handle */ bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); hdl.ih_cb_arg1 = px_p; hdl.ih_ver = DDI_INTR_VERSION; hdl.ih_state = DDI_IHDL_STATE_ALLOC; hdl.ih_dip = dip; hdl.ih_pri = px_pwr_pil; /* Add PME_TO_ACK message handler */ hdl.ih_cb_func = (ddi_intr_handler_t *)px_pmeq_intr; if (px_add_msiq_intr(dip, dip, &hdl, MSG_REC, (msgcode_t)PCIE_PME_ACK_MSG, -1, &px_p->px_pm_msiq_id) != DDI_SUCCESS) { DBG(DBG_PWR, dip, "px_pwr_setup: couldn't add " " PME_TO_ACK intr\n"); goto pwr_setup_err1; } px_lib_msg_setmsiq(dip, PCIE_PME_ACK_MSG, px_p->px_pm_msiq_id); px_lib_msg_setvalid(dip, PCIE_PME_ACK_MSG, PCIE_MSG_VALID); if (px_ib_update_intr_state(px_p, px_p->px_dip, hdl.ih_inum, px_msiqid_to_devino(px_p, px_p->px_pm_msiq_id), px_pwr_pil, PX_INTR_STATE_ENABLE, MSG_REC, PCIE_PME_ACK_MSG) != DDI_SUCCESS) { DBG(DBG_PWR, dip, "px_pwr_setup: PME_TO_ACK update interrupt" " state failed\n"); goto px_pwrsetup_err_state; } return (DDI_SUCCESS); px_pwrsetup_err_state: px_lib_msg_setvalid(dip, PCIE_PME_ACK_MSG, PCIE_MSG_INVALID); (void) px_rem_msiq_intr(dip, dip, &hdl, MSG_REC, PCIE_PME_ACK_MSG, px_p->px_pm_msiq_id); pwr_setup_err1: mutex_destroy(&px_p->px_l23ready_lock); cv_destroy(&px_p->px_l23ready_cv); return (DDI_FAILURE); }
/* * Controller specific initialization */ uint_t sil3xxx_init_controller(dev_info_t *dip, /* LINTED */ ushort_t vendor_id, ushort_t device_id) { ddi_acc_handle_t pci_conf_handle; /* pci config space handle */ uint8_t cache_lnsz, frrc = 0; uint32_t fifo_cnt_ctl; int ports, i; #ifdef DEBUG /* LINTED */ ushort_t sfiscfg_val; #endif /* * Sil3114, Sil3512, Sil3112 * We want to perform this initialization only once per entire * pciide controller (all channels) */ if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_get_parent(dip), DDI_PROP_DONTPASS, "sil3xxx-initialized")) { return (TRUE); } if (pci_config_setup(ddi_get_parent(dip), &pci_conf_handle) != DDI_SUCCESS) { cmn_err(CE_WARN, "sil3xxx_init_controller: Can't do pci_config_setup\n"); return (FALSE); } /* * Sil3114/3512/3112 incorrectly change between MR and back to * MRM for same transaction, which violates the PCI spec and can * lead to incorrect data reads. The workaround * is to set bits 2:0 in the FIFO count and control register so * that its value, a multiple of 32 bytes starting at 32, not 0, * is greater or equal to the cacheline size, a multiple of 4 * bytes. This will prevent any reads until the FIFO free space * is greater than a cacheline size, ensuring only MRM is issued. */ cache_lnsz = pci_config_get8(pci_conf_handle, PCI_CONF_CACHE_LINESZ); /* * The cache line is specified in 32-bit words, so multiply by 4 * to get bytes. Then divide by 32 bytes, the granularity of the * FIFO control bits 2:0. Add 1 if there is any remainder to * account for a partial 32-byte block, then subtract 1 since for * FIFO controls bits 2:0, 0 corresponds to 32, 1 corresponds to * 64, and so on. The calculation is expanded for clarity. */ if (cache_lnsz != 0) { frrc = (cache_lnsz * 4 / 32) + (((cache_lnsz * 4) % 32) ? 1 : 0) - 1; } if (device_id == SIL3114_DEVICE_ID) { ports = 4; } else { ports = 2; } /* * The following BAR5 registers are accessed via an indirect register * in the PCI configuration space rather than mapping BAR5. */ for (i = 0; i < ports; i++) { GET_BAR5_INDIRECT(pci_conf_handle, fifocntctl[i], fifo_cnt_ctl); fifo_cnt_ctl = (fifo_cnt_ctl & ~0x7) | (frrc & 0x7); PUT_BAR5_INDIRECT(pci_conf_handle, fifocntctl[i], fifo_cnt_ctl); /* * Correct default setting for FIS0cfg */ #ifdef DEBUG GET_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i], sfiscfg_val); ADBG_WARN(("sil3xxx_init_controller: old val SFISCfg " "ch%d: %x\n", i, sfiscfg_val)); #endif PUT_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i], SFISCFG_ERRATA); #ifdef DEBUG GET_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i], sfiscfg_val); ADBG_WARN(("sil3xxx_init_controller: new val SFISCfg " "ch%d: %x\n", i, sfiscfg_val)); #endif } /* Now tear down the pci config setup */ pci_config_teardown(&pci_conf_handle); /* Create property indicating that initialization was done */ (void) ddi_prop_update_int(DDI_DEV_T_NONE, ddi_get_parent(dip), "sil3xxx-initialized", 1); return (TRUE); }
static int _raw_get_bsize(dev_t dev, uint64_t *bsizep, int *partitionp) { #ifdef DKIOCPARTITION struct partition64 *p64 = NULL; #endif struct dk_cinfo *dki_info = NULL; struct dev_ops *ops; struct cred *cred; struct vtoc *vtoc = NULL; dev_info_t *dip; raw_dev_t *cdi; int rc, cd; int flags; int rval; *partitionp = -1; *bsizep = 0; if ((cd = __raw_get_cd(dev)) == -1 || !_nsc_raw_files[cd].in_use) return (-1); cdi = &_nsc_raw_files[cd]; ops = cdi->major->devops; if (ops == NULL) { return (-1); } rc = (*ops->devo_getinfo)(NULL, DDI_INFO_DEVT2DEVINFO, (void *)dev, (void **)&dip); if (rc != DDI_SUCCESS || dip == NULL) { return (-1); } if (!ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, DDI_KERNEL_IOCTL)) { return (-1); } cred = ddi_get_cred(); flags = FKIOCTL | FREAD | FWRITE | DATAMODEL_NATIVE; dki_info = kmem_alloc(sizeof (*dki_info), KM_SLEEP); /* DKIOCINFO */ rc = (*cdi->major->ioctl)(dev, DKIOCINFO, (intptr_t)dki_info, flags, cred, &rval); if (rc != 0) { goto out; } /* return partition number */ *partitionp = (int)dki_info->dki_partition; vtoc = kmem_alloc(sizeof (*vtoc), KM_SLEEP); /* DKIOCGVTOC */ rc = (*cdi->major->ioctl)(dev, DKIOCGVTOC, (intptr_t)vtoc, flags, cred, &rval); if (rc) { /* DKIOCGVTOC failed, but there might be an EFI label */ rc = -1; #ifdef DKIOCPARTITION /* do we have an EFI partition table? */ p64 = kmem_alloc(sizeof (*p64), KM_SLEEP); p64->p_partno = (uint_t)*partitionp; /* DKIOCPARTITION */ rc = (*cdi->major->ioctl)(dev, DKIOCPARTITION, (intptr_t)p64, flags, cred, &rval); if (rc == 0) { /* found EFI, return size */ *bsizep = (uint64_t)p64->p_size; } else { /* both DKIOCGVTOC and DKIOCPARTITION failed - error */ rc = -1; } #endif goto out; } if ((vtoc->v_sanity != VTOC_SANE) || (vtoc->v_version != V_VERSION && vtoc->v_version != 0) || (dki_info->dki_partition > V_NUMPAR)) { rc = -1; goto out; } *bsizep = (uint64_t)vtoc->v_part[(int)dki_info->dki_partition].p_size; rc = 0; out: if (dki_info) { kmem_free(dki_info, sizeof (*dki_info)); } if (vtoc) { kmem_free(vtoc, sizeof (*vtoc)); } #ifdef DKIOCPARTITION if (p64) { kmem_free(p64, sizeof (*p64)); } #endif return (rc); }
static int gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) { int instance = ddi_get_instance(devi); struct dstate *dstatep; int rval; int n_devs; int n_minorcomps; int isclone; ddi_eventcookie_t dev_offline_cookie, dev_reset_cookie; ddi_eventcookie_t bus_reset_cookie, bus_quiesce_cookie; ddi_eventcookie_t bus_unquiesce_cookie, bus_test_post_cookie; int i_init = 0; int level_tmp; int i; char *pm_comp[] = { "NAME=leaf0", "0=D0", "1=D1", "2=D2", "3=D3", "NAME=leaf1", "0=off", "1=blank", "2=on"}; char *pm_hw_state = {"needs-suspend-resume"}; switch (cmd) { case DDI_ATTACH: if (ddi_soft_state_zalloc(dstates, instance) != DDI_SUCCESS) { cmn_err(CE_CONT, "%s%d: can't allocate state\n", ddi_get_name(devi), instance); return (DDI_FAILURE); } dstatep = ddi_get_soft_state(dstates, instance); dstatep->dip = devi; mutex_init(&dstatep->lock, NULL, MUTEX_DRIVER, NULL); n_devs = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, "ndevs", 1); isclone = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, "isclone", 0); n_minorcomps = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, "ncomps", 1); GEN_DEBUG((CE_CONT, "%s%d attaching: n_devs=%d n_minorcomps=%d isclone=%d", ddi_get_name(devi), ddi_get_instance(devi), n_devs, n_minorcomps, isclone)); if (isclone) { if (ddi_create_minor_node(devi, "gen", S_IFCHR, INST_TO_MINOR(instance), mnodetypes[0], isclone) != DDI_SUCCESS) { ddi_remove_minor_node(devi, NULL); ddi_soft_state_free(dstates, instance); cmn_err(CE_WARN, "%s%d: can't create minor " "node", ddi_get_name(devi), instance); return (DDI_FAILURE); } rval = DDI_SUCCESS; } else { rval = gen_create_minor_nodes(devi, dstatep); if (rval != DDI_SUCCESS) { ddi_prop_remove_all(devi); ddi_remove_minor_node(devi, NULL); ddi_soft_state_free(dstates, instance); cmn_err(CE_WARN, "%s%d: can't create minor " "nodes", ddi_get_name(devi), instance); return (DDI_FAILURE); } } if (ddi_get_eventcookie(devi, "pshot_dev_offline", &dev_offline_cookie) == DDI_SUCCESS) { (void) ddi_add_event_handler(devi, dev_offline_cookie, gen_event_cb, NULL, &(dstatep->gen_cb_ids[0])); } if (ddi_get_eventcookie(devi, "pshot_dev_reset", &dev_reset_cookie) == DDI_SUCCESS) { (void) ddi_add_event_handler(devi, dev_reset_cookie, gen_event_cb, NULL, &(dstatep->gen_cb_ids[1])); } if (ddi_get_eventcookie(devi, "pshot_bus_reset", &bus_reset_cookie) == DDI_SUCCESS) { (void) ddi_add_event_handler(devi, bus_reset_cookie, gen_event_cb, NULL, &(dstatep->gen_cb_ids[2])); } if (ddi_get_eventcookie(devi, "pshot_bus_quiesce", &bus_quiesce_cookie) == DDI_SUCCESS) { (void) ddi_add_event_handler(devi, bus_quiesce_cookie, gen_event_cb, NULL, &(dstatep->gen_cb_ids[3])); } if (ddi_get_eventcookie(devi, "pshot_bus_unquiesce", &bus_unquiesce_cookie) == DDI_SUCCESS) { (void) ddi_add_event_handler(devi, bus_unquiesce_cookie, gen_event_cb, NULL, &(dstatep->gen_cb_ids[4])); } if (ddi_get_eventcookie(devi, "pshot_bus_test_post", &bus_test_post_cookie) == DDI_SUCCESS) { (void) ddi_add_event_handler(devi, bus_test_post_cookie, gen_event_cb, NULL, &(dstatep->gen_cb_ids[5])); } /* * initialize the devices' pm state */ mutex_enter(&dstatep->lock); dstatep->flag &= ~OPEN_FLAG; dstatep->flag &= ~PWR_HAS_CHANGED_ON_RESUME_FLAG; dstatep->flag &= ~FAIL_SUSPEND_FLAG; dstatep->flag &= ~PUP_WITH_PWR_HAS_CHANGED_FLAG; dstatep->flag |= LOWER_POWER_FLAG; dstatep->flag &= ~NO_INVOL_FLAG; dstatep->flag |= PM_SUPPORTED_FLAG; dstatep->busy[0] = 0; dstatep->busy[1] = 0; dstatep->level[0] = -1; dstatep->level[1] = -1; mutex_exit(&dstatep->lock); /* * stash the nodename */ dstatep->nodename = ddi_node_name(devi); /* * Check if the no-involuntary-power-cycles property * was created. Set NO_INVOL_FLAG if so. */ if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip, (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), "no-involuntary-power-cycles") == 1) { GEN_DEBUG((CE_CONT, "%s%d: DDI_ATTACH:\n\tno-involuntary-power-cycles" " property was created", ddi_node_name(devi), ddi_get_instance(devi))); mutex_enter(&dstatep->lock); dstatep->flag |= NO_INVOL_FLAG; mutex_exit(&dstatep->lock); } /* * Check if the dependency-property property * was created. */ if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip, (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), "dependency-property") == 1) { GEN_DEBUG((CE_CONT, "%s%d: DDI_ATTACH:\n\tdependency-property" " property was created", ddi_node_name(devi), ddi_get_instance(devi))); } /* * create the pm-components property. two comps: * 4 levels on comp0, 3 on comp 1. * - skip for a "tape" device, clear PM_SUPPORTED_FLAG */ if (strcmp(ddi_node_name(devi), "tape") != 0) { if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi, "pm-components", pm_comp, 9) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d: %s\n", ddi_node_name(devi), ddi_get_instance(devi), "unable to create \"pm-components\" " " property."); return (DDI_FAILURE); } } else { mutex_enter(&dstatep->lock); dstatep->flag &= ~PM_SUPPORTED_FLAG; mutex_exit(&dstatep->lock); } /* * Check if the pm-components property was created */ if (dstatep->flag & PM_SUPPORTED_FLAG) { if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip, (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), "pm-components") != 1) { cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t%s", ddi_node_name(devi), ddi_get_instance(devi), "\"pm-components\" property does" " not exist"); return (DDI_FAILURE); } else { GEN_DEBUG((CE_CONT, "%s%d: DDI_ATTACH:" " created pm-components property", ddi_node_name(devi), ddi_get_instance(devi))); } } /* * create the pm-hardware-state property. * needed to get DDI_SUSPEND and DDI_RESUME calls */ if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t%s\n", ddi_node_name(devi), ddi_get_instance(devi), "unable to create \"pm-hardware-state\" " " property."); return (DDI_FAILURE); } /* * set power levels to max via pm_raise_power(), */ mutex_enter(&dstatep->lock); i_init = (dstatep->flag & PM_SUPPORTED_FLAG) ? 0 : COMPONENTS; mutex_exit(&dstatep->lock); for (i = i_init; i < COMPONENTS; i++) { GEN_DEBUG((CE_CONT, "%s%d: DDI_ATTACH: pm_raise_power comp %d " "to level %d", ddi_node_name(devi), ddi_get_instance(devi), i, maxpwr[i])); if (pm_raise_power(dstatep->dip, i, maxpwr[i]) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: DDI_ATTACH: pm_raise_power failed\n", ddi_node_name(devi), ddi_get_instance(devi)); dstatep->level[i] = -1; return (DDI_FAILURE); } } if (rval == DDI_SUCCESS) { ddi_report_dev(devi); } return (rval); case DDI_RESUME: GEN_DEBUG((CE_CONT, "%s%d: DDI_RESUME", ddi_node_name(devi), ddi_get_instance(devi))); dstatep = ddi_get_soft_state(dstates, ddi_get_instance(devi)); if (dstatep == NULL) { return (DDI_FAILURE); } /* * Call pm_power_has_changed() if flag * PWR_HAS_CHANGED_ON_RESUME_FLAG is set, * then clear the flag */ mutex_enter(&dstatep->lock); i_init = (dstatep->flag & PM_SUPPORTED_FLAG) ? 0 : COMPONENTS; mutex_exit(&dstatep->lock); if (dstatep->flag & PWR_HAS_CHANGED_ON_RESUME_FLAG) { for (i = i_init; i < COMPONENTS; i++) { GEN_DEBUG((CE_CONT, "%s%d: DDI_RESUME: pm_power_has_changed " "comp %d to level %d", ddi_node_name(devi), ddi_get_instance(devi), i, maxpwr[i])); mutex_enter(&dstatep->lock); level_tmp = dstatep->level[i]; dstatep->level[i] = maxpwr[i]; if (pm_power_has_changed(dstatep->dip, i, maxpwr[i]) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: DDI_RESUME:\n\t" " pm_power_has_changed" " failed: comp %d to level %d\n", ddi_node_name(devi), ddi_get_instance(devi), i, maxpwr[i]); dstatep->level[i] = level_tmp; } mutex_exit(&dstatep->lock); } } else { /* * Call pm_raise_power() instead */ for (i = i_init; i < COMPONENTS; i++) { GEN_DEBUG((CE_CONT, "%s%d: DDI_RESUME: pm_raise_power" " comp %d to level %d", ddi_node_name(devi), ddi_get_instance(devi), i, maxpwr[i])); if (pm_raise_power(dstatep->dip, i, maxpwr[i]) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: DDI_RESUME:" "\n\tpm_raise_power" "failed: comp %d to level %d\n", ddi_node_name(devi), ddi_get_instance(devi), i, maxpwr[i]); } } } return (DDI_SUCCESS); default: GEN_DEBUG((CE_WARN, "attach: default")); return (DDI_FAILURE); } }
/* * Find the BIOS date, and return TRUE if supplied * date is same or later than the BIOS date, or FALSE * if the BIOS date can't be fetched for any reason */ static int acpica_check_bios_date(int yy, int mm, int dd) { char *datep; int bios_year, bios_month, bios_day; /* If firmware has no bios, skip the check */ if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS, "efi-systab")) return (TRUE); /* * PC BIOSes contain a string in the form of * "mm/dd/yy" at absolute address 0xffff5, * where mm, dd and yy are all ASCII digits. * We map the string, pluck out the values, * and accept all BIOSes from 1 Jan 1999 on * as valid. */ if ((datep = (char *)AcpiOsMapMemory(0xffff5, 8)) == NULL) return (FALSE); /* year */ bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0'); /* month */ bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0'); /* day */ bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0'); AcpiOsUnmapMemory((void *) datep, 8); if (bios_year < 0 || bios_year > 99 || bios_month < 0 || bios_month > 99 || bios_day < 0 || bios_day > 99) { /* non-digit chars in BIOS date */ return (FALSE); } /* * Adjust for 2-digit year; note to grand-children: * need a new scheme before 2080 rolls around */ bios_year += (bios_year >= 80 && bios_year <= 99) ? 1900 : 2000; if (bios_year < yy) return (FALSE); else if (bios_year > yy) return (TRUE); if (bios_month < mm) return (FALSE); else if (bios_month > mm) return (TRUE); if (bios_day < dd) return (FALSE); return (TRUE); }
/* * smp_probe: probe device and create inquiry-like properties. */ int smp_probe(struct smp_device *smp_sd) { smp_pkt_t *smp_pkt; smp_pkt_t smp_pkt_data; smp_request_frame_t *srq; smp_response_frame_t *srs; smp_report_manufacturer_info_resp_t *srmir; int ilen, clen; char *component; uint8_t srq_buf[SMP_REQ_MINLEN]; uint8_t srs_buf[SMP_RESP_MINLEN + sizeof (*srmir)]; srq = (smp_request_frame_t *)srq_buf; bzero(srq, sizeof (srq_buf)); srq->srf_frame_type = SMP_FRAME_TYPE_REQUEST; srq->srf_function = SMP_FUNC_REPORT_MANUFACTURER_INFO; smp_pkt = &smp_pkt_data; bzero(smp_pkt, sizeof (*smp_pkt)); smp_pkt->smp_pkt_address = &smp_sd->smp_sd_address; smp_pkt->smp_pkt_req = (caddr_t)srq; smp_pkt->smp_pkt_reqsize = sizeof (srq_buf); smp_pkt->smp_pkt_rsp = (caddr_t)srs_buf; smp_pkt->smp_pkt_rspsize = sizeof (srs_buf); smp_pkt->smp_pkt_timeout = SMP_DEFAULT_TIMEOUT; bzero(srs_buf, sizeof (srs_buf)); if (smp_transport(smp_pkt) != DDI_SUCCESS) { /* * The EOVERFLOW should be excluded here, because it indicates * the buffer (defined according to SAS1.1 Spec) to store * response is shorter than transferred message frame. * In this case, the smp device is alive and should be * enumerated. */ if (smp_pkt->smp_pkt_reason != EOVERFLOW) return (DDI_PROBE_FAILURE); } /* * NOTE: Deal with old drivers (mpt, mpt_sas) that allocate * 'struct smp_device' on the stack. When these drivers convert to * SCSAv3, the check for a NULL smp_sd_dev can be removed. */ if (smp_sd->smp_sd_dev == NULL) return (DDI_PROBE_SUCCESS); /* Save raw response data for devid */ srs = (smp_response_frame_t *)srs_buf; if (srs->srf_result != SMP_RES_FUNCTION_ACCEPTED) return (DDI_PROBE_SUCCESS); /* * Convert smp_report_manufacturer_info_resp_t data into properties. * NOTE: since things show up in the oposite order in prtconf, we are * going from detailed information to generic here. */ srmir = (smp_report_manufacturer_info_resp_t *)&srs->srf_data[0]; if (srmir->srmir_sas_1_1_format) { /* Establish 'component' property. */ ilen = scsi_ascii_inquiry_len( srmir->srmir_component_vendor_identification, sizeof (srmir->srmir_component_vendor_identification)); if (ilen > 0) { /* component value format is '%s.%05d.%03d' */ clen = ilen + 1 + 5 + 1 + 3 + 1; component = kmem_zalloc(clen, KM_SLEEP); bcopy(srmir->srmir_component_vendor_identification, component, ilen); (void) snprintf(&component[ilen], clen - ilen, ".%05d.%03d", BE_16(srmir->srmir_component_id), srmir->srmir_component_revision_level); if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "component") == 0) (void) ndi_prop_update_string(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, "component", component); kmem_free(component, clen); } } /* First one to define the property wins */ if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_REVISION_ID) == 0) (void) smp_device_prop_update_inqstring(smp_sd, INQUIRY_REVISION_ID, srmir->srmir_product_revision_level, sizeof (srmir->srmir_product_revision_level)); if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_PRODUCT_ID) == 0) (void) smp_device_prop_update_inqstring(smp_sd, INQUIRY_PRODUCT_ID, srmir->srmir_product_identification, sizeof (srmir->srmir_product_identification)); if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_VENDOR_ID) == 0) (void) smp_device_prop_update_inqstring(smp_sd, INQUIRY_VENDOR_ID, srmir->srmir_vendor_identification, sizeof (srmir->srmir_vendor_identification)); /* NOTE: SMP_PROP_REPORT_MANUFACTURER is deleted after devid created */ if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SMP_PROP_REPORT_MANUFACTURER) == 0) (void) ndi_prop_update_byte_array(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, SMP_PROP_REPORT_MANUFACTURER, (uchar_t *)srs, sizeof (srs_buf)); return (DDI_PROBE_SUCCESS); }
static int pseudonex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { switch (ctlop) { case DDI_CTLOPS_REPORTDEV: if (rdip == NULL) return (DDI_FAILURE); cmn_err(CE_CONT, "?pseudo-device: %s%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_SUCCESS); case DDI_CTLOPS_INITCHILD: { char name[12]; /* enough for a decimal integer */ int instance = -1; dev_info_t *child = (dev_info_t *)arg; const char *childname = ddi_driver_name(child); char **childlist; uint_t nelems; int auto_assign = 0; /* * If this pseudonex node has a valid-children property, * then that acts as an access control list for children * allowed to attach beneath this node. Honor it. */ if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "valid-children", &childlist, &nelems) == DDI_PROP_SUCCESS) { int i, ok = 0; for (i = 0; i < nelems; i++) { if (strcmp(childlist[i], childname) == 0) { ok = 1; break; } } ddi_prop_free(childlist); if (!ok) return (DDI_FAILURE); } /* * Look up the "instance" property. If it does not exist, * check to see if the "auto-assign-instance" property is set. * If not, default to using instance 0; while not ideal, this * is a legacy behavior we must continue to support. */ instance = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "instance", -1); auto_assign = ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "auto-assign-instance"); NDI_CONFIG_DEBUG((CE_NOTE, "pseudonex: DDI_CTLOPS_INITCHILD(instance=%d, " "auto-assign=%d)", instance, auto_assign)); if (instance != -1 && auto_assign != 0) { NDI_CONFIG_DEBUG((CE_NOTE, "both instance and " "auto-assign-instance properties specified. " "Node rejected.")); return (DDI_FAILURE); } if (instance == -1 && auto_assign == 0) { /* default to instance 0 if not specified */ NDI_CONFIG_DEBUG((CE_NOTE, "defaulting to 0")); instance = 0; } /* * If an instance has been specified, determine if this * instance is already in use; if we need to pick an instance, * we do it here. */ if (auto_assign) { if ((instance = pseudonex_auto_assign(child)) == -1) { NDI_CONFIG_DEBUG((CE_NOTE, "failed to " "auto-select instance for %s", childname)); return (DDI_FAILURE); } NDI_CONFIG_DEBUG((CE_NOTE, "auto-selected instance for %s: %d", childname, instance)); } else { if (pseudonex_check_assignment(child, instance) == DDI_FAILURE) { NDI_CONFIG_DEBUG((CE_WARN, "Duplicate instance %d of node \"%s\" " "ignored.", instance, childname)); return (DDI_FAILURE); } NDI_CONFIG_DEBUG((CE_NOTE, "using fixed-assignment instance for %s: %d", childname, instance)); } /* * Attach the instance number to the node. This allows * us to have multiple instances of the same pseudo * device, they will be named 'device@instance'. If this * breaks programs, we may need to special-case instance 0 * into 'device'. Ick. devlinks appears to handle the * new names ok, so if only names in /dev are used * this may not be necessary. */ (void) snprintf(name, sizeof (name), "%d", instance); DEVI(child)->devi_instance = instance; ddi_set_name_addr(child, name); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: { dev_info_t *child = (dev_info_t *)arg; NDI_CONFIG_DEBUG((CE_NOTE, "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)", ddi_driver_name(child), DEVI(child)->devi_instance)); ddi_set_name_addr(child, NULL); return (DDI_SUCCESS); } case DDI_CTLOPS_DMAPMAPC: case DDI_CTLOPS_REPORTINT: case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: case DDI_CTLOPS_SIDDEV: case DDI_CTLOPS_SLAVEONLY: case DDI_CTLOPS_AFFINITY: case DDI_CTLOPS_POKE: case DDI_CTLOPS_PEEK: /* * These ops correspond to functions that "shouldn't" be called * by a pseudo driver. So we whine when we're called. */ cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n", ddi_driver_name(dip), ddi_get_instance(dip), ctlop, ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_FAILURE); case DDI_CTLOPS_ATTACH: case DDI_CTLOPS_BTOP: case DDI_CTLOPS_BTOPR: case DDI_CTLOPS_DETACH: case DDI_CTLOPS_DVMAPAGESIZE: case DDI_CTLOPS_IOMIN: case DDI_CTLOPS_POWER: case DDI_CTLOPS_PTOB: default: /* * The ops that we pass up (default). We pass up memory * allocation oriented ops that we receive - these may be * associated with pseudo HBA drivers below us with target * drivers below them that use ddi memory allocation * interfaces like scsi_alloc_consistent_buf. */ return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } }
/* * nx1394_bus_ctl() * This routine implements nexus bus ctl operations. Of importance are * DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD * and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup * reg property on the child node and builds and sets the name * (name is of the form GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where * GGGGGGGGGGGGGGGG is the GUID and AAAAAAAAAAAA is the optional unit * address). */ static int nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg, void *result) { int status; TNF_PROBE_0_DEBUG(nx1394_bus_ctl_enter, S1394_TNF_SL_NEXUS_STACK, ""); switch (op) { case DDI_CTLOPS_REPORTDEV: { dev_info_t *pdip = ddi_get_parent(rdip); cmn_err(CE_CONT, "?%s%d at %s%d", ddi_node_name(rdip), ddi_get_instance(rdip), ddi_node_name(pdip), ddi_get_instance(pdip)); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (DDI_SUCCESS); } case DDI_CTLOPS_INITCHILD: { dev_info_t *ocdip, *cdip = (dev_info_t *)arg; dev_info_t *pdip = ddi_get_parent(cdip); int reglen, i; uint32_t *regptr; char addr[MAXNAMELEN]; TNF_PROBE_1(nx1394_bus_ctl_init_child, S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque, dip, cdip); i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "reg", (int **)®ptr, (uint_t *)®len); if (i != DDI_PROP_SUCCESS) { cmn_err(CE_NOTE, "!%s(%d): \"reg\" property not found", ddi_node_name(cdip), ddi_get_instance(cdip)); TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Reg property not found", tnf_int, reason, i); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); return (DDI_NOT_WELL_FORMED); } ASSERT(reglen != 0); /* * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA] */ if (regptr[2] || regptr[3]) { (void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0], regptr[1], regptr[2], regptr[3]); } else { (void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]); } ddi_prop_free(regptr); ddi_set_name_addr(cdip, addr); /* * Check for a node with the same name & addr as the current * node. If such a node exists, return failure. */ if ((ocdip = ndi_devi_find(pdip, ddi_node_name(cdip), addr)) != NULL && ocdip != cdip) { cmn_err(CE_NOTE, "!%s(%d): Duplicate dev_info node found %s@%s", ddi_node_name(cdip), ddi_get_instance(cdip), ddi_node_name(ocdip), addr); TNF_PROBE_1(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Duplicate nodes"); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); ddi_set_name_addr(cdip, NULL); return (DDI_NOT_WELL_FORMED); } /* * If HAL (parent dip) has "active-dma-flush" property, then * add property to child as well. Workaround for active * context flushing bug in Schizo rev 2.1 and 2.2. */ if (ddi_prop_exists(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "active-dma-flush") != 0) { status = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "active-dma-flush", 1); if (status != NDI_SUCCESS) { cmn_err(CE_NOTE, "!%s(%d): Unable to add " "\"active-dma-flush\" property", ddi_node_name(cdip), ddi_get_instance(cdip)); TNF_PROBE_1(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Unable to add \"active-dma-flush\" " "property"); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); ddi_set_name_addr(cdip, NULL); return (DDI_NOT_WELL_FORMED); } } TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: { ddi_prop_remove_all((dev_info_t *)arg); ddi_set_name_addr((dev_info_t *)arg, NULL); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "uninitchild"); return (DDI_SUCCESS); } case DDI_CTLOPS_IOMIN: { status = ddi_ctlops(dip, rdip, op, arg, result); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "iomin"); return (status); } case DDI_CTLOPS_POWER: { return (DDI_SUCCESS); } /* * These ops correspond to functions that "shouldn't" be called * by a 1394 client driver. */ case DDI_CTLOPS_DMAPMAPC: case DDI_CTLOPS_REPORTINT: case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: case DDI_CTLOPS_SIDDEV: case DDI_CTLOPS_SLAVEONLY: case DDI_CTLOPS_AFFINITY: case DDI_CTLOPS_POKE: case DDI_CTLOPS_PEEK: { cmn_err(CE_CONT, "!%s(%d): invalid op (%d) from %s(%d)", ddi_node_name(dip), ddi_get_instance(dip), op, ddi_node_name(rdip), ddi_get_instance(rdip)); TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "invalid op", tnf_int, op, op); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (DDI_FAILURE); } /* * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up */ default: { status = ddi_ctlops(dip, rdip, op, arg, result); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (status); } } }
/* * A hotplug version of fill_cpu(). (Doesn't assume that there's a node * in the PROM device tree for this CPU.) We still need the PROM version * since it is called very early in the boot cycle before (before * setup_ddi()). Sigh...someday this will all be cleaned up. */ void fill_cpu_ddi(dev_info_t *dip) { extern int cpu_get_cpu_unum(int, char *, int, int *); struct cpu_node *cpunode; processorid_t cpuid; int portid; int len = OBP_MAXPROPNAME; int tlbsize; dev_info_t *cmpnode; char namebuf[OBP_MAXPROPNAME], unum[UNUM_NAMLEN]; char *namebufp; char dev_type[OBP_MAXPROPNAME]; if ((portid = get_portid_ddi(dip, &cmpnode)) == -1) { cmn_err(CE_PANIC, "portid not found"); } if ((cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "cpuid", -1)) == -1) { cpuid = portid; } if (cpuid < 0 || cpuid >= NCPU) { cmn_err(CE_PANIC, "cpu dip %p: cpuid %d out of range", (void *)dip, cpuid); return; } cpunode = &cpunodes[cpuid]; cpunode->portid = portid; cpunode->nodeid = ddi_get_nodeid(dip); if (cmpnode != NULL) { /* * For the CMT case, the parent "core" node contains * properties needed below, use it instead of the * cpu node. */ if ((ddi_prop_op(DDI_DEV_T_ANY, cmpnode, PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type, &len) == DDI_PROP_SUCCESS) && (strcmp(dev_type, "core") == 0)) dip = cmpnode; } if (cpu_get_cpu_unum(cpuid, unum, UNUM_NAMLEN, &len) != 0) { cpunode->fru_fmri[0] = '\0'; } else { (void) snprintf(cpunode->fru_fmri, sizeof (cpunode->fru_fmri), "%s%s", CPU_FRU_FMRI, unum); } len = sizeof (namebuf); (void) ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, (cmpnode ? "compatible" : "name"), (caddr_t)namebuf, &len); namebufp = namebuf; if (strncmp(namebufp, "SUNW,", 5) == 0) namebufp += 5; else if (strncmp(namebufp, "FJSV,", 5) == 0) namebufp += 5; (void) strcpy(cpunode->name, namebufp); cpunode->implementation = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "implementation#", 0); cpunode->version = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "mask#", 0); if (IS_CHEETAH(cpunode->implementation)) { /* remap mask reg */ cpunode->version = REMAP_CHEETAH_MASK(cpunode->version); } cpunode->clock_freq = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "clock-frequency", 0); ASSERT(cpunode->clock_freq != 0); /* * Compute scaling factor based on rate of %tick. This is used * to convert from ticks derived from %tick to nanoseconds. See * comment in sun4u/sys/clock.h for details. */ cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); tlbsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "#itlb-entries", 0); ASSERT(tlbsize < USHRT_MAX); /* since we cast it */ cpunode->itlb_size = (ushort_t)tlbsize; tlbsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "#dtlb-entries", 0); ASSERT(tlbsize < USHRT_MAX); /* since we cast it */ cpunode->dtlb_size = (ushort_t)tlbsize; if (cmpnode != NULL) { /* * If the CPU has a level 3 cache, then that is it's * external cache. Otherwise the external cache must * be the level 2 cache. */ cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "l3-cache-size", 0); if (cpunode->ecache_size == 0) cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "l2-cache-size", 0); ASSERT(cpunode->ecache_size != 0); cpunode->ecache_linesize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "l3-cache-line-size", 0); if (cpunode->ecache_linesize == 0) cpunode->ecache_linesize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "l2-cache-line-size", 0); ASSERT(cpunode->ecache_linesize != 0); cpunode->ecache_associativity = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "l2-cache-associativity", 0); ASSERT(cpunode->ecache_associativity != 0); cmp_add_cpu(portid, cpuid); } else { cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ecache-size", 0); ASSERT(cpunode->ecache_size != 0); cpunode->ecache_linesize = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ecache-line-size", 0); ASSERT(cpunode->ecache_linesize != 0); cpunode->ecache_associativity = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ecache-associativity", 0); ASSERT(cpunode->ecache_associativity != 0); } /* by default set msram to non-mirrored one */ cpunode->msram = ECACHE_CPU_NON_MIRROR; if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "msram")) { cpunode->msram = ECACHE_CPU_MIRROR; } else if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "msram-observed")) { cpunode->msram = ECACHE_CPU_MIRROR; } ASSERT(ncpunode > 0); /* fiximp not req'd */ cpunode->ecache_setsize = cpunode->ecache_size / cpunode->ecache_associativity; adj_ecache_setsize(cpunode->ecache_setsize); ncpunode++; }
static int ppb_initchild(dev_info_t *child) { char name[MAXNAMELEN]; ddi_acc_handle_t config_handle; ushort_t command_preserve, command; uint_t n; ushort_t bcr; uchar_t header_type; uchar_t min_gnt, latency_timer; ppb_devstate_t *ppb; /* * Name the child */ if (ppb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) return (DDI_FAILURE); ddi_set_name_addr(child, name); ddi_set_parent_data(child, NULL); /* * Pseudo nodes indicate a prototype node with per-instance * properties to be merged into the real h/w device node. * The interpretation of the unit-address is DD[,F] * where DD is the device id and F is the function. */ if (ndi_dev_is_persistent_node(child) == 0) { extern int pci_allow_pseudo_children; /* * Try to merge the properties from this prototype * node into real h/w nodes. */ if (ndi_merge_node(child, ppb_name_child) == DDI_SUCCESS) { /* * Merged ok - return failure to remove the node. */ ppb_removechild(child); return (DDI_FAILURE); } /* workaround for ddivs to run under PCI */ if (pci_allow_pseudo_children) return (DDI_SUCCESS); /* * The child was not merged into a h/w node, * but there's not much we can do with it other * than return failure to cause the node to be removed. */ cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", ddi_driver_name(child), ddi_get_name_addr(child), ddi_driver_name(child)); ppb_removechild(child); return (DDI_NOT_WELL_FORMED); } ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, ddi_get_instance(ddi_get_parent(child))); ddi_set_parent_data(child, NULL); /* * If hardware is PM capable, set up the power info structure. * This also ensures the the bus will not be off (0MHz) otherwise * system panics during a bus access. */ if (PM_CAPABLE(ppb->ppb_pwr_p)) { /* * Create a pwr_info struct for child. Bus will be * at full speed after creating info. */ pci_pwr_create_info(ppb->ppb_pwr_p, child); #ifdef DEBUG ASSERT(ppb->ppb_pwr_p->current_lvl == PM_LEVEL_B0); #endif } /* * If configuration registers were previously saved by * child (before it entered D3), then let the child do the * restore to set up the config regs as it'll first need to * power the device out of D3. */ if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "config-regs-saved-by-child") == 1) { DEBUG2(DBG_PWR, ddi_get_parent(child), "INITCHILD: config regs to be restored by child" " for %s@%s\n", ddi_node_name(child), ddi_get_name_addr(child)); return (DDI_SUCCESS); } DEBUG2(DBG_PWR, ddi_get_parent(child), "INITCHILD: config regs setup for %s@%s\n", ddi_node_name(child), ddi_get_name_addr(child)); if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) { if (PM_CAPABLE(ppb->ppb_pwr_p)) { pci_pwr_rm_info(ppb->ppb_pwr_p, child); } return (DDI_FAILURE); } /* * Determine the configuration header type. */ header_type = pci_config_get8(config_handle, PCI_CONF_HEADER); /* * Support for the "command-preserve" property. */ command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "command-preserve", 0); command = pci_config_get16(config_handle, PCI_CONF_COMM); command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB); command |= (ppb_command_default & ~command_preserve); pci_config_put16(config_handle, PCI_CONF_COMM, command); /* * If the device has a bus control register then program it * based on the settings in the command register. */ if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL); if (ppb_command_default & PCI_COMM_PARITY_DETECT) bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE; if (ppb_command_default & PCI_COMM_SERR_ENABLE) bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE; bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE; pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr); } /* * Initialize cache-line-size configuration register if needed. */ if (ppb_set_cache_line_size_register && ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "cache-line-size", 0) == 0) { pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ, ppb->ppb_cache_line_size); n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ); if (n != 0) { (void) ndi_prop_update_int(DDI_DEV_T_NONE, child, "cache-line-size", n); } } /* * Initialize latency timer configuration registers if needed. */ if (ppb_set_latency_timer_register && ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "latency-timer", 0) == 0) { if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { latency_timer = ppb->ppb_latency_timer; pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER, ppb->ppb_latency_timer); } else { min_gnt = pci_config_get8(config_handle, PCI_CONF_MIN_G); latency_timer = min_gnt * 8; } pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER, latency_timer); n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER); if (n != 0) { (void) ndi_prop_update_int(DDI_DEV_T_NONE, child, "latency-timer", n); } } /* * SPARC PCIe FMA specific * * Note: parent_data for parent is created only if this is sparc PCI-E * platform, for which, SG take a different route to handle device * errors. */ if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) { if (pcie_init_cfghdl(child) != DDI_SUCCESS) { pci_config_teardown(&config_handle); return (DDI_FAILURE); } pcie_init_dom(child); } /* * Check to see if the XMITS/PCI-X workaround applies. */ n = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_NOTPROM, "pcix-update-cmd-reg", -1); if (n != -1) { extern void pcix_set_cmd_reg(dev_info_t *child, uint16_t value); DEBUG1(DBG_INIT_CLD, child, "Turning on XMITS NCPQ " "Workaround: value = %x\n", n); pcix_set_cmd_reg(child, n); } pci_config_teardown(&config_handle); return (DDI_SUCCESS); }
/*ARGSUSED*/ static int ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) { dev_info_t *root = ddi_root_node(); int instance; ppb_devstate_t *ppb; dev_info_t *pdip; ddi_acc_handle_t config_handle; char *bus; switch (cmd) { case DDI_ATTACH: /* * Make sure the "device_type" property exists. */ (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci"); /* * Allocate and get soft state structure. */ instance = ddi_get_instance(devi); if (ddi_soft_state_zalloc(ppb_state, instance) != DDI_SUCCESS) return (DDI_FAILURE); ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, instance); ppb->dip = devi; mutex_init(&ppb->ppb_mutex, NULL, MUTEX_DRIVER, NULL); ppb->ppb_soft_state = PCI_SOFT_STATE_CLOSED; if (pci_config_setup(devi, &config_handle) != DDI_SUCCESS) { mutex_destroy(&ppb->ppb_mutex); ddi_soft_state_free(ppb_state, instance); return (DDI_FAILURE); } ppb_pwr_setup(ppb, devi); if (PM_CAPABLE(ppb->ppb_pwr_p)) { mutex_enter(&ppb->ppb_pwr_p->pwr_mutex); /* * Before reading config registers, make sure power is * on, and remains on. */ ppb->ppb_pwr_p->pwr_fp++; pci_pwr_change(ppb->ppb_pwr_p, ppb->ppb_pwr_p->current_lvl, pci_pwr_new_lvl(ppb->ppb_pwr_p)); } ppb->ppb_cache_line_size = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ); ppb->ppb_latency_timer = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER); /* * Check whether the "ranges" property is present. * Otherwise create the ranges property by reading * the configuration registers */ if (ddi_prop_exists(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, "ranges") == 0) { ppb_create_ranges_prop(devi, config_handle); } pci_config_teardown(&config_handle); if (PM_CAPABLE(ppb->ppb_pwr_p)) { ppb->ppb_pwr_p->pwr_fp--; pci_pwr_change(ppb->ppb_pwr_p, ppb->ppb_pwr_p->current_lvl, pci_pwr_new_lvl(ppb->ppb_pwr_p)); mutex_exit(&ppb->ppb_pwr_p->pwr_mutex); } ppb->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO; for (pdip = ddi_get_parent(ppb->dip); pdip && (pdip != root) && (ppb->parent_bus != PCIE_PCIECAP_DEV_TYPE_PCIE_DEV); pdip = ddi_get_parent(pdip)) { if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "device_type", &bus) != DDI_PROP_SUCCESS) break; if (strcmp(bus, "pciex") == 0) ppb->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV; ddi_prop_free(bus); } /* * Initialize hotplug support on this bus. */ if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) if (pcie_init(devi, NULL) != DDI_SUCCESS) { (void) ppb_detach(devi, DDI_DETACH); return (DDI_FAILURE); } else ppb_init_hotplug(ppb); DEBUG1(DBG_ATTACH, devi, "ppb_attach(): this nexus %s hotplug slots\n", ppb->hotplug_capable == B_TRUE ? "has":"has no"); ppb_fm_init(ppb); ddi_report_dev(devi); return (DDI_SUCCESS); case DDI_RESUME: /* * Get the soft state structure for the bridge. */ ppb = (ppb_devstate_t *) ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); pci_pwr_resume(devi, ppb->ppb_pwr_p); return (DDI_SUCCESS); } return (DDI_FAILURE); }