17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 500d0963fSdilpreet * Common Development and Distribution License (the "License"). 600d0963fSdilpreet * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 229757e35cSStephen Hanson * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 25cd21e7c5SGarrett D'Amore /* 26cd21e7c5SGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 27*abe68f2cSRobert Mustacchi * Copyright 2016 Joyent, Inc. 28cd21e7c5SGarrett D'Amore */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Host to PCI local bus driver 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/conf.h> 357c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 367c478bd9Sstevel@tonic-gate #include <sys/pci.h> 377c478bd9Sstevel@tonic-gate #include <sys/pci_impl.h> 3870025d76Sjohnny #include <sys/sysmacros.h> 397c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 4000d0963fSdilpreet #include <sys/ddifm.h> 4100d0963fSdilpreet #include <sys/ndifm.h> 4200d0963fSdilpreet #include <sys/fm/protocol.h> 437c478bd9Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h> 4470025d76Sjohnny #include <io/pci/pci_common.h> 4570025d76Sjohnny #include <io/pci/pci_tools_ext.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* Save minimal state. */ 487c478bd9Sstevel@tonic-gate void *pci_statep; 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * Bus Operation functions 527c478bd9Sstevel@tonic-gate */ 537c478bd9Sstevel@tonic-gate static int pci_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 547c478bd9Sstevel@tonic-gate off_t, off_t, caddr_t *); 557c478bd9Sstevel@tonic-gate static int pci_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 567c478bd9Sstevel@tonic-gate void *, void *); 577c478bd9Sstevel@tonic-gate static int pci_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 587c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *, void *); 5900d0963fSdilpreet static int pci_fm_init(dev_info_t *, dev_info_t *, int, 6000d0963fSdilpreet ddi_iblock_cookie_t *); 6100d0963fSdilpreet static int pci_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *); 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate struct bus_ops pci_bus_ops = { 647c478bd9Sstevel@tonic-gate BUSO_REV, 657c478bd9Sstevel@tonic-gate pci_bus_map, 667c478bd9Sstevel@tonic-gate NULL, 677c478bd9Sstevel@tonic-gate NULL, 687c478bd9Sstevel@tonic-gate NULL, 697c478bd9Sstevel@tonic-gate i_ddi_map_fault, 70cd21e7c5SGarrett D'Amore NULL, 717c478bd9Sstevel@tonic-gate ddi_dma_allochdl, 727c478bd9Sstevel@tonic-gate ddi_dma_freehdl, 737c478bd9Sstevel@tonic-gate ddi_dma_bindhdl, 747c478bd9Sstevel@tonic-gate ddi_dma_unbindhdl, 757c478bd9Sstevel@tonic-gate ddi_dma_flush, 767c478bd9Sstevel@tonic-gate ddi_dma_win, 777c478bd9Sstevel@tonic-gate ddi_dma_mctl, 787c478bd9Sstevel@tonic-gate pci_ctlops, 797c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 807c478bd9Sstevel@tonic-gate 0, /* (*bus_get_eventcookie)(); */ 817c478bd9Sstevel@tonic-gate 0, /* (*bus_add_eventcall)(); */ 827c478bd9Sstevel@tonic-gate 0, /* (*bus_remove_eventcall)(); */ 837c478bd9Sstevel@tonic-gate 0, /* (*bus_post_event)(); */ 847c478bd9Sstevel@tonic-gate 0, /* (*bus_intr_ctl)(); */ 857c478bd9Sstevel@tonic-gate 0, /* (*bus_config)(); */ 867c478bd9Sstevel@tonic-gate 0, /* (*bus_unconfig)(); */ 8700d0963fSdilpreet pci_fm_init, /* (*bus_fm_init)(); */ 887c478bd9Sstevel@tonic-gate NULL, /* (*bus_fm_fini)(); */ 897c478bd9Sstevel@tonic-gate NULL, /* (*bus_fm_access_enter)(); */ 907c478bd9Sstevel@tonic-gate NULL, /* (*bus_fm_access_exit)(); */ 917c478bd9Sstevel@tonic-gate NULL, /* (*bus_power)(); */ 927c478bd9Sstevel@tonic-gate pci_intr_ops /* (*bus_intr_op)(); */ 937c478bd9Sstevel@tonic-gate }; 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * One goal here is to leverage off of the pcihp.c source without making 977c478bd9Sstevel@tonic-gate * changes to it. Call into it's cb_ops directly if needed, piggybacking 987c478bd9Sstevel@tonic-gate * anything else needed by the pci_tools.c module. Only pci_tools and pcihp 997851eb82Sschwartz * will be opening PCI nexus driver file descriptors. 1007c478bd9Sstevel@tonic-gate */ 10170025d76Sjohnny static int pci_open(dev_t *, int, int, cred_t *); 10270025d76Sjohnny static int pci_close(dev_t, int, int, cred_t *); 10370025d76Sjohnny static int pci_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 10470025d76Sjohnny static int pci_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, 10570025d76Sjohnny caddr_t, int *); 10670025d76Sjohnny static int pci_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 107eae2e508Skrishnae static void pci_peekpoke_cb(dev_info_t *, ddi_fm_error_t *); 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate struct cb_ops pci_cb_ops = { 1107c478bd9Sstevel@tonic-gate pci_open, /* open */ 1117c478bd9Sstevel@tonic-gate pci_close, /* close */ 1127c478bd9Sstevel@tonic-gate nodev, /* strategy */ 1137c478bd9Sstevel@tonic-gate nodev, /* print */ 1147c478bd9Sstevel@tonic-gate nodev, /* dump */ 1157c478bd9Sstevel@tonic-gate nodev, /* read */ 1167c478bd9Sstevel@tonic-gate nodev, /* write */ 1177c478bd9Sstevel@tonic-gate pci_ioctl, /* ioctl */ 1187c478bd9Sstevel@tonic-gate nodev, /* devmap */ 1197c478bd9Sstevel@tonic-gate nodev, /* mmap */ 1207c478bd9Sstevel@tonic-gate nodev, /* segmap */ 1217c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 1227c478bd9Sstevel@tonic-gate pci_prop_op, /* cb_prop_op */ 1237c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 1247c478bd9Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 1257c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 1267c478bd9Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 1277c478bd9Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 1287c478bd9Sstevel@tonic-gate }; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * Device Node Operation functions 1327c478bd9Sstevel@tonic-gate */ 1337c478bd9Sstevel@tonic-gate static int pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 1347c478bd9Sstevel@tonic-gate static int pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate struct dev_ops pci_ops = { 1377c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 1387c478bd9Sstevel@tonic-gate 0, /* refcnt */ 1397c478bd9Sstevel@tonic-gate pci_info, /* info */ 1407c478bd9Sstevel@tonic-gate nulldev, /* identify */ 1417c478bd9Sstevel@tonic-gate nulldev, /* probe */ 1427c478bd9Sstevel@tonic-gate pci_attach, /* attach */ 1437c478bd9Sstevel@tonic-gate pci_detach, /* detach */ 1447c478bd9Sstevel@tonic-gate nulldev, /* reset */ 1457c478bd9Sstevel@tonic-gate &pci_cb_ops, /* driver operations */ 14619397407SSherry Moore &pci_bus_ops, /* bus operations */ 14719397407SSherry Moore NULL, /* power */ 14819397407SSherry Moore ddi_quiesce_not_needed /* quiesce */ 1497c478bd9Sstevel@tonic-gate }; 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* 152c11e1991Smyers * This variable controls the default setting of the command register 153c11e1991Smyers * for pci devices. See pci_initchild() for details. 154c11e1991Smyers */ 155c11e1991Smyers static ushort_t pci_command_default = PCI_COMM_ME | 156c11e1991Smyers PCI_COMM_MAE | 157c11e1991Smyers PCI_COMM_IO; 158c11e1991Smyers 159c11e1991Smyers /* 1607c478bd9Sstevel@tonic-gate * Internal routines in support of particular pci_ctlops. 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate static int pci_removechild(dev_info_t *child); 1637c478bd9Sstevel@tonic-gate static int pci_initchild(dev_info_t *child); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* 1667c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1707c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module */ 17126947304SEvan Yan "x86 Host to PCI nexus driver", /* Name of module */ 1727c478bd9Sstevel@tonic-gate &pci_ops, /* driver ops */ 1737c478bd9Sstevel@tonic-gate }; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1767c478bd9Sstevel@tonic-gate MODREV_1, 1777c478bd9Sstevel@tonic-gate (void *)&modldrv, 1787c478bd9Sstevel@tonic-gate NULL 1797c478bd9Sstevel@tonic-gate }; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate int 1827c478bd9Sstevel@tonic-gate _init(void) 1837c478bd9Sstevel@tonic-gate { 1847c478bd9Sstevel@tonic-gate int e; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * Initialize per-pci bus soft state pointer. 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate e = ddi_soft_state_init(&pci_statep, sizeof (pci_state_t), 1); 1907c478bd9Sstevel@tonic-gate if (e != 0) 1917c478bd9Sstevel@tonic-gate return (e); 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) 1947c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&pci_statep); 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate return (e); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate int 2007c478bd9Sstevel@tonic-gate _fini(void) 2017c478bd9Sstevel@tonic-gate { 2027c478bd9Sstevel@tonic-gate int rc; 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate rc = mod_remove(&modlinkage); 2057c478bd9Sstevel@tonic-gate if (rc != 0) 2067c478bd9Sstevel@tonic-gate return (rc); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&pci_statep); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate return (rc); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate int 2147c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2207c478bd9Sstevel@tonic-gate static int 2217c478bd9Sstevel@tonic-gate pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2227c478bd9Sstevel@tonic-gate { 2237c478bd9Sstevel@tonic-gate /* 2247c478bd9Sstevel@tonic-gate * Use the minor number as constructed by pcihp, as the index value to 2257c478bd9Sstevel@tonic-gate * ddi_soft_state_zalloc. 2267c478bd9Sstevel@tonic-gate */ 2277851eb82Sschwartz int instance = ddi_get_instance(devi); 2287c478bd9Sstevel@tonic-gate pci_state_t *pcip = NULL; 2292df1fe9cSrandyf switch (cmd) { 2302df1fe9cSrandyf case DDI_ATTACH: 2312df1fe9cSrandyf break; 2322df1fe9cSrandyf 2332df1fe9cSrandyf case DDI_RESUME: 2342df1fe9cSrandyf return (DDI_SUCCESS); 2352df1fe9cSrandyf 2362df1fe9cSrandyf default: 2372df1fe9cSrandyf return (DDI_FAILURE); 2382df1fe9cSrandyf } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci") 2417c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 2427c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pci: 'device_type' prop create failed"); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457851eb82Sschwartz if (ddi_soft_state_zalloc(pci_statep, instance) == DDI_SUCCESS) { 2467851eb82Sschwartz pcip = ddi_get_soft_state(pci_statep, instance); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if (pcip == NULL) { 2507851eb82Sschwartz goto bad_soft_state; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate pcip->pci_dip = devi; 25426947304SEvan Yan pcip->pci_soft_state = PCI_SOFT_STATE_CLOSED; 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate /* 2577c478bd9Sstevel@tonic-gate * Initialize hotplug support on this bus. At minimum 2587c478bd9Sstevel@tonic-gate * (for non hotplug bus) this would create ":devctl" minor 2597c478bd9Sstevel@tonic-gate * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls 2607c478bd9Sstevel@tonic-gate * to this bus. 2617c478bd9Sstevel@tonic-gate */ 2627c478bd9Sstevel@tonic-gate if (pcihp_init(devi) != DDI_SUCCESS) { 2637c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pci: Failed to setup hotplug framework"); 2647851eb82Sschwartz goto bad_pcihp_init; 2657851eb82Sschwartz } 2667851eb82Sschwartz 267d4476ccbSschwartz /* Second arg: initialize for pci, not pci_express */ 268d4476ccbSschwartz if (pcitool_init(devi, B_FALSE) != DDI_SUCCESS) { 2697851eb82Sschwartz goto bad_pcitool_init; 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 27200d0963fSdilpreet pcip->pci_fmcap = DDI_FM_ERRCB_CAPABLE | 27300d0963fSdilpreet DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; 27400d0963fSdilpreet ddi_fm_init(devi, &pcip->pci_fmcap, &pcip->pci_fm_ibc); 27526947304SEvan Yan mutex_init(&pcip->pci_mutex, NULL, MUTEX_DRIVER, NULL); 27600d0963fSdilpreet mutex_init(&pcip->pci_err_mutex, NULL, MUTEX_DRIVER, 27700d0963fSdilpreet (void *)pcip->pci_fm_ibc); 27800d0963fSdilpreet mutex_init(&pcip->pci_peek_poke_mutex, NULL, MUTEX_DRIVER, 27900d0963fSdilpreet (void *)pcip->pci_fm_ibc); 28000d0963fSdilpreet if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) { 28100d0963fSdilpreet pci_ereport_setup(devi); 28200d0963fSdilpreet ddi_fm_handler_register(devi, pci_fm_callback, NULL); 28300d0963fSdilpreet } 28400d0963fSdilpreet 2857c478bd9Sstevel@tonic-gate ddi_report_dev(devi); 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2887851eb82Sschwartz 2897851eb82Sschwartz bad_pcitool_init: 2907851eb82Sschwartz (void) pcihp_uninit(devi); 2917851eb82Sschwartz bad_pcihp_init: 2927851eb82Sschwartz ddi_soft_state_free(pci_statep, instance); 2937851eb82Sschwartz bad_soft_state: 2947851eb82Sschwartz return (DDI_FAILURE); 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2987c478bd9Sstevel@tonic-gate static int 2997c478bd9Sstevel@tonic-gate pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 3007c478bd9Sstevel@tonic-gate { 3017a364d25Sschwartz int instance = ddi_get_instance(devi); 30200d0963fSdilpreet pci_state_t *pcip; 30300d0963fSdilpreet 30400d0963fSdilpreet pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(devi)); 3052df1fe9cSrandyf 3062df1fe9cSrandyf 3072df1fe9cSrandyf switch (cmd) { 3082df1fe9cSrandyf case DDI_DETACH: 30900d0963fSdilpreet if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) { 31000d0963fSdilpreet ddi_fm_handler_unregister(devi); 31100d0963fSdilpreet pci_ereport_teardown(devi); 31200d0963fSdilpreet } 31300d0963fSdilpreet mutex_destroy(&pcip->pci_peek_poke_mutex); 31400d0963fSdilpreet mutex_destroy(&pcip->pci_err_mutex); 31526947304SEvan Yan mutex_destroy(&pcip->pci_mutex); 3162df1fe9cSrandyf ddi_fm_fini(devi); /* Uninitialize pcitool support. */ 3177851eb82Sschwartz pcitool_uninit(devi); 3187851eb82Sschwartz 3197851eb82Sschwartz /* Uninitialize hotplug support on this bus. */ 3207c478bd9Sstevel@tonic-gate (void) pcihp_uninit(devi); 3217851eb82Sschwartz 3227a364d25Sschwartz ddi_soft_state_free(pci_statep, instance); 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3252df1fe9cSrandyf case DDI_SUSPEND: 3262df1fe9cSrandyf return (DDI_SUCCESS); 3272df1fe9cSrandyf default: 3282df1fe9cSrandyf return (DDI_FAILURE); 3292df1fe9cSrandyf } 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate static int 3337c478bd9Sstevel@tonic-gate pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 3347c478bd9Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 3357c478bd9Sstevel@tonic-gate { 336*abe68f2cSRobert Mustacchi struct regspec64 reg; 3377c478bd9Sstevel@tonic-gate ddi_map_req_t mr; 3387c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp; 339837c1ac4SStephen Hanson ddi_acc_impl_t *hdlp; 3407c478bd9Sstevel@tonic-gate pci_regspec_t pci_reg; 3417c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp; 3427c478bd9Sstevel@tonic-gate int rnumber; 343*abe68f2cSRobert Mustacchi uint64_t pci_rlength; 344*abe68f2cSRobert Mustacchi uint_t nelems; 3457c478bd9Sstevel@tonic-gate pci_acc_cfblk_t *cfp; 3467c478bd9Sstevel@tonic-gate int space; 347837c1ac4SStephen Hanson pci_state_t *pcip; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate mr = *mp; /* Get private copy of request */ 3507c478bd9Sstevel@tonic-gate mp = &mr; 3517c478bd9Sstevel@tonic-gate 3529757e35cSStephen Hanson if (mp->map_handlep != NULL) { 353837c1ac4SStephen Hanson pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip)); 354837c1ac4SStephen Hanson hdlp = (ddi_acc_impl_t *)(mp->map_handlep)->ah_platform_private; 355837c1ac4SStephen Hanson hdlp->ahi_err_mutexp = &pcip->pci_err_mutex; 356837c1ac4SStephen Hanson hdlp->ahi_peekpoke_mutexp = &pcip->pci_peek_poke_mutex; 357837c1ac4SStephen Hanson hdlp->ahi_scan_dip = dip; 358837c1ac4SStephen Hanson hdlp->ahi_scan = pci_peekpoke_cb; 3599757e35cSStephen Hanson } 360837c1ac4SStephen Hanson 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate * check for register number 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate switch (mp->map_type) { 3657c478bd9Sstevel@tonic-gate case DDI_MT_REGSPEC: 3667c478bd9Sstevel@tonic-gate pci_reg = *(pci_regspec_t *)(mp->map_obj.rp); 3677c478bd9Sstevel@tonic-gate pci_rp = &pci_reg; 36870025d76Sjohnny if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 3697c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3707c478bd9Sstevel@tonic-gate break; 3717c478bd9Sstevel@tonic-gate case DDI_MT_RNUMBER: 3727c478bd9Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 3737c478bd9Sstevel@tonic-gate /* 3747c478bd9Sstevel@tonic-gate * get ALL "reg" properties for dip, select the one of 3757c478bd9Sstevel@tonic-gate * of interest. In x86, "assigned-addresses" property 3767c478bd9Sstevel@tonic-gate * is identical to the "reg" property, so there is no 3777c478bd9Sstevel@tonic-gate * need to cross check the two to determine the physical 3787c478bd9Sstevel@tonic-gate * address of the registers. 3797c478bd9Sstevel@tonic-gate * This routine still performs some validity checks to 3807c478bd9Sstevel@tonic-gate * make sure that everything is okay. 3817c478bd9Sstevel@tonic-gate */ 38270025d76Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 383*abe68f2cSRobert Mustacchi DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &nelems) != 384*abe68f2cSRobert Mustacchi DDI_PROP_SUCCESS) 3857c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate /* 3887c478bd9Sstevel@tonic-gate * validate the register number. 3897c478bd9Sstevel@tonic-gate */ 390*abe68f2cSRobert Mustacchi nelems /= (sizeof (pci_regspec_t) / sizeof (int)); 391*abe68f2cSRobert Mustacchi if (rnumber >= nelems) { 3927c478bd9Sstevel@tonic-gate ddi_prop_free(pci_rp); 3937c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * copy the required entry. 3987c478bd9Sstevel@tonic-gate */ 3997c478bd9Sstevel@tonic-gate pci_reg = pci_rp[rnumber]; 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * free the memory allocated by ddi_prop_lookup_int_array 4037c478bd9Sstevel@tonic-gate */ 4047c478bd9Sstevel@tonic-gate ddi_prop_free(pci_rp); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate pci_rp = &pci_reg; 40770025d76Sjohnny if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) 4087c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4097c478bd9Sstevel@tonic-gate mp->map_type = DDI_MT_REGSPEC; 4107c478bd9Sstevel@tonic-gate break; 4117c478bd9Sstevel@tonic-gate default: 4127c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* 4187c478bd9Sstevel@tonic-gate * check for unmap and unlock of address space 4197c478bd9Sstevel@tonic-gate */ 4207c478bd9Sstevel@tonic-gate if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) { 4217c478bd9Sstevel@tonic-gate switch (space) { 4227c478bd9Sstevel@tonic-gate case PCI_ADDR_CONFIG: 4237c478bd9Sstevel@tonic-gate /* No work required on unmap of Config space */ 4247c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate case PCI_ADDR_IO: 4277c478bd9Sstevel@tonic-gate reg.regspec_bustype = 1; 4287c478bd9Sstevel@tonic-gate break; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate case PCI_ADDR_MEM64: 4317c478bd9Sstevel@tonic-gate case PCI_ADDR_MEM32: 4327c478bd9Sstevel@tonic-gate reg.regspec_bustype = 0; 4337c478bd9Sstevel@tonic-gate break; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate default: 4367c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 439*abe68f2cSRobert Mustacchi reg.regspec_addr = (uint64_t)pci_rp->pci_phys_mid << 32 | 440*abe68f2cSRobert Mustacchi (uint64_t)pci_rp->pci_phys_low; 441*abe68f2cSRobert Mustacchi reg.regspec_size = (uint64_t)pci_rp->pci_size_hi << 32 | 442*abe68f2cSRobert Mustacchi (uint64_t)pci_rp->pci_size_low; 443*abe68f2cSRobert Mustacchi 444*abe68f2cSRobert Mustacchi /* 445*abe68f2cSRobert Mustacchi * Adjust offset and length 446*abe68f2cSRobert Mustacchi * A non-zero length means override the one in the regspec. 447*abe68f2cSRobert Mustacchi */ 448*abe68f2cSRobert Mustacchi if (reg.regspec_addr + offset < MAX(reg.regspec_addr, offset)) 449*abe68f2cSRobert Mustacchi return (DDI_FAILURE); 450*abe68f2cSRobert Mustacchi reg.regspec_addr += offset; 451*abe68f2cSRobert Mustacchi if (len != 0) 452*abe68f2cSRobert Mustacchi reg.regspec_size = len; 453*abe68f2cSRobert Mustacchi 454*abe68f2cSRobert Mustacchi mp->map_obj.rp = (struct regspec *)® 455*abe68f2cSRobert Mustacchi mp->map_flags |= DDI_MF_EXT_REGSPEC; 4567c478bd9Sstevel@tonic-gate return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* check for user mapping request - not legal for Config */ 4617c478bd9Sstevel@tonic-gate if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) { 4627c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* 4667c478bd9Sstevel@tonic-gate * check for config space 4677c478bd9Sstevel@tonic-gate * On x86, CONFIG is not mapped via MMU and there is 4687c478bd9Sstevel@tonic-gate * no endian-ness issues. Set the attr field in the handle to 4697c478bd9Sstevel@tonic-gate * indicate that the common routines to call the nexus driver. 4707c478bd9Sstevel@tonic-gate */ 4717c478bd9Sstevel@tonic-gate if (space == PCI_ADDR_CONFIG) { 4727c478bd9Sstevel@tonic-gate /* Can't map config space without a handle */ 47300d0963fSdilpreet hp = (ddi_acc_hdl_t *)mp->map_handlep; 47470025d76Sjohnny if (hp == NULL) 4757c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* record the device address for future reference */ 4787c478bd9Sstevel@tonic-gate cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private; 4797c478bd9Sstevel@tonic-gate cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 4807c478bd9Sstevel@tonic-gate cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 4817c478bd9Sstevel@tonic-gate cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 4827c478bd9Sstevel@tonic-gate 48300d0963fSdilpreet *vaddrp = (caddr_t)offset; 48400d0963fSdilpreet return (pci_fm_acc_setup(hp, offset, len)); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate /* 4887c478bd9Sstevel@tonic-gate * range check 4897c478bd9Sstevel@tonic-gate */ 490*abe68f2cSRobert Mustacchi pci_rlength = (uint64_t)pci_rp->pci_size_low | 491*abe68f2cSRobert Mustacchi (uint64_t)pci_rp->pci_size_hi << 32; 492*abe68f2cSRobert Mustacchi if ((offset >= pci_rlength) || (len > pci_rlength) || 493*abe68f2cSRobert Mustacchi (offset + len > pci_rlength) || (offset + len < MAX(offset, len))) { 4947c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /* 4987c478bd9Sstevel@tonic-gate * convert the pci regsec into the generic regspec used by the 4997c478bd9Sstevel@tonic-gate * parent root nexus driver. 5007c478bd9Sstevel@tonic-gate */ 5017c478bd9Sstevel@tonic-gate switch (space) { 5027c478bd9Sstevel@tonic-gate case PCI_ADDR_IO: 5037c478bd9Sstevel@tonic-gate reg.regspec_bustype = 1; 5047c478bd9Sstevel@tonic-gate break; 5057c478bd9Sstevel@tonic-gate case PCI_ADDR_MEM64: 5067c478bd9Sstevel@tonic-gate case PCI_ADDR_MEM32: 5077c478bd9Sstevel@tonic-gate reg.regspec_bustype = 0; 5087c478bd9Sstevel@tonic-gate break; 5097c478bd9Sstevel@tonic-gate default: 5107c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 513*abe68f2cSRobert Mustacchi reg.regspec_addr = (uint64_t)pci_rp->pci_phys_mid << 32 | 514*abe68f2cSRobert Mustacchi (uint64_t)pci_rp->pci_phys_low; 515*abe68f2cSRobert Mustacchi reg.regspec_size = pci_rlength; 516*abe68f2cSRobert Mustacchi 517*abe68f2cSRobert Mustacchi /* 518*abe68f2cSRobert Mustacchi * Adjust offset and length 519*abe68f2cSRobert Mustacchi * A non-zero length means override the one in the regspec. 520*abe68f2cSRobert Mustacchi */ 521*abe68f2cSRobert Mustacchi if (reg.regspec_addr + offset < MAX(reg.regspec_addr, offset)) 522*abe68f2cSRobert Mustacchi return (DDI_FAILURE); 523*abe68f2cSRobert Mustacchi reg.regspec_addr += offset; 524*abe68f2cSRobert Mustacchi if (len != 0) 525*abe68f2cSRobert Mustacchi reg.regspec_size = len; 526*abe68f2cSRobert Mustacchi 527*abe68f2cSRobert Mustacchi mp->map_obj.rp = (struct regspec *)® 528*abe68f2cSRobert Mustacchi mp->map_flags |= DDI_MF_EXT_REGSPEC; 5297c478bd9Sstevel@tonic-gate return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5347c478bd9Sstevel@tonic-gate static int 5357c478bd9Sstevel@tonic-gate pci_ctlops(dev_info_t *dip, dev_info_t *rdip, 5367c478bd9Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 5377c478bd9Sstevel@tonic-gate { 5387c478bd9Sstevel@tonic-gate pci_regspec_t *drv_regp; 5397c478bd9Sstevel@tonic-gate uint_t reglen; 5407c478bd9Sstevel@tonic-gate int totreg; 54100d0963fSdilpreet pci_state_t *pcip; 5422df1fe9cSrandyf struct attachspec *asp; 5432c2d21e9SRichard Lowe struct detachspec *dsp; 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate switch (ctlop) { 5467c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 5477c478bd9Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 5487c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5497c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", 5507c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip), 5517c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), 5527c478bd9Sstevel@tonic-gate ddi_get_instance(rdip)); 5537c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 5567c478bd9Sstevel@tonic-gate return (pci_initchild((dev_info_t *)arg)); 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 5597c478bd9Sstevel@tonic-gate return (pci_removechild((dev_info_t *)arg)); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 5627c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 5657c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 5667c478bd9Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 5677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate *(int *)result = 0; 5707c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 5717c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (int **)&drv_regp, 5727c478bd9Sstevel@tonic-gate ®len) != DDI_PROP_SUCCESS) { 5737c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t); 5777c478bd9Sstevel@tonic-gate if (ctlop == DDI_CTLOPS_NREGS) 5787c478bd9Sstevel@tonic-gate *(int *)result = totreg; 5797c478bd9Sstevel@tonic-gate else if (ctlop == DDI_CTLOPS_REGSIZE) { 580*abe68f2cSRobert Mustacchi uint64_t val; 581*abe68f2cSRobert Mustacchi int rn; 582*abe68f2cSRobert Mustacchi 5837c478bd9Sstevel@tonic-gate rn = *(int *)arg; 5847c478bd9Sstevel@tonic-gate if (rn >= totreg) { 5857c478bd9Sstevel@tonic-gate ddi_prop_free(drv_regp); 5867c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5877c478bd9Sstevel@tonic-gate } 588*abe68f2cSRobert Mustacchi val = drv_regp[rn].pci_size_low | 589*abe68f2cSRobert Mustacchi (uint64_t)drv_regp[rn].pci_size_hi << 32; 590*abe68f2cSRobert Mustacchi if (val > OFF_MAX) { 591*abe68f2cSRobert Mustacchi int ce = CE_NOTE; 592*abe68f2cSRobert Mustacchi #ifdef DEBUG 593*abe68f2cSRobert Mustacchi ce = CE_WARN; 594*abe68f2cSRobert Mustacchi #endif 595*abe68f2cSRobert Mustacchi dev_err(rdip, ce, "failed to get register " 596*abe68f2cSRobert Mustacchi "size, value larger than OFF_MAX: 0x%" 597*abe68f2cSRobert Mustacchi PRIx64 "\n", val); 598*abe68f2cSRobert Mustacchi return (DDI_FAILURE); 599*abe68f2cSRobert Mustacchi } 600*abe68f2cSRobert Mustacchi *(off_t *)result = (off_t)val; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate ddi_prop_free(drv_regp); 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate case DDI_CTLOPS_POWER: { 6077c478bd9Sstevel@tonic-gate power_req_t *reqp = (power_req_t *)arg; 6087c478bd9Sstevel@tonic-gate /* 6097c478bd9Sstevel@tonic-gate * We currently understand reporting of PCI_PM_IDLESPEED 6107c478bd9Sstevel@tonic-gate * capability. Everything else is passed up. 6117c478bd9Sstevel@tonic-gate */ 6127c478bd9Sstevel@tonic-gate if ((reqp->request_type == PMR_REPORT_PMCAP) && 6137c478bd9Sstevel@tonic-gate (reqp->req.report_pmcap_req.cap == PCI_PM_IDLESPEED)) { 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 62000d0963fSdilpreet case DDI_CTLOPS_PEEK: 62100d0963fSdilpreet case DDI_CTLOPS_POKE: 62200d0963fSdilpreet pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip)); 62300d0963fSdilpreet return (pci_peekpoke_check(dip, rdip, ctlop, arg, result, 62400d0963fSdilpreet pci_common_peekpoke, &pcip->pci_err_mutex, 625eae2e508Skrishnae &pcip->pci_peek_poke_mutex, pci_peekpoke_cb)); 62600d0963fSdilpreet 6272df1fe9cSrandyf /* for now only X86 systems support PME wakeup from suspended state */ 6282df1fe9cSrandyf case DDI_CTLOPS_ATTACH: 6292df1fe9cSrandyf asp = (struct attachspec *)arg; 6302df1fe9cSrandyf if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE) 6312df1fe9cSrandyf if (pci_pre_resume(rdip) != DDI_SUCCESS) 6322df1fe9cSrandyf return (DDI_FAILURE); 6332df1fe9cSrandyf return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6342df1fe9cSrandyf 6352df1fe9cSrandyf case DDI_CTLOPS_DETACH: 6362c2d21e9SRichard Lowe dsp = (struct detachspec *)arg; 6372c2d21e9SRichard Lowe if (dsp->cmd == DDI_SUSPEND && dsp->when == DDI_POST) 6382df1fe9cSrandyf if (pci_post_suspend(rdip) != DDI_SUCCESS) 6392df1fe9cSrandyf return (DDI_FAILURE); 6402df1fe9cSrandyf return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6412df1fe9cSrandyf 6427c478bd9Sstevel@tonic-gate default: 6437c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* 65170025d76Sjohnny * pci_intr_ops 6527c478bd9Sstevel@tonic-gate */ 6537c478bd9Sstevel@tonic-gate static int 65470025d76Sjohnny pci_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 65570025d76Sjohnny ddi_intr_handle_impl_t *hdlp, void *result) 6567c478bd9Sstevel@tonic-gate { 65770025d76Sjohnny return (pci_common_intr_ops(pdip, rdip, intr_op, hdlp, result)); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate static int 6627c478bd9Sstevel@tonic-gate pci_initchild(dev_info_t *child) 6637c478bd9Sstevel@tonic-gate { 6647c478bd9Sstevel@tonic-gate char name[80]; 665c11e1991Smyers ddi_acc_handle_t config_handle; 666c11e1991Smyers ushort_t command_preserve, command; 6677c478bd9Sstevel@tonic-gate 66870025d76Sjohnny if (pci_common_name_child(child, name, 80) != DDI_SUCCESS) { 6697c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate /* 6747c478bd9Sstevel@tonic-gate * Pseudo nodes indicate a prototype node with per-instance 6757c478bd9Sstevel@tonic-gate * properties to be merged into the real h/w device node. 6767c478bd9Sstevel@tonic-gate * The interpretation of the unit-address is DD[,F] 6777c478bd9Sstevel@tonic-gate * where DD is the device id and F is the function. 6787c478bd9Sstevel@tonic-gate */ 6797c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 6807c478bd9Sstevel@tonic-gate extern int pci_allow_pseudo_children; 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* 6857c478bd9Sstevel@tonic-gate * Try to merge the properties from this prototype 6867c478bd9Sstevel@tonic-gate * node into real h/w nodes. 6877c478bd9Sstevel@tonic-gate */ 68870025d76Sjohnny if (ndi_merge_node(child, pci_common_name_child) == 68970025d76Sjohnny DDI_SUCCESS) { 6907c478bd9Sstevel@tonic-gate /* 6917c478bd9Sstevel@tonic-gate * Merged ok - return failure to remove the node. 6927c478bd9Sstevel@tonic-gate */ 6937c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 6947c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate /* workaround for ddivs to run under PCI */ 6987c478bd9Sstevel@tonic-gate if (pci_allow_pseudo_children) { 6997c478bd9Sstevel@tonic-gate /* 7007c478bd9Sstevel@tonic-gate * If the "interrupts" property doesn't exist, 7017c478bd9Sstevel@tonic-gate * this must be the ddivs no-intr case, and it returns 7027c478bd9Sstevel@tonic-gate * DDI_SUCCESS instead of DDI_FAILURE. 7037c478bd9Sstevel@tonic-gate */ 7047c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, child, 7057c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "interrupts", -1) == -1) 7067c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7077c478bd9Sstevel@tonic-gate /* 7087c478bd9Sstevel@tonic-gate * Create the ddi_parent_private_data for a pseudo 7097c478bd9Sstevel@tonic-gate * child. 7107c478bd9Sstevel@tonic-gate */ 71170025d76Sjohnny pci_common_set_parent_private_data(child); 7127c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate /* 7167c478bd9Sstevel@tonic-gate * The child was not merged into a h/w node, 7177c478bd9Sstevel@tonic-gate * but there's not much we can do with it other 7187c478bd9Sstevel@tonic-gate * than return failure to cause the node to be removed. 7197c478bd9Sstevel@tonic-gate */ 7207c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 7217c478bd9Sstevel@tonic-gate ddi_get_name(child), ddi_get_name_addr(child), 7227c478bd9Sstevel@tonic-gate ddi_get_name(child)); 7237c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 7247c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 72870025d76Sjohnny "interrupts", -1) != -1) 72970025d76Sjohnny pci_common_set_parent_private_data(child); 73070025d76Sjohnny else 7317c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 7327c478bd9Sstevel@tonic-gate 733c11e1991Smyers /* 734c11e1991Smyers * initialize command register 735c11e1991Smyers */ 736c11e1991Smyers if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) 737c11e1991Smyers return (DDI_FAILURE); 738c11e1991Smyers 739c11e1991Smyers /* 740c11e1991Smyers * Support for the "command-preserve" property. 741c11e1991Smyers */ 742c11e1991Smyers command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child, 7432df1fe9cSrandyf DDI_PROP_DONTPASS, "command-preserve", 0); 744c11e1991Smyers command = pci_config_get16(config_handle, PCI_CONF_COMM); 745c11e1991Smyers command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB); 746c11e1991Smyers command |= (pci_command_default & ~command_preserve); 747c11e1991Smyers pci_config_put16(config_handle, PCI_CONF_COMM, command); 748c11e1991Smyers 749c11e1991Smyers pci_config_teardown(&config_handle); 7507c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate static int 7547c478bd9Sstevel@tonic-gate pci_removechild(dev_info_t *dip) 7557c478bd9Sstevel@tonic-gate { 7567c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate if ((pdptr = ddi_get_parent_data(dip)) != NULL) { 7597c478bd9Sstevel@tonic-gate kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec))); 7607c478bd9Sstevel@tonic-gate ddi_set_parent_data(dip, NULL); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate /* 7657c478bd9Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 7667c478bd9Sstevel@tonic-gate */ 7677c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate impl_rem_dev_props(dip); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate /* 7767c478bd9Sstevel@tonic-gate * When retrofitting this module for pci_tools, functions such as open, close, 7777c478bd9Sstevel@tonic-gate * and ioctl are now pulled into this module. Before this, the functions in 7787c478bd9Sstevel@tonic-gate * the pcihp module were referenced directly. Now they are called or 7797c478bd9Sstevel@tonic-gate * referenced through the pcihp cb_ops structure from functions in this module. 7807c478bd9Sstevel@tonic-gate */ 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate static int 7837c478bd9Sstevel@tonic-gate pci_open(dev_t *devp, int flags, int otyp, cred_t *credp) 7847c478bd9Sstevel@tonic-gate { 78570025d76Sjohnny return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp)); 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate static int 7897c478bd9Sstevel@tonic-gate pci_close(dev_t dev, int flags, int otyp, cred_t *credp) 7907c478bd9Sstevel@tonic-gate { 79170025d76Sjohnny return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp)); 7927c478bd9Sstevel@tonic-gate } 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate static int 79570025d76Sjohnny pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 7967c478bd9Sstevel@tonic-gate { 7977851eb82Sschwartz minor_t minor = getminor(dev); 79826947304SEvan Yan int instance = PCI_MINOR_NUM_TO_INSTANCE(minor); 799d4476ccbSschwartz pci_state_t *pci_p = ddi_get_soft_state(pci_statep, instance); 80026947304SEvan Yan int ret = ENOTTY; 8017c478bd9Sstevel@tonic-gate 80270025d76Sjohnny if (pci_p == NULL) 80370025d76Sjohnny return (ENXIO); 8047851eb82Sschwartz 80526947304SEvan Yan switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 80626947304SEvan Yan case PCI_TOOL_REG_MINOR_NUM: 80726947304SEvan Yan case PCI_TOOL_INTR_MINOR_NUM: 80826947304SEvan Yan /* To handle pcitool related ioctls */ 80926947304SEvan Yan ret = pci_common_ioctl(pci_p->pci_dip, dev, cmd, arg, mode, 81026947304SEvan Yan credp, rvalp); 81126947304SEvan Yan break; 81226947304SEvan Yan default: 81326947304SEvan Yan /* To handle devctl and hotplug related ioctls */ 81426947304SEvan Yan ret = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, 81526947304SEvan Yan credp, rvalp); 81626947304SEvan Yan break; 81726947304SEvan Yan } 81826947304SEvan Yan 81926947304SEvan Yan return (ret); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate static int 8247c478bd9Sstevel@tonic-gate pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 8257c478bd9Sstevel@tonic-gate int flags, char *name, caddr_t valuep, int *lengthp) 8267c478bd9Sstevel@tonic-gate { 82770025d76Sjohnny return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags, 8287c478bd9Sstevel@tonic-gate name, valuep, lengthp)); 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate static int 8327c478bd9Sstevel@tonic-gate pci_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 8337c478bd9Sstevel@tonic-gate { 8347c478bd9Sstevel@tonic-gate return (pcihp_info(dip, cmd, arg, result)); 8357c478bd9Sstevel@tonic-gate } 83600d0963fSdilpreet 837eae2e508Skrishnae void pci_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) { 838eae2e508Skrishnae (void) pci_ereport_post(dip, derr, NULL); 839eae2e508Skrishnae } 840eae2e508Skrishnae 84100d0963fSdilpreet /*ARGSUSED*/ 84200d0963fSdilpreet static int 84300d0963fSdilpreet pci_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap, 84400d0963fSdilpreet ddi_iblock_cookie_t *ibc) 84500d0963fSdilpreet { 84600d0963fSdilpreet pci_state_t *pcip = ddi_get_soft_state(pci_statep, 84700d0963fSdilpreet ddi_get_instance(dip)); 84800d0963fSdilpreet 84900d0963fSdilpreet ASSERT(ibc != NULL); 85000d0963fSdilpreet *ibc = pcip->pci_fm_ibc; 85100d0963fSdilpreet 85200d0963fSdilpreet return (pcip->pci_fmcap); 85300d0963fSdilpreet } 85400d0963fSdilpreet 85500d0963fSdilpreet /*ARGSUSED*/ 85600d0963fSdilpreet static int 85700d0963fSdilpreet pci_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used) 85800d0963fSdilpreet { 85900d0963fSdilpreet pci_state_t *pcip = ddi_get_soft_state(pci_statep, 86000d0963fSdilpreet ddi_get_instance(dip)); 86100d0963fSdilpreet 86200d0963fSdilpreet mutex_enter(&pcip->pci_err_mutex); 86300d0963fSdilpreet pci_ereport_post(dip, derr, NULL); 86400d0963fSdilpreet mutex_exit(&pcip->pci_err_mutex); 86500d0963fSdilpreet return (derr->fme_status); 86600d0963fSdilpreet } 867