10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51865Sdilpreet * Common Development and Distribution License (the "License"). 61865Sdilpreet * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 2210923SEvan.Yan@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * Host to PCI local bus driver 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/conf.h> 310Sstevel@tonic-gate #include <sys/modctl.h> 320Sstevel@tonic-gate #include <sys/pci.h> 330Sstevel@tonic-gate #include <sys/pci_impl.h> 34881Sjohnny #include <sys/sysmacros.h> 350Sstevel@tonic-gate #include <sys/sunndi.h> 361865Sdilpreet #include <sys/ddifm.h> 371865Sdilpreet #include <sys/ndifm.h> 381865Sdilpreet #include <sys/fm/protocol.h> 390Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h> 40881Sjohnny #include <io/pci/pci_common.h> 41881Sjohnny #include <io/pci/pci_tools_ext.h> 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* Save minimal state. */ 440Sstevel@tonic-gate void *pci_statep; 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * Bus Operation functions 480Sstevel@tonic-gate */ 490Sstevel@tonic-gate static int pci_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 500Sstevel@tonic-gate off_t, off_t, caddr_t *); 510Sstevel@tonic-gate static int pci_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 520Sstevel@tonic-gate void *, void *); 530Sstevel@tonic-gate static int pci_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 540Sstevel@tonic-gate ddi_intr_handle_impl_t *, void *); 551865Sdilpreet static int pci_fm_init(dev_info_t *, dev_info_t *, int, 561865Sdilpreet ddi_iblock_cookie_t *); 571865Sdilpreet static int pci_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *); 580Sstevel@tonic-gate 590Sstevel@tonic-gate struct bus_ops pci_bus_ops = { 600Sstevel@tonic-gate BUSO_REV, 610Sstevel@tonic-gate pci_bus_map, 620Sstevel@tonic-gate NULL, 630Sstevel@tonic-gate NULL, 640Sstevel@tonic-gate NULL, 650Sstevel@tonic-gate i_ddi_map_fault, 660Sstevel@tonic-gate ddi_dma_map, 670Sstevel@tonic-gate ddi_dma_allochdl, 680Sstevel@tonic-gate ddi_dma_freehdl, 690Sstevel@tonic-gate ddi_dma_bindhdl, 700Sstevel@tonic-gate ddi_dma_unbindhdl, 710Sstevel@tonic-gate ddi_dma_flush, 720Sstevel@tonic-gate ddi_dma_win, 730Sstevel@tonic-gate ddi_dma_mctl, 740Sstevel@tonic-gate pci_ctlops, 750Sstevel@tonic-gate ddi_bus_prop_op, 760Sstevel@tonic-gate 0, /* (*bus_get_eventcookie)(); */ 770Sstevel@tonic-gate 0, /* (*bus_add_eventcall)(); */ 780Sstevel@tonic-gate 0, /* (*bus_remove_eventcall)(); */ 790Sstevel@tonic-gate 0, /* (*bus_post_event)(); */ 800Sstevel@tonic-gate 0, /* (*bus_intr_ctl)(); */ 810Sstevel@tonic-gate 0, /* (*bus_config)(); */ 820Sstevel@tonic-gate 0, /* (*bus_unconfig)(); */ 831865Sdilpreet pci_fm_init, /* (*bus_fm_init)(); */ 840Sstevel@tonic-gate NULL, /* (*bus_fm_fini)(); */ 850Sstevel@tonic-gate NULL, /* (*bus_fm_access_enter)(); */ 860Sstevel@tonic-gate NULL, /* (*bus_fm_access_exit)(); */ 870Sstevel@tonic-gate NULL, /* (*bus_power)(); */ 880Sstevel@tonic-gate pci_intr_ops /* (*bus_intr_op)(); */ 890Sstevel@tonic-gate }; 900Sstevel@tonic-gate 910Sstevel@tonic-gate /* 920Sstevel@tonic-gate * One goal here is to leverage off of the pcihp.c source without making 930Sstevel@tonic-gate * changes to it. Call into it's cb_ops directly if needed, piggybacking 940Sstevel@tonic-gate * anything else needed by the pci_tools.c module. Only pci_tools and pcihp 95117Sschwartz * will be opening PCI nexus driver file descriptors. 960Sstevel@tonic-gate */ 97881Sjohnny static int pci_open(dev_t *, int, int, cred_t *); 98881Sjohnny static int pci_close(dev_t, int, int, cred_t *); 99881Sjohnny static int pci_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 100881Sjohnny static int pci_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, 101881Sjohnny caddr_t, int *); 102881Sjohnny static int pci_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 1036313Skrishnae static void pci_peekpoke_cb(dev_info_t *, ddi_fm_error_t *); 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate struct cb_ops pci_cb_ops = { 1060Sstevel@tonic-gate pci_open, /* open */ 1070Sstevel@tonic-gate pci_close, /* close */ 1080Sstevel@tonic-gate nodev, /* strategy */ 1090Sstevel@tonic-gate nodev, /* print */ 1100Sstevel@tonic-gate nodev, /* dump */ 1110Sstevel@tonic-gate nodev, /* read */ 1120Sstevel@tonic-gate nodev, /* write */ 1130Sstevel@tonic-gate pci_ioctl, /* ioctl */ 1140Sstevel@tonic-gate nodev, /* devmap */ 1150Sstevel@tonic-gate nodev, /* mmap */ 1160Sstevel@tonic-gate nodev, /* segmap */ 1170Sstevel@tonic-gate nochpoll, /* poll */ 1180Sstevel@tonic-gate pci_prop_op, /* cb_prop_op */ 1190Sstevel@tonic-gate NULL, /* streamtab */ 1200Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 1210Sstevel@tonic-gate CB_REV, /* rev */ 1220Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 1230Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 1240Sstevel@tonic-gate }; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate /* 1270Sstevel@tonic-gate * Device Node Operation functions 1280Sstevel@tonic-gate */ 1290Sstevel@tonic-gate static int pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 1300Sstevel@tonic-gate static int pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate struct dev_ops pci_ops = { 1330Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 1340Sstevel@tonic-gate 0, /* refcnt */ 1350Sstevel@tonic-gate pci_info, /* info */ 1360Sstevel@tonic-gate nulldev, /* identify */ 1370Sstevel@tonic-gate nulldev, /* probe */ 1380Sstevel@tonic-gate pci_attach, /* attach */ 1390Sstevel@tonic-gate pci_detach, /* detach */ 1400Sstevel@tonic-gate nulldev, /* reset */ 1410Sstevel@tonic-gate &pci_cb_ops, /* driver operations */ 1427656SSherry.Moore@Sun.COM &pci_bus_ops, /* bus operations */ 1437656SSherry.Moore@Sun.COM NULL, /* power */ 1447656SSherry.Moore@Sun.COM ddi_quiesce_not_needed /* quiesce */ 1450Sstevel@tonic-gate }; 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate /* 148354Smyers * This variable controls the default setting of the command register 149354Smyers * for pci devices. See pci_initchild() for details. 150354Smyers */ 151354Smyers static ushort_t pci_command_default = PCI_COMM_ME | 152354Smyers PCI_COMM_MAE | 153354Smyers PCI_COMM_IO; 154354Smyers 155354Smyers /* 1560Sstevel@tonic-gate * Internal routines in support of particular pci_ctlops. 1570Sstevel@tonic-gate */ 1580Sstevel@tonic-gate static int pci_removechild(dev_info_t *child); 1590Sstevel@tonic-gate static int pci_initchild(dev_info_t *child); 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1620Sstevel@tonic-gate * Module linkage information for the kernel. 1630Sstevel@tonic-gate */ 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate static struct modldrv modldrv = { 16610923SEvan.Yan@Sun.COM &mod_driverops, /* Type of module */ 16710923SEvan.Yan@Sun.COM "x86 Host to PCI nexus driver", /* Name of module */ 16810923SEvan.Yan@Sun.COM &pci_ops, /* driver ops */ 1690Sstevel@tonic-gate }; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate static struct modlinkage modlinkage = { 1720Sstevel@tonic-gate MODREV_1, 1730Sstevel@tonic-gate (void *)&modldrv, 1740Sstevel@tonic-gate NULL 1750Sstevel@tonic-gate }; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate int 1780Sstevel@tonic-gate _init(void) 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate int e; 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate /* 1830Sstevel@tonic-gate * Initialize per-pci bus soft state pointer. 1840Sstevel@tonic-gate */ 1850Sstevel@tonic-gate e = ddi_soft_state_init(&pci_statep, sizeof (pci_state_t), 1); 1860Sstevel@tonic-gate if (e != 0) 1870Sstevel@tonic-gate return (e); 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) 1900Sstevel@tonic-gate ddi_soft_state_fini(&pci_statep); 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate return (e); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate int 1960Sstevel@tonic-gate _fini(void) 1970Sstevel@tonic-gate { 1980Sstevel@tonic-gate int rc; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate rc = mod_remove(&modlinkage); 2010Sstevel@tonic-gate if (rc != 0) 2020Sstevel@tonic-gate return (rc); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate ddi_soft_state_fini(&pci_statep); 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate return (rc); 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate int 2100Sstevel@tonic-gate _info(struct modinfo *modinfop) 2110Sstevel@tonic-gate { 2120Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate /*ARGSUSED*/ 2160Sstevel@tonic-gate static int 2170Sstevel@tonic-gate pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2180Sstevel@tonic-gate { 2190Sstevel@tonic-gate /* 2200Sstevel@tonic-gate * Use the minor number as constructed by pcihp, as the index value to 2210Sstevel@tonic-gate * ddi_soft_state_zalloc. 2220Sstevel@tonic-gate */ 223117Sschwartz int instance = ddi_get_instance(devi); 2240Sstevel@tonic-gate pci_state_t *pcip = NULL; 2255295Srandyf switch (cmd) { 2265295Srandyf case DDI_ATTACH: 2275295Srandyf break; 2285295Srandyf 2295295Srandyf case DDI_RESUME: 2305295Srandyf return (DDI_SUCCESS); 2315295Srandyf 2325295Srandyf default: 2335295Srandyf return (DDI_FAILURE); 2345295Srandyf } 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci") 2370Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 2380Sstevel@tonic-gate cmn_err(CE_WARN, "pci: 'device_type' prop create failed"); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 241117Sschwartz if (ddi_soft_state_zalloc(pci_statep, instance) == DDI_SUCCESS) { 242117Sschwartz pcip = ddi_get_soft_state(pci_statep, instance); 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate if (pcip == NULL) { 246117Sschwartz goto bad_soft_state; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate pcip->pci_dip = devi; 25010923SEvan.Yan@Sun.COM pcip->pci_soft_state = PCI_SOFT_STATE_CLOSED; 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * Initialize hotplug support on this bus. At minimum 2540Sstevel@tonic-gate * (for non hotplug bus) this would create ":devctl" minor 2550Sstevel@tonic-gate * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls 2560Sstevel@tonic-gate * to this bus. 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate if (pcihp_init(devi) != DDI_SUCCESS) { 2590Sstevel@tonic-gate cmn_err(CE_WARN, "pci: Failed to setup hotplug framework"); 260117Sschwartz goto bad_pcihp_init; 261117Sschwartz } 262117Sschwartz 263777Sschwartz /* Second arg: initialize for pci, not pci_express */ 264777Sschwartz if (pcitool_init(devi, B_FALSE) != DDI_SUCCESS) { 265117Sschwartz goto bad_pcitool_init; 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate 2681865Sdilpreet pcip->pci_fmcap = DDI_FM_ERRCB_CAPABLE | 2691865Sdilpreet DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; 2701865Sdilpreet ddi_fm_init(devi, &pcip->pci_fmcap, &pcip->pci_fm_ibc); 27110923SEvan.Yan@Sun.COM mutex_init(&pcip->pci_mutex, NULL, MUTEX_DRIVER, NULL); 2721865Sdilpreet mutex_init(&pcip->pci_err_mutex, NULL, MUTEX_DRIVER, 2731865Sdilpreet (void *)pcip->pci_fm_ibc); 2741865Sdilpreet mutex_init(&pcip->pci_peek_poke_mutex, NULL, MUTEX_DRIVER, 2751865Sdilpreet (void *)pcip->pci_fm_ibc); 2761865Sdilpreet if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) { 2771865Sdilpreet pci_ereport_setup(devi); 2781865Sdilpreet ddi_fm_handler_register(devi, pci_fm_callback, NULL); 2791865Sdilpreet } 2801865Sdilpreet 2810Sstevel@tonic-gate ddi_report_dev(devi); 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate return (DDI_SUCCESS); 284117Sschwartz 285117Sschwartz bad_pcitool_init: 286117Sschwartz (void) pcihp_uninit(devi); 287117Sschwartz bad_pcihp_init: 288117Sschwartz ddi_soft_state_free(pci_statep, instance); 289117Sschwartz bad_soft_state: 290117Sschwartz return (DDI_FAILURE); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate /*ARGSUSED*/ 2940Sstevel@tonic-gate static int 2950Sstevel@tonic-gate pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 2960Sstevel@tonic-gate { 297916Sschwartz int instance = ddi_get_instance(devi); 2981865Sdilpreet pci_state_t *pcip; 2991865Sdilpreet 3001865Sdilpreet pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(devi)); 3015295Srandyf 302916Sschwartz 3035295Srandyf switch (cmd) { 3045295Srandyf case DDI_DETACH: 3055295Srandyf if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) { 3065295Srandyf ddi_fm_handler_unregister(devi); 3075295Srandyf pci_ereport_teardown(devi); 3085295Srandyf } 3095295Srandyf mutex_destroy(&pcip->pci_peek_poke_mutex); 3105295Srandyf mutex_destroy(&pcip->pci_err_mutex); 31110923SEvan.Yan@Sun.COM mutex_destroy(&pcip->pci_mutex); 3125295Srandyf ddi_fm_fini(devi); /* Uninitialize pcitool support. */ 3135295Srandyf pcitool_uninit(devi); 314117Sschwartz 3155295Srandyf /* Uninitialize hotplug support on this bus. */ 3165295Srandyf (void) pcihp_uninit(devi); 3175295Srandyf 3185295Srandyf ddi_soft_state_free(pci_statep, instance); 319117Sschwartz 3205295Srandyf return (DDI_SUCCESS); 3215295Srandyf case DDI_SUSPEND: 3225295Srandyf return (DDI_SUCCESS); 3235295Srandyf default: 3245295Srandyf return (DDI_FAILURE); 3255295Srandyf } 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate static int 3290Sstevel@tonic-gate pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 3300Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 3310Sstevel@tonic-gate { 3320Sstevel@tonic-gate struct regspec reg; 3330Sstevel@tonic-gate ddi_map_req_t mr; 3340Sstevel@tonic-gate ddi_acc_hdl_t *hp; 335*11236SStephen.Hanson@Sun.COM ddi_acc_impl_t *hdlp; 3360Sstevel@tonic-gate pci_regspec_t pci_reg; 3370Sstevel@tonic-gate pci_regspec_t *pci_rp; 3380Sstevel@tonic-gate int rnumber; 3390Sstevel@tonic-gate int length; 3400Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 3410Sstevel@tonic-gate int space; 342*11236SStephen.Hanson@Sun.COM pci_state_t *pcip; 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate mr = *mp; /* Get private copy of request */ 3450Sstevel@tonic-gate mp = &mr; 3460Sstevel@tonic-gate 347*11236SStephen.Hanson@Sun.COM pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip)); 348*11236SStephen.Hanson@Sun.COM hdlp = (ddi_acc_impl_t *)(mp->map_handlep)->ah_platform_private; 349*11236SStephen.Hanson@Sun.COM hdlp->ahi_err_mutexp = &pcip->pci_err_mutex; 350*11236SStephen.Hanson@Sun.COM hdlp->ahi_peekpoke_mutexp = &pcip->pci_peek_poke_mutex; 351*11236SStephen.Hanson@Sun.COM hdlp->ahi_scan_dip = dip; 352*11236SStephen.Hanson@Sun.COM hdlp->ahi_scan = pci_peekpoke_cb; 353*11236SStephen.Hanson@Sun.COM 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * check for register number 3560Sstevel@tonic-gate */ 3570Sstevel@tonic-gate switch (mp->map_type) { 3580Sstevel@tonic-gate case DDI_MT_REGSPEC: 3590Sstevel@tonic-gate pci_reg = *(pci_regspec_t *)(mp->map_obj.rp); 3600Sstevel@tonic-gate pci_rp = &pci_reg; 361881Sjohnny if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 3620Sstevel@tonic-gate return (DDI_FAILURE); 3630Sstevel@tonic-gate break; 3640Sstevel@tonic-gate case DDI_MT_RNUMBER: 3650Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 3660Sstevel@tonic-gate /* 3670Sstevel@tonic-gate * get ALL "reg" properties for dip, select the one of 3680Sstevel@tonic-gate * of interest. In x86, "assigned-addresses" property 3690Sstevel@tonic-gate * is identical to the "reg" property, so there is no 3700Sstevel@tonic-gate * need to cross check the two to determine the physical 3710Sstevel@tonic-gate * address of the registers. 3720Sstevel@tonic-gate * This routine still performs some validity checks to 3730Sstevel@tonic-gate * make sure that everything is okay. 3740Sstevel@tonic-gate */ 375881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 376881Sjohnny DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 377881Sjohnny (uint_t *)&length) != DDI_PROP_SUCCESS) 3780Sstevel@tonic-gate return (DDI_FAILURE); 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate /* 3810Sstevel@tonic-gate * validate the register number. 3820Sstevel@tonic-gate */ 3830Sstevel@tonic-gate length /= (sizeof (pci_regspec_t) / sizeof (int)); 3840Sstevel@tonic-gate if (rnumber >= length) { 3850Sstevel@tonic-gate ddi_prop_free(pci_rp); 3860Sstevel@tonic-gate return (DDI_FAILURE); 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate /* 3900Sstevel@tonic-gate * copy the required entry. 3910Sstevel@tonic-gate */ 3920Sstevel@tonic-gate pci_reg = pci_rp[rnumber]; 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate /* 3950Sstevel@tonic-gate * free the memory allocated by ddi_prop_lookup_int_array 3960Sstevel@tonic-gate */ 3970Sstevel@tonic-gate ddi_prop_free(pci_rp); 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate pci_rp = &pci_reg; 400881Sjohnny if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 4010Sstevel@tonic-gate return (DDI_FAILURE); 4020Sstevel@tonic-gate mp->map_type = DDI_MT_REGSPEC; 4030Sstevel@tonic-gate break; 4040Sstevel@tonic-gate default: 4050Sstevel@tonic-gate return (DDI_ME_INVAL); 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate /* 4110Sstevel@tonic-gate * check for unmap and unlock of address space 4120Sstevel@tonic-gate */ 4130Sstevel@tonic-gate if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) { 4140Sstevel@tonic-gate /* 4150Sstevel@tonic-gate * Adjust offset and length 4160Sstevel@tonic-gate * A non-zero length means override the one in the regspec. 4170Sstevel@tonic-gate */ 4180Sstevel@tonic-gate pci_rp->pci_phys_low += (uint_t)offset; 4190Sstevel@tonic-gate if (len != 0) 4200Sstevel@tonic-gate pci_rp->pci_size_low = len; 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate switch (space) { 4230Sstevel@tonic-gate case PCI_ADDR_CONFIG: 4240Sstevel@tonic-gate /* No work required on unmap of Config space */ 4250Sstevel@tonic-gate return (DDI_SUCCESS); 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate case PCI_ADDR_IO: 4280Sstevel@tonic-gate reg.regspec_bustype = 1; 4290Sstevel@tonic-gate break; 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate case PCI_ADDR_MEM64: 4320Sstevel@tonic-gate /* 4330Sstevel@tonic-gate * MEM64 requires special treatment on map, to check 4340Sstevel@tonic-gate * that the device is below 4G. On unmap, however, 4350Sstevel@tonic-gate * we can assume that everything is OK... the map 4360Sstevel@tonic-gate * must have succeeded. 4370Sstevel@tonic-gate */ 4380Sstevel@tonic-gate /* FALLTHROUGH */ 4390Sstevel@tonic-gate case PCI_ADDR_MEM32: 4400Sstevel@tonic-gate reg.regspec_bustype = 0; 4410Sstevel@tonic-gate break; 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate default: 4440Sstevel@tonic-gate return (DDI_FAILURE); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate reg.regspec_addr = pci_rp->pci_phys_low; 4470Sstevel@tonic-gate reg.regspec_size = pci_rp->pci_size_low; 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate mp->map_obj.rp = ® 4500Sstevel@tonic-gate return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate /* check for user mapping request - not legal for Config */ 4550Sstevel@tonic-gate if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) { 4560Sstevel@tonic-gate return (DDI_FAILURE); 4570Sstevel@tonic-gate } 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate /* 4600Sstevel@tonic-gate * check for config space 4610Sstevel@tonic-gate * On x86, CONFIG is not mapped via MMU and there is 4620Sstevel@tonic-gate * no endian-ness issues. Set the attr field in the handle to 4630Sstevel@tonic-gate * indicate that the common routines to call the nexus driver. 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate if (space == PCI_ADDR_CONFIG) { 4661865Sdilpreet /* Can't map config space without a handle */ 4670Sstevel@tonic-gate hp = (ddi_acc_hdl_t *)mp->map_handlep; 468881Sjohnny if (hp == NULL) 4690Sstevel@tonic-gate return (DDI_FAILURE); 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* record the device address for future reference */ 4720Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private; 4730Sstevel@tonic-gate cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 4740Sstevel@tonic-gate cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 4750Sstevel@tonic-gate cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 4760Sstevel@tonic-gate 4771865Sdilpreet *vaddrp = (caddr_t)offset; 4781865Sdilpreet return (pci_fm_acc_setup(hp, offset, len)); 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate /* 4820Sstevel@tonic-gate * range check 4830Sstevel@tonic-gate */ 4840Sstevel@tonic-gate if ((offset >= pci_rp->pci_size_low) || 4850Sstevel@tonic-gate (len > pci_rp->pci_size_low) || 4860Sstevel@tonic-gate (offset + len > pci_rp->pci_size_low)) { 4870Sstevel@tonic-gate return (DDI_FAILURE); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate /* 4910Sstevel@tonic-gate * Adjust offset and length 4920Sstevel@tonic-gate * A non-zero length means override the one in the regspec. 4930Sstevel@tonic-gate */ 4940Sstevel@tonic-gate pci_rp->pci_phys_low += (uint_t)offset; 4950Sstevel@tonic-gate if (len != 0) 4960Sstevel@tonic-gate pci_rp->pci_size_low = len; 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate /* 4990Sstevel@tonic-gate * convert the pci regsec into the generic regspec used by the 5000Sstevel@tonic-gate * parent root nexus driver. 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate switch (space) { 5030Sstevel@tonic-gate case PCI_ADDR_IO: 5040Sstevel@tonic-gate reg.regspec_bustype = 1; 5050Sstevel@tonic-gate break; 5060Sstevel@tonic-gate case PCI_ADDR_MEM64: 5070Sstevel@tonic-gate /* 5080Sstevel@tonic-gate * We can't handle 64-bit devices that are mapped above 5090Sstevel@tonic-gate * 4G or that are larger than 4G. 5100Sstevel@tonic-gate */ 5110Sstevel@tonic-gate if (pci_rp->pci_phys_mid != 0 || 5120Sstevel@tonic-gate pci_rp->pci_size_hi != 0) 5130Sstevel@tonic-gate return (DDI_FAILURE); 5140Sstevel@tonic-gate /* 5150Sstevel@tonic-gate * Other than that, we can treat them as 32-bit mappings 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate /* FALLTHROUGH */ 5180Sstevel@tonic-gate case PCI_ADDR_MEM32: 5190Sstevel@tonic-gate reg.regspec_bustype = 0; 5200Sstevel@tonic-gate break; 5210Sstevel@tonic-gate default: 5220Sstevel@tonic-gate return (DDI_FAILURE); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate reg.regspec_addr = pci_rp->pci_phys_low; 5250Sstevel@tonic-gate reg.regspec_size = pci_rp->pci_size_low; 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate mp->map_obj.rp = ® 5280Sstevel@tonic-gate return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate /*ARGSUSED*/ 5330Sstevel@tonic-gate static int 5340Sstevel@tonic-gate pci_ctlops(dev_info_t *dip, dev_info_t *rdip, 5350Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 5360Sstevel@tonic-gate { 5370Sstevel@tonic-gate pci_regspec_t *drv_regp; 5380Sstevel@tonic-gate uint_t reglen; 5390Sstevel@tonic-gate int rn; 5400Sstevel@tonic-gate int totreg; 5411865Sdilpreet pci_state_t *pcip; 5425295Srandyf struct attachspec *asp; 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate switch (ctlop) { 5450Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 5460Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 5470Sstevel@tonic-gate return (DDI_FAILURE); 5480Sstevel@tonic-gate cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", 5490Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip), 5500Sstevel@tonic-gate ddi_driver_name(rdip), 5510Sstevel@tonic-gate ddi_get_instance(rdip)); 5520Sstevel@tonic-gate return (DDI_SUCCESS); 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 5550Sstevel@tonic-gate return (pci_initchild((dev_info_t *)arg)); 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 5580Sstevel@tonic-gate return (pci_removechild((dev_info_t *)arg)); 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 5610Sstevel@tonic-gate return (DDI_SUCCESS); 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 5640Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 5650Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 5660Sstevel@tonic-gate return (DDI_FAILURE); 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate *(int *)result = 0; 5690Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 5705295Srandyf DDI_PROP_DONTPASS, "reg", (int **)&drv_regp, 5715295Srandyf ®len) != DDI_PROP_SUCCESS) { 5720Sstevel@tonic-gate return (DDI_FAILURE); 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t); 5760Sstevel@tonic-gate if (ctlop == DDI_CTLOPS_NREGS) 5770Sstevel@tonic-gate *(int *)result = totreg; 5780Sstevel@tonic-gate else if (ctlop == DDI_CTLOPS_REGSIZE) { 5790Sstevel@tonic-gate rn = *(int *)arg; 5800Sstevel@tonic-gate if (rn >= totreg) { 5810Sstevel@tonic-gate ddi_prop_free(drv_regp); 5820Sstevel@tonic-gate return (DDI_FAILURE); 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate *(off_t *)result = drv_regp[rn].pci_size_low; 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate ddi_prop_free(drv_regp); 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate return (DDI_SUCCESS); 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate case DDI_CTLOPS_POWER: { 5910Sstevel@tonic-gate power_req_t *reqp = (power_req_t *)arg; 5920Sstevel@tonic-gate /* 5930Sstevel@tonic-gate * We currently understand reporting of PCI_PM_IDLESPEED 5940Sstevel@tonic-gate * capability. Everything else is passed up. 5950Sstevel@tonic-gate */ 5960Sstevel@tonic-gate if ((reqp->request_type == PMR_REPORT_PMCAP) && 5970Sstevel@tonic-gate (reqp->req.report_pmcap_req.cap == PCI_PM_IDLESPEED)) { 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate return (DDI_SUCCESS); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate 6041865Sdilpreet case DDI_CTLOPS_PEEK: 6051865Sdilpreet case DDI_CTLOPS_POKE: 6061865Sdilpreet pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip)); 6071865Sdilpreet return (pci_peekpoke_check(dip, rdip, ctlop, arg, result, 6081865Sdilpreet pci_common_peekpoke, &pcip->pci_err_mutex, 6096313Skrishnae &pcip->pci_peek_poke_mutex, pci_peekpoke_cb)); 6101865Sdilpreet 6115295Srandyf /* for now only X86 systems support PME wakeup from suspended state */ 6125295Srandyf case DDI_CTLOPS_ATTACH: 6135295Srandyf asp = (struct attachspec *)arg; 6145295Srandyf if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE) 6155295Srandyf if (pci_pre_resume(rdip) != DDI_SUCCESS) 6165295Srandyf return (DDI_FAILURE); 6175295Srandyf return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6185295Srandyf 6195295Srandyf case DDI_CTLOPS_DETACH: 6205295Srandyf asp = (struct attachspec *)arg; 6215295Srandyf if (asp->cmd == DDI_SUSPEND && asp->when == DDI_POST) 6225295Srandyf if (pci_post_suspend(rdip) != DDI_SUCCESS) 6235295Srandyf return (DDI_FAILURE); 6245295Srandyf return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6255295Srandyf 6260Sstevel@tonic-gate default: 6270Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate /* NOTREACHED */ 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate /* 635881Sjohnny * pci_intr_ops 6360Sstevel@tonic-gate */ 6370Sstevel@tonic-gate static int 638881Sjohnny pci_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 639881Sjohnny ddi_intr_handle_impl_t *hdlp, void *result) 6400Sstevel@tonic-gate { 641881Sjohnny return (pci_common_intr_ops(pdip, rdip, intr_op, hdlp, result)); 642881Sjohnny } 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate static int 6460Sstevel@tonic-gate pci_initchild(dev_info_t *child) 6470Sstevel@tonic-gate { 6480Sstevel@tonic-gate char name[80]; 649354Smyers ddi_acc_handle_t config_handle; 650354Smyers ushort_t command_preserve, command; 6510Sstevel@tonic-gate 652881Sjohnny if (pci_common_name_child(child, name, 80) != DDI_SUCCESS) { 6530Sstevel@tonic-gate return (DDI_FAILURE); 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate ddi_set_name_addr(child, name); 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate /* 6580Sstevel@tonic-gate * Pseudo nodes indicate a prototype node with per-instance 6590Sstevel@tonic-gate * properties to be merged into the real h/w device node. 6600Sstevel@tonic-gate * The interpretation of the unit-address is DD[,F] 6610Sstevel@tonic-gate * where DD is the device id and F is the function. 6620Sstevel@tonic-gate */ 6630Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 6640Sstevel@tonic-gate extern int pci_allow_pseudo_children; 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate /* 6690Sstevel@tonic-gate * Try to merge the properties from this prototype 6700Sstevel@tonic-gate * node into real h/w nodes. 6710Sstevel@tonic-gate */ 672881Sjohnny if (ndi_merge_node(child, pci_common_name_child) == 673881Sjohnny DDI_SUCCESS) { 6740Sstevel@tonic-gate /* 6750Sstevel@tonic-gate * Merged ok - return failure to remove the node. 6760Sstevel@tonic-gate */ 6770Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 6780Sstevel@tonic-gate return (DDI_FAILURE); 6790Sstevel@tonic-gate } 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate /* workaround for ddivs to run under PCI */ 6820Sstevel@tonic-gate if (pci_allow_pseudo_children) { 6830Sstevel@tonic-gate /* 6840Sstevel@tonic-gate * If the "interrupts" property doesn't exist, 6850Sstevel@tonic-gate * this must be the ddivs no-intr case, and it returns 6860Sstevel@tonic-gate * DDI_SUCCESS instead of DDI_FAILURE. 6870Sstevel@tonic-gate */ 6880Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, child, 6890Sstevel@tonic-gate DDI_PROP_DONTPASS, "interrupts", -1) == -1) 6900Sstevel@tonic-gate return (DDI_SUCCESS); 6910Sstevel@tonic-gate /* 6920Sstevel@tonic-gate * Create the ddi_parent_private_data for a pseudo 6930Sstevel@tonic-gate * child. 6940Sstevel@tonic-gate */ 695881Sjohnny pci_common_set_parent_private_data(child); 6960Sstevel@tonic-gate return (DDI_SUCCESS); 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate /* 7000Sstevel@tonic-gate * The child was not merged into a h/w node, 7010Sstevel@tonic-gate * but there's not much we can do with it other 7020Sstevel@tonic-gate * than return failure to cause the node to be removed. 7030Sstevel@tonic-gate */ 7040Sstevel@tonic-gate cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 7050Sstevel@tonic-gate ddi_get_name(child), ddi_get_name_addr(child), 7060Sstevel@tonic-gate ddi_get_name(child)); 7070Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 7080Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 712881Sjohnny "interrupts", -1) != -1) 713881Sjohnny pci_common_set_parent_private_data(child); 714881Sjohnny else 7150Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 7160Sstevel@tonic-gate 717354Smyers /* 718354Smyers * initialize command register 719354Smyers */ 720354Smyers if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) 721354Smyers return (DDI_FAILURE); 722354Smyers 723354Smyers /* 724354Smyers * Support for the "command-preserve" property. 725354Smyers */ 726354Smyers command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child, 7275295Srandyf DDI_PROP_DONTPASS, "command-preserve", 0); 728354Smyers command = pci_config_get16(config_handle, PCI_CONF_COMM); 729354Smyers command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB); 730354Smyers command |= (pci_command_default & ~command_preserve); 731354Smyers pci_config_put16(config_handle, PCI_CONF_COMM, command); 732354Smyers 733354Smyers pci_config_teardown(&config_handle); 7340Sstevel@tonic-gate return (DDI_SUCCESS); 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate static int 7380Sstevel@tonic-gate pci_removechild(dev_info_t *dip) 7390Sstevel@tonic-gate { 7400Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate if ((pdptr = ddi_get_parent_data(dip)) != NULL) { 7430Sstevel@tonic-gate kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec))); 7440Sstevel@tonic-gate ddi_set_parent_data(dip, NULL); 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate /* 7490Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 7500Sstevel@tonic-gate */ 7510Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate impl_rem_dev_props(dip); 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate return (DDI_SUCCESS); 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate /* 7600Sstevel@tonic-gate * When retrofitting this module for pci_tools, functions such as open, close, 7610Sstevel@tonic-gate * and ioctl are now pulled into this module. Before this, the functions in 7620Sstevel@tonic-gate * the pcihp module were referenced directly. Now they are called or 7630Sstevel@tonic-gate * referenced through the pcihp cb_ops structure from functions in this module. 7640Sstevel@tonic-gate */ 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate static int 7670Sstevel@tonic-gate pci_open(dev_t *devp, int flags, int otyp, cred_t *credp) 7680Sstevel@tonic-gate { 769881Sjohnny return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp)); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate static int 7730Sstevel@tonic-gate pci_close(dev_t dev, int flags, int otyp, cred_t *credp) 7740Sstevel@tonic-gate { 775881Sjohnny return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp)); 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate static int 779881Sjohnny pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 7800Sstevel@tonic-gate { 781777Sschwartz minor_t minor = getminor(dev); 78210923SEvan.Yan@Sun.COM int instance = PCI_MINOR_NUM_TO_INSTANCE(minor); 783777Sschwartz pci_state_t *pci_p = ddi_get_soft_state(pci_statep, instance); 78410923SEvan.Yan@Sun.COM int ret = ENOTTY; 7850Sstevel@tonic-gate 786881Sjohnny if (pci_p == NULL) 787881Sjohnny return (ENXIO); 788117Sschwartz 78910923SEvan.Yan@Sun.COM switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 79010923SEvan.Yan@Sun.COM case PCI_TOOL_REG_MINOR_NUM: 79110923SEvan.Yan@Sun.COM case PCI_TOOL_INTR_MINOR_NUM: 79210923SEvan.Yan@Sun.COM /* To handle pcitool related ioctls */ 79310923SEvan.Yan@Sun.COM ret = pci_common_ioctl(pci_p->pci_dip, dev, cmd, arg, mode, 79410923SEvan.Yan@Sun.COM credp, rvalp); 79510923SEvan.Yan@Sun.COM break; 79610923SEvan.Yan@Sun.COM default: 79710923SEvan.Yan@Sun.COM /* To handle devctl and hotplug related ioctls */ 79810923SEvan.Yan@Sun.COM ret = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, 79910923SEvan.Yan@Sun.COM credp, rvalp); 80010923SEvan.Yan@Sun.COM break; 80110923SEvan.Yan@Sun.COM } 80210923SEvan.Yan@Sun.COM 80310923SEvan.Yan@Sun.COM return (ret); 804881Sjohnny } 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate static int 8080Sstevel@tonic-gate pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 809117Sschwartz int flags, char *name, caddr_t valuep, int *lengthp) 8100Sstevel@tonic-gate { 811881Sjohnny return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags, 8120Sstevel@tonic-gate name, valuep, lengthp)); 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate 8150Sstevel@tonic-gate static int 8160Sstevel@tonic-gate pci_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 8170Sstevel@tonic-gate { 8180Sstevel@tonic-gate return (pcihp_info(dip, cmd, arg, result)); 8190Sstevel@tonic-gate } 8201865Sdilpreet 8216313Skrishnae void pci_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) { 8226313Skrishnae (void) pci_ereport_post(dip, derr, NULL); 8236313Skrishnae } 8246313Skrishnae 8251865Sdilpreet /*ARGSUSED*/ 8261865Sdilpreet static int 8271865Sdilpreet pci_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap, 8281865Sdilpreet ddi_iblock_cookie_t *ibc) 8291865Sdilpreet { 8301865Sdilpreet pci_state_t *pcip = ddi_get_soft_state(pci_statep, 8311865Sdilpreet ddi_get_instance(dip)); 8321865Sdilpreet 8331865Sdilpreet ASSERT(ibc != NULL); 8341865Sdilpreet *ibc = pcip->pci_fm_ibc; 8351865Sdilpreet 8361865Sdilpreet return (pcip->pci_fmcap); 8371865Sdilpreet } 8381865Sdilpreet 8391865Sdilpreet /*ARGSUSED*/ 8401865Sdilpreet static int 8411865Sdilpreet pci_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used) 8421865Sdilpreet { 8431865Sdilpreet pci_state_t *pcip = ddi_get_soft_state(pci_statep, 8441865Sdilpreet ddi_get_instance(dip)); 8451865Sdilpreet 8461865Sdilpreet mutex_enter(&pcip->pci_err_mutex); 8471865Sdilpreet pci_ereport_post(dip, derr, NULL); 8481865Sdilpreet mutex_exit(&pcip->pci_err_mutex); 8491865Sdilpreet return (derr->fme_status); 8501865Sdilpreet } 851