1881Sjohnny /*
2881Sjohnny * CDDL HEADER START
3881Sjohnny *
4881Sjohnny * The contents of this file are subject to the terms of the
51542Sjohnny * Common Development and Distribution License (the "License").
61542Sjohnny * You may not use this file except in compliance with the License.
7881Sjohnny *
8881Sjohnny * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9881Sjohnny * or http://www.opensolaris.org/os/licensing.
10881Sjohnny * See the License for the specific language governing permissions
11881Sjohnny * and limitations under the License.
12881Sjohnny *
13881Sjohnny * When distributing Covered Code, include this CDDL HEADER in each
14881Sjohnny * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15881Sjohnny * If applicable, add the following below this CDDL HEADER, with the
16881Sjohnny * fields enclosed by brackets "[]" replaced with your own identifying
17881Sjohnny * information: Portions Copyright [yyyy] [name of copyright owner]
18881Sjohnny *
19881Sjohnny * CDDL HEADER END
20881Sjohnny */
21881Sjohnny
22881Sjohnny /*
23*12825SJimmy.Vetayases@oracle.com * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24881Sjohnny */
25881Sjohnny
26881Sjohnny /*
27881Sjohnny * File that has code which is common between pci(7d) and npe(7d)
28881Sjohnny * It shares the following:
29881Sjohnny * - interrupt code
30881Sjohnny * - pci_tools ioctl code
31881Sjohnny * - name_child code
32881Sjohnny * - set_parent_private_data code
33881Sjohnny */
34881Sjohnny
35881Sjohnny #include <sys/conf.h>
36881Sjohnny #include <sys/pci.h>
37881Sjohnny #include <sys/sunndi.h>
38916Sschwartz #include <sys/mach_intr.h>
39881Sjohnny #include <sys/pci_intr_lib.h>
40881Sjohnny #include <sys/psm.h>
41881Sjohnny #include <sys/policy.h>
42881Sjohnny #include <sys/sysmacros.h>
43916Sschwartz #include <sys/clock.h>
443446Smrj #include <sys/apic.h>
45881Sjohnny #include <sys/pci_tools.h>
46881Sjohnny #include <io/pci/pci_var.h>
47881Sjohnny #include <io/pci/pci_tools_ext.h>
48881Sjohnny #include <io/pci/pci_common.h>
491083Sanish #include <sys/pci_cfgspace.h>
501083Sanish #include <sys/pci_impl.h>
514160Sjveta #include <sys/pci_cap.h>
52881Sjohnny
53881Sjohnny /*
54881Sjohnny * Function prototypes
55881Sjohnny */
56881Sjohnny static int pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
57881Sjohnny static int pci_enable_intr(dev_info_t *, dev_info_t *,
58881Sjohnny ddi_intr_handle_impl_t *, uint32_t);
59881Sjohnny static void pci_disable_intr(dev_info_t *, dev_info_t *,
60881Sjohnny ddi_intr_handle_impl_t *, uint32_t);
6112683SJimmy.Vetayases@oracle.com static int pci_alloc_intr_fixed(dev_info_t *, dev_info_t *,
6212683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *, void *);
6312683SJimmy.Vetayases@oracle.com static int pci_free_intr_fixed(dev_info_t *, dev_info_t *,
6412683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *);
65881Sjohnny
6612683SJimmy.Vetayases@oracle.com /* Extern declarations for PSM module */
67881Sjohnny extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
68881Sjohnny psm_intr_op_t, int *);
6912683SJimmy.Vetayases@oracle.com extern ddi_irm_pool_t *apix_irm_pool_p;
70881Sjohnny
71881Sjohnny /*
72881Sjohnny * pci_name_child:
73881Sjohnny *
74881Sjohnny * Assign the address portion of the node name
75881Sjohnny */
76881Sjohnny int
pci_common_name_child(dev_info_t * child,char * name,int namelen)77881Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen)
78881Sjohnny {
79881Sjohnny int dev, func, length;
80881Sjohnny char **unit_addr;
81881Sjohnny uint_t n;
82881Sjohnny pci_regspec_t *pci_rp;
83881Sjohnny
84881Sjohnny if (ndi_dev_is_persistent_node(child) == 0) {
85881Sjohnny /*
86881Sjohnny * For .conf node, use "unit-address" property
87881Sjohnny */
88881Sjohnny if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
89881Sjohnny DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
90881Sjohnny DDI_PROP_SUCCESS) {
91881Sjohnny cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
92881Sjohnny ddi_get_name(child));
93881Sjohnny return (DDI_FAILURE);
94881Sjohnny }
95881Sjohnny if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
96881Sjohnny cmn_err(CE_WARN, "unit-address property in %s.conf"
97881Sjohnny " not well-formed", ddi_get_name(child));
98881Sjohnny ddi_prop_free(unit_addr);
99881Sjohnny return (DDI_FAILURE);
100881Sjohnny }
101881Sjohnny (void) snprintf(name, namelen, "%s", *unit_addr);
102881Sjohnny ddi_prop_free(unit_addr);
103881Sjohnny return (DDI_SUCCESS);
104881Sjohnny }
105881Sjohnny
106881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
107881Sjohnny "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
108881Sjohnny cmn_err(CE_WARN, "cannot find reg property in %s",
109881Sjohnny ddi_get_name(child));
110881Sjohnny return (DDI_FAILURE);
111881Sjohnny }
112881Sjohnny
113881Sjohnny /* copy the device identifications */
114881Sjohnny dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
115881Sjohnny func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
116881Sjohnny
117881Sjohnny /*
118881Sjohnny * free the memory allocated by ddi_prop_lookup_int_array
119881Sjohnny */
120881Sjohnny ddi_prop_free(pci_rp);
121881Sjohnny
122881Sjohnny if (func != 0) {
123881Sjohnny (void) snprintf(name, namelen, "%x,%x", dev, func);
124881Sjohnny } else {
125881Sjohnny (void) snprintf(name, namelen, "%x", dev);
126881Sjohnny }
127881Sjohnny
128881Sjohnny return (DDI_SUCCESS);
129881Sjohnny }
130881Sjohnny
131881Sjohnny /*
132881Sjohnny * Interrupt related code:
133881Sjohnny *
134881Sjohnny * The following busop is common to npe and pci drivers
135881Sjohnny * bus_introp
136881Sjohnny */
137881Sjohnny
138881Sjohnny /*
139881Sjohnny * Create the ddi_parent_private_data for a pseudo child.
140881Sjohnny */
141881Sjohnny void
pci_common_set_parent_private_data(dev_info_t * dip)142881Sjohnny pci_common_set_parent_private_data(dev_info_t *dip)
143881Sjohnny {
144881Sjohnny struct ddi_parent_private_data *pdptr;
145881Sjohnny
146881Sjohnny pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
147881Sjohnny (sizeof (struct ddi_parent_private_data) +
1484397Sschwartz sizeof (struct intrspec)), KM_SLEEP);
149881Sjohnny pdptr->par_intr = (struct intrspec *)(pdptr + 1);
150881Sjohnny pdptr->par_nintr = 1;
151881Sjohnny ddi_set_parent_data(dip, pdptr);
152881Sjohnny }
153881Sjohnny
154881Sjohnny /*
155881Sjohnny * pci_get_priority:
156881Sjohnny * Figure out the priority of the device
157881Sjohnny */
158881Sjohnny static int
pci_get_priority(dev_info_t * dip,ddi_intr_handle_impl_t * hdlp,int * pri)159881Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
160881Sjohnny {
161881Sjohnny struct intrspec *ispec;
162881Sjohnny
163881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
164881Sjohnny (void *)dip, (void *)hdlp));
165881Sjohnny
166881Sjohnny if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
167881Sjohnny hdlp->ih_inum)) == NULL) {
168881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
1698535Sevan.yan@sun.com *pri = pci_class_to_pil(dip);
170881Sjohnny pci_common_set_parent_private_data(hdlp->ih_dip);
171881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
172881Sjohnny hdlp->ih_inum);
173881Sjohnny return (DDI_SUCCESS);
174881Sjohnny }
175881Sjohnny return (DDI_FAILURE);
176881Sjohnny }
177881Sjohnny
178881Sjohnny *pri = ispec->intrspec_pri;
179881Sjohnny return (DDI_SUCCESS);
180881Sjohnny }
181881Sjohnny
182881Sjohnny
183881Sjohnny
18410187SKrishna.Elango@Sun.COM static int pcieb_intr_pri_counter = 0;
185881Sjohnny
186881Sjohnny /*
187881Sjohnny * pci_common_intr_ops: bus_intr_op() function for interrupt support
188881Sjohnny */
189881Sjohnny int
pci_common_intr_ops(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)190881Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
191881Sjohnny ddi_intr_handle_impl_t *hdlp, void *result)
192881Sjohnny {
193881Sjohnny int priority = 0;
194881Sjohnny int psm_status = 0;
195881Sjohnny int pci_status = 0;
196881Sjohnny int pci_rval, psm_rval = PSM_FAILURE;
197881Sjohnny int types = 0;
198881Sjohnny int pciepci = 0;
1991542Sjohnny int i, j, count;
2004160Sjveta int rv;
201881Sjohnny int behavior;
2021997Sanish int cap_ptr;
2034160Sjveta uint16_t msi_cap_base, msix_cap_base, cap_ctrl;
2044160Sjveta char *prop;
205881Sjohnny ddi_intrspec_t isp;
206881Sjohnny struct intrspec *ispec;
207881Sjohnny ddi_intr_handle_impl_t tmp_hdl;
208881Sjohnny ddi_intr_msix_t *msix_p;
2091087Sschwartz ihdl_plat_t *ihdl_plat_datap;
2101542Sjohnny ddi_intr_handle_t *h_array;
2111997Sanish ddi_acc_handle_t handle;
21212683SJimmy.Vetayases@oracle.com apic_get_intr_t intrinfo;
213881Sjohnny
214881Sjohnny DDI_INTR_NEXDBG((CE_CONT,
215881Sjohnny "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
216881Sjohnny (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
217881Sjohnny
218881Sjohnny /* Process the request */
219881Sjohnny switch (intr_op) {
220881Sjohnny case DDI_INTROP_SUPPORTED_TYPES:
2214160Sjveta /*
2224160Sjveta * First we determine the interrupt types supported by the
2234160Sjveta * device itself, then we filter them through what the OS
2244160Sjveta * and system supports. We determine system-level
2254160Sjveta * interrupt type support for anything other than fixed intrs
2264160Sjveta * through the psm_intr_ops vector
2274160Sjveta */
2284160Sjveta rv = DDI_FAILURE;
2294160Sjveta
230881Sjohnny /* Fixed supported by default */
2314160Sjveta types = DDI_INTR_TYPE_FIXED;
2324160Sjveta
2334160Sjveta if (psm_intr_ops == NULL) {
2344160Sjveta *(int *)result = types;
2354160Sjveta return (DDI_SUCCESS);
2364160Sjveta }
2374160Sjveta if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
2384160Sjveta return (DDI_FAILURE);
239881Sjohnny
2404160Sjveta /* Sanity test cap control values if found */
2414160Sjveta
2424160Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) ==
2434160Sjveta DDI_SUCCESS) {
2444160Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base,
2454160Sjveta PCI_MSI_CTRL);
2464160Sjveta if (cap_ctrl == PCI_CAP_EINVAL16)
2474160Sjveta goto SUPPORTED_TYPES_OUT;
2484160Sjveta
2494160Sjveta types |= DDI_INTR_TYPE_MSI;
2504160Sjveta }
2514160Sjveta
2524160Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) ==
2534160Sjveta DDI_SUCCESS) {
2544160Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base,
2554160Sjveta PCI_MSIX_CTRL);
2564160Sjveta if (cap_ctrl == PCI_CAP_EINVAL16)
2574160Sjveta goto SUPPORTED_TYPES_OUT;
258881Sjohnny
2594160Sjveta types |= DDI_INTR_TYPE_MSIX;
2604160Sjveta }
2614160Sjveta
2624160Sjveta /*
2634160Sjveta * Filter device-level types through system-level support
2644160Sjveta */
2654160Sjveta tmp_hdl.ih_type = types;
2664160Sjveta if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI,
2674160Sjveta &types) != PSM_SUCCESS)
2684160Sjveta goto SUPPORTED_TYPES_OUT;
2694160Sjveta
2704160Sjveta DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
2714160Sjveta "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
27212683SJimmy.Vetayases@oracle.com types));
273881Sjohnny
2744160Sjveta /*
2754160Sjveta * Export any MSI/MSI-X cap locations via properties
2764160Sjveta */
2774160Sjveta if (types & DDI_INTR_TYPE_MSI) {
2784160Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
2794160Sjveta "pci-msi-capid-pointer", (int)msi_cap_base) !=
2804160Sjveta DDI_PROP_SUCCESS)
2814160Sjveta goto SUPPORTED_TYPES_OUT;
282881Sjohnny }
2834160Sjveta if (types & DDI_INTR_TYPE_MSIX) {
2844160Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
2854160Sjveta "pci-msix-capid-pointer", (int)msix_cap_base) !=
2864160Sjveta DDI_PROP_SUCCESS)
2874160Sjveta goto SUPPORTED_TYPES_OUT;
2884160Sjveta }
2894160Sjveta
2904160Sjveta rv = DDI_SUCCESS;
2914160Sjveta
2924160Sjveta SUPPORTED_TYPES_OUT:
2934160Sjveta *(int *)result = types;
2944160Sjveta pci_config_teardown(&handle);
2954160Sjveta return (rv);
2964160Sjveta
2972580Sanish case DDI_INTROP_NAVAIL:
298881Sjohnny case DDI_INTROP_NINTRS:
2992580Sanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
3002580Sanish if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
3012580Sanish result) != DDI_SUCCESS)
3022580Sanish return (DDI_FAILURE);
3032580Sanish } else {
3042580Sanish *(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
3052580Sanish if (*(int *)result == 0)
3062580Sanish return (DDI_FAILURE);
3072580Sanish }
308881Sjohnny break;
309881Sjohnny case DDI_INTROP_ALLOC:
31012683SJimmy.Vetayases@oracle.com
31112683SJimmy.Vetayases@oracle.com /*
31212683SJimmy.Vetayases@oracle.com * FIXED type
31312683SJimmy.Vetayases@oracle.com */
31412683SJimmy.Vetayases@oracle.com if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
31512683SJimmy.Vetayases@oracle.com return (pci_alloc_intr_fixed(pdip, rdip, hdlp, result));
316881Sjohnny /*
317881Sjohnny * MSI or MSIX (figure out number of vectors available)
318881Sjohnny */
319881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
320881Sjohnny (psm_intr_ops != NULL) &&
321881Sjohnny (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
322881Sjohnny /*
32310187SKrishna.Elango@Sun.COM * Following check is a special case for 'pcieb'.
324881Sjohnny * This makes sure vectors with the right priority
32510187SKrishna.Elango@Sun.COM * are allocated for pcieb during ALLOC time.
326881Sjohnny */
32710187SKrishna.Elango@Sun.COM if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) {
328881Sjohnny hdlp->ih_pri =
32910187SKrishna.Elango@Sun.COM (pcieb_intr_pri_counter % 2) ? 4 : 7;
330881Sjohnny pciepci = 1;
331881Sjohnny } else
332881Sjohnny hdlp->ih_pri = priority;
3331717Swesolows behavior = (int)(uintptr_t)hdlp->ih_scratch2;
3341997Sanish
3351997Sanish /*
3361997Sanish * Cache in the config handle and cap_ptr
3371997Sanish */
3381997Sanish if (i_ddi_get_pci_config_handle(rdip) == NULL) {
3391997Sanish if (pci_config_setup(rdip, &handle) !=
3401997Sanish DDI_SUCCESS)
3411997Sanish return (DDI_FAILURE);
3421997Sanish i_ddi_set_pci_config_handle(rdip, handle);
3431997Sanish }
3441997Sanish
3454160Sjveta prop = NULL;
3464160Sjveta cap_ptr = 0;
3474160Sjveta if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
3484160Sjveta prop = "pci-msi-capid-pointer";
3494160Sjveta else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX)
3504160Sjveta prop = "pci-msix-capid-pointer";
3511997Sanish
3524160Sjveta /*
3534160Sjveta * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES
3544160Sjveta * for MSI(X) before allocation
3554160Sjveta */
3564160Sjveta if (prop != NULL) {
3571997Sanish cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
3584160Sjveta DDI_PROP_DONTPASS, prop, 0);
3594160Sjveta if (cap_ptr == 0) {
3604160Sjveta DDI_INTR_NEXDBG((CE_CONT,
3614160Sjveta "pci_common_intr_ops: rdip: 0x%p "
3624160Sjveta "attempted MSI(X) alloc without "
3634160Sjveta "cap property\n", (void *)rdip));
3644160Sjveta return (DDI_FAILURE);
3654160Sjveta }
3661997Sanish }
3674160Sjveta i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
3681997Sanish
3694160Sjveta /*
3704160Sjveta * Allocate interrupt vectors
3714160Sjveta */
372881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp,
373881Sjohnny PSM_INTR_OP_ALLOC_VECTORS, result);
374881Sjohnny
3753112Sanish if (*(int *)result == 0)
3763112Sanish return (DDI_INTR_NOTFOUND);
3773112Sanish
378881Sjohnny /* verify behavior flag and take appropriate action */
379881Sjohnny if ((behavior == DDI_INTR_ALLOC_STRICT) &&
380881Sjohnny (*(int *)result < hdlp->ih_scratch1)) {
381881Sjohnny DDI_INTR_NEXDBG((CE_CONT,
382881Sjohnny "pci_common_intr_ops: behavior %x, "
383881Sjohnny "couldn't get enough intrs\n", behavior));
384881Sjohnny hdlp->ih_scratch1 = *(int *)result;
385881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp,
386881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL);
387881Sjohnny return (DDI_EAGAIN);
388881Sjohnny }
389881Sjohnny
390881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
391881Sjohnny if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
392881Sjohnny msix_p = pci_msix_init(hdlp->ih_dip);
39310647SLipeng.Sang@Sun.COM if (msix_p) {
394881Sjohnny i_ddi_set_msix(hdlp->ih_dip,
395881Sjohnny msix_p);
39610647SLipeng.Sang@Sun.COM } else {
39710647SLipeng.Sang@Sun.COM DDI_INTR_NEXDBG((CE_CONT,
39810647SLipeng.Sang@Sun.COM "pci_common_intr_ops: MSI-X"
39910647SLipeng.Sang@Sun.COM "table initilization failed"
40010647SLipeng.Sang@Sun.COM ", rdip 0x%p inum 0x%x\n",
40110647SLipeng.Sang@Sun.COM (void *)rdip,
40210647SLipeng.Sang@Sun.COM hdlp->ih_inum));
40310647SLipeng.Sang@Sun.COM
40410647SLipeng.Sang@Sun.COM (void) (*psm_intr_ops)(rdip,
40510647SLipeng.Sang@Sun.COM hdlp,
40610647SLipeng.Sang@Sun.COM PSM_INTR_OP_FREE_VECTORS,
40710647SLipeng.Sang@Sun.COM NULL);
40810647SLipeng.Sang@Sun.COM
40910647SLipeng.Sang@Sun.COM return (DDI_FAILURE);
41010647SLipeng.Sang@Sun.COM }
411881Sjohnny }
412881Sjohnny }
413881Sjohnny
414881Sjohnny if (pciepci) {
415881Sjohnny /* update priority in ispec */
416881Sjohnny isp = pci_intx_get_ispec(pdip, rdip,
4174397Sschwartz (int)hdlp->ih_inum);
418881Sjohnny ispec = (struct intrspec *)isp;
419881Sjohnny if (ispec)
420881Sjohnny ispec->intrspec_pri = hdlp->ih_pri;
42110187SKrishna.Elango@Sun.COM ++pcieb_intr_pri_counter;
422881Sjohnny }
423881Sjohnny
424881Sjohnny } else
425881Sjohnny return (DDI_FAILURE);
426881Sjohnny break;
427881Sjohnny case DDI_INTROP_FREE:
428881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
429881Sjohnny (psm_intr_ops != NULL)) {
4302018Sanish if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
4312018Sanish 0) {
4321997Sanish if (handle = i_ddi_get_pci_config_handle(
4331997Sanish rdip)) {
4341997Sanish (void) pci_config_teardown(&handle);
4351997Sanish i_ddi_set_pci_config_handle(rdip, NULL);
4361997Sanish }
4371997Sanish if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
4381997Sanish i_ddi_set_msi_msix_cap_ptr(rdip, 0);
4391997Sanish }
4401997Sanish
441881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp,
442881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL);
443881Sjohnny
444881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
445881Sjohnny msix_p = i_ddi_get_msix(hdlp->ih_dip);
446881Sjohnny if (msix_p &&
4472018Sanish (i_ddi_intr_get_current_nintrs(
4484397Sschwartz hdlp->ih_dip) - 1) == 0) {
449881Sjohnny pci_msix_fini(msix_p);
450881Sjohnny i_ddi_set_msix(hdlp->ih_dip, NULL);
451881Sjohnny }
452881Sjohnny }
45312683SJimmy.Vetayases@oracle.com } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
45412683SJimmy.Vetayases@oracle.com return (pci_free_intr_fixed(pdip, rdip, hdlp));
45512683SJimmy.Vetayases@oracle.com } else
45612683SJimmy.Vetayases@oracle.com return (DDI_FAILURE);
457881Sjohnny break;
458881Sjohnny case DDI_INTROP_GETPRI:
459881Sjohnny /* Get the priority */
460881Sjohnny if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
461881Sjohnny return (DDI_FAILURE);
462881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
463881Sjohnny "priority = 0x%x\n", priority));
464881Sjohnny *(int *)result = priority;
465881Sjohnny break;
466881Sjohnny case DDI_INTROP_SETPRI:
467881Sjohnny /* Validate the interrupt priority passed */
468881Sjohnny if (*(int *)result > LOCK_LEVEL)
469881Sjohnny return (DDI_FAILURE);
470881Sjohnny
471881Sjohnny /* Ensure that PSM is all initialized */
472881Sjohnny if (psm_intr_ops == NULL)
473881Sjohnny return (DDI_FAILURE);
474881Sjohnny
47510190SSophia.Li@Sun.COM isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
47610190SSophia.Li@Sun.COM ispec = (struct intrspec *)isp;
47710190SSophia.Li@Sun.COM if (ispec == NULL)
47810190SSophia.Li@Sun.COM return (DDI_FAILURE);
47910190SSophia.Li@Sun.COM
48010190SSophia.Li@Sun.COM /* For fixed interrupts */
48110190SSophia.Li@Sun.COM if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
48210190SSophia.Li@Sun.COM /* if interrupt is shared, return failure */
48310190SSophia.Li@Sun.COM ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
48410190SSophia.Li@Sun.COM psm_rval = (*psm_intr_ops)(rdip, hdlp,
48510190SSophia.Li@Sun.COM PSM_INTR_OP_GET_SHARED, &psm_status);
48610190SSophia.Li@Sun.COM /*
48710190SSophia.Li@Sun.COM * For fixed interrupts, the irq may not have been
48810190SSophia.Li@Sun.COM * allocated when SET_PRI is called, and the above
48910190SSophia.Li@Sun.COM * GET_SHARED op may return PSM_FAILURE. This is not
49010190SSophia.Li@Sun.COM * a real error and is ignored below.
49110190SSophia.Li@Sun.COM */
49210190SSophia.Li@Sun.COM if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) {
49310190SSophia.Li@Sun.COM DDI_INTR_NEXDBG((CE_CONT,
49410190SSophia.Li@Sun.COM "pci_common_intr_ops: "
49510190SSophia.Li@Sun.COM "dip 0x%p cannot setpri, psm_rval=%d,"
49610190SSophia.Li@Sun.COM "psm_status=%d\n", (void *)rdip, psm_rval,
49710190SSophia.Li@Sun.COM psm_status));
49810190SSophia.Li@Sun.COM return (DDI_FAILURE);
49910190SSophia.Li@Sun.COM }
50010190SSophia.Li@Sun.COM }
50110190SSophia.Li@Sun.COM
502881Sjohnny /* Change the priority */
503881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
504881Sjohnny PSM_FAILURE)
505881Sjohnny return (DDI_FAILURE);
506881Sjohnny
507881Sjohnny /* update ispec */
50810190SSophia.Li@Sun.COM ispec->intrspec_pri = *(int *)result;
509881Sjohnny break;
510881Sjohnny case DDI_INTROP_ADDISR:
511881Sjohnny /* update ispec */
512881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
513881Sjohnny ispec = (struct intrspec *)isp;
5141087Sschwartz if (ispec) {
515881Sjohnny ispec->intrspec_func = hdlp->ih_cb_func;
5161087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
5171087Sschwartz pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
5181087Sschwartz }
519881Sjohnny break;
520881Sjohnny case DDI_INTROP_REMISR:
521881Sjohnny /* Get the interrupt structure pointer */
522881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
523881Sjohnny ispec = (struct intrspec *)isp;
5241087Sschwartz if (ispec) {
525881Sjohnny ispec->intrspec_func = (uint_t (*)()) 0;
5261087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
5271087Sschwartz if (ihdl_plat_datap->ip_ksp != NULL)
5281087Sschwartz pci_kstat_delete(ihdl_plat_datap->ip_ksp);
5291087Sschwartz }
530881Sjohnny break;
531881Sjohnny case DDI_INTROP_GETCAP:
532881Sjohnny /*
533881Sjohnny * First check the config space and/or
534881Sjohnny * MSI capability register(s)
535881Sjohnny */
536881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
537881Sjohnny pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
538881Sjohnny &pci_status);
539881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
540881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status);
541881Sjohnny
54212683SJimmy.Vetayases@oracle.com /* next check with PSM module */
543881Sjohnny if (psm_intr_ops != NULL)
544881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp,
545881Sjohnny PSM_INTR_OP_GET_CAP, &psm_status);
546881Sjohnny
547881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
548881Sjohnny "psm_status = %x, pci_rval = %x, pci_status = %x\n",
549881Sjohnny psm_rval, psm_status, pci_rval, pci_status));
550881Sjohnny
551881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
552881Sjohnny *(int *)result = 0;
553881Sjohnny return (DDI_FAILURE);
554881Sjohnny }
555881Sjohnny
556881Sjohnny if (psm_rval == PSM_SUCCESS)
557881Sjohnny *(int *)result = psm_status;
558881Sjohnny
559881Sjohnny if (pci_rval == DDI_SUCCESS)
560881Sjohnny *(int *)result |= pci_status;
561881Sjohnny
562881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
563881Sjohnny *(int *)result));
564881Sjohnny break;
565881Sjohnny case DDI_INTROP_SETCAP:
566881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
567881Sjohnny "SETCAP cap=0x%x\n", *(int *)result));
568881Sjohnny if (psm_intr_ops == NULL)
569881Sjohnny return (DDI_FAILURE);
570881Sjohnny
571881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
572881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
573881Sjohnny " returned failure\n"));
574881Sjohnny return (DDI_FAILURE);
575881Sjohnny }
576881Sjohnny break;
577881Sjohnny case DDI_INTROP_ENABLE:
578881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
579881Sjohnny if (psm_intr_ops == NULL)
580881Sjohnny return (DDI_FAILURE);
581881Sjohnny
582881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
583881Sjohnny DDI_SUCCESS)
584881Sjohnny return (DDI_FAILURE);
585881Sjohnny
586881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
587881Sjohnny "vector=0x%x\n", hdlp->ih_vector));
588881Sjohnny break;
589881Sjohnny case DDI_INTROP_DISABLE:
590881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
591881Sjohnny if (psm_intr_ops == NULL)
592881Sjohnny return (DDI_FAILURE);
593881Sjohnny
594881Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
595881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
596881Sjohnny "vector = %x\n", hdlp->ih_vector));
597881Sjohnny break;
598881Sjohnny case DDI_INTROP_BLOCKENABLE:
599881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
600881Sjohnny "BLOCKENABLE\n"));
601881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
602881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
603881Sjohnny return (DDI_FAILURE);
604881Sjohnny }
605881Sjohnny
606881Sjohnny /* Check if psm_intr_ops is NULL? */
607881Sjohnny if (psm_intr_ops == NULL)
608881Sjohnny return (DDI_FAILURE);
609881Sjohnny
6101542Sjohnny count = hdlp->ih_scratch1;
6111542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
6121542Sjohnny for (i = 0; i < count; i++) {
6131542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i];
614881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp,
6151542Sjohnny hdlp->ih_inum) != DDI_SUCCESS) {
616881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
617881Sjohnny "pci_enable_intr failed for %d\n", i));
6181542Sjohnny for (j = 0; j < i; j++) {
6194397Sschwartz hdlp = (ddi_intr_handle_impl_t *)
6204397Sschwartz h_array[j];
6214397Sschwartz pci_disable_intr(pdip, rdip, hdlp,
6221542Sjohnny hdlp->ih_inum);
6231542Sjohnny }
624881Sjohnny return (DDI_FAILURE);
625881Sjohnny }
626881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
6271542Sjohnny "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
628881Sjohnny }
629881Sjohnny break;
630881Sjohnny case DDI_INTROP_BLOCKDISABLE:
631881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
632881Sjohnny "BLOCKDISABLE\n"));
633881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
634881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
635881Sjohnny return (DDI_FAILURE);
636881Sjohnny }
637881Sjohnny
638881Sjohnny /* Check if psm_intr_ops is present */
639881Sjohnny if (psm_intr_ops == NULL)
640881Sjohnny return (DDI_FAILURE);
641881Sjohnny
6421542Sjohnny count = hdlp->ih_scratch1;
6431542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
6441542Sjohnny for (i = 0; i < count; i++) {
6451542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i];
6461542Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
647881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
6481542Sjohnny "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
649881Sjohnny }
650881Sjohnny break;
651881Sjohnny case DDI_INTROP_SETMASK:
652881Sjohnny case DDI_INTROP_CLRMASK:
653881Sjohnny /*
654881Sjohnny * First handle in the config space
655881Sjohnny */
656881Sjohnny if (intr_op == DDI_INTROP_SETMASK) {
657881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
658881Sjohnny pci_status = pci_msi_set_mask(rdip,
659881Sjohnny hdlp->ih_type, hdlp->ih_inum);
660881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
661881Sjohnny pci_status = pci_intx_set_mask(rdip);
662881Sjohnny } else {
663881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
664881Sjohnny pci_status = pci_msi_clr_mask(rdip,
665881Sjohnny hdlp->ih_type, hdlp->ih_inum);
666881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
667881Sjohnny pci_status = pci_intx_clr_mask(rdip);
668881Sjohnny }
669881Sjohnny
67012683SJimmy.Vetayases@oracle.com /* For MSI/X; no need to check with PSM module */
671881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
672881Sjohnny return (pci_status);
673881Sjohnny
674881Sjohnny /* For fixed interrupts only: handle config space first */
675881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
676881Sjohnny pci_status == DDI_SUCCESS)
677881Sjohnny break;
678881Sjohnny
67912683SJimmy.Vetayases@oracle.com /* For fixed interrupts only: confer with PSM module next */
680881Sjohnny if (psm_intr_ops != NULL) {
681881Sjohnny /* If interrupt is shared; do nothing */
682881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp,
683881Sjohnny PSM_INTR_OP_GET_SHARED, &psm_status);
684881Sjohnny
685881Sjohnny if (psm_rval == PSM_FAILURE || psm_status == 1)
686881Sjohnny return (pci_status);
687881Sjohnny
68812683SJimmy.Vetayases@oracle.com /* Now, PSM module should try to set/clear the mask */
689881Sjohnny if (intr_op == DDI_INTROP_SETMASK)
690881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp,
691881Sjohnny PSM_INTR_OP_SET_MASK, NULL);
692881Sjohnny else
693881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp,
694881Sjohnny PSM_INTR_OP_CLEAR_MASK, NULL);
695881Sjohnny }
696881Sjohnny return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
697881Sjohnny case DDI_INTROP_GETPENDING:
698881Sjohnny /*
699881Sjohnny * First check the config space and/or
700881Sjohnny * MSI capability register(s)
701881Sjohnny */
702881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
703881Sjohnny pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
704881Sjohnny hdlp->ih_inum, &pci_status);
705881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
706881Sjohnny pci_rval = pci_intx_get_pending(rdip, &pci_status);
707881Sjohnny
70812683SJimmy.Vetayases@oracle.com /* On failure; next try with PSM module */
709881Sjohnny if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
710881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp,
711881Sjohnny PSM_INTR_OP_GET_PENDING, &psm_status);
712881Sjohnny
713881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
714881Sjohnny "psm_rval = %x, psm_status = %x, pci_rval = %x, "
715881Sjohnny "pci_status = %x\n", psm_rval, psm_status, pci_rval,
716881Sjohnny pci_status));
717881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
718881Sjohnny *(int *)result = 0;
719881Sjohnny return (DDI_FAILURE);
720881Sjohnny }
721881Sjohnny
722881Sjohnny if (psm_rval != PSM_FAILURE)
723881Sjohnny *(int *)result = psm_status;
724881Sjohnny else if (pci_rval != DDI_FAILURE)
725881Sjohnny *(int *)result = pci_status;
726881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
727881Sjohnny *(int *)result));
728881Sjohnny break;
72910053SEvan.Yan@Sun.COM case DDI_INTROP_GETTARGET:
73010053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n"));
73110053SEvan.Yan@Sun.COM
73212683SJimmy.Vetayases@oracle.com bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
73312683SJimmy.Vetayases@oracle.com tmp_hdl.ih_private = (void *)&intrinfo;
73412683SJimmy.Vetayases@oracle.com intrinfo.avgi_req_flags = PSMGI_INTRBY_DEFAULT;
73512683SJimmy.Vetayases@oracle.com intrinfo.avgi_req_flags |= PSMGI_REQ_CPUID;
73612683SJimmy.Vetayases@oracle.com
73712683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_GET_INTR,
73812683SJimmy.Vetayases@oracle.com NULL) == PSM_FAILURE)
73910053SEvan.Yan@Sun.COM return (DDI_FAILURE);
74012683SJimmy.Vetayases@oracle.com
74112683SJimmy.Vetayases@oracle.com *(int *)result = intrinfo.avgi_cpu_id;
74210053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET "
74312683SJimmy.Vetayases@oracle.com "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector,
74412683SJimmy.Vetayases@oracle.com *(int *)result));
74510053SEvan.Yan@Sun.COM break;
74610053SEvan.Yan@Sun.COM case DDI_INTROP_SETTARGET:
74710053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n"));
74810053SEvan.Yan@Sun.COM
74912683SJimmy.Vetayases@oracle.com bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
75010053SEvan.Yan@Sun.COM tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result;
75112683SJimmy.Vetayases@oracle.com tmp_hdl.ih_flags = PSMGI_INTRBY_DEFAULT;
75212683SJimmy.Vetayases@oracle.com
75312683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU,
75412683SJimmy.Vetayases@oracle.com &psm_status) == PSM_FAILURE)
75512683SJimmy.Vetayases@oracle.com return (DDI_FAILURE);
75610053SEvan.Yan@Sun.COM
75712683SJimmy.Vetayases@oracle.com hdlp->ih_vector = tmp_hdl.ih_vector;
75812683SJimmy.Vetayases@oracle.com DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET "
75912683SJimmy.Vetayases@oracle.com "vector = 0x%x\n", hdlp->ih_vector));
76010053SEvan.Yan@Sun.COM break;
76112683SJimmy.Vetayases@oracle.com case DDI_INTROP_GETPOOL:
76212683SJimmy.Vetayases@oracle.com /*
76312683SJimmy.Vetayases@oracle.com * For MSI/X interrupts use global IRM pool if available.
76412683SJimmy.Vetayases@oracle.com */
76512683SJimmy.Vetayases@oracle.com if (apix_irm_pool_p && DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
76612683SJimmy.Vetayases@oracle.com *(ddi_irm_pool_t **)result = apix_irm_pool_p;
76712683SJimmy.Vetayases@oracle.com return (DDI_SUCCESS);
76812683SJimmy.Vetayases@oracle.com }
76912683SJimmy.Vetayases@oracle.com return (DDI_ENOTSUP);
770881Sjohnny default:
771881Sjohnny return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
772881Sjohnny }
773881Sjohnny
774881Sjohnny return (DDI_SUCCESS);
775881Sjohnny }
776881Sjohnny
77712683SJimmy.Vetayases@oracle.com /*
77812683SJimmy.Vetayases@oracle.com * Allocate a vector for FIXED type interrupt.
77912683SJimmy.Vetayases@oracle.com */
78012683SJimmy.Vetayases@oracle.com int
pci_alloc_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,void * result)78112683SJimmy.Vetayases@oracle.com pci_alloc_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
78212683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *hdlp, void *result)
78312683SJimmy.Vetayases@oracle.com {
78412683SJimmy.Vetayases@oracle.com struct intrspec *ispec;
78512683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t info_hdl;
78612683SJimmy.Vetayases@oracle.com int ret;
78712683SJimmy.Vetayases@oracle.com int free_phdl = 0;
78812683SJimmy.Vetayases@oracle.com int pci_rval;
78912683SJimmy.Vetayases@oracle.com int pci_status = 0;
79012683SJimmy.Vetayases@oracle.com apic_get_type_t type_info;
79112683SJimmy.Vetayases@oracle.com
79212683SJimmy.Vetayases@oracle.com if (psm_intr_ops == NULL)
79312683SJimmy.Vetayases@oracle.com return (DDI_FAILURE);
79412683SJimmy.Vetayases@oracle.com
79512683SJimmy.Vetayases@oracle.com /* Figure out if this device supports MASKING */
79612683SJimmy.Vetayases@oracle.com pci_rval = pci_intx_get_cap(rdip, &pci_status);
79712683SJimmy.Vetayases@oracle.com if (pci_rval == DDI_SUCCESS && pci_status)
79812683SJimmy.Vetayases@oracle.com hdlp->ih_cap |= pci_status;
79912683SJimmy.Vetayases@oracle.com
80012683SJimmy.Vetayases@oracle.com /*
80112683SJimmy.Vetayases@oracle.com * If the PSM module is "APIX" then pass the request for
80212683SJimmy.Vetayases@oracle.com * allocating the vector now.
80312683SJimmy.Vetayases@oracle.com */
80412683SJimmy.Vetayases@oracle.com bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
80512683SJimmy.Vetayases@oracle.com info_hdl.ih_private = &type_info;
80612683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
80712683SJimmy.Vetayases@oracle.com PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
80812683SJimmy.Vetayases@oracle.com ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
80912683SJimmy.Vetayases@oracle.com (int)hdlp->ih_inum);
81012683SJimmy.Vetayases@oracle.com if (ispec == NULL)
81112683SJimmy.Vetayases@oracle.com return (DDI_FAILURE);
81212683SJimmy.Vetayases@oracle.com if (hdlp->ih_private == NULL) { /* allocate phdl structure */
81312683SJimmy.Vetayases@oracle.com free_phdl = 1;
81412683SJimmy.Vetayases@oracle.com i_ddi_alloc_intr_phdl(hdlp);
81512683SJimmy.Vetayases@oracle.com }
81612683SJimmy.Vetayases@oracle.com ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
81712683SJimmy.Vetayases@oracle.com ret = (*psm_intr_ops)(rdip, hdlp,
81812683SJimmy.Vetayases@oracle.com PSM_INTR_OP_ALLOC_VECTORS, result);
81912683SJimmy.Vetayases@oracle.com if (free_phdl) { /* free up the phdl structure */
82012683SJimmy.Vetayases@oracle.com free_phdl = 0;
82112683SJimmy.Vetayases@oracle.com i_ddi_free_intr_phdl(hdlp);
82212683SJimmy.Vetayases@oracle.com hdlp->ih_private = NULL;
82312683SJimmy.Vetayases@oracle.com }
82412683SJimmy.Vetayases@oracle.com } else {
82512683SJimmy.Vetayases@oracle.com /*
82612683SJimmy.Vetayases@oracle.com * No APIX module; fall back to the old scheme where the
82712683SJimmy.Vetayases@oracle.com * interrupt vector is allocated during ddi_enable_intr() call.
82812683SJimmy.Vetayases@oracle.com */
82912683SJimmy.Vetayases@oracle.com *(int *)result = 1;
83012683SJimmy.Vetayases@oracle.com ret = DDI_SUCCESS;
83112683SJimmy.Vetayases@oracle.com }
83212683SJimmy.Vetayases@oracle.com
83312683SJimmy.Vetayases@oracle.com return (ret);
83412683SJimmy.Vetayases@oracle.com }
83512683SJimmy.Vetayases@oracle.com
83612683SJimmy.Vetayases@oracle.com /*
83712683SJimmy.Vetayases@oracle.com * Free up the vector for FIXED (legacy) type interrupt.
83812683SJimmy.Vetayases@oracle.com */
83912683SJimmy.Vetayases@oracle.com static int
pci_free_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)84012683SJimmy.Vetayases@oracle.com pci_free_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
84112683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *hdlp)
84212683SJimmy.Vetayases@oracle.com {
84312683SJimmy.Vetayases@oracle.com struct intrspec *ispec;
84412683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t info_hdl;
84512683SJimmy.Vetayases@oracle.com int ret;
84612683SJimmy.Vetayases@oracle.com apic_get_type_t type_info;
84712683SJimmy.Vetayases@oracle.com
84812683SJimmy.Vetayases@oracle.com if (psm_intr_ops == NULL)
84912683SJimmy.Vetayases@oracle.com return (DDI_FAILURE);
85012683SJimmy.Vetayases@oracle.com
85112683SJimmy.Vetayases@oracle.com /*
85212683SJimmy.Vetayases@oracle.com * If the PSM module is "APIX" then pass the request to it
85312683SJimmy.Vetayases@oracle.com * to free up the vector now.
85412683SJimmy.Vetayases@oracle.com */
85512683SJimmy.Vetayases@oracle.com bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
85612683SJimmy.Vetayases@oracle.com info_hdl.ih_private = &type_info;
85712683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
85812683SJimmy.Vetayases@oracle.com PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
85912683SJimmy.Vetayases@oracle.com ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
86012683SJimmy.Vetayases@oracle.com (int)hdlp->ih_inum);
86112683SJimmy.Vetayases@oracle.com if (ispec == NULL)
86212683SJimmy.Vetayases@oracle.com return (DDI_FAILURE);
86312683SJimmy.Vetayases@oracle.com ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
86412683SJimmy.Vetayases@oracle.com ret = (*psm_intr_ops)(rdip, hdlp,
86512683SJimmy.Vetayases@oracle.com PSM_INTR_OP_FREE_VECTORS, NULL);
86612683SJimmy.Vetayases@oracle.com } else {
86712683SJimmy.Vetayases@oracle.com /*
86812683SJimmy.Vetayases@oracle.com * No APIX module; fall back to the old scheme where
86912683SJimmy.Vetayases@oracle.com * the interrupt vector was already freed during
87012683SJimmy.Vetayases@oracle.com * ddi_disable_intr() call.
87112683SJimmy.Vetayases@oracle.com */
87212683SJimmy.Vetayases@oracle.com ret = DDI_SUCCESS;
87312683SJimmy.Vetayases@oracle.com }
87412683SJimmy.Vetayases@oracle.com
87512683SJimmy.Vetayases@oracle.com return (ret);
87612683SJimmy.Vetayases@oracle.com }
87712683SJimmy.Vetayases@oracle.com
878916Sschwartz int
pci_get_intr_from_vecirq(apic_get_intr_t * intrinfo_p,int vecirq,boolean_t is_irq)879916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
880916Sschwartz int vecirq, boolean_t is_irq)
881916Sschwartz {
882916Sschwartz ddi_intr_handle_impl_t get_info_ii_hdl;
883916Sschwartz
884916Sschwartz if (is_irq)
885916Sschwartz intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
886916Sschwartz
887916Sschwartz /*
888916Sschwartz * For this locally-declared and used handle, ih_private will contain a
889916Sschwartz * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
890916Sschwartz * global interrupt handling.
891916Sschwartz */
892916Sschwartz get_info_ii_hdl.ih_private = intrinfo_p;
89312683SJimmy.Vetayases@oracle.com get_info_ii_hdl.ih_vector = vecirq;
894916Sschwartz
895916Sschwartz if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
896916Sschwartz PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
897916Sschwartz return (DDI_FAILURE);
898916Sschwartz
899916Sschwartz return (DDI_SUCCESS);
900916Sschwartz }
901916Sschwartz
902916Sschwartz
903916Sschwartz int
pci_get_cpu_from_vecirq(int vecirq,boolean_t is_irq)904916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
905916Sschwartz {
906916Sschwartz int rval;
90712683SJimmy.Vetayases@oracle.com apic_get_intr_t intrinfo;
908916Sschwartz
909916Sschwartz intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
910916Sschwartz rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
911916Sschwartz
912916Sschwartz if (rval == DDI_SUCCESS)
913916Sschwartz return (intrinfo.avgi_cpu_id);
914916Sschwartz else
915916Sschwartz return (-1);
916916Sschwartz }
917916Sschwartz
918881Sjohnny
919881Sjohnny static int
pci_enable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)920881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
921881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum)
922881Sjohnny {
923881Sjohnny struct intrspec *ispec;
924916Sschwartz int irq;
925916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
926881Sjohnny
927881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
928881Sjohnny (void *)hdlp, inum));
929881Sjohnny
930881Sjohnny /* Translate the interrupt if needed */
931881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
9322288Sanish if (ispec == NULL)
9332288Sanish return (DDI_FAILURE);
93410190SSophia.Li@Sun.COM if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
935881Sjohnny ispec->intrspec_vec = inum;
93610190SSophia.Li@Sun.COM ispec->intrspec_pri = hdlp->ih_pri;
93710190SSophia.Li@Sun.COM }
938916Sschwartz ihdl_plat_datap->ip_ispecp = ispec;
939881Sjohnny
940881Sjohnny /* translate the interrupt if needed */
94111465SKerry.Shu@Sun.COM if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) ==
94211465SKerry.Shu@Sun.COM PSM_FAILURE)
94311465SKerry.Shu@Sun.COM return (DDI_FAILURE);
944916Sschwartz DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
945916Sschwartz hdlp->ih_pri, irq));
946881Sjohnny
947881Sjohnny /* Add the interrupt handler */
948881Sjohnny if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
949916Sschwartz DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
950916Sschwartz hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
951881Sjohnny return (DDI_FAILURE);
952881Sjohnny
95312683SJimmy.Vetayases@oracle.com hdlp->ih_vector = irq;
954916Sschwartz
955881Sjohnny return (DDI_SUCCESS);
956881Sjohnny }
957881Sjohnny
958881Sjohnny
959881Sjohnny static void
pci_disable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)960881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
961881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum)
962881Sjohnny {
963916Sschwartz int irq;
964881Sjohnny struct intrspec *ispec;
965916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
966881Sjohnny
967881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
968881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
9692288Sanish if (ispec == NULL)
9702288Sanish return;
97110190SSophia.Li@Sun.COM if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
972881Sjohnny ispec->intrspec_vec = inum;
97310190SSophia.Li@Sun.COM ispec->intrspec_pri = hdlp->ih_pri;
97410190SSophia.Li@Sun.COM }
975916Sschwartz ihdl_plat_datap->ip_ispecp = ispec;
976881Sjohnny
977881Sjohnny /* translate the interrupt if needed */
978916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
979881Sjohnny
980881Sjohnny /* Disable the interrupt handler */
981916Sschwartz rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
982916Sschwartz ihdl_plat_datap->ip_ispecp = NULL;
983881Sjohnny }
984881Sjohnny
985881Sjohnny /*
986881Sjohnny * Miscellaneous library function
987881Sjohnny */
988881Sjohnny int
pci_common_get_reg_prop(dev_info_t * dip,pci_regspec_t * pci_rp)989881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
990881Sjohnny {
991881Sjohnny int i;
992881Sjohnny int number;
993881Sjohnny int assigned_addr_len;
994881Sjohnny uint_t phys_hi = pci_rp->pci_phys_hi;
995881Sjohnny pci_regspec_t *assigned_addr;
996881Sjohnny
997881Sjohnny if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
998881Sjohnny (phys_hi & PCI_RELOCAT_B))
999881Sjohnny return (DDI_SUCCESS);
1000881Sjohnny
1001881Sjohnny /*
1002881Sjohnny * the "reg" property specifies relocatable, get and interpret the
1003881Sjohnny * "assigned-addresses" property.
1004881Sjohnny */
1005881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1006881Sjohnny "assigned-addresses", (int **)&assigned_addr,
1007881Sjohnny (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
1008881Sjohnny return (DDI_FAILURE);
1009881Sjohnny
1010881Sjohnny /*
1011881Sjohnny * Scan the "assigned-addresses" for one that matches the specified
1012881Sjohnny * "reg" property entry.
1013881Sjohnny */
1014881Sjohnny phys_hi &= PCI_CONF_ADDR_MASK;
1015881Sjohnny number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
1016881Sjohnny for (i = 0; i < number; i++) {
1017881Sjohnny if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
1018881Sjohnny phys_hi) {
1019881Sjohnny pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
1020881Sjohnny pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
1021881Sjohnny ddi_prop_free(assigned_addr);
1022881Sjohnny return (DDI_SUCCESS);
1023881Sjohnny }
1024881Sjohnny }
1025881Sjohnny
1026881Sjohnny ddi_prop_free(assigned_addr);
1027881Sjohnny return (DDI_FAILURE);
1028881Sjohnny }
1029881Sjohnny
1030881Sjohnny
1031881Sjohnny /*
103210923SEvan.Yan@Sun.COM * To handle PCI tool ioctls
1033881Sjohnny */
1034881Sjohnny
103510923SEvan.Yan@Sun.COM /*ARGSUSED*/
1036881Sjohnny int
pci_common_ioctl(dev_info_t * dip,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1037881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
1038881Sjohnny int mode, cred_t *credp, int *rvalp)
1039881Sjohnny {
104010923SEvan.Yan@Sun.COM minor_t minor = getminor(dev);
104110923SEvan.Yan@Sun.COM int rv = ENOTTY;
1042881Sjohnny
104310923SEvan.Yan@Sun.COM switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
1044881Sjohnny case PCI_TOOL_REG_MINOR_NUM:
1045881Sjohnny
1046881Sjohnny switch (cmd) {
1047881Sjohnny case PCITOOL_DEVICE_SET_REG:
1048881Sjohnny case PCITOOL_DEVICE_GET_REG:
1049881Sjohnny
1050881Sjohnny /* Require full privileges. */
1051881Sjohnny if (secpolicy_kmdb(credp))
1052881Sjohnny rv = EPERM;
1053881Sjohnny else
1054881Sjohnny rv = pcitool_dev_reg_ops(dip, (void *)arg,
1055881Sjohnny cmd, mode);
1056881Sjohnny break;
1057881Sjohnny
1058881Sjohnny case PCITOOL_NEXUS_SET_REG:
1059881Sjohnny case PCITOOL_NEXUS_GET_REG:
1060881Sjohnny
1061881Sjohnny /* Require full privileges. */
1062881Sjohnny if (secpolicy_kmdb(credp))
1063881Sjohnny rv = EPERM;
1064881Sjohnny else
1065881Sjohnny rv = pcitool_bus_reg_ops(dip, (void *)arg,
1066881Sjohnny cmd, mode);
1067881Sjohnny break;
1068881Sjohnny }
1069881Sjohnny break;
1070881Sjohnny
1071881Sjohnny case PCI_TOOL_INTR_MINOR_NUM:
1072881Sjohnny
1073881Sjohnny switch (cmd) {
1074881Sjohnny case PCITOOL_DEVICE_SET_INTR:
1075881Sjohnny
1076881Sjohnny /* Require PRIV_SYS_RES_CONFIG, same as psradm */
1077881Sjohnny if (secpolicy_ponline(credp)) {
1078881Sjohnny rv = EPERM;
1079881Sjohnny break;
1080881Sjohnny }
1081881Sjohnny
1082881Sjohnny /*FALLTHRU*/
1083881Sjohnny /* These require no special privileges. */
1084881Sjohnny case PCITOOL_DEVICE_GET_INTR:
10854397Sschwartz case PCITOOL_SYSTEM_INTR_INFO:
1086881Sjohnny rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
1087881Sjohnny break;
1088881Sjohnny }
1089881Sjohnny break;
1090881Sjohnny
1091881Sjohnny default:
1092881Sjohnny break;
1093881Sjohnny }
1094881Sjohnny
1095881Sjohnny return (rv);
1096881Sjohnny }
10971083Sanish
10981083Sanish
10991865Sdilpreet int
pci_common_ctlops_poke(peekpoke_ctlops_t * in_args)11001865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
11011865Sdilpreet {
11021865Sdilpreet size_t size = in_args->size;
11031865Sdilpreet uintptr_t dev_addr = in_args->dev_addr;
11041865Sdilpreet uintptr_t host_addr = in_args->host_addr;
11051865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
11061865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
11071865Sdilpreet size_t repcount = in_args->repcount;
11081865Sdilpreet uint_t flags = in_args->flags;
11091865Sdilpreet int err = DDI_SUCCESS;
11101865Sdilpreet
11111865Sdilpreet /*
11121865Sdilpreet * if no handle then this is a poke. We have to return failure here
11131865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access
11141865Sdilpreet */
11151865Sdilpreet if (in_args->handle == NULL)
11161865Sdilpreet return (DDI_FAILURE);
11171865Sdilpreet
11181865Sdilpreet /*
11191865Sdilpreet * rest of this function is actually for cautious puts
11201865Sdilpreet */
11211865Sdilpreet for (; repcount; repcount--) {
11221865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
11231865Sdilpreet switch (size) {
11241865Sdilpreet case sizeof (uint8_t):
11251865Sdilpreet pci_config_wr8(hp, (uint8_t *)dev_addr,
11261865Sdilpreet *(uint8_t *)host_addr);
11271865Sdilpreet break;
11281865Sdilpreet case sizeof (uint16_t):
11291865Sdilpreet pci_config_wr16(hp, (uint16_t *)dev_addr,
11301865Sdilpreet *(uint16_t *)host_addr);
11311865Sdilpreet break;
11321865Sdilpreet case sizeof (uint32_t):
11331865Sdilpreet pci_config_wr32(hp, (uint32_t *)dev_addr,
11341865Sdilpreet *(uint32_t *)host_addr);
11351865Sdilpreet break;
11361865Sdilpreet case sizeof (uint64_t):
11371865Sdilpreet pci_config_wr64(hp, (uint64_t *)dev_addr,
11381865Sdilpreet *(uint64_t *)host_addr);
11391865Sdilpreet break;
11401865Sdilpreet default:
11411865Sdilpreet err = DDI_FAILURE;
11421865Sdilpreet break;
11431865Sdilpreet }
11441865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
11451865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags ==
11461865Sdilpreet DDI_STRUCTURE_BE_ACC) {
11471865Sdilpreet switch (size) {
11481865Sdilpreet case sizeof (uint8_t):
11491865Sdilpreet i_ddi_io_put8(hp,
11501865Sdilpreet (uint8_t *)dev_addr,
11511865Sdilpreet *(uint8_t *)host_addr);
11521865Sdilpreet break;
11531865Sdilpreet case sizeof (uint16_t):
11541865Sdilpreet i_ddi_io_swap_put16(hp,
11551865Sdilpreet (uint16_t *)dev_addr,
11561865Sdilpreet *(uint16_t *)host_addr);
11571865Sdilpreet break;
11581865Sdilpreet case sizeof (uint32_t):
11591865Sdilpreet i_ddi_io_swap_put32(hp,
11601865Sdilpreet (uint32_t *)dev_addr,
11611865Sdilpreet *(uint32_t *)host_addr);
11621865Sdilpreet break;
11631865Sdilpreet /*
11641865Sdilpreet * note the 64-bit case is a dummy
11651865Sdilpreet * function - so no need to swap
11661865Sdilpreet */
11671865Sdilpreet case sizeof (uint64_t):
11681865Sdilpreet i_ddi_io_put64(hp,
11691865Sdilpreet (uint64_t *)dev_addr,
11701865Sdilpreet *(uint64_t *)host_addr);
11711865Sdilpreet break;
11721865Sdilpreet default:
11731865Sdilpreet err = DDI_FAILURE;
11741865Sdilpreet break;
11751865Sdilpreet }
11761865Sdilpreet } else {
11771865Sdilpreet switch (size) {
11781865Sdilpreet case sizeof (uint8_t):
11791865Sdilpreet i_ddi_io_put8(hp,
11801865Sdilpreet (uint8_t *)dev_addr,
11811865Sdilpreet *(uint8_t *)host_addr);
11821865Sdilpreet break;
11831865Sdilpreet case sizeof (uint16_t):
11841865Sdilpreet i_ddi_io_put16(hp,
11851865Sdilpreet (uint16_t *)dev_addr,
11861865Sdilpreet *(uint16_t *)host_addr);
11871865Sdilpreet break;
11881865Sdilpreet case sizeof (uint32_t):
11891865Sdilpreet i_ddi_io_put32(hp,
11901865Sdilpreet (uint32_t *)dev_addr,
11911865Sdilpreet *(uint32_t *)host_addr);
11921865Sdilpreet break;
11931865Sdilpreet case sizeof (uint64_t):
11941865Sdilpreet i_ddi_io_put64(hp,
11951865Sdilpreet (uint64_t *)dev_addr,
11961865Sdilpreet *(uint64_t *)host_addr);
11971865Sdilpreet break;
11981865Sdilpreet default:
11991865Sdilpreet err = DDI_FAILURE;
12001865Sdilpreet break;
12011865Sdilpreet }
12021865Sdilpreet }
12031865Sdilpreet } else {
12041865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags ==
12051865Sdilpreet DDI_STRUCTURE_BE_ACC) {
12061865Sdilpreet switch (size) {
12071865Sdilpreet case sizeof (uint8_t):
12081865Sdilpreet *(uint8_t *)dev_addr =
12091865Sdilpreet *(uint8_t *)host_addr;
12101865Sdilpreet break;
12111865Sdilpreet case sizeof (uint16_t):
12121865Sdilpreet *(uint16_t *)dev_addr =
12131865Sdilpreet ddi_swap16(*(uint16_t *)host_addr);
12141865Sdilpreet break;
12151865Sdilpreet case sizeof (uint32_t):
12161865Sdilpreet *(uint32_t *)dev_addr =
12171865Sdilpreet ddi_swap32(*(uint32_t *)host_addr);
12181865Sdilpreet break;
12191865Sdilpreet case sizeof (uint64_t):
12201865Sdilpreet *(uint64_t *)dev_addr =
12211865Sdilpreet ddi_swap64(*(uint64_t *)host_addr);
12221865Sdilpreet break;
12231865Sdilpreet default:
12241865Sdilpreet err = DDI_FAILURE;
12251865Sdilpreet break;
12261865Sdilpreet }
12271865Sdilpreet } else {
12281865Sdilpreet switch (size) {
12291865Sdilpreet case sizeof (uint8_t):
12301865Sdilpreet *(uint8_t *)dev_addr =
12311865Sdilpreet *(uint8_t *)host_addr;
12321865Sdilpreet break;
12331865Sdilpreet case sizeof (uint16_t):
12341865Sdilpreet *(uint16_t *)dev_addr =
12351865Sdilpreet *(uint16_t *)host_addr;
12361865Sdilpreet break;
12371865Sdilpreet case sizeof (uint32_t):
12381865Sdilpreet *(uint32_t *)dev_addr =
12391865Sdilpreet *(uint32_t *)host_addr;
12401865Sdilpreet break;
12411865Sdilpreet case sizeof (uint64_t):
12421865Sdilpreet *(uint64_t *)dev_addr =
12431865Sdilpreet *(uint64_t *)host_addr;
12441865Sdilpreet break;
12451865Sdilpreet default:
12461865Sdilpreet err = DDI_FAILURE;
12471865Sdilpreet break;
12481865Sdilpreet }
12491865Sdilpreet }
12501865Sdilpreet }
12511865Sdilpreet host_addr += size;
12521865Sdilpreet if (flags == DDI_DEV_AUTOINCR)
12531865Sdilpreet dev_addr += size;
12541865Sdilpreet }
12551865Sdilpreet return (err);
12561865Sdilpreet }
12571865Sdilpreet
12581865Sdilpreet
12591865Sdilpreet int
pci_fm_acc_setup(ddi_acc_hdl_t * hp,off_t offset,off_t len)12601865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
12611865Sdilpreet {
12621865Sdilpreet ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private;
12631865Sdilpreet
12641865Sdilpreet /* endian-ness check */
12651865Sdilpreet if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
12661865Sdilpreet return (DDI_FAILURE);
12671865Sdilpreet
12681865Sdilpreet /*
12691865Sdilpreet * range check
12701865Sdilpreet */
12711865Sdilpreet if ((offset >= PCI_CONF_HDR_SIZE) ||
12721865Sdilpreet (len > PCI_CONF_HDR_SIZE) ||
12731865Sdilpreet (offset + len > PCI_CONF_HDR_SIZE))
12741865Sdilpreet return (DDI_FAILURE);
12751865Sdilpreet
12761865Sdilpreet ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
12771865Sdilpreet /*
12781865Sdilpreet * always use cautious mechanism for config space gets
12791865Sdilpreet */
12801865Sdilpreet ap->ahi_get8 = i_ddi_caut_get8;
12811865Sdilpreet ap->ahi_get16 = i_ddi_caut_get16;
12821865Sdilpreet ap->ahi_get32 = i_ddi_caut_get32;
12831865Sdilpreet ap->ahi_get64 = i_ddi_caut_get64;
12841865Sdilpreet ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
12851865Sdilpreet ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
12861865Sdilpreet ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
12871865Sdilpreet ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
12881865Sdilpreet if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
12891865Sdilpreet ap->ahi_put8 = i_ddi_caut_put8;
12901865Sdilpreet ap->ahi_put16 = i_ddi_caut_put16;
12911865Sdilpreet ap->ahi_put32 = i_ddi_caut_put32;
12921865Sdilpreet ap->ahi_put64 = i_ddi_caut_put64;
12931865Sdilpreet ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
12941865Sdilpreet ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
12951865Sdilpreet ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
12961865Sdilpreet ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
12971865Sdilpreet } else {
12981865Sdilpreet ap->ahi_put8 = pci_config_wr8;
12991865Sdilpreet ap->ahi_put16 = pci_config_wr16;
13001865Sdilpreet ap->ahi_put32 = pci_config_wr32;
13011865Sdilpreet ap->ahi_put64 = pci_config_wr64;
13021865Sdilpreet ap->ahi_rep_put8 = pci_config_rep_wr8;
13031865Sdilpreet ap->ahi_rep_put16 = pci_config_rep_wr16;
13041865Sdilpreet ap->ahi_rep_put32 = pci_config_rep_wr32;
13051865Sdilpreet ap->ahi_rep_put64 = pci_config_rep_wr64;
13061865Sdilpreet }
13071865Sdilpreet
13081865Sdilpreet /* Initialize to default check/notify functions */
13091865Sdilpreet ap->ahi_fault_check = i_ddi_acc_fault_check;
13101865Sdilpreet ap->ahi_fault_notify = i_ddi_acc_fault_notify;
13111865Sdilpreet ap->ahi_fault = 0;
13121865Sdilpreet impl_acc_err_init(hp);
13131865Sdilpreet return (DDI_SUCCESS);
13141865Sdilpreet }
13151865Sdilpreet
13161865Sdilpreet
13171865Sdilpreet int
pci_common_ctlops_peek(peekpoke_ctlops_t * in_args)13181865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
13191865Sdilpreet {
13201865Sdilpreet size_t size = in_args->size;
13211865Sdilpreet uintptr_t dev_addr = in_args->dev_addr;
13221865Sdilpreet uintptr_t host_addr = in_args->host_addr;
13231865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
13241865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
13251865Sdilpreet size_t repcount = in_args->repcount;
13261865Sdilpreet uint_t flags = in_args->flags;
13271865Sdilpreet int err = DDI_SUCCESS;
13281865Sdilpreet
13291865Sdilpreet /*
13301865Sdilpreet * if no handle then this is a peek. We have to return failure here
13311865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access
13321865Sdilpreet */
13331865Sdilpreet if (in_args->handle == NULL)
13341865Sdilpreet return (DDI_FAILURE);
13351865Sdilpreet
13361865Sdilpreet for (; repcount; repcount--) {
13371865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
13381865Sdilpreet switch (size) {
13391865Sdilpreet case sizeof (uint8_t):
13401865Sdilpreet *(uint8_t *)host_addr = pci_config_rd8(hp,
13411865Sdilpreet (uint8_t *)dev_addr);
13421865Sdilpreet break;
13431865Sdilpreet case sizeof (uint16_t):
13441865Sdilpreet *(uint16_t *)host_addr = pci_config_rd16(hp,
13451865Sdilpreet (uint16_t *)dev_addr);
13461865Sdilpreet break;
13471865Sdilpreet case sizeof (uint32_t):
13481865Sdilpreet *(uint32_t *)host_addr = pci_config_rd32(hp,
13491865Sdilpreet (uint32_t *)dev_addr);
13501865Sdilpreet break;
13511865Sdilpreet case sizeof (uint64_t):
13521865Sdilpreet *(uint64_t *)host_addr = pci_config_rd64(hp,
13531865Sdilpreet (uint64_t *)dev_addr);
13541865Sdilpreet break;
13551865Sdilpreet default:
13561865Sdilpreet err = DDI_FAILURE;
13571865Sdilpreet break;
13581865Sdilpreet }
13591865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
13601865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags ==
13611865Sdilpreet DDI_STRUCTURE_BE_ACC) {
13621865Sdilpreet switch (size) {
13631865Sdilpreet case sizeof (uint8_t):
13641865Sdilpreet *(uint8_t *)host_addr =
13651865Sdilpreet i_ddi_io_get8(hp,
13661865Sdilpreet (uint8_t *)dev_addr);
13671865Sdilpreet break;
13681865Sdilpreet case sizeof (uint16_t):
13691865Sdilpreet *(uint16_t *)host_addr =
13701865Sdilpreet i_ddi_io_swap_get16(hp,
13711865Sdilpreet (uint16_t *)dev_addr);
13721865Sdilpreet break;
13731865Sdilpreet case sizeof (uint32_t):
13741865Sdilpreet *(uint32_t *)host_addr =
13751865Sdilpreet i_ddi_io_swap_get32(hp,
13761865Sdilpreet (uint32_t *)dev_addr);
13771865Sdilpreet break;
13781865Sdilpreet /*
13791865Sdilpreet * note the 64-bit case is a dummy
13801865Sdilpreet * function - so no need to swap
13811865Sdilpreet */
13821865Sdilpreet case sizeof (uint64_t):
13831865Sdilpreet *(uint64_t *)host_addr =
13841865Sdilpreet i_ddi_io_get64(hp,
13851865Sdilpreet (uint64_t *)dev_addr);
13861865Sdilpreet break;
13871865Sdilpreet default:
13881865Sdilpreet err = DDI_FAILURE;
13891865Sdilpreet break;
13901865Sdilpreet }
13911865Sdilpreet } else {
13921865Sdilpreet switch (size) {
13931865Sdilpreet case sizeof (uint8_t):
13941865Sdilpreet *(uint8_t *)host_addr =
13951865Sdilpreet i_ddi_io_get8(hp,
13961865Sdilpreet (uint8_t *)dev_addr);
13971865Sdilpreet break;
13981865Sdilpreet case sizeof (uint16_t):
13991865Sdilpreet *(uint16_t *)host_addr =
14001865Sdilpreet i_ddi_io_get16(hp,
14011865Sdilpreet (uint16_t *)dev_addr);
14021865Sdilpreet break;
14031865Sdilpreet case sizeof (uint32_t):
14041865Sdilpreet *(uint32_t *)host_addr =
14051865Sdilpreet i_ddi_io_get32(hp,
14061865Sdilpreet (uint32_t *)dev_addr);
14071865Sdilpreet break;
14081865Sdilpreet case sizeof (uint64_t):
14091865Sdilpreet *(uint64_t *)host_addr =
14101865Sdilpreet i_ddi_io_get64(hp,
14111865Sdilpreet (uint64_t *)dev_addr);
14121865Sdilpreet break;
14131865Sdilpreet default:
14141865Sdilpreet err = DDI_FAILURE;
14151865Sdilpreet break;
14161865Sdilpreet }
14171865Sdilpreet }
14181865Sdilpreet } else {
14191865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags ==
14201865Sdilpreet DDI_STRUCTURE_BE_ACC) {
14211865Sdilpreet switch (in_args->size) {
14221865Sdilpreet case sizeof (uint8_t):
14231865Sdilpreet *(uint8_t *)host_addr =
14241865Sdilpreet *(uint8_t *)dev_addr;
14251865Sdilpreet break;
14261865Sdilpreet case sizeof (uint16_t):
14271865Sdilpreet *(uint16_t *)host_addr =
14281865Sdilpreet ddi_swap16(*(uint16_t *)dev_addr);
14291865Sdilpreet break;
14301865Sdilpreet case sizeof (uint32_t):
14311865Sdilpreet *(uint32_t *)host_addr =
14321865Sdilpreet ddi_swap32(*(uint32_t *)dev_addr);
14331865Sdilpreet break;
14341865Sdilpreet case sizeof (uint64_t):
14351865Sdilpreet *(uint64_t *)host_addr =
14361865Sdilpreet ddi_swap64(*(uint64_t *)dev_addr);
14371865Sdilpreet break;
14381865Sdilpreet default:
14391865Sdilpreet err = DDI_FAILURE;
14401865Sdilpreet break;
14411865Sdilpreet }
14421865Sdilpreet } else {
14431865Sdilpreet switch (in_args->size) {
14441865Sdilpreet case sizeof (uint8_t):
14451865Sdilpreet *(uint8_t *)host_addr =
14461865Sdilpreet *(uint8_t *)dev_addr;
14471865Sdilpreet break;
14481865Sdilpreet case sizeof (uint16_t):
14491865Sdilpreet *(uint16_t *)host_addr =
14501865Sdilpreet *(uint16_t *)dev_addr;
14511865Sdilpreet break;
14521865Sdilpreet case sizeof (uint32_t):
14531865Sdilpreet *(uint32_t *)host_addr =
14541865Sdilpreet *(uint32_t *)dev_addr;
14551865Sdilpreet break;
14561865Sdilpreet case sizeof (uint64_t):
14571865Sdilpreet *(uint64_t *)host_addr =
14581865Sdilpreet *(uint64_t *)dev_addr;
14591865Sdilpreet break;
14601865Sdilpreet default:
14611865Sdilpreet err = DDI_FAILURE;
14621865Sdilpreet break;
14631865Sdilpreet }
14641865Sdilpreet }
14651865Sdilpreet }
14661865Sdilpreet host_addr += size;
14671865Sdilpreet if (flags == DDI_DEV_AUTOINCR)
14681865Sdilpreet dev_addr += size;
14691865Sdilpreet }
14701865Sdilpreet return (err);
14711865Sdilpreet }
14721865Sdilpreet
14731865Sdilpreet /*ARGSUSED*/
14741865Sdilpreet int
pci_common_peekpoke(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)14751865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
14761865Sdilpreet ddi_ctl_enum_t ctlop, void *arg, void *result)
14771865Sdilpreet {
14781865Sdilpreet if (ctlop == DDI_CTLOPS_PEEK)
14791865Sdilpreet return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
14801865Sdilpreet else
14811865Sdilpreet return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
14821865Sdilpreet }
14831865Sdilpreet
14841083Sanish /*
14851083Sanish * These are the get and put functions to be shared with drivers. The
14861083Sanish * mutex locking is done inside the functions referenced, rather than
14871083Sanish * here, and is thus shared across PCI child drivers and any other
14881083Sanish * consumers of PCI config space (such as the ACPI subsystem).
14891083Sanish *
14901083Sanish * The configuration space addresses come in as pointers. This is fine on
14911083Sanish * a 32-bit system, where the VM space and configuration space are the same
14921083Sanish * size. It's not such a good idea on a 64-bit system, where memory
14931083Sanish * addresses are twice as large as configuration space addresses. At some
14941083Sanish * point in the call tree we need to take a stand and say "you are 32-bit
14951083Sanish * from this time forth", and this seems like a nice self-contained place.
14961083Sanish */
14971083Sanish
14981083Sanish uint8_t
pci_config_rd8(ddi_acc_impl_t * hdlp,uint8_t * addr)14991083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
15001083Sanish {
15011083Sanish pci_acc_cfblk_t *cfp;
15021083Sanish uint8_t rval;
15031083Sanish int reg;
15041083Sanish
15051083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0);
15061083Sanish
15071083Sanish reg = (int)(uintptr_t)addr;
15081083Sanish
15091083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
15101083Sanish
15111083Sanish rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
15121083Sanish reg);
15131083Sanish
15141083Sanish return (rval);
15151083Sanish }
15161083Sanish
15171083Sanish void
pci_config_rep_rd8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)15181083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
15191083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags)
15201083Sanish {
15211083Sanish uint8_t *h, *d;
15221083Sanish
15231083Sanish h = host_addr;
15241083Sanish d = dev_addr;
15251083Sanish
15261083Sanish if (flags == DDI_DEV_AUTOINCR)
15271083Sanish for (; repcount; repcount--)
15281083Sanish *h++ = pci_config_rd8(hdlp, d++);
15291083Sanish else
15301083Sanish for (; repcount; repcount--)
15311083Sanish *h++ = pci_config_rd8(hdlp, d);
15321083Sanish }
15331083Sanish
15341083Sanish uint16_t
pci_config_rd16(ddi_acc_impl_t * hdlp,uint16_t * addr)15351083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
15361083Sanish {
15371083Sanish pci_acc_cfblk_t *cfp;
15381083Sanish uint16_t rval;
15391083Sanish int reg;
15401083Sanish
15411083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0);
15421083Sanish
15431083Sanish reg = (int)(uintptr_t)addr;
15441083Sanish
15451083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
15461083Sanish
15471083Sanish rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
15481083Sanish reg);
15491083Sanish
15501083Sanish return (rval);
15511083Sanish }
15521083Sanish
15531083Sanish void
pci_config_rep_rd16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)15541083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
15551083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags)
15561083Sanish {
15571083Sanish uint16_t *h, *d;
15581083Sanish
15591083Sanish h = host_addr;
15601083Sanish d = dev_addr;
15611083Sanish
15621083Sanish if (flags == DDI_DEV_AUTOINCR)
15631083Sanish for (; repcount; repcount--)
15641083Sanish *h++ = pci_config_rd16(hdlp, d++);
15651083Sanish else
15661083Sanish for (; repcount; repcount--)
15671083Sanish *h++ = pci_config_rd16(hdlp, d);
15681083Sanish }
15691083Sanish
15701083Sanish uint32_t
pci_config_rd32(ddi_acc_impl_t * hdlp,uint32_t * addr)15711083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
15721083Sanish {
15731083Sanish pci_acc_cfblk_t *cfp;
15741083Sanish uint32_t rval;
15751083Sanish int reg;
15761083Sanish
15771083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0);
15781083Sanish
15791083Sanish reg = (int)(uintptr_t)addr;
15801083Sanish
15811083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
15821083Sanish
15831083Sanish rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
15841083Sanish cfp->c_funcnum, reg);
15851083Sanish
15861083Sanish return (rval);
15871083Sanish }
15881083Sanish
15891083Sanish void
pci_config_rep_rd32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)15901083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
15911083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags)
15921083Sanish {
15931083Sanish uint32_t *h, *d;
15941083Sanish
15951083Sanish h = host_addr;
15961083Sanish d = dev_addr;
15971083Sanish
15981083Sanish if (flags == DDI_DEV_AUTOINCR)
15991083Sanish for (; repcount; repcount--)
16001083Sanish *h++ = pci_config_rd32(hdlp, d++);
16011083Sanish else
16021083Sanish for (; repcount; repcount--)
16031083Sanish *h++ = pci_config_rd32(hdlp, d);
16041083Sanish }
16051083Sanish
16061083Sanish
16071083Sanish void
pci_config_wr8(ddi_acc_impl_t * hdlp,uint8_t * addr,uint8_t value)16081083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
16091083Sanish {
16101083Sanish pci_acc_cfblk_t *cfp;
16111083Sanish int reg;
16121083Sanish
16131083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0);
16141083Sanish
16151083Sanish reg = (int)(uintptr_t)addr;
16161083Sanish
16171083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
16181083Sanish
16191083Sanish (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
16201083Sanish cfp->c_funcnum, reg, value);
16211083Sanish }
16221083Sanish
16231083Sanish void
pci_config_rep_wr8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)16241083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
16251083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags)
16261083Sanish {
16271083Sanish uint8_t *h, *d;
16281083Sanish
16291083Sanish h = host_addr;
16301083Sanish d = dev_addr;
16311083Sanish
16321083Sanish if (flags == DDI_DEV_AUTOINCR)
16331083Sanish for (; repcount; repcount--)
16341083Sanish pci_config_wr8(hdlp, d++, *h++);
16351083Sanish else
16361083Sanish for (; repcount; repcount--)
16371083Sanish pci_config_wr8(hdlp, d, *h++);
16381083Sanish }
16391083Sanish
16401083Sanish void
pci_config_wr16(ddi_acc_impl_t * hdlp,uint16_t * addr,uint16_t value)16411083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
16421083Sanish {
16431083Sanish pci_acc_cfblk_t *cfp;
16441083Sanish int reg;
16451083Sanish
16461083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0);
16471083Sanish
16481083Sanish reg = (int)(uintptr_t)addr;
16491083Sanish
16501083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
16511083Sanish
16521083Sanish (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
16531083Sanish cfp->c_funcnum, reg, value);
16541083Sanish }
16551083Sanish
16561083Sanish void
pci_config_rep_wr16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)16571083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
16581083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags)
16591083Sanish {
16601083Sanish uint16_t *h, *d;
16611083Sanish
16621083Sanish h = host_addr;
16631083Sanish d = dev_addr;
16641083Sanish
16651083Sanish if (flags == DDI_DEV_AUTOINCR)
16661083Sanish for (; repcount; repcount--)
16671083Sanish pci_config_wr16(hdlp, d++, *h++);
16681083Sanish else
16691083Sanish for (; repcount; repcount--)
16701083Sanish pci_config_wr16(hdlp, d, *h++);
16711083Sanish }
16721083Sanish
16731083Sanish void
pci_config_wr32(ddi_acc_impl_t * hdlp,uint32_t * addr,uint32_t value)16741083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
16751083Sanish {
16761083Sanish pci_acc_cfblk_t *cfp;
16771083Sanish int reg;
16781083Sanish
16791083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0);
16801083Sanish
16811083Sanish reg = (int)(uintptr_t)addr;
16821083Sanish
16831083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
16841083Sanish
16851083Sanish (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
16861083Sanish cfp->c_funcnum, reg, value);
16871083Sanish }
16881083Sanish
16891083Sanish void
pci_config_rep_wr32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)16901083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
16911083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags)
16921083Sanish {
16931083Sanish uint32_t *h, *d;
16941083Sanish
16951083Sanish h = host_addr;
16961083Sanish d = dev_addr;
16971083Sanish
16981083Sanish if (flags == DDI_DEV_AUTOINCR)
16991083Sanish for (; repcount; repcount--)
17001083Sanish pci_config_wr32(hdlp, d++, *h++);
17011083Sanish else
17021083Sanish for (; repcount; repcount--)
17031083Sanish pci_config_wr32(hdlp, d, *h++);
17041083Sanish }
17051083Sanish
17061083Sanish uint64_t
pci_config_rd64(ddi_acc_impl_t * hdlp,uint64_t * addr)17071083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
17081083Sanish {
17091083Sanish uint32_t lw_val;
17101083Sanish uint32_t hi_val;
17111083Sanish uint32_t *dp;
17121083Sanish uint64_t val;
17131083Sanish
17141083Sanish dp = (uint32_t *)addr;
17151083Sanish lw_val = pci_config_rd32(hdlp, dp);
17161083Sanish dp++;
17171083Sanish hi_val = pci_config_rd32(hdlp, dp);
17181083Sanish val = ((uint64_t)hi_val << 32) | lw_val;
17191083Sanish return (val);
17201083Sanish }
17211083Sanish
17221083Sanish void
pci_config_wr64(ddi_acc_impl_t * hdlp,uint64_t * addr,uint64_t value)17231083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
17241083Sanish {
17251083Sanish uint32_t lw_val;
17261083Sanish uint32_t hi_val;
17271083Sanish uint32_t *dp;
17281083Sanish
17291083Sanish dp = (uint32_t *)addr;
17301083Sanish lw_val = (uint32_t)(value & 0xffffffff);
17311083Sanish hi_val = (uint32_t)(value >> 32);
17321083Sanish pci_config_wr32(hdlp, dp, lw_val);
17331083Sanish dp++;
17341083Sanish pci_config_wr32(hdlp, dp, hi_val);
17351083Sanish }
17361083Sanish
17371083Sanish void
pci_config_rep_rd64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)17381083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
17391083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags)
17401083Sanish {
17411083Sanish if (flags == DDI_DEV_AUTOINCR) {
17421083Sanish for (; repcount; repcount--)
17431083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr++);
17441083Sanish } else {
17451083Sanish for (; repcount; repcount--)
17461083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr);
17471083Sanish }
17481083Sanish }
17491083Sanish
17501083Sanish void
pci_config_rep_wr64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)17511083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
17521083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags)
17531083Sanish {
17541083Sanish if (flags == DDI_DEV_AUTOINCR) {
17551083Sanish for (; repcount; repcount--)
17561083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr++);
17571083Sanish } else {
17581083Sanish for (; repcount; repcount--)
17591083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr);
17601083Sanish }
17611083Sanish }
1762