111600SVikram.Hegde@Sun.COM /*
211600SVikram.Hegde@Sun.COM * CDDL HEADER START
311600SVikram.Hegde@Sun.COM *
411600SVikram.Hegde@Sun.COM * The contents of this file are subject to the terms of the
511600SVikram.Hegde@Sun.COM * Common Development and Distribution License (the "License").
611600SVikram.Hegde@Sun.COM * You may not use this file except in compliance with the License.
711600SVikram.Hegde@Sun.COM *
811600SVikram.Hegde@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911600SVikram.Hegde@Sun.COM * or http://www.opensolaris.org/os/licensing.
1011600SVikram.Hegde@Sun.COM * See the License for the specific language governing permissions
1111600SVikram.Hegde@Sun.COM * and limitations under the License.
1211600SVikram.Hegde@Sun.COM *
1311600SVikram.Hegde@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1411600SVikram.Hegde@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511600SVikram.Hegde@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1611600SVikram.Hegde@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1711600SVikram.Hegde@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1811600SVikram.Hegde@Sun.COM *
1911600SVikram.Hegde@Sun.COM * CDDL HEADER END
2011600SVikram.Hegde@Sun.COM */
2111600SVikram.Hegde@Sun.COM /*
2212513Sfrank.van.der.linden@oracle.com * Portions Copyright (c) 2010, Oracle and/or its affiliates.
2312513Sfrank.van.der.linden@oracle.com * All rights reserved.
2411600SVikram.Hegde@Sun.COM */
2511600SVikram.Hegde@Sun.COM
2611600SVikram.Hegde@Sun.COM /*
2711600SVikram.Hegde@Sun.COM * immu_regs.c - File that operates on a IMMU unit's regsiters
2811600SVikram.Hegde@Sun.COM */
2911600SVikram.Hegde@Sun.COM #include <sys/dditypes.h>
3011600SVikram.Hegde@Sun.COM #include <sys/ddi.h>
3111600SVikram.Hegde@Sun.COM #include <sys/archsystm.h>
3211600SVikram.Hegde@Sun.COM #include <sys/x86_archext.h>
3311600SVikram.Hegde@Sun.COM #include <sys/spl.h>
3411658SVikram.Hegde@Sun.COM #include <sys/sysmacros.h>
3511600SVikram.Hegde@Sun.COM #include <sys/immu.h>
36*13050Sfrank.van.der.linden@oracle.com #include <sys/cpu.h>
3711600SVikram.Hegde@Sun.COM
3811600SVikram.Hegde@Sun.COM #define get_reg32(immu, offset) ddi_get32((immu)->immu_regs_handle, \
3911600SVikram.Hegde@Sun.COM (uint32_t *)(immu->immu_regs_addr + (offset)))
4011600SVikram.Hegde@Sun.COM #define get_reg64(immu, offset) ddi_get64((immu)->immu_regs_handle, \
4111600SVikram.Hegde@Sun.COM (uint64_t *)(immu->immu_regs_addr + (offset)))
4211600SVikram.Hegde@Sun.COM #define put_reg32(immu, offset, val) ddi_put32\
4311600SVikram.Hegde@Sun.COM ((immu)->immu_regs_handle, \
4411600SVikram.Hegde@Sun.COM (uint32_t *)(immu->immu_regs_addr + (offset)), val)
4511600SVikram.Hegde@Sun.COM #define put_reg64(immu, offset, val) ddi_put64\
4611600SVikram.Hegde@Sun.COM ((immu)->immu_regs_handle, \
4711600SVikram.Hegde@Sun.COM (uint64_t *)(immu->immu_regs_addr + (offset)), val)
4811600SVikram.Hegde@Sun.COM
49*13050Sfrank.van.der.linden@oracle.com static void immu_regs_inv_wait(immu_inv_wait_t *iwp);
50*13050Sfrank.van.der.linden@oracle.com
5112513Sfrank.van.der.linden@oracle.com struct immu_flushops immu_regs_flushops = {
5212513Sfrank.van.der.linden@oracle.com immu_regs_context_fsi,
5312513Sfrank.van.der.linden@oracle.com immu_regs_context_dsi,
5412513Sfrank.van.der.linden@oracle.com immu_regs_context_gbl,
5512513Sfrank.van.der.linden@oracle.com immu_regs_iotlb_psi,
5612513Sfrank.van.der.linden@oracle.com immu_regs_iotlb_dsi,
57*13050Sfrank.van.der.linden@oracle.com immu_regs_iotlb_gbl,
58*13050Sfrank.van.der.linden@oracle.com immu_regs_inv_wait
5912513Sfrank.van.der.linden@oracle.com };
6012513Sfrank.van.der.linden@oracle.com
6111600SVikram.Hegde@Sun.COM /*
6211600SVikram.Hegde@Sun.COM * wait max 60s for the hardware completion
6311600SVikram.Hegde@Sun.COM */
6411600SVikram.Hegde@Sun.COM #define IMMU_MAX_WAIT_TIME 60000000
6511600SVikram.Hegde@Sun.COM #define wait_completion(immu, offset, getf, completion, status) \
6611600SVikram.Hegde@Sun.COM { \
6711600SVikram.Hegde@Sun.COM clock_t stick = ddi_get_lbolt(); \
6811600SVikram.Hegde@Sun.COM clock_t ntick; \
6911600SVikram.Hegde@Sun.COM _NOTE(CONSTCOND) \
7011600SVikram.Hegde@Sun.COM while (1) { \
7111600SVikram.Hegde@Sun.COM status = getf(immu, offset); \
7211600SVikram.Hegde@Sun.COM ntick = ddi_get_lbolt(); \
7311600SVikram.Hegde@Sun.COM if (completion) { \
7411600SVikram.Hegde@Sun.COM break; \
7511600SVikram.Hegde@Sun.COM } \
7611600SVikram.Hegde@Sun.COM if (ntick - stick >= drv_usectohz(IMMU_MAX_WAIT_TIME)) { \
7711600SVikram.Hegde@Sun.COM ddi_err(DER_PANIC, NULL, \
7811600SVikram.Hegde@Sun.COM "immu wait completion time out"); \
7911600SVikram.Hegde@Sun.COM /*NOTREACHED*/ \
8011600SVikram.Hegde@Sun.COM } else { \
81*13050Sfrank.van.der.linden@oracle.com ht_pause();\
8211600SVikram.Hegde@Sun.COM }\
8311600SVikram.Hegde@Sun.COM }\
8411600SVikram.Hegde@Sun.COM }
8511600SVikram.Hegde@Sun.COM
8611600SVikram.Hegde@Sun.COM static ddi_device_acc_attr_t immu_regs_attr = {
8711600SVikram.Hegde@Sun.COM DDI_DEVICE_ATTR_V0,
8811600SVikram.Hegde@Sun.COM DDI_NEVERSWAP_ACC,
8911600SVikram.Hegde@Sun.COM DDI_STRICTORDER_ACC,
9011600SVikram.Hegde@Sun.COM };
9111600SVikram.Hegde@Sun.COM
9211600SVikram.Hegde@Sun.COM /*
9311600SVikram.Hegde@Sun.COM * iotlb_flush()
9411600SVikram.Hegde@Sun.COM * flush the iotlb cache
9511600SVikram.Hegde@Sun.COM */
9611600SVikram.Hegde@Sun.COM static void
iotlb_flush(immu_t * immu,uint_t domain_id,uint64_t addr,uint_t am,uint_t hint,immu_iotlb_inv_t type)9711600SVikram.Hegde@Sun.COM iotlb_flush(immu_t *immu, uint_t domain_id,
9811600SVikram.Hegde@Sun.COM uint64_t addr, uint_t am, uint_t hint, immu_iotlb_inv_t type)
9911600SVikram.Hegde@Sun.COM {
10011600SVikram.Hegde@Sun.COM uint64_t command = 0, iva = 0;
10111600SVikram.Hegde@Sun.COM uint_t iva_offset, iotlb_offset;
10211600SVikram.Hegde@Sun.COM uint64_t status = 0;
10311600SVikram.Hegde@Sun.COM
10411600SVikram.Hegde@Sun.COM /* no lock needed since cap and excap fields are RDONLY */
10511600SVikram.Hegde@Sun.COM iva_offset = IMMU_ECAP_GET_IRO(immu->immu_regs_excap);
10611600SVikram.Hegde@Sun.COM iotlb_offset = iva_offset + 8;
10711600SVikram.Hegde@Sun.COM
10811600SVikram.Hegde@Sun.COM /*
10911600SVikram.Hegde@Sun.COM * prepare drain read/write command
11011600SVikram.Hegde@Sun.COM */
11111600SVikram.Hegde@Sun.COM if (IMMU_CAP_GET_DWD(immu->immu_regs_cap)) {
11211600SVikram.Hegde@Sun.COM command |= TLB_INV_DRAIN_WRITE;
11311600SVikram.Hegde@Sun.COM }
11411600SVikram.Hegde@Sun.COM
11511600SVikram.Hegde@Sun.COM if (IMMU_CAP_GET_DRD(immu->immu_regs_cap)) {
11611600SVikram.Hegde@Sun.COM command |= TLB_INV_DRAIN_READ;
11711600SVikram.Hegde@Sun.COM }
11811600SVikram.Hegde@Sun.COM
11911600SVikram.Hegde@Sun.COM /*
12011600SVikram.Hegde@Sun.COM * if the hardward doesn't support page selective invalidation, we
12111600SVikram.Hegde@Sun.COM * will use domain type. Otherwise, use global type
12211600SVikram.Hegde@Sun.COM */
12311600SVikram.Hegde@Sun.COM switch (type) {
12411600SVikram.Hegde@Sun.COM case IOTLB_PSI:
12511600SVikram.Hegde@Sun.COM command |= TLB_INV_PAGE | TLB_INV_IVT |
12611600SVikram.Hegde@Sun.COM TLB_INV_DID(domain_id);
12711600SVikram.Hegde@Sun.COM iva = addr | am | TLB_IVA_HINT(hint);
12811600SVikram.Hegde@Sun.COM break;
12911600SVikram.Hegde@Sun.COM case IOTLB_DSI:
13011600SVikram.Hegde@Sun.COM command |= TLB_INV_DOMAIN | TLB_INV_IVT |
13111600SVikram.Hegde@Sun.COM TLB_INV_DID(domain_id);
13211600SVikram.Hegde@Sun.COM break;
13311600SVikram.Hegde@Sun.COM case IOTLB_GLOBAL:
13411600SVikram.Hegde@Sun.COM command |= TLB_INV_GLOBAL | TLB_INV_IVT;
13511600SVikram.Hegde@Sun.COM break;
13611600SVikram.Hegde@Sun.COM default:
13711600SVikram.Hegde@Sun.COM ddi_err(DER_MODE, NULL, "%s: incorrect iotlb flush type",
13811600SVikram.Hegde@Sun.COM immu->immu_name);
13911600SVikram.Hegde@Sun.COM return;
14011600SVikram.Hegde@Sun.COM }
14111600SVikram.Hegde@Sun.COM
14211600SVikram.Hegde@Sun.COM if (iva)
14311600SVikram.Hegde@Sun.COM put_reg64(immu, iva_offset, iva);
14411600SVikram.Hegde@Sun.COM put_reg64(immu, iotlb_offset, command);
14511600SVikram.Hegde@Sun.COM wait_completion(immu, iotlb_offset, get_reg64,
14611600SVikram.Hegde@Sun.COM (!(status & TLB_INV_IVT)), status);
14711600SVikram.Hegde@Sun.COM }
14811600SVikram.Hegde@Sun.COM
14911600SVikram.Hegde@Sun.COM /*
15012513Sfrank.van.der.linden@oracle.com * immu_regs_iotlb_psi()
15111600SVikram.Hegde@Sun.COM * iotlb page specific invalidation
15211600SVikram.Hegde@Sun.COM */
153*13050Sfrank.van.der.linden@oracle.com /*ARGSUSED*/
15412513Sfrank.van.der.linden@oracle.com void
immu_regs_iotlb_psi(immu_t * immu,uint_t did,uint64_t dvma,uint_t snpages,uint_t hint,immu_inv_wait_t * iwp)15512513Sfrank.van.der.linden@oracle.com immu_regs_iotlb_psi(immu_t *immu, uint_t did, uint64_t dvma, uint_t snpages,
156*13050Sfrank.van.der.linden@oracle.com uint_t hint, immu_inv_wait_t *iwp)
15711600SVikram.Hegde@Sun.COM {
15811658SVikram.Hegde@Sun.COM int dvma_am;
15911658SVikram.Hegde@Sun.COM int npg_am;
16011658SVikram.Hegde@Sun.COM int max_am;
16111658SVikram.Hegde@Sun.COM int am;
16211658SVikram.Hegde@Sun.COM uint64_t align;
16311658SVikram.Hegde@Sun.COM int npages_left;
16411658SVikram.Hegde@Sun.COM int npages;
16511658SVikram.Hegde@Sun.COM int i;
16611658SVikram.Hegde@Sun.COM
16712513Sfrank.van.der.linden@oracle.com if (!IMMU_CAP_GET_PSI(immu->immu_regs_cap)) {
168*13050Sfrank.van.der.linden@oracle.com immu_regs_iotlb_dsi(immu, did, iwp);
16912513Sfrank.van.der.linden@oracle.com return;
17012513Sfrank.van.der.linden@oracle.com }
17112513Sfrank.van.der.linden@oracle.com
17211658SVikram.Hegde@Sun.COM max_am = IMMU_CAP_GET_MAMV(immu->immu_regs_cap);
17311600SVikram.Hegde@Sun.COM
17411600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
17511600SVikram.Hegde@Sun.COM
17611658SVikram.Hegde@Sun.COM npages_left = snpages;
17711658SVikram.Hegde@Sun.COM for (i = 0; i < immu_flush_gran && npages_left > 0; i++) {
17811658SVikram.Hegde@Sun.COM /* First calculate alignment of DVMA */
17911658SVikram.Hegde@Sun.COM
18011658SVikram.Hegde@Sun.COM if (dvma == 0) {
18111658SVikram.Hegde@Sun.COM dvma_am = max_am;
18211658SVikram.Hegde@Sun.COM } else {
18311658SVikram.Hegde@Sun.COM for (align = (1 << 12), dvma_am = 1;
18411658SVikram.Hegde@Sun.COM (dvma & align) == 0; align <<= 1, dvma_am++)
18511600SVikram.Hegde@Sun.COM ;
18611658SVikram.Hegde@Sun.COM dvma_am--;
18711600SVikram.Hegde@Sun.COM }
18811658SVikram.Hegde@Sun.COM
18911658SVikram.Hegde@Sun.COM /* Calculate the npg_am */
19011658SVikram.Hegde@Sun.COM npages = npages_left;
19111658SVikram.Hegde@Sun.COM for (npg_am = 0, npages >>= 1; npages; npages >>= 1, npg_am++)
19211658SVikram.Hegde@Sun.COM ;
19311658SVikram.Hegde@Sun.COM
19411658SVikram.Hegde@Sun.COM am = MIN(max_am, MIN(dvma_am, npg_am));
19511658SVikram.Hegde@Sun.COM
19611658SVikram.Hegde@Sun.COM iotlb_flush(immu, did, dvma, am, hint, IOTLB_PSI);
19711658SVikram.Hegde@Sun.COM
19811658SVikram.Hegde@Sun.COM npages = (1 << am);
19911658SVikram.Hegde@Sun.COM npages_left -= npages;
20011658SVikram.Hegde@Sun.COM dvma += (npages * IMMU_PAGESIZE);
20111600SVikram.Hegde@Sun.COM }
20211600SVikram.Hegde@Sun.COM
20311658SVikram.Hegde@Sun.COM if (npages_left) {
20411658SVikram.Hegde@Sun.COM iotlb_flush(immu, did, 0, 0, 0, IOTLB_DSI);
20511658SVikram.Hegde@Sun.COM }
20611600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
20711600SVikram.Hegde@Sun.COM }
20811600SVikram.Hegde@Sun.COM
20911600SVikram.Hegde@Sun.COM /*
21012513Sfrank.van.der.linden@oracle.com * immu_regs_iotlb_dsi()
21111600SVikram.Hegde@Sun.COM * domain specific invalidation
21211600SVikram.Hegde@Sun.COM */
213*13050Sfrank.van.der.linden@oracle.com /*ARGSUSED*/
21412513Sfrank.van.der.linden@oracle.com void
immu_regs_iotlb_dsi(immu_t * immu,uint_t domain_id,immu_inv_wait_t * iwp)215*13050Sfrank.van.der.linden@oracle.com immu_regs_iotlb_dsi(immu_t *immu, uint_t domain_id, immu_inv_wait_t *iwp)
21611600SVikram.Hegde@Sun.COM {
21711600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
21811600SVikram.Hegde@Sun.COM iotlb_flush(immu, domain_id, 0, 0, 0, IOTLB_DSI);
21911600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
22011600SVikram.Hegde@Sun.COM }
22111600SVikram.Hegde@Sun.COM
22211600SVikram.Hegde@Sun.COM /*
22312513Sfrank.van.der.linden@oracle.com * immu_regs_iotlb_gbl()
22411600SVikram.Hegde@Sun.COM * global iotlb invalidation
22511600SVikram.Hegde@Sun.COM */
226*13050Sfrank.van.der.linden@oracle.com /*ARGSUSED*/
22712513Sfrank.van.der.linden@oracle.com void
immu_regs_iotlb_gbl(immu_t * immu,immu_inv_wait_t * iwp)228*13050Sfrank.van.der.linden@oracle.com immu_regs_iotlb_gbl(immu_t *immu, immu_inv_wait_t *iwp)
22911600SVikram.Hegde@Sun.COM {
23011600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
23111600SVikram.Hegde@Sun.COM iotlb_flush(immu, 0, 0, 0, 0, IOTLB_GLOBAL);
23211600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
23311600SVikram.Hegde@Sun.COM }
23411600SVikram.Hegde@Sun.COM
23511600SVikram.Hegde@Sun.COM
23611600SVikram.Hegde@Sun.COM static int
gaw2agaw(int gaw)23711600SVikram.Hegde@Sun.COM gaw2agaw(int gaw)
23811600SVikram.Hegde@Sun.COM {
23911600SVikram.Hegde@Sun.COM int r, agaw;
24011600SVikram.Hegde@Sun.COM
24111600SVikram.Hegde@Sun.COM r = (gaw - 12) % 9;
24211600SVikram.Hegde@Sun.COM
24311600SVikram.Hegde@Sun.COM if (r == 0)
24411600SVikram.Hegde@Sun.COM agaw = gaw;
24511600SVikram.Hegde@Sun.COM else
24611600SVikram.Hegde@Sun.COM agaw = gaw + 9 - r;
24711600SVikram.Hegde@Sun.COM
24811600SVikram.Hegde@Sun.COM if (agaw > 64)
24911600SVikram.Hegde@Sun.COM agaw = 64;
25011600SVikram.Hegde@Sun.COM
25111600SVikram.Hegde@Sun.COM return (agaw);
25211600SVikram.Hegde@Sun.COM }
25311600SVikram.Hegde@Sun.COM
25411600SVikram.Hegde@Sun.COM /*
25511600SVikram.Hegde@Sun.COM * set_immu_agaw()
25611600SVikram.Hegde@Sun.COM * calculate agaw for a IOMMU unit
25711600SVikram.Hegde@Sun.COM */
25811600SVikram.Hegde@Sun.COM static int
set_agaw(immu_t * immu)25911600SVikram.Hegde@Sun.COM set_agaw(immu_t *immu)
26011600SVikram.Hegde@Sun.COM {
26111600SVikram.Hegde@Sun.COM int mgaw, magaw, agaw;
26211600SVikram.Hegde@Sun.COM uint_t bitpos;
26311600SVikram.Hegde@Sun.COM int max_sagaw_mask, sagaw_mask, mask;
26411600SVikram.Hegde@Sun.COM int nlevels;
26511600SVikram.Hegde@Sun.COM
26611600SVikram.Hegde@Sun.COM /*
26711600SVikram.Hegde@Sun.COM * mgaw is the maximum guest address width.
26811600SVikram.Hegde@Sun.COM * Addresses above this value will be
26911600SVikram.Hegde@Sun.COM * blocked by the IOMMU unit.
27011600SVikram.Hegde@Sun.COM * sagaw is a bitmask that lists all the
27111600SVikram.Hegde@Sun.COM * AGAWs supported by this IOMMU unit.
27211600SVikram.Hegde@Sun.COM */
27311600SVikram.Hegde@Sun.COM mgaw = IMMU_CAP_MGAW(immu->immu_regs_cap);
27411600SVikram.Hegde@Sun.COM sagaw_mask = IMMU_CAP_SAGAW(immu->immu_regs_cap);
27511600SVikram.Hegde@Sun.COM
27611600SVikram.Hegde@Sun.COM magaw = gaw2agaw(mgaw);
27711600SVikram.Hegde@Sun.COM
27811600SVikram.Hegde@Sun.COM /*
27911600SVikram.Hegde@Sun.COM * Get bitpos corresponding to
28011600SVikram.Hegde@Sun.COM * magaw
28111600SVikram.Hegde@Sun.COM */
28211600SVikram.Hegde@Sun.COM
28311600SVikram.Hegde@Sun.COM /*
28411600SVikram.Hegde@Sun.COM * Maximum SAGAW is specified by
28511600SVikram.Hegde@Sun.COM * Vt-d spec.
28611600SVikram.Hegde@Sun.COM */
28711600SVikram.Hegde@Sun.COM max_sagaw_mask = ((1 << 5) - 1);
28811600SVikram.Hegde@Sun.COM
28911600SVikram.Hegde@Sun.COM if (sagaw_mask > max_sagaw_mask) {
29011600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "%s: SAGAW bitmask (%x) "
29111600SVikram.Hegde@Sun.COM "is larger than maximu SAGAW bitmask "
29211600SVikram.Hegde@Sun.COM "(%x) specified by Intel Vt-d spec",
29311600SVikram.Hegde@Sun.COM immu->immu_name, sagaw_mask, max_sagaw_mask);
29411600SVikram.Hegde@Sun.COM return (DDI_FAILURE);
29511600SVikram.Hegde@Sun.COM }
29611600SVikram.Hegde@Sun.COM
29711600SVikram.Hegde@Sun.COM /*
29811600SVikram.Hegde@Sun.COM * Find a supported AGAW <= magaw
29911600SVikram.Hegde@Sun.COM *
30011600SVikram.Hegde@Sun.COM * sagaw_mask bitpos AGAW (bits) nlevels
30111600SVikram.Hegde@Sun.COM * ==============================================
30211600SVikram.Hegde@Sun.COM * 0 0 0 0 1 0 30 2
30311600SVikram.Hegde@Sun.COM * 0 0 0 1 0 1 39 3
30411600SVikram.Hegde@Sun.COM * 0 0 1 0 0 2 48 4
30511600SVikram.Hegde@Sun.COM * 0 1 0 0 0 3 57 5
30611600SVikram.Hegde@Sun.COM * 1 0 0 0 0 4 64(66) 6
30711600SVikram.Hegde@Sun.COM */
30811600SVikram.Hegde@Sun.COM mask = 1;
30911600SVikram.Hegde@Sun.COM nlevels = 0;
31011600SVikram.Hegde@Sun.COM agaw = 0;
31111600SVikram.Hegde@Sun.COM for (mask = 1, bitpos = 0; bitpos < 5;
31211600SVikram.Hegde@Sun.COM bitpos++, mask <<= 1) {
31311600SVikram.Hegde@Sun.COM if (mask & sagaw_mask) {
31411600SVikram.Hegde@Sun.COM nlevels = bitpos + 2;
31511600SVikram.Hegde@Sun.COM agaw = 30 + (bitpos * 9);
31611600SVikram.Hegde@Sun.COM }
31711600SVikram.Hegde@Sun.COM }
31811600SVikram.Hegde@Sun.COM
31911600SVikram.Hegde@Sun.COM /* calculated agaw can be > 64 */
32011600SVikram.Hegde@Sun.COM agaw = (agaw > 64) ? 64 : agaw;
32111600SVikram.Hegde@Sun.COM
32211600SVikram.Hegde@Sun.COM if (agaw < 30 || agaw > magaw) {
32311600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "%s: Calculated AGAW (%d) "
32411600SVikram.Hegde@Sun.COM "is outside valid limits [30,%d] specified by Vt-d spec "
32511600SVikram.Hegde@Sun.COM "and magaw", immu->immu_name, agaw, magaw);
32611600SVikram.Hegde@Sun.COM return (DDI_FAILURE);
32711600SVikram.Hegde@Sun.COM }
32811600SVikram.Hegde@Sun.COM
32911600SVikram.Hegde@Sun.COM if (nlevels < 2 || nlevels > 6) {
33011600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "%s: Calculated pagetable "
33111600SVikram.Hegde@Sun.COM "level (%d) is outside valid limits [2,6]",
33211600SVikram.Hegde@Sun.COM immu->immu_name, nlevels);
33311600SVikram.Hegde@Sun.COM return (DDI_FAILURE);
33411600SVikram.Hegde@Sun.COM }
33511600SVikram.Hegde@Sun.COM
33611600SVikram.Hegde@Sun.COM ddi_err(DER_LOG, NULL, "Calculated pagetable "
33711600SVikram.Hegde@Sun.COM "level (%d), agaw = %d", nlevels, agaw);
33811600SVikram.Hegde@Sun.COM
33911600SVikram.Hegde@Sun.COM immu->immu_dvma_nlevels = nlevels;
34011600SVikram.Hegde@Sun.COM immu->immu_dvma_agaw = agaw;
34111600SVikram.Hegde@Sun.COM
34211600SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
34311600SVikram.Hegde@Sun.COM }
34411600SVikram.Hegde@Sun.COM
34511600SVikram.Hegde@Sun.COM static int
setup_regs(immu_t * immu)34611600SVikram.Hegde@Sun.COM setup_regs(immu_t *immu)
34711600SVikram.Hegde@Sun.COM {
34811600SVikram.Hegde@Sun.COM int error;
34911600SVikram.Hegde@Sun.COM
35011600SVikram.Hegde@Sun.COM /*
35111600SVikram.Hegde@Sun.COM * This lock may be acquired by the IOMMU interrupt handler
35211600SVikram.Hegde@Sun.COM */
35311600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_regs_lock), NULL, MUTEX_DRIVER,
35411600SVikram.Hegde@Sun.COM (void *)ipltospl(IMMU_INTR_IPL));
35511600SVikram.Hegde@Sun.COM
35611600SVikram.Hegde@Sun.COM /*
35711600SVikram.Hegde@Sun.COM * map the register address space
35811600SVikram.Hegde@Sun.COM */
35911600SVikram.Hegde@Sun.COM error = ddi_regs_map_setup(immu->immu_dip, 0,
36011600SVikram.Hegde@Sun.COM (caddr_t *)&(immu->immu_regs_addr), (offset_t)0,
36111600SVikram.Hegde@Sun.COM (offset_t)IMMU_REGSZ, &immu_regs_attr,
36211600SVikram.Hegde@Sun.COM &(immu->immu_regs_handle));
36311600SVikram.Hegde@Sun.COM
36411600SVikram.Hegde@Sun.COM if (error == DDI_FAILURE) {
36511600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "%s: Intel IOMMU register map failed",
36611600SVikram.Hegde@Sun.COM immu->immu_name);
36711600SVikram.Hegde@Sun.COM mutex_destroy(&(immu->immu_regs_lock));
36811600SVikram.Hegde@Sun.COM return (DDI_FAILURE);
36911600SVikram.Hegde@Sun.COM }
37011600SVikram.Hegde@Sun.COM
37111600SVikram.Hegde@Sun.COM /*
37211600SVikram.Hegde@Sun.COM * get the register value
37311600SVikram.Hegde@Sun.COM */
37411600SVikram.Hegde@Sun.COM immu->immu_regs_cap = get_reg64(immu, IMMU_REG_CAP);
37511600SVikram.Hegde@Sun.COM immu->immu_regs_excap = get_reg64(immu, IMMU_REG_EXCAP);
37611600SVikram.Hegde@Sun.COM
37711600SVikram.Hegde@Sun.COM /*
37811600SVikram.Hegde@Sun.COM * if the hardware access is non-coherent, we need clflush
37911600SVikram.Hegde@Sun.COM */
38011600SVikram.Hegde@Sun.COM if (IMMU_ECAP_GET_C(immu->immu_regs_excap)) {
38111600SVikram.Hegde@Sun.COM immu->immu_dvma_coherent = B_TRUE;
38211600SVikram.Hegde@Sun.COM } else {
38311600SVikram.Hegde@Sun.COM immu->immu_dvma_coherent = B_FALSE;
38412826Skuriakose.kuruvilla@oracle.com if (!is_x86_feature(x86_featureset, X86FSET_CLFSH)) {
38511600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL,
38611600SVikram.Hegde@Sun.COM "immu unit %s can't be enabled due to "
38711600SVikram.Hegde@Sun.COM "missing clflush functionality", immu->immu_name);
38811600SVikram.Hegde@Sun.COM ddi_regs_map_free(&(immu->immu_regs_handle));
38911600SVikram.Hegde@Sun.COM mutex_destroy(&(immu->immu_regs_lock));
39011600SVikram.Hegde@Sun.COM return (DDI_FAILURE);
39111600SVikram.Hegde@Sun.COM }
39211600SVikram.Hegde@Sun.COM }
39311600SVikram.Hegde@Sun.COM
39411658SVikram.Hegde@Sun.COM /* Setup SNP and TM reserved fields */
39511658SVikram.Hegde@Sun.COM immu->immu_SNP_reserved = immu_regs_is_SNP_reserved(immu);
39611658SVikram.Hegde@Sun.COM immu->immu_TM_reserved = immu_regs_is_TM_reserved(immu);
39711658SVikram.Hegde@Sun.COM
398*13050Sfrank.van.der.linden@oracle.com if (IMMU_ECAP_GET_CH(immu->immu_regs_excap) && immu_use_tm)
399*13050Sfrank.van.der.linden@oracle.com immu->immu_ptemask = PDTE_MASK_TM;
400*13050Sfrank.van.der.linden@oracle.com else
401*13050Sfrank.van.der.linden@oracle.com immu->immu_ptemask = 0;
402*13050Sfrank.van.der.linden@oracle.com
40311600SVikram.Hegde@Sun.COM /*
40411600SVikram.Hegde@Sun.COM * Check for Mobile 4 series chipset
40511600SVikram.Hegde@Sun.COM */
40611600SVikram.Hegde@Sun.COM if (immu_quirk_mobile4 == B_TRUE &&
40711600SVikram.Hegde@Sun.COM !IMMU_CAP_GET_RWBF(immu->immu_regs_cap)) {
40811600SVikram.Hegde@Sun.COM ddi_err(DER_LOG, NULL,
40911600SVikram.Hegde@Sun.COM "IMMU: Mobile 4 chipset quirk detected. "
41011600SVikram.Hegde@Sun.COM "Force-setting RWBF");
41111600SVikram.Hegde@Sun.COM IMMU_CAP_SET_RWBF(immu->immu_regs_cap);
41211600SVikram.Hegde@Sun.COM }
41311600SVikram.Hegde@Sun.COM
41411600SVikram.Hegde@Sun.COM /*
41511600SVikram.Hegde@Sun.COM * retrieve the maximum number of domains
41611600SVikram.Hegde@Sun.COM */
41711600SVikram.Hegde@Sun.COM immu->immu_max_domains = IMMU_CAP_ND(immu->immu_regs_cap);
41811600SVikram.Hegde@Sun.COM
41911600SVikram.Hegde@Sun.COM /*
42011600SVikram.Hegde@Sun.COM * calculate the agaw
42111600SVikram.Hegde@Sun.COM */
42211600SVikram.Hegde@Sun.COM if (set_agaw(immu) != DDI_SUCCESS) {
42311600SVikram.Hegde@Sun.COM ddi_regs_map_free(&(immu->immu_regs_handle));
42411600SVikram.Hegde@Sun.COM mutex_destroy(&(immu->immu_regs_lock));
42511600SVikram.Hegde@Sun.COM return (DDI_FAILURE);
42611600SVikram.Hegde@Sun.COM }
42711600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval = 0;
42811600SVikram.Hegde@Sun.COM
42912513Sfrank.van.der.linden@oracle.com immu->immu_flushops = &immu_regs_flushops;
43012513Sfrank.van.der.linden@oracle.com
43111600SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
43211600SVikram.Hegde@Sun.COM }
43311600SVikram.Hegde@Sun.COM
43411600SVikram.Hegde@Sun.COM /* ############### Functions exported ################## */
43511600SVikram.Hegde@Sun.COM
43611600SVikram.Hegde@Sun.COM /*
43711600SVikram.Hegde@Sun.COM * immu_regs_setup()
43811600SVikram.Hegde@Sun.COM * Setup mappings to a IMMU unit's registers
43911600SVikram.Hegde@Sun.COM * so that they can be read/written
44011600SVikram.Hegde@Sun.COM */
44111600SVikram.Hegde@Sun.COM void
immu_regs_setup(list_t * listp)44211600SVikram.Hegde@Sun.COM immu_regs_setup(list_t *listp)
44311600SVikram.Hegde@Sun.COM {
44411600SVikram.Hegde@Sun.COM int i;
44511600SVikram.Hegde@Sun.COM immu_t *immu;
44611600SVikram.Hegde@Sun.COM
44711600SVikram.Hegde@Sun.COM for (i = 0; i < IMMU_MAXSEG; i++) {
44811600SVikram.Hegde@Sun.COM immu = list_head(listp);
44911600SVikram.Hegde@Sun.COM for (; immu; immu = list_next(listp, immu)) {
45011600SVikram.Hegde@Sun.COM /* do your best, continue on error */
45111600SVikram.Hegde@Sun.COM if (setup_regs(immu) != DDI_SUCCESS) {
45211600SVikram.Hegde@Sun.COM immu->immu_regs_setup = B_FALSE;
45311600SVikram.Hegde@Sun.COM } else {
45411600SVikram.Hegde@Sun.COM immu->immu_regs_setup = B_TRUE;
45511600SVikram.Hegde@Sun.COM }
45611600SVikram.Hegde@Sun.COM }
45711600SVikram.Hegde@Sun.COM }
45811600SVikram.Hegde@Sun.COM }
45911600SVikram.Hegde@Sun.COM
46011600SVikram.Hegde@Sun.COM /*
46111600SVikram.Hegde@Sun.COM * immu_regs_map()
46211600SVikram.Hegde@Sun.COM */
46311600SVikram.Hegde@Sun.COM int
immu_regs_resume(immu_t * immu)46411600SVikram.Hegde@Sun.COM immu_regs_resume(immu_t *immu)
46511600SVikram.Hegde@Sun.COM {
46611600SVikram.Hegde@Sun.COM int error;
46711600SVikram.Hegde@Sun.COM
46811600SVikram.Hegde@Sun.COM /*
46911600SVikram.Hegde@Sun.COM * remap the register address space
47011600SVikram.Hegde@Sun.COM */
47111600SVikram.Hegde@Sun.COM error = ddi_regs_map_setup(immu->immu_dip, 0,
47211600SVikram.Hegde@Sun.COM (caddr_t *)&(immu->immu_regs_addr), (offset_t)0,
47311600SVikram.Hegde@Sun.COM (offset_t)IMMU_REGSZ, &immu_regs_attr,
47411600SVikram.Hegde@Sun.COM &(immu->immu_regs_handle));
47511600SVikram.Hegde@Sun.COM if (error != DDI_SUCCESS) {
47611600SVikram.Hegde@Sun.COM return (DDI_FAILURE);
47711600SVikram.Hegde@Sun.COM }
47811600SVikram.Hegde@Sun.COM
47911600SVikram.Hegde@Sun.COM immu_regs_set_root_table(immu);
48011600SVikram.Hegde@Sun.COM
48111600SVikram.Hegde@Sun.COM immu_regs_intr_enable(immu, immu->immu_regs_intr_msi_addr,
48211600SVikram.Hegde@Sun.COM immu->immu_regs_intr_msi_data, immu->immu_regs_intr_uaddr);
48311600SVikram.Hegde@Sun.COM
48411600SVikram.Hegde@Sun.COM (void) immu_intr_handler(immu);
48511600SVikram.Hegde@Sun.COM
48611600SVikram.Hegde@Sun.COM immu_regs_intrmap_enable(immu, immu->immu_intrmap_irta_reg);
48711600SVikram.Hegde@Sun.COM
48811600SVikram.Hegde@Sun.COM immu_regs_qinv_enable(immu, immu->immu_qinv_reg_value);
48911600SVikram.Hegde@Sun.COM
49011600SVikram.Hegde@Sun.COM
49111600SVikram.Hegde@Sun.COM return (error);
49211600SVikram.Hegde@Sun.COM }
49311600SVikram.Hegde@Sun.COM
49411600SVikram.Hegde@Sun.COM /*
49511600SVikram.Hegde@Sun.COM * immu_regs_suspend()
49611600SVikram.Hegde@Sun.COM */
49711600SVikram.Hegde@Sun.COM void
immu_regs_suspend(immu_t * immu)49811600SVikram.Hegde@Sun.COM immu_regs_suspend(immu_t *immu)
49911600SVikram.Hegde@Sun.COM {
50011600SVikram.Hegde@Sun.COM
50111600SVikram.Hegde@Sun.COM immu->immu_intrmap_running = B_FALSE;
50211600SVikram.Hegde@Sun.COM
50311600SVikram.Hegde@Sun.COM /* Finally, unmap the regs */
50411600SVikram.Hegde@Sun.COM ddi_regs_map_free(&(immu->immu_regs_handle));
50511600SVikram.Hegde@Sun.COM }
50611600SVikram.Hegde@Sun.COM
50711600SVikram.Hegde@Sun.COM /*
50811600SVikram.Hegde@Sun.COM * immu_regs_startup()
50911600SVikram.Hegde@Sun.COM * set a IMMU unit's registers to startup the unit
51011600SVikram.Hegde@Sun.COM */
51111600SVikram.Hegde@Sun.COM void
immu_regs_startup(immu_t * immu)51211600SVikram.Hegde@Sun.COM immu_regs_startup(immu_t *immu)
51311600SVikram.Hegde@Sun.COM {
51411600SVikram.Hegde@Sun.COM uint32_t status;
51511600SVikram.Hegde@Sun.COM
51611600SVikram.Hegde@Sun.COM if (immu->immu_regs_setup == B_FALSE) {
51711600SVikram.Hegde@Sun.COM return;
51811600SVikram.Hegde@Sun.COM }
51911600SVikram.Hegde@Sun.COM
52011600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
52111600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_GLOBAL_CMD,
52211600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval | IMMU_GCMD_TE);
52311600SVikram.Hegde@Sun.COM wait_completion(immu, IMMU_REG_GLOBAL_STS,
52411600SVikram.Hegde@Sun.COM get_reg32, (status & IMMU_GSTS_TES), status);
52511600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval |= IMMU_GCMD_TE;
52611600SVikram.Hegde@Sun.COM immu->immu_regs_running = B_TRUE;
52711600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
52811600SVikram.Hegde@Sun.COM
529*13050Sfrank.van.der.linden@oracle.com ddi_err(DER_NOTE, NULL, "%s running", immu->immu_name);
53011600SVikram.Hegde@Sun.COM }
53111600SVikram.Hegde@Sun.COM
53211600SVikram.Hegde@Sun.COM /*
53311600SVikram.Hegde@Sun.COM * immu_regs_shutdown()
53411600SVikram.Hegde@Sun.COM * shutdown a unit
53511600SVikram.Hegde@Sun.COM */
53611600SVikram.Hegde@Sun.COM void
immu_regs_shutdown(immu_t * immu)53711600SVikram.Hegde@Sun.COM immu_regs_shutdown(immu_t *immu)
53811600SVikram.Hegde@Sun.COM {
53911600SVikram.Hegde@Sun.COM uint32_t status;
54011600SVikram.Hegde@Sun.COM
54111600SVikram.Hegde@Sun.COM if (immu->immu_regs_running == B_FALSE) {
54211600SVikram.Hegde@Sun.COM return;
54311600SVikram.Hegde@Sun.COM }
54411600SVikram.Hegde@Sun.COM
54511600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
54611600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval &= ~IMMU_GCMD_TE;
54711600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_GLOBAL_CMD,
54811600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval);
54911600SVikram.Hegde@Sun.COM wait_completion(immu, IMMU_REG_GLOBAL_STS,
55011600SVikram.Hegde@Sun.COM get_reg32, !(status & IMMU_GSTS_TES), status);
55111600SVikram.Hegde@Sun.COM immu->immu_regs_running = B_FALSE;
55211600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
55311600SVikram.Hegde@Sun.COM
55411600SVikram.Hegde@Sun.COM ddi_err(DER_NOTE, NULL, "IOMMU %s stopped", immu->immu_name);
55511600SVikram.Hegde@Sun.COM }
55611600SVikram.Hegde@Sun.COM
55711600SVikram.Hegde@Sun.COM /*
55811600SVikram.Hegde@Sun.COM * immu_regs_intr()
55911600SVikram.Hegde@Sun.COM * Set a IMMU unit regs to setup a IMMU unit's
56011600SVikram.Hegde@Sun.COM * interrupt handler
56111600SVikram.Hegde@Sun.COM */
56211600SVikram.Hegde@Sun.COM void
immu_regs_intr_enable(immu_t * immu,uint32_t msi_addr,uint32_t msi_data,uint32_t uaddr)56311600SVikram.Hegde@Sun.COM immu_regs_intr_enable(immu_t *immu, uint32_t msi_addr, uint32_t msi_data,
56411600SVikram.Hegde@Sun.COM uint32_t uaddr)
56511600SVikram.Hegde@Sun.COM {
56611600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
56711600SVikram.Hegde@Sun.COM immu->immu_regs_intr_msi_addr = msi_addr;
56811600SVikram.Hegde@Sun.COM immu->immu_regs_intr_uaddr = uaddr;
56911600SVikram.Hegde@Sun.COM immu->immu_regs_intr_msi_data = msi_data;
57011600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_FEVNT_ADDR, msi_addr);
57111600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_FEVNT_UADDR, uaddr);
57211600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_FEVNT_DATA, msi_data);
57311600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_FEVNT_CON, 0);
57411600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
57511600SVikram.Hegde@Sun.COM }
57611600SVikram.Hegde@Sun.COM
57711600SVikram.Hegde@Sun.COM /*
57811600SVikram.Hegde@Sun.COM * immu_regs_passthru_supported()
57911600SVikram.Hegde@Sun.COM * Returns B_TRUE ifi passthru is supported
58011600SVikram.Hegde@Sun.COM */
58111600SVikram.Hegde@Sun.COM boolean_t
immu_regs_passthru_supported(immu_t * immu)58211600SVikram.Hegde@Sun.COM immu_regs_passthru_supported(immu_t *immu)
58311600SVikram.Hegde@Sun.COM {
58411600SVikram.Hegde@Sun.COM if (IMMU_ECAP_GET_PT(immu->immu_regs_excap)) {
58511600SVikram.Hegde@Sun.COM return (B_TRUE);
58611600SVikram.Hegde@Sun.COM }
58711600SVikram.Hegde@Sun.COM
58811600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "Passthru not supported");
58911600SVikram.Hegde@Sun.COM return (B_FALSE);
59011600SVikram.Hegde@Sun.COM }
59111600SVikram.Hegde@Sun.COM
59211600SVikram.Hegde@Sun.COM /*
59311600SVikram.Hegde@Sun.COM * immu_regs_is_TM_reserved()
59411600SVikram.Hegde@Sun.COM * Returns B_TRUE if TM field is reserved
59511600SVikram.Hegde@Sun.COM */
59611600SVikram.Hegde@Sun.COM boolean_t
immu_regs_is_TM_reserved(immu_t * immu)59711600SVikram.Hegde@Sun.COM immu_regs_is_TM_reserved(immu_t *immu)
59811600SVikram.Hegde@Sun.COM {
59911600SVikram.Hegde@Sun.COM if (IMMU_ECAP_GET_DI(immu->immu_regs_excap) ||
60011600SVikram.Hegde@Sun.COM IMMU_ECAP_GET_CH(immu->immu_regs_excap)) {
60111600SVikram.Hegde@Sun.COM return (B_FALSE);
60211600SVikram.Hegde@Sun.COM }
60311600SVikram.Hegde@Sun.COM return (B_TRUE);
60411600SVikram.Hegde@Sun.COM }
60511600SVikram.Hegde@Sun.COM
60611600SVikram.Hegde@Sun.COM /*
60711600SVikram.Hegde@Sun.COM * immu_regs_is_SNP_reserved()
60811600SVikram.Hegde@Sun.COM * Returns B_TRUE if SNP field is reserved
60911600SVikram.Hegde@Sun.COM */
61011600SVikram.Hegde@Sun.COM boolean_t
immu_regs_is_SNP_reserved(immu_t * immu)61111600SVikram.Hegde@Sun.COM immu_regs_is_SNP_reserved(immu_t *immu)
61211600SVikram.Hegde@Sun.COM {
61311600SVikram.Hegde@Sun.COM
61411600SVikram.Hegde@Sun.COM return (IMMU_ECAP_GET_SC(immu->immu_regs_excap) ? B_FALSE : B_TRUE);
61511600SVikram.Hegde@Sun.COM }
61611600SVikram.Hegde@Sun.COM
61711600SVikram.Hegde@Sun.COM /*
61811600SVikram.Hegde@Sun.COM * immu_regs_wbf_flush()
61911600SVikram.Hegde@Sun.COM * If required and supported, write to IMMU
62011600SVikram.Hegde@Sun.COM * unit's regs to flush DMA write buffer(s)
62111600SVikram.Hegde@Sun.COM */
62211600SVikram.Hegde@Sun.COM void
immu_regs_wbf_flush(immu_t * immu)62311600SVikram.Hegde@Sun.COM immu_regs_wbf_flush(immu_t *immu)
62411600SVikram.Hegde@Sun.COM {
62511600SVikram.Hegde@Sun.COM uint32_t status;
62611600SVikram.Hegde@Sun.COM
62711600SVikram.Hegde@Sun.COM if (!IMMU_CAP_GET_RWBF(immu->immu_regs_cap)) {
62811600SVikram.Hegde@Sun.COM return;
62911600SVikram.Hegde@Sun.COM }
63011600SVikram.Hegde@Sun.COM
63111600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
63211600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_GLOBAL_CMD,
63311600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval | IMMU_GCMD_WBF);
63411600SVikram.Hegde@Sun.COM wait_completion(immu, IMMU_REG_GLOBAL_STS,
63511600SVikram.Hegde@Sun.COM get_reg32, (!(status & IMMU_GSTS_WBFS)), status);
63611600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
63711600SVikram.Hegde@Sun.COM }
63811600SVikram.Hegde@Sun.COM
63911600SVikram.Hegde@Sun.COM /*
64011600SVikram.Hegde@Sun.COM * immu_regs_cpu_flush()
64111600SVikram.Hegde@Sun.COM * flush the cpu cache line after CPU memory writes, so
64211600SVikram.Hegde@Sun.COM * IOMMU can see the writes
64311600SVikram.Hegde@Sun.COM */
64411600SVikram.Hegde@Sun.COM void
immu_regs_cpu_flush(immu_t * immu,caddr_t addr,uint_t size)64511600SVikram.Hegde@Sun.COM immu_regs_cpu_flush(immu_t *immu, caddr_t addr, uint_t size)
64611600SVikram.Hegde@Sun.COM {
647*13050Sfrank.van.der.linden@oracle.com uintptr_t startline, endline;
64811600SVikram.Hegde@Sun.COM
64911600SVikram.Hegde@Sun.COM if (immu->immu_dvma_coherent == B_TRUE)
65011600SVikram.Hegde@Sun.COM return;
65111600SVikram.Hegde@Sun.COM
652*13050Sfrank.van.der.linden@oracle.com startline = (uintptr_t)addr & ~(uintptr_t)(x86_clflush_size - 1);
653*13050Sfrank.van.der.linden@oracle.com endline = ((uintptr_t)addr + size - 1) &
654*13050Sfrank.van.der.linden@oracle.com ~(uintptr_t)(x86_clflush_size - 1);
655*13050Sfrank.van.der.linden@oracle.com while (startline <= endline) {
656*13050Sfrank.van.der.linden@oracle.com clflush_insn((caddr_t)startline);
657*13050Sfrank.van.der.linden@oracle.com startline += x86_clflush_size;
65811600SVikram.Hegde@Sun.COM }
65911600SVikram.Hegde@Sun.COM
66011600SVikram.Hegde@Sun.COM mfence_insn();
66111600SVikram.Hegde@Sun.COM }
66211600SVikram.Hegde@Sun.COM
66311600SVikram.Hegde@Sun.COM /*
66411600SVikram.Hegde@Sun.COM * immu_regs_context_flush()
66511600SVikram.Hegde@Sun.COM * flush the context cache
66611600SVikram.Hegde@Sun.COM */
66712513Sfrank.van.der.linden@oracle.com static void
context_flush(immu_t * immu,uint8_t function_mask,uint16_t sid,uint_t did,immu_context_inv_t type)66812513Sfrank.van.der.linden@oracle.com context_flush(immu_t *immu, uint8_t function_mask,
66911600SVikram.Hegde@Sun.COM uint16_t sid, uint_t did, immu_context_inv_t type)
67011600SVikram.Hegde@Sun.COM {
67111600SVikram.Hegde@Sun.COM uint64_t command = 0;
67211600SVikram.Hegde@Sun.COM uint64_t status;
67311600SVikram.Hegde@Sun.COM
67411600SVikram.Hegde@Sun.COM /*
67511600SVikram.Hegde@Sun.COM * define the command
67611600SVikram.Hegde@Sun.COM */
67711600SVikram.Hegde@Sun.COM switch (type) {
67811600SVikram.Hegde@Sun.COM case CONTEXT_FSI:
67911600SVikram.Hegde@Sun.COM command |= CCMD_INV_ICC | CCMD_INV_DEVICE
68011600SVikram.Hegde@Sun.COM | CCMD_INV_DID(did)
68111600SVikram.Hegde@Sun.COM | CCMD_INV_SID(sid) | CCMD_INV_FM(function_mask);
68211600SVikram.Hegde@Sun.COM break;
68311600SVikram.Hegde@Sun.COM case CONTEXT_DSI:
68411600SVikram.Hegde@Sun.COM command |= CCMD_INV_ICC | CCMD_INV_DOMAIN
68511600SVikram.Hegde@Sun.COM | CCMD_INV_DID(did);
68611600SVikram.Hegde@Sun.COM break;
68711600SVikram.Hegde@Sun.COM case CONTEXT_GLOBAL:
68811600SVikram.Hegde@Sun.COM command |= CCMD_INV_ICC | CCMD_INV_GLOBAL;
68911600SVikram.Hegde@Sun.COM break;
69011600SVikram.Hegde@Sun.COM default:
69111600SVikram.Hegde@Sun.COM ddi_err(DER_PANIC, NULL,
69211600SVikram.Hegde@Sun.COM "%s: incorrect context cache flush type",
69311600SVikram.Hegde@Sun.COM immu->immu_name);
69411600SVikram.Hegde@Sun.COM /*NOTREACHED*/
69511600SVikram.Hegde@Sun.COM }
69611600SVikram.Hegde@Sun.COM
69711600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
69811600SVikram.Hegde@Sun.COM put_reg64(immu, IMMU_REG_CONTEXT_CMD, command);
69911600SVikram.Hegde@Sun.COM wait_completion(immu, IMMU_REG_CONTEXT_CMD, get_reg64,
70011600SVikram.Hegde@Sun.COM (!(status & CCMD_INV_ICC)), status);
70111600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
70211600SVikram.Hegde@Sun.COM }
70311600SVikram.Hegde@Sun.COM
704*13050Sfrank.van.der.linden@oracle.com /*ARGSUSED*/
70511600SVikram.Hegde@Sun.COM void
immu_regs_context_fsi(immu_t * immu,uint8_t function_mask,uint16_t source_id,uint_t domain_id,immu_inv_wait_t * iwp)70612513Sfrank.van.der.linden@oracle.com immu_regs_context_fsi(immu_t *immu, uint8_t function_mask,
707*13050Sfrank.van.der.linden@oracle.com uint16_t source_id, uint_t domain_id, immu_inv_wait_t *iwp)
70812513Sfrank.van.der.linden@oracle.com {
70912513Sfrank.van.der.linden@oracle.com context_flush(immu, function_mask, source_id, domain_id, CONTEXT_FSI);
71012513Sfrank.van.der.linden@oracle.com }
71112513Sfrank.van.der.linden@oracle.com
712*13050Sfrank.van.der.linden@oracle.com /*ARGSUSED*/
71312513Sfrank.van.der.linden@oracle.com void
immu_regs_context_dsi(immu_t * immu,uint_t domain_id,immu_inv_wait_t * iwp)714*13050Sfrank.van.der.linden@oracle.com immu_regs_context_dsi(immu_t *immu, uint_t domain_id, immu_inv_wait_t *iwp)
71512513Sfrank.van.der.linden@oracle.com {
71612513Sfrank.van.der.linden@oracle.com context_flush(immu, 0, 0, domain_id, CONTEXT_DSI);
71712513Sfrank.van.der.linden@oracle.com }
71812513Sfrank.van.der.linden@oracle.com
719*13050Sfrank.van.der.linden@oracle.com /*ARGSUSED*/
72012513Sfrank.van.der.linden@oracle.com void
immu_regs_context_gbl(immu_t * immu,immu_inv_wait_t * iwp)721*13050Sfrank.van.der.linden@oracle.com immu_regs_context_gbl(immu_t *immu, immu_inv_wait_t *iwp)
72212513Sfrank.van.der.linden@oracle.com {
72312513Sfrank.van.der.linden@oracle.com context_flush(immu, 0, 0, 0, CONTEXT_GLOBAL);
72412513Sfrank.van.der.linden@oracle.com }
72512513Sfrank.van.der.linden@oracle.com
726*13050Sfrank.van.der.linden@oracle.com /*
727*13050Sfrank.van.der.linden@oracle.com * Nothing to do, all register operations are synchronous.
728*13050Sfrank.van.der.linden@oracle.com */
729*13050Sfrank.van.der.linden@oracle.com /*ARGSUSED*/
730*13050Sfrank.van.der.linden@oracle.com static void
immu_regs_inv_wait(immu_inv_wait_t * iwp)731*13050Sfrank.van.der.linden@oracle.com immu_regs_inv_wait(immu_inv_wait_t *iwp)
732*13050Sfrank.van.der.linden@oracle.com {
733*13050Sfrank.van.der.linden@oracle.com }
734*13050Sfrank.van.der.linden@oracle.com
73512513Sfrank.van.der.linden@oracle.com void
immu_regs_set_root_table(immu_t * immu)73611600SVikram.Hegde@Sun.COM immu_regs_set_root_table(immu_t *immu)
73711600SVikram.Hegde@Sun.COM {
73811600SVikram.Hegde@Sun.COM uint32_t status;
73911600SVikram.Hegde@Sun.COM
74011600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
74111600SVikram.Hegde@Sun.COM put_reg64(immu, IMMU_REG_ROOTENTRY,
74211600SVikram.Hegde@Sun.COM immu->immu_ctx_root->hwpg_paddr);
74311600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_GLOBAL_CMD,
74411600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval | IMMU_GCMD_SRTP);
74511600SVikram.Hegde@Sun.COM wait_completion(immu, IMMU_REG_GLOBAL_STS,
74611600SVikram.Hegde@Sun.COM get_reg32, (status & IMMU_GSTS_RTPS), status);
74711600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
74811600SVikram.Hegde@Sun.COM }
74911600SVikram.Hegde@Sun.COM
75011600SVikram.Hegde@Sun.COM
75111600SVikram.Hegde@Sun.COM /* enable queued invalidation interface */
75211600SVikram.Hegde@Sun.COM void
immu_regs_qinv_enable(immu_t * immu,uint64_t qinv_reg_value)75311600SVikram.Hegde@Sun.COM immu_regs_qinv_enable(immu_t *immu, uint64_t qinv_reg_value)
75411600SVikram.Hegde@Sun.COM {
75511600SVikram.Hegde@Sun.COM uint32_t status;
75611600SVikram.Hegde@Sun.COM
75711600SVikram.Hegde@Sun.COM if (immu_qinv_enable == B_FALSE)
75811600SVikram.Hegde@Sun.COM return;
75911600SVikram.Hegde@Sun.COM
76011600SVikram.Hegde@Sun.COM mutex_enter(&immu->immu_regs_lock);
76111600SVikram.Hegde@Sun.COM immu->immu_qinv_reg_value = qinv_reg_value;
76211600SVikram.Hegde@Sun.COM /* Initialize the Invalidation Queue Tail register to zero */
76311600SVikram.Hegde@Sun.COM put_reg64(immu, IMMU_REG_INVAL_QT, 0);
76411600SVikram.Hegde@Sun.COM
76511600SVikram.Hegde@Sun.COM /* set invalidation queue base address register */
76611600SVikram.Hegde@Sun.COM put_reg64(immu, IMMU_REG_INVAL_QAR, qinv_reg_value);
76711600SVikram.Hegde@Sun.COM
76811600SVikram.Hegde@Sun.COM /* enable queued invalidation interface */
76911600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_GLOBAL_CMD,
77011600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval | IMMU_GCMD_QIE);
77111600SVikram.Hegde@Sun.COM wait_completion(immu, IMMU_REG_GLOBAL_STS,
77211600SVikram.Hegde@Sun.COM get_reg32, (status & IMMU_GSTS_QIES), status);
77311600SVikram.Hegde@Sun.COM mutex_exit(&immu->immu_regs_lock);
77411600SVikram.Hegde@Sun.COM
77511600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval |= IMMU_GCMD_QIE;
77611600SVikram.Hegde@Sun.COM immu->immu_qinv_running = B_TRUE;
77711600SVikram.Hegde@Sun.COM
77811600SVikram.Hegde@Sun.COM }
77911600SVikram.Hegde@Sun.COM
78011600SVikram.Hegde@Sun.COM /* enable interrupt remapping hardware unit */
78111600SVikram.Hegde@Sun.COM void
immu_regs_intrmap_enable(immu_t * immu,uint64_t irta_reg)78211600SVikram.Hegde@Sun.COM immu_regs_intrmap_enable(immu_t *immu, uint64_t irta_reg)
78311600SVikram.Hegde@Sun.COM {
78411600SVikram.Hegde@Sun.COM uint32_t status;
78511600SVikram.Hegde@Sun.COM
78611600SVikram.Hegde@Sun.COM if (immu_intrmap_enable == B_FALSE)
78711600SVikram.Hegde@Sun.COM return;
78811600SVikram.Hegde@Sun.COM
78911600SVikram.Hegde@Sun.COM /* set interrupt remap table pointer */
79011600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
79111600SVikram.Hegde@Sun.COM immu->immu_intrmap_irta_reg = irta_reg;
79211600SVikram.Hegde@Sun.COM put_reg64(immu, IMMU_REG_IRTAR, irta_reg);
79311600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_GLOBAL_CMD,
79411600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval | IMMU_GCMD_SIRTP);
79511600SVikram.Hegde@Sun.COM wait_completion(immu, IMMU_REG_GLOBAL_STS,
79611600SVikram.Hegde@Sun.COM get_reg32, (status & IMMU_GSTS_IRTPS), status);
79711600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
79811600SVikram.Hegde@Sun.COM
79911600SVikram.Hegde@Sun.COM /* global flush intr entry cache */
800*13050Sfrank.van.der.linden@oracle.com immu_qinv_intr_global(immu, &immu->immu_intrmap_inv_wait);
80111600SVikram.Hegde@Sun.COM
80211600SVikram.Hegde@Sun.COM /* enable interrupt remapping */
80311600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock));
80411600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_GLOBAL_CMD,
80511600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval | IMMU_GCMD_IRE);
80611600SVikram.Hegde@Sun.COM wait_completion(immu, IMMU_REG_GLOBAL_STS,
80711600SVikram.Hegde@Sun.COM get_reg32, (status & IMMU_GSTS_IRES),
80811600SVikram.Hegde@Sun.COM status);
80911600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval |= IMMU_GCMD_IRE;
81011600SVikram.Hegde@Sun.COM
81111600SVikram.Hegde@Sun.COM /* set compatible mode */
81211600SVikram.Hegde@Sun.COM put_reg32(immu, IMMU_REG_GLOBAL_CMD,
81311600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval | IMMU_GCMD_CFI);
81411600SVikram.Hegde@Sun.COM wait_completion(immu, IMMU_REG_GLOBAL_STS,
81511600SVikram.Hegde@Sun.COM get_reg32, (status & IMMU_GSTS_CFIS),
81611600SVikram.Hegde@Sun.COM status);
81711600SVikram.Hegde@Sun.COM immu->immu_regs_cmdval |= IMMU_GCMD_CFI;
81811600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock));
81911600SVikram.Hegde@Sun.COM
82011600SVikram.Hegde@Sun.COM immu->immu_intrmap_running = B_TRUE;
82111600SVikram.Hegde@Sun.COM }
82211600SVikram.Hegde@Sun.COM
82311600SVikram.Hegde@Sun.COM uint64_t
immu_regs_get64(immu_t * immu,uint_t reg)82411600SVikram.Hegde@Sun.COM immu_regs_get64(immu_t *immu, uint_t reg)
82511600SVikram.Hegde@Sun.COM {
82611600SVikram.Hegde@Sun.COM return (get_reg64(immu, reg));
82711600SVikram.Hegde@Sun.COM }
82811600SVikram.Hegde@Sun.COM
82911600SVikram.Hegde@Sun.COM uint32_t
immu_regs_get32(immu_t * immu,uint_t reg)83011600SVikram.Hegde@Sun.COM immu_regs_get32(immu_t *immu, uint_t reg)
83111600SVikram.Hegde@Sun.COM {
83211600SVikram.Hegde@Sun.COM return (get_reg32(immu, reg));
83311600SVikram.Hegde@Sun.COM }
83411600SVikram.Hegde@Sun.COM
83511600SVikram.Hegde@Sun.COM void
immu_regs_put64(immu_t * immu,uint_t reg,uint64_t val)83611600SVikram.Hegde@Sun.COM immu_regs_put64(immu_t *immu, uint_t reg, uint64_t val)
83711600SVikram.Hegde@Sun.COM {
83811600SVikram.Hegde@Sun.COM put_reg64(immu, reg, val);
83911600SVikram.Hegde@Sun.COM }
84011600SVikram.Hegde@Sun.COM
84111600SVikram.Hegde@Sun.COM void
immu_regs_put32(immu_t * immu,uint_t reg,uint32_t val)84211600SVikram.Hegde@Sun.COM immu_regs_put32(immu_t *immu, uint_t reg, uint32_t val)
84311600SVikram.Hegde@Sun.COM {
84411600SVikram.Hegde@Sun.COM put_reg32(immu, reg, val);
84511600SVikram.Hegde@Sun.COM }
846