changeset 3664:ecc47116246b

6522697 cardbus should work better under subtractive decode bridge 6460235 pcic does not recognize "pciex" bus_type 6516884 pcic_add_debqueue() could cause panic under memory shortage
author rw148561
date Fri, 16 Feb 2007 00:52:01 -0800
parents 718327411bfa
children fa2488776409
files usr/src/uts/common/io/cardbus/cardbus_cfg.c usr/src/uts/common/io/pcic.c usr/src/uts/common/pcmcia/nexus/pcmcia.c usr/src/uts/common/sys/pcic_var.h usr/src/uts/common/sys/sservice.h
diffstat 5 files changed, 136 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/cardbus/cardbus_cfg.c	Thu Feb 15 15:33:40 2007 -0800
+++ b/usr/src/uts/common/io/cardbus/cardbus_cfg.c	Fri Feb 16 00:52:01 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -45,6 +45,7 @@
 
 #include <sys/pctypes.h>
 #include <sys/pcmcia.h>
+#include <sys/sservice.h>
 
 #include <sys/isa_defs.h>
 
@@ -131,6 +132,7 @@
 struct cardbus_phdl {
 
 	dev_info_t	*dip;	/* Associated with the attach point */
+	dev_info_t	*res_dip; /* dip from which io/mem is allocated */
 	cardbus_phdl_t  *next;
 
 	uint64_t	memory_base;    /* Memory base for this attach point */
@@ -551,6 +553,7 @@
 {
 	cardbus_phdl_t *entry;
 	cardbus_phdl_t *follow = NULL;
+	ra_return_t	res;
 
 	mutex_enter(&cardbus_list_mutex);
 	for (entry = cardbus_phdl_list; entry != NULL; follow = entry,
@@ -567,9 +570,9 @@
 			 * must be freed up.
 			 */
 			if (entry->memory_len > 0) {
-				(void) ndi_ra_free(dip,
-				    entry->memory_base, entry->memory_len,
-				    NDI_RA_TYPE_MEM, NDI_RA_PASS);
+				res.ra_addr_lo = entry->memory_base;
+				res.ra_len = entry->memory_len;
+				(void) pcmcia_free_mem(entry->res_dip, &res);
 #ifdef  _LP64
 				cardbus_err(dip, 8,
 				    "cardbus_destroy_phdl: "
@@ -583,9 +586,9 @@
 #endif
 			}
 			if (entry->io_len > 0) {
-				(void) ndi_ra_free(dip,
-				    entry->io_base, entry->io_len,
-				    NDI_RA_TYPE_IO, NDI_RA_PASS);
+				res.ra_addr_lo = entry->io_base;
+				res.ra_len = entry->io_len;
+				(void) pcmcia_free_io(entry->res_dip, &res);
 				cardbus_err(dip, 8,
 				    "cardbus_destroy_phdl: "
 				    "IO BASE = [0x%x] length [0x%x]\n",
@@ -1170,10 +1173,8 @@
 	cardbus_phdl_t		*phdl;
 	ndi_ra_request_t	*mem_request;
 	ndi_ra_request_t	*io_request;
-	uint64_t		mem_answer;
-	uint64_t		io_answer;
+	ra_return_t		res;
 	int			count;
-	uint64_t		alen;
 
 	/*
 	 * This should not find an existing entry - so
@@ -1248,15 +1249,15 @@
 		    mem_request->ra_len);
 #endif
 
-		if (ndi_ra_alloc(dip, mem_request, &mem_answer, &alen,
-		    NDI_RA_TYPE_MEM, NDI_RA_PASS) != NDI_SUCCESS) {
+		if (pcmcia_alloc_mem(dip, mem_request, &res,
+		    &phdl->res_dip) != NDI_SUCCESS) {
 			cmn_err(CE_WARN, "Failed to allocate memory for %s\n",
 				ddi_driver_name(dip));
 			return (PCICFG_FAILURE);
 		}
 
-		phdl->memory_base = phdl->memory_last = mem_answer;
-		phdl->memory_len = alen;
+		phdl->memory_base = phdl->memory_last = res.ra_addr_lo;
+		phdl->memory_len = res.ra_len;
 	}
 
 	io_request->ra_len += cardbus_min_spare_io;
@@ -1272,21 +1273,24 @@
 		io_request->ra_flags |= NDI_RA_ALLOC_BOUNDED;
 		io_request->ra_len = PCICFG_ROUND_UP(io_request->ra_len,
 				phdl->io_gran);
-
-		if (ndi_ra_alloc(dip, io_request, &io_answer,
-		    &alen, NDI_RA_TYPE_IO, NDI_RA_PASS) != NDI_SUCCESS) {
+		io_request->ra_align_mask = max(PCICFG_IOGRAN,
+				phdl->io_gran) - 1;
+
+		if (pcmcia_alloc_io(dip, io_request, &res,
+		    &phdl->res_dip) != NDI_SUCCESS) {
 			cmn_err(CE_WARN, "Failed to allocate I/O space "
 				"for %s\n", ddi_driver_name(dip));
 			if (mem_request->ra_len) {
-				(void) ndi_ra_free(dip, mem_answer,
-					alen, NDI_RA_TYPE_MEM, NDI_RA_PASS);
+				res.ra_addr_lo = phdl->memory_base;
+				res.ra_len = phdl->memory_len;
+				(void) pcmcia_free_mem(phdl->res_dip, &res);
 				phdl->memory_len = phdl->io_len = 0;
 			}
 			return (PCICFG_FAILURE);
 		}
 
-		phdl->io_base = phdl->io_last = (uint32_t)io_answer;
-		phdl->io_len  = (uint32_t)alen;
+		phdl->io_base = phdl->io_last = (uint32_t)res.ra_addr_lo;
+		phdl->io_len  = (uint32_t)res.ra_len;
 	}
 
 #ifdef  _LP64
--- a/usr/src/uts/common/io/pcic.c	Thu Feb 15 15:33:40 2007 -0800
+++ b/usr/src/uts/common/io/pcic.c	Fri Feb 16 00:52:01 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -812,7 +812,8 @@
 		}
 	} /* ddi_prop_op("device_type") */
 
-	if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0) {
+	if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 ||
+		strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0) {
 		pcic->pc_flags = PCF_PCIBUS;
 	} else {
 #if defined(__sparc)
@@ -2128,7 +2129,7 @@
 			    (uint32_t *)(pcic->cfgaddr + PCIC_MFROUTE_REG));
 			value &= ~0xff;
 			ddi_put32(pcic->cfg_handle, (uint32_t *)(pcic->cfgaddr +
-			    PCIC_MFROUTE_REG), value|0x22);
+			    PCIC_MFROUTE_REG), value|PCIC_TI_MFUNC_SEL);
 		}
 
 		/* setup general card status change interrupt */
@@ -2810,7 +2811,7 @@
 				ddi_regs_map_free(&memp->pcw_handle);
 				res.ra_addr_lo = memp->pcw_base;
 				res.ra_len = memp->pcw_len;
-				(void) pcmcia_free_mem(dip, &res);
+				(void) pcmcia_free_mem(memp->res_dip, &res);
 				memp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
 				memp->pcw_hostmem = NULL;
 				memp->pcw_base = NULL;
@@ -2845,7 +2846,8 @@
 					    req.ra_align_mask);
 #endif
 
-				ret = pcmcia_alloc_mem(dip, &req, &res);
+				ret = pcmcia_alloc_mem(dip, &req, &res,
+					&memp->res_dip);
 				if (ret == DDI_FAILURE) {
 					mutex_exit(&pcic->pc_lock);
 					cmn_err(CE_WARN,
@@ -2880,7 +2882,7 @@
 
 				    res.ra_addr_lo = memp->pcw_base;
 				    res.ra_len = memp->pcw_len;
-				    (void) pcmcia_free_mem(pcic->dip, &res);
+				    (void) pcmcia_free_mem(memp->res_dip, &res);
 
 				    mutex_exit(&pcic->pc_lock);
 
@@ -3091,7 +3093,7 @@
 				ddi_regs_map_free(&memp->pcw_handle);
 				res.ra_addr_lo = memp->pcw_base;
 				res.ra_len = memp->pcw_len;
-				(void) pcmcia_free_mem(pcic->dip, &res);
+				(void) pcmcia_free_mem(memp->res_dip, &res);
 				memp->pcw_hostmem = NULL;
 				memp->pcw_status &= ~PCW_MAPPED;
 			}
@@ -3146,7 +3148,7 @@
 				ddi_regs_map_free(&winp->pcw_handle);
 				res.ra_addr_lo = winp->pcw_base;
 				res.ra_len = winp->pcw_len;
-				(void) pcmcia_free_io(pcic->dip, &res);
+				(void) pcmcia_free_io(winp->res_dip, &res);
 				winp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
 			}
 
@@ -3212,7 +3214,8 @@
 			 *	on whether the caller specified a
 			 *	specific base address or not.
 			 */
-			if (pcmcia_alloc_io(dip, &req, &res) == DDI_FAILURE) {
+			if (pcmcia_alloc_io(dip, &req, &res,
+					&winp->res_dip) == DDI_FAILURE) {
 				winp->pcw_status &= ~PCW_ENABLED;
 				mutex_exit(&pcic->pc_lock);
 				cmn_err(CE_WARN, "Failed to alloc I/O:\n"
@@ -3257,7 +3260,7 @@
 
 				    res.ra_addr_lo = winp->pcw_base;
 				    res.ra_len = winp->pcw_len;
-				    (void) pcmcia_free_io(pcic->dip, &res);
+				    (void) pcmcia_free_io(winp->res_dip, &res);
 
 				    mutex_exit(&pcic->pc_lock);
 				    return (BAD_WINDOW);
@@ -3431,7 +3434,7 @@
 				ddi_regs_map_free(&winp->pcw_handle);
 				res.ra_addr_lo = winp->pcw_base;
 				res.ra_len = winp->pcw_len;
-				(void) pcmcia_free_io(pcic->dip, &res);
+				(void) pcmcia_free_io(winp->res_dip, &res);
 				winp->pcw_status &= ~PCW_MAPPED;
 			}
 
@@ -5911,7 +5914,8 @@
 			    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
 			    "device_type",
 			    (caddr_t)&bus_type, &len) == DDI_SUCCESS) &&
-			    (strcmp(bus_type, "pci") == 0))
+			    (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 ||
+				strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0))
 				break;
 		}
 		if (par != NULL &&
@@ -6491,7 +6495,7 @@
 	struct debounce *dbp, **dbpp = &pcic_deb_queue;
 
 	(void) drv_getparm(LBOLT, &lbolt);
-	dbp = kmem_alloc(sizeof (struct debounce), KM_NOSLEEP);
+	dbp = kmem_alloc(sizeof (struct debounce), KM_SLEEP);
 
 	dbp->expire = lbolt + clocks;
 	dbp->pcs = pcs;
--- a/usr/src/uts/common/pcmcia/nexus/pcmcia.c	Thu Feb 15 15:33:40 2007 -0800
+++ b/usr/src/uts/common/pcmcia/nexus/pcmcia.c	Fri Feb 16 00:52:01 2007 -0800
@@ -196,6 +196,8 @@
 					sizeof (char *))
 #define	PCMCIA_MAP_IO	0x0
 #define	PCMCIA_MAP_MEM	0x1
