12305Sstevel /*
22305Sstevel * CDDL HEADER START
32305Sstevel *
42305Sstevel * The contents of this file are subject to the terms of the
52305Sstevel * Common Development and Distribution License (the "License").
62305Sstevel * You may not use this file except in compliance with the License.
72305Sstevel *
82305Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92305Sstevel * or http://www.opensolaris.org/os/licensing.
102305Sstevel * See the License for the specific language governing permissions
112305Sstevel * and limitations under the License.
122305Sstevel *
132305Sstevel * When distributing Covered Code, include this CDDL HEADER in each
142305Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152305Sstevel * If applicable, add the following below this CDDL HEADER, with the
162305Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
172305Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
182305Sstevel *
192305Sstevel * CDDL HEADER END
202305Sstevel */
212305Sstevel /*
227151Srw148561 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
232305Sstevel * Use is subject to license terms.
242305Sstevel */
252305Sstevel
262305Sstevel /*
272305Sstevel * Copyright (c) * Copyright (c) 2001 Tadpole Technology plc
282305Sstevel * All rights reserved.
292305Sstevel * From "@(#)pcicfg.c 1.31 99/06/18 SMI"
302305Sstevel */
312305Sstevel
322305Sstevel #pragma ident "%Z%%M% %I% %E% SMI"
332305Sstevel
342305Sstevel /*
352305Sstevel * Cardbus module
362305Sstevel */
372305Sstevel
382305Sstevel #include <sys/conf.h>
392305Sstevel #include <sys/modctl.h>
402305Sstevel
412305Sstevel #include <sys/pci.h>
422305Sstevel
432305Sstevel #include <sys/ddi.h>
442305Sstevel #include <sys/sunndi.h>
452305Sstevel #include <sys/ddi_impldefs.h>
462305Sstevel
472305Sstevel #include <sys/hotplug/hpcsvc.h>
482305Sstevel
492305Sstevel #include <sys/pctypes.h>
502305Sstevel #include <sys/pcmcia.h>
512305Sstevel #include <sys/sservice.h>
522305Sstevel #include <sys/note.h>
532305Sstevel
542305Sstevel #include <sys/pci/pci_types.h>
552305Sstevel #include <sys/pci/pci_sc.h>
562305Sstevel
572305Sstevel #include <sys/pcic_reg.h>
582305Sstevel #include <sys/pcic_var.h>
592305Sstevel #include <sys/pcmcia.h>
602305Sstevel
612305Sstevel #ifdef sparc
622305Sstevel #include <sys/ddi_subrdefs.h>
632305Sstevel #elif defined(__x86) || defined(__amd64)
642305Sstevel #include <sys/pci_intr_lib.h>
652305Sstevel #include <sys/mach_intr.h>
662305Sstevel #endif
672305Sstevel
682305Sstevel #include "cardbus.h"
692305Sstevel #include "cardbus_parse.h"
702305Sstevel #include "cardbus_hp.h"
712305Sstevel #include "cardbus_cfg.h"
722305Sstevel
732305Sstevel static int cardbus_command_default = PCI_COMM_SERR_ENABLE |
742305Sstevel PCI_COMM_WAIT_CYC_ENAB |
752305Sstevel PCI_COMM_PARITY_DETECT |
762305Sstevel PCI_COMM_ME | PCI_COMM_MAE |
772305Sstevel PCI_COMM_IO;
782305Sstevel
792305Sstevel static int cardbus_next_instance = 0;
802305Sstevel static int cardbus_count = 0;
812451Srw148561 int number_of_cardbus_cards = 0;
822305Sstevel
832305Sstevel static int cardbus_bus_map(dev_info_t *dip, dev_info_t *rdip,
842305Sstevel ddi_map_req_t *mp, off_t offset, off_t len, caddr_t *vaddrp);
852305Sstevel static void pcirp2rp(const pci_regspec_t *pci_rp, struct regspec *rp);
862305Sstevel
872305Sstevel static int cardbus_ctlops(dev_info_t *, dev_info_t *,
882305Sstevel ddi_ctl_enum_t, void *arg, void *);
892305Sstevel static void cardbus_init_child_regs(dev_info_t *child);
902305Sstevel static int cardbus_initchild(dev_info_t *, dev_info_t *,
912305Sstevel dev_info_t *, void *);
922305Sstevel static int cardbus_name_child(dev_info_t *, char *, int);
932305Sstevel static void cardbus_removechild(dev_info_t *dip);
942305Sstevel
952305Sstevel static int cardbus_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
962305Sstevel ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg,
972305Sstevel ddi_dma_handle_t *handlep);
982305Sstevel static int cardbus_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
992305Sstevel ddi_dma_handle_t handle);
1002305Sstevel static int cardbus_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
1012305Sstevel ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
1022305Sstevel ddi_dma_cookie_t *cp, uint_t *ccountp);
1032305Sstevel static int cardbus_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
1042305Sstevel ddi_dma_handle_t handle);
1052305Sstevel static int cardbus_dma_flush(dev_info_t *dip, dev_info_t *rdip,
1062305Sstevel ddi_dma_handle_t handle, off_t off, size_t len,
1072305Sstevel uint_t cache_flags);
1082305Sstevel static int cardbus_dma_win(dev_info_t *dip, dev_info_t *rdip,
1092305Sstevel ddi_dma_handle_t handle, uint_t win, off_t *offp,
1102305Sstevel size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp);
1112305Sstevel static int cardbus_dma_map(dev_info_t *dip, dev_info_t *rdip,
1122305Sstevel struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep);
1132305Sstevel
1142305Sstevel static int cardbus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
1152305Sstevel ddi_prop_op_t prop_op, int mod_flags,
1162305Sstevel char *name, caddr_t valuep, int *lengthp);
1172305Sstevel
1182305Sstevel static int cardbus_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
1192305Sstevel char *eventname, ddi_eventcookie_t *cookiep);
1202305Sstevel static int cardbus_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
1212305Sstevel ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
1222305Sstevel ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
1232305Sstevel void *arg, ddi_callback_id_t *cb_id);
1242305Sstevel static int cardbus_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id);
1252305Sstevel static int cardbus_post_event(dev_info_t *dip, dev_info_t *rdip,
1262305Sstevel ddi_eventcookie_t cookie, void *bus_impldata);
1272305Sstevel
1282305Sstevel static int cardbus_intr_ops(dev_info_t *dip, dev_info_t *rdip,
1292305Sstevel ddi_intr_op_t intr_op,
1302305Sstevel ddi_intr_handle_impl_t *hdlp, void *result);
1312305Sstevel
1322305Sstevel static int check_token(char *token, int *len);
1332305Sstevel static char *find_token(char **cp, int *l, char *endc);
1342305Sstevel static int parse_token(char *token);
1352305Sstevel static int token_to_hex(char *token, unsigned *val, int len);
1362305Sstevel static int token_to_dec(char *token, unsigned *val, int len);
1372305Sstevel static void cardbus_add_prop(struct cb_deviceset_props *cdsp, int type,
1382305Sstevel char *name, caddr_t vp, int len);
1392305Sstevel static void cardbus_add_stringprop(struct cb_deviceset_props *cdsp,
1402305Sstevel char *name, char *vp, int len);
1412305Sstevel static void cardbus_prop_free(ddi_prop_t *propp);
1422305Sstevel static void cardbus_devprops_free(struct cb_deviceset_props *cbdp);
1432305Sstevel static int cardbus_parse_devprop(cbus_t *cbp, char *cp);
1442305Sstevel static void cardbus_device_props(cbus_t *cbp);
1452305Sstevel
1462305Sstevel static void cardbus_expand_busrange(dev_info_t *dip);
1472305Sstevel
1482305Sstevel static int cardbus_convert_properties(dev_info_t *dip);
1492305Sstevel static void cardbus_revert_properties(dev_info_t *dip);
1502305Sstevel
1512305Sstevel /*
1522305Sstevel * driver global data
1532305Sstevel */
1542305Sstevel kmutex_t cardbus_list_mutex; /* Protects the probe handle list */
1552305Sstevel void *cardbus_state;
1562305Sstevel int cardbus_latency_timer = 0x40;
1572305Sstevel int cardbus_debug = 0;
1582305Sstevel
1592305Sstevel /*
1602305Sstevel * Module linkage information for the kernel.
1612305Sstevel */
1622305Sstevel extern struct mod_ops mod_miscops;
1632305Sstevel static struct modlmisc modlmisc = {
1642305Sstevel &mod_miscops,
165*7240Srh87107 "Cardbus Configurator support",
1662305Sstevel };
1672305Sstevel
1682305Sstevel static struct modlinkage modlinkage = {
1692305Sstevel MODREV_1,
1702305Sstevel &modlmisc,
1712305Sstevel NULL
1722305Sstevel };
1732305Sstevel
1742305Sstevel int
_init(void)1752305Sstevel _init(void)
1762305Sstevel {
1772305Sstevel int error;
1782305Sstevel
1792305Sstevel error = ddi_soft_state_init(&cardbus_state, sizeof (cbus_t), 0);
1802305Sstevel if (error != 0)
1812305Sstevel return (error);
1822305Sstevel
1832305Sstevel mutex_init(&cardbus_list_mutex, NULL, MUTEX_DRIVER, NULL);
1842305Sstevel if ((error = mod_install(&modlinkage)) != 0) {
1852305Sstevel mutex_destroy(&cardbus_list_mutex);
1862305Sstevel }
1872305Sstevel
1882305Sstevel return (error);
1892305Sstevel }
1902305Sstevel
1912305Sstevel int
_fini(void)1922305Sstevel _fini(void)
1932305Sstevel {
1942305Sstevel int error;
1952305Sstevel if ((error = mod_remove(&modlinkage)) == 0) {
1962305Sstevel mutex_destroy(&cardbus_list_mutex);
1972305Sstevel ddi_soft_state_fini(&cardbus_state);
1982305Sstevel }
1992305Sstevel return (error);
2002305Sstevel }
2012305Sstevel
2022305Sstevel int
_info(struct modinfo * modinfop)2032305Sstevel _info(struct modinfo *modinfop)
2042305Sstevel {
2052305Sstevel return (mod_info(&modlinkage, modinfop));
2062305Sstevel }
2072305Sstevel
2082305Sstevel static
2092305Sstevel struct bus_ops cardbusbus_ops = {
2102305Sstevel BUSO_REV,
2112305Sstevel cardbus_bus_map,
2122305Sstevel NULL,
2132305Sstevel NULL,
2142305Sstevel NULL,
2152305Sstevel i_ddi_map_fault,
2162305Sstevel cardbus_dma_map,
2172305Sstevel cardbus_dma_allochdl,
2182305Sstevel cardbus_dma_freehdl,
2192305Sstevel cardbus_dma_bindhdl,
2202305Sstevel cardbus_dma_unbindhdl,
2212305Sstevel cardbus_dma_flush,
2222305Sstevel cardbus_dma_win,
2232305Sstevel ddi_dma_mctl,
2242305Sstevel cardbus_ctlops, /* (*bus_ctl)(); */
2252305Sstevel cardbus_prop_op,
2262305Sstevel cardbus_get_eventcookie, /* (*bus_get_eventcookie)(); */
2272305Sstevel cardbus_add_eventcall, /* (*bus_add_eventcall)(); */
2282305Sstevel cardbus_remove_eventcall, /* (*bus_remove_eventcall)(); */
2292305Sstevel cardbus_post_event, /* (*bus_post_event)(); */
2302305Sstevel NULL, /* (*bus_intr_ctl)(); */
2312305Sstevel NULL, /* (*bus_config)(); */
2322305Sstevel NULL, /* (*bus_unconfig)(); */
2332305Sstevel NULL, /* (*bus_fm_init)(); */
2342305Sstevel NULL, /* (*bus_fm_fini)(); */
2352305Sstevel NULL, /* (*bus_enter)(); */
2362305Sstevel NULL, /* (*bus_exit)(); */
2372305Sstevel NULL, /* (*bus_power)(); */
2382305Sstevel cardbus_intr_ops /* (*bus_intr_op)(); */
2392305Sstevel };
2402305Sstevel
2412305Sstevel #define CB_EVENT_TAG_INSERT 0
2422305Sstevel #define CB_EVENT_TAG_REMOVE 1
2432305Sstevel
2442305Sstevel static ndi_event_definition_t cb_ndi_event_defs[] = {
2452305Sstevel { CB_EVENT_TAG_INSERT, DDI_DEVI_INSERT_EVENT, EPL_INTERRUPT, 0 },
2462305Sstevel { CB_EVENT_TAG_REMOVE, DDI_DEVI_REMOVE_EVENT, EPL_INTERRUPT, 0 }
2472305Sstevel };
2482305Sstevel
2492305Sstevel #define CB_N_NDI_EVENTS \
2502305Sstevel (sizeof (cb_ndi_event_defs) / sizeof (cb_ndi_event_defs[0]))
2512305Sstevel
2522305Sstevel #ifdef sparc
2532305Sstevel struct busnum_ctrl {
2542305Sstevel int rv;
2552305Sstevel dev_info_t *dip;
2562305Sstevel cardbus_bus_range_t *range;
2572305Sstevel };
2582305Sstevel
2592305Sstevel static int
cardbus_claim_pci_busnum(dev_info_t * dip,void * arg)2602305Sstevel cardbus_claim_pci_busnum(dev_info_t *dip, void *arg)
2612305Sstevel {
2622305Sstevel cardbus_bus_range_t pci_bus_range;
2632305Sstevel struct busnum_ctrl *ctrl;
2642305Sstevel ndi_ra_request_t req;
2652305Sstevel char bus_type[16] = "(unknown)";
2662305Sstevel int len;
2672305Sstevel uint64_t base;
2682305Sstevel uint64_t retlen;
2692305Sstevel
2702305Sstevel ctrl = (struct busnum_ctrl *)arg;
2712305Sstevel
2722305Sstevel /* check if this is a PCI bus node */
2732305Sstevel len = sizeof (bus_type);
2742305Sstevel if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
2752305Sstevel DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
2762305Sstevel "device_type",
2772305Sstevel (caddr_t)&bus_type, &len) != DDI_SUCCESS)
2782305Sstevel return (0); /* (DDI_WALK_PRUNECHILD); */
2792305Sstevel
2802305Sstevel if ((strcmp(bus_type, "pci") != 0) &&
2812305Sstevel (strcmp(bus_type, "pciex") != 0)) /* it is not a pci bus type */
2822305Sstevel return (0); /* (DDI_WALK_PRUNECHILD); */
2832305Sstevel
2842305Sstevel /* look for the bus-range property */
2852305Sstevel len = sizeof (struct cardbus_bus_range);
2862305Sstevel if (ddi_getlongprop_buf(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
2872305Sstevel "bus-range", (caddr_t)&pci_bus_range, &len) == DDI_SUCCESS) {
2882305Sstevel cardbus_err(dip, 1, "cardbus_claim_pci_busnum: %u -> %u \n",
289*7240Srh87107 pci_bus_range.lo, pci_bus_range.hi);
2902305Sstevel if ((pci_bus_range.lo >= ctrl->range->lo) &&
2912305Sstevel (pci_bus_range.hi <= ctrl->range->hi)) {
2922305Sstevel cardbus_err(dip, 1,
2932305Sstevel "cardbus_claim_pci_busnum: claim %u -> %u \n",
2942305Sstevel pci_bus_range.lo, pci_bus_range.hi);
2952305Sstevel
2962305Sstevel /* claim the bus range from the bus resource map */
2972305Sstevel bzero((caddr_t)&req, sizeof (req));
2982305Sstevel req.ra_addr = (uint64_t)pci_bus_range.lo;
2992305Sstevel req.ra_flags |= NDI_RA_ALLOC_SPECIFIED;
3002305Sstevel req.ra_len = (uint64_t)pci_bus_range.hi -
3012305Sstevel (uint64_t)pci_bus_range.lo + 1;
3022305Sstevel
3032305Sstevel if (ndi_ra_alloc(ctrl->dip, &req, &base, &retlen,
3042305Sstevel NDI_RA_TYPE_PCI_BUSNUM, 0) == NDI_SUCCESS)
3052305Sstevel return (0); /* (DDI_WALK_PRUNECHILD); */
3062305Sstevel }
3072305Sstevel }
3082305Sstevel
3092305Sstevel /*
3102305Sstevel * never Error return.
3112305Sstevel */
3122305Sstevel ctrl->rv = DDI_SUCCESS;
3132305Sstevel return (DDI_WALK_TERMINATE);
3142305Sstevel }
3152305Sstevel
3162305Sstevel static void
cardbus_walk_node_child(dev_info_t * parent,int (* f)(dev_info_t *,void *),void * arg)3172305Sstevel cardbus_walk_node_child(dev_info_t *parent,
3182305Sstevel int (*f)(dev_info_t *, void *), void *arg)
3192305Sstevel {
3202305Sstevel dev_info_t *dip;
3212305Sstevel int ret;
3222305Sstevel
3232305Sstevel for (dip = ddi_get_child(parent); dip;
3242305Sstevel dip = ddi_get_next_sibling(dip)) {
3252305Sstevel
3262305Sstevel ret = (*f) (dip, arg);
3272305Sstevel if (ret)
3282305Sstevel return;
3292305Sstevel }
3302305Sstevel }
3312305Sstevel
cardbus_fix_hostbridge_busrange(dev_info_t * dip)3322305Sstevel static void cardbus_fix_hostbridge_busrange(dev_info_t *dip)
3332305Sstevel {
3342305Sstevel cardbus_bus_range_t bus_range;
3352305Sstevel struct busnum_ctrl ctrl;
3362305Sstevel
3372305Sstevel uint64_t next_bus;
3382305Sstevel uint64_t blen;
3392305Sstevel ndi_ra_request_t req;
3402305Sstevel int len;
3412305Sstevel
3422305Sstevel cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange\n");
3432305Sstevel
3442305Sstevel bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
3452305Sstevel req.ra_len = 1;
3462305Sstevel if (ndi_ra_alloc(dip, &req,
3472305Sstevel &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
3482305Sstevel 0) != NDI_SUCCESS) {
3492305Sstevel (void) ndi_ra_map_destroy(dip, NDI_RA_TYPE_PCI_BUSNUM);
3502305Sstevel
3512305Sstevel if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM)
3522305Sstevel == NDI_FAILURE) {
3532305Sstevel cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
3542305Sstevel "NDI_RA_TYPE_PCI_BUSNUM setup fail\n");
3552305Sstevel return;
3562305Sstevel }
3572305Sstevel
3582305Sstevel bus_range.lo = 0;
3592305Sstevel (void) ddi_getlongprop_buf(DDI_DEV_T_NONE, dip,
360*7240Srh87107 DDI_PROP_DONTPASS, "bus-range", (caddr_t)&bus_range, &len);
3612305Sstevel bus_range.hi = 255;
3622305Sstevel
3632305Sstevel (void) ndi_ra_free(dip,
3642305Sstevel (uint64_t)bus_range.lo + 1,
3652305Sstevel (uint64_t)bus_range.hi - (uint64_t)bus_range.lo,
3662305Sstevel NDI_RA_TYPE_PCI_BUSNUM, 0);
3672305Sstevel
3682305Sstevel ctrl.rv = DDI_SUCCESS;
3692305Sstevel ctrl.dip = dip;
3702305Sstevel ctrl.range = &bus_range;
3712305Sstevel
3722305Sstevel cardbus_walk_node_child(dip, cardbus_claim_pci_busnum,
3732305Sstevel (void*)&ctrl);
3742305Sstevel
3752305Sstevel if (ctrl.rv != DDI_SUCCESS)
3762305Sstevel cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
3772305Sstevel "cardbus_walk_node_child fails\n");
3782305Sstevel
3792305Sstevel (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
380*7240Srh87107 "bus-range", (int *)&bus_range, 2);
3812305Sstevel
3822305Sstevel } else {
3832305Sstevel cardbus_err(dip, 1, "cardbus_fix_hostbridge_busrange "
3842305Sstevel "already set up %x\n", (int)next_bus);
3852305Sstevel (void) ndi_ra_free(dip, next_bus, (uint64_t)1,
3862305Sstevel NDI_RA_TYPE_PCI_BUSNUM, 0);
3872305Sstevel }
3882305Sstevel }
3892305Sstevel
3902305Sstevel static dev_info_t *
cardbus_find_hsbridge_dip(dev_info_t * dip)3912305Sstevel cardbus_find_hsbridge_dip(dev_info_t *dip)
3922305Sstevel {
3932305Sstevel dev_info_t *pdip;
3942305Sstevel
3952305Sstevel pdip = ddi_get_parent(dip);
3962305Sstevel while (pdip) {
3972305Sstevel if (ddi_get_parent(pdip) == ddi_root_node())
3982305Sstevel break;
3992305Sstevel pdip = ddi_get_parent(pdip);
4002305Sstevel }
4012305Sstevel
4022305Sstevel return (pdip);
4032305Sstevel }
4042305Sstevel #endif /* sparc */
4052305Sstevel
4062305Sstevel /*
4072305Sstevel * Attach a device to the cardbus infrastructure.
4082305Sstevel */
4092305Sstevel int
cardbus_attach(dev_info_t * dip,cb_nexus_cb_t * nex_ops)4102305Sstevel cardbus_attach(dev_info_t *dip, cb_nexus_cb_t *nex_ops)
4112305Sstevel {
4122305Sstevel cbus_t *cbp;
4132305Sstevel int cb_instance;
4142305Sstevel anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
4152305Sstevel struct dev_info *devi = DEVI(dip);
4162305Sstevel
4172305Sstevel mutex_enter(&cardbus_list_mutex);
4182305Sstevel
4192305Sstevel /*
4202305Sstevel * Make sure that it is not already initialized.
4212305Sstevel */
4222305Sstevel if (ddi_prop_exists(DDI_DEV_T_ANY, dip,
4232305Sstevel DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
4242305Sstevel "cbus-instance") == 1) {
4252305Sstevel cmn_err(CE_WARN,
4262305Sstevel "%s%d: cardbus instance already initialized!\n",
4272305Sstevel ddi_driver_name(dip), ddi_get_instance(dip));
428*7240Srh87107 mutex_exit(&cardbus_list_mutex);
4292305Sstevel return (DDI_FAILURE);
4302305Sstevel }
4312305Sstevel
4322305Sstevel /*
4332305Sstevel * initialize soft state structure for the bus instance.
4342305Sstevel */
4352305Sstevel cb_instance = cardbus_next_instance++;
4362305Sstevel
4372305Sstevel if (ddi_soft_state_zalloc(cardbus_state, cb_instance) != DDI_SUCCESS) {
4382305Sstevel cmn_err(CE_WARN, "%s%d: can't allocate cardbus soft state\n",
4392305Sstevel ddi_driver_name(dip), ddi_get_instance(dip));
4402305Sstevel mutex_exit(&cardbus_list_mutex);
4412305Sstevel return (DDI_FAILURE);
4422305Sstevel }
4432305Sstevel
4442305Sstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
4452305Sstevel cbp->cb_instance = cb_instance;
4462305Sstevel cbp->cb_dip = dip;
4472305Sstevel mutex_init(&cbp->cb_mutex, NULL, MUTEX_DRIVER, NULL);
4482305Sstevel
4492305Sstevel /*
4502305Sstevel * Save the instance number of the soft state structure for
4512305Sstevel * this bus as a devinfo property.
4522305Sstevel */
4532305Sstevel if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
4542305Sstevel "cbus-instance", (caddr_t)&cb_instance,
4552305Sstevel sizeof (cb_instance)) != DDI_SUCCESS) {
4562305Sstevel cmn_err(CE_WARN,
4572305Sstevel "%s%d: failed to add the property 'cbus-instance'",
4582305Sstevel ddi_driver_name(dip), ddi_get_instance(dip));
4592305Sstevel ddi_soft_state_free(cardbus_state, cb_instance);
4602305Sstevel mutex_exit(&cardbus_list_mutex);
4612305Sstevel return (DDI_FAILURE);
4622305Sstevel }
4632305Sstevel
4642305Sstevel cbp->cb_nex_ops = nex_ops;
4652305Sstevel /*
4662305Sstevel * TODO - Should probably be some sort of locking on the devinfo here.
4672305Sstevel */
4682305Sstevel cbp->orig_dopsp = devi->devi_ops;
4692305Sstevel cbp->orig_bopsp = devi->devi_ops->devo_bus_ops;
4702305Sstevel cbp->cb_dops = *devi->devi_ops;
4712305Sstevel devi->devi_ops = &cbp->cb_dops;
4722305Sstevel
4732305Sstevel if (ndi_event_alloc_hdl(dip, *anp->an_iblock, &cbp->cb_ndi_event_hdl,
4742305Sstevel NDI_SLEEP) == NDI_SUCCESS) {
4752305Sstevel cbp->cb_ndi_events.ndi_n_events = CB_N_NDI_EVENTS;
4762305Sstevel cbp->cb_ndi_events.ndi_events_version = NDI_EVENTS_REV1;
4772305Sstevel cbp->cb_ndi_events.ndi_event_defs = cb_ndi_event_defs;
4782305Sstevel if (ndi_event_bind_set(cbp->cb_ndi_event_hdl,
4792305Sstevel &cbp->cb_ndi_events,
4802305Sstevel NDI_SLEEP) != NDI_SUCCESS) {
4812305Sstevel cardbus_err(dip, 1,
4822305Sstevel "cardbus_attach: ndi_event_bind_set failed\n");
4832305Sstevel }
4842305Sstevel }
4852305Sstevel
4862305Sstevel /*
4872305Sstevel * Check for device initialization property.
4882305Sstevel */
4892305Sstevel cardbus_device_props(cbp);
4902305Sstevel
4912305Sstevel if (cardbus_init_hotplug(cbp) != DDI_SUCCESS) {
4922305Sstevel ddi_soft_state_free(cardbus_state, cb_instance);
4932305Sstevel mutex_exit(&cardbus_list_mutex);
4942305Sstevel return (DDI_FAILURE);
4952305Sstevel }
4962305Sstevel
4972305Sstevel #ifdef sparc
4982305Sstevel /* a hack to fix the bus-range problem on pci root nodes */
4992305Sstevel {
5002305Sstevel dev_info_t *hs_dip;
5012305Sstevel
5022305Sstevel hs_dip = cardbus_find_hsbridge_dip(dip);
5032305Sstevel cardbus_fix_hostbridge_busrange(hs_dip);
5042305Sstevel }
5052305Sstevel #endif
5062305Sstevel
5072305Sstevel cardbus_expand_busrange(dip);
5082305Sstevel cardbus_count++;
5092305Sstevel mutex_exit(&cardbus_list_mutex);
5102305Sstevel return (DDI_SUCCESS);
5112305Sstevel }
5122305Sstevel
5132305Sstevel #ifdef TODO
5142305Sstevel static int
cardbus_detach(dev_info_t * dip)5152305Sstevel cardbus_detach(dev_info_t *dip)
5162305Sstevel {
5172305Sstevel int cb_instance;
5182305Sstevel cbus_t *cbp;
5192305Sstevel
5202305Sstevel mutex_enter(&cardbus_list_mutex);
5212305Sstevel /* get the instance number for the cardbus soft state data */
5222305Sstevel cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
523*7240Srh87107 DDI_PROP_DONTPASS, "cbus-instance", -1);
5242305Sstevel if (cb_instance < 0) {
5252305Sstevel mutex_exit(&cardbus_list_mutex);
5262305Sstevel return (DDI_FAILURE); /* no instance is setup for this bus */
5272305Sstevel }
5282305Sstevel
5292305Sstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
5302305Sstevel
5312305Sstevel if (cbp->cb_dsp) {
5322305Sstevel struct cb_deviceset_props *cbdp, *ncbdp;
5332305Sstevel
5342305Sstevel cbdp = cbp->cb_dsp;
5352305Sstevel while (cbdp) {
5362305Sstevel ncbdp = cbdp->next;
5372305Sstevel cardbus_devprops_free(cbdp);
5382305Sstevel cbdp = ncbdp;
5392305Sstevel }
5402305Sstevel }
5412305Sstevel /*
5422305Sstevel * Unregister the bus with the HPS.
5432305Sstevel *
5442305Sstevel * (Note: It is assumed that the HPS framework uninstalls
5452305Sstevel * event handlers for all the hot plug slots on this bus.)
5462305Sstevel */
5472305Sstevel (void) hpc_nexus_unregister_bus(dip);
5482305Sstevel
5492305Sstevel if (cbp->cb_ndi_event_hdl != NULL) {
5502305Sstevel (void) ndi_event_unbind_set(cbp->cb_ndi_event_hdl,
5512305Sstevel &cbp->cb_ndi_events, NDI_SLEEP);
5522305Sstevel ndi_event_free_hdl(cbp->cb_ndi_event_hdl);
5532305Sstevel }
5542305Sstevel
5552305Sstevel mutex_destroy(&cbp->cb_mutex);
5562305Sstevel if (cbp->nexus_path)
5572305Sstevel kmem_free(cbp->nexus_path, strlen(cbp->nexus_path) + 1);
5582305Sstevel if (cbp->name)
5592305Sstevel kmem_free(cbp->name, strlen(cbp->name) + 1);
5602305Sstevel
5612305Sstevel ddi_soft_state_free(cardbus_state, cb_instance);
5622305Sstevel
5632305Sstevel /* remove the 'cbus-instance' property from the devinfo node */
5642305Sstevel (void) ddi_prop_remove(DDI_DEV_T_ANY, dip, "cbus-instance");
5652305Sstevel
5662305Sstevel ASSERT(cardbus_count != 0);
5672305Sstevel --cardbus_count;
5682305Sstevel
5692305Sstevel mutex_exit(&cardbus_list_mutex);
5702305Sstevel return (DDI_SUCCESS);
5712305Sstevel }
5722305Sstevel #endif
5732305Sstevel
5742305Sstevel boolean_t
cardbus_load_cardbus(dev_info_t * dip,uint_t socket,uint32_t pc_base)5752305Sstevel cardbus_load_cardbus(dev_info_t *dip, uint_t socket, uint32_t pc_base)
5762305Sstevel {
5772305Sstevel #ifndef HOTPLUG
5782305Sstevel struct cardbus_config_ctrl ctrl;
5792305Sstevel int circular_count;
5802305Sstevel #endif
5812305Sstevel int cb_instance;
5822305Sstevel cbus_t *cbp;
5832305Sstevel struct dev_info *devi = DEVI(dip);
5842305Sstevel
5852305Sstevel _NOTE(ARGUNUSED(socket, pc_base))
5862305Sstevel
5872305Sstevel #if defined(CARDBUS_DEBUG)
5882305Sstevel cardbus_err(dip, 6, "cardbus_load_cardbus\n");
5892305Sstevel #endif
5902305Sstevel
5912305Sstevel cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
592*7240Srh87107 DDI_PROP_DONTPASS, "cbus-instance", -1);
5932305Sstevel ASSERT(cb_instance >= 0);
5942305Sstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
5952305Sstevel
5962305Sstevel if (cbp->fatal_problem)
5972305Sstevel return (B_FALSE);
5982305Sstevel
5992305Sstevel if (cardbus_convert_properties(dip) == DDI_FAILURE)
6002305Sstevel return (B_FALSE);
6012305Sstevel
6022305Sstevel number_of_cardbus_cards++;
6032305Sstevel devi->devi_ops->devo_bus_ops = &cardbusbus_ops;
6042305Sstevel
6052305Sstevel #ifdef HOTPLUG
6062305Sstevel mutex_enter(&cbp->cb_mutex);
6072305Sstevel cbp->card_present = B_TRUE;
6082305Sstevel
6092305Sstevel (void) hpc_slot_event_notify(cbp->slot_handle,
6102305Sstevel HPC_EVENT_SLOT_INSERTION, 0);
6112305Sstevel (void) hpc_slot_event_notify(cbp->slot_handle,
6122305Sstevel HPC_EVENT_SLOT_POWER_ON, 0);
6132305Sstevel (void) hpc_slot_event_notify(cbp->slot_handle,
6142305Sstevel HPC_EVENT_SLOT_CONFIGURE, 0);
6152305Sstevel
6162305Sstevel mutex_exit(&cbp->cb_mutex);
6172305Sstevel #else
6182305Sstevel if (cardbus_configure(cbp) != PCICFG_SUCCESS) {
6192305Sstevel #if defined(CARDBUS_DEBUG)
6202305Sstevel cardbus_err(dip, 6, "cardbus_configure failed\n");
6212305Sstevel #endif
6222305Sstevel return (B_FALSE);
6232305Sstevel }
6242305Sstevel
6252305Sstevel ctrl.rv = NDI_SUCCESS;
6262305Sstevel ctrl.busno = cardbus_primary_busno(dip);
6272305Sstevel ctrl.op = PCICFG_OP_ONLINE;
6282305Sstevel ctrl.dip = NULL;
6292305Sstevel ctrl.flags = PCICFG_FLAGS_CONTINUE;
6302305Sstevel
6312305Sstevel /*
6322305Sstevel * The child of the dip is the cardbus dip. The child of the
6332305Sstevel * cardbus dip is the device itself
6342305Sstevel */
6352305Sstevel #if defined(CARDBUS_DEBUG)
6362305Sstevel cardbus_err(dip, 8, "cardbus_load_cardbus: calling cbus_configure\n");
6372305Sstevel #endif
6382305Sstevel ndi_devi_enter(dip, &circular_count);
6392305Sstevel ddi_walk_devs(ddi_get_child(dip), cbus_configure, (void *)&ctrl);
6402305Sstevel ndi_devi_exit(dip, circular_count);
6412305Sstevel
6422305Sstevel if (ctrl.rv != NDI_SUCCESS) {
6432305Sstevel cardbus_err(dip, 1,
6442305Sstevel "cardbus_load_cardbus (%s%d): failed to attach (%d)\n",
6452305Sstevel ctrl.dip ? ddi_driver_name(ctrl.dip) : "Unknown",
6462305Sstevel ctrl.dip ? ddi_get_instance(ctrl.dip) : 0,
6472305Sstevel ctrl.rv);
6482305Sstevel
6492305Sstevel /*
6502305Sstevel * Returning error here will cause the pcic_load_cardbus() call
6512305Sstevel * to fail. This will invoke pcic_unload_cardbus() which calls
6522305Sstevel * cardbus_unload_cardbus() below.
6532305Sstevel */
6542305Sstevel return (B_FALSE);
6552305Sstevel }
6562305Sstevel #endif
6572305Sstevel
6582305Sstevel #if defined(CARDBUS_DEBUG)
6592305Sstevel cardbus_err(dip, 7, "cardbus_load_cardbus: returning TRUE\n");
6602305Sstevel #endif
6612305Sstevel
6622305Sstevel return (B_TRUE);
6632305Sstevel }
6642305Sstevel
6652305Sstevel /*
6662305Sstevel * Unload the cardbus module
6672305Sstevel */
6682305Sstevel void
cardbus_unload_cardbus(dev_info_t * dip)6692305Sstevel cardbus_unload_cardbus(dev_info_t *dip)
6702305Sstevel {
6712305Sstevel int cb_instance;
6722305Sstevel #ifndef HOTPLUG
6732305Sstevel int prim_bus = cardbus_primary_busno(dip);
6742305Sstevel int rval;
6752305Sstevel #endif
6762305Sstevel cbus_t *cbp;
6772305Sstevel
6782305Sstevel cardbus_err(dip, 6, "cardbus_unload_cardbus\n");
6792305Sstevel
6802305Sstevel cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
6812305Sstevel DDI_PROP_DONTPASS, "cbus-instance", -1);
6822305Sstevel ASSERT(cb_instance >= 0);
6832305Sstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
6842305Sstevel
6852305Sstevel if (number_of_cardbus_cards == 0)
6862305Sstevel return;
6872305Sstevel
6882305Sstevel #ifdef HOTPLUG
6892305Sstevel mutex_enter(&cbp->cb_mutex);
6902305Sstevel cbp->card_present = B_FALSE;
6912305Sstevel
6922305Sstevel (void) hpc_slot_event_notify(cbp->slot_handle,
6932305Sstevel HPC_EVENT_SLOT_POWER_OFF, 0);
6942305Sstevel (void) hpc_slot_event_notify(cbp->slot_handle,
6952451Srw148561 HPC_EVENT_SLOT_UNCONFIGURE, 0);
6962451Srw148561 (void) hpc_slot_event_notify(cbp->slot_handle,
6972305Sstevel HPC_EVENT_SLOT_REMOVAL, 0);
6982305Sstevel
6992305Sstevel mutex_exit(&cbp->cb_mutex);
7002305Sstevel #else
7012305Sstevel
7022305Sstevel cardbus_err(dip, 8,
7032305Sstevel "cardbus_unload_cardbus: calling cardbus_unconfigure_node\n");
7042305Sstevel
7052305Sstevel rval = cardbus_unconfigure_node(dip, prim_bus, B_TRUE);
7062305Sstevel
7072305Sstevel if (rval != NDI_SUCCESS) {
7082305Sstevel cardbus_err(dip, 4,
7092305Sstevel "cardbus_unload_cardbus: "
7102305Sstevel "cardbus_unconfigure_node failed\n");
7112305Sstevel number_of_cardbus_cards--;
7122305Sstevel cbp->fatal_problem = B_TRUE;
7132305Sstevel cmn_err(CE_WARN,
7142305Sstevel "cardbus(%s%d): Failed to remove device tree: "
7152305Sstevel "Slot disabled",
7162305Sstevel ddi_get_name(dip), ddi_get_instance(dip));
7172305Sstevel return;
7182305Sstevel }
7192305Sstevel
7202305Sstevel (void) cardbus_unconfigure(cbp);
7212305Sstevel #endif
7222305Sstevel
7232305Sstevel /*
7242305Sstevel * Inform the lower drivers that the card has been removed
7252305Sstevel */
7262305Sstevel if (cbp->cb_ndi_event_hdl != NULL) {
7272305Sstevel ddi_eventcookie_t cookie;
7282305Sstevel if (ndi_event_retrieve_cookie(cbp->cb_ndi_event_hdl, dip,
7292305Sstevel DDI_DEVI_REMOVE_EVENT, &cookie, 0) == NDI_SUCCESS) {
7302305Sstevel (void) ndi_event_run_callbacks(cbp->cb_ndi_event_hdl,
7312305Sstevel dip, cookie, NULL);
7322305Sstevel }
7332305Sstevel }
7342305Sstevel
7352305Sstevel cardbus_revert_properties(dip);
7362305Sstevel }
7372305Sstevel
7387151Srw148561 static boolean_t
is_32bit_pccard(dev_info_t * dip)7397151Srw148561 is_32bit_pccard(dev_info_t *dip)
7402305Sstevel {
7417151Srw148561 int len;
7427151Srw148561 char bus_type[16];
7437151Srw148561
7447151Srw148561 len = sizeof (bus_type);
7457151Srw148561 if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
7467151Srw148561 PROP_LEN_AND_VAL_BUF,
7477151Srw148561 DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
7487151Srw148561 "device_type",
7497151Srw148561 (caddr_t)&bus_type, &len) != DDI_SUCCESS)
7507151Srw148561 return (B_FALSE);
7517151Srw148561
7527151Srw148561 if ((strcmp(bus_type, "pci") != 0) &&
7537151Srw148561 (strcmp(bus_type, "pciex") != 0) &&
7547151Srw148561 (strcmp(bus_type, "cardbus") != 0)) /* not of pci type */
7557151Srw148561 return (B_FALSE);
7567151Srw148561
7577151Srw148561 return (B_TRUE);
7587151Srw148561 }
7592305Sstevel
7607151Srw148561 void
cardbus_save_children(dev_info_t * dip)7617151Srw148561 cardbus_save_children(dev_info_t *dip)
7627151Srw148561 {
7637151Srw148561 for (; dip != NULL; dip = ddi_get_next_sibling(dip)) {
7647151Srw148561 cardbus_save_children(ddi_get_child(dip));
7657151Srw148561
7667151Srw148561 if (strcmp("pcs", ddi_node_name(dip)) == 0)
7677151Srw148561 continue;
7687151Srw148561 if (!is_32bit_pccard(dip))
7697151Srw148561 continue;
7707151Srw148561 cardbus_err(dip, 1, "Saving device\n");
7717151Srw148561 (void) pci_save_config_regs(dip);
7727151Srw148561 }
7737151Srw148561
7747151Srw148561 }
7757151Srw148561
7767151Srw148561 void
cardbus_restore_children(dev_info_t * dip)7777151Srw148561 cardbus_restore_children(dev_info_t *dip)
7787151Srw148561 {
7797151Srw148561 for (; dip != NULL; dip = ddi_get_next_sibling(dip)) {
7807151Srw148561 cardbus_restore_children(ddi_get_child(dip));
7817151Srw148561
7827151Srw148561 if (strcmp("pcs", ddi_node_name(dip)) == 0)
7837151Srw148561 continue;
7847151Srw148561 if (!is_32bit_pccard(dip))
7857151Srw148561 continue;
7867151Srw148561 cardbus_err(dip, 1, "restoring device\n");
7877151Srw148561 (void) pci_restore_config_regs(dip);
7887151Srw148561 }
7897151Srw148561
7902305Sstevel }
7912305Sstevel
7922305Sstevel static int
cardbus_convert_properties(dev_info_t * dip)7932305Sstevel cardbus_convert_properties(dev_info_t *dip)
7942305Sstevel {
7952305Sstevel struct pcm_regs *pcic_avail_p, *old_avail_p;
7962305Sstevel pci_regspec_t *cb_avail_p, *new_avail_p;
7972305Sstevel pcic_ranges_t *pcic_range_p, *old_range_p;
7982305Sstevel cardbus_range_t *cb_range_p, *new_range_p;
7992305Sstevel int range_len, range_entries, i;
8002305Sstevel int avail_len, avail_entries;
8012305Sstevel
8022305Sstevel #if defined(CARDBUS_DEBUG)
8032305Sstevel cardbus_err(dip, 6, "cardbus_convert_properties\n");
8042305Sstevel #endif
8052305Sstevel
8062305Sstevel if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
8072305Sstevel "#address-cells", 3) != DDI_SUCCESS) {
8082305Sstevel cardbus_err(dip, 1, "cardbus_convert_properties: "
8092305Sstevel "failed to update #address-cells property\n");
8102305Sstevel return (DDI_FAILURE);
8112305Sstevel }
8122305Sstevel if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
8132305Sstevel "#size-cells", 2) != DDI_SUCCESS) {
8142305Sstevel cardbus_err(dip, 1, "cardbus_convert_properties: "
8152305Sstevel "failed to update #size-cells property\n");
8162305Sstevel return (DDI_FAILURE);
8172305Sstevel }
8182305Sstevel
8192305Sstevel if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "available",
8202305Sstevel (caddr_t)&pcic_avail_p, &avail_len) != DDI_PROP_SUCCESS) {
8212305Sstevel cardbus_err(dip, 1, "cardbus_convert_properties: "
8222305Sstevel "no available property for pcmcia\n");
8232305Sstevel } else {
8242305Sstevel avail_entries = avail_len / sizeof (struct pcm_regs);
8252305Sstevel cb_avail_p = kmem_alloc(sizeof (pci_regspec_t) * avail_entries,
8262305Sstevel KM_SLEEP);
8272305Sstevel
8282305Sstevel old_avail_p = pcic_avail_p;
8292305Sstevel new_avail_p = cb_avail_p;
8302305Sstevel for (i = 0; i < avail_entries;
8312305Sstevel i++, old_avail_p++, new_avail_p++) {
8322305Sstevel new_avail_p->pci_phys_hi = old_avail_p->phys_hi;
8332305Sstevel new_avail_p->pci_phys_mid = 0;
8342305Sstevel new_avail_p->pci_phys_low = old_avail_p->phys_lo;
8352305Sstevel new_avail_p->pci_size_hi = 0;
8362305Sstevel new_avail_p->pci_size_low = old_avail_p->phys_len;
8372305Sstevel }
8382305Sstevel
8392305Sstevel (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
8402305Sstevel "available",
8412305Sstevel (int *)cb_avail_p,
8422305Sstevel (sizeof (pci_regspec_t) * avail_entries)/sizeof (int));
8432305Sstevel
8442305Sstevel kmem_free(pcic_avail_p, avail_len);
8452305Sstevel kmem_free(cb_avail_p, sizeof (pci_regspec_t) * avail_entries);
8462305Sstevel }
8472305Sstevel
8482305Sstevel if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "ranges",
8492305Sstevel (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) {
8502305Sstevel cardbus_err(dip, 1, "cardbus_convert_properties: "
8512305Sstevel "no ranges property for pcmcia\n");
8522305Sstevel } else {
8532305Sstevel range_entries = range_len / sizeof (pcic_ranges_t);
8542305Sstevel cb_range_p = kmem_alloc(
8552305Sstevel sizeof (cardbus_range_t) * range_entries, KM_SLEEP);
8562305Sstevel
8572305Sstevel old_range_p = pcic_range_p;
8582305Sstevel new_range_p = cb_range_p;
8592305Sstevel for (i = 0; i < range_entries;
8602305Sstevel i++, old_range_p++, new_range_p++) {
8612305Sstevel new_range_p->child_hi =
8622305Sstevel old_range_p->pcic_range_caddrhi;
8632305Sstevel new_range_p->child_mid = 0;
8642305Sstevel new_range_p->child_lo =
8652305Sstevel old_range_p->pcic_range_caddrlo;
8662305Sstevel new_range_p->parent_hi =
8672305Sstevel old_range_p->pcic_range_paddrhi;
8682305Sstevel new_range_p->parent_mid =
8692305Sstevel old_range_p->pcic_range_paddrmid;
8702305Sstevel new_range_p->parent_lo =
8712305Sstevel old_range_p->pcic_range_paddrlo;
8722305Sstevel new_range_p->size_hi = 0;
8732305Sstevel new_range_p->size_lo = old_range_p->pcic_range_size;
8742305Sstevel }
8752305Sstevel
8762305Sstevel (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
8772305Sstevel (int *)cb_range_p,
8782305Sstevel (sizeof (cardbus_range_t) * range_entries)/sizeof (int));
8792305Sstevel
8802305Sstevel kmem_free(pcic_range_p, range_len);
8812305Sstevel kmem_free(cb_range_p, sizeof (cardbus_range_t) * range_entries);
8822305Sstevel }
8832305Sstevel
8842305Sstevel return (DDI_SUCCESS);
8852305Sstevel }
8862305Sstevel
8872305Sstevel static void
cardbus_revert_properties(dev_info_t * dip)8882305Sstevel cardbus_revert_properties(dev_info_t *dip)
8892305Sstevel {
8902305Sstevel #if defined(CARDBUS_DEBUG)
8912305Sstevel cardbus_err(dip, 6, "cardbus_revert_properties\n");
8922305Sstevel #endif
8932305Sstevel
8942305Sstevel (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "#address-cells");
8952305Sstevel
8962305Sstevel (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "#size-cells");
8972305Sstevel
8982305Sstevel (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "available");
8992305Sstevel }
9002305Sstevel
9012305Sstevel 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)9022305Sstevel cardbus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
9032305Sstevel ddi_prop_op_t prop_op, int mod_flags,
9042305Sstevel char *name, caddr_t valuep, int *lengthp)
9052305Sstevel {
9062305Sstevel #if defined(CARDBUS_DEBUG)
9072305Sstevel if ((ch_dip != dip) || (cardbus_debug >= 9))
9082305Sstevel cardbus_err(dip, 6,
9092305Sstevel "cardbus_prop_op(%s) (dip=0x%p, op=%d, name=%s)\n",
9102305Sstevel ddi_driver_name(ch_dip), (void *) dip, prop_op, name);
9112305Sstevel #endif
9122305Sstevel return (impl_ddi_bus_prop_op(dev, dip, ch_dip, prop_op,
9132305Sstevel mod_flags, name, valuep, lengthp));
9142305Sstevel }
9152305Sstevel
9162305Sstevel static int
cardbus_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)9172305Sstevel cardbus_ctlops(dev_info_t *dip, dev_info_t *rdip,
9182305Sstevel ddi_ctl_enum_t ctlop, void *arg, void *result)
9192305Sstevel {
9202305Sstevel pci_regspec_t *regs;
9212305Sstevel int totreg, reglen;
9222305Sstevel const char *dname = ddi_driver_name(dip);
9232305Sstevel
9242305Sstevel ASSERT(number_of_cardbus_cards != 0);
9252305Sstevel
9262305Sstevel cardbus_err(dip, 6,
9272305Sstevel "cardbus_ctlops(%p, %p, %d, %p, %p)\n",
9282305Sstevel (void *)dip, (void *)rdip, ctlop, (void *)arg, (void *)result);
9292305Sstevel
9302305Sstevel switch (ctlop) {
9312305Sstevel case DDI_CTLOPS_UNINITCHILD:
9322305Sstevel cardbus_removechild((dev_info_t *)arg);
9332305Sstevel return (DDI_SUCCESS);
9347151Srw148561 case DDI_CTLOPS_POWER:
9357151Srw148561 return (DDI_SUCCESS);
9362305Sstevel
9372305Sstevel default:
9382305Sstevel /*
9392305Sstevel * Do Nothing
9402305Sstevel */
9412305Sstevel cardbus_err(dip, 8,
9422305Sstevel "cardbus_ctlops: Unsupported DDI_CTLOP %d\n", ctlop);
9432305Sstevel return (ddi_ctlops(dip, rdip, ctlop, arg, result));
9442305Sstevel
9452305Sstevel case DDI_CTLOPS_SIDDEV: /* see ddi_dev_is_sid(9F) */
9462305Sstevel return (DDI_SUCCESS);
9472305Sstevel
9482305Sstevel case DDI_CTLOPS_SLAVEONLY: /* see ddi_slaveonly(9F) */
9492305Sstevel return (DDI_FAILURE); /* cardbus */
9502305Sstevel
9512305Sstevel case DDI_CTLOPS_REGSIZE:
9522305Sstevel case DDI_CTLOPS_NREGS:
9532305Sstevel if (rdip == (dev_info_t *)NULL) {
9542305Sstevel *(int *)result = 0;
9552305Sstevel return (DDI_FAILURE);
9562305Sstevel }
9572305Sstevel break;
9582305Sstevel
9592305Sstevel case DDI_CTLOPS_IOMIN:
9602305Sstevel /*
9612305Sstevel * If we are using the streaming cache, align at
9622305Sstevel * least on a cache line boundary. Otherwise use
9632305Sstevel * whatever alignment is passed in.
9642305Sstevel */
9652305Sstevel
9662305Sstevel if (arg) {
9672305Sstevel int val = *((int *)result);
9682305Sstevel
9692305Sstevel #ifdef PCI_SBUF_LINE_SIZE
9702305Sstevel val = maxbit(val, PCI_SBUF_LINE_SIZE);
9712305Sstevel #else
9722305Sstevel val = maxbit(val, 64);
9732305Sstevel #endif
9742305Sstevel *((int *)result) = val;
9752305Sstevel }
9762305Sstevel return (DDI_SUCCESS);
9772305Sstevel
9782305Sstevel case DDI_CTLOPS_INITCHILD:
9792305Sstevel return (cardbus_initchild(rdip, dip, (dev_info_t *)arg,
980*7240Srh87107 result));
9812305Sstevel
9822305Sstevel case DDI_CTLOPS_REPORTDEV:
9832305Sstevel if (rdip == (dev_info_t *)0)
9842305Sstevel return (DDI_FAILURE);
9852305Sstevel
9862305Sstevel if (strcmp("pcs", ddi_node_name(rdip)) == 0)
9872305Sstevel cardbus_err(dip, 1,
9882305Sstevel "cardbus_ctlops: PCCard socket %d at %s@%s\n",
9892305Sstevel ddi_get_instance(rdip),
9902305Sstevel dname, ddi_get_name_addr(dip));
9912305Sstevel else {
9922305Sstevel pci_regspec_t *pci_rp;
9932305Sstevel dev_info_t *next;
9942305Sstevel int length;
9952305Sstevel
9962305Sstevel if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
9972305Sstevel DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
9982305Sstevel (uint_t *)&length) != DDI_PROP_SUCCESS)
9992305Sstevel return (DDI_FAILURE);
10002305Sstevel
10012305Sstevel if (pci_rp->pci_phys_hi == 0)
10022305Sstevel cardbus_err(dip, 1, "%s%d at %s@%s\n",
10032305Sstevel ddi_driver_name(rdip),
10042305Sstevel ddi_get_instance(rdip),
10052305Sstevel dname, ddi_get_name_addr(dip));
10062305Sstevel else {
10072305Sstevel uint8_t bus, device, function;
10082305Sstevel int32_t val32;
10092305Sstevel char *ptr, buf[128];
10102305Sstevel
10112305Sstevel bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
10122305Sstevel device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
10132305Sstevel function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
10142305Sstevel
10152305Sstevel ptr = buf;
10162305Sstevel (void) sprintf(ptr, " "
10172305Sstevel "Bus %3d Device %2d Function %2d",
10182305Sstevel bus, device, function);
10192305Sstevel ptr = &ptr[strlen(ptr)];
10202305Sstevel
10212305Sstevel val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
10222305Sstevel DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
10232305Sstevel "vendor-id", -1);
10242305Sstevel if (val32 != -1) {
10252305Sstevel (void) sprintf(ptr, " Vendor 0x%04x",
10262305Sstevel val32);
10272305Sstevel ptr = &ptr[strlen(ptr)];
10282305Sstevel }
10292305Sstevel val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
10302305Sstevel DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
10312305Sstevel "device-id", -1);
10322305Sstevel if (val32 != -1) {
10332305Sstevel (void) sprintf(ptr, " Device 0x%04x",
10342305Sstevel val32);
10352305Sstevel ptr = &ptr[strlen(ptr)];
10362305Sstevel }
10372305Sstevel val32 = ddi_getprop(DDI_DEV_T_ANY, rdip,
10382305Sstevel DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
10392305Sstevel "class-code", -1);
10402305Sstevel if (val32 != -1) {
10412305Sstevel const char *name;
10422305Sstevel
10432305Sstevel if ((name = ddi_get_name(rdip)) !=
10442305Sstevel NULL)
10452305Sstevel (void) sprintf(ptr, " Name %s",
10462305Sstevel name);
10472305Sstevel else
10482305Sstevel (void) sprintf(ptr,
10492305Sstevel " Class 0x%x", val32 >> 8);
10502305Sstevel ptr = &ptr[strlen(ptr)];
10512305Sstevel }
10522305Sstevel
10532305Sstevel *ptr++ = '\n';
10542305Sstevel ASSERT(((caddr_t)ptr - (caddr_t)buf) <
1055*7240Srh87107 sizeof (buf));
10562305Sstevel *ptr = '\0';
10572305Sstevel
10582305Sstevel cardbus_err(dip, 1, buf);
10592305Sstevel }
10602305Sstevel ddi_prop_free(pci_rp);
10612305Sstevel
10622305Sstevel for (next = ddi_get_child(rdip); next;
10632305Sstevel next = ddi_get_next_sibling(next))
10642305Sstevel (void) cardbus_ctlops(next, next,
10652305Sstevel DDI_CTLOPS_REPORTDEV, arg, result);
10662305Sstevel }
10672305Sstevel return (DDI_SUCCESS);
10682305Sstevel }
10692305Sstevel *(int *)result = 0;
10702305Sstevel
10712305Sstevel if (ddi_getlongprop(DDI_DEV_T_NONE, rdip,
10722305Sstevel DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg",
10732305Sstevel (caddr_t)®s, ®len) != DDI_SUCCESS)
10742305Sstevel return (DDI_FAILURE);
10752305Sstevel
10762305Sstevel totreg = reglen / sizeof (pci_regspec_t);
10772305Sstevel if (ctlop == DDI_CTLOPS_NREGS) {
10782305Sstevel cardbus_err(dip, 6,
10792305Sstevel "cardbus_ctlops, returning NREGS = %d\n", totreg);
10802305Sstevel *(int *)result = totreg;
10812305Sstevel } else if (ctlop == DDI_CTLOPS_REGSIZE) {
10822305Sstevel const int rn = *(int *)arg;
10832305Sstevel if (rn > totreg)
10842305Sstevel return (DDI_FAILURE);
10852305Sstevel cardbus_err(dip, 6,
10862305Sstevel "cardbus_ctlops, returning REGSIZE(%d) = %d\n",
10872305Sstevel rn, regs[rn].pci_size_low);
10882305Sstevel *(off_t *)result = regs[rn].pci_size_low;
10892305Sstevel }
10902305Sstevel kmem_free(regs, reglen);
10912305Sstevel return (DDI_SUCCESS);
10922305Sstevel }
10932305Sstevel
10942305Sstevel static void
cardbus_init_child_regs(dev_info_t * child)10952305Sstevel cardbus_init_child_regs(dev_info_t *child)
10962305Sstevel {
10972305Sstevel ddi_acc_handle_t config_handle;
10982305Sstevel uint16_t command_preserve, command;
10992305Sstevel #if !defined(__i386) && !defined(__amd64)
11002305Sstevel uint8_t bcr;
11012305Sstevel #endif
11022305Sstevel uint8_t header_type;
11032305Sstevel uint8_t min_gnt, latency_timer;
11042305Sstevel uint_t n;
11052305Sstevel
11062305Sstevel /*
11072305Sstevel * Map the child configuration space to for initialization.
11082305Sstevel *
11092305Sstevel * Set the latency-timer register to values appropriate
11102305Sstevel * for the devices on the bus (based on other devices
11112305Sstevel * MIN_GNT and MAX_LAT registers.
11122305Sstevel *
11132305Sstevel * Set the fast back-to-back enable bit in the command
11142305Sstevel * register if it's supported and all devices on the bus
11152305Sstevel * have the capability.
11162305Sstevel *
11172305Sstevel */
11182305Sstevel if (pci_config_setup(child, &config_handle) != DDI_SUCCESS)
11192305Sstevel return;
11202305Sstevel
11212305Sstevel cardbus_err(child, 6, "cardbus_init_child_regs()\n");
11222305Sstevel
11232305Sstevel /*
11242305Sstevel * Determine the configuration header type.
11252305Sstevel */
11262305Sstevel header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
11272305Sstevel
11282305Sstevel /*
11292305Sstevel * Support for "command-preserve" property. Note that we
11302305Sstevel * add PCI_COMM_BACK2BACK_ENAB to the bits to be preserved
11312305Sstevel * since the obp will set this if the device supports and
11322305Sstevel * all targets on the same bus support it. Since psycho
11332305Sstevel * doesn't support PCI_COMM_BACK2BACK_ENAB, it will never
11342305Sstevel * be set. This is just here in case future revs do support
11352305Sstevel * PCI_COMM_BACK2BACK_ENAB.
11362305Sstevel */
11372305Sstevel command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
11382305Sstevel DDI_PROP_DONTPASS,
11392305Sstevel "command-preserve", 0);
11402305Sstevel command = pci_config_get16(config_handle, PCI_CONF_COMM);
11412305Sstevel command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
11422305Sstevel command |= (cardbus_command_default & ~command_preserve);
11432305Sstevel pci_config_put16(config_handle, PCI_CONF_COMM, command);
11442305Sstevel command = pci_config_get16(config_handle, PCI_CONF_COMM);
11452305Sstevel
11462305Sstevel #if !defined(__i386) && !defined(__amd64)
11472305Sstevel /*
11482305Sstevel * If the device has a bus control register then program it
11492305Sstevel * based on the settings in the command register.
11502305Sstevel */
11512305Sstevel if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
11522305Sstevel bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
11532305Sstevel if (cardbus_command_default & PCI_COMM_PARITY_DETECT)
11542305Sstevel bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
11552305Sstevel if (cardbus_command_default & PCI_COMM_SERR_ENABLE)
11562305Sstevel bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
11572305Sstevel bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
11582305Sstevel pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
11592305Sstevel }
11602305Sstevel #endif
11612305Sstevel
11622305Sstevel /*
11632305Sstevel * Initialize cache-line-size configuration register if needed.
11642305Sstevel */
11652305Sstevel if (ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
11662305Sstevel "cache-line-size", 0) == 0) {
11672305Sstevel
11682305Sstevel pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
11692305Sstevel PCI_CACHE_LINE_SIZE);
11702305Sstevel n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
11712305Sstevel if (n != 0)
11722305Sstevel (void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
1173*7240Srh87107 "cache-line-size", n);
11742305Sstevel }
11752305Sstevel
11762305Sstevel /*
11772305Sstevel * Initialize latency timer registers if needed.
11782305Sstevel */
11792305Sstevel if (ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
11802305Sstevel "latency-timer", 0) == 0) {
11812305Sstevel
11822305Sstevel if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
11832305Sstevel latency_timer = cardbus_latency_timer;
11842305Sstevel pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
1185*7240Srh87107 latency_timer);
11862305Sstevel } else {
11872305Sstevel min_gnt = pci_config_get8(config_handle,
1188*7240Srh87107 PCI_CONF_MIN_G);
11892305Sstevel
11902305Sstevel /*
11912305Sstevel * Cardbus os only 33Mhz
11922305Sstevel */
11932305Sstevel if (min_gnt != 0) {
11942305Sstevel latency_timer = min_gnt * 8;
11952305Sstevel }
11962305Sstevel }
11972305Sstevel pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
1198*7240Srh87107 latency_timer);
11992305Sstevel n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
12002305Sstevel if (n != 0)
12012305Sstevel (void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
1202*7240Srh87107 "latency-timer", n);
12032305Sstevel }
12042305Sstevel
12052305Sstevel pci_config_teardown(&config_handle);
12062305Sstevel }
12072305Sstevel
12082305Sstevel static int
cardbus_initchild(dev_info_t * rdip,dev_info_t * dip,dev_info_t * child,void * result)12092305Sstevel cardbus_initchild(dev_info_t *rdip, dev_info_t *dip, dev_info_t *child,
12102305Sstevel void *result)
12112305Sstevel {
12122305Sstevel char name[MAXNAMELEN];
12132305Sstevel const char *dname = ddi_driver_name(dip);
12142305Sstevel const struct cb_ops *cop;
12152305Sstevel
12162305Sstevel _NOTE(ARGUNUSED(rdip, result))
12172305Sstevel
12182305Sstevel cardbus_err(child, 6, "cardbus_initchild\n");
12192305Sstevel
12202305Sstevel /*
12212305Sstevel * Name the child
12222305Sstevel */
12232305Sstevel if (cardbus_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
12242305Sstevel return (DDI_FAILURE);
12252305Sstevel
12262305Sstevel ddi_set_name_addr(child, name);
12272305Sstevel ddi_set_parent_data(child, NULL);
12282305Sstevel
12292305Sstevel if (ndi_dev_is_persistent_node(child) == 0) {
12302305Sstevel /*
12312305Sstevel * Try to merge the properties from this prototype
12322305Sstevel * node into real h/w nodes.
12332305Sstevel */
12342305Sstevel if (ndi_merge_node(child, cardbus_name_child) == DDI_SUCCESS) {
12352305Sstevel /*
12362305Sstevel * Merged ok - return failure to remove the node.
12372305Sstevel */
12382305Sstevel cardbus_removechild(child);
12392305Sstevel return (DDI_FAILURE);
12402305Sstevel }
12412305Sstevel /*
12422305Sstevel * The child was not merged into a h/w node,
12432305Sstevel * but there's not much we can do with it other
12442305Sstevel * than return failure to cause the node to be removed.
12452305Sstevel */
12462305Sstevel cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
12472305Sstevel ddi_driver_name(child), ddi_get_name_addr(child),
12482305Sstevel ddi_driver_name(child));
12492305Sstevel cardbus_removechild(child);
12502305Sstevel return (DDI_NOT_WELL_FORMED);
12512305Sstevel }
12522305Sstevel cop = DEVI(dip)->devi_ops->devo_cb_ops;
12532305Sstevel
12542305Sstevel if ((cop == NULL) || (!(cop->cb_flag & D_HOTPLUG))) {
12552305Sstevel cmn_err(CE_WARN, "%s: driver doesn't support HOTPLUG\n", dname);
12562305Sstevel return (DDI_FAILURE);
12572305Sstevel }
12582305Sstevel
12592305Sstevel cardbus_init_child_regs(child);
12602305Sstevel
12612305Sstevel /*
12622305Sstevel * Create ppd if needed.
12632305Sstevel */
12642305Sstevel if (ddi_get_parent_data(child) == NULL) {
12652305Sstevel struct cardbus_parent_private_data *ppd;
12662305Sstevel
12672305Sstevel #ifdef sparc
12682305Sstevel ppd = (struct cardbus_parent_private_data *)
1269*7240Srh87107 kmem_zalloc(sizeof (struct cardbus_parent_private_data),
12702305Sstevel KM_SLEEP);
12712305Sstevel
12722305Sstevel #elif defined(__x86) || defined(__amd64)
12732305Sstevel ppd = (struct cardbus_parent_private_data *)
12742305Sstevel kmem_zalloc(sizeof (struct cardbus_parent_private_data)
1275*7240Srh87107 + sizeof (struct intrspec), KM_SLEEP);
12762305Sstevel
12772305Sstevel ppd->ppd.par_intr = (struct intrspec *)(ppd + 1);
12782305Sstevel (ppd->ppd.par_intr)->intrspec_pri = 0;
12792305Sstevel (ppd->ppd.par_intr)->intrspec_vec = 0;
12802305Sstevel (ppd->ppd.par_intr)->intrspec_func = (uint_t (*)()) 0;
12812305Sstevel #endif
12822305Sstevel
12832305Sstevel if (ddi_getprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
12842305Sstevel "interrupts", -1) != -1)
12852305Sstevel ppd->ppd.par_nintr = 1;
12862305Sstevel
12872305Sstevel ppd->code = CB_PPD_CODE;
12882305Sstevel
12892305Sstevel cardbus_err(child, 5,
12902305Sstevel "cardbus_initchild: Creating empty ppd\n");
12912305Sstevel ppd->ppd.par_nreg = 0;
12922305Sstevel ppd->ppd.par_reg = NULL;
12932305Sstevel
12942305Sstevel ddi_set_parent_data(child, (caddr_t)ppd);
12952305Sstevel }
12962305Sstevel
12972305Sstevel return (DDI_SUCCESS);
12982305Sstevel }
12992305Sstevel
13002305Sstevel static int
cardbus_name_child(dev_info_t * child,char * name,int namelen)13012305Sstevel cardbus_name_child(dev_info_t *child, char *name, int namelen)
13022305Sstevel {
13032305Sstevel pci_regspec_t *pci_rp;
13042305Sstevel char **unit_addr;
13052305Sstevel uint_t n;
13062305Sstevel int bus, device, func;
13072305Sstevel
13082305Sstevel /*
13092305Sstevel * Pseudo nodes indicate a prototype node with per-instance
13102305Sstevel * properties to be merged into the real h/w device node.
13112305Sstevel * The interpretation of the unit-address is DD[,F]
13122305Sstevel * where DD is the device id and F is the function.
13132305Sstevel */
13142305Sstevel if (ndi_dev_is_persistent_node(child) == 0) {
13152305Sstevel if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
13162305Sstevel DDI_PROP_DONTPASS,
13172305Sstevel "unit-address", &unit_addr, &n) != DDI_PROP_SUCCESS) {
13182305Sstevel cmn_err(CE_WARN, "cannot name node from %s.conf",
13192305Sstevel ddi_driver_name(child));
13202305Sstevel return (DDI_FAILURE);
13212305Sstevel }
13222305Sstevel if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
13232305Sstevel cmn_err(CE_WARN, "unit-address property in %s.conf"
13242305Sstevel " not well-formed", ddi_driver_name(child));
13252305Sstevel ddi_prop_free(unit_addr);
13262305Sstevel return (DDI_FAILURE);
13272305Sstevel }
13282305Sstevel (void) snprintf(name, namelen, "%s", *unit_addr);
13292305Sstevel ddi_prop_free(unit_addr);
13302305Sstevel return (DDI_SUCCESS);
13312305Sstevel }
13322305Sstevel
13332305Sstevel /*
13342305Sstevel * Get the address portion of the node name based on
13352305Sstevel * the function and device number.
13362305Sstevel */
13372305Sstevel if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
13382305Sstevel "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) {
13392305Sstevel return (DDI_FAILURE);
13402305Sstevel }
13412305Sstevel
13422305Sstevel bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
13432305Sstevel device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
13442305Sstevel func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
13452305Sstevel ddi_prop_free(pci_rp);
13462305Sstevel
13472305Sstevel if (func != 0)
13482305Sstevel (void) snprintf(name, namelen, "%x,%x", device, func);
13492305Sstevel else
13502305Sstevel (void) snprintf(name, namelen, "%x", device);
13512305Sstevel
13522305Sstevel cardbus_err(child, 8,
13532305Sstevel "cardbus_name_child: system init done [%x][%x][%x]"
13542305Sstevel " for %s [%s] nodeid: %x @%s\n",
13552305Sstevel bus, device, func,
13562305Sstevel ddi_get_name(child), ddi_get_name_addr(child),
13572305Sstevel DEVI(child)->devi_nodeid, name);
13582305Sstevel
13592305Sstevel return (DDI_SUCCESS);
13602305Sstevel }
13612305Sstevel
13622305Sstevel static void
cardbus_removechild(dev_info_t * dip)13632305Sstevel cardbus_removechild(dev_info_t *dip)
13642305Sstevel {
13652305Sstevel struct cardbus_parent_private_data *ppd;
13662305Sstevel
13672305Sstevel ddi_set_name_addr(dip, NULL);
13682305Sstevel impl_rem_dev_props(dip);
13692305Sstevel ppd = (struct cardbus_parent_private_data *)ddi_get_parent_data(dip);
13702305Sstevel if (ppd && (ppd->code == CB_PPD_CODE)) {
13712305Sstevel if (ppd->ppd.par_reg && (ppd->ppd.par_nreg > 0))
13722305Sstevel kmem_free((caddr_t)ppd->ppd.par_reg,
13732305Sstevel ppd->ppd.par_nreg * sizeof (struct regspec));
13742305Sstevel #ifdef sparc
13752305Sstevel kmem_free(ppd, sizeof (struct cardbus_parent_private_data));
13762305Sstevel #elif defined(__x86) || defined(__amd64)
13772305Sstevel kmem_free(ppd, sizeof (struct cardbus_parent_private_data) +
13782305Sstevel sizeof (struct intrspec));
13792305Sstevel #endif
13802305Sstevel cardbus_err(dip, 5,
13812305Sstevel "cardbus_removechild: ddi_set_parent_data(NULL)\n");
13822305Sstevel ddi_set_parent_data(dip, NULL);
13832305Sstevel }
13842305Sstevel }
13852305Sstevel
13862305Sstevel
13872305Sstevel static char cb_bnamestr[] = "binding_name";
13882305Sstevel static char cb_venidstr[] = "VendorID";
13892305Sstevel static char cb_devidstr[] = "DeviceID";
13902305Sstevel static char cb_nnamestr[] = "nodename";
13912305Sstevel
13922305Sstevel static cb_props_parse_tree_t cb_props_parse_tree[] = {
13932305Sstevel { cb_bnamestr, PT_STATE_STRING_VAR },
13942305Sstevel { cb_venidstr, PT_STATE_HEX_VAR },
13952305Sstevel { cb_devidstr, PT_STATE_HEX_VAR } };
13962305Sstevel
13972305Sstevel static int
check_token(char * token,int * len)13982305Sstevel check_token(char *token, int *len)
13992305Sstevel {
14002305Sstevel int state = PT_STATE_DEC_VAR;
14012305Sstevel int sl = strlen(token), il = 1;
14022305Sstevel char c;
14032305Sstevel
14042305Sstevel if (token[0] == '0' && token[2] && (token[1] == 'x' || token[1] ==
14052305Sstevel 'X')) {
14062305Sstevel state = PT_STATE_HEX_VAR;
14072305Sstevel token += 2;
14082305Sstevel }
14092305Sstevel
14102305Sstevel while (c = *token++) {
14112305Sstevel if (isdigit(c))
14122305Sstevel continue;
14132305Sstevel if (c == PARSE_COMMA) {
14142305Sstevel il++;
14152305Sstevel if (token[0] == '0' && token[2] && isx(token[1])) {
14162305Sstevel state = PT_STATE_HEX_VAR;
14172305Sstevel token += 2;
14182305Sstevel }
14192305Sstevel continue;
14202305Sstevel }
14212305Sstevel if (!isxdigit(c)) {
14222305Sstevel *len = sl;
14232305Sstevel return (PT_STATE_STRING_VAR);
14242305Sstevel }
14252305Sstevel state = PT_STATE_HEX_VAR;
14262305Sstevel }
14272305Sstevel *len = il;
14282305Sstevel return (state);
14292305Sstevel }
14302305Sstevel
14312305Sstevel
14322305Sstevel static char *
find_token(char ** cp,int * l,char * endc)14332305Sstevel find_token(char **cp, int *l, char *endc)
14342305Sstevel {
14352305Sstevel char *cpp = *cp;
14362305Sstevel
14372305Sstevel while ((**cp && (isalpha(**cp) || isxdigit(**cp) ||
14382305Sstevel (**cp == PARSE_UNDERSCORE) ||
14392305Sstevel (**cp == PARSE_COMMA) ||
14402305Sstevel (**cp == PARSE_DASH)))) {
14412305Sstevel (*cp)++;
14422305Sstevel (*l)++;
14432305Sstevel }
14442305Sstevel
14452305Sstevel *endc = **cp;
14462305Sstevel **cp = NULL;
14472305Sstevel
14482305Sstevel return (cpp);
14492305Sstevel }
14502305Sstevel
14512305Sstevel static int
parse_token(char * token)14522305Sstevel parse_token(char *token)
14532305Sstevel {
14542305Sstevel cb_props_parse_tree_t *pt = cb_props_parse_tree;
14552305Sstevel int k = sizeof (cb_props_parse_tree) /
14562305Sstevel sizeof (cb_props_parse_tree_t);
14572305Sstevel
14582305Sstevel while (k--) {
14592305Sstevel if (strcmp((char *)token, pt->token) == 0)
14602305Sstevel return (pt->state);
14612305Sstevel pt++;
14622305Sstevel }
14632305Sstevel
14642305Sstevel return (PT_STATE_UNKNOWN);
14652305Sstevel }
14662305Sstevel
14672305Sstevel static int
token_to_hex(char * token,unsigned * val,int len)14682305Sstevel token_to_hex(char *token, unsigned *val, int len)
14692305Sstevel {
14702305Sstevel uchar_t c;
14712305Sstevel
14722305Sstevel *val = 0;
14732305Sstevel if (token[0] == '0' && (token[1] == 'x' || token[1] == 'X')) {
14742305Sstevel token += 2;
14752305Sstevel }
14762305Sstevel
14772305Sstevel while (*token) {
14782305Sstevel if (!isxdigit(*token)) {
14792305Sstevel if (*token == PARSE_COMMA) {
14802305Sstevel if (!(--len))
14812305Sstevel return (1);
14822305Sstevel val++;
14832305Sstevel *val = 0;
14842305Sstevel token++;
14852305Sstevel if (token[0] == '0' && (token[1] == 'x' ||
14862305Sstevel token[1] == 'X')) {
14872305Sstevel token += 2;
14882305Sstevel }
14892305Sstevel continue;
14902305Sstevel }
14912305Sstevel return (0);
14922305Sstevel }
14932305Sstevel c = toupper(*token);
14942305Sstevel if (c >= 'A')
14952305Sstevel c = c - 'A' + 10 + '0';
14962305Sstevel *val = ((*val * 16) + (c - '0'));
14972305Sstevel token++;
14982305Sstevel }
14992305Sstevel
15002305Sstevel return (1);
15012305Sstevel }
15022305Sstevel
15032305Sstevel static int
token_to_dec(char * token,unsigned * val,int len)15042305Sstevel token_to_dec(char *token, unsigned *val, int len)
15052305Sstevel {
15062305Sstevel *val = 0;
15072305Sstevel
15082305Sstevel while (*token) {
15092305Sstevel if (!isdigit(*token)) {
15102305Sstevel if (*token == PARSE_COMMA) {
15112305Sstevel if (!(--len))
15122305Sstevel return (1);
15132305Sstevel val++;
15142305Sstevel *val = 0;
15152305Sstevel token++;
15162305Sstevel continue;
15172305Sstevel }
15182305Sstevel return (0);
15192305Sstevel }
15202305Sstevel *val = ((*val * 10) + (*token - '0'));
15212305Sstevel token++;
15222305Sstevel }
15232305Sstevel
15242305Sstevel return (1);
15252305Sstevel }
15262305Sstevel
15272305Sstevel static void
cardbus_add_prop(struct cb_deviceset_props * cdsp,int type,char * name,caddr_t vp,int len)15282305Sstevel cardbus_add_prop(struct cb_deviceset_props *cdsp, int type, char *name,
15292305Sstevel caddr_t vp, int len)
15302305Sstevel {
15312305Sstevel ddi_prop_t *propp;
15322305Sstevel int pnlen = strlen(name) + 1;
15332305Sstevel
15342305Sstevel propp = (ddi_prop_t *)kmem_zalloc(sizeof (ddi_prop_t), KM_SLEEP);
15352305Sstevel propp->prop_name = (char *)kmem_alloc(pnlen, KM_SLEEP);
15362305Sstevel propp->prop_val = vp;
15372305Sstevel bcopy(name, propp->prop_name, pnlen);
15382305Sstevel propp->prop_len = len;
15392305Sstevel propp->prop_flags = type;
15402305Sstevel propp->prop_next = cdsp->prop_list;
15412305Sstevel cdsp->prop_list = propp;
15422305Sstevel }
15432305Sstevel
15442305Sstevel static void
cardbus_add_stringprop(struct cb_deviceset_props * cdsp,char * name,char * vp,int len)15452305Sstevel cardbus_add_stringprop(struct cb_deviceset_props *cdsp, char *name,
15462305Sstevel char *vp, int len)
15472305Sstevel {
15482305Sstevel char *nstr = kmem_zalloc(len + 1, KM_SLEEP);
15492305Sstevel
15502305Sstevel bcopy(vp, nstr, len);
15512305Sstevel cardbus_add_prop(cdsp, DDI_PROP_TYPE_STRING, name, (caddr_t)nstr,
15522305Sstevel len + 1);
15532305Sstevel }
15542305Sstevel
15552305Sstevel static void
cardbus_prop_free(ddi_prop_t * propp)15562305Sstevel cardbus_prop_free(ddi_prop_t *propp)
15572305Sstevel {
15582305Sstevel if (propp->prop_len) {
15592305Sstevel switch (propp->prop_flags) {
15602305Sstevel case DDI_PROP_TYPE_STRING:
15612305Sstevel kmem_free(propp->prop_val, propp->prop_len);
15622305Sstevel break;
15632305Sstevel case DDI_PROP_TYPE_INT:
15642305Sstevel kmem_free(propp->prop_val,
15652305Sstevel propp->prop_len * sizeof (int));
15662305Sstevel break;
15672305Sstevel }
15682305Sstevel }
15692305Sstevel kmem_free(propp->prop_name, strlen(propp->prop_name) + 1);
15702305Sstevel kmem_free(propp, sizeof (ddi_prop_t *));
15712305Sstevel }
15722305Sstevel
15732305Sstevel static void
cardbus_devprops_free(struct cb_deviceset_props * cbdp)15742305Sstevel cardbus_devprops_free(struct cb_deviceset_props *cbdp)
15752305Sstevel {
15762305Sstevel ddi_prop_t *propp, *npropp;
15772305Sstevel
15782305Sstevel propp = cbdp->prop_list;
15792305Sstevel while (propp) {
15802305Sstevel npropp = propp->prop_next;
15812305Sstevel cardbus_prop_free(propp);
15822305Sstevel propp = npropp;
15832305Sstevel }
15842305Sstevel if (cbdp->nodename)
15852305Sstevel kmem_free(cbdp->nodename, strlen(cbdp->nodename) + 1);
15862305Sstevel if (cbdp->binding_name)
15872305Sstevel kmem_free(cbdp->binding_name, strlen(cbdp->binding_name) +
15882305Sstevel 1);
15892305Sstevel kmem_free(cbdp, sizeof (*cbdp));
15902305Sstevel }
15912305Sstevel
15922305Sstevel /*
15932305Sstevel * Format of "cb-device-init-props" property:
15942305Sstevel * Anything before the semi-colon is an identifying equate, anything
15952305Sstevel * after the semi-colon is a setting equate.
15962305Sstevel *
15972305Sstevel * "binding_name=xXxXxX VendorID=NNNN DeviceID=NNNN; nodename=NewName
15982305Sstevel * Prop=PropVal"
15992305Sstevel *
16002305Sstevel */
16012305Sstevel static int
cardbus_parse_devprop(cbus_t * cbp,char * cp)16022305Sstevel cardbus_parse_devprop(cbus_t *cbp, char *cp)
16032305Sstevel {
16042305Sstevel int state = PT_STATE_TOKEN, qm = 0, em = 0, smc = 0, l = 0;
16052305Sstevel int length;
16062305Sstevel char *token = "beginning of line";
16072305Sstevel char *ptoken = NULL, *quote;
16082305Sstevel char eq = NULL;
16092305Sstevel struct cb_deviceset_props *cdsp;
16102305Sstevel
16112305Sstevel cdsp = (struct cb_deviceset_props *)kmem_zalloc(sizeof (*cdsp),
16122305Sstevel KM_SLEEP);
16132305Sstevel length = strlen(cp);
16142305Sstevel
16152305Sstevel while ((*cp) && (l < length)) {
16162305Sstevel /*
16172305Sstevel * Check for escaped characters
16182305Sstevel */
16192305Sstevel if (*cp == PARSE_ESCAPE) {
16202305Sstevel char *cpp = cp, *cppp = cp + 1;
16212305Sstevel
16222305Sstevel em = 1;
16232305Sstevel
16242305Sstevel if (!qm) {
16252305Sstevel cmn_err(CE_CONT, "cardbus_parse_devprop: "
16262305Sstevel "escape not allowed outside "
16272305Sstevel "of quotes at [%s]\n", token);
16282305Sstevel return (DDI_FAILURE);
16292305Sstevel
16302305Sstevel } /* if (!qm) */
16312305Sstevel
16322305Sstevel while (*cppp)
16332305Sstevel *cpp++ = *cppp++;
16342305Sstevel
16352305Sstevel l++;
16362305Sstevel
16372305Sstevel *cpp = NULL;
16382305Sstevel } /* PARSE_ESCAPE */
16392305Sstevel
16402305Sstevel /*
16412305Sstevel * Check for quoted strings
16422305Sstevel */
16432305Sstevel if (!em && (*cp == PARSE_QUOTE)) {
16442305Sstevel qm ^= 1;
16452305Sstevel if (qm) {
16462305Sstevel quote = cp + 1;
16472305Sstevel } else {
16482305Sstevel *cp = NULL;
16492305Sstevel if (state == PT_STATE_CHECK) {
16502305Sstevel if (strcmp(token, cb_nnamestr) == 0) {
16512305Sstevel cdsp->nodename = kmem_alloc(
16522305Sstevel strlen(quote) + 1,
16532305Sstevel KM_SLEEP);
16542305Sstevel (void) strcpy(cdsp->nodename,
16552305Sstevel quote);
16562305Sstevel } else
16572305Sstevel cardbus_add_stringprop(cdsp,
16582305Sstevel token, quote,
16592305Sstevel strlen(quote));
16602305Sstevel } else if (state != PT_STATE_STRING_VAR) {
16612305Sstevel cmn_err(CE_CONT,
16622305Sstevel "cardbus_parse_devprop: "
16632305Sstevel "unexpected string [%s] after "
16642305Sstevel "[%s]\n", quote, token);
16652305Sstevel return (DDI_FAILURE);
16662305Sstevel } else {
16672305Sstevel if (strcmp(token, cb_bnamestr) == 0) {
16682305Sstevel cdsp->binding_name = kmem_alloc(
16692305Sstevel strlen(quote) + 1,
16702305Sstevel KM_SLEEP);
16712305Sstevel (void) strcpy(
16722305Sstevel cdsp->binding_name, quote);
16732305Sstevel }
16742305Sstevel }
16752305Sstevel state = PT_STATE_TOKEN;
16762305Sstevel } /* if (qm) */
16772305Sstevel } /* PARSE_QUOTE */
16782305Sstevel
16792305Sstevel em = 0;
16802305Sstevel
16812305Sstevel if (!qm && (*cp == PARSE_SEMICOLON)) {
16822305Sstevel smc = 1;
16832305Sstevel }
16842305Sstevel
16852305Sstevel /*
16862305Sstevel * Check for tokens
16872305Sstevel */
16882305Sstevel else if (!qm && (isalpha(*cp) || isxdigit(*cp))) {
16892305Sstevel int tl;
16902305Sstevel unsigned *intp;
16912305Sstevel ptoken = token;
16922305Sstevel token = find_token(&cp, &l, &eq);
16932305Sstevel
16942305Sstevel switch (state) {
16952305Sstevel case PT_STATE_TOKEN:
16962305Sstevel if (smc) {
16972305Sstevel if (eq == PARSE_EQUALS)
16982305Sstevel state = PT_STATE_CHECK;
16992305Sstevel else
17002305Sstevel cardbus_add_prop(cdsp,
17012305Sstevel DDI_PROP_TYPE_ANY,
17022305Sstevel token,
17032305Sstevel NULL, 0);
17042305Sstevel } else if (eq == PARSE_EQUALS)
17052305Sstevel switch (state = parse_token(token)) {
17062305Sstevel case PT_STATE_UNKNOWN:
17072305Sstevel cmn_err(CE_CONT,
17082305Sstevel "cardbus_parse_devprop: "
17092305Sstevel "unknown token [%s]\n",
17102305Sstevel token);
17112305Sstevel state = PT_STATE_TOKEN;
17122305Sstevel } /* switch (parse_token) */
17132305Sstevel else
17142305Sstevel state = PT_STATE_TOKEN;
17152305Sstevel break;
17162305Sstevel
17172305Sstevel case PT_STATE_CHECK:
17182305Sstevel switch (check_token(token, &tl)) {
17192305Sstevel case PT_STATE_DEC_VAR:
17202305Sstevel intp = (unsigned *)kmem_alloc(
17212305Sstevel sizeof (int)*tl,
17222305Sstevel KM_SLEEP);
17232305Sstevel if (token_to_dec(token, intp, tl))
17242305Sstevel cardbus_add_prop(cdsp,
17252305Sstevel DDI_PROP_TYPE_INT, ptoken,
17262305Sstevel (caddr_t)intp, tl);
17272305Sstevel else
17282305Sstevel kmem_free(intp,
17292305Sstevel sizeof (int)*tl);
17302305Sstevel break;
17312305Sstevel case PT_STATE_HEX_VAR:
17322305Sstevel intp = (unsigned *)kmem_alloc(
17332305Sstevel sizeof (int)*tl,
17342305Sstevel KM_SLEEP);
17352305Sstevel if (token_to_hex(token, intp, tl))
17362305Sstevel cardbus_add_prop(cdsp,
17372305Sstevel DDI_PROP_TYPE_INT,
17382305Sstevel ptoken,
17392305Sstevel (caddr_t)intp, tl);
17402305Sstevel else
17412305Sstevel kmem_free(intp,
17422305Sstevel sizeof (int)*tl);
17432305Sstevel break;
17442305Sstevel case PT_STATE_STRING_VAR:
17452305Sstevel if (strcmp(ptoken, cb_nnamestr) == 0) {
17462305Sstevel cdsp->nodename = kmem_alloc(
17472305Sstevel tl + 1, KM_SLEEP);
17482305Sstevel (void) strcpy(cdsp->nodename,
17492305Sstevel token);
17502305Sstevel } else
17512305Sstevel cardbus_add_stringprop(cdsp,
17522305Sstevel ptoken, token, tl);
17532305Sstevel break;
17542305Sstevel }
17552305Sstevel state = PT_STATE_TOKEN;
17562305Sstevel break;
17572305Sstevel
17582305Sstevel case PT_STATE_HEX_VAR:
17592305Sstevel if (strcmp(ptoken, cb_venidstr) == 0) {
17602305Sstevel uint_t val;
17612305Sstevel if (token_to_hex(token, &val, 1))
17622305Sstevel cdsp->venid = val;
17632305Sstevel } else if (strcmp(ptoken, cb_devidstr) == 0) {
17642305Sstevel uint_t val;
17652305Sstevel if (token_to_hex(token, &val, 1))
17662305Sstevel cdsp->devid = val;
17672305Sstevel }
17682305Sstevel state = PT_STATE_TOKEN;
17692305Sstevel break;
17702305Sstevel
17712305Sstevel case PT_STATE_DEC_VAR:
17722305Sstevel if (strcmp(ptoken, cb_venidstr) == 0) {
17732305Sstevel uint_t val;
17742305Sstevel if (token_to_dec(token, &val, 1))
17752305Sstevel cdsp->venid = val;
17762305Sstevel } else if (strcmp(ptoken, cb_devidstr) == 0) {
17772305Sstevel uint_t val;
17782305Sstevel if (token_to_dec(token, &val, 1))
17792305Sstevel cdsp->devid = val;
17802305Sstevel }
17812305Sstevel state = PT_STATE_TOKEN;
17822305Sstevel break;
17832305Sstevel
17842305Sstevel case PT_STATE_STRING_VAR:
17852305Sstevel if (strcmp(ptoken, cb_bnamestr) == 0) {
17862305Sstevel cdsp->binding_name = kmem_alloc(
17872305Sstevel strlen(token) + 1, KM_SLEEP);
17882305Sstevel (void) strcpy(cdsp->binding_name,
17892305Sstevel token);
17902305Sstevel }
17912305Sstevel state = PT_STATE_TOKEN;
17922305Sstevel break;
17932305Sstevel
17942305Sstevel default:
17952305Sstevel cmn_err(CE_CONT, "cardbus_parse_devprop: "
17962305Sstevel "unknown state machine state = %d\n",
17972305Sstevel state);
17982305Sstevel
17992305Sstevel cardbus_devprops_free(cdsp);
18002305Sstevel return (DDI_FAILURE);
18012305Sstevel } /* switch (state) */
18022305Sstevel if (eq == PARSE_SEMICOLON)
18032305Sstevel smc = 1;
18042305Sstevel }
18052305Sstevel cp++;
18062305Sstevel l++;
18072305Sstevel } /* while (*cp) */
18082305Sstevel
18092305Sstevel if (qm) {
18102305Sstevel cmn_err(CE_CONT, "cb_props_parse_line: unterminated "
18112305Sstevel "string = [%s]\n", quote);
18122305Sstevel cardbus_devprops_free(cdsp);
18132305Sstevel return (DDI_FAILURE);
18142305Sstevel }
18152305Sstevel
18162305Sstevel if (state != PT_STATE_TOKEN) {
18172305Sstevel cmn_err(CE_CONT, "cardbus_parse_devprop: token [%s] "
18182305Sstevel "requires value\n", token);
18192305Sstevel cardbus_devprops_free(cdsp);
18202305Sstevel return (DDI_FAILURE);
18212305Sstevel }
18222305Sstevel
18232305Sstevel if (cdsp->venid == 0 || cdsp->devid == 0) {
18242305Sstevel cmn_err(CE_CONT, "cardbus_parse_devprop: Entry "
18252305Sstevel "requires VendorID and DeviceID\n");
18262305Sstevel cardbus_devprops_free(cdsp);
18272305Sstevel return (DDI_FAILURE);
18282305Sstevel }
18292305Sstevel
18302305Sstevel cdsp->next = cbp->cb_dsp;
18312305Sstevel cbp->cb_dsp = cdsp;
18322305Sstevel return (DDI_SUCCESS);
18332305Sstevel }
18342305Sstevel
18352305Sstevel static void
cardbus_device_props(cbus_t * cbp)18362305Sstevel cardbus_device_props(cbus_t *cbp)
18372305Sstevel {
18382305Sstevel char **prop_array;
18392305Sstevel uint_t i, n;
18402305Sstevel
18412305Sstevel if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, cbp->cb_dip,
18422305Sstevel DDI_PROP_DONTPASS,
18432305Sstevel "cb-device-init-props", &prop_array,
18442305Sstevel &n) != DDI_PROP_SUCCESS)
18452305Sstevel return;
18462305Sstevel
18472305Sstevel for (i = 0; i < n; i++)
18482305Sstevel (void) cardbus_parse_devprop(cbp, prop_array[i]);
18492305Sstevel
18502305Sstevel ddi_prop_free(prop_array);
18512305Sstevel }
18522305Sstevel
18532305Sstevel 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)18542305Sstevel cardbus_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
18552305Sstevel off_t offset, off_t len, caddr_t *vaddrp)
18562305Sstevel {
18572305Sstevel register dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
18582305Sstevel int rc;
18592305Sstevel
18602305Sstevel cardbus_err(dip, 9,
18612305Sstevel "cardbus_bus_map(dip=0x%p, rdip=0x%p)\n",
18622305Sstevel (void *) dip, (void *) rdip);
18632305Sstevel
18642305Sstevel if (pdip == NULL)
18652305Sstevel return (DDI_FAILURE);
18662305Sstevel
18672305Sstevel /* A child has asked us to set something up */
18682305Sstevel cardbus_err(dip, 9,
18692305Sstevel "cardbus_bus_map(%s) calling %s - 0x%p, "
18702305Sstevel "offset 0x%x, len 0x%x\n",
18712305Sstevel ddi_driver_name(rdip),
18722305Sstevel ddi_driver_name(pdip),
18732305Sstevel (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_map,
18742305Sstevel (int)offset, (int)len);
18752305Sstevel
18762305Sstevel rc = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
18772305Sstevel (pdip, rdip, mp, offset, len, vaddrp);
18782305Sstevel /* rc = ddi_map(dip, mp, offset, len, vaddrp); */
18792305Sstevel
18803097Srw148561 if (rc != DDI_SUCCESS) {
18812305Sstevel cardbus_err(rdip, 8, "cardbus_bus_map failed, rc = %d\n", rc);
18823097Srw148561 return (DDI_FAILURE);
18833097Srw148561 } else {
18842305Sstevel cardbus_err(rdip, 9, "cardbus_bus_map OK\n");
18852305Sstevel return (DDI_SUCCESS);
18862305Sstevel }
18872305Sstevel }
18882305Sstevel
18892305Sstevel static void
pcirp2rp(const pci_regspec_t * pci_rp,struct regspec * rp)18902305Sstevel pcirp2rp(const pci_regspec_t *pci_rp, struct regspec *rp)
18912305Sstevel {
18922305Sstevel /* bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); */
18932305Sstevel if (PCI_REG_ADDR_G(pci_rp->pci_phys_hi) ==
18942305Sstevel PCI_REG_ADDR_G(PCI_ADDR_IO)) {
18952305Sstevel /* I/O */
18962305Sstevel rp->regspec_bustype = 1;
18972305Sstevel } else {
18982305Sstevel /* memory */
18992305Sstevel rp->regspec_bustype = 0;
19002305Sstevel }
19012305Sstevel rp->regspec_addr = pci_rp->pci_phys_low;
19022305Sstevel rp->regspec_size = pci_rp->pci_size_low;
19032305Sstevel }
19042305Sstevel
19052305Sstevel 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)19062305Sstevel cardbus_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
19072305Sstevel int (*waitfp)(caddr_t), caddr_t arg,
19082305Sstevel ddi_dma_handle_t *handlep)
19092305Sstevel {
19102305Sstevel dev_info_t *pdip = ddi_get_parent(dip);
19112305Sstevel
19122305Sstevel cardbus_err(dip, 10,
19132305Sstevel "cardbus_dma_allochdl(dip=0x%p, rdip=0x%p)\n",
19142305Sstevel (void *) dip, (void *) rdip);
19152305Sstevel
19162305Sstevel if (pdip == NULL)
19172305Sstevel return (DDI_FAILURE);
19182305Sstevel
19192305Sstevel cardbus_err(dip, 11,
19202305Sstevel "cardbus_dma_allochdl calling %s - 0x%p\n",
19212305Sstevel ddi_driver_name(pdip),
19222305Sstevel (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_allochdl);
19232305Sstevel
19242305Sstevel return (ddi_dma_allochdl(dip, rdip, attr, waitfp, arg, handlep));
19252305Sstevel }
19262305Sstevel
19272305Sstevel static int
cardbus_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)19282305Sstevel cardbus_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
19292305Sstevel ddi_dma_handle_t handle)
19302305Sstevel {
19312305Sstevel dev_info_t *pdip = ddi_get_parent(dip);
19322305Sstevel
19332305Sstevel cardbus_err(dip, 10,
19342305Sstevel "cardbus_dma_freehdl(dip=0x%p, rdip=0x%p)\n",
19352305Sstevel (void *) dip, (void *) rdip);
19362305Sstevel
19372305Sstevel if (pdip == NULL)
19382305Sstevel return (DDI_FAILURE);
19392305Sstevel
19402305Sstevel cardbus_err(dip, 11,
19412305Sstevel "cardbus_dma_freehdl calling %s - 0x%p\n",
19422305Sstevel ddi_driver_name(pdip),
19432305Sstevel (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_freehdl);
19442305Sstevel
19452305Sstevel return (ddi_dma_freehdl(dip, rdip, handle));
19462305Sstevel }
19472305Sstevel
19482305Sstevel 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)19492305Sstevel cardbus_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
19502305Sstevel ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
19512305Sstevel ddi_dma_cookie_t *cp, uint_t *ccountp)
19522305Sstevel {
19532305Sstevel dev_info_t *pdip = ddi_get_parent(dip);
19542305Sstevel
19552305Sstevel cardbus_err(dip, 10,
19562305Sstevel "cardbus_dma_bindhdl(dip=0x%p, rdip=0x%p)\n",
19572305Sstevel (void *) dip, (void *) rdip);
19582305Sstevel
19592305Sstevel if (pdip == NULL)
19602305Sstevel return (DDI_FAILURE);
19612305Sstevel
19622305Sstevel cardbus_err(dip, 11,
19632305Sstevel "cardbus_dma_bindhdl calling %s - 0x%p\n",
19642305Sstevel ddi_driver_name(pdip),
19652305Sstevel (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_bindhdl);
19662305Sstevel
19672305Sstevel return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_bindhdl(pdip,
19682305Sstevel rdip, handle, dmareq, cp, ccountp));
19692305Sstevel }
19702305Sstevel
19712305Sstevel static int
cardbus_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)19722305Sstevel cardbus_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
19732305Sstevel ddi_dma_handle_t handle)
19742305Sstevel {
19752305Sstevel dev_info_t *pdip = ddi_get_parent(dip);
19762305Sstevel
19772305Sstevel cardbus_err(dip, 10,
19782305Sstevel "cardbus_dma_unbindhdl(dip=0x%p, rdip=0x%p)\n",
19792305Sstevel (void *) dip, (void *) rdip);
19802305Sstevel
19812305Sstevel if (pdip == NULL)
19822305Sstevel return (DDI_FAILURE);
19832305Sstevel
19842305Sstevel cardbus_err(dip, 11,
19852305Sstevel "cardbus_dma_unbindhdl calling %s - 0x%p\n",
19862305Sstevel ddi_driver_name(pdip),
19872305Sstevel (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl);
19882305Sstevel
19892305Sstevel return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl(pdip,
19902305Sstevel rdip, handle));
19912305Sstevel }
19922305Sstevel
19932305Sstevel 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)19942305Sstevel cardbus_dma_flush(dev_info_t *dip, dev_info_t *rdip,
19952305Sstevel ddi_dma_handle_t handle, off_t off, size_t len,
19962305Sstevel uint_t cache_flags)
19972305Sstevel {
19982305Sstevel dev_info_t *pdip = ddi_get_parent(dip);
19992305Sstevel
20002305Sstevel cardbus_err(dip, 10,
20012305Sstevel "cardbus_dma_flush(dip=0x%p, rdip=0x%p)\n",
20022305Sstevel (void *) dip, (void *) rdip);
20032305Sstevel
20042305Sstevel if (pdip == NULL)
20052305Sstevel return (DDI_FAILURE);
20062305Sstevel
20072305Sstevel cardbus_err(dip, 11,
20082305Sstevel "cardbus_dma_flush calling %s - 0x%p\n",
20092305Sstevel ddi_driver_name(pdip),
20102305Sstevel (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_flush);
20112305Sstevel
20122305Sstevel return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_flush(pdip, rdip,
20132305Sstevel handle, off, len, cache_flags));
20142305Sstevel }
20152305Sstevel
20162305Sstevel 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)20172305Sstevel cardbus_dma_win(dev_info_t *dip, dev_info_t *rdip,
20182305Sstevel ddi_dma_handle_t handle, uint_t win, off_t *offp,
20192305Sstevel size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
20202305Sstevel {
20212305Sstevel dev_info_t *pdip = ddi_get_parent(dip);
20222305Sstevel cardbus_err(dip, 6,
20232305Sstevel "cardbus_dma_win(dip=0x%p, rdip=0x%p)\n",
20242305Sstevel (void *) dip, (void *) rdip);
20252305Sstevel
20262305Sstevel if (pdip == NULL)
20272305Sstevel return (DDI_FAILURE);
20282305Sstevel
20292305Sstevel cardbus_err(dip, 8,
20302305Sstevel "cardbus_dma_win calling %s - 0x%p\n",
20312305Sstevel ddi_driver_name(pdip),
20322305Sstevel (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_win);
20332305Sstevel
20342305Sstevel return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_win(pdip, rdip,
20352305Sstevel handle, win, offp, lenp, cookiep, ccountp));
20362305Sstevel }
20372305Sstevel
20382305Sstevel static int
cardbus_dma_map(dev_info_t * dip,dev_info_t * rdip,struct ddi_dma_req * dmareqp,ddi_dma_handle_t * handlep)20392305Sstevel cardbus_dma_map(dev_info_t *dip, dev_info_t *rdip,
20402305Sstevel struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
20412305Sstevel {
20422305Sstevel dev_info_t *pdip = ddi_get_parent(dip);
20432305Sstevel
20442305Sstevel cardbus_err(dip, 10,
20452305Sstevel "cardbus_dma_map(dip=0x%p, rdip=0x%p)\n",
20462305Sstevel (void *) dip, (void *) rdip);
20472305Sstevel
20482305Sstevel if (pdip == NULL)
20492305Sstevel return (DDI_FAILURE);
20502305Sstevel
20512305Sstevel cardbus_err(dip, 11,
20522305Sstevel "cardbus_dma_map calling %s - 0x%p\n",
20532305Sstevel ddi_driver_name(pdip),
20542305Sstevel (void *) DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_map);
20552305Sstevel
20562305Sstevel return (DEVI(pdip)->devi_ops->devo_bus_ops->bus_dma_map(pdip, rdip,
20572305Sstevel dmareqp, handlep));
20582305Sstevel }
20592305Sstevel
20602305Sstevel static int
cardbus_get_eventcookie(dev_info_t * dip,dev_info_t * rdip,char * eventname,ddi_eventcookie_t * cookiep)20612305Sstevel cardbus_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
20622305Sstevel char *eventname, ddi_eventcookie_t *cookiep)
20632305Sstevel {
20642305Sstevel cbus_t *cbp;
20652305Sstevel int cb_instance;
20662305Sstevel int rc;
20672305Sstevel
20682305Sstevel /*
20692305Sstevel * get the soft state structure for the bus instance.
20702305Sstevel */
20712305Sstevel cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
20722305Sstevel DDI_PROP_DONTPASS, "cbus-instance", -1);
20732305Sstevel ASSERT(cb_instance >= 0);
20742305Sstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
20752305Sstevel
20762305Sstevel cardbus_err(dip, 6, "cardbus_get_eventcookie %s\n", eventname);
20772305Sstevel
20782305Sstevel ASSERT(number_of_cardbus_cards != 0);
20792305Sstevel
20802305Sstevel if (cbp->cb_ndi_event_hdl == NULL) {
20812305Sstevel /*
20822305Sstevel * We can't handle up (probably called at the attachment
20832305Sstevel * point) so pass it on up
20842305Sstevel */
20852305Sstevel dev_info_t *pdip = ddi_get_parent(dip);
20862305Sstevel cardbus_err(dip, 8,
20872305Sstevel "cardbus_get_eventcookie calling %s - 0x%p\n",
20882305Sstevel ddi_driver_name(pdip),
20892305Sstevel (void *)
20902305Sstevel DEVI(pdip)->devi_ops->devo_bus_ops->bus_get_eventcookie);
20912305Sstevel return (DEVI(pdip)->devi_ops->devo_bus_ops->
20922305Sstevel bus_get_eventcookie(pdip, rdip, eventname, cookiep));
20932305Sstevel }
20942305Sstevel
20952305Sstevel cardbus_err(dip, 8,
20962305Sstevel "cardbus_get_eventcookie calling ndi_event_retrieve_cookie\n");
20972305Sstevel
20982305Sstevel rc = ndi_event_retrieve_cookie(cbp->cb_ndi_event_hdl, rdip, eventname,
20992305Sstevel cookiep, NDI_EVENT_NOPASS);
21002305Sstevel
21012305Sstevel cardbus_err(dip, 7,
21022305Sstevel "cardbus_get_eventcookie rc %d cookie %p\n", rc, (void *)*cookiep);
21032305Sstevel return (rc);
21042305Sstevel }
21052305Sstevel
21062305Sstevel 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)21072305Sstevel cardbus_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
21082305Sstevel ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
21092305Sstevel ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
21102305Sstevel void *arg, ddi_callback_id_t *cb_id)
21112305Sstevel {
21122305Sstevel cbus_t *cbp;
21132305Sstevel int cb_instance;
21142305Sstevel int rc;
21152305Sstevel
21162305Sstevel /*
21172305Sstevel * get the soft state structure for the bus instance.
21182305Sstevel */
21192305Sstevel cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
21202305Sstevel DDI_PROP_DONTPASS, "cbus-instance", -1);
21212305Sstevel ASSERT(cb_instance >= 0);
21222305Sstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
21232305Sstevel
21242305Sstevel cardbus_err(dip, 6, "cardbus_add_eventcall\n");
21252305Sstevel
21262305Sstevel ASSERT(number_of_cardbus_cards != 0);
21272305Sstevel
21282305Sstevel if (cbp->cb_ndi_event_hdl == NULL) {
21292305Sstevel /*
21302305Sstevel * We can't handle up (probably called at the attachment
21312305Sstevel * point) so pass it on up
21322305Sstevel */
21332305Sstevel dev_info_t *pdip = ddi_get_parent(dip);
21342305Sstevel cardbus_err(dip, 8,
21352305Sstevel "cardbus_add_eventcall calling %s - 0x%p\n",
21362305Sstevel ddi_driver_name(pdip),
21372305Sstevel (void *)
21382305Sstevel DEVI(pdip)->devi_ops->devo_bus_ops->bus_add_eventcall);
21392305Sstevel return (DEVI(pdip)->devi_ops->devo_bus_ops->
21402305Sstevel bus_add_eventcall(pdip, rdip, cookie, callback,
21412305Sstevel arg, cb_id));
21422305Sstevel }
21432305Sstevel
21442305Sstevel cardbus_err(dip, 8,
21452305Sstevel "cardbus_add_eventcall calling ndi_event_add_callback\n");
21462305Sstevel
21472305Sstevel rc = ndi_event_add_callback(cbp->cb_ndi_event_hdl, rdip, cookie,
21482305Sstevel callback, arg, NDI_EVENT_NOPASS, cb_id);
21492305Sstevel cardbus_err(dip, 7,
21502305Sstevel "cardbus_add_eventcall rc %d cookie %p\n", rc, (void *)cookie);
21512305Sstevel return (rc);
21522305Sstevel }
21532305Sstevel
21542305Sstevel static int
cardbus_remove_eventcall(dev_info_t * dip,ddi_callback_id_t cb_id)21552305Sstevel cardbus_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
21562305Sstevel {
21572305Sstevel cbus_t *cbp;
21582305Sstevel int cb_instance;
21592305Sstevel
21602305Sstevel /*
21612305Sstevel * get the soft state structure for the bus instance.
21622305Sstevel */
21632305Sstevel cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
21642305Sstevel DDI_PROP_DONTPASS, "cbus-instance", -1);
21652305Sstevel ASSERT(cb_instance >= 0);
21662305Sstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
21672305Sstevel
21682305Sstevel cardbus_err(dip, 6, "cardbus_remove_eventcall\n");
21692305Sstevel
21702305Sstevel ASSERT(number_of_cardbus_cards != 0);
21712305Sstevel
21722305Sstevel if (cbp->cb_ndi_event_hdl == NULL) {
21732305Sstevel /*
21742305Sstevel * We can't handle up (probably called at the attachment
21752305Sstevel * point) so pass it on up
21762305Sstevel */
21772305Sstevel dev_info_t *pdip = ddi_get_parent(dip);
21782305Sstevel cardbus_err(dip, 8,
21792305Sstevel "cardbus_remove_eventcall calling %s - 0x%p\n",
21802305Sstevel ddi_driver_name(pdip),
21812305Sstevel (void *)
21822305Sstevel DEVI(pdip)->devi_ops->devo_bus_ops->bus_remove_eventcall);
21832305Sstevel return (DEVI(pdip)->devi_ops->devo_bus_ops->
21842305Sstevel bus_remove_eventcall(pdip, cb_id));
21852305Sstevel }
21862305Sstevel
21872305Sstevel return (ndi_event_remove_callback(cbp->cb_ndi_event_hdl, cb_id));
21882305Sstevel }
21892305Sstevel
21902305Sstevel static int
cardbus_post_event(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void * bus_impldata)21912305Sstevel cardbus_post_event(dev_info_t *dip, dev_info_t *rdip,
21922305Sstevel ddi_eventcookie_t cookie, void *bus_impldata)
21932305Sstevel {
21942305Sstevel _NOTE(ARGUNUSED(rdip, cookie, bus_impldata))
21952305Sstevel cardbus_err(dip, 1, "cardbus_post_event()\n");
21962305Sstevel return (DDI_FAILURE);
21972305Sstevel }
21982305Sstevel
21992305Sstevel static int cardbus_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22002305Sstevel ddi_intr_handle_impl_t *hdlp);
22012305Sstevel static int cardbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22022305Sstevel ddi_intr_handle_impl_t *hdlp);
22032305Sstevel static int cardbus_enable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22042305Sstevel ddi_intr_handle_impl_t *hdlp);
22052305Sstevel static int cardbus_disable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22062305Sstevel ddi_intr_handle_impl_t *hdlp);
22072305Sstevel
22082451Srw148561 static int
cardbus_get_pil(dev_info_t * dip)22092451Srw148561 cardbus_get_pil(dev_info_t *dip)
22102451Srw148561 {
22112451Srw148561 return ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
22122451Srw148561 "interrupt-priorities", 6);
22132451Srw148561 }
22142451Srw148561
22152305Sstevel 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)22162305Sstevel cardbus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
22172305Sstevel ddi_intr_handle_impl_t *hdlp, void *result)
22182305Sstevel {
22192305Sstevel int ret = DDI_SUCCESS;
22202305Sstevel
22212305Sstevel #if defined(CARDBUS_DEBUG)
22222305Sstevel cardbus_err(dip, 8, "cardbus_intr_ops() intr_op=%d\n", (int)intr_op);
22232305Sstevel #endif
22242305Sstevel
22252305Sstevel switch (intr_op) {
22262305Sstevel case DDI_INTROP_GETCAP:
22272305Sstevel *(int *)result = DDI_INTR_FLAG_LEVEL;
22282305Sstevel break;
22292305Sstevel case DDI_INTROP_ALLOC:
22302305Sstevel *(int *)result = hdlp->ih_scratch1;
22312305Sstevel break;
22322305Sstevel case DDI_INTROP_FREE:
22332305Sstevel break;
22342305Sstevel case DDI_INTROP_GETPRI:
22352305Sstevel *(int *)result = hdlp->ih_pri ?
22362451Srw148561 hdlp->ih_pri : cardbus_get_pil(dip);
22372305Sstevel break;
22382305Sstevel case DDI_INTROP_SETPRI:
22392305Sstevel break;
22402305Sstevel case DDI_INTROP_ADDISR:
22412305Sstevel case DDI_INTROP_REMISR:
22422305Sstevel if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
22432305Sstevel cardbus_err(dip, 1, "Only fixed interrupts\n");
22442305Sstevel return (DDI_FAILURE);
22452305Sstevel }
22462305Sstevel break;
22472305Sstevel case DDI_INTROP_ENABLE:
22482305Sstevel ret = cardbus_enable_intr_impl(dip, rdip, hdlp);
22492305Sstevel break;
22502305Sstevel case DDI_INTROP_DISABLE:
22512305Sstevel ret = cardbus_disable_intr_impl(dip, rdip, hdlp);
22522305Sstevel break;
22532305Sstevel case DDI_INTROP_NINTRS:
22542305Sstevel case DDI_INTROP_NAVAIL:
22552451Srw148561 #ifdef sparc
22562580Sanish *(int *)result = i_ddi_get_intx_nintrs(rdip);
22572451Srw148561 #else
22582451Srw148561 *(int *)result = 1;
22592451Srw148561 #endif
22602305Sstevel break;
22612305Sstevel case DDI_INTROP_SUPPORTED_TYPES:
22622451Srw148561 *(int *)result = DDI_INTR_TYPE_FIXED;
22632305Sstevel break;
22642305Sstevel default:
22652305Sstevel ret = DDI_ENOTSUP;
22662305Sstevel break;
22672305Sstevel }
22682305Sstevel
22692305Sstevel return (ret);
22702305Sstevel }
22712305Sstevel
22722305Sstevel static int
cardbus_enable_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)22732305Sstevel cardbus_enable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
22742305Sstevel ddi_intr_handle_impl_t *hdlp)
22752305Sstevel {
22762305Sstevel anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
22772305Sstevel set_irq_handler_t sih;
22782305Sstevel uint_t socket = 0; /* We only support devices */
22792305Sstevel /* with one socket per function */
22802305Sstevel
22812305Sstevel ASSERT(anp != NULL);
22822305Sstevel
22832305Sstevel cardbus_err(dip, 9,
22842305Sstevel "cardbus_enable_intr_impl, intr=0x%p, arg1=0x%p, arg2=0x%p"
22852305Sstevel "rdip=0x%p(%s)\n",
22862305Sstevel (void *) hdlp->ih_cb_func,
22872305Sstevel hdlp->ih_cb_arg1, hdlp->ih_cb_arg2,
22882305Sstevel (void *) rdip, ddi_driver_name(rdip));
22892305Sstevel
22902305Sstevel if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
22912305Sstevel cardbus_err(dip, 1, "Only fixed interrupts\n");
22922305Sstevel return (DDI_FAILURE);
22932305Sstevel }
22942305Sstevel
22952305Sstevel sih.socket = socket;
22962451Srw148561 sih.handler_id = (unsigned)(long)rdip;
22972305Sstevel sih.handler = (f_tt *)hdlp->ih_cb_func;
22982305Sstevel sih.arg1 = hdlp->ih_cb_arg1;
22992305Sstevel sih.arg2 = hdlp->ih_cb_arg2;
23002451Srw148561 sih.irq = cardbus_get_pil(dip);
23012305Sstevel
23022305Sstevel if ((*anp->an_if->pcif_set_interrupt)(dip, &sih) != SUCCESS)
23032305Sstevel return (DDI_FAILURE);
23042305Sstevel
23052305Sstevel return (DDI_SUCCESS);
23062305Sstevel }
23072305Sstevel
23082305Sstevel static int
cardbus_disable_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)23092305Sstevel cardbus_disable_intr_impl(dev_info_t *dip, dev_info_t *rdip,
23102305Sstevel ddi_intr_handle_impl_t *hdlp)
23112305Sstevel {
23122305Sstevel anp_t *anp = (anp_t *)ddi_get_driver_private(dip);
23132305Sstevel clear_irq_handler_t cih;
23142305Sstevel uint_t socket = 0; /* We only support devices with 1 socket per */
23152305Sstevel /* function. */
23162305Sstevel
23172305Sstevel ASSERT(anp != NULL);
23182305Sstevel
23192305Sstevel cardbus_err(dip, 9,
23202305Sstevel "cardbus_disable_intr_impl, intr=0x%p, arg1=0x%p, arg2=0x%p"
23212305Sstevel "rdip=0x%p(%s%d)\n",
23222305Sstevel (void *) hdlp->ih_cb_func,
23232305Sstevel hdlp->ih_cb_arg1, hdlp->ih_cb_arg2,
23242305Sstevel (void *) rdip, ddi_driver_name(rdip), ddi_get_instance(rdip));
23252305Sstevel
23262305Sstevel if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) {
23272305Sstevel cardbus_err(dip, 1, "Only fixed interrupts\n");
23282305Sstevel return (DDI_FAILURE);
23292305Sstevel }
23302305Sstevel
23312305Sstevel cih.socket = socket;
23322451Srw148561 cih.handler_id = (unsigned)(long)rdip;
23332305Sstevel cih.handler = (f_tt *)hdlp->ih_cb_func;
23342305Sstevel
23352305Sstevel if ((*anp->an_if->pcif_clr_interrupt)(dip, &cih) != SUCCESS)
23362305Sstevel return (DDI_FAILURE);
23372305Sstevel
23382305Sstevel return (DDI_SUCCESS);
23392305Sstevel }
23402305Sstevel
23412305Sstevel #if defined(CARDBUS_DEBUG)
23422305Sstevel static int cardbus_do_pprintf = 0;
23432305Sstevel #endif
23442305Sstevel
23452305Sstevel /*PRINTFLIKE3*/
23462305Sstevel void
cardbus_err(dev_info_t * dip,int level,const char * fmt,...)23472305Sstevel cardbus_err(dev_info_t *dip, int level, const char *fmt, ...)
23482305Sstevel {
23492305Sstevel if (cardbus_debug && (level <= cardbus_debug)) {
23502305Sstevel va_list adx;
23512305Sstevel int instance;
23522305Sstevel char buf[256];
23532305Sstevel const char *name;
23542305Sstevel char *nl = "";
23552305Sstevel #if !defined(CARDBUS_DEBUG)
23562305Sstevel int ce;
23572305Sstevel char qmark = 0;
23582305Sstevel
23592305Sstevel if (level <= 3)
23602305Sstevel ce = CE_WARN;
23612305Sstevel else
23622305Sstevel ce = CE_CONT;
23632305Sstevel if (level == 4)
23642305Sstevel qmark = 1;
23652305Sstevel #endif
23662305Sstevel
23672305Sstevel if (dip) {
23682305Sstevel instance = ddi_get_instance(dip);
23692305Sstevel /* name = ddi_binding_name(dip); */
23702305Sstevel name = ddi_driver_name(dip);
23712305Sstevel } else {
23722305Sstevel instance = 0;
23732305Sstevel name = "";
23742305Sstevel }
23752305Sstevel
23762305Sstevel va_start(adx, fmt);
23772305Sstevel /* vcmn_err(ce, fmt, adx); */
23782305Sstevel /* vprintf(fmt, adx); */
23792305Sstevel /* prom_vprintf(fmt, adx); */
23802305Sstevel (void) vsprintf(buf, fmt, adx);
23812305Sstevel va_end(adx);
23822305Sstevel
23832305Sstevel if (buf[strlen(buf) - 1] != '\n')
23842305Sstevel nl = "\n";
23852305Sstevel
23862305Sstevel #if defined(CARDBUS_DEBUG)
23872305Sstevel if (cardbus_do_pprintf) {
23882305Sstevel if (dip) {
23892305Sstevel if (instance >= 0)
23902305Sstevel prom_printf("%s(%d),0x%p: %s%s",
2391*7240Srh87107 name, instance, (void *)dip,
2392*7240Srh87107 buf, nl);
23932305Sstevel else
23942305Sstevel prom_printf("%s,0x%p: %s%s", name,
2395*7240Srh87107 (void *)dip, buf, nl);
23962305Sstevel } else
23972305Sstevel prom_printf("%s%s", buf, nl);
23982305Sstevel } else {
23992305Sstevel if (dip) {
24002305Sstevel if (instance >= 0)
24012305Sstevel cmn_err(CE_CONT, "%s(%d),0x%p: %s%s",
2402*7240Srh87107 name, instance, (void *)dip,
24032305Sstevel buf, nl);
24042305Sstevel else
24052305Sstevel cmn_err(CE_CONT, "%s,0x%p: %s%s",
2406*7240Srh87107 name, (void *)dip, buf, nl);
24072305Sstevel } else
24082305Sstevel cmn_err(CE_CONT, "%s%s", buf, nl);
24092305Sstevel }
24102305Sstevel #else
24112305Sstevel if (dip)
24122305Sstevel cmn_err(ce, qmark ? "?%s%d: %s%s" : "%s%d: %s%s",
24132305Sstevel name, instance, buf, nl);
24142305Sstevel else
24152305Sstevel cmn_err(ce, qmark ? "?%s%s" : "%s%s", buf, nl);
24162305Sstevel #endif
24172305Sstevel }
24182305Sstevel }
24192305Sstevel
cardbus_expand_busrange(dev_info_t * dip)24202305Sstevel static void cardbus_expand_busrange(dev_info_t *dip)
24212305Sstevel {
24222305Sstevel dev_info_t *pdip;
24232305Sstevel cardbus_bus_range_t *bus_range;
24242305Sstevel int len;
24252305Sstevel
24262305Sstevel pdip = ddi_get_parent(dip);
24272305Sstevel
24282305Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "bus-range",
24292305Sstevel (caddr_t)&bus_range, &len) == DDI_PROP_SUCCESS) {
24302305Sstevel ndi_ra_request_t req;
24312305Sstevel uint64_t next_bus, blen;
24322305Sstevel uint32_t ret;
24332305Sstevel ddi_acc_handle_t handle;
24342305Sstevel
24352305Sstevel if (bus_range->lo != bus_range->hi)
24362305Sstevel cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24372305Sstevel "%u -> %u\n", bus_range->lo, bus_range->hi);
24382305Sstevel else {
24392305Sstevel
24402305Sstevel bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
24412305Sstevel req.ra_addr = bus_range->lo + 1;
24422305Sstevel req.ra_flags = NDI_RA_ALLOC_SPECIFIED;
24432305Sstevel req.ra_len = 12;
24442305Sstevel
24452305Sstevel while ((req.ra_len > 0) &&
24462305Sstevel (ret = ndi_ra_alloc(ddi_get_parent(pdip), &req,
24472305Sstevel &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
24482305Sstevel NDI_RA_PASS)) != NDI_SUCCESS)
24492305Sstevel req.ra_len--;
24502305Sstevel
24512305Sstevel if (ret != NDI_SUCCESS) {
24522305Sstevel cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24532305Sstevel "fail to allocate bus number\n");
24542305Sstevel goto exit;
24552305Sstevel }
24562305Sstevel
24572305Sstevel bus_range->hi = bus_range->lo + req.ra_len;
24582305Sstevel if (ndi_prop_update_int_array(DDI_DEV_T_NONE, pdip,
24592305Sstevel "bus-range", (int *)bus_range, 2) != DDI_SUCCESS) {
24602305Sstevel cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24612305Sstevel "fail to update bus-range property\n");
24622305Sstevel goto exit;
24632305Sstevel }
24642305Sstevel
24652305Sstevel if (pci_config_setup(pdip, &handle) != DDI_SUCCESS) {
24662305Sstevel cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24672305Sstevel "fail to pci_config_setup\n");
24682305Sstevel goto exit;
24692305Sstevel }
24702305Sstevel
24712305Sstevel pci_config_put8(handle, PCI_BCNF_SECBUS, bus_range->lo);
24722305Sstevel pci_config_put8(handle, PCI_BCNF_SUBBUS, bus_range->hi);
24732305Sstevel
24742305Sstevel cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24752305Sstevel "parent dip %u -> %u\n",
24762305Sstevel pci_config_get8(handle, PCI_BCNF_SECBUS),
24772305Sstevel pci_config_get8(handle, PCI_BCNF_SUBBUS));
24782305Sstevel pci_config_teardown(&handle);
24792305Sstevel
24802305Sstevel if (ndi_ra_map_setup(pdip, NDI_RA_TYPE_PCI_BUSNUM)
24812305Sstevel != NDI_SUCCESS) {
24822305Sstevel cardbus_err(pdip, 1, "cardbus_expand_busrange: "
24832305Sstevel "fail to ndi_ra_map_setup of bus number\n");
24842305Sstevel goto exit;
24852305Sstevel }
24862305Sstevel
24872305Sstevel (void) ndi_ra_free(pdip,
24882305Sstevel (uint64_t)bus_range->lo + 1, req.ra_len,
24892305Sstevel NDI_RA_TYPE_PCI_BUSNUM, 0);
24902305Sstevel }
24912305Sstevel
24922305Sstevel bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
24932305Sstevel req.ra_len = 2;
24942305Sstevel
24952305Sstevel while ((req.ra_len > 0) &&
24962305Sstevel (ret = ndi_ra_alloc(pdip, &req,
24972305Sstevel &next_bus, &blen, NDI_RA_TYPE_PCI_BUSNUM,
24982305Sstevel 0)) != NDI_SUCCESS)
24992305Sstevel req.ra_len--;
25002305Sstevel
25012305Sstevel cardbus_err(dip, 1, "cardbus_expand_busrange: "
25022305Sstevel "cardbus dip base %u length %d\n",
25032305Sstevel (int)next_bus, (int)req.ra_len);
25042305Sstevel
25052305Sstevel if (ret != NDI_SUCCESS) {
25062305Sstevel cardbus_err(dip, 1, "cardbus_expand_busrange: "
25072305Sstevel "fail to allocate bus number of length %d "
25082305Sstevel "from parent\n",
25092305Sstevel (int)req.ra_len);
25102305Sstevel goto exit;
25112305Sstevel }
25122305Sstevel
25132305Sstevel if (ndi_ra_map_setup(dip, NDI_RA_TYPE_PCI_BUSNUM)
25142305Sstevel != NDI_SUCCESS) {
25152305Sstevel cardbus_err(dip, 1, "cardbus_expand_busrange: "
25162305Sstevel "fail to ndi_ra_map_setup of bus numbers\n");
25172305Sstevel goto exit;
25182305Sstevel }
25192305Sstevel
25202305Sstevel (void) ndi_ra_free(dip,
25212305Sstevel (uint64_t)next_bus, req.ra_len,
25222305Sstevel NDI_RA_TYPE_PCI_BUSNUM, 0);
25232305Sstevel exit:
25242305Sstevel kmem_free(bus_range, len);
25252305Sstevel
25262305Sstevel } else
25272305Sstevel cardbus_err(pdip, 1, "cardbus_expand_busrange: "
25282305Sstevel "parent dip doesn't have busrange prop\n");
25292305Sstevel }
2530