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