summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/mdb/sparc/modules/intr/intr.c74
-rw-r--r--usr/src/uts/common/io/bge/bge_chip.c37
-rw-r--r--usr/src/uts/common/io/bge/bge_main.c245
-rw-r--r--usr/src/uts/common/io/pci_intr_lib.c275
-rw-r--r--usr/src/uts/common/io/usb/hcd/ehci/ehci.c16
-rw-r--r--usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c291
-rw-r--r--usr/src/uts/common/io/usb/hcd/openhci/ohci.c284
-rw-r--r--usr/src/uts/common/io/usb/hcd/uhci/uhci.c338
-rw-r--r--usr/src/uts/common/os/ddi_intr.c8
-rw-r--r--usr/src/uts/common/sys/bge_impl.h6
-rw-r--r--usr/src/uts/common/sys/ddi_intr_impl.h8
-rw-r--r--usr/src/uts/common/sys/pci.h6
-rw-r--r--usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h8
-rw-r--r--usr/src/uts/common/sys/usb/hcd/openhci/ohcid.h3
-rw-r--r--usr/src/uts/common/sys/usb/hcd/uhci/uhcid.h4
-rw-r--r--usr/src/uts/i86pc/io/pciex/pcie_pci.c2
-rw-r--r--usr/src/uts/sun4/io/px/px.c13
-rw-r--r--usr/src/uts/sun4/io/px/px_intr.c47
-rw-r--r--usr/src/uts/sun4/io/px/px_pci.c14
-rw-r--r--usr/src/uts/sun4/io/px/px_pec.c33
-rw-r--r--usr/src/uts/sun4u/io/px/px_lib4u.c4
-rw-r--r--usr/src/uts/sun4u/io/sysiosbus.c6
-rw-r--r--usr/src/uts/sun4u/sys/sysiosbus.h1
-rw-r--r--usr/src/uts/sun4v/io/px/px_lib4v.c22
24 files changed, 1115 insertions, 630 deletions
diff --git a/usr/src/cmd/mdb/sparc/modules/intr/intr.c b/usr/src/cmd/mdb/sparc/modules/intr/intr.c
index 25439b1249..c37cf082b5 100644
--- a/usr/src/cmd/mdb/sparc/modules/intr/intr.c
+++ b/usr/src/cmd/mdb/sparc/modules/intr/intr.c
@@ -38,7 +38,6 @@ static int intr_px_walk_step(mdb_walk_state_t *);
static void intr_pci_print_items(mdb_walk_state_t *);
static void intr_px_print_items(mdb_walk_state_t *);
static char *intr_get_intr_type(msiq_rec_type_t);
-static void intr_print_line(int);
static void intr_print_banner(void);
typedef struct intr_info {
@@ -108,6 +107,8 @@ intr_pci_walk_step(mdb_walk_state_t *wsp)
/* Figure out how many items are here */
start_addr = (uintptr_t)pci_per_p;
+ intr_print_banner();
+
while (mdb_vread(&pci_per_p, sizeof (uintptr_t),
(uintptr_t)start_addr) != -1) {
/* Read until nothing is left */
@@ -143,6 +144,8 @@ intr_px_walk_step(mdb_walk_state_t *wsp)
/* Figure out how many items are here */
start_addr = (uintptr_t)px_state_p;
+ intr_print_banner();
+
while (mdb_vread(&px_state_p, sizeof (uintptr_t),
(uintptr_t)start_addr) != -1) {
/* Read until nothing is left */
@@ -187,10 +190,6 @@ intr_pci_print_items(mdb_walk_state_t *wsp)
return;
}
- intr_print_line(77);
- intr_print_banner();
- intr_print_line(77);
-
do {
if (mdb_vread(&ih, sizeof (ih_t),
(uintptr_t)list.ino_ih_start) == -1) {
@@ -246,8 +245,6 @@ intr_pci_print_items(mdb_walk_state_t *wsp)
} while (mdb_vread(&list, sizeof (ib_ino_info_t),
(uintptr_t)list.ino_next) != -1);
-
- intr_print_line(77);
}
static void
@@ -276,10 +273,6 @@ intr_px_print_items(mdb_walk_state_t *wsp)
return;
}
- intr_print_line(77);
- intr_print_banner();
- intr_print_line(77);
-
do {
if (mdb_vread(&px_ih, sizeof (px_ih_t),
(uintptr_t)px_list.ino_ih_start) == -1) {
@@ -335,8 +328,6 @@ intr_px_print_items(mdb_walk_state_t *wsp)
} while (mdb_vread(&px_list, sizeof (px_ib_ino_info_t),
(uintptr_t)px_list.ino_next) != -1);
-
- intr_print_line(77);
}
static char *
@@ -355,33 +346,19 @@ intr_get_intr_type(msiq_rec_type_t rec_type)
}
static void
-intr_print_line(int cnt)
-{
- int x;
-
- if (!detailed) {
- mdb_printf("+");
- for (x = 0; x < cnt; x++) {
- mdb_printf("-");
- }
- mdb_printf("+\n");
- }
-}
-
-static void
intr_print_banner(void)
{
if (!detailed) {
- mdb_printf("| Device\t"
- "| Shard\t"
- "| Type\t"
- "| MSG #\t"
- "| State "
- "| INO\t"
- "| Mondo\t"
- "| Pil\t"
- "| CPU "
- "|\n");
+ mdb_printf("\n%<u>\tDevice\t"
+ " Shared\t"
+ " Type\t"
+ " MSG #\t"
+ " State\t"
+ " INO\t"
+ " Mondo\t"
+ " Pil\t"
+ " CPU %</u>"
+ "\n");
}
}
@@ -389,25 +366,22 @@ static void
intr_print_elements(intr_info_t info)
{
if (!detailed) {
- mdb_printf("| %11s#%d\t", info.driver_name, info.instance);
- mdb_printf("| %s\t",
+ mdb_printf(" %11s#%d\t", info.driver_name, info.instance);
+ mdb_printf(" %5s\t",
info.shared ? "yes" : "no");
- mdb_printf("| %s\t", intr_get_intr_type(info.intr_type));
+ mdb_printf(" %s\t", intr_get_intr_type(info.intr_type));
if (strcmp("Fixed", intr_get_intr_type(info.intr_type)) == 0) {
- mdb_printf("| --- \t");
+ mdb_printf(" --- \t");
} else {
- mdb_printf("| %4d\t", info.num);
+ mdb_printf(" %4d\t", info.num);
}
- mdb_printf("| %2s\t",
+ mdb_printf(" %2s\t",
info.intr_state ? "enbl" : "disbl");
- mdb_printf("| 0x%x\t", info.ino_ino);
- mdb_printf("| 0x%x", info.mondo);
- if (!(info.mondo & 0xF000)) { /* Don't overrun table width */
- mdb_printf("\t");
- }
- mdb_printf("| %4d\t", info.pil);
- mdb_printf("| %3d |\n", info.cpuid);
+ mdb_printf(" 0x%x\t", info.ino_ino);
+ mdb_printf(" 0x%x\t", info.mondo);
+ mdb_printf(" %4d\t", info.pil);
+ mdb_printf(" %3d \n", info.cpuid);
} else {
mdb_printf("\n-------------------------------------------\n");
mdb_printf("Device:\t\t%s\n", info.driver_name);
diff --git a/usr/src/uts/common/io/bge/bge_chip.c b/usr/src/uts/common/io/bge/bge_chip.c
index dead764834..bcc266b927 100644
--- a/usr/src/uts/common/io/bge/bge_chip.c
+++ b/usr/src/uts/common/io/bge/bge_chip.c
@@ -38,6 +38,16 @@
#define BGE_IND_IO32 0 /* indirect access code */
#define BGE_SEE_IO32 1 /* SEEPROM access code */
#define BGE_FLASH_IO32 1 /* FLASH access code */
+
+/*
+ * BGE MSI tunable:
+ *
+ * By default MSI is enabled on all supported platforms but it is disabled
+ * for some Broadcom chips due to known MSI hardware issues. Currently MSI
+ * is enabled only for 5714C A2, 5715C A2, 5721, and 5751 broadcom chips.
+ */
+boolean_t bge_enable_msi = B_TRUE;
+
/*
* Property names
*/
@@ -499,11 +509,15 @@ bge_chip_cfg_init(bge_t *bgep, chip_id_t *cidp, boolean_t enable_dma)
mhcr = MHCR_ENABLE_INDIRECT_ACCESS |
MHCR_ENABLE_TAGGED_STATUS_MODE |
MHCR_MASK_INTERRUPT_MODE |
- MHCR_MASK_PCI_INT_OUTPUT |
MHCR_CLEAR_INTERRUPT_INTA;
+
+ if (bgep->intr_type == DDI_INTR_TYPE_FIXED)
+ mhcr |= MHCR_MASK_PCI_INT_OUTPUT;
+
#ifdef _BIG_ENDIAN
mhcr |= MHCR_ENABLE_ENDIAN_WORD_SWAP | MHCR_ENABLE_ENDIAN_BYTE_SWAP;
#endif /* _BIG_ENDIAN */
+
pci_config_put32(handle, PCI_CONF_BGE_MHCR, mhcr);
/*
@@ -1857,7 +1871,9 @@ bge_chip_id_init(bge_t *bgep)
cidp->rx_rings = BGE_RECV_RINGS_DEFAULT;
if (cidp->tx_rings == 0 || cidp->tx_rings > BGE_SEND_RINGS_MAX)
cidp->tx_rings = BGE_SEND_RINGS_DEFAULT;
- cidp->bge_msi_enabled = B_FALSE;
+
+ cidp->msi_enabled = B_FALSE;
+
switch (cidp->device) {
case DEVICE_ID_5700:
case DEVICE_ID_5700x:
@@ -1953,6 +1969,9 @@ bge_chip_id_init(bge_t *bgep)
break;
case DEVICE_ID_5714C:
+ if (cidp->revision >= 0xa2)
+ cidp->msi_enabled = bge_enable_msi;
+ /* FALLTHRU */
case DEVICE_ID_5714S:
cidp->chip_label = 5714;
cidp->mbuf_base = bge_mbuf_pool_base_5721;
@@ -1972,6 +1991,8 @@ bge_chip_id_init(bge_t *bgep)
cidp->bge_dma_rwctrl = bge_dma_rwctrl_5714;
cidp->bge_mlcr_default = bge_mlcr_default_5714;
cidp->pci_type = BGE_PCI_E;
+ if (cidp->revision >= 0xa2)
+ cidp->msi_enabled = bge_enable_msi;
dev_ok = B_TRUE;
break;
@@ -1982,6 +2003,7 @@ bge_chip_id_init(bge_t *bgep)
cidp->recv_slots = BGE_RECV_SLOTS_5721;
cidp->pci_type = BGE_PCI_E;
cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721;
+ cidp->msi_enabled = bge_enable_msi;
dev_ok = B_TRUE;
break;
@@ -1993,6 +2015,7 @@ bge_chip_id_init(bge_t *bgep)
cidp->recv_slots = BGE_RECV_SLOTS_5721;
cidp->bge_dma_rwctrl = bge_dma_rwctrl_5721;
cidp->pci_type = BGE_PCI_E;
+ cidp->msi_enabled = bge_enable_msi;
dev_ok = B_TRUE;
break;
@@ -3275,19 +3298,19 @@ bge_wake_factotum(bge_t *bgep)
/*
* bge_intr() -- handle chip interrupts
*/
-uint_t bge_intr(caddr_t arg);
+uint_t bge_intr(caddr_t arg1, caddr_t arg2);
#pragma no_inline(bge_intr)
uint_t
-bge_intr(caddr_t arg)
+bge_intr(caddr_t arg1, caddr_t arg2)
{
- bge_t *bgep = (bge_t *)arg; /* private device info */
+ bge_t *bgep = (bge_t *)arg1; /* private device info */
bge_status_t *bsp;
uint64_t flags;
uint32_t mlcr;
uint_t result;
- BGE_TRACE(("bge_intr($%p)", arg));
+ BGE_TRACE(("bge_intr($%p) ($%p)", arg1, arg2));
/*
* GLD v2 checks that s/w setup is complete before passing
@@ -3309,7 +3332,7 @@ bge_intr(caddr_t arg)
if (bgep->intr_type == DDI_INTR_TYPE_FIXED)
mlcr = bge_reg_get32(bgep, MISC_LOCAL_CONTROL_REG);
- BGE_DEBUG(("bge_intr($%p) mlcr 0x%08x", arg, mlcr));
+ BGE_DEBUG(("bge_intr($%p) ($%p) mlcr 0x%08x", arg1, arg2, mlcr));
if ((mlcr & MLCR_INTA_STATE) == 0) {
/*
diff --git a/usr/src/uts/common/io/bge/bge_main.c b/usr/src/uts/common/io/bge/bge_main.c
index 994710919b..ebe6f5bba9 100644
--- a/usr/src/uts/common/io/bge/bge_main.c
+++ b/usr/src/uts/common/io/bge/bge_main.c
@@ -49,8 +49,7 @@ static char subven_propname[] = "subsystem-vendor-id";
static char rxrings_propname[] = "bge-rx-rings";
static char txrings_propname[] = "bge-tx-rings";
-static int bge_add_legacy_intrs(bge_t *);
-static int bge_add_msi_intrs(bge_t *);
+static int bge_add_intrs(bge_t *, int);
static void bge_rem_intrs(bge_t *);
/*
@@ -247,8 +246,8 @@ bge_reinit_rings(bge_t *bgep)
static void
bge_reset(bge_t *bgep)
{
- uint64_t ring;
- int x;
+ uint64_t ring;
+ int i;
BGE_TRACE(("bge_reset($%p)", (void *)bgep));
@@ -274,8 +273,8 @@ bge_reset(bge_t *bgep)
(void) ddi_intr_block_disable(bgep->htable,
bgep->intr_cnt);
} else {
- for (x = 0; x < bgep->intr_cnt; x++) {
- (void) ddi_intr_disable(bgep->htable[x]);
+ for (i = 0; i < bgep->intr_cnt; i++) {
+ (void) ddi_intr_disable(bgep->htable[i]);
}
}
}
@@ -318,7 +317,7 @@ bge_stop(bge_t *bgep)
static void
bge_start(bge_t *bgep, boolean_t reset_phys)
{
- int x;
+ int i;
BGE_TRACE(("bge_start($%p, %d)", (void *)bgep, reset_phys));
@@ -340,8 +339,8 @@ bge_start(bge_t *bgep, boolean_t reset_phys)
bgep->intr_cnt);
} else {
/* Call ddi_intr_enable for MSI non block enable */
- for (x = 0; x < bgep->intr_cnt; x++) {
- (void) ddi_intr_enable(bgep->htable[x]);
+ for (i = 0; i < bgep->intr_cnt; i++) {
+ (void) ddi_intr_enable(bgep->htable[i]);
}
}
}
@@ -1084,7 +1083,7 @@ bge_init_send_ring(bge_t *bgep, uint64_t ring)
srp->cons_index_p = SEND_INDEX_P(bsp, ring);
srp->chip_mbx_reg = SEND_RING_HOST_INDEX_REG(ring);
rw_init(srp->tx_lock, NULL, RW_DRIVER,
- (void *)(uintptr_t)bgep->intr_pri);
+ DDI_INTR_PRI(bgep->intr_pri));
mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER,
DDI_INTR_PRI(bgep->intr_pri));
@@ -1688,7 +1687,7 @@ bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
int err;
mac_info_t *mip;
int intr_types;
- int x;
+ int i;
instance = ddi_get_instance(devinfo);
@@ -1848,28 +1847,30 @@ bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
bge_log(bgep, "ddi_intr_get_supported_types() returned: %x",
intr_types);
- if ((intr_types & DDI_INTR_TYPE_MSI) && bgep->chipid.bge_msi_enabled) {
- if (bge_add_msi_intrs(bgep) != DDI_SUCCESS) {
+ if ((intr_types & DDI_INTR_TYPE_MSI) && bgep->chipid.msi_enabled) {
+ if (bge_add_intrs(bgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
bge_error(bgep, "MSI registration failed, "
- "trying LEGACY interrupt type\n");
+ "trying FIXED interrupt type\n");
} else {
+ bge_log(bgep, "Using MSI interrupt type\n");
+
bgep->intr_type = DDI_INTR_TYPE_MSI;
bgep->progress |= PROGRESS_INTR;
}
- bge_log(bgep, "Using MSI interrupt type\n");
}
if (!(bgep->progress & PROGRESS_INTR) &&
(intr_types & DDI_INTR_TYPE_FIXED)) {
- if (bge_add_legacy_intrs(bgep) != DDI_SUCCESS) {
- bge_error(bgep, "Legacy interrupt "
+ if (bge_add_intrs(bgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
+ bge_error(bgep, "FIXED interrupt "
"registration failed\n");
goto attach_fail;
}
+ bge_log(bgep, "Using FIXED interrupt type\n");
+
bgep->intr_type = DDI_INTR_TYPE_FIXED;
bgep->progress |= PROGRESS_INTR;
- bge_log(bgep, "Using Legacy interrupt type\n");
}
if (!(bgep->progress & PROGRESS_INTR)) {
@@ -1889,12 +1890,12 @@ bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
* Now that mutex locks are initialized, enable interrupts.
*/
if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) {
- /* Call ddi_intr_block_enable() for MSI */
+ /* Call ddi_intr_block_enable() for MSI interrupts */
(void) ddi_intr_block_enable(bgep->htable, bgep->intr_cnt);
} else {
- /* Call ddi_intr_enable() for Legacy/MSI non block enable */
- for (x = 0; x < bgep->intr_cnt; x++) {
- (void) ddi_intr_enable(bgep->htable[x]);
+ /* Call ddi_intr_enable for MSI or FIXED interrupts */
+ for (i = 0; i < bgep->intr_cnt; i++) {
+ (void) ddi_intr_enable(bgep->htable[i]);
}
}
@@ -2120,113 +2121,33 @@ _fini(void)
/*
- * bge_add_legacy_intrs() handles INTx and legacy interrupts
- */
-static int
-bge_add_legacy_intrs(bge_t *bgep)
-{
- dev_info_t *devinfo = bgep->devinfo;
- int actual, count = 0;
- int x, y, rc, inum = 0;
-
- bge_log(bgep, "bge_add_legacy_intrs\n");
-
- /* get number of interrupts */
- rc = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_FIXED, &count);
- if ((rc != DDI_SUCCESS) || (count == 0)) {
- bge_error(bgep, "ddi_intr_get_nintrs() failure, "
- "rc: %d, count: %d", rc, count);
-
- return (DDI_FAILURE);
- }
-
- /* Allocate an array of interrupt handles */
- bgep->intr_size = count * sizeof (ddi_intr_handle_t);
- bgep->htable = kmem_zalloc(bgep->intr_size, KM_SLEEP);
-
- /* call ddi_intr_alloc() */
- rc = ddi_intr_alloc(devinfo, bgep->htable, DDI_INTR_TYPE_FIXED, inum,
- count, &actual, DDI_INTR_ALLOC_STRICT);
-
- if ((rc != DDI_SUCCESS) || (actual == 0)) {
- bge_error(bgep, "ddi_intr_alloc() failed: %d\n", rc);
- kmem_free(bgep->htable, bgep->intr_size);
-
- return (DDI_FAILURE);
- }
-
- if (actual < count) {
- bge_log(bgep, "Requested: %d, Received: %d\n",
- count, actual);
-
- for (x = 0; x < actual; x++) {
- (void) ddi_intr_free(bgep->htable[x]);
- }
-
- kmem_free(bgep->htable, bgep->intr_size);
- return (DDI_FAILURE);
- }
-
- bgep->intr_cnt = actual;
-
- /* Get intr priority */
- if (ddi_intr_get_pri(bgep->htable[0], &bgep->intr_pri) !=
- DDI_SUCCESS) {
- bge_error(bgep, "ddi_intr_get_pri() failed\n");
-
- for (x = 0; x < actual; x++) {
- (void) ddi_intr_free(bgep->htable[x]);
- }
-
- kmem_free(bgep->htable, bgep->intr_size);
- return (DDI_FAILURE);
- }
-
- /* Call ddi_intr_add_handler() */
- for (x = 0; x < actual; x++) {
- if (ddi_intr_add_handler(bgep->htable[x],
- (ddi_intr_handler_t *)bge_intr,
- (caddr_t)bgep, NULL) != DDI_SUCCESS) {
- bge_error(bgep, "ddi_add_intr() failed\n");
-
- for (y = 0; y < actual; y++) {
- (void) ddi_intr_free(bgep->htable[y]);
- }
-
- kmem_free(bgep->htable, bgep->intr_size);
- return (DDI_FAILURE);
- }
- }
-
- return (DDI_SUCCESS);
-}
-
-/*
- * bge_add_msi_intrs() handles MSI interrupts
+ * bge_add_intrs:
+ *
+ * Register FIXED or MSI interrupts.
*/
static int
-bge_add_msi_intrs(bge_t *bgep)
+bge_add_intrs(bge_t *bgep, int intr_type)
{
- dev_info_t *devinfo = bgep->devinfo;
- int count, avail, actual;
- int x, y, rc, inum = 0;
+ dev_info_t *dip = bgep->devinfo;
+ int avail, actual, intr_size, count = 0;
+ int i, flag, ret;
- bge_log(bgep, "bge_add_msi_intrs\n");
+ bge_log(bgep, "bge_add_intrs: interrupt type 0x%x\n", intr_type);
- /* get number of interrupts */
- rc = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_MSI, &count);
- if ((rc != DDI_SUCCESS) || (count == 0)) {
- cmn_err(CE_WARN, "ddi_intr_get_nintrs() failure, rc: %d, "
- "count: %d", rc, count);
+ /* Get number of interrupts */
+ ret = ddi_intr_get_nintrs(dip, intr_type, &count);
+ if ((ret != DDI_SUCCESS) || (count == 0)) {
+ bge_error(bgep, "ddi_intr_get_nintrs() failure, ret: %d, "
+ "count: %d", ret, count);
return (DDI_FAILURE);
}
- /* get number of available interrupts */
- rc = ddi_intr_get_navail(devinfo, DDI_INTR_TYPE_MSI, &avail);
- if ((rc != DDI_SUCCESS) || (avail == 0)) {
+ /* Get number of available interrupts */
+ ret = ddi_intr_get_navail(dip, intr_type, &avail);
+ if ((ret != DDI_SUCCESS) || (avail == 0)) {
bge_error(bgep, "ddi_intr_get_navail() failure, "
- "rc: %d, avail: %d\n", rc, avail);
+ "ret: %d, avail: %d\n", ret, avail);
return (DDI_FAILURE);
}
@@ -2236,18 +2157,29 @@ bge_add_msi_intrs(bge_t *bgep)
count, avail);
}
+ /*
+ * BGE hardware generates only single MSI even though it claims
+ * to support multiple MSIs. So, hard code MSI count value to 1.
+ */
+ if (intr_type == DDI_INTR_TYPE_MSI) {
+ count = 1;
+ flag = DDI_INTR_ALLOC_STRICT;
+ } else {
+ flag = DDI_INTR_ALLOC_NORMAL;
+ }
+
/* Allocate an array of interrupt handles */
- bgep->intr_size = count * sizeof (ddi_intr_handle_t);
- bgep->htable = kmem_alloc(bgep->intr_size, KM_SLEEP);
+ intr_size = count * sizeof (ddi_intr_handle_t);
+ bgep->htable = kmem_alloc(intr_size, KM_SLEEP);
- /* call ddi_intr_alloc() */
- rc = ddi_intr_alloc(devinfo, bgep->htable, DDI_INTR_TYPE_MSI, inum,
- count, &actual, DDI_INTR_ALLOC_NORMAL);
+ /* Call ddi_intr_alloc() */
+ ret = ddi_intr_alloc(dip, bgep->htable, intr_type, 0,
+ count, &actual, flag);
- if ((rc != DDI_SUCCESS) || (actual == 0)) {
- bge_error(bgep, "ddi_intr_alloc() failed: %d\n", rc);
+ if ((ret != DDI_SUCCESS) || (actual == 0)) {
+ bge_error(bgep, "ddi_intr_alloc() failed %d\n", ret);
- kmem_free(bgep->htable, bgep->intr_size);
+ kmem_free(bgep->htable, intr_size);
return (DDI_FAILURE);
}
@@ -2260,46 +2192,61 @@ bge_add_msi_intrs(bge_t *bgep)
/*
* Get priority for first msi, assume remaining are all the same
*/
- if (ddi_intr_get_pri(bgep->htable[0], &bgep->intr_pri) !=
+ if ((ret = ddi_intr_get_pri(bgep->htable[0], &bgep->intr_pri)) !=
DDI_SUCCESS) {
- bge_error(bgep, "ddi_intr_get_pri() failed\n");
+ bge_error(bgep, "ddi_intr_get_pri() failed %d\n", ret);
/* Free already allocated intr */
- for (y = 0; y < actual; y++) {
- (void) ddi_intr_free(bgep->htable[y]);
+ for (i = 0; i < actual; i++) {
+ (void) ddi_intr_free(bgep->htable[i]);
}
- kmem_free(bgep->htable, bgep->intr_size);
-
+ kmem_free(bgep->htable, intr_size);
return (DDI_FAILURE);
}
/* Call ddi_intr_add_handler() */
- for (x = 0; x < actual; x++) {
- if (ddi_intr_add_handler(bgep->htable[x],
- (ddi_intr_handler_t *)bge_intr,
- (caddr_t)bgep, NULL) != DDI_SUCCESS) {
- bge_error(bgep, "ddi_intr_add_handler() failed\n");
+ for (i = 0; i < actual; i++) {
+ if ((ret = ddi_intr_add_handler(bgep->htable[i], bge_intr,
+ (caddr_t)bgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
+ bge_error(bgep, "ddi_intr_add_handler() "
+ "failed %d\n", ret);
/* Free already allocated intr */
- for (y = 0; y < actual; y++) {
- (void) ddi_intr_free(bgep->htable[y]);
+ for (i = 0; i < actual; i++) {
+ (void) ddi_intr_free(bgep->htable[i]);
}
- kmem_free(bgep->htable, bgep->intr_size);
+ kmem_free(bgep->htable, intr_size);
return (DDI_FAILURE);
}
}
- (void) ddi_intr_get_cap(bgep->htable[0], &bgep->intr_cap);
+ if ((ret = ddi_intr_get_cap(bgep->htable[0], &bgep->intr_cap))
+ != DDI_SUCCESS) {
+ bge_error(bgep, "ddi_intr_get_cap() failed %d\n", ret);
+
+ for (i = 0; i < actual; i++) {
+ (void) ddi_intr_remove_handler(bgep->htable[i]);
+ (void) ddi_intr_free(bgep->htable[i]);
+ }
+
+ kmem_free(bgep->htable, intr_size);
+ return (DDI_FAILURE);
+ }
return (DDI_SUCCESS);
}
+/*
+ * bge_rem_intrs:
+ *
+ * Unregister FIXED or MSI interrupts
+ */
static void
bge_rem_intrs(bge_t *bgep)
{
- int x;
+ int i;
bge_log(bgep, "bge_rem_intrs\n");
@@ -2308,16 +2255,16 @@ bge_rem_intrs(bge_t *bgep)
/* Call ddi_intr_block_disable() */
(void) ddi_intr_block_disable(bgep->htable, bgep->intr_cnt);
} else {
- for (x = 0; x < bgep->intr_cnt; x++) {
- (void) ddi_intr_disable(bgep->htable[x]);
+ for (i = 0; i < bgep->intr_cnt; i++) {
+ (void) ddi_intr_disable(bgep->htable[i]);
}
}
/* Call ddi_intr_remove_handler() */
- for (x = 0; x < bgep->intr_cnt; x++) {
- (void) ddi_intr_remove_handler(bgep->htable[x]);
- (void) ddi_intr_free(bgep->htable[x]);
+ for (i = 0; i < bgep->intr_cnt; i++) {
+ (void) ddi_intr_remove_handler(bgep->htable[i]);
+ (void) ddi_intr_free(bgep->htable[i]);
}
- kmem_free(bgep->htable, bgep->intr_size);
+ kmem_free(bgep->htable, bgep->intr_cnt * sizeof (ddi_intr_handle_t));
}
diff --git a/usr/src/uts/common/io/pci_intr_lib.c b/usr/src/uts/common/io/pci_intr_lib.c
index b204daad70..7ccbea7929 100644
--- a/usr/src/uts/common/io/pci_intr_lib.c
+++ b/usr/src/uts/common/io/pci_intr_lib.c
@@ -37,6 +37,14 @@
#include <sys/bitmap.h>
/*
+ * MSI-X BIR Index Table:
+ *
+ * BAR indicator register (BIR) to Base Address register.
+ */
+static uchar_t pci_msix_bir_index[8] = {0x10, 0x14, 0x18, 0x1c,
+ 0x20, 0x24, 0xff, 0xff};
+
+/*
* Library utility functions
*/
@@ -98,13 +106,13 @@ static int
pci_get_msi_ctrl(dev_info_t *dip, int type, ushort_t *msi_ctrl,
ushort_t *caps_ptr, ddi_acc_handle_t *cfg_hdle)
{
- ushort_t cap, cap_count;
+ ushort_t cap;
*msi_ctrl = *caps_ptr = 0;
if (pci_config_setup(dip, cfg_hdle) != DDI_SUCCESS) {
DDI_INTR_NEXDBG((CE_CONT, "pci_get_msi_ctrl: "
- "%s%d can't get config handle",
+ "%s%d can't get config handle\n",
ddi_driver_name(dip), ddi_get_instance(dip)));
return (DDI_FAILURE);
@@ -120,9 +128,8 @@ pci_get_msi_ctrl(dev_info_t *dip, int type, ushort_t *msi_ctrl,
}
*caps_ptr = pci_config_get8(*cfg_hdle, PCI_CONF_CAP_PTR);
- cap_count = PCI_CAP_MAX_PTR;
- while ((cap_count--) && (*caps_ptr >= PCI_CAP_PTR_OFF)) {
+ while (*caps_ptr && (*caps_ptr >= PCI_CAP_PTR_OFF)) {
*caps_ptr &= PCI_CAP_PTR_MASK;
cap = pci_config_get8(*cfg_hdle, *caps_ptr);
@@ -213,8 +220,9 @@ pci_msi_configure(dev_info_t *rdip, int type, int count, int inum,
ushort_t caps_ptr, msi_ctrl;
ddi_acc_handle_t cfg_hdle;
- DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: rdip = 0x%p\n",
- (void *)rdip));
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: rdip = 0x%p type 0x%x "
+ "count 0x%x inum 0x%x addr 0x%" PRIx64 " data 0x%" PRIx64 "\n",
+ (void *)rdip, type, count, inum, addr, data));
if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
&caps_ptr, &cfg_hdle) != DDI_SUCCESS)
@@ -226,36 +234,60 @@ pci_msi_configure(dev_info_t *rdip, int type, int count, int inum,
pci_config_put16(cfg_hdle,
caps_ptr + PCI_MSI_CTRL, msi_ctrl);
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_ctrl = %x\n",
+ pci_config_get16(cfg_hdle, caps_ptr + PCI_MSI_CTRL)));
+
/* Set the "data" and "addr" bits */
pci_config_put32(cfg_hdle,
caps_ptr + PCI_MSI_ADDR_OFFSET, addr);
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_addr = %x\n",
+ pci_config_get32(cfg_hdle, caps_ptr +
+ PCI_MSI_ADDR_OFFSET)));
+
if (msi_ctrl & PCI_MSI_64BIT_MASK) {
pci_config_put32(cfg_hdle,
- caps_ptr + PCI_MSI_ADDR_OFFSET + 4, 0);
+ caps_ptr + PCI_MSI_ADDR_OFFSET + 4, addr >> 32);
+
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: "
+ "upper 32bit msi_addr = %x\n", pci_config_get32(
+ cfg_hdle, caps_ptr + PCI_MSI_ADDR_OFFSET + 4)));
+
pci_config_put16(cfg_hdle,
caps_ptr + PCI_MSI_64BIT_DATA, data);
+
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: "
+ "msi_data = %x\n", pci_config_get16(cfg_hdle,
+ caps_ptr + PCI_MSI_64BIT_DATA)));
} else {
pci_config_put16(cfg_hdle,
caps_ptr + PCI_MSI_32BIT_DATA, data);
- }
-
- DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_ctrl = %x\n",
- pci_config_get16(cfg_hdle, caps_ptr + PCI_MSI_CTRL)));
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: "
+ "msi_data = %x\n", pci_config_get16(cfg_hdle,
+ caps_ptr + PCI_MSI_32BIT_DATA)));
+ }
} else if (type == DDI_INTR_TYPE_MSIX) {
uintptr_t off;
ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
/* Offset into the "inum"th entry in the MSI-X table */
off = (uintptr_t)msix_p->msix_tbl_addr +
- ((inum - 1) * PCI_MSIX_VECTOR_SIZE);
+ (inum * PCI_MSIX_VECTOR_SIZE);
/* Set the "data" and "addr" bits */
ddi_put32(msix_p->msix_tbl_hdl,
- (uint32_t *)((uchar_t *)off + PCI_MSIX_DATA_OFFSET), data);
+ (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), data);
- ddi_put64(msix_p->msix_tbl_hdl, (uint64_t *)off, addr);
+ ddi_put64(msix_p->msix_tbl_hdl,
+ (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), addr);
+
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: "
+ "msix_addr 0x%" PRIx64 " msix_data 0x%x\n",
+ ddi_get64(msix_p->msix_tbl_hdl,
+ (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET)),
+ ddi_get32(msix_p->msix_tbl_hdl,
+ (uint32_t *)(off + PCI_MSIX_DATA_OFFSET))));
}
pci_config_teardown(&cfg_hdle);
@@ -309,11 +341,11 @@ pci_msi_unconfigure(dev_info_t *rdip, int type, int inum)
/* Offset into the "inum"th entry in the MSI-X table */
off = (uintptr_t)msix_p->msix_tbl_addr +
- ((inum - 1) * PCI_MSIX_VECTOR_SIZE);
+ (inum * PCI_MSIX_VECTOR_SIZE);
/* Reset the "data" and "addr" bits */
ddi_put32(msix_p->msix_tbl_hdl,
- (uint32_t *)((uchar_t *)off + PCI_MSIX_DATA_OFFSET), 0);
+ (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), 0);
ddi_put64(msix_p->msix_tbl_hdl, (uint64_t *)off, 0);
}
@@ -364,7 +396,6 @@ int
pci_msi_enable_mode(dev_info_t *rdip, int type, int inum)
{
ushort_t caps_ptr, msi_ctrl;
- uint16_t cmd_reg;
ddi_acc_handle_t cfg_hdle;
DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable_mode: rdip = 0x%p, "
@@ -374,17 +405,6 @@ pci_msi_enable_mode(dev_info_t *rdip, int type, int inum)
&caps_ptr, &cfg_hdle) != DDI_SUCCESS)
return (DDI_FAILURE);
- /* Disable INTx simulation, if applicable */
- cmd_reg = pci_config_get16(cfg_hdle, PCI_CONF_COMM);
-
- /* This write succeeds only for devices > PCI2.3 */
- pci_config_put16(cfg_hdle, PCI_CONF_COMM,
- cmd_reg | PCI_COMM_INTX_DISABLE);
-
- DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable_mode: "
- "Before CmdReg = 0x%x, After CmdReg = 0x%x\n",
- cmd_reg, pci_config_get16(cfg_hdle, PCI_CONF_COMM)));
-
if (type == DDI_INTR_TYPE_MSI) {
if (msi_ctrl & PCI_MSI_ENABLE_BIT)
goto finished;
@@ -395,7 +415,6 @@ pci_msi_enable_mode(dev_info_t *rdip, int type, int inum)
} else if (type == DDI_INTR_TYPE_MSIX) {
uintptr_t off;
- uint32_t mask_bits;
ddi_intr_msix_t *msix_p;
if (msi_ctrl & PCI_MSIX_ENABLE_BIT)
@@ -408,17 +427,15 @@ pci_msi_enable_mode(dev_info_t *rdip, int type, int inum)
msix_p = i_ddi_get_msix(rdip);
/* Offset into the "inum"th entry in the MSI-X table */
- off = (uintptr_t)msix_p->msix_tbl_addr + ((inum - 1) *
+ off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
/* Clear the Mask bit */
- mask_bits = ddi_get32(msix_p->msix_tbl_hdl,
- (uint32_t *)((uchar_t *)off));
-
- mask_bits &= ~0;
+ ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x0);
- ddi_put32(msix_p->msix_tbl_hdl,
- (uint32_t *)((uchar_t *)off), mask_bits);
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable: "
+ "msix_vector_mask 0x%x\n",
+ ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off)));
}
finished:
@@ -466,12 +483,11 @@ pci_msi_disable_mode(dev_info_t *rdip, int type, int inum)
msix_p = i_ddi_get_msix(rdip);
/* Offset into the "inum"th entry in the MSI-X table */
- off = (uintptr_t)msix_p->msix_tbl_addr + ((inum - 1) *
+ off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
/* Set the Mask bit */
- ddi_put32(msix_p->msix_tbl_hdl,
- (uint32_t *)((uchar_t *)off), 0x1);
+ ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x1);
}
finished:
@@ -496,7 +512,7 @@ pci_msi_set_mask(dev_info_t *rdip, int type, int inum)
int ret = DDI_FAILURE;
ushort_t caps_ptr, msi_ctrl;
ddi_acc_handle_t cfg_hdle;
- uint_t mask_bits;
+ uint32_t mask_bits;
DDI_INTR_NEXDBG((CE_CONT, "pci_msi_set_mask: rdip = 0x%p, "
"type = 0x%x\n", (void *)rdip, type));
@@ -533,12 +549,11 @@ pci_msi_set_mask(dev_info_t *rdip, int type, int inum)
msix_p = i_ddi_get_msix(rdip);
/* Offset into the "inum"th entry in the MSI-X table */
- off = (uintptr_t)msix_p->msix_tbl_addr + ((inum - 1) *
+ off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
/* Set the Mask bit */
- ddi_put32(msix_p->msix_tbl_hdl,
- (uint32_t *)((uchar_t *)off), 0x1);
+ ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x1);
}
ret = DDI_SUCCESS;
@@ -561,7 +576,7 @@ pci_msi_clr_mask(dev_info_t *rdip, int type, int inum)
ddi_acc_handle_t cfg_hdle;
int offset;
int ret = DDI_FAILURE;
- uint_t mask_bits;
+ uint32_t mask_bits;
DDI_INTR_NEXDBG((CE_CONT, "pci_msi_clr_mask: rdip = 0x%p, "
"type = 0x%x\n", (void *)rdip, type));
@@ -596,17 +611,11 @@ pci_msi_clr_mask(dev_info_t *rdip, int type, int inum)
msix_p = i_ddi_get_msix(rdip);
/* Offset into the "inum"th entry in the MSI-X table */
- off = (uintptr_t)msix_p->msix_tbl_addr + ((inum - 1) *
+ off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
/* Clear the Mask bit */
- mask_bits = ddi_get32(msix_p->msix_tbl_hdl,
- (uint32_t *)((uchar_t *)off));
-
- mask_bits &= ~0;
-
- ddi_put32(msix_p->msix_tbl_hdl,
- (uint32_t *)((uchar_t *)off), mask_bits);
+ ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x0);
}
ret = DDI_SUCCESS;
@@ -660,11 +669,10 @@ pci_msi_get_pending(dev_info_t *rdip, int type, int inum, int *pendingp)
ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
/* Offset into the PBA array which has entry for "inum" */
- off = (uintptr_t)msix_p->msix_pba_addr + ((inum - 1) / 64);
+ off = (uintptr_t)msix_p->msix_pba_addr + (inum / 64);
/* Read the PBA array */
- pending_bits = ddi_get64(msix_p->msix_pba_hdl,
- (uint64_t *)((uchar_t *)off));
+ pending_bits = ddi_get64(msix_p->msix_pba_hdl, (uint64_t *)off);
*pendingp = pending_bits & ~(1 >> inum);
}
@@ -794,16 +802,19 @@ pci_msi_get_supported_type(dev_info_t *rdip, int *typesp)
ddi_intr_msix_t *
pci_msix_init(dev_info_t *rdip)
{
- uint_t rnumber;
+ uint_t rnumber, breg, nregs;
size_t msix_tbl_size;
size_t pba_tbl_size;
- ushort_t caps_ptr, msi_ctrl;
+ ushort_t caps_ptr, msix_ctrl;
ddi_intr_msix_t *msix_p;
ddi_acc_handle_t cfg_hdle;
+ pci_regspec_t *rp;
+ int reg_size, addr_space, offset, *regs_list;
+ int i, ret;
DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: rdip = %p\n", (void *)rdip));
- if (pci_get_msi_ctrl(rdip, DDI_INTR_TYPE_MSI, &msi_ctrl,
+ if (pci_get_msi_ctrl(rdip, DDI_INTR_TYPE_MSIX, &msix_ctrl,
&caps_ptr, &cfg_hdle) != DDI_SUCCESS)
return (NULL);
@@ -817,60 +828,128 @@ pci_msix_init(dev_info_t *rdip)
DDI_STRUCTURE_LE_ACC;
msix_p->msix_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
- /*
- * Map the entire MSI-X vector table
- */
+ /* Map the entire MSI-X vector table */
msix_p->msix_tbl_offset = pci_config_get32(cfg_hdle,
caps_ptr + PCI_MSIX_TBL_OFFSET);
- rnumber = msix_p->msix_tbl_offset & PCI_MSIX_TBL_BIR_MASK;
- msix_p->msix_tbl_offset &= ~rnumber; /* Clear BIR from the offset */
-
- msix_tbl_size = (msi_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1;
-
- if (ddi_regs_map_setup(rdip,
- rnumber,
- &msix_p->msix_tbl_addr,
- msix_p->msix_tbl_offset,
- msix_tbl_size,
- &msix_p->msix_dev_attr,
- &msix_p->msix_tbl_hdl) !=
- DDI_SUCCESS) {
- DDI_INTR_NEXDBG((CE_CONT, "pci_msix_initialize: MSI-X Table "
- "ddi_regs_map_setup failed\n"));
- kmem_free(msix_p, sizeof (ddi_intr_msix_t));
- pci_config_teardown(&cfg_hdle);
- return (NULL);
+
+ if ((breg = pci_msix_bir_index[msix_p->msix_tbl_offset &
+ PCI_MSIX_TBL_BIR_MASK]) == 0xff)
+ goto fail1;
+
+ msix_p->msix_tbl_offset = msix_p->msix_tbl_offset &
+ ~PCI_MSIX_TBL_BIR_MASK;
+ msix_tbl_size = ((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1) *
+ PCI_MSIX_VECTOR_SIZE;
+
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: MSI-X table offset 0x%x "
+ "breg 0x%x size 0x%lx\n", msix_p->msix_tbl_offset, breg,
+ msix_tbl_size));
+
+ if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
+ DDI_PROP_DONTPASS, "reg", (int **)&regs_list, &nregs))
+ != DDI_PROP_SUCCESS) {
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: "
+ "ddi_prop_lookup_int_array failed %d\n", ret));
+
+ goto fail1;
+ }
+
+ reg_size = sizeof (pci_regspec_t) / sizeof (int);
+
+ for (i = 1, rnumber = 0; i < nregs/reg_size; i++) {
+ rp = (pci_regspec_t *)&regs_list[i * reg_size];
+ addr_space = rp->pci_phys_hi & PCI_ADDR_MASK;
+ offset = PCI_REG_REG_G(rp->pci_phys_hi);
+
+ if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) ||
+ (addr_space == PCI_ADDR_MEM64))) {
+ rnumber = i;
+ break;
+ }
+ }
+
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: MSI-X rnum = %d\n", rnumber));
+
+ if (rnumber == 0) {
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: "
+ "no mtaching reg number for offset 0x%x\n", breg));
+
+ goto fail2;
+ }
+
+ if ((ret = ddi_regs_map_setup(rdip, rnumber,
+ (caddr_t *)&msix_p->msix_tbl_addr, msix_p->msix_tbl_offset,
+ msix_tbl_size, &msix_p->msix_dev_attr,
+ &msix_p->msix_tbl_hdl)) != DDI_SUCCESS) {
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: MSI-X Table "
+ "ddi_regs_map_setup failed %d\n", ret));
+
+ goto fail2;
}
/*
* Map in the MSI-X Pending Bit Array
*/
- if (msi_ctrl & PCI_MSIX_TBL_SIZE_MASK)
- pba_tbl_size = ((msi_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1)/64;
-
msix_p->msix_pba_offset = pci_config_get32(cfg_hdle,
caps_ptr + PCI_MSIX_PBA_OFFSET);
- rnumber = msix_p->msix_pba_offset & PCI_MSIX_PBA_BIR_MASK;
- msix_p->msix_pba_offset &= ~rnumber; /* Clear offset from BIR */
-
- if (ddi_regs_map_setup(rdip,
- rnumber,
- &msix_p->msix_pba_addr,
- msix_p->msix_pba_offset,
- pba_tbl_size,
- &msix_p->msix_dev_attr,
- &msix_p->msix_pba_hdl) != DDI_SUCCESS) {
- DDI_INTR_NEXDBG((CE_CONT, "pci_msix_initialize: PBA "
- "ddi_regs_map_setup failed\n"));
- ddi_regs_map_free(&msix_p->msix_tbl_hdl);
- kmem_free(msix_p, sizeof (ddi_intr_msix_t));
- pci_config_teardown(&cfg_hdle);
- return (NULL);
+
+ if ((breg = pci_msix_bir_index[msix_p->msix_pba_offset &
+ PCI_MSIX_PBA_BIR_MASK]) == 0xff)
+ goto fail3;
+
+ msix_p->msix_pba_offset = msix_p->msix_pba_offset &
+ ~PCI_MSIX_PBA_BIR_MASK;
+ pba_tbl_size = ((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1)/8;
+
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: PBA table offset 0x%x "
+ "breg 0x%x size 0x%lx\n", msix_p->msix_pba_offset, breg,
+ pba_tbl_size));
+
+ for (i = 1, rnumber = 0; i < nregs/reg_size; i++) {
+ rp = (pci_regspec_t *)&regs_list[i * reg_size];
+ addr_space = rp->pci_phys_hi & PCI_ADDR_MASK;
+ offset = PCI_REG_REG_G(rp->pci_phys_hi);
+
+ if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) ||
+ (addr_space == PCI_ADDR_MEM64))) {
+ ddi_prop_free(regs_list);
+ rnumber = i;
+ break;
+ }
+ }
+
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: PBA rnum = %d\n", rnumber));
+
+ if (rnumber == 0) {
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: "
+ "no mtaching reg number for offset 0x%x\n", breg));
+
+ goto fail3;
+ }
+
+ if ((ret = ddi_regs_map_setup(rdip, rnumber,
+ (caddr_t *)&msix_p->msix_pba_addr, msix_p->msix_pba_offset,
+ pba_tbl_size, &msix_p->msix_dev_attr,
+ &msix_p->msix_pba_hdl)) != DDI_SUCCESS) {
+ DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: PBA "
+ "ddi_regs_map_setup failed %d\n", ret));
+
+ goto fail3;
}
DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: msix_p = 0x%p DONE!!\n",
(void *)msix_p));
+ goto done;
+
+fail3:
+ ddi_regs_map_free(&msix_p->msix_tbl_hdl);
+fail2:
+ ddi_prop_free(regs_list);
+fail1:
+ kmem_free(msix_p, sizeof (ddi_intr_msix_t));
+ msix_p = NULL;
+done:
pci_config_teardown(&cfg_hdle);
return (msix_p);
}
diff --git a/usr/src/uts/common/io/usb/hcd/ehci/ehci.c b/usr/src/uts/common/io/usb/hcd/ehci/ehci.c
index 18e1f4e27c..6db17b59c8 100644
--- a/usr/src/uts/common/io/usb/hcd/ehci/ehci.c
+++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci.c
@@ -275,6 +275,14 @@ ehci_attach(dev_info_t *dip,
return (DDI_FAILURE);
}
+ /* Get the ehci chip vendor and device id */
+ ehcip->ehci_vendor_id = pci_config_get16(
+ ehcip->ehci_config_handle, PCI_CONF_VENID);
+ ehcip->ehci_device_id = pci_config_get16(
+ ehcip->ehci_config_handle, PCI_CONF_DEVID);
+ ehcip->ehci_rev_id = pci_config_get8(
+ ehcip->ehci_config_handle, PCI_CONF_REVID);
+
/* Register interrupts */
if (ehci_register_intrs_and_init_mutex(ehcip) != DDI_SUCCESS) {
(void) ehci_cleanup(ehcip);
@@ -282,8 +290,6 @@ ehci_attach(dev_info_t *dip,
return (DDI_FAILURE);
}
- ehcip->ehci_flags |= EHCI_INTR;
-
mutex_enter(&ehcip->ehci_int_mutex);
/* Initialize the controller */
@@ -563,13 +569,13 @@ ehci_ioctl(dev_t dev,
* EHCI (EHCI) interrupt handling routine.
*/
uint_t
-ehci_intr(caddr_t arg)
+ehci_intr(caddr_t arg1, caddr_t arg2)
{
uint_t intr;
- ehci_state_t *ehcip = (ehci_state_t *)arg;
+ ehci_state_t *ehcip = (ehci_state_t *)arg1;
USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
- "ehci_intr: Interrupt occurred");
+ "ehci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p", arg1, arg2);
/* Get the ehci global mutex */
mutex_enter(&ehcip->ehci_int_mutex);
diff --git a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c
index 33ff4ecefb..8aa42e4c45 100644
--- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c
+++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c
@@ -41,6 +41,14 @@
#include <sys/usb/hcd/ehci/ehci_isoch.h>
#include <sys/usb/hcd/ehci/ehci_xfer.h>
+/*
+ * EHCI MSI tunable:
+ *
+ * By default MSI is enabled on all supported platforms except for the
+ * EHCI controller of ULI1575 South bridge.
+ */
+boolean_t ehci_enable_msi = B_TRUE;
+
/* Pointer to the state structure */
extern void *ehci_statep;
@@ -128,6 +136,8 @@ void ehci_decode_ddi_dma_addr_bind_handle_result(
int ehci_map_regs(ehci_state_t *ehcip);
int ehci_register_intrs_and_init_mutex(
ehci_state_t *ehcip);
+static int ehci_add_intrs(ehci_state_t *ehcip,
+ int intr_type);
int ehci_init_ctlr(ehci_state_t *ehcip);
static int ehci_take_control(ehci_state_t *ehcip);
static int ehci_init_periodic_frame_lst_table(
@@ -138,6 +148,7 @@ usba_hcdi_ops_t *ehci_alloc_hcdi_ops(ehci_state_t *ehcip);
/* Host Controller Driver (HCD) deinitialization functions */
int ehci_cleanup(ehci_state_t *ehcip);
+static void ehci_rem_intrs(ehci_state_t *ehcip);
int ehci_cpr_suspend(ehci_state_t *ehcip);
int ehci_cpr_resume(ehci_state_t *ehcip);
@@ -641,7 +652,7 @@ ehci_map_regs(ehci_state_t *ehcip)
int
ehci_register_intrs_and_init_mutex(ehci_state_t *ehcip)
{
- int type, count = 0, actual, ret;
+ int intr_types;
#if defined(__x86)
uint8_t iline;
@@ -650,6 +661,18 @@ ehci_register_intrs_and_init_mutex(ehci_state_t *ehcip)
USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
"ehci_register_intrs_and_init_mutex:");
+ /*
+ * There is a known MSI hardware bug with the EHCI controller
+ * of ULI1575 southbridge. Hence MSI is disabled for this chip.
+ */
+ if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
+ (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) {
+ ehcip->ehci_msi_enabled = B_FALSE;
+ } else {
+ /* Set the MSI enable flag from the global EHCI MSI tunable */
+ ehcip->ehci_msi_enabled = ehci_enable_msi;
+ }
+
#if defined(__x86)
/*
* Make sure that the interrupt pin is connected to the
@@ -672,70 +695,165 @@ ehci_register_intrs_and_init_mutex(ehci_state_t *ehcip)
}
#endif /* __x86 */
- ret = ddi_intr_get_supported_types(ehcip->ehci_dip, &type);
-
- if ((ret != DDI_SUCCESS) || (!(type & DDI_INTR_TYPE_FIXED))) {
+ /* Get supported interrupt types */
+ if (ddi_intr_get_supported_types(ehcip->ehci_dip,
+ &intr_types) != DDI_SUCCESS) {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
"ehci_register_intrs_and_init_mutex: "
- "Fixed type interrupt is not supported");
+ "ddi_intr_get_supported_types failed");
return (DDI_FAILURE);
}
- ret = ddi_intr_get_nintrs(ehcip->ehci_dip, DDI_INTR_TYPE_FIXED, &count);
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_register_intrs_and_init_mutex: "
+ "supported interrupt types 0x%x", intr_types);
+
+ if ((intr_types & DDI_INTR_TYPE_MSI) && ehcip->ehci_msi_enabled) {
+ if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_MSI)
+ != DDI_SUCCESS) {
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_register_intrs_and_init_mutex: MSI "
+ "registration failed, trying FIXED interrupt \n");
+ } else {
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_register_intrs_and_init_mutex: "
+ "Using MSI interrupt type\n");
- /*
- * Fixed interrupts can only have one interrupt. Check to make
- * sure that number of supported interrupts and number of
- * available interrupts are both equal to 1.
- */
- if ((ret != DDI_SUCCESS) || (count != 1)) {
- USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ ehcip->ehci_intr_type = DDI_INTR_TYPE_MSI;
+ ehcip->ehci_flags |= EHCI_INTR;
+ }
+ }
+
+ if ((!(ehcip->ehci_flags & EHCI_INTR)) &&
+ (intr_types & DDI_INTR_TYPE_FIXED)) {
+ if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_FIXED)
+ != DDI_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_register_intrs_and_init_mutex: "
+ "FIXED interrupt registration failed\n");
+
+ return (DDI_FAILURE);
+ }
+
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
"ehci_register_intrs_and_init_mutex: "
- "no fixed interrupts");
+ "Using FIXED interrupt type\n");
+
+ ehcip->ehci_intr_type = DDI_INTR_TYPE_FIXED;
+ ehcip->ehci_flags |= EHCI_INTR;
+ }
+
+ /* Create prototype for advance on async schedule */
+ cv_init(&ehcip->ehci_async_schedule_advance_cv,
+ NULL, CV_DRIVER, NULL);
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * ehci_add_intrs:
+ *
+ * Register FIXED or MSI interrupts.
+ */
+static int
+ehci_add_intrs(ehci_state_t *ehcip,
+ int intr_type)
+{
+ int actual, avail, intr_size, count = 0;
+ int i, flag, ret;
+
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_add_intrs: interrupt type 0x%x", intr_type);
+
+ /* Get number of interrupts */
+ ret = ddi_intr_get_nintrs(ehcip->ehci_dip, intr_type, &count);
+ if ((ret != DDI_SUCCESS) || (count == 0)) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_add_intrs: ddi_intr_get_nintrs() failure, "
+ "ret: %d, count: %d", ret, count);
return (DDI_FAILURE);
}
- ehcip->ehci_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
+ /* Get number of available interrupts */
+ ret = ddi_intr_get_navail(ehcip->ehci_dip, intr_type, &avail);
+ if ((ret != DDI_SUCCESS) || (avail == 0)) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_add_intrs: ddi_intr_get_navail() failure, "
+ "ret: %d, count: %d", ret, count);
+
+ return (DDI_FAILURE);
+ }
+
+ if (avail < count) {
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_add_intrs: ehci_add_intrs: nintrs () "
+ "returned %d, navail returned %d\n", count, avail);
+ }
+
+ /* Allocate an array of interrupt handles */
+ intr_size = count * sizeof (ddi_intr_handle_t);
+ ehcip->ehci_htable = kmem_zalloc(intr_size, KM_SLEEP);
+
+ flag = (intr_type == DDI_INTR_TYPE_MSI) ?
+ DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
+
+ /* call ddi_intr_alloc() */
ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable,
- DDI_INTR_TYPE_FIXED, 0, count, &actual, 0);
+ intr_type, 0, count, &actual, flag);
- if ((ret != DDI_SUCCESS) || (actual != 1)) {
+ if ((ret != DDI_SUCCESS) || (actual == 0)) {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
- "ehci_register_intrs_and_init_mutex: "
- "ddi_intr_alloc() failed 0x%x", ret);
+ "ehci_add_intrs: ddi_intr_alloc() failed %d", ret);
+
+ kmem_free(ehcip->ehci_htable, intr_size);
+
+ return (DDI_FAILURE);
+ }
+
+ if (actual < count) {
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_add_intrs: Requested: %d, Received: %d\n",
+ count, actual);
+
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(ehcip->ehci_htable[i]);
- kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
+ kmem_free(ehcip->ehci_htable, intr_size);
return (DDI_FAILURE);
}
- /* Sanity check that count and avail are the same. */
- ASSERT(count == actual);
+ ehcip->ehci_intr_cnt = actual;
- if (ddi_intr_get_pri(ehcip->ehci_htable[0], &ehcip->ehci_intr_pri)) {
+ if ((ret = ddi_intr_get_pri(ehcip->ehci_htable[0],
+ &ehcip->ehci_intr_pri)) != DDI_SUCCESS) {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
- "ehci_register_intrs_and_init_mutex: "
- "ddi_intr_get_pri() failed");
+ "ehci_add_intrs: ddi_intr_get_pri() failed %d", ret);
+
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(ehcip->ehci_htable[i]);
- (void) ddi_intr_free(ehcip->ehci_htable[0]);
- kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
+ kmem_free(ehcip->ehci_htable, intr_size);
return (DDI_FAILURE);
}
- USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
- "Supported Interrupt priority = 0x%x", ehcip->ehci_intr_pri);
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_add_intrs: Supported Interrupt priority 0x%x",
+ ehcip->ehci_intr_pri);
/* Test for high level mutex */
if (ehcip->ehci_intr_pri >= ddi_intr_get_hilevel_pri()) {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
- "ehci_register_intrs_and_init_mutex: "
- "Hi level interrupt not supported");
+ "ehci_add_intrs: Hi level interrupt not supported");
- (void) ddi_intr_free(ehcip->ehci_htable[0]);
- kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(ehcip->ehci_htable[i]);
+
+ kmem_free(ehcip->ehci_htable, intr_size);
return (DDI_FAILURE);
}
@@ -744,36 +862,51 @@ ehci_register_intrs_and_init_mutex(ehci_state_t *ehcip)
mutex_init(&ehcip->ehci_int_mutex, NULL, MUTEX_DRIVER,
DDI_INTR_PRI(ehcip->ehci_intr_pri));
- if (ddi_intr_add_handler(ehcip->ehci_htable[0],
- (ddi_intr_handler_t *)ehci_intr, (caddr_t)ehcip, NULL) !=
- DDI_SUCCESS) {
- USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
- "ehci_register_intrs_and_init_mutex: "
- "ddi_intr_add_handler() failed");
+ /* Call ddi_intr_add_handler() */
+ for (i = 0; i < actual; i++) {
+ if ((ret = ddi_intr_add_handler(ehcip->ehci_htable[i],
+ ehci_intr, (caddr_t)ehcip,
+ (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_add_intrs:ddi_intr_add_handler() "
+ "failed %d", ret);
- mutex_destroy(&ehcip->ehci_int_mutex);
- (void) ddi_intr_free(ehcip->ehci_htable[0]);
- kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(ehcip->ehci_htable[i]);
- return (DDI_FAILURE);
+ mutex_destroy(&ehcip->ehci_int_mutex);
+ kmem_free(ehcip->ehci_htable, intr_size);
+
+ return (DDI_FAILURE);
+ }
}
- if (ddi_intr_enable(ehcip->ehci_htable[0]) != DDI_SUCCESS) {
+ if ((ret = ddi_intr_get_cap(ehcip->ehci_htable[0],
+ &ehcip->ehci_intr_cap)) != DDI_SUCCESS) {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
- "ehci_register_intrs_and_init_mutex: "
- "ddi_intr_enable() failed");
+ "ehci_add_intrs: ddi_intr_get_cap() failed %d", ret);
+
+ for (i = 0; i < actual; i++) {
+ (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]);
+ (void) ddi_intr_free(ehcip->ehci_htable[i]);
+ }
- (void) ddi_intr_remove_handler(ehcip->ehci_htable[0]);
mutex_destroy(&ehcip->ehci_int_mutex);
- (void) ddi_intr_free(ehcip->ehci_htable[0]);
- kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
+ kmem_free(ehcip->ehci_htable, intr_size);
return (DDI_FAILURE);
}
- /* Create prototype for advance on async schedule */
- cv_init(&ehcip->ehci_async_schedule_advance_cv,
- NULL, CV_DRIVER, NULL);
+ /* Enable all interrupts */
+ if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) {
+ /* Call ddi_intr_block_enable() for MSI interrupts */
+ (void) ddi_intr_block_enable(ehcip->ehci_htable,
+ ehcip->ehci_intr_cnt);
+ } else {
+ /* Call ddi_intr_enable for MSI or FIXED interrupts */
+ for (i = 0; i < ehcip->ehci_intr_cnt; i++)
+ (void) ddi_intr_enable(ehcip->ehci_htable[i]);
+ }
return (DDI_SUCCESS);
}
@@ -849,14 +982,6 @@ ehci_init_ctlr(ehci_state_t *ehcip)
if (ehcip->ehci_hc_soft_state == EHCI_CTLR_INIT_STATE) {
- /* Get the ehci chip vendor and device id */
- ehcip->ehci_vendor_id = pci_config_get16(
- ehcip->ehci_config_handle, PCI_CONF_VENID);
- ehcip->ehci_device_id = pci_config_get16(
- ehcip->ehci_config_handle, PCI_CONF_DEVID);
- ehcip->ehci_rev_id = pci_config_get8(
- ehcip->ehci_config_handle, PCI_CONF_REVID);
-
/* Initialize the Frame list base address area */
if (ehci_init_periodic_frame_lst_table(ehcip) != DDI_SUCCESS) {
@@ -1537,17 +1662,7 @@ ehci_cleanup(ehci_state_t *ehcip)
mutex_exit(&ehcip->ehci_int_mutex);
- /* disable interrupt */
- (void) ddi_intr_disable(ehcip->ehci_htable[0]);
-
- /* Remove interrupt handler */
- (void) ddi_intr_remove_handler(ehcip->ehci_htable[0]);
-
- /* free interrupt handle */
- (void) ddi_intr_free(ehcip->ehci_htable[0]);
-
- /* free memory */
- kmem_free(ehcip->ehci_htable, sizeof (ddi_intr_handle_t));
+ ehci_rem_intrs(ehcip);
}
/* Unmap the EHCI registers */
@@ -1689,6 +1804,40 @@ ehci_cleanup(ehci_state_t *ehcip)
/*
+ * ehci_rem_intrs:
+ *
+ * Unregister FIXED or MSI interrupts
+ */
+static void
+ehci_rem_intrs(ehci_state_t *ehcip)
+{
+ int i;
+
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
+ "ehci_rem_intrs: interrupt type 0x%x", ehcip->ehci_intr_type);
+
+ /* Disable all interrupts */
+ if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) {
+ (void) ddi_intr_block_disable(ehcip->ehci_htable,
+ ehcip->ehci_intr_cnt);
+ } else {
+ for (i = 0; i < ehcip->ehci_intr_cnt; i++) {
+ (void) ddi_intr_disable(ehcip->ehci_htable[i]);
+ }
+ }
+
+ /* Call ddi_intr_remove_handler() */
+ for (i = 0; i < ehcip->ehci_intr_cnt; i++) {
+ (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]);
+ (void) ddi_intr_free(ehcip->ehci_htable[i]);
+ }
+
+ kmem_free(ehcip->ehci_htable,
+ ehcip->ehci_intr_cnt * sizeof (ddi_intr_handle_t));
+}
+
+
+/*
* ehci_cpr_suspend
*/
int
diff --git a/usr/src/uts/common/io/usb/hcd/openhci/ohci.c b/usr/src/uts/common/io/usb/hcd/openhci/ohci.c
index a1ae8311e3..72d518400c 100644
--- a/usr/src/uts/common/io/usb/hcd/openhci/ohci.c
+++ b/usr/src/uts/common/io/usb/hcd/openhci/ohci.c
@@ -67,6 +67,13 @@ uint_t ohci_errlevel = USB_LOG_L2;
uint_t ohci_instance_debug = (uint_t)-1;
/*
+ * OHCI MSI tunable:
+ *
+ * By default MSI is enabled on all supported platforms.
+ */
+boolean_t ohci_enable_msi = B_TRUE;
+
+/*
* HCDI entry points
*
* The Host Controller Driver Interfaces (HCDI) are the software interfaces
@@ -125,6 +132,8 @@ static void ohci_decode_ddi_dma_addr_bind_handle_result(
static int ohci_map_regs(ohci_state_t *ohcip);
static int ohci_register_intrs_and_init_mutex(
ohci_state_t *ohcip);
+static int ohci_add_intrs(ohci_state_t *ohcip,
+ int intr_type);
static int ohci_init_ctlr(ohci_state_t *ohcip);
static int ohci_init_hcca(ohci_state_t *ohcip);
static void ohci_build_interrupt_lattice(
@@ -135,6 +144,7 @@ static usba_hcdi_ops_t *ohci_alloc_hcdi_ops(
/* Host Controller Driver (HCD) deinitialization functions */
static int ohci_cleanup(ohci_state_t *ohcip);
+static void ohci_rem_intrs(ohci_state_t *ohcip);
static int ohci_cpr_suspend(ohci_state_t *ohcip);
static int ohci_cpr_resume(ohci_state_t *ohcip);
@@ -333,7 +343,8 @@ static void ohci_free_tw(ohci_state_t *ohcip,
ohci_trans_wrapper_t *tw);
/* Interrupt Handling functions */
-static uint_t ohci_intr(caddr_t arg);
+static uint_t ohci_intr(caddr_t arg1,
+ caddr_t arg2);
static void ohci_handle_missed_intr(
ohci_state_t *ohcip);
static void ohci_handle_ue(ohci_state_t *ohcip);
@@ -650,7 +661,6 @@ ohci_attach(dev_info_t *dip,
return (DDI_FAILURE);
}
- ohcip->ohci_flags |= OHCI_INTR;
mutex_enter(&ohcip->ohci_int_mutex);
@@ -1181,76 +1191,172 @@ ohci_map_regs(ohci_state_t *ohcip)
static int
ohci_register_intrs_and_init_mutex(ohci_state_t *ohcip)
{
- int type, count = 0, actual, ret;
+ int intr_types;
USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
"ohci_register_intrs_and_init_mutex:");
- ret = ddi_intr_get_supported_types(ohcip->ohci_dip, &type);
-
- if ((ret != DDI_SUCCESS) || (!(type & DDI_INTR_TYPE_FIXED))) {
+ /* Get supported interrupt types */
+ if (ddi_intr_get_supported_types(ohcip->ohci_dip,
+ &intr_types) != DDI_SUCCESS) {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
"ohci_register_intrs_and_init_mutex: "
- "Fixed type interrupt is not supported");
+ "ddi_intr_get_supported_types failed");
return (DDI_FAILURE);
}
- ret = ddi_intr_get_nintrs(ohcip->ohci_dip, DDI_INTR_TYPE_FIXED, &count);
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_register_intrs_and_init_mutex: "
+ "supported interrupt types 0x%x", intr_types);
+
+ if ((intr_types & DDI_INTR_TYPE_MSI) && ohci_enable_msi) {
+ if (ohci_add_intrs(ohcip, DDI_INTR_TYPE_MSI)
+ != DDI_SUCCESS) {
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_register_intrs_and_init_mutex: MSI "
+ "registration failed, trying FIXED interrupt \n");
+ } else {
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_register_intrs_and_init_mutex: "
+ "Using MSI interrupt type\n");
+
+ ohcip->ohci_intr_type = DDI_INTR_TYPE_MSI;
+ ohcip->ohci_flags |= OHCI_INTR;
+ }
+ }
- /*
- * Fixed interrupts can only have one interrupt. Check to make
- * sure that number of supported interrupts and number of
- * available interrupts are both equal to 1.
- */
- if ((ret != DDI_SUCCESS) || (count != 1)) {
- USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ if ((!(ohcip->ohci_flags & OHCI_INTR)) &&
+ (intr_types & DDI_INTR_TYPE_FIXED)) {
+ if (ohci_add_intrs(ohcip, DDI_INTR_TYPE_FIXED)
+ != DDI_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_register_intrs_and_init_mutex: "
+ "FIXED interrupt registration failed\n");
+
+ return (DDI_FAILURE);
+ }
+
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
"ohci_register_intrs_and_init_mutex: "
- "no fixed interrupts");
+ "Using FIXED interrupt type\n");
+
+ ohcip->ohci_intr_type = DDI_INTR_TYPE_FIXED;
+ ohcip->ohci_flags |= OHCI_INTR;
+ }
+
+ /* Create prototype for SOF condition variable */
+ cv_init(&ohcip->ohci_SOF_cv, NULL, CV_DRIVER, NULL);
+
+ /* Semaphore to serialize opens and closes */
+ sema_init(&ohcip->ohci_ocsem, 1, NULL, SEMA_DRIVER, NULL);
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * ohci_add_intrs:
+ *
+ * Register FIXED or MSI interrupts.
+ */
+static int
+ohci_add_intrs(ohci_state_t *ohcip,
+ int intr_type)
+{
+ int actual, avail, intr_size, count = 0;
+ int i, flag, ret;
+
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_add_intrs: interrupt type 0x%x", intr_type);
+
+ /* Get number of interrupts */
+ ret = ddi_intr_get_nintrs(ohcip->ohci_dip, intr_type, &count);
+ if ((ret != DDI_SUCCESS) || (count == 0)) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_add_intrs: ddi_intr_get_nintrs() failure, "
+ "ret: %d, count: %d", ret, count);
return (DDI_FAILURE);
}
- ohcip->ohci_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
+ /* Get number of available interrupts */
+ ret = ddi_intr_get_navail(ohcip->ohci_dip, intr_type, &avail);
+ if ((ret != DDI_SUCCESS) || (avail == 0)) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_add_intrs: ddi_intr_get_navail() failure, "
+ "ret: %d, count: %d", ret, count);
+
+ return (DDI_FAILURE);
+ }
+
+ if (avail < count) {
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_add_intrs: ohci_add_intrs: nintrs () "
+ "returned %d, navail returned %d\n", count, avail);
+ }
+
+ /* Allocate an array of interrupt handles */
+ intr_size = count * sizeof (ddi_intr_handle_t);
+ ohcip->ohci_htable = kmem_zalloc(intr_size, KM_SLEEP);
+
+ flag = (intr_type == DDI_INTR_TYPE_MSI) ?
+ DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
+
+ /* call ddi_intr_alloc() */
ret = ddi_intr_alloc(ohcip->ohci_dip, ohcip->ohci_htable,
- DDI_INTR_TYPE_FIXED, 0, count, &actual, 0);
+ intr_type, 0, count, &actual, flag);
- if ((ret != DDI_SUCCESS) || (actual != 1)) {
+ if ((ret != DDI_SUCCESS) || (actual == 0)) {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
- "ohci_register_intrs_and_init_mutex: "
- "ddi_intr_alloc() failed 0x%x", ret);
+ "ohci_add_intrs: ddi_intr_alloc() failed %d", ret);
- kmem_free(ohcip->ohci_htable, sizeof (ddi_intr_handle_t));
+ kmem_free(ohcip->ohci_htable, intr_size);
return (DDI_FAILURE);
}
- /* Sanity check that count and actual are the same. */
- ASSERT(count == actual);
+ if (actual < count) {
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_add_intrs: Requested: %d, Received: %d\n",
+ count, actual);
- if (ddi_intr_get_pri(ohcip->ohci_htable[0], &ohcip->ohci_intr_pri)
- != DDI_SUCCESS) {
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(ohcip->ohci_htable[i]);
+
+ kmem_free(ohcip->ohci_htable, intr_size);
+
+ return (DDI_FAILURE);
+ }
+
+ ohcip->ohci_intr_cnt = actual;
+
+ if ((ret = ddi_intr_get_pri(ohcip->ohci_htable[0],
+ &ohcip->ohci_intr_pri)) != DDI_SUCCESS) {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
- "ohci_register_intrs_and_init_mutex: "
- "ddi_intr_get_pri() failed");
+ "ohci_add_intrs: ddi_intr_get_pri() failed %d", ret);
- (void) ddi_intr_free(ohcip->ohci_htable[0]);
- kmem_free(ohcip->ohci_htable, sizeof (ddi_intr_handle_t));
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(ohcip->ohci_htable[i]);
+
+ kmem_free(ohcip->ohci_htable, intr_size);
return (DDI_FAILURE);
}
- USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
- "Supported Interrupt priority = 0x%x", ohcip->ohci_intr_pri);
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_add_intrs: Supported Interrupt priority 0x%x",
+ ohcip->ohci_intr_pri);
/* Test for high level mutex */
if (ohcip->ohci_intr_pri >= ddi_intr_get_hilevel_pri()) {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
- "ohci_register_intrs_and_init_mutex: "
- "Hi level interrupt not supported");
+ "ohci_add_intrs: Hi level interrupt not supported");
+
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(ohcip->ohci_htable[i]);
- (void) ddi_intr_free(ohcip->ohci_htable[0]);
- kmem_free(ohcip->ohci_htable, sizeof (ddi_intr_handle_t));
+ kmem_free(ohcip->ohci_htable, intr_size);
return (DDI_FAILURE);
}
@@ -1259,37 +1365,51 @@ ohci_register_intrs_and_init_mutex(ohci_state_t *ohcip)
mutex_init(&ohcip->ohci_int_mutex, NULL, MUTEX_DRIVER,
DDI_INTR_PRI(ohcip->ohci_intr_pri));
- if (ddi_intr_add_handler(ohcip->ohci_htable[0],
- (ddi_intr_handler_t *)ohci_intr, (caddr_t)ohcip, NULL)) {
- USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
- "ohci_register_intrs_and_init_mutex: "
- "ddi_intr_add_handler() failed");
+ /* Call ddi_intr_add_handler() */
+ for (i = 0; i < actual; i++) {
+ if ((ret = ddi_intr_add_handler(ohcip->ohci_htable[i],
+ ohci_intr, (caddr_t)ohcip,
+ (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_add_intrs: ddi_intr_add_handler() "
+ "failed %d", ret);
- mutex_destroy(&ohcip->ohci_int_mutex);
- (void) ddi_intr_free(ohcip->ohci_htable[0]);
- kmem_free(ohcip->ohci_htable, sizeof (ddi_intr_handle_t));
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(ohcip->ohci_htable[i]);
- return (DDI_FAILURE);
+ mutex_destroy(&ohcip->ohci_int_mutex);
+ kmem_free(ohcip->ohci_htable, intr_size);
+
+ return (DDI_FAILURE);
+ }
}
- if (ddi_intr_enable(ohcip->ohci_htable[0]) != DDI_SUCCESS) {
+ if ((ret = ddi_intr_get_cap(ohcip->ohci_htable[0],
+ &ohcip->ohci_intr_cap)) != DDI_SUCCESS) {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
- "ohci_register_intrs_and_init_mutex: "
- "ddi_intr_enable() failed");
+ "ohci_add_intrs: ddi_intr_get_cap() failed %d", ret);
+
+ for (i = 0; i < actual; i++) {
+ (void) ddi_intr_remove_handler(ohcip->ohci_htable[i]);
+ (void) ddi_intr_free(ohcip->ohci_htable[i]);
+ }
- (void) ddi_intr_remove_handler(ohcip->ohci_htable[0]);
mutex_destroy(&ohcip->ohci_int_mutex);
- (void) ddi_intr_free(ohcip->ohci_htable[0]);
- kmem_free(ohcip->ohci_htable, sizeof (ddi_intr_handle_t));
+ kmem_free(ohcip->ohci_htable, intr_size);
return (DDI_FAILURE);
}
- /* Create prototype for SOF condition variable */
- cv_init(&ohcip->ohci_SOF_cv, NULL, CV_DRIVER, NULL);
-
- /* Semaphore to serialize opens and closes */
- sema_init(&ohcip->ohci_ocsem, 1, NULL, SEMA_DRIVER, NULL);
+ /* Enable all interrupts */
+ if (ohcip->ohci_intr_cap & DDI_INTR_FLAG_BLOCK) {
+ /* Call ddi_intr_block_enable() for MSI interrupts */
+ (void) ddi_intr_block_enable(ohcip->ohci_htable,
+ ohcip->ohci_intr_cnt);
+ } else {
+ /* Call ddi_intr_enable for MSI or FIXED interrupts */
+ for (i = 0; i < ohcip->ohci_intr_cnt; i++)
+ (void) ddi_intr_enable(ohcip->ohci_htable[i]);
+ }
return (DDI_SUCCESS);
}
@@ -1899,17 +2019,7 @@ ohci_cleanup(ohci_state_t *ohcip)
mutex_exit(&ohcip->ohci_int_mutex);
- /* disable interrupt */
- (void) ddi_intr_disable(ohcip->ohci_htable[0]);
-
- /* Remove interrupt handler */
- (void) ddi_intr_remove_handler(ohcip->ohci_htable[0]);
-
- /* free interrupt handle */
- (void) ddi_intr_free(ohcip->ohci_htable[0]);
-
- /* free memory */
- kmem_free(ohcip->ohci_htable, sizeof (ddi_intr_handle_t));
+ ohci_rem_intrs(ohcip);
}
/* Unmap the OHCI registers */
@@ -2053,6 +2163,40 @@ ohci_cleanup(ohci_state_t *ohcip)
/*
+ * ohci_rem_intrs:
+ *
+ * Unregister FIXED or MSI interrupts
+ */
+static void
+ohci_rem_intrs(ohci_state_t *ohcip)
+{
+ int i;
+
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, ohcip->ohci_log_hdl,
+ "ohci_rem_intrs: interrupt type 0x%x", ohcip->ohci_intr_type);
+
+ /* Disable all interrupts */
+ if (ohcip->ohci_intr_cap & DDI_INTR_FLAG_BLOCK) {
+ (void) ddi_intr_block_disable(ohcip->ohci_htable,
+ ohcip->ohci_intr_cnt);
+ } else {
+ for (i = 0; i < ohcip->ohci_intr_cnt; i++) {
+ (void) ddi_intr_disable(ohcip->ohci_htable[i]);
+ }
+ }
+
+ /* Call ddi_intr_remove_handler() */
+ for (i = 0; i < ohcip->ohci_intr_cnt; i++) {
+ (void) ddi_intr_remove_handler(ohcip->ohci_htable[i]);
+ (void) ddi_intr_free(ohcip->ohci_htable[i]);
+ }
+
+ kmem_free(ohcip->ohci_htable,
+ ohcip->ohci_intr_cnt * sizeof (ddi_intr_handle_t));
+}
+
+
+/*
* ohci_cpr_suspend
*/
static int
@@ -6937,15 +7081,15 @@ ohci_free_tw(
* OpenHCI (OHCI) interrupt handling routine.
*/
static uint_t
-ohci_intr(caddr_t arg)
+ohci_intr(caddr_t arg1, caddr_t arg2)
{
- ohci_state_t *ohcip = (ohci_state_t *)arg;
+ ohci_state_t *ohcip = (ohci_state_t *)arg1;
uint_t intr;
ohci_td_t *done_head = NULL;
ohci_save_intr_sts_t *ohci_intr_sts = &ohcip->ohci_save_intr_sts;
USB_DPRINTF_L3(PRINT_MASK_INTR, ohcip->ohci_log_hdl,
- "Interrupt occurred");
+ "ohci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p", arg1, arg2);
mutex_enter(&ohcip->ohci_int_mutex);
diff --git a/usr/src/uts/common/io/usb/hcd/uhci/uhci.c b/usr/src/uts/common/io/usb/hcd/uhci/uhci.c
index 3f021c55f5..c76170332a 100644
--- a/usr/src/uts/common/io/usb/hcd/uhci/uhci.c
+++ b/usr/src/uts/common/io/usb/hcd/uhci/uhci.c
@@ -43,7 +43,9 @@
* Prototype Declarations for cb_ops and dev_ops
*/
static int uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+static int uhci_add_intrs(uhci_state_t *uhcip, int intr_type);
static int uhci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
+static void uhci_rem_intrs(uhci_state_t *uhcip);
static int uhci_open(dev_t *devp, int flags, int otyp, cred_t *credp);
static int uhci_close(dev_t dev, int flag, int otyp, cred_t *credp);
static int uhci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
@@ -108,6 +110,13 @@ ushort_t uhci_tree_bottom_nodes[NUM_FRAME_LST_ENTRIES];
/*
+ * UHCI MSI tunable:
+ *
+ * By default MSI is enabled on all supported platforms.
+ */
+boolean_t uhci_enable_msi = B_TRUE;
+
+/*
* tunable, delay during attach in seconds
*/
int uhci_attach_wait = 1;
@@ -117,7 +126,7 @@ static void uhci_handle_intr_td_errors(uhci_state_t *uhcip, uhci_td_t *td,
uhci_trans_wrapper_t *tw, uhci_pipe_private_t *pp);
static void uhci_handle_one_xfer_completion(uhci_state_t *uhcip,
usb_cr_t usb_err, uhci_td_t *td);
-static uint_t uhci_intr(caddr_t arg);
+static uint_t uhci_intr(caddr_t arg1, caddr_t arg2);
static int uhci_cleanup(uhci_state_t *uhcip);
@@ -203,8 +212,7 @@ static int
uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
int instance;
- int type, count, actual, ret;
- uint_t intr_pri;
+ int i, intr_types;
uhci_state_t *uhcip = NULL;
usba_hcdi_register_args_t hcdi_args;
@@ -241,95 +249,60 @@ uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
uhcip->uhci_dip = dip;
uhcip->uhci_instance = instance;
- /* Semaphore to serialize opens and closes */
- sema_init(&uhcip->uhci_ocsem, 1, NULL, SEMA_DRIVER, NULL);
+ /* Get supported interrupt types */
+ if (ddi_intr_get_supported_types(uhcip->uhci_dip,
+ &intr_types) != DDI_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_attach: ddi_intr_get_supported_types failed");
- ret = ddi_intr_get_supported_types(dip, &type);
- if ((ret != DDI_SUCCESS) || (!(type & DDI_INTR_TYPE_FIXED))) {
- USB_DPRINTF_L1(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
- "Fixed type interrupts not supported");
usb_free_log_hdl(uhcip->uhci_log_hdl);
ddi_soft_state_free(uhci_statep, instance);
return (DDI_FAILURE);
}
- ret = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &count);
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_attach: supported interrupt types 0x%x", intr_types);
- /*
- * Fixed interrupts can only have one interrupt. Check to make
- * sure that number of supported interrupts and number of
- * available interrupts are both equal to 1.
- */
- if ((ret != DDI_SUCCESS) || (count != 1)) {
- USB_DPRINTF_L1(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
- "No Fixed interrupts found");
- usb_free_log_hdl(uhcip->uhci_log_hdl);
- ddi_soft_state_free(uhci_statep, instance);
-
- return (DDI_FAILURE);
- }
-
- USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
- "Supported Intr types = 0x%x, #Intrs = 0x%x", type, count);
- uhcip->uhci_htable = kmem_zalloc(count * sizeof (ddi_intr_handle_t),
- KM_SLEEP);
-
- ret = ddi_intr_alloc(dip, uhcip->uhci_htable, DDI_INTR_TYPE_FIXED, 0,
- count,
- &actual, 0);
- if ((ret != DDI_SUCCESS) || (actual != 1)) {
- USB_DPRINTF_L1(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
- "ddi_intr_alloc failed 0x%x", ret);
- kmem_free(uhcip->uhci_htable, sizeof (ddi_intr_handle_t));
- usb_free_log_hdl(uhcip->uhci_log_hdl);
- ddi_soft_state_free(uhci_statep, instance);
+ if ((intr_types & DDI_INTR_TYPE_MSI) && uhci_enable_msi) {
+ if (uhci_add_intrs(uhcip, DDI_INTR_TYPE_MSI)
+ != DDI_SUCCESS) {
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_attach: MSI registration failed, "
+ "trying FIXED interrupt \n");
+ } else {
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_attach: Using MSI interrupt type\n");
- return (DDI_FAILURE);
+ uhcip->uhci_intr_type = DDI_INTR_TYPE_MSI;
+ }
}
- ret = ddi_intr_get_pri(uhcip->uhci_htable[0], &intr_pri);
- if (ret != DDI_SUCCESS) {
- USB_DPRINTF_L1(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
- "ddi_intr_get_pri failed 0x%x", ret);
- (void) ddi_intr_free(uhcip->uhci_htable[0]);
- kmem_free(uhcip->uhci_htable, sizeof (ddi_intr_handle_t));
- usb_free_log_hdl(uhcip->uhci_log_hdl);
- ddi_soft_state_free(uhci_statep, instance);
+ if (!(uhcip->uhci_htable) && (intr_types & DDI_INTR_TYPE_FIXED)) {
+ if (uhci_add_intrs(uhcip, DDI_INTR_TYPE_FIXED)
+ != DDI_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_attach: FIXED interrupt registration "
+ "failed\n");
- return (DDI_FAILURE);
- }
+ usb_free_log_hdl(uhcip->uhci_log_hdl);
+ ddi_soft_state_free(uhci_statep, instance);
- USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
- "Supported Interrupt priority = 0x%x", intr_pri);
+ return (DDI_FAILURE);
+ }
- if (intr_pri >= ddi_intr_get_hilevel_pri()) {
- USB_DPRINTF_L1(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
- "Hi level interrupt not supported");
- (void) ddi_intr_free(uhcip->uhci_htable[0]);
- kmem_free(uhcip->uhci_htable, sizeof (ddi_intr_handle_t));
- usb_free_log_hdl(uhcip->uhci_log_hdl);
- ddi_soft_state_free(uhci_statep, instance);
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_attach: Using FIXED interrupt type\n");
- return (DDI_FAILURE);
+ uhcip->uhci_intr_type = DDI_INTR_TYPE_FIXED;
}
- /* Initialize the mutex */
- mutex_init(&uhcip->uhci_int_mutex, NULL, MUTEX_DRIVER,
- DDI_INTR_PRI(intr_pri));
+ /* Semaphore to serialize opens and closes */
+ sema_init(&uhcip->uhci_ocsem, 1, NULL, SEMA_DRIVER, NULL);
/* Create prototype condition variable */
cv_init(&uhcip->uhci_cv_SOF, NULL, CV_DRIVER, NULL);
- ret = ddi_intr_add_handler(uhcip->uhci_htable[0],
- (ddi_intr_handler_t *)uhci_intr, (caddr_t)uhcip, NULL);
- if (ret != DDI_SUCCESS) {
- USB_DPRINTF_L1(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
- "ddi_intr_add_handler failed 0x%x", ret);
-
- goto fail;
- }
-
/* Initialize the DMA attributes */
uhci_set_dma_attributes(uhcip);
@@ -351,15 +324,18 @@ uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
/* Set the flag that uhci controller has not been initialized. */
uhcip->uhci_ctlr_init_flag = B_FALSE;
- /* finally enable the interrupt */
- ret = ddi_intr_enable(uhcip->uhci_htable[0]);
- if (ret != DDI_SUCCESS) {
- USB_DPRINTF_L1(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
- "ddi_intr_enable failed 0x%x", ret);
-
- goto fail;
+ /* Enable all interrupts */
+ if (uhcip->uhci_intr_cap & DDI_INTR_FLAG_BLOCK) {
+ /* Call ddi_intr_block_enable() for MSI interrupts */
+ (void) ddi_intr_block_enable(uhcip->uhci_htable,
+ uhcip->uhci_intr_cnt);
+ } else {
+ /* Call ddi_intr_enable for MSI or FIXED interrupts */
+ for (i = 0; i < uhcip->uhci_intr_cnt; i++)
+ (void) ddi_intr_enable(uhcip->uhci_htable[i]);
}
+
/* Initialize the controller */
if (uhci_init_ctlr(uhcip) != USB_SUCCESS) {
@@ -381,7 +357,7 @@ uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
hcdi_args.usba_hcdi_register_ops = uhcip->uhci_hcdi_ops;
hcdi_args.usba_hcdi_register_dma_attr = &uhcip->uhci_dma_attr;
hcdi_args.usba_hcdi_register_iblock_cookie =
- (ddi_iblock_cookie_t)(uintptr_t)intr_pri;
+ (ddi_iblock_cookie_t)(uintptr_t)uhcip->uhci_intr_pri;
if (usba_hcdi_register(&hcdi_args, 0) != USB_SUCCESS) {
@@ -449,6 +425,155 @@ fail:
/*
+ * uhci_add_intrs:
+ *
+ * Register FIXED or MSI interrupts.
+ */
+static int
+uhci_add_intrs(uhci_state_t *uhcip,
+ int intr_type)
+{
+ int actual, avail, intr_size, count = 0;
+ int i, flag, ret;
+
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: interrupt type 0x%x", intr_type);
+
+ /* Get number of interrupts */
+ ret = ddi_intr_get_nintrs(uhcip->uhci_dip, intr_type, &count);
+ if ((ret != DDI_SUCCESS) || (count == 0)) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: ddi_intr_get_nintrs() failure, "
+ "ret: %d, count: %d", ret, count);
+
+ return (DDI_FAILURE);
+ }
+
+ /* Get number of available interrupts */
+ ret = ddi_intr_get_navail(uhcip->uhci_dip, intr_type, &avail);
+ if ((ret != DDI_SUCCESS) || (avail == 0)) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: ddi_intr_get_navail() failure, "
+ "ret: %d, count: %d", ret, count);
+
+ return (DDI_FAILURE);
+ }
+
+ if (avail < count) {
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: uhci_add_intrs: nintrs () "
+ "returned %d, navail returned %d\n", count, avail);
+ }
+
+ /* Allocate an array of interrupt handles */
+ intr_size = count * sizeof (ddi_intr_handle_t);
+ uhcip->uhci_htable = kmem_zalloc(intr_size, KM_SLEEP);
+
+ flag = (intr_type == DDI_INTR_TYPE_MSI) ?
+ DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
+
+ /* call ddi_intr_alloc() */
+ ret = ddi_intr_alloc(uhcip->uhci_dip, uhcip->uhci_htable,
+ intr_type, 0, count, &actual, flag);
+
+ if ((ret != DDI_SUCCESS) || (actual == 0)) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: ddi_intr_alloc() failed %d", ret);
+
+ kmem_free(uhcip->uhci_htable, intr_size);
+
+ return (DDI_FAILURE);
+ }
+
+ if (actual < count) {
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: Requested: %d, Received: %d\n",
+ count, actual);
+
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(uhcip->uhci_htable[i]);
+
+ kmem_free(uhcip->uhci_htable, intr_size);
+
+ return (DDI_FAILURE);
+ }
+
+ uhcip->uhci_intr_cnt = actual;
+
+ if ((ret = ddi_intr_get_pri(uhcip->uhci_htable[0],
+ &uhcip->uhci_intr_pri)) != DDI_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: ddi_intr_get_pri() failed %d", ret);
+
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(uhcip->uhci_htable[i]);
+
+ kmem_free(uhcip->uhci_htable, intr_size);
+
+ return (DDI_FAILURE);
+ }
+
+ USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: Supported Interrupt priority 0x%x",
+ uhcip->uhci_intr_pri);
+
+ /* Test for high level mutex */
+ if (uhcip->uhci_intr_pri >= ddi_intr_get_hilevel_pri()) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: Hi level interrupt not supported");
+
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(uhcip->uhci_htable[i]);
+
+ kmem_free(uhcip->uhci_htable, intr_size);
+
+ return (DDI_FAILURE);
+ }
+
+ /* Initialize the mutex */
+ mutex_init(&uhcip->uhci_int_mutex, NULL, MUTEX_DRIVER,
+ DDI_INTR_PRI(uhcip->uhci_intr_pri));
+
+ /* Call ddi_intr_add_handler() */
+ for (i = 0; i < actual; i++) {
+ if ((ret = ddi_intr_add_handler(uhcip->uhci_htable[i],
+ uhci_intr, (caddr_t)uhcip,
+ (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: ddi_intr_add_handler() "
+ "failed %d", ret);
+
+ for (i = 0; i < actual; i++)
+ (void) ddi_intr_free(uhcip->uhci_htable[i]);
+
+ mutex_destroy(&uhcip->uhci_int_mutex);
+ kmem_free(uhcip->uhci_htable, intr_size);
+
+ return (DDI_FAILURE);
+ }
+ }
+
+ if ((ret = ddi_intr_get_cap(uhcip->uhci_htable[0],
+ &uhcip->uhci_intr_cap)) != DDI_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_add_intrs: ddi_intr_get_cap() failed %d", ret);
+
+ for (i = 0; i < actual; i++) {
+ (void) ddi_intr_remove_handler(uhcip->uhci_htable[i]);
+ (void) ddi_intr_free(uhcip->uhci_htable[i]);
+ }
+
+ mutex_destroy(&uhcip->uhci_int_mutex);
+ kmem_free(uhcip->uhci_htable, intr_size);
+
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
* Function Name: uhci_detach
* Description: Detach entry point - called by the Kernel.
* Deallocates all the memory
@@ -481,6 +606,40 @@ uhci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
/*
+ * uhci_rem_intrs:
+ *
+ * Unregister FIXED or MSI interrupts
+ */
+static void
+uhci_rem_intrs(uhci_state_t *uhcip)
+{
+ int i;
+
+ USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
+ "uhci_rem_intrs: interrupt type 0x%x", uhcip->uhci_intr_type);
+
+ /* Disable all interrupts */
+ if (uhcip->uhci_intr_cap & DDI_INTR_FLAG_BLOCK) {
+ (void) ddi_intr_block_disable(uhcip->uhci_htable,
+ uhcip->uhci_intr_cnt);
+ } else {
+ for (i = 0; i < uhcip->uhci_intr_cnt; i++) {
+ (void) ddi_intr_disable(uhcip->uhci_htable[i]);
+ }
+ }
+
+ /* Call ddi_intr_remove_handler() */
+ for (i = 0; i < uhcip->uhci_intr_cnt; i++) {
+ (void) ddi_intr_remove_handler(uhcip->uhci_htable[i]);
+ (void) ddi_intr_free(uhcip->uhci_htable[i]);
+ }
+
+ kmem_free(uhcip->uhci_htable,
+ uhcip->uhci_intr_cnt * sizeof (ddi_intr_handle_t));
+}
+
+
+/*
* Function Name: uhci_reset
* Description: Reset entry point - called by the Kernel
* on the way down.
@@ -575,18 +734,8 @@ uhci_cleanup(uhci_state_t *uhcip)
mutex_exit(&uhcip->uhci_int_mutex);
/* do interrupt cleanup */
- if (uhcip->uhci_htable[0]) {
- /* disable interrupt */
- (void) ddi_intr_disable(uhcip->uhci_htable[0]);
-
- /* remove interrupt handler */
- (void) ddi_intr_remove_handler(uhcip->uhci_htable[0]);
-
- /* free interrupt handle */
- (void) ddi_intr_free(uhcip->uhci_htable[0]);
-
- /* free memory */
- kmem_free(uhcip->uhci_htable, sizeof (ddi_intr_handle_t));
+ if (uhcip->uhci_htable) {
+ uhci_rem_intrs(uhcip);
}
mutex_enter(&uhcip->uhci_int_mutex);
@@ -620,10 +769,13 @@ uhci_cleanup(uhci_state_t *uhcip)
* uhci interrupt handling routine.
*/
static uint_t
-uhci_intr(caddr_t arg)
+uhci_intr(caddr_t arg1, caddr_t arg2)
{
ushort_t intr_status, cmd_reg;
- uhci_state_t *uhcip = (uhci_state_t *)arg;
+ uhci_state_t *uhcip = (uhci_state_t *)arg1;
+
+ USB_DPRINTF_L3(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
+ "uhci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p", arg1, arg2);
mutex_enter(&uhcip->uhci_int_mutex);
diff --git a/usr/src/uts/common/os/ddi_intr.c b/usr/src/uts/common/os/ddi_intr.c
index cb04896cb5..319ff06c2b 100644
--- a/usr/src/uts/common/os/ddi_intr.c
+++ b/usr/src/uts/common/os/ddi_intr.c
@@ -1129,7 +1129,8 @@ ddi_intr_hilevel(dev_info_t *dip, uint_t inumber)
hdl = existing_hdlp[0]; /* Use existing handle */
} else {
if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
- inumber, 1, &actual, 0)) != DDI_SUCCESS) {
+ inumber, 1, &actual,
+ DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
"ddi_intr_alloc failed, ret 0x%x\n", ret));
return (0);
@@ -1195,7 +1196,8 @@ ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber,
hdl = existing_hdlp[0]; /* Use existing handle */
} else {
if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
- inumber, 1, &actual, 0)) != DDI_SUCCESS) {
+ inumber, 1, &actual,
+ DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
"ddi_intr_alloc failed, ret 0x%x\n", ret));
return (DDI_INTR_NOTFOUND);
@@ -1236,7 +1238,7 @@ ddi_add_intr(dev_info_t *dip, uint_t inumber,
hdl_p = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
- inumber, 1, &actual, 0)) != DDI_SUCCESS) {
+ inumber, 1, &actual, DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
"ddi_intr_alloc failed, ret 0x%x\n", ret));
kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
diff --git a/usr/src/uts/common/sys/bge_impl.h b/usr/src/uts/common/sys/bge_impl.h
index b1c74ca83c..9739b57cc3 100644
--- a/usr/src/uts/common/sys/bge_impl.h
+++ b/usr/src/uts/common/sys/bge_impl.h
@@ -569,7 +569,7 @@ typedef struct {
uint64_t hw_mac_addr; /* from chip register */
bge_mac_addr_t vendor_addr; /* transform of same */
- boolean_t bge_msi_enabled; /* default to false */
+ boolean_t msi_enabled; /* default to true */
} chip_id_t;
#define CHIP_FLAG_SUPPORTED 0x80
@@ -730,8 +730,6 @@ typedef struct bge {
ddi_intr_handle_t *htable; /* For array of interrupts */
int intr_type; /* What type of interrupt */
int intr_cnt; /* # of intrs count returned */
- size_t intr_size; /* Size of intr array to */
- /* allocate */
uint_t intr_pri; /* Interrupt priority */
int intr_cap; /* Interrupt capabilities */
uint32_t progress; /* attach tracking */
@@ -1134,7 +1132,7 @@ uint_t bge_chip_factotum(caddr_t arg);
void bge_chip_cyclic(void *arg);
enum ioc_reply bge_chip_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp,
struct iocblk *iocp);
-uint_t bge_intr(caddr_t arg);
+uint_t bge_intr(caddr_t arg1, caddr_t arg2);
extern uint32_t bge_rx_ticks_norm;
extern uint32_t bge_tx_ticks_norm;
extern uint32_t bge_rx_count_norm;
diff --git a/usr/src/uts/common/sys/ddi_intr_impl.h b/usr/src/uts/common/sys/ddi_intr_impl.h
index 24a1a86310..1afcca6faa 100644
--- a/usr/src/uts/common/sys/ddi_intr_impl.h
+++ b/usr/src/uts/common/sys/ddi_intr_impl.h
@@ -155,13 +155,13 @@ typedef struct ddi_intr_msix {
/* MSI-X Table related information */
ddi_acc_handle_t msix_tbl_hdl; /* MSI-X table handle */
- caddr_t msix_tbl_addr; /* MSI-X table addr */
- offset_t msix_tbl_offset; /* MSI-X table offset */
+ uint32_t *msix_tbl_addr; /* MSI-X table addr */
+ uint32_t msix_tbl_offset; /* MSI-X table offset */
/* MSI-X PBA Table related information */
ddi_acc_handle_t msix_pba_hdl; /* MSI-X PBA handle */
- caddr_t msix_pba_addr; /* MSI-X PBA addr */
- offset_t msix_pba_offset; /* MSI-X PBA offset */
+ uint32_t *msix_pba_addr; /* MSI-X PBA addr */
+ uint32_t msix_pba_offset; /* MSI-X PBA offset */
ddi_device_acc_attr_t msix_dev_attr; /* MSI-X device attr */
} ddi_intr_msix_t;
diff --git a/usr/src/uts/common/sys/pci.h b/usr/src/uts/common/sys/pci.h
index bd0bb7cd52..cfbe0d84a9 100644
--- a/usr/src/uts/common/sys/pci.h
+++ b/usr/src/uts/common/sys/pci.h
@@ -679,9 +679,9 @@ extern "C" {
*/
#define PCI_MSIX_CTRL 0x02 /* MSI-X control register, 2 bytes */
#define PCI_MSIX_TBL_OFFSET 0x04 /* MSI-X table offset, 4 bytes */
-#define PCI_MSIX_TBL_BIR_MASK 0x0003 /* MSI-X table BIR mask */
-#define PCI_MSIX_PBA_OFFSET 0x0C /* MSI-X pending bit array, 4 bytes */
-#define PCI_MSIX_PBA_BIR_MASK 0x0003 /* MSI-X PBA BIR mask */
+#define PCI_MSIX_TBL_BIR_MASK 0x0007 /* MSI-X table BIR mask */
+#define PCI_MSIX_PBA_OFFSET 0x08 /* MSI-X pending bit array, 4 bytes */
+#define PCI_MSIX_PBA_BIR_MASK 0x0007 /* MSI-X PBA BIR mask */
#define PCI_MSIX_TBL_SIZE_MASK 0x07FF /* table size mask in MSI-X ctrl reg */
#define PCI_MSIX_FUNCTION_MASK 0x4000 /* function mask in MSI-X ctrl reg */
diff --git a/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h b/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h
index af98789cef..478b3cd747 100644
--- a/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h
+++ b/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h
@@ -90,7 +90,11 @@ typedef struct ehci_state {
ddi_dma_attr_t ehci_dma_attr; /* DMA attributes */
ddi_intr_handle_t *ehci_htable; /* intr handle */
+ int ehci_intr_type; /* intr type used */
+ int ehci_intr_cnt; /* # of intrs inuse */
uint_t ehci_intr_pri; /* intr priority */
+ int ehci_intr_cap; /* intr capabilities */
+ boolean_t ehci_msi_enabled; /* default to true */
kmutex_t ehci_int_mutex; /* Global EHCI mutex */
/* Periodic Frame List area */
@@ -1006,7 +1010,6 @@ typedef struct setup_pkt {
#define PRINT_MASK_DUMPING 0x00000100 /* Dump ehci info */
#define PRINT_MASK_ALL 0xFFFFFFFF
-
/*
* workaround for ALI chips
*/
@@ -1135,7 +1138,8 @@ void ehci_handle_root_hub_pipe_stop_intr_polling(
/*
* EHCI Interrupt Handler entry point.
*/
-uint_t ehci_intr(caddr_t arg);
+uint_t ehci_intr(caddr_t arg1,
+ caddr_t arg2);
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/usb/hcd/openhci/ohcid.h b/usr/src/uts/common/sys/usb/hcd/openhci/ohcid.h
index a0f553e77f..518727dc1b 100644
--- a/usr/src/uts/common/sys/usb/hcd/openhci/ohcid.h
+++ b/usr/src/uts/common/sys/usb/hcd/openhci/ohcid.h
@@ -138,7 +138,10 @@ typedef struct ohci_state {
ddi_dma_attr_t ohci_dma_attr; /* DMA attributes */
ddi_intr_handle_t *ohci_htable; /* intr handle */
+ int ohci_intr_type; /* intr type used */
+ int ohci_intr_cnt; /* # of intrs inuse */
uint_t ohci_intr_pri; /* intr priority */
+ int ohci_intr_cap; /* intr capabilities */
kmutex_t ohci_int_mutex; /* Mutex for struct */
/* HCCA area */
diff --git a/usr/src/uts/common/sys/usb/hcd/uhci/uhcid.h b/usr/src/uts/common/sys/usb/hcd/uhci/uhcid.h
index b428e37b38..1c817837b9 100644
--- a/usr/src/uts/common/sys/usb/hcd/uhci/uhcid.h
+++ b/usr/src/uts/common/sys/usb/hcd/uhci/uhcid.h
@@ -137,6 +137,10 @@ typedef struct uhci_state {
ddi_dma_attr_t uhci_dma_attr; /* DMA attributes */
ddi_intr_handle_t *uhci_htable; /* intr handle */
+ int uhci_intr_type; /* intr type used */
+ int uhci_intr_cnt; /* # of intrs inuse */
+ uint_t uhci_intr_pri; /* intr priority */
+ int uhci_intr_cap; /* intr capabilities */
kmutex_t uhci_int_mutex; /* Mutex for struct */
frame_lst_table_t *uhci_frame_lst_tablep; /* Virtual HCCA ptr */
diff --git a/usr/src/uts/i86pc/io/pciex/pcie_pci.c b/usr/src/uts/i86pc/io/pciex/pcie_pci.c
index 2e05880740..58af38be1a 100644
--- a/usr/src/uts/i86pc/io/pciex/pcie_pci.c
+++ b/usr/src/uts/i86pc/io/pciex/pcie_pci.c
@@ -917,7 +917,7 @@ pepb_intr_init(pepb_devstate_t *pepb_p, int intr_type)
pepb_p->soft_state |= PEPB_SOFT_STATE_INIT_HTABLE;
ret = ddi_intr_alloc(dip, pepb_p->htable, intr_type, 0, request,
- &count, 0);
+ &count, DDI_INTR_ALLOC_NORMAL);
if ((ret != DDI_SUCCESS) || (count == 0)) {
PEPB_DEBUG((CE_NOTE, "ddi_intr_alloc() ret: %d ask: %d"
" actual: %d\n", ret, request, count));
diff --git a/usr/src/uts/sun4/io/px/px.c b/usr/src/uts/sun4/io/px/px.c
index 43c306fc7e..67ccc3ca95 100644
--- a/usr/src/uts/sun4/io/px/px.c
+++ b/usr/src/uts/sun4/io/px/px.c
@@ -444,6 +444,8 @@ px_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
ddi_remove_minor_node(dip, "devctl");
px_err_rem_intr(&px_p->px_fault);
px_pec_detach(px_p);
+ px_pwr_teardown(dip);
+ pwr_common_teardown(dip);
px_msi_detach(px_p);
px_msiq_detach(px_p);
px_mmu_detach(px_p);
@@ -457,8 +459,6 @@ px_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
* resources it's using.
*/
px_free_props(px_p);
- px_pwr_teardown(dip);
- pwr_common_teardown(dip);
mutex_exit(&px_p->px_mutex);
mutex_destroy(&px_p->px_mutex);
ddi_soft_state_free(px_state_p, instance);
@@ -1295,9 +1295,6 @@ px_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
/* Process DDI_INTROP_SUPPORTED_TYPES request here */
if (intr_op == DDI_INTROP_SUPPORTED_TYPES) {
- px_t *px_p = DIP_TO_STATE(dip);
- px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state;
-
*(int *)result = i_ddi_get_nintrs(rdip) ?
DDI_INTR_TYPE_FIXED : 0;
@@ -1306,8 +1303,12 @@ px_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
/*
* Double check supported interrupt types vs.
* what the host bridge supports.
+ *
+ * NOTE:
+ * Currently MSI-X is disabled since px driver
+ * don't fully support this feature.
*/
- *(int *)result |= (intr_types & msi_state_p->msi_type);
+ *(int *)result |= (intr_types & DDI_INTR_TYPE_MSI);
}
return (ret);
diff --git a/usr/src/uts/sun4/io/px/px_intr.c b/usr/src/uts/sun4/io/px/px_intr.c
index 7261709dd8..c4b9a23323 100644
--- a/usr/src/uts/sun4/io/px/px_intr.c
+++ b/usr/src/uts/sun4/io/px/px_intr.c
@@ -582,9 +582,6 @@ px_intx_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
case DDI_INTROP_NAVAIL:
*(int *)result = i_ddi_get_nintrs(rdip);
break;
- case DDI_INTROP_SUPPORTED_TYPES:
- *(int *)result = DDI_INTR_TYPE_FIXED;
- break;
default:
ret = DDI_ENOTSUP;
break;
@@ -600,6 +597,9 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
{
px_t *px_p = DIP_TO_STATE(dip);
px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state;
+ msiq_rec_type_t msiq_rec_type;
+ msi_type_t msi_type;
+ uint64_t msi_addr;
msinum_t msi_num;
msiqid_t msiq_id;
uint_t nintrs;
@@ -608,6 +608,18 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
DBG(DBG_INTROPS, dip, "px_msix_ops: dip=%x rdip=%x intr_op=%x "
"handle=%p\n", dip, rdip, intr_op, hdlp);
+ /* Check for MSI64 support */
+ if (hdlp->ih_cap & DDI_INTR_FLAG_MSI64) {
+ msiq_rec_type = MSI64_REC;
+ msi_type = MSI64_TYPE;
+ msi_addr = msi_state_p->msi_addr64 ?
+ msi_state_p->msi_addr64:msi_state_p->msi_addr32;
+ } else {
+ msiq_rec_type = MSI32_REC;
+ msi_type = MSI32_TYPE;
+ msi_addr = msi_state_p->msi_addr32;
+ }
+
switch (intr_op) {
case DDI_INTROP_GETCAP:
ret = pci_msi_get_cap(rdip, hdlp->ih_type, (int *)result);
@@ -650,7 +662,7 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
return (ret);
if ((ret = px_add_msiq_intr(dip, rdip, hdlp,
- MSI32_REC, msi_num, &msiq_id)) != DDI_SUCCESS) {
+ msiq_rec_type, msi_num, &msiq_id)) != DDI_SUCCESS) {
DBG(DBG_INTROPS, dip, "px_msix_ops: Add MSI handler "
"failed, rdip 0x%p msi 0x%x\n", rdip, msi_num);
return (ret);
@@ -659,16 +671,16 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
DBG(DBG_INTROPS, dip, "px_msix_ops: msiq used 0x%x\n", msiq_id);
if ((ret = px_lib_msi_setmsiq(dip, msi_num,
- msiq_id, MSI32_TYPE)) != DDI_SUCCESS) {
+ msiq_id, msi_type)) != DDI_SUCCESS) {
(void) px_rem_msiq_intr(dip, rdip,
- hdlp, MSI32_REC, msi_num, msiq_id);
+ hdlp, msiq_rec_type, msi_num, msiq_id);
return (ret);
}
if ((ret = px_lib_msi_setstate(dip, msi_num,
PCI_MSI_STATE_IDLE)) != DDI_SUCCESS) {
(void) px_rem_msiq_intr(dip, rdip,
- hdlp, MSI32_REC, msi_num, msiq_id);
+ hdlp, msiq_rec_type, msi_num, msiq_id);
return (ret);
}
@@ -686,11 +698,11 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
return (ret);
if ((ret = px_lib_msi_setstate(dip, msi_num,
- PCI_MSI_STATE_DELIVERED)) != DDI_SUCCESS)
+ PCI_MSI_STATE_IDLE)) != DDI_SUCCESS)
return (ret);
ret = px_rem_msiq_intr(dip, rdip,
- hdlp, MSI32_REC, msi_num, msiq_id);
+ hdlp, msiq_rec_type, msi_num, msiq_id);
hdlp->ih_vector = 0;
break;
@@ -705,7 +717,7 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip);
if ((ret = pci_msi_configure(rdip, hdlp->ih_type,
- nintrs, hdlp->ih_inum, msi_state_p->msi_addr32,
+ nintrs, hdlp->ih_inum, msi_addr,
msi_num & ~(nintrs - 1))) != DDI_SUCCESS)
return (ret);
@@ -724,7 +736,7 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum,
px_msiqid_to_devino(px_p, msiq_id), PX_INTR_STATE_ENABLE,
- MSI32_REC, msi_num);
+ msiq_rec_type, msi_num);
break;
case DDI_INTROP_DISABLE:
@@ -744,7 +756,7 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
ret = px_ib_update_intr_state(px_p, rdip,
hdlp->ih_inum, px_msiqid_to_devino(px_p, msiq_id),
- PX_INTR_STATE_DISABLE, MSI32_REC, msi_num);
+ PX_INTR_STATE_DISABLE, msiq_rec_type, msi_num);
break;
case DDI_INTROP_BLOCKENABLE:
@@ -752,7 +764,7 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
msi_num = hdlp->ih_vector;
if ((ret = pci_msi_configure(rdip, hdlp->ih_type,
- nintrs, hdlp->ih_inum, msi_state_p->msi_addr32,
+ nintrs, hdlp->ih_inum, msi_addr,
msi_num & ~(nintrs - 1))) != DDI_SUCCESS)
return (ret);
@@ -767,8 +779,8 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
if ((ret = px_ib_update_intr_state(px_p, rdip,
hdlp->ih_inum + i, px_msiqid_to_devino(px_p,
- msiq_id), PX_INTR_STATE_ENABLE, MSI32_REC, msi_num))
- != DDI_SUCCESS)
+ msiq_id), PX_INTR_STATE_ENABLE, msiq_rec_type,
+ msi_num)) != DDI_SUCCESS)
return (ret);
}
@@ -793,7 +805,7 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
if ((ret = px_ib_update_intr_state(px_p, rdip,
hdlp->ih_inum + i, px_msiqid_to_devino(px_p,
- msiq_id), PX_INTR_STATE_DISABLE, MSI32_REC,
+ msiq_id), PX_INTR_STATE_DISABLE, msiq_rec_type,
msi_num)) != DDI_SUCCESS)
return (ret);
}
@@ -816,9 +828,6 @@ px_msix_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
/* XXX - a new interface may be needed */
ret = pci_msi_get_nintrs(rdip, hdlp->ih_type, (int *)result);
break;
- case DDI_INTROP_SUPPORTED_TYPES:
- ret = pci_msi_get_supported_type(rdip, (int *)result);
- break;
default:
ret = DDI_ENOTSUP;
break;
diff --git a/usr/src/uts/sun4/io/px/px_pci.c b/usr/src/uts/sun4/io/px/px_pci.c
index c3f6ac5e0b..02be175437 100644
--- a/usr/src/uts/sun4/io/px/px_pci.c
+++ b/usr/src/uts/sun4/io/px/px_pci.c
@@ -50,6 +50,13 @@
#include "px_pci.h"
#include "px_debug.h"
+/*
+ * PXB MSI tunable:
+ *
+ * By default MSI is enabled on all supported platforms.
+ */
+boolean_t pxb_enable_msi = B_TRUE;
+
static int pxb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
off_t, off_t, caddr_t *);
static int pxb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
@@ -370,10 +377,7 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
goto fail;
}
- /* Do not support FIXED interrupts at this time, only MSI */
- intr_types &= ~DDI_INTR_TYPE_FIXED;
-
- if (intr_types & DDI_INTR_TYPE_MSI) {
+ if ((intr_types & DDI_INTR_TYPE_MSI) && pxb_enable_msi) {
if (pxb_intr_init(pxb, DDI_INTR_TYPE_MSI) == DDI_SUCCESS)
intr_types = DDI_INTR_TYPE_MSI;
else
@@ -935,7 +939,7 @@ pxb_intr_init(pxb_devstate_t *pxb, int intr_type) {
pxb->pxb_init_flags |= PXB_INIT_HTABLE;
ret = ddi_intr_alloc(dip, pxb->pxb_htable, intr_type,
- 0, request, &count, 0);
+ 0, request, &count, DDI_INTR_ALLOC_NORMAL);
if ((ret != DDI_SUCCESS) || (count == 0)) {
DBG(DBG_ATTACH, dip,
"ddi_intr_alloc() ret: %d ask: %d actual: %d\n",
diff --git a/usr/src/uts/sun4/io/px/px_pec.c b/usr/src/uts/sun4/io/px/px_pec.c
index 173e906d15..8da111855d 100644
--- a/usr/src/uts/sun4/io/px/px_pec.c
+++ b/usr/src/uts/sun4/io/px/px_pec.c
@@ -121,38 +121,17 @@ px_pec_attach(px_t *px_p)
*pfnlp = mmu_btop(rng_addr + rng_size);
}
- /*
- * Register a function to disable pec error interrupts during a panic.
- * do in px_attach. bus_func_register(BF_TYPE_ERRDIS,
- * (busfunc_t)pec_disable_pci_errors, pec_p);
- */
-
mutex_init(&pec_p->pec_pokefault_mutex, NULL, MUTEX_DRIVER,
(void *)px_p->px_fm_ibc);
return (DDI_SUCCESS);
}
-uint_t
-pec_disable_px_errors(px_pec_t *pec_p)
-{
- px_t *px_p = pec_p->pec_px_p;
- px_ib_t *ib_p = px_p->px_ib_p;
-
- /*
- * Disable error interrupts via the interrupt mapping register.
- */
- px_ib_intr_disable(ib_p, px_p->px_inos[PX_INTR_PEC], IB_INTR_NOWAIT);
- return (BF_NONE);
-}
-
void
px_pec_detach(px_t *px_p)
{
dev_info_t *dip = px_p->px_dip;
px_pec_t *pec_p = px_p->px_pec_p;
- px_ib_t *ib_p = px_p->px_ib_p;
- devino_t ino = px_p->px_inos[PX_INTR_PEC];
/*
* Free the pokefault mutex.
@@ -161,18 +140,6 @@ px_pec_detach(px_t *px_p)
mutex_destroy(&pec_p->pec_pokefault_mutex);
/*
- * Remove the pci error interrupt handler.
- */
- px_ib_intr_disable(ib_p, ino, IB_INTR_WAIT);
- ddi_remove_intr(dip, 0, NULL);
-
- /*
- * Remove the error disable function.
- */
- bus_func_unregister(BF_TYPE_ERRDIS,
- (busfunc_t)pec_disable_px_errors, pec_p);
-
- /*
* Remove interrupt handlers to process correctable/fatal/non fatal
* PCIE messages.
*/
diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.c b/usr/src/uts/sun4u/io/px/px_lib4u.c
index 07daff7f4e..c213962d27 100644
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c
@@ -1925,10 +1925,10 @@ px_err_rem_intr(px_fault_t *px_fault_p)
dev_info_t *dip = px_fault_p->px_fh_dip;
px_t *px_p = DIP_TO_STATE(dip);
- rem_ivintr(px_fault_p->px_fh_sysino, NULL);
-
px_ib_intr_disable(px_p->px_ib_p, px_fault_p->px_intr_ino,
IB_INTR_WAIT);
+
+ rem_ivintr(px_fault_p->px_fh_sysino, NULL);
}
#ifdef FMA
diff --git a/usr/src/uts/sun4u/io/sysiosbus.c b/usr/src/uts/sun4u/io/sysiosbus.c
index 3f6297da67..665252a8d5 100644
--- a/usr/src/uts/sun4u/io/sysiosbus.c
+++ b/usr/src/uts/sun4u/io/sysiosbus.c
@@ -1810,8 +1810,10 @@ sbus_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, intr_handler->funcp,
intr_handler->arg1, intr_handler->arg2);
- if (ret != DDI_SUCCESS)
- goto done;
+ if (ret != DDI_SUCCESS) {
+ mutex_exit(&softsp->intr_poll_list_lock);
+ goto done;
+ }
if ((slot >= EXT_SBUS_SLOTS) ||
(softsp->intr_hndlr_cnt[slot] == 0)) {
diff --git a/usr/src/uts/sun4u/sys/sysiosbus.h b/usr/src/uts/sun4u/sys/sysiosbus.h
index 22a21bc5e2..d72c1c0aa3 100644
--- a/usr/src/uts/sun4u/sys/sysiosbus.h
+++ b/usr/src/uts/sun4u/sys/sysiosbus.h
@@ -374,6 +374,7 @@ struct sysio_parent_private_data {
int par_nreg; /* number of regs */
struct regspec *par_reg; /* array of regs */
int par_nintr; /* number of interrupts */
+ struct sysiointrspec *par_intr; /* array of possible interrupts */
int par_nrng; /* number of ranges */
struct rangespec *par_rng; /* array of ranges */
uint_t slot; /* Slot number, on this sbus */
diff --git a/usr/src/uts/sun4v/io/px/px_lib4v.c b/usr/src/uts/sun4v/io/px/px_lib4v.c
index 33b507ac77..8a611ed352 100644
--- a/usr/src/uts/sun4v/io/px/px_lib4v.c
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.c
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/ddi.h>
+#include <sys/async.h>
#include <sys/sunddi.h>
#include <sys/ddifm.h>
#include <sys/fm/protocol.h>
@@ -233,9 +234,24 @@ px_lib_intr_settarget(dev_info_t *dip, sysino_t sysino, cpuid_t cpuid)
int
px_lib_intr_reset(dev_info_t *dip)
{
+ px_t *px_p = DIP_TO_STATE(dip);
+ px_ib_t *ib_p = px_p->px_ib_p;
+ px_ib_ino_info_t *ino_p;
+
DBG(DBG_LIB_INT, dip, "px_lib_intr_reset: dip 0x%p\n", dip);
- return (DDI_SUCCESS);
+ mutex_enter(&ib_p->ib_ino_lst_mutex);
+
+ /* Reset all Interrupts */
+ for (ino_p = ib_p->ib_ino_lst; ino_p; ino_p = ino_p->ino_next) {
+ if (px_lib_intr_setstate(dip, ino_p->ino_sysino,
+ INTR_IDLE_STATE) != DDI_SUCCESS)
+ return (BF_FATAL);
+ }
+
+ mutex_exit(&ib_p->ib_ino_lst_mutex);
+
+ return (BF_NONE);
}
/*ARGSUSED*/
@@ -1710,10 +1726,10 @@ px_err_rem_intr(px_fault_t *px_fault_p)
{
px_t *px_p = DIP_TO_STATE(px_fault_p->px_fh_dip);
- rem_ivintr(px_fault_p->px_fh_sysino, NULL);
-
px_ib_intr_disable(px_p->px_ib_p, px_fault_p->px_intr_ino,
IB_INTR_WAIT);
+
+ rem_ivintr(px_fault_p->px_fh_sysino, NULL);
}