1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2016 Joyent, Inc. 14 */ 15 16 /* 17 * Device Context Base Address Array (DCBAA) Management and Scratchpad 18 * management. This is also used to manage the device slot contexts in shared 19 * memory. 20 * 21 * Please see the big theory statement in xhci.c for more information. 22 */ 23 24 #include <sys/usb/hcd/xhci/xhci.h> 25 #include <sys/byteorder.h> 26 27 static void 28 xhci_scratchpad_fini(xhci_t *xhcip) 29 { 30 xhci_scratchpad_t *xsp = &xhcip->xhci_scratchpad; 31 32 if (xsp->xsp_scratch_dma != NULL) { 33 int i, npages; 34 npages = xhcip->xhci_caps.xcap_max_scratch; 35 for (i = 0; i < npages; i++) { 36 xhci_dma_free(&xsp->xsp_scratch_dma[i]); 37 } 38 kmem_free(xsp->xsp_scratch_dma, 39 sizeof (xhci_dma_buffer_t) * npages); 40 xsp->xsp_scratch_dma = NULL; 41 } 42 xhci_dma_free(&xsp->xsp_addr_dma); 43 xsp->xsp_addrs = NULL; 44 } 45 46 void 47 xhci_context_fini(xhci_t *xhcip) 48 { 49 xhci_scratchpad_fini(xhcip); 50 xhci_dma_free(&xhcip->xhci_dcbaa.xdc_dma); 51 xhcip->xhci_dcbaa.xdc_base_addrs = NULL; 52 } 53 54 static int 55 xhci_scratchpad_alloc(xhci_t *xhcip) 56 { 57 int npages, i; 58 xhci_scratchpad_t *xsp; 59 ddi_device_acc_attr_t acc; 60 ddi_dma_attr_t attr; 61 62 /* 63 * First allocate the scratchpad table, then the actual pages. 64 */ 65 ASSERT(xhcip->xhci_caps.xcap_max_scratch > 0); 66 npages = xhcip->xhci_caps.xcap_max_scratch; 67 xhci_dma_acc_attr(xhcip, &acc); 68 xhci_dma_dma_attr(xhcip, &attr); 69 xsp = &xhcip->xhci_scratchpad; 70 if (xhci_dma_alloc(xhcip, &xsp->xsp_addr_dma, &attr, &acc, 71 B_TRUE, sizeof (uint64_t) * npages, B_FALSE) == B_FALSE) { 72 xhci_log(xhcip, "!failed to allocate DMA memory for device " 73 "context"); 74 return (ENOMEM); 75 } 76 77 xsp->xsp_addrs = (void *)xsp->xsp_addr_dma.xdb_va; 78 79 /* 80 * Note that the scratchpad memory itself can actually be relaxed, which 81 * is almost better, since we'll never actually access this memory 82 * ourselves, only use it to tear things down. As such, we also bump up 83 * the segment boundary restrictions, since we don't really have any for 84 * this memory. 85 */ 86 xhci_dma_scratchpad_attr(xhcip, &attr); 87 xsp->xsp_scratch_dma = kmem_zalloc(sizeof (xhci_dma_buffer_t) * npages, 88 KM_SLEEP); 89 for (i = 0; i < npages; i++) { 90 if (xhci_dma_alloc(xhcip, &xsp->xsp_scratch_dma[i], &attr, &acc, 91 B_TRUE, xhcip->xhci_caps.xcap_pagesize, B_FALSE) == 92 B_FALSE) { 93 /* 94 * It is safe for us to call xhci_scratchpad_fini() in a 95 * partially constructed state. Because we've zeroed the 96 * structures in the above allocation, the DMA buffer 97 * teardown code can handle these zeroed or partially 98 * initialized structures correctly. 99 */ 100 xhci_scratchpad_fini(xhcip); 101 xhci_log(xhcip, "!failed to allocate DMA memory for " 102 "device scratchpad"); 103 return (ENOMEM); 104 } 105 } 106 107 return (0); 108 } 109 110 /* 111 * We always allocate the DCBAA based on its maximum possible size, simplifying 112 * the code and at worst wasting only a couple hundred bytes. 113 */ 114 static int 115 xhci_dcbaa_alloc(xhci_t *xhcip) 116 { 117 xhci_dcbaa_t *dcb; 118 ddi_device_acc_attr_t acc; 119 ddi_dma_attr_t attr; 120 121 dcb = &xhcip->xhci_dcbaa; 122 xhci_dma_acc_attr(xhcip, &acc); 123 xhci_dma_dma_attr(xhcip, &attr); 124 if (xhci_dma_alloc(xhcip, &dcb->xdc_dma, &attr, &acc, 125 B_FALSE, sizeof (uint64_t) * XHCI_MAX_SLOTS, B_FALSE) == B_FALSE) { 126 xhci_log(xhcip, "!failed to allocate DMA memory for device " 127 "context"); 128 return (ENOMEM); 129 } 130 131 /* 132 * This lint gag is safe, because we always have at least a 64-byte 133 * alignment from the DMA attributes. 134 */ 135 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 136 dcb->xdc_base_addrs = (uint64_t *)dcb->xdc_dma.xdb_va; 137 return (0); 138 } 139 140 /* 141 * We are called to initialize the DCBAA every time that we start the 142 * controller. This happens both the first time we bring it up and after we 143 * reset it from errors. Therefore to initialize the DCBAA we need to do the 144 * following: 145 * 146 * o Allocate DMA memory (if it doesn't already exist) 147 * o If scratchpad slots have been requested, allocate and program them if 148 * necessary 149 * o Program the DCBAAP register. 150 */ 151 int 152 xhci_context_init(xhci_t *xhcip) 153 { 154 int ret; 155 xhci_dcbaa_t *dcb = &xhcip->xhci_dcbaa; 156 157 if (dcb->xdc_base_addrs == NULL) { 158 if ((ret = xhci_dcbaa_alloc(xhcip)) != 0) 159 return (ret); 160 } 161 162 bzero(dcb->xdc_base_addrs, sizeof (uint64_t) * XHCI_MAX_SLOTS); 163 if (xhcip->xhci_caps.xcap_max_scratch != 0) { 164 int i, npages; 165 xhci_scratchpad_t *xsp = &xhcip->xhci_scratchpad; 166 167 if (xsp->xsp_addrs == NULL && 168 (ret = xhci_scratchpad_alloc(xhcip)) != 0) { 169 xhci_context_fini(xhcip); 170 return (ret); 171 } 172 173 dcb->xdc_base_addrs[XHCI_DCBAA_SCRATCHPAD_INDEX] = 174 LE_64(xhci_dma_pa(&xsp->xsp_addr_dma)); 175 176 npages = xhcip->xhci_caps.xcap_max_scratch; 177 for (i = 0; i < npages; i++) { 178 xsp->xsp_addrs[i] = 179 LE_64(xhci_dma_pa(&xsp->xsp_scratch_dma[i])); 180 } 181 182 XHCI_DMA_SYNC(xsp->xsp_addr_dma, DDI_DMA_SYNC_FORDEV); 183 if (xhci_check_dma_handle(xhcip, &xsp->xsp_addr_dma) != 184 DDI_FM_OK) { 185 ddi_fm_service_impact(xhcip->xhci_dip, 186 DDI_SERVICE_LOST); 187 return (EIO); 188 } 189 } 190 191 XHCI_DMA_SYNC(dcb->xdc_dma, DDI_DMA_SYNC_FORDEV); 192 if (xhci_check_dma_handle(xhcip, &dcb->xdc_dma) != DDI_FM_OK) { 193 ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST); 194 return (EIO); 195 } 196 197 xhci_put64(xhcip, XHCI_R_OPER, XHCI_DCBAAP, 198 LE_64(xhci_dma_pa(&dcb->xdc_dma))); 199 if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) { 200 ddi_fm_service_impact(xhcip->xhci_dip, 201 DDI_SERVICE_LOST); 202 return (EIO); 203 } 204 205 return (0); 206 } 207 208 /* 209 * Initialize the default output context. It should already have been zeroed, so 210 * all we need to do is insert it into the right place in the device context 211 * array. 212 */ 213 boolean_t 214 xhci_context_slot_output_init(xhci_t *xhcip, xhci_device_t *xd) 215 { 216 xhci_dcbaa_t *dcb = &xhcip->xhci_dcbaa; 217 VERIFY(xd->xd_slot > 0 && 218 xd->xd_slot <= xhcip->xhci_caps.xcap_max_slots); 219 220 xhcip->xhci_dcbaa.xdc_base_addrs[xd->xd_slot] = 221 LE_64(xhci_dma_pa(&xd->xd_octx)); 222 XHCI_DMA_SYNC(dcb->xdc_dma, DDI_DMA_SYNC_FORDEV); 223 if (xhci_check_dma_handle(xhcip, &dcb->xdc_dma) != DDI_FM_OK) { 224 xhci_error(xhcip, "failed to initialize slot output context " 225 "for device on port %d, slot %d: fatal FM error " 226 "synchronizing DCBAA slot DMA memory", xd->xd_slot, 227 xd->xd_port); 228 xhci_fm_runtime_reset(xhcip); 229 return (B_FALSE); 230 } 231 232 return (B_TRUE); 233 } 234 235 void 236 xhci_context_slot_output_fini(xhci_t *xhcip, xhci_device_t *xd) 237 { 238 xhci_dcbaa_t *dcb = &xhcip->xhci_dcbaa; 239 VERIFY(xd->xd_slot > 0 && 240 xd->xd_slot <= xhcip->xhci_caps.xcap_max_slots); 241 242 xhcip->xhci_dcbaa.xdc_base_addrs[xd->xd_slot] = 0ULL; 243 XHCI_DMA_SYNC(dcb->xdc_dma, DDI_DMA_SYNC_FORDEV); 244 if (xhci_check_dma_handle(xhcip, &dcb->xdc_dma) != DDI_FM_OK) { 245 xhci_error(xhcip, "failed to finalize slot output context " 246 "for device on port %d, slot %d: fatal FM error " 247 "synchronizing DCBAA slot DMA memory", xd->xd_slot, 248 xd->xd_port); 249 xhci_fm_runtime_reset(xhcip); 250 } 251 } 252