diff options
author | cth <none@none> | 2006-06-08 16:03:08 -0700 |
---|---|---|
committer | cth <none@none> | 2006-06-08 16:03:08 -0700 |
commit | 5e3986cb9bc07bde1dfa1a7028d5ad3e501abae4 (patch) | |
tree | 2fe2331bc52401ed96a5ffb073cd13d4262099ce /usr/src/uts/common/io | |
parent | eaa0962daa5398b8d08376d2c36d6f72906490a2 (diff) | |
download | illumos-joyent-5e3986cb9bc07bde1dfa1a7028d5ad3e501abae4.tar.gz |
6423041 PSARC 2006/242 'mdi interfaces to support pHCI driver locking' and related fixes
Diffstat (limited to 'usr/src/uts/common/io')
-rw-r--r-- | usr/src/uts/common/io/ib/ibnex/ibnex.c | 77 | ||||
-rw-r--r-- | usr/src/uts/common/io/pshot.c | 15 | ||||
-rw-r--r-- | usr/src/uts/common/io/tphci.c | 100 | ||||
-rw-r--r-- | usr/src/uts/common/io/tvhci.c | 175 |
4 files changed, 165 insertions, 202 deletions
diff --git a/usr/src/uts/common/io/ib/ibnex/ibnex.c b/usr/src/uts/common/io/ib/ibnex/ibnex.c index be0cdf833b..a14ba9f6e3 100644 --- a/usr/src/uts/common/io/ib/ibnex/ibnex.c +++ b/usr/src/uts/common/io/ib/ibnex/ibnex.c @@ -1104,8 +1104,21 @@ ibnex_bus_config(dev_info_t *parent, uint_t flag, dev_info_t *cdip, *pdip = NULL; ibnex_node_data_t *node_data; ibnex_port_node_t *port_node; + int use_mdi_devi_locking = 0; - ndi_devi_enter(parent, &circ); + + /* Set use_mdi_devi_locking appropriately */ + if ((mdi_component_is_phci(parent, NULL) == MDI_SUCCESS) && + ((op != BUS_CONFIG_ONE) || (op == BUS_CONFIG_ONE && + strncmp((char *)devname, IBNEX_IBPORT_CNAME, 6) != 0))) { + IBTF_DPRINTF_L4("ibnex", "\tbus_config: using mdi_devi_enter"); + use_mdi_devi_locking = 1; + } + + if (use_mdi_devi_locking) + mdi_devi_enter(parent, &circ); + else + ndi_devi_enter(parent, &circ); switch (op) { case BUS_CONFIG_ONE: @@ -1118,7 +1131,10 @@ ibnex_bus_config(dev_info_t *parent, uint_t flag, if (caddr == NULL || (strlen(caddr) == 0)) { kmem_free(device_name, len); - ndi_devi_exit(parent, circ); + if (use_mdi_devi_locking) + mdi_devi_exit(parent, circ); + else + ndi_devi_exit(parent, circ); return (NDI_FAILURE); } @@ -1137,7 +1153,11 @@ ibnex_bus_config(dev_info_t *parent, uint_t flag, if (cdip == NULL) { /* Node is not present */ if (strncmp(cname, IBNEX_IOC_CNAME, 3) == 0) { - ndi_devi_exit(parent, circ); + if (use_mdi_devi_locking) + mdi_devi_exit(parent, circ); + else + ndi_devi_exit(parent, circ); + ret = ibnex_ioc_bus_config_one(&parent, flag, op, devname, child, &need_bus_config); if (!need_bus_config) { @@ -1145,7 +1165,10 @@ ibnex_bus_config(dev_info_t *parent, uint_t flag, return (ret); } - ndi_devi_enter(parent, &circ); + if (use_mdi_devi_locking) + mdi_devi_enter(parent, &circ); + else + ndi_devi_enter(parent, &circ); } else if ((strncmp(cname, IBNEX_IBPORT_CNAME, 6) == 0) && (parent != ibnex.ibnex_dip)) { /* parent is HCA */ @@ -1168,7 +1191,11 @@ ibnex_bus_config(dev_info_t *parent, uint_t flag, ret = IBNEX_SUCCESS; ibnex_pseudo_initnodes(); if (parent == ibnex.ibnex_dip) { - ndi_devi_exit(parent, circ); + if (use_mdi_devi_locking) + mdi_devi_exit(parent, circ); + else + ndi_devi_exit(parent, circ); + mutex_enter(&ibnex.ibnex_mutex); ret = ibnex_pseudo_mdi_config_one( flag, devname, child, cname, @@ -1226,6 +1253,15 @@ ibnex_bus_config(dev_info_t *parent, uint_t flag, ", parent %p", parent); /* + * No locks to be held while calling mdi_vhci_bus_config() + * ibnex_config_all_children() holds appropriate locks. + */ + if (use_mdi_devi_locking) + mdi_devi_exit(parent, circ); + else + ndi_devi_exit(parent, circ); + + /* * Drive CONFIG requests for IB Nexus parent through * MDI. This is needed to load the HCA drivers in x86 SRP * boot case. @@ -1234,12 +1270,16 @@ ibnex_bus_config(dev_info_t *parent, uint_t flag, * ibdm and configure all children. */ if (parent == ibnex.ibnex_dip) { - ndi_devi_exit(parent, circ); ret = mdi_vhci_bus_config(parent, flag, op, devname, child, NULL); return (ret); } else { ibnex_config_all_children(parent); + + if (use_mdi_devi_locking) + mdi_devi_enter(parent, &circ); + else + ndi_devi_enter(parent, &circ); } break; default: @@ -1247,7 +1287,12 @@ ibnex_bus_config(dev_info_t *parent, uint_t flag, ret = IBNEX_FAILURE; break; } - ndi_devi_exit(parent, circ); + + if (use_mdi_devi_locking) + mdi_devi_exit(parent, circ); + else + ndi_devi_exit(parent, circ); + if (ret == IBNEX_SUCCESS) { if (op == BUS_CONFIG_OBP_ARGS) op = BUS_CONFIG_ONE; @@ -1386,13 +1431,17 @@ ibnex_config_all_children(dev_info_t *parent) ibdm_ioc_info_t *ioc_list, *ioc; ibdm_hca_list_t *hca_list; ib_guid_t hca_guid; + int circ; IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: Begin"); /* * Enumerate children of this HCA, port nodes, - * VPPA & HCA_SVC nodes + * VPPA & HCA_SVC nodes. Use ndi_devi_enter() for + * locking. IB Nexus is enumerating the children + * of HCA, not MPXIO clients. */ + ndi_devi_enter(parent, &circ); hca_guid = ibtl_ibnex_hcadip2guid(parent); wait_time = ibdm_ibnex_get_waittime( hca_guid, &ibnex_port_settling_time); @@ -1410,6 +1459,13 @@ ibnex_config_all_children(dev_info_t *parent) parent, &hca_list->hl_port_attr[ii]); } ibdm_ibnex_free_hca_list(hca_list); + ndi_devi_exit(parent, circ); + + /* + * Use mdi_devi_enter() for locking. IB Nexus is + * enumerating MPXIO clients. + */ + mdi_devi_enter(parent, &circ); ibnex_pseudo_initnodes(); @@ -1438,6 +1494,7 @@ ibnex_config_all_children(dev_info_t *parent) mutex_exit(&ibnex.ibnex_mutex); ibdm_ibnex_free_ioc_list(ioc); + mdi_devi_exit(parent, circ); IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: End"); } @@ -4053,7 +4110,7 @@ ibnex_ioc_bus_config_one(dev_info_t **pdipp, uint_t flag, if (ret == MDI_SUCCESS) *need_bus_config = 0; } else { - ndi_devi_enter(pdip, &circ); + mdi_devi_enter(pdip, &circ); if (strstr((char *)devname, ":port=") != NULL) { ret = ibnex_config_root_iocnode(pdip, devname); ASSERT(ibnex.ibnex_dip == NULL); @@ -4061,7 +4118,7 @@ ibnex_ioc_bus_config_one(dev_info_t **pdipp, uint_t flag, } else { ret = ibnex_config_ioc_node(devname, pdip); } - ndi_devi_exit(pdip, circ); + mdi_devi_exit(pdip, circ); } return (ret); } diff --git a/usr/src/uts/common/io/pshot.c b/usr/src/uts/common/io/pshot.c index 81047bf9fb..15af33341c 100644 --- a/usr/src/uts/common/io/pshot.c +++ b/usr/src/uts/common/io/pshot.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1192,8 +1191,6 @@ pshot_ctl(dev_info_t *dip, dev_info_t *rdip, return (rval); } - case DDI_CTLOPS_BTOP: - case DDI_CTLOPS_BTOPR: case DDI_CTLOPS_DETACH: { dev_info_t *child = (dev_info_t *)rdip; @@ -1297,6 +1294,8 @@ pshot_ctl(dev_info_t *dip, dev_info_t *rdip, return (rval); } + case DDI_CTLOPS_BTOP: + case DDI_CTLOPS_BTOPR: case DDI_CTLOPS_DVMAPAGESIZE: case DDI_CTLOPS_IOMIN: case DDI_CTLOPS_PTOB: @@ -2600,9 +2599,6 @@ pshot_bus_config(dev_info_t *parent, uint_t flags, break; case BUS_CONFIG_DRIVER: - rval = NDI_FAILURE; - break; - case BUS_CONFIG_ALL: rval = NDI_SUCCESS; break; @@ -2894,6 +2890,7 @@ pshot_bus_config_setup_nexus(dev_info_t *parent, char *cname, char *caddr) "pshot%d: bus_config one %s@%s found\n", ddi_get_instance(parent), cname, caddr); } + /* * create the "pm-want-child-notification?" property * for this child, if it doesn't already exist diff --git a/usr/src/uts/common/io/tphci.c b/usr/src/uts/common/io/tphci.c index b9a3b43fb3..1aa9c4ebf1 100644 --- a/usr/src/uts/common/io/tphci.c +++ b/usr/src/uts/common/io/tphci.c @@ -39,7 +39,6 @@ #include <sys/sunddi.h> #include <sys/sunndi.h> #include <sys/sunmdi.h> -#include <sys/mdi_impldefs.h> #include <sys/disp.h> /* cb_ops entry points */ @@ -483,18 +482,18 @@ tphci_bus_config(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op, void *arg, dev_info_t **childp) { _NOTE(ARGUNUSED(flags)) - char *cname, *paddr, *guid, *devnm; - mdi_pathinfo_t *pip; - int len; + char *cname, *paddr, *guid, *devnm; + mdi_pathinfo_t *pip; + int len, circ, rval; switch (op) { case BUS_CONFIG_ONE: break; case BUS_CONFIG_DRIVER: /* no direct children to configure */ case BUS_CONFIG_ALL: - return (DDI_SUCCESS); + return (NDI_SUCCESS); default: - return (DDI_FAILURE); + return (NDI_FAILURE); } /* only implement BUS_CONFIG_ONE */ @@ -506,75 +505,102 @@ tphci_bus_config(dev_info_t *parent, uint_t flags, cmn_err(CE_NOTE, "tphci_bus_config -- invalid device %s", (char *)arg); kmem_free(devnm, len); - return (DDI_FAILURE); + return (NDI_FAILURE); } - if (mdi_pi_alloc(parent, cname, guid, paddr, 0, &pip) - != MDI_SUCCESS) { + mdi_devi_enter(parent, &circ); + rval = mdi_pi_alloc(parent, cname, guid, paddr, 0, &pip); + kmem_free(devnm, len); + if (rval != MDI_SUCCESS) { cmn_err(CE_NOTE, "tphci_bus_config -- mdi_pi_alloc failed"); - kmem_free(devnm, len); - return (DDI_FAILURE); + mdi_devi_exit(parent, circ); + return (NDI_FAILURE); } - kmem_free(devnm, len); - if (mdi_pi_online(pip, 0) != MDI_SUCCESS) { + /* + * Hold the path and exit the pHCI while calling mdi_pi_online + * to avoid deadlock with power management of pHCI. + */ + mdi_hold_path(pip); + mdi_devi_exit_phci(parent, circ); + rval = mdi_pi_online(pip, 0); + mdi_devi_enter_phci(parent, &circ); + mdi_rele_path(pip); + + if (rval != MDI_SUCCESS) { cmn_err(CE_NOTE, "tphci_bus_config -- mdi_pi_online failed"); (void) mdi_pi_free(pip, 0); - return (DDI_FAILURE); + mdi_devi_exit(parent, circ); + return (NDI_FAILURE); } if (childp) { - *childp = MDI_PI(pip)->pi_client->ct_dip; + *childp = mdi_pi_get_client(pip); ndi_hold_devi(*childp); } - return (DDI_SUCCESS); + mdi_devi_exit(parent, circ); + + return (NDI_SUCCESS); } static int tphci_bus_unconfig(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op, void *arg) { - int rval, circ; - mdi_pathinfo_t *pip; - mdi_phci_t *ph; - char *devnm, *cname, *caddr; + int rval = MDI_SUCCESS; + int circ; + mdi_pathinfo_t *pip, *next; + char *devnm, *cname, *caddr; switch (op) { case BUS_UNCONFIG_ONE: devnm = (char *)arg; i_ddi_parse_name(devnm, &cname, &caddr, NULL); if (strcmp(cname, "tclient") != 0) - return (DDI_SUCCESS); /* no such device */ + return (NDI_SUCCESS); /* no such device */ + + mdi_devi_enter(parent, &circ); pip = mdi_pi_find(parent, NULL, caddr); - if (pip == NULL) - return (DDI_SUCCESS); - rval = mdi_pi_offline(pip, NDI_DEVI_REMOVE); + if (pip) { + mdi_hold_path(pip); + mdi_devi_exit_phci(parent, circ); + rval = mdi_pi_offline(pip, NDI_DEVI_REMOVE); + mdi_devi_enter_phci(parent, &circ); + mdi_rele_path(pip); + + if (rval == MDI_SUCCESS) + (void) mdi_pi_free(pip, 0); + } + mdi_devi_exit(parent, circ); return (rval == MDI_SUCCESS ? NDI_SUCCESS : NDI_FAILURE); case BUS_UNCONFIG_ALL: if (flags & NDI_AUTODETACH) - return (DDI_FAILURE); + return (NDI_FAILURE); - ph = DEVI(parent)->devi_mdi_xhci; - ASSERT(ph != NULL); + mdi_devi_enter(parent, &circ); + next = mdi_get_next_client_path(parent, NULL); + while ((pip = next) != NULL) { + next = mdi_get_next_client_path(parent, pip); - rval = MDI_SUCCESS; - ndi_devi_enter(parent, &circ); - pip = (mdi_pathinfo_t *)ph->ph_path_head; - while (pip) { + mdi_hold_path(pip); + mdi_devi_exit_phci(parent, circ); rval = mdi_pi_offline(pip, NDI_DEVI_REMOVE); - if (rval != MDI_SUCCESS) { + mdi_devi_enter_phci(parent, &circ); + mdi_rele_path(pip); + + if (rval != MDI_SUCCESS) break; - } - pip = (mdi_pathinfo_t *)ph->ph_path_head; + (void) mdi_pi_free(pip, 0); } - ndi_devi_exit(parent, circ); + mdi_devi_exit(parent, circ); return (rval == MDI_SUCCESS ? NDI_SUCCESS : NDI_FAILURE); case BUS_UNCONFIG_DRIVER: /* nothing to do */ - return (DDI_SUCCESS); + return (NDI_SUCCESS); + default: - return (DDI_FAILURE); + return (NDI_FAILURE); } /*NOTREACHED*/ } diff --git a/usr/src/uts/common/io/tvhci.c b/usr/src/uts/common/io/tvhci.c index daa418966a..8c7034399d 100644 --- a/usr/src/uts/common/io/tvhci.c +++ b/usr/src/uts/common/io/tvhci.c @@ -541,163 +541,46 @@ tvh_get_phci_devname(char *cname, char *guid, return (pname); } -static int -tvh_enum_by_phci(dev_info_t *vdip, char *devnm, int flags) +/* + * Return a pointer to the guid part of the devnm. + * devnm format is "nodename@busaddr", busaddr format is "gGUID". + */ +static char * +tvhci_devnm_to_guid(char *devnm) { - mdi_phci_t *ph; - mdi_vhci_t *vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci; - dev_info_t *pdip, *cdip; - char *cname, *caddr, *guid, *pname; - int rval = DDI_FAILURE; - - (void) i_ddi_parse_name(devnm, &cname, &caddr, NULL); - if (cname == NULL || caddr == NULL || caddr[0] != 'g') - return (rval); - - guid = caddr + 1; - pname = kmem_alloc(MAXNAMELEN, KM_SLEEP); - - /* mutex_enter(&mdi_mutex); XXX need lock access */ - ph = vh->vh_phci_head; - while (ph) { - pdip = ph->ph_dip; - /* mutex_exit(&mdi_mutex); */ - (void) tvh_get_phci_devname(cname, guid, pdip, pname, - MAXNAMELEN); - if (ndi_devi_config_one(pdip, pname, &cdip, flags) - == DDI_SUCCESS) { - ndi_rele_devi(cdip); - rval = DDI_SUCCESS; - } - /* mutex_enter(&mdi_mutex); */ - ph = ph->ph_next; - } - /* mutex_exit(&mdi_mutex); */ - - *(caddr - 1) = '@'; /* undo damage from i_ddi_parse_name() */ - kmem_free(pname, MAXNAMELEN); - return (rval); -} + char *cp = devnm; -static int -tvh_remove_by_phci(dev_info_t *vdip, char *devnm, int flags) -{ - int rval = DDI_SUCCESS; - mdi_phci_t *ph; - mdi_vhci_t *vh = (mdi_vhci_t *)DEVI(vdip)->devi_mdi_xhci; - dev_info_t *pdip; - char *cname, *caddr, *guid, *pname; - - (void) i_ddi_parse_name(devnm, &cname, &caddr, NULL); - if (cname == NULL || caddr == NULL || caddr[0] != 'g') - return (rval); /* devnm can't exist */ - - guid = caddr + 1; - pname = kmem_alloc(MAXNAMELEN, KM_SLEEP); - - /* mutex_enter(&mdi_mutex); XXX need lock access */ - ph = vh->vh_phci_head; - while (ph) { - pdip = ph->ph_dip; - /* mutex_exit(&mdi_mutex); */ - (void) tvh_get_phci_devname(cname, guid, pdip, pname, - MAXNAMELEN); - rval = ndi_devi_unconfig_one(pdip, pname, NULL, flags); - /* mutex_enter(&mdi_mutex); */ - if (rval != NDI_SUCCESS) - break; - ph = ph->ph_next; - } - /* mutex_exit(&mdi_mutex); */ + if (devnm == NULL) + return (NULL); - kmem_free(pname, MAXNAMELEN); - return (rval); + while (*cp != '\0' && *cp != '@') + cp++; + if (*cp == '@' && *(cp + 1) == 'g') + return (cp + 2); + return (NULL); } static int -tvhci_bus_config(dev_info_t *parent, uint_t flags, - ddi_bus_config_op_t op, void *arg, dev_info_t **childp) +tvhci_bus_config(dev_info_t *pdip, uint_t flags, ddi_bus_config_op_t op, + void *arg, dev_info_t **child) { - char *devnm; - dev_info_t *cdip; - int circ; - - switch (op) { - case BUS_CONFIG_ONE: - break; - case BUS_CONFIG_ALL: - /* XXX call into phci's here? */ - case BUS_CONFIG_DRIVER: - return (ndi_busop_bus_config(parent, flags, op, arg, childp, - 0)); - default: - return (DDI_FAILURE); - } - - devnm = (char *)arg; - ndi_devi_enter(parent, &circ); - cdip = ndi_devi_findchild(parent, devnm); - ndi_devi_exit(parent, circ); - if (cdip == NULL) { - /* call into registered phci's */ - (void) tvh_enum_by_phci(parent, devnm, flags); - } - - return (ndi_busop_bus_config(parent, flags, op, arg, childp, 0)); + char *guid; + + if (op == BUS_CONFIG_ONE || op == BUS_UNCONFIG_ONE) + guid = tvhci_devnm_to_guid((char *)arg); + else + guid = NULL; + + if (mdi_vhci_bus_config(pdip, flags, op, arg, child, guid) + == MDI_SUCCESS) + return (NDI_SUCCESS); + else + return (NDI_FAILURE); } static int tvhci_bus_unconfig(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op, void *arg) { - char *devnm, *slashname; - int rval, circ; - dev_info_t *cdip, *ndip; - - /* - * If we are not removing device nodes, pathinfo can be - * left as is. So no need to disturb the phci's. - */ - if ((flags & NDI_DEVI_REMOVE) == 0) { - return (ndi_busop_bus_unconfig(parent, flags, op, arg)); - } - - switch (op) { - case BUS_UNCONFIG_ONE: - devnm = (char *)arg; - ndi_devi_enter(parent, &circ); - if (ndi_devi_findchild(parent, devnm) == NULL) { - ndi_devi_exit(parent, circ); - return (DDI_SUCCESS); - } - ndi_devi_exit(parent, circ); - return (tvh_remove_by_phci(parent, devnm, flags)); - - case BUS_UNCONFIG_ALL: - /* this functionality is for developers only */ - rval = DDI_SUCCESS; - slashname = kmem_alloc(MAXNAMELEN, KM_SLEEP); - devnm = slashname + 1; - ndi_devi_enter(parent, &circ); - cdip = ddi_get_child(parent); - while (cdip != NULL) { - ndip = ddi_get_next_sibling(cdip); - (void) ddi_deviname(cdip, slashname); - ndi_devi_exit(parent, circ); - rval = tvh_remove_by_phci(parent, devnm, flags); - if (rval != DDI_SUCCESS) { - break; - } - ndi_devi_enter(parent, &circ); - cdip = ndip; - } - ndi_devi_exit(parent, circ); - return (rval); - - case BUS_UNCONFIG_DRIVER: - /* unconfig driver never comes with NDI_DEVI_REMOVE */ - default: - return (DDI_FAILURE); - } - /*NOTREACHED*/ + return (ndi_busop_bus_unconfig(parent, flags, op, arg)); } |