+#define	PPB_SUBTRACTIVE	((PCI_CLASS_BRIDGE << 16) | (PCI_BRIDGE_PCI << 8) | \
+		(PCI_BRIDGE_PCI_IF_SUBDECODE))
 
 /*
  * The following should be 2^^n - 1
@@ -237,7 +239,8 @@
 static void pcmcia_ppd_free(struct pcmcia_parent_private *ppd);
 int pcmcia_get_intr(dev_info_t *, int);
 int pcmcia_return_intr(dev_info_t *, int);
-int pcmcia_ra_alloc(dev_info_t *, ndi_ra_request_t *, ra_return_t *, char *);
+int pcmcia_ra_alloc(dev_info_t *, ndi_ra_request_t *, ra_return_t *, char *,
+		dev_info_t **);
 int pcmcia_ra_free(dev_info_t *, ra_return_t *, char *);
 
 extern int cs_init(void);
@@ -4452,22 +4455,83 @@
 }
 
 int
-pcmcia_alloc_mem(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret)
+pcmcia_alloc_mem(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
+		dev_info_t **res_dip)
 {
-	return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_MEM));
+	return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_MEM, res_dip));
 }
 
 int
-pcmcia_alloc_io(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret)
+pcmcia_alloc_io(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
+		dev_info_t **res_dip)
+{
+	return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_IO, res_dip));
+}
+
+static boolean_t
+is_subtractv(dev_info_t *dip)
 {
-	return (pcmcia_ra_alloc(dip, req, ret, NDI_RA_TYPE_IO));
+	uint_t  class;
+
+	if (dip == NULL)
+		return (B_FALSE);
+	class = ddi_getprop(DDI_DEV_T_ANY, dip,
+		DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
+		"class-code", 0xff);
+	if (class == PPB_SUBTRACTIVE) {
+		return (B_TRUE);
+	}
+	return (B_FALSE);
+}
+
+/*
+ * pcmcia_pci_alloc()
+ * 	allocate mem or I/O resource from the ancestor of the cardbus bridge.
+ * 	First start from the parent node. If the parent is a subtractive
+ * 	decode bridge and it does not have the requested resource, go up the
+ * 	device tree to find the resource.
+ *
+ * 	dip		the parent node of the cardbus bridge
+ *
+ * 	res_dip		returns a pointer to the node from which the
+ * 			resource is obtained. *res_dip could point to
+ * 			the parent or a higher level ancestor. *res_dip
+ * 			should be saved by the caller and later passed
+ * 			to pcmcia_ra_free();
+ */
+int
+pcmcia_pci_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
+		char *type, dev_info_t **res_dip)
+{
+	uint64_t base = 0;
+	uint64_t len = 0;
+
+	if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS)
+							== NDI_FAILURE) ||
+	    ((base >> 32) != 0)) {
+		if (is_subtractv(dip)) {
+			return (pcmcia_pci_alloc(ddi_get_parent(dip),
+					req, ret, type, res_dip));
+
+		} else {
+			ret->ra_addr_hi = 0;
+			ret->ra_addr_lo = 0;
+			ret->ra_len = 0;
+			*res_dip = (dev_info_t *)-1;
+			return (DDI_FAILURE);
+		}
+	}
+	ret->ra_addr_lo =  base & 0xffffffff;
+	ret->ra_addr_hi = 0;
+	ret->ra_len = len;
+	*res_dip = dip;
+	return (DDI_SUCCESS);
 }
 
 int
 pcmcia_ra_alloc(dev_info_t *dip, ndi_ra_request_t *req, ra_return_t *ret,
-		char *type)
+		char *type, dev_info_t **res_dip)
 {
-	int rval;
 	uint64_t base = 0;
 	uint64_t len = 0;
 
@@ -4479,16 +4543,15 @@
 	if ((ndi_ra_alloc(dip, req, &base, &len, type, NDI_RA_PASS)
 							== NDI_FAILURE) ||
 	    ((base >> 32) != 0)) {
-		ret->ra_addr_lo = 0;
-		ret->ra_len = 0;
-		rval = DDI_FAILURE;
+		return (pcmcia_pci_alloc(ddi_get_parent(dip), req, ret,
+				type, res_dip));
 	} else {
 		ret->ra_addr_lo =  base & 0xffffffff;
+		ret->ra_addr_hi = 0;
 		ret->ra_len = len;
-		rval = DDI_SUCCESS;
+		*res_dip = dip;
+		return (DDI_SUCCESS);
 	}
-	ret->ra_addr_hi = 0;
-	return (rval);
 }
 
 int
