summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorgovinda <none@none>2005-11-22 09:04:33 -0800
committergovinda <none@none>2005-11-22 09:04:33 -0800
commit9c75c6bf17b72bb057d7a8879feba77ece65241a (patch)
treeb57f6279f6889ff9a74d728102c7a18ac2739e22 /usr/src
parente487bac029356f425a49182e98c030a816c1fd60 (diff)
downloadillumos-gate-9c75c6bf17b72bb057d7a8879feba77ece65241a.tar.gz
6344060 Add MSI software support in bge driver
6344997 Add MSI software support in ohci driver 6344998 Add MSI software support in ehci driver 6348120 Add MSI software support in uhci driver 6349315 Add support for MSI64 transactions 6347105 Update MSI software support in mpt driver 6347109 Fix DDI framework MSI-X issues 6352670 Use proper behavior flag while calling ddi_intr_alloc 6343017 ddi_intr_remove_handler() returns DDI_FAILURE for MSI interrupts 6349316 px_pci should register legacy/fixed interrupt if MSIs are not available 6342807 Fire/Oberon driver panics on detach 6343874 Fire/Oberon Sun4u interrupt vector removal sequence incorrect 6343908 implement sun4v version of px_ib_intr_reset() 6348244 NGDR: panic when addboard resume on Starfire with socal 6348171 panic in ddi framework during esp_attach 6352440 sparc MDB ::interrupts output cleanup
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);
}