1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 25 * Copyright 2019 Joyent, Inc. 26 */ 27 28 #include <sys/sunddi.h> 29 #include <sys/sunndi.h> 30 #include <sys/iommulib.h> 31 #include <sys/amd_iommu.h> 32 #include <sys/pci_cap.h> 33 #include <sys/bootconf.h> 34 #include <sys/ddidmareq.h> 35 36 #include "amd_iommu_impl.h" 37 #include "amd_iommu_acpi.h" 38 #include "amd_iommu_page_tables.h" 39 40 static int amd_iommu_fini(amd_iommu_t *iommu, int type); 41 static void amd_iommu_teardown_interrupts(amd_iommu_t *iommu); 42 static void amd_iommu_stop(amd_iommu_t *iommu); 43 44 static int amd_iommu_probe(iommulib_handle_t handle, dev_info_t *rdip); 45 static int amd_iommu_allochdl(iommulib_handle_t handle, 46 dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr, 47 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *dma_handlep); 48 static int amd_iommu_freehdl(iommulib_handle_t handle, 49 dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle); 50 static int amd_iommu_bindhdl(iommulib_handle_t handle, dev_info_t *dip, 51 dev_info_t *rdip, ddi_dma_handle_t dma_handle, 52 struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookiep, 53 uint_t *ccountp); 54 static int amd_iommu_unbindhdl(iommulib_handle_t handle, 55 dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle); 56 static int amd_iommu_sync(iommulib_handle_t handle, dev_info_t *dip, 57 dev_info_t *rdip, ddi_dma_handle_t dma_handle, off_t off, 58 size_t len, uint_t cache_flags); 59 static int amd_iommu_win(iommulib_handle_t handle, dev_info_t *dip, 60 dev_info_t *rdip, ddi_dma_handle_t dma_handle, uint_t win, 61 off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep, 62 uint_t *ccountp); 63 static int amd_iommu_mapobject(iommulib_handle_t handle, dev_info_t *dip, 64 dev_info_t *rdip, ddi_dma_handle_t dma_handle, 65 struct ddi_dma_req *dmareq, ddi_dma_obj_t *dmao); 66 static int amd_iommu_unmapobject(iommulib_handle_t handle, dev_info_t *dip, 67 dev_info_t *rdip, ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao); 68 69 static int unmap_current_window(amd_iommu_t *iommu, dev_info_t *rdip, 70 ddi_dma_cookie_t *cookie_array, uint_t ccount, int ncookies, int locked); 71 72 extern void *device_arena_alloc(size_t size, int vm_flag); 73 extern void device_arena_free(void * vaddr, size_t size); 74 75 ddi_dma_attr_t amd_iommu_dma_attr = { 76 DMA_ATTR_V0, 77 0U, /* dma_attr_addr_lo */ 78 0xffffffffffffffffULL, /* dma_attr_addr_hi */ 79 0xffffffffU, /* dma_attr_count_max */ 80 (uint64_t)4096, /* dma_attr_align */ 81 1, /* dma_attr_burstsizes */ 82 64, /* dma_attr_minxfer */ 83 0xffffffffU, /* dma_attr_maxxfer */ 84 0xffffffffU, /* dma_attr_seg */ 85 1, /* dma_attr_sgllen, variable */ 86 64, /* dma_attr_granular */ 87 0 /* dma_attr_flags */ 88 }; 89 90 ddi_device_acc_attr_t amd_iommu_devacc = { 91 DDI_DEVICE_ATTR_V0, 92 DDI_NEVERSWAP_ACC, 93 DDI_STRICTORDER_ACC 94 }; 95 96 struct iommulib_ops amd_iommulib_ops = { 97 IOMMU_OPS_VERSION, 98 AMD_IOMMU, 99 "AMD IOMMU Vers. 1", 100 NULL, 101 amd_iommu_probe, 102 amd_iommu_allochdl, 103 amd_iommu_freehdl, 104 amd_iommu_bindhdl, 105 amd_iommu_unbindhdl, 106 amd_iommu_sync, 107 amd_iommu_win, 108 amd_iommu_mapobject, 109 amd_iommu_unmapobject, 110 }; 111 112 static kmutex_t amd_iommu_pgtable_lock; 113 114 static int 115 amd_iommu_register(amd_iommu_t *iommu) 116 { 117 dev_info_t *dip = iommu->aiomt_dip; 118 const char *driver = ddi_driver_name(dip); 119 int instance = ddi_get_instance(dip); 120 iommulib_ops_t *iommulib_ops; 121 iommulib_handle_t handle; 122 const char *f = "amd_iommu_register"; 123 124 iommulib_ops = kmem_zalloc(sizeof (iommulib_ops_t), KM_SLEEP); 125 126 *iommulib_ops = amd_iommulib_ops; 127 128 iommulib_ops->ilops_data = (void *)iommu; 129 iommu->aiomt_iommulib_ops = iommulib_ops; 130 131 if (iommulib_iommu_register(dip, iommulib_ops, &handle) 132 != DDI_SUCCESS) { 133 cmn_err(CE_WARN, "%s: %s%d: Register with iommulib " 134 "failed idx=%d", f, driver, instance, iommu->aiomt_idx); 135 kmem_free(iommulib_ops, sizeof (iommulib_ops_t)); 136 return (DDI_FAILURE); 137 } 138 139 iommu->aiomt_iommulib_handle = handle; 140 141 return (DDI_SUCCESS); 142 } 143 144 static int 145 amd_iommu_unregister(amd_iommu_t *iommu) 146 { 147 if (iommu->aiomt_iommulib_handle == NULL) { 148 /* we never registered */ 149 return (DDI_SUCCESS); 150 } 151 152 if (iommulib_iommu_unregister(iommu->aiomt_iommulib_handle) 153 != DDI_SUCCESS) { 154 return (DDI_FAILURE); 155 } 156 157 kmem_free(iommu->aiomt_iommulib_ops, sizeof (iommulib_ops_t)); 158 iommu->aiomt_iommulib_ops = NULL; 159 iommu->aiomt_iommulib_handle = NULL; 160 161 return (DDI_SUCCESS); 162 } 163 164 static int 165 amd_iommu_setup_passthru(amd_iommu_t *iommu) 166 { 167 gfx_entry_t *gfxp; 168 dev_info_t *dip; 169 170 /* 171 * Setup passthru mapping for "special" devices 172 */ 173 amd_iommu_set_passthru(iommu, NULL); 174 175 for (gfxp = gfx_devinfo_list; gfxp; gfxp = gfxp->g_next) { 176 gfxp->g_ref++; 177 dip = gfxp->g_dip; 178 if (dip) { 179 amd_iommu_set_passthru(iommu, dip); 180 } 181 gfxp->g_ref--; 182 } 183 184 return (DDI_SUCCESS); 185 } 186 187 static int 188 amd_iommu_start(amd_iommu_t *iommu) 189 { 190 dev_info_t *dip = iommu->aiomt_dip; 191 int instance = ddi_get_instance(dip); 192 const char *driver = ddi_driver_name(dip); 193 amd_iommu_acpi_ivhd_t *hinfop; 194 const char *f = "amd_iommu_start"; 195 196 hinfop = amd_iommu_lookup_all_ivhd(); 197 198 /* 199 * Disable HT tunnel translation. 200 * XXX use ACPI 201 */ 202 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 203 AMD_IOMMU_HT_TUN_ENABLE, 0); 204 205 if (hinfop) { 206 if (amd_iommu_debug) { 207 cmn_err(CE_NOTE, 208 "amd_iommu: using ACPI for CTRL registers"); 209 } 210 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 211 AMD_IOMMU_ISOC, hinfop->ach_Isoc); 212 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 213 AMD_IOMMU_RESPASSPW, hinfop->ach_ResPassPW); 214 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 215 AMD_IOMMU_PASSPW, hinfop->ach_PassPW); 216 } 217 218 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 219 AMD_IOMMU_INVTO, 5); 220 221 222 /* 223 * The Device table entry bit 0 (V) controls whether the device 224 * table entry is valid for address translation and Device table 225 * entry bit 128 (IV) controls whether interrupt remapping is valid. 226 * By setting both to zero we are essentially doing pass-thru. Since 227 * this table is zeroed on allocation, essentially we will have 228 * pass-thru when IOMMU is enabled. 229 */ 230 231 /* Finally enable the IOMMU ... */ 232 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 233 AMD_IOMMU_ENABLE, 1); 234 235 if (amd_iommu_debug) { 236 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. " 237 "Successfully started AMD IOMMU", f, driver, instance, 238 iommu->aiomt_idx); 239 } 240 cmn_err(CE_NOTE, "AMD IOMMU (%d,%d) enabled", 241 instance, iommu->aiomt_idx); 242 243 return (DDI_SUCCESS); 244 } 245 246 static void 247 amd_iommu_stop(amd_iommu_t *iommu) 248 { 249 dev_info_t *dip = iommu->aiomt_dip; 250 int instance = ddi_get_instance(dip); 251 const char *driver = ddi_driver_name(dip); 252 const char *f = "amd_iommu_stop"; 253 254 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 255 AMD_IOMMU_ENABLE, 0); 256 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 257 AMD_IOMMU_EVENTINT_ENABLE, 0); 258 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 259 AMD_IOMMU_COMWAITINT_ENABLE, 0); 260 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 261 AMD_IOMMU_EVENTLOG_ENABLE, 0); 262 263 /* 264 * Disable translation on HT tunnel traffic 265 */ 266 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 267 AMD_IOMMU_HT_TUN_ENABLE, 0); 268 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 269 AMD_IOMMU_CMDBUF_ENABLE, 0); 270 271 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMYU idx=%d. " 272 "Successfully stopped AMD IOMMU", f, driver, instance, 273 iommu->aiomt_idx); 274 } 275 276 static int 277 amd_iommu_setup_tables_and_buffers(amd_iommu_t *iommu) 278 { 279 dev_info_t *dip = iommu->aiomt_dip; 280 int instance = ddi_get_instance(dip); 281 const char *driver = ddi_driver_name(dip); 282 uint32_t dma_bufsz; 283 caddr_t addr; 284 uint32_t sz; 285 uint32_t p2sz; 286 int i; 287 uint64_t *dentry; 288 int err; 289 const char *f = "amd_iommu_setup_tables_and_buffers"; 290 291 /* 292 * We will put the Device Table, Command Buffer and 293 * Event Log in contiguous memory. Allocate the maximum 294 * size allowed for such structures 295 * Device Table: 256b * 64K = 32B * 64K 296 * Command Buffer: 128b * 32K = 16B * 32K 297 * Event Log: 128b * 32K = 16B * 32K 298 */ 299 iommu->aiomt_devtbl_sz = (1<<AMD_IOMMU_DEVTBL_SZ) * AMD_IOMMU_DEVENT_SZ; 300 iommu->aiomt_cmdbuf_sz = (1<<AMD_IOMMU_CMDBUF_SZ) * AMD_IOMMU_CMD_SZ; 301 iommu->aiomt_eventlog_sz = 302 (1<<AMD_IOMMU_EVENTLOG_SZ) * AMD_IOMMU_EVENT_SZ; 303 304 dma_bufsz = iommu->aiomt_devtbl_sz + iommu->aiomt_cmdbuf_sz 305 + iommu->aiomt_eventlog_sz; 306 307 /* 308 * Alloc a DMA handle. 309 */ 310 err = ddi_dma_alloc_handle(dip, &amd_iommu_dma_attr, 311 DDI_DMA_SLEEP, NULL, &iommu->aiomt_dmahdl); 312 if (err != DDI_SUCCESS) { 313 cmn_err(CE_WARN, "%s: %s%d: Cannot alloc DMA handle for " 314 "AMD IOMMU tables and buffers", f, driver, instance); 315 return (DDI_FAILURE); 316 } 317 318 /* 319 * Alloc memory for tables and buffers 320 * XXX remove cast to size_t 321 */ 322 err = ddi_dma_mem_alloc(iommu->aiomt_dmahdl, dma_bufsz, 323 &amd_iommu_devacc, DDI_DMA_CONSISTENT|IOMEM_DATA_UNCACHED, 324 DDI_DMA_SLEEP, NULL, (caddr_t *)&iommu->aiomt_dma_bufva, 325 (size_t *)&iommu->aiomt_dma_mem_realsz, &iommu->aiomt_dma_mem_hdl); 326 if (err != DDI_SUCCESS) { 327 cmn_err(CE_WARN, "%s: %s%d: Cannot alloc memory for DMA " 328 "to AMD IOMMU tables and buffers", f, driver, instance); 329 iommu->aiomt_dma_bufva = NULL; 330 iommu->aiomt_dma_mem_realsz = 0; 331 ddi_dma_free_handle(&iommu->aiomt_dmahdl); 332 iommu->aiomt_dmahdl = NULL; 333 return (DDI_FAILURE); 334 } 335 336 /* 337 * The VA must be 4K aligned and >= table size 338 */ 339 ASSERT(((uintptr_t)iommu->aiomt_dma_bufva & 340 AMD_IOMMU_TABLE_ALIGN) == 0); 341 ASSERT(iommu->aiomt_dma_mem_realsz >= dma_bufsz); 342 343 /* 344 * Now bind the handle 345 */ 346 err = ddi_dma_addr_bind_handle(iommu->aiomt_dmahdl, NULL, 347 iommu->aiomt_dma_bufva, iommu->aiomt_dma_mem_realsz, 348 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 349 NULL, &iommu->aiomt_buf_dma_cookie, &iommu->aiomt_buf_dma_ncookie); 350 if (err != DDI_DMA_MAPPED) { 351 cmn_err(CE_WARN, "%s: %s%d: Cannot bind memory for DMA " 352 "to AMD IOMMU tables and buffers. bufrealsz=%p", 353 f, driver, instance, 354 (void *)(uintptr_t)iommu->aiomt_dma_mem_realsz); 355 iommu->aiomt_buf_dma_cookie.dmac_laddress = 0; 356 iommu->aiomt_buf_dma_cookie.dmac_size = 0; 357 iommu->aiomt_buf_dma_cookie.dmac_type = 0; 358 iommu->aiomt_buf_dma_ncookie = 0; 359 ddi_dma_mem_free(&iommu->aiomt_dma_mem_hdl); 360 iommu->aiomt_dma_mem_hdl = NULL; 361 iommu->aiomt_dma_bufva = NULL; 362 iommu->aiomt_dma_mem_realsz = 0; 363 ddi_dma_free_handle(&iommu->aiomt_dmahdl); 364 iommu->aiomt_dmahdl = NULL; 365 return (DDI_FAILURE); 366 } 367 368 /* 369 * We assume the DMA engine on the IOMMU is capable of handling the 370 * whole table buffer in a single cookie. If not and multiple cookies 371 * are needed we fail. 372 */ 373 if (iommu->aiomt_buf_dma_ncookie != 1) { 374 cmn_err(CE_WARN, "%s: %s%d: Cannot handle multiple " 375 "cookies for DMA to AMD IOMMU tables and buffers. " 376 "#cookies=%u", f, driver, instance, 377 iommu->aiomt_buf_dma_ncookie); 378 (void) ddi_dma_unbind_handle(iommu->aiomt_dmahdl); 379 iommu->aiomt_buf_dma_cookie.dmac_laddress = 0; 380 iommu->aiomt_buf_dma_cookie.dmac_size = 0; 381 iommu->aiomt_buf_dma_cookie.dmac_type = 0; 382 iommu->aiomt_buf_dma_ncookie = 0; 383 ddi_dma_mem_free(&iommu->aiomt_dma_mem_hdl); 384 iommu->aiomt_dma_mem_hdl = NULL; 385 iommu->aiomt_dma_bufva = NULL; 386 iommu->aiomt_dma_mem_realsz = 0; 387 ddi_dma_free_handle(&iommu->aiomt_dmahdl); 388 iommu->aiomt_dmahdl = NULL; 389 return (DDI_FAILURE); 390 } 391 392 /* 393 * The address in the cookie must be 4K aligned and >= table size 394 */ 395 ASSERT((iommu->aiomt_buf_dma_cookie.dmac_cookie_addr 396 & AMD_IOMMU_TABLE_ALIGN) == 0); 397 ASSERT(iommu->aiomt_buf_dma_cookie.dmac_size 398 <= iommu->aiomt_dma_mem_realsz); 399 ASSERT(iommu->aiomt_buf_dma_cookie.dmac_size >= dma_bufsz); 400 401 /* 402 * Setup the device table pointers in the iommu struct as 403 * well as the IOMMU device table register 404 */ 405 iommu->aiomt_devtbl = iommu->aiomt_dma_bufva; 406 bzero(iommu->aiomt_devtbl, iommu->aiomt_devtbl_sz); 407 408 /* 409 * Set V=1 and TV = 0, so any inadvertant pass-thrus cause 410 * page faults. Also set SE bit so we aren't swamped with 411 * page fault messages 412 */ 413 for (i = 0; i <= AMD_IOMMU_MAX_DEVICEID; i++) { 414 /*LINTED*/ 415 dentry = (uint64_t *)&iommu->aiomt_devtbl 416 [i * AMD_IOMMU_DEVTBL_ENTRY_SZ]; 417 AMD_IOMMU_REG_SET64(dentry, AMD_IOMMU_DEVTBL_V, 1); 418 AMD_IOMMU_REG_SET64(&(dentry[1]), AMD_IOMMU_DEVTBL_SE, 1); 419 } 420 421 addr = (caddr_t)(uintptr_t)iommu->aiomt_buf_dma_cookie.dmac_cookie_addr; 422 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va), 423 AMD_IOMMU_DEVTABBASE, ((uint64_t)(uintptr_t)addr) >> 12); 424 sz = (iommu->aiomt_devtbl_sz >> 12) - 1; 425 ASSERT(sz <= ((1 << 9) - 1)); 426 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va), 427 AMD_IOMMU_DEVTABSIZE, sz); 428 429 /* 430 * Setup the command buffer pointers 431 */ 432 iommu->aiomt_cmdbuf = iommu->aiomt_devtbl + 433 iommu->aiomt_devtbl_sz; 434 bzero(iommu->aiomt_cmdbuf, iommu->aiomt_cmdbuf_sz); 435 addr += iommu->aiomt_devtbl_sz; 436 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va), 437 AMD_IOMMU_COMBASE, ((uint64_t)(uintptr_t)addr) >> 12); 438 439 p2sz = AMD_IOMMU_CMDBUF_SZ; 440 ASSERT(p2sz >= AMD_IOMMU_CMDBUF_MINSZ && 441 p2sz <= AMD_IOMMU_CMDBUF_MAXSZ); 442 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va), 443 AMD_IOMMU_COMLEN, p2sz); 444 /*LINTED*/ 445 iommu->aiomt_cmd_tail = (uint32_t *)iommu->aiomt_cmdbuf; 446 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_head_va), 447 AMD_IOMMU_CMDHEADPTR, 0); 448 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_tail_va), 449 AMD_IOMMU_CMDTAILPTR, 0); 450 451 /* 452 * Setup the event log pointers 453 */ 454 iommu->aiomt_eventlog = iommu->aiomt_cmdbuf + 455 iommu->aiomt_eventlog_sz; 456 bzero(iommu->aiomt_eventlog, iommu->aiomt_eventlog_sz); 457 addr += iommu->aiomt_cmdbuf_sz; 458 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va), 459 AMD_IOMMU_EVENTBASE, ((uint64_t)(uintptr_t)addr) >> 12); 460 p2sz = AMD_IOMMU_EVENTLOG_SZ; 461 ASSERT(p2sz >= AMD_IOMMU_EVENTLOG_MINSZ && 462 p2sz <= AMD_IOMMU_EVENTLOG_MAXSZ); 463 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va), 464 AMD_IOMMU_EVENTLEN, sz); 465 /*LINTED*/ 466 iommu->aiomt_event_head = (uint32_t *)iommu->aiomt_eventlog; 467 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_head_va), 468 AMD_IOMMU_EVENTHEADPTR, 0); 469 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_tail_va), 470 AMD_IOMMU_EVENTTAILPTR, 0); 471 472 /* dma sync so device sees this init */ 473 SYNC_FORDEV(iommu->aiomt_dmahdl); 474 475 if (amd_iommu_debug & AMD_IOMMU_DEBUG_TABLES) { 476 cmn_err(CE_NOTE, "%s: %s%d: successfully setup AMD IOMMU " 477 "tables, idx=%d", f, driver, instance, iommu->aiomt_idx); 478 } 479 480 return (DDI_SUCCESS); 481 } 482 483 static void 484 amd_iommu_teardown_tables_and_buffers(amd_iommu_t *iommu, int type) 485 { 486 dev_info_t *dip = iommu->aiomt_dip; 487 int instance = ddi_get_instance(dip); 488 const char *driver = ddi_driver_name(dip); 489 const char *f = "amd_iommu_teardown_tables_and_buffers"; 490 491 iommu->aiomt_eventlog = NULL; 492 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va), 493 AMD_IOMMU_EVENTBASE, 0); 494 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va), 495 AMD_IOMMU_EVENTLEN, 0); 496 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_head_va), 497 AMD_IOMMU_EVENTHEADPTR, 0); 498 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_head_va), 499 AMD_IOMMU_EVENTTAILPTR, 0); 500 501 502 iommu->aiomt_cmdbuf = NULL; 503 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va), 504 AMD_IOMMU_COMBASE, 0); 505 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va), 506 AMD_IOMMU_COMLEN, 0); 507 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_head_va), 508 AMD_IOMMU_CMDHEADPTR, 0); 509 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_head_va), 510 AMD_IOMMU_CMDTAILPTR, 0); 511 512 513 iommu->aiomt_devtbl = NULL; 514 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va), 515 AMD_IOMMU_DEVTABBASE, 0); 516 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va), 517 AMD_IOMMU_DEVTABSIZE, 0); 518 519 if (iommu->aiomt_dmahdl == NULL || type == AMD_IOMMU_QUIESCE) 520 return; 521 522 /* Unbind the handle */ 523 if (ddi_dma_unbind_handle(iommu->aiomt_dmahdl) != DDI_SUCCESS) { 524 cmn_err(CE_WARN, "%s: %s%d: failed to unbind handle: " 525 "%p for IOMMU idx=%d", f, driver, instance, 526 (void *)iommu->aiomt_dmahdl, iommu->aiomt_idx); 527 } 528 iommu->aiomt_buf_dma_cookie.dmac_laddress = 0; 529 iommu->aiomt_buf_dma_cookie.dmac_size = 0; 530 iommu->aiomt_buf_dma_cookie.dmac_type = 0; 531 iommu->aiomt_buf_dma_ncookie = 0; 532 533 /* Free the table memory allocated for DMA */ 534 ddi_dma_mem_free(&iommu->aiomt_dma_mem_hdl); 535 iommu->aiomt_dma_mem_hdl = NULL; 536 iommu->aiomt_dma_bufva = NULL; 537 iommu->aiomt_dma_mem_realsz = 0; 538 539 /* Free the DMA handle */ 540 ddi_dma_free_handle(&iommu->aiomt_dmahdl); 541 iommu->aiomt_dmahdl = NULL; 542 } 543 544 static void 545 amd_iommu_enable_interrupts(amd_iommu_t *iommu) 546 { 547 ASSERT(AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va), 548 AMD_IOMMU_CMDBUF_RUN) == 0); 549 ASSERT(AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va), 550 AMD_IOMMU_EVENT_LOG_RUN) == 0); 551 552 /* Must be set prior to enabling command buffer */ 553 /* Must be set prior to enabling event logging */ 554 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 555 AMD_IOMMU_CMDBUF_ENABLE, 1); 556 /* No interrupts for completion wait - too heavy weight. use polling */ 557 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 558 AMD_IOMMU_COMWAITINT_ENABLE, 0); 559 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 560 AMD_IOMMU_EVENTLOG_ENABLE, 1); 561 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va), 562 AMD_IOMMU_EVENTINT_ENABLE, 1); 563 } 564 565 static int 566 amd_iommu_setup_exclusion(amd_iommu_t *iommu) 567 { 568 amd_iommu_acpi_ivmd_t *minfop; 569 570 minfop = amd_iommu_lookup_all_ivmd(); 571 572 if (minfop && minfop->acm_ExclRange == 1) { 573 cmn_err(CE_NOTE, "Programming exclusion range"); 574 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va), 575 AMD_IOMMU_EXCL_BASE_ADDR, 576 minfop->acm_ivmd_phys_start >> 12); 577 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va), 578 AMD_IOMMU_EXCL_BASE_ALLOW, 1); 579 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va), 580 AMD_IOMMU_EXCL_BASE_EXEN, 1); 581 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_lim_va), 582 AMD_IOMMU_EXCL_LIM, (minfop->acm_ivmd_phys_start + 583 minfop->acm_ivmd_phys_len) >> 12); 584 } else { 585 if (amd_iommu_debug) { 586 cmn_err(CE_NOTE, "Skipping exclusion range"); 587 } 588 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va), 589 AMD_IOMMU_EXCL_BASE_ADDR, 0); 590 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va), 591 AMD_IOMMU_EXCL_BASE_ALLOW, 1); 592 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va), 593 AMD_IOMMU_EXCL_BASE_EXEN, 0); 594 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_lim_va), 595 AMD_IOMMU_EXCL_LIM, 0); 596 } 597 598 return (DDI_SUCCESS); 599 } 600 601 static void 602 amd_iommu_teardown_exclusion(amd_iommu_t *iommu) 603 { 604 (void) amd_iommu_setup_exclusion(iommu); 605 } 606 607 static uint_t 608 amd_iommu_intr_handler(caddr_t arg1, caddr_t arg2) 609 { 610 /*LINTED*/ 611 amd_iommu_t *iommu = (amd_iommu_t *)arg1; 612 dev_info_t *dip = iommu->aiomt_dip; 613 int instance = ddi_get_instance(dip); 614 const char *driver = ddi_driver_name(dip); 615 const char *f = "amd_iommu_intr_handler"; 616 617 ASSERT(arg1); 618 ASSERT(arg2 == NULL); 619 620 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 621 cmn_err(CE_NOTE, "%s: %s%d: IOMMU unit idx=%d. In INTR handler", 622 f, driver, instance, iommu->aiomt_idx); 623 } 624 625 if (AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va), 626 AMD_IOMMU_EVENT_LOG_INT) == 1) { 627 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 628 cmn_err(CE_NOTE, "%s: %s%d: IOMMU unit idx=%d " 629 "Event Log Interrupt", f, driver, instance, 630 iommu->aiomt_idx); 631 } 632 (void) amd_iommu_read_log(iommu, AMD_IOMMU_LOG_DISPLAY); 633 WAIT_SEC(1); 634 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_status_va), 635 AMD_IOMMU_EVENT_LOG_INT, 1); 636 return (DDI_INTR_CLAIMED); 637 } 638 639 if (AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va), 640 AMD_IOMMU_EVENT_OVERFLOW_INT) == 1) { 641 cmn_err(CE_NOTE, "!%s: %s%d: IOMMU unit idx=%d " 642 "Event Overflow Interrupt", f, driver, instance, 643 iommu->aiomt_idx); 644 (void) amd_iommu_read_log(iommu, AMD_IOMMU_LOG_DISCARD); 645 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_status_va), 646 AMD_IOMMU_EVENT_LOG_INT, 1); 647 AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_status_va), 648 AMD_IOMMU_EVENT_OVERFLOW_INT, 1); 649 return (DDI_INTR_CLAIMED); 650 } 651 652 return (DDI_INTR_UNCLAIMED); 653 } 654 655 656 static int 657 amd_iommu_setup_interrupts(amd_iommu_t *iommu) 658 { 659 dev_info_t *dip = iommu->aiomt_dip; 660 int instance = ddi_get_instance(dip); 661 const char *driver = ddi_driver_name(dip); 662 int intrcap0; 663 int intrcapN; 664 int type; 665 int err; 666 int req; 667 int avail; 668 int p2req; 669 int actual; 670 int i; 671 int j; 672 const char *f = "amd_iommu_setup_interrupts"; 673 674 if (ddi_intr_get_supported_types(dip, &type) != DDI_SUCCESS) { 675 cmn_err(CE_WARN, "%s: %s%d: ddi_intr_get_supported_types " 676 "failed: idx=%d", f, driver, instance, iommu->aiomt_idx); 677 return (DDI_FAILURE); 678 } 679 680 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 681 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. " 682 "Interrupt types supported = 0x%x", f, driver, instance, 683 iommu->aiomt_idx, type); 684 } 685 686 /* 687 * for now we only support MSI 688 */ 689 if ((type & DDI_INTR_TYPE_MSI) == 0) { 690 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d. " 691 "MSI interrupts not supported. Failing init.", 692 f, driver, instance, iommu->aiomt_idx); 693 return (DDI_FAILURE); 694 } 695 696 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 697 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. MSI supported", 698 f, driver, instance, iommu->aiomt_idx); 699 } 700 701 err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_MSI, &req); 702 if (err != DDI_SUCCESS) { 703 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d. " 704 "ddi_intr_get_nintrs failed err = %d", 705 f, driver, instance, iommu->aiomt_idx, err); 706 return (DDI_FAILURE); 707 } 708 709 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 710 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. " 711 "MSI number of interrupts requested: %d", 712 f, driver, instance, iommu->aiomt_idx, req); 713 } 714 715 if (req == 0) { 716 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: 0 MSI " 717 "interrupts requested. Failing init", f, 718 driver, instance, iommu->aiomt_idx); 719 return (DDI_FAILURE); 720 } 721 722 err = ddi_intr_get_navail(dip, DDI_INTR_TYPE_MSI, &avail); 723 if (err != DDI_SUCCESS) { 724 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d " 725 "ddi_intr_get_navail failed err = %d", f, 726 driver, instance, iommu->aiomt_idx, err); 727 return (DDI_FAILURE); 728 } 729 730 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 731 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. " 732 "MSI number of interrupts available: %d", 733 f, driver, instance, iommu->aiomt_idx, avail); 734 } 735 736 if (avail == 0) { 737 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: 0 MSI " 738 "interrupts available. Failing init", f, 739 driver, instance, iommu->aiomt_idx); 740 return (DDI_FAILURE); 741 } 742 743 if (avail < req) { 744 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: MSI " 745 "interrupts: requested (%d) > available (%d). " 746 "Failing init", f, driver, instance, iommu->aiomt_idx, 747 req, avail); 748 return (DDI_FAILURE); 749 } 750 751 /* Allocate memory for DDI interrupt handles */ 752 iommu->aiomt_intr_htable_sz = req * sizeof (ddi_intr_handle_t); 753 iommu->aiomt_intr_htable = kmem_zalloc(iommu->aiomt_intr_htable_sz, 754 KM_SLEEP); 755 756 iommu->aiomt_intr_state = AMD_IOMMU_INTR_TABLE; 757 758 /* Convert req to a power of two as required by ddi_intr_alloc */ 759 p2req = 0; 760 while (1<<p2req <= req) 761 p2req++; 762 p2req--; 763 req = 1<<p2req; 764 765 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 766 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. " 767 "MSI power of 2 number of interrupts: %d,%d", 768 f, driver, instance, iommu->aiomt_idx, p2req, req); 769 } 770 771 err = ddi_intr_alloc(iommu->aiomt_dip, iommu->aiomt_intr_htable, 772 DDI_INTR_TYPE_MSI, 0, req, &actual, DDI_INTR_ALLOC_STRICT); 773 if (err != DDI_SUCCESS) { 774 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: " 775 "ddi_intr_alloc failed: err = %d", 776 f, driver, instance, iommu->aiomt_idx, err); 777 amd_iommu_teardown_interrupts(iommu); 778 return (DDI_FAILURE); 779 } 780 781 iommu->aiomt_actual_intrs = actual; 782 iommu->aiomt_intr_state = AMD_IOMMU_INTR_ALLOCED; 783 784 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 785 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. " 786 "number of interrupts actually allocated %d", 787 f, driver, instance, iommu->aiomt_idx, actual); 788 } 789 790 if (iommu->aiomt_actual_intrs < req) { 791 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: " 792 "ddi_intr_alloc failed: actual (%d) < req (%d)", 793 f, driver, instance, iommu->aiomt_idx, 794 iommu->aiomt_actual_intrs, req); 795 amd_iommu_teardown_interrupts(iommu); 796 return (DDI_FAILURE); 797 } 798 799 for (i = 0; i < iommu->aiomt_actual_intrs; i++) { 800 if (ddi_intr_add_handler(iommu->aiomt_intr_htable[i], 801 amd_iommu_intr_handler, (void *)iommu, NULL) 802 != DDI_SUCCESS) { 803 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: " 804 "ddi_intr_add_handler failed: intr = %d, err = %d", 805 f, driver, instance, iommu->aiomt_idx, i, err); 806 for (j = 0; j < i; j++) { 807 (void) ddi_intr_remove_handler( 808 iommu->aiomt_intr_htable[j]); 809 } 810 amd_iommu_teardown_interrupts(iommu); 811 return (DDI_FAILURE); 812 } 813 } 814 iommu->aiomt_intr_state = AMD_IOMMU_INTR_HANDLER; 815 816 intrcap0 = intrcapN = -1; 817 if (ddi_intr_get_cap(iommu->aiomt_intr_htable[0], &intrcap0) 818 != DDI_SUCCESS || 819 ddi_intr_get_cap( 820 iommu->aiomt_intr_htable[iommu->aiomt_actual_intrs - 1], &intrcapN) 821 != DDI_SUCCESS || intrcap0 != intrcapN) { 822 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: " 823 "ddi_intr_get_cap failed or inconsistent cap among " 824 "interrupts: intrcap0 (%d) < intrcapN (%d)", 825 f, driver, instance, iommu->aiomt_idx, intrcap0, intrcapN); 826 amd_iommu_teardown_interrupts(iommu); 827 return (DDI_FAILURE); 828 } 829 iommu->aiomt_intr_cap = intrcap0; 830 831 if (intrcap0 & DDI_INTR_FLAG_BLOCK) { 832 /* Need to call block enable */ 833 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 834 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d: " 835 "Need to call block enable", 836 f, driver, instance, iommu->aiomt_idx); 837 } 838 if (ddi_intr_block_enable(iommu->aiomt_intr_htable, 839 iommu->aiomt_actual_intrs) != DDI_SUCCESS) { 840 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: " 841 "ddi_intr_block enable failed ", f, driver, 842 instance, iommu->aiomt_idx); 843 (void) ddi_intr_block_disable(iommu->aiomt_intr_htable, 844 iommu->aiomt_actual_intrs); 845 amd_iommu_teardown_interrupts(iommu); 846 return (DDI_FAILURE); 847 } 848 } else { 849 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 850 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d: " 851 "Need to call individual enable", 852 f, driver, instance, iommu->aiomt_idx); 853 } 854 for (i = 0; i < iommu->aiomt_actual_intrs; i++) { 855 if (ddi_intr_enable(iommu->aiomt_intr_htable[i]) 856 != DDI_SUCCESS) { 857 cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: " 858 "ddi_intr_enable failed: intr = %d", f, 859 driver, instance, iommu->aiomt_idx, i); 860 for (j = 0; j < i; j++) { 861 (void) ddi_intr_disable( 862 iommu->aiomt_intr_htable[j]); 863 } 864 amd_iommu_teardown_interrupts(iommu); 865 return (DDI_FAILURE); 866 } 867 } 868 } 869 iommu->aiomt_intr_state = AMD_IOMMU_INTR_ENABLED; 870 871 if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) { 872 cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d: " 873 "Interrupts successfully %s enabled. # of interrupts = %d", 874 f, driver, instance, iommu->aiomt_idx, 875 (intrcap0 & DDI_INTR_FLAG_BLOCK) ? "(block)" : 876 "(individually)", iommu->aiomt_actual_intrs); 877 } 878 879 return (DDI_SUCCESS); 880 } 881 882 static void 883 amd_iommu_teardown_interrupts(amd_iommu_t *iommu) 884 { 885 int i; 886 887 if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_ENABLED) { 888 if (iommu->aiomt_intr_cap & DDI_INTR_FLAG_BLOCK) { 889 (void) ddi_intr_block_disable(iommu->aiomt_intr_htable, 890 iommu->aiomt_actual_intrs); 891 } else { 892 for (i = 0; i < iommu->aiomt_actual_intrs; i++) { 893 (void) ddi_intr_disable( 894 iommu->aiomt_intr_htable[i]); 895 } 896 } 897 } 898 899 if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_HANDLER) { 900 for (i = 0; i < iommu->aiomt_actual_intrs; i++) { 901 (void) ddi_intr_remove_handler( 902 iommu->aiomt_intr_htable[i]); 903 } 904 } 905 906 if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_ALLOCED) { 907 for (i = 0; i < iommu->aiomt_actual_intrs; i++) { 908 (void) ddi_intr_free(iommu->aiomt_intr_htable[i]); 909 } 910 } 911 if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_TABLE) { 912 kmem_free(iommu->aiomt_intr_htable, 913 iommu->aiomt_intr_htable_sz); 914 } 915 iommu->aiomt_intr_htable = NULL; 916 iommu->aiomt_intr_htable_sz = 0; 917 iommu->aiomt_intr_state = AMD_IOMMU_INTR_INVALID; 918 } 919 920 static amd_iommu_t * 921 amd_iommu_init(dev_info_t *dip, ddi_acc_handle_t handle, int idx, 922 uint16_t cap_base) 923 { 924 amd_iommu_t *iommu; 925 int instance = ddi_get_instance(dip); 926 const char *driver = ddi_driver_name(dip); 927 uint32_t caphdr; 928 uint32_t low_addr32; 929 uint32_t hi_addr32; 930 uint32_t range; 931 uint32_t misc; 932 uint64_t pgoffset; 933 amd_iommu_acpi_global_t *global; 934 amd_iommu_acpi_ivhd_t *hinfop; 935 int bus, device, func; 936 const char *f = "amd_iommu_init"; 937 938 low_addr32 = PCI_CAP_GET32(handle, 0, cap_base, 939 AMD_IOMMU_CAP_ADDR_LOW_OFF); 940 if (!(low_addr32 & AMD_IOMMU_REG_ADDR_LOCKED)) { 941 cmn_err(CE_WARN, "%s: %s%d: capability registers not locked. " 942 "Unable to use IOMMU unit idx=%d - skipping ...", f, driver, 943 instance, idx); 944 return (NULL); 945 } 946 947 iommu = kmem_zalloc(sizeof (amd_iommu_t), KM_SLEEP); 948 mutex_init(&iommu->aiomt_mutex, NULL, MUTEX_DRIVER, NULL); 949 mutex_enter(&iommu->aiomt_mutex); 950 951 mutex_init(&iommu->aiomt_cmdlock, NULL, MUTEX_DRIVER, NULL); 952 mutex_init(&iommu->aiomt_eventlock, NULL, MUTEX_DRIVER, NULL); 953 954 iommu->aiomt_dip = dip; 955 iommu->aiomt_idx = idx; 956 957 if (acpica_get_bdf(iommu->aiomt_dip, &bus, &device, &func) 958 != DDI_SUCCESS) { 959 cmn_err(CE_WARN, "%s: %s%d: Failed to get BDF" 960 "Unable to use IOMMU unit idx=%d - skipping ...", 961 f, driver, instance, idx); 962 return (NULL); 963 } 964 965 iommu->aiomt_bdf = ((uint8_t)bus << 8) | ((uint8_t)device << 3) | 966 (uint8_t)func; 967 968 /* 969 * Since everything in the capability block is locked and RO at this 970 * point, copy everything into the IOMMU struct 971 */ 972 973 /* Get cap header */ 974 caphdr = PCI_CAP_GET32(handle, 0, cap_base, AMD_IOMMU_CAP_HDR_OFF); 975 iommu->aiomt_cap_hdr = caphdr; 976 iommu->aiomt_npcache = AMD_IOMMU_REG_GET32(&caphdr, 977 AMD_IOMMU_CAP_NPCACHE); 978 iommu->aiomt_httun = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_HTTUN); 979 980 global = amd_iommu_lookup_acpi_global(); 981 hinfop = amd_iommu_lookup_any_ivhd(iommu); 982 983 if (hinfop) 984 iommu->aiomt_iotlb = hinfop->ach_IotlbSup; 985 else 986 iommu->aiomt_iotlb = 987 AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_IOTLB); 988 989 iommu->aiomt_captype = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_TYPE); 990 iommu->aiomt_capid = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_ID); 991 992 /* 993 * Get address of IOMMU control registers 994 */ 995 hi_addr32 = PCI_CAP_GET32(handle, 0, cap_base, 996 AMD_IOMMU_CAP_ADDR_HI_OFF); 997 iommu->aiomt_low_addr32 = low_addr32; 998 iommu->aiomt_hi_addr32 = hi_addr32; 999 low_addr32 &= ~AMD_IOMMU_REG_ADDR_LOCKED; 1000 1001 if (hinfop) { 1002 iommu->aiomt_reg_pa = hinfop->ach_IOMMU_reg_base; 1003 ASSERT(hinfop->ach_IOMMU_pci_seg == 0); 1004 } else { 1005 iommu->aiomt_reg_pa = ((uint64_t)hi_addr32 << 32 | low_addr32); 1006 } 1007 1008 /* 1009 * Get cap range reg 1010 */ 1011 range = PCI_CAP_GET32(handle, 0, cap_base, AMD_IOMMU_CAP_RANGE_OFF); 1012 iommu->aiomt_range = range; 1013 iommu->aiomt_rng_valid = AMD_IOMMU_REG_GET32(&range, 1014 AMD_IOMMU_RNG_VALID); 1015 if (iommu->aiomt_rng_valid) { 1016 iommu->aiomt_rng_bus = AMD_IOMMU_REG_GET32(&range, 1017 AMD_IOMMU_RNG_BUS); 1018 iommu->aiomt_first_devfn = AMD_IOMMU_REG_GET32(&range, 1019 AMD_IOMMU_FIRST_DEVFN); 1020 iommu->aiomt_last_devfn = AMD_IOMMU_REG_GET32(&range, 1021 AMD_IOMMU_LAST_DEVFN); 1022 } else { 1023 iommu->aiomt_rng_bus = 0; 1024 iommu->aiomt_first_devfn = 0; 1025 iommu->aiomt_last_devfn = 0; 1026 } 1027 1028 if (hinfop) 1029 iommu->aiomt_ht_unitid = hinfop->ach_IOMMU_UnitID; 1030 else 1031 iommu->aiomt_ht_unitid = AMD_IOMMU_REG_GET32(&range, 1032 AMD_IOMMU_HT_UNITID); 1033 1034 /* 1035 * Get cap misc reg 1036 */ 1037 misc = PCI_CAP_GET32(handle, 0, cap_base, AMD_IOMMU_CAP_MISC_OFF); 1038 iommu->aiomt_misc = misc; 1039 1040 if (global) { 1041 iommu->aiomt_htatsresv = global->acg_HtAtsResv; 1042 iommu->aiomt_vasize = global->acg_VAsize; 1043 iommu->aiomt_pasize = global->acg_PAsize; 1044 } else { 1045 iommu->aiomt_htatsresv = AMD_IOMMU_REG_GET32(&misc, 1046 AMD_IOMMU_HT_ATSRSV); 1047 iommu->aiomt_vasize = AMD_IOMMU_REG_GET32(&misc, 1048 AMD_IOMMU_VA_SIZE); 1049 iommu->aiomt_pasize = AMD_IOMMU_REG_GET32(&misc, 1050 AMD_IOMMU_PA_SIZE); 1051 } 1052 1053 if (hinfop) { 1054 iommu->aiomt_msinum = hinfop->ach_IOMMU_MSInum; 1055 } else { 1056 iommu->aiomt_msinum = 1057 AMD_IOMMU_REG_GET32(&misc, AMD_IOMMU_MSINUM); 1058 } 1059 1060 /* 1061 * Set up mapping between control registers PA and VA 1062 */ 1063 pgoffset = iommu->aiomt_reg_pa & MMU_PAGEOFFSET; 1064 ASSERT(pgoffset == 0); 1065 iommu->aiomt_reg_pages = mmu_btopr(AMD_IOMMU_REG_SIZE + pgoffset); 1066 iommu->aiomt_reg_size = mmu_ptob(iommu->aiomt_reg_pages); 1067 1068 iommu->aiomt_va = (uintptr_t)device_arena_alloc( 1069 ptob(iommu->aiomt_reg_pages), VM_SLEEP); 1070 if (iommu->aiomt_va == 0) { 1071 cmn_err(CE_WARN, "%s: %s%d: Failed to alloc VA for IOMMU " 1072 "control regs. Skipping IOMMU idx=%d", f, driver, 1073 instance, idx); 1074 mutex_exit(&iommu->aiomt_mutex); 1075 (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN); 1076 return (NULL); 1077 } 1078 1079 hat_devload(kas.a_hat, (void *)(uintptr_t)iommu->aiomt_va, 1080 iommu->aiomt_reg_size, 1081 mmu_btop(iommu->aiomt_reg_pa), PROT_READ | PROT_WRITE 1082 | HAT_STRICTORDER, HAT_LOAD_LOCK); 1083 1084 iommu->aiomt_reg_va = iommu->aiomt_va + pgoffset; 1085 1086 /* 1087 * Setup the various control register's VA 1088 */ 1089 iommu->aiomt_reg_devtbl_va = iommu->aiomt_reg_va + 1090 AMD_IOMMU_DEVTBL_REG_OFF; 1091 iommu->aiomt_reg_cmdbuf_va = iommu->aiomt_reg_va + 1092 AMD_IOMMU_CMDBUF_REG_OFF; 1093 iommu->aiomt_reg_eventlog_va = iommu->aiomt_reg_va + 1094 AMD_IOMMU_EVENTLOG_REG_OFF; 1095 iommu->aiomt_reg_ctrl_va = iommu->aiomt_reg_va + 1096 AMD_IOMMU_CTRL_REG_OFF; 1097 iommu->aiomt_reg_excl_base_va = iommu->aiomt_reg_va + 1098 AMD_IOMMU_EXCL_BASE_REG_OFF; 1099 iommu->aiomt_reg_excl_lim_va = iommu->aiomt_reg_va + 1100 AMD_IOMMU_EXCL_LIM_REG_OFF; 1101 iommu->aiomt_reg_cmdbuf_head_va = iommu->aiomt_reg_va + 1102 AMD_IOMMU_CMDBUF_HEAD_REG_OFF; 1103 iommu->aiomt_reg_cmdbuf_tail_va = iommu->aiomt_reg_va + 1104 AMD_IOMMU_CMDBUF_TAIL_REG_OFF; 1105 iommu->aiomt_reg_eventlog_head_va = iommu->aiomt_reg_va + 1106 AMD_IOMMU_EVENTLOG_HEAD_REG_OFF; 1107 iommu->aiomt_reg_eventlog_tail_va = iommu->aiomt_reg_va + 1108 AMD_IOMMU_EVENTLOG_TAIL_REG_OFF; 1109 iommu->aiomt_reg_status_va = iommu->aiomt_reg_va + 1110 AMD_IOMMU_STATUS_REG_OFF; 1111 1112 1113 /* 1114 * Setup the DEVICE table, CMD buffer, and LOG buffer in 1115 * memory and setup DMA access to this memory location 1116 */ 1117 if (amd_iommu_setup_tables_and_buffers(iommu) != DDI_SUCCESS) { 1118 mutex_exit(&iommu->aiomt_mutex); 1119 (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN); 1120 return (NULL); 1121 } 1122 1123 if (amd_iommu_setup_exclusion(iommu) != DDI_SUCCESS) { 1124 mutex_exit(&iommu->aiomt_mutex); 1125 (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN); 1126 return (NULL); 1127 } 1128 1129 amd_iommu_enable_interrupts(iommu); 1130 1131 if (amd_iommu_setup_interrupts(iommu) != DDI_SUCCESS) { 1132 mutex_exit(&iommu->aiomt_mutex); 1133 (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN); 1134 return (NULL); 1135 } 1136 1137 /* 1138 * need to setup domain table before gfx bypass 1139 */ 1140 amd_iommu_init_page_tables(iommu); 1141 1142 /* 1143 * Set pass-thru for special devices like IOAPIC and HPET 1144 * 1145 * Also, gfx devices don't use DDI for DMA. No need to register 1146 * before setting up gfx passthru 1147 */ 1148 if (amd_iommu_setup_passthru(iommu) != DDI_SUCCESS) { 1149 mutex_exit(&iommu->aiomt_mutex); 1150 (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN); 1151 return (NULL); 1152 } 1153 1154 /* Initialize device table entries based on ACPI settings */ 1155 if (amd_iommu_acpi_init_devtbl(iommu) != DDI_SUCCESS) { 1156 cmn_err(CE_WARN, "%s: %s%d: Can't initialize device table", 1157 f, driver, instance); 1158 mutex_exit(&iommu->aiomt_mutex); 1159 (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN); 1160 return (NULL); 1161 } 1162 1163 if (amd_iommu_start(iommu) != DDI_SUCCESS) { 1164 mutex_exit(&iommu->aiomt_mutex); 1165 (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN); 1166 return (NULL); 1167 } 1168 1169 /* xxx register/start race */ 1170 if (amd_iommu_register(iommu) != DDI_SUCCESS) { 1171 mutex_exit(&iommu->aiomt_mutex); 1172 (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN); 1173 return (NULL); 1174 } 1175 1176 if (amd_iommu_debug) { 1177 cmn_err(CE_NOTE, "%s: %s%d: IOMMU idx=%d inited.", f, driver, 1178 instance, idx); 1179 } 1180 1181 return (iommu); 1182 } 1183 1184 static int 1185 amd_iommu_fini(amd_iommu_t *iommu, int type) 1186 { 1187 int idx = iommu->aiomt_idx; 1188 dev_info_t *dip = iommu->aiomt_dip; 1189 int instance = ddi_get_instance(dip); 1190 const char *driver = ddi_driver_name(dip); 1191 const char *f = "amd_iommu_fini"; 1192 1193 if (type == AMD_IOMMU_TEARDOWN) { 1194 mutex_enter(&iommu->aiomt_mutex); 1195 if (amd_iommu_unregister(iommu) != DDI_SUCCESS) { 1196 cmn_err(CE_NOTE, "%s: %s%d: Fini of IOMMU unit failed. " 1197 "idx = %d", f, driver, instance, idx); 1198 return (DDI_FAILURE); 1199 } 1200 } 1201 1202 amd_iommu_stop(iommu); 1203 1204 if (type == AMD_IOMMU_TEARDOWN) { 1205 amd_iommu_fini_page_tables(iommu); 1206 amd_iommu_teardown_interrupts(iommu); 1207 amd_iommu_teardown_exclusion(iommu); 1208 } 1209 1210 amd_iommu_teardown_tables_and_buffers(iommu, type); 1211 1212 if (type == AMD_IOMMU_QUIESCE) 1213 return (DDI_SUCCESS); 1214 1215 if (iommu->aiomt_va != 0) { 1216 hat_unload(kas.a_hat, (void *)(uintptr_t)iommu->aiomt_va, 1217 iommu->aiomt_reg_size, HAT_UNLOAD_UNLOCK); 1218 device_arena_free((void *)(uintptr_t)iommu->aiomt_va, 1219 ptob(iommu->aiomt_reg_pages)); 1220 iommu->aiomt_va = 0; 1221 iommu->aiomt_reg_va = 0; 1222 } 1223 mutex_destroy(&iommu->aiomt_eventlock); 1224 mutex_destroy(&iommu->aiomt_cmdlock); 1225 mutex_exit(&iommu->aiomt_mutex); 1226 mutex_destroy(&iommu->aiomt_mutex); 1227 kmem_free(iommu, sizeof (amd_iommu_t)); 1228 1229 cmn_err(CE_NOTE, "%s: %s%d: Fini of IOMMU unit complete. idx = %d", 1230 f, driver, instance, idx); 1231 1232 return (DDI_SUCCESS); 1233 } 1234 1235 int 1236 amd_iommu_setup(dev_info_t *dip, amd_iommu_state_t *statep) 1237 { 1238 int instance = ddi_get_instance(dip); 1239 const char *driver = ddi_driver_name(dip); 1240 ddi_acc_handle_t handle; 1241 uint8_t base_class; 1242 uint8_t sub_class; 1243 uint8_t prog_class; 1244 int idx; 1245 uint32_t id; 1246 uint16_t cap_base; 1247 uint32_t caphdr; 1248 uint8_t cap_type; 1249 uint8_t cap_id; 1250 amd_iommu_t *iommu; 1251 const char *f = "amd_iommu_setup"; 1252 1253 ASSERT(instance >= 0); 1254 ASSERT(driver); 1255 1256 /* First setup PCI access to config space */ 1257 1258 if (pci_config_setup(dip, &handle) != DDI_SUCCESS) { 1259 cmn_err(CE_WARN, "%s: PCI config setup failed: %s%d", 1260 f, driver, instance); 1261 return (DDI_FAILURE); 1262 } 1263 1264 /* 1265 * The AMD IOMMU is part of an independent PCI function. There may be 1266 * more than one IOMMU in that PCI function 1267 */ 1268 base_class = pci_config_get8(handle, PCI_CONF_BASCLASS); 1269 sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS); 1270 prog_class = pci_config_get8(handle, PCI_CONF_PROGCLASS); 1271 1272 if (base_class != PCI_CLASS_PERIPH || sub_class != PCI_PERIPH_IOMMU || 1273 prog_class != AMD_IOMMU_PCI_PROG_IF) { 1274 cmn_err(CE_WARN, "%s: %s%d: invalid PCI class(0x%x)/" 1275 "subclass(0x%x)/programming interface(0x%x)", f, driver, 1276 instance, base_class, sub_class, prog_class); 1277 pci_config_teardown(&handle); 1278 return (DDI_FAILURE); 1279 } 1280 1281 /* 1282 * Find and initialize all IOMMU units in this function 1283 */ 1284 for (idx = 0; ; idx++) { 1285 if (pci_cap_probe(handle, idx, &id, &cap_base) != DDI_SUCCESS) 1286 break; 1287 1288 /* check if cap ID is secure device cap id */ 1289 if (id != PCI_CAP_ID_SECURE_DEV) { 1290 if (amd_iommu_debug) { 1291 cmn_err(CE_NOTE, 1292 "%s: %s%d: skipping IOMMU: idx(0x%x) " 1293 "cap ID (0x%x) != secure dev capid (0x%x)", 1294 f, driver, instance, idx, id, 1295 PCI_CAP_ID_SECURE_DEV); 1296 } 1297 continue; 1298 } 1299 1300 /* check if cap type is IOMMU cap type */ 1301 caphdr = PCI_CAP_GET32(handle, 0, cap_base, 1302 AMD_IOMMU_CAP_HDR_OFF); 1303 cap_type = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_TYPE); 1304 cap_id = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_ID); 1305 1306 if (cap_type != AMD_IOMMU_CAP) { 1307 cmn_err(CE_WARN, "%s: %s%d: skipping IOMMU: idx(0x%x) " 1308 "cap type (0x%x) != AMD IOMMU CAP (0x%x)", f, 1309 driver, instance, idx, cap_type, AMD_IOMMU_CAP); 1310 continue; 1311 } 1312 ASSERT(cap_id == PCI_CAP_ID_SECURE_DEV); 1313 ASSERT(cap_id == id); 1314 1315 iommu = amd_iommu_init(dip, handle, idx, cap_base); 1316 if (iommu == NULL) { 1317 cmn_err(CE_WARN, "%s: %s%d: skipping IOMMU: idx(0x%x) " 1318 "failed to init IOMMU", f, 1319 driver, instance, idx); 1320 continue; 1321 } 1322 1323 if (statep->aioms_iommu_start == NULL) { 1324 statep->aioms_iommu_start = iommu; 1325 } else { 1326 statep->aioms_iommu_end->aiomt_next = iommu; 1327 } 1328 statep->aioms_iommu_end = iommu; 1329 1330 statep->aioms_nunits++; 1331 } 1332 1333 pci_config_teardown(&handle); 1334 1335 if (amd_iommu_debug) { 1336 cmn_err(CE_NOTE, "%s: %s%d: state=%p: setup %d IOMMU units", 1337 f, driver, instance, (void *)statep, statep->aioms_nunits); 1338 } 1339 1340 return (DDI_SUCCESS); 1341 } 1342 1343 int 1344 amd_iommu_teardown(dev_info_t *dip, amd_iommu_state_t *statep, int type) 1345 { 1346 int instance = ddi_get_instance(dip); 1347 const char *driver = ddi_driver_name(dip); 1348 amd_iommu_t *iommu, *next_iommu; 1349 int teardown; 1350 int error = DDI_SUCCESS; 1351 const char *f = "amd_iommu_teardown"; 1352 1353 teardown = 0; 1354 for (iommu = statep->aioms_iommu_start; iommu; 1355 iommu = next_iommu) { 1356 ASSERT(statep->aioms_nunits > 0); 1357 next_iommu = iommu->aiomt_next; 1358 if (amd_iommu_fini(iommu, type) != DDI_SUCCESS) { 1359 error = DDI_FAILURE; 1360 continue; 1361 } 1362 statep->aioms_nunits--; 1363 teardown++; 1364 } 1365 1366 cmn_err(CE_NOTE, "%s: %s%d: state=%p: toredown %d units. " 1367 "%d units left", f, driver, instance, (void *)statep, 1368 teardown, statep->aioms_nunits); 1369 1370 return (error); 1371 } 1372 1373 dev_info_t * 1374 amd_iommu_pci_dip(dev_info_t *rdip, const char *path) 1375 { 1376 dev_info_t *pdip; 1377 const char *driver = ddi_driver_name(rdip); 1378 int instance = ddi_get_instance(rdip); 1379 const char *f = "amd_iommu_pci_dip"; 1380 1381 /* Hold rdip so it and its parents don't go away */ 1382 ndi_hold_devi(rdip); 1383 1384 if (ddi_is_pci_dip(rdip)) 1385 return (rdip); 1386 1387 pdip = rdip; 1388 while (pdip = ddi_get_parent(pdip)) { 1389 if (ddi_is_pci_dip(pdip)) { 1390 ndi_hold_devi(pdip); 1391 ndi_rele_devi(rdip); 1392 return (pdip); 1393 } 1394 } 1395 1396 #ifdef DEBUG 1397 cmn_err(CE_PANIC, "%s: %s%d dip = %p has no PCI parent, path = %s", 1398 f, driver, instance, (void *)rdip, path); 1399 #else 1400 cmn_err(CE_WARN, "%s: %s%d dip = %p has no PCI parent, path = %s", 1401 f, driver, instance, (void *)rdip, path); 1402 ndi_rele_devi(rdip); 1403 #endif /* DEBUG */ 1404 1405 return (NULL); 1406 } 1407 1408 /* Interface with IOMMULIB */ 1409 /*ARGSUSED*/ 1410 static int 1411 amd_iommu_probe(iommulib_handle_t handle, dev_info_t *rdip) 1412 { 1413 const char *driver = ddi_driver_name(rdip); 1414 char *s; 1415 int bus, device, func, bdf; 1416 amd_iommu_acpi_ivhd_t *hinfop; 1417 dev_info_t *pci_dip; 1418 amd_iommu_t *iommu = iommulib_iommu_getdata(handle); 1419 const char *f = "amd_iommu_probe"; 1420 int instance = ddi_get_instance(iommu->aiomt_dip); 1421 const char *idriver = ddi_driver_name(iommu->aiomt_dip); 1422 char *path, *pathp; 1423 1424 if (amd_iommu_disable_list) { 1425 s = strstr(amd_iommu_disable_list, driver); 1426 if (s == NULL) 1427 return (DDI_SUCCESS); 1428 if (s == amd_iommu_disable_list || *(s - 1) == ':') { 1429 s += strlen(driver); 1430 if (*s == '\0' || *s == ':') { 1431 amd_iommu_set_passthru(iommu, rdip); 1432 return (DDI_FAILURE); 1433 } 1434 } 1435 } 1436 1437 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1438 if ((pathp = ddi_pathname(rdip, path)) == NULL) 1439 pathp = "<unknown>"; 1440 1441 pci_dip = amd_iommu_pci_dip(rdip, path); 1442 if (pci_dip == NULL) { 1443 cmn_err(CE_WARN, "%s: %s%d: idx = %d, failed to get PCI dip " 1444 "for rdip=%p, path = %s", 1445 f, idriver, instance, iommu->aiomt_idx, (void *)rdip, 1446 pathp); 1447 kmem_free(path, MAXPATHLEN); 1448 return (DDI_FAILURE); 1449 } 1450 1451 if (acpica_get_bdf(pci_dip, &bus, &device, &func) != DDI_SUCCESS) { 1452 cmn_err(CE_WARN, "%s: %s%d: idx = %d, failed to get BDF " 1453 "for rdip=%p, path = %s", 1454 f, idriver, instance, iommu->aiomt_idx, (void *)rdip, 1455 pathp); 1456 kmem_free(path, MAXPATHLEN); 1457 return (DDI_FAILURE); 1458 } 1459 kmem_free(path, MAXPATHLEN); 1460 1461 /* 1462 * See whether device is described by IVRS as being managed 1463 * by this IOMMU 1464 */ 1465 bdf = ((uint8_t)bus << 8) | ((uint8_t)device << 3) | (uint8_t)func; 1466 hinfop = amd_iommu_lookup_ivhd(bdf); 1467 if (hinfop && hinfop->ach_IOMMU_deviceid == iommu->aiomt_bdf) 1468 return (DDI_SUCCESS); 1469 1470 return (DDI_FAILURE); 1471 } 1472 1473 /*ARGSUSED*/ 1474 static int 1475 amd_iommu_allochdl(iommulib_handle_t handle, 1476 dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr, 1477 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *dma_handlep) 1478 { 1479 return (iommulib_iommu_dma_allochdl(dip, rdip, attr, waitfp, 1480 arg, dma_handlep)); 1481 } 1482 1483 /*ARGSUSED*/ 1484 static int 1485 amd_iommu_freehdl(iommulib_handle_t handle, 1486 dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle) 1487 { 1488 return (iommulib_iommu_dma_freehdl(dip, rdip, dma_handle)); 1489 } 1490 1491 /*ARGSUSED*/ 1492 static int 1493 map_current_window(amd_iommu_t *iommu, dev_info_t *rdip, ddi_dma_attr_t *attrp, 1494 struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookie_array, uint_t ccount, 1495 int km_flags) 1496 { 1497 const char *driver = ddi_driver_name(iommu->aiomt_dip); 1498 int instance = ddi_get_instance(iommu->aiomt_dip); 1499 int idx = iommu->aiomt_idx; 1500 int i; 1501 uint64_t start_va; 1502 char *path; 1503 int error = DDI_FAILURE; 1504 const char *f = "map_current_window"; 1505 1506 path = kmem_alloc(MAXPATHLEN, km_flags); 1507 if (path == NULL) { 1508 return (DDI_DMA_NORESOURCES); 1509 } 1510 1511 (void) ddi_pathname(rdip, path); 1512 mutex_enter(&amd_iommu_pgtable_lock); 1513 1514 if (amd_iommu_debug == AMD_IOMMU_DEBUG_PAGE_TABLES) { 1515 cmn_err(CE_NOTE, "%s: %s%d: idx=%d Attempting to get cookies " 1516 "from handle for device %s", 1517 f, driver, instance, idx, path); 1518 } 1519 1520 start_va = 0; 1521 for (i = 0; i < ccount; i++) { 1522 if ((error = amd_iommu_map_pa2va(iommu, rdip, attrp, dmareq, 1523 cookie_array[i].dmac_cookie_addr, 1524 cookie_array[i].dmac_size, 1525 AMD_IOMMU_VMEM_MAP, &start_va, km_flags)) != DDI_SUCCESS) { 1526 break; 1527 } 1528 cookie_array[i].dmac_cookie_addr = (uintptr_t)start_va; 1529 cookie_array[i].dmac_type = 0; 1530 } 1531 1532 if (i != ccount) { 1533 cmn_err(CE_WARN, "%s: %s%d: idx=%d Cannot map cookie# %d " 1534 "for device %s", f, driver, instance, idx, i, path); 1535 (void) unmap_current_window(iommu, rdip, cookie_array, 1536 ccount, i, 1); 1537 goto out; 1538 } 1539 1540 if (amd_iommu_debug & AMD_IOMMU_DEBUG_PAGE_TABLES) { 1541 cmn_err(CE_NOTE, "%s: return SUCCESS", f); 1542 } 1543 1544 error = DDI_DMA_MAPPED; 1545 out: 1546 mutex_exit(&amd_iommu_pgtable_lock); 1547 kmem_free(path, MAXPATHLEN); 1548 return (error); 1549 } 1550 1551 /*ARGSUSED*/ 1552 static int 1553 unmap_current_window(amd_iommu_t *iommu, dev_info_t *rdip, 1554 ddi_dma_cookie_t *cookie_array, uint_t ccount, int ncookies, int locked) 1555 { 1556 const char *driver = ddi_driver_name(iommu->aiomt_dip); 1557 int instance = ddi_get_instance(iommu->aiomt_dip); 1558 int idx = iommu->aiomt_idx; 1559 int i; 1560 int error = DDI_FAILURE; 1561 char *path; 1562 int pathfree; 1563 const char *f = "unmap_current_window"; 1564 1565 if (!locked) 1566 mutex_enter(&amd_iommu_pgtable_lock); 1567 1568 path = kmem_alloc(MAXPATHLEN, KM_NOSLEEP); 1569 if (path) { 1570 (void) ddi_pathname(rdip, path); 1571 pathfree = 1; 1572 } else { 1573 path = "<path-mem-alloc-failed>"; 1574 pathfree = 0; 1575 } 1576 1577 if (ncookies == -1) 1578 ncookies = ccount; 1579 1580 for (i = 0; i < ncookies; i++) { 1581 if (amd_iommu_unmap_va(iommu, rdip, 1582 cookie_array[i].dmac_cookie_addr, 1583 cookie_array[i].dmac_size, 1584 AMD_IOMMU_VMEM_MAP) != DDI_SUCCESS) { 1585 break; 1586 } 1587 } 1588 1589 if (amd_iommu_cmd(iommu, AMD_IOMMU_CMD_COMPL_WAIT, NULL, 0, 0) 1590 != DDI_SUCCESS) { 1591 cmn_err(CE_WARN, "%s: AMD IOMMU completion wait failed for: %s", 1592 f, path); 1593 } 1594 1595 if (i != ncookies) { 1596 cmn_err(CE_WARN, "%s: %s%d: idx=%d Cannot unmap cookie# %d " 1597 "for device %s", f, driver, instance, idx, i, path); 1598 error = DDI_FAILURE; 1599 goto out; 1600 } 1601 1602 error = DDI_SUCCESS; 1603 1604 out: 1605 if (pathfree) 1606 kmem_free(path, MAXPATHLEN); 1607 if (!locked) 1608 mutex_exit(&amd_iommu_pgtable_lock); 1609 return (error); 1610 } 1611 1612 /*ARGSUSED*/ 1613 static int 1614 amd_iommu_bindhdl(iommulib_handle_t handle, dev_info_t *dip, 1615 dev_info_t *rdip, ddi_dma_handle_t dma_handle, 1616 struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookiep, 1617 uint_t *ccountp) 1618 { 1619 int dma_error = DDI_DMA_NOMAPPING; 1620 int error; 1621 char *path; 1622 ddi_dma_cookie_t *cookie_array = NULL; 1623 uint_t ccount = 0; 1624 ddi_dma_impl_t *hp; 1625 ddi_dma_attr_t *attrp; 1626 int km_flags; 1627 amd_iommu_t *iommu = iommulib_iommu_getdata(handle); 1628 int instance = ddi_get_instance(rdip); 1629 const char *driver = ddi_driver_name(rdip); 1630 const char *f = "amd_iommu_bindhdl"; 1631 1632 dma_error = iommulib_iommu_dma_bindhdl(dip, rdip, dma_handle, 1633 dmareq, cookiep, ccountp); 1634 1635 if (dma_error != DDI_DMA_MAPPED && dma_error != DDI_DMA_PARTIAL_MAP) 1636 return (dma_error); 1637 1638 km_flags = iommulib_iommu_dma_get_sleep_flags(dip, dma_handle); 1639 1640 path = kmem_alloc(MAXPATHLEN, km_flags); 1641 if (path) { 1642 (void) ddi_pathname(rdip, path); 1643 } else { 1644 dma_error = DDI_DMA_NORESOURCES; 1645 goto unbind; 1646 } 1647 1648 if (amd_iommu_debug & AMD_IOMMU_DEBUG_BIND) { 1649 cmn_err(CE_NOTE, "%s: %s got cookie (%p), #cookies: %d", 1650 f, path, 1651 (void *)cookiep->dmac_cookie_addr, 1652 *ccountp); 1653 } 1654 1655 cookie_array = NULL; 1656 ccount = 0; 1657 if ((error = iommulib_iommu_dma_get_cookies(dip, dma_handle, 1658 &cookie_array, &ccount)) != DDI_SUCCESS) { 1659 cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies " 1660 "for device %s", f, driver, instance, path); 1661 dma_error = error; 1662 goto unbind; 1663 } 1664 1665 hp = (ddi_dma_impl_t *)dma_handle; 1666 attrp = &hp->dmai_attr; 1667 1668 error = map_current_window(iommu, rdip, attrp, dmareq, 1669 cookie_array, ccount, km_flags); 1670 if (error != DDI_SUCCESS) { 1671 dma_error = error; 1672 goto unbind; 1673 } 1674 1675 if ((error = iommulib_iommu_dma_set_cookies(dip, dma_handle, 1676 cookie_array, ccount)) != DDI_SUCCESS) { 1677 cmn_err(CE_WARN, "%s: %s%d: Cannot set cookies " 1678 "for device %s", f, driver, instance, path); 1679 dma_error = error; 1680 goto unbind; 1681 } 1682 1683 *cookiep = cookie_array[0]; 1684 1685 if (amd_iommu_debug & AMD_IOMMU_DEBUG_BIND) { 1686 cmn_err(CE_NOTE, "%s: %s remapped cookie (%p), #cookies: %d", 1687 f, path, 1688 (void *)(uintptr_t)cookiep->dmac_cookie_addr, 1689 *ccountp); 1690 } 1691 1692 kmem_free(path, MAXPATHLEN); 1693 ASSERT(dma_error == DDI_DMA_MAPPED || dma_error == DDI_DMA_PARTIAL_MAP); 1694 return (dma_error); 1695 unbind: 1696 kmem_free(path, MAXPATHLEN); 1697 (void) iommulib_iommu_dma_unbindhdl(dip, rdip, dma_handle); 1698 return (dma_error); 1699 } 1700 1701 /*ARGSUSED*/ 1702 static int 1703 amd_iommu_unbindhdl(iommulib_handle_t handle, 1704 dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle) 1705 { 1706 amd_iommu_t *iommu = iommulib_iommu_getdata(handle); 1707 ddi_dma_cookie_t *cookie_array = NULL; 1708 uint_t ccount = 0; 1709 int error = DDI_FAILURE; 1710 int instance = ddi_get_instance(rdip); 1711 const char *driver = ddi_driver_name(rdip); 1712 const char *f = "amd_iommu_unbindhdl"; 1713 1714 cookie_array = NULL; 1715 ccount = 0; 1716 if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array, 1717 &ccount) != DDI_SUCCESS) { 1718 cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies " 1719 "for device %p", f, driver, instance, (void *)rdip); 1720 error = DDI_FAILURE; 1721 goto out; 1722 } 1723 1724 if (iommulib_iommu_dma_clear_cookies(dip, dma_handle) != DDI_SUCCESS) { 1725 cmn_err(CE_WARN, "%s: %s%d: Cannot clear cookies " 1726 "for device %p", f, driver, instance, (void *)rdip); 1727 error = DDI_FAILURE; 1728 goto out; 1729 } 1730 1731 if (iommulib_iommu_dma_unbindhdl(dip, rdip, dma_handle) 1732 != DDI_SUCCESS) { 1733 cmn_err(CE_WARN, "%s: %s%d: failed to unbindhdl for dip=%p", 1734 f, driver, instance, (void *)rdip); 1735 error = DDI_FAILURE; 1736 goto out; 1737 } 1738 1739 if (unmap_current_window(iommu, rdip, cookie_array, ccount, -1, 0) 1740 != DDI_SUCCESS) { 1741 cmn_err(CE_WARN, "%s: %s%d: failed to unmap current window " 1742 "for dip=%p", f, driver, instance, (void *)rdip); 1743 error = DDI_FAILURE; 1744 } else { 1745 error = DDI_SUCCESS; 1746 } 1747 out: 1748 if (cookie_array) 1749 kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount); 1750 return (error); 1751 } 1752 1753 /*ARGSUSED*/ 1754 static int 1755 amd_iommu_sync(iommulib_handle_t handle, dev_info_t *dip, 1756 dev_info_t *rdip, ddi_dma_handle_t dma_handle, off_t off, 1757 size_t len, uint_t cache_flags) 1758 { 1759 ddi_dma_cookie_t *cookie_array = NULL; 1760 uint_t ccount = 0; 1761 int error; 1762 const char *f = "amd_iommu_sync"; 1763 1764 cookie_array = NULL; 1765 ccount = 0; 1766 if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array, 1767 &ccount) != DDI_SUCCESS) { 1768 ASSERT(cookie_array == NULL); 1769 cmn_err(CE_WARN, "%s: Cannot get cookies " 1770 "for device %p", f, (void *)rdip); 1771 error = DDI_FAILURE; 1772 goto out; 1773 } 1774 1775 if (iommulib_iommu_dma_clear_cookies(dip, dma_handle) != DDI_SUCCESS) { 1776 cmn_err(CE_WARN, "%s: Cannot clear cookies " 1777 "for device %p", f, (void *)rdip); 1778 error = DDI_FAILURE; 1779 goto out; 1780 } 1781 1782 error = iommulib_iommu_dma_sync(dip, rdip, dma_handle, off, 1783 len, cache_flags); 1784 1785 if (iommulib_iommu_dma_set_cookies(dip, dma_handle, cookie_array, 1786 ccount) != DDI_SUCCESS) { 1787 cmn_err(CE_WARN, "%s: Cannot set cookies " 1788 "for device %p", f, (void *)rdip); 1789 error = DDI_FAILURE; 1790 } else { 1791 cookie_array = NULL; 1792 ccount = 0; 1793 } 1794 1795 out: 1796 if (cookie_array) 1797 kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount); 1798 return (error); 1799 } 1800 1801 /*ARGSUSED*/ 1802 static int 1803 amd_iommu_win(iommulib_handle_t handle, dev_info_t *dip, 1804 dev_info_t *rdip, ddi_dma_handle_t dma_handle, uint_t win, 1805 off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep, 1806 uint_t *ccountp) 1807 { 1808 int error = DDI_FAILURE; 1809 amd_iommu_t *iommu = iommulib_iommu_getdata(handle); 1810 ddi_dma_cookie_t *cookie_array = NULL; 1811 uint_t ccount = 0; 1812 int km_flags; 1813 ddi_dma_impl_t *hp; 1814 ddi_dma_attr_t *attrp; 1815 struct ddi_dma_req sdmareq = {0}; 1816 int instance = ddi_get_instance(rdip); 1817 const char *driver = ddi_driver_name(rdip); 1818 const char *f = "amd_iommu_win"; 1819 1820 km_flags = iommulib_iommu_dma_get_sleep_flags(dip, dma_handle); 1821 1822 cookie_array = NULL; 1823 ccount = 0; 1824 if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array, 1825 &ccount) != DDI_SUCCESS) { 1826 cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies " 1827 "for device %p", f, driver, instance, (void *)rdip); 1828 error = DDI_FAILURE; 1829 goto out; 1830 } 1831 1832 if (iommulib_iommu_dma_clear_cookies(dip, dma_handle) != DDI_SUCCESS) { 1833 cmn_err(CE_WARN, "%s: %s%d: Cannot clear cookies " 1834 "for device %p", f, driver, instance, (void *)rdip); 1835 error = DDI_FAILURE; 1836 goto out; 1837 } 1838 1839 if (iommulib_iommu_dma_win(dip, rdip, dma_handle, win, 1840 offp, lenp, cookiep, ccountp) != DDI_SUCCESS) { 1841 cmn_err(CE_WARN, "%s: %s%d: failed switch windows for dip=%p", 1842 f, driver, instance, (void *)rdip); 1843 error = DDI_FAILURE; 1844 goto out; 1845 } 1846 1847 (void) unmap_current_window(iommu, rdip, cookie_array, ccount, -1, 0); 1848 1849 if (cookie_array) { 1850 kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount); 1851 cookie_array = NULL; 1852 ccount = 0; 1853 } 1854 1855 cookie_array = NULL; 1856 ccount = 0; 1857 if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array, 1858 &ccount) != DDI_SUCCESS) { 1859 cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies " 1860 "for device %p", f, driver, instance, (void *)rdip); 1861 error = DDI_FAILURE; 1862 goto out; 1863 } 1864 1865 hp = (ddi_dma_impl_t *)dma_handle; 1866 attrp = &hp->dmai_attr; 1867 1868 sdmareq.dmar_flags = DDI_DMA_RDWR; 1869 error = map_current_window(iommu, rdip, attrp, &sdmareq, 1870 cookie_array, ccount, km_flags); 1871 1872 if (iommulib_iommu_dma_set_cookies(dip, dma_handle, cookie_array, 1873 ccount) != DDI_SUCCESS) { 1874 cmn_err(CE_WARN, "%s: %s%d: Cannot set cookies " 1875 "for device %p", f, driver, instance, (void *)rdip); 1876 error = DDI_FAILURE; 1877 goto out; 1878 } 1879 1880 *cookiep = cookie_array[0]; 1881 1882 return (error == DDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE); 1883 out: 1884 if (cookie_array) 1885 kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount); 1886 1887 return (error); 1888 } 1889 1890 /*ARGSUSED*/ 1891 static int 1892 amd_iommu_mapobject(iommulib_handle_t handle, dev_info_t *dip, 1893 dev_info_t *rdip, ddi_dma_handle_t dma_handle, 1894 struct ddi_dma_req *dmareq, ddi_dma_obj_t *dmao) 1895 { 1896 return (DDI_ENOTSUP); 1897 } 1898 1899 /*ARGSUSED*/ 1900 static int 1901 amd_iommu_unmapobject(iommulib_handle_t handle, dev_info_t *dip, 1902 dev_info_t *rdip, ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao) 1903 { 1904 return (DDI_ENOTSUP); 1905 } 1906 1907 uint64_t 1908 amd_iommu_reg_get64_workaround(uint64_t *regp, uint32_t bits) 1909 { 1910 split_t s; 1911 uint32_t *ptr32 = (uint32_t *)regp; 1912 uint64_t *s64p = &(s.u64); 1913 1914 s.u32[0] = ptr32[0]; 1915 s.u32[1] = ptr32[1]; 1916 1917 return (AMD_IOMMU_REG_GET64_IMPL(s64p, bits)); 1918 } 1919 1920 uint64_t 1921 amd_iommu_reg_set64_workaround(uint64_t *regp, uint32_t bits, uint64_t value) 1922 { 1923 split_t s; 1924 uint32_t *ptr32 = (uint32_t *)regp; 1925 uint64_t *s64p = &(s.u64); 1926 1927 s.u32[0] = ptr32[0]; 1928 s.u32[1] = ptr32[1]; 1929 1930 AMD_IOMMU_REG_SET64_IMPL(s64p, bits, value); 1931 1932 *regp = s.u64; 1933 1934 return (s.u64); 1935 } 1936 1937 void 1938 amd_iommu_read_boot_props(void) 1939 { 1940 char *propval; 1941 1942 /* 1943 * if "amd-iommu = no/false" boot property is set, 1944 * ignore AMD iommu 1945 */ 1946 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1947 DDI_PROP_DONTPASS, "amd-iommu", &propval) == DDI_SUCCESS) { 1948 if (strcmp(propval, "no") == 0 || 1949 strcmp(propval, "false") == 0) { 1950 amd_iommu_disable = 1; 1951 } 1952 ddi_prop_free(propval); 1953 } 1954 1955 /* 1956 * Copy the list of drivers for which IOMMU is disabled by user. 1957 */ 1958 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1959 DDI_PROP_DONTPASS, "amd-iommu-disable-list", &propval) 1960 == DDI_SUCCESS) { 1961 amd_iommu_disable_list = kmem_alloc(strlen(propval) + 1, 1962 KM_SLEEP); 1963 (void) strcpy(amd_iommu_disable_list, propval); 1964 ddi_prop_free(propval); 1965 } 1966 1967 } 1968 1969 void 1970 amd_iommu_lookup_conf_props(dev_info_t *dip) 1971 { 1972 char *disable; 1973 1974 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 1975 DDI_PROP_DONTPASS|DDI_PROP_NOTPROM, "amd-iommu", &disable) 1976 == DDI_PROP_SUCCESS) { 1977 if (strcmp(disable, "no") == 0) { 1978 amd_iommu_disable = 1; 1979 } 1980 ddi_prop_free(disable); 1981 } 1982 1983 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 1984 DDI_PROP_DONTPASS|DDI_PROP_NOTPROM, "amd-iommu-disable-list", 1985 &disable) == DDI_PROP_SUCCESS) { 1986 amd_iommu_disable_list = kmem_alloc(strlen(disable) + 1, 1987 KM_SLEEP); 1988 (void) strcpy(amd_iommu_disable_list, disable); 1989 ddi_prop_free(disable); 1990 } 1991 }