diff options
Diffstat (limited to 'usr/src')
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 **)®s_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 *)®s_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 *)®s_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); } |