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 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * Host to PCI local bus driver 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/conf.h> 340Sstevel@tonic-gate #include <sys/modctl.h> 350Sstevel@tonic-gate #include <sys/pci.h> 360Sstevel@tonic-gate #include <sys/pci_impl.h> 37*881Sjohnny #include <sys/sysmacros.h> 380Sstevel@tonic-gate #include <sys/sunndi.h> 390Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h> 400Sstevel@tonic-gate #include <sys/pci_cfgspace.h> 41*881Sjohnny #include <io/pci/pci_common.h> 42*881Sjohnny #include <io/pci/pci_tools_ext.h> 43*881Sjohnny #include <io/pci/pci_var.h> 440Sstevel@tonic-gate 450Sstevel@tonic-gate /* Save minimal state. */ 460Sstevel@tonic-gate void *pci_statep; 470Sstevel@tonic-gate 480Sstevel@tonic-gate /* 490Sstevel@tonic-gate * Bus Operation functions 500Sstevel@tonic-gate */ 510Sstevel@tonic-gate static int pci_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 520Sstevel@tonic-gate off_t, off_t, caddr_t *); 530Sstevel@tonic-gate static int pci_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 540Sstevel@tonic-gate void *, void *); 550Sstevel@tonic-gate static int pci_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 560Sstevel@tonic-gate ddi_intr_handle_impl_t *, void *); 570Sstevel@tonic-gate 580Sstevel@tonic-gate struct bus_ops pci_bus_ops = { 590Sstevel@tonic-gate BUSO_REV, 600Sstevel@tonic-gate pci_bus_map, 610Sstevel@tonic-gate NULL, 620Sstevel@tonic-gate NULL, 630Sstevel@tonic-gate NULL, 640Sstevel@tonic-gate i_ddi_map_fault, 650Sstevel@tonic-gate ddi_dma_map, 660Sstevel@tonic-gate ddi_dma_allochdl, 670Sstevel@tonic-gate ddi_dma_freehdl, 680Sstevel@tonic-gate ddi_dma_bindhdl, 690Sstevel@tonic-gate ddi_dma_unbindhdl, 700Sstevel@tonic-gate ddi_dma_flush, 710Sstevel@tonic-gate ddi_dma_win, 720Sstevel@tonic-gate ddi_dma_mctl, 730Sstevel@tonic-gate pci_ctlops, 740Sstevel@tonic-gate ddi_bus_prop_op, 750Sstevel@tonic-gate 0, /* (*bus_get_eventcookie)(); */ 760Sstevel@tonic-gate 0, /* (*bus_add_eventcall)(); */ 770Sstevel@tonic-gate 0, /* (*bus_remove_eventcall)(); */ 780Sstevel@tonic-gate 0, /* (*bus_post_event)(); */ 790Sstevel@tonic-gate 0, /* (*bus_intr_ctl)(); */ 800Sstevel@tonic-gate 0, /* (*bus_config)(); */ 810Sstevel@tonic-gate 0, /* (*bus_unconfig)(); */ 820Sstevel@tonic-gate NULL, /* (*bus_fm_init)(); */ 830Sstevel@tonic-gate NULL, /* (*bus_fm_fini)(); */ 840Sstevel@tonic-gate NULL, /* (*bus_fm_access_enter)(); */ 850Sstevel@tonic-gate NULL, /* (*bus_fm_access_exit)(); */ 860Sstevel@tonic-gate NULL, /* (*bus_power)(); */ 870Sstevel@tonic-gate pci_intr_ops /* (*bus_intr_op)(); */ 880Sstevel@tonic-gate }; 890Sstevel@tonic-gate 900Sstevel@tonic-gate /* 910Sstevel@tonic-gate * One goal here is to leverage off of the pcihp.c source without making 920Sstevel@tonic-gate * changes to it. Call into it's cb_ops directly if needed, piggybacking 930Sstevel@tonic-gate * anything else needed by the pci_tools.c module. Only pci_tools and pcihp 94117Sschwartz * will be opening PCI nexus driver file descriptors. 950Sstevel@tonic-gate */ 96*881Sjohnny static int pci_open(dev_t *, int, int, cred_t *); 97*881Sjohnny static int pci_close(dev_t, int, int, cred_t *); 98*881Sjohnny static int pci_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 99*881Sjohnny static int pci_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, 100*881Sjohnny caddr_t, int *); 101*881Sjohnny static int pci_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate struct cb_ops pci_cb_ops = { 1040Sstevel@tonic-gate pci_open, /* open */ 1050Sstevel@tonic-gate pci_close, /* close */ 1060Sstevel@tonic-gate nodev, /* strategy */ 1070Sstevel@tonic-gate nodev, /* print */ 1080Sstevel@tonic-gate nodev, /* dump */ 1090Sstevel@tonic-gate nodev, /* read */ 1100Sstevel@tonic-gate nodev, /* write */ 1110Sstevel@tonic-gate pci_ioctl, /* ioctl */ 1120Sstevel@tonic-gate nodev, /* devmap */ 1130Sstevel@tonic-gate nodev, /* mmap */ 1140Sstevel@tonic-gate nodev, /* segmap */ 1150Sstevel@tonic-gate nochpoll, /* poll */ 1160Sstevel@tonic-gate pci_prop_op, /* cb_prop_op */ 1170Sstevel@tonic-gate NULL, /* streamtab */ 1180Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 1190Sstevel@tonic-gate CB_REV, /* rev */ 1200Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 1210Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 1220Sstevel@tonic-gate }; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate /* 1250Sstevel@tonic-gate * Device Node Operation functions 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate static int pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 1280Sstevel@tonic-gate static int pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate struct dev_ops pci_ops = { 1310Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 1320Sstevel@tonic-gate 0, /* refcnt */ 1330Sstevel@tonic-gate pci_info, /* info */ 1340Sstevel@tonic-gate nulldev, /* identify */ 1350Sstevel@tonic-gate nulldev, /* probe */ 1360Sstevel@tonic-gate pci_attach, /* attach */ 1370Sstevel@tonic-gate pci_detach, /* detach */ 1380Sstevel@tonic-gate nulldev, /* reset */ 1390Sstevel@tonic-gate &pci_cb_ops, /* driver operations */ 1400Sstevel@tonic-gate &pci_bus_ops /* bus operations */ 1410Sstevel@tonic-gate }; 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate /* 144354Smyers * This variable controls the default setting of the command register 145354Smyers * for pci devices. See pci_initchild() for details. 146354Smyers */ 147354Smyers static ushort_t pci_command_default = PCI_COMM_ME | 148354Smyers PCI_COMM_MAE | 149354Smyers PCI_COMM_IO; 150354Smyers 151354Smyers /* 1520Sstevel@tonic-gate * Internal routines in support of particular pci_ctlops. 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate static int pci_removechild(dev_info_t *child); 1550Sstevel@tonic-gate static int pci_initchild(dev_info_t *child); 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate /* 1580Sstevel@tonic-gate * These are the access routines. The pci_bus_map sets the handle 1590Sstevel@tonic-gate * to point to these. 1600Sstevel@tonic-gate */ 1610Sstevel@tonic-gate static uint8_t pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr); 1620Sstevel@tonic-gate static uint16_t pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr); 1630Sstevel@tonic-gate static uint32_t pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr); 1640Sstevel@tonic-gate static uint64_t pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr); 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate static void pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, 1670Sstevel@tonic-gate uint8_t value); 1680Sstevel@tonic-gate static void pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, 1690Sstevel@tonic-gate uint16_t value); 1700Sstevel@tonic-gate static void pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, 1710Sstevel@tonic-gate uint32_t value); 1720Sstevel@tonic-gate static void pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, 1730Sstevel@tonic-gate uint64_t value); 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate static void pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 1760Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags); 1770Sstevel@tonic-gate static void pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1780Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags); 1790Sstevel@tonic-gate static void pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1800Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags); 1810Sstevel@tonic-gate static void pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1820Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate static void pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 1850Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags); 1860Sstevel@tonic-gate static void pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1870Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags); 1880Sstevel@tonic-gate static void pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1890Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags); 1900Sstevel@tonic-gate static void pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1910Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags); 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate /* 1940Sstevel@tonic-gate * Module linkage information for the kernel. 1950Sstevel@tonic-gate */ 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate static struct modldrv modldrv = { 1980Sstevel@tonic-gate &mod_driverops, /* Type of module */ 1990Sstevel@tonic-gate "host to PCI nexus driver %I%", 2000Sstevel@tonic-gate &pci_ops, /* driver ops */ 2010Sstevel@tonic-gate }; 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate static struct modlinkage modlinkage = { 2040Sstevel@tonic-gate MODREV_1, 2050Sstevel@tonic-gate (void *)&modldrv, 2060Sstevel@tonic-gate NULL 2070Sstevel@tonic-gate }; 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate int 2100Sstevel@tonic-gate _init(void) 2110Sstevel@tonic-gate { 2120Sstevel@tonic-gate int e; 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate /* 2150Sstevel@tonic-gate * Initialize per-pci bus soft state pointer. 2160Sstevel@tonic-gate */ 2170Sstevel@tonic-gate e = ddi_soft_state_init(&pci_statep, sizeof (pci_state_t), 1); 2180Sstevel@tonic-gate if (e != 0) 2190Sstevel@tonic-gate return (e); 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) 2220Sstevel@tonic-gate ddi_soft_state_fini(&pci_statep); 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate return (e); 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate int 2280Sstevel@tonic-gate _fini(void) 2290Sstevel@tonic-gate { 2300Sstevel@tonic-gate int rc; 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate rc = mod_remove(&modlinkage); 2330Sstevel@tonic-gate if (rc != 0) 2340Sstevel@tonic-gate return (rc); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate ddi_soft_state_fini(&pci_statep); 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate return (rc); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate int 2420Sstevel@tonic-gate _info(struct modinfo *modinfop) 2430Sstevel@tonic-gate { 2440Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate /*ARGSUSED*/ 2480Sstevel@tonic-gate static int 2490Sstevel@tonic-gate pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2500Sstevel@tonic-gate { 2510Sstevel@tonic-gate /* 2520Sstevel@tonic-gate * Use the minor number as constructed by pcihp, as the index value to 2530Sstevel@tonic-gate * ddi_soft_state_zalloc. 2540Sstevel@tonic-gate */ 255117Sschwartz int instance = ddi_get_instance(devi); 2560Sstevel@tonic-gate pci_state_t *pcip = NULL; 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci") 2590Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 2600Sstevel@tonic-gate cmn_err(CE_WARN, "pci: 'device_type' prop create failed"); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate 263117Sschwartz if (ddi_soft_state_zalloc(pci_statep, instance) == DDI_SUCCESS) { 264117Sschwartz pcip = ddi_get_soft_state(pci_statep, instance); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate if (pcip == NULL) { 268117Sschwartz goto bad_soft_state; 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate pcip->pci_dip = devi; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* 2740Sstevel@tonic-gate * Initialize hotplug support on this bus. At minimum 2750Sstevel@tonic-gate * (for non hotplug bus) this would create ":devctl" minor 2760Sstevel@tonic-gate * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls 2770Sstevel@tonic-gate * to this bus. 2780Sstevel@tonic-gate */ 2790Sstevel@tonic-gate if (pcihp_init(devi) != DDI_SUCCESS) { 2800Sstevel@tonic-gate cmn_err(CE_WARN, "pci: Failed to setup hotplug framework"); 281117Sschwartz goto bad_pcihp_init; 282117Sschwartz } 283117Sschwartz 284777Sschwartz /* Second arg: initialize for pci, not pci_express */ 285777Sschwartz if (pcitool_init(devi, B_FALSE) != DDI_SUCCESS) { 286117Sschwartz goto bad_pcitool_init; 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate ddi_report_dev(devi); 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate return (DDI_SUCCESS); 292117Sschwartz 293117Sschwartz bad_pcitool_init: 294117Sschwartz (void) pcihp_uninit(devi); 295117Sschwartz bad_pcihp_init: 296117Sschwartz ddi_soft_state_free(pci_statep, instance); 297117Sschwartz bad_soft_state: 298117Sschwartz return (DDI_FAILURE); 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate /*ARGSUSED*/ 3020Sstevel@tonic-gate static int 3030Sstevel@tonic-gate pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 3040Sstevel@tonic-gate { 305117Sschwartz /* Uninitialize pcitool support. */ 306117Sschwartz pcitool_uninit(devi); 307117Sschwartz 308117Sschwartz /* Uninitialize hotplug support on this bus. */ 3090Sstevel@tonic-gate (void) pcihp_uninit(devi); 310117Sschwartz 3110Sstevel@tonic-gate ddi_soft_state_free(pci_statep, DIP_TO_MINOR(devi)); 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate return (DDI_SUCCESS); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate static int 3170Sstevel@tonic-gate pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 3180Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 3190Sstevel@tonic-gate { 3200Sstevel@tonic-gate struct regspec reg; 3210Sstevel@tonic-gate ddi_map_req_t mr; 3220Sstevel@tonic-gate ddi_acc_hdl_t *hp; 3230Sstevel@tonic-gate ddi_acc_impl_t *ap; 3240Sstevel@tonic-gate pci_regspec_t pci_reg; 3250Sstevel@tonic-gate pci_regspec_t *pci_rp; 3260Sstevel@tonic-gate int rnumber; 3270Sstevel@tonic-gate int length; 3280Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 3290Sstevel@tonic-gate int space; 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate mr = *mp; /* Get private copy of request */ 3330Sstevel@tonic-gate mp = &mr; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * check for register number 3370Sstevel@tonic-gate */ 3380Sstevel@tonic-gate switch (mp->map_type) { 3390Sstevel@tonic-gate case DDI_MT_REGSPEC: 3400Sstevel@tonic-gate pci_reg = *(pci_regspec_t *)(mp->map_obj.rp); 3410Sstevel@tonic-gate pci_rp = &pci_reg; 342*881Sjohnny if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 3430Sstevel@tonic-gate return (DDI_FAILURE); 3440Sstevel@tonic-gate break; 3450Sstevel@tonic-gate case DDI_MT_RNUMBER: 3460Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 3470Sstevel@tonic-gate /* 3480Sstevel@tonic-gate * get ALL "reg" properties for dip, select the one of 3490Sstevel@tonic-gate * of interest. In x86, "assigned-addresses" property 3500Sstevel@tonic-gate * is identical to the "reg" property, so there is no 3510Sstevel@tonic-gate * need to cross check the two to determine the physical 3520Sstevel@tonic-gate * address of the registers. 3530Sstevel@tonic-gate * This routine still performs some validity checks to 3540Sstevel@tonic-gate * make sure that everything is okay. 3550Sstevel@tonic-gate */ 356*881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 357*881Sjohnny DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 358*881Sjohnny (uint_t *)&length) != DDI_PROP_SUCCESS) 3590Sstevel@tonic-gate return (DDI_FAILURE); 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate /* 3620Sstevel@tonic-gate * validate the register number. 3630Sstevel@tonic-gate */ 3640Sstevel@tonic-gate length /= (sizeof (pci_regspec_t) / sizeof (int)); 3650Sstevel@tonic-gate if (rnumber >= length) { 3660Sstevel@tonic-gate ddi_prop_free(pci_rp); 3670Sstevel@tonic-gate return (DDI_FAILURE); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate /* 3710Sstevel@tonic-gate * copy the required entry. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate pci_reg = pci_rp[rnumber]; 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate /* 3760Sstevel@tonic-gate * free the memory allocated by ddi_prop_lookup_int_array 3770Sstevel@tonic-gate */ 3780Sstevel@tonic-gate ddi_prop_free(pci_rp); 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate pci_rp = &pci_reg; 381*881Sjohnny if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 3820Sstevel@tonic-gate return (DDI_FAILURE); 3830Sstevel@tonic-gate mp->map_type = DDI_MT_REGSPEC; 3840Sstevel@tonic-gate break; 3850Sstevel@tonic-gate default: 3860Sstevel@tonic-gate return (DDI_ME_INVAL); 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M; 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate /* 3920Sstevel@tonic-gate * check for unmap and unlock of address space 3930Sstevel@tonic-gate */ 3940Sstevel@tonic-gate if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) { 3950Sstevel@tonic-gate /* 3960Sstevel@tonic-gate * Adjust offset and length 3970Sstevel@tonic-gate * A non-zero length means override the one in the regspec. 3980Sstevel@tonic-gate */ 3990Sstevel@tonic-gate pci_rp->pci_phys_low += (uint_t)offset; 4000Sstevel@tonic-gate if (len != 0) 4010Sstevel@tonic-gate pci_rp->pci_size_low = len; 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate switch (space) { 4040Sstevel@tonic-gate case PCI_ADDR_CONFIG: 4050Sstevel@tonic-gate /* No work required on unmap of Config space */ 4060Sstevel@tonic-gate return (DDI_SUCCESS); 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate case PCI_ADDR_IO: 4090Sstevel@tonic-gate reg.regspec_bustype = 1; 4100Sstevel@tonic-gate break; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate case PCI_ADDR_MEM64: 4130Sstevel@tonic-gate /* 4140Sstevel@tonic-gate * MEM64 requires special treatment on map, to check 4150Sstevel@tonic-gate * that the device is below 4G. On unmap, however, 4160Sstevel@tonic-gate * we can assume that everything is OK... the map 4170Sstevel@tonic-gate * must have succeeded. 4180Sstevel@tonic-gate */ 4190Sstevel@tonic-gate /* FALLTHROUGH */ 4200Sstevel@tonic-gate case PCI_ADDR_MEM32: 4210Sstevel@tonic-gate reg.regspec_bustype = 0; 4220Sstevel@tonic-gate break; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate default: 4250Sstevel@tonic-gate return (DDI_FAILURE); 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate reg.regspec_addr = pci_rp->pci_phys_low; 4280Sstevel@tonic-gate reg.regspec_size = pci_rp->pci_size_low; 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate mp->map_obj.rp = ® 4310Sstevel@tonic-gate return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate /* check for user mapping request - not legal for Config */ 4360Sstevel@tonic-gate if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) { 4370Sstevel@tonic-gate return (DDI_FAILURE); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate /* 4410Sstevel@tonic-gate * check for config space 4420Sstevel@tonic-gate * On x86, CONFIG is not mapped via MMU and there is 4430Sstevel@tonic-gate * no endian-ness issues. Set the attr field in the handle to 4440Sstevel@tonic-gate * indicate that the common routines to call the nexus driver. 4450Sstevel@tonic-gate */ 4460Sstevel@tonic-gate if (space == PCI_ADDR_CONFIG) { 4470Sstevel@tonic-gate hp = (ddi_acc_hdl_t *)mp->map_handlep; 4480Sstevel@tonic-gate 449*881Sjohnny /* Can't map config space without a handle */ 450*881Sjohnny if (hp == NULL) 4510Sstevel@tonic-gate return (DDI_FAILURE); 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate ap = (ddi_acc_impl_t *)hp->ah_platform_private; 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* endian-ness check */ 4560Sstevel@tonic-gate if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 4570Sstevel@tonic-gate return (DDI_FAILURE); 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate /* 4600Sstevel@tonic-gate * range check 4610Sstevel@tonic-gate */ 4620Sstevel@tonic-gate if ((offset >= 256) || (len > 256) || (offset + len > 256)) 4630Sstevel@tonic-gate return (DDI_FAILURE); 4640Sstevel@tonic-gate *vaddrp = (caddr_t)offset; 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 4670Sstevel@tonic-gate ap->ahi_put8 = pci_config_wr8; 4680Sstevel@tonic-gate ap->ahi_get8 = pci_config_rd8; 4690Sstevel@tonic-gate ap->ahi_put64 = pci_config_wr64; 4700Sstevel@tonic-gate ap->ahi_get64 = pci_config_rd64; 4710Sstevel@tonic-gate ap->ahi_rep_put8 = pci_config_rep_wr8; 4720Sstevel@tonic-gate ap->ahi_rep_get8 = pci_config_rep_rd8; 4730Sstevel@tonic-gate ap->ahi_rep_put64 = pci_config_rep_wr64; 4740Sstevel@tonic-gate ap->ahi_rep_get64 = pci_config_rep_rd64; 4750Sstevel@tonic-gate ap->ahi_get16 = pci_config_rd16; 4760Sstevel@tonic-gate ap->ahi_get32 = pci_config_rd32; 4770Sstevel@tonic-gate ap->ahi_put16 = pci_config_wr16; 4780Sstevel@tonic-gate ap->ahi_put32 = pci_config_wr32; 4790Sstevel@tonic-gate ap->ahi_rep_get16 = pci_config_rep_rd16; 4800Sstevel@tonic-gate ap->ahi_rep_get32 = pci_config_rep_rd32; 4810Sstevel@tonic-gate ap->ahi_rep_put16 = pci_config_rep_wr16; 4820Sstevel@tonic-gate ap->ahi_rep_put32 = pci_config_rep_wr32; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate /* Initialize to default check/notify functions */ 4850Sstevel@tonic-gate ap->ahi_fault_check = i_ddi_acc_fault_check; 4860Sstevel@tonic-gate ap->ahi_fault_notify = i_ddi_acc_fault_notify; 4870Sstevel@tonic-gate ap->ahi_fault = 0; 4880Sstevel@tonic-gate impl_acc_err_init(hp); 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate /* record the device address for future reference */ 4910Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private; 4920Sstevel@tonic-gate cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 4930Sstevel@tonic-gate cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 4940Sstevel@tonic-gate cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate return (DDI_SUCCESS); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* 5000Sstevel@tonic-gate * range check 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate if ((offset >= pci_rp->pci_size_low) || 5030Sstevel@tonic-gate (len > pci_rp->pci_size_low) || 5040Sstevel@tonic-gate (offset + len > pci_rp->pci_size_low)) { 5050Sstevel@tonic-gate return (DDI_FAILURE); 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate /* 5090Sstevel@tonic-gate * Adjust offset and length 5100Sstevel@tonic-gate * A non-zero length means override the one in the regspec. 5110Sstevel@tonic-gate */ 5120Sstevel@tonic-gate pci_rp->pci_phys_low += (uint_t)offset; 5130Sstevel@tonic-gate if (len != 0) 5140Sstevel@tonic-gate pci_rp->pci_size_low = len; 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate /* 5170Sstevel@tonic-gate * convert the pci regsec into the generic regspec used by the 5180Sstevel@tonic-gate * parent root nexus driver. 5190Sstevel@tonic-gate */ 5200Sstevel@tonic-gate switch (space) { 5210Sstevel@tonic-gate case PCI_ADDR_IO: 5220Sstevel@tonic-gate reg.regspec_bustype = 1; 5230Sstevel@tonic-gate break; 5240Sstevel@tonic-gate case PCI_ADDR_MEM64: 5250Sstevel@tonic-gate /* 5260Sstevel@tonic-gate * We can't handle 64-bit devices that are mapped above 5270Sstevel@tonic-gate * 4G or that are larger than 4G. 5280Sstevel@tonic-gate */ 5290Sstevel@tonic-gate if (pci_rp->pci_phys_mid != 0 || 5300Sstevel@tonic-gate pci_rp->pci_size_hi != 0) 5310Sstevel@tonic-gate return (DDI_FAILURE); 5320Sstevel@tonic-gate /* 5330Sstevel@tonic-gate * Other than that, we can treat them as 32-bit mappings 5340Sstevel@tonic-gate */ 5350Sstevel@tonic-gate /* FALLTHROUGH */ 5360Sstevel@tonic-gate case PCI_ADDR_MEM32: 5370Sstevel@tonic-gate reg.regspec_bustype = 0; 5380Sstevel@tonic-gate break; 5390Sstevel@tonic-gate default: 5400Sstevel@tonic-gate return (DDI_FAILURE); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate reg.regspec_addr = pci_rp->pci_phys_low; 5430Sstevel@tonic-gate reg.regspec_size = pci_rp->pci_size_low; 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate mp->map_obj.rp = ® 5460Sstevel@tonic-gate return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate /*ARGSUSED*/ 5510Sstevel@tonic-gate static int 5520Sstevel@tonic-gate pci_ctlops(dev_info_t *dip, dev_info_t *rdip, 5530Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 5540Sstevel@tonic-gate { 5550Sstevel@tonic-gate pci_regspec_t *drv_regp; 5560Sstevel@tonic-gate uint_t reglen; 5570Sstevel@tonic-gate int rn; 5580Sstevel@tonic-gate int totreg; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate switch (ctlop) { 5610Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 5620Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 5630Sstevel@tonic-gate return (DDI_FAILURE); 5640Sstevel@tonic-gate cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", 5650Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip), 5660Sstevel@tonic-gate ddi_driver_name(rdip), 5670Sstevel@tonic-gate ddi_get_instance(rdip)); 5680Sstevel@tonic-gate return (DDI_SUCCESS); 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 5710Sstevel@tonic-gate return (pci_initchild((dev_info_t *)arg)); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 5740Sstevel@tonic-gate return (pci_removechild((dev_info_t *)arg)); 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 5770Sstevel@tonic-gate return (DDI_SUCCESS); 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 5800Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 5810Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 5820Sstevel@tonic-gate return (DDI_FAILURE); 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate *(int *)result = 0; 5850Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 5860Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (int **)&drv_regp, 5870Sstevel@tonic-gate ®len) != DDI_PROP_SUCCESS) { 5880Sstevel@tonic-gate return (DDI_FAILURE); 5890Sstevel@tonic-gate } 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t); 5920Sstevel@tonic-gate if (ctlop == DDI_CTLOPS_NREGS) 5930Sstevel@tonic-gate *(int *)result = totreg; 5940Sstevel@tonic-gate else if (ctlop == DDI_CTLOPS_REGSIZE) { 5950Sstevel@tonic-gate rn = *(int *)arg; 5960Sstevel@tonic-gate if (rn >= totreg) { 5970Sstevel@tonic-gate ddi_prop_free(drv_regp); 5980Sstevel@tonic-gate return (DDI_FAILURE); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate *(off_t *)result = drv_regp[rn].pci_size_low; 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate ddi_prop_free(drv_regp); 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate return (DDI_SUCCESS); 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate case DDI_CTLOPS_POWER: { 6070Sstevel@tonic-gate power_req_t *reqp = (power_req_t *)arg; 6080Sstevel@tonic-gate /* 6090Sstevel@tonic-gate * We currently understand reporting of PCI_PM_IDLESPEED 6100Sstevel@tonic-gate * capability. Everything else is passed up. 6110Sstevel@tonic-gate */ 6120Sstevel@tonic-gate if ((reqp->request_type == PMR_REPORT_PMCAP) && 6130Sstevel@tonic-gate (reqp->req.report_pmcap_req.cap == PCI_PM_IDLESPEED)) { 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate return (DDI_SUCCESS); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate default: 6210Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate /* NOTREACHED */ 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /* 629*881Sjohnny * pci_intr_ops 6300Sstevel@tonic-gate */ 6310Sstevel@tonic-gate static int 632*881Sjohnny pci_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 633*881Sjohnny ddi_intr_handle_impl_t *hdlp, void *result) 6340Sstevel@tonic-gate { 635*881Sjohnny return (pci_common_intr_ops(pdip, rdip, intr_op, hdlp, result)); 636*881Sjohnny } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate static int 6400Sstevel@tonic-gate pci_initchild(dev_info_t *child) 6410Sstevel@tonic-gate { 6420Sstevel@tonic-gate char name[80]; 643354Smyers ddi_acc_handle_t config_handle; 644354Smyers ushort_t command_preserve, command; 6450Sstevel@tonic-gate 646*881Sjohnny if (pci_common_name_child(child, name, 80) != DDI_SUCCESS) { 6470Sstevel@tonic-gate return (DDI_FAILURE); 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate ddi_set_name_addr(child, name); 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate /* 6520Sstevel@tonic-gate * Pseudo nodes indicate a prototype node with per-instance 6530Sstevel@tonic-gate * properties to be merged into the real h/w device node. 6540Sstevel@tonic-gate * The interpretation of the unit-address is DD[,F] 6550Sstevel@tonic-gate * where DD is the device id and F is the function. 6560Sstevel@tonic-gate */ 6570Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 6580Sstevel@tonic-gate extern int pci_allow_pseudo_children; 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate /* 6630Sstevel@tonic-gate * Try to merge the properties from this prototype 6640Sstevel@tonic-gate * node into real h/w nodes. 6650Sstevel@tonic-gate */ 666*881Sjohnny if (ndi_merge_node(child, pci_common_name_child) == 667*881Sjohnny DDI_SUCCESS) { 6680Sstevel@tonic-gate /* 6690Sstevel@tonic-gate * Merged ok - return failure to remove the node. 6700Sstevel@tonic-gate */ 6710Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 6720Sstevel@tonic-gate return (DDI_FAILURE); 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate /* workaround for ddivs to run under PCI */ 6760Sstevel@tonic-gate if (pci_allow_pseudo_children) { 6770Sstevel@tonic-gate /* 6780Sstevel@tonic-gate * If the "interrupts" property doesn't exist, 6790Sstevel@tonic-gate * this must be the ddivs no-intr case, and it returns 6800Sstevel@tonic-gate * DDI_SUCCESS instead of DDI_FAILURE. 6810Sstevel@tonic-gate */ 6820Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, child, 6830Sstevel@tonic-gate DDI_PROP_DONTPASS, "interrupts", -1) == -1) 6840Sstevel@tonic-gate return (DDI_SUCCESS); 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * Create the ddi_parent_private_data for a pseudo 6870Sstevel@tonic-gate * child. 6880Sstevel@tonic-gate */ 689*881Sjohnny pci_common_set_parent_private_data(child); 6900Sstevel@tonic-gate return (DDI_SUCCESS); 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate /* 6940Sstevel@tonic-gate * The child was not merged into a h/w node, 6950Sstevel@tonic-gate * but there's not much we can do with it other 6960Sstevel@tonic-gate * than return failure to cause the node to be removed. 6970Sstevel@tonic-gate */ 6980Sstevel@tonic-gate cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 6990Sstevel@tonic-gate ddi_get_name(child), ddi_get_name_addr(child), 7000Sstevel@tonic-gate ddi_get_name(child)); 7010Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 7020Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 706*881Sjohnny "interrupts", -1) != -1) 707*881Sjohnny pci_common_set_parent_private_data(child); 708*881Sjohnny else 7090Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 7100Sstevel@tonic-gate 711354Smyers /* 712354Smyers * initialize command register 713354Smyers */ 714354Smyers if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) 715354Smyers return (DDI_FAILURE); 716354Smyers 717354Smyers /* 718354Smyers * Support for the "command-preserve" property. 719354Smyers */ 720354Smyers command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child, 721354Smyers DDI_PROP_DONTPASS, 722354Smyers "command-preserve", 0); 723354Smyers command = pci_config_get16(config_handle, PCI_CONF_COMM); 724354Smyers command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB); 725354Smyers command |= (pci_command_default & ~command_preserve); 726354Smyers pci_config_put16(config_handle, PCI_CONF_COMM, command); 727354Smyers 728354Smyers pci_config_teardown(&config_handle); 7290Sstevel@tonic-gate return (DDI_SUCCESS); 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate static int 7330Sstevel@tonic-gate pci_removechild(dev_info_t *dip) 7340Sstevel@tonic-gate { 7350Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate if ((pdptr = ddi_get_parent_data(dip)) != NULL) { 7380Sstevel@tonic-gate kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec))); 7390Sstevel@tonic-gate ddi_set_parent_data(dip, NULL); 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate /* 7440Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 7450Sstevel@tonic-gate */ 7460Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate impl_rem_dev_props(dip); 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate return (DDI_SUCCESS); 7510Sstevel@tonic-gate } 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate /* 7550Sstevel@tonic-gate * These are the get and put functions to be shared with drivers. The 7560Sstevel@tonic-gate * mutex locking is done inside the functions referenced, rather than 7570Sstevel@tonic-gate * here, and is thus shared across PCI child drivers and any other 7580Sstevel@tonic-gate * consumers of PCI config space (such as the ACPI subsystem). 7590Sstevel@tonic-gate * 7600Sstevel@tonic-gate * The configuration space addresses come in as pointers. This is fine on 7610Sstevel@tonic-gate * a 32-bit system, where the VM space and configuration space are the same 7620Sstevel@tonic-gate * size. It's not such a good idea on a 64-bit system, where memory 7630Sstevel@tonic-gate * addresses are twice as large as configuration space addresses. At some 7640Sstevel@tonic-gate * point in the call tree we need to take a stand and say "you are 32-bit 7650Sstevel@tonic-gate * from this time forth", and this seems like a nice self-contained place. 7660Sstevel@tonic-gate */ 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate static uint8_t 7690Sstevel@tonic-gate pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 7700Sstevel@tonic-gate { 7710Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 7720Sstevel@tonic-gate uint8_t rval; 7730Sstevel@tonic-gate int reg; 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 7820Sstevel@tonic-gate reg); 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate return (rval); 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate static void 7880Sstevel@tonic-gate pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 7890Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags) 7900Sstevel@tonic-gate { 7910Sstevel@tonic-gate uint8_t *h, *d; 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate h = host_addr; 7940Sstevel@tonic-gate d = dev_addr; 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 7970Sstevel@tonic-gate for (; repcount; repcount--) 7980Sstevel@tonic-gate *h++ = pci_config_rd8(hdlp, d++); 7990Sstevel@tonic-gate else 8000Sstevel@tonic-gate for (; repcount; repcount--) 8010Sstevel@tonic-gate *h++ = pci_config_rd8(hdlp, d); 8020Sstevel@tonic-gate } 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate static uint16_t 8050Sstevel@tonic-gate pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 8060Sstevel@tonic-gate { 8070Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 8080Sstevel@tonic-gate uint16_t rval; 8090Sstevel@tonic-gate int reg; 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 8140Sstevel@tonic-gate 8150Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 8180Sstevel@tonic-gate reg); 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate return (rval); 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate static void 8240Sstevel@tonic-gate pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 8250Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 8260Sstevel@tonic-gate { 8270Sstevel@tonic-gate uint16_t *h, *d; 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate h = host_addr; 8300Sstevel@tonic-gate d = dev_addr; 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 8330Sstevel@tonic-gate for (; repcount; repcount--) 8340Sstevel@tonic-gate *h++ = pci_config_rd16(hdlp, d++); 8350Sstevel@tonic-gate else 8360Sstevel@tonic-gate for (; repcount; repcount--) 8370Sstevel@tonic-gate *h++ = pci_config_rd16(hdlp, d); 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate static uint32_t 8410Sstevel@tonic-gate pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 8420Sstevel@tonic-gate { 8430Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 8440Sstevel@tonic-gate uint32_t rval; 8450Sstevel@tonic-gate int reg; 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 8540Sstevel@tonic-gate cfp->c_funcnum, reg); 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate return (rval); 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate static void 8600Sstevel@tonic-gate pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 8610Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 8620Sstevel@tonic-gate { 8630Sstevel@tonic-gate uint32_t *h, *d; 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate h = host_addr; 8660Sstevel@tonic-gate d = dev_addr; 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 8690Sstevel@tonic-gate for (; repcount; repcount--) 8700Sstevel@tonic-gate *h++ = pci_config_rd32(hdlp, d++); 8710Sstevel@tonic-gate else 8720Sstevel@tonic-gate for (; repcount; repcount--) 8730Sstevel@tonic-gate *h++ = pci_config_rd32(hdlp, d); 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate static void 8780Sstevel@tonic-gate pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 8790Sstevel@tonic-gate { 8800Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 8810Sstevel@tonic-gate int reg; 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 8900Sstevel@tonic-gate cfp->c_funcnum, reg, value); 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate static void 8940Sstevel@tonic-gate pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 8950Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags) 8960Sstevel@tonic-gate { 8970Sstevel@tonic-gate uint8_t *h, *d; 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate h = host_addr; 9000Sstevel@tonic-gate d = dev_addr; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 9030Sstevel@tonic-gate for (; repcount; repcount--) 9040Sstevel@tonic-gate pci_config_wr8(hdlp, d++, *h++); 9050Sstevel@tonic-gate else 9060Sstevel@tonic-gate for (; repcount; repcount--) 9070Sstevel@tonic-gate pci_config_wr8(hdlp, d, *h++); 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate static void 9110Sstevel@tonic-gate pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 9120Sstevel@tonic-gate { 9130Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 9140Sstevel@tonic-gate int reg; 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 9230Sstevel@tonic-gate cfp->c_funcnum, reg, value); 9240Sstevel@tonic-gate } 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate static void 9270Sstevel@tonic-gate pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 9280Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 9290Sstevel@tonic-gate { 9300Sstevel@tonic-gate uint16_t *h, *d; 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate h = host_addr; 9330Sstevel@tonic-gate d = dev_addr; 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 9360Sstevel@tonic-gate for (; repcount; repcount--) 9370Sstevel@tonic-gate pci_config_wr16(hdlp, d++, *h++); 9380Sstevel@tonic-gate else 9390Sstevel@tonic-gate for (; repcount; repcount--) 9400Sstevel@tonic-gate pci_config_wr16(hdlp, d, *h++); 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate static void 9440Sstevel@tonic-gate pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 9450Sstevel@tonic-gate { 9460Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 9470Sstevel@tonic-gate int reg; 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 9560Sstevel@tonic-gate cfp->c_funcnum, reg, value); 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate static void 9600Sstevel@tonic-gate pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 9610Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 9620Sstevel@tonic-gate { 9630Sstevel@tonic-gate uint32_t *h, *d; 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate h = host_addr; 9660Sstevel@tonic-gate d = dev_addr; 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 9690Sstevel@tonic-gate for (; repcount; repcount--) 9700Sstevel@tonic-gate pci_config_wr32(hdlp, d++, *h++); 9710Sstevel@tonic-gate else 9720Sstevel@tonic-gate for (; repcount; repcount--) 9730Sstevel@tonic-gate pci_config_wr32(hdlp, d, *h++); 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate static uint64_t 9770Sstevel@tonic-gate pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 9780Sstevel@tonic-gate { 9790Sstevel@tonic-gate uint32_t lw_val; 9800Sstevel@tonic-gate uint32_t hi_val; 9810Sstevel@tonic-gate uint32_t *dp; 9820Sstevel@tonic-gate uint64_t val; 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate dp = (uint32_t *)addr; 9850Sstevel@tonic-gate lw_val = pci_config_rd32(hdlp, dp); 9860Sstevel@tonic-gate dp++; 9870Sstevel@tonic-gate hi_val = pci_config_rd32(hdlp, dp); 9880Sstevel@tonic-gate val = ((uint64_t)hi_val << 32) | lw_val; 9890Sstevel@tonic-gate return (val); 9900Sstevel@tonic-gate } 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate static void 9930Sstevel@tonic-gate pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 9940Sstevel@tonic-gate { 9950Sstevel@tonic-gate uint32_t lw_val; 9960Sstevel@tonic-gate uint32_t hi_val; 9970Sstevel@tonic-gate uint32_t *dp; 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate dp = (uint32_t *)addr; 10000Sstevel@tonic-gate lw_val = (uint32_t)(value & 0xffffffff); 10010Sstevel@tonic-gate hi_val = (uint32_t)(value >> 32); 10020Sstevel@tonic-gate pci_config_wr32(hdlp, dp, lw_val); 10030Sstevel@tonic-gate dp++; 10040Sstevel@tonic-gate pci_config_wr32(hdlp, dp, hi_val); 10050Sstevel@tonic-gate } 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate static void 10080Sstevel@tonic-gate pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 10090Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 10100Sstevel@tonic-gate { 10110Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) { 10120Sstevel@tonic-gate for (; repcount; repcount--) 10130Sstevel@tonic-gate *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 10140Sstevel@tonic-gate } else { 10150Sstevel@tonic-gate for (; repcount; repcount--) 10160Sstevel@tonic-gate *host_addr++ = pci_config_rd64(hdlp, dev_addr); 10170Sstevel@tonic-gate } 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate static void 10210Sstevel@tonic-gate pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 10220Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 10230Sstevel@tonic-gate { 10240Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) { 10250Sstevel@tonic-gate for (; repcount; repcount--) 10260Sstevel@tonic-gate pci_config_wr64(hdlp, host_addr++, *dev_addr++); 10270Sstevel@tonic-gate } else { 10280Sstevel@tonic-gate for (; repcount; repcount--) 10290Sstevel@tonic-gate pci_config_wr64(hdlp, host_addr++, *dev_addr); 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate } 10320Sstevel@tonic-gate 1033*881Sjohnny 10340Sstevel@tonic-gate /* 10350Sstevel@tonic-gate * When retrofitting this module for pci_tools, functions such as open, close, 10360Sstevel@tonic-gate * and ioctl are now pulled into this module. Before this, the functions in 10370Sstevel@tonic-gate * the pcihp module were referenced directly. Now they are called or 10380Sstevel@tonic-gate * referenced through the pcihp cb_ops structure from functions in this module. 10390Sstevel@tonic-gate */ 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate static int 10420Sstevel@tonic-gate pci_open(dev_t *devp, int flags, int otyp, cred_t *credp) 10430Sstevel@tonic-gate { 1044*881Sjohnny return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp)); 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate 10470Sstevel@tonic-gate static int 10480Sstevel@tonic-gate pci_close(dev_t dev, int flags, int otyp, cred_t *credp) 10490Sstevel@tonic-gate { 1050*881Sjohnny return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp)); 10510Sstevel@tonic-gate } 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate static int 1054*881Sjohnny pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 10550Sstevel@tonic-gate { 1056777Sschwartz minor_t minor = getminor(dev); 1057777Sschwartz int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 1058777Sschwartz pci_state_t *pci_p = ddi_get_soft_state(pci_statep, instance); 10590Sstevel@tonic-gate 1060*881Sjohnny if (pci_p == NULL) 1061*881Sjohnny return (ENXIO); 1062117Sschwartz 1063*881Sjohnny return (pci_common_ioctl(pci_p->pci_dip, 1064*881Sjohnny dev, cmd, arg, mode, credp, rvalp)); 1065*881Sjohnny } 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate static int 10690Sstevel@tonic-gate pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 1070117Sschwartz int flags, char *name, caddr_t valuep, int *lengthp) 10710Sstevel@tonic-gate { 1072*881Sjohnny return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags, 10730Sstevel@tonic-gate name, valuep, lengthp)); 10740Sstevel@tonic-gate } 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate static int 10770Sstevel@tonic-gate pci_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 10780Sstevel@tonic-gate { 10790Sstevel@tonic-gate return (pcihp_info(dip, cmd, arg, result)); 10800Sstevel@tonic-gate } 1081