summaryrefslogtreecommitdiff
path: root/usr/src/uts/i86pc/io/pci/pci_tools.c
diff options
context:
space:
mode:
authorschwartz <none@none>2007-06-06 13:05:49 -0700
committerschwartz <none@none>2007-06-06 13:05:49 -0700
commit2917a9c9c3eee6fcaedb239f5f68da01f4ed0da9 (patch)
tree3f14bba948390bf71a80d57812d56948c29c8bd6 /usr/src/uts/i86pc/io/pci/pci_tools.c
parentc4e3866948e749beb3671a51c589da2ba299dc03 (diff)
downloadillumos-gate-2917a9c9c3eee6fcaedb239f5f68da01f4ed0da9.tar.gz
PSARC/2007/301 PCItool extensions for handling groups of interrupt vectors
PSARC/2007/302 PSM_INTR_OPS extensions for handling groups of interrupt vectors 6458838 Once intrd performs reassignment, MSI interrupts stop coming 6564773 Cleanup pcitool versioning 6565502 apic_rebind could write IOAPIC for fixed interrupts
Diffstat (limited to 'usr/src/uts/i86pc/io/pci/pci_tools.c')
-rw-r--r--usr/src/uts/i86pc/io/pci/pci_tools.c117
1 files changed, 91 insertions, 26 deletions
diff --git a/usr/src/uts/i86pc/io/pci/pci_tools.c b/usr/src/uts/i86pc/io/pci/pci_tools.c
index 7e4c90c432..7d35c9724b 100644
--- a/usr/src/uts/i86pc/io/pci/pci_tools.c
+++ b/usr/src/uts/i86pc/io/pci/pci_tools.c
@@ -84,7 +84,7 @@ static int pcitool_mem_access(dev_info_t *dip, pcitool_reg_t *prg,
static uint64_t pcitool_map(uint64_t phys_addr, size_t size, size_t *num_pages);
static void pcitool_unmap(uint64_t virt_addr, size_t num_pages);
-/* Extern decalrations */
+/* Extern declarations */
extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
psm_intr_op_t, int *);
@@ -121,21 +121,6 @@ pcitool_uninit(dev_info_t *dip)
ddi_remove_minor_node(dip, PCI_MINOR_REG);
}
-
-/* Return the number of interrupts on a pci bus. */
-static int
-pcitool_intr_get_max_ino(uint32_t *arg, int mode)
-{
- uint32_t num_intr = APIC_MAX_VECTOR;
-
- if (ddi_copyout(&num_intr, arg, sizeof (uint32_t), mode) !=
- DDI_SUCCESS)
- return (EFAULT);
- else
- return (SUCCESS);
-}
-
-
/*ARGSUSED*/
static int
pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
@@ -144,12 +129,31 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
pcitool_intr_set_t iset;
uint32_t old_cpu;
int ret, result;
+ size_t copyinout_size;
int rval = SUCCESS;
- if (ddi_copyin(arg, &iset, sizeof (pcitool_intr_set_t), mode) !=
- DDI_SUCCESS)
+ /* Version 1 of pcitool_intr_set_t doesn't have flags. */
+ copyinout_size = (size_t)&iset.flags - (size_t)&iset;
+
+ if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS)
return (EFAULT);
+ switch (iset.user_version) {
+ case PCITOOL_V1:
+ break;
+
+ case PCITOOL_V2:
+ copyinout_size = sizeof (pcitool_intr_set_t);
+ if (ddi_copyin(arg, &iset, copyinout_size, mode) != DDI_SUCCESS)
+ return (EFAULT);
+ break;
+
+ default:
+ iset.status = PCITOOL_OUT_OF_RANGE;
+ rval = ENOTSUP;
+ goto done_set_intr;
+ }
+
if (iset.ino > APIC_MAX_VECTOR) {
rval = EINVAL;
iset.status = PCITOOL_INVALID_INO;
@@ -164,6 +168,7 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
goto done_set_intr;
}
+
old_cpu &= ~PSMGI_CPU_USER_BOUND;
/*
@@ -172,9 +177,20 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
*/
info_hdl.ih_vector = iset.ino;
info_hdl.ih_private = (void *)(uintptr_t)iset.cpu_id;
- ret = (*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_SET_CPU, &result);
+ if (pcitool_debug)
+ prom_printf("user version:%d, flags:0x%x\n",
+ iset.user_version, iset.flags);
+
+ result = ENOTSUP;
+ if ((iset.user_version >= PCITOOL_V2) &&
+ (iset.flags & PCITOOL_INTR_SET_FLAG_GROUP)) {
+ ret = (*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_GRP_SET_CPU,
+ &result);
+ } else {
+ ret = (*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_SET_CPU,
+ &result);
+ }
- iset.drvr_version = PCITOOL_DRVR_VERSION;
if (ret != PSM_SUCCESS) {
switch (result) {
case EIO: /* Error making the change */
@@ -189,6 +205,10 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
rval = EINVAL;
iset.status = PCITOOL_INVALID_CPUID;
break;
+ case ENOTSUP: /* Requested PSM intr ops missing */
+ rval = ENOTSUP;
+ iset.status = PCITOOL_IO_ERROR;
+ break;
}
}
@@ -196,8 +216,8 @@ pcitool_set_intr(dev_info_t *dip, void *arg, int mode)
iset.cpu_id = old_cpu;
done_set_intr:
- if (ddi_copyout(&iset, arg, sizeof (pcitool_intr_set_t), mode) !=
- DDI_SUCCESS)
+ iset.drvr_version = PCITOOL_VERSION;
+ if (ddi_copyout(&iset, arg, copyinout_size, mode) != DDI_SUCCESS)
rval = EFAULT;
return (rval);
}
@@ -337,7 +357,7 @@ done_get_intr:
ndi_devi_exit(dip, circ);
}
- iget->drvr_version = PCITOOL_DRVR_VERSION;
+ iget->drvr_version = PCITOOL_VERSION;
copyout_rval = ddi_copyout(iget, arg,
PCITOOL_IGET_SIZE(num_devs_ret), mode);
@@ -350,6 +370,50 @@ done_get_intr:
return (rval);
}
+/*ARGSUSED*/
+static int
+pcitool_intr_info(dev_info_t *dip, void *arg, int mode)
+{
+ pcitool_intr_info_t intr_info;
+ ddi_intr_handle_impl_t info_hdl;
+ int rval = SUCCESS;
+
+ /* If we need user_version, and to ret same user version as passed in */
+ if (ddi_copyin(arg, &intr_info, sizeof (pcitool_intr_info_t), mode) !=
+ DDI_SUCCESS) {
+ if (pcitool_debug)
+ prom_printf("Error reading arguments\n");
+ return (EFAULT);
+ }
+
+ /* For UPPC systems, psm_intr_ops has no entry for APIC_TYPE. */
+ if ((rval = (*psm_intr_ops)(NULL, &info_hdl,
+ PSM_INTR_OP_APIC_TYPE, NULL)) != PSM_SUCCESS) {
+ intr_info.ctlr_type = PCITOOL_CTLR_TYPE_UPPC;
+ intr_info.ctlr_version = 0;
+
+ } else {
+ intr_info.ctlr_version = (uint32_t)info_hdl.ih_ver;
+ if (strcmp((char *)info_hdl.ih_private,
+ APIC_PCPLUSMP_NAME) == 0)
+ intr_info.ctlr_type = PCITOOL_CTLR_TYPE_PCPLUSMP;
+ else
+ intr_info.ctlr_type = PCITOOL_CTLR_TYPE_UNKNOWN;
+ }
+
+ intr_info.num_intr = APIC_MAX_VECTOR;
+ intr_info.drvr_version = PCITOOL_VERSION;
+ if (ddi_copyout(&intr_info, arg, sizeof (pcitool_intr_info_t), mode) !=
+ DDI_SUCCESS) {
+ if (pcitool_debug)
+ prom_printf("Error returning arguments.\n");
+ rval = EFAULT;
+ }
+
+ return (rval);
+}
+
+
/*
* Main function for handling interrupt CPU binding requests and queries.
@@ -372,8 +436,8 @@ pcitool_intr_admn(dev_info_t *dip, void *arg, int cmd, int mode)
rval = pcitool_get_intr(dip, arg, mode);
break;
- case PCITOOL_DEVICE_NUM_INTR:
- rval = pcitool_intr_get_max_ino(arg, mode);
+ case PCITOOL_SYSTEM_INTR_INFO:
+ rval = pcitool_intr_info(dip, arg, mode);
break;
default:
@@ -571,7 +635,7 @@ pcitool_io_access(dev_info_t *dip, pcitool_reg_t *prg, boolean_t write_flag)
no_trap();
if (pcitool_debug)
prom_printf(
- "pcitool_mem_access: on_trap caught an error...\n");
+ "pcitool_io_access: on_trap caught an error...\n");
prg->status = PCITOOL_INVALID_ADDRESS;
return (EFAULT);
}
@@ -1075,6 +1139,7 @@ pcitool_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode)
pcitool_unmap(virt_addr, num_virt_pages);
}
done_reg:
+ prg.drvr_version = PCITOOL_VERSION;
if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t), mode) !=
DDI_SUCCESS) {
if (pcitool_debug)