--- a/usr/src/uts/common/sys/pcic_var.h	Thu Feb 15 15:33:40 2007 -0800
+++ b/usr/src/uts/common/sys/pcic_var.h	Fri Feb 16 00:52:01 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -79,6 +79,7 @@
 	volatile caddr_t	pcw_hostmem;
 	off_t			pcw_offset;
 	ddi_acc_handle_t	pcw_handle;
+	dev_info_t		*res_dip; /* dip from which mem is allocated */
 } pcs_memwin_t;
 
 typedef struct pci_iowin {
@@ -90,6 +91,7 @@
 				/* Cirrus Logic specific offset info */
 	int			pcw_offset;
 	ddi_acc_handle_t	pcw_handle;
+	dev_info_t		*res_dip; /* dip from which io is allocated */
 } pcs_iowin_t;
 
 #define	PCW_MAPPED	0x0001	/* window is mapped */
@@ -540,6 +542,10 @@
 #define	PCIC_DATA_LOST		0x100		/* Data lost */
 #define	PCIC_BAD_VCC_REQ	0x200		/* Bad Vcc request */
 
+
+/* TI Multi Function Terminal selection (MFUNC0 selected as INTA) */
+#define	PCIC_TI_MFUNC_SEL	0x22
+
 #define	PCICPROP_CTL		"controller"
 
 #define	PCIC_REV_LEVEL_LOW	0x02
