170025d76Sjohnny /*
270025d76Sjohnny * CDDL HEADER START
370025d76Sjohnny *
470025d76Sjohnny * The contents of this file are subject to the terms of the
5102cb92eSjohnny * Common Development and Distribution License (the "License").
6102cb92eSjohnny * You may not use this file except in compliance with the License.
770025d76Sjohnny *
870025d76Sjohnny * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
970025d76Sjohnny * or http://www.opensolaris.org/os/licensing.
1070025d76Sjohnny * See the License for the specific language governing permissions
1170025d76Sjohnny * and limitations under the License.
1270025d76Sjohnny *
1370025d76Sjohnny * When distributing Covered Code, include this CDDL HEADER in each
1470025d76Sjohnny * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1570025d76Sjohnny * If applicable, add the following below this CDDL HEADER, with the
1670025d76Sjohnny * fields enclosed by brackets "[]" replaced with your own identifying
1770025d76Sjohnny * information: Portions Copyright [yyyy] [name of copyright owner]
1870025d76Sjohnny *
1970025d76Sjohnny * CDDL HEADER END
2070025d76Sjohnny */
2170025d76Sjohnny
2270025d76Sjohnny /*
235cd376e8SJimmy Vetayases * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2470025d76Sjohnny */
2570025d76Sjohnny
2670025d76Sjohnny /*
2770025d76Sjohnny * File that has code which is common between pci(7d) and npe(7d)
2870025d76Sjohnny * It shares the following:
2970025d76Sjohnny * - interrupt code
3070025d76Sjohnny * - pci_tools ioctl code
3170025d76Sjohnny * - name_child code
3270025d76Sjohnny * - set_parent_private_data code
3370025d76Sjohnny */
3470025d76Sjohnny
3570025d76Sjohnny #include <sys/conf.h>
3670025d76Sjohnny #include <sys/pci.h>
3770025d76Sjohnny #include <sys/sunndi.h>
387a364d25Sschwartz #include <sys/mach_intr.h>
3970025d76Sjohnny #include <sys/pci_intr_lib.h>
4070025d76Sjohnny #include <sys/psm.h>
4170025d76Sjohnny #include <sys/policy.h>
4270025d76Sjohnny #include <sys/sysmacros.h>
437a364d25Sschwartz #include <sys/clock.h>
44ae115bc7Smrj #include <sys/apic.h>
4570025d76Sjohnny #include <sys/pci_tools.h>
4670025d76Sjohnny #include <io/pci/pci_var.h>
4770025d76Sjohnny #include <io/pci/pci_tools_ext.h>
4870025d76Sjohnny #include <io/pci/pci_common.h>
49649d4cceSanish #include <sys/pci_cfgspace.h>
50649d4cceSanish #include <sys/pci_impl.h>
51600d7745Sjveta #include <sys/pci_cap.h>
5270025d76Sjohnny
5370025d76Sjohnny /*
5470025d76Sjohnny * Function prototypes
5570025d76Sjohnny */
5670025d76Sjohnny static int pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
5770025d76Sjohnny static int pci_enable_intr(dev_info_t *, dev_info_t *,
5870025d76Sjohnny ddi_intr_handle_impl_t *, uint32_t);
5970025d76Sjohnny static void pci_disable_intr(dev_info_t *, dev_info_t *,
6070025d76Sjohnny ddi_intr_handle_impl_t *, uint32_t);
61*7ff178cdSJimmy Vetayases static int pci_alloc_intr_fixed(dev_info_t *, dev_info_t *,
62*7ff178cdSJimmy Vetayases ddi_intr_handle_impl_t *, void *);
63*7ff178cdSJimmy Vetayases static int pci_free_intr_fixed(dev_info_t *, dev_info_t *,
64*7ff178cdSJimmy Vetayases ddi_intr_handle_impl_t *);
6570025d76Sjohnny
66*7ff178cdSJimmy Vetayases /* Extern declarations for PSM module */
6770025d76Sjohnny extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
6870025d76Sjohnny psm_intr_op_t, int *);
69*7ff178cdSJimmy Vetayases extern ddi_irm_pool_t *apix_irm_pool_p;
7070025d76Sjohnny
7170025d76Sjohnny /*
7270025d76Sjohnny * pci_name_child:
7370025d76Sjohnny *
7470025d76Sjohnny * Assign the address portion of the node name
7570025d76Sjohnny */
7670025d76Sjohnny int
pci_common_name_child(dev_info_t * child,char * name,int namelen)7770025d76Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen)
7870025d76Sjohnny {
7970025d76Sjohnny int dev, func, length;
8070025d76Sjohnny char **unit_addr;
8170025d76Sjohnny uint_t n;
8270025d76Sjohnny pci_regspec_t *pci_rp;
8370025d76Sjohnny
8470025d76Sjohnny if (ndi_dev_is_persistent_node(child) == 0) {
8570025d76Sjohnny /*
8670025d76Sjohnny * For .conf node, use "unit-address" property
8770025d76Sjohnny */
8870025d76Sjohnny if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
8970025d76Sjohnny DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
9070025d76Sjohnny DDI_PROP_SUCCESS) {
9170025d76Sjohnny cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
9270025d76Sjohnny ddi_get_name(child));
9370025d76Sjohnny return (DDI_FAILURE);
9470025d76Sjohnny }
9570025d76Sjohnny if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
9670025d76Sjohnny cmn_err(CE_WARN, "unit-address property in %s.conf"
9770025d76Sjohnny " not well-formed", ddi_get_name(child));
9870025d76Sjohnny ddi_prop_free(unit_addr);
9970025d76Sjohnny return (DDI_FAILURE);
10070025d76Sjohnny }
10170025d76Sjohnny (void) snprintf(name, namelen, "%s", *unit_addr);
10270025d76Sjohnny ddi_prop_free(unit_addr);
10370025d76Sjohnny return (DDI_SUCCESS);
10470025d76Sjohnny }
10570025d76Sjohnny
10670025d76Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
10770025d76Sjohnny "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
10870025d76Sjohnny cmn_err(CE_WARN, "cannot find reg property in %s",
10970025d76Sjohnny ddi_get_name(child));
11070025d76Sjohnny return (DDI_FAILURE);
11170025d76Sjohnny }
11270025d76Sjohnny
11370025d76Sjohnny /* copy the device identifications */
11470025d76Sjohnny dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
11570025d76Sjohnny func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
11670025d76Sjohnny
11770025d76Sjohnny /*
11870025d76Sjohnny * free the memory allocated by ddi_prop_lookup_int_array
11970025d76Sjohnny */
12070025d76Sjohnny ddi_prop_free(pci_rp);
12170025d76Sjohnny
12270025d76Sjohnny if (func != 0) {
12370025d76Sjohnny (void) snprintf(name, namelen, "%x,%x", dev, func);
12470025d76Sjohnny } else {
12570025d76Sjohnny (void) snprintf(name, namelen, "%x", dev);
12670025d76Sjohnny }
12770025d76Sjohnny
12870025d76Sjohnny return (DDI_SUCCESS);
12970025d76Sjohnny }
13070025d76Sjohnny
13170025d76Sjohnny /*
13270025d76Sjohnny * Interrupt related code:
13370025d76Sjohnny *
13470025d76Sjohnny * The following busop is common to npe and pci drivers
13570025d76Sjohnny * bus_introp
13670025d76Sjohnny */
13770025d76Sjohnny
13870025d76Sjohnny /*
13970025d76Sjohnny * Create the ddi_parent_private_data for a pseudo child.
14070025d76Sjohnny */
14170025d76Sjohnny void
pci_common_set_parent_private_data(dev_info_t * dip)14270025d76Sjohnny pci_common_set_parent_private_data(dev_info_t *dip)
14370025d76Sjohnny {
14470025d76Sjohnny struct ddi_parent_private_data *pdptr;
14570025d76Sjohnny
14670025d76Sjohnny pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
14770025d76Sjohnny (sizeof (struct ddi_parent_private_data) +
14870025d76Sjohnny sizeof (struct intrspec)), KM_SLEEP);
14970025d76Sjohnny pdptr->par_intr = (struct intrspec *)(pdptr + 1);
15070025d76Sjohnny pdptr->par_nintr = 1;
15170025d76Sjohnny ddi_set_parent_data(dip, pdptr);
15270025d76Sjohnny }
15370025d76Sjohnny
15470025d76Sjohnny /*
15570025d76Sjohnny * pci_get_priority:
15670025d76Sjohnny * Figure out the priority of the device
15770025d76Sjohnny */
15870025d76Sjohnny static int
pci_get_priority(dev_info_t * dip,ddi_intr_handle_impl_t * hdlp,int * pri)15970025d76Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
16070025d76Sjohnny {
16170025d76Sjohnny struct intrspec *ispec;
16270025d76Sjohnny
16370025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
16470025d76Sjohnny (void *)dip, (void *)hdlp));
16570025d76Sjohnny
16670025d76Sjohnny if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
16770025d76Sjohnny hdlp->ih_inum)) == NULL) {
16870025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
169614edcaeSEvan Yan *pri = pci_class_to_pil(dip);
17070025d76Sjohnny pci_common_set_parent_private_data(hdlp->ih_dip);
17170025d76Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
17270025d76Sjohnny hdlp->ih_inum);
17370025d76Sjohnny return (DDI_SUCCESS);
17470025d76Sjohnny }
17570025d76Sjohnny return (DDI_FAILURE);
17670025d76Sjohnny }
17770025d76Sjohnny
17870025d76Sjohnny *pri = ispec->intrspec_pri;
17970025d76Sjohnny return (DDI_SUCCESS);
18070025d76Sjohnny }
18170025d76Sjohnny
18270025d76Sjohnny
18370025d76Sjohnny
184d4bc0535SKrishna Elango static int pcieb_intr_pri_counter = 0;
18570025d76Sjohnny
18670025d76Sjohnny /*
18770025d76Sjohnny * pci_common_intr_ops: bus_intr_op() function for interrupt support
18870025d76Sjohnny */
18970025d76Sjohnny 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)19070025d76Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
19170025d76Sjohnny ddi_intr_handle_impl_t *hdlp, void *result)
19270025d76Sjohnny {
19370025d76Sjohnny int priority = 0;
19470025d76Sjohnny int psm_status = 0;
19570025d76Sjohnny int pci_status = 0;
19670025d76Sjohnny int pci_rval, psm_rval = PSM_FAILURE;
19770025d76Sjohnny int types = 0;
19870025d76Sjohnny int pciepci = 0;
199102cb92eSjohnny int i, j, count;
200600d7745Sjveta int rv;
20170025d76Sjohnny int behavior;
202d12abe7cSanish int cap_ptr;
203600d7745Sjveta uint16_t msi_cap_base, msix_cap_base, cap_ctrl;
204600d7745Sjveta char *prop;
20570025d76Sjohnny ddi_intrspec_t isp;
20670025d76Sjohnny struct intrspec *ispec;
20770025d76Sjohnny ddi_intr_handle_impl_t tmp_hdl;
20870025d76Sjohnny ddi_intr_msix_t *msix_p;
209e1d9f4e6Sschwartz ihdl_plat_t *ihdl_plat_datap;
210102cb92eSjohnny ddi_intr_handle_t *h_array;
211d12abe7cSanish ddi_acc_handle_t handle;
212*7ff178cdSJimmy Vetayases apic_get_intr_t intrinfo;
21370025d76Sjohnny
21470025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT,
21570025d76Sjohnny "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
21670025d76Sjohnny (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
21770025d76Sjohnny
21870025d76Sjohnny /* Process the request */
21970025d76Sjohnny switch (intr_op) {
22070025d76Sjohnny case DDI_INTROP_SUPPORTED_TYPES:
22120036fe5Segillett /*
222600d7745Sjveta * First we determine the interrupt types supported by the
223600d7745Sjveta * device itself, then we filter them through what the OS
224600d7745Sjveta * and system supports. We determine system-level
225600d7745Sjveta * interrupt type support for anything other than fixed intrs
226600d7745Sjveta * through the psm_intr_ops vector
22720036fe5Segillett */
228600d7745Sjveta rv = DDI_FAILURE;
22970025d76Sjohnny
230600d7745Sjveta /* Fixed supported by default */
231600d7745Sjveta types = DDI_INTR_TYPE_FIXED;
232600d7745Sjveta
233600d7745Sjveta if (psm_intr_ops == NULL) {
234600d7745Sjveta *(int *)result = types;
235600d7745Sjveta return (DDI_SUCCESS);
236600d7745Sjveta }
237600d7745Sjveta if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
238600d7745Sjveta return (DDI_FAILURE);
239600d7745Sjveta
240600d7745Sjveta /* Sanity test cap control values if found */
241600d7745Sjveta
242600d7745Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) ==
243600d7745Sjveta DDI_SUCCESS) {
244600d7745Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base,
245600d7745Sjveta PCI_MSI_CTRL);
246600d7745Sjveta if (cap_ctrl == PCI_CAP_EINVAL16)
247600d7745Sjveta goto SUPPORTED_TYPES_OUT;
248600d7745Sjveta
249600d7745Sjveta types |= DDI_INTR_TYPE_MSI;
250600d7745Sjveta }
251600d7745Sjveta
252600d7745Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) ==
253600d7745Sjveta DDI_SUCCESS) {
254600d7745Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base,
255600d7745Sjveta PCI_MSIX_CTRL);
256600d7745Sjveta if (cap_ctrl == PCI_CAP_EINVAL16)
257600d7745Sjveta goto SUPPORTED_TYPES_OUT;
258600d7745Sjveta
259600d7745Sjveta types |= DDI_INTR_TYPE_MSIX;
260600d7745Sjveta }
261600d7745Sjveta
262600d7745Sjveta /*
263600d7745Sjveta * Filter device-level types through system-level support
264600d7745Sjveta */
265600d7745Sjveta tmp_hdl.ih_type = types;
266600d7745Sjveta if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI,
267600d7745Sjveta &types) != PSM_SUCCESS)
268600d7745Sjveta goto SUPPORTED_TYPES_OUT;
269600d7745Sjveta
27070025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
27170025d76Sjohnny "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
272*7ff178cdSJimmy Vetayases types));
273600d7745Sjveta
274600d7745Sjveta /*
275600d7745Sjveta * Export any MSI/MSI-X cap locations via properties
276600d7745Sjveta */
277600d7745Sjveta if (types & DDI_INTR_TYPE_MSI) {
278600d7745Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
279600d7745Sjveta "pci-msi-capid-pointer", (int)msi_cap_base) !=
280600d7745Sjveta DDI_PROP_SUCCESS)
281600d7745Sjveta goto SUPPORTED_TYPES_OUT;
28270025d76Sjohnny }
283600d7745Sjveta if (types & DDI_INTR_TYPE_MSIX) {
284600d7745Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
285600d7745Sjveta "pci-msix-capid-pointer", (int)msix_cap_base) !=
286600d7745Sjveta DDI_PROP_SUCCESS)
287600d7745Sjveta goto SUPPORTED_TYPES_OUT;
288600d7745Sjveta }
289600d7745Sjveta
290600d7745Sjveta rv = DDI_SUCCESS;
291600d7745Sjveta
292600d7745Sjveta SUPPORTED_TYPES_OUT:
293600d7745Sjveta *(int *)result = types;
294600d7745Sjveta pci_config_teardown(&handle);
295600d7745Sjveta return (rv);
296600d7745Sjveta
297a54f81fbSanish case DDI_INTROP_NAVAIL:
29870025d76Sjohnny case DDI_INTROP_NINTRS:
299a54f81fbSanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
300a54f81fbSanish if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
301a54f81fbSanish result) != DDI_SUCCESS)
30270025d76Sjohnny return (DDI_FAILURE);
303a54f81fbSanish } else {
304a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
305a54f81fbSanish if (*(int *)result == 0)
306a54f81fbSanish return (DDI_FAILURE);
307a54f81fbSanish }
30870025d76Sjohnny break;
30970025d76Sjohnny case DDI_INTROP_ALLOC:
310*7ff178cdSJimmy Vetayases
311*7ff178cdSJimmy Vetayases /*
312*7ff178cdSJimmy Vetayases * FIXED type
313*7ff178cdSJimmy Vetayases */
314*7ff178cdSJimmy Vetayases if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
315*7ff178cdSJimmy Vetayases return (pci_alloc_intr_fixed(pdip, rdip, hdlp, result));
31670025d76Sjohnny /*
31770025d76Sjohnny * MSI or MSIX (figure out number of vectors available)
31870025d76Sjohnny */
31970025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
32070025d76Sjohnny (psm_intr_ops != NULL) &&
32170025d76Sjohnny (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
32270025d76Sjohnny /*
323d4bc0535SKrishna Elango * Following check is a special case for 'pcieb'.
32470025d76Sjohnny * This makes sure vectors with the right priority
325d4bc0535SKrishna Elango * are allocated for pcieb during ALLOC time.
32670025d76Sjohnny */
327d4bc0535SKrishna Elango if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) {
32870025d76Sjohnny hdlp->ih_pri =
329d4bc0535SKrishna Elango (pcieb_intr_pri_counter % 2) ? 4 : 7;
33070025d76Sjohnny pciepci = 1;
33170025d76Sjohnny } else
33270025d76Sjohnny hdlp->ih_pri = priority;
33380ab886dSwesolows behavior = (int)(uintptr_t)hdlp->ih_scratch2;
334d12abe7cSanish
335d12abe7cSanish /*
336d12abe7cSanish * Cache in the config handle and cap_ptr
337d12abe7cSanish */
338d12abe7cSanish if (i_ddi_get_pci_config_handle(rdip) == NULL) {
339d12abe7cSanish if (pci_config_setup(rdip, &handle) !=
340d12abe7cSanish DDI_SUCCESS)
341d12abe7cSanish return (DDI_FAILURE);
342d12abe7cSanish i_ddi_set_pci_config_handle(rdip, handle);
343d12abe7cSanish }
344d12abe7cSanish
345600d7745Sjveta prop = NULL;
346600d7745Sjveta cap_ptr = 0;
347600d7745Sjveta if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
348600d7745Sjveta prop = "pci-msi-capid-pointer";
349600d7745Sjveta else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX)
350600d7745Sjveta prop = "pci-msix-capid-pointer";
351d12abe7cSanish
352600d7745Sjveta /*
353600d7745Sjveta * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES
354600d7745Sjveta * for MSI(X) before allocation
355600d7745Sjveta */
356600d7745Sjveta if (prop != NULL) {
357d12abe7cSanish cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
358600d7745Sjveta DDI_PROP_DONTPASS, prop, 0);
359600d7745Sjveta if (cap_ptr == 0) {
360600d7745Sjveta DDI_INTR_NEXDBG((CE_CONT,
361600d7745Sjveta "pci_common_intr_ops: rdip: 0x%p "
362600d7745Sjveta "attempted MSI(X) alloc without "
363600d7745Sjveta "cap property\n", (void *)rdip));
364600d7745Sjveta return (DDI_FAILURE);
365d12abe7cSanish }
366600d7745Sjveta }
367600d7745Sjveta i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
368d12abe7cSanish
369600d7745Sjveta /*
370600d7745Sjveta * Allocate interrupt vectors
371600d7745Sjveta */
37270025d76Sjohnny (void) (*psm_intr_ops)(rdip, hdlp,
37370025d76Sjohnny PSM_INTR_OP_ALLOC_VECTORS, result);
37470025d76Sjohnny
3751ac1709fSanish if (*(int *)result == 0)
3761ac1709fSanish return (DDI_INTR_NOTFOUND);
3771ac1709fSanish
37870025d76Sjohnny /* verify behavior flag and take appropriate action */
37970025d76Sjohnny if ((behavior == DDI_INTR_ALLOC_STRICT) &&
38070025d76Sjohnny (*(int *)result < hdlp->ih_scratch1)) {
38170025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT,
38270025d76Sjohnny "pci_common_intr_ops: behavior %x, "
38370025d76Sjohnny "couldn't get enough intrs\n", behavior));
38470025d76Sjohnny hdlp->ih_scratch1 = *(int *)result;
38570025d76Sjohnny (void) (*psm_intr_ops)(rdip, hdlp,
38670025d76Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL);
38770025d76Sjohnny return (DDI_EAGAIN);
38870025d76Sjohnny }
38970025d76Sjohnny
39070025d76Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
39170025d76Sjohnny if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
39270025d76Sjohnny msix_p = pci_msix_init(hdlp->ih_dip);
393fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China if (msix_p) {
39470025d76Sjohnny i_ddi_set_msix(hdlp->ih_dip,
39570025d76Sjohnny msix_p);
396fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China } else {
397fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China DDI_INTR_NEXDBG((CE_CONT,
398fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China "pci_common_intr_ops: MSI-X"
399fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China "table initilization failed"
400fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China ", rdip 0x%p inum 0x%x\n",
401fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China (void *)rdip,
402fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China hdlp->ih_inum));
403fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China
404fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China (void) (*psm_intr_ops)(rdip,
405fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China hdlp,
406fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China PSM_INTR_OP_FREE_VECTORS,
407fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China NULL);
408fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China
409fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China return (DDI_FAILURE);
410fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China }
41170025d76Sjohnny }
41270025d76Sjohnny }
41370025d76Sjohnny
41470025d76Sjohnny if (pciepci) {
41570025d76Sjohnny /* update priority in ispec */
41670025d76Sjohnny isp = pci_intx_get_ispec(pdip, rdip,
41770025d76Sjohnny (int)hdlp->ih_inum);
41870025d76Sjohnny ispec = (struct intrspec *)isp;
41970025d76Sjohnny if (ispec)
42070025d76Sjohnny ispec->intrspec_pri = hdlp->ih_pri;
421d4bc0535SKrishna Elango ++pcieb_intr_pri_counter;
42270025d76Sjohnny }
42370025d76Sjohnny
42470025d76Sjohnny } else
42570025d76Sjohnny return (DDI_FAILURE);
42670025d76Sjohnny break;
42770025d76Sjohnny case DDI_INTROP_FREE:
42870025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
42970025d76Sjohnny (psm_intr_ops != NULL)) {
43068565200Sanish if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
43168565200Sanish 0) {
432d12abe7cSanish if (handle = i_ddi_get_pci_config_handle(
433d12abe7cSanish rdip)) {
434d12abe7cSanish (void) pci_config_teardown(&handle);
435d12abe7cSanish i_ddi_set_pci_config_handle(rdip, NULL);
436d12abe7cSanish }
437d12abe7cSanish if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
438d12abe7cSanish i_ddi_set_msi_msix_cap_ptr(rdip, 0);
439d12abe7cSanish }
440d12abe7cSanish
44170025d76Sjohnny (void) (*psm_intr_ops)(rdip, hdlp,
44270025d76Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL);
44370025d76Sjohnny
44470025d76Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
44570025d76Sjohnny msix_p = i_ddi_get_msix(hdlp->ih_dip);
44670025d76Sjohnny if (msix_p &&
44768565200Sanish (i_ddi_intr_get_current_nintrs(
44868565200Sanish hdlp->ih_dip) - 1) == 0) {
44970025d76Sjohnny pci_msix_fini(msix_p);
45070025d76Sjohnny i_ddi_set_msix(hdlp->ih_dip, NULL);
45170025d76Sjohnny }
45270025d76Sjohnny }
453*7ff178cdSJimmy Vetayases } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
454*7ff178cdSJimmy Vetayases return (pci_free_intr_fixed(pdip, rdip, hdlp));
455*7ff178cdSJimmy Vetayases } else
456*7ff178cdSJimmy Vetayases return (DDI_FAILURE);
45770025d76Sjohnny break;
45870025d76Sjohnny case DDI_INTROP_GETPRI:
45970025d76Sjohnny /* Get the priority */
46070025d76Sjohnny if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
46170025d76Sjohnny return (DDI_FAILURE);
46270025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
46370025d76Sjohnny "priority = 0x%x\n", priority));
46470025d76Sjohnny *(int *)result = priority;
46570025d76Sjohnny break;
46670025d76Sjohnny case DDI_INTROP_SETPRI:
46770025d76Sjohnny /* Validate the interrupt priority passed */
46870025d76Sjohnny if (*(int *)result > LOCK_LEVEL)
46970025d76Sjohnny return (DDI_FAILURE);
47070025d76Sjohnny
47170025d76Sjohnny /* Ensure that PSM is all initialized */
47270025d76Sjohnny if (psm_intr_ops == NULL)
47370025d76Sjohnny return (DDI_FAILURE);
47470025d76Sjohnny
47596f82fefSSophia Li isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
47696f82fefSSophia Li ispec = (struct intrspec *)isp;
47796f82fefSSophia Li if (ispec == NULL)
47896f82fefSSophia Li return (DDI_FAILURE);
47996f82fefSSophia Li
48096f82fefSSophia Li /* For fixed interrupts */
48196f82fefSSophia Li if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
48296f82fefSSophia Li /* if interrupt is shared, return failure */
48396f82fefSSophia Li ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
48496f82fefSSophia Li psm_rval = (*psm_intr_ops)(rdip, hdlp,
48596f82fefSSophia Li PSM_INTR_OP_GET_SHARED, &psm_status);
48696f82fefSSophia Li /*
48796f82fefSSophia Li * For fixed interrupts, the irq may not have been
48896f82fefSSophia Li * allocated when SET_PRI is called, and the above
48996f82fefSSophia Li * GET_SHARED op may return PSM_FAILURE. This is not
49096f82fefSSophia Li * a real error and is ignored below.
49196f82fefSSophia Li */
49296f82fefSSophia Li if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) {
49396f82fefSSophia Li DDI_INTR_NEXDBG((CE_CONT,
49496f82fefSSophia Li "pci_common_intr_ops: "
49596f82fefSSophia Li "dip 0x%p cannot setpri, psm_rval=%d,"
49696f82fefSSophia Li "psm_status=%d\n", (void *)rdip, psm_rval,
49796f82fefSSophia Li psm_status));
49896f82fefSSophia Li return (DDI_FAILURE);
49996f82fefSSophia Li }
50096f82fefSSophia Li }
50196f82fefSSophia Li
50270025d76Sjohnny /* Change the priority */
50370025d76Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
50470025d76Sjohnny PSM_FAILURE)
50570025d76Sjohnny return (DDI_FAILURE);
50670025d76Sjohnny
50770025d76Sjohnny /* update ispec */
50870025d76Sjohnny ispec->intrspec_pri = *(int *)result;
50970025d76Sjohnny break;
51070025d76Sjohnny case DDI_INTROP_ADDISR:
51170025d76Sjohnny /* update ispec */
51270025d76Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
51370025d76Sjohnny ispec = (struct intrspec *)isp;
514e1d9f4e6Sschwartz if (ispec) {
51570025d76Sjohnny ispec->intrspec_func = hdlp->ih_cb_func;
516e1d9f4e6Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
517e1d9f4e6Sschwartz pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
518e1d9f4e6Sschwartz }
51970025d76Sjohnny break;
52070025d76Sjohnny case DDI_INTROP_REMISR:
52170025d76Sjohnny /* Get the interrupt structure pointer */
52270025d76Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
52370025d76Sjohnny ispec = (struct intrspec *)isp;
524e1d9f4e6Sschwartz if (ispec) {
52570025d76Sjohnny ispec->intrspec_func = (uint_t (*)()) 0;
526e1d9f4e6Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
527e1d9f4e6Sschwartz if (ihdl_plat_datap->ip_ksp != NULL)
528e1d9f4e6Sschwartz pci_kstat_delete(ihdl_plat_datap->ip_ksp);
529e1d9f4e6Sschwartz }
53070025d76Sjohnny break;
53170025d76Sjohnny case DDI_INTROP_GETCAP:
53270025d76Sjohnny /*
53370025d76Sjohnny * First check the config space and/or
53470025d76Sjohnny * MSI capability register(s)
53570025d76Sjohnny */
53670025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
53770025d76Sjohnny pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
53870025d76Sjohnny &pci_status);
53970025d76Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
54070025d76Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status);
54170025d76Sjohnny
542*7ff178cdSJimmy Vetayases /* next check with PSM module */
54370025d76Sjohnny if (psm_intr_ops != NULL)
54470025d76Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp,
54570025d76Sjohnny PSM_INTR_OP_GET_CAP, &psm_status);
54670025d76Sjohnny
54770025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
54870025d76Sjohnny "psm_status = %x, pci_rval = %x, pci_status = %x\n",
54970025d76Sjohnny psm_rval, psm_status, pci_rval, pci_status));
55070025d76Sjohnny
55170025d76Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
55270025d76Sjohnny *(int *)result = 0;
55370025d76Sjohnny return (DDI_FAILURE);
55470025d76Sjohnny }
55570025d76Sjohnny
55670025d76Sjohnny if (psm_rval == PSM_SUCCESS)
55770025d76Sjohnny *(int *)result = psm_status;
55870025d76Sjohnny
55970025d76Sjohnny if (pci_rval == DDI_SUCCESS)
56070025d76Sjohnny *(int *)result |= pci_status;
56170025d76Sjohnny
56270025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
56370025d76Sjohnny *(int *)result));
56470025d76Sjohnny break;
56570025d76Sjohnny case DDI_INTROP_SETCAP:
56670025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
56770025d76Sjohnny "SETCAP cap=0x%x\n", *(int *)result));
56870025d76Sjohnny if (psm_intr_ops == NULL)
56970025d76Sjohnny return (DDI_FAILURE);
57070025d76Sjohnny
57170025d76Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
57270025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
57370025d76Sjohnny " returned failure\n"));
57470025d76Sjohnny return (DDI_FAILURE);
57570025d76Sjohnny }
57670025d76Sjohnny break;
57770025d76Sjohnny case DDI_INTROP_ENABLE:
57870025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
57970025d76Sjohnny if (psm_intr_ops == NULL)
58070025d76Sjohnny return (DDI_FAILURE);
58170025d76Sjohnny
58270025d76Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
58370025d76Sjohnny DDI_SUCCESS)
58470025d76Sjohnny return (DDI_FAILURE);
58570025d76Sjohnny
58670025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
58770025d76Sjohnny "vector=0x%x\n", hdlp->ih_vector));
58870025d76Sjohnny break;
58970025d76Sjohnny case DDI_INTROP_DISABLE:
59070025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
59170025d76Sjohnny if (psm_intr_ops == NULL)
59270025d76Sjohnny return (DDI_FAILURE);
59370025d76Sjohnny
59470025d76Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
59570025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
59670025d76Sjohnny "vector = %x\n", hdlp->ih_vector));
59770025d76Sjohnny break;
59870025d76Sjohnny case DDI_INTROP_BLOCKENABLE:
59970025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
60070025d76Sjohnny "BLOCKENABLE\n"));
60170025d76Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
60270025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
60370025d76Sjohnny return (DDI_FAILURE);
60470025d76Sjohnny }
60570025d76Sjohnny
60670025d76Sjohnny /* Check if psm_intr_ops is NULL? */
60770025d76Sjohnny if (psm_intr_ops == NULL)
60870025d76Sjohnny return (DDI_FAILURE);
60970025d76Sjohnny
610102cb92eSjohnny count = hdlp->ih_scratch1;
611102cb92eSjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
612102cb92eSjohnny for (i = 0; i < count; i++) {
613102cb92eSjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i];
61470025d76Sjohnny if (pci_enable_intr(pdip, rdip, hdlp,
615102cb92eSjohnny hdlp->ih_inum) != DDI_SUCCESS) {
61670025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
61770025d76Sjohnny "pci_enable_intr failed for %d\n", i));
618102cb92eSjohnny for (j = 0; j < i; j++) {
6192917a9c9Sschwartz hdlp = (ddi_intr_handle_impl_t *)
6202917a9c9Sschwartz h_array[j];
62170025d76Sjohnny pci_disable_intr(pdip, rdip, hdlp,
622102cb92eSjohnny hdlp->ih_inum);
623102cb92eSjohnny }
62470025d76Sjohnny return (DDI_FAILURE);
62570025d76Sjohnny }
62670025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
627102cb92eSjohnny "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
62870025d76Sjohnny }
62970025d76Sjohnny break;
63070025d76Sjohnny case DDI_INTROP_BLOCKDISABLE:
63170025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
63270025d76Sjohnny "BLOCKDISABLE\n"));
63370025d76Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
63470025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
63570025d76Sjohnny return (DDI_FAILURE);
63670025d76Sjohnny }
63770025d76Sjohnny
63870025d76Sjohnny /* Check if psm_intr_ops is present */
63970025d76Sjohnny if (psm_intr_ops == NULL)
64070025d76Sjohnny return (DDI_FAILURE);
64170025d76Sjohnny
642102cb92eSjohnny count = hdlp->ih_scratch1;
643102cb92eSjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
644102cb92eSjohnny for (i = 0; i < count; i++) {
645102cb92eSjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i];
646102cb92eSjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
64770025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
648102cb92eSjohnny "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
64970025d76Sjohnny }
65070025d76Sjohnny break;
65170025d76Sjohnny case DDI_INTROP_SETMASK:
65270025d76Sjohnny case DDI_INTROP_CLRMASK:
65370025d76Sjohnny /*
65470025d76Sjohnny * First handle in the config space
65570025d76Sjohnny */
65670025d76Sjohnny if (intr_op == DDI_INTROP_SETMASK) {
65770025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
65870025d76Sjohnny pci_status = pci_msi_set_mask(rdip,
65970025d76Sjohnny hdlp->ih_type, hdlp->ih_inum);
66070025d76Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
66170025d76Sjohnny pci_status = pci_intx_set_mask(rdip);
66270025d76Sjohnny } else {
66370025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
66470025d76Sjohnny pci_status = pci_msi_clr_mask(rdip,
66570025d76Sjohnny hdlp->ih_type, hdlp->ih_inum);
66670025d76Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
66770025d76Sjohnny pci_status = pci_intx_clr_mask(rdip);
66870025d76Sjohnny }
66970025d76Sjohnny
670*7ff178cdSJimmy Vetayases /* For MSI/X; no need to check with PSM module */
67170025d76Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
67270025d76Sjohnny return (pci_status);
67370025d76Sjohnny
67470025d76Sjohnny /* For fixed interrupts only: handle config space first */
67570025d76Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
67670025d76Sjohnny pci_status == DDI_SUCCESS)
67770025d76Sjohnny break;
67870025d76Sjohnny
679*7ff178cdSJimmy Vetayases /* For fixed interrupts only: confer with PSM module next */
68070025d76Sjohnny if (psm_intr_ops != NULL) {
68170025d76Sjohnny /* If interrupt is shared; do nothing */
68270025d76Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp,
68370025d76Sjohnny PSM_INTR_OP_GET_SHARED, &psm_status);
68470025d76Sjohnny
68570025d76Sjohnny if (psm_rval == PSM_FAILURE || psm_status == 1)
68670025d76Sjohnny return (pci_status);
68770025d76Sjohnny
688*7ff178cdSJimmy Vetayases /* Now, PSM module should try to set/clear the mask */
68970025d76Sjohnny if (intr_op == DDI_INTROP_SETMASK)
69070025d76Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp,
69170025d76Sjohnny PSM_INTR_OP_SET_MASK, NULL);
69270025d76Sjohnny else
69370025d76Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp,
69470025d76Sjohnny PSM_INTR_OP_CLEAR_MASK, NULL);
69570025d76Sjohnny }
69670025d76Sjohnny return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
69770025d76Sjohnny case DDI_INTROP_GETPENDING:
69870025d76Sjohnny /*
69970025d76Sjohnny * First check the config space and/or
70070025d76Sjohnny * MSI capability register(s)
70170025d76Sjohnny */
70270025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
70370025d76Sjohnny pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
70470025d76Sjohnny hdlp->ih_inum, &pci_status);
70570025d76Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
70670025d76Sjohnny pci_rval = pci_intx_get_pending(rdip, &pci_status);
70770025d76Sjohnny
708*7ff178cdSJimmy Vetayases /* On failure; next try with PSM module */
70970025d76Sjohnny if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
71070025d76Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp,
71170025d76Sjohnny PSM_INTR_OP_GET_PENDING, &psm_status);
71270025d76Sjohnny
71370025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
71470025d76Sjohnny "psm_rval = %x, psm_status = %x, pci_rval = %x, "
71570025d76Sjohnny "pci_status = %x\n", psm_rval, psm_status, pci_rval,
71670025d76Sjohnny pci_status));
71770025d76Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
71870025d76Sjohnny *(int *)result = 0;
71970025d76Sjohnny return (DDI_FAILURE);
72070025d76Sjohnny }
72170025d76Sjohnny
72270025d76Sjohnny if (psm_rval != PSM_FAILURE)
72370025d76Sjohnny *(int *)result = psm_status;
72470025d76Sjohnny else if (pci_rval != DDI_FAILURE)
72570025d76Sjohnny *(int *)result = pci_status;
72670025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
72770025d76Sjohnny *(int *)result));
72870025d76Sjohnny break;
72909b1eac2SEvan Yan case DDI_INTROP_GETTARGET:
73009b1eac2SEvan Yan DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n"));
73109b1eac2SEvan Yan
732*7ff178cdSJimmy Vetayases bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
733*7ff178cdSJimmy Vetayases tmp_hdl.ih_private = (void *)&intrinfo;
734*7ff178cdSJimmy Vetayases intrinfo.avgi_req_flags = PSMGI_INTRBY_DEFAULT;
735*7ff178cdSJimmy Vetayases intrinfo.avgi_req_flags |= PSMGI_REQ_CPUID;
736*7ff178cdSJimmy Vetayases
737*7ff178cdSJimmy Vetayases if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_GET_INTR,
738*7ff178cdSJimmy Vetayases NULL) == PSM_FAILURE)
73909b1eac2SEvan Yan return (DDI_FAILURE);
740*7ff178cdSJimmy Vetayases
741*7ff178cdSJimmy Vetayases *(int *)result = intrinfo.avgi_cpu_id;
74209b1eac2SEvan Yan DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET "
743*7ff178cdSJimmy Vetayases "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector,
744*7ff178cdSJimmy Vetayases *(int *)result));
74509b1eac2SEvan Yan break;
74609b1eac2SEvan Yan case DDI_INTROP_SETTARGET:
74709b1eac2SEvan Yan DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n"));
74809b1eac2SEvan Yan
749*7ff178cdSJimmy Vetayases bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
75009b1eac2SEvan Yan tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result;
751*7ff178cdSJimmy Vetayases tmp_hdl.ih_flags = PSMGI_INTRBY_DEFAULT;
75209b1eac2SEvan Yan
753*7ff178cdSJimmy Vetayases if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU,
754*7ff178cdSJimmy Vetayases &psm_status) == PSM_FAILURE)
75509b1eac2SEvan Yan return (DDI_FAILURE);
756*7ff178cdSJimmy Vetayases
757*7ff178cdSJimmy Vetayases hdlp->ih_vector = tmp_hdl.ih_vector;
758*7ff178cdSJimmy Vetayases DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET "
759*7ff178cdSJimmy Vetayases "vector = 0x%x\n", hdlp->ih_vector));
76009b1eac2SEvan Yan break;
761*7ff178cdSJimmy Vetayases case DDI_INTROP_GETPOOL:
762*7ff178cdSJimmy Vetayases /*
763*7ff178cdSJimmy Vetayases * For MSI/X interrupts use global IRM pool if available.
764*7ff178cdSJimmy Vetayases */
765*7ff178cdSJimmy Vetayases if (apix_irm_pool_p && DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
766*7ff178cdSJimmy Vetayases *(ddi_irm_pool_t **)result = apix_irm_pool_p;
767*7ff178cdSJimmy Vetayases return (DDI_SUCCESS);
768*7ff178cdSJimmy Vetayases }
769*7ff178cdSJimmy Vetayases return (DDI_ENOTSUP);
77070025d76Sjohnny default:
77170025d76Sjohnny return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
77270025d76Sjohnny }
77370025d76Sjohnny
77470025d76Sjohnny return (DDI_SUCCESS);
77570025d76Sjohnny }
77670025d76Sjohnny
777*7ff178cdSJimmy Vetayases /*
778*7ff178cdSJimmy Vetayases * Allocate a vector for FIXED type interrupt.
779*7ff178cdSJimmy Vetayases */
780*7ff178cdSJimmy Vetayases int
pci_alloc_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,void * result)781*7ff178cdSJimmy Vetayases pci_alloc_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
782*7ff178cdSJimmy Vetayases ddi_intr_handle_impl_t *hdlp, void *result)
783*7ff178cdSJimmy Vetayases {
784*7ff178cdSJimmy Vetayases struct intrspec *ispec;
785*7ff178cdSJimmy Vetayases ddi_intr_handle_impl_t info_hdl;
786*7ff178cdSJimmy Vetayases int ret;
787*7ff178cdSJimmy Vetayases int free_phdl = 0;
788*7ff178cdSJimmy Vetayases int pci_rval;
789*7ff178cdSJimmy Vetayases int pci_status = 0;
790*7ff178cdSJimmy Vetayases apic_get_type_t type_info;
791*7ff178cdSJimmy Vetayases
792*7ff178cdSJimmy Vetayases if (psm_intr_ops == NULL)
793*7ff178cdSJimmy Vetayases return (DDI_FAILURE);
794*7ff178cdSJimmy Vetayases
795*7ff178cdSJimmy Vetayases /* Figure out if this device supports MASKING */
796*7ff178cdSJimmy Vetayases pci_rval = pci_intx_get_cap(rdip, &pci_status);
797*7ff178cdSJimmy Vetayases if (pci_rval == DDI_SUCCESS && pci_status)
798*7ff178cdSJimmy Vetayases hdlp->ih_cap |= pci_status;
799*7ff178cdSJimmy Vetayases
800*7ff178cdSJimmy Vetayases /*
801*7ff178cdSJimmy Vetayases * If the PSM module is "APIX" then pass the request for
802*7ff178cdSJimmy Vetayases * allocating the vector now.
803*7ff178cdSJimmy Vetayases */
804*7ff178cdSJimmy Vetayases bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
805*7ff178cdSJimmy Vetayases info_hdl.ih_private = &type_info;
806*7ff178cdSJimmy Vetayases if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
807*7ff178cdSJimmy Vetayases PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
808*7ff178cdSJimmy Vetayases ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
809*7ff178cdSJimmy Vetayases (int)hdlp->ih_inum);
810*7ff178cdSJimmy Vetayases if (ispec == NULL)
811*7ff178cdSJimmy Vetayases return (DDI_FAILURE);
812*7ff178cdSJimmy Vetayases if (hdlp->ih_private == NULL) { /* allocate phdl structure */
813*7ff178cdSJimmy Vetayases free_phdl = 1;
814*7ff178cdSJimmy Vetayases i_ddi_alloc_intr_phdl(hdlp);
815*7ff178cdSJimmy Vetayases }
816*7ff178cdSJimmy Vetayases ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
817*7ff178cdSJimmy Vetayases ret = (*psm_intr_ops)(rdip, hdlp,
818*7ff178cdSJimmy Vetayases PSM_INTR_OP_ALLOC_VECTORS, result);
819*7ff178cdSJimmy Vetayases if (free_phdl) { /* free up the phdl structure */
820*7ff178cdSJimmy Vetayases free_phdl = 0;
821*7ff178cdSJimmy Vetayases i_ddi_free_intr_phdl(hdlp);
822*7ff178cdSJimmy Vetayases hdlp->ih_private = NULL;
823*7ff178cdSJimmy Vetayases }
824*7ff178cdSJimmy Vetayases } else {
825*7ff178cdSJimmy Vetayases /*
826*7ff178cdSJimmy Vetayases * No APIX module; fall back to the old scheme where the
827*7ff178cdSJimmy Vetayases * interrupt vector is allocated during ddi_enable_intr() call.
828*7ff178cdSJimmy Vetayases */
829*7ff178cdSJimmy Vetayases *(int *)result = 1;
830*7ff178cdSJimmy Vetayases ret = DDI_SUCCESS;
831*7ff178cdSJimmy Vetayases }
832*7ff178cdSJimmy Vetayases
833*7ff178cdSJimmy Vetayases return (ret);
834*7ff178cdSJimmy Vetayases }
835*7ff178cdSJimmy Vetayases
836*7ff178cdSJimmy Vetayases /*
837*7ff178cdSJimmy Vetayases * Free up the vector for FIXED (legacy) type interrupt.
838*7ff178cdSJimmy Vetayases */
839*7ff178cdSJimmy Vetayases static int
pci_free_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)840*7ff178cdSJimmy Vetayases pci_free_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
841*7ff178cdSJimmy Vetayases ddi_intr_handle_impl_t *hdlp)
842*7ff178cdSJimmy Vetayases {
843*7ff178cdSJimmy Vetayases struct intrspec *ispec;
844*7ff178cdSJimmy Vetayases ddi_intr_handle_impl_t info_hdl;
845*7ff178cdSJimmy Vetayases int ret;
846*7ff178cdSJimmy Vetayases apic_get_type_t type_info;
847*7ff178cdSJimmy Vetayases
848*7ff178cdSJimmy Vetayases if (psm_intr_ops == NULL)
849*7ff178cdSJimmy Vetayases return (DDI_FAILURE);
850*7ff178cdSJimmy Vetayases
851*7ff178cdSJimmy Vetayases /*
852*7ff178cdSJimmy Vetayases * If the PSM module is "APIX" then pass the request to it
853*7ff178cdSJimmy Vetayases * to free up the vector now.
854*7ff178cdSJimmy Vetayases */
855*7ff178cdSJimmy Vetayases bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
856*7ff178cdSJimmy Vetayases info_hdl.ih_private = &type_info;
857*7ff178cdSJimmy Vetayases if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
858*7ff178cdSJimmy Vetayases PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
859*7ff178cdSJimmy Vetayases ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
860*7ff178cdSJimmy Vetayases (int)hdlp->ih_inum);
861*7ff178cdSJimmy Vetayases if (ispec == NULL)
862*7ff178cdSJimmy Vetayases return (DDI_FAILURE);
863*7ff178cdSJimmy Vetayases ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
864*7ff178cdSJimmy Vetayases ret = (*psm_intr_ops)(rdip, hdlp,
865*7ff178cdSJimmy Vetayases PSM_INTR_OP_FREE_VECTORS, NULL);
866*7ff178cdSJimmy Vetayases } else {
867*7ff178cdSJimmy Vetayases /*
868*7ff178cdSJimmy Vetayases * No APIX module; fall back to the old scheme where
869*7ff178cdSJimmy Vetayases * the interrupt vector was already freed during
870*7ff178cdSJimmy Vetayases * ddi_disable_intr() call.
871*7ff178cdSJimmy Vetayases */
872*7ff178cdSJimmy Vetayases ret = DDI_SUCCESS;
873*7ff178cdSJimmy Vetayases }
874*7ff178cdSJimmy Vetayases
875*7ff178cdSJimmy Vetayases return (ret);
876*7ff178cdSJimmy Vetayases }
877*7ff178cdSJimmy Vetayases
8787a364d25Sschwartz int
pci_get_intr_from_vecirq(apic_get_intr_t * intrinfo_p,int vecirq,boolean_t is_irq)8797a364d25Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
8807a364d25Sschwartz int vecirq, boolean_t is_irq)
8817a364d25Sschwartz {
8827a364d25Sschwartz ddi_intr_handle_impl_t get_info_ii_hdl;
8837a364d25Sschwartz
8847a364d25Sschwartz if (is_irq)
8857a364d25Sschwartz intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
8867a364d25Sschwartz
8877a364d25Sschwartz /*
8887a364d25Sschwartz * For this locally-declared and used handle, ih_private will contain a
8897a364d25Sschwartz * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
8907a364d25Sschwartz * global interrupt handling.
8917a364d25Sschwartz */
8927a364d25Sschwartz get_info_ii_hdl.ih_private = intrinfo_p;
893*7ff178cdSJimmy Vetayases get_info_ii_hdl.ih_vector = vecirq;
8947a364d25Sschwartz
8957a364d25Sschwartz if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
8967a364d25Sschwartz PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
8977a364d25Sschwartz return (DDI_FAILURE);
8987a364d25Sschwartz
8997a364d25Sschwartz return (DDI_SUCCESS);
9007a364d25Sschwartz }
9017a364d25Sschwartz
9027a364d25Sschwartz
9037a364d25Sschwartz int
pci_get_cpu_from_vecirq(int vecirq,boolean_t is_irq)9047a364d25Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
9057a364d25Sschwartz {
9067a364d25Sschwartz int rval;
9077a364d25Sschwartz apic_get_intr_t intrinfo;
908*7ff178cdSJimmy Vetayases
9097a364d25Sschwartz intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
9107a364d25Sschwartz rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
9117a364d25Sschwartz
9127a364d25Sschwartz if (rval == DDI_SUCCESS)
9137a364d25Sschwartz return (intrinfo.avgi_cpu_id);
9147a364d25Sschwartz else
9157a364d25Sschwartz return (-1);
9167a364d25Sschwartz }
9177a364d25Sschwartz
91870025d76Sjohnny
91970025d76Sjohnny static int
pci_enable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)92070025d76Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
92170025d76Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum)
92270025d76Sjohnny {
92370025d76Sjohnny struct intrspec *ispec;
9247a364d25Sschwartz int irq;
9257a364d25Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
92670025d76Sjohnny
92770025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
92870025d76Sjohnny (void *)hdlp, inum));
92970025d76Sjohnny
93070025d76Sjohnny /* Translate the interrupt if needed */
93170025d76Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
9328d9a0e26Sanish if (ispec == NULL)
9338d9a0e26Sanish return (DDI_FAILURE);
93496f82fefSSophia Li if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
93570025d76Sjohnny ispec->intrspec_vec = inum;
93696f82fefSSophia Li ispec->intrspec_pri = hdlp->ih_pri;
93796f82fefSSophia Li }
9387a364d25Sschwartz ihdl_plat_datap->ip_ispecp = ispec;
93970025d76Sjohnny
94070025d76Sjohnny /* translate the interrupt if needed */
94186a9c507SGuoli Shu if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) ==
94286a9c507SGuoli Shu PSM_FAILURE)
94386a9c507SGuoli Shu return (DDI_FAILURE);
9447a364d25Sschwartz DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
9457a364d25Sschwartz hdlp->ih_pri, irq));
94670025d76Sjohnny
94770025d76Sjohnny /* Add the interrupt handler */
94870025d76Sjohnny if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
9497a364d25Sschwartz DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
9507a364d25Sschwartz hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
95170025d76Sjohnny return (DDI_FAILURE);
95270025d76Sjohnny
953*7ff178cdSJimmy Vetayases hdlp->ih_vector = irq;
9547a364d25Sschwartz
95570025d76Sjohnny return (DDI_SUCCESS);
95670025d76Sjohnny }
95770025d76Sjohnny
95870025d76Sjohnny
95970025d76Sjohnny static void
pci_disable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)96070025d76Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
96170025d76Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum)
96270025d76Sjohnny {
9637a364d25Sschwartz int irq;
96470025d76Sjohnny struct intrspec *ispec;
9657a364d25Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
96670025d76Sjohnny
96770025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
96870025d76Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
9698d9a0e26Sanish if (ispec == NULL)
9708d9a0e26Sanish return;
97196f82fefSSophia Li if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
97270025d76Sjohnny ispec->intrspec_vec = inum;
97396f82fefSSophia Li ispec->intrspec_pri = hdlp->ih_pri;
97496f82fefSSophia Li }
9757a364d25Sschwartz ihdl_plat_datap->ip_ispecp = ispec;
97670025d76Sjohnny
97770025d76Sjohnny /* translate the interrupt if needed */
9787a364d25Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
97970025d76Sjohnny
98070025d76Sjohnny /* Disable the interrupt handler */
9817a364d25Sschwartz rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
9827a364d25Sschwartz ihdl_plat_datap->ip_ispecp = NULL;
98370025d76Sjohnny }
98470025d76Sjohnny
98570025d76Sjohnny /*
98670025d76Sjohnny * Miscellaneous library function
98770025d76Sjohnny */
98870025d76Sjohnny int
pci_common_get_reg_prop(dev_info_t * dip,pci_regspec_t * pci_rp)98970025d76Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
99070025d76Sjohnny {
99170025d76Sjohnny int i;
99270025d76Sjohnny int number;
99370025d76Sjohnny int assigned_addr_len;
99470025d76Sjohnny uint_t phys_hi = pci_rp->pci_phys_hi;
99570025d76Sjohnny pci_regspec_t *assigned_addr;
99670025d76Sjohnny
99770025d76Sjohnny if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
99870025d76Sjohnny (phys_hi & PCI_RELOCAT_B))
99970025d76Sjohnny return (DDI_SUCCESS);
100070025d76Sjohnny
100170025d76Sjohnny /*
100270025d76Sjohnny * the "reg" property specifies relocatable, get and interpret the
100370025d76Sjohnny * "assigned-addresses" property.
100470025d76Sjohnny */
100570025d76Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
100670025d76Sjohnny "assigned-addresses", (int **)&assigned_addr,
100770025d76Sjohnny (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
100870025d76Sjohnny return (DDI_FAILURE);
100970025d76Sjohnny
101070025d76Sjohnny /*
101170025d76Sjohnny * Scan the "assigned-addresses" for one that matches the specified
101270025d76Sjohnny * "reg" property entry.
101370025d76Sjohnny */
101470025d76Sjohnny phys_hi &= PCI_CONF_ADDR_MASK;
101570025d76Sjohnny number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
101670025d76Sjohnny for (i = 0; i < number; i++) {
101770025d76Sjohnny if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
101870025d76Sjohnny phys_hi) {
101970025d76Sjohnny pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
102070025d76Sjohnny pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
102170025d76Sjohnny ddi_prop_free(assigned_addr);
102270025d76Sjohnny return (DDI_SUCCESS);
102370025d76Sjohnny }
102470025d76Sjohnny }
102570025d76Sjohnny
102670025d76Sjohnny ddi_prop_free(assigned_addr);
102770025d76Sjohnny return (DDI_FAILURE);
102870025d76Sjohnny }
102970025d76Sjohnny
103070025d76Sjohnny
103170025d76Sjohnny /*
103226947304SEvan Yan * To handle PCI tool ioctls
103370025d76Sjohnny */
103470025d76Sjohnny
103526947304SEvan Yan /*ARGSUSED*/
103670025d76Sjohnny int
pci_common_ioctl(dev_info_t * dip,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)103770025d76Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
103870025d76Sjohnny int mode, cred_t *credp, int *rvalp)
103970025d76Sjohnny {
104026947304SEvan Yan minor_t minor = getminor(dev);
104170025d76Sjohnny int rv = ENOTTY;
104270025d76Sjohnny
104326947304SEvan Yan switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
104470025d76Sjohnny case PCI_TOOL_REG_MINOR_NUM:
104570025d76Sjohnny
104670025d76Sjohnny switch (cmd) {
104770025d76Sjohnny case PCITOOL_DEVICE_SET_REG:
104870025d76Sjohnny case PCITOOL_DEVICE_GET_REG:
104970025d76Sjohnny
105070025d76Sjohnny /* Require full privileges. */
105170025d76Sjohnny if (secpolicy_kmdb(credp))
105270025d76Sjohnny rv = EPERM;
105370025d76Sjohnny else
105470025d76Sjohnny rv = pcitool_dev_reg_ops(dip, (void *)arg,
105570025d76Sjohnny cmd, mode);
105670025d76Sjohnny break;
105770025d76Sjohnny
105870025d76Sjohnny case PCITOOL_NEXUS_SET_REG:
105970025d76Sjohnny case PCITOOL_NEXUS_GET_REG:
106070025d76Sjohnny
106170025d76Sjohnny /* Require full privileges. */
106270025d76Sjohnny if (secpolicy_kmdb(credp))
106370025d76Sjohnny rv = EPERM;
106470025d76Sjohnny else
106570025d76Sjohnny rv = pcitool_bus_reg_ops(dip, (void *)arg,
106670025d76Sjohnny cmd, mode);
106770025d76Sjohnny break;
106870025d76Sjohnny }
106970025d76Sjohnny break;
107070025d76Sjohnny
107170025d76Sjohnny case PCI_TOOL_INTR_MINOR_NUM:
107270025d76Sjohnny
107370025d76Sjohnny switch (cmd) {
107470025d76Sjohnny case PCITOOL_DEVICE_SET_INTR:
107570025d76Sjohnny
107670025d76Sjohnny /* Require PRIV_SYS_RES_CONFIG, same as psradm */
107770025d76Sjohnny if (secpolicy_ponline(credp)) {
107870025d76Sjohnny rv = EPERM;
107970025d76Sjohnny break;
108070025d76Sjohnny }
108170025d76Sjohnny
108270025d76Sjohnny /*FALLTHRU*/
108370025d76Sjohnny /* These require no special privileges. */
108470025d76Sjohnny case PCITOOL_DEVICE_GET_INTR:
10852917a9c9Sschwartz case PCITOOL_SYSTEM_INTR_INFO:
108670025d76Sjohnny rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
108770025d76Sjohnny break;
108870025d76Sjohnny }
108970025d76Sjohnny break;
109070025d76Sjohnny
109170025d76Sjohnny default:
109270025d76Sjohnny break;
109370025d76Sjohnny }
109470025d76Sjohnny
109570025d76Sjohnny return (rv);
109670025d76Sjohnny }
1097649d4cceSanish
1098649d4cceSanish
109900d0963fSdilpreet int
pci_common_ctlops_poke(peekpoke_ctlops_t * in_args)110000d0963fSdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
110100d0963fSdilpreet {
110200d0963fSdilpreet size_t size = in_args->size;
110300d0963fSdilpreet uintptr_t dev_addr = in_args->dev_addr;
110400d0963fSdilpreet uintptr_t host_addr = in_args->host_addr;
110500d0963fSdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
110600d0963fSdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
110700d0963fSdilpreet size_t repcount = in_args->repcount;
110800d0963fSdilpreet uint_t flags = in_args->flags;
110900d0963fSdilpreet int err = DDI_SUCCESS;
111000d0963fSdilpreet
111100d0963fSdilpreet /*
111200d0963fSdilpreet * if no handle then this is a poke. We have to return failure here
111300d0963fSdilpreet * as we have no way of knowing whether this is a MEM or IO space access
111400d0963fSdilpreet */
111500d0963fSdilpreet if (in_args->handle == NULL)
111600d0963fSdilpreet return (DDI_FAILURE);
111700d0963fSdilpreet
111800d0963fSdilpreet /*
111900d0963fSdilpreet * rest of this function is actually for cautious puts
112000d0963fSdilpreet */
112100d0963fSdilpreet for (; repcount; repcount--) {
112200d0963fSdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
112300d0963fSdilpreet switch (size) {
112400d0963fSdilpreet case sizeof (uint8_t):
112500d0963fSdilpreet pci_config_wr8(hp, (uint8_t *)dev_addr,
112600d0963fSdilpreet *(uint8_t *)host_addr);
112700d0963fSdilpreet break;
112800d0963fSdilpreet case sizeof (uint16_t):
112900d0963fSdilpreet pci_config_wr16(hp, (uint16_t *)dev_addr,
113000d0963fSdilpreet *(uint16_t *)host_addr);
113100d0963fSdilpreet break;
113200d0963fSdilpreet case sizeof (uint32_t):
113300d0963fSdilpreet pci_config_wr32(hp, (uint32_t *)dev_addr,
113400d0963fSdilpreet *(uint32_t *)host_addr);
113500d0963fSdilpreet break;
113600d0963fSdilpreet case sizeof (uint64_t):
113700d0963fSdilpreet pci_config_wr64(hp, (uint64_t *)dev_addr,
113800d0963fSdilpreet *(uint64_t *)host_addr);
113900d0963fSdilpreet break;
114000d0963fSdilpreet default:
114100d0963fSdilpreet err = DDI_FAILURE;
114200d0963fSdilpreet break;
114300d0963fSdilpreet }
114400d0963fSdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
114500d0963fSdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags ==
114600d0963fSdilpreet DDI_STRUCTURE_BE_ACC) {
114700d0963fSdilpreet switch (size) {
114800d0963fSdilpreet case sizeof (uint8_t):
114900d0963fSdilpreet i_ddi_io_put8(hp,
115000d0963fSdilpreet (uint8_t *)dev_addr,
115100d0963fSdilpreet *(uint8_t *)host_addr);
115200d0963fSdilpreet break;
115300d0963fSdilpreet case sizeof (uint16_t):
115400d0963fSdilpreet i_ddi_io_swap_put16(hp,
115500d0963fSdilpreet (uint16_t *)dev_addr,
115600d0963fSdilpreet *(uint16_t *)host_addr);
115700d0963fSdilpreet break;
115800d0963fSdilpreet case sizeof (uint32_t):
115900d0963fSdilpreet i_ddi_io_swap_put32(hp,
116000d0963fSdilpreet (uint32_t *)dev_addr,
116100d0963fSdilpreet *(uint32_t *)host_addr);
116200d0963fSdilpreet break;
116300d0963fSdilpreet /*
116400d0963fSdilpreet * note the 64-bit case is a dummy
116500d0963fSdilpreet * function - so no need to swap
116600d0963fSdilpreet */
116700d0963fSdilpreet case sizeof (uint64_t):
116800d0963fSdilpreet i_ddi_io_put64(hp,
116900d0963fSdilpreet (uint64_t *)dev_addr,
117000d0963fSdilpreet *(uint64_t *)host_addr);
117100d0963fSdilpreet break;
117200d0963fSdilpreet default:
117300d0963fSdilpreet err = DDI_FAILURE;
117400d0963fSdilpreet break;
117500d0963fSdilpreet }
117600d0963fSdilpreet } else {
117700d0963fSdilpreet switch (size) {
117800d0963fSdilpreet case sizeof (uint8_t):
117900d0963fSdilpreet i_ddi_io_put8(hp,
118000d0963fSdilpreet (uint8_t *)dev_addr,
118100d0963fSdilpreet *(uint8_t *)host_addr);
118200d0963fSdilpreet break;
118300d0963fSdilpreet case sizeof (uint16_t):
118400d0963fSdilpreet i_ddi_io_put16(hp,
118500d0963fSdilpreet (uint16_t *)dev_addr,
118600d0963fSdilpreet *(uint16_t *)host_addr);
118700d0963fSdilpreet break;
118800d0963fSdilpreet case sizeof (uint32_t):
118900d0963fSdilpreet i_ddi_io_put32(hp,
119000d0963fSdilpreet (uint32_t *)dev_addr,
119100d0963fSdilpreet *(uint32_t *)host_addr);
119200d0963fSdilpreet break;
119300d0963fSdilpreet case sizeof (uint64_t):
119400d0963fSdilpreet i_ddi_io_put64(hp,
119500d0963fSdilpreet (uint64_t *)dev_addr,
119600d0963fSdilpreet *(uint64_t *)host_addr);
119700d0963fSdilpreet break;
119800d0963fSdilpreet default:
119900d0963fSdilpreet err = DDI_FAILURE;
120000d0963fSdilpreet break;
120100d0963fSdilpreet }
120200d0963fSdilpreet }
120300d0963fSdilpreet } else {
120400d0963fSdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags ==
120500d0963fSdilpreet DDI_STRUCTURE_BE_ACC) {
120600d0963fSdilpreet switch (size) {
120700d0963fSdilpreet case sizeof (uint8_t):
120800d0963fSdilpreet *(uint8_t *)dev_addr =
120900d0963fSdilpreet *(uint8_t *)host_addr;
121000d0963fSdilpreet break;
121100d0963fSdilpreet case sizeof (uint16_t):
121200d0963fSdilpreet *(uint16_t *)dev_addr =
121300d0963fSdilpreet ddi_swap16(*(uint16_t *)host_addr);
121400d0963fSdilpreet break;
121500d0963fSdilpreet case sizeof (uint32_t):
121600d0963fSdilpreet *(uint32_t *)dev_addr =
121700d0963fSdilpreet ddi_swap32(*(uint32_t *)host_addr);
121800d0963fSdilpreet break;
121900d0963fSdilpreet case sizeof (uint64_t):
122000d0963fSdilpreet *(uint64_t *)dev_addr =
122100d0963fSdilpreet ddi_swap64(*(uint64_t *)host_addr);
122200d0963fSdilpreet break;
122300d0963fSdilpreet default:
122400d0963fSdilpreet err = DDI_FAILURE;
122500d0963fSdilpreet break;
122600d0963fSdilpreet }
122700d0963fSdilpreet } else {
122800d0963fSdilpreet switch (size) {
122900d0963fSdilpreet case sizeof (uint8_t):
123000d0963fSdilpreet *(uint8_t *)dev_addr =
123100d0963fSdilpreet *(uint8_t *)host_addr;
123200d0963fSdilpreet break;
123300d0963fSdilpreet case sizeof (uint16_t):
123400d0963fSdilpreet *(uint16_t *)dev_addr =
123500d0963fSdilpreet *(uint16_t *)host_addr;
123600d0963fSdilpreet break;
123700d0963fSdilpreet case sizeof (uint32_t):
123800d0963fSdilpreet *(uint32_t *)dev_addr =
123900d0963fSdilpreet *(uint32_t *)host_addr;
124000d0963fSdilpreet break;
124100d0963fSdilpreet case sizeof (uint64_t):
124200d0963fSdilpreet *(uint64_t *)dev_addr =
124300d0963fSdilpreet *(uint64_t *)host_addr;
124400d0963fSdilpreet break;
124500d0963fSdilpreet default:
124600d0963fSdilpreet err = DDI_FAILURE;
124700d0963fSdilpreet break;
124800d0963fSdilpreet }
124900d0963fSdilpreet }
125000d0963fSdilpreet }
125100d0963fSdilpreet host_addr += size;
125200d0963fSdilpreet if (flags == DDI_DEV_AUTOINCR)
125300d0963fSdilpreet dev_addr += size;
125400d0963fSdilpreet }
125500d0963fSdilpreet return (err);
125600d0963fSdilpreet }
125700d0963fSdilpreet
125800d0963fSdilpreet
125900d0963fSdilpreet int
pci_fm_acc_setup(ddi_acc_hdl_t * hp,off_t offset,off_t len)126000d0963fSdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
126100d0963fSdilpreet {
126200d0963fSdilpreet ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private;
126300d0963fSdilpreet
126400d0963fSdilpreet /* endian-ness check */
126500d0963fSdilpreet if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
126600d0963fSdilpreet return (DDI_FAILURE);
126700d0963fSdilpreet
126800d0963fSdilpreet /*
126900d0963fSdilpreet * range check
127000d0963fSdilpreet */
127100d0963fSdilpreet if ((offset >= PCI_CONF_HDR_SIZE) ||
127200d0963fSdilpreet (len > PCI_CONF_HDR_SIZE) ||
127300d0963fSdilpreet (offset + len > PCI_CONF_HDR_SIZE))
127400d0963fSdilpreet return (DDI_FAILURE);
127500d0963fSdilpreet
127600d0963fSdilpreet ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
127700d0963fSdilpreet /*
127800d0963fSdilpreet * always use cautious mechanism for config space gets
127900d0963fSdilpreet */
128000d0963fSdilpreet ap->ahi_get8 = i_ddi_caut_get8;
128100d0963fSdilpreet ap->ahi_get16 = i_ddi_caut_get16;
128200d0963fSdilpreet ap->ahi_get32 = i_ddi_caut_get32;
128300d0963fSdilpreet ap->ahi_get64 = i_ddi_caut_get64;
128400d0963fSdilpreet ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
128500d0963fSdilpreet ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
128600d0963fSdilpreet ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
128700d0963fSdilpreet ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
128800d0963fSdilpreet if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
128900d0963fSdilpreet ap->ahi_put8 = i_ddi_caut_put8;
129000d0963fSdilpreet ap->ahi_put16 = i_ddi_caut_put16;
129100d0963fSdilpreet ap->ahi_put32 = i_ddi_caut_put32;
129200d0963fSdilpreet ap->ahi_put64 = i_ddi_caut_put64;
129300d0963fSdilpreet ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
129400d0963fSdilpreet ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
129500d0963fSdilpreet ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
129600d0963fSdilpreet ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
129700d0963fSdilpreet } else {
129800d0963fSdilpreet ap->ahi_put8 = pci_config_wr8;
129900d0963fSdilpreet ap->ahi_put16 = pci_config_wr16;
130000d0963fSdilpreet ap->ahi_put32 = pci_config_wr32;
130100d0963fSdilpreet ap->ahi_put64 = pci_config_wr64;
130200d0963fSdilpreet ap->ahi_rep_put8 = pci_config_rep_wr8;
130300d0963fSdilpreet ap->ahi_rep_put16 = pci_config_rep_wr16;
130400d0963fSdilpreet ap->ahi_rep_put32 = pci_config_rep_wr32;
130500d0963fSdilpreet ap->ahi_rep_put64 = pci_config_rep_wr64;
130600d0963fSdilpreet }
130700d0963fSdilpreet
130800d0963fSdilpreet /* Initialize to default check/notify functions */
130900d0963fSdilpreet ap->ahi_fault_check = i_ddi_acc_fault_check;
131000d0963fSdilpreet ap->ahi_fault_notify = i_ddi_acc_fault_notify;
131100d0963fSdilpreet ap->ahi_fault = 0;
131200d0963fSdilpreet impl_acc_err_init(hp);
131300d0963fSdilpreet return (DDI_SUCCESS);
131400d0963fSdilpreet }
131500d0963fSdilpreet
131600d0963fSdilpreet
131700d0963fSdilpreet int
pci_common_ctlops_peek(peekpoke_ctlops_t * in_args)131800d0963fSdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
131900d0963fSdilpreet {
132000d0963fSdilpreet size_t size = in_args->size;
132100d0963fSdilpreet uintptr_t dev_addr = in_args->dev_addr;
132200d0963fSdilpreet uintptr_t host_addr = in_args->host_addr;
132300d0963fSdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
132400d0963fSdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
132500d0963fSdilpreet size_t repcount = in_args->repcount;
132600d0963fSdilpreet uint_t flags = in_args->flags;
132700d0963fSdilpreet int err = DDI_SUCCESS;
132800d0963fSdilpreet
132900d0963fSdilpreet /*
133000d0963fSdilpreet * if no handle then this is a peek. We have to return failure here
133100d0963fSdilpreet * as we have no way of knowing whether this is a MEM or IO space access
133200d0963fSdilpreet */
133300d0963fSdilpreet if (in_args->handle == NULL)
133400d0963fSdilpreet return (DDI_FAILURE);
133500d0963fSdilpreet
133600d0963fSdilpreet for (; repcount; repcount--) {
133700d0963fSdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
133800d0963fSdilpreet switch (size) {
133900d0963fSdilpreet case sizeof (uint8_t):
134000d0963fSdilpreet *(uint8_t *)host_addr = pci_config_rd8(hp,
134100d0963fSdilpreet (uint8_t *)dev_addr);
134200d0963fSdilpreet break;
134300d0963fSdilpreet case sizeof (uint16_t):
134400d0963fSdilpreet *(uint16_t *)host_addr = pci_config_rd16(hp,
134500d0963fSdilpreet (uint16_t *)dev_addr);
134600d0963fSdilpreet break;
134700d0963fSdilpreet case sizeof (uint32_t):
134800d0963fSdilpreet *(uint32_t *)host_addr = pci_config_rd32(hp,
134900d0963fSdilpreet (uint32_t *)dev_addr);
135000d0963fSdilpreet break;
135100d0963fSdilpreet case sizeof (uint64_t):
135200d0963fSdilpreet *(uint64_t *)host_addr = pci_config_rd64(hp,
135300d0963fSdilpreet (uint64_t *)dev_addr);
135400d0963fSdilpreet break;
135500d0963fSdilpreet default:
135600d0963fSdilpreet err = DDI_FAILURE;
135700d0963fSdilpreet break;
135800d0963fSdilpreet }
135900d0963fSdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
136000d0963fSdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags ==
136100d0963fSdilpreet DDI_STRUCTURE_BE_ACC) {
136200d0963fSdilpreet switch (size) {
136300d0963fSdilpreet case sizeof (uint8_t):
136400d0963fSdilpreet *(uint8_t *)host_addr =
136500d0963fSdilpreet i_ddi_io_get8(hp,
136600d0963fSdilpreet (uint8_t *)dev_addr);
136700d0963fSdilpreet break;
136800d0963fSdilpreet case sizeof (uint16_t):
136900d0963fSdilpreet *(uint16_t *)host_addr =
137000d0963fSdilpreet i_ddi_io_swap_get16(hp,
137100d0963fSdilpreet (uint16_t *)dev_addr);
137200d0963fSdilpreet break;
137300d0963fSdilpreet case sizeof (uint32_t):
137400d0963fSdilpreet *(uint32_t *)host_addr =
137500d0963fSdilpreet i_ddi_io_swap_get32(hp,
137600d0963fSdilpreet (uint32_t *)dev_addr);
137700d0963fSdilpreet break;
137800d0963fSdilpreet /*
137900d0963fSdilpreet * note the 64-bit case is a dummy
138000d0963fSdilpreet * function - so no need to swap
138100d0963fSdilpreet */
138200d0963fSdilpreet case sizeof (uint64_t):
138300d0963fSdilpreet *(uint64_t *)host_addr =
138400d0963fSdilpreet i_ddi_io_get64(hp,
138500d0963fSdilpreet (uint64_t *)dev_addr);
138600d0963fSdilpreet break;
138700d0963fSdilpreet default:
138800d0963fSdilpreet err = DDI_FAILURE;
138900d0963fSdilpreet break;
139000d0963fSdilpreet }
139100d0963fSdilpreet } else {
139200d0963fSdilpreet switch (size) {
139300d0963fSdilpreet case sizeof (uint8_t):
139400d0963fSdilpreet *(uint8_t *)host_addr =
139500d0963fSdilpreet i_ddi_io_get8(hp,
139600d0963fSdilpreet (uint8_t *)dev_addr);
139700d0963fSdilpreet break;
139800d0963fSdilpreet case sizeof (uint16_t):
139900d0963fSdilpreet *(uint16_t *)host_addr =
140000d0963fSdilpreet i_ddi_io_get16(hp,
140100d0963fSdilpreet (uint16_t *)dev_addr);
140200d0963fSdilpreet break;
140300d0963fSdilpreet case sizeof (uint32_t):
140400d0963fSdilpreet *(uint32_t *)host_addr =
140500d0963fSdilpreet i_ddi_io_get32(hp,
140600d0963fSdilpreet (uint32_t *)dev_addr);
140700d0963fSdilpreet break;
140800d0963fSdilpreet case sizeof (uint64_t):
140900d0963fSdilpreet *(uint64_t *)host_addr =
141000d0963fSdilpreet i_ddi_io_get64(hp,
141100d0963fSdilpreet (uint64_t *)dev_addr);
141200d0963fSdilpreet break;
141300d0963fSdilpreet default:
141400d0963fSdilpreet err = DDI_FAILURE;
141500d0963fSdilpreet break;
141600d0963fSdilpreet }
141700d0963fSdilpreet }
141800d0963fSdilpreet } else {
141900d0963fSdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags ==
142000d0963fSdilpreet DDI_STRUCTURE_BE_ACC) {
142100d0963fSdilpreet switch (in_args->size) {
142200d0963fSdilpreet case sizeof (uint8_t):
142300d0963fSdilpreet *(uint8_t *)host_addr =
142400d0963fSdilpreet *(uint8_t *)dev_addr;
142500d0963fSdilpreet break;
142600d0963fSdilpreet case sizeof (uint16_t):
142700d0963fSdilpreet *(uint16_t *)host_addr =
142800d0963fSdilpreet ddi_swap16(*(uint16_t *)dev_addr);
142900d0963fSdilpreet break;
143000d0963fSdilpreet case sizeof (uint32_t):
143100d0963fSdilpreet *(uint32_t *)host_addr =
143200d0963fSdilpreet ddi_swap32(*(uint32_t *)dev_addr);
143300d0963fSdilpreet break;
143400d0963fSdilpreet case sizeof (uint64_t):
143500d0963fSdilpreet *(uint64_t *)host_addr =
143600d0963fSdilpreet ddi_swap64(*(uint64_t *)dev_addr);
143700d0963fSdilpreet break;
143800d0963fSdilpreet default:
143900d0963fSdilpreet err = DDI_FAILURE;
144000d0963fSdilpreet break;
144100d0963fSdilpreet }
144200d0963fSdilpreet } else {
144300d0963fSdilpreet switch (in_args->size) {
144400d0963fSdilpreet case sizeof (uint8_t):
144500d0963fSdilpreet *(uint8_t *)host_addr =
144600d0963fSdilpreet *(uint8_t *)dev_addr;
144700d0963fSdilpreet break;
144800d0963fSdilpreet case sizeof (uint16_t):
144900d0963fSdilpreet *(uint16_t *)host_addr =
145000d0963fSdilpreet *(uint16_t *)dev_addr;
145100d0963fSdilpreet break;
145200d0963fSdilpreet case sizeof (uint32_t):
145300d0963fSdilpreet *(uint32_t *)host_addr =
145400d0963fSdilpreet *(uint32_t *)dev_addr;
145500d0963fSdilpreet break;
145600d0963fSdilpreet case sizeof (uint64_t):
145700d0963fSdilpreet *(uint64_t *)host_addr =
145800d0963fSdilpreet *(uint64_t *)dev_addr;
145900d0963fSdilpreet break;
146000d0963fSdilpreet default:
146100d0963fSdilpreet err = DDI_FAILURE;
146200d0963fSdilpreet break;
146300d0963fSdilpreet }
146400d0963fSdilpreet }
146500d0963fSdilpreet }
146600d0963fSdilpreet host_addr += size;
146700d0963fSdilpreet if (flags == DDI_DEV_AUTOINCR)
146800d0963fSdilpreet dev_addr += size;
146900d0963fSdilpreet }
147000d0963fSdilpreet return (err);
147100d0963fSdilpreet }
147200d0963fSdilpreet
147300d0963fSdilpreet /*ARGSUSED*/
147400d0963fSdilpreet int
pci_common_peekpoke(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)147500d0963fSdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
147600d0963fSdilpreet ddi_ctl_enum_t ctlop, void *arg, void *result)
147700d0963fSdilpreet {
147800d0963fSdilpreet if (ctlop == DDI_CTLOPS_PEEK)
147900d0963fSdilpreet return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
148000d0963fSdilpreet else
148100d0963fSdilpreet return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
148200d0963fSdilpreet }
148300d0963fSdilpreet
1484649d4cceSanish /*
1485649d4cceSanish * These are the get and put functions to be shared with drivers. The
1486649d4cceSanish * mutex locking is done inside the functions referenced, rather than
1487649d4cceSanish * here, and is thus shared across PCI child drivers and any other
1488649d4cceSanish * consumers of PCI config space (such as the ACPI subsystem).
1489649d4cceSanish *
1490649d4cceSanish * The configuration space addresses come in as pointers. This is fine on
1491649d4cceSanish * a 32-bit system, where the VM space and configuration space are the same
1492649d4cceSanish * size. It's not such a good idea on a 64-bit system, where memory
1493649d4cceSanish * addresses are twice as large as configuration space addresses. At some
1494649d4cceSanish * point in the call tree we need to take a stand and say "you are 32-bit
1495649d4cceSanish * from this time forth", and this seems like a nice self-contained place.
1496649d4cceSanish */
1497649d4cceSanish
1498649d4cceSanish uint8_t
pci_config_rd8(ddi_acc_impl_t * hdlp,uint8_t * addr)1499649d4cceSanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1500649d4cceSanish {
1501649d4cceSanish pci_acc_cfblk_t *cfp;
1502649d4cceSanish uint8_t rval;
1503649d4cceSanish int reg;
1504649d4cceSanish
1505649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0);
1506649d4cceSanish
1507649d4cceSanish reg = (int)(uintptr_t)addr;
1508649d4cceSanish
1509649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1510649d4cceSanish
1511649d4cceSanish rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1512649d4cceSanish reg);
1513649d4cceSanish
1514649d4cceSanish return (rval);
1515649d4cceSanish }
1516649d4cceSanish
1517649d4cceSanish void
pci_config_rep_rd8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)1518649d4cceSanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1519649d4cceSanish uint8_t *dev_addr, size_t repcount, uint_t flags)
1520649d4cceSanish {
1521649d4cceSanish uint8_t *h, *d;
1522649d4cceSanish
1523649d4cceSanish h = host_addr;
1524649d4cceSanish d = dev_addr;
1525649d4cceSanish
1526649d4cceSanish if (flags == DDI_DEV_AUTOINCR)
1527649d4cceSanish for (; repcount; repcount--)
1528649d4cceSanish *h++ = pci_config_rd8(hdlp, d++);
1529649d4cceSanish else
1530649d4cceSanish for (; repcount; repcount--)
1531649d4cceSanish *h++ = pci_config_rd8(hdlp, d);
1532649d4cceSanish }
1533649d4cceSanish
1534649d4cceSanish uint16_t
pci_config_rd16(ddi_acc_impl_t * hdlp,uint16_t * addr)1535649d4cceSanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1536649d4cceSanish {
1537649d4cceSanish pci_acc_cfblk_t *cfp;
1538649d4cceSanish uint16_t rval;
1539649d4cceSanish int reg;
1540649d4cceSanish
1541649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0);
1542649d4cceSanish
1543649d4cceSanish reg = (int)(uintptr_t)addr;
1544649d4cceSanish
1545649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1546649d4cceSanish
1547649d4cceSanish rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1548649d4cceSanish reg);
1549649d4cceSanish
1550649d4cceSanish return (rval);
1551649d4cceSanish }
1552649d4cceSanish
1553649d4cceSanish void
pci_config_rep_rd16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)1554649d4cceSanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1555649d4cceSanish uint16_t *dev_addr, size_t repcount, uint_t flags)
1556649d4cceSanish {
1557649d4cceSanish uint16_t *h, *d;
1558649d4cceSanish
1559649d4cceSanish h = host_addr;
1560649d4cceSanish d = dev_addr;
1561649d4cceSanish
1562649d4cceSanish if (flags == DDI_DEV_AUTOINCR)
1563649d4cceSanish for (; repcount; repcount--)
1564649d4cceSanish *h++ = pci_config_rd16(hdlp, d++);
1565649d4cceSanish else
1566649d4cceSanish for (; repcount; repcount--)
1567649d4cceSanish *h++ = pci_config_rd16(hdlp, d);
1568649d4cceSanish }
1569649d4cceSanish
1570649d4cceSanish uint32_t
pci_config_rd32(ddi_acc_impl_t * hdlp,uint32_t * addr)1571649d4cceSanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1572649d4cceSanish {
1573649d4cceSanish pci_acc_cfblk_t *cfp;
1574649d4cceSanish uint32_t rval;
1575649d4cceSanish int reg;
1576649d4cceSanish
1577649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0);
1578649d4cceSanish
1579649d4cceSanish reg = (int)(uintptr_t)addr;
1580649d4cceSanish
1581649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1582649d4cceSanish
1583649d4cceSanish rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1584649d4cceSanish cfp->c_funcnum, reg);
1585649d4cceSanish
1586649d4cceSanish return (rval);
1587649d4cceSanish }
1588649d4cceSanish
1589649d4cceSanish void
pci_config_rep_rd32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)1590649d4cceSanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1591649d4cceSanish uint32_t *dev_addr, size_t repcount, uint_t flags)
1592649d4cceSanish {
1593649d4cceSanish uint32_t *h, *d;
1594649d4cceSanish
1595649d4cceSanish h = host_addr;
1596649d4cceSanish d = dev_addr;
1597649d4cceSanish
1598649d4cceSanish if (flags == DDI_DEV_AUTOINCR)
1599649d4cceSanish for (; repcount; repcount--)
1600649d4cceSanish *h++ = pci_config_rd32(hdlp, d++);
1601649d4cceSanish else
1602649d4cceSanish for (; repcount; repcount--)
1603649d4cceSanish *h++ = pci_config_rd32(hdlp, d);
1604649d4cceSanish }
1605649d4cceSanish
1606649d4cceSanish
1607649d4cceSanish void
pci_config_wr8(ddi_acc_impl_t * hdlp,uint8_t * addr,uint8_t value)1608649d4cceSanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1609649d4cceSanish {
1610649d4cceSanish pci_acc_cfblk_t *cfp;
1611649d4cceSanish int reg;
1612649d4cceSanish
1613649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0);
1614649d4cceSanish
1615649d4cceSanish reg = (int)(uintptr_t)addr;
1616649d4cceSanish
1617649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1618649d4cceSanish
1619649d4cceSanish (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1620649d4cceSanish cfp->c_funcnum, reg, value);
1621649d4cceSanish }
1622649d4cceSanish
1623649d4cceSanish void
pci_config_rep_wr8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)1624649d4cceSanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1625649d4cceSanish uint8_t *dev_addr, size_t repcount, uint_t flags)
1626649d4cceSanish {
1627649d4cceSanish uint8_t *h, *d;
1628649d4cceSanish
1629649d4cceSanish h = host_addr;
1630649d4cceSanish d = dev_addr;
1631649d4cceSanish
1632649d4cceSanish if (flags == DDI_DEV_AUTOINCR)
1633649d4cceSanish for (; repcount; repcount--)
1634649d4cceSanish pci_config_wr8(hdlp, d++, *h++);
1635649d4cceSanish else
1636649d4cceSanish for (; repcount; repcount--)
1637649d4cceSanish pci_config_wr8(hdlp, d, *h++);
1638649d4cceSanish }
1639649d4cceSanish
1640649d4cceSanish void
pci_config_wr16(ddi_acc_impl_t * hdlp,uint16_t * addr,uint16_t value)1641649d4cceSanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1642649d4cceSanish {
1643649d4cceSanish pci_acc_cfblk_t *cfp;
1644649d4cceSanish int reg;
1645649d4cceSanish
1646649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0);
1647649d4cceSanish
1648649d4cceSanish reg = (int)(uintptr_t)addr;
1649649d4cceSanish
1650649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1651649d4cceSanish
1652649d4cceSanish (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1653649d4cceSanish cfp->c_funcnum, reg, value);
1654649d4cceSanish }
1655649d4cceSanish
1656649d4cceSanish void
pci_config_rep_wr16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)1657649d4cceSanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1658649d4cceSanish uint16_t *dev_addr, size_t repcount, uint_t flags)
1659649d4cceSanish {
1660649d4cceSanish uint16_t *h, *d;
1661649d4cceSanish
1662649d4cceSanish h = host_addr;
1663649d4cceSanish d = dev_addr;
1664649d4cceSanish
1665649d4cceSanish if (flags == DDI_DEV_AUTOINCR)
1666649d4cceSanish for (; repcount; repcount--)
1667649d4cceSanish pci_config_wr16(hdlp, d++, *h++);
1668649d4cceSanish else
1669649d4cceSanish for (; repcount; repcount--)
1670649d4cceSanish pci_config_wr16(hdlp, d, *h++);
1671649d4cceSanish }
1672649d4cceSanish
1673649d4cceSanish void
pci_config_wr32(ddi_acc_impl_t * hdlp,uint32_t * addr,uint32_t value)1674649d4cceSanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1675649d4cceSanish {
1676649d4cceSanish pci_acc_cfblk_t *cfp;
1677649d4cceSanish int reg;
1678649d4cceSanish
1679649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0);
1680649d4cceSanish
1681649d4cceSanish reg = (int)(uintptr_t)addr;
1682649d4cceSanish
1683649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1684649d4cceSanish
1685649d4cceSanish (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1686649d4cceSanish cfp->c_funcnum, reg, value);
1687649d4cceSanish }
1688649d4cceSanish
1689649d4cceSanish void
pci_config_rep_wr32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)1690649d4cceSanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1691649d4cceSanish uint32_t *dev_addr, size_t repcount, uint_t flags)
1692649d4cceSanish {
1693649d4cceSanish uint32_t *h, *d;
1694649d4cceSanish
1695649d4cceSanish h = host_addr;
1696649d4cceSanish d = dev_addr;
1697649d4cceSanish
1698649d4cceSanish if (flags == DDI_DEV_AUTOINCR)
1699649d4cceSanish for (; repcount; repcount--)
1700649d4cceSanish pci_config_wr32(hdlp, d++, *h++);
1701649d4cceSanish else
1702649d4cceSanish for (; repcount; repcount--)
1703649d4cceSanish pci_config_wr32(hdlp, d, *h++);
1704649d4cceSanish }
1705649d4cceSanish
1706649d4cceSanish uint64_t
pci_config_rd64(ddi_acc_impl_t * hdlp,uint64_t * addr)1707649d4cceSanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1708649d4cceSanish {
1709649d4cceSanish uint32_t lw_val;
1710649d4cceSanish uint32_t hi_val;
1711649d4cceSanish uint32_t *dp;
1712649d4cceSanish uint64_t val;
1713649d4cceSanish
1714649d4cceSanish dp = (uint32_t *)addr;
1715649d4cceSanish lw_val = pci_config_rd32(hdlp, dp);
1716649d4cceSanish dp++;
1717649d4cceSanish hi_val = pci_config_rd32(hdlp, dp);
1718649d4cceSanish val = ((uint64_t)hi_val << 32) | lw_val;
1719649d4cceSanish return (val);
1720649d4cceSanish }
1721649d4cceSanish
1722649d4cceSanish void
pci_config_wr64(ddi_acc_impl_t * hdlp,uint64_t * addr,uint64_t value)1723649d4cceSanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1724649d4cceSanish {
1725649d4cceSanish uint32_t lw_val;
1726649d4cceSanish uint32_t hi_val;
1727649d4cceSanish uint32_t *dp;
1728649d4cceSanish
1729649d4cceSanish dp = (uint32_t *)addr;
1730649d4cceSanish lw_val = (uint32_t)(value & 0xffffffff);
1731649d4cceSanish hi_val = (uint32_t)(value >> 32);
1732649d4cceSanish pci_config_wr32(hdlp, dp, lw_val);
1733649d4cceSanish dp++;
1734649d4cceSanish pci_config_wr32(hdlp, dp, hi_val);
1735649d4cceSanish }
1736649d4cceSanish
1737649d4cceSanish void
pci_config_rep_rd64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)1738649d4cceSanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1739649d4cceSanish uint64_t *dev_addr, size_t repcount, uint_t flags)
1740649d4cceSanish {
1741649d4cceSanish if (flags == DDI_DEV_AUTOINCR) {
1742649d4cceSanish for (; repcount; repcount--)
1743649d4cceSanish *host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1744649d4cceSanish } else {
1745649d4cceSanish for (; repcount; repcount--)
1746649d4cceSanish *host_addr++ = pci_config_rd64(hdlp, dev_addr);
1747649d4cceSanish }
1748649d4cceSanish }
1749649d4cceSanish
1750649d4cceSanish void
pci_config_rep_wr64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)1751649d4cceSanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1752649d4cceSanish uint64_t *dev_addr, size_t repcount, uint_t flags)
1753649d4cceSanish {
1754649d4cceSanish if (flags == DDI_DEV_AUTOINCR) {
1755649d4cceSanish for (; repcount; repcount--)
1756649d4cceSanish pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1757649d4cceSanish } else {
1758649d4cceSanish for (; repcount; repcount--)
1759649d4cceSanish pci_config_wr64(hdlp, host_addr++, *dev_addr);
1760649d4cceSanish }
1761649d4cceSanish }
1762