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 /* 22*567c0b92SStephen Hanson * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * PCI nexus driver interface 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/conf.h> /* nulldev */ 327c478bd9Sstevel@tonic-gate #include <sys/stat.h> /* devctl */ 337c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 347c478bd9Sstevel@tonic-gate #include <sys/async.h> /* ecc_flt for pci_ecc.h */ 357c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 367c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 377c478bd9Sstevel@tonic-gate #include <sys/ndifm.h> 387c478bd9Sstevel@tonic-gate #include <sys/ontrap.h> 397c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 407c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 417c478bd9Sstevel@tonic-gate #include <sys/epm.h> 427c478bd9Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h> 43d4476ccbSschwartz #include <sys/pci/pci_tools_ext.h> 447c478bd9Sstevel@tonic-gate #include <sys/spl.h> 457c478bd9Sstevel@tonic-gate #include <sys/pci/pci_obj.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* 507c478bd9Sstevel@tonic-gate * function prototype for hotplug routine: 517c478bd9Sstevel@tonic-gate */ 527c478bd9Sstevel@tonic-gate static void 537c478bd9Sstevel@tonic-gate pci_init_hotplug(struct pci *); 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* 567c478bd9Sstevel@tonic-gate * function prototypes for dev ops routines: 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate static int pci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 597c478bd9Sstevel@tonic-gate static int pci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 607c478bd9Sstevel@tonic-gate static int pci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 617c478bd9Sstevel@tonic-gate void *arg, void **result); 627c478bd9Sstevel@tonic-gate static int pci_ctlops_poke(pci_t *pci_p, peekpoke_ctlops_t *in_args); 637c478bd9Sstevel@tonic-gate static int pci_ctlops_peek(pci_t *pci_p, peekpoke_ctlops_t *in_args, 647c478bd9Sstevel@tonic-gate void *result); 657c478bd9Sstevel@tonic-gate static off_t get_reg_set_size(dev_info_t *child, int rnumber); 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate /* 687c478bd9Sstevel@tonic-gate * bus ops and dev ops structures: 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate static struct bus_ops pci_bus_ops = { 717c478bd9Sstevel@tonic-gate BUSO_REV, 727c478bd9Sstevel@tonic-gate pci_map, 737c478bd9Sstevel@tonic-gate 0, 747c478bd9Sstevel@tonic-gate 0, 757c478bd9Sstevel@tonic-gate 0, 767c478bd9Sstevel@tonic-gate i_ddi_map_fault, 777c478bd9Sstevel@tonic-gate pci_dma_setup, 787c478bd9Sstevel@tonic-gate pci_dma_allochdl, 797c478bd9Sstevel@tonic-gate pci_dma_freehdl, 807c478bd9Sstevel@tonic-gate pci_dma_bindhdl, 817c478bd9Sstevel@tonic-gate pci_dma_unbindhdl, 827c478bd9Sstevel@tonic-gate pci_dma_sync, 837c478bd9Sstevel@tonic-gate pci_dma_win, 847c478bd9Sstevel@tonic-gate pci_dma_ctlops, 857c478bd9Sstevel@tonic-gate pci_ctlops, 867c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 877c478bd9Sstevel@tonic-gate ndi_busop_get_eventcookie, /* (*bus_get_eventcookie)(); */ 887c478bd9Sstevel@tonic-gate ndi_busop_add_eventcall, /* (*bus_add_eventcall)(); */ 897c478bd9Sstevel@tonic-gate ndi_busop_remove_eventcall, /* (*bus_remove_eventcall)(); */ 907c478bd9Sstevel@tonic-gate ndi_post_event, /* (*bus_post_event)(); */ 917c478bd9Sstevel@tonic-gate NULL, /* (*bus_intr_ctl)(); */ 927c478bd9Sstevel@tonic-gate NULL, /* (*bus_config)(); */ 937c478bd9Sstevel@tonic-gate NULL, /* (*bus_unconfig)(); */ 947c478bd9Sstevel@tonic-gate pci_fm_init_child, /* (*bus_fm_init)(); */ 957c478bd9Sstevel@tonic-gate NULL, /* (*bus_fm_fini)(); */ 967c478bd9Sstevel@tonic-gate pci_bus_enter, /* (*bus_fm_access_enter)(); */ 977c478bd9Sstevel@tonic-gate pci_bus_exit, /* (*bus_fm_access_fini)(); */ 987c478bd9Sstevel@tonic-gate NULL, /* (*bus_power)(); */ 997c478bd9Sstevel@tonic-gate pci_intr_ops /* (*bus_intr_op)(); */ 1007c478bd9Sstevel@tonic-gate }; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate extern struct cb_ops pci_cb_ops; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate static struct dev_ops pci_ops = { 1057c478bd9Sstevel@tonic-gate DEVO_REV, 1067c478bd9Sstevel@tonic-gate 0, 1077c478bd9Sstevel@tonic-gate pci_info, 1087c478bd9Sstevel@tonic-gate nulldev, 1097c478bd9Sstevel@tonic-gate 0, 1107c478bd9Sstevel@tonic-gate pci_attach, 1117c478bd9Sstevel@tonic-gate pci_detach, 1127c478bd9Sstevel@tonic-gate nodev, 1137c478bd9Sstevel@tonic-gate &pci_cb_ops, 1147c478bd9Sstevel@tonic-gate &pci_bus_ops, 11519397407SSherry Moore 0, 11619397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 1177c478bd9Sstevel@tonic-gate }; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * module definitions: 1217c478bd9Sstevel@tonic-gate */ 1227c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 1237c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1267c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module - driver */ 12726947304SEvan Yan "Sun4u Host to PCI nexus driver", /* Name of module. */ 1287c478bd9Sstevel@tonic-gate &pci_ops, /* driver ops */ 1297c478bd9Sstevel@tonic-gate }; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1327c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 1337c478bd9Sstevel@tonic-gate }; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * driver global data: 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate void *per_pci_state; /* per-pbm soft state pointer */ 1397c478bd9Sstevel@tonic-gate void *per_pci_common_state; /* per-psycho soft state pointer */ 1407c478bd9Sstevel@tonic-gate kmutex_t pci_global_mutex; /* attach/detach common struct lock */ 1417c478bd9Sstevel@tonic-gate errorq_t *pci_ecc_queue = NULL; /* per-system ecc handling queue */ 14200d0963fSdilpreet extern errorq_t *pci_target_queue; 143e389d146Sschwartz struct cb_ops *pcihp_ops = NULL; /* hotplug module cb ops */ 144e389d146Sschwartz 1457c478bd9Sstevel@tonic-gate extern void pci_child_cfg_save(dev_info_t *dip); 1467c478bd9Sstevel@tonic-gate extern void pci_child_cfg_restore(dev_info_t *dip); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate int 1497c478bd9Sstevel@tonic-gate _init(void) 1507c478bd9Sstevel@tonic-gate { 1517c478bd9Sstevel@tonic-gate int e; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * Initialize per-pci bus soft state pointer. 1557c478bd9Sstevel@tonic-gate */ 1567c478bd9Sstevel@tonic-gate e = ddi_soft_state_init(&per_pci_state, sizeof (pci_t), 1); 1577c478bd9Sstevel@tonic-gate if (e != 0) 1587c478bd9Sstevel@tonic-gate return (e); 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * Initialize per-psycho soft state pointer. 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate e = ddi_soft_state_init(&per_pci_common_state, 1647c478bd9Sstevel@tonic-gate sizeof (pci_common_t), 1); 1657c478bd9Sstevel@tonic-gate if (e != 0) { 1667c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_pci_state); 1677c478bd9Sstevel@tonic-gate return (e); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * Initialize global mutexes. 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate mutex_init(&pci_global_mutex, NULL, MUTEX_DRIVER, NULL); 1747c478bd9Sstevel@tonic-gate pci_reloc_init(); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* 1777c478bd9Sstevel@tonic-gate * Create the performance kstats. 1787c478bd9Sstevel@tonic-gate */ 1797c478bd9Sstevel@tonic-gate pci_kstat_init(); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * Install the module. 1837c478bd9Sstevel@tonic-gate */ 1847c478bd9Sstevel@tonic-gate e = mod_install(&modlinkage); 1857c478bd9Sstevel@tonic-gate if (e != 0) { 1867c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_pci_state); 1877c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_pci_common_state); 1887c478bd9Sstevel@tonic-gate mutex_destroy(&pci_global_mutex); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate return (e); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate int 1947c478bd9Sstevel@tonic-gate _fini(void) 1957c478bd9Sstevel@tonic-gate { 1967c478bd9Sstevel@tonic-gate int e; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * Remove the module. 2007c478bd9Sstevel@tonic-gate */ 2017c478bd9Sstevel@tonic-gate e = mod_remove(&modlinkage); 2027c478bd9Sstevel@tonic-gate if (e != 0) 2037c478bd9Sstevel@tonic-gate return (e); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * Destroy pci_ecc_queue, and set it to NULL. 2077c478bd9Sstevel@tonic-gate */ 2087c478bd9Sstevel@tonic-gate if (pci_ecc_queue) 2097c478bd9Sstevel@tonic-gate errorq_destroy(pci_ecc_queue); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate pci_ecc_queue = NULL; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * Destroy pci_target_queue, and set it to NULL. 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate if (pci_target_queue) 2177c478bd9Sstevel@tonic-gate errorq_destroy(pci_target_queue); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate pci_target_queue = NULL; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* 2227c478bd9Sstevel@tonic-gate * Destroy the performance kstats. 2237c478bd9Sstevel@tonic-gate */ 2247c478bd9Sstevel@tonic-gate pci_kstat_fini(); 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate /* 2277c478bd9Sstevel@tonic-gate * Free the per-pci and per-psycho soft state info and destroy 2287c478bd9Sstevel@tonic-gate * mutex for per-psycho soft state. 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_pci_state); 2317c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_pci_common_state); 2327c478bd9Sstevel@tonic-gate mutex_destroy(&pci_global_mutex); 2337c478bd9Sstevel@tonic-gate pci_reloc_fini(); 2347c478bd9Sstevel@tonic-gate return (e); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate int 2387c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2397c478bd9Sstevel@tonic-gate { 2407c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2447c478bd9Sstevel@tonic-gate static int 2457c478bd9Sstevel@tonic-gate pci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(getminor((dev_t)arg)); 2487c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(instance); 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate /* allow hotplug to deal with ones it manages */ 2517c478bd9Sstevel@tonic-gate if (pci_p && (pci_p->hotplug_capable == B_TRUE)) 2527c478bd9Sstevel@tonic-gate return (pcihp_info(dip, infocmd, arg, result)); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* non-hotplug or not attached */ 2557c478bd9Sstevel@tonic-gate switch (infocmd) { 2567c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 257f47a9c50Smathue *result = (void *)(uintptr_t)instance; 2587c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2617c478bd9Sstevel@tonic-gate if (pci_p == NULL) 2627c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2637c478bd9Sstevel@tonic-gate *result = (void *)pci_p->pci_dip; 2647c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate default: 2677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* device driver entry points */ 2737c478bd9Sstevel@tonic-gate /* 2747c478bd9Sstevel@tonic-gate * attach entry point: 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate static int 2777c478bd9Sstevel@tonic-gate pci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2787c478bd9Sstevel@tonic-gate { 2797c478bd9Sstevel@tonic-gate pci_t *pci_p; /* per bus state pointer */ 2807c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate switch (cmd) { 2837c478bd9Sstevel@tonic-gate case DDI_ATTACH: 2847c478bd9Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "DDI_ATTACH\n"); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate /* 2877c478bd9Sstevel@tonic-gate * Allocate and get the per-pci soft state structure. 2887c478bd9Sstevel@tonic-gate */ 2897c478bd9Sstevel@tonic-gate if (alloc_pci_soft_state(instance) != DDI_SUCCESS) { 2907c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: can't allocate pci state", 2917c478bd9Sstevel@tonic-gate ddi_driver_name(dip), instance); 2927c478bd9Sstevel@tonic-gate goto err_bad_pci_softstate; 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate pci_p = get_pci_soft_state(instance); 2957c478bd9Sstevel@tonic-gate pci_p->pci_dip = dip; 2967c478bd9Sstevel@tonic-gate mutex_init(&pci_p->pci_mutex, NULL, MUTEX_DRIVER, NULL); 2977c478bd9Sstevel@tonic-gate pci_p->pci_soft_state = PCI_SOFT_STATE_CLOSED; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* 3007c478bd9Sstevel@tonic-gate * Get key properties of the pci bridge node and 3017c478bd9Sstevel@tonic-gate * determine it's type (psycho, schizo, etc ...). 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate if (get_pci_properties(pci_p, dip) == DDI_FAILURE) 3047c478bd9Sstevel@tonic-gate goto err_bad_pci_prop; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * Map in the registers. 3087c478bd9Sstevel@tonic-gate */ 3097c478bd9Sstevel@tonic-gate if (map_pci_registers(pci_p, dip) == DDI_FAILURE) 3107c478bd9Sstevel@tonic-gate goto err_bad_reg_prop; 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate if (pci_obj_setup(pci_p) != DDI_SUCCESS) 3137c478bd9Sstevel@tonic-gate goto err_bad_objs; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * If this PCI leaf has hotplug and this platform 3177c478bd9Sstevel@tonic-gate * loads hotplug modules then initialize the 3187c478bd9Sstevel@tonic-gate * hotplug framework. 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate pci_init_hotplug(pci_p); 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /* 3237c478bd9Sstevel@tonic-gate * Create the "devctl" node for hotplug support. 3247c478bd9Sstevel@tonic-gate * For non-hotplug bus, we still need ":devctl" to 3257c478bd9Sstevel@tonic-gate * support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls. 3267c478bd9Sstevel@tonic-gate */ 3277c478bd9Sstevel@tonic-gate if (pci_p->hotplug_capable == B_FALSE) { 3287c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, "devctl", S_IFCHR, 3297c478bd9Sstevel@tonic-gate PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR), 3307c478bd9Sstevel@tonic-gate DDI_NT_NEXUS, 0) != DDI_SUCCESS) 3317c478bd9Sstevel@tonic-gate goto err_bad_devctl_node; 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate /* 3357851eb82Sschwartz * Create pcitool nodes for register access and interrupt 3367851eb82Sschwartz * routing. 3377851eb82Sschwartz */ 3387851eb82Sschwartz if (pcitool_init(dip) != DDI_SUCCESS) { 3397851eb82Sschwartz goto err_bad_pcitool_nodes; 3407851eb82Sschwartz } 3417c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate pci_p->pci_state = PCI_ATTACHED; 3447c478bd9Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "attach success\n"); 3457c478bd9Sstevel@tonic-gate break; 3467c478bd9Sstevel@tonic-gate 3477851eb82Sschwartz err_bad_pcitool_nodes: 3487851eb82Sschwartz if (pci_p->hotplug_capable == B_FALSE) 3497c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, "devctl"); 3507851eb82Sschwartz else 3517851eb82Sschwartz (void) pcihp_uninit(dip); 3527c478bd9Sstevel@tonic-gate err_bad_devctl_node: 3537851eb82Sschwartz pci_obj_destroy(pci_p); 3547851eb82Sschwartz err_bad_objs: 3557c478bd9Sstevel@tonic-gate unmap_pci_registers(pci_p); 3567c478bd9Sstevel@tonic-gate err_bad_reg_prop: 3577c478bd9Sstevel@tonic-gate free_pci_properties(pci_p); 3587c478bd9Sstevel@tonic-gate err_bad_pci_prop: 3597c478bd9Sstevel@tonic-gate mutex_destroy(&pci_p->pci_mutex); 3607c478bd9Sstevel@tonic-gate free_pci_soft_state(instance); 3617c478bd9Sstevel@tonic-gate err_bad_pci_softstate: 3627c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate case DDI_RESUME: 3657c478bd9Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "DDI_RESUME\n"); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * Make sure the Psycho control registers and IOMMU 3697c478bd9Sstevel@tonic-gate * are configured properly. 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate pci_p = get_pci_soft_state(instance); 3727c478bd9Sstevel@tonic-gate mutex_enter(&pci_p->pci_mutex); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * Make sure this instance has been suspended. 3767c478bd9Sstevel@tonic-gate */ 3777c478bd9Sstevel@tonic-gate if (pci_p->pci_state != PCI_SUSPENDED) { 3787c478bd9Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "instance NOT suspended\n"); 3797c478bd9Sstevel@tonic-gate mutex_exit(&pci_p->pci_mutex); 3807c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate pci_obj_resume(pci_p); 3837c478bd9Sstevel@tonic-gate pci_p->pci_state = PCI_ATTACHED; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate pci_child_cfg_restore(dip); 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate mutex_exit(&pci_p->pci_mutex); 3887c478bd9Sstevel@tonic-gate break; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate default: 3917c478bd9Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "unsupported attach op\n"); 3927c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate /* 3997c478bd9Sstevel@tonic-gate * detach entry point: 4007c478bd9Sstevel@tonic-gate */ 4017c478bd9Sstevel@tonic-gate static int 4027c478bd9Sstevel@tonic-gate pci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4037c478bd9Sstevel@tonic-gate { 4047c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 4057c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(instance); 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate /* 4087c478bd9Sstevel@tonic-gate * Make sure we are currently attached 4097c478bd9Sstevel@tonic-gate */ 4107c478bd9Sstevel@tonic-gate if (pci_p->pci_state != PCI_ATTACHED) { 4117c478bd9Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "failed - instance not attached\n"); 4127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate mutex_enter(&pci_p->pci_mutex); 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate switch (cmd) { 4187c478bd9Sstevel@tonic-gate case DDI_DETACH: 4197c478bd9Sstevel@tonic-gate DEBUG0(DBG_DETACH, dip, "DDI_DETACH\n"); 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate if (pci_p->hotplug_capable == B_TRUE) 4227c478bd9Sstevel@tonic-gate if (pcihp_uninit(dip) == DDI_FAILURE) { 4237c478bd9Sstevel@tonic-gate mutex_exit(&pci_p->pci_mutex); 4247c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277851eb82Sschwartz pcitool_uninit(dip); 4287851eb82Sschwartz 4297c478bd9Sstevel@tonic-gate pci_obj_destroy(pci_p); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* 4327c478bd9Sstevel@tonic-gate * Free the pci soft state structure and the rest of the 4337c478bd9Sstevel@tonic-gate * resources it's using. 4347c478bd9Sstevel@tonic-gate */ 4357c478bd9Sstevel@tonic-gate free_pci_properties(pci_p); 4367c478bd9Sstevel@tonic-gate unmap_pci_registers(pci_p); 4377c478bd9Sstevel@tonic-gate mutex_exit(&pci_p->pci_mutex); 4387c478bd9Sstevel@tonic-gate mutex_destroy(&pci_p->pci_mutex); 4397c478bd9Sstevel@tonic-gate free_pci_soft_state(instance); 4407c478bd9Sstevel@tonic-gate 44119397407SSherry Moore /* Free the interrupt-priorities prop if we created it. */ 44219397407SSherry Moore { 4437c478bd9Sstevel@tonic-gate int len; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate if (ddi_getproplen(DDI_DEV_T_ANY, dip, 4467c478bd9Sstevel@tonic-gate DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 4477c478bd9Sstevel@tonic-gate "interrupt-priorities", &len) == DDI_PROP_SUCCESS) 4487c478bd9Sstevel@tonic-gate (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 4497c478bd9Sstevel@tonic-gate "interrupt-priorities"); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 4547c478bd9Sstevel@tonic-gate pci_child_cfg_save(dip); 4557c478bd9Sstevel@tonic-gate pci_obj_suspend(pci_p); 4567c478bd9Sstevel@tonic-gate pci_p->pci_state = PCI_SUSPENDED; 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate mutex_exit(&pci_p->pci_mutex); 4597c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate default: 4627c478bd9Sstevel@tonic-gate DEBUG0(DBG_DETACH, dip, "unsupported detach op\n"); 4637c478bd9Sstevel@tonic-gate mutex_exit(&pci_p->pci_mutex); 4647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /* bus driver entry points */ 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* 4727c478bd9Sstevel@tonic-gate * bus map entry point: 4737c478bd9Sstevel@tonic-gate * 4747c478bd9Sstevel@tonic-gate * if map request is for an rnumber 4757c478bd9Sstevel@tonic-gate * get the corresponding regspec from device node 4767c478bd9Sstevel@tonic-gate * build a new regspec in our parent's format 4777c478bd9Sstevel@tonic-gate * build a new map_req with the new regspec 4787c478bd9Sstevel@tonic-gate * call up the tree to complete the mapping 4797c478bd9Sstevel@tonic-gate */ 4807c478bd9Sstevel@tonic-gate int 4817c478bd9Sstevel@tonic-gate pci_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 4827c478bd9Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp) 4837c478bd9Sstevel@tonic-gate { 4847c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 4857c478bd9Sstevel@tonic-gate struct regspec p_regspec; 4867c478bd9Sstevel@tonic-gate ddi_map_req_t p_mapreq; 4877c478bd9Sstevel@tonic-gate int reglen, rval, r_no; 4887c478bd9Sstevel@tonic-gate pci_regspec_t reloc_reg, *rp = &reloc_reg; 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate DEBUG2(DBG_MAP, dip, "rdip=%s%d:", 4917c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip)); 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate if (mp->map_flags & DDI_MF_USER_MAPPING) 4947c478bd9Sstevel@tonic-gate return (DDI_ME_UNIMPLEMENTED); 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate switch (mp->map_type) { 4977c478bd9Sstevel@tonic-gate case DDI_MT_REGSPEC: 4987c478bd9Sstevel@tonic-gate reloc_reg = *(pci_regspec_t *)mp->map_obj.rp; /* dup whole */ 4997c478bd9Sstevel@tonic-gate break; 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate case DDI_MT_RNUMBER: 5027c478bd9Sstevel@tonic-gate r_no = mp->map_obj.rnumber; 5037c478bd9Sstevel@tonic-gate DEBUG1(DBG_MAP | DBG_CONT, dip, " r#=%x", r_no); 5047c478bd9Sstevel@tonic-gate 505a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 5067c478bd9Sstevel@tonic-gate "reg", (caddr_t)&rp, ®len) != DDI_SUCCESS) 5077c478bd9Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate if (r_no < 0 || r_no >= reglen / sizeof (pci_regspec_t)) { 5107c478bd9Sstevel@tonic-gate kmem_free(rp, reglen); 5117c478bd9Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate rp += r_no; 5147c478bd9Sstevel@tonic-gate break; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate default: 5177c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate DEBUG0(DBG_MAP | DBG_CONT, dip, "\n"); 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* use "assigned-addresses" to relocate regspec within pci space */ 5227c478bd9Sstevel@tonic-gate if (rval = pci_reloc_reg(dip, rdip, pci_p, rp)) 5237c478bd9Sstevel@tonic-gate goto done; 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate if (len) /* adjust regspec according to mapping request */ 5267c478bd9Sstevel@tonic-gate rp->pci_size_low = len; 5277c478bd9Sstevel@tonic-gate rp->pci_phys_low += off; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* use "ranges" to translate relocated pci regspec into parent space */ 5307c478bd9Sstevel@tonic-gate if (rval = pci_xlate_reg(pci_p, rp, &p_regspec)) 5317c478bd9Sstevel@tonic-gate goto done; 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate p_mapreq = *mp; /* dup the whole structure */ 5347c478bd9Sstevel@tonic-gate p_mapreq.map_type = DDI_MT_REGSPEC; 5357c478bd9Sstevel@tonic-gate p_mapreq.map_obj.rp = &p_regspec; 5367c478bd9Sstevel@tonic-gate rval = ddi_map(dip, &p_mapreq, 0, 0, addrp); 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate if (rval == DDI_SUCCESS) { 5397c478bd9Sstevel@tonic-gate /* 5407c478bd9Sstevel@tonic-gate * Set-up access functions for FM access error capable drivers. 5417c478bd9Sstevel@tonic-gate * The axq workaround prevents fault management support 5427c478bd9Sstevel@tonic-gate */ 5437c478bd9Sstevel@tonic-gate if (DDI_FM_ACC_ERR_CAP(pci_p->pci_fm_cap) && 5447c478bd9Sstevel@tonic-gate DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) && 5457c478bd9Sstevel@tonic-gate mp->map_handlep->ah_acc.devacc_attr_access != 5467c478bd9Sstevel@tonic-gate DDI_DEFAULT_ACC) 5477c478bd9Sstevel@tonic-gate pci_fm_acc_setup(mp, rdip); 5487c478bd9Sstevel@tonic-gate pci_axq_setup(mp, pci_p->pci_pbm_p); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate done: 5527c478bd9Sstevel@tonic-gate if (mp->map_type == DDI_MT_RNUMBER) 5537c478bd9Sstevel@tonic-gate kmem_free(rp - r_no, reglen); 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate return (rval); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate /* 5597c478bd9Sstevel@tonic-gate * bus dma map entry point 5607c478bd9Sstevel@tonic-gate * return value: 5617c478bd9Sstevel@tonic-gate * DDI_DMA_PARTIAL_MAP 1 5627c478bd9Sstevel@tonic-gate * DDI_DMA_MAPOK 0 5637c478bd9Sstevel@tonic-gate * DDI_DMA_MAPPED 0 5647c478bd9Sstevel@tonic-gate * DDI_DMA_NORESOURCES -1 5657c478bd9Sstevel@tonic-gate * DDI_DMA_NOMAPPING -2 5667c478bd9Sstevel@tonic-gate * DDI_DMA_TOOBIG -3 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate int 5697c478bd9Sstevel@tonic-gate pci_dma_setup(dev_info_t *dip, dev_info_t *rdip, ddi_dma_req_t *dmareq, 5707c478bd9Sstevel@tonic-gate ddi_dma_handle_t *handlep) 5717c478bd9Sstevel@tonic-gate { 5727c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 5737c478bd9Sstevel@tonic-gate iommu_t *iommu_p = pci_p->pci_iommu_p; 5747c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp; 5757c478bd9Sstevel@tonic-gate int ret; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate DEBUG3(DBG_DMA_MAP, dip, "mapping - rdip=%s%d type=%s\n", 5787c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), 5797c478bd9Sstevel@tonic-gate handlep ? "alloc" : "advisory"); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate if (!(mp = pci_dma_lmts2hdl(dip, rdip, iommu_p, dmareq))) 5827c478bd9Sstevel@tonic-gate return (DDI_DMA_NORESOURCES); 5837c478bd9Sstevel@tonic-gate if (mp == (ddi_dma_impl_t *)DDI_DMA_NOMAPPING) 5847c478bd9Sstevel@tonic-gate return (DDI_DMA_NOMAPPING); 5857c478bd9Sstevel@tonic-gate if (ret = pci_dma_type(pci_p, dmareq, mp)) 5867c478bd9Sstevel@tonic-gate goto freehandle; 5877c478bd9Sstevel@tonic-gate if (ret = pci_dma_pfn(pci_p, dmareq, mp)) 5887c478bd9Sstevel@tonic-gate goto freehandle; 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate switch (PCI_DMA_TYPE(mp)) { 5917c478bd9Sstevel@tonic-gate case DMAI_FLAGS_DVMA: /* LINTED E_EQUALITY_NOT_ASSIGNMENT */ 5927c478bd9Sstevel@tonic-gate if ((ret = pci_dvma_win(pci_p, dmareq, mp)) || !handlep) 5937c478bd9Sstevel@tonic-gate goto freehandle; 5947c478bd9Sstevel@tonic-gate if (!PCI_DMA_CANCACHE(mp)) { /* try fast track */ 5957c478bd9Sstevel@tonic-gate if (PCI_DMA_CANFAST(mp)) { 5967c478bd9Sstevel@tonic-gate if (!pci_dvma_map_fast(iommu_p, mp)) 5977c478bd9Sstevel@tonic-gate break; 5987c478bd9Sstevel@tonic-gate /* LINTED E_NOP_ELSE_STMT */ 5997c478bd9Sstevel@tonic-gate } else { 6007c478bd9Sstevel@tonic-gate PCI_DVMA_FASTTRAK_PROF(mp); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate if (ret = pci_dvma_map(mp, dmareq, iommu_p)) 6047c478bd9Sstevel@tonic-gate goto freehandle; 6057c478bd9Sstevel@tonic-gate break; 6067c478bd9Sstevel@tonic-gate case DMAI_FLAGS_PEER_TO_PEER: /* LINTED E_EQUALITY_NOT_ASSIGNMENT */ 6077c478bd9Sstevel@tonic-gate if ((ret = pci_dma_physwin(pci_p, dmareq, mp)) || !handlep) 6087c478bd9Sstevel@tonic-gate goto freehandle; 6097c478bd9Sstevel@tonic-gate break; 6107c478bd9Sstevel@tonic-gate case DMAI_FLAGS_BYPASS: 6117c478bd9Sstevel@tonic-gate default: 6127c478bd9Sstevel@tonic-gate panic("%s%d: pci_dma_setup: bad dma type 0x%x", 6137c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), 6147c478bd9Sstevel@tonic-gate PCI_DMA_TYPE(mp)); 6157c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate *handlep = (ddi_dma_handle_t)mp; 6187c478bd9Sstevel@tonic-gate mp->dmai_flags |= (DMAI_FLAGS_INUSE | DMAI_FLAGS_MAPPED); 6197c478bd9Sstevel@tonic-gate dump_dma_handle(DBG_DMA_MAP, dip, mp); 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate return ((mp->dmai_nwin == 1) ? DDI_DMA_MAPPED : DDI_DMA_PARTIAL_MAP); 6227c478bd9Sstevel@tonic-gate freehandle: 6237c478bd9Sstevel@tonic-gate if (ret == DDI_DMA_NORESOURCES) 6247c478bd9Sstevel@tonic-gate pci_dma_freemp(mp); /* don't run_callback() */ 6257c478bd9Sstevel@tonic-gate else 6267c478bd9Sstevel@tonic-gate (void) pci_dma_freehdl(dip, rdip, (ddi_dma_handle_t)mp); 6277c478bd9Sstevel@tonic-gate return (ret); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * bus dma alloc handle entry point: 6337c478bd9Sstevel@tonic-gate */ 6347c478bd9Sstevel@tonic-gate int 6357c478bd9Sstevel@tonic-gate pci_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp, 6367c478bd9Sstevel@tonic-gate int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 6377c478bd9Sstevel@tonic-gate { 6387c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 6397c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp; 6407c478bd9Sstevel@tonic-gate int rval; 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate DEBUG2(DBG_DMA_ALLOCH, dip, "rdip=%s%d\n", 6437c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip)); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate if (attrp->dma_attr_version != DMA_ATTR_V0) 6467c478bd9Sstevel@tonic-gate return (DDI_DMA_BADATTR); 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if (!(mp = pci_dma_allocmp(dip, rdip, waitfp, arg))) 6497c478bd9Sstevel@tonic-gate return (DDI_DMA_NORESOURCES); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate /* 6527c478bd9Sstevel@tonic-gate * Save requestor's information 6537c478bd9Sstevel@tonic-gate */ 6547c478bd9Sstevel@tonic-gate mp->dmai_attr = *attrp; /* whole object - augmented later */ 6557c478bd9Sstevel@tonic-gate *DEV_ATTR(mp) = *attrp; /* whole object - device orig attr */ 6567c478bd9Sstevel@tonic-gate DEBUG1(DBG_DMA_ALLOCH, dip, "mp=%p\n", mp); 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate /* check and convert dma attributes to handle parameters */ 6597c478bd9Sstevel@tonic-gate if (rval = pci_dma_attr2hdl(pci_p, mp)) { 6607c478bd9Sstevel@tonic-gate pci_dma_freehdl(dip, rdip, (ddi_dma_handle_t)mp); 6617c478bd9Sstevel@tonic-gate *handlep = NULL; 6627c478bd9Sstevel@tonic-gate return (rval); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate *handlep = (ddi_dma_handle_t)mp; 6657c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * bus dma free handle entry point: 6717c478bd9Sstevel@tonic-gate */ 6727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6737c478bd9Sstevel@tonic-gate int 6747c478bd9Sstevel@tonic-gate pci_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 6757c478bd9Sstevel@tonic-gate { 6767c478bd9Sstevel@tonic-gate DEBUG3(DBG_DMA_FREEH, dip, "rdip=%s%d mp=%p\n", 6777c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), handle); 6787c478bd9Sstevel@tonic-gate pci_dma_freemp((ddi_dma_impl_t *)handle); 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate if (pci_kmem_clid) { 6817c478bd9Sstevel@tonic-gate DEBUG0(DBG_DMA_FREEH, dip, "run handle callback\n"); 6827c478bd9Sstevel@tonic-gate ddi_run_callback(&pci_kmem_clid); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate /* 6897c478bd9Sstevel@tonic-gate * bus dma bind handle entry point: 6907c478bd9Sstevel@tonic-gate */ 6917c478bd9Sstevel@tonic-gate int 6927c478bd9Sstevel@tonic-gate pci_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 6937c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, ddi_dma_req_t *dmareq, 6947c478bd9Sstevel@tonic-gate ddi_dma_cookie_t *cookiep, uint_t *ccountp) 6957c478bd9Sstevel@tonic-gate { 6967c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 6977c478bd9Sstevel@tonic-gate iommu_t *iommu_p = pci_p->pci_iommu_p; 6987c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 6997c478bd9Sstevel@tonic-gate int ret; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate DEBUG4(DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n", 7027c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), mp, dmareq); 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate if (mp->dmai_flags & DMAI_FLAGS_INUSE) 7057c478bd9Sstevel@tonic-gate return (DDI_DMA_INUSE); 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate ASSERT((mp->dmai_flags & ~DMAI_FLAGS_PRESERVE) == 0); 7087c478bd9Sstevel@tonic-gate mp->dmai_flags |= DMAI_FLAGS_INUSE; 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate if (ret = pci_dma_type(pci_p, dmareq, mp)) 7117c478bd9Sstevel@tonic-gate goto err; 7127c478bd9Sstevel@tonic-gate if (ret = pci_dma_pfn(pci_p, dmareq, mp)) 7137c478bd9Sstevel@tonic-gate goto err; 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate switch (PCI_DMA_TYPE(mp)) { 7167c478bd9Sstevel@tonic-gate case DMAI_FLAGS_DVMA: 7177c478bd9Sstevel@tonic-gate if (ret = pci_dvma_win(pci_p, dmareq, mp)) 7187c478bd9Sstevel@tonic-gate goto map_err; 7197c478bd9Sstevel@tonic-gate if (!PCI_DMA_CANCACHE(mp)) { /* try fast track */ 7207c478bd9Sstevel@tonic-gate if (PCI_DMA_CANFAST(mp)) { 7217c478bd9Sstevel@tonic-gate if (!pci_dvma_map_fast(iommu_p, mp)) 7227c478bd9Sstevel@tonic-gate goto mapped; /*LINTED E_NOP_ELSE_STMT*/ 7237c478bd9Sstevel@tonic-gate } else { 7247c478bd9Sstevel@tonic-gate PCI_DVMA_FASTTRAK_PROF(mp); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate if (ret = pci_dvma_map(mp, dmareq, iommu_p)) 7287c478bd9Sstevel@tonic-gate goto map_err; 7297c478bd9Sstevel@tonic-gate mapped: 7307c478bd9Sstevel@tonic-gate *ccountp = 1; 7317c478bd9Sstevel@tonic-gate MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping, mp->dmai_size); 7327c478bd9Sstevel@tonic-gate break; 7337c478bd9Sstevel@tonic-gate case DMAI_FLAGS_BYPASS: 7347c478bd9Sstevel@tonic-gate case DMAI_FLAGS_PEER_TO_PEER: 7357c478bd9Sstevel@tonic-gate if (ret = pci_dma_physwin(pci_p, dmareq, mp)) 7367c478bd9Sstevel@tonic-gate goto map_err; 7377c478bd9Sstevel@tonic-gate *ccountp = WINLST(mp)->win_ncookies; 7387c478bd9Sstevel@tonic-gate *cookiep = *(ddi_dma_cookie_t *)(WINLST(mp) + 1); /* wholeobj */ 7397c478bd9Sstevel@tonic-gate break; 7407c478bd9Sstevel@tonic-gate default: 7417c478bd9Sstevel@tonic-gate panic("%s%d: pci_dma_bindhdl(%p): bad dma type", 7427c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), mp); 7437c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate DEBUG2(DBG_DMA_BINDH, dip, "cookie %x+%x\n", cookiep->dmac_address, 7467c478bd9Sstevel@tonic-gate cookiep->dmac_size); 7477c478bd9Sstevel@tonic-gate dump_dma_handle(DBG_DMA_MAP, dip, mp); 7487c478bd9Sstevel@tonic-gate 749*567c0b92SStephen Hanson if (mp->dmai_attr.dma_attr_flags & DDI_DMA_FLAGERR) 75000d0963fSdilpreet mp->dmai_error.err_cf = impl_dma_check; 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate mp->dmai_flags |= DMAI_FLAGS_MAPPED; 7537c478bd9Sstevel@tonic-gate return (mp->dmai_nwin == 1 ? DDI_DMA_MAPPED : DDI_DMA_PARTIAL_MAP); 7547c478bd9Sstevel@tonic-gate map_err: 7557c478bd9Sstevel@tonic-gate pci_dvma_unregister_callbacks(pci_p, mp); 7567c478bd9Sstevel@tonic-gate pci_dma_freepfn(mp); 7577c478bd9Sstevel@tonic-gate err: 7587c478bd9Sstevel@tonic-gate mp->dmai_flags &= DMAI_FLAGS_PRESERVE; 7597c478bd9Sstevel@tonic-gate return (ret); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate /* 7637c478bd9Sstevel@tonic-gate * bus dma unbind handle entry point: 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7667c478bd9Sstevel@tonic-gate int 7677c478bd9Sstevel@tonic-gate pci_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 7687c478bd9Sstevel@tonic-gate { 7697c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 7707c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 7717c478bd9Sstevel@tonic-gate iommu_t *iommu_p = pci_p->pci_iommu_p; 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate DEBUG3(DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n", 7747c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), handle); 7757c478bd9Sstevel@tonic-gate if ((mp->dmai_flags & DMAI_FLAGS_INUSE) == 0) { 7767c478bd9Sstevel@tonic-gate DEBUG0(DBG_DMA_UNBINDH, dip, "handle not in use\n"); 7777c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate mp->dmai_flags &= ~DMAI_FLAGS_MAPPED; 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate switch (PCI_DMA_TYPE(mp)) { 7837c478bd9Sstevel@tonic-gate case DMAI_FLAGS_DVMA: 7847c478bd9Sstevel@tonic-gate pci_dvma_unregister_callbacks(pci_p, mp); 7857c478bd9Sstevel@tonic-gate pci_dma_sync_unmap(dip, rdip, mp); 7867c478bd9Sstevel@tonic-gate pci_dvma_unmap(iommu_p, mp); 7877c478bd9Sstevel@tonic-gate pci_dma_freepfn(mp); 7887c478bd9Sstevel@tonic-gate break; 7897c478bd9Sstevel@tonic-gate case DMAI_FLAGS_BYPASS: 7907c478bd9Sstevel@tonic-gate case DMAI_FLAGS_PEER_TO_PEER: 7917c478bd9Sstevel@tonic-gate pci_dma_freewin(mp); 7927c478bd9Sstevel@tonic-gate break; 7937c478bd9Sstevel@tonic-gate default: 7947c478bd9Sstevel@tonic-gate panic("%s%d: pci_dma_unbindhdl:bad dma type %p", 7957c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), mp); 7967c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate if (iommu_p->iommu_dvma_clid != 0) { 7997c478bd9Sstevel@tonic-gate DEBUG0(DBG_DMA_UNBINDH, dip, "run dvma callback\n"); 8007c478bd9Sstevel@tonic-gate ddi_run_callback(&iommu_p->iommu_dvma_clid); 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate if (pci_kmem_clid) { 8037c478bd9Sstevel@tonic-gate DEBUG0(DBG_DMA_UNBINDH, dip, "run handle callback\n"); 8047c478bd9Sstevel@tonic-gate ddi_run_callback(&pci_kmem_clid); 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate mp->dmai_flags &= DMAI_FLAGS_PRESERVE; 8077c478bd9Sstevel@tonic-gate SYNC_BUF_PA(mp) = 0; 8087c478bd9Sstevel@tonic-gate 809*567c0b92SStephen Hanson mp->dmai_error.err_cf = NULL; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate /* 8167c478bd9Sstevel@tonic-gate * bus dma win entry point: 8177c478bd9Sstevel@tonic-gate */ 8187c478bd9Sstevel@tonic-gate int 8197c478bd9Sstevel@tonic-gate pci_dma_win(dev_info_t *dip, dev_info_t *rdip, 8207c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, uint_t win, off_t *offp, 8217c478bd9Sstevel@tonic-gate size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp) 8227c478bd9Sstevel@tonic-gate { 8237c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 8247c478bd9Sstevel@tonic-gate DEBUG2(DBG_DMA_WIN, dip, "rdip=%s%d\n", 8257c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip)); 8267c478bd9Sstevel@tonic-gate dump_dma_handle(DBG_DMA_WIN, dip, mp); 8277c478bd9Sstevel@tonic-gate if (win >= mp->dmai_nwin) { 8287c478bd9Sstevel@tonic-gate DEBUG1(DBG_DMA_WIN, dip, "%x out of range\n", win); 8297c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate switch (PCI_DMA_TYPE(mp)) { 8337c478bd9Sstevel@tonic-gate case DMAI_FLAGS_DVMA: 8347c478bd9Sstevel@tonic-gate if (win != PCI_DMA_CURWIN(mp)) { 8357c478bd9Sstevel@tonic-gate pci_t *pci_p = 8367c478bd9Sstevel@tonic-gate get_pci_soft_state(ddi_get_instance(dip)); 8377c478bd9Sstevel@tonic-gate pci_dma_sync_unmap(dip, rdip, mp); 8387c478bd9Sstevel@tonic-gate /* map_window sets dmai_mapping/size/offset */ 8397c478bd9Sstevel@tonic-gate iommu_map_window(pci_p->pci_iommu_p, mp, win); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate if (cookiep) 8427c478bd9Sstevel@tonic-gate MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping, 8437c478bd9Sstevel@tonic-gate mp->dmai_size); 8447c478bd9Sstevel@tonic-gate if (ccountp) 8457c478bd9Sstevel@tonic-gate *ccountp = 1; 8467c478bd9Sstevel@tonic-gate break; 8477c478bd9Sstevel@tonic-gate case DMAI_FLAGS_PEER_TO_PEER: 8487c478bd9Sstevel@tonic-gate case DMAI_FLAGS_BYPASS: { 8497c478bd9Sstevel@tonic-gate int i; 8507c478bd9Sstevel@tonic-gate ddi_dma_cookie_t *ck_p; 8517c478bd9Sstevel@tonic-gate pci_dma_win_t *win_p = mp->dmai_winlst; 8527c478bd9Sstevel@tonic-gate 85319397407SSherry Moore for (i = 0; i < win; win_p = win_p->win_next, i++) 85419397407SSherry Moore ; 8557c478bd9Sstevel@tonic-gate ck_p = (ddi_dma_cookie_t *)(win_p + 1); 8567c478bd9Sstevel@tonic-gate *cookiep = *ck_p; 8577c478bd9Sstevel@tonic-gate mp->dmai_offset = win_p->win_offset; 8587c478bd9Sstevel@tonic-gate mp->dmai_size = win_p->win_size; 8597c478bd9Sstevel@tonic-gate mp->dmai_mapping = ck_p->dmac_laddress; 8607c478bd9Sstevel@tonic-gate mp->dmai_cookie = ck_p + 1; 8617c478bd9Sstevel@tonic-gate win_p->win_curseg = 0; 8627c478bd9Sstevel@tonic-gate if (ccountp) 8637c478bd9Sstevel@tonic-gate *ccountp = win_p->win_ncookies; 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate break; 8667c478bd9Sstevel@tonic-gate default: 8677c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: pci_dma_win:bad dma type 0x%x", 8687c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), 8697c478bd9Sstevel@tonic-gate PCI_DMA_TYPE(mp)); 8707c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate if (cookiep) 8737c478bd9Sstevel@tonic-gate DEBUG2(DBG_DMA_WIN, dip, 8747c478bd9Sstevel@tonic-gate "cookie - dmac_address=%x dmac_size=%x\n", 8757c478bd9Sstevel@tonic-gate cookiep->dmac_address, cookiep->dmac_size); 8767c478bd9Sstevel@tonic-gate if (offp) 8777c478bd9Sstevel@tonic-gate *offp = (off_t)mp->dmai_offset; 8787c478bd9Sstevel@tonic-gate if (lenp) 8797c478bd9Sstevel@tonic-gate *lenp = mp->dmai_size; 8807c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate #ifdef DEBUG 8847c478bd9Sstevel@tonic-gate static char *pci_dmactl_str[] = { 8857c478bd9Sstevel@tonic-gate "DDI_DMA_FREE", 8867c478bd9Sstevel@tonic-gate "DDI_DMA_SYNC", 8877c478bd9Sstevel@tonic-gate "DDI_DMA_HTOC", 8887c478bd9Sstevel@tonic-gate "DDI_DMA_KVADDR", 8897c478bd9Sstevel@tonic-gate "DDI_DMA_MOVWIN", 8907c478bd9Sstevel@tonic-gate "DDI_DMA_REPWIN", 8917c478bd9Sstevel@tonic-gate "DDI_DMA_GETERR", 8927c478bd9Sstevel@tonic-gate "DDI_DMA_COFF", 8937c478bd9Sstevel@tonic-gate "DDI_DMA_NEXTWIN", 8947c478bd9Sstevel@tonic-gate "DDI_DMA_NEXTSEG", 8957c478bd9Sstevel@tonic-gate "DDI_DMA_SEGTOC", 8967c478bd9Sstevel@tonic-gate "DDI_DMA_RESERVE", 8977c478bd9Sstevel@tonic-gate "DDI_DMA_RELEASE", 8987c478bd9Sstevel@tonic-gate "DDI_DMA_RESETH", 8997c478bd9Sstevel@tonic-gate "DDI_DMA_CKSYNC", 9007c478bd9Sstevel@tonic-gate "DDI_DMA_IOPB_ALLOC", 9017c478bd9Sstevel@tonic-gate "DDI_DMA_IOPB_FREE", 9027c478bd9Sstevel@tonic-gate "DDI_DMA_SMEM_ALLOC", 9037c478bd9Sstevel@tonic-gate "DDI_DMA_SMEM_FREE", 9047c478bd9Sstevel@tonic-gate "DDI_DMA_SET_SBUS64", 9057c478bd9Sstevel@tonic-gate "DDI_DMA_REMAP" 9067c478bd9Sstevel@tonic-gate }; 9077c478bd9Sstevel@tonic-gate #endif 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * bus dma control entry point: 9117c478bd9Sstevel@tonic-gate */ 9127c478bd9Sstevel@tonic-gate int 9137c478bd9Sstevel@tonic-gate pci_dma_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, 9147c478bd9Sstevel@tonic-gate enum ddi_dma_ctlops cmd, off_t *offp, size_t *lenp, caddr_t *objp, 9157c478bd9Sstevel@tonic-gate uint_t cache_flags) 9167c478bd9Sstevel@tonic-gate { 9177c478bd9Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 9187c478bd9Sstevel@tonic-gate DEBUG3(DBG_DMA_CTL, dip, "%s: rdip=%s%d\n", pci_dmactl_str[cmd], 9197c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip)); 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate switch (cmd) { 9227c478bd9Sstevel@tonic-gate case DDI_DMA_FREE: 9237c478bd9Sstevel@tonic-gate (void) pci_dma_unbindhdl(dip, rdip, handle); 9247c478bd9Sstevel@tonic-gate (void) pci_dma_freehdl(dip, rdip, handle); 9257c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9267c478bd9Sstevel@tonic-gate case DDI_DMA_RESERVE: { 9277c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 9287c478bd9Sstevel@tonic-gate return (pci_fdvma_reserve(dip, rdip, pci_p, 9297c478bd9Sstevel@tonic-gate (ddi_dma_req_t *)offp, (ddi_dma_handle_t *)objp)); 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate case DDI_DMA_RELEASE: { 9327c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 9337c478bd9Sstevel@tonic-gate return (pci_fdvma_release(dip, pci_p, mp)); 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate default: 9367c478bd9Sstevel@tonic-gate break; 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate switch (PCI_DMA_TYPE(mp)) { 9407c478bd9Sstevel@tonic-gate case DMAI_FLAGS_DVMA: 9417c478bd9Sstevel@tonic-gate return (pci_dvma_ctl(dip, rdip, mp, cmd, offp, lenp, objp, 9427c478bd9Sstevel@tonic-gate cache_flags)); 9437c478bd9Sstevel@tonic-gate case DMAI_FLAGS_PEER_TO_PEER: 9447c478bd9Sstevel@tonic-gate case DMAI_FLAGS_BYPASS: 9457c478bd9Sstevel@tonic-gate return (pci_dma_ctl(dip, rdip, mp, cmd, offp, lenp, objp, 9467c478bd9Sstevel@tonic-gate cache_flags)); 9477c478bd9Sstevel@tonic-gate default: 9487c478bd9Sstevel@tonic-gate panic("%s%d: pci_dma_ctlops(%x):bad dma type %x", 9497c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), cmd, 9507c478bd9Sstevel@tonic-gate mp->dmai_flags); 9517c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate #ifdef DEBUG 9567c478bd9Sstevel@tonic-gate int pci_peekfault_cnt = 0; 9577c478bd9Sstevel@tonic-gate int pci_pokefault_cnt = 0; 9587c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate static int 9617c478bd9Sstevel@tonic-gate pci_do_poke(pci_t *pci_p, peekpoke_ctlops_t *in_args) 9627c478bd9Sstevel@tonic-gate { 9637c478bd9Sstevel@tonic-gate pbm_t *pbm_p = pci_p->pci_pbm_p; 9647c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 9657c478bd9Sstevel@tonic-gate on_trap_data_t otd; 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate mutex_enter(&pbm_p->pbm_pokefault_mutex); 9687c478bd9Sstevel@tonic-gate pbm_p->pbm_ontrap_data = &otd; 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate /* Set up protected environment. */ 9717c478bd9Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 9727c478bd9Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&poke_fault; 9757c478bd9Sstevel@tonic-gate err = do_poke(in_args->size, (void *)in_args->dev_addr, 9767c478bd9Sstevel@tonic-gate (void *)in_args->host_addr); 9777c478bd9Sstevel@tonic-gate otd.ot_trampoline = tramp; 9787c478bd9Sstevel@tonic-gate } else 9797c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * Read the async fault register for the PBM to see it sees 9837c478bd9Sstevel@tonic-gate * a master-abort. 9847c478bd9Sstevel@tonic-gate */ 9857c478bd9Sstevel@tonic-gate pbm_clear_error(pbm_p); 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate if (otd.ot_trap & OT_DATA_ACCESS) 9887c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* Take down protected environment. */ 9917c478bd9Sstevel@tonic-gate no_trap(); 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate pbm_p->pbm_ontrap_data = NULL; 9947c478bd9Sstevel@tonic-gate mutex_exit(&pbm_p->pbm_pokefault_mutex); 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate #ifdef DEBUG 9977c478bd9Sstevel@tonic-gate if (err == DDI_FAILURE) 9987c478bd9Sstevel@tonic-gate pci_pokefault_cnt++; 9997c478bd9Sstevel@tonic-gate #endif 10007c478bd9Sstevel@tonic-gate return (err); 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate static int 10057c478bd9Sstevel@tonic-gate pci_do_caut_put(pci_t *pci_p, peekpoke_ctlops_t *cautacc_ctlops_arg) 10067c478bd9Sstevel@tonic-gate { 10077c478bd9Sstevel@tonic-gate size_t size = cautacc_ctlops_arg->size; 10087c478bd9Sstevel@tonic-gate uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr; 10097c478bd9Sstevel@tonic-gate uintptr_t host_addr = cautacc_ctlops_arg->host_addr; 10107c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle; 10117c478bd9Sstevel@tonic-gate size_t repcount = cautacc_ctlops_arg->repcount; 10127c478bd9Sstevel@tonic-gate uint_t flags = cautacc_ctlops_arg->flags; 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED; 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate /* 10177c478bd9Sstevel@tonic-gate * Note that i_ndi_busop_access_enter ends up grabbing the pokefault 10187c478bd9Sstevel@tonic-gate * mutex. 10197c478bd9Sstevel@tonic-gate */ 10207c478bd9Sstevel@tonic-gate i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 10237c478bd9Sstevel@tonic-gate for (; repcount; repcount--) { 10247c478bd9Sstevel@tonic-gate switch (size) { 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate case sizeof (uint8_t): 10277c478bd9Sstevel@tonic-gate i_ddi_put8(hp, (uint8_t *)dev_addr, 10287c478bd9Sstevel@tonic-gate *(uint8_t *)host_addr); 10297c478bd9Sstevel@tonic-gate break; 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate case sizeof (uint16_t): 10327c478bd9Sstevel@tonic-gate i_ddi_put16(hp, (uint16_t *)dev_addr, 10337c478bd9Sstevel@tonic-gate *(uint16_t *)host_addr); 10347c478bd9Sstevel@tonic-gate break; 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 10377c478bd9Sstevel@tonic-gate i_ddi_put32(hp, (uint32_t *)dev_addr, 10387c478bd9Sstevel@tonic-gate *(uint32_t *)host_addr); 10397c478bd9Sstevel@tonic-gate break; 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 10427c478bd9Sstevel@tonic-gate i_ddi_put64(hp, (uint64_t *)dev_addr, 10437c478bd9Sstevel@tonic-gate *(uint64_t *)host_addr); 10447c478bd9Sstevel@tonic-gate break; 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate host_addr += size; 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 10507c478bd9Sstevel@tonic-gate dev_addr += size; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate i_ddi_notrap((ddi_acc_handle_t)hp); 10567c478bd9Sstevel@tonic-gate i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 10577c478bd9Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED; 10587c478bd9Sstevel@tonic-gate 10594fd7ecabSdilpreet if (hp->ahi_err->err_status != DDI_FM_OK) { 10604fd7ecabSdilpreet /* Clear the expected fault from the handle before returning */ 10614fd7ecabSdilpreet hp->ahi_err->err_status = DDI_FM_OK; 10624fd7ecabSdilpreet return (DDI_FAILURE); 10634fd7ecabSdilpreet } 10644fd7ecabSdilpreet 10654fd7ecabSdilpreet return (DDI_SUCCESS); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate static int 10707c478bd9Sstevel@tonic-gate pci_ctlops_poke(pci_t *pci_p, peekpoke_ctlops_t *in_args) 10717c478bd9Sstevel@tonic-gate { 10727c478bd9Sstevel@tonic-gate return (in_args->handle ? pci_do_caut_put(pci_p, in_args) : 10737c478bd9Sstevel@tonic-gate pci_do_poke(pci_p, in_args)); 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate static int 10787c478bd9Sstevel@tonic-gate pci_do_peek(pci_t *pci_p, peekpoke_ctlops_t *in_args) 10797c478bd9Sstevel@tonic-gate { 10807c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 10817c478bd9Sstevel@tonic-gate on_trap_data_t otd; 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 10847c478bd9Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&peek_fault; 10877c478bd9Sstevel@tonic-gate err = do_peek(in_args->size, (void *)in_args->dev_addr, 10887c478bd9Sstevel@tonic-gate (void *)in_args->host_addr); 10897c478bd9Sstevel@tonic-gate otd.ot_trampoline = tramp; 10907c478bd9Sstevel@tonic-gate } else 10917c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate no_trap(); 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate #ifdef DEBUG 10967c478bd9Sstevel@tonic-gate if (err == DDI_FAILURE) 10977c478bd9Sstevel@tonic-gate pci_peekfault_cnt++; 10987c478bd9Sstevel@tonic-gate #endif 10997c478bd9Sstevel@tonic-gate return (err); 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate static int 11037c478bd9Sstevel@tonic-gate pci_do_caut_get(pci_t *pci_p, peekpoke_ctlops_t *cautacc_ctlops_arg) 11047c478bd9Sstevel@tonic-gate { 11057c478bd9Sstevel@tonic-gate size_t size = cautacc_ctlops_arg->size; 11067c478bd9Sstevel@tonic-gate uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr; 11077c478bd9Sstevel@tonic-gate uintptr_t host_addr = cautacc_ctlops_arg->host_addr; 11087c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle; 11097c478bd9Sstevel@tonic-gate size_t repcount = cautacc_ctlops_arg->repcount; 11107c478bd9Sstevel@tonic-gate uint_t flags = cautacc_ctlops_arg->flags; 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED; 11157c478bd9Sstevel@tonic-gate i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 11187c478bd9Sstevel@tonic-gate for (; repcount; repcount--) { 11197c478bd9Sstevel@tonic-gate i_ddi_caut_get(size, (void *)dev_addr, 11207c478bd9Sstevel@tonic-gate (void *)host_addr); 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate host_addr += size; 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 11257c478bd9Sstevel@tonic-gate dev_addr += size; 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate } else { 11284fd7ecabSdilpreet int i; 11294fd7ecabSdilpreet uint8_t *ff_addr = (uint8_t *)host_addr; 11304fd7ecabSdilpreet for (i = 0; i < size; i++) 11314fd7ecabSdilpreet *ff_addr++ = 0xff; 11324fd7ecabSdilpreet 11337c478bd9Sstevel@tonic-gate err = DDI_FAILURE; 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate i_ddi_notrap((ddi_acc_handle_t)hp); 11377c478bd9Sstevel@tonic-gate i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 11387c478bd9Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED; 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate return (err); 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate static int 11457c478bd9Sstevel@tonic-gate pci_ctlops_peek(pci_t *pci_p, peekpoke_ctlops_t *in_args, void *result) 11467c478bd9Sstevel@tonic-gate { 11477c478bd9Sstevel@tonic-gate result = (void *)in_args->host_addr; 11487c478bd9Sstevel@tonic-gate return (in_args->handle ? pci_do_caut_get(pci_p, in_args) : 11497c478bd9Sstevel@tonic-gate pci_do_peek(pci_p, in_args)); 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate /* 11537c478bd9Sstevel@tonic-gate * get_reg_set_size 11547c478bd9Sstevel@tonic-gate * 11557c478bd9Sstevel@tonic-gate * Given a dev info pointer to a pci child and a register number, this 11567c478bd9Sstevel@tonic-gate * routine returns the size element of that reg set property. 11577c478bd9Sstevel@tonic-gate * return value: size of reg set on success, -1 on error 11587c478bd9Sstevel@tonic-gate */ 11597c478bd9Sstevel@tonic-gate static off_t 11607c478bd9Sstevel@tonic-gate get_reg_set_size(dev_info_t *child, int rnumber) 11617c478bd9Sstevel@tonic-gate { 11627c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp; 11637c478bd9Sstevel@tonic-gate off_t size; 11647c478bd9Sstevel@tonic-gate int i; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate if (rnumber < 0) 11677c478bd9Sstevel@tonic-gate return (-1); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate /* 11707c478bd9Sstevel@tonic-gate * Get the reg property for the device. 11717c478bd9Sstevel@tonic-gate */ 11727c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 11737c478bd9Sstevel@tonic-gate (caddr_t)&pci_rp, &i) != DDI_SUCCESS) 11747c478bd9Sstevel@tonic-gate return (-1); 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate if (rnumber >= (i / (int)sizeof (pci_regspec_t))) { 11777c478bd9Sstevel@tonic-gate kmem_free(pci_rp, i); 11787c478bd9Sstevel@tonic-gate return (-1); 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate size = pci_rp[rnumber].pci_size_low | 11827c478bd9Sstevel@tonic-gate ((uint64_t)pci_rp[rnumber].pci_size_hi << 32); 11837c478bd9Sstevel@tonic-gate kmem_free(pci_rp, i); 11847c478bd9Sstevel@tonic-gate return (size); 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* 11897c478bd9Sstevel@tonic-gate * control ops entry point: 11907c478bd9Sstevel@tonic-gate * 11917c478bd9Sstevel@tonic-gate * Requests handled completely: 11927c478bd9Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD see init_child() for details 11937c478bd9Sstevel@tonic-gate * DDI_CTLOPS_UNINITCHILD 11947c478bd9Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV see report_dev() for details 11957c478bd9Sstevel@tonic-gate * DDI_CTLOPS_IOMIN cache line size if streaming otherwise 1 11967c478bd9Sstevel@tonic-gate * DDI_CTLOPS_REGSIZE 11977c478bd9Sstevel@tonic-gate * DDI_CTLOPS_NREGS 11987c478bd9Sstevel@tonic-gate * DDI_CTLOPS_DVMAPAGESIZE 11997c478bd9Sstevel@tonic-gate * DDI_CTLOPS_POKE 12007c478bd9Sstevel@tonic-gate * DDI_CTLOPS_PEEK 12017c478bd9Sstevel@tonic-gate * DDI_CTLOPS_QUIESCE 12027c478bd9Sstevel@tonic-gate * DDI_CTLOPS_UNQUIESCE 12037c478bd9Sstevel@tonic-gate * 12047c478bd9Sstevel@tonic-gate * All others passed to parent. 12057c478bd9Sstevel@tonic-gate */ 12067c478bd9Sstevel@tonic-gate int 12077c478bd9Sstevel@tonic-gate pci_ctlops(dev_info_t *dip, dev_info_t *rdip, 12087c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result) 12097c478bd9Sstevel@tonic-gate { 12107c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate switch (op) { 12137c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 12147c478bd9Sstevel@tonic-gate return (init_child(pci_p, (dev_info_t *)arg)); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 12177c478bd9Sstevel@tonic-gate return (uninit_child(pci_p, (dev_info_t *)arg)); 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 12207c478bd9Sstevel@tonic-gate return (report_dev(rdip)); 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate case DDI_CTLOPS_IOMIN: 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate /* 12257c478bd9Sstevel@tonic-gate * If we are using the streaming cache, align at 12267c478bd9Sstevel@tonic-gate * least on a cache line boundary. Otherwise use 12277c478bd9Sstevel@tonic-gate * whatever alignment is passed in. 12287c478bd9Sstevel@tonic-gate */ 12297c478bd9Sstevel@tonic-gate 1230f47a9c50Smathue if ((uintptr_t)arg) { 12317c478bd9Sstevel@tonic-gate int val = *((int *)result); 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate val = maxbit(val, PCI_SBUF_LINE_SIZE); 12347c478bd9Sstevel@tonic-gate *((int *)result) = val; 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 12397c478bd9Sstevel@tonic-gate *((off_t *)result) = get_reg_set_size(rdip, *((int *)arg)); 12407c478bd9Sstevel@tonic-gate return (*((off_t *)result) == -1 ? DDI_FAILURE : DDI_SUCCESS); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 12437c478bd9Sstevel@tonic-gate *((uint_t *)result) = get_nreg_set(rdip); 12447c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate case DDI_CTLOPS_DVMAPAGESIZE: 12477c478bd9Sstevel@tonic-gate *((ulong_t *)result) = IOMMU_PAGE_SIZE; 12487c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate case DDI_CTLOPS_POKE: 12517c478bd9Sstevel@tonic-gate return (pci_ctlops_poke(pci_p, (peekpoke_ctlops_t *)arg)); 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate case DDI_CTLOPS_PEEK: 12547c478bd9Sstevel@tonic-gate return (pci_ctlops_peek(pci_p, (peekpoke_ctlops_t *)arg, 12557c478bd9Sstevel@tonic-gate result)); 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate case DDI_CTLOPS_AFFINITY: 12587c478bd9Sstevel@tonic-gate break; 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate case DDI_CTLOPS_QUIESCE: 12617c478bd9Sstevel@tonic-gate return (pci_bus_quiesce(pci_p, rdip, result)); 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNQUIESCE: 12647c478bd9Sstevel@tonic-gate return (pci_bus_unquiesce(pci_p, rdip, result)); 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate default: 12677c478bd9Sstevel@tonic-gate break; 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate /* 12717c478bd9Sstevel@tonic-gate * Now pass the request up to our parent. 12727c478bd9Sstevel@tonic-gate */ 12737c478bd9Sstevel@tonic-gate DEBUG2(DBG_CTLOPS, dip, "passing request to parent: rdip=%s%d\n", 12747c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip)); 12757c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate /* ARGSUSED */ 12807c478bd9Sstevel@tonic-gate int 12817c478bd9Sstevel@tonic-gate pci_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 12827c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 12837c478bd9Sstevel@tonic-gate { 128409b1eac2SEvan Yan pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip)); 128509b1eac2SEvan Yan ib_ino_t ino; 12867c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate switch (intr_op) { 12897c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 12907c478bd9Sstevel@tonic-gate /* GetCap will always fail for all non PCI devices */ 12917c478bd9Sstevel@tonic-gate (void) pci_intx_get_cap(rdip, (int *)result); 12927c478bd9Sstevel@tonic-gate break; 12937c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 12947c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 12957c478bd9Sstevel@tonic-gate break; 12967c478bd9Sstevel@tonic-gate case DDI_INTROP_ALLOC: 12977c478bd9Sstevel@tonic-gate *(int *)result = hdlp->ih_scratch1; 12987c478bd9Sstevel@tonic-gate break; 12997c478bd9Sstevel@tonic-gate case DDI_INTROP_FREE: 13007c478bd9Sstevel@tonic-gate break; 13017c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPRI: 1302a195726fSgovinda *(int *)result = hdlp->ih_pri ? 1303a195726fSgovinda hdlp->ih_pri : pci_class_to_pil(rdip); 13047c478bd9Sstevel@tonic-gate break; 13057c478bd9Sstevel@tonic-gate case DDI_INTROP_SETPRI: 13067c478bd9Sstevel@tonic-gate break; 13077c478bd9Sstevel@tonic-gate case DDI_INTROP_ADDISR: 13087c478bd9Sstevel@tonic-gate ret = pci_add_intr(dip, rdip, hdlp); 13097c478bd9Sstevel@tonic-gate break; 13107c478bd9Sstevel@tonic-gate case DDI_INTROP_REMISR: 13117c478bd9Sstevel@tonic-gate ret = pci_remove_intr(dip, rdip, hdlp); 13127c478bd9Sstevel@tonic-gate break; 131309b1eac2SEvan Yan case DDI_INTROP_GETTARGET: 131409b1eac2SEvan Yan ino = IB_MONDO_TO_INO(pci_xlate_intr(dip, rdip, 131509b1eac2SEvan Yan pci_p->pci_ib_p, IB_MONDO_TO_INO(hdlp->ih_vector))); 131609b1eac2SEvan Yan ret = ib_get_intr_target(pci_p, ino, (int *)result); 131709b1eac2SEvan Yan break; 131809b1eac2SEvan Yan case DDI_INTROP_SETTARGET: 131909b1eac2SEvan Yan ret = DDI_ENOTSUP; 132009b1eac2SEvan Yan break; 13217c478bd9Sstevel@tonic-gate case DDI_INTROP_ENABLE: 13227c478bd9Sstevel@tonic-gate ret = ib_update_intr_state(pci_p, rdip, hdlp, 13237c478bd9Sstevel@tonic-gate PCI_INTR_STATE_ENABLE); 13247c478bd9Sstevel@tonic-gate break; 13257c478bd9Sstevel@tonic-gate case DDI_INTROP_DISABLE: 13267c478bd9Sstevel@tonic-gate ret = ib_update_intr_state(pci_p, rdip, hdlp, 13277c478bd9Sstevel@tonic-gate PCI_INTR_STATE_DISABLE); 13287c478bd9Sstevel@tonic-gate break; 13297c478bd9Sstevel@tonic-gate case DDI_INTROP_SETMASK: 13307c478bd9Sstevel@tonic-gate ret = pci_intx_set_mask(rdip); 13317c478bd9Sstevel@tonic-gate break; 13327c478bd9Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 13337c478bd9Sstevel@tonic-gate ret = pci_intx_clr_mask(rdip); 13347c478bd9Sstevel@tonic-gate break; 13357c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 13367c478bd9Sstevel@tonic-gate ret = pci_intx_get_pending(rdip, (int *)result); 13377c478bd9Sstevel@tonic-gate break; 13387c478bd9Sstevel@tonic-gate case DDI_INTROP_NINTRS: 13397c478bd9Sstevel@tonic-gate case DDI_INTROP_NAVAIL: 1340a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip); 13417c478bd9Sstevel@tonic-gate break; 13427c478bd9Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 13437c478bd9Sstevel@tonic-gate /* PCI nexus driver supports only fixed interrupts */ 1344a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip) ? 13457c478bd9Sstevel@tonic-gate DDI_INTR_TYPE_FIXED : 0; 13467c478bd9Sstevel@tonic-gate break; 13477c478bd9Sstevel@tonic-gate default: 13487c478bd9Sstevel@tonic-gate ret = DDI_ENOTSUP; 13497c478bd9Sstevel@tonic-gate break; 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate return (ret); 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate static void 13567c478bd9Sstevel@tonic-gate pci_init_hotplug(struct pci *pci_p) 13577c478bd9Sstevel@tonic-gate { 13587c478bd9Sstevel@tonic-gate pci_bus_range_t bus_range; 13597c478bd9Sstevel@tonic-gate dev_info_t *dip; 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate /* 13627c478bd9Sstevel@tonic-gate * Before initializing hotplug - open up 13637c478bd9Sstevel@tonic-gate * bus range. The busra module will 13647c478bd9Sstevel@tonic-gate * initialize its pool of bus numbers from 13657c478bd9Sstevel@tonic-gate * this. "busra" will be the agent that keeps 13667c478bd9Sstevel@tonic-gate * track of them during hotplug. Also, note, 13677c478bd9Sstevel@tonic-gate * that busra will remove any bus numbers 13687c478bd9Sstevel@tonic-gate * already in use from boot time. 13697c478bd9Sstevel@tonic-gate */ 13707c478bd9Sstevel@tonic-gate bus_range.lo = 0x0; 13717c478bd9Sstevel@tonic-gate bus_range.hi = 0xff; 13727c478bd9Sstevel@tonic-gate dip = pci_p->pci_dip; 13737c478bd9Sstevel@tonic-gate pci_p->hotplug_capable = B_FALSE; 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate /* 13767c478bd9Sstevel@tonic-gate * If this property exists, this nexus has hot-plug 13777c478bd9Sstevel@tonic-gate * slots. 13787c478bd9Sstevel@tonic-gate */ 13797c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 13807c478bd9Sstevel@tonic-gate "hotplug-capable")) { 13817c478bd9Sstevel@tonic-gate if (ndi_prop_update_int_array(DDI_DEV_T_NONE, 13827c478bd9Sstevel@tonic-gate dip, "bus-range", 13837c478bd9Sstevel@tonic-gate (int *)&bus_range, 13847c478bd9Sstevel@tonic-gate 2) != DDI_PROP_SUCCESS) { 13857c478bd9Sstevel@tonic-gate return; 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate 13887c478bd9Sstevel@tonic-gate if (pcihp_init(dip) != DDI_SUCCESS) { 13897c478bd9Sstevel@tonic-gate return; 13907c478bd9Sstevel@tonic-gate } 13917c478bd9Sstevel@tonic-gate 1392e389d146Sschwartz if ((pcihp_ops = pcihp_get_cb_ops()) != NULL) { 13937c478bd9Sstevel@tonic-gate DEBUG2(DBG_ATTACH, dip, "%s%d hotplug enabled", 13947c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 13957c478bd9Sstevel@tonic-gate pci_p->hotplug_capable = B_TRUE; 13967c478bd9Sstevel@tonic-gate } 13977c478bd9Sstevel@tonic-gate } 1398e389d146Sschwartz } 1399