110535SVikram.Hegde@Sun.COM /*
210535SVikram.Hegde@Sun.COM * CDDL HEADER START
310535SVikram.Hegde@Sun.COM *
410535SVikram.Hegde@Sun.COM * The contents of this file are subject to the terms of the
510535SVikram.Hegde@Sun.COM * Common Development and Distribution License (the "License").
610535SVikram.Hegde@Sun.COM * You may not use this file except in compliance with the License.
710535SVikram.Hegde@Sun.COM *
810535SVikram.Hegde@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910535SVikram.Hegde@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010535SVikram.Hegde@Sun.COM * See the License for the specific language governing permissions
1110535SVikram.Hegde@Sun.COM * and limitations under the License.
1210535SVikram.Hegde@Sun.COM *
1310535SVikram.Hegde@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410535SVikram.Hegde@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510535SVikram.Hegde@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610535SVikram.Hegde@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710535SVikram.Hegde@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810535SVikram.Hegde@Sun.COM *
1910535SVikram.Hegde@Sun.COM * CDDL HEADER END
2010535SVikram.Hegde@Sun.COM */
2110535SVikram.Hegde@Sun.COM
2210535SVikram.Hegde@Sun.COM /*
2312203SJerry.Gilliam@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410535SVikram.Hegde@Sun.COM */
2510535SVikram.Hegde@Sun.COM
2610535SVikram.Hegde@Sun.COM #include <sys/sunddi.h>
2712203SJerry.Gilliam@Sun.COM #include <sys/sunndi.h>
2810535SVikram.Hegde@Sun.COM #include <sys/iommulib.h>
2910535SVikram.Hegde@Sun.COM #include <sys/amd_iommu.h>
3010535SVikram.Hegde@Sun.COM #include <sys/pci_cap.h>
3110535SVikram.Hegde@Sun.COM #include <sys/bootconf.h>
3210535SVikram.Hegde@Sun.COM #include <sys/ddidmareq.h>
3310535SVikram.Hegde@Sun.COM
3410535SVikram.Hegde@Sun.COM #include "amd_iommu_impl.h"
3510535SVikram.Hegde@Sun.COM #include "amd_iommu_acpi.h"
3610535SVikram.Hegde@Sun.COM #include "amd_iommu_page_tables.h"
3710535SVikram.Hegde@Sun.COM
3810536SVikram.Hegde@Sun.COM static int amd_iommu_fini(amd_iommu_t *iommu, int type);
3910535SVikram.Hegde@Sun.COM static void amd_iommu_teardown_interrupts(amd_iommu_t *iommu);
4010535SVikram.Hegde@Sun.COM static void amd_iommu_stop(amd_iommu_t *iommu);
4110535SVikram.Hegde@Sun.COM
4210535SVikram.Hegde@Sun.COM static int amd_iommu_probe(iommulib_handle_t handle, dev_info_t *rdip);
4310535SVikram.Hegde@Sun.COM static int amd_iommu_allochdl(iommulib_handle_t handle,
4410535SVikram.Hegde@Sun.COM dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
4510535SVikram.Hegde@Sun.COM int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *dma_handlep);
4610535SVikram.Hegde@Sun.COM static int amd_iommu_freehdl(iommulib_handle_t handle,
4710535SVikram.Hegde@Sun.COM dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle);
4810535SVikram.Hegde@Sun.COM static int amd_iommu_bindhdl(iommulib_handle_t handle, dev_info_t *dip,
4910535SVikram.Hegde@Sun.COM dev_info_t *rdip, ddi_dma_handle_t dma_handle,
5010535SVikram.Hegde@Sun.COM struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookiep,
5110535SVikram.Hegde@Sun.COM uint_t *ccountp);
5210535SVikram.Hegde@Sun.COM static int amd_iommu_unbindhdl(iommulib_handle_t handle,
5310535SVikram.Hegde@Sun.COM dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle);
5410535SVikram.Hegde@Sun.COM static int amd_iommu_sync(iommulib_handle_t handle, dev_info_t *dip,
5510535SVikram.Hegde@Sun.COM dev_info_t *rdip, ddi_dma_handle_t dma_handle, off_t off,
5610535SVikram.Hegde@Sun.COM size_t len, uint_t cache_flags);
5710535SVikram.Hegde@Sun.COM static int amd_iommu_win(iommulib_handle_t handle, dev_info_t *dip,
5810535SVikram.Hegde@Sun.COM dev_info_t *rdip, ddi_dma_handle_t dma_handle, uint_t win,
5910535SVikram.Hegde@Sun.COM off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep,
6010535SVikram.Hegde@Sun.COM uint_t *ccountp);
61*13050Sfrank.van.der.linden@oracle.com static int amd_iommu_mapobject(iommulib_handle_t handle, dev_info_t *dip,
62*13050Sfrank.van.der.linden@oracle.com dev_info_t *rdip, ddi_dma_handle_t dma_handle,
63*13050Sfrank.van.der.linden@oracle.com struct ddi_dma_req *dmareq, ddi_dma_obj_t *dmao);
64*13050Sfrank.van.der.linden@oracle.com static int amd_iommu_unmapobject(iommulib_handle_t handle, dev_info_t *dip,
65*13050Sfrank.van.der.linden@oracle.com dev_info_t *rdip, ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao);
6610535SVikram.Hegde@Sun.COM static int amd_iommu_map(iommulib_handle_t handle, dev_info_t *dip,
6710535SVikram.Hegde@Sun.COM dev_info_t *rdip, struct ddi_dma_req *dmareq,
6810535SVikram.Hegde@Sun.COM ddi_dma_handle_t *dma_handle);
6910535SVikram.Hegde@Sun.COM static int amd_iommu_mctl(iommulib_handle_t handle, dev_info_t *dip,
7010535SVikram.Hegde@Sun.COM dev_info_t *rdip, ddi_dma_handle_t dma_handle,
7110535SVikram.Hegde@Sun.COM enum ddi_dma_ctlops request, off_t *offp, size_t *lenp,
7210535SVikram.Hegde@Sun.COM caddr_t *objpp, uint_t cache_flags);
7310535SVikram.Hegde@Sun.COM
7410535SVikram.Hegde@Sun.COM static int unmap_current_window(amd_iommu_t *iommu, dev_info_t *rdip,
7510535SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookie_array, uint_t ccount, int ncookies, int locked);
7610535SVikram.Hegde@Sun.COM
7710535SVikram.Hegde@Sun.COM extern void *device_arena_alloc(size_t size, int vm_flag);
7810535SVikram.Hegde@Sun.COM extern void device_arena_free(void * vaddr, size_t size);
7910535SVikram.Hegde@Sun.COM
8010535SVikram.Hegde@Sun.COM ddi_dma_attr_t amd_iommu_dma_attr = {
8110535SVikram.Hegde@Sun.COM DMA_ATTR_V0,
8210535SVikram.Hegde@Sun.COM 0U, /* dma_attr_addr_lo */
8310535SVikram.Hegde@Sun.COM 0xffffffffffffffffULL, /* dma_attr_addr_hi */
8410535SVikram.Hegde@Sun.COM 0xffffffffU, /* dma_attr_count_max */
8510535SVikram.Hegde@Sun.COM (uint64_t)4096, /* dma_attr_align */
8610535SVikram.Hegde@Sun.COM 1, /* dma_attr_burstsizes */
8710535SVikram.Hegde@Sun.COM 64, /* dma_attr_minxfer */
8810535SVikram.Hegde@Sun.COM 0xffffffffU, /* dma_attr_maxxfer */
8910535SVikram.Hegde@Sun.COM 0xffffffffU, /* dma_attr_seg */
9010535SVikram.Hegde@Sun.COM 1, /* dma_attr_sgllen, variable */
9110535SVikram.Hegde@Sun.COM 64, /* dma_attr_granular */
9210535SVikram.Hegde@Sun.COM 0 /* dma_attr_flags */
9310535SVikram.Hegde@Sun.COM };
9410535SVikram.Hegde@Sun.COM
9510535SVikram.Hegde@Sun.COM ddi_device_acc_attr_t amd_iommu_devacc = {
9610535SVikram.Hegde@Sun.COM DDI_DEVICE_ATTR_V0,
9710535SVikram.Hegde@Sun.COM DDI_NEVERSWAP_ACC,
9810535SVikram.Hegde@Sun.COM DDI_STRICTORDER_ACC
9910535SVikram.Hegde@Sun.COM };
10010535SVikram.Hegde@Sun.COM
10110535SVikram.Hegde@Sun.COM struct iommulib_ops amd_iommulib_ops = {
10210535SVikram.Hegde@Sun.COM IOMMU_OPS_VERSION,
10310535SVikram.Hegde@Sun.COM AMD_IOMMU,
10410535SVikram.Hegde@Sun.COM "AMD IOMMU Vers. 1",
10510535SVikram.Hegde@Sun.COM NULL,
10610535SVikram.Hegde@Sun.COM amd_iommu_probe,
10710535SVikram.Hegde@Sun.COM amd_iommu_allochdl,
10810535SVikram.Hegde@Sun.COM amd_iommu_freehdl,
10910535SVikram.Hegde@Sun.COM amd_iommu_bindhdl,
11010535SVikram.Hegde@Sun.COM amd_iommu_unbindhdl,
11110535SVikram.Hegde@Sun.COM amd_iommu_sync,
11210535SVikram.Hegde@Sun.COM amd_iommu_win,
113*13050Sfrank.van.der.linden@oracle.com amd_iommu_mapobject,
114*13050Sfrank.van.der.linden@oracle.com amd_iommu_unmapobject,
11510535SVikram.Hegde@Sun.COM amd_iommu_map,
11610535SVikram.Hegde@Sun.COM amd_iommu_mctl
11710535SVikram.Hegde@Sun.COM };
11810535SVikram.Hegde@Sun.COM
11910535SVikram.Hegde@Sun.COM static kmutex_t amd_iommu_pgtable_lock;
12010535SVikram.Hegde@Sun.COM
12110535SVikram.Hegde@Sun.COM static int
amd_iommu_register(amd_iommu_t * iommu)12210535SVikram.Hegde@Sun.COM amd_iommu_register(amd_iommu_t *iommu)
12310535SVikram.Hegde@Sun.COM {
12410535SVikram.Hegde@Sun.COM dev_info_t *dip = iommu->aiomt_dip;
12510535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
12610535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
12710535SVikram.Hegde@Sun.COM iommulib_ops_t *iommulib_ops;
12810535SVikram.Hegde@Sun.COM iommulib_handle_t handle;
12910535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_register";
13010535SVikram.Hegde@Sun.COM
13110535SVikram.Hegde@Sun.COM iommulib_ops = kmem_zalloc(sizeof (iommulib_ops_t), KM_SLEEP);
13210535SVikram.Hegde@Sun.COM
13310535SVikram.Hegde@Sun.COM *iommulib_ops = amd_iommulib_ops;
13410535SVikram.Hegde@Sun.COM
13510535SVikram.Hegde@Sun.COM iommulib_ops->ilops_data = (void *)iommu;
13610535SVikram.Hegde@Sun.COM iommu->aiomt_iommulib_ops = iommulib_ops;
13710535SVikram.Hegde@Sun.COM
13810535SVikram.Hegde@Sun.COM if (iommulib_iommu_register(dip, iommulib_ops, &handle)
13910535SVikram.Hegde@Sun.COM != DDI_SUCCESS) {
14010535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Register with iommulib "
14110535SVikram.Hegde@Sun.COM "failed idx=%d", f, driver, instance, iommu->aiomt_idx);
14210535SVikram.Hegde@Sun.COM kmem_free(iommulib_ops, sizeof (iommulib_ops_t));
14310535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
14410535SVikram.Hegde@Sun.COM }
14510535SVikram.Hegde@Sun.COM
14610535SVikram.Hegde@Sun.COM iommu->aiomt_iommulib_handle = handle;
14710535SVikram.Hegde@Sun.COM
14810535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
14910535SVikram.Hegde@Sun.COM }
15010535SVikram.Hegde@Sun.COM
15110535SVikram.Hegde@Sun.COM static int
amd_iommu_unregister(amd_iommu_t * iommu)15210535SVikram.Hegde@Sun.COM amd_iommu_unregister(amd_iommu_t *iommu)
15310535SVikram.Hegde@Sun.COM {
15410535SVikram.Hegde@Sun.COM if (iommu->aiomt_iommulib_handle == NULL) {
15510535SVikram.Hegde@Sun.COM /* we never registered */
15610535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
15710535SVikram.Hegde@Sun.COM }
15810535SVikram.Hegde@Sun.COM
15910535SVikram.Hegde@Sun.COM if (iommulib_iommu_unregister(iommu->aiomt_iommulib_handle)
16010535SVikram.Hegde@Sun.COM != DDI_SUCCESS) {
16110535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
16210535SVikram.Hegde@Sun.COM }
16310535SVikram.Hegde@Sun.COM
16410535SVikram.Hegde@Sun.COM kmem_free(iommu->aiomt_iommulib_ops, sizeof (iommulib_ops_t));
16510535SVikram.Hegde@Sun.COM iommu->aiomt_iommulib_ops = NULL;
16610535SVikram.Hegde@Sun.COM iommu->aiomt_iommulib_handle = NULL;
16710535SVikram.Hegde@Sun.COM
16810535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
16910535SVikram.Hegde@Sun.COM }
17010535SVikram.Hegde@Sun.COM
17110535SVikram.Hegde@Sun.COM static int
amd_iommu_setup_passthru(amd_iommu_t * iommu)17210535SVikram.Hegde@Sun.COM amd_iommu_setup_passthru(amd_iommu_t *iommu)
17310535SVikram.Hegde@Sun.COM {
17410535SVikram.Hegde@Sun.COM gfx_entry_t *gfxp;
17510535SVikram.Hegde@Sun.COM dev_info_t *dip;
17610535SVikram.Hegde@Sun.COM
17710535SVikram.Hegde@Sun.COM /*
17810535SVikram.Hegde@Sun.COM * Setup passthru mapping for "special" devices
17910535SVikram.Hegde@Sun.COM */
18010535SVikram.Hegde@Sun.COM amd_iommu_set_passthru(iommu, NULL);
18110535SVikram.Hegde@Sun.COM
18210535SVikram.Hegde@Sun.COM for (gfxp = gfx_devinfo_list; gfxp; gfxp = gfxp->g_next) {
18310535SVikram.Hegde@Sun.COM gfxp->g_ref++;
18410535SVikram.Hegde@Sun.COM dip = gfxp->g_dip;
18510535SVikram.Hegde@Sun.COM if (dip) {
18610535SVikram.Hegde@Sun.COM amd_iommu_set_passthru(iommu, dip);
18710535SVikram.Hegde@Sun.COM }
18810535SVikram.Hegde@Sun.COM gfxp->g_ref--;
18910535SVikram.Hegde@Sun.COM }
19010535SVikram.Hegde@Sun.COM
19110535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
19210535SVikram.Hegde@Sun.COM }
19310535SVikram.Hegde@Sun.COM
19410535SVikram.Hegde@Sun.COM static int
amd_iommu_start(amd_iommu_t * iommu)19510535SVikram.Hegde@Sun.COM amd_iommu_start(amd_iommu_t *iommu)
19610535SVikram.Hegde@Sun.COM {
19710535SVikram.Hegde@Sun.COM dev_info_t *dip = iommu->aiomt_dip;
19810535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
19910535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
20010535SVikram.Hegde@Sun.COM amd_iommu_acpi_ivhd_t *hinfop;
20110535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_start";
20210535SVikram.Hegde@Sun.COM
20310535SVikram.Hegde@Sun.COM hinfop = amd_iommu_lookup_all_ivhd();
20410535SVikram.Hegde@Sun.COM
20510535SVikram.Hegde@Sun.COM /*
20610535SVikram.Hegde@Sun.COM * Disable HT tunnel translation.
20710535SVikram.Hegde@Sun.COM * XXX use ACPI
20810535SVikram.Hegde@Sun.COM */
20910535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
21010535SVikram.Hegde@Sun.COM AMD_IOMMU_HT_TUN_ENABLE, 0);
21110535SVikram.Hegde@Sun.COM
21210535SVikram.Hegde@Sun.COM if (hinfop) {
21310535SVikram.Hegde@Sun.COM if (amd_iommu_debug) {
21410535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE,
21510535SVikram.Hegde@Sun.COM "amd_iommu: using ACPI for CTRL registers");
21610535SVikram.Hegde@Sun.COM }
21710535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
21810535SVikram.Hegde@Sun.COM AMD_IOMMU_ISOC, hinfop->ach_Isoc);
21910535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
22010535SVikram.Hegde@Sun.COM AMD_IOMMU_RESPASSPW, hinfop->ach_ResPassPW);
22110535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
22210535SVikram.Hegde@Sun.COM AMD_IOMMU_PASSPW, hinfop->ach_PassPW);
22310535SVikram.Hegde@Sun.COM }
22410535SVikram.Hegde@Sun.COM
22510535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
22610535SVikram.Hegde@Sun.COM AMD_IOMMU_INVTO, 5);
22710535SVikram.Hegde@Sun.COM
22810535SVikram.Hegde@Sun.COM
22910535SVikram.Hegde@Sun.COM /*
23010535SVikram.Hegde@Sun.COM * The Device table entry bit 0 (V) controls whether the device
23110535SVikram.Hegde@Sun.COM * table entry is valid for address translation and Device table
23210535SVikram.Hegde@Sun.COM * entry bit 128 (IV) controls whether interrupt remapping is valid.
23310535SVikram.Hegde@Sun.COM * By setting both to zero we are essentially doing pass-thru. Since
23410535SVikram.Hegde@Sun.COM * this table is zeroed on allocation, essentially we will have
23510535SVikram.Hegde@Sun.COM * pass-thru when IOMMU is enabled.
23610535SVikram.Hegde@Sun.COM */
23710535SVikram.Hegde@Sun.COM
23810535SVikram.Hegde@Sun.COM /* Finally enable the IOMMU ... */
23910535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
24010535SVikram.Hegde@Sun.COM AMD_IOMMU_ENABLE, 1);
24110535SVikram.Hegde@Sun.COM
24210535SVikram.Hegde@Sun.COM if (amd_iommu_debug) {
24310535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
24410535SVikram.Hegde@Sun.COM "Successfully started AMD IOMMU", f, driver, instance,
24510535SVikram.Hegde@Sun.COM iommu->aiomt_idx);
24610535SVikram.Hegde@Sun.COM }
24710535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "AMD IOMMU (%d,%d) enabled",
24810535SVikram.Hegde@Sun.COM instance, iommu->aiomt_idx);
24910535SVikram.Hegde@Sun.COM
25010535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
25110535SVikram.Hegde@Sun.COM }
25210535SVikram.Hegde@Sun.COM
25310535SVikram.Hegde@Sun.COM static void
amd_iommu_stop(amd_iommu_t * iommu)25410535SVikram.Hegde@Sun.COM amd_iommu_stop(amd_iommu_t *iommu)
25510535SVikram.Hegde@Sun.COM {
25610535SVikram.Hegde@Sun.COM dev_info_t *dip = iommu->aiomt_dip;
25710535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
25810535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
25910535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_stop";
26010535SVikram.Hegde@Sun.COM
26110535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
26210535SVikram.Hegde@Sun.COM AMD_IOMMU_ENABLE, 0);
26310535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
26410535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTINT_ENABLE, 0);
26510535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
26610535SVikram.Hegde@Sun.COM AMD_IOMMU_COMWAITINT_ENABLE, 0);
26710535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
26810535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTLOG_ENABLE, 0);
26910535SVikram.Hegde@Sun.COM
27010535SVikram.Hegde@Sun.COM /*
27110535SVikram.Hegde@Sun.COM * Disable translation on HT tunnel traffic
27210535SVikram.Hegde@Sun.COM */
27310535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
27410535SVikram.Hegde@Sun.COM AMD_IOMMU_HT_TUN_ENABLE, 0);
27510535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
27610535SVikram.Hegde@Sun.COM AMD_IOMMU_CMDBUF_ENABLE, 0);
27710535SVikram.Hegde@Sun.COM
27810535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMYU idx=%d. "
27910535SVikram.Hegde@Sun.COM "Successfully stopped AMD IOMMU", f, driver, instance,
28010535SVikram.Hegde@Sun.COM iommu->aiomt_idx);
28110535SVikram.Hegde@Sun.COM }
28210535SVikram.Hegde@Sun.COM
28310535SVikram.Hegde@Sun.COM static int
amd_iommu_setup_tables_and_buffers(amd_iommu_t * iommu)28410535SVikram.Hegde@Sun.COM amd_iommu_setup_tables_and_buffers(amd_iommu_t *iommu)
28510535SVikram.Hegde@Sun.COM {
28610535SVikram.Hegde@Sun.COM dev_info_t *dip = iommu->aiomt_dip;
28710535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
28810535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
28910535SVikram.Hegde@Sun.COM uint32_t dma_bufsz;
29010535SVikram.Hegde@Sun.COM caddr_t addr;
29110535SVikram.Hegde@Sun.COM uint32_t sz;
29210535SVikram.Hegde@Sun.COM uint32_t p2sz;
29310535SVikram.Hegde@Sun.COM int i;
29410535SVikram.Hegde@Sun.COM uint64_t *dentry;
29510535SVikram.Hegde@Sun.COM int err;
29610535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_setup_tables_and_buffers";
29710535SVikram.Hegde@Sun.COM
29810535SVikram.Hegde@Sun.COM /*
29910535SVikram.Hegde@Sun.COM * We will put the Device Table, Command Buffer and
30010535SVikram.Hegde@Sun.COM * Event Log in contiguous memory. Allocate the maximum
30110535SVikram.Hegde@Sun.COM * size allowed for such structures
30210535SVikram.Hegde@Sun.COM * Device Table: 256b * 64K = 32B * 64K
30310535SVikram.Hegde@Sun.COM * Command Buffer: 128b * 32K = 16B * 32K
30410535SVikram.Hegde@Sun.COM * Event Log: 128b * 32K = 16B * 32K
30510535SVikram.Hegde@Sun.COM */
30610535SVikram.Hegde@Sun.COM iommu->aiomt_devtbl_sz = (1<<AMD_IOMMU_DEVTBL_SZ) * AMD_IOMMU_DEVENT_SZ;
30710535SVikram.Hegde@Sun.COM iommu->aiomt_cmdbuf_sz = (1<<AMD_IOMMU_CMDBUF_SZ) * AMD_IOMMU_CMD_SZ;
30810535SVikram.Hegde@Sun.COM iommu->aiomt_eventlog_sz =
30910535SVikram.Hegde@Sun.COM (1<<AMD_IOMMU_EVENTLOG_SZ) * AMD_IOMMU_EVENT_SZ;
31010535SVikram.Hegde@Sun.COM
31110535SVikram.Hegde@Sun.COM dma_bufsz = iommu->aiomt_devtbl_sz + iommu->aiomt_cmdbuf_sz
31210535SVikram.Hegde@Sun.COM + iommu->aiomt_eventlog_sz;
31310535SVikram.Hegde@Sun.COM
31410535SVikram.Hegde@Sun.COM /*
31510535SVikram.Hegde@Sun.COM * Alloc a DMA handle.
31610535SVikram.Hegde@Sun.COM */
31710535SVikram.Hegde@Sun.COM err = ddi_dma_alloc_handle(dip, &amd_iommu_dma_attr,
31810535SVikram.Hegde@Sun.COM DDI_DMA_SLEEP, NULL, &iommu->aiomt_dmahdl);
31910535SVikram.Hegde@Sun.COM if (err != DDI_SUCCESS) {
32010535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot alloc DMA handle for "
32110535SVikram.Hegde@Sun.COM "AMD IOMMU tables and buffers", f, driver, instance);
32210535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
32310535SVikram.Hegde@Sun.COM }
32410535SVikram.Hegde@Sun.COM
32510535SVikram.Hegde@Sun.COM /*
32610535SVikram.Hegde@Sun.COM * Alloc memory for tables and buffers
32710535SVikram.Hegde@Sun.COM * XXX remove cast to size_t
32810535SVikram.Hegde@Sun.COM */
32910535SVikram.Hegde@Sun.COM err = ddi_dma_mem_alloc(iommu->aiomt_dmahdl, dma_bufsz,
33010535SVikram.Hegde@Sun.COM &amd_iommu_devacc, DDI_DMA_CONSISTENT|IOMEM_DATA_UNCACHED,
33110535SVikram.Hegde@Sun.COM DDI_DMA_SLEEP, NULL, (caddr_t *)&iommu->aiomt_dma_bufva,
33210535SVikram.Hegde@Sun.COM (size_t *)&iommu->aiomt_dma_mem_realsz, &iommu->aiomt_dma_mem_hdl);
33310535SVikram.Hegde@Sun.COM if (err != DDI_SUCCESS) {
33410535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot alloc memory for DMA "
33510535SVikram.Hegde@Sun.COM "to AMD IOMMU tables and buffers", f, driver, instance);
33610535SVikram.Hegde@Sun.COM iommu->aiomt_dma_bufva = NULL;
33710535SVikram.Hegde@Sun.COM iommu->aiomt_dma_mem_realsz = 0;
33810535SVikram.Hegde@Sun.COM ddi_dma_free_handle(&iommu->aiomt_dmahdl);
33910535SVikram.Hegde@Sun.COM iommu->aiomt_dmahdl = NULL;
34010535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
34110535SVikram.Hegde@Sun.COM }
34210535SVikram.Hegde@Sun.COM
34310535SVikram.Hegde@Sun.COM /*
34410535SVikram.Hegde@Sun.COM * The VA must be 4K aligned and >= table size
34510535SVikram.Hegde@Sun.COM */
34610535SVikram.Hegde@Sun.COM ASSERT(((uintptr_t)iommu->aiomt_dma_bufva &
34710535SVikram.Hegde@Sun.COM AMD_IOMMU_TABLE_ALIGN) == 0);
34810535SVikram.Hegde@Sun.COM ASSERT(iommu->aiomt_dma_mem_realsz >= dma_bufsz);
34910535SVikram.Hegde@Sun.COM
35010535SVikram.Hegde@Sun.COM /*
35110535SVikram.Hegde@Sun.COM * Now bind the handle
35210535SVikram.Hegde@Sun.COM */
35310535SVikram.Hegde@Sun.COM err = ddi_dma_addr_bind_handle(iommu->aiomt_dmahdl, NULL,
35410535SVikram.Hegde@Sun.COM iommu->aiomt_dma_bufva, iommu->aiomt_dma_mem_realsz,
35510535SVikram.Hegde@Sun.COM DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
35610535SVikram.Hegde@Sun.COM NULL, &iommu->aiomt_buf_dma_cookie, &iommu->aiomt_buf_dma_ncookie);
35710535SVikram.Hegde@Sun.COM if (err != DDI_DMA_MAPPED) {
35810535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot bind memory for DMA "
35910535SVikram.Hegde@Sun.COM "to AMD IOMMU tables and buffers. bufrealsz=%p",
36010535SVikram.Hegde@Sun.COM f, driver, instance,
36110535SVikram.Hegde@Sun.COM (void *)(uintptr_t)iommu->aiomt_dma_mem_realsz);
36210535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_cookie.dmac_laddress = 0;
36310535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_cookie.dmac_size = 0;
36410535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_cookie.dmac_type = 0;
36510535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_ncookie = 0;
36610535SVikram.Hegde@Sun.COM ddi_dma_mem_free(&iommu->aiomt_dma_mem_hdl);
36710535SVikram.Hegde@Sun.COM iommu->aiomt_dma_mem_hdl = NULL;
36810535SVikram.Hegde@Sun.COM iommu->aiomt_dma_bufva = NULL;
36910535SVikram.Hegde@Sun.COM iommu->aiomt_dma_mem_realsz = 0;
37010535SVikram.Hegde@Sun.COM ddi_dma_free_handle(&iommu->aiomt_dmahdl);
37110535SVikram.Hegde@Sun.COM iommu->aiomt_dmahdl = NULL;
37210535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
37310535SVikram.Hegde@Sun.COM }
37410535SVikram.Hegde@Sun.COM
37510535SVikram.Hegde@Sun.COM /*
37610535SVikram.Hegde@Sun.COM * We assume the DMA engine on the IOMMU is capable of handling the
37710535SVikram.Hegde@Sun.COM * whole table buffer in a single cookie. If not and multiple cookies
37810535SVikram.Hegde@Sun.COM * are needed we fail.
37910535SVikram.Hegde@Sun.COM */
38010535SVikram.Hegde@Sun.COM if (iommu->aiomt_buf_dma_ncookie != 1) {
38110535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot handle multiple "
38210535SVikram.Hegde@Sun.COM "cookies for DMA to AMD IOMMU tables and buffers. "
38310535SVikram.Hegde@Sun.COM "#cookies=%u", f, driver, instance,
38410535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_ncookie);
38510535SVikram.Hegde@Sun.COM (void) ddi_dma_unbind_handle(iommu->aiomt_dmahdl);
38610535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_cookie.dmac_laddress = 0;
38710535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_cookie.dmac_size = 0;
38810535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_cookie.dmac_type = 0;
38910535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_ncookie = 0;
39010535SVikram.Hegde@Sun.COM ddi_dma_mem_free(&iommu->aiomt_dma_mem_hdl);
39110535SVikram.Hegde@Sun.COM iommu->aiomt_dma_mem_hdl = NULL;
39210535SVikram.Hegde@Sun.COM iommu->aiomt_dma_bufva = NULL;
39310535SVikram.Hegde@Sun.COM iommu->aiomt_dma_mem_realsz = 0;
39410535SVikram.Hegde@Sun.COM ddi_dma_free_handle(&iommu->aiomt_dmahdl);
39510535SVikram.Hegde@Sun.COM iommu->aiomt_dmahdl = NULL;
39610535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
39710535SVikram.Hegde@Sun.COM }
39810535SVikram.Hegde@Sun.COM
39910535SVikram.Hegde@Sun.COM /*
40010535SVikram.Hegde@Sun.COM * The address in the cookie must be 4K aligned and >= table size
40110535SVikram.Hegde@Sun.COM */
40210535SVikram.Hegde@Sun.COM ASSERT((iommu->aiomt_buf_dma_cookie.dmac_cookie_addr
40310535SVikram.Hegde@Sun.COM & AMD_IOMMU_TABLE_ALIGN) == 0);
40410535SVikram.Hegde@Sun.COM ASSERT(iommu->aiomt_buf_dma_cookie.dmac_size
40510535SVikram.Hegde@Sun.COM <= iommu->aiomt_dma_mem_realsz);
40610535SVikram.Hegde@Sun.COM ASSERT(iommu->aiomt_buf_dma_cookie.dmac_size >= dma_bufsz);
40710535SVikram.Hegde@Sun.COM
40810535SVikram.Hegde@Sun.COM /*
40910535SVikram.Hegde@Sun.COM * Setup the device table pointers in the iommu struct as
41010535SVikram.Hegde@Sun.COM * well as the IOMMU device table register
41110535SVikram.Hegde@Sun.COM */
41210535SVikram.Hegde@Sun.COM iommu->aiomt_devtbl = iommu->aiomt_dma_bufva;
41310535SVikram.Hegde@Sun.COM bzero(iommu->aiomt_devtbl, iommu->aiomt_devtbl_sz);
41410535SVikram.Hegde@Sun.COM
41510535SVikram.Hegde@Sun.COM /*
41610535SVikram.Hegde@Sun.COM * Set V=1 and TV = 0, so any inadvertant pass-thrus cause
41710535SVikram.Hegde@Sun.COM * page faults. Also set SE bit so we aren't swamped with
41810535SVikram.Hegde@Sun.COM * page fault messages
41910535SVikram.Hegde@Sun.COM */
42010535SVikram.Hegde@Sun.COM for (i = 0; i <= AMD_IOMMU_MAX_DEVICEID; i++) {
42110535SVikram.Hegde@Sun.COM /*LINTED*/
42210535SVikram.Hegde@Sun.COM dentry = (uint64_t *)&iommu->aiomt_devtbl
42310535SVikram.Hegde@Sun.COM [i * AMD_IOMMU_DEVTBL_ENTRY_SZ];
42410535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(dentry, AMD_IOMMU_DEVTBL_V, 1);
42510535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(&(dentry[1]), AMD_IOMMU_DEVTBL_SE, 1);
42610535SVikram.Hegde@Sun.COM }
42710535SVikram.Hegde@Sun.COM
42810535SVikram.Hegde@Sun.COM addr = (caddr_t)(uintptr_t)iommu->aiomt_buf_dma_cookie.dmac_cookie_addr;
42910535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va),
43010535SVikram.Hegde@Sun.COM AMD_IOMMU_DEVTABBASE, ((uint64_t)(uintptr_t)addr) >> 12);
43110535SVikram.Hegde@Sun.COM sz = (iommu->aiomt_devtbl_sz >> 12) - 1;
43210535SVikram.Hegde@Sun.COM ASSERT(sz <= ((1 << 9) - 1));
43310535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va),
43410535SVikram.Hegde@Sun.COM AMD_IOMMU_DEVTABSIZE, sz);
43510535SVikram.Hegde@Sun.COM
43610535SVikram.Hegde@Sun.COM /*
43710535SVikram.Hegde@Sun.COM * Setup the command buffer pointers
43810535SVikram.Hegde@Sun.COM */
43910535SVikram.Hegde@Sun.COM iommu->aiomt_cmdbuf = iommu->aiomt_devtbl +
44010535SVikram.Hegde@Sun.COM iommu->aiomt_devtbl_sz;
44110535SVikram.Hegde@Sun.COM bzero(iommu->aiomt_cmdbuf, iommu->aiomt_cmdbuf_sz);
44210535SVikram.Hegde@Sun.COM addr += iommu->aiomt_devtbl_sz;
44310535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va),
44410535SVikram.Hegde@Sun.COM AMD_IOMMU_COMBASE, ((uint64_t)(uintptr_t)addr) >> 12);
44510535SVikram.Hegde@Sun.COM
44610535SVikram.Hegde@Sun.COM p2sz = AMD_IOMMU_CMDBUF_SZ;
44710535SVikram.Hegde@Sun.COM ASSERT(p2sz >= AMD_IOMMU_CMDBUF_MINSZ &&
44810535SVikram.Hegde@Sun.COM p2sz <= AMD_IOMMU_CMDBUF_MAXSZ);
44910535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va),
45010535SVikram.Hegde@Sun.COM AMD_IOMMU_COMLEN, p2sz);
45110535SVikram.Hegde@Sun.COM /*LINTED*/
45210535SVikram.Hegde@Sun.COM iommu->aiomt_cmd_tail = (uint32_t *)iommu->aiomt_cmdbuf;
45310535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_head_va),
45410535SVikram.Hegde@Sun.COM AMD_IOMMU_CMDHEADPTR, 0);
45510535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_tail_va),
45610535SVikram.Hegde@Sun.COM AMD_IOMMU_CMDTAILPTR, 0);
45710535SVikram.Hegde@Sun.COM
45810535SVikram.Hegde@Sun.COM /*
45910535SVikram.Hegde@Sun.COM * Setup the event log pointers
46010535SVikram.Hegde@Sun.COM */
46110535SVikram.Hegde@Sun.COM iommu->aiomt_eventlog = iommu->aiomt_cmdbuf +
46210535SVikram.Hegde@Sun.COM iommu->aiomt_eventlog_sz;
46310535SVikram.Hegde@Sun.COM bzero(iommu->aiomt_eventlog, iommu->aiomt_eventlog_sz);
46410535SVikram.Hegde@Sun.COM addr += iommu->aiomt_cmdbuf_sz;
46510535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va),
46610535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTBASE, ((uint64_t)(uintptr_t)addr) >> 12);
46710535SVikram.Hegde@Sun.COM p2sz = AMD_IOMMU_EVENTLOG_SZ;
46810535SVikram.Hegde@Sun.COM ASSERT(p2sz >= AMD_IOMMU_EVENTLOG_MINSZ &&
46910535SVikram.Hegde@Sun.COM p2sz <= AMD_IOMMU_EVENTLOG_MAXSZ);
47010535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va),
47110535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTLEN, sz);
47210535SVikram.Hegde@Sun.COM /*LINTED*/
47310535SVikram.Hegde@Sun.COM iommu->aiomt_event_head = (uint32_t *)iommu->aiomt_eventlog;
47410535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_head_va),
47510535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTHEADPTR, 0);
47610535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_tail_va),
47710535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTTAILPTR, 0);
47810535SVikram.Hegde@Sun.COM
47910535SVikram.Hegde@Sun.COM /* dma sync so device sees this init */
48010535SVikram.Hegde@Sun.COM SYNC_FORDEV(iommu->aiomt_dmahdl);
48110535SVikram.Hegde@Sun.COM
48210535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_TABLES) {
48310535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: successfully setup AMD IOMMU "
48410535SVikram.Hegde@Sun.COM "tables, idx=%d", f, driver, instance, iommu->aiomt_idx);
48510535SVikram.Hegde@Sun.COM }
48610535SVikram.Hegde@Sun.COM
48710535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
48810535SVikram.Hegde@Sun.COM }
48910535SVikram.Hegde@Sun.COM
49010535SVikram.Hegde@Sun.COM static void
amd_iommu_teardown_tables_and_buffers(amd_iommu_t * iommu,int type)49110536SVikram.Hegde@Sun.COM amd_iommu_teardown_tables_and_buffers(amd_iommu_t *iommu, int type)
49210535SVikram.Hegde@Sun.COM {
49310535SVikram.Hegde@Sun.COM dev_info_t *dip = iommu->aiomt_dip;
49410535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
49510535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
49610535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_teardown_tables_and_buffers";
49710535SVikram.Hegde@Sun.COM
49810535SVikram.Hegde@Sun.COM iommu->aiomt_eventlog = NULL;
49910535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va),
50010535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTBASE, 0);
50110535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va),
50210535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTLEN, 0);
50310536SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_head_va),
50410536SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTHEADPTR, 0);
50510536SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_head_va),
50610536SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTTAILPTR, 0);
50710536SVikram.Hegde@Sun.COM
50810535SVikram.Hegde@Sun.COM
50910535SVikram.Hegde@Sun.COM iommu->aiomt_cmdbuf = NULL;
51010535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va),
51110535SVikram.Hegde@Sun.COM AMD_IOMMU_COMBASE, 0);
51210535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va),
51310535SVikram.Hegde@Sun.COM AMD_IOMMU_COMLEN, 0);
51410536SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_head_va),
51510536SVikram.Hegde@Sun.COM AMD_IOMMU_CMDHEADPTR, 0);
51610536SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_head_va),
51710536SVikram.Hegde@Sun.COM AMD_IOMMU_CMDTAILPTR, 0);
51810536SVikram.Hegde@Sun.COM
51910535SVikram.Hegde@Sun.COM
52010535SVikram.Hegde@Sun.COM iommu->aiomt_devtbl = NULL;
52110535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va),
52210535SVikram.Hegde@Sun.COM AMD_IOMMU_DEVTABBASE, 0);
52310535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va),
52410535SVikram.Hegde@Sun.COM AMD_IOMMU_DEVTABSIZE, 0);
52510535SVikram.Hegde@Sun.COM
52610536SVikram.Hegde@Sun.COM if (iommu->aiomt_dmahdl == NULL || type == AMD_IOMMU_QUIESCE)
52710535SVikram.Hegde@Sun.COM return;
52810535SVikram.Hegde@Sun.COM
52910535SVikram.Hegde@Sun.COM /* Unbind the handle */
53010535SVikram.Hegde@Sun.COM if (ddi_dma_unbind_handle(iommu->aiomt_dmahdl) != DDI_SUCCESS) {
53110535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: failed to unbind handle: "
53210535SVikram.Hegde@Sun.COM "%p for IOMMU idx=%d", f, driver, instance,
53310535SVikram.Hegde@Sun.COM (void *)iommu->aiomt_dmahdl, iommu->aiomt_idx);
53410535SVikram.Hegde@Sun.COM }
53510535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_cookie.dmac_laddress = 0;
53610535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_cookie.dmac_size = 0;
53710535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_cookie.dmac_type = 0;
53810535SVikram.Hegde@Sun.COM iommu->aiomt_buf_dma_ncookie = 0;
53910535SVikram.Hegde@Sun.COM
54010535SVikram.Hegde@Sun.COM /* Free the table memory allocated for DMA */
54110535SVikram.Hegde@Sun.COM ddi_dma_mem_free(&iommu->aiomt_dma_mem_hdl);
54210535SVikram.Hegde@Sun.COM iommu->aiomt_dma_mem_hdl = NULL;
54310535SVikram.Hegde@Sun.COM iommu->aiomt_dma_bufva = NULL;
54410535SVikram.Hegde@Sun.COM iommu->aiomt_dma_mem_realsz = 0;
54510535SVikram.Hegde@Sun.COM
54610535SVikram.Hegde@Sun.COM /* Free the DMA handle */
54710535SVikram.Hegde@Sun.COM ddi_dma_free_handle(&iommu->aiomt_dmahdl);
54810535SVikram.Hegde@Sun.COM iommu->aiomt_dmahdl = NULL;
54910535SVikram.Hegde@Sun.COM }
55010535SVikram.Hegde@Sun.COM
55110535SVikram.Hegde@Sun.COM static void
amd_iommu_enable_interrupts(amd_iommu_t * iommu)55210535SVikram.Hegde@Sun.COM amd_iommu_enable_interrupts(amd_iommu_t *iommu)
55310535SVikram.Hegde@Sun.COM {
55410535SVikram.Hegde@Sun.COM ASSERT(AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va),
55510535SVikram.Hegde@Sun.COM AMD_IOMMU_CMDBUF_RUN) == 0);
55610535SVikram.Hegde@Sun.COM ASSERT(AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va),
55710535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENT_LOG_RUN) == 0);
55810535SVikram.Hegde@Sun.COM
55910535SVikram.Hegde@Sun.COM /* Must be set prior to enabling command buffer */
56010535SVikram.Hegde@Sun.COM /* Must be set prior to enabling event logging */
56110535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
56210535SVikram.Hegde@Sun.COM AMD_IOMMU_CMDBUF_ENABLE, 1);
56310535SVikram.Hegde@Sun.COM /* No interrupts for completion wait - too heavy weight. use polling */
56410535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
56510535SVikram.Hegde@Sun.COM AMD_IOMMU_COMWAITINT_ENABLE, 0);
56610535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
56710535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTLOG_ENABLE, 1);
56810535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
56910535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTINT_ENABLE, 1);
57010535SVikram.Hegde@Sun.COM }
57110535SVikram.Hegde@Sun.COM
57210535SVikram.Hegde@Sun.COM static int
amd_iommu_setup_exclusion(amd_iommu_t * iommu)57310535SVikram.Hegde@Sun.COM amd_iommu_setup_exclusion(amd_iommu_t *iommu)
57410535SVikram.Hegde@Sun.COM {
57510535SVikram.Hegde@Sun.COM amd_iommu_acpi_ivmd_t *minfop;
57610535SVikram.Hegde@Sun.COM
57710535SVikram.Hegde@Sun.COM minfop = amd_iommu_lookup_all_ivmd();
57810535SVikram.Hegde@Sun.COM
57910535SVikram.Hegde@Sun.COM if (minfop && minfop->acm_ExclRange == 1) {
58010535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "Programming exclusion range");
58110535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
58210535SVikram.Hegde@Sun.COM AMD_IOMMU_EXCL_BASE_ADDR,
58310535SVikram.Hegde@Sun.COM minfop->acm_ivmd_phys_start >> 12);
58410535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
58510535SVikram.Hegde@Sun.COM AMD_IOMMU_EXCL_BASE_ALLOW, 1);
58610535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
58710535SVikram.Hegde@Sun.COM AMD_IOMMU_EXCL_BASE_EXEN, 1);
58810535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_lim_va),
58910535SVikram.Hegde@Sun.COM AMD_IOMMU_EXCL_LIM, (minfop->acm_ivmd_phys_start +
59010535SVikram.Hegde@Sun.COM minfop->acm_ivmd_phys_len) >> 12);
59110535SVikram.Hegde@Sun.COM } else {
59210535SVikram.Hegde@Sun.COM if (amd_iommu_debug) {
59310535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "Skipping exclusion range");
59410535SVikram.Hegde@Sun.COM }
59510535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
59610535SVikram.Hegde@Sun.COM AMD_IOMMU_EXCL_BASE_ADDR, 0);
59710535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
59810535SVikram.Hegde@Sun.COM AMD_IOMMU_EXCL_BASE_ALLOW, 1);
59910535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
60010535SVikram.Hegde@Sun.COM AMD_IOMMU_EXCL_BASE_EXEN, 0);
60110535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_lim_va),
60210535SVikram.Hegde@Sun.COM AMD_IOMMU_EXCL_LIM, 0);
60310535SVikram.Hegde@Sun.COM }
60410535SVikram.Hegde@Sun.COM
60510535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
60610535SVikram.Hegde@Sun.COM }
60710535SVikram.Hegde@Sun.COM
60810535SVikram.Hegde@Sun.COM static void
amd_iommu_teardown_exclusion(amd_iommu_t * iommu)60910535SVikram.Hegde@Sun.COM amd_iommu_teardown_exclusion(amd_iommu_t *iommu)
61010535SVikram.Hegde@Sun.COM {
61110535SVikram.Hegde@Sun.COM (void) amd_iommu_setup_exclusion(iommu);
61210535SVikram.Hegde@Sun.COM }
61310535SVikram.Hegde@Sun.COM
61410535SVikram.Hegde@Sun.COM static uint_t
amd_iommu_intr_handler(caddr_t arg1,caddr_t arg2)61510535SVikram.Hegde@Sun.COM amd_iommu_intr_handler(caddr_t arg1, caddr_t arg2)
61610535SVikram.Hegde@Sun.COM {
61710535SVikram.Hegde@Sun.COM /*LINTED*/
61810535SVikram.Hegde@Sun.COM amd_iommu_t *iommu = (amd_iommu_t *)arg1;
61910535SVikram.Hegde@Sun.COM dev_info_t *dip = iommu->aiomt_dip;
62010535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
62110535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
62210535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_intr_handler";
62310535SVikram.Hegde@Sun.COM
62410535SVikram.Hegde@Sun.COM ASSERT(arg1);
62510535SVikram.Hegde@Sun.COM ASSERT(arg2 == NULL);
62610535SVikram.Hegde@Sun.COM
62710535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
62810535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: IOMMU unit idx=%d. In INTR handler",
62910535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx);
63010535SVikram.Hegde@Sun.COM }
63110535SVikram.Hegde@Sun.COM
63210535SVikram.Hegde@Sun.COM if (AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va),
63310535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENT_LOG_INT) == 1) {
63410535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
63510535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: IOMMU unit idx=%d "
63610535SVikram.Hegde@Sun.COM "Event Log Interrupt", f, driver, instance,
63710535SVikram.Hegde@Sun.COM iommu->aiomt_idx);
63810535SVikram.Hegde@Sun.COM }
63910535SVikram.Hegde@Sun.COM (void) amd_iommu_read_log(iommu, AMD_IOMMU_LOG_DISPLAY);
64010535SVikram.Hegde@Sun.COM WAIT_SEC(1);
64110535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_status_va),
64210535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENT_LOG_INT, 1);
64310535SVikram.Hegde@Sun.COM return (DDI_INTR_CLAIMED);
64410535SVikram.Hegde@Sun.COM }
64510535SVikram.Hegde@Sun.COM
64610535SVikram.Hegde@Sun.COM if (AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va),
64710535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENT_OVERFLOW_INT) == 1) {
64810535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "!%s: %s%d: IOMMU unit idx=%d "
64910535SVikram.Hegde@Sun.COM "Event Overflow Interrupt", f, driver, instance,
65010535SVikram.Hegde@Sun.COM iommu->aiomt_idx);
65110535SVikram.Hegde@Sun.COM (void) amd_iommu_read_log(iommu, AMD_IOMMU_LOG_DISCARD);
65210535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_status_va),
65310535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENT_LOG_INT, 1);
65410535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_status_va),
65510535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENT_OVERFLOW_INT, 1);
65610535SVikram.Hegde@Sun.COM return (DDI_INTR_CLAIMED);
65710535SVikram.Hegde@Sun.COM }
65810535SVikram.Hegde@Sun.COM
65910535SVikram.Hegde@Sun.COM return (DDI_INTR_UNCLAIMED);
66010535SVikram.Hegde@Sun.COM }
66110535SVikram.Hegde@Sun.COM
66210535SVikram.Hegde@Sun.COM
66310535SVikram.Hegde@Sun.COM static int
amd_iommu_setup_interrupts(amd_iommu_t * iommu)66410535SVikram.Hegde@Sun.COM amd_iommu_setup_interrupts(amd_iommu_t *iommu)
66510535SVikram.Hegde@Sun.COM {
66610535SVikram.Hegde@Sun.COM dev_info_t *dip = iommu->aiomt_dip;
66710535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
66810535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
66910535SVikram.Hegde@Sun.COM int intrcap0;
67010535SVikram.Hegde@Sun.COM int intrcapN;
67110535SVikram.Hegde@Sun.COM int type;
67210535SVikram.Hegde@Sun.COM int err;
67310535SVikram.Hegde@Sun.COM int req;
67410535SVikram.Hegde@Sun.COM int avail;
67510535SVikram.Hegde@Sun.COM int p2req;
67610535SVikram.Hegde@Sun.COM int actual;
67710535SVikram.Hegde@Sun.COM int i;
67810535SVikram.Hegde@Sun.COM int j;
67910535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_setup_interrupts";
68010535SVikram.Hegde@Sun.COM
68110535SVikram.Hegde@Sun.COM if (ddi_intr_get_supported_types(dip, &type) != DDI_SUCCESS) {
68210535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: ddi_intr_get_supported_types "
68310535SVikram.Hegde@Sun.COM "failed: idx=%d", f, driver, instance, iommu->aiomt_idx);
68410535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
68510535SVikram.Hegde@Sun.COM }
68610535SVikram.Hegde@Sun.COM
68710535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
68810535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
68910535SVikram.Hegde@Sun.COM "Interrupt types supported = 0x%x", f, driver, instance,
69010535SVikram.Hegde@Sun.COM iommu->aiomt_idx, type);
69110535SVikram.Hegde@Sun.COM }
69210535SVikram.Hegde@Sun.COM
69310535SVikram.Hegde@Sun.COM /*
69410535SVikram.Hegde@Sun.COM * for now we only support MSI
69510535SVikram.Hegde@Sun.COM */
69610535SVikram.Hegde@Sun.COM if ((type & DDI_INTR_TYPE_MSI) == 0) {
69710535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d. "
69810535SVikram.Hegde@Sun.COM "MSI interrupts not supported. Failing init.",
69910535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx);
70010535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
70110535SVikram.Hegde@Sun.COM }
70210535SVikram.Hegde@Sun.COM
70310535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
70410535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. MSI supported",
70510535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx);
70610535SVikram.Hegde@Sun.COM }
70710535SVikram.Hegde@Sun.COM
70810535SVikram.Hegde@Sun.COM err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_MSI, &req);
70910535SVikram.Hegde@Sun.COM if (err != DDI_SUCCESS) {
71010535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d. "
71110535SVikram.Hegde@Sun.COM "ddi_intr_get_nintrs failed err = %d",
71210535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx, err);
71310535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
71410535SVikram.Hegde@Sun.COM }
71510535SVikram.Hegde@Sun.COM
71610535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
71710535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
71810535SVikram.Hegde@Sun.COM "MSI number of interrupts requested: %d",
71910535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx, req);
72010535SVikram.Hegde@Sun.COM }
72110535SVikram.Hegde@Sun.COM
72210535SVikram.Hegde@Sun.COM if (req == 0) {
72310535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: 0 MSI "
72410535SVikram.Hegde@Sun.COM "interrupts requested. Failing init", f,
72510535SVikram.Hegde@Sun.COM driver, instance, iommu->aiomt_idx);
72610535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
72710535SVikram.Hegde@Sun.COM }
72810535SVikram.Hegde@Sun.COM
72910535SVikram.Hegde@Sun.COM err = ddi_intr_get_navail(dip, DDI_INTR_TYPE_MSI, &avail);
73010535SVikram.Hegde@Sun.COM if (err != DDI_SUCCESS) {
73110535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d "
73210535SVikram.Hegde@Sun.COM "ddi_intr_get_navail failed err = %d", f,
73310535SVikram.Hegde@Sun.COM driver, instance, iommu->aiomt_idx, err);
73410535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
73510535SVikram.Hegde@Sun.COM }
73610535SVikram.Hegde@Sun.COM
73710535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
73810535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
73910535SVikram.Hegde@Sun.COM "MSI number of interrupts available: %d",
74010535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx, avail);
74110535SVikram.Hegde@Sun.COM }
74210535SVikram.Hegde@Sun.COM
74310535SVikram.Hegde@Sun.COM if (avail == 0) {
74410535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: 0 MSI "
74510535SVikram.Hegde@Sun.COM "interrupts available. Failing init", f,
74610535SVikram.Hegde@Sun.COM driver, instance, iommu->aiomt_idx);
74710535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
74810535SVikram.Hegde@Sun.COM }
74910535SVikram.Hegde@Sun.COM
75010535SVikram.Hegde@Sun.COM if (avail < req) {
75110535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: MSI "
75210535SVikram.Hegde@Sun.COM "interrupts: requested (%d) > available (%d). "
75310535SVikram.Hegde@Sun.COM "Failing init", f, driver, instance, iommu->aiomt_idx,
75410535SVikram.Hegde@Sun.COM req, avail);
75510535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
75610535SVikram.Hegde@Sun.COM }
75710535SVikram.Hegde@Sun.COM
75810535SVikram.Hegde@Sun.COM /* Allocate memory for DDI interrupt handles */
75910535SVikram.Hegde@Sun.COM iommu->aiomt_intr_htable_sz = req * sizeof (ddi_intr_handle_t);
76010535SVikram.Hegde@Sun.COM iommu->aiomt_intr_htable = kmem_zalloc(iommu->aiomt_intr_htable_sz,
76110535SVikram.Hegde@Sun.COM KM_SLEEP);
76210535SVikram.Hegde@Sun.COM
76310535SVikram.Hegde@Sun.COM iommu->aiomt_intr_state = AMD_IOMMU_INTR_TABLE;
76410535SVikram.Hegde@Sun.COM
76510535SVikram.Hegde@Sun.COM /* Convert req to a power of two as required by ddi_intr_alloc */
76610535SVikram.Hegde@Sun.COM p2req = 0;
76710535SVikram.Hegde@Sun.COM while (1<<p2req <= req)
76810535SVikram.Hegde@Sun.COM p2req++;
76910535SVikram.Hegde@Sun.COM p2req--;
77010535SVikram.Hegde@Sun.COM req = 1<<p2req;
77110535SVikram.Hegde@Sun.COM
77210535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
77310535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
77410535SVikram.Hegde@Sun.COM "MSI power of 2 number of interrupts: %d,%d",
77510535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx, p2req, req);
77610535SVikram.Hegde@Sun.COM }
77710535SVikram.Hegde@Sun.COM
77810535SVikram.Hegde@Sun.COM err = ddi_intr_alloc(iommu->aiomt_dip, iommu->aiomt_intr_htable,
77910535SVikram.Hegde@Sun.COM DDI_INTR_TYPE_MSI, 0, req, &actual, DDI_INTR_ALLOC_STRICT);
78010535SVikram.Hegde@Sun.COM if (err != DDI_SUCCESS) {
78110535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
78210535SVikram.Hegde@Sun.COM "ddi_intr_alloc failed: err = %d",
78310535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx, err);
78410535SVikram.Hegde@Sun.COM amd_iommu_teardown_interrupts(iommu);
78510535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
78610535SVikram.Hegde@Sun.COM }
78710535SVikram.Hegde@Sun.COM
78810535SVikram.Hegde@Sun.COM iommu->aiomt_actual_intrs = actual;
78910535SVikram.Hegde@Sun.COM iommu->aiomt_intr_state = AMD_IOMMU_INTR_ALLOCED;
79010535SVikram.Hegde@Sun.COM
79110535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
79210535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
79310535SVikram.Hegde@Sun.COM "number of interrupts actually allocated %d",
79410535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx, actual);
79510535SVikram.Hegde@Sun.COM }
79610535SVikram.Hegde@Sun.COM
79710535SVikram.Hegde@Sun.COM if (iommu->aiomt_actual_intrs < req) {
79810535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
79910535SVikram.Hegde@Sun.COM "ddi_intr_alloc failed: actual (%d) < req (%d)",
80010535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx,
80110535SVikram.Hegde@Sun.COM iommu->aiomt_actual_intrs, req);
80210535SVikram.Hegde@Sun.COM amd_iommu_teardown_interrupts(iommu);
80310535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
80410535SVikram.Hegde@Sun.COM }
80510535SVikram.Hegde@Sun.COM
80610535SVikram.Hegde@Sun.COM for (i = 0; i < iommu->aiomt_actual_intrs; i++) {
80710535SVikram.Hegde@Sun.COM if (ddi_intr_add_handler(iommu->aiomt_intr_htable[i],
80810535SVikram.Hegde@Sun.COM amd_iommu_intr_handler, (void *)iommu, NULL)
80910535SVikram.Hegde@Sun.COM != DDI_SUCCESS) {
81010535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
81110535SVikram.Hegde@Sun.COM "ddi_intr_add_handler failed: intr = %d, err = %d",
81210535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx, i, err);
81310535SVikram.Hegde@Sun.COM for (j = 0; j < i; j++) {
81410535SVikram.Hegde@Sun.COM (void) ddi_intr_remove_handler(
81510535SVikram.Hegde@Sun.COM iommu->aiomt_intr_htable[j]);
81610535SVikram.Hegde@Sun.COM }
81710535SVikram.Hegde@Sun.COM amd_iommu_teardown_interrupts(iommu);
81810535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
81910535SVikram.Hegde@Sun.COM }
82010535SVikram.Hegde@Sun.COM }
82110535SVikram.Hegde@Sun.COM iommu->aiomt_intr_state = AMD_IOMMU_INTR_HANDLER;
82210535SVikram.Hegde@Sun.COM
82310535SVikram.Hegde@Sun.COM intrcap0 = intrcapN = -1;
82410535SVikram.Hegde@Sun.COM if (ddi_intr_get_cap(iommu->aiomt_intr_htable[0], &intrcap0)
82510535SVikram.Hegde@Sun.COM != DDI_SUCCESS ||
82610535SVikram.Hegde@Sun.COM ddi_intr_get_cap(
82710535SVikram.Hegde@Sun.COM iommu->aiomt_intr_htable[iommu->aiomt_actual_intrs - 1], &intrcapN)
82810535SVikram.Hegde@Sun.COM != DDI_SUCCESS || intrcap0 != intrcapN) {
82910535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
83010535SVikram.Hegde@Sun.COM "ddi_intr_get_cap failed or inconsistent cap among "
83110535SVikram.Hegde@Sun.COM "interrupts: intrcap0 (%d) < intrcapN (%d)",
83210535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx, intrcap0, intrcapN);
83310535SVikram.Hegde@Sun.COM amd_iommu_teardown_interrupts(iommu);
83410535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
83510535SVikram.Hegde@Sun.COM }
83610535SVikram.Hegde@Sun.COM iommu->aiomt_intr_cap = intrcap0;
83710535SVikram.Hegde@Sun.COM
83810535SVikram.Hegde@Sun.COM if (intrcap0 & DDI_INTR_FLAG_BLOCK) {
83910535SVikram.Hegde@Sun.COM /* Need to call block enable */
84010535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
84110535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d: "
84210535SVikram.Hegde@Sun.COM "Need to call block enable",
84310535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx);
84410535SVikram.Hegde@Sun.COM }
84510535SVikram.Hegde@Sun.COM if (ddi_intr_block_enable(iommu->aiomt_intr_htable,
84610535SVikram.Hegde@Sun.COM iommu->aiomt_actual_intrs) != DDI_SUCCESS) {
84710535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
84810535SVikram.Hegde@Sun.COM "ddi_intr_block enable failed ", f, driver,
84910535SVikram.Hegde@Sun.COM instance, iommu->aiomt_idx);
85010535SVikram.Hegde@Sun.COM (void) ddi_intr_block_disable(iommu->aiomt_intr_htable,
85110535SVikram.Hegde@Sun.COM iommu->aiomt_actual_intrs);
85210535SVikram.Hegde@Sun.COM amd_iommu_teardown_interrupts(iommu);
85310535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
85410535SVikram.Hegde@Sun.COM }
85510535SVikram.Hegde@Sun.COM } else {
85610535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
85710535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d: "
85810535SVikram.Hegde@Sun.COM "Need to call individual enable",
85910535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx);
86010535SVikram.Hegde@Sun.COM }
86110535SVikram.Hegde@Sun.COM for (i = 0; i < iommu->aiomt_actual_intrs; i++) {
86210535SVikram.Hegde@Sun.COM if (ddi_intr_enable(iommu->aiomt_intr_htable[i])
86310535SVikram.Hegde@Sun.COM != DDI_SUCCESS) {
86410535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
86510535SVikram.Hegde@Sun.COM "ddi_intr_enable failed: intr = %d", f,
86610535SVikram.Hegde@Sun.COM driver, instance, iommu->aiomt_idx, i);
86710535SVikram.Hegde@Sun.COM for (j = 0; j < i; j++) {
86810535SVikram.Hegde@Sun.COM (void) ddi_intr_disable(
86910535SVikram.Hegde@Sun.COM iommu->aiomt_intr_htable[j]);
87010535SVikram.Hegde@Sun.COM }
87110535SVikram.Hegde@Sun.COM amd_iommu_teardown_interrupts(iommu);
87210535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
87310535SVikram.Hegde@Sun.COM }
87410535SVikram.Hegde@Sun.COM }
87510535SVikram.Hegde@Sun.COM }
87610535SVikram.Hegde@Sun.COM iommu->aiomt_intr_state = AMD_IOMMU_INTR_ENABLED;
87710535SVikram.Hegde@Sun.COM
87810535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
87910535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d: "
88010535SVikram.Hegde@Sun.COM "Interrupts successfully %s enabled. # of interrupts = %d",
88110535SVikram.Hegde@Sun.COM f, driver, instance, iommu->aiomt_idx,
88210535SVikram.Hegde@Sun.COM (intrcap0 & DDI_INTR_FLAG_BLOCK) ? "(block)" :
88310535SVikram.Hegde@Sun.COM "(individually)", iommu->aiomt_actual_intrs);
88410535SVikram.Hegde@Sun.COM }
88510535SVikram.Hegde@Sun.COM
88610535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
88710535SVikram.Hegde@Sun.COM }
88810535SVikram.Hegde@Sun.COM
88910535SVikram.Hegde@Sun.COM static void
amd_iommu_teardown_interrupts(amd_iommu_t * iommu)89010535SVikram.Hegde@Sun.COM amd_iommu_teardown_interrupts(amd_iommu_t *iommu)
89110535SVikram.Hegde@Sun.COM {
89210535SVikram.Hegde@Sun.COM int i;
89310535SVikram.Hegde@Sun.COM
89410535SVikram.Hegde@Sun.COM if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_ENABLED) {
89510535SVikram.Hegde@Sun.COM if (iommu->aiomt_intr_cap & DDI_INTR_FLAG_BLOCK) {
89610535SVikram.Hegde@Sun.COM (void) ddi_intr_block_disable(iommu->aiomt_intr_htable,
89710535SVikram.Hegde@Sun.COM iommu->aiomt_actual_intrs);
89810535SVikram.Hegde@Sun.COM } else {
89910535SVikram.Hegde@Sun.COM for (i = 0; i < iommu->aiomt_actual_intrs; i++) {
90010535SVikram.Hegde@Sun.COM (void) ddi_intr_disable(
90110535SVikram.Hegde@Sun.COM iommu->aiomt_intr_htable[i]);
90210535SVikram.Hegde@Sun.COM }
90310535SVikram.Hegde@Sun.COM }
90410535SVikram.Hegde@Sun.COM }
90510535SVikram.Hegde@Sun.COM
90610535SVikram.Hegde@Sun.COM if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_HANDLER) {
90710535SVikram.Hegde@Sun.COM for (i = 0; i < iommu->aiomt_actual_intrs; i++) {
90810535SVikram.Hegde@Sun.COM (void) ddi_intr_remove_handler(
90910535SVikram.Hegde@Sun.COM iommu->aiomt_intr_htable[i]);
91010535SVikram.Hegde@Sun.COM }
91110535SVikram.Hegde@Sun.COM }
91210535SVikram.Hegde@Sun.COM
91310535SVikram.Hegde@Sun.COM if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_ALLOCED) {
91410535SVikram.Hegde@Sun.COM for (i = 0; i < iommu->aiomt_actual_intrs; i++) {
91510535SVikram.Hegde@Sun.COM (void) ddi_intr_free(iommu->aiomt_intr_htable[i]);
91610535SVikram.Hegde@Sun.COM }
91710535SVikram.Hegde@Sun.COM }
91810535SVikram.Hegde@Sun.COM if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_TABLE) {
91910535SVikram.Hegde@Sun.COM kmem_free(iommu->aiomt_intr_htable,
92010535SVikram.Hegde@Sun.COM iommu->aiomt_intr_htable_sz);
92110535SVikram.Hegde@Sun.COM }
92210535SVikram.Hegde@Sun.COM iommu->aiomt_intr_htable = NULL;
92310535SVikram.Hegde@Sun.COM iommu->aiomt_intr_htable_sz = 0;
92410535SVikram.Hegde@Sun.COM iommu->aiomt_intr_state = AMD_IOMMU_INTR_INVALID;
92510535SVikram.Hegde@Sun.COM }
92610535SVikram.Hegde@Sun.COM
92710535SVikram.Hegde@Sun.COM static amd_iommu_t *
amd_iommu_init(dev_info_t * dip,ddi_acc_handle_t handle,int idx,uint16_t cap_base)92810535SVikram.Hegde@Sun.COM amd_iommu_init(dev_info_t *dip, ddi_acc_handle_t handle, int idx,
92910535SVikram.Hegde@Sun.COM uint16_t cap_base)
93010535SVikram.Hegde@Sun.COM {
93110535SVikram.Hegde@Sun.COM amd_iommu_t *iommu;
93210535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
93310535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
93410535SVikram.Hegde@Sun.COM uint32_t caphdr;
93510535SVikram.Hegde@Sun.COM uint32_t low_addr32;
93610535SVikram.Hegde@Sun.COM uint32_t hi_addr32;
93710535SVikram.Hegde@Sun.COM uint32_t range;
93810535SVikram.Hegde@Sun.COM uint32_t misc;
93910535SVikram.Hegde@Sun.COM uint64_t pgoffset;
94010535SVikram.Hegde@Sun.COM amd_iommu_acpi_global_t *global;
94110535SVikram.Hegde@Sun.COM amd_iommu_acpi_ivhd_t *hinfop;
94212203SJerry.Gilliam@Sun.COM int bus, device, func;
94310535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_init";
94410535SVikram.Hegde@Sun.COM
94510535SVikram.Hegde@Sun.COM low_addr32 = PCI_CAP_GET32(handle, 0, cap_base,
94610535SVikram.Hegde@Sun.COM AMD_IOMMU_CAP_ADDR_LOW_OFF);
94710535SVikram.Hegde@Sun.COM if (!(low_addr32 & AMD_IOMMU_REG_ADDR_LOCKED)) {
94810535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: capability registers not locked. "
94910535SVikram.Hegde@Sun.COM "Unable to use IOMMU unit idx=%d - skipping ...", f, driver,
95010535SVikram.Hegde@Sun.COM instance, idx);
95110535SVikram.Hegde@Sun.COM return (NULL);
95210535SVikram.Hegde@Sun.COM }
95310535SVikram.Hegde@Sun.COM
95410535SVikram.Hegde@Sun.COM iommu = kmem_zalloc(sizeof (amd_iommu_t), KM_SLEEP);
95510535SVikram.Hegde@Sun.COM mutex_init(&iommu->aiomt_mutex, NULL, MUTEX_DRIVER, NULL);
95610535SVikram.Hegde@Sun.COM mutex_enter(&iommu->aiomt_mutex);
95710535SVikram.Hegde@Sun.COM
95810535SVikram.Hegde@Sun.COM mutex_init(&iommu->aiomt_cmdlock, NULL, MUTEX_DRIVER, NULL);
95910535SVikram.Hegde@Sun.COM mutex_init(&iommu->aiomt_eventlock, NULL, MUTEX_DRIVER, NULL);
96010535SVikram.Hegde@Sun.COM
96110535SVikram.Hegde@Sun.COM iommu->aiomt_dip = dip;
96210535SVikram.Hegde@Sun.COM iommu->aiomt_idx = idx;
96310535SVikram.Hegde@Sun.COM
96412203SJerry.Gilliam@Sun.COM if (acpica_get_bdf(iommu->aiomt_dip, &bus, &device, &func)
96512203SJerry.Gilliam@Sun.COM != DDI_SUCCESS) {
96612203SJerry.Gilliam@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Failed to get BDF"
96712203SJerry.Gilliam@Sun.COM "Unable to use IOMMU unit idx=%d - skipping ...",
96812203SJerry.Gilliam@Sun.COM f, driver, instance, idx);
96912203SJerry.Gilliam@Sun.COM return (NULL);
97012203SJerry.Gilliam@Sun.COM }
97112203SJerry.Gilliam@Sun.COM
97212203SJerry.Gilliam@Sun.COM iommu->aiomt_bdf = ((uint8_t)bus << 8) | ((uint8_t)device << 3) |
97312203SJerry.Gilliam@Sun.COM (uint8_t)func;
97412203SJerry.Gilliam@Sun.COM
97510535SVikram.Hegde@Sun.COM /*
97610535SVikram.Hegde@Sun.COM * Since everything in the capability block is locked and RO at this
97710535SVikram.Hegde@Sun.COM * point, copy everything into the IOMMU struct
97810535SVikram.Hegde@Sun.COM */
97910535SVikram.Hegde@Sun.COM
98010535SVikram.Hegde@Sun.COM /* Get cap header */
98110535SVikram.Hegde@Sun.COM caphdr = PCI_CAP_GET32(handle, 0, cap_base, AMD_IOMMU_CAP_HDR_OFF);
98210535SVikram.Hegde@Sun.COM iommu->aiomt_cap_hdr = caphdr;
98310535SVikram.Hegde@Sun.COM iommu->aiomt_npcache = AMD_IOMMU_REG_GET32(&caphdr,
98410535SVikram.Hegde@Sun.COM AMD_IOMMU_CAP_NPCACHE);
98510535SVikram.Hegde@Sun.COM iommu->aiomt_httun = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_HTTUN);
98610535SVikram.Hegde@Sun.COM
98712203SJerry.Gilliam@Sun.COM global = amd_iommu_lookup_acpi_global();
98812203SJerry.Gilliam@Sun.COM hinfop = amd_iommu_lookup_any_ivhd(iommu);
98912203SJerry.Gilliam@Sun.COM
99010535SVikram.Hegde@Sun.COM if (hinfop)
99110535SVikram.Hegde@Sun.COM iommu->aiomt_iotlb = hinfop->ach_IotlbSup;
99210535SVikram.Hegde@Sun.COM else
99310535SVikram.Hegde@Sun.COM iommu->aiomt_iotlb =
99410535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_IOTLB);
99510535SVikram.Hegde@Sun.COM
99610535SVikram.Hegde@Sun.COM iommu->aiomt_captype = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_TYPE);
99710535SVikram.Hegde@Sun.COM iommu->aiomt_capid = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_ID);
99810535SVikram.Hegde@Sun.COM
99910535SVikram.Hegde@Sun.COM /*
100010535SVikram.Hegde@Sun.COM * Get address of IOMMU control registers
100110535SVikram.Hegde@Sun.COM */
100210535SVikram.Hegde@Sun.COM hi_addr32 = PCI_CAP_GET32(handle, 0, cap_base,
100310535SVikram.Hegde@Sun.COM AMD_IOMMU_CAP_ADDR_HI_OFF);
100410535SVikram.Hegde@Sun.COM iommu->aiomt_low_addr32 = low_addr32;
100510535SVikram.Hegde@Sun.COM iommu->aiomt_hi_addr32 = hi_addr32;
100610535SVikram.Hegde@Sun.COM low_addr32 &= ~AMD_IOMMU_REG_ADDR_LOCKED;
100710535SVikram.Hegde@Sun.COM
100810535SVikram.Hegde@Sun.COM if (hinfop) {
100910535SVikram.Hegde@Sun.COM iommu->aiomt_reg_pa = hinfop->ach_IOMMU_reg_base;
101010535SVikram.Hegde@Sun.COM ASSERT(hinfop->ach_IOMMU_pci_seg == 0);
101110535SVikram.Hegde@Sun.COM } else {
101210535SVikram.Hegde@Sun.COM iommu->aiomt_reg_pa = ((uint64_t)hi_addr32 << 32 | low_addr32);
101310535SVikram.Hegde@Sun.COM }
101410535SVikram.Hegde@Sun.COM
101510535SVikram.Hegde@Sun.COM /*
101610535SVikram.Hegde@Sun.COM * Get cap range reg
101710535SVikram.Hegde@Sun.COM */
101810535SVikram.Hegde@Sun.COM range = PCI_CAP_GET32(handle, 0, cap_base, AMD_IOMMU_CAP_RANGE_OFF);
101910535SVikram.Hegde@Sun.COM iommu->aiomt_range = range;
102010535SVikram.Hegde@Sun.COM iommu->aiomt_rng_valid = AMD_IOMMU_REG_GET32(&range,
102110535SVikram.Hegde@Sun.COM AMD_IOMMU_RNG_VALID);
102210535SVikram.Hegde@Sun.COM if (iommu->aiomt_rng_valid) {
102310535SVikram.Hegde@Sun.COM iommu->aiomt_rng_bus = AMD_IOMMU_REG_GET32(&range,
102410535SVikram.Hegde@Sun.COM AMD_IOMMU_RNG_BUS);
102510535SVikram.Hegde@Sun.COM iommu->aiomt_first_devfn = AMD_IOMMU_REG_GET32(&range,
102610535SVikram.Hegde@Sun.COM AMD_IOMMU_FIRST_DEVFN);
102710535SVikram.Hegde@Sun.COM iommu->aiomt_last_devfn = AMD_IOMMU_REG_GET32(&range,
102810535SVikram.Hegde@Sun.COM AMD_IOMMU_LAST_DEVFN);
102910535SVikram.Hegde@Sun.COM } else {
103010535SVikram.Hegde@Sun.COM iommu->aiomt_rng_bus = 0;
103110535SVikram.Hegde@Sun.COM iommu->aiomt_first_devfn = 0;
103210535SVikram.Hegde@Sun.COM iommu->aiomt_last_devfn = 0;
103310535SVikram.Hegde@Sun.COM }
103410535SVikram.Hegde@Sun.COM
103510535SVikram.Hegde@Sun.COM if (hinfop)
103610535SVikram.Hegde@Sun.COM iommu->aiomt_ht_unitid = hinfop->ach_IOMMU_UnitID;
103710535SVikram.Hegde@Sun.COM else
103810535SVikram.Hegde@Sun.COM iommu->aiomt_ht_unitid = AMD_IOMMU_REG_GET32(&range,
103910535SVikram.Hegde@Sun.COM AMD_IOMMU_HT_UNITID);
104010535SVikram.Hegde@Sun.COM
104110535SVikram.Hegde@Sun.COM /*
104210535SVikram.Hegde@Sun.COM * Get cap misc reg
104310535SVikram.Hegde@Sun.COM */
104410535SVikram.Hegde@Sun.COM misc = PCI_CAP_GET32(handle, 0, cap_base, AMD_IOMMU_CAP_MISC_OFF);
104510535SVikram.Hegde@Sun.COM iommu->aiomt_misc = misc;
104610535SVikram.Hegde@Sun.COM
104710535SVikram.Hegde@Sun.COM if (global) {
104810535SVikram.Hegde@Sun.COM iommu->aiomt_htatsresv = global->acg_HtAtsResv;
104910535SVikram.Hegde@Sun.COM iommu->aiomt_vasize = global->acg_VAsize;
105010535SVikram.Hegde@Sun.COM iommu->aiomt_pasize = global->acg_PAsize;
105110535SVikram.Hegde@Sun.COM } else {
105210535SVikram.Hegde@Sun.COM iommu->aiomt_htatsresv = AMD_IOMMU_REG_GET32(&misc,
105310535SVikram.Hegde@Sun.COM AMD_IOMMU_HT_ATSRSV);
105410535SVikram.Hegde@Sun.COM iommu->aiomt_vasize = AMD_IOMMU_REG_GET32(&misc,
105510535SVikram.Hegde@Sun.COM AMD_IOMMU_VA_SIZE);
105610535SVikram.Hegde@Sun.COM iommu->aiomt_pasize = AMD_IOMMU_REG_GET32(&misc,
105710535SVikram.Hegde@Sun.COM AMD_IOMMU_PA_SIZE);
105810535SVikram.Hegde@Sun.COM }
105910535SVikram.Hegde@Sun.COM
106010535SVikram.Hegde@Sun.COM if (hinfop) {
106110535SVikram.Hegde@Sun.COM iommu->aiomt_msinum = hinfop->ach_IOMMU_MSInum;
106210535SVikram.Hegde@Sun.COM } else {
106310535SVikram.Hegde@Sun.COM iommu->aiomt_msinum =
106410535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_GET32(&misc, AMD_IOMMU_MSINUM);
106510535SVikram.Hegde@Sun.COM }
106610535SVikram.Hegde@Sun.COM
106710535SVikram.Hegde@Sun.COM /*
106810535SVikram.Hegde@Sun.COM * Set up mapping between control registers PA and VA
106910535SVikram.Hegde@Sun.COM */
107010535SVikram.Hegde@Sun.COM pgoffset = iommu->aiomt_reg_pa & MMU_PAGEOFFSET;
107110535SVikram.Hegde@Sun.COM ASSERT(pgoffset == 0);
107210535SVikram.Hegde@Sun.COM iommu->aiomt_reg_pages = mmu_btopr(AMD_IOMMU_REG_SIZE + pgoffset);
107310535SVikram.Hegde@Sun.COM iommu->aiomt_reg_size = mmu_ptob(iommu->aiomt_reg_pages);
107410535SVikram.Hegde@Sun.COM
107510535SVikram.Hegde@Sun.COM iommu->aiomt_va = (uintptr_t)device_arena_alloc(
107610535SVikram.Hegde@Sun.COM ptob(iommu->aiomt_reg_pages), VM_SLEEP);
107710535SVikram.Hegde@Sun.COM if (iommu->aiomt_va == 0) {
107810535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Failed to alloc VA for IOMMU "
107910535SVikram.Hegde@Sun.COM "control regs. Skipping IOMMU idx=%d", f, driver,
108010535SVikram.Hegde@Sun.COM instance, idx);
108110535SVikram.Hegde@Sun.COM mutex_exit(&iommu->aiomt_mutex);
108210536SVikram.Hegde@Sun.COM (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
108310535SVikram.Hegde@Sun.COM return (NULL);
108410535SVikram.Hegde@Sun.COM }
108510535SVikram.Hegde@Sun.COM
108610535SVikram.Hegde@Sun.COM hat_devload(kas.a_hat, (void *)(uintptr_t)iommu->aiomt_va,
108710535SVikram.Hegde@Sun.COM iommu->aiomt_reg_size,
108810535SVikram.Hegde@Sun.COM mmu_btop(iommu->aiomt_reg_pa), PROT_READ | PROT_WRITE
108910535SVikram.Hegde@Sun.COM | HAT_STRICTORDER, HAT_LOAD_LOCK);
109010535SVikram.Hegde@Sun.COM
109110535SVikram.Hegde@Sun.COM iommu->aiomt_reg_va = iommu->aiomt_va + pgoffset;
109210535SVikram.Hegde@Sun.COM
109310535SVikram.Hegde@Sun.COM /*
109410535SVikram.Hegde@Sun.COM * Setup the various control register's VA
109510535SVikram.Hegde@Sun.COM */
109610535SVikram.Hegde@Sun.COM iommu->aiomt_reg_devtbl_va = iommu->aiomt_reg_va +
109710535SVikram.Hegde@Sun.COM AMD_IOMMU_DEVTBL_REG_OFF;
109810535SVikram.Hegde@Sun.COM iommu->aiomt_reg_cmdbuf_va = iommu->aiomt_reg_va +
109910535SVikram.Hegde@Sun.COM AMD_IOMMU_CMDBUF_REG_OFF;
110010535SVikram.Hegde@Sun.COM iommu->aiomt_reg_eventlog_va = iommu->aiomt_reg_va +
110110535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTLOG_REG_OFF;
110210535SVikram.Hegde@Sun.COM iommu->aiomt_reg_ctrl_va = iommu->aiomt_reg_va +
110310535SVikram.Hegde@Sun.COM AMD_IOMMU_CTRL_REG_OFF;
110410535SVikram.Hegde@Sun.COM iommu->aiomt_reg_excl_base_va = iommu->aiomt_reg_va +
110510535SVikram.Hegde@Sun.COM AMD_IOMMU_EXCL_BASE_REG_OFF;
110610535SVikram.Hegde@Sun.COM iommu->aiomt_reg_excl_lim_va = iommu->aiomt_reg_va +
110710535SVikram.Hegde@Sun.COM AMD_IOMMU_EXCL_LIM_REG_OFF;
110810535SVikram.Hegde@Sun.COM iommu->aiomt_reg_cmdbuf_head_va = iommu->aiomt_reg_va +
110910535SVikram.Hegde@Sun.COM AMD_IOMMU_CMDBUF_HEAD_REG_OFF;
111010535SVikram.Hegde@Sun.COM iommu->aiomt_reg_cmdbuf_tail_va = iommu->aiomt_reg_va +
111110535SVikram.Hegde@Sun.COM AMD_IOMMU_CMDBUF_TAIL_REG_OFF;
111210535SVikram.Hegde@Sun.COM iommu->aiomt_reg_eventlog_head_va = iommu->aiomt_reg_va +
111310535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTLOG_HEAD_REG_OFF;
111410535SVikram.Hegde@Sun.COM iommu->aiomt_reg_eventlog_tail_va = iommu->aiomt_reg_va +
111510535SVikram.Hegde@Sun.COM AMD_IOMMU_EVENTLOG_TAIL_REG_OFF;
111610535SVikram.Hegde@Sun.COM iommu->aiomt_reg_status_va = iommu->aiomt_reg_va +
111710535SVikram.Hegde@Sun.COM AMD_IOMMU_STATUS_REG_OFF;
111810535SVikram.Hegde@Sun.COM
111910535SVikram.Hegde@Sun.COM
112010535SVikram.Hegde@Sun.COM /*
112110535SVikram.Hegde@Sun.COM * Setup the DEVICE table, CMD buffer, and LOG buffer in
112210535SVikram.Hegde@Sun.COM * memory and setup DMA access to this memory location
112310535SVikram.Hegde@Sun.COM */
112410535SVikram.Hegde@Sun.COM if (amd_iommu_setup_tables_and_buffers(iommu) != DDI_SUCCESS) {
112510535SVikram.Hegde@Sun.COM mutex_exit(&iommu->aiomt_mutex);
112610536SVikram.Hegde@Sun.COM (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
112710535SVikram.Hegde@Sun.COM return (NULL);
112810535SVikram.Hegde@Sun.COM }
112910535SVikram.Hegde@Sun.COM
113010535SVikram.Hegde@Sun.COM if (amd_iommu_setup_exclusion(iommu) != DDI_SUCCESS) {
113110535SVikram.Hegde@Sun.COM mutex_exit(&iommu->aiomt_mutex);
113210536SVikram.Hegde@Sun.COM (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
113310535SVikram.Hegde@Sun.COM return (NULL);
113410535SVikram.Hegde@Sun.COM }
113510535SVikram.Hegde@Sun.COM
113610535SVikram.Hegde@Sun.COM amd_iommu_enable_interrupts(iommu);
113710535SVikram.Hegde@Sun.COM
113810535SVikram.Hegde@Sun.COM if (amd_iommu_setup_interrupts(iommu) != DDI_SUCCESS) {
113910535SVikram.Hegde@Sun.COM mutex_exit(&iommu->aiomt_mutex);
114010536SVikram.Hegde@Sun.COM (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
114110535SVikram.Hegde@Sun.COM return (NULL);
114210535SVikram.Hegde@Sun.COM }
114310535SVikram.Hegde@Sun.COM
114410535SVikram.Hegde@Sun.COM /*
114510535SVikram.Hegde@Sun.COM * need to setup domain table before gfx bypass
114610535SVikram.Hegde@Sun.COM */
114710535SVikram.Hegde@Sun.COM amd_iommu_init_page_tables(iommu);
114810535SVikram.Hegde@Sun.COM
114910535SVikram.Hegde@Sun.COM /*
115010535SVikram.Hegde@Sun.COM * Set pass-thru for special devices like IOAPIC and HPET
115110535SVikram.Hegde@Sun.COM *
115210535SVikram.Hegde@Sun.COM * Also, gfx devices don't use DDI for DMA. No need to register
115310535SVikram.Hegde@Sun.COM * before setting up gfx passthru
115410535SVikram.Hegde@Sun.COM */
115510535SVikram.Hegde@Sun.COM if (amd_iommu_setup_passthru(iommu) != DDI_SUCCESS) {
115610535SVikram.Hegde@Sun.COM mutex_exit(&iommu->aiomt_mutex);
115710536SVikram.Hegde@Sun.COM (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
115810535SVikram.Hegde@Sun.COM return (NULL);
115910535SVikram.Hegde@Sun.COM }
116010535SVikram.Hegde@Sun.COM
116112203SJerry.Gilliam@Sun.COM /* Initialize device table entries based on ACPI settings */
116212203SJerry.Gilliam@Sun.COM if (amd_iommu_acpi_init_devtbl(iommu) != DDI_SUCCESS) {
116312203SJerry.Gilliam@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Can't initialize device table",
116412203SJerry.Gilliam@Sun.COM f, driver, instance);
116512203SJerry.Gilliam@Sun.COM mutex_exit(&iommu->aiomt_mutex);
116612203SJerry.Gilliam@Sun.COM (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
116712203SJerry.Gilliam@Sun.COM return (NULL);
116812203SJerry.Gilliam@Sun.COM }
116912203SJerry.Gilliam@Sun.COM
117010535SVikram.Hegde@Sun.COM if (amd_iommu_start(iommu) != DDI_SUCCESS) {
117110535SVikram.Hegde@Sun.COM mutex_exit(&iommu->aiomt_mutex);
117210536SVikram.Hegde@Sun.COM (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
117310535SVikram.Hegde@Sun.COM return (NULL);
117410535SVikram.Hegde@Sun.COM }
117510535SVikram.Hegde@Sun.COM
117610535SVikram.Hegde@Sun.COM /* xxx register/start race */
117710535SVikram.Hegde@Sun.COM if (amd_iommu_register(iommu) != DDI_SUCCESS) {
117810535SVikram.Hegde@Sun.COM mutex_exit(&iommu->aiomt_mutex);
117910536SVikram.Hegde@Sun.COM (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
118010535SVikram.Hegde@Sun.COM return (NULL);
118110535SVikram.Hegde@Sun.COM }
118210535SVikram.Hegde@Sun.COM
118310535SVikram.Hegde@Sun.COM if (amd_iommu_debug) {
118410535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: IOMMU idx=%d inited.", f, driver,
118510535SVikram.Hegde@Sun.COM instance, idx);
118610535SVikram.Hegde@Sun.COM }
118710535SVikram.Hegde@Sun.COM
118810535SVikram.Hegde@Sun.COM return (iommu);
118910535SVikram.Hegde@Sun.COM }
119010535SVikram.Hegde@Sun.COM
119110535SVikram.Hegde@Sun.COM static int
amd_iommu_fini(amd_iommu_t * iommu,int type)119210536SVikram.Hegde@Sun.COM amd_iommu_fini(amd_iommu_t *iommu, int type)
119310535SVikram.Hegde@Sun.COM {
119410535SVikram.Hegde@Sun.COM int idx = iommu->aiomt_idx;
119510535SVikram.Hegde@Sun.COM dev_info_t *dip = iommu->aiomt_dip;
119610535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
119710535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
119810535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_fini";
119910535SVikram.Hegde@Sun.COM
120010536SVikram.Hegde@Sun.COM if (type == AMD_IOMMU_TEARDOWN) {
120110536SVikram.Hegde@Sun.COM mutex_enter(&iommu->aiomt_mutex);
120210536SVikram.Hegde@Sun.COM if (amd_iommu_unregister(iommu) != DDI_SUCCESS) {
120310536SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: Fini of IOMMU unit failed. "
120410536SVikram.Hegde@Sun.COM "idx = %d", f, driver, instance, idx);
120510536SVikram.Hegde@Sun.COM return (DDI_FAILURE);
120610536SVikram.Hegde@Sun.COM }
120710535SVikram.Hegde@Sun.COM }
120810536SVikram.Hegde@Sun.COM
120910535SVikram.Hegde@Sun.COM amd_iommu_stop(iommu);
121010536SVikram.Hegde@Sun.COM
121110536SVikram.Hegde@Sun.COM if (type == AMD_IOMMU_TEARDOWN) {
121210536SVikram.Hegde@Sun.COM amd_iommu_fini_page_tables(iommu);
121310536SVikram.Hegde@Sun.COM amd_iommu_teardown_interrupts(iommu);
121410536SVikram.Hegde@Sun.COM amd_iommu_teardown_exclusion(iommu);
121510536SVikram.Hegde@Sun.COM }
121610536SVikram.Hegde@Sun.COM
121710536SVikram.Hegde@Sun.COM amd_iommu_teardown_tables_and_buffers(iommu, type);
121810536SVikram.Hegde@Sun.COM
121910536SVikram.Hegde@Sun.COM if (type == AMD_IOMMU_QUIESCE)
122010536SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
122110536SVikram.Hegde@Sun.COM
122210535SVikram.Hegde@Sun.COM if (iommu->aiomt_va != NULL) {
122310535SVikram.Hegde@Sun.COM hat_unload(kas.a_hat, (void *)(uintptr_t)iommu->aiomt_va,
122410535SVikram.Hegde@Sun.COM iommu->aiomt_reg_size, HAT_UNLOAD_UNLOCK);
122510535SVikram.Hegde@Sun.COM device_arena_free((void *)(uintptr_t)iommu->aiomt_va,
122610535SVikram.Hegde@Sun.COM ptob(iommu->aiomt_reg_pages));
122710535SVikram.Hegde@Sun.COM iommu->aiomt_va = NULL;
122810535SVikram.Hegde@Sun.COM iommu->aiomt_reg_va = NULL;
122910535SVikram.Hegde@Sun.COM }
123010535SVikram.Hegde@Sun.COM mutex_destroy(&iommu->aiomt_eventlock);
123110535SVikram.Hegde@Sun.COM mutex_destroy(&iommu->aiomt_cmdlock);
123210535SVikram.Hegde@Sun.COM mutex_exit(&iommu->aiomt_mutex);
123310535SVikram.Hegde@Sun.COM mutex_destroy(&iommu->aiomt_mutex);
123410535SVikram.Hegde@Sun.COM kmem_free(iommu, sizeof (amd_iommu_t));
123510535SVikram.Hegde@Sun.COM
123610535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: Fini of IOMMU unit complete. idx = %d",
123710535SVikram.Hegde@Sun.COM f, driver, instance, idx);
123810535SVikram.Hegde@Sun.COM
123910535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
124010535SVikram.Hegde@Sun.COM }
124110535SVikram.Hegde@Sun.COM
124210535SVikram.Hegde@Sun.COM int
amd_iommu_setup(dev_info_t * dip,amd_iommu_state_t * statep)124310535SVikram.Hegde@Sun.COM amd_iommu_setup(dev_info_t *dip, amd_iommu_state_t *statep)
124410535SVikram.Hegde@Sun.COM {
124510535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
124610535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
124710535SVikram.Hegde@Sun.COM ddi_acc_handle_t handle;
124810535SVikram.Hegde@Sun.COM uint8_t base_class;
124910535SVikram.Hegde@Sun.COM uint8_t sub_class;
125010535SVikram.Hegde@Sun.COM uint8_t prog_class;
125110535SVikram.Hegde@Sun.COM int idx;
125210535SVikram.Hegde@Sun.COM uint32_t id;
125310535SVikram.Hegde@Sun.COM uint16_t cap_base;
125410535SVikram.Hegde@Sun.COM uint32_t caphdr;
125510535SVikram.Hegde@Sun.COM uint8_t cap_type;
125610535SVikram.Hegde@Sun.COM uint8_t cap_id;
125710535SVikram.Hegde@Sun.COM amd_iommu_t *iommu;
125810535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_setup";
125910535SVikram.Hegde@Sun.COM
126010535SVikram.Hegde@Sun.COM ASSERT(instance >= 0);
126110535SVikram.Hegde@Sun.COM ASSERT(driver);
126210535SVikram.Hegde@Sun.COM
126310535SVikram.Hegde@Sun.COM /* First setup PCI access to config space */
126410535SVikram.Hegde@Sun.COM
126510535SVikram.Hegde@Sun.COM if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
126610535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: PCI config setup failed: %s%d",
126710535SVikram.Hegde@Sun.COM f, driver, instance);
126810535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
126910535SVikram.Hegde@Sun.COM }
127010535SVikram.Hegde@Sun.COM
127110535SVikram.Hegde@Sun.COM /*
127210535SVikram.Hegde@Sun.COM * The AMD IOMMU is part of an independent PCI function. There may be
127310535SVikram.Hegde@Sun.COM * more than one IOMMU in that PCI function
127410535SVikram.Hegde@Sun.COM */
127510535SVikram.Hegde@Sun.COM base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
127610535SVikram.Hegde@Sun.COM sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
127710535SVikram.Hegde@Sun.COM prog_class = pci_config_get8(handle, PCI_CONF_PROGCLASS);
127810535SVikram.Hegde@Sun.COM
127910535SVikram.Hegde@Sun.COM if (base_class != PCI_CLASS_PERIPH || sub_class != PCI_PERIPH_IOMMU ||
128010535SVikram.Hegde@Sun.COM prog_class != AMD_IOMMU_PCI_PROG_IF) {
128110535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: invalid PCI class(0x%x)/"
128210535SVikram.Hegde@Sun.COM "subclass(0x%x)/programming interface(0x%x)", f, driver,
128310535SVikram.Hegde@Sun.COM instance, base_class, sub_class, prog_class);
128410535SVikram.Hegde@Sun.COM pci_config_teardown(&handle);
128510535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
128610535SVikram.Hegde@Sun.COM }
128710535SVikram.Hegde@Sun.COM
128810535SVikram.Hegde@Sun.COM /*
128910535SVikram.Hegde@Sun.COM * Find and initialize all IOMMU units in this function
129010535SVikram.Hegde@Sun.COM */
129110535SVikram.Hegde@Sun.COM for (idx = 0; ; idx++) {
129210535SVikram.Hegde@Sun.COM if (pci_cap_probe(handle, idx, &id, &cap_base) != DDI_SUCCESS)
129310535SVikram.Hegde@Sun.COM break;
129410535SVikram.Hegde@Sun.COM
129510535SVikram.Hegde@Sun.COM /* check if cap ID is secure device cap id */
129610535SVikram.Hegde@Sun.COM if (id != PCI_CAP_ID_SECURE_DEV) {
129710535SVikram.Hegde@Sun.COM if (amd_iommu_debug) {
129810536SVikram.Hegde@Sun.COM cmn_err(CE_NOTE,
129910535SVikram.Hegde@Sun.COM "%s: %s%d: skipping IOMMU: idx(0x%x) "
130010535SVikram.Hegde@Sun.COM "cap ID (0x%x) != secure dev capid (0x%x)",
130110535SVikram.Hegde@Sun.COM f, driver, instance, idx, id,
130210535SVikram.Hegde@Sun.COM PCI_CAP_ID_SECURE_DEV);
130310535SVikram.Hegde@Sun.COM }
130410535SVikram.Hegde@Sun.COM continue;
130510535SVikram.Hegde@Sun.COM }
130610535SVikram.Hegde@Sun.COM
130710535SVikram.Hegde@Sun.COM /* check if cap type is IOMMU cap type */
130810535SVikram.Hegde@Sun.COM caphdr = PCI_CAP_GET32(handle, 0, cap_base,
130910535SVikram.Hegde@Sun.COM AMD_IOMMU_CAP_HDR_OFF);
131010535SVikram.Hegde@Sun.COM cap_type = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_TYPE);
131110535SVikram.Hegde@Sun.COM cap_id = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_ID);
131210535SVikram.Hegde@Sun.COM
131310535SVikram.Hegde@Sun.COM if (cap_type != AMD_IOMMU_CAP) {
131410535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: skipping IOMMU: idx(0x%x) "
131510535SVikram.Hegde@Sun.COM "cap type (0x%x) != AMD IOMMU CAP (0x%x)", f,
131610535SVikram.Hegde@Sun.COM driver, instance, idx, cap_type, AMD_IOMMU_CAP);
131710535SVikram.Hegde@Sun.COM continue;
131810535SVikram.Hegde@Sun.COM }
131910535SVikram.Hegde@Sun.COM ASSERT(cap_id == PCI_CAP_ID_SECURE_DEV);
132010535SVikram.Hegde@Sun.COM ASSERT(cap_id == id);
132110535SVikram.Hegde@Sun.COM
132210535SVikram.Hegde@Sun.COM iommu = amd_iommu_init(dip, handle, idx, cap_base);
132310535SVikram.Hegde@Sun.COM if (iommu == NULL) {
132410535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: skipping IOMMU: idx(0x%x) "
132510535SVikram.Hegde@Sun.COM "failed to init IOMMU", f,
132610535SVikram.Hegde@Sun.COM driver, instance, idx);
132710535SVikram.Hegde@Sun.COM continue;
132810535SVikram.Hegde@Sun.COM }
132910535SVikram.Hegde@Sun.COM
133010535SVikram.Hegde@Sun.COM if (statep->aioms_iommu_start == NULL) {
133110535SVikram.Hegde@Sun.COM statep->aioms_iommu_start = iommu;
133210535SVikram.Hegde@Sun.COM } else {
133310535SVikram.Hegde@Sun.COM statep->aioms_iommu_end->aiomt_next = iommu;
133410535SVikram.Hegde@Sun.COM }
133510535SVikram.Hegde@Sun.COM statep->aioms_iommu_end = iommu;
133610535SVikram.Hegde@Sun.COM
133710535SVikram.Hegde@Sun.COM statep->aioms_nunits++;
133810535SVikram.Hegde@Sun.COM }
133910535SVikram.Hegde@Sun.COM
134010535SVikram.Hegde@Sun.COM pci_config_teardown(&handle);
134110535SVikram.Hegde@Sun.COM
134210535SVikram.Hegde@Sun.COM if (amd_iommu_debug) {
134310535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: state=%p: setup %d IOMMU units",
134410535SVikram.Hegde@Sun.COM f, driver, instance, (void *)statep, statep->aioms_nunits);
134510535SVikram.Hegde@Sun.COM }
134610535SVikram.Hegde@Sun.COM
134710535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
134810535SVikram.Hegde@Sun.COM }
134910535SVikram.Hegde@Sun.COM
135010535SVikram.Hegde@Sun.COM int
amd_iommu_teardown(dev_info_t * dip,amd_iommu_state_t * statep,int type)135110536SVikram.Hegde@Sun.COM amd_iommu_teardown(dev_info_t *dip, amd_iommu_state_t *statep, int type)
135210535SVikram.Hegde@Sun.COM {
135310535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip);
135410535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip);
135510536SVikram.Hegde@Sun.COM amd_iommu_t *iommu, *next_iommu;
135610535SVikram.Hegde@Sun.COM int teardown;
135710535SVikram.Hegde@Sun.COM int error = DDI_SUCCESS;
135810535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_teardown";
135910535SVikram.Hegde@Sun.COM
136010535SVikram.Hegde@Sun.COM teardown = 0;
136110535SVikram.Hegde@Sun.COM for (iommu = statep->aioms_iommu_start; iommu;
136210536SVikram.Hegde@Sun.COM iommu = next_iommu) {
136310535SVikram.Hegde@Sun.COM ASSERT(statep->aioms_nunits > 0);
136410536SVikram.Hegde@Sun.COM next_iommu = iommu->aiomt_next;
136510536SVikram.Hegde@Sun.COM if (amd_iommu_fini(iommu, type) != DDI_SUCCESS) {
136610535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
136710535SVikram.Hegde@Sun.COM continue;
136810535SVikram.Hegde@Sun.COM }
136910535SVikram.Hegde@Sun.COM statep->aioms_nunits--;
137010535SVikram.Hegde@Sun.COM teardown++;
137110535SVikram.Hegde@Sun.COM }
137210535SVikram.Hegde@Sun.COM
137310535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: state=%p: toredown %d units. "
137410535SVikram.Hegde@Sun.COM "%d units left", f, driver, instance, (void *)statep,
137510535SVikram.Hegde@Sun.COM teardown, statep->aioms_nunits);
137610535SVikram.Hegde@Sun.COM
137710535SVikram.Hegde@Sun.COM return (error);
137810535SVikram.Hegde@Sun.COM }
137910535SVikram.Hegde@Sun.COM
138012203SJerry.Gilliam@Sun.COM dev_info_t *
amd_iommu_pci_dip(dev_info_t * rdip,const char * path)138112203SJerry.Gilliam@Sun.COM amd_iommu_pci_dip(dev_info_t *rdip, const char *path)
138212203SJerry.Gilliam@Sun.COM {
138312203SJerry.Gilliam@Sun.COM dev_info_t *pdip;
138412203SJerry.Gilliam@Sun.COM const char *driver = ddi_driver_name(rdip);
138512203SJerry.Gilliam@Sun.COM int instance = ddi_get_instance(rdip);
138612203SJerry.Gilliam@Sun.COM const char *f = "amd_iommu_pci_dip";
138712203SJerry.Gilliam@Sun.COM
138812203SJerry.Gilliam@Sun.COM /* Hold rdip so it and its parents don't go away */
138912203SJerry.Gilliam@Sun.COM ndi_hold_devi(rdip);
139012203SJerry.Gilliam@Sun.COM
139112203SJerry.Gilliam@Sun.COM if (ddi_is_pci_dip(rdip))
139212203SJerry.Gilliam@Sun.COM return (rdip);
139312203SJerry.Gilliam@Sun.COM
139412203SJerry.Gilliam@Sun.COM pdip = rdip;
139512203SJerry.Gilliam@Sun.COM while (pdip = ddi_get_parent(pdip)) {
139612203SJerry.Gilliam@Sun.COM if (ddi_is_pci_dip(pdip)) {
139712203SJerry.Gilliam@Sun.COM ndi_hold_devi(pdip);
139812203SJerry.Gilliam@Sun.COM ndi_rele_devi(rdip);
139912203SJerry.Gilliam@Sun.COM return (pdip);
140012203SJerry.Gilliam@Sun.COM }
140112203SJerry.Gilliam@Sun.COM }
140212203SJerry.Gilliam@Sun.COM
140312203SJerry.Gilliam@Sun.COM cmn_err(
140412203SJerry.Gilliam@Sun.COM #ifdef DEBUG
140512203SJerry.Gilliam@Sun.COM CE_PANIC,
140612203SJerry.Gilliam@Sun.COM #else
140712203SJerry.Gilliam@Sun.COM CE_WARN,
140812203SJerry.Gilliam@Sun.COM #endif /* DEBUG */
140912203SJerry.Gilliam@Sun.COM "%s: %s%d dip = %p has no PCI parent, path = %s",
141012203SJerry.Gilliam@Sun.COM f, driver, instance, (void *)rdip, path);
141112203SJerry.Gilliam@Sun.COM
141212203SJerry.Gilliam@Sun.COM ndi_rele_devi(rdip);
141312203SJerry.Gilliam@Sun.COM
141412203SJerry.Gilliam@Sun.COM return (NULL);
141512203SJerry.Gilliam@Sun.COM }
141612203SJerry.Gilliam@Sun.COM
141710535SVikram.Hegde@Sun.COM /* Interface with IOMMULIB */
141810535SVikram.Hegde@Sun.COM /*ARGSUSED*/
141910535SVikram.Hegde@Sun.COM static int
amd_iommu_probe(iommulib_handle_t handle,dev_info_t * rdip)142010535SVikram.Hegde@Sun.COM amd_iommu_probe(iommulib_handle_t handle, dev_info_t *rdip)
142110535SVikram.Hegde@Sun.COM {
142210535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(rdip);
142310535SVikram.Hegde@Sun.COM char *s;
142412203SJerry.Gilliam@Sun.COM int bus, device, func, bdf;
142512203SJerry.Gilliam@Sun.COM amd_iommu_acpi_ivhd_t *hinfop;
142612203SJerry.Gilliam@Sun.COM dev_info_t *pci_dip;
142710535SVikram.Hegde@Sun.COM amd_iommu_t *iommu = iommulib_iommu_getdata(handle);
142812203SJerry.Gilliam@Sun.COM const char *f = "amd_iommu_probe";
142912203SJerry.Gilliam@Sun.COM int instance = ddi_get_instance(iommu->aiomt_dip);
143012203SJerry.Gilliam@Sun.COM const char *idriver = ddi_driver_name(iommu->aiomt_dip);
143112203SJerry.Gilliam@Sun.COM char *path, *pathp;
143210535SVikram.Hegde@Sun.COM
143310535SVikram.Hegde@Sun.COM if (amd_iommu_disable_list) {
143410535SVikram.Hegde@Sun.COM s = strstr(amd_iommu_disable_list, driver);
143510535SVikram.Hegde@Sun.COM if (s == NULL)
143610535SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
143710535SVikram.Hegde@Sun.COM if (s == amd_iommu_disable_list || *(s - 1) == ':') {
143810535SVikram.Hegde@Sun.COM s += strlen(driver);
143910535SVikram.Hegde@Sun.COM if (*s == '\0' || *s == ':') {
144010535SVikram.Hegde@Sun.COM amd_iommu_set_passthru(iommu, rdip);
144110535SVikram.Hegde@Sun.COM return (DDI_FAILURE);
144210535SVikram.Hegde@Sun.COM }
144310535SVikram.Hegde@Sun.COM }
144410535SVikram.Hegde@Sun.COM }
144510535SVikram.Hegde@Sun.COM
144612203SJerry.Gilliam@Sun.COM path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
144712203SJerry.Gilliam@Sun.COM if ((pathp = ddi_pathname(rdip, path)) == NULL)
144812203SJerry.Gilliam@Sun.COM pathp = "<unknown>";
144912203SJerry.Gilliam@Sun.COM
145012203SJerry.Gilliam@Sun.COM pci_dip = amd_iommu_pci_dip(rdip, path);
145112203SJerry.Gilliam@Sun.COM if (pci_dip == NULL) {
145212203SJerry.Gilliam@Sun.COM cmn_err(CE_WARN, "%s: %s%d: idx = %d, failed to get PCI dip "
145312203SJerry.Gilliam@Sun.COM "for rdip=%p, path = %s",
145412203SJerry.Gilliam@Sun.COM f, idriver, instance, iommu->aiomt_idx, (void *)rdip,
145512203SJerry.Gilliam@Sun.COM pathp);
145612203SJerry.Gilliam@Sun.COM kmem_free(path, MAXPATHLEN);
145712203SJerry.Gilliam@Sun.COM return (DDI_FAILURE);
145812203SJerry.Gilliam@Sun.COM }
145912203SJerry.Gilliam@Sun.COM
146012203SJerry.Gilliam@Sun.COM if (acpica_get_bdf(pci_dip, &bus, &device, &func) != DDI_SUCCESS) {
146112203SJerry.Gilliam@Sun.COM cmn_err(CE_WARN, "%s: %s%d: idx = %d, failed to get BDF "
146212203SJerry.Gilliam@Sun.COM "for rdip=%p, path = %s",
146312203SJerry.Gilliam@Sun.COM f, idriver, instance, iommu->aiomt_idx, (void *)rdip,
146412203SJerry.Gilliam@Sun.COM pathp);
146512203SJerry.Gilliam@Sun.COM kmem_free(path, MAXPATHLEN);
146612203SJerry.Gilliam@Sun.COM return (DDI_FAILURE);
146712203SJerry.Gilliam@Sun.COM }
146812203SJerry.Gilliam@Sun.COM kmem_free(path, MAXPATHLEN);
146912203SJerry.Gilliam@Sun.COM
147012203SJerry.Gilliam@Sun.COM /*
147112203SJerry.Gilliam@Sun.COM * See whether device is described by IVRS as being managed
147212203SJerry.Gilliam@Sun.COM * by this IOMMU
147312203SJerry.Gilliam@Sun.COM */
147412203SJerry.Gilliam@Sun.COM bdf = ((uint8_t)bus << 8) | ((uint8_t)device << 3) | (uint8_t)func;
147512203SJerry.Gilliam@Sun.COM hinfop = amd_iommu_lookup_ivhd(bdf);
147612203SJerry.Gilliam@Sun.COM if (hinfop && hinfop->ach_IOMMU_deviceid == iommu->aiomt_bdf)
147712203SJerry.Gilliam@Sun.COM return (DDI_SUCCESS);
147812203SJerry.Gilliam@Sun.COM
147912203SJerry.Gilliam@Sun.COM return (DDI_FAILURE);
148010535SVikram.Hegde@Sun.COM }
148110535SVikram.Hegde@Sun.COM
148210535SVikram.Hegde@Sun.COM /*ARGSUSED*/
148310535SVikram.Hegde@Sun.COM static int
amd_iommu_allochdl(iommulib_handle_t handle,dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * attr,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * dma_handlep)148410535SVikram.Hegde@Sun.COM amd_iommu_allochdl(iommulib_handle_t handle,
148510535SVikram.Hegde@Sun.COM dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
148610535SVikram.Hegde@Sun.COM int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *dma_handlep)
148710535SVikram.Hegde@Sun.COM {
148810535SVikram.Hegde@Sun.COM return (iommulib_iommu_dma_allochdl(dip, rdip, attr, waitfp,
148910535SVikram.Hegde@Sun.COM arg, dma_handlep));
149010535SVikram.Hegde@Sun.COM }
149110535SVikram.Hegde@Sun.COM
149210535SVikram.Hegde@Sun.COM /*ARGSUSED*/
149310535SVikram.Hegde@Sun.COM static int
amd_iommu_freehdl(iommulib_handle_t handle,dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t dma_handle)149410535SVikram.Hegde@Sun.COM amd_iommu_freehdl(iommulib_handle_t handle,
149510535SVikram.Hegde@Sun.COM dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle)
149610535SVikram.Hegde@Sun.COM {
149710535SVikram.Hegde@Sun.COM return (iommulib_iommu_dma_freehdl(dip, rdip, dma_handle));
149810535SVikram.Hegde@Sun.COM }
149910535SVikram.Hegde@Sun.COM
150010535SVikram.Hegde@Sun.COM /*ARGSUSED*/
150110535SVikram.Hegde@Sun.COM static int
map_current_window(amd_iommu_t * iommu,dev_info_t * rdip,ddi_dma_attr_t * attrp,struct ddi_dma_req * dmareq,ddi_dma_cookie_t * cookie_array,uint_t ccount,int km_flags)150210535SVikram.Hegde@Sun.COM map_current_window(amd_iommu_t *iommu, dev_info_t *rdip, ddi_dma_attr_t *attrp,
150310535SVikram.Hegde@Sun.COM struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookie_array, uint_t ccount,
150410535SVikram.Hegde@Sun.COM int km_flags)
150510535SVikram.Hegde@Sun.COM {
150610535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(iommu->aiomt_dip);
150710535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(iommu->aiomt_dip);
150810535SVikram.Hegde@Sun.COM int idx = iommu->aiomt_idx;
150910535SVikram.Hegde@Sun.COM int i;
151010535SVikram.Hegde@Sun.COM uint64_t start_va;
151110535SVikram.Hegde@Sun.COM char *path;
151210535SVikram.Hegde@Sun.COM int error = DDI_FAILURE;
151310535SVikram.Hegde@Sun.COM const char *f = "map_current_window";
151410535SVikram.Hegde@Sun.COM
151510535SVikram.Hegde@Sun.COM path = kmem_alloc(MAXPATHLEN, km_flags);
151610535SVikram.Hegde@Sun.COM if (path == NULL) {
151710535SVikram.Hegde@Sun.COM return (DDI_DMA_NORESOURCES);
151810535SVikram.Hegde@Sun.COM }
151910535SVikram.Hegde@Sun.COM
152010535SVikram.Hegde@Sun.COM (void) ddi_pathname(rdip, path);
152110535SVikram.Hegde@Sun.COM mutex_enter(&amd_iommu_pgtable_lock);
152210535SVikram.Hegde@Sun.COM
152310535SVikram.Hegde@Sun.COM if (amd_iommu_debug == AMD_IOMMU_DEBUG_PAGE_TABLES) {
152410536SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: idx=%d Attempting to get cookies "
152510535SVikram.Hegde@Sun.COM "from handle for device %s",
152610535SVikram.Hegde@Sun.COM f, driver, instance, idx, path);
152710535SVikram.Hegde@Sun.COM }
152810535SVikram.Hegde@Sun.COM
152910535SVikram.Hegde@Sun.COM start_va = 0;
153010535SVikram.Hegde@Sun.COM for (i = 0; i < ccount; i++) {
153110535SVikram.Hegde@Sun.COM if ((error = amd_iommu_map_pa2va(iommu, rdip, attrp, dmareq,
153210535SVikram.Hegde@Sun.COM cookie_array[i].dmac_cookie_addr,
153310535SVikram.Hegde@Sun.COM cookie_array[i].dmac_size,
153410535SVikram.Hegde@Sun.COM AMD_IOMMU_VMEM_MAP, &start_va, km_flags)) != DDI_SUCCESS) {
153510535SVikram.Hegde@Sun.COM break;
153610535SVikram.Hegde@Sun.COM }
153710535SVikram.Hegde@Sun.COM cookie_array[i].dmac_cookie_addr = (uintptr_t)start_va;
153810535SVikram.Hegde@Sun.COM cookie_array[i].dmac_type = 0;
153910535SVikram.Hegde@Sun.COM }
154010535SVikram.Hegde@Sun.COM
154110535SVikram.Hegde@Sun.COM if (i != ccount) {
154210535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: idx=%d Cannot map cookie# %d "
154310535SVikram.Hegde@Sun.COM "for device %s", f, driver, instance, idx, i, path);
154410535SVikram.Hegde@Sun.COM (void) unmap_current_window(iommu, rdip, cookie_array,
154510535SVikram.Hegde@Sun.COM ccount, i, 1);
154610535SVikram.Hegde@Sun.COM goto out;
154710535SVikram.Hegde@Sun.COM }
154810535SVikram.Hegde@Sun.COM
154910535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_PAGE_TABLES) {
155010535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: return SUCCESS", f);
155110535SVikram.Hegde@Sun.COM }
155210535SVikram.Hegde@Sun.COM
155310535SVikram.Hegde@Sun.COM error = DDI_DMA_MAPPED;
155410535SVikram.Hegde@Sun.COM out:
155510535SVikram.Hegde@Sun.COM mutex_exit(&amd_iommu_pgtable_lock);
155610535SVikram.Hegde@Sun.COM kmem_free(path, MAXPATHLEN);
155710535SVikram.Hegde@Sun.COM return (error);
155810535SVikram.Hegde@Sun.COM }
155910535SVikram.Hegde@Sun.COM
156010535SVikram.Hegde@Sun.COM /*ARGSUSED*/
156110535SVikram.Hegde@Sun.COM static int
unmap_current_window(amd_iommu_t * iommu,dev_info_t * rdip,ddi_dma_cookie_t * cookie_array,uint_t ccount,int ncookies,int locked)156210535SVikram.Hegde@Sun.COM unmap_current_window(amd_iommu_t *iommu, dev_info_t *rdip,
156310535SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookie_array, uint_t ccount, int ncookies, int locked)
156410535SVikram.Hegde@Sun.COM {
156510535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(iommu->aiomt_dip);
156610535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(iommu->aiomt_dip);
156710535SVikram.Hegde@Sun.COM int idx = iommu->aiomt_idx;
156810535SVikram.Hegde@Sun.COM int i;
156910535SVikram.Hegde@Sun.COM int error = DDI_FAILURE;
157010535SVikram.Hegde@Sun.COM char *path;
157110535SVikram.Hegde@Sun.COM int pathfree;
157210535SVikram.Hegde@Sun.COM const char *f = "unmap_current_window";
157310535SVikram.Hegde@Sun.COM
157410535SVikram.Hegde@Sun.COM if (!locked)
157510535SVikram.Hegde@Sun.COM mutex_enter(&amd_iommu_pgtable_lock);
157610535SVikram.Hegde@Sun.COM
157710535SVikram.Hegde@Sun.COM path = kmem_alloc(MAXPATHLEN, KM_NOSLEEP);
157810535SVikram.Hegde@Sun.COM if (path) {
157910535SVikram.Hegde@Sun.COM (void) ddi_pathname(rdip, path);
158010535SVikram.Hegde@Sun.COM pathfree = 1;
158110535SVikram.Hegde@Sun.COM } else {
158210535SVikram.Hegde@Sun.COM path = "<path-mem-alloc-failed>";
158310535SVikram.Hegde@Sun.COM pathfree = 0;
158410535SVikram.Hegde@Sun.COM }
158510535SVikram.Hegde@Sun.COM
158610535SVikram.Hegde@Sun.COM if (ncookies == -1)
158710535SVikram.Hegde@Sun.COM ncookies = ccount;
158810535SVikram.Hegde@Sun.COM
158910535SVikram.Hegde@Sun.COM for (i = 0; i < ncookies; i++) {
159010535SVikram.Hegde@Sun.COM if (amd_iommu_unmap_va(iommu, rdip,
159110535SVikram.Hegde@Sun.COM cookie_array[i].dmac_cookie_addr,
159210535SVikram.Hegde@Sun.COM cookie_array[i].dmac_size,
159310535SVikram.Hegde@Sun.COM AMD_IOMMU_VMEM_MAP) != DDI_SUCCESS) {
159410535SVikram.Hegde@Sun.COM break;
159510535SVikram.Hegde@Sun.COM }
159610535SVikram.Hegde@Sun.COM }
159710535SVikram.Hegde@Sun.COM
159810535SVikram.Hegde@Sun.COM if (amd_iommu_cmd(iommu, AMD_IOMMU_CMD_COMPL_WAIT, NULL, 0, 0)
159910535SVikram.Hegde@Sun.COM != DDI_SUCCESS) {
160010535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: AMD IOMMU completion wait failed for: %s",
160110535SVikram.Hegde@Sun.COM f, path);
160210535SVikram.Hegde@Sun.COM }
160310535SVikram.Hegde@Sun.COM
160410535SVikram.Hegde@Sun.COM if (i != ncookies) {
160510535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: idx=%d Cannot unmap cookie# %d "
160610535SVikram.Hegde@Sun.COM "for device %s", f, driver, instance, idx, i, path);
160710535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
160810535SVikram.Hegde@Sun.COM goto out;
160910535SVikram.Hegde@Sun.COM }
161010535SVikram.Hegde@Sun.COM
161110535SVikram.Hegde@Sun.COM error = DDI_SUCCESS;
161210535SVikram.Hegde@Sun.COM
161310535SVikram.Hegde@Sun.COM out:
161410535SVikram.Hegde@Sun.COM if (pathfree)
161510535SVikram.Hegde@Sun.COM kmem_free(path, MAXPATHLEN);
161610535SVikram.Hegde@Sun.COM if (!locked)
161710535SVikram.Hegde@Sun.COM mutex_exit(&amd_iommu_pgtable_lock);
161810535SVikram.Hegde@Sun.COM return (error);
161910535SVikram.Hegde@Sun.COM }
162010535SVikram.Hegde@Sun.COM
162110535SVikram.Hegde@Sun.COM /*ARGSUSED*/
162210535SVikram.Hegde@Sun.COM static int
amd_iommu_bindhdl(iommulib_handle_t handle,dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t dma_handle,struct ddi_dma_req * dmareq,ddi_dma_cookie_t * cookiep,uint_t * ccountp)162310535SVikram.Hegde@Sun.COM amd_iommu_bindhdl(iommulib_handle_t handle, dev_info_t *dip,
162410535SVikram.Hegde@Sun.COM dev_info_t *rdip, ddi_dma_handle_t dma_handle,
162510535SVikram.Hegde@Sun.COM struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookiep,
162610535SVikram.Hegde@Sun.COM uint_t *ccountp)
162710535SVikram.Hegde@Sun.COM {
162810535SVikram.Hegde@Sun.COM int dma_error = DDI_DMA_NOMAPPING;
162910535SVikram.Hegde@Sun.COM int error;
163010535SVikram.Hegde@Sun.COM char *path;
163110535SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookie_array = NULL;
163210535SVikram.Hegde@Sun.COM uint_t ccount = 0;
163310535SVikram.Hegde@Sun.COM ddi_dma_impl_t *hp;
163410535SVikram.Hegde@Sun.COM ddi_dma_attr_t *attrp;
163510535SVikram.Hegde@Sun.COM int km_flags;
163610535SVikram.Hegde@Sun.COM amd_iommu_t *iommu = iommulib_iommu_getdata(handle);
163710535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(rdip);
163810535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(rdip);
163910535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_bindhdl";
164010535SVikram.Hegde@Sun.COM
164110535SVikram.Hegde@Sun.COM dma_error = iommulib_iommu_dma_bindhdl(dip, rdip, dma_handle,
164210535SVikram.Hegde@Sun.COM dmareq, cookiep, ccountp);
164310535SVikram.Hegde@Sun.COM
164410535SVikram.Hegde@Sun.COM if (dma_error != DDI_DMA_MAPPED && dma_error != DDI_DMA_PARTIAL_MAP)
164510535SVikram.Hegde@Sun.COM return (dma_error);
164610535SVikram.Hegde@Sun.COM
164710535SVikram.Hegde@Sun.COM km_flags = iommulib_iommu_dma_get_sleep_flags(dip, dma_handle);
164810535SVikram.Hegde@Sun.COM
164910535SVikram.Hegde@Sun.COM path = kmem_alloc(MAXPATHLEN, km_flags);
165010535SVikram.Hegde@Sun.COM if (path) {
165110535SVikram.Hegde@Sun.COM (void) ddi_pathname(rdip, path);
165210535SVikram.Hegde@Sun.COM } else {
165310535SVikram.Hegde@Sun.COM dma_error = DDI_DMA_NORESOURCES;
165410535SVikram.Hegde@Sun.COM goto unbind;
165510535SVikram.Hegde@Sun.COM }
165610535SVikram.Hegde@Sun.COM
165710535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_BIND) {
165810535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s got cookie (%p), #cookies: %d",
165910535SVikram.Hegde@Sun.COM f, path,
166010535SVikram.Hegde@Sun.COM (void *)cookiep->dmac_cookie_addr,
166110535SVikram.Hegde@Sun.COM *ccountp);
166210535SVikram.Hegde@Sun.COM }
166310535SVikram.Hegde@Sun.COM
166410535SVikram.Hegde@Sun.COM cookie_array = NULL;
166510535SVikram.Hegde@Sun.COM ccount = 0;
166610535SVikram.Hegde@Sun.COM if ((error = iommulib_iommu_dma_get_cookies(dip, dma_handle,
166710535SVikram.Hegde@Sun.COM &cookie_array, &ccount)) != DDI_SUCCESS) {
166810535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies "
166910535SVikram.Hegde@Sun.COM "for device %s", f, driver, instance, path);
167010535SVikram.Hegde@Sun.COM dma_error = error;
167110535SVikram.Hegde@Sun.COM goto unbind;
167210535SVikram.Hegde@Sun.COM }
167310535SVikram.Hegde@Sun.COM
167410535SVikram.Hegde@Sun.COM hp = (ddi_dma_impl_t *)dma_handle;
167510535SVikram.Hegde@Sun.COM attrp = &hp->dmai_attr;
167610535SVikram.Hegde@Sun.COM
167710535SVikram.Hegde@Sun.COM error = map_current_window(iommu, rdip, attrp, dmareq,
167810535SVikram.Hegde@Sun.COM cookie_array, ccount, km_flags);
167910535SVikram.Hegde@Sun.COM if (error != DDI_SUCCESS) {
168010535SVikram.Hegde@Sun.COM dma_error = error;
168110535SVikram.Hegde@Sun.COM goto unbind;
168210535SVikram.Hegde@Sun.COM }
168310535SVikram.Hegde@Sun.COM
168410535SVikram.Hegde@Sun.COM if ((error = iommulib_iommu_dma_set_cookies(dip, dma_handle,
168510535SVikram.Hegde@Sun.COM cookie_array, ccount)) != DDI_SUCCESS) {
168610535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot set cookies "
168710535SVikram.Hegde@Sun.COM "for device %s", f, driver, instance, path);
168810535SVikram.Hegde@Sun.COM dma_error = error;
168910535SVikram.Hegde@Sun.COM goto unbind;
169010535SVikram.Hegde@Sun.COM }
169110535SVikram.Hegde@Sun.COM
169210535SVikram.Hegde@Sun.COM *cookiep = cookie_array[0];
169310535SVikram.Hegde@Sun.COM
169410535SVikram.Hegde@Sun.COM if (amd_iommu_debug & AMD_IOMMU_DEBUG_BIND) {
169510535SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s remapped cookie (%p), #cookies: %d",
169610535SVikram.Hegde@Sun.COM f, path,
169710535SVikram.Hegde@Sun.COM (void *)(uintptr_t)cookiep->dmac_cookie_addr,
169810535SVikram.Hegde@Sun.COM *ccountp);
169910535SVikram.Hegde@Sun.COM }
170010535SVikram.Hegde@Sun.COM
170110535SVikram.Hegde@Sun.COM kmem_free(path, MAXPATHLEN);
170210535SVikram.Hegde@Sun.COM ASSERT(dma_error == DDI_DMA_MAPPED || dma_error == DDI_DMA_PARTIAL_MAP);
170310535SVikram.Hegde@Sun.COM return (dma_error);
170410535SVikram.Hegde@Sun.COM unbind:
170510535SVikram.Hegde@Sun.COM kmem_free(path, MAXPATHLEN);
170610535SVikram.Hegde@Sun.COM (void) iommulib_iommu_dma_unbindhdl(dip, rdip, dma_handle);
170710535SVikram.Hegde@Sun.COM return (dma_error);
170810535SVikram.Hegde@Sun.COM }
170910535SVikram.Hegde@Sun.COM
171010535SVikram.Hegde@Sun.COM /*ARGSUSED*/
171110535SVikram.Hegde@Sun.COM static int
amd_iommu_unbindhdl(iommulib_handle_t handle,dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t dma_handle)171210535SVikram.Hegde@Sun.COM amd_iommu_unbindhdl(iommulib_handle_t handle,
171310535SVikram.Hegde@Sun.COM dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle)
171410535SVikram.Hegde@Sun.COM {
171510535SVikram.Hegde@Sun.COM amd_iommu_t *iommu = iommulib_iommu_getdata(handle);
171610535SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookie_array = NULL;
171710535SVikram.Hegde@Sun.COM uint_t ccount = 0;
171810535SVikram.Hegde@Sun.COM int error = DDI_FAILURE;
171910535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(rdip);
172010535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(rdip);
172110535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_unbindhdl";
172210535SVikram.Hegde@Sun.COM
172310535SVikram.Hegde@Sun.COM cookie_array = NULL;
172410535SVikram.Hegde@Sun.COM ccount = 0;
172510535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array,
172610535SVikram.Hegde@Sun.COM &ccount) != DDI_SUCCESS) {
172710535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies "
172810535SVikram.Hegde@Sun.COM "for device %p", f, driver, instance, (void *)rdip);
172910535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
173010535SVikram.Hegde@Sun.COM goto out;
173110535SVikram.Hegde@Sun.COM }
173210535SVikram.Hegde@Sun.COM
173310535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_clear_cookies(dip, dma_handle) != DDI_SUCCESS) {
173410535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot clear cookies "
173510535SVikram.Hegde@Sun.COM "for device %p", f, driver, instance, (void *)rdip);
173610535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
173710535SVikram.Hegde@Sun.COM goto out;
173810535SVikram.Hegde@Sun.COM }
173910535SVikram.Hegde@Sun.COM
174010535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_unbindhdl(dip, rdip, dma_handle)
174110535SVikram.Hegde@Sun.COM != DDI_SUCCESS) {
174210535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: failed to unbindhdl for dip=%p",
174310535SVikram.Hegde@Sun.COM f, driver, instance, (void *)rdip);
174410535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
174510535SVikram.Hegde@Sun.COM goto out;
174610535SVikram.Hegde@Sun.COM }
174710535SVikram.Hegde@Sun.COM
174810535SVikram.Hegde@Sun.COM if (unmap_current_window(iommu, rdip, cookie_array, ccount, -1, 0)
174910535SVikram.Hegde@Sun.COM != DDI_SUCCESS) {
175010535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: failed to unmap current window "
175110535SVikram.Hegde@Sun.COM "for dip=%p", f, driver, instance, (void *)rdip);
175210535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
175310535SVikram.Hegde@Sun.COM } else {
175410535SVikram.Hegde@Sun.COM error = DDI_SUCCESS;
175510535SVikram.Hegde@Sun.COM }
175610535SVikram.Hegde@Sun.COM out:
175710535SVikram.Hegde@Sun.COM if (cookie_array)
175810535SVikram.Hegde@Sun.COM kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount);
175910535SVikram.Hegde@Sun.COM return (error);
176010535SVikram.Hegde@Sun.COM }
176110535SVikram.Hegde@Sun.COM
176210535SVikram.Hegde@Sun.COM /*ARGSUSED*/
176310535SVikram.Hegde@Sun.COM static int
amd_iommu_sync(iommulib_handle_t handle,dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t dma_handle,off_t off,size_t len,uint_t cache_flags)176410535SVikram.Hegde@Sun.COM amd_iommu_sync(iommulib_handle_t handle, dev_info_t *dip,
176510535SVikram.Hegde@Sun.COM dev_info_t *rdip, ddi_dma_handle_t dma_handle, off_t off,
176610535SVikram.Hegde@Sun.COM size_t len, uint_t cache_flags)
176710535SVikram.Hegde@Sun.COM {
176810535SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookie_array = NULL;
176910535SVikram.Hegde@Sun.COM uint_t ccount = 0;
177010535SVikram.Hegde@Sun.COM int error;
177110535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_sync";
177210535SVikram.Hegde@Sun.COM
177310535SVikram.Hegde@Sun.COM cookie_array = NULL;
177410535SVikram.Hegde@Sun.COM ccount = 0;
177510535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array,
177610535SVikram.Hegde@Sun.COM &ccount) != DDI_SUCCESS) {
177710535SVikram.Hegde@Sun.COM ASSERT(cookie_array == NULL);
177810535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: Cannot get cookies "
177910535SVikram.Hegde@Sun.COM "for device %p", f, (void *)rdip);
178010535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
178110535SVikram.Hegde@Sun.COM goto out;
178210535SVikram.Hegde@Sun.COM }
178310535SVikram.Hegde@Sun.COM
178410535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_clear_cookies(dip, dma_handle) != DDI_SUCCESS) {
178510535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: Cannot clear cookies "
178610535SVikram.Hegde@Sun.COM "for device %p", f, (void *)rdip);
178710535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
178810535SVikram.Hegde@Sun.COM goto out;
178910535SVikram.Hegde@Sun.COM }
179010535SVikram.Hegde@Sun.COM
179110535SVikram.Hegde@Sun.COM error = iommulib_iommu_dma_sync(dip, rdip, dma_handle, off,
179210535SVikram.Hegde@Sun.COM len, cache_flags);
179310535SVikram.Hegde@Sun.COM
179410535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_set_cookies(dip, dma_handle, cookie_array,
179510535SVikram.Hegde@Sun.COM ccount) != DDI_SUCCESS) {
179610535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: Cannot set cookies "
179710535SVikram.Hegde@Sun.COM "for device %p", f, (void *)rdip);
179810535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
179910535SVikram.Hegde@Sun.COM } else {
180010535SVikram.Hegde@Sun.COM cookie_array = NULL;
180110535SVikram.Hegde@Sun.COM ccount = 0;
180210535SVikram.Hegde@Sun.COM }
180310535SVikram.Hegde@Sun.COM
180410535SVikram.Hegde@Sun.COM out:
180510535SVikram.Hegde@Sun.COM if (cookie_array)
180610535SVikram.Hegde@Sun.COM kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount);
180710535SVikram.Hegde@Sun.COM return (error);
180810535SVikram.Hegde@Sun.COM }
180910535SVikram.Hegde@Sun.COM
181010535SVikram.Hegde@Sun.COM /*ARGSUSED*/
181110535SVikram.Hegde@Sun.COM static int
amd_iommu_win(iommulib_handle_t handle,dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t dma_handle,uint_t win,off_t * offp,size_t * lenp,ddi_dma_cookie_t * cookiep,uint_t * ccountp)181210535SVikram.Hegde@Sun.COM amd_iommu_win(iommulib_handle_t handle, dev_info_t *dip,
181310535SVikram.Hegde@Sun.COM dev_info_t *rdip, ddi_dma_handle_t dma_handle, uint_t win,
181410535SVikram.Hegde@Sun.COM off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep,
181510535SVikram.Hegde@Sun.COM uint_t *ccountp)
181610535SVikram.Hegde@Sun.COM {
181710535SVikram.Hegde@Sun.COM int error = DDI_FAILURE;
181810535SVikram.Hegde@Sun.COM amd_iommu_t *iommu = iommulib_iommu_getdata(handle);
181910535SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookie_array = NULL;
182010535SVikram.Hegde@Sun.COM uint_t ccount = 0;
182110535SVikram.Hegde@Sun.COM int km_flags;
182210535SVikram.Hegde@Sun.COM ddi_dma_impl_t *hp;
182310535SVikram.Hegde@Sun.COM ddi_dma_attr_t *attrp;
182410535SVikram.Hegde@Sun.COM struct ddi_dma_req sdmareq = {0};
182510535SVikram.Hegde@Sun.COM int instance = ddi_get_instance(rdip);
182610535SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(rdip);
182710535SVikram.Hegde@Sun.COM const char *f = "amd_iommu_win";
182810535SVikram.Hegde@Sun.COM
182910535SVikram.Hegde@Sun.COM km_flags = iommulib_iommu_dma_get_sleep_flags(dip, dma_handle);
183010535SVikram.Hegde@Sun.COM
183110535SVikram.Hegde@Sun.COM cookie_array = NULL;
183210535SVikram.Hegde@Sun.COM ccount = 0;
183310535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array,
183410535SVikram.Hegde@Sun.COM &ccount) != DDI_SUCCESS) {
183510535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies "
183610535SVikram.Hegde@Sun.COM "for device %p", f, driver, instance, (void *)rdip);
183710535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
183810535SVikram.Hegde@Sun.COM goto out;
183910535SVikram.Hegde@Sun.COM }
184010535SVikram.Hegde@Sun.COM
184110535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_clear_cookies(dip, dma_handle) != DDI_SUCCESS) {
184210535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot clear cookies "
184310535SVikram.Hegde@Sun.COM "for device %p", f, driver, instance, (void *)rdip);
184410535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
184510535SVikram.Hegde@Sun.COM goto out;
184610535SVikram.Hegde@Sun.COM }
184710535SVikram.Hegde@Sun.COM
184810535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_win(dip, rdip, dma_handle, win,
184910535SVikram.Hegde@Sun.COM offp, lenp, cookiep, ccountp) != DDI_SUCCESS) {
185010535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: failed switch windows for dip=%p",
185110535SVikram.Hegde@Sun.COM f, driver, instance, (void *)rdip);
185210535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
185310535SVikram.Hegde@Sun.COM goto out;
185410535SVikram.Hegde@Sun.COM }
185510535SVikram.Hegde@Sun.COM
185610535SVikram.Hegde@Sun.COM (void) unmap_current_window(iommu, rdip, cookie_array, ccount, -1, 0);
185710535SVikram.Hegde@Sun.COM
185810535SVikram.Hegde@Sun.COM if (cookie_array) {
185910535SVikram.Hegde@Sun.COM kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount);
186010535SVikram.Hegde@Sun.COM cookie_array = NULL;
186110535SVikram.Hegde@Sun.COM ccount = 0;
186210535SVikram.Hegde@Sun.COM }
186310535SVikram.Hegde@Sun.COM
186410535SVikram.Hegde@Sun.COM cookie_array = NULL;
186510535SVikram.Hegde@Sun.COM ccount = 0;
186610535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array,
186710535SVikram.Hegde@Sun.COM &ccount) != DDI_SUCCESS) {
186810535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies "
186910535SVikram.Hegde@Sun.COM "for device %p", f, driver, instance, (void *)rdip);
187010535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
187110535SVikram.Hegde@Sun.COM goto out;
187210535SVikram.Hegde@Sun.COM }
187310535SVikram.Hegde@Sun.COM
187410535SVikram.Hegde@Sun.COM hp = (ddi_dma_impl_t *)dma_handle;
187510535SVikram.Hegde@Sun.COM attrp = &hp->dmai_attr;
187610535SVikram.Hegde@Sun.COM
187710535SVikram.Hegde@Sun.COM sdmareq.dmar_flags = DDI_DMA_RDWR;
187810535SVikram.Hegde@Sun.COM error = map_current_window(iommu, rdip, attrp, &sdmareq,
187910535SVikram.Hegde@Sun.COM cookie_array, ccount, km_flags);
188010535SVikram.Hegde@Sun.COM
188110535SVikram.Hegde@Sun.COM if (iommulib_iommu_dma_set_cookies(dip, dma_handle, cookie_array,
188210535SVikram.Hegde@Sun.COM ccount) != DDI_SUCCESS) {
188310535SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Cannot set cookies "
188410535SVikram.Hegde@Sun.COM "for device %p", f, driver, instance, (void *)rdip);
188510535SVikram.Hegde@Sun.COM error = DDI_FAILURE;
188610535SVikram.Hegde@Sun.COM goto out;
188710535SVikram.Hegde@Sun.COM }
188810535SVikram.Hegde@Sun.COM
188910535SVikram.Hegde@Sun.COM *cookiep = cookie_array[0];
189010535SVikram.Hegde@Sun.COM
189110535SVikram.Hegde@Sun.COM return (error == DDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
189210535SVikram.Hegde@Sun.COM out:
189310535SVikram.Hegde@Sun.COM if (cookie_array)
189410535SVikram.Hegde@Sun.COM kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount);
189510535SVikram.Hegde@Sun.COM
189610535SVikram.Hegde@Sun.COM return (error);
189710535SVikram.Hegde@Sun.COM }
189810535SVikram.Hegde@Sun.COM
189910535SVikram.Hegde@Sun.COM /* Obsoleted DMA routines */
190010535SVikram.Hegde@Sun.COM
190110535SVikram.Hegde@Sun.COM /*ARGSUSED*/
190210535SVikram.Hegde@Sun.COM static int
amd_iommu_map(iommulib_handle_t handle,dev_info_t * dip,dev_info_t * rdip,struct ddi_dma_req * dmareq,ddi_dma_handle_t * dma_handle)190310535SVikram.Hegde@Sun.COM amd_iommu_map(iommulib_handle_t handle, dev_info_t *dip,
190410535SVikram.Hegde@Sun.COM dev_info_t *rdip, struct ddi_dma_req *dmareq,
190510535SVikram.Hegde@Sun.COM ddi_dma_handle_t *dma_handle)
190610535SVikram.Hegde@Sun.COM {
190710535SVikram.Hegde@Sun.COM ASSERT(0);
190810535SVikram.Hegde@Sun.COM return (iommulib_iommu_dma_map(dip, rdip, dmareq, dma_handle));
190910535SVikram.Hegde@Sun.COM }
191010535SVikram.Hegde@Sun.COM
191110535SVikram.Hegde@Sun.COM /*ARGSUSED*/
191210535SVikram.Hegde@Sun.COM static int
amd_iommu_mctl(iommulib_handle_t handle,dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t dma_handle,enum ddi_dma_ctlops request,off_t * offp,size_t * lenp,caddr_t * objpp,uint_t cache_flags)191310535SVikram.Hegde@Sun.COM amd_iommu_mctl(iommulib_handle_t handle, dev_info_t *dip,
191410535SVikram.Hegde@Sun.COM dev_info_t *rdip, ddi_dma_handle_t dma_handle,
191510535SVikram.Hegde@Sun.COM enum ddi_dma_ctlops request, off_t *offp, size_t *lenp,
191610535SVikram.Hegde@Sun.COM caddr_t *objpp, uint_t cache_flags)
191710535SVikram.Hegde@Sun.COM {
191810535SVikram.Hegde@Sun.COM ASSERT(0);
191910535SVikram.Hegde@Sun.COM return (iommulib_iommu_dma_mctl(dip, rdip, dma_handle,
192010535SVikram.Hegde@Sun.COM request, offp, lenp, objpp, cache_flags));
192110535SVikram.Hegde@Sun.COM }
192210535SVikram.Hegde@Sun.COM
1923*13050Sfrank.van.der.linden@oracle.com /*ARGSUSED*/
1924*13050Sfrank.van.der.linden@oracle.com static int
amd_iommu_mapobject(iommulib_handle_t handle,dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t dma_handle,struct ddi_dma_req * dmareq,ddi_dma_obj_t * dmao)1925*13050Sfrank.van.der.linden@oracle.com amd_iommu_mapobject(iommulib_handle_t handle, dev_info_t *dip,
1926*13050Sfrank.van.der.linden@oracle.com dev_info_t *rdip, ddi_dma_handle_t dma_handle,
1927*13050Sfrank.van.der.linden@oracle.com struct ddi_dma_req *dmareq, ddi_dma_obj_t *dmao)
1928*13050Sfrank.van.der.linden@oracle.com {
1929*13050Sfrank.van.der.linden@oracle.com return (DDI_ENOTSUP);
1930*13050Sfrank.van.der.linden@oracle.com }
1931*13050Sfrank.van.der.linden@oracle.com
1932*13050Sfrank.van.der.linden@oracle.com /*ARGSUSED*/
1933*13050Sfrank.van.der.linden@oracle.com static int
amd_iommu_unmapobject(iommulib_handle_t handle,dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t dma_handle,ddi_dma_obj_t * dmao)1934*13050Sfrank.van.der.linden@oracle.com amd_iommu_unmapobject(iommulib_handle_t handle, dev_info_t *dip,
1935*13050Sfrank.van.der.linden@oracle.com dev_info_t *rdip, ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao)
1936*13050Sfrank.van.der.linden@oracle.com {
1937*13050Sfrank.van.der.linden@oracle.com return (DDI_ENOTSUP);
1938*13050Sfrank.van.der.linden@oracle.com }
1939*13050Sfrank.van.der.linden@oracle.com
194010535SVikram.Hegde@Sun.COM uint64_t
amd_iommu_reg_get64_workaround(uint64_t * regp,uint32_t bits)194110535SVikram.Hegde@Sun.COM amd_iommu_reg_get64_workaround(uint64_t *regp, uint32_t bits)
194210535SVikram.Hegde@Sun.COM {
194310535SVikram.Hegde@Sun.COM split_t s;
194410535SVikram.Hegde@Sun.COM uint32_t *ptr32 = (uint32_t *)regp;
194510535SVikram.Hegde@Sun.COM uint64_t *s64p = &(s.u64);
194610535SVikram.Hegde@Sun.COM
194710535SVikram.Hegde@Sun.COM s.u32[0] = ptr32[0];
194810535SVikram.Hegde@Sun.COM s.u32[1] = ptr32[1];
194910535SVikram.Hegde@Sun.COM
195010535SVikram.Hegde@Sun.COM return (AMD_IOMMU_REG_GET64_IMPL(s64p, bits));
195110535SVikram.Hegde@Sun.COM }
195210535SVikram.Hegde@Sun.COM
195310535SVikram.Hegde@Sun.COM uint64_t
amd_iommu_reg_set64_workaround(uint64_t * regp,uint32_t bits,uint64_t value)195410535SVikram.Hegde@Sun.COM amd_iommu_reg_set64_workaround(uint64_t *regp, uint32_t bits, uint64_t value)
195510535SVikram.Hegde@Sun.COM {
195610535SVikram.Hegde@Sun.COM split_t s;
195710535SVikram.Hegde@Sun.COM uint32_t *ptr32 = (uint32_t *)regp;
195810535SVikram.Hegde@Sun.COM uint64_t *s64p = &(s.u64);
195910535SVikram.Hegde@Sun.COM
196010535SVikram.Hegde@Sun.COM s.u32[0] = ptr32[0];
196110535SVikram.Hegde@Sun.COM s.u32[1] = ptr32[1];
196210535SVikram.Hegde@Sun.COM
196310535SVikram.Hegde@Sun.COM AMD_IOMMU_REG_SET64_IMPL(s64p, bits, value);
196410535SVikram.Hegde@Sun.COM
196510535SVikram.Hegde@Sun.COM *regp = s.u64;
196610535SVikram.Hegde@Sun.COM
196710535SVikram.Hegde@Sun.COM return (s.u64);
196810535SVikram.Hegde@Sun.COM }
196910535SVikram.Hegde@Sun.COM
197010535SVikram.Hegde@Sun.COM void
amd_iommu_read_boot_props(void)197110535SVikram.Hegde@Sun.COM amd_iommu_read_boot_props(void)
197210535SVikram.Hegde@Sun.COM {
197310535SVikram.Hegde@Sun.COM char *propval;
197410535SVikram.Hegde@Sun.COM
197510535SVikram.Hegde@Sun.COM /*
197610535SVikram.Hegde@Sun.COM * if "amd-iommu = no/false" boot property is set,
197710535SVikram.Hegde@Sun.COM * ignore AMD iommu
197810535SVikram.Hegde@Sun.COM */
197910535SVikram.Hegde@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
198010535SVikram.Hegde@Sun.COM DDI_PROP_DONTPASS, "amd-iommu", &propval) == DDI_SUCCESS) {
198110535SVikram.Hegde@Sun.COM if (strcmp(propval, "no") == 0 ||
198210535SVikram.Hegde@Sun.COM strcmp(propval, "false") == 0) {
198310535SVikram.Hegde@Sun.COM amd_iommu_disable = 1;
198410535SVikram.Hegde@Sun.COM }
198510535SVikram.Hegde@Sun.COM ddi_prop_free(propval);
198610535SVikram.Hegde@Sun.COM }
198710535SVikram.Hegde@Sun.COM
198810535SVikram.Hegde@Sun.COM /*
198910535SVikram.Hegde@Sun.COM * Copy the list of drivers for which IOMMU is disabled by user.
199010535SVikram.Hegde@Sun.COM */
199110535SVikram.Hegde@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
199210535SVikram.Hegde@Sun.COM DDI_PROP_DONTPASS, "amd-iommu-disable-list", &propval)
199310535SVikram.Hegde@Sun.COM == DDI_SUCCESS) {
199410535SVikram.Hegde@Sun.COM amd_iommu_disable_list = kmem_alloc(strlen(propval) + 1,
199510535SVikram.Hegde@Sun.COM KM_SLEEP);
199610535SVikram.Hegde@Sun.COM (void) strcpy(amd_iommu_disable_list, propval);
199710535SVikram.Hegde@Sun.COM ddi_prop_free(propval);
199810535SVikram.Hegde@Sun.COM }
199910535SVikram.Hegde@Sun.COM
200010535SVikram.Hegde@Sun.COM }
200110535SVikram.Hegde@Sun.COM
200210535SVikram.Hegde@Sun.COM void
amd_iommu_lookup_conf_props(dev_info_t * dip)200310535SVikram.Hegde@Sun.COM amd_iommu_lookup_conf_props(dev_info_t *dip)
200410535SVikram.Hegde@Sun.COM {
200510535SVikram.Hegde@Sun.COM char *disable;
200610535SVikram.Hegde@Sun.COM
200710535SVikram.Hegde@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
200810535SVikram.Hegde@Sun.COM DDI_PROP_DONTPASS|DDI_PROP_NOTPROM, "amd-iommu", &disable)
200910535SVikram.Hegde@Sun.COM == DDI_PROP_SUCCESS) {
201010535SVikram.Hegde@Sun.COM if (strcmp(disable, "no") == 0) {
201110535SVikram.Hegde@Sun.COM amd_iommu_disable = 1;
201210535SVikram.Hegde@Sun.COM }
201310535SVikram.Hegde@Sun.COM ddi_prop_free(disable);
201410535SVikram.Hegde@Sun.COM }
201510535SVikram.Hegde@Sun.COM
201610535SVikram.Hegde@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
201710535SVikram.Hegde@Sun.COM DDI_PROP_DONTPASS|DDI_PROP_NOTPROM, "amd-iommu-disable-list",
201810535SVikram.Hegde@Sun.COM &disable) == DDI_PROP_SUCCESS) {
201910535SVikram.Hegde@Sun.COM amd_iommu_disable_list = kmem_alloc(strlen(disable) + 1,
202010535SVikram.Hegde@Sun.COM KM_SLEEP);
202110535SVikram.Hegde@Sun.COM (void) strcpy(amd_iommu_disable_list, disable);
202210535SVikram.Hegde@Sun.COM ddi_prop_free(disable);
202310535SVikram.Hegde@Sun.COM }
202410535SVikram.Hegde@Sun.COM }
2025