diff options
Diffstat (limited to 'usr/src/uts/sun4u/io/pci/pci_pci.c')
| -rw-r--r-- | usr/src/uts/sun4u/io/pci/pci_pci.c | 238 |
1 files changed, 131 insertions, 107 deletions
diff --git a/usr/src/uts/sun4u/io/pci/pci_pci.c b/usr/src/uts/sun4u/io/pci/pci_pci.c index 9b1799feec..d2d4718fa1 100644 --- a/usr/src/uts/sun4u/io/pci/pci_pci.c +++ b/usr/src/uts/sun4u/io/pci/pci_pci.c @@ -23,7 +23,6 @@ * Use is subject to license terms. */ - /* * Sun4u PCI to PCI bus bridge nexus driver */ @@ -35,7 +34,7 @@ #include <sys/autoconf.h> #include <sys/ddi_impldefs.h> #include <sys/ddi_subrdefs.h> -#include <sys/pcie.h> +#include <sys/pci_impl.h> #include <sys/pcie_impl.h> #include <sys/pci_cap.h> #include <sys/pci/pci_nexus.h> @@ -47,6 +46,7 @@ #include <sys/ddifm.h> #include <sys/pci/pci_pwr.h> #include <sys/pci/pci_debug.h> +#include <sys/hotplug/pci/pcie_hp.h> #include <sys/hotplug/pci/pcihp.h> #include <sys/open.h> #include <sys/stat.h> @@ -130,7 +130,8 @@ struct bus_ops ppb_bus_ops = { ppb_bus_enter, /* (*bus_enter)() */ ppb_bus_exit, /* (*bus_exit)() */ ppb_bus_power, /* (*bus_power)() */ - ppb_intr_ops /* (*bus_intr_op)(); */ + ppb_intr_ops, /* (*bus_intr_op)(); */ + pcie_hp_common_ops /* (*bus_hp_op)(); */ }; static int ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp); @@ -164,7 +165,7 @@ static struct cb_ops ppb_cb_ops = { static int ppb_probe(dev_info_t *); static int ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); static int ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); -static int ppb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, +static int ppb_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result); static int ppb_pwr(dev_info_t *dip, int component, int level); @@ -238,9 +239,6 @@ typedef struct { kmutex_t ppb_mutex; uint_t ppb_soft_state; -#define PPB_SOFT_STATE_CLOSED 0x00 -#define PPB_SOFT_STATE_OPEN 0x01 -#define PPB_SOFT_STATE_OPEN_EXCL 0x02 int fm_cap; ddi_iblock_cookie_t fm_ibc; @@ -328,16 +326,18 @@ _info(struct modinfo *modinfop) /*ARGSUSED*/ static int -ppb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +ppb_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) { - ppb_devstate_t *ppb_p; /* per ppb state pointer */ minor_t minor = getminor((dev_t)arg); - int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); - - ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, + int instance = PCI_MINOR_NUM_TO_INSTANCE(minor); + ppb_devstate_t *ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, instance); - switch (infocmd) { + + if (ppb_p->parent_bus != PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) + return (pcihp_info(dip, cmd, arg, result)); + + switch (cmd) { default: return (DDI_FAILURE); @@ -364,9 +364,12 @@ ppb_probe(register dev_info_t *devi) 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: @@ -386,7 +389,7 @@ ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 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 = PPB_SOFT_STATE_CLOSED; + 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); @@ -435,30 +438,32 @@ ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 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. At minimum - * (for non hotplug bus) this would create ":devctl" minor - * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls - * to this bus. This all takes place if this nexus has hot-plug - * slots and successfully initializes Hot Plug Framework. + * Initialize hotplug support on this bus. */ - ppb->hotplug_capable = B_FALSE; - ppb_init_hotplug(ppb); - if (ppb->hotplug_capable == B_FALSE) { - /* - * create minor node for devctl interfaces - */ - if (ddi_create_minor_node(devi, "devctl", S_IFCHR, - PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR), - DDI_NT_NEXUS, 0) != DDI_SUCCESS) { - if (ppb->ppb_pwr_p != NULL) { - ppb_pwr_teardown(ppb, devi); - } - mutex_destroy(&ppb->ppb_mutex); - ddi_soft_state_free(ppb_state, instance); + 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", @@ -488,6 +493,7 @@ static int ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) { ppb_devstate_t *ppb; + int ret = DDI_SUCCESS; switch (cmd) { case DDI_DETACH: @@ -500,12 +506,16 @@ ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) ppb_fm_fini(ppb); - if (ppb->hotplug_capable == B_TRUE) - if (pcihp_uninit(devi) == DDI_FAILURE) - return (DDI_FAILURE); + if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) + ret = pcie_uninit(devi); + else if (ppb->hotplug_capable == B_TRUE) + ret = pcihp_init(devi); else ddi_remove_minor_node(devi, "devctl"); + if (ret != DDI_SUCCESS) + return (DDI_FAILURE); + (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type"); if (ppb->ppb_pwr_p != NULL) { @@ -1428,6 +1438,8 @@ ppb_pwr(dev_info_t *dip, int component, int lvl) 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"); @@ -1441,6 +1453,18 @@ ppb_init_hotplug(ppb_devstate_t *ppb) 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 void @@ -1516,9 +1540,8 @@ ppb_create_ranges_prop(dev_info_t *dip, static int ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp) { - ppb_devstate_t *ppb_p; - minor_t minor = getminor(*devp); - int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); + int instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(*devp)); + ppb_devstate_t *ppb_p = ddi_get_soft_state(ppb_state, instance); /* * Make sure the open is for the right file type. @@ -1526,35 +1549,44 @@ ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp) if (otyp != OTYP_CHR) return (EINVAL); + if (ppb_p == NULL) + return (ENXIO); + + mutex_enter(&ppb_p->ppb_mutex); + /* - * Get the soft state structure for the device. + * Ioctls will be handled by SPARC PCI Express framework for all + * PCIe platforms */ - ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, - instance); + if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) { + int rv; - if (ppb_p == NULL) - return (ENXIO); + rv = pcie_open(ppb_p->dip, devp, flags, otyp, credp); + mutex_exit(&ppb_p->ppb_mutex); + + return (rv); + } else if (ppb_p->hotplug_capable == B_TRUE) { + mutex_exit(&ppb_p->ppb_mutex); - if (ppb_p->hotplug_capable == B_TRUE) - return ((pcihp_get_cb_ops())->cb_open(devp, flags, - otyp, credp)); + return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, + credp)); + } /* * Handle the open by tracking the device state. */ - mutex_enter(&ppb_p->ppb_mutex); if (flags & FEXCL) { - if (ppb_p->ppb_soft_state != PPB_SOFT_STATE_CLOSED) { + if (ppb_p->ppb_soft_state != PCI_SOFT_STATE_CLOSED) { mutex_exit(&ppb_p->ppb_mutex); return (EBUSY); } - ppb_p->ppb_soft_state = PPB_SOFT_STATE_OPEN_EXCL; + ppb_p->ppb_soft_state = PCI_SOFT_STATE_OPEN_EXCL; } else { - if (ppb_p->ppb_soft_state == PPB_SOFT_STATE_OPEN_EXCL) { + if (ppb_p->ppb_soft_state == PCI_SOFT_STATE_OPEN_EXCL) { mutex_exit(&ppb_p->ppb_mutex); return (EBUSY); } - ppb_p->ppb_soft_state = PPB_SOFT_STATE_OPEN; + ppb_p->ppb_soft_state = PCI_SOFT_STATE_OPEN; } mutex_exit(&ppb_p->ppb_mutex); return (0); @@ -1565,25 +1597,34 @@ ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp) static int ppb_close(dev_t dev, int flags, int otyp, cred_t *credp) { - ppb_devstate_t *ppb_p; - minor_t minor = getminor(dev); - int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); + int instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev)); + ppb_devstate_t *ppb_p = ddi_get_soft_state(ppb_state, instance); if (otyp != OTYP_CHR) return (EINVAL); - ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, - instance); - if (ppb_p == NULL) return (ENXIO); - if (ppb_p->hotplug_capable == B_TRUE) - return ((pcihp_get_cb_ops())->cb_close(dev, flags, - otyp, credp)); - mutex_enter(&ppb_p->ppb_mutex); - ppb_p->ppb_soft_state = PPB_SOFT_STATE_CLOSED; + /* + * Ioctls will be handled by SPARC PCI Express framework for all + * PCIe platforms + */ + if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) { + int rv; + + rv = pcie_close(ppb_p->dip, dev, flags, otyp, credp); + mutex_exit(&ppb_p->ppb_mutex); + + return (rv); + } else if (ppb_p->hotplug_capable == B_TRUE) { + mutex_exit(&ppb_p->ppb_mutex); + return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, + credp)); + } + + ppb_p->ppb_soft_state = PCI_SOFT_STATE_CLOSED; mutex_exit(&ppb_p->ppb_mutex); return (0); } @@ -1597,23 +1638,26 @@ static int ppb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) { - ppb_devstate_t *ppb_p; - dev_info_t *self; + int instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev)); + ppb_devstate_t *ppb_p = ddi_get_soft_state(ppb_state, instance); struct devctl_iocdata *dcp; - uint_t bus_state; - int rv = 0; - minor_t minor = getminor(dev); - int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); - - ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, - instance); + uint_t bus_state; + dev_info_t *self; + int rv = 0; if (ppb_p == NULL) return (ENXIO); - if (ppb_p->hotplug_capable == B_TRUE) - return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd, - arg, mode, credp, rvalp)); + /* + * Ioctls will be handled by SPARC PCI Express framework for all + * PCIe platforms + */ + if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) + return (pcie_ioctl(ppb_p->dip, dev, cmd, arg, mode, credp, + rvalp)); + else if (ppb_p->hotplug_capable == B_TRUE) + return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, + credp, rvalp)); self = ppb_p->dip; @@ -1670,24 +1714,23 @@ ppb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, return (rv); } -static int ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, - int flags, char *name, caddr_t valuep, int *lengthp) +static int +ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags, + char *name, caddr_t valuep, int *lengthp) { - ppb_devstate_t *ppb_p; - minor_t minor = getminor(dev); - int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); - - ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, - instance); + int instance = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev)); + ppb_devstate_t *ppb_p = (ppb_devstate_t *) + ddi_get_soft_state(ppb_state, instance); if (ppb_p == NULL) return (ENXIO); - if (ppb_p->hotplug_capable == B_TRUE) - return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, - flags, name, valuep, lengthp)); + if (ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) + return (pcie_prop_op(dev, dip, prop_op, flags, name, + valuep, lengthp)); - return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); + return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags, + name, valuep, lengthp)); } /* @@ -1696,10 +1739,6 @@ static int ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, static void ppb_fm_init(ppb_devstate_t *ppb_p) { - dev_info_t *root = ddi_root_node(); - dev_info_t *pdip; - char *bus; - ppb_p->fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE | DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; @@ -1717,21 +1756,6 @@ ppb_fm_init(ppb_devstate_t *ppb_p) * Register error callback with our parent. */ ddi_fm_handler_register(ppb_p->dip, ppb_err_callback, NULL); - - ppb_p->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO; - for (pdip = ddi_get_parent(ppb_p->dip); pdip && (pdip != root) && - (ppb_p->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_p->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV; - - ddi_prop_free(bus); - } } /* |
