summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io
diff options
context:
space:
mode:
authorcth <none@none>2006-06-08 16:03:08 -0700
committercth <none@none>2006-06-08 16:03:08 -0700
commit5e3986cb9bc07bde1dfa1a7028d5ad3e501abae4 (patch)
tree2fe2331bc52401ed96a5ffb073cd13d4262099ce /usr/src/uts/common/io
parenteaa0962daa5398b8d08376d2c36d6f72906490a2 (diff)
downloadillumos-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.c77
-rw-r--r--usr/src/uts/common/io/pshot.c15
-rw-r--r--usr/src/uts/common/io/tphci.c100
-rw-r--r--usr/src/uts/common/io/tvhci.c175
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));
}