1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Host to PCI local bus driver 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/conf.h> 34*0Sstevel@tonic-gate #include <sys/kmem.h> 35*0Sstevel@tonic-gate #include <sys/debug.h> 36*0Sstevel@tonic-gate #include <sys/modctl.h> 37*0Sstevel@tonic-gate #include <sys/autoconf.h> 38*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 39*0Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 40*0Sstevel@tonic-gate #include <sys/pci.h> 41*0Sstevel@tonic-gate #include <sys/pci_impl.h> 42*0Sstevel@tonic-gate #include <sys/ddi.h> 43*0Sstevel@tonic-gate #include <sys/sunddi.h> 44*0Sstevel@tonic-gate #include <sys/sunndi.h> 45*0Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h> 46*0Sstevel@tonic-gate #include <sys/pci_cfgspace.h> 47*0Sstevel@tonic-gate #include <sys/avintr.h> 48*0Sstevel@tonic-gate #include <sys/psm.h> 49*0Sstevel@tonic-gate #include <sys/pci_intr_lib.h> 50*0Sstevel@tonic-gate #include <sys/policy.h> 51*0Sstevel@tonic-gate #include <sys/pci_tools.h> 52*0Sstevel@tonic-gate #include <sys/pci_tools_var.h> 53*0Sstevel@tonic-gate #include "pci_var.h" 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate /* Save minimal state. */ 57*0Sstevel@tonic-gate void *pci_statep; 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate /* 60*0Sstevel@tonic-gate * Bus Operation functions 61*0Sstevel@tonic-gate */ 62*0Sstevel@tonic-gate static int pci_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 63*0Sstevel@tonic-gate off_t, off_t, caddr_t *); 64*0Sstevel@tonic-gate static int pci_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 65*0Sstevel@tonic-gate void *, void *); 66*0Sstevel@tonic-gate static int pci_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 67*0Sstevel@tonic-gate ddi_intr_handle_impl_t *, void *); 68*0Sstevel@tonic-gate static int pci_get_priority(dev_info_t *, int, int *); 69*0Sstevel@tonic-gate static int pci_get_nintrs(dev_info_t *, int, int *); 70*0Sstevel@tonic-gate static int pci_enable_intr(dev_info_t *, dev_info_t *, 71*0Sstevel@tonic-gate ddi_intr_handle_impl_t *, uint32_t); 72*0Sstevel@tonic-gate static void pci_disable_intr(dev_info_t *, dev_info_t *, 73*0Sstevel@tonic-gate ddi_intr_handle_impl_t *, uint32_t); 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate /* Extern decalrations */ 76*0Sstevel@tonic-gate extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 77*0Sstevel@tonic-gate psm_intr_op_t, int *); 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate struct bus_ops pci_bus_ops = { 80*0Sstevel@tonic-gate BUSO_REV, 81*0Sstevel@tonic-gate pci_bus_map, 82*0Sstevel@tonic-gate NULL, 83*0Sstevel@tonic-gate NULL, 84*0Sstevel@tonic-gate NULL, 85*0Sstevel@tonic-gate i_ddi_map_fault, 86*0Sstevel@tonic-gate ddi_dma_map, 87*0Sstevel@tonic-gate ddi_dma_allochdl, 88*0Sstevel@tonic-gate ddi_dma_freehdl, 89*0Sstevel@tonic-gate ddi_dma_bindhdl, 90*0Sstevel@tonic-gate ddi_dma_unbindhdl, 91*0Sstevel@tonic-gate ddi_dma_flush, 92*0Sstevel@tonic-gate ddi_dma_win, 93*0Sstevel@tonic-gate ddi_dma_mctl, 94*0Sstevel@tonic-gate pci_ctlops, 95*0Sstevel@tonic-gate ddi_bus_prop_op, 96*0Sstevel@tonic-gate 0, /* (*bus_get_eventcookie)(); */ 97*0Sstevel@tonic-gate 0, /* (*bus_add_eventcall)(); */ 98*0Sstevel@tonic-gate 0, /* (*bus_remove_eventcall)(); */ 99*0Sstevel@tonic-gate 0, /* (*bus_post_event)(); */ 100*0Sstevel@tonic-gate 0, /* (*bus_intr_ctl)(); */ 101*0Sstevel@tonic-gate 0, /* (*bus_config)(); */ 102*0Sstevel@tonic-gate 0, /* (*bus_unconfig)(); */ 103*0Sstevel@tonic-gate NULL, /* (*bus_fm_init)(); */ 104*0Sstevel@tonic-gate NULL, /* (*bus_fm_fini)(); */ 105*0Sstevel@tonic-gate NULL, /* (*bus_fm_access_enter)(); */ 106*0Sstevel@tonic-gate NULL, /* (*bus_fm_access_exit)(); */ 107*0Sstevel@tonic-gate NULL, /* (*bus_power)(); */ 108*0Sstevel@tonic-gate pci_intr_ops /* (*bus_intr_op)(); */ 109*0Sstevel@tonic-gate }; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate static int pci_open(dev_t *devp, int flags, int otyp, cred_t *credp); 112*0Sstevel@tonic-gate static int pci_close(dev_t dev, int flags, int otyp, cred_t *credp); 113*0Sstevel@tonic-gate static int pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 114*0Sstevel@tonic-gate int *rvalp); 115*0Sstevel@tonic-gate static int pci_prop_op(dev_t dev, dev_info_t *devi, ddi_prop_op_t prop_op, 116*0Sstevel@tonic-gate int flags, char *name, caddr_t valuep, int *lengthp); 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /* 119*0Sstevel@tonic-gate * One goal here is to leverage off of the pcihp.c source without making 120*0Sstevel@tonic-gate * changes to it. Call into it's cb_ops directly if needed, piggybacking 121*0Sstevel@tonic-gate * anything else needed by the pci_tools.c module. Only pci_tools and pcihp 122*0Sstevel@tonic-gate * will be using the PCI devctl node. 123*0Sstevel@tonic-gate */ 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate struct cb_ops pci_cb_ops = { 126*0Sstevel@tonic-gate pci_open, /* open */ 127*0Sstevel@tonic-gate pci_close, /* close */ 128*0Sstevel@tonic-gate nodev, /* strategy */ 129*0Sstevel@tonic-gate nodev, /* print */ 130*0Sstevel@tonic-gate nodev, /* dump */ 131*0Sstevel@tonic-gate nodev, /* read */ 132*0Sstevel@tonic-gate nodev, /* write */ 133*0Sstevel@tonic-gate pci_ioctl, /* ioctl */ 134*0Sstevel@tonic-gate nodev, /* devmap */ 135*0Sstevel@tonic-gate nodev, /* mmap */ 136*0Sstevel@tonic-gate nodev, /* segmap */ 137*0Sstevel@tonic-gate nochpoll, /* poll */ 138*0Sstevel@tonic-gate pci_prop_op, /* cb_prop_op */ 139*0Sstevel@tonic-gate NULL, /* streamtab */ 140*0Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 141*0Sstevel@tonic-gate CB_REV, /* rev */ 142*0Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 143*0Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 144*0Sstevel@tonic-gate }; 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /* 147*0Sstevel@tonic-gate * Device Node Operation functions 148*0Sstevel@tonic-gate */ 149*0Sstevel@tonic-gate static int pci_info(dev_info_t *devi, ddi_info_cmd_t cmd, void *arg, 150*0Sstevel@tonic-gate void **result); 151*0Sstevel@tonic-gate static int pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 152*0Sstevel@tonic-gate static int pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate struct dev_ops pci_ops = { 155*0Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 156*0Sstevel@tonic-gate 0, /* refcnt */ 157*0Sstevel@tonic-gate pci_info, /* info */ 158*0Sstevel@tonic-gate nulldev, /* identify */ 159*0Sstevel@tonic-gate nulldev, /* probe */ 160*0Sstevel@tonic-gate pci_attach, /* attach */ 161*0Sstevel@tonic-gate pci_detach, /* detach */ 162*0Sstevel@tonic-gate nulldev, /* reset */ 163*0Sstevel@tonic-gate &pci_cb_ops, /* driver operations */ 164*0Sstevel@tonic-gate &pci_bus_ops /* bus operations */ 165*0Sstevel@tonic-gate }; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate /* 168*0Sstevel@tonic-gate * Internal routines in support of particular pci_ctlops. 169*0Sstevel@tonic-gate */ 170*0Sstevel@tonic-gate static int pci_removechild(dev_info_t *child); 171*0Sstevel@tonic-gate static int pci_initchild(dev_info_t *child); 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* 174*0Sstevel@tonic-gate * Miscellaneous internal function 175*0Sstevel@tonic-gate */ 176*0Sstevel@tonic-gate static int pci_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp); 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * These are the access routines. The pci_bus_map sets the handle 180*0Sstevel@tonic-gate * to point to these. 181*0Sstevel@tonic-gate */ 182*0Sstevel@tonic-gate static uint8_t pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr); 183*0Sstevel@tonic-gate static uint16_t pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr); 184*0Sstevel@tonic-gate static uint32_t pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr); 185*0Sstevel@tonic-gate static uint64_t pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr); 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate static void pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, 188*0Sstevel@tonic-gate uint8_t value); 189*0Sstevel@tonic-gate static void pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, 190*0Sstevel@tonic-gate uint16_t value); 191*0Sstevel@tonic-gate static void pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, 192*0Sstevel@tonic-gate uint32_t value); 193*0Sstevel@tonic-gate static void pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, 194*0Sstevel@tonic-gate uint64_t value); 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate static void pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 197*0Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags); 198*0Sstevel@tonic-gate static void pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 199*0Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags); 200*0Sstevel@tonic-gate static void pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 201*0Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags); 202*0Sstevel@tonic-gate static void pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 203*0Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate static void pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 206*0Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags); 207*0Sstevel@tonic-gate static void pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 208*0Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags); 209*0Sstevel@tonic-gate static void pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 210*0Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags); 211*0Sstevel@tonic-gate static void pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 212*0Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags); 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate /* 215*0Sstevel@tonic-gate * Module linkage information for the kernel. 216*0Sstevel@tonic-gate */ 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate static struct modldrv modldrv = { 219*0Sstevel@tonic-gate &mod_driverops, /* Type of module */ 220*0Sstevel@tonic-gate "host to PCI nexus driver %I%", 221*0Sstevel@tonic-gate &pci_ops, /* driver ops */ 222*0Sstevel@tonic-gate }; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 225*0Sstevel@tonic-gate MODREV_1, 226*0Sstevel@tonic-gate (void *)&modldrv, 227*0Sstevel@tonic-gate NULL 228*0Sstevel@tonic-gate }; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate int 231*0Sstevel@tonic-gate _init(void) 232*0Sstevel@tonic-gate { 233*0Sstevel@tonic-gate int e; 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate /* 236*0Sstevel@tonic-gate * Initialize per-pci bus soft state pointer. 237*0Sstevel@tonic-gate */ 238*0Sstevel@tonic-gate e = ddi_soft_state_init(&pci_statep, sizeof (pci_state_t), 1); 239*0Sstevel@tonic-gate if (e != 0) 240*0Sstevel@tonic-gate return (e); 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) 243*0Sstevel@tonic-gate ddi_soft_state_fini(&pci_statep); 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate return (e); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate int 249*0Sstevel@tonic-gate _fini(void) 250*0Sstevel@tonic-gate { 251*0Sstevel@tonic-gate int rc; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate rc = mod_remove(&modlinkage); 254*0Sstevel@tonic-gate if (rc != 0) 255*0Sstevel@tonic-gate return (rc); 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate ddi_soft_state_fini(&pci_statep); 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate return (rc); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate int 263*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 264*0Sstevel@tonic-gate { 265*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate /*ARGSUSED*/ 269*0Sstevel@tonic-gate static int 270*0Sstevel@tonic-gate pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 271*0Sstevel@tonic-gate { 272*0Sstevel@tonic-gate /* 273*0Sstevel@tonic-gate * Use the minor number as constructed by pcihp, as the index value to 274*0Sstevel@tonic-gate * ddi_soft_state_zalloc. 275*0Sstevel@tonic-gate */ 276*0Sstevel@tonic-gate int minor = DIP_TO_MINOR(devi); 277*0Sstevel@tonic-gate pci_state_t *pcip = NULL; 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci") 280*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 281*0Sstevel@tonic-gate cmn_err(CE_WARN, "pci: 'device_type' prop create failed"); 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate if (ddi_soft_state_zalloc(pci_statep, minor) == DDI_SUCCESS) { 285*0Sstevel@tonic-gate pcip = ddi_get_soft_state(pci_statep, minor); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate if (pcip == NULL) { 289*0Sstevel@tonic-gate return (DDI_FAILURE); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate pcip->pci_dip = devi; 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate /* 295*0Sstevel@tonic-gate * Initialize hotplug support on this bus. At minimum 296*0Sstevel@tonic-gate * (for non hotplug bus) this would create ":devctl" minor 297*0Sstevel@tonic-gate * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls 298*0Sstevel@tonic-gate * to this bus. 299*0Sstevel@tonic-gate */ 300*0Sstevel@tonic-gate if (pcihp_init(devi) != DDI_SUCCESS) { 301*0Sstevel@tonic-gate cmn_err(CE_WARN, "pci: Failed to setup hotplug framework"); 302*0Sstevel@tonic-gate ddi_soft_state_free(pci_statep, minor); 303*0Sstevel@tonic-gate return (DDI_FAILURE); 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate ddi_report_dev(devi); 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate return (DDI_SUCCESS); 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate /*ARGSUSED*/ 312*0Sstevel@tonic-gate static int 313*0Sstevel@tonic-gate pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 314*0Sstevel@tonic-gate { 315*0Sstevel@tonic-gate /* 316*0Sstevel@tonic-gate * Uninitialize hotplug support on this bus. 317*0Sstevel@tonic-gate */ 318*0Sstevel@tonic-gate (void) pcihp_uninit(devi); 319*0Sstevel@tonic-gate ddi_soft_state_free(pci_statep, DIP_TO_MINOR(devi)); 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate return (DDI_SUCCESS); 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate static int 325*0Sstevel@tonic-gate pci_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 326*0Sstevel@tonic-gate { 327*0Sstevel@tonic-gate pci_regspec_t *assigned_addr; 328*0Sstevel@tonic-gate int assigned_addr_len; 329*0Sstevel@tonic-gate uint_t phys_hi; 330*0Sstevel@tonic-gate int i; 331*0Sstevel@tonic-gate int rc; 332*0Sstevel@tonic-gate int number; 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate phys_hi = pci_rp->pci_phys_hi; 335*0Sstevel@tonic-gate if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 336*0Sstevel@tonic-gate (phys_hi & PCI_RELOCAT_B)) 337*0Sstevel@tonic-gate return (DDI_SUCCESS); 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate /* 340*0Sstevel@tonic-gate * the "reg" property specifies relocatable, get and interpret the 341*0Sstevel@tonic-gate * "assigned-addresses" property. 342*0Sstevel@tonic-gate */ 343*0Sstevel@tonic-gate rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 344*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "assigned-addresses", 345*0Sstevel@tonic-gate (int **)&assigned_addr, (uint_t *)&assigned_addr_len); 346*0Sstevel@tonic-gate if (rc != DDI_PROP_SUCCESS) 347*0Sstevel@tonic-gate return (DDI_FAILURE); 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate /* 350*0Sstevel@tonic-gate * Scan the "assigned-addresses" for one that matches the specified 351*0Sstevel@tonic-gate * "reg" property entry. 352*0Sstevel@tonic-gate */ 353*0Sstevel@tonic-gate phys_hi &= PCI_CONF_ADDR_MASK; 354*0Sstevel@tonic-gate number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 355*0Sstevel@tonic-gate for (i = 0; i < number; i++) { 356*0Sstevel@tonic-gate if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 357*0Sstevel@tonic-gate phys_hi) { 358*0Sstevel@tonic-gate pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 359*0Sstevel@tonic-gate pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 360*0Sstevel@tonic-gate ddi_prop_free(assigned_addr); 361*0Sstevel@tonic-gate return (DDI_SUCCESS); 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate ddi_prop_free(assigned_addr); 366*0Sstevel@tonic-gate return (DDI_FAILURE); 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate static int 370*0Sstevel@tonic-gate pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 371*0Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 372*0Sstevel@tonic-gate { 373*0Sstevel@tonic-gate struct regspec reg; 374*0Sstevel@tonic-gate ddi_map_req_t mr; 375*0Sstevel@tonic-gate ddi_acc_hdl_t *hp; 376*0Sstevel@tonic-gate ddi_acc_impl_t *ap; 377*0Sstevel@tonic-gate pci_regspec_t pci_reg; 378*0Sstevel@tonic-gate pci_regspec_t *pci_rp; 379*0Sstevel@tonic-gate int rnumber; 380*0Sstevel@tonic-gate int length; 381*0Sstevel@tonic-gate int rc; 382*0Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 383*0Sstevel@tonic-gate int space; 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate mr = *mp; /* Get private copy of request */ 387*0Sstevel@tonic-gate mp = &mr; 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* 390*0Sstevel@tonic-gate * check for register number 391*0Sstevel@tonic-gate */ 392*0Sstevel@tonic-gate switch (mp->map_type) { 393*0Sstevel@tonic-gate case DDI_MT_REGSPEC: 394*0Sstevel@tonic-gate pci_reg = *(pci_regspec_t *)(mp->map_obj.rp); 395*0Sstevel@tonic-gate pci_rp = &pci_reg; 396*0Sstevel@tonic-gate if (pci_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 397*0Sstevel@tonic-gate return (DDI_FAILURE); 398*0Sstevel@tonic-gate break; 399*0Sstevel@tonic-gate case DDI_MT_RNUMBER: 400*0Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 401*0Sstevel@tonic-gate /* 402*0Sstevel@tonic-gate * get ALL "reg" properties for dip, select the one of 403*0Sstevel@tonic-gate * of interest. In x86, "assigned-addresses" property 404*0Sstevel@tonic-gate * is identical to the "reg" property, so there is no 405*0Sstevel@tonic-gate * need to cross check the two to determine the physical 406*0Sstevel@tonic-gate * address of the registers. 407*0Sstevel@tonic-gate * This routine still performs some validity checks to 408*0Sstevel@tonic-gate * make sure that everything is okay. 409*0Sstevel@tonic-gate */ 410*0Sstevel@tonic-gate rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 411*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 412*0Sstevel@tonic-gate (uint_t *)&length); 413*0Sstevel@tonic-gate if (rc != DDI_PROP_SUCCESS) { 414*0Sstevel@tonic-gate return (DDI_FAILURE); 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate /* 418*0Sstevel@tonic-gate * validate the register number. 419*0Sstevel@tonic-gate */ 420*0Sstevel@tonic-gate length /= (sizeof (pci_regspec_t) / sizeof (int)); 421*0Sstevel@tonic-gate if (rnumber >= length) { 422*0Sstevel@tonic-gate ddi_prop_free(pci_rp); 423*0Sstevel@tonic-gate return (DDI_FAILURE); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate /* 427*0Sstevel@tonic-gate * copy the required entry. 428*0Sstevel@tonic-gate */ 429*0Sstevel@tonic-gate pci_reg = pci_rp[rnumber]; 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate /* 432*0Sstevel@tonic-gate * free the memory allocated by ddi_prop_lookup_int_array 433*0Sstevel@tonic-gate */ 434*0Sstevel@tonic-gate ddi_prop_free(pci_rp); 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate pci_rp = &pci_reg; 437*0Sstevel@tonic-gate if (pci_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 438*0Sstevel@tonic-gate return (DDI_FAILURE); 439*0Sstevel@tonic-gate mp->map_type = DDI_MT_REGSPEC; 440*0Sstevel@tonic-gate break; 441*0Sstevel@tonic-gate default: 442*0Sstevel@tonic-gate return (DDI_ME_INVAL); 443*0Sstevel@tonic-gate } 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M; 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate /* 448*0Sstevel@tonic-gate * check for unmap and unlock of address space 449*0Sstevel@tonic-gate */ 450*0Sstevel@tonic-gate if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) { 451*0Sstevel@tonic-gate /* 452*0Sstevel@tonic-gate * Adjust offset and length 453*0Sstevel@tonic-gate * A non-zero length means override the one in the regspec. 454*0Sstevel@tonic-gate */ 455*0Sstevel@tonic-gate pci_rp->pci_phys_low += (uint_t)offset; 456*0Sstevel@tonic-gate if (len != 0) 457*0Sstevel@tonic-gate pci_rp->pci_size_low = len; 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate switch (space) { 460*0Sstevel@tonic-gate case PCI_ADDR_CONFIG: 461*0Sstevel@tonic-gate /* No work required on unmap of Config space */ 462*0Sstevel@tonic-gate return (DDI_SUCCESS); 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate case PCI_ADDR_IO: 465*0Sstevel@tonic-gate reg.regspec_bustype = 1; 466*0Sstevel@tonic-gate break; 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate case PCI_ADDR_MEM64: 469*0Sstevel@tonic-gate /* 470*0Sstevel@tonic-gate * MEM64 requires special treatment on map, to check 471*0Sstevel@tonic-gate * that the device is below 4G. On unmap, however, 472*0Sstevel@tonic-gate * we can assume that everything is OK... the map 473*0Sstevel@tonic-gate * must have succeeded. 474*0Sstevel@tonic-gate */ 475*0Sstevel@tonic-gate /* FALLTHROUGH */ 476*0Sstevel@tonic-gate case PCI_ADDR_MEM32: 477*0Sstevel@tonic-gate reg.regspec_bustype = 0; 478*0Sstevel@tonic-gate break; 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate default: 481*0Sstevel@tonic-gate return (DDI_FAILURE); 482*0Sstevel@tonic-gate } 483*0Sstevel@tonic-gate reg.regspec_addr = pci_rp->pci_phys_low; 484*0Sstevel@tonic-gate reg.regspec_size = pci_rp->pci_size_low; 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate mp->map_obj.rp = ® 487*0Sstevel@tonic-gate return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate } 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate /* check for user mapping request - not legal for Config */ 492*0Sstevel@tonic-gate if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) { 493*0Sstevel@tonic-gate return (DDI_FAILURE); 494*0Sstevel@tonic-gate } 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate /* 497*0Sstevel@tonic-gate * check for config space 498*0Sstevel@tonic-gate * On x86, CONFIG is not mapped via MMU and there is 499*0Sstevel@tonic-gate * no endian-ness issues. Set the attr field in the handle to 500*0Sstevel@tonic-gate * indicate that the common routines to call the nexus driver. 501*0Sstevel@tonic-gate */ 502*0Sstevel@tonic-gate if (space == PCI_ADDR_CONFIG) { 503*0Sstevel@tonic-gate hp = (ddi_acc_hdl_t *)mp->map_handlep; 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate if (hp == NULL) { 506*0Sstevel@tonic-gate /* Can't map config space without a handle */ 507*0Sstevel@tonic-gate return (DDI_FAILURE); 508*0Sstevel@tonic-gate } 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate ap = (ddi_acc_impl_t *)hp->ah_platform_private; 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate /* endian-ness check */ 513*0Sstevel@tonic-gate if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 514*0Sstevel@tonic-gate return (DDI_FAILURE); 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate /* 517*0Sstevel@tonic-gate * range check 518*0Sstevel@tonic-gate */ 519*0Sstevel@tonic-gate if ((offset >= 256) || (len > 256) || (offset + len > 256)) 520*0Sstevel@tonic-gate return (DDI_FAILURE); 521*0Sstevel@tonic-gate *vaddrp = (caddr_t)offset; 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 524*0Sstevel@tonic-gate ap->ahi_put8 = pci_config_wr8; 525*0Sstevel@tonic-gate ap->ahi_get8 = pci_config_rd8; 526*0Sstevel@tonic-gate ap->ahi_put64 = pci_config_wr64; 527*0Sstevel@tonic-gate ap->ahi_get64 = pci_config_rd64; 528*0Sstevel@tonic-gate ap->ahi_rep_put8 = pci_config_rep_wr8; 529*0Sstevel@tonic-gate ap->ahi_rep_get8 = pci_config_rep_rd8; 530*0Sstevel@tonic-gate ap->ahi_rep_put64 = pci_config_rep_wr64; 531*0Sstevel@tonic-gate ap->ahi_rep_get64 = pci_config_rep_rd64; 532*0Sstevel@tonic-gate ap->ahi_get16 = pci_config_rd16; 533*0Sstevel@tonic-gate ap->ahi_get32 = pci_config_rd32; 534*0Sstevel@tonic-gate ap->ahi_put16 = pci_config_wr16; 535*0Sstevel@tonic-gate ap->ahi_put32 = pci_config_wr32; 536*0Sstevel@tonic-gate ap->ahi_rep_get16 = pci_config_rep_rd16; 537*0Sstevel@tonic-gate ap->ahi_rep_get32 = pci_config_rep_rd32; 538*0Sstevel@tonic-gate ap->ahi_rep_put16 = pci_config_rep_wr16; 539*0Sstevel@tonic-gate ap->ahi_rep_put32 = pci_config_rep_wr32; 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate /* Initialize to default check/notify functions */ 542*0Sstevel@tonic-gate ap->ahi_fault_check = i_ddi_acc_fault_check; 543*0Sstevel@tonic-gate ap->ahi_fault_notify = i_ddi_acc_fault_notify; 544*0Sstevel@tonic-gate ap->ahi_fault = 0; 545*0Sstevel@tonic-gate impl_acc_err_init(hp); 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate /* record the device address for future reference */ 548*0Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private; 549*0Sstevel@tonic-gate cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 550*0Sstevel@tonic-gate cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 551*0Sstevel@tonic-gate cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate return (DDI_SUCCESS); 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate /* 557*0Sstevel@tonic-gate * range check 558*0Sstevel@tonic-gate */ 559*0Sstevel@tonic-gate if ((offset >= pci_rp->pci_size_low) || 560*0Sstevel@tonic-gate (len > pci_rp->pci_size_low) || 561*0Sstevel@tonic-gate (offset + len > pci_rp->pci_size_low)) { 562*0Sstevel@tonic-gate return (DDI_FAILURE); 563*0Sstevel@tonic-gate } 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate /* 566*0Sstevel@tonic-gate * Adjust offset and length 567*0Sstevel@tonic-gate * A non-zero length means override the one in the regspec. 568*0Sstevel@tonic-gate */ 569*0Sstevel@tonic-gate pci_rp->pci_phys_low += (uint_t)offset; 570*0Sstevel@tonic-gate if (len != 0) 571*0Sstevel@tonic-gate pci_rp->pci_size_low = len; 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate /* 574*0Sstevel@tonic-gate * convert the pci regsec into the generic regspec used by the 575*0Sstevel@tonic-gate * parent root nexus driver. 576*0Sstevel@tonic-gate */ 577*0Sstevel@tonic-gate switch (space) { 578*0Sstevel@tonic-gate case PCI_ADDR_IO: 579*0Sstevel@tonic-gate reg.regspec_bustype = 1; 580*0Sstevel@tonic-gate break; 581*0Sstevel@tonic-gate case PCI_ADDR_MEM64: 582*0Sstevel@tonic-gate /* 583*0Sstevel@tonic-gate * We can't handle 64-bit devices that are mapped above 584*0Sstevel@tonic-gate * 4G or that are larger than 4G. 585*0Sstevel@tonic-gate */ 586*0Sstevel@tonic-gate if (pci_rp->pci_phys_mid != 0 || 587*0Sstevel@tonic-gate pci_rp->pci_size_hi != 0) 588*0Sstevel@tonic-gate return (DDI_FAILURE); 589*0Sstevel@tonic-gate /* 590*0Sstevel@tonic-gate * Other than that, we can treat them as 32-bit mappings 591*0Sstevel@tonic-gate */ 592*0Sstevel@tonic-gate /* FALLTHROUGH */ 593*0Sstevel@tonic-gate case PCI_ADDR_MEM32: 594*0Sstevel@tonic-gate reg.regspec_bustype = 0; 595*0Sstevel@tonic-gate break; 596*0Sstevel@tonic-gate default: 597*0Sstevel@tonic-gate return (DDI_FAILURE); 598*0Sstevel@tonic-gate } 599*0Sstevel@tonic-gate reg.regspec_addr = pci_rp->pci_phys_low; 600*0Sstevel@tonic-gate reg.regspec_size = pci_rp->pci_size_low; 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate mp->map_obj.rp = ® 603*0Sstevel@tonic-gate return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate /* 608*0Sstevel@tonic-gate * pci_get_priority: 609*0Sstevel@tonic-gate * Figure out the priority of the device 610*0Sstevel@tonic-gate */ 611*0Sstevel@tonic-gate static int 612*0Sstevel@tonic-gate pci_get_priority(dev_info_t *dip, int inum, int *pri) 613*0Sstevel@tonic-gate { 614*0Sstevel@tonic-gate struct intrspec *ispec; 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p\n", 617*0Sstevel@tonic-gate (void *)dip)); 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, inum)) == 620*0Sstevel@tonic-gate NULL) 621*0Sstevel@tonic-gate return (DDI_FAILURE); 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate *pri = ispec->intrspec_pri; 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate return (DDI_SUCCESS); 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate /* 630*0Sstevel@tonic-gate * pci_get_nintrs: 631*0Sstevel@tonic-gate * Figure out how many interrupts the device supports 632*0Sstevel@tonic-gate */ 633*0Sstevel@tonic-gate static int 634*0Sstevel@tonic-gate pci_get_nintrs(dev_info_t *dip, int type, int *nintrs) 635*0Sstevel@tonic-gate { 636*0Sstevel@tonic-gate int ret; 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate *nintrs = 0; 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(type)) 641*0Sstevel@tonic-gate ret = pci_msi_get_nintrs(dip, type, nintrs); 642*0Sstevel@tonic-gate else { 643*0Sstevel@tonic-gate ret = DDI_FAILURE; 644*0Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 645*0Sstevel@tonic-gate "interrupts", -1) != -1) { 646*0Sstevel@tonic-gate *nintrs = 1; 647*0Sstevel@tonic-gate ret = DDI_SUCCESS; 648*0Sstevel@tonic-gate } 649*0Sstevel@tonic-gate } 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate return (ret); 652*0Sstevel@tonic-gate } 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate /* 656*0Sstevel@tonic-gate * pci_intr_ops: bus_intr_op() function for interrupt support 657*0Sstevel@tonic-gate */ 658*0Sstevel@tonic-gate /* ARGSUSED */ 659*0Sstevel@tonic-gate static int 660*0Sstevel@tonic-gate pci_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 661*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 662*0Sstevel@tonic-gate { 663*0Sstevel@tonic-gate int priority = 0; 664*0Sstevel@tonic-gate int psm_status = 0; 665*0Sstevel@tonic-gate int pci_status = 0; 666*0Sstevel@tonic-gate int pci_rval, psm_rval = PSM_FAILURE; 667*0Sstevel@tonic-gate int types = 0; 668*0Sstevel@tonic-gate int i, j; 669*0Sstevel@tonic-gate int behavior; 670*0Sstevel@tonic-gate ddi_intrspec_t isp; 671*0Sstevel@tonic-gate struct intrspec *ispec; 672*0Sstevel@tonic-gate ddi_intr_handle_impl_t tmp_hdl; 673*0Sstevel@tonic-gate ddi_intr_msix_t *msix_p; 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, 676*0Sstevel@tonic-gate "pci_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n", 677*0Sstevel@tonic-gate (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate /* Process the request */ 680*0Sstevel@tonic-gate switch (intr_op) { 681*0Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 682*0Sstevel@tonic-gate /* Fixed supported by default */ 683*0Sstevel@tonic-gate *(int *)result = DDI_INTR_TYPE_FIXED; 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate /* Figure out if MSI or MSI-X is supported? */ 686*0Sstevel@tonic-gate if (pci_msi_get_supported_type(rdip, &types) != DDI_SUCCESS) 687*0Sstevel@tonic-gate return (DDI_SUCCESS); 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate if (psm_intr_ops != NULL) { 690*0Sstevel@tonic-gate /* MSI or MSI-X is supported, OR it in */ 691*0Sstevel@tonic-gate *(int *)result |= types; 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate tmp_hdl.ih_type = *(int *)result; 694*0Sstevel@tonic-gate (void) (*psm_intr_ops)(rdip, &tmp_hdl, 695*0Sstevel@tonic-gate PSM_INTR_OP_CHECK_MSI, result); 696*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: rdip: 0x%p " 697*0Sstevel@tonic-gate "supported types: 0x%x\n", (void *)rdip, 698*0Sstevel@tonic-gate *(int *)result)); 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate break; 701*0Sstevel@tonic-gate case DDI_INTROP_NINTRS: 702*0Sstevel@tonic-gate if (pci_get_nintrs(rdip, hdlp->ih_type, result) != DDI_SUCCESS) 703*0Sstevel@tonic-gate return (DDI_FAILURE); 704*0Sstevel@tonic-gate break; 705*0Sstevel@tonic-gate case DDI_INTROP_ALLOC: 706*0Sstevel@tonic-gate /* 707*0Sstevel@tonic-gate * MSI or MSIX (figure out number of vectors available) 708*0Sstevel@tonic-gate * FIXED interrupts: just return available interrupts 709*0Sstevel@tonic-gate */ 710*0Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 711*0Sstevel@tonic-gate (psm_intr_ops != NULL) && 712*0Sstevel@tonic-gate (pci_get_priority(rdip, hdlp->ih_inum, 713*0Sstevel@tonic-gate &priority) == DDI_SUCCESS)) { 714*0Sstevel@tonic-gate hdlp->ih_pri = priority; 715*0Sstevel@tonic-gate behavior = hdlp->ih_scratch2; 716*0Sstevel@tonic-gate (void) (*psm_intr_ops)(rdip, hdlp, 717*0Sstevel@tonic-gate PSM_INTR_OP_ALLOC_VECTORS, result); 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate /* verify behavior flag and take appropriate action */ 720*0Sstevel@tonic-gate if ((behavior == DDI_INTR_ALLOC_STRICT) && 721*0Sstevel@tonic-gate (*(int *)result < hdlp->ih_scratch1)) { 722*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: " 723*0Sstevel@tonic-gate "behavior %x, couldn't get enough intrs\n", 724*0Sstevel@tonic-gate behavior)); 725*0Sstevel@tonic-gate hdlp->ih_scratch1 = *(int *)result; 726*0Sstevel@tonic-gate (void) (*psm_intr_ops)(rdip, hdlp, 727*0Sstevel@tonic-gate PSM_INTR_OP_FREE_VECTORS, NULL); 728*0Sstevel@tonic-gate return (DDI_EAGAIN); 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 732*0Sstevel@tonic-gate if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) { 733*0Sstevel@tonic-gate msix_p = pci_msix_init(hdlp->ih_dip); 734*0Sstevel@tonic-gate if (msix_p) 735*0Sstevel@tonic-gate i_ddi_set_msix(hdlp->ih_dip, 736*0Sstevel@tonic-gate msix_p); 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate msix_p->msix_intrs_in_use += *(int *)result; 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 742*0Sstevel@tonic-gate /* Figure out if this device supports MASKING */ 743*0Sstevel@tonic-gate pci_rval = pci_intx_get_cap(rdip, &pci_status); 744*0Sstevel@tonic-gate if (pci_rval == DDI_SUCCESS && pci_status) 745*0Sstevel@tonic-gate hdlp->ih_cap |= pci_status; 746*0Sstevel@tonic-gate *(int *)result = 1; /* DDI_INTR_TYPE_FIXED */ 747*0Sstevel@tonic-gate } else 748*0Sstevel@tonic-gate return (DDI_FAILURE); 749*0Sstevel@tonic-gate break; 750*0Sstevel@tonic-gate case DDI_INTROP_FREE: 751*0Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 752*0Sstevel@tonic-gate (psm_intr_ops != NULL)) { 753*0Sstevel@tonic-gate (void) (*psm_intr_ops)(rdip, hdlp, 754*0Sstevel@tonic-gate PSM_INTR_OP_FREE_VECTORS, NULL); 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 757*0Sstevel@tonic-gate msix_p = i_ddi_get_msix(hdlp->ih_dip); 758*0Sstevel@tonic-gate if (msix_p && 759*0Sstevel@tonic-gate --msix_p->msix_intrs_in_use == 0) { 760*0Sstevel@tonic-gate pci_msix_fini(msix_p); 761*0Sstevel@tonic-gate i_ddi_set_msix(hdlp->ih_dip, NULL); 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate } 765*0Sstevel@tonic-gate break; 766*0Sstevel@tonic-gate case DDI_INTROP_GETPRI: 767*0Sstevel@tonic-gate if (pci_get_priority(rdip, hdlp->ih_inum, &priority) != 768*0Sstevel@tonic-gate DDI_SUCCESS) /* Get the priority */ 769*0Sstevel@tonic-gate return (DDI_FAILURE); 770*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: priority = 0x%x\n", 771*0Sstevel@tonic-gate priority)); 772*0Sstevel@tonic-gate *(int *)result = priority; 773*0Sstevel@tonic-gate break; 774*0Sstevel@tonic-gate case DDI_INTROP_SETPRI: 775*0Sstevel@tonic-gate /* Validate the interrupt priority passed */ 776*0Sstevel@tonic-gate if (*(int *)result > LOCK_LEVEL) 777*0Sstevel@tonic-gate return (DDI_FAILURE); 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate /* Ensure that PSM is all initialized */ 780*0Sstevel@tonic-gate if (psm_intr_ops == NULL) 781*0Sstevel@tonic-gate return (DDI_FAILURE); 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate /* Change the priority */ 784*0Sstevel@tonic-gate if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 785*0Sstevel@tonic-gate PSM_FAILURE) 786*0Sstevel@tonic-gate return (DDI_FAILURE); 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate /* update ispec */ 789*0Sstevel@tonic-gate isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 790*0Sstevel@tonic-gate ispec = (struct intrspec *)isp; 791*0Sstevel@tonic-gate ispec->intrspec_pri = *(int *)result; 792*0Sstevel@tonic-gate break; 793*0Sstevel@tonic-gate case DDI_INTROP_ADDISR: 794*0Sstevel@tonic-gate /* update ispec */ 795*0Sstevel@tonic-gate isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 796*0Sstevel@tonic-gate ispec = (struct intrspec *)isp; 797*0Sstevel@tonic-gate ispec->intrspec_func = hdlp->ih_cb_func; 798*0Sstevel@tonic-gate break; 799*0Sstevel@tonic-gate case DDI_INTROP_REMISR: 800*0Sstevel@tonic-gate /* Get the interrupt structure pointer */ 801*0Sstevel@tonic-gate isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 802*0Sstevel@tonic-gate ispec = (struct intrspec *)isp; 803*0Sstevel@tonic-gate ispec->intrspec_func = (uint_t (*)()) 0; 804*0Sstevel@tonic-gate break; 805*0Sstevel@tonic-gate case DDI_INTROP_GETCAP: 806*0Sstevel@tonic-gate /* 807*0Sstevel@tonic-gate * First check the config space and/or 808*0Sstevel@tonic-gate * MSI capability register(s) 809*0Sstevel@tonic-gate */ 810*0Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 811*0Sstevel@tonic-gate pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type, 812*0Sstevel@tonic-gate &pci_status); 813*0Sstevel@tonic-gate else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 814*0Sstevel@tonic-gate pci_rval = pci_intx_get_cap(rdip, &pci_status); 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate /* next check with pcplusmp */ 817*0Sstevel@tonic-gate if (psm_intr_ops != NULL) 818*0Sstevel@tonic-gate psm_rval = (*psm_intr_ops)(rdip, hdlp, 819*0Sstevel@tonic-gate PSM_INTR_OP_GET_CAP, &psm_status); 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, " 822*0Sstevel@tonic-gate "psm_status = %x, pci_rval = %x, pci_status = %x\n", 823*0Sstevel@tonic-gate psm_rval, psm_status, pci_rval, pci_status)); 824*0Sstevel@tonic-gate 825*0Sstevel@tonic-gate if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 826*0Sstevel@tonic-gate *(int *)result = 0; 827*0Sstevel@tonic-gate return (DDI_FAILURE); 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate if (psm_rval == PSM_SUCCESS) 831*0Sstevel@tonic-gate *(int *)result = psm_status; 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate if (pci_rval == DDI_SUCCESS) 834*0Sstevel@tonic-gate *(int *)result |= pci_status; 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n", 837*0Sstevel@tonic-gate *(int *)result)); 838*0Sstevel@tonic-gate break; 839*0Sstevel@tonic-gate case DDI_INTROP_SETCAP: 840*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: SETCAP cap=0x%x\n", 841*0Sstevel@tonic-gate *(int *)result)); 842*0Sstevel@tonic-gate if (psm_intr_ops == NULL) 843*0Sstevel@tonic-gate return (DDI_FAILURE); 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) { 846*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops" 847*0Sstevel@tonic-gate " returned failure\n")); 848*0Sstevel@tonic-gate return (DDI_FAILURE); 849*0Sstevel@tonic-gate } 850*0Sstevel@tonic-gate break; 851*0Sstevel@tonic-gate case DDI_INTROP_ENABLE: 852*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: ENABLE\n")); 853*0Sstevel@tonic-gate if (psm_intr_ops == NULL) 854*0Sstevel@tonic-gate return (DDI_FAILURE); 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) != 857*0Sstevel@tonic-gate DDI_SUCCESS) 858*0Sstevel@tonic-gate return (DDI_FAILURE); 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: ENABLE vector=0x%x\n", 861*0Sstevel@tonic-gate hdlp->ih_vector)); 862*0Sstevel@tonic-gate break; 863*0Sstevel@tonic-gate case DDI_INTROP_DISABLE: 864*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: DISABLE\n")); 865*0Sstevel@tonic-gate if (psm_intr_ops == NULL) 866*0Sstevel@tonic-gate return (DDI_FAILURE); 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 869*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: DISABLE vector = %x\n", 870*0Sstevel@tonic-gate hdlp->ih_vector)); 871*0Sstevel@tonic-gate break; 872*0Sstevel@tonic-gate case DDI_INTROP_BLOCKENABLE: 873*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: BLOCKENABLE\n")); 874*0Sstevel@tonic-gate if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 875*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n")); 876*0Sstevel@tonic-gate return (DDI_FAILURE); 877*0Sstevel@tonic-gate } 878*0Sstevel@tonic-gate 879*0Sstevel@tonic-gate /* Check if psm_intr_ops is NULL? */ 880*0Sstevel@tonic-gate if (psm_intr_ops == NULL) 881*0Sstevel@tonic-gate return (DDI_FAILURE); 882*0Sstevel@tonic-gate 883*0Sstevel@tonic-gate for (i = 0; i < hdlp->ih_scratch1; i++) { 884*0Sstevel@tonic-gate if (pci_enable_intr(pdip, rdip, hdlp, 885*0Sstevel@tonic-gate hdlp->ih_inum + i) != DDI_SUCCESS) { 886*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: " 887*0Sstevel@tonic-gate "pci_enable_intr failed for %d\n", i)); 888*0Sstevel@tonic-gate for (j = 0; j < i; j++) 889*0Sstevel@tonic-gate pci_disable_intr(pdip, rdip, hdlp, 890*0Sstevel@tonic-gate hdlp->ih_inum + j); 891*0Sstevel@tonic-gate return (DDI_FAILURE); 892*0Sstevel@tonic-gate } 893*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: BLOCKENABLE " 894*0Sstevel@tonic-gate "inum %x done\n", hdlp->ih_inum + i)); 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate break; 897*0Sstevel@tonic-gate case DDI_INTROP_BLOCKDISABLE: 898*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: BLOCKDISABLE\n")); 899*0Sstevel@tonic-gate if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 900*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n")); 901*0Sstevel@tonic-gate return (DDI_FAILURE); 902*0Sstevel@tonic-gate } 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate /* Check if psm_intr_ops is present */ 905*0Sstevel@tonic-gate if (psm_intr_ops == NULL) 906*0Sstevel@tonic-gate return (DDI_FAILURE); 907*0Sstevel@tonic-gate 908*0Sstevel@tonic-gate for (i = 0; i < hdlp->ih_scratch1; i++) { 909*0Sstevel@tonic-gate pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum + i); 910*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: BLOCKDISABLE " 911*0Sstevel@tonic-gate "inum %x done\n", hdlp->ih_inum + i)); 912*0Sstevel@tonic-gate } 913*0Sstevel@tonic-gate break; 914*0Sstevel@tonic-gate case DDI_INTROP_SETMASK: 915*0Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 916*0Sstevel@tonic-gate /* 917*0Sstevel@tonic-gate * First handle in the config space 918*0Sstevel@tonic-gate */ 919*0Sstevel@tonic-gate if (intr_op == DDI_INTROP_SETMASK) { 920*0Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 921*0Sstevel@tonic-gate pci_status = pci_msi_set_mask(rdip, 922*0Sstevel@tonic-gate hdlp->ih_type, hdlp->ih_inum); 923*0Sstevel@tonic-gate else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 924*0Sstevel@tonic-gate pci_status = pci_intx_set_mask(rdip); 925*0Sstevel@tonic-gate } else { 926*0Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 927*0Sstevel@tonic-gate pci_status = pci_msi_clr_mask(rdip, 928*0Sstevel@tonic-gate hdlp->ih_type, hdlp->ih_inum); 929*0Sstevel@tonic-gate else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 930*0Sstevel@tonic-gate pci_status = pci_intx_clr_mask(rdip); 931*0Sstevel@tonic-gate } 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate /* For MSI/X; no need to check with pcplusmp */ 934*0Sstevel@tonic-gate if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 935*0Sstevel@tonic-gate return (pci_status); 936*0Sstevel@tonic-gate 937*0Sstevel@tonic-gate /* For fixed interrupts only: handle config space first */ 938*0Sstevel@tonic-gate if (hdlp->ih_type == DDI_INTR_TYPE_FIXED && 939*0Sstevel@tonic-gate pci_status == DDI_SUCCESS) 940*0Sstevel@tonic-gate break; 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate /* For fixed interrupts only: confer with pcplusmp next */ 943*0Sstevel@tonic-gate if (psm_intr_ops != NULL) { 944*0Sstevel@tonic-gate /* If interrupt is shared; do nothing */ 945*0Sstevel@tonic-gate psm_rval = (*psm_intr_ops)(rdip, hdlp, 946*0Sstevel@tonic-gate PSM_INTR_OP_GET_SHARED, &psm_status); 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate if (psm_rval == PSM_FAILURE || psm_status == 1) 949*0Sstevel@tonic-gate return (pci_status); 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate /* Now, pcplusmp should try to set/clear the mask */ 952*0Sstevel@tonic-gate if (intr_op == DDI_INTROP_SETMASK) 953*0Sstevel@tonic-gate psm_rval = (*psm_intr_ops)(rdip, hdlp, 954*0Sstevel@tonic-gate PSM_INTR_OP_SET_MASK, NULL); 955*0Sstevel@tonic-gate else 956*0Sstevel@tonic-gate psm_rval = (*psm_intr_ops)(rdip, hdlp, 957*0Sstevel@tonic-gate PSM_INTR_OP_CLEAR_MASK, NULL); 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS); 960*0Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 961*0Sstevel@tonic-gate /* 962*0Sstevel@tonic-gate * First check the config space and/or 963*0Sstevel@tonic-gate * MSI capability register(s) 964*0Sstevel@tonic-gate */ 965*0Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 966*0Sstevel@tonic-gate pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type, 967*0Sstevel@tonic-gate hdlp->ih_inum, &pci_status); 968*0Sstevel@tonic-gate else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 969*0Sstevel@tonic-gate pci_rval = pci_intx_get_pending(rdip, &pci_status); 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate /* On failure; next try with pcplusmp */ 972*0Sstevel@tonic-gate if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL) 973*0Sstevel@tonic-gate psm_rval = (*psm_intr_ops)(rdip, hdlp, 974*0Sstevel@tonic-gate PSM_INTR_OP_GET_PENDING, &psm_status); 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned " 977*0Sstevel@tonic-gate "psm_rval = %x, psm_status = %x, pci_rval = %x, " 978*0Sstevel@tonic-gate "pci_status = %x\n", psm_rval, psm_status, pci_rval, 979*0Sstevel@tonic-gate pci_status)); 980*0Sstevel@tonic-gate if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 981*0Sstevel@tonic-gate *(int *)result = 0; 982*0Sstevel@tonic-gate return (DDI_FAILURE); 983*0Sstevel@tonic-gate } 984*0Sstevel@tonic-gate 985*0Sstevel@tonic-gate if (psm_rval != PSM_FAILURE) 986*0Sstevel@tonic-gate *(int *)result = psm_status; 987*0Sstevel@tonic-gate else if (pci_rval != DDI_FAILURE) 988*0Sstevel@tonic-gate *(int *)result = pci_status; 989*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n", 990*0Sstevel@tonic-gate *(int *)result)); 991*0Sstevel@tonic-gate break; 992*0Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 993*0Sstevel@tonic-gate if ((psm_intr_ops != NULL) && (pci_get_priority(rdip, 994*0Sstevel@tonic-gate hdlp->ih_inum, &priority) == DDI_SUCCESS)) { 995*0Sstevel@tonic-gate /* Priority in the handle not initialized yet */ 996*0Sstevel@tonic-gate hdlp->ih_pri = priority; 997*0Sstevel@tonic-gate (void) (*psm_intr_ops)(rdip, hdlp, 998*0Sstevel@tonic-gate PSM_INTR_OP_NAVAIL_VECTORS, result); 999*0Sstevel@tonic-gate } else { 1000*0Sstevel@tonic-gate *(int *)result = 1; 1001*0Sstevel@tonic-gate } 1002*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci: NAVAIL returned = %x\n", 1003*0Sstevel@tonic-gate *(int *)result)); 1004*0Sstevel@tonic-gate break; 1005*0Sstevel@tonic-gate default: 1006*0Sstevel@tonic-gate return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 1007*0Sstevel@tonic-gate } 1008*0Sstevel@tonic-gate 1009*0Sstevel@tonic-gate return (DDI_SUCCESS); 1010*0Sstevel@tonic-gate } 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate 1013*0Sstevel@tonic-gate static int 1014*0Sstevel@tonic-gate pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 1015*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, uint32_t inum) 1016*0Sstevel@tonic-gate { 1017*0Sstevel@tonic-gate int vector; 1018*0Sstevel@tonic-gate struct intrspec *ispec; 1019*0Sstevel@tonic-gate 1020*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 1021*0Sstevel@tonic-gate (void *)hdlp, inum)); 1022*0Sstevel@tonic-gate 1023*0Sstevel@tonic-gate /* Translate the interrupt if needed */ 1024*0Sstevel@tonic-gate ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 1025*0Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 1026*0Sstevel@tonic-gate ispec->intrspec_vec = inum; 1027*0Sstevel@tonic-gate hdlp->ih_private = (void *)ispec; 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate /* translate the interrupt if needed */ 1030*0Sstevel@tonic-gate (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &vector); 1031*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x vector=%x\n", 1032*0Sstevel@tonic-gate hdlp->ih_pri, vector)); 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate /* Add the interrupt handler */ 1035*0Sstevel@tonic-gate if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 1036*0Sstevel@tonic-gate DEVI(rdip)->devi_name, vector, hdlp->ih_cb_arg1, 1037*0Sstevel@tonic-gate hdlp->ih_cb_arg2, rdip)) 1038*0Sstevel@tonic-gate return (DDI_FAILURE); 1039*0Sstevel@tonic-gate 1040*0Sstevel@tonic-gate return (DDI_SUCCESS); 1041*0Sstevel@tonic-gate } 1042*0Sstevel@tonic-gate 1043*0Sstevel@tonic-gate 1044*0Sstevel@tonic-gate static void 1045*0Sstevel@tonic-gate pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 1046*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, uint32_t inum) 1047*0Sstevel@tonic-gate { 1048*0Sstevel@tonic-gate int vector; 1049*0Sstevel@tonic-gate struct intrspec *ispec; 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 1052*0Sstevel@tonic-gate ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 1053*0Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 1054*0Sstevel@tonic-gate ispec->intrspec_vec = inum; 1055*0Sstevel@tonic-gate hdlp->ih_private = (void *)ispec; 1056*0Sstevel@tonic-gate 1057*0Sstevel@tonic-gate /* translate the interrupt if needed */ 1058*0Sstevel@tonic-gate (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &vector); 1059*0Sstevel@tonic-gate 1060*0Sstevel@tonic-gate /* Disable the interrupt handler */ 1061*0Sstevel@tonic-gate rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, vector); 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate 1064*0Sstevel@tonic-gate 1065*0Sstevel@tonic-gate /*ARGSUSED*/ 1066*0Sstevel@tonic-gate static int 1067*0Sstevel@tonic-gate pci_ctlops(dev_info_t *dip, dev_info_t *rdip, 1068*0Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 1069*0Sstevel@tonic-gate { 1070*0Sstevel@tonic-gate pci_regspec_t *drv_regp; 1071*0Sstevel@tonic-gate uint_t reglen; 1072*0Sstevel@tonic-gate int rn; 1073*0Sstevel@tonic-gate int totreg; 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate switch (ctlop) { 1076*0Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 1077*0Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 1078*0Sstevel@tonic-gate return (DDI_FAILURE); 1079*0Sstevel@tonic-gate cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", 1080*0Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip), 1081*0Sstevel@tonic-gate ddi_driver_name(rdip), 1082*0Sstevel@tonic-gate ddi_get_instance(rdip)); 1083*0Sstevel@tonic-gate return (DDI_SUCCESS); 1084*0Sstevel@tonic-gate 1085*0Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 1086*0Sstevel@tonic-gate return (pci_initchild((dev_info_t *)arg)); 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 1089*0Sstevel@tonic-gate return (pci_removechild((dev_info_t *)arg)); 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate case DDI_CTLOPS_NINTRS: 1092*0Sstevel@tonic-gate if (ddi_get_parent_data(rdip)) 1093*0Sstevel@tonic-gate *(int *)result = 1; 1094*0Sstevel@tonic-gate else 1095*0Sstevel@tonic-gate *(int *)result = 0; 1096*0Sstevel@tonic-gate return (DDI_SUCCESS); 1097*0Sstevel@tonic-gate 1098*0Sstevel@tonic-gate case DDI_CTLOPS_XLATE_INTRS: 1099*0Sstevel@tonic-gate return (DDI_SUCCESS); 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 1102*0Sstevel@tonic-gate return (DDI_SUCCESS); 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 1105*0Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 1106*0Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 1107*0Sstevel@tonic-gate return (DDI_FAILURE); 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate *(int *)result = 0; 1110*0Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 1111*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (int **)&drv_regp, 1112*0Sstevel@tonic-gate ®len) != DDI_PROP_SUCCESS) { 1113*0Sstevel@tonic-gate return (DDI_FAILURE); 1114*0Sstevel@tonic-gate } 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t); 1117*0Sstevel@tonic-gate if (ctlop == DDI_CTLOPS_NREGS) 1118*0Sstevel@tonic-gate *(int *)result = totreg; 1119*0Sstevel@tonic-gate else if (ctlop == DDI_CTLOPS_REGSIZE) { 1120*0Sstevel@tonic-gate rn = *(int *)arg; 1121*0Sstevel@tonic-gate if (rn >= totreg) { 1122*0Sstevel@tonic-gate ddi_prop_free(drv_regp); 1123*0Sstevel@tonic-gate return (DDI_FAILURE); 1124*0Sstevel@tonic-gate } 1125*0Sstevel@tonic-gate *(off_t *)result = drv_regp[rn].pci_size_low; 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate ddi_prop_free(drv_regp); 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate return (DDI_SUCCESS); 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate case DDI_CTLOPS_POWER: { 1132*0Sstevel@tonic-gate power_req_t *reqp = (power_req_t *)arg; 1133*0Sstevel@tonic-gate /* 1134*0Sstevel@tonic-gate * We currently understand reporting of PCI_PM_IDLESPEED 1135*0Sstevel@tonic-gate * capability. Everything else is passed up. 1136*0Sstevel@tonic-gate */ 1137*0Sstevel@tonic-gate if ((reqp->request_type == PMR_REPORT_PMCAP) && 1138*0Sstevel@tonic-gate (reqp->req.report_pmcap_req.cap == PCI_PM_IDLESPEED)) { 1139*0Sstevel@tonic-gate 1140*0Sstevel@tonic-gate return (DDI_SUCCESS); 1141*0Sstevel@tonic-gate } 1142*0Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 1143*0Sstevel@tonic-gate } 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate default: 1146*0Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 1147*0Sstevel@tonic-gate } 1148*0Sstevel@tonic-gate 1149*0Sstevel@tonic-gate /* NOTREACHED */ 1150*0Sstevel@tonic-gate 1151*0Sstevel@tonic-gate } 1152*0Sstevel@tonic-gate 1153*0Sstevel@tonic-gate /* 1154*0Sstevel@tonic-gate * Assign the address portion of the node name 1155*0Sstevel@tonic-gate */ 1156*0Sstevel@tonic-gate static int 1157*0Sstevel@tonic-gate pci_name_child(dev_info_t *child, char *name, int namelen) 1158*0Sstevel@tonic-gate { 1159*0Sstevel@tonic-gate pci_regspec_t *pci_rp; 1160*0Sstevel@tonic-gate char **unit_addr; 1161*0Sstevel@tonic-gate int dev, func, length; 1162*0Sstevel@tonic-gate uint_t n; 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 1165*0Sstevel@tonic-gate /* 1166*0Sstevel@tonic-gate * For .conf node, use "unit-address" property 1167*0Sstevel@tonic-gate */ 1168*0Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 1169*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 1170*0Sstevel@tonic-gate DDI_PROP_SUCCESS) { 1171*0Sstevel@tonic-gate cmn_err(CE_WARN, 1172*0Sstevel@tonic-gate "cannot find unit-address in %s.conf", 1173*0Sstevel@tonic-gate ddi_get_name(child)); 1174*0Sstevel@tonic-gate return (DDI_FAILURE); 1175*0Sstevel@tonic-gate } 1176*0Sstevel@tonic-gate if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 1177*0Sstevel@tonic-gate cmn_err(CE_WARN, "unit-address property in %s.conf" 1178*0Sstevel@tonic-gate " not well-formed", ddi_get_name(child)); 1179*0Sstevel@tonic-gate ddi_prop_free(unit_addr); 1180*0Sstevel@tonic-gate return (DDI_FAILURE); 1181*0Sstevel@tonic-gate } 1182*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%s", *unit_addr); 1183*0Sstevel@tonic-gate ddi_prop_free(unit_addr); 1184*0Sstevel@tonic-gate return (DDI_SUCCESS); 1185*0Sstevel@tonic-gate } 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 1188*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 1189*0Sstevel@tonic-gate (uint_t *)&length) != DDI_PROP_SUCCESS) { 1190*0Sstevel@tonic-gate cmn_err(CE_WARN, "cannot find reg property in %s", 1191*0Sstevel@tonic-gate ddi_get_name(child)); 1192*0Sstevel@tonic-gate return (DDI_FAILURE); 1193*0Sstevel@tonic-gate } 1194*0Sstevel@tonic-gate 1195*0Sstevel@tonic-gate /* copy the device identifications */ 1196*0Sstevel@tonic-gate dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 1197*0Sstevel@tonic-gate func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate /* 1200*0Sstevel@tonic-gate * free the memory allocated by ddi_prop_lookup_int_array 1201*0Sstevel@tonic-gate */ 1202*0Sstevel@tonic-gate ddi_prop_free(pci_rp); 1203*0Sstevel@tonic-gate 1204*0Sstevel@tonic-gate if (func != 0) { 1205*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", dev, func); 1206*0Sstevel@tonic-gate } else { 1207*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%x", dev); 1208*0Sstevel@tonic-gate } 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate return (DDI_SUCCESS); 1211*0Sstevel@tonic-gate } 1212*0Sstevel@tonic-gate 1213*0Sstevel@tonic-gate static int 1214*0Sstevel@tonic-gate pci_initchild(dev_info_t *child) 1215*0Sstevel@tonic-gate { 1216*0Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 1217*0Sstevel@tonic-gate char name[80]; 1218*0Sstevel@tonic-gate 1219*0Sstevel@tonic-gate if (pci_name_child(child, name, 80) != DDI_SUCCESS) { 1220*0Sstevel@tonic-gate return (DDI_FAILURE); 1221*0Sstevel@tonic-gate } 1222*0Sstevel@tonic-gate ddi_set_name_addr(child, name); 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate /* 1225*0Sstevel@tonic-gate * Pseudo nodes indicate a prototype node with per-instance 1226*0Sstevel@tonic-gate * properties to be merged into the real h/w device node. 1227*0Sstevel@tonic-gate * The interpretation of the unit-address is DD[,F] 1228*0Sstevel@tonic-gate * where DD is the device id and F is the function. 1229*0Sstevel@tonic-gate */ 1230*0Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 1231*0Sstevel@tonic-gate extern int pci_allow_pseudo_children; 1232*0Sstevel@tonic-gate 1233*0Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 1234*0Sstevel@tonic-gate 1235*0Sstevel@tonic-gate /* 1236*0Sstevel@tonic-gate * Try to merge the properties from this prototype 1237*0Sstevel@tonic-gate * node into real h/w nodes. 1238*0Sstevel@tonic-gate */ 1239*0Sstevel@tonic-gate if (ndi_merge_node(child, pci_name_child) == DDI_SUCCESS) { 1240*0Sstevel@tonic-gate /* 1241*0Sstevel@tonic-gate * Merged ok - return failure to remove the node. 1242*0Sstevel@tonic-gate */ 1243*0Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 1244*0Sstevel@tonic-gate return (DDI_FAILURE); 1245*0Sstevel@tonic-gate } 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate /* workaround for ddivs to run under PCI */ 1248*0Sstevel@tonic-gate if (pci_allow_pseudo_children) { 1249*0Sstevel@tonic-gate /* 1250*0Sstevel@tonic-gate * If the "interrupts" property doesn't exist, 1251*0Sstevel@tonic-gate * this must be the ddivs no-intr case, and it returns 1252*0Sstevel@tonic-gate * DDI_SUCCESS instead of DDI_FAILURE. 1253*0Sstevel@tonic-gate */ 1254*0Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, child, 1255*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "interrupts", -1) == -1) 1256*0Sstevel@tonic-gate return (DDI_SUCCESS); 1257*0Sstevel@tonic-gate /* 1258*0Sstevel@tonic-gate * Create the ddi_parent_private_data for a pseudo 1259*0Sstevel@tonic-gate * child. 1260*0Sstevel@tonic-gate */ 1261*0Sstevel@tonic-gate pdptr = (struct ddi_parent_private_data *)kmem_zalloc( 1262*0Sstevel@tonic-gate (sizeof (struct ddi_parent_private_data) + 1263*0Sstevel@tonic-gate sizeof (struct intrspec)), KM_SLEEP); 1264*0Sstevel@tonic-gate pdptr->par_intr = (struct intrspec *)(pdptr + 1); 1265*0Sstevel@tonic-gate pdptr->par_nintr = 1; 1266*0Sstevel@tonic-gate ddi_set_parent_data(child, pdptr); 1267*0Sstevel@tonic-gate return (DDI_SUCCESS); 1268*0Sstevel@tonic-gate } 1269*0Sstevel@tonic-gate 1270*0Sstevel@tonic-gate /* 1271*0Sstevel@tonic-gate * The child was not merged into a h/w node, 1272*0Sstevel@tonic-gate * but there's not much we can do with it other 1273*0Sstevel@tonic-gate * than return failure to cause the node to be removed. 1274*0Sstevel@tonic-gate */ 1275*0Sstevel@tonic-gate cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 1276*0Sstevel@tonic-gate ddi_get_name(child), ddi_get_name_addr(child), 1277*0Sstevel@tonic-gate ddi_get_name(child)); 1278*0Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 1279*0Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 1280*0Sstevel@tonic-gate } 1281*0Sstevel@tonic-gate 1282*0Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 1283*0Sstevel@tonic-gate "interrupts", -1) != -1) { 1284*0Sstevel@tonic-gate pdptr = (struct ddi_parent_private_data *) 1285*0Sstevel@tonic-gate kmem_zalloc((sizeof (struct ddi_parent_private_data) + 1286*0Sstevel@tonic-gate sizeof (struct intrspec)), KM_SLEEP); 1287*0Sstevel@tonic-gate pdptr->par_intr = (struct intrspec *)(pdptr + 1); 1288*0Sstevel@tonic-gate pdptr->par_nintr = 1; 1289*0Sstevel@tonic-gate ddi_set_parent_data(child, pdptr); 1290*0Sstevel@tonic-gate } else 1291*0Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 1292*0Sstevel@tonic-gate 1293*0Sstevel@tonic-gate return (DDI_SUCCESS); 1294*0Sstevel@tonic-gate } 1295*0Sstevel@tonic-gate 1296*0Sstevel@tonic-gate static int 1297*0Sstevel@tonic-gate pci_removechild(dev_info_t *dip) 1298*0Sstevel@tonic-gate { 1299*0Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 1300*0Sstevel@tonic-gate 1301*0Sstevel@tonic-gate if ((pdptr = ddi_get_parent_data(dip)) != NULL) { 1302*0Sstevel@tonic-gate kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec))); 1303*0Sstevel@tonic-gate ddi_set_parent_data(dip, NULL); 1304*0Sstevel@tonic-gate } 1305*0Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 1306*0Sstevel@tonic-gate 1307*0Sstevel@tonic-gate /* 1308*0Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 1309*0Sstevel@tonic-gate */ 1310*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 1311*0Sstevel@tonic-gate 1312*0Sstevel@tonic-gate impl_rem_dev_props(dip); 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate return (DDI_SUCCESS); 1315*0Sstevel@tonic-gate } 1316*0Sstevel@tonic-gate 1317*0Sstevel@tonic-gate 1318*0Sstevel@tonic-gate /* 1319*0Sstevel@tonic-gate * These are the get and put functions to be shared with drivers. The 1320*0Sstevel@tonic-gate * mutex locking is done inside the functions referenced, rather than 1321*0Sstevel@tonic-gate * here, and is thus shared across PCI child drivers and any other 1322*0Sstevel@tonic-gate * consumers of PCI config space (such as the ACPI subsystem). 1323*0Sstevel@tonic-gate * 1324*0Sstevel@tonic-gate * The configuration space addresses come in as pointers. This is fine on 1325*0Sstevel@tonic-gate * a 32-bit system, where the VM space and configuration space are the same 1326*0Sstevel@tonic-gate * size. It's not such a good idea on a 64-bit system, where memory 1327*0Sstevel@tonic-gate * addresses are twice as large as configuration space addresses. At some 1328*0Sstevel@tonic-gate * point in the call tree we need to take a stand and say "you are 32-bit 1329*0Sstevel@tonic-gate * from this time forth", and this seems like a nice self-contained place. 1330*0Sstevel@tonic-gate */ 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate static uint8_t 1333*0Sstevel@tonic-gate pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 1334*0Sstevel@tonic-gate { 1335*0Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 1336*0Sstevel@tonic-gate uint8_t rval; 1337*0Sstevel@tonic-gate int reg; 1338*0Sstevel@tonic-gate 1339*0Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 1340*0Sstevel@tonic-gate 1341*0Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 1342*0Sstevel@tonic-gate 1343*0Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1344*0Sstevel@tonic-gate 1345*0Sstevel@tonic-gate rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 1346*0Sstevel@tonic-gate reg); 1347*0Sstevel@tonic-gate 1348*0Sstevel@tonic-gate return (rval); 1349*0Sstevel@tonic-gate } 1350*0Sstevel@tonic-gate 1351*0Sstevel@tonic-gate static void 1352*0Sstevel@tonic-gate pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 1353*0Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags) 1354*0Sstevel@tonic-gate { 1355*0Sstevel@tonic-gate uint8_t *h, *d; 1356*0Sstevel@tonic-gate 1357*0Sstevel@tonic-gate h = host_addr; 1358*0Sstevel@tonic-gate d = dev_addr; 1359*0Sstevel@tonic-gate 1360*0Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 1361*0Sstevel@tonic-gate for (; repcount; repcount--) 1362*0Sstevel@tonic-gate *h++ = pci_config_rd8(hdlp, d++); 1363*0Sstevel@tonic-gate else 1364*0Sstevel@tonic-gate for (; repcount; repcount--) 1365*0Sstevel@tonic-gate *h++ = pci_config_rd8(hdlp, d); 1366*0Sstevel@tonic-gate } 1367*0Sstevel@tonic-gate 1368*0Sstevel@tonic-gate static uint16_t 1369*0Sstevel@tonic-gate pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 1370*0Sstevel@tonic-gate { 1371*0Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 1372*0Sstevel@tonic-gate uint16_t rval; 1373*0Sstevel@tonic-gate int reg; 1374*0Sstevel@tonic-gate 1375*0Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 1376*0Sstevel@tonic-gate 1377*0Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 1378*0Sstevel@tonic-gate 1379*0Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1380*0Sstevel@tonic-gate 1381*0Sstevel@tonic-gate rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 1382*0Sstevel@tonic-gate reg); 1383*0Sstevel@tonic-gate 1384*0Sstevel@tonic-gate return (rval); 1385*0Sstevel@tonic-gate } 1386*0Sstevel@tonic-gate 1387*0Sstevel@tonic-gate static void 1388*0Sstevel@tonic-gate pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1389*0Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 1390*0Sstevel@tonic-gate { 1391*0Sstevel@tonic-gate uint16_t *h, *d; 1392*0Sstevel@tonic-gate 1393*0Sstevel@tonic-gate h = host_addr; 1394*0Sstevel@tonic-gate d = dev_addr; 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 1397*0Sstevel@tonic-gate for (; repcount; repcount--) 1398*0Sstevel@tonic-gate *h++ = pci_config_rd16(hdlp, d++); 1399*0Sstevel@tonic-gate else 1400*0Sstevel@tonic-gate for (; repcount; repcount--) 1401*0Sstevel@tonic-gate *h++ = pci_config_rd16(hdlp, d); 1402*0Sstevel@tonic-gate } 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate static uint32_t 1405*0Sstevel@tonic-gate pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 1406*0Sstevel@tonic-gate { 1407*0Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 1408*0Sstevel@tonic-gate uint32_t rval; 1409*0Sstevel@tonic-gate int reg; 1410*0Sstevel@tonic-gate 1411*0Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 1414*0Sstevel@tonic-gate 1415*0Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1416*0Sstevel@tonic-gate 1417*0Sstevel@tonic-gate rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 1418*0Sstevel@tonic-gate cfp->c_funcnum, reg); 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate return (rval); 1421*0Sstevel@tonic-gate } 1422*0Sstevel@tonic-gate 1423*0Sstevel@tonic-gate static void 1424*0Sstevel@tonic-gate pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1425*0Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 1426*0Sstevel@tonic-gate { 1427*0Sstevel@tonic-gate uint32_t *h, *d; 1428*0Sstevel@tonic-gate 1429*0Sstevel@tonic-gate h = host_addr; 1430*0Sstevel@tonic-gate d = dev_addr; 1431*0Sstevel@tonic-gate 1432*0Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 1433*0Sstevel@tonic-gate for (; repcount; repcount--) 1434*0Sstevel@tonic-gate *h++ = pci_config_rd32(hdlp, d++); 1435*0Sstevel@tonic-gate else 1436*0Sstevel@tonic-gate for (; repcount; repcount--) 1437*0Sstevel@tonic-gate *h++ = pci_config_rd32(hdlp, d); 1438*0Sstevel@tonic-gate } 1439*0Sstevel@tonic-gate 1440*0Sstevel@tonic-gate 1441*0Sstevel@tonic-gate static void 1442*0Sstevel@tonic-gate pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 1443*0Sstevel@tonic-gate { 1444*0Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 1445*0Sstevel@tonic-gate int reg; 1446*0Sstevel@tonic-gate 1447*0Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 1448*0Sstevel@tonic-gate 1449*0Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 1450*0Sstevel@tonic-gate 1451*0Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 1454*0Sstevel@tonic-gate cfp->c_funcnum, reg, value); 1455*0Sstevel@tonic-gate } 1456*0Sstevel@tonic-gate 1457*0Sstevel@tonic-gate static void 1458*0Sstevel@tonic-gate pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 1459*0Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags) 1460*0Sstevel@tonic-gate { 1461*0Sstevel@tonic-gate uint8_t *h, *d; 1462*0Sstevel@tonic-gate 1463*0Sstevel@tonic-gate h = host_addr; 1464*0Sstevel@tonic-gate d = dev_addr; 1465*0Sstevel@tonic-gate 1466*0Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 1467*0Sstevel@tonic-gate for (; repcount; repcount--) 1468*0Sstevel@tonic-gate pci_config_wr8(hdlp, d++, *h++); 1469*0Sstevel@tonic-gate else 1470*0Sstevel@tonic-gate for (; repcount; repcount--) 1471*0Sstevel@tonic-gate pci_config_wr8(hdlp, d, *h++); 1472*0Sstevel@tonic-gate } 1473*0Sstevel@tonic-gate 1474*0Sstevel@tonic-gate static void 1475*0Sstevel@tonic-gate pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 1476*0Sstevel@tonic-gate { 1477*0Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 1478*0Sstevel@tonic-gate int reg; 1479*0Sstevel@tonic-gate 1480*0Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 1481*0Sstevel@tonic-gate 1482*0Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 1483*0Sstevel@tonic-gate 1484*0Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1485*0Sstevel@tonic-gate 1486*0Sstevel@tonic-gate (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 1487*0Sstevel@tonic-gate cfp->c_funcnum, reg, value); 1488*0Sstevel@tonic-gate } 1489*0Sstevel@tonic-gate 1490*0Sstevel@tonic-gate static void 1491*0Sstevel@tonic-gate pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1492*0Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 1493*0Sstevel@tonic-gate { 1494*0Sstevel@tonic-gate uint16_t *h, *d; 1495*0Sstevel@tonic-gate 1496*0Sstevel@tonic-gate h = host_addr; 1497*0Sstevel@tonic-gate d = dev_addr; 1498*0Sstevel@tonic-gate 1499*0Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 1500*0Sstevel@tonic-gate for (; repcount; repcount--) 1501*0Sstevel@tonic-gate pci_config_wr16(hdlp, d++, *h++); 1502*0Sstevel@tonic-gate else 1503*0Sstevel@tonic-gate for (; repcount; repcount--) 1504*0Sstevel@tonic-gate pci_config_wr16(hdlp, d, *h++); 1505*0Sstevel@tonic-gate } 1506*0Sstevel@tonic-gate 1507*0Sstevel@tonic-gate static void 1508*0Sstevel@tonic-gate pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 1509*0Sstevel@tonic-gate { 1510*0Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 1511*0Sstevel@tonic-gate int reg; 1512*0Sstevel@tonic-gate 1513*0Sstevel@tonic-gate ASSERT64(((uintptr_t)addr >> 32) == 0); 1514*0Sstevel@tonic-gate 1515*0Sstevel@tonic-gate reg = (int)(uintptr_t)addr; 1516*0Sstevel@tonic-gate 1517*0Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1518*0Sstevel@tonic-gate 1519*0Sstevel@tonic-gate (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 1520*0Sstevel@tonic-gate cfp->c_funcnum, reg, value); 1521*0Sstevel@tonic-gate } 1522*0Sstevel@tonic-gate 1523*0Sstevel@tonic-gate static void 1524*0Sstevel@tonic-gate pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1525*0Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 1526*0Sstevel@tonic-gate { 1527*0Sstevel@tonic-gate uint32_t *h, *d; 1528*0Sstevel@tonic-gate 1529*0Sstevel@tonic-gate h = host_addr; 1530*0Sstevel@tonic-gate d = dev_addr; 1531*0Sstevel@tonic-gate 1532*0Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 1533*0Sstevel@tonic-gate for (; repcount; repcount--) 1534*0Sstevel@tonic-gate pci_config_wr32(hdlp, d++, *h++); 1535*0Sstevel@tonic-gate else 1536*0Sstevel@tonic-gate for (; repcount; repcount--) 1537*0Sstevel@tonic-gate pci_config_wr32(hdlp, d, *h++); 1538*0Sstevel@tonic-gate } 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate static uint64_t 1541*0Sstevel@tonic-gate pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 1542*0Sstevel@tonic-gate { 1543*0Sstevel@tonic-gate uint32_t lw_val; 1544*0Sstevel@tonic-gate uint32_t hi_val; 1545*0Sstevel@tonic-gate uint32_t *dp; 1546*0Sstevel@tonic-gate uint64_t val; 1547*0Sstevel@tonic-gate 1548*0Sstevel@tonic-gate dp = (uint32_t *)addr; 1549*0Sstevel@tonic-gate lw_val = pci_config_rd32(hdlp, dp); 1550*0Sstevel@tonic-gate dp++; 1551*0Sstevel@tonic-gate hi_val = pci_config_rd32(hdlp, dp); 1552*0Sstevel@tonic-gate val = ((uint64_t)hi_val << 32) | lw_val; 1553*0Sstevel@tonic-gate return (val); 1554*0Sstevel@tonic-gate } 1555*0Sstevel@tonic-gate 1556*0Sstevel@tonic-gate static void 1557*0Sstevel@tonic-gate pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 1558*0Sstevel@tonic-gate { 1559*0Sstevel@tonic-gate uint32_t lw_val; 1560*0Sstevel@tonic-gate uint32_t hi_val; 1561*0Sstevel@tonic-gate uint32_t *dp; 1562*0Sstevel@tonic-gate 1563*0Sstevel@tonic-gate dp = (uint32_t *)addr; 1564*0Sstevel@tonic-gate lw_val = (uint32_t)(value & 0xffffffff); 1565*0Sstevel@tonic-gate hi_val = (uint32_t)(value >> 32); 1566*0Sstevel@tonic-gate pci_config_wr32(hdlp, dp, lw_val); 1567*0Sstevel@tonic-gate dp++; 1568*0Sstevel@tonic-gate pci_config_wr32(hdlp, dp, hi_val); 1569*0Sstevel@tonic-gate } 1570*0Sstevel@tonic-gate 1571*0Sstevel@tonic-gate static void 1572*0Sstevel@tonic-gate pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1573*0Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 1574*0Sstevel@tonic-gate { 1575*0Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) { 1576*0Sstevel@tonic-gate for (; repcount; repcount--) 1577*0Sstevel@tonic-gate *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 1578*0Sstevel@tonic-gate } else { 1579*0Sstevel@tonic-gate for (; repcount; repcount--) 1580*0Sstevel@tonic-gate *host_addr++ = pci_config_rd64(hdlp, dev_addr); 1581*0Sstevel@tonic-gate } 1582*0Sstevel@tonic-gate } 1583*0Sstevel@tonic-gate 1584*0Sstevel@tonic-gate static void 1585*0Sstevel@tonic-gate pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1586*0Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 1587*0Sstevel@tonic-gate { 1588*0Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) { 1589*0Sstevel@tonic-gate for (; repcount; repcount--) 1590*0Sstevel@tonic-gate pci_config_wr64(hdlp, host_addr++, *dev_addr++); 1591*0Sstevel@tonic-gate } else { 1592*0Sstevel@tonic-gate for (; repcount; repcount--) 1593*0Sstevel@tonic-gate pci_config_wr64(hdlp, host_addr++, *dev_addr); 1594*0Sstevel@tonic-gate } 1595*0Sstevel@tonic-gate } 1596*0Sstevel@tonic-gate 1597*0Sstevel@tonic-gate /* 1598*0Sstevel@tonic-gate * When retrofitting this module for pci_tools, functions such as open, close, 1599*0Sstevel@tonic-gate * and ioctl are now pulled into this module. Before this, the functions in 1600*0Sstevel@tonic-gate * the pcihp module were referenced directly. Now they are called or 1601*0Sstevel@tonic-gate * referenced through the pcihp cb_ops structure from functions in this module. 1602*0Sstevel@tonic-gate */ 1603*0Sstevel@tonic-gate 1604*0Sstevel@tonic-gate static int 1605*0Sstevel@tonic-gate pci_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1606*0Sstevel@tonic-gate { 1607*0Sstevel@tonic-gate return ((pcihp_cb_ops.cb_open)(devp, flags, otyp, credp)); 1608*0Sstevel@tonic-gate } 1609*0Sstevel@tonic-gate 1610*0Sstevel@tonic-gate static int 1611*0Sstevel@tonic-gate pci_close(dev_t dev, int flags, int otyp, cred_t *credp) 1612*0Sstevel@tonic-gate { 1613*0Sstevel@tonic-gate return ((pcihp_cb_ops.cb_close)(dev, flags, otyp, credp)); 1614*0Sstevel@tonic-gate } 1615*0Sstevel@tonic-gate 1616*0Sstevel@tonic-gate static int 1617*0Sstevel@tonic-gate pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1618*0Sstevel@tonic-gate int *rvalp) 1619*0Sstevel@tonic-gate { 1620*0Sstevel@tonic-gate int rv = ENOTTY; 1621*0Sstevel@tonic-gate 1622*0Sstevel@tonic-gate if (IS_DEVCTL(cmd)) { 1623*0Sstevel@tonic-gate return ((pcihp_cb_ops.cb_ioctl)(dev, cmd, arg, mode, 1624*0Sstevel@tonic-gate credp, rvalp)); 1625*0Sstevel@tonic-gate } 1626*0Sstevel@tonic-gate 1627*0Sstevel@tonic-gate /* 1628*0Sstevel@tonic-gate * PCI tools. 1629*0Sstevel@tonic-gate */ 1630*0Sstevel@tonic-gate 1631*0Sstevel@tonic-gate if ((cmd & ~IOCPARM_MASK) == PCITOOL_IOC) { 1632*0Sstevel@tonic-gate switch (cmd) { 1633*0Sstevel@tonic-gate case PCITOOL_DEVICE_SET_REG: 1634*0Sstevel@tonic-gate case PCITOOL_DEVICE_GET_REG: 1635*0Sstevel@tonic-gate 1636*0Sstevel@tonic-gate /* Require full privileges. */ 1637*0Sstevel@tonic-gate if (secpolicy_kmdb(credp)) 1638*0Sstevel@tonic-gate rv = EPERM; 1639*0Sstevel@tonic-gate else 1640*0Sstevel@tonic-gate rv = pcitool_dev_reg_ops( 1641*0Sstevel@tonic-gate dev, (void *)arg, cmd, mode); 1642*0Sstevel@tonic-gate break; 1643*0Sstevel@tonic-gate 1644*0Sstevel@tonic-gate case PCITOOL_NEXUS_SET_REG: 1645*0Sstevel@tonic-gate case PCITOOL_NEXUS_GET_REG: 1646*0Sstevel@tonic-gate 1647*0Sstevel@tonic-gate /* Require full privileges. */ 1648*0Sstevel@tonic-gate if (secpolicy_kmdb(credp)) 1649*0Sstevel@tonic-gate rv = EPERM; 1650*0Sstevel@tonic-gate else 1651*0Sstevel@tonic-gate rv = pcitool_bus_reg_ops( 1652*0Sstevel@tonic-gate dev, (void *)arg, cmd, mode); 1653*0Sstevel@tonic-gate break; 1654*0Sstevel@tonic-gate 1655*0Sstevel@tonic-gate case PCITOOL_DEVICE_SET_INTR: 1656*0Sstevel@tonic-gate 1657*0Sstevel@tonic-gate /* Require PRIV_SYS_RES_CONFIG */ 1658*0Sstevel@tonic-gate if (secpolicy_ponline(credp)) { 1659*0Sstevel@tonic-gate rv = EPERM; 1660*0Sstevel@tonic-gate break; 1661*0Sstevel@tonic-gate } 1662*0Sstevel@tonic-gate 1663*0Sstevel@tonic-gate /*FALLTHRU*/ 1664*0Sstevel@tonic-gate /* These require no special privileges. */ 1665*0Sstevel@tonic-gate case PCITOOL_DEVICE_GET_INTR: 1666*0Sstevel@tonic-gate case PCITOOL_DEVICE_NUM_INTR: 1667*0Sstevel@tonic-gate rv = pcitool_intr_admn(dev, (void *)arg, cmd, mode); 1668*0Sstevel@tonic-gate break; 1669*0Sstevel@tonic-gate 1670*0Sstevel@tonic-gate default: 1671*0Sstevel@tonic-gate rv = ENOTTY; 1672*0Sstevel@tonic-gate break; 1673*0Sstevel@tonic-gate } 1674*0Sstevel@tonic-gate } 1675*0Sstevel@tonic-gate 1676*0Sstevel@tonic-gate return (rv); 1677*0Sstevel@tonic-gate } 1678*0Sstevel@tonic-gate 1679*0Sstevel@tonic-gate static int 1680*0Sstevel@tonic-gate pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 1681*0Sstevel@tonic-gate int flags, char *name, caddr_t valuep, int *lengthp) 1682*0Sstevel@tonic-gate { 1683*0Sstevel@tonic-gate return ((pcihp_cb_ops.cb_prop_op)(dev, dip, prop_op, flags, 1684*0Sstevel@tonic-gate name, valuep, lengthp)); 1685*0Sstevel@tonic-gate } 1686*0Sstevel@tonic-gate 1687*0Sstevel@tonic-gate static int 1688*0Sstevel@tonic-gate pci_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 1689*0Sstevel@tonic-gate { 1690*0Sstevel@tonic-gate return (pcihp_info(dip, cmd, arg, result)); 1691*0Sstevel@tonic-gate } 1692