@@ -554,6 +560,10 @@
 #define	DEVI_PCI_NEXNAME	"pci"
 #endif
 
+#ifndef DEVI_PCIEX_NEXNAME
+#define	DEVI_PCIEX_NEXNAME	"pciex"
+#endif
+
 /* PCI Class Code stuff */
 #define	PCIC_PCI_CLASS(cls, subclass)	(((cls) << 16) | ((subclass) << 8))
 #define	PCIC_PCI_PCMCIA	PCIC_PCI_CLASS(PCI_CLASS_BRIDGE, PCI_BRIDGE_PCMCIA)
--- a/usr/src/uts/common/sys/sservice.h	Thu Feb 15 15:33:40 2007 -0800
+++ b/usr/src/uts/common/sys/sservice.h	Fri Feb 16 00:52:01 2007 -0800
@@ -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 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -570,8 +569,10 @@
 	uint_t	ra_len;
 } ra_return_t;
 
-int pcmcia_alloc_mem(dev_info_t *, ndi_ra_request_t *, ra_return_t *);
-int pcmcia_alloc_io(dev_info_t *, ndi_ra_request_t *, ra_return_t *);
+int pcmcia_alloc_mem(dev_info_t *, ndi_ra_request_t *, ra_return_t *,
+		dev_info_t **);
+int pcmcia_alloc_io(dev_info_t *, ndi_ra_request_t *, ra_return_t *,
+		dev_info_t **);
 int pcmcia_free_mem(dev_info_t *, ra_return_t *);
 int pcmcia_free_io(dev_info_t *, ra_return_t *);
 int pcmcia_map_reg(dev_info_t *, dev_info_t *, ra_return_t *,