xref: /illumos-gate/usr/src/uts/common/io/cardbus/cardbus.c (revision d74fa75ecbb3506071638c87d211a33ecce72271)
13db86aabSstevel /*
23db86aabSstevel  * CDDL HEADER START
33db86aabSstevel  *
43db86aabSstevel  * The contents of this file are subject to the terms of the
53db86aabSstevel  * Common Development and Distribution License (the "License").
63db86aabSstevel  * You may not use this file except in compliance with the License.
73db86aabSstevel  *
83db86aabSstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93db86aabSstevel  * or http://www.opensolaris.org/os/licensing.
103db86aabSstevel  * See the License for the specific language governing permissions
113db86aabSstevel  * and limitations under the License.
123db86aabSstevel  *
133db86aabSstevel  * When distributing Covered Code, include this CDDL HEADER in each
143db86aabSstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153db86aabSstevel  * If applicable, add the following below this CDDL HEADER, with the
163db86aabSstevel  * fields enclosed by brackets "[]" replaced with your own identifying
173db86aabSstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
183db86aabSstevel  *
193db86aabSstevel  * CDDL HEADER END
203db86aabSstevel  */
213db86aabSstevel /*
2211c2b4c0Srw148561  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
233db86aabSstevel  * Use is subject to license terms.
243db86aabSstevel  */
253db86aabSstevel 
263db86aabSstevel /*
273db86aabSstevel  * Copyright (c)  * Copyright (c) 2001 Tadpole Technology plc
283db86aabSstevel  * All rights reserved.
293db86aabSstevel  * From "@(#)pcicfg.c   1.31    99/06/18 SMI"
303db86aabSstevel  */
313db86aabSstevel 
323db86aabSstevel /*
333fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
343fe80ca4SDan Cross  */
353fe80ca4SDan Cross 
363fe80ca4SDan Cross /*
373db86aabSstevel  * Cardbus module
383db86aabSstevel  */
393db86aabSstevel 
403db86aabSstevel #include <sys/conf.h>
413db86aabSstevel #include <sys/modctl.h>
423db86aabSstevel 
433db86aabSstevel #include <sys/pci.h>
443db86aabSstevel 
453db86aabSstevel #include <sys/ddi.h>
463db86aabSstevel #include <sys/sunndi.h>
473db86aabSstevel #include <sys/ddi_impldefs.h>
483db86aabSstevel 
493db86aabSstevel #include <sys/hotplug/hpcsvc.h>
503db86aabSstevel 
513db86aabSstevel #include <sys/pctypes.h>
523db86aabSstevel #include <sys/pcmcia.h>
533db86aabSstevel #include <sys/sservice.h>
543db86aabSstevel #include <sys/note.h>
553db86aabSstevel 
563db86aabSstevel #include <sys/pci/pci_types.h>
573db86aabSstevel #include <sys/pci/pci_sc.h>
583db86aabSstevel 
593db86aabSstevel #include <sys/pcic_reg.h>
603db86aabSstevel #include <sys/pcic_var.h>
613db86aabSstevel #include <sys/pcmcia.h>
623db86aabSstevel 
633db86aabSstevel #ifdef sparc
643db86aabSstevel #include <sys/ddi_subrdefs.h>
6586ef0a63SRichard Lowe #elif defined(__x86)
663db86aabSstevel #include <sys/pci_intr_lib.h>
673db86aabSstevel #include <sys/mach_intr.h>
683db86aabSstevel #endif
693db86aabSstevel 
703db86aabSstevel #include "cardbus.h"
713db86aabSstevel #include "cardbus_parse.h"
723db86aabSstevel #include "cardbus_hp.h"
733db86aabSstevel #include "cardbus_cfg.h"
743db86aabSstevel 
753db86aabSstevel static int cardbus_command_default = PCI_COMM_SERR_ENABLE |
763db86aabSstevel 				PCI_COMM_WAIT_CYC_ENAB |
773db86aabSstevel 				PCI_COMM_PARITY_DETECT |
783db86aabSstevel 				PCI_COMM_ME | PCI_COMM_MAE |
793db86aabSstevel 				PCI_COMM_IO;
803db86aabSstevel 
813db86aabSstevel static int cardbus_next_instance = 0;
823db86aabSstevel static int cardbus_count = 0;
830d282d13Srw148561 int number_of_cardbus_cards = 0;
843db86aabSstevel 
853db86aabSstevel static int cardbus_bus_map(dev_info_t *dip, dev_info_t *rdip,
863db86aabSstevel 		ddi_map_req_t *mp, off_t offset, off_t len, caddr_t *vaddrp);
873db86aabSstevel static void pcirp2rp(const pci_regspec_t *pci_rp, struct regspec *rp);
883db86aabSstevel 
893db86aabSstevel static int cardbus_ctlops(dev_info_t *, dev_info_t *,
903db86aabSstevel 			ddi_ctl_enum_t, void *arg, void *);
913db86aabSstevel static void cardbus_init_child_regs(dev_info_t *child);
923db86aabSstevel static int cardbus_initchild(dev_info_t *, dev_info_t *,
933db86aabSstevel 			dev_info_t *, void *);
943db86aabSstevel static int cardbus_name_child(dev_info_t *, char *, int);
953db86aabSstevel static void cardbus_removechild(dev_info_t *dip);
963db86aabSstevel 
973db86aabSstevel static int cardbus_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
983db86aabSstevel 		ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg,
993db86aabSstevel 		ddi_dma_handle_t *handlep);
1003db86aabSstevel static int cardbus_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
1013db86aabSstevel 		ddi_dma_handle_t handle);
1023db86aabSstevel static int cardbus_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
1033db86aabSstevel 		ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
1043db86aabSstevel 		ddi_dma_cookie_t *cp, uint_t *ccountp);
1053db86aabSstevel static int cardbus_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
1063db86aabSstevel 		ddi_dma_handle_t handle);
1073db86aabSstevel static int cardbus_dma_flush(dev_info_t *dip, dev_info_t *rdip,
1083db86aabSstevel 		ddi_dma_handle_t handle, off_t off, size_t len,
1093db86aabSstevel 		uint_t cache_flags);
1103db86aabSstevel static int cardbus_dma_win(dev_info_t *dip, dev_info_t *rdip,
1113db86aabSstevel 		ddi_dma_handle_t handle, uint_t win, off_t *offp,
1123db86aabSstevel 		size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp);
1133db86aabSstevel static int cardbus_dma_map(dev_info_t *dip, dev_info_t *rdip,
1143db86aabSstevel 		struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep);
1153db86aabSstevel 
1163db86aabSstevel static int cardbus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
1173db86aabSstevel 		ddi_prop_op_t prop_op, int mod_flags,
1183db86aabSstevel 		char *name, caddr_t valuep, int *lengthp);
1193db86aabSstevel 
1203db86aabSstevel static int cardbus_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
1213db86aabSstevel 		char *eventname, ddi_eventcookie_t *cookiep);
1223db86aabSstevel static int cardbus_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
1233db86aabSstevel 		ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
1243db86aabSstevel 		ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
1253db86aabSstevel 		void *arg, ddi_callback_id_t *cb_id);
1263db86aabSstevel static int cardbus_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id);
1273db86aabSstevel static int cardbus_post_event(dev_info_t *dip, dev_info_t *rdip,
1283db86aabSstevel 		ddi_eventcookie_t cookie, void *bus_impldata);
1293db86aabSstevel 
1303db86aabSstevel static int cardbus_intr_ops(dev_info_t *dip, dev_info_t *rdip,
1313db86aabSstevel 		ddi_intr_op_t intr_op,
1323db86aabSstevel 		ddi_intr_handle_impl_t *hdlp, void *result);
1333db86aabSstevel 
1343db86aabSstevel static int check_token(char *token, int *len);
1353db86aabSstevel static char *find_token(char **cp, int *l, char *endc);
1363db86aabSstevel static int parse_token(char *token);
1373db86aabSstevel static int token_to_hex(char *token, unsigned *val, int len);
1383db86aabSstevel static int token_to_dec(char *token, unsigned *val, int len);
1393db86aabSstevel static void cardbus_add_prop(struct cb_deviceset_props *cdsp, int type,
1403db86aabSstevel 		char *name, caddr_t vp, int len);
1413db86aabSstevel static void cardbus_add_stringprop(struct cb_deviceset_props *cdsp,
1423db86aabSstevel 		char *name, char *vp, int len);
1433db86aabSstevel static void cardbus_prop_free(ddi_prop_t *propp);
1443db86aabSstevel static void cardbus_devprops_free(struct cb_deviceset_props *cbdp);
1453db86aabSstevel static int cardbus_parse_devprop(cbus_t *cbp, char *cp);
1463db86aabSstevel static void cardbus_device_props(cbus_t *cbp);
1473db86aabSstevel 
1483db86aabSstevel static void cardbus_expand_busrange(dev_info_t *dip);
1493db86aabSstevel 
1503db86aabSstevel static int cardbus_convert_properties(dev_info_t *dip);
1513db86aabSstevel static void cardbus_revert_properties(dev_info_t *dip);
1523db86aabSstevel 
1533db86aabSstevel /*
1543db86aabSstevel  * driver global data
1553db86aabSstevel  */
1563db86aabSstevel kmutex_t cardbus_list_mutex; /* Protects the probe handle list */
1573db86aabSstevel void *cardbus_state;
1583db86aabSstevel int cardbus_latency_timer = 0x40;
1593db86aabSstevel int cardbus_debug = 0;
1603db86aabSstevel 
1613db86aabSstevel /*
1623db86aabSstevel  * Module linkage information for the kernel.
1633db86aabSstevel  */
1643db86aabSstevel extern struct mod_ops mod_miscops;
1653db86aabSstevel static struct modlmisc modlmisc = {
1663db86aabSstevel 	&mod_miscops,
167903a11ebSrh87107 	"Cardbus Configurator support",
1683db86aabSstevel };
1693db86aabSstevel 
1703db86aabSstevel static struct modlinkage modlinkage = {
1713db86aabSstevel 	MODREV_1,
1723db86aabSstevel 	&modlmisc,
1733db86aabSstevel 	NULL
1743db86aabSstevel };
1753db86aabSstevel 
1763db86aabSstevel int
_init(void)1773db86aabSstevel _init(void)
1783db86aabSstevel {
1793db86aabSstevel 	int error;
1803db86aabSstevel 
1813db86aabSstevel 	error =  ddi_soft_state_init(&cardbus_state, sizeof (cbus_t), 0);
1823db86aabSstevel 	if (error != 0)
1833db86aabSstevel 		return (error);
1843db86aabSstevel 
1853db86aabSstevel 	mutex_init(&cardbus_list_mutex, NULL, MUTEX_DRIVER, NULL);
1863db86aabSstevel 	if ((error = mod_install(&modlinkage)) != 0) {
1873db86aabSstevel 		mutex_destroy(&cardbus_list_mutex);
1883db86aabSstevel 	}
1893db86aabSstevel 
1903db86aabSstevel 	return (error);
1913db86aabSstevel }
1923db86aabSstevel 
1933db86aabSstevel int
_fini(void)1943db86aabSstevel _fini(void)
1953db86aabSstevel {
1963db86aabSstevel 	int error;
1973db86aabSstevel 	if ((error = mod_remove(&modlinkage)) == 0) {
1983db86aabSstevel 		mutex_destroy(&cardbus_list_mutex);
1993db86aabSstevel 		ddi_soft_state_fini(&cardbus_state);
2003db86aabSstevel 	}
2013db86aabSstevel 	return (error);
2023db86aabSstevel }
2033db86aabSstevel 
2043db86aabSstevel int
_info(struct modinfo * modinfop)2053db86aabSstevel _info(struct modinfo *modinfop)
2063db86aabSstevel {
2073db86aabSstevel 	return (mod_info(&modlinkage, modinfop));
2083db86aabSstevel }
2093db86aabSstevel 
2103db86aabSstevel static
2113db86aabSstevel struct bus_ops cardbusbus_ops = {
2123db86aabSstevel 	BUSO_REV,
2133db86aabSstevel 	cardbus_bus_map,
2143db86aabSstevel 	NULL,
2153db86aabSstevel 	NULL,
2163db86aabSstevel 	NULL,
2173db86aabSstevel 	i_ddi_map_fault,
2183db86aabSstevel 	cardbus_dma_map,
2193db86aabSstevel 	cardbus_dma_allochdl,
2203db86aabSstevel 	cardbus_dma_freehdl,
2213db86aabSstevel 	cardbus_dma_bindhdl,
2223db86aabSstevel 	cardbus_dma_unbindhdl,
2233db86aabSstevel 	cardbus_dma_flush,
2243db86aabSstevel 	cardbus_dma_win,
2253db86aabSstevel 	ddi_dma_mctl,
2263db86aabSstevel 	cardbus_ctlops,			/* (*bus_ctl)();		*/
2273db86aabSstevel 	cardbus_prop_op,
2283db86aabSstevel 	cardbus_get_eventcookie,	/* (*bus_get_eventcookie)();	*/
2293db86aabSstevel 	cardbus_add_eventcall,		/* (*bus_add_eventcall)();	*/
2303db86aabSstevel 	cardbus_remove_eventcall,	/* (*bus_remove_eventcall)();	*/
2313db86aabSstevel 	cardbus_post_event,		/* (*bus_post_event)();		*/
2323db86aabSstevel 	NULL,				/* (*bus_intr_ctl)();		*/
2333db86aabSstevel 	NULL,				/* (*bus_config)();		*/
2343db86aabSstevel 	NULL,				/* (*bus_unconfig)();		*/
2353db86aabSstevel 	NULL,				/* (*bus_fm_init)();		*/
2363db86aabSstevel 	NULL,				/* (*bus_fm_fini)();		*/
2373db86aabSstevel 	NULL,				/* (*bus_enter)();		*/
2383db86aabSstevel 	NULL,				/* (*bus_exit)();		*/
2393db86aabSstevel 	NULL,				/* (*bus_power)();		*/
2403db86aabSstevel 	cardbus_intr_ops		/* (*bus_intr_op)();		*/
2413db86aabSstevel };
2423db86aabSstevel 
2433db86aabSstevel #define	CB_EVENT_TAG_INSERT	0
2443db86aabSstevel #define	CB_EVENT_TAG_REMOVE	1
2453db86aabSstevel 
2463db86aabSstevel static ndi_event_definition_t cb_ndi_event_defs[] = {
2473db86aabSstevel 	{ CB_EVENT_TAG_INSERT, DDI_DEVI_INSERT_EVENT, EPL_INTERRUPT, 0 },
2483db86aabSstevel 	{ CB_EVENT_TAG_REMOVE, DDI_DEVI_REMOVE_EVENT, EPL_INTERRUPT, 0 }
2493db86aabSstevel };
2503db86aabSstevel 
2513db86aabSstevel #define	CB_N_NDI_EVENTS \
2523db86aabSstevel 	(sizeof (cb_ndi_event_defs) / sizeof (cb_ndi_event_defs[0]))
2533db86aabSstevel 
2543db86aabSstevel #ifdef sparc
2553db86aabSstevel struct busnum_ctrl {
2563db86aabSstevel 	int	rv;
2573db86aabSstevel 	dev_info_t *dip;
2583db86aabSstevel 	cardbus_bus_range_t *range;
2593db86aabSstevel };
2603db86aabSstevel 
2613db86aabSstevel static int
cardbus_claim_pci_busnum(dev_info_t * dip,void * arg)2623db86aabSstevel cardbus_claim_pci_busnum(dev_info_t *dip, void *arg)
2633db86aabSstevel {
2643db86aabSstevel 	cardbus_bus_range_t pci_bus_range;
2653db86aabSstevel 	struct busnum_ctrl *ctrl;
2663db86aabSstevel 	ndi_ra_request_t req;
2673db86aabSstevel 	char bus_type[16] = "(unknown)";
2683db86aabSstevel 	int len;
2693db86aabSstevel 	uint64_t base;
2703db86aabSstevel 	uint64_t retlen;
2713db86aabSstevel 
2723db86aabSstevel 	ctrl = (struct busnum_ctrl *)arg;
2733db86aabSstevel 
2743db86aabSstevel 	/* check if this is a PCI bus node */
2753db86aabSstevel 	len = sizeof (bus_type);
2763db86aabSstevel 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
2773db86aabSstevel 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
2783db86aabSstevel 	    "device_type",
2793db86aabSstevel 	    (caddr_t)&bus_type, &len) != DDI_SUCCESS)
2803db86aabSstevel 		return (0);	/* (DDI_WALK_PRUNECHILD); */
2813db86aabSstevel 
2823db86aabSstevel 	if ((strcmp(bus_type, "pci") != 0) &&
2833db86aabSstevel 	    (strcmp(bus_type, "pciex") != 0)) /* it is not a pci bus type */
2843db86aabSstevel 		return (0);	/* (DDI_WALK_PRUNECHILD); */
2853db86aabSstevel 
2863db86aabSstevel 	/* look for the bus-range property */
2873db86aabSstevel 	len = sizeof (struct cardbus_bus_range);
2883db86aabSstevel 	if (ddi_getlongprop_buf(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
2893db86aabSstevel 	    "bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) {
2903db86aabSstevel 		cardbus_err(dip, 1, "cardbus_claim_pci_busnum: %u -> %u \n",
2913db86aabSstevel 		    pci_bus_range.lo, pci_bus_range.hi);
2923db86aabSstevel 		if ((pci_bus_range.lo >= ctrl->range->lo) &&
2933db86aabSstevel 		    (pci_bus_range.hi <= ctrl->range->hi)) {
2943db86aabSstevel 			cardbus_err(dip, 1,
2953db86aabSstevel 			    "cardbus_claim_pci_busnum: claim %u -> %u \n",
2963db86aabSstevel 			    pci_bus_range.lo, pci_bus_range.hi);
2973db86aabSstevel 
2983db86aabSstevel 			/* claim the bus range from the bus resource map */
2993db86aabSstevel 			bzero((caddr_t)&req, sizeof (req));
3003db86aabSstevel 			req.ra_addr = (uint64_t)pci_bus_range.lo;
3013db86aabSstevel 			req.ra_flags |= NDI_RA_ALLOC_SPECIFIED;
3023db86aabSstevel 			req.ra_len = (uint64_t)pci_bus_range.hi -
3033db86aabSstevel 			    (uint64_t)pci_bus_range.lo + 1;
3043db86aabSstevel 
3053db86aabSstevel 			if (ndi_ra_alloc(ctrl->dip, &req, &base, &retlen,
3063db86aabSstevel 			    NDI_RA_TYPE_PCI_BUSNUM, 0) == NDI_SUCCESS)
3073db86aabSstevel 				return (0);	/* (DDI_WALK_PRUNECHILD); */
3083db86aabSstevel 		}
3093db86aabSstevel 	}
3103db86aabSstevel 
3113db86aabSstevel 	/*
3123db86aabSstevel 	 * never Error return.
3133db86aabSstevel 	 */
3143db86aabSstevel 	ctrl->rv = DDI_SUCCESS;
3153db86aabSstevel 	return (DDI_WALK_TERMINATE);
3163db86aabSstevel }
3173db86aabSstevel 
3183db86aabSstevel static void
cardbus_walk_node_child(dev_info_t * parent,int (* f)(dev_info_t *,void *),void * arg)3193db86aabSstevel cardbus_walk_node_child(dev_info_t *parent,
3203db86aabSstevel     int (*f)(dev_info_t *, void *), void *arg)
3213db86aabSstevel {
3223db86aabSstevel 	dev_info_t *dip;
3233db86aabSstevel 	int ret;
3243db86aabSstevel 
3253db86aabSstevel 	for (dip = ddi_get_child(parent); dip;
3263db86aabSstevel 	    dip = ddi_get_next_sibling(dip)) {
3273db86aabSstevel 
3283db86aabSstevel 		ret = (*f) (dip, arg);
3293db86aabSstevel 		if (ret)
3303db86aabSstevel 			return;
3313db86aabSstevel 	}
3323db86aabSstevel }
3333db86aabSstevel 
cardbus_fix_hostbridge_busrange(dev_info_t * dip)3343db86aabSstevel static void cardbus_fix_hostbridge_busrange(dev_info_t *dip)
3353db86aabSstevel {
3363db86aabSstevel 	cardbus_bus_range_t bus_range;
3373db86aabSstevel 	struct busnum_ctrl ctrl;
3383db86aabSstevel 
3393db86aabSstevel 	uint64_t next_bus;
3403db86aabSstevel 	uint64_t blen;
3413db86aabSstevel 	ndi_ra_request_t req;
3423db86aabSstevel 	int	len;
3433db86aabSstevel 
3443db86aabSstevel 	cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange\n");
3453db86aabSstevel 
3463db86aabSstevel 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
3473db86aabSstevel 	req.ra_len = 1;
3483db86aabSstevel 	if (ndi_ra_alloc(dip, &req,
3493db86aabSstevel 	    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
3503db86aabSstevel 	    0) != NDI_SUCCESS) {
3513db86aabSstevel 		(void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_BUSNUM);
3523db86aabSstevel 
3533db86aabSstevel 		if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM)
3543db86aabSstevel 		    == NDI_FAILURE) {
3553db86aabSstevel 			cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
3563db86aabSstevel 			    "NDI_RA_TYPE_PCI_BUSNUM setup fail\n");
3573db86aabSstevel 			return;
3583db86aabSstevel 		}
3593db86aabSstevel 
3603db86aabSstevel 		bus_range.lo = 0;
3613db86aabSstevel 		(void) ddi_getlongprop_buf(DDI_DEV_T_NONE, dip,
3623db86aabSstevel 		    DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus_range, &len);
3633db86aabSstevel 		bus_range.hi = 255;
3643db86aabSstevel 
3653db86aabSstevel 		(void) ndi_ra_free(dip,
3663db86aabSstevel 		    (uint64_t)bus_range.lo + 1,
3673db86aabSstevel 		    (uint64_t)bus_range.hi - (uint64_t)bus_range.lo,
3683db86aabSstevel 		    NDI_RA_TYPE_PCI_BUSNUM, 0);
3693db86aabSstevel 
3703db86aabSstevel 		ctrl.rv = DDI_SUCCESS;
3713db86aabSstevel 		ctrl.dip = dip;
3723db86aabSstevel 		ctrl.range = &bus_range;
3733db86aabSstevel 
3743db86aabSstevel 		cardbus_walk_node_child(dip, cardbus_claim_pci_busnum,
3753db86aabSstevel 		    (void*)&ctrl);
3763db86aabSstevel 
3773db86aabSstevel 		if (ctrl.rv != DDI_SUCCESS)
3783db86aabSstevel 			cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
3793db86aabSstevel 			    "cardbus_walk_node_child fails\n");
3803db86aabSstevel 
3813db86aabSstevel 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
3823db86aabSstevel 		    "bus-range", (int *)&bus_range, 2);
3833db86aabSstevel 
3843db86aabSstevel 	} else {
3853db86aabSstevel 		cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
3863db86aabSstevel 		    "already set up %x\n", (int)next_bus);
3873db86aabSstevel 		(void) ndi_ra_free(dip, next_bus, (uint64_t)1,
3883db86aabSstevel 		    NDI_RA_TYPE_PCI_BUSNUM, 0);
3893db86aabSstevel 	}
3903db86aabSstevel }
3913db86aabSstevel 
3923db86aabSstevel static dev_info_t *
cardbus_find_hsbridge_dip(dev_info_t * dip)3933db86aabSstevel cardbus_find_hsbridge_dip(dev_info_t *dip)
3943db86aabSstevel {
3953db86aabSstevel 	dev_info_t *pdip;
3963db86aabSstevel 
3973db86aabSstevel 	pdip = ddi_get_parent(dip);
3983db86aabSstevel 	while (pdip) {
3993db86aabSstevel 		if (ddi_get_parent(pdip) == ddi_root_node())
4003db86aabSstevel 			break;
4013db86aabSstevel 		pdip = ddi_get_parent(pdip);
4023db86aabSstevel 	}
4033db86aabSstevel 
4043db86aabSstevel 	return (pdip);
4053db86aabSstevel }
4063db86aabSstevel #endif /* sparc */
4073db86aabSstevel 
4083db86aabSstevel /*
4093db86aabSstevel  * Attach a device to the cardbus infrastructure.
4103db86aabSstevel  */
4113db86aabSstevel int
cardbus_attach(dev_info_t * dip,cb_nexus_cb_t * nex_ops)4123db86aabSstevel cardbus_attach(dev_info_t *dip, cb_nexus_cb_t *nex_ops)
4133db86aabSstevel {
4143db86aabSstevel 	cbus_t *cbp;
4153db86aabSstevel 	int cb_instance;
4163db86aabSstevel 	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
4173db86aabSstevel 	struct dev_info *devi = DEVI(dip);
4183db86aabSstevel 
4193db86aabSstevel 	mutex_enter(&cardbus_list_mutex);
4203db86aabSstevel 
4213db86aabSstevel 	/*
4223db86aabSstevel 	 * Make sure that it is not already initialized.
4233db86aabSstevel 	 */
4243db86aabSstevel 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip,
4253db86aabSstevel 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
4263db86aabSstevel 	    "cbus-instance") == 1) {
4273db86aabSstevel 		cmn_err(CE_WARN,
4283db86aabSstevel 		    "%s%d: cardbus instance already initialized!\n",
4293db86aabSstevel 		    ddi_driver_name(dip), ddi_get_instance(dip));
4303db86aabSstevel 			mutex_exit(&cardbus_list_mutex);
4313db86aabSstevel 		return (DDI_FAILURE);
4323db86aabSstevel 	}
4333db86aabSstevel 
4343db86aabSstevel 	/*
4353db86aabSstevel 	 * initialize soft state structure for the bus instance.
4363db86aabSstevel 	 */
4373db86aabSstevel 	cb_instance = cardbus_next_instance++;
4383db86aabSstevel 
4393db86aabSstevel 	if (ddi_soft_state_zalloc(cardbus_state, cb_instance) != DDI_SUCCESS) {
4403db86aabSstevel 		cmn_err(CE_WARN, "%s%d: can't allocate cardbus soft state\n",
4413db86aabSstevel 		    ddi_driver_name(dip), ddi_get_instance(dip));
4423db86aabSstevel 		mutex_exit(&cardbus_list_mutex);
4433db86aabSstevel 		return (DDI_FAILURE);
4443db86aabSstevel 	}
4453db86aabSstevel 
4463db86aabSstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
4473db86aabSstevel 	cbp->cb_instance = cb_instance;
4483db86aabSstevel 	cbp->cb_dip = dip;
4493db86aabSstevel 	mutex_init(&cbp->cb_mutex, NULL, MUTEX_DRIVER, NULL);
4503db86aabSstevel 
4513db86aabSstevel 	/*
4523db86aabSstevel 	 * Save the instance number of the soft state structure for
4533db86aabSstevel 	 * this bus as a devinfo property.
4543db86aabSstevel 	 */
4553db86aabSstevel 	if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
4563db86aabSstevel 	    "cbus-instance", (caddr_t)&cb_instance,
4573db86aabSstevel 	    sizeof (cb_instance)) != DDI_SUCCESS) {
4583db86aabSstevel 		cmn_err(CE_WARN,
4593db86aabSstevel 		    "%s%d: failed to add the property 'cbus-instance'",
4603db86aabSstevel 		    ddi_driver_name(dip), ddi_get_instance(dip));
4613db86aabSstevel 		ddi_soft_state_free(cardbus_state, cb_instance);
4623db86aabSstevel 		mutex_exit(&cardbus_list_mutex);
4633db86aabSstevel 		return (DDI_FAILURE);
4643db86aabSstevel 	}
4653db86aabSstevel 
4663db86aabSstevel 	cbp->cb_nex_ops = nex_ops;
4673db86aabSstevel 	/*
4683db86aabSstevel 	 * TODO - Should probably be some sort of locking on the devinfo here.
4693db86aabSstevel 	 */
4703db86aabSstevel 	cbp->orig_dopsp = devi->devi_ops;
4713db86aabSstevel 	cbp->orig_bopsp = devi->devi_ops->devo_bus_ops;
4723db86aabSstevel 	cbp->cb_dops = *devi->devi_ops;
4733db86aabSstevel 	devi->devi_ops = &cbp->cb_dops;
4743db86aabSstevel 
4753db86aabSstevel 	if (ndi_event_alloc_hdl(dip, *anp->an_iblock, &cbp->cb_ndi_event_hdl,
4763db86aabSstevel 	    NDI_SLEEP) == NDI_SUCCESS) {
4773db86aabSstevel 		cbp->cb_ndi_events.ndi_n_events = CB_N_NDI_EVENTS;
4783db86aabSstevel 		cbp->cb_ndi_events.ndi_events_version = NDI_EVENTS_REV1;
4793db86aabSstevel 		cbp->cb_ndi_events.ndi_event_defs = cb_ndi_event_defs;
4803db86aabSstevel 		if (ndi_event_bind_set(cbp->cb_ndi_event_hdl,
4813db86aabSstevel 		    &cbp->cb_ndi_events,
4823db86aabSstevel 		    NDI_SLEEP) != NDI_SUCCESS) {
4833db86aabSstevel 			cardbus_err(dip, 1,
4843db86aabSstevel 			    "cardbus_attach: ndi_event_bind_set failed\n");
4853db86aabSstevel 		}
4863db86aabSstevel 	}
4873db86aabSstevel 
4883db86aabSstevel 	/*
4893db86aabSstevel 	 * Check for device initialization property.
4903db86aabSstevel 	 */
4913db86aabSstevel 	cardbus_device_props(cbp);
4923db86aabSstevel 
4933db86aabSstevel 	if (cardbus_init_hotplug(cbp) != DDI_SUCCESS) {
4943db86aabSstevel 		ddi_soft_state_free(cardbus_state, cb_instance);
4953db86aabSstevel 		mutex_exit(&cardbus_list_mutex);
4963db86aabSstevel 		return (DDI_FAILURE);
4973db86aabSstevel 	}
4983db86aabSstevel 
4993db86aabSstevel #ifdef sparc
5003db86aabSstevel 	/* a hack to fix the bus-range problem on pci root nodes */
5013db86aabSstevel 	{
5023db86aabSstevel 		dev_info_t *hs_dip;
5033db86aabSstevel 
5043db86aabSstevel 		hs_dip = cardbus_find_hsbridge_dip(dip);
5053db86aabSstevel 		cardbus_fix_hostbridge_busrange(hs_dip);
5063db86aabSstevel 	}
5073db86aabSstevel #endif
5083db86aabSstevel 
5093db86aabSstevel 	cardbus_expand_busrange(dip);
5103db86aabSstevel 	cardbus_count++;
5113db86aabSstevel 	mutex_exit(&cardbus_list_mutex);
5123db86aabSstevel 	return (DDI_SUCCESS);
5133db86aabSstevel }
5143db86aabSstevel 
5153db86aabSstevel #ifdef TODO
5163db86aabSstevel static int
cardbus_detach(dev_info_t * dip)5173db86aabSstevel cardbus_detach(dev_info_t *dip)
5183db86aabSstevel {
5193db86aabSstevel 	int cb_instance;
5203db86aabSstevel 	cbus_t *cbp;
5213db86aabSstevel 
5223db86aabSstevel 	mutex_enter(&cardbus_list_mutex);
5233db86aabSstevel 	/* get the instance number for the cardbus soft state data */
5243db86aabSstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
5253db86aabSstevel 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
5263db86aabSstevel 	if (cb_instance < 0) {
5273db86aabSstevel 		mutex_exit(&cardbus_list_mutex);
5283db86aabSstevel 		return (DDI_FAILURE); /* no instance is setup for this bus */
5293db86aabSstevel 	}
5303db86aabSstevel 
5313db86aabSstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
5323db86aabSstevel 
5333db86aabSstevel 	if (cbp->cb_dsp) {
5343db86aabSstevel 		struct cb_deviceset_props *cbdp, *ncbdp;
5353db86aabSstevel 
5363db86aabSstevel 		cbdp = cbp->cb_dsp;
5373db86aabSstevel 		while (cbdp) {
5383db86aabSstevel 			ncbdp = cbdp->next;
5393db86aabSstevel 			cardbus_devprops_free(cbdp);
5403db86aabSstevel 			cbdp = ncbdp;
5413db86aabSstevel 		}
5423db86aabSstevel 	}
5433db86aabSstevel 	/*
5443db86aabSstevel 	 * Unregister the bus with the HPS.
5453db86aabSstevel 	 *
5463db86aabSstevel 	 * (Note: It is assumed that the HPS framework uninstalls
5473db86aabSstevel 	 *  event handlers for all the hot plug slots on this bus.)
5483db86aabSstevel 	 */
5493db86aabSstevel 	(void) hpc_nexus_unregister_bus(dip);
5503db86aabSstevel 
5513db86aabSstevel 	if (cbp->cb_ndi_event_hdl != NULL) {
5523db86aabSstevel 		(void) ndi_event_unbind_set(cbp->cb_ndi_event_hdl,
5533db86aabSstevel 		    &cbp->cb_ndi_events, NDI_SLEEP);
5543db86aabSstevel 		ndi_event_free_hdl(cbp->cb_ndi_event_hdl);
5553db86aabSstevel 	}
5563db86aabSstevel 
5573db86aabSstevel 	mutex_destroy(&cbp->cb_mutex);
5583db86aabSstevel 	if (cbp->nexus_path)
5593db86aabSstevel 		kmem_free(cbp->nexus_path, strlen(cbp->nexus_path) + 1);
5603db86aabSstevel 	if (cbp->name)
5613db86aabSstevel 		kmem_free(cbp->name, strlen(cbp->name) + 1);
5623db86aabSstevel 
5633db86aabSstevel 	ddi_soft_state_free(cardbus_state, cb_instance);
5643db86aabSstevel 
5653db86aabSstevel 	/* remove the 'cbus-instance' property from the devinfo node */
5663db86aabSstevel 	(void) ddi_prop_remove(DDI_DEV_T_ANY, dip, "cbus-instance");
5673db86aabSstevel 
5683db86aabSstevel 	ASSERT(cardbus_count != 0);
5693db86aabSstevel 	--cardbus_count;
5703db86aabSstevel 
5713db86aabSstevel 	mutex_exit(&cardbus_list_mutex);
5723db86aabSstevel 	return (DDI_SUCCESS);
5733db86aabSstevel }
5743db86aabSstevel #endif
5753db86aabSstevel 
5763db86aabSstevel boolean_t
cardbus_load_cardbus(dev_info_t * dip,uint_t socket,uint32_t pc_base)5773db86aabSstevel cardbus_load_cardbus(dev_info_t *dip, uint_t socket, uint32_t pc_base)
5783db86aabSstevel {
5793db86aabSstevel #ifndef HOTPLUG
5803db86aabSstevel 	struct cardbus_config_ctrl ctrl;
5813db86aabSstevel #endif
5823db86aabSstevel 	int cb_instance;
5833db86aabSstevel 	cbus_t *cbp;
5843db86aabSstevel 	struct dev_info *devi = DEVI(dip);
5853db86aabSstevel 
5863db86aabSstevel 	_NOTE(ARGUNUSED(socket, pc_base))
5873db86aabSstevel 
5883db86aabSstevel #if defined(CARDBUS_DEBUG)
5893db86aabSstevel 	cardbus_err(dip, 6, "cardbus_load_cardbus\n");
5903db86aabSstevel #endif
5913db86aabSstevel 
5923db86aabSstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
5933db86aabSstevel 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
5943db86aabSstevel 	ASSERT(cb_instance >= 0);
5953db86aabSstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
5963db86aabSstevel 
5973db86aabSstevel 	if (cbp->fatal_problem)
5983db86aabSstevel 		return (B_FALSE);
5993db86aabSstevel 
6003db86aabSstevel 	if (cardbus_convert_properties(dip) == DDI_FAILURE)
6013db86aabSstevel 		return (B_FALSE);
6023db86aabSstevel 
6033db86aabSstevel 	number_of_cardbus_cards++;
6043db86aabSstevel 	devi->devi_ops->devo_bus_ops = &cardbusbus_ops;
6053db86aabSstevel 
6063db86aabSstevel #ifdef HOTPLUG
6073db86aabSstevel 	mutex_enter(&cbp->cb_mutex);
6083db86aabSstevel 	cbp->card_present = B_TRUE;
6093db86aabSstevel 
6103db86aabSstevel 	(void) hpc_slot_event_notify(cbp->slot_handle,
6113db86aabSstevel 	    HPC_EVENT_SLOT_INSERTION, 0);
6123db86aabSstevel 	(void) hpc_slot_event_notify(cbp->slot_handle,
6133db86aabSstevel 	    HPC_EVENT_SLOT_POWER_ON, 0);
6143db86aabSstevel 	(void) hpc_slot_event_notify(cbp->slot_handle,
6153db86aabSstevel 	    HPC_EVENT_SLOT_CONFIGURE, 0);
6163db86aabSstevel 
6173db86aabSstevel 	mutex_exit(&cbp->cb_mutex);
6183db86aabSstevel #else
6193db86aabSstevel 	if (cardbus_configure(cbp) != PCICFG_SUCCESS) {
6203db86aabSstevel #if defined(CARDBUS_DEBUG)
6213db86aabSstevel 		cardbus_err(dip, 6, "cardbus_configure failed\n");
6223db86aabSstevel #endif
6233db86aabSstevel 		return (B_FALSE);
6243db86aabSstevel 	}
6253db86aabSstevel 
6263db86aabSstevel 	ctrl.rv = NDI_SUCCESS;
6273db86aabSstevel 	ctrl.busno = cardbus_primary_busno(dip);
6283db86aabSstevel 	ctrl.op = PCICFG_OP_ONLINE;
6293db86aabSstevel 	ctrl.dip = NULL;
6303db86aabSstevel 	ctrl.flags = PCICFG_FLAGS_CONTINUE;
6313db86aabSstevel 
6323db86aabSstevel 	/*
6333db86aabSstevel 	 * The child of the dip is the cardbus dip. The child of the
6343db86aabSstevel 	 * cardbus dip is the device itself
6353db86aabSstevel 	 */
6363db86aabSstevel #if defined(CARDBUS_DEBUG)
6373db86aabSstevel 	cardbus_err(dip, 8, "cardbus_load_cardbus: calling cbus_configure\n");
6383db86aabSstevel #endif
6393fe80ca4SDan Cross 	ndi_devi_enter(dip);
6403db86aabSstevel 	ddi_walk_devs(ddi_get_child(dip), cbus_configure, (void *)&ctrl);
6413fe80ca4SDan Cross 	ndi_devi_exit(dip);
6423db86aabSstevel 
6433db86aabSstevel 	if (ctrl.rv != NDI_SUCCESS) {
6443db86aabSstevel 		cardbus_err(dip, 1,
6453db86aabSstevel 		    "cardbus_load_cardbus (%s%d): failed to attach (%d)\n",
6463db86aabSstevel 		    ctrl.dip ? ddi_driver_name(ctrl.dip) : "Unknown",
6473db86aabSstevel 		    ctrl.dip ? ddi_get_instance(ctrl.dip) : 0,
6483db86aabSstevel 		    ctrl.rv);
6493db86aabSstevel 
6503db86aabSstevel 		/*
6513db86aabSstevel 		 * Returning error here will cause the pcic_load_cardbus() call
6523db86aabSstevel 		 * to fail. This will invoke pcic_unload_cardbus() which calls
6533db86aabSstevel 		 * cardbus_unload_cardbus() below.
6543db86aabSstevel 		 */
6553db86aabSstevel 		return (B_FALSE);
6563db86aabSstevel 	}
6573db86aabSstevel #endif
6583db86aabSstevel 
6593db86aabSstevel #if defined(CARDBUS_DEBUG)
6603db86aabSstevel 	cardbus_err(dip, 7, "cardbus_load_cardbus: returning TRUE\n");
6613db86aabSstevel #endif
6623db86aabSstevel 
6633db86aabSstevel 	return (B_TRUE);
6643db86aabSstevel }
6653db86aabSstevel 
6663db86aabSstevel /*
6673db86aabSstevel  * Unload the cardbus module
6683db86aabSstevel  */
6693db86aabSstevel void
cardbus_unload_cardbus(dev_info_t * dip)6703db86aabSstevel cardbus_unload_cardbus(dev_info_t *dip)
6713db86aabSstevel {
6723db86aabSstevel 	int	cb_instance;
6733db86aabSstevel #ifndef HOTPLUG
6743db86aabSstevel 	int	prim_bus = cardbus_primary_busno(dip);
6753db86aabSstevel 	int	rval;
6763db86aabSstevel #endif
6773db86aabSstevel 	cbus_t *cbp;
6783db86aabSstevel 
6793db86aabSstevel 	cardbus_err(dip, 6, "cardbus_unload_cardbus\n");
6803db86aabSstevel 
6813db86aabSstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
6823db86aabSstevel 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
6833db86aabSstevel 	ASSERT(cb_instance >= 0);
6843db86aabSstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
6853db86aabSstevel 
6863db86aabSstevel 	if (number_of_cardbus_cards == 0)
6873db86aabSstevel 		return;
6883db86aabSstevel 
6893db86aabSstevel #ifdef HOTPLUG
6903db86aabSstevel 	mutex_enter(&cbp->cb_mutex);
6913db86aabSstevel 	cbp->card_present = B_FALSE;
6923db86aabSstevel 
6933db86aabSstevel 	(void) hpc_slot_event_notify(cbp->slot_handle,
6943db86aabSstevel 	    HPC_EVENT_SLOT_POWER_OFF, 0);
6953db86aabSstevel 	(void) hpc_slot_event_notify(cbp->slot_handle,
6960d282d13Srw148561 	    HPC_EVENT_SLOT_UNCONFIGURE, 0);
6970d282d13Srw148561 	(void) hpc_slot_event_notify(cbp->slot_handle,
6983db86aabSstevel 	    HPC_EVENT_SLOT_REMOVAL, 0);
6993db86aabSstevel 
7003db86aabSstevel 	mutex_exit(&cbp->cb_mutex);
7013db86aabSstevel #else
7023db86aabSstevel 
7033db86aabSstevel 	cardbus_err(dip, 8,
7043db86aabSstevel 	    "cardbus_unload_cardbus: calling cardbus_unconfigure_node\n");
7053db86aabSstevel 
7063db86aabSstevel 	rval = cardbus_unconfigure_node(dip, prim_bus, B_TRUE);
7073db86aabSstevel 
7083db86aabSstevel 	if (rval != NDI_SUCCESS) {
7093db86aabSstevel 		cardbus_err(dip, 4,
7103db86aabSstevel 		    "cardbus_unload_cardbus: "
7113db86aabSstevel 		    "cardbus_unconfigure_node failed\n");
7123db86aabSstevel 		number_of_cardbus_cards--;
7133db86aabSstevel 		cbp->fatal_problem = B_TRUE;
7143db86aabSstevel 		cmn_err(CE_WARN,
7153db86aabSstevel 		    "cardbus(%s%d): Failed to remove device tree: "
7163db86aabSstevel 		    "Slot disabled",
7173db86aabSstevel 		    ddi_get_name(dip), ddi_get_instance(dip));
7183db86aabSstevel 		return;
7193db86aabSstevel 	}
7203db86aabSstevel 
7213db86aabSstevel 	(void) cardbus_unconfigure(cbp);
7223db86aabSstevel #endif
7233db86aabSstevel 
7243db86aabSstevel 	/*
7253db86aabSstevel 	 * Inform the lower drivers that the card has been removed
7263db86aabSstevel 	 */
7273db86aabSstevel 	if (cbp->cb_ndi_event_hdl != NULL) {
7283db86aabSstevel 		ddi_eventcookie_t cookie;
7293db86aabSstevel 		if (ndi_event_retrieve_cookie(cbp->cb_ndi_event_hdl, dip,
7303db86aabSstevel 		    DDI_DEVI_REMOVE_EVENT, &cookie, 0) == NDI_SUCCESS) {
7313db86aabSstevel 			(void) ndi_event_run_callbacks(cbp->cb_ndi_event_hdl,
7323db86aabSstevel 			    dip, cookie, NULL);
7333db86aabSstevel 		}
7343db86aabSstevel 	}
7353db86aabSstevel 
7363db86aabSstevel 	cardbus_revert_properties(dip);
7373db86aabSstevel }
7383db86aabSstevel 
73911c2b4c0Srw148561 static boolean_t
is_32bit_pccard(dev_info_t * dip)74011c2b4c0Srw148561 is_32bit_pccard(dev_info_t *dip)
7413db86aabSstevel {
74211c2b4c0Srw148561 	int len;
74311c2b4c0Srw148561 	char bus_type[16];
7443db86aabSstevel 
74511c2b4c0Srw148561 	len = sizeof (bus_type);
74611c2b4c0Srw148561 	if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
747152f8055SToomas Soome 	    PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
748152f8055SToomas Soome 	    "device_type", (caddr_t)&bus_type, &len) != DDI_SUCCESS)
7493db86aabSstevel 		return (B_FALSE);
75011c2b4c0Srw148561 
75111c2b4c0Srw148561 	if ((strcmp(bus_type, "pci") != 0) &&
75211c2b4c0Srw148561 	    (strcmp(bus_type, "pciex") != 0) &&
75311c2b4c0Srw148561 	    (strcmp(bus_type, "cardbus") != 0)) /* not of pci type */
75411c2b4c0Srw148561 		return (B_FALSE);
75511c2b4c0Srw148561 
75611c2b4c0Srw148561 	return (B_TRUE);
75711c2b4c0Srw148561 }
75811c2b4c0Srw148561 
75911c2b4c0Srw148561 void
cardbus_save_children(dev_info_t * dip)76011c2b4c0Srw148561 cardbus_save_children(dev_info_t *dip)
76111c2b4c0Srw148561 {
76211c2b4c0Srw148561 	for (; dip != NULL; dip = ddi_get_next_sibling(dip)) {
76311c2b4c0Srw148561 		cardbus_save_children(ddi_get_child(dip));
76411c2b4c0Srw148561 
76511c2b4c0Srw148561 		if (strcmp("pcs", ddi_node_name(dip)) == 0)
76611c2b4c0Srw148561 			continue;
76711c2b4c0Srw148561 		if (!is_32bit_pccard(dip))
76811c2b4c0Srw148561 			continue;
76911c2b4c0Srw148561 		cardbus_err(dip, 1, "Saving device\n");
77011c2b4c0Srw148561 		(void) pci_save_config_regs(dip);
77111c2b4c0Srw148561 	}
77211c2b4c0Srw148561 
77311c2b4c0Srw148561 }
77411c2b4c0Srw148561 
77511c2b4c0Srw148561 void
cardbus_restore_children(dev_info_t * dip)77611c2b4c0Srw148561 cardbus_restore_children(dev_info_t *dip)
77711c2b4c0Srw148561 {
77811c2b4c0Srw148561 	for (; dip != NULL; dip = ddi_get_next_sibling(dip)) {
77911c2b4c0Srw148561 		cardbus_restore_children(ddi_get_child(dip));
78011c2b4c0Srw148561 
78111c2b4c0Srw148561 		if (strcmp("pcs", ddi_node_name(dip)) == 0)
78211c2b4c0Srw148561 			continue;
78311c2b4c0Srw148561 		if (!is_32bit_pccard(dip))
78411c2b4c0Srw148561 			continue;
78511c2b4c0Srw148561 		cardbus_err(dip, 1, "restoring device\n");
78611c2b4c0Srw148561 		(void) pci_restore_config_regs(dip);
78711c2b4c0Srw148561 	}
78811c2b4c0Srw148561 
7893db86aabSstevel }
7903db86aabSstevel 
7913db86aabSstevel static int
cardbus_convert_properties(dev_info_t * dip)7923db86aabSstevel cardbus_convert_properties(dev_info_t *dip)
7933db86aabSstevel {
7943db86aabSstevel 	struct pcm_regs *pcic_avail_p, *old_avail_p;
7953db86aabSstevel 	pci_regspec_t *cb_avail_p, *new_avail_p;
7963db86aabSstevel 	pcic_ranges_t *pcic_range_p, *old_range_p;
7973db86aabSstevel 	cardbus_range_t *cb_range_p, *new_range_p;
7983db86aabSstevel 	int range_len, range_entries, i;
7993db86aabSstevel 	int avail_len, avail_entries;
8003db86aabSstevel 
8013db86aabSstevel #if defined(CARDBUS_DEBUG)
8023db86aabSstevel 	cardbus_err(dip, 6, "cardbus_convert_properties\n");
8033db86aabSstevel #endif
8043db86aabSstevel 
8053db86aabSstevel 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
8063db86aabSstevel 	    "#address-cells", 3) != DDI_SUCCESS) {
8073db86aabSstevel 		cardbus_err(dip, 1, "cardbus_convert_properties: "
8083db86aabSstevel 		    "failed to update #address-cells property\n");
8093db86aabSstevel 		return (DDI_FAILURE);
8103db86aabSstevel 	}
8113db86aabSstevel 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
8123db86aabSstevel 	    "#size-cells", 2) != DDI_SUCCESS) {
8133db86aabSstevel 		cardbus_err(dip, 1, "cardbus_convert_properties: "
8143db86aabSstevel 		    "failed to update #size-cells property\n");
8153db86aabSstevel 		return (DDI_FAILURE);
8163db86aabSstevel 	}
8173db86aabSstevel 
8183db86aabSstevel 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "available",
8193db86aabSstevel 	    (caddr_t)&pcic_avail_p, &avail_len) != DDI_PROP_SUCCESS) {
8203db86aabSstevel 		cardbus_err(dip, 1, "cardbus_convert_properties: "
8213db86aabSstevel 		    "no available property for pcmcia\n");
8223db86aabSstevel 	} else {
8233db86aabSstevel 		avail_entries = avail_len / sizeof (struct pcm_regs);
8243db86aabSstevel 		cb_avail_p = kmem_alloc(sizeof (pci_regspec_t) * avail_entries,
8253db86aabSstevel 		    KM_SLEEP);
8263db86aabSstevel 
8273db86aabSstevel 		old_avail_p = pcic_avail_p;
8283db86aabSstevel 		new_avail_p = cb_avail_p;
8293db86aabSstevel 		for (i = 0; i < avail_entries;
8303db86aabSstevel 		    i++, old_avail_p++, new_avail_p++) {
8313db86aabSstevel 			new_avail_p->pci_phys_hi = old_avail_p->phys_hi;
8323db86aabSstevel 			new_avail_p->pci_phys_mid = 0;
8333db86aabSstevel 			new_avail_p->pci_phys_low = old_avail_p->phys_lo;
8343db86aabSstevel 			new_avail_p->pci_size_hi = 0;
8353db86aabSstevel 			new_avail_p->pci_size_low = old_avail_p->phys_len;
8363db86aabSstevel 		}
8373db86aabSstevel 
8383db86aabSstevel 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
8393db86aabSstevel 		    "available",
8403db86aabSstevel 		    (int *)cb_avail_p,
8413db86aabSstevel 		    (sizeof (pci_regspec_t) * avail_entries)/sizeof (int));
8423db86aabSstevel 
8433db86aabSstevel 		kmem_free(pcic_avail_p, avail_len);
8443db86aabSstevel 		kmem_free(cb_avail_p, sizeof (pci_regspec_t) * avail_entries);
8453db86aabSstevel 	}
8463db86aabSstevel 
8473db86aabSstevel 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "ranges",
8483db86aabSstevel 	    (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) {
8493db86aabSstevel 		cardbus_err(dip, 1, "cardbus_convert_properties: "
8503db86aabSstevel 		    "no ranges property for pcmcia\n");
8513db86aabSstevel 	} else {
8523db86aabSstevel 		range_entries = range_len / sizeof (pcic_ranges_t);
8533db86aabSstevel 		cb_range_p = kmem_alloc(
8543db86aabSstevel 		    sizeof (cardbus_range_t) * range_entries, KM_SLEEP);
8553db86aabSstevel 
8563db86aabSstevel 		old_range_p = pcic_range_p;
8573db86aabSstevel 		new_range_p = cb_range_p;
8583db86aabSstevel 		for (i = 0; i < range_entries;
8593db86aabSstevel 		    i++, old_range_p++, new_range_p++) {
8603db86aabSstevel 			new_range_p->child_hi =
8613db86aabSstevel 			    old_range_p->pcic_range_caddrhi;
8623db86aabSstevel 			new_range_p->child_mid = 0;
8633db86aabSstevel 			new_range_p->child_lo =
8643db86aabSstevel 			    old_range_p->pcic_range_caddrlo;
8653db86aabSstevel 			new_range_p->parent_hi =
8663db86aabSstevel 			    old_range_p->pcic_range_paddrhi;
8673db86aabSstevel 			new_range_p->parent_mid =
8683db86aabSstevel 			    old_range_p->pcic_range_paddrmid;
8693db86aabSstevel 			new_range_p->parent_lo =
8703db86aabSstevel 			    old_range_p->pcic_range_paddrlo;
8713db86aabSstevel 			new_range_p->size_hi = 0;
8723db86aabSstevel 			new_range_p->size_lo = old_range_p->pcic_range_size;
8733db86aabSstevel 		}
8743db86aabSstevel 
8753db86aabSstevel 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
8763db86aabSstevel 		    (int *)cb_range_p,
8773db86aabSstevel 		    (sizeof (cardbus_range_t) * range_entries)/sizeof (int));
8783db86aabSstevel 
8793db86aabSstevel 		kmem_free(pcic_range_p, range_len);
8803db86aabSstevel 		kmem_free(cb_range_p, sizeof (cardbus_range_t) * range_entries);
8813db86aabSstevel 	}
8823db86aabSstevel 
8833db86aabSstevel 	return (DDI_SUCCESS);
8843db86aabSstevel }
8853db86aabSstevel 
8863db86aabSstevel static void
cardbus_revert_properties(dev_info_t * dip)8873db86aabSstevel cardbus_revert_properties(dev_info_t *dip)
8883db86aabSstevel {
8893db86aabSstevel #if defined(CARDBUS_DEBUG)
8903db86aabSstevel 	cardbus_err(dip, 6, "cardbus_revert_properties\n");
8913db86aabSstevel #endif
8923db86aabSstevel 
8933db86aabSstevel 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "#address-cells");
8943db86aabSstevel 
8953db86aabSstevel 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "#size-cells");
8963db86aabSstevel 
8973db86aabSstevel 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
8983db86aabSstevel }
8993db86aabSstevel 
9003db86aabSstevel static int
cardbus_prop_op(dev_t dev,dev_info_t * dip,dev_info_t * ch_dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)9013db86aabSstevel cardbus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
9023db86aabSstevel     ddi_prop_op_t prop_op, int mod_flags,
9033db86aabSstevel     char *name, caddr_t valuep, int *lengthp)
9043db86aabSstevel {
9053db86aabSstevel #if defined(CARDBUS_DEBUG)
9063db86aabSstevel 	if ((ch_dip != dip) || (cardbus_debug >= 9))
9073db86aabSstevel 		cardbus_err(dip, 6,
9083db86aabSstevel 		    "cardbus_prop_op(%s) (dip=0x%p, op=%d, name=%s)\n",
9093db86aabSstevel 		    ddi_driver_name(ch_dip), (void *) dip, prop_op, name);
9103db86aabSstevel #endif
9113db86aabSstevel 	return (impl_ddi_bus_prop_op(dev, dip, ch_dip, prop_op,
9123db86aabSstevel 	    mod_flags, name, valuep, lengthp));
9133db86aabSstevel }
9143db86aabSstevel 
9153db86aabSstevel static int
cardbus_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)9163db86aabSstevel cardbus_ctlops(dev_info_t *dip, dev_info_t *rdip,
9173db86aabSstevel     ddi_ctl_enum_t ctlop, void *arg, void *result)
9183db86aabSstevel {
9193db86aabSstevel 	pci_regspec_t *regs;
9203db86aabSstevel 	int	totreg, reglen;
9213db86aabSstevel 	const char	*dname = ddi_driver_name(dip);
9223db86aabSstevel 
9233db86aabSstevel 	ASSERT(number_of_cardbus_cards != 0);
9243db86aabSstevel 
9253db86aabSstevel 	cardbus_err(dip, 6,
9263db86aabSstevel 	    "cardbus_ctlops(%p, %p, %d, %p, %p)\n",
9273db86aabSstevel 	    (void *)dip, (void *)rdip, ctlop, (void *)arg, (void *)result);
9283db86aabSstevel 
9293db86aabSstevel 	switch (ctlop) {
9303db86aabSstevel 	case DDI_CTLOPS_UNINITCHILD:
9313db86aabSstevel 		cardbus_removechild((dev_info_t *)arg);
9323db86aabSstevel 		return (DDI_SUCCESS);
93311c2b4c0Srw148561 	case DDI_CTLOPS_POWER:
93411c2b4c0Srw148561 		return (DDI_SUCCESS);
9353db86aabSstevel 
9363db86aabSstevel 	default:
9373db86aabSstevel 		/*
9383db86aabSstevel 		 * Do Nothing
9393db86aabSstevel 		 */
9403db86aabSstevel 		cardbus_err(dip, 8,
9413db86aabSstevel 		    "cardbus_ctlops: Unsupported DDI_CTLOP %d\n", ctlop);
9423db86aabSstevel 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
9433db86aabSstevel 
9443db86aabSstevel 	case DDI_CTLOPS_SIDDEV:		/* see ddi_dev_is_sid(9F) */
9453db86aabSstevel 		return (DDI_SUCCESS);
9463db86aabSstevel 
9473db86aabSstevel 	case DDI_CTLOPS_SLAVEONLY:	/* see ddi_slaveonly(9F) */
9483db86aabSstevel 		return (DDI_FAILURE);	/* cardbus */
9493db86aabSstevel 
9503db86aabSstevel 	case DDI_CTLOPS_REGSIZE:
9513db86aabSstevel 	case DDI_CTLOPS_NREGS:
9523db86aabSstevel 		if (rdip == (dev_info_t *)NULL) {
9533db86aabSstevel 			*(int *)result = 0;
9543db86aabSstevel 			return (DDI_FAILURE);
9553db86aabSstevel 		}
9563db86aabSstevel 		break;
9573db86aabSstevel 
9583db86aabSstevel 	case DDI_CTLOPS_IOMIN:
9593db86aabSstevel 		/*
9603db86aabSstevel 		 * If we are using the streaming cache, align at
9613db86aabSstevel 		 * least on a cache line boundary. Otherwise use
9623db86aabSstevel 		 * whatever alignment is passed in.
9633db86aabSstevel 		 */
9643db86aabSstevel 
9653db86aabSstevel 		if (arg) {
9663db86aabSstevel 			int	val = *((int *)result);
9673db86aabSstevel 
9683db86aabSstevel #ifdef  PCI_SBUF_LINE_SIZE
9693db86aabSstevel 			val = maxbit(val, PCI_SBUF_LINE_SIZE);
9703db86aabSstevel #else
9713db86aabSstevel 			val = maxbit(val, 64);
9723db86aabSstevel #endif
9733db86aabSstevel 			*((int *)result) = val;
9743db86aabSstevel 		}
9753db86aabSstevel 		return (DDI_SUCCESS);
9763db86aabSstevel 
9773db86aabSstevel 	case DDI_CTLOPS_INITCHILD:
9783db86aabSstevel 		return (cardbus_initchild(rdip, dip, (dev_info_t *)arg,
9793db86aabSstevel 		    result));
9803db86aabSstevel 
9813db86aabSstevel 	case DDI_CTLOPS_REPORTDEV:
9823db86aabSstevel 		if (rdip == (dev_info_t *)0)
9833db86aabSstevel 			return (DDI_FAILURE);
9843db86aabSstevel 
9853db86aabSstevel 		if (strcmp("pcs", ddi_node_name(rdip)) == 0)
9863db86aabSstevel 			cardbus_err(dip, 1,
9873db86aabSstevel 			    "cardbus_ctlops: PCCard socket %d at %s@%s\n",
9883db86aabSstevel 			    ddi_get_instance(rdip),
9893db86aabSstevel 			    dname, ddi_get_name_addr(dip));
9903db86aabSstevel 		else {
9913db86aabSstevel 			pci_regspec_t *pci_rp;
9923db86aabSstevel 			dev_info_t *next;
9933db86aabSstevel 			int	length;
9943db86aabSstevel 
9953db86aabSstevel 			if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
9963db86aabSstevel 			    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
9973db86aabSstevel 			    (uint_t *)&length) != DDI_PROP_SUCCESS)
9983db86aabSstevel 				return (DDI_FAILURE);
9993db86aabSstevel 
10003db86aabSstevel 			if (pci_rp->pci_phys_hi == 0)
10013db86aabSstevel 				cardbus_err(dip, 1, "%s%d at %s@%s\n",
10023db86aabSstevel 				    ddi_driver_name(rdip),
10033db86aabSstevel 				    ddi_get_instance(rdip),
10043db86aabSstevel 				    dname, ddi_get_name_addr(dip));
10053db86aabSstevel 			else {
10063db86aabSstevel 				uint8_t bus, device, function;
10073db86aabSstevel 				int32_t val32;
10083db86aabSstevel 				char	*ptr, buf[128];
10093db86aabSstevel 
10103db86aabSstevel 				bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
10113db86aabSstevel 				device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
10123db86aabSstevel 				function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
10133db86aabSstevel 
10143db86aabSstevel 				ptr = buf;
10153db86aabSstevel 				(void) sprintf(ptr, "  "
10163db86aabSstevel 				    "Bus %3d Device %2d Function %2d",
10173db86aabSstevel 				    bus, device, function);
10183db86aabSstevel 				ptr = &ptr[strlen(ptr)];
10193db86aabSstevel 
10203db86aabSstevel 				val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
10213db86aabSstevel 				    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
10223db86aabSstevel 				    "vendor-id", -1);
10233db86aabSstevel 				if (val32 != -1) {
10243db86aabSstevel 					(void) sprintf(ptr, " Vendor 0x%04x",
10253db86aabSstevel 					    val32);
10263db86aabSstevel 					ptr = &ptr[strlen(ptr)];
10273db86aabSstevel 				}
10283db86aabSstevel 				val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
10293db86aabSstevel 				    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
10303db86aabSstevel 				    "device-id", -1);
10313db86aabSstevel 				if (val32 != -1) {
10323db86aabSstevel 					(void) sprintf(ptr, " Device 0x%04x",
10333db86aabSstevel 					    val32);
10343db86aabSstevel 					ptr = &ptr[strlen(ptr)];
10353db86aabSstevel 				}
10363db86aabSstevel 				val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
10373db86aabSstevel 				    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
10383db86aabSstevel 				    "class-code", -1);
10393db86aabSstevel 				if (val32 != -1) {
10403db86aabSstevel 					const char	*name;
10413db86aabSstevel 
10423db86aabSstevel 					if ((name = ddi_get_name(rdip)) !=
10433db86aabSstevel 					    NULL)
10443db86aabSstevel 						(void) sprintf(ptr, " Name %s",
10453db86aabSstevel 						    name);
10463db86aabSstevel 					else
10473db86aabSstevel 						(void) sprintf(ptr,
10483db86aabSstevel 						    " Class 0x%x", val32 >> 8);
10493db86aabSstevel 					ptr = &ptr[strlen(ptr)];
10503db86aabSstevel 				}
10513db86aabSstevel 
10523db86aabSstevel 				*ptr++ = '\n';
10533db86aabSstevel 				ASSERT(((caddr_t)ptr - (caddr_t)buf) <
10543db86aabSstevel 				    sizeof (buf));
10553db86aabSstevel 				*ptr = '\0';
10563db86aabSstevel 
10573db86aabSstevel 				cardbus_err(dip, 1, buf);
10583db86aabSstevel 			}
10593db86aabSstevel 			ddi_prop_free(pci_rp);
10603db86aabSstevel 
10613db86aabSstevel 			for (next = ddi_get_child(rdip); next;
10623db86aabSstevel 			    next = ddi_get_next_sibling(next))
10633db86aabSstevel 				(void) cardbus_ctlops(next, next,
10643db86aabSstevel 				    DDI_CTLOPS_REPORTDEV, arg, result);
10653db86aabSstevel 		}
10663db86aabSstevel 		return (DDI_SUCCESS);
10673db86aabSstevel 	}
10683db86aabSstevel 	*(int *)result = 0;
10693db86aabSstevel 
10703db86aabSstevel 	if (ddi_getlongprop(DDI_DEV_T_NONE, rdip,
10713db86aabSstevel 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg",
10723db86aabSstevel 	    (caddr_t)&regs, &reglen) != DDI_SUCCESS)
10733db86aabSstevel 		return (DDI_FAILURE);
10743db86aabSstevel 
10753db86aabSstevel 	totreg = reglen / sizeof (pci_regspec_t);
10763db86aabSstevel 	if (ctlop == DDI_CTLOPS_NREGS) {
10773db86aabSstevel 		cardbus_err(dip, 6,
10783db86aabSstevel 		    "cardbus_ctlops, returning NREGS = %d\n", totreg);
10793db86aabSstevel 		*(int *)result = totreg;
10803db86aabSstevel 	} else if (ctlop == DDI_CTLOPS_REGSIZE) {
10813db86aabSstevel 		const int	rn = *(int *)arg;
10823db86aabSstevel 		if (rn > totreg)
10833db86aabSstevel 			return (DDI_FAILURE);
10843db86aabSstevel 		cardbus_err(dip, 6,
10853db86aabSstevel 		    "cardbus_ctlops, returning REGSIZE(%d) = %d\n",
10863db86aabSstevel 		    rn, regs[rn].pci_size_low);
10873db86aabSstevel 		*(off_t *)result = regs[rn].pci_size_low;
10883db86aabSstevel 	}
10893db86aabSstevel 	kmem_free(regs, reglen);
10903db86aabSstevel 	return (DDI_SUCCESS);
10913db86aabSstevel }
10923db86aabSstevel 
10933db86aabSstevel static void
cardbus_init_child_regs(dev_info_t * child)10943db86aabSstevel cardbus_init_child_regs(dev_info_t *child)
10953db86aabSstevel {
10963db86aabSstevel 	ddi_acc_handle_t config_handle;
10973db86aabSstevel 	uint16_t command_preserve, command;
109886ef0a63SRichard Lowe #if !defined(__x86)
10993db86aabSstevel 	uint8_t bcr;
11003db86aabSstevel #endif
11013db86aabSstevel 	uint8_t header_type;
11023db86aabSstevel 	uint8_t min_gnt, latency_timer;
11033db86aabSstevel 	uint_t n;
11043db86aabSstevel 
11053db86aabSstevel 	/*
11063db86aabSstevel 	 * Map the child configuration space to for initialization.
11073db86aabSstevel 	 *
11083db86aabSstevel 	 *  Set the latency-timer register to values appropriate
11093db86aabSstevel 	 *  for the devices on the bus (based on other devices
11103db86aabSstevel 	 *  MIN_GNT and MAX_LAT registers.
11113db86aabSstevel 	 *
11123db86aabSstevel 	 *  Set the fast back-to-back enable bit in the command
11133db86aabSstevel 	 *  register if it's supported and all devices on the bus
11143db86aabSstevel 	 *  have the capability.
11153db86aabSstevel 	 *
11163db86aabSstevel 	 */
11173db86aabSstevel 	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS)
11183db86aabSstevel 		return;
11193db86aabSstevel 
11203db86aabSstevel 	cardbus_err(child, 6, "cardbus_init_child_regs()\n");
11213db86aabSstevel 
11223db86aabSstevel 	/*
11233db86aabSstevel 	 * Determine the configuration header type.
11243db86aabSstevel 	 */
11253db86aabSstevel 	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
11263db86aabSstevel 
11273db86aabSstevel 	/*
11283db86aabSstevel 	 * Support for "command-preserve" property.  Note that we
11293db86aabSstevel 	 * add PCI_COMM_BACK2BACK_ENAB to the bits to be preserved
11303db86aabSstevel 	 * since the obp will set this if the device supports and
11313db86aabSstevel 	 * all targets on the same bus support it.  Since psycho
11323db86aabSstevel 	 * doesn't support PCI_COMM_BACK2BACK_ENAB, it will never
11333db86aabSstevel 	 * be set.  This is just here in case future revs do support
11343db86aabSstevel 	 * PCI_COMM_BACK2BACK_ENAB.
11353db86aabSstevel 	 */
11363db86aabSstevel 	command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
11373db86aabSstevel 	    DDI_PROP_DONTPASS,
11383db86aabSstevel 	    "command-preserve", 0);
11393db86aabSstevel 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
11403db86aabSstevel 	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
11413db86aabSstevel 	command |= (cardbus_command_default & ~command_preserve);
11423db86aabSstevel 	pci_config_put16(config_handle, PCI_CONF_COMM, command);
11433db86aabSstevel 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
11443db86aabSstevel 
114586ef0a63SRichard Lowe #if !defined(__x86)
11463db86aabSstevel 	/*
11473db86aabSstevel 	 * If the device has a bus control register then program it
11483db86aabSstevel 	 * based on the settings in the command register.
11493db86aabSstevel 	 */
11503db86aabSstevel 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
11513db86aabSstevel 		bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
11523db86aabSstevel 		if (cardbus_command_default & PCI_COMM_PARITY_DETECT)
11533db86aabSstevel 			bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
11543db86aabSstevel 		if (cardbus_command_default & PCI_COMM_SERR_ENABLE)
11553db86aabSstevel 			bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
11563db86aabSstevel 		bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
11573db86aabSstevel 		pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
11583db86aabSstevel 	}
11593db86aabSstevel #endif
11603db86aabSstevel 
11613db86aabSstevel 	/*
11623db86aabSstevel 	 * Initialize cache-line-size configuration register if needed.
11633db86aabSstevel 	 */
11643db86aabSstevel 	if (ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
11653db86aabSstevel 	    "cache-line-size", 0) == 0) {
11663db86aabSstevel 
11673db86aabSstevel 		pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
11683db86aabSstevel 		    PCI_CACHE_LINE_SIZE);
11693db86aabSstevel 		n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
11703db86aabSstevel 		if (n != 0)
11713db86aabSstevel 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
11723db86aabSstevel 			    "cache-line-size", n);
11733db86aabSstevel 	}
11743db86aabSstevel 
11753db86aabSstevel 	/*
11763db86aabSstevel 	 * Initialize latency timer registers if needed.
11773db86aabSstevel 	 */
11783db86aabSstevel 	if (ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
11793db86aabSstevel 	    "latency-timer", 0) == 0) {
11803db86aabSstevel 
11813db86aabSstevel 		if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
11823db86aabSstevel 			latency_timer = cardbus_latency_timer;
11833db86aabSstevel 			pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
11843db86aabSstevel 			    latency_timer);
11853db86aabSstevel 		} else {
11863db86aabSstevel 			min_gnt = pci_config_get8(config_handle,
11873db86aabSstevel 			    PCI_CONF_MIN_G);
11883db86aabSstevel 
11893db86aabSstevel 			/*
11903db86aabSstevel 			 * Cardbus os only 33Mhz
11913db86aabSstevel 			 */
11923db86aabSstevel 			if (min_gnt != 0) {
11933db86aabSstevel 				latency_timer = min_gnt * 8;
11943db86aabSstevel 			}
11953db86aabSstevel 		}
11963db86aabSstevel 		pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
11973db86aabSstevel 		    latency_timer);
11983db86aabSstevel 		n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
11993db86aabSstevel 		if (n != 0)
12003db86aabSstevel 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
12013db86aabSstevel 			"latency-timer", n);
12023db86aabSstevel 	}
12033db86aabSstevel 
12043db86aabSstevel 	pci_config_teardown(&config_handle);
12053db86aabSstevel }
12063db86aabSstevel 
12073db86aabSstevel static int
cardbus_initchild(dev_info_t * rdip,dev_info_t * dip,dev_info_t * child,void * result)12083db86aabSstevel cardbus_initchild(dev_info_t *rdip, dev_info_t *dip, dev_info_t *child,
12093db86aabSstevel     void *result)
12103db86aabSstevel {
12113db86aabSstevel 	char	name[MAXNAMELEN];
12123db86aabSstevel 	const char	*dname = ddi_driver_name(dip);
12133db86aabSstevel 	const struct cb_ops *cop;
12143db86aabSstevel 
12153db86aabSstevel 	_NOTE(ARGUNUSED(rdip, result))
12163db86aabSstevel 
12173db86aabSstevel 	cardbus_err(child, 6, "cardbus_initchild\n");
12183db86aabSstevel 
12193db86aabSstevel 	/*
12203db86aabSstevel 	 * Name the child
12213db86aabSstevel 	 */
12223db86aabSstevel 	if (cardbus_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
12233db86aabSstevel 		return (DDI_FAILURE);
12243db86aabSstevel 
12253db86aabSstevel 	ddi_set_name_addr(child, name);
12263db86aabSstevel 	ddi_set_parent_data(child, NULL);
12273db86aabSstevel 
12283db86aabSstevel 	if (ndi_dev_is_persistent_node(child) == 0) {
12293db86aabSstevel 		/*
12303db86aabSstevel 		 * Try to merge the properties from this prototype
12313db86aabSstevel 		 * node into real h/w nodes.
12323db86aabSstevel 		 */
12333db86aabSstevel 		if (ndi_merge_node(child, cardbus_name_child) == DDI_SUCCESS) {
12343db86aabSstevel 			/*
12353db86aabSstevel 			 * Merged ok - return failure to remove the node.
12363db86aabSstevel 			 */
12373db86aabSstevel 			cardbus_removechild(child);
12383db86aabSstevel 			return (DDI_FAILURE);
12393db86aabSstevel 		}
12403db86aabSstevel 		/*
12413db86aabSstevel 		 * The child was not merged into a h/w node,
12423db86aabSstevel 		 * but there's not much we can do with it other
12433db86aabSstevel 		 * than return failure to cause the node to be removed.
12443db86aabSstevel 		 */
12453db86aabSstevel 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
12463db86aabSstevel 		    ddi_driver_name(child), ddi_get_name_addr(child),
12473db86aabSstevel 		    ddi_driver_name(child));
12483db86aabSstevel 		cardbus_removechild(child);
12493db86aabSstevel 		return (DDI_NOT_WELL_FORMED);
12503db86aabSstevel 	}
12513db86aabSstevel 	cop = DEVI(dip)->devi_ops->devo_cb_ops;
12523db86aabSstevel 
12533db86aabSstevel 	if ((cop == NULL) || (!(cop->cb_flag & D_HOTPLUG))) {
12543db86aabSstevel 		cmn_err(CE_WARN, "%s: driver doesn't support HOTPLUG\n", dname);
12553db86aabSstevel 		return (DDI_FAILURE);
12563db86aabSstevel 	}
12573db86aabSstevel 
12583db86aabSstevel 	cardbus_init_child_regs(child);
12593db86aabSstevel 
12603db86aabSstevel 	/*
12613db86aabSstevel 	 * Create ppd if needed.
12623db86aabSstevel 	 */
12633db86aabSstevel 	if (ddi_get_parent_data(child) == NULL) {
12643db86aabSstevel 		struct cardbus_parent_private_data *ppd;
12653db86aabSstevel 
12663db86aabSstevel #ifdef sparc
12673db86aabSstevel 		ppd = (struct cardbus_parent_private_data *)
12683db86aabSstevel 		    kmem_zalloc(sizeof (struct cardbus_parent_private_data),
12693db86aabSstevel 		    KM_SLEEP);
12703db86aabSstevel 
127186ef0a63SRichard Lowe #elif defined(__x86)
12723db86aabSstevel 		ppd = (struct cardbus_parent_private_data *)
12733db86aabSstevel 		    kmem_zalloc(sizeof (struct cardbus_parent_private_data)
12743db86aabSstevel 		    + sizeof (struct intrspec), KM_SLEEP);
12753db86aabSstevel 
12763db86aabSstevel 		ppd->ppd.par_intr = (struct intrspec *)(ppd + 1);
12773db86aabSstevel 		(ppd->ppd.par_intr)->intrspec_pri = 0;
12783db86aabSstevel 		(ppd->ppd.par_intr)->intrspec_vec = 0;
12793db86aabSstevel 		(ppd->ppd.par_intr)->intrspec_func = (uint_t (*)()) 0;
12803db86aabSstevel #endif
12813db86aabSstevel 
12823db86aabSstevel 		if (ddi_getprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
12833db86aabSstevel 		    "interrupts", -1) != -1)
12843db86aabSstevel 			ppd->ppd.par_nintr = 1;
12853db86aabSstevel 
12863db86aabSstevel 		ppd->code = CB_PPD_CODE;
12873db86aabSstevel 
12883db86aabSstevel 		cardbus_err(child, 5,
12893db86aabSstevel 		    "cardbus_initchild: Creating empty ppd\n");
12903db86aabSstevel 		ppd->ppd.par_nreg = 0;
12913db86aabSstevel 		ppd->ppd.par_reg = NULL;
12923db86aabSstevel 
12933db86aabSstevel 		ddi_set_parent_data(child, (caddr_t)ppd);
12943db86aabSstevel 	}
12953db86aabSstevel 
12963db86aabSstevel 	return (DDI_SUCCESS);
12973db86aabSstevel }
12983db86aabSstevel 
12993db86aabSstevel static int
cardbus_name_child(dev_info_t * child,char * name,int namelen)13003db86aabSstevel cardbus_name_child(dev_info_t *child, char *name, int namelen)
13013db86aabSstevel {
13023db86aabSstevel 	pci_regspec_t *pci_rp;
13033db86aabSstevel 	char	**unit_addr;
13043db86aabSstevel 	uint_t n;
13053db86aabSstevel 	int	bus, device, func;
13063db86aabSstevel 
13073db86aabSstevel 	/*
13083db86aabSstevel 	 * Pseudo nodes indicate a prototype node with per-instance
13093db86aabSstevel 	 * properties to be merged into the real h/w device node.
13103db86aabSstevel 	 * The interpretation of the unit-address is DD[,F]
13113db86aabSstevel 	 * where DD is the device id and F is the function.
13123db86aabSstevel 	 */
13133db86aabSstevel 	if (ndi_dev_is_persistent_node(child) == 0) {
13143db86aabSstevel 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
13153db86aabSstevel 		    DDI_PROP_DONTPASS,
13163db86aabSstevel 		    "unit-address", &unit_addr, &n) != DDI_PROP_SUCCESS) {
13173db86aabSstevel 			cmn_err(CE_WARN, "cannot name node from %s.conf",
13183db86aabSstevel 			    ddi_driver_name(child));
13193db86aabSstevel 			return (DDI_FAILURE);
13203db86aabSstevel 		}
13213db86aabSstevel 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
13223db86aabSstevel 			cmn_err(CE_WARN, "unit-address property in %s.conf"
13233db86aabSstevel 			    " not well-formed", ddi_driver_name(child));
13243db86aabSstevel 			ddi_prop_free(unit_addr);
13253db86aabSstevel 			return (DDI_FAILURE);
13263db86aabSstevel 		}
13273db86aabSstevel 		(void) snprintf(name, namelen, "%s", *unit_addr);
13283db86aabSstevel 		ddi_prop_free(unit_addr);
13293db86aabSstevel 		return (DDI_SUCCESS);
13303db86aabSstevel 	}
13313db86aabSstevel 
13323db86aabSstevel 	/*
13333db86aabSstevel 	 * Get the address portion of the node name based on
13343db86aabSstevel 	 * the function and device number.
13353db86aabSstevel 	 */
13363db86aabSstevel 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
13373db86aabSstevel 	    "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) {
13383db86aabSstevel 		return (DDI_FAILURE);
13393db86aabSstevel 	}
13403db86aabSstevel 
13413db86aabSstevel 	bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
13423db86aabSstevel 	device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
13433db86aabSstevel 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
13443db86aabSstevel 	ddi_prop_free(pci_rp);
13453db86aabSstevel 
13463db86aabSstevel 	if (func != 0)
13473db86aabSstevel 		(void) snprintf(name, namelen, "%x,%x", device, func);
13483db86aabSstevel 	else
13493db86aabSstevel 		(void) snprintf(name, namelen, "%x", device);
13503db86aabSstevel 
13513db86aabSstevel 	cardbus_err(child, 8,
13523db86aabSstevel 	    "cardbus_name_child: system init done [%x][%x][%x]"
13533db86aabSstevel 	    " for %s [%s] nodeid: %x @%s\n",
13543db86aabSstevel 	    bus, device, func,
13553db86aabSstevel 	    ddi_get_name(child), ddi_get_name_addr(child),
13563db86aabSstevel 	    DEVI(child)->devi_nodeid, name);
13573db86aabSstevel 
13583db86aabSstevel 	return (DDI_SUCCESS);
13593db86aabSstevel }
13603db86aabSstevel 
13613db86aabSstevel static void
cardbus_removechild(dev_info_t * dip)13623db86aabSstevel cardbus_removechild(dev_info_t *dip)
13633db86aabSstevel {
13643db86aabSstevel 	struct cardbus_parent_private_data *ppd;
13653db86aabSstevel 
13663db86aabSstevel 	ddi_set_name_addr(dip, NULL);
13673db86aabSstevel 	impl_rem_dev_props(dip);
13683db86aabSstevel 	ppd = (struct cardbus_parent_private_data *)ddi_get_parent_data(dip);
13693db86aabSstevel 	if (ppd && (ppd->code == CB_PPD_CODE)) {
13703db86aabSstevel 		if (ppd->ppd.par_reg && (ppd->ppd.par_nreg > 0))
13713db86aabSstevel 			kmem_free((caddr_t)ppd->ppd.par_reg,
13723db86aabSstevel 			    ppd->ppd.par_nreg * sizeof (struct regspec));
13733db86aabSstevel #ifdef sparc
13743db86aabSstevel 		kmem_free(ppd, sizeof (struct cardbus_parent_private_data));
137586ef0a63SRichard Lowe #elif defined(__x86)
13763db86aabSstevel 		kmem_free(ppd, sizeof (struct cardbus_parent_private_data) +
13773db86aabSstevel 		    sizeof (struct intrspec));
13783db86aabSstevel #endif
13793db86aabSstevel 		cardbus_err(dip, 5,
13803db86aabSstevel 		    "cardbus_removechild: ddi_set_parent_data(NULL)\n");
13813db86aabSstevel 		ddi_set_parent_data(dip, NULL);
13823db86aabSstevel 	}
13833db86aabSstevel }
13843db86aabSstevel 
13853db86aabSstevel 
13863db86aabSstevel static char	cb_bnamestr[] = "binding_name";
13873db86aabSstevel static char	cb_venidstr[] = "VendorID";
13883db86aabSstevel static char	cb_devidstr[] = "DeviceID";
13893db86aabSstevel static char	cb_nnamestr[] = "nodename";
13903db86aabSstevel 
13913db86aabSstevel static cb_props_parse_tree_t cb_props_parse_tree[] = {
13923db86aabSstevel 	{ cb_bnamestr, PT_STATE_STRING_VAR },
13933db86aabSstevel 	{ cb_venidstr, PT_STATE_HEX_VAR },
13943db86aabSstevel 	{ cb_devidstr, PT_STATE_HEX_VAR } };
13953db86aabSstevel 
13963db86aabSstevel static int
check_token(char * token,int * len)13973db86aabSstevel check_token(char *token, int *len)
13983db86aabSstevel {
13993db86aabSstevel 	int	state = PT_STATE_DEC_VAR;
14003db86aabSstevel 	int	sl = strlen(token), il = 1;
14013db86aabSstevel 	char	c;
14023db86aabSstevel 
14033db86aabSstevel 	if (token[0] == '0' && token[2] && (token[1] == 'x' || token[1] ==
14043db86aabSstevel 	    'X')) {
14053db86aabSstevel 		state = PT_STATE_HEX_VAR;
14063db86aabSstevel 		token += 2;
14073db86aabSstevel 	}
14083db86aabSstevel 
14093db86aabSstevel 	while (c = *token++) {
14103db86aabSstevel 		if (isdigit(c))
14113db86aabSstevel 			continue;
14123db86aabSstevel 		if (c == PARSE_COMMA) {
14133db86aabSstevel 			il++;
14143db86aabSstevel 			if (token[0] == '0' && token[2] && isx(token[1])) {
14153db86aabSstevel 				state = PT_STATE_HEX_VAR;
14163db86aabSstevel 				token += 2;
14173db86aabSstevel 			}
14183db86aabSstevel 			continue;
14193db86aabSstevel 		}
14203db86aabSstevel 		if (!isxdigit(c)) {
14213db86aabSstevel 			*len = sl;
14223db86aabSstevel 			return (PT_STATE_STRING_VAR);
14233db86aabSstevel 		}
14243db86aabSstevel 		state = PT_STATE_HEX_VAR;
14253db86aabSstevel 	}
14263db86aabSstevel 	*len = il;
14273db86aabSstevel 	return (state);
14283db86aabSstevel }
14293db86aabSstevel 
14303db86aabSstevel 
14313db86aabSstevel static char *
find_token(char ** cp,int * l,char * endc)14323db86aabSstevel find_token(char **cp, int *l, char *endc)
14333db86aabSstevel {
14343db86aabSstevel 	char	*cpp = *cp;
14353db86aabSstevel 
14363db86aabSstevel 	while ((**cp && (isalpha(**cp) || isxdigit(**cp) ||
14373db86aabSstevel 	    (**cp == PARSE_UNDERSCORE) ||
14383db86aabSstevel 	    (**cp == PARSE_COMMA) ||
14393db86aabSstevel 	    (**cp == PARSE_DASH)))) {
14403db86aabSstevel 		(*cp)++;
14413db86aabSstevel 		(*l)++;
14423db86aabSstevel 	}
14433db86aabSstevel 
14443db86aabSstevel 	*endc = **cp;
1445152f8055SToomas Soome 	**cp = '\0';
14463db86aabSstevel 
14473db86aabSstevel 	return (cpp);
14483db86aabSstevel }
14493db86aabSstevel 
14503db86aabSstevel static int
parse_token(char * token)14513db86aabSstevel parse_token(char *token)
14523db86aabSstevel {
14533db86aabSstevel 	cb_props_parse_tree_t *pt = cb_props_parse_tree;
14543db86aabSstevel 	int	k = sizeof (cb_props_parse_tree) /
14553db86aabSstevel 	    sizeof (cb_props_parse_tree_t);
14563db86aabSstevel 
14573db86aabSstevel 	while (k--) {
14583db86aabSstevel 		if (strcmp((char *)token, pt->token) == 0)
14593db86aabSstevel 			return (pt->state);
14603db86aabSstevel 		pt++;
14613db86aabSstevel 	}
14623db86aabSstevel 
14633db86aabSstevel 	return (PT_STATE_UNKNOWN);
14643db86aabSstevel }
14653db86aabSstevel 
14663db86aabSstevel static int
token_to_hex(char * token,unsigned * val,int len)14673db86aabSstevel token_to_hex(char *token, unsigned *val, int len)
14683db86aabSstevel {
14693db86aabSstevel 	uchar_t c;
14703db86aabSstevel 
14713db86aabSstevel 	*val = 0;
14723db86aabSstevel 	if (token[0] == '0' && (token[1] == 'x' || token[1] == 'X')) {
14733db86aabSstevel 		token += 2;
14743db86aabSstevel 	}
14753db86aabSstevel 
14763db86aabSstevel 	while (*token) {
14773db86aabSstevel 		if (!isxdigit(*token)) {
14783db86aabSstevel 			if (*token == PARSE_COMMA) {
14793db86aabSstevel 				if (!(--len))
14803db86aabSstevel 					return (1);
14813db86aabSstevel 				val++;
14823db86aabSstevel 				*val = 0;
14833db86aabSstevel 				token++;
14843db86aabSstevel 				if (token[0] == '0' && (token[1] == 'x' ||
14853db86aabSstevel 				    token[1] == 'X')) {
14863db86aabSstevel 					token += 2;
14873db86aabSstevel 				}
14883db86aabSstevel 				continue;
14893db86aabSstevel 			}
14903db86aabSstevel 			return (0);
14913db86aabSstevel 		}
14923db86aabSstevel 		c = toupper(*token);
14933db86aabSstevel 		if (c >= 'A')
14943db86aabSstevel 			c = c - 'A' + 10 + '0';
14953db86aabSstevel 		*val = ((*val * 16) + (c - '0'));
14963db86aabSstevel 		token++;
14973db86aabSstevel 	}
14983db86aabSstevel 
14993db86aabSstevel 	return (1);
15003db86aabSstevel }
15013db86aabSstevel 
15023db86aabSstevel static int
token_to_dec(char * token,unsigned * val,int len)15033db86aabSstevel token_to_dec(char *token, unsigned *val, int len)
15043db86aabSstevel {
15053db86aabSstevel 	*val = 0;
15063db86aabSstevel 
15073db86aabSstevel 	while (*token) {
15083db86aabSstevel 		if (!isdigit(*token)) {
15093db86aabSstevel 			if (*token == PARSE_COMMA) {
15103db86aabSstevel 				if (!(--len))
15113db86aabSstevel 					return (1);
15123db86aabSstevel 				val++;
15133db86aabSstevel 				*val = 0;
15143db86aabSstevel 				token++;
15153db86aabSstevel 				continue;
15163db86aabSstevel 			}
15173db86aabSstevel 			return (0);
15183db86aabSstevel 		}
15193db86aabSstevel 		*val = ((*val * 10) + (*token - '0'));
15203db86aabSstevel 		token++;
15213db86aabSstevel 	}
15223db86aabSstevel 
15233db86aabSstevel 	return (1);
15243db86aabSstevel }
15253db86aabSstevel 
15263db86aabSstevel static void
cardbus_add_prop(struct cb_deviceset_props * cdsp,int type,char * name,caddr_t vp,int len)15273db86aabSstevel cardbus_add_prop(struct cb_deviceset_props *cdsp, int type, char *name,
15283db86aabSstevel     caddr_t vp, int len)
15293db86aabSstevel {
15303db86aabSstevel 	ddi_prop_t *propp;
15313db86aabSstevel 	int	pnlen = strlen(name) + 1;
15323db86aabSstevel 
15333db86aabSstevel 	propp = (ddi_prop_t *)kmem_zalloc(sizeof (ddi_prop_t), KM_SLEEP);
15343db86aabSstevel 	propp->prop_name = (char *)kmem_alloc(pnlen, KM_SLEEP);
15353db86aabSstevel 	propp->prop_val = vp;
15363db86aabSstevel 	bcopy(name, propp->prop_name, pnlen);
15373db86aabSstevel 	propp->prop_len = len;
15383db86aabSstevel 	propp->prop_flags = type;
15393db86aabSstevel 	propp->prop_next = cdsp->prop_list;
15403db86aabSstevel 	cdsp->prop_list = propp;
15413db86aabSstevel }
15423db86aabSstevel 
15433db86aabSstevel static void
cardbus_add_stringprop(struct cb_deviceset_props * cdsp,char * name,char * vp,int len)15443db86aabSstevel cardbus_add_stringprop(struct cb_deviceset_props *cdsp, char *name,
15453db86aabSstevel     char *vp, int len)
15463db86aabSstevel {
15473db86aabSstevel 	char	*nstr = kmem_zalloc(len + 1, KM_SLEEP);
15483db86aabSstevel 
15493db86aabSstevel 	bcopy(vp, nstr, len);
15503db86aabSstevel 	cardbus_add_prop(cdsp, DDI_PROP_TYPE_STRING, name, (caddr_t)nstr,
15513db86aabSstevel 	    len + 1);
15523db86aabSstevel }
15533db86aabSstevel 
15543db86aabSstevel static void
cardbus_prop_free(ddi_prop_t * propp)15553db86aabSstevel cardbus_prop_free(ddi_prop_t *propp)
15563db86aabSstevel {
15573db86aabSstevel 	if (propp->prop_len) {
15583db86aabSstevel 		switch (propp->prop_flags) {
15593db86aabSstevel 		case DDI_PROP_TYPE_STRING:
15603db86aabSstevel 			kmem_free(propp->prop_val, propp->prop_len);
15613db86aabSstevel 			break;
15623db86aabSstevel 		case DDI_PROP_TYPE_INT:
15633db86aabSstevel 			kmem_free(propp->prop_val,
15643db86aabSstevel 			    propp->prop_len * sizeof (int));
15653db86aabSstevel 			break;
15663db86aabSstevel 		}
15673db86aabSstevel 	}
15683db86aabSstevel 	kmem_free(propp->prop_name, strlen(propp->prop_name) + 1);
15693db86aabSstevel 	kmem_free(propp, sizeof (ddi_prop_t *));
15703db86aabSstevel }
15713db86aabSstevel 
15723db86aabSstevel static void
cardbus_devprops_free(struct cb_deviceset_props * cbdp)15733db86aabSstevel cardbus_devprops_free(struct cb_deviceset_props *cbdp)
15743db86aabSstevel {
15753db86aabSstevel 	ddi_prop_t *propp, *npropp;
15763db86aabSstevel 
15773db86aabSstevel 	propp = cbdp->prop_list;
15783db86aabSstevel 	while (propp) {
15793db86aabSstevel 		npropp = propp->prop_next;
15803db86aabSstevel 		cardbus_prop_free(propp);
15813db86aabSstevel 		propp = npropp;
15823db86aabSstevel 	}
15833db86aabSstevel 	if (cbdp->nodename)
15843db86aabSstevel 		kmem_free(cbdp->nodename, strlen(cbdp->nodename) + 1);
15853db86aabSstevel 	if (cbdp->binding_name)
15863db86aabSstevel 		kmem_free(cbdp->binding_name, strlen(cbdp->binding_name) +
15873db86aabSstevel 		    1);
15883db86aabSstevel 	kmem_free(cbdp, sizeof (*cbdp));
15893db86aabSstevel }
15903db86aabSstevel 
15913db86aabSstevel /*
15923db86aabSstevel  * Format of "cb-device-init-props" property:
15933db86aabSstevel  * Anything before the semi-colon is an identifying equate, anything
15943db86aabSstevel  * after the semi-colon is a setting equate.
15953db86aabSstevel  *
15963db86aabSstevel  * "binding_name=xXxXxX VendorID=NNNN DeviceID=NNNN; nodename=NewName
15973db86aabSstevel  *					Prop=PropVal"
15983db86aabSstevel  *
15993db86aabSstevel  */
16003db86aabSstevel static int
cardbus_parse_devprop(cbus_t * cbp,char * cp)16013db86aabSstevel cardbus_parse_devprop(cbus_t *cbp, char *cp)
16023db86aabSstevel {
16033db86aabSstevel 	int	state = PT_STATE_TOKEN, qm = 0, em = 0, smc = 0, l = 0;
16043db86aabSstevel 	int	length;
16053db86aabSstevel 	char	*token = "beginning of line";
16063db86aabSstevel 	char	*ptoken = NULL, *quote;
1607152f8055SToomas Soome 	char	eq = '\0';
16083db86aabSstevel 	struct cb_deviceset_props *cdsp;
16093db86aabSstevel 
1610152f8055SToomas Soome 	cdsp = kmem_zalloc(sizeof (*cdsp), KM_SLEEP);
16113db86aabSstevel 	length = strlen(cp);
16123db86aabSstevel 
16133db86aabSstevel 	while ((*cp) && (l < length)) {
16143db86aabSstevel 		/*
16153db86aabSstevel 		 * Check for escaped characters
16163db86aabSstevel 		 */
16173db86aabSstevel 		if (*cp == PARSE_ESCAPE) {
16183db86aabSstevel 			char	*cpp = cp, *cppp = cp + 1;
16193db86aabSstevel 
16203db86aabSstevel 			em = 1;
16213db86aabSstevel 
16223db86aabSstevel 			if (!qm) {
16233db86aabSstevel 				cmn_err(CE_CONT, "cardbus_parse_devprop: "
16243db86aabSstevel 				    "escape not allowed outside "
16253db86aabSstevel 				    "of quotes at [%s]\n", token);
1626*d74fa75eSToomas Soome 				cardbus_devprops_free(cdsp);
16273db86aabSstevel 				return (DDI_FAILURE);
16283db86aabSstevel 
16293db86aabSstevel 			} /* if (!qm) */
16303db86aabSstevel 
16313db86aabSstevel 			while (*cppp)
16323db86aabSstevel 				*cpp++ = *cppp++;
16333db86aabSstevel 
16343db86aabSstevel 			l++;
16353db86aabSstevel 
1636152f8055SToomas Soome 			*cpp = '\0';
16373db86aabSstevel 		} /* PARSE_ESCAPE */
16383db86aabSstevel 
16393db86aabSstevel 		/*
16403db86aabSstevel 		 * Check for quoted strings
16413db86aabSstevel 		 */
16423db86aabSstevel 		if (!em && (*cp == PARSE_QUOTE)) {
16433db86aabSstevel 			qm ^= 1;
16443db86aabSstevel 			if (qm) {
16453db86aabSstevel 				quote = cp + 1;
16463db86aabSstevel 			} else {
1647152f8055SToomas Soome 				*cp = '\0';
16483db86aabSstevel 				if (state == PT_STATE_CHECK) {
16493db86aabSstevel 					if (strcmp(token, cb_nnamestr) == 0) {
16503db86aabSstevel 						cdsp->nodename = kmem_alloc(
16513db86aabSstevel 						    strlen(quote) + 1,
16523db86aabSstevel 						    KM_SLEEP);
16533db86aabSstevel 						(void) strcpy(cdsp->nodename,
16543db86aabSstevel 						    quote);
16553db86aabSstevel 					} else
16563db86aabSstevel 						cardbus_add_stringprop(cdsp,
16573db86aabSstevel 						    token, quote,
16583db86aabSstevel 						    strlen(quote));
16593db86aabSstevel 				} else if (state != PT_STATE_STRING_VAR) {
16603db86aabSstevel 					cmn_err(CE_CONT,
16613db86aabSstevel 					    "cardbus_parse_devprop: "
16623db86aabSstevel 					    "unexpected string [%s] after "
16633db86aabSstevel 					    "[%s]\n", quote, token);
1664*d74fa75eSToomas Soome 					cardbus_devprops_free(cdsp);
16653db86aabSstevel 					return (DDI_FAILURE);
16663db86aabSstevel 				} else {
16673db86aabSstevel 					if (strcmp(token, cb_bnamestr) == 0) {
16683db86aabSstevel 						cdsp->binding_name = kmem_alloc(
16693db86aabSstevel 						    strlen(quote) + 1,
16703db86aabSstevel 						    KM_SLEEP);
16713db86aabSstevel 						(void) strcpy(
16723db86aabSstevel 						    cdsp->binding_name, quote);
16733db86aabSstevel 					}
16743db86aabSstevel 				}
16753db86aabSstevel 				state = PT_STATE_TOKEN;
16763db86aabSstevel 			} /* if (qm) */
16773db86aabSstevel 		} /* PARSE_QUOTE */
16783db86aabSstevel 
16793db86aabSstevel 		em = 0;
16803db86aabSstevel 
16813db86aabSstevel 		if (!qm && (*cp == PARSE_SEMICOLON)) {
16823db86aabSstevel 			smc = 1;
16833db86aabSstevel 		}
16843db86aabSstevel 
16853db86aabSstevel 		/*
16863db86aabSstevel 		 * Check for tokens
16873db86aabSstevel 		 */
16883db86aabSstevel 		else if (!qm && (isalpha(*cp) || isxdigit(*cp))) {
16893db86aabSstevel 			int	tl;
16903db86aabSstevel 			unsigned	*intp;
16913db86aabSstevel 			ptoken = token;
16923db86aabSstevel 			token = find_token(&cp, &l, &eq);
16933db86aabSstevel 
16943db86aabSstevel 			switch (state) {
16953db86aabSstevel 			case PT_STATE_TOKEN:
16963db86aabSstevel 				if (smc) {
16973db86aabSstevel 					if (eq == PARSE_EQUALS)
16983db86aabSstevel 						state = PT_STATE_CHECK;
16993db86aabSstevel 					else
17003db86aabSstevel 						cardbus_add_prop(cdsp,
17013db86aabSstevel 						    DDI_PROP_TYPE_ANY,
17023db86aabSstevel 						    token,
17033db86aabSstevel 						    NULL, 0);
17043db86aabSstevel 				} else if (eq == PARSE_EQUALS)
17053db86aabSstevel 					switch (state = parse_token(token)) {
17063db86aabSstevel 					case PT_STATE_UNKNOWN:
17073db86aabSstevel 						cmn_err(CE_CONT,
17083db86aabSstevel 						    "cardbus_parse_devprop: "
17093db86aabSstevel 						    "unknown token [%s]\n",
17103db86aabSstevel 						    token);
17113db86aabSstevel 						state = PT_STATE_TOKEN;
17123db86aabSstevel 					} /* switch (parse_token) */
17133db86aabSstevel 				else
17143db86aabSstevel 					state = PT_STATE_TOKEN;
17153db86aabSstevel 				break;
17163db86aabSstevel 
17173db86aabSstevel 			case PT_STATE_CHECK:
17183db86aabSstevel 				switch (check_token(token, &tl)) {
17193db86aabSstevel 				case PT_STATE_DEC_VAR:
17203db86aabSstevel 					intp = (unsigned *)kmem_alloc(
17213db86aabSstevel 					    sizeof (int)*tl,
17223db86aabSstevel 					    KM_SLEEP);
17233db86aabSstevel 					if (token_to_dec(token, intp, tl))
17243db86aabSstevel 						cardbus_add_prop(cdsp,
17253db86aabSstevel 						    DDI_PROP_TYPE_INT, ptoken,
17263db86aabSstevel 						    (caddr_t)intp, tl);
17273db86aabSstevel 					else
17283db86aabSstevel 						kmem_free(intp,
17293db86aabSstevel 						    sizeof (int)*tl);
17303db86aabSstevel 					break;
17313db86aabSstevel 				case PT_STATE_HEX_VAR:
17323db86aabSstevel 					intp = (unsigned *)kmem_alloc(
17333db86aabSstevel 					    sizeof (int)*tl,
17343db86aabSstevel 					    KM_SLEEP);
17353db86aabSstevel 					if (token_to_hex(token, intp, tl))
17363db86aabSstevel 						cardbus_add_prop(cdsp,
17373db86aabSstevel 						    DDI_PROP_TYPE_INT,
17383db86aabSstevel 						    ptoken,
17393db86aabSstevel 						    (caddr_t)intp, tl);
17403db86aabSstevel 					else
17413db86aabSstevel 						kmem_free(intp,
17423db86aabSstevel 						    sizeof (int)*tl);
17433db86aabSstevel 					break;
17443db86aabSstevel 				case PT_STATE_STRING_VAR:
17453db86aabSstevel 					if (strcmp(ptoken, cb_nnamestr) == 0) {
17463db86aabSstevel 						cdsp->nodename = kmem_alloc(
17473db86aabSstevel 						    tl + 1, KM_SLEEP);
17483db86aabSstevel 						(void) strcpy(cdsp->nodename,
17493db86aabSstevel 						    token);
17503db86aabSstevel 					} else
17513db86aabSstevel 						cardbus_add_stringprop(cdsp,
17523db86aabSstevel 						    ptoken, token, tl);
17533db86aabSstevel 					break;
17543db86aabSstevel 				}
17553db86aabSstevel 				state = PT_STATE_TOKEN;
17563db86aabSstevel 				break;
17573db86aabSstevel 
17583db86aabSstevel 			case PT_STATE_HEX_VAR:
17593db86aabSstevel 				if (strcmp(ptoken, cb_venidstr) == 0) {
17603db86aabSstevel 					uint_t val;
17613db86aabSstevel 					if (token_to_hex(token, &val, 1))
17623db86aabSstevel 						cdsp->venid = val;
17633db86aabSstevel 				} else if (strcmp(ptoken, cb_devidstr) == 0) {
17643db86aabSstevel 					uint_t val;
17653db86aabSstevel 					if (token_to_hex(token, &val, 1))
17663db86aabSstevel 						cdsp->devid = val;
17673db86aabSstevel 				}
17683db86aabSstevel 				state = PT_STATE_TOKEN;
17693db86aabSstevel 				break;
17703db86aabSstevel 
17713db86aabSstevel 			case PT_STATE_DEC_VAR:
17723db86aabSstevel 				if (strcmp(ptoken, cb_venidstr) == 0) {
17733db86aabSstevel 					uint_t val;
17743db86aabSstevel 					if (token_to_dec(token, &val, 1))
17753db86aabSstevel 						cdsp->venid = val;
17763db86aabSstevel 				} else if (strcmp(ptoken, cb_devidstr) == 0) {
17773db86aabSstevel 					uint_t val;
17783db86aabSstevel 					if (token_to_dec(token, &val, 1))
17793db86aabSstevel 						cdsp->devid = val;
17803db86aabSstevel 				}
17813db86aabSstevel 				state = PT_STATE_TOKEN;
17823db86aabSstevel 				break;
17833db86aabSstevel 
17843db86aabSstevel 			case PT_STATE_STRING_VAR:
17853db86aabSstevel 				if (strcmp(ptoken, cb_bnamestr) == 0) {
17863db86aabSstevel 					cdsp->binding_name = kmem_alloc(
17873db86aabSstevel 					    strlen(token) + 1, KM_SLEEP);
17883db86aabSstevel 					(void) strcpy(cdsp->binding_name,
17893db86aabSstevel 					    token);
17903db86aabSstevel 				}
17913db86aabSstevel 				state = PT_STATE_TOKEN;
17923db86aabSstevel 				break;
17933db86aabSstevel 
17943db86aabSstevel 			default:
17953db86aabSstevel 				cmn_err(CE_CONT, "cardbus_parse_devprop: "
17963db86aabSstevel 				    "unknown state machine state = %d\n",
17973db86aabSstevel 				    state);
17983db86aabSstevel 
17993db86aabSstevel 				cardbus_devprops_free(cdsp);
18003db86aabSstevel 				return (DDI_FAILURE);
18013db86aabSstevel 			} /* switch (state) */
18023db86aabSstevel 			if (eq == PARSE_SEMICOLON)
18033db86aabSstevel 				smc = 1;
18043db86aabSstevel 		}
18053db86aabSstevel 		cp++;
18063db86aabSstevel 		l++;
18073db86aabSstevel 	} /* while (*cp) */
18083db86aabSstevel 
18093db86aabSstevel 	if (qm) {
18103db86aabSstevel 		cmn_err(CE_CONT, "cb_props_parse_line: unterminated "
18113db86aabSstevel 		    "string = [%s]\n", quote);
18123db86aabSstevel 		cardbus_devprops_free(cdsp);
18133db86aabSstevel 		return (DDI_FAILURE);
18143db86aabSstevel 	}
18153db86aabSstevel 
18163db86aabSstevel 	if (state != PT_STATE_TOKEN) {
18173db86aabSstevel 		cmn_err(CE_CONT, "cardbus_parse_devprop: token [%s] "
18183db86aabSstevel 		    "requires value\n", token);
18193db86aabSstevel 		cardbus_devprops_free(cdsp);
18203db86aabSstevel 		return (DDI_FAILURE);
18213db86aabSstevel 	}
18223db86aabSstevel 
18233db86aabSstevel 	if (cdsp->venid == 0 || cdsp->devid == 0) {
18243db86aabSstevel 		cmn_err(CE_CONT, "cardbus_parse_devprop: Entry "
18253db86aabSstevel 		    "requires VendorID and DeviceID\n");
18263db86aabSstevel 		cardbus_devprops_free(cdsp);
18273db86aabSstevel 		return (DDI_FAILURE);
18283db86aabSstevel 	}
18293db86aabSstevel 
18303db86aabSstevel 	cdsp->next = cbp->cb_dsp;
18313db86aabSstevel 	cbp->cb_dsp = cdsp;
18323db86aabSstevel 	return (DDI_SUCCESS);
18333db86aabSstevel }
18343db86aabSstevel 
18353db86aabSstevel static void
cardbus_device_props(cbus_t * cbp)18363db86aabSstevel cardbus_device_props(cbus_t *cbp)
18373db86aabSstevel {
18383db86aabSstevel 	char	**prop_array;
18393db86aabSstevel 	uint_t i, n;
18403db86aabSstevel 
18413db86aabSstevel 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, cbp->cb_dip,
18423db86aabSstevel 	    DDI_PROP_DONTPASS,
18433db86aabSstevel 	    "cb-device-init-props", &prop_array,
18443db86aabSstevel 	    &n) != DDI_PROP_SUCCESS)
18453db86aabSstevel 		return;
18463db86aabSstevel 
18473db86aabSstevel 	for (i = 0; i < n; i++)
18483db86aabSstevel 		(void) cardbus_parse_devprop(cbp, prop_array[i]);
18493db86aabSstevel 
18503db86aabSstevel 	ddi_prop_free(prop_array);
18513db86aabSstevel }
18523db86aabSstevel 
18533db86aabSstevel static int
cardbus_bus_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)18543db86aabSstevel cardbus_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
18553db86aabSstevel     off_t offset, off_t len, caddr_t *vaddrp)
18563db86aabSstevel {
18573db86aabSstevel 	register dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
18583db86aabSstevel 	int	rc;
18593db86aabSstevel 
18603db86aabSstevel 	cardbus_err(dip, 9,
18613db86aabSstevel 	    "cardbus_bus_map(dip=0x%p, rdip=0x%p)\n",
18623db86aabSstevel 	    (void *) dip, (void *) rdip);
18633db86aabSstevel 
18643db86aabSstevel 	if (pdip == NULL)
18653db86aabSstevel 		return (DDI_FAILURE);
18663db86aabSstevel 
18673db86aabSstevel 	/* A child has asked us to set something up */
18683db86aabSstevel 	cardbus_err(dip, 9,
18693db86aabSstevel 	    "cardbus_bus_map(%s) calling %s - 0x%p, "
18703db86aabSstevel 	    "offset 0x%x, len 0x%x\n",
18713db86aabSstevel 	    ddi_driver_name(rdip),
18723db86aabSstevel 	    ddi_driver_name(pdip),
18733db86aabSstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_map,
18743db86aabSstevel 	    (int)offset, (int)len);
18753db86aabSstevel 
18763db86aabSstevel 	rc = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
18773db86aabSstevel 	    (pdip, rdip, mp, offset, len, vaddrp);
18783db86aabSstevel 	/* rc = ddi_map(dip, mp, offset, len, vaddrp); */
18793db86aabSstevel 
1880bb3a048dSrw148561 	if (rc != DDI_SUCCESS) {
18813db86aabSstevel 		cardbus_err(rdip, 8, "cardbus_bus_map failed, rc = %d\n", rc);
1882bb3a048dSrw148561 		return (DDI_FAILURE);
1883bb3a048dSrw148561 	} else {
18843db86aabSstevel 		cardbus_err(rdip, 9, "cardbus_bus_map OK\n");
18853db86aabSstevel 		return (DDI_SUCCESS);
18863db86aabSstevel 	}
18873db86aabSstevel }
18883db86aabSstevel 
18893db86aabSstevel static void
pcirp2rp(const pci_regspec_t * pci_rp,struct regspec * rp)18903db86aabSstevel pcirp2rp(const pci_regspec_t *pci_rp, struct regspec *rp)
18913db86aabSstevel {
18923db86aabSstevel 	/* bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); */
18933db86aabSstevel 	if (PCI_REG_ADDR_G(pci_rp->pci_phys_hi) ==
18943db86aabSstevel 	    PCI_REG_ADDR_G(PCI_ADDR_IO)) {
18953db86aabSstevel 		/* I/O */
18963db86aabSstevel 		rp->regspec_bustype = 1;
18973db86aabSstevel 	} else {
18983db86aabSstevel 		/* memory */
18993db86aabSstevel 		rp->regspec_bustype = 0;
19003db86aabSstevel 	}
19013db86aabSstevel 	rp->regspec_addr = pci_rp->pci_phys_low;
19023db86aabSstevel 	rp->regspec_size = pci_rp->pci_size_low;
19033db86aabSstevel }
19043db86aabSstevel 
19053db86aabSstevel static int
cardbus_dma_allochdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * attr,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)19063db86aabSstevel cardbus_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
19073db86aabSstevel     int (*waitfp)(caddr_t), caddr_t arg,
19083db86aabSstevel     ddi_dma_handle_t *handlep)
19093db86aabSstevel {
19103db86aabSstevel 	dev_info_t *pdip = ddi_get_parent(dip);
19113db86aabSstevel 
19123db86aabSstevel 	cardbus_err(dip, 10,
19133db86aabSstevel 	    "cardbus_dma_allochdl(dip=0x%p, rdip=0x%p)\n",
19143db86aabSstevel 	    (void *) dip, (void *) rdip);
19153db86aabSstevel 
19163db86aabSstevel 	if (pdip == NULL)
19173db86aabSstevel 		return (DDI_FAILURE);
19183db86aabSstevel 
19193db86aabSstevel 	cardbus_err(dip, 11,
19203db86aabSstevel 	    "cardbus_dma_allochdl calling %s - 0x%p\n",
19213db86aabSstevel 	    ddi_driver_name(pdip),
19223db86aabSstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_allochdl);
19233db86aabSstevel 
19243db86aabSstevel 	return (ddi_dma_allochdl(dip, rdip, attr, waitfp, arg, handlep));
19253db86aabSstevel }
19263db86aabSstevel 
19273db86aabSstevel static int
cardbus_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)19283db86aabSstevel cardbus_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
19293db86aabSstevel     ddi_dma_handle_t handle)
19303db86aabSstevel {
19313db86aabSstevel 	dev_info_t *pdip = ddi_get_parent(dip);
19323db86aabSstevel 
19333db86aabSstevel 	cardbus_err(dip, 10,
19343db86aabSstevel 	    "cardbus_dma_freehdl(dip=0x%p, rdip=0x%p)\n",
19353db86aabSstevel 	    (void *) dip, (void *) rdip);
19363db86aabSstevel 
19373db86aabSstevel 	if (pdip == NULL)
19383db86aabSstevel 		return (DDI_FAILURE);
19393db86aabSstevel 
19403db86aabSstevel 	cardbus_err(dip, 11,
19413db86aabSstevel 	    "cardbus_dma_freehdl calling %s - 0x%p\n",
19423db86aabSstevel 	    ddi_driver_name(pdip),
19433db86aabSstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_freehdl);
19443db86aabSstevel 
19453db86aabSstevel 	return (ddi_dma_freehdl(dip, rdip, handle));
19463db86aabSstevel }
19473db86aabSstevel 
19483db86aabSstevel static int
cardbus_dma_bindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,struct ddi_dma_req * dmareq,ddi_dma_cookie_t * cp,uint_t * ccountp)19493db86aabSstevel cardbus_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
19503db86aabSstevel     ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
19513db86aabSstevel     ddi_dma_cookie_t *cp, uint_t *ccountp)
19523db86aabSstevel {
19533db86aabSstevel 	dev_info_t *pdip = ddi_get_parent(dip);
19543db86aabSstevel 
19553db86aabSstevel 	cardbus_err(dip, 10,
19563db86aabSstevel 	    "cardbus_dma_bindhdl(dip=0x%p, rdip=0x%p)\n",
19573db86aabSstevel 	    (void *) dip, (void *) rdip);
19583db86aabSstevel 
19593db86aabSstevel 	if (pdip == NULL)
19603db86aabSstevel 		return (DDI_FAILURE);
19613db86aabSstevel 
19623db86aabSstevel 	cardbus_err(dip, 11,
19633db86aabSstevel 	    "cardbus_dma_bindhdl calling %s - 0x%p\n",
19643db86aabSstevel 	    ddi_driver_name(pdip),
19653db86aabSstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_bindhdl);
19663db86aabSstevel 
19673db86aabSstevel 	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_bindhdl(pdip,
19683db86aabSstevel 	    rdip, handle, dmareq, cp, ccountp));
19693db86aabSstevel }
19703db86aabSstevel 
19713db86aabSstevel static int
cardbus_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)19723db86aabSstevel cardbus_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
19733db86aabSstevel     ddi_dma_handle_t handle)
19743db86aabSstevel {
19753db86aabSstevel 	dev_info_t *pdip = ddi_get_parent(dip);
19763db86aabSstevel 
19773db86aabSstevel 	cardbus_err(dip, 10,
19783db86aabSstevel 	    "cardbus_dma_unbindhdl(dip=0x%p, rdip=0x%p)\n",
19793db86aabSstevel 	    (void *) dip, (void *) rdip);
19803db86aabSstevel 
19813db86aabSstevel 	if (pdip == NULL)
19823db86aabSstevel 		return (DDI_FAILURE);
19833db86aabSstevel 
19843db86aabSstevel 	cardbus_err(dip, 11,
19853db86aabSstevel 	    "cardbus_dma_unbindhdl calling %s - 0x%p\n",
19863db86aabSstevel 	    ddi_driver_name(pdip),
19873db86aabSstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl);
19883db86aabSstevel 
19893db86aabSstevel 	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl(pdip,
19903db86aabSstevel 	    rdip, handle));
19913db86aabSstevel }
19923db86aabSstevel 
19933db86aabSstevel static int
cardbus_dma_flush(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,off_t off,size_t len,uint_t cache_flags)19943db86aabSstevel cardbus_dma_flush(dev_info_t *dip, dev_info_t *rdip,
19953db86aabSstevel     ddi_dma_handle_t handle, off_t off, size_t len,
19963db86aabSstevel     uint_t cache_flags)
19973db86aabSstevel {
19983db86aabSstevel 	dev_info_t *pdip = ddi_get_parent(dip);
19993db86aabSstevel 
20003db86aabSstevel 	cardbus_err(dip, 10,
20013db86aabSstevel 	    "cardbus_dma_flush(dip=0x%p, rdip=0x%p)\n",
20023db86aabSstevel 	    (void *) dip, (void *) rdip);
20033db86aabSstevel 
20043db86aabSstevel 	if (pdip == NULL)
20053db86aabSstevel 		return (DDI_FAILURE);
20063db86aabSstevel 
20073db86aabSstevel 	cardbus_err(dip, 11,
20083db86aabSstevel 	    "cardbus_dma_flush calling %s - 0x%p\n",
20093db86aabSstevel 	    ddi_driver_name(pdip),
20103db86aabSstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_flush);
20113db86aabSstevel 
20123db86aabSstevel 	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_flush(pdip, rdip,
20133db86aabSstevel 	    handle, off, len, cache_flags));
20143db86aabSstevel }
20153db86aabSstevel 
20163db86aabSstevel static int
cardbus_dma_win(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,uint_t win,off_t * offp,size_t * lenp,ddi_dma_cookie_t * cookiep,uint_t * ccountp)20173db86aabSstevel cardbus_dma_win(dev_info_t *dip, dev_info_t *rdip,
20183db86aabSstevel     ddi_dma_handle_t handle, uint_t win, off_t *offp,
20193db86aabSstevel     size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
20203db86aabSstevel {
20213db86aabSstevel 	dev_info_t *pdip = ddi_get_parent(dip);
20223db86aabSstevel 	cardbus_err(dip, 6,
20233db86aabSstevel 	    "cardbus_dma_win(dip=0x%p, rdip=0x%p)\n",
20243db86aabSstevel 	    (void *) dip, (void *) rdip);
20253db86aabSstevel 
20263db86aabSstevel 	if (pdip == NULL)
20273db86aabSstevel 		return (DDI_FAILURE);
20283db86aabSstevel 
20293db86aabSstevel 	cardbus_err(dip, 8,
20303db86aabSstevel 	    "cardbus_dma_win calling %s - 0x%p\n",
20313db86aabSstevel 	    ddi_driver_name(pdip),
20323db86aabSstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_win);
20333db86aabSstevel 
20343db86aabSstevel 	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_win(pdip, rdip,
20353db86aabSstevel 	    handle, win, offp, lenp, cookiep, ccountp));
20363db86aabSstevel }
20373db86aabSstevel 
20383db86aabSstevel static int
cardbus_dma_map(dev_info_t * dip,dev_info_t * rdip,struct ddi_dma_req * dmareqp,ddi_dma_handle_t * handlep)20393db86aabSstevel cardbus_dma_map(dev_info_t *dip, dev_info_t *rdip,
20403db86aabSstevel     struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
20413db86aabSstevel {
20423db86aabSstevel 	dev_info_t *pdip = ddi_get_parent(dip);
20433db86aabSstevel 
20443db86aabSstevel 	cardbus_err(dip, 10,
20453db86aabSstevel 	    "cardbus_dma_map(dip=0x%p, rdip=0x%p)\n",
20463db86aabSstevel 	    (void *) dip, (void *) rdip);
20473db86aabSstevel 
20483db86aabSstevel 	if (pdip == NULL)
20493db86aabSstevel 		return (DDI_FAILURE);
20503db86aabSstevel 
20513db86aabSstevel 	cardbus_err(dip, 11,
20523db86aabSstevel 	    "cardbus_dma_map calling %s - 0x%p\n",
20533db86aabSstevel 	    ddi_driver_name(pdip),
20543db86aabSstevel 	    (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_map);
20553db86aabSstevel 
20563db86aabSstevel 	return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_map(pdip, rdip,
20573db86aabSstevel 	    dmareqp, handlep));
20583db86aabSstevel }
20593db86aabSstevel 
20603db86aabSstevel static int
cardbus_get_eventcookie(dev_info_t * dip,dev_info_t * rdip,char * eventname,ddi_eventcookie_t * cookiep)20613db86aabSstevel cardbus_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
20623db86aabSstevel     char *eventname, ddi_eventcookie_t *cookiep)
20633db86aabSstevel {
20643db86aabSstevel 	cbus_t *cbp;
20653db86aabSstevel 	int	cb_instance;
20663db86aabSstevel 	int	rc;
20673db86aabSstevel 
20683db86aabSstevel 	/*
20693db86aabSstevel 	 * get the soft state structure for the bus instance.
20703db86aabSstevel 	 */
20713db86aabSstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
20723db86aabSstevel 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
20733db86aabSstevel 	ASSERT(cb_instance >= 0);
20743db86aabSstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
20753db86aabSstevel 
20763db86aabSstevel 	cardbus_err(dip, 6, "cardbus_get_eventcookie %s\n", eventname);
20773db86aabSstevel 
20783db86aabSstevel 	ASSERT(number_of_cardbus_cards != 0);
20793db86aabSstevel 
20803db86aabSstevel 	if (cbp->cb_ndi_event_hdl == NULL) {
20813db86aabSstevel 		/*
20823db86aabSstevel 		 * We can't handle up (probably called at the attachment
20833db86aabSstevel 		 * point) so pass it on up
20843db86aabSstevel 		 */
20853db86aabSstevel 		dev_info_t *pdip = ddi_get_parent(dip);
20863db86aabSstevel 		cardbus_err(dip, 8,
20873db86aabSstevel 		    "cardbus_get_eventcookie calling %s - 0x%p\n",
20883db86aabSstevel 		    ddi_driver_name(pdip),
20893db86aabSstevel 		    (void *)
20903db86aabSstevel 		    DEVI(pdip)->devi_ops->devo_bus_ops->bus_get_eventcookie);
20913db86aabSstevel 		return (DEVI(pdip)->devi_ops->devo_bus_ops->
20923db86aabSstevel 		    bus_get_eventcookie(pdip, rdip, eventname, cookiep));
20933db86aabSstevel 	}
20943db86aabSstevel 
20953db86aabSstevel 	cardbus_err(dip, 8,
20963db86aabSstevel 	    "cardbus_get_eventcookie calling ndi_event_retrieve_cookie\n");
20973db86aabSstevel 
20983db86aabSstevel 	rc = ndi_event_retrieve_cookie(cbp->cb_ndi_event_hdl, rdip, eventname,
20993db86aabSstevel 	    cookiep, NDI_EVENT_NOPASS);
21003db86aabSstevel 
21013db86aabSstevel 	cardbus_err(dip, 7,
21023db86aabSstevel 	    "cardbus_get_eventcookie rc %d cookie %p\n", rc, (void *)*cookiep);
21033db86aabSstevel 	return (rc);
21043db86aabSstevel }
21053db86aabSstevel 
21063db86aabSstevel static int
cardbus_add_eventcall(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void (* callback)(dev_info_t * dip,ddi_eventcookie_t cookie,void * arg,void * bus_impldata),void * arg,ddi_callback_id_t * cb_id)21073db86aabSstevel cardbus_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
21083db86aabSstevel     ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
21093db86aabSstevel     ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
21103db86aabSstevel     void *arg, ddi_callback_id_t *cb_id)
21113db86aabSstevel {
21123db86aabSstevel 	cbus_t *cbp;
21133db86aabSstevel 	int	cb_instance;
21143db86aabSstevel 	int	rc;
21153db86aabSstevel 
21163db86aabSstevel 	/*
21173db86aabSstevel 	 * get the soft state structure for the bus instance.
21183db86aabSstevel 	 */
21193db86aabSstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
21203db86aabSstevel 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
21213db86aabSstevel 	ASSERT(cb_instance >= 0);
21223db86aabSstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
21233db86aabSstevel 
21243db86aabSstevel 	cardbus_err(dip, 6, "cardbus_add_eventcall\n");
21253db86aabSstevel 
21263db86aabSstevel 	ASSERT(number_of_cardbus_cards != 0);
21273db86aabSstevel 
21283db86aabSstevel 	if (cbp->cb_ndi_event_hdl == NULL) {
21293db86aabSstevel 		/*
21303db86aabSstevel 		 * We can't handle up (probably called at the attachment
21313db86aabSstevel 		 * point) so pass it on up
21323db86aabSstevel 		 */
21333db86aabSstevel 		dev_info_t *pdip = ddi_get_parent(dip);
21343db86aabSstevel 		cardbus_err(dip, 8,
21353db86aabSstevel 		    "cardbus_add_eventcall calling %s - 0x%p\n",
21363db86aabSstevel 		    ddi_driver_name(pdip),
21373db86aabSstevel 		    (void *)
21383db86aabSstevel 		    DEVI(pdip)->devi_ops->devo_bus_ops->bus_add_eventcall);
21393db86aabSstevel 		return (DEVI(pdip)->devi_ops->devo_bus_ops->
21403db86aabSstevel 		    bus_add_eventcall(pdip, rdip, cookie, callback,
21413db86aabSstevel 		    arg, cb_id));
21423db86aabSstevel 	}
21433db86aabSstevel 
21443db86aabSstevel 	cardbus_err(dip, 8,
21453db86aabSstevel 	    "cardbus_add_eventcall calling ndi_event_add_callback\n");
21463db86aabSstevel 
21473db86aabSstevel 	rc = ndi_event_add_callback(cbp->cb_ndi_event_hdl, rdip, cookie,
21483db86aabSstevel 	    callback, arg, NDI_EVENT_NOPASS, cb_id);
21493db86aabSstevel 	cardbus_err(dip, 7,
21503db86aabSstevel 	    "cardbus_add_eventcall rc %d cookie %p\n", rc, (void *)cookie);
21513db86aabSstevel 	return (rc);
21523db86aabSstevel }
21533db86aabSstevel 
21543db86aabSstevel static int
cardbus_remove_eventcall(dev_info_t * dip,ddi_callback_id_t cb_id)21553db86aabSstevel cardbus_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
21563db86aabSstevel {
21573db86aabSstevel 	cbus_t *cbp;
21583db86aabSstevel 	int	cb_instance;
21593db86aabSstevel 
21603db86aabSstevel 	/*
21613db86aabSstevel 	 * get the soft state structure for the bus instance.
21623db86aabSstevel 	 */
21633db86aabSstevel 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
21643db86aabSstevel 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
21653db86aabSstevel 	ASSERT(cb_instance >= 0);
21663db86aabSstevel 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
21673db86aabSstevel 
21683db86aabSstevel 	cardbus_err(dip, 6, "cardbus_remove_eventcall\n");
21693db86aabSstevel 
21703db86aabSstevel 	ASSERT(number_of_cardbus_cards != 0);
21713db86aabSstevel 
21723db86aabSstevel 	if (cbp->cb_ndi_event_hdl == NULL) {
21733db86aabSstevel 		/*
21743db86aabSstevel 		 * We can't handle up (probably called at the attachment
21753db86aabSstevel 		 * point) so pass it on up
21763db86aabSstevel 		 */
21773db86aabSstevel 		dev_info_t *pdip = ddi_get_parent(dip);
21783db86aabSstevel 		cardbus_err(dip, 8,
21793db86aabSstevel 		    "cardbus_remove_eventcall calling %s - 0x%p\n",
21803db86aabSstevel 		    ddi_driver_name(pdip),
21813db86aabSstevel 		    (void *)
21823db86aabSstevel 		    DEVI(pdip)->devi_ops->devo_bus_ops->bus_remove_eventcall);
21833db86aabSstevel 		return (DEVI(pdip)->devi_ops->devo_bus_ops->
21843db86aabSstevel 		    bus_remove_eventcall(pdip, cb_id));
21853db86aabSstevel 	}
21863db86aabSstevel 
21873db86aabSstevel 	return (ndi_event_remove_callback(cbp->cb_ndi_event_hdl, cb_id));
21883db86aabSstevel }
21893db86aabSstevel 
21903db86aabSstevel static int
cardbus_post_event(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void * bus_impldata)21913db86aabSstevel cardbus_post_event(dev_info_t *dip, dev_info_t *rdip,
21923db86aabSstevel     ddi_eventcookie_t cookie, void *bus_impldata)
21933db86aabSstevel {
21943db86aabSstevel 	_NOTE(ARGUNUSED(rdip, cookie, bus_impldata))
21953db86aabSstevel 	cardbus_err(dip, 1, "cardbus_post_event()\n");
21963db86aabSstevel 	return (DDI_FAILURE);
21973db86aabSstevel }
21983db86aabSstevel 
21993db86aabSstevel static int cardbus_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22003db86aabSstevel 		ddi_intr_handle_impl_t *hdlp);
22013db86aabSstevel static int cardbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22023db86aabSstevel 		ddi_intr_handle_impl_t *hdlp);
22033db86aabSstevel static int cardbus_enable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22043db86aabSstevel 		ddi_intr_handle_impl_t *hdlp);
22053db86aabSstevel static int cardbus_disable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22063db86aabSstevel 		ddi_intr_handle_impl_t *hdlp);
22073db86aabSstevel 
22080d282d13Srw148561 static int
cardbus_get_pil(dev_info_t * dip)22090d282d13Srw148561 cardbus_get_pil(dev_info_t *dip)
22100d282d13Srw148561 {
22110d282d13Srw148561 	return ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
22120d282d13Srw148561 	    "interrupt-priorities", 6);
22130d282d13Srw148561 }
22140d282d13Srw148561 
22153db86aabSstevel static int
cardbus_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)22163db86aabSstevel cardbus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
22173db86aabSstevel     ddi_intr_handle_impl_t *hdlp, void *result)
22183db86aabSstevel {
22193db86aabSstevel 	int ret = DDI_SUCCESS;
22203db86aabSstevel 
22213db86aabSstevel #if defined(CARDBUS_DEBUG)
22223db86aabSstevel 	cardbus_err(dip, 8, "cardbus_intr_ops() intr_op=%d\n", (int)intr_op);
22233db86aabSstevel #endif
22243db86aabSstevel 
22253db86aabSstevel 	switch (intr_op) {
22263db86aabSstevel 	case DDI_INTROP_GETCAP:
22273db86aabSstevel 		*(int *)result = DDI_INTR_FLAG_LEVEL;
22283db86aabSstevel 		break;
22293db86aabSstevel 	case DDI_INTROP_ALLOC:
22303db86aabSstevel 		*(int *)result = hdlp->ih_scratch1;
22313db86aabSstevel 		break;
22323db86aabSstevel 	case DDI_INTROP_FREE:
22333db86aabSstevel 		break;
22343db86aabSstevel 	case DDI_INTROP_GETPRI:
22353db86aabSstevel 		*(int *)result = hdlp->ih_pri ?
22360d282d13Srw148561 		    hdlp->ih_pri : cardbus_get_pil(dip);
22373db86aabSstevel 		break;
22383db86aabSstevel 	case DDI_INTROP_SETPRI:
22393db86aabSstevel 		break;
22403db86aabSstevel 	case DDI_INTROP_ADDISR:
22413db86aabSstevel 	case DDI_INTROP_REMISR:
22423db86aabSstevel 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
22433db86aabSstevel 			cardbus_err(dip, 1, "Only fixed interrupts\n");
22443db86aabSstevel 			return (DDI_FAILURE);
22453db86aabSstevel 		}
22463db86aabSstevel 		break;
22473db86aabSstevel 	case DDI_INTROP_ENABLE:
22483db86aabSstevel 		ret = cardbus_enable_intr_impl(dip, rdip, hdlp);
22493db86aabSstevel 		break;
22503db86aabSstevel 	case DDI_INTROP_DISABLE:
22513db86aabSstevel 		ret = cardbus_disable_intr_impl(dip, rdip, hdlp);
22523db86aabSstevel 		break;
22533db86aabSstevel 	case DDI_INTROP_NINTRS:
22543db86aabSstevel 	case DDI_INTROP_NAVAIL:
22550d282d13Srw148561 #ifdef sparc
2256a54f81fbSanish 		*(int *)result = i_ddi_get_intx_nintrs(rdip);
22570d282d13Srw148561 #else
22580d282d13Srw148561 		*(int *)result = 1;
22590d282d13Srw148561 #endif
22603db86aabSstevel 		break;
22613db86aabSstevel 	case DDI_INTROP_SUPPORTED_TYPES:
22620d282d13Srw148561 		*(int *)result = DDI_INTR_TYPE_FIXED;
22633db86aabSstevel 		break;
22643db86aabSstevel 	default:
22653db86aabSstevel 		ret = DDI_ENOTSUP;
22663db86aabSstevel 		break;
22673db86aabSstevel 	}
22683db86aabSstevel 
22693db86aabSstevel 	return (ret);
22703db86aabSstevel }
22713db86aabSstevel 
22723db86aabSstevel static int
cardbus_enable_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)22733db86aabSstevel cardbus_enable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22743db86aabSstevel     ddi_intr_handle_impl_t *hdlp)
22753db86aabSstevel {
22763db86aabSstevel 	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
22773db86aabSstevel 	set_irq_handler_t sih;
22783db86aabSstevel 	uint_t socket = 0; /* We only support devices */
22793db86aabSstevel 			    /* with one socket per function */
22803db86aabSstevel 
22813db86aabSstevel 	ASSERT(anp != NULL);
22823db86aabSstevel 
22833db86aabSstevel 	cardbus_err(dip, 9,
22843db86aabSstevel 	    "cardbus_enable_intr_impl, intr=0x%p, arg1=0x%p, arg2=0x%p"
22853db86aabSstevel 	    "rdip=0x%p(%s)\n",
22863db86aabSstevel 	    (void *) hdlp->ih_cb_func,
22873db86aabSstevel 	    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2,
22883db86aabSstevel 	    (void *) rdip, ddi_driver_name(rdip));
22893db86aabSstevel 
22903db86aabSstevel 	if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
22913db86aabSstevel 		cardbus_err(dip, 1, "Only fixed interrupts\n");
22923db86aabSstevel 		return (DDI_FAILURE);
22933db86aabSstevel 	}
22943db86aabSstevel 
22953db86aabSstevel 	sih.socket = socket;
22960d282d13Srw148561 	sih.handler_id = (unsigned)(long)rdip;
2297647709cbSToomas Soome 	sih.handler = (f_tt *)(uintptr_t)hdlp->ih_cb_func;
22983db86aabSstevel 	sih.arg1 = hdlp->ih_cb_arg1;
22993db86aabSstevel 	sih.arg2 = hdlp->ih_cb_arg2;
23000d282d13Srw148561 	sih.irq = cardbus_get_pil(dip);
23013db86aabSstevel 
23023db86aabSstevel 	if ((*anp->an_if->pcif_set_interrupt)(dip, &sih) != SUCCESS)
23033db86aabSstevel 		return (DDI_FAILURE);
23043db86aabSstevel 
23053db86aabSstevel 	return (DDI_SUCCESS);
23063db86aabSstevel }
23073db86aabSstevel 
23083db86aabSstevel static int
cardbus_disable_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)23093db86aabSstevel cardbus_disable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
23103db86aabSstevel     ddi_intr_handle_impl_t *hdlp)
23113db86aabSstevel {
23123db86aabSstevel 	anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
23133db86aabSstevel 	clear_irq_handler_t cih;
23143db86aabSstevel 	uint_t socket = 0; /* We only support devices with 1 socket per */
23153db86aabSstevel 			    /* function. */
23163db86aabSstevel 
23173db86aabSstevel 	ASSERT(anp != NULL);
23183db86aabSstevel 
23193db86aabSstevel 	cardbus_err(dip, 9,
23203db86aabSstevel 	    "cardbus_disable_intr_impl, intr=0x%p, arg1=0x%p, arg2=0x%p"
23213db86aabSstevel 	    "rdip=0x%p(%s%d)\n",
23223db86aabSstevel 	    (void *) hdlp->ih_cb_func,
23233db86aabSstevel 	    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2,
23243db86aabSstevel 	    (void *) rdip, ddi_driver_name(rdip), ddi_get_instance(rdip));
23253db86aabSstevel 
23263db86aabSstevel 	if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
23273db86aabSstevel 		cardbus_err(dip, 1, "Only fixed interrupts\n");
23283db86aabSstevel 		return (DDI_FAILURE);
23293db86aabSstevel 	}
23303db86aabSstevel 
23313db86aabSstevel 	cih.socket = socket;
23320d282d13Srw148561 	cih.handler_id = (unsigned)(long)rdip;
2333647709cbSToomas Soome 	cih.handler = (f_tt *)(uintptr_t)hdlp->ih_cb_func;
23343db86aabSstevel 
23353db86aabSstevel 	if ((*anp->an_if->pcif_clr_interrupt)(dip, &cih) != SUCCESS)
23363db86aabSstevel 		return (DDI_FAILURE);
23373db86aabSstevel 
23383db86aabSstevel 	return (DDI_SUCCESS);
23393db86aabSstevel }
23403db86aabSstevel 
23413db86aabSstevel #if defined(CARDBUS_DEBUG)
23423db86aabSstevel static int	cardbus_do_pprintf = 0;
23433db86aabSstevel #endif
23443db86aabSstevel 
23453db86aabSstevel /*PRINTFLIKE3*/
23463db86aabSstevel void
cardbus_err(dev_info_t * dip,int level,const char * fmt,...)23473db86aabSstevel cardbus_err(dev_info_t *dip, int level, const char *fmt, ...)
23483db86aabSstevel {
23493db86aabSstevel 	if (cardbus_debug && (level <= cardbus_debug)) {
23503db86aabSstevel 		va_list adx;
23513db86aabSstevel 		int	instance;
23523db86aabSstevel 		char	buf[256];
23533db86aabSstevel 		const char	*name;
23543db86aabSstevel 		char	*nl = "";
23553db86aabSstevel #if !defined(CARDBUS_DEBUG)
23563db86aabSstevel 		int	ce;
23573db86aabSstevel 		char	qmark = 0;
23583db86aabSstevel 
23593db86aabSstevel 		if (level <= 3)
23603db86aabSstevel 			ce = CE_WARN;
23613db86aabSstevel 		else
23623db86aabSstevel 			ce = CE_CONT;
23633db86aabSstevel 		if (level == 4)
23643db86aabSstevel 			qmark = 1;
23653db86aabSstevel #endif
23663db86aabSstevel 
23673db86aabSstevel 		if (dip) {
23683db86aabSstevel 			instance = ddi_get_instance(dip);
23693db86aabSstevel 			/* name = ddi_binding_name(dip); */
23703db86aabSstevel 			name = ddi_driver_name(dip);
23713db86aabSstevel 		} else {
23723db86aabSstevel 			instance = 0;
23733db86aabSstevel 			name = "";
23743db86aabSstevel 		}
23753db86aabSstevel 
23763db86aabSstevel 		va_start(adx, fmt);
23773db86aabSstevel 		/* vcmn_err(ce, fmt, adx); */
23783db86aabSstevel 		/* vprintf(fmt, adx); */
23793db86aabSstevel 		/* prom_vprintf(fmt, adx); */
23803db86aabSstevel 		(void) vsprintf(buf, fmt, adx);
23813db86aabSstevel 		va_end(adx);
23823db86aabSstevel 
23833db86aabSstevel 		if (buf[strlen(buf) - 1] != '\n')
23843db86aabSstevel 			nl = "\n";
23853db86aabSstevel 
23863db86aabSstevel #if defined(CARDBUS_DEBUG)
23873db86aabSstevel 		if (cardbus_do_pprintf) {
23883db86aabSstevel 			if (dip) {
23893db86aabSstevel 				if (instance >= 0)
23903db86aabSstevel 					prom_printf("%s(%d),0x%p: %s%s",
2391903a11ebSrh87107 					    name, instance, (void *)dip,
2392903a11ebSrh87107 					    buf, nl);
23933db86aabSstevel 				else
23943db86aabSstevel 					prom_printf("%s,0x%p: %s%s", name,
2395903a11ebSrh87107 					    (void *)dip, buf, nl);
23963db86aabSstevel 			} else
23973db86aabSstevel 				prom_printf("%s%s", buf, nl);
23983db86aabSstevel 		} else {
23993db86aabSstevel 			if (dip) {
24003db86aabSstevel 				if (instance >= 0)
24013db86aabSstevel 					cmn_err(CE_CONT, "%s(%d),0x%p: %s%s",
24023db86aabSstevel 					    name, instance, (void *)dip,
24033db86aabSstevel 					    buf, nl);
24043db86aabSstevel 				else
24053db86aabSstevel 					cmn_err(CE_CONT, "%s,0x%p: %s%s",
24063db86aabSstevel 					    name, (void *)dip, buf, nl);
24073db86aabSstevel 			} else
24083db86aabSstevel 				cmn_err(CE_CONT, "%s%s", buf, nl);
24093db86aabSstevel 		}
24103db86aabSstevel #else
24113db86aabSstevel 		if (dip)
24123db86aabSstevel 			cmn_err(ce, qmark ? "?%s%d: %s%s" : "%s%d: %s%s",
24133db86aabSstevel 			    name, instance, buf, nl);
24143db86aabSstevel 		else
24153db86aabSstevel 			cmn_err(ce, qmark ? "?%s%s" : "%s%s", buf, nl);
24163db86aabSstevel #endif
24173db86aabSstevel 	}
24183db86aabSstevel }
24193db86aabSstevel 
cardbus_expand_busrange(dev_info_t * dip)24203db86aabSstevel static void cardbus_expand_busrange(dev_info_t *dip)
24213db86aabSstevel {
24223db86aabSstevel 	dev_info_t *pdip;
24233db86aabSstevel 	cardbus_bus_range_t *bus_range;
24243db86aabSstevel 	int len;
24253db86aabSstevel 
24263db86aabSstevel 	pdip = ddi_get_parent(dip);
24273db86aabSstevel 
24283db86aabSstevel 	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "bus-range",
24293db86aabSstevel 	    (caddr_t)&bus_range, &len) == DDI_PROP_SUCCESS) {
24303db86aabSstevel 		ndi_ra_request_t req;
24313db86aabSstevel 		uint64_t next_bus, blen;
24323db86aabSstevel 		uint32_t ret;
24333db86aabSstevel 		ddi_acc_handle_t handle;
24343db86aabSstevel 
24353db86aabSstevel 		if (bus_range->lo != bus_range->hi)
24363db86aabSstevel 			cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24373db86aabSstevel 			    "%u -> %u\n", bus_range->lo, bus_range->hi);
24383db86aabSstevel 		else {
24393db86aabSstevel 
24403db86aabSstevel 			bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
24413db86aabSstevel 			req.ra_addr = bus_range->lo + 1;
24423db86aabSstevel 			req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
24433db86aabSstevel 			req.ra_len = 12;
24443db86aabSstevel 
24453db86aabSstevel 			while ((req.ra_len > 0) &&
24463db86aabSstevel 			    (ret = ndi_ra_alloc(ddi_get_parent(pdip), &req,
24473db86aabSstevel 			    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
24483db86aabSstevel 			    NDI_RA_PASS)) != NDI_SUCCESS)
24493db86aabSstevel 				req.ra_len--;
24503db86aabSstevel 
24513db86aabSstevel 			if (ret != NDI_SUCCESS) {
24523db86aabSstevel 				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24533db86aabSstevel 				    "fail to allocate bus number\n");
24543db86aabSstevel 				goto exit;
24553db86aabSstevel 			}
24563db86aabSstevel 
24573db86aabSstevel 			bus_range->hi = bus_range->lo + req.ra_len;
24583db86aabSstevel 			if (ndi_prop_update_int_array(DDI_DEV_T_NONE, pdip,
24593db86aabSstevel 			    "bus-range", (int *)bus_range, 2) != DDI_SUCCESS) {
24603db86aabSstevel 				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24613db86aabSstevel 				    "fail to update bus-range property\n");
24623db86aabSstevel 				goto exit;
24633db86aabSstevel 			}
24643db86aabSstevel 
24653db86aabSstevel 			if (pci_config_setup(pdip, &handle) != DDI_SUCCESS) {
24663db86aabSstevel 				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24673db86aabSstevel 				    "fail to pci_config_setup\n");
24683db86aabSstevel 				goto exit;
24693db86aabSstevel 			}
24703db86aabSstevel 
24713db86aabSstevel 			pci_config_put8(handle, PCI_BCNF_SECBUS, bus_range->lo);
24723db86aabSstevel 			pci_config_put8(handle, PCI_BCNF_SUBBUS, bus_range->hi);
24733db86aabSstevel 
24743db86aabSstevel 			cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24753db86aabSstevel 			    "parent dip %u -> %u\n",
24763db86aabSstevel 			    pci_config_get8(handle, PCI_BCNF_SECBUS),
24773db86aabSstevel 			    pci_config_get8(handle, PCI_BCNF_SUBBUS));
24783db86aabSstevel 			pci_config_teardown(&handle);
24793db86aabSstevel 
24803db86aabSstevel 			if (ndi_ra_map_setup(pdip, NDI_RA_TYPE_PCI_BUSNUM)
24813db86aabSstevel 			    != NDI_SUCCESS) {
24823db86aabSstevel 				cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24833db86aabSstevel 				    "fail to ndi_ra_map_setup of bus number\n");
24843db86aabSstevel 				goto exit;
24853db86aabSstevel 			}
24863db86aabSstevel 
24873db86aabSstevel 			(void) ndi_ra_free(pdip,
24883db86aabSstevel 			    (uint64_t)bus_range->lo + 1, req.ra_len,
24893db86aabSstevel 			    NDI_RA_TYPE_PCI_BUSNUM, 0);
24903db86aabSstevel 		}
24913db86aabSstevel 
24923db86aabSstevel 		bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
24933db86aabSstevel 		req.ra_len = 2;
24943db86aabSstevel 
24953db86aabSstevel 		while ((req.ra_len > 0) &&
24963db86aabSstevel 		    (ret = ndi_ra_alloc(pdip, &req,
24973db86aabSstevel 		    &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
24983db86aabSstevel 		    0)) != NDI_SUCCESS)
24993db86aabSstevel 			req.ra_len--;
25003db86aabSstevel 
25013db86aabSstevel 		cardbus_err(dip, 1, "cardbus_expand_busrange: "
25023db86aabSstevel 		    "cardbus dip base %u length %d\n",
25033db86aabSstevel 		    (int)next_bus, (int)req.ra_len);
25043db86aabSstevel 
25053db86aabSstevel 		if (ret != NDI_SUCCESS) {
25063db86aabSstevel 			cardbus_err(dip, 1, "cardbus_expand_busrange: "
25073db86aabSstevel 			    "fail to allocate bus number of length %d "
25083db86aabSstevel 			    "from parent\n",
25093db86aabSstevel 			    (int)req.ra_len);
25103db86aabSstevel 			goto exit;
25113db86aabSstevel 		}
25123db86aabSstevel 
25133db86aabSstevel 		if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM)
25143db86aabSstevel 		    != NDI_SUCCESS) {
25153db86aabSstevel 			cardbus_err(dip, 1, "cardbus_expand_busrange: "
25163db86aabSstevel 			    "fail to ndi_ra_map_setup of bus numbers\n");
25173db86aabSstevel 			goto exit;
25183db86aabSstevel 		}
25193db86aabSstevel 
25203db86aabSstevel 		(void) ndi_ra_free(dip,
25213db86aabSstevel 		    (uint64_t)next_bus, req.ra_len,
25223db86aabSstevel 		    NDI_RA_TYPE_PCI_BUSNUM, 0);
25233db86aabSstevel exit:
25243db86aabSstevel 		kmem_free(bus_range, len);
25253db86aabSstevel 
25263db86aabSstevel 	} else
25273db86aabSstevel 		cardbus_err(pdip, 1, "cardbus_expand_busrange: "
25283db86aabSstevel 		    "parent dip doesn't have busrange prop\n");
25293db86aabSstevel }
2530