3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * CDDL HEADER START
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * The contents of this file are subject to the terms of the
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Common Development and Distribution License (the "License").
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * You may not use this file except in compliance with the License.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * or http://www.opensolaris.org/os/licensing.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * See the License for the specific language governing permissions
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * and limitations under the License.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * When distributing Covered Code, include this CDDL HEADER in each
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * If applicable, add the following below this CDDL HEADER, with the
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * fields enclosed by brackets "[]" replaced with your own identifying
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * information: Portions Copyright [yyyy] [name of copyright owner]
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * CDDL HEADER END
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
9e986f0e5fb5e5ac09af90cd3b63f7836d983f9dFrank Van Der Linden * Portions Copyright (c) 2010, Oracle and/or its affiliates.
9e986f0e5fb5e5ac09af90cd3b63f7836d983f9dFrank Van Der Linden * All rights reserved.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Copyright (c) 2009, Intel Corporation.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * All rights reserved.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
cd21e7c548ae2a3b5e522244bf798f2a6b4ba02dGarrett D'Amore/*
cd21e7c548ae2a3b5e522244bf798f2a6b4ba02dGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
cd21e7c548ae2a3b5e522244bf798f2a6b4ba02dGarrett D'Amore */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * DVMA code
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * This file contains Intel IOMMU code that deals with DVMA
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * i.e. DMA remapping.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#include <sys/sysmacros.h>
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#include <sys/pcie.h>
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#include <sys/pci_cfgspace.h>
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#include <vm/hat_i86.h>
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#include <sys/memlist.h>
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#include <sys/acpi/acpi.h>
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#include <sys/acpica.h>
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#include <sys/modhash.h>
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#include <sys/immu.h>
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#include <sys/x86_archext.h>
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#include <sys/archsystm.h>
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#undef TEST
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Macros based on PCI spec
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#define IMMU_PCI_REV2CLASS(r) ((r) >> 8) /* classcode from revid */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#define IMMU_PCI_CLASS2BASE(c) ((c) >> 16) /* baseclass from classcode */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#define IMMU_PCI_CLASS2SUB(c) (((c) >> 8) & 0xff); /* classcode */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#define IMMU_CONTIG_PADDR(d, p) \
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ((d).dck_paddr && ((d).dck_paddr + IMMU_PAGESIZE) == (p))
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdetypedef struct dvma_arg {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_t *dva_immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *dva_rdip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *dva_ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain_t *dva_domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int dva_level;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_flags_t dva_flags;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde list_t *dva_list;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int dva_error;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde} dvma_arg_t;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic domain_t *domain_create(immu_t *immu, dev_info_t *ddip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *rdip, immu_flags_t immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic immu_devi_t *create_immu_devi(dev_info_t *rdip, int bus,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int dev, int func, immu_flags_t immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void destroy_immu_devi(immu_devi_t *immu_devi);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic boolean_t dvma_map(domain_t *domain, uint64_t sdvma,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t nvpages, immu_dcookie_t *dcookies, int dcount, dev_info_t *rdip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_flags_t immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde/* Extern globals */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdeextern struct memlist *phys_install;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * iommulib interface functions.
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int immu_probe(iommulib_handle_t unitp, dev_info_t *dip);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int immu_allochdl(iommulib_handle_t handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *dma_handlep);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int immu_freehdl(iommulib_handle_t handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int immu_bindhdl(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle, struct ddi_dma_req *dma_req,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_dma_cookie_t *cookiep, uint_t *ccountp);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int immu_unbindhdl(iommulib_handle_t handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int immu_sync(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle, off_t off, size_t len,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint_t cachefl);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int immu_win(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle, uint_t win,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int immu_mapobject(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden struct ddi_dma_req *dmareq, ddi_dma_obj_t *dmao);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int immu_unmapobject(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* static Globals */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Used to setup DMA objects (memory regions)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * for DMA reads by IOMMU units
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic ddi_dma_attr_t immu_dma_attr = {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde DMA_ATTR_V0,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 0U,
d2256d265bf2bcad0d811b81411de3802a4b97c6Frank Van Der Linden 0xffffffffffffffffULL,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 0xffffffffU,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde MMU_PAGESIZE, /* MMU page aligned */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 0x1,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 0x1,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 0xffffffffU,
d2256d265bf2bcad0d811b81411de3802a4b97c6Frank Van Der Linden 0xffffffffffffffffULL,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 1,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 4,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 0
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde};
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic ddi_device_acc_attr_t immu_acc_attr = {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde DDI_DEVICE_ATTR_V0,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde DDI_NEVERSWAP_ACC,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde DDI_STRICTORDER_ACC
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde};
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstruct iommulib_ops immulib_ops = {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden IOMMU_OPS_VERSION,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden INTEL_IOMMU,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "Intel IOMMU",
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden NULL,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_probe,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_allochdl,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_freehdl,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_bindhdl,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_unbindhdl,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_sync,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_win,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_mapobject,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_unmapobject,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden};
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * Fake physical address range used to set up initial prealloc mappings.
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * This memory is never actually accessed. It is mapped read-only,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * and is overwritten as soon as the first DMA bind operation is
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * performed. Since 0 is a special case, just start at the 2nd
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * physical page.
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic immu_dcookie_t immu_precookie = { MMU_PAGESIZE, IMMU_NPREPTES };
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* globals private to this file */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic kmutex_t immu_domain_lock;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic list_t immu_unity_domain_list;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic list_t immu_xlate_domain_list;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* structure used to store idx into each level of the page tables */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdetypedef struct xlate {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int xlt_level;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint_t xlt_idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *xlt_pgtable;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde} xlate_t;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* 0 is reserved by Vt-d spec. Solaris reserves 1 */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#define IMMU_UNITY_DID 1
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic mod_hash_t *bdf_domain_hash;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenint immu_use_alh;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenint immu_use_tm;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic domain_t *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdebdf_domain_lookup(immu_devi_t *immu_devi)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain_t *domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int16_t seg = immu_devi->imd_seg;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int16_t bus = immu_devi->imd_bus;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int16_t devfunc = immu_devi->imd_devfunc;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uintptr_t bdf = (seg << 16 | bus << 8 | devfunc);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (seg < 0 || bus < 0 || devfunc < 0) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (mod_hash_find(bdf_domain_hash,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (void *)bdf, (void *)&domain) == 0) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(domain->dom_did > 0);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdebdf_domain_insert(immu_devi_t *immu_devi, domain_t *domain)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int16_t seg = immu_devi->imd_seg;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int16_t bus = immu_devi->imd_bus;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int16_t devfunc = immu_devi->imd_devfunc;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uintptr_t bdf = (seg << 16 | bus << 8 | devfunc);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (seg < 0 || bus < 0 || devfunc < 0) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void) mod_hash_insert(bdf_domain_hash, (void *)bdf, (void *)domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic int
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdematch_lpc(dev_info_t *pdip, void *arg)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvma_arg_t *dvap = (dvma_arg_t *)arg;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (list_is_empty(dvap->dva_list)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_TERMINATE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = list_head(dvap->dva_list);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde for (; immu_devi; immu_devi = list_next(dvap->dva_list,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi->imd_dip == pdip) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvap->dva_ddip = pdip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvap->dva_error = DDI_SUCCESS;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_TERMINATE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_CONTINUE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeimmu_devi_set_spclist(dev_info_t *dip, immu_t *immu)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde list_t *spclist = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = IMMU_DEVI(dip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi->imd_display == B_TRUE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde spclist = &(immu->immu_dvma_gfx_list);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else if (immu_devi->imd_lpc == B_TRUE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde spclist = &(immu->immu_dvma_lpc_list);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (spclist) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(immu->immu_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde list_insert_head(spclist, immu_devi);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(immu->immu_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Set the immu_devi struct in the immu_devi field of a devinfo node
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeint
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeimmu_devi_set(dev_info_t *dip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int bus, dev, func;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *new_imd;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = immu_devi_get(dip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi != NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_SUCCESS);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde bus = dev = func = -1;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Assume a new immu_devi struct is needed
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (!DEVI_IS_PCI(dip) || acpica_get_bdf(dip, &bus, &dev, &func) != 0) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * No BDF. Set bus = -1 to indicate this.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * We still need to create a immu_devi struct
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * though
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde bus = -1;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev = 0;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde func = 0;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde new_imd = create_immu_devi(dip, bus, dev, func, immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (new_imd == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_WARN, dip, "Failed to create immu_devi "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "structure");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_FAILURE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Check if some other thread allocated a immu_devi while we
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * didn't own the lock.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(DEVI(dip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (IMMU_DEVI(dip) == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde IMMU_DEVI_SET(dip, new_imd);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde destroy_immu_devi(new_imd);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(DEVI(dip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_SUCCESS);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic dev_info_t *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeget_lpc_devinfo(immu_t *immu, dev_info_t *rdip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvma_arg_t dvarg = {0};
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvarg.dva_list = &(immu->immu_dvma_lpc_list);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvarg.dva_rdip = rdip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvarg.dva_error = DDI_FAILURE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_walk_ancestor(rdip, NULL, match_lpc,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde &dvarg, NULL, immu_flags) != DDI_SUCCESS) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "Could not walk ancestors to "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "find lpc_devinfo for ISA device");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (dvarg.dva_error != DDI_SUCCESS || dvarg.dva_ddip == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "Could not find lpc_devinfo for "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "ISA device");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (dvarg.dva_ddip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic dev_info_t *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeget_gfx_devinfo(dev_info_t *rdip)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_t *immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde list_t *list_gfx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * The GFX device may not be on the same iommu unit as "agpgart"
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * so search globally
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu = list_head(&immu_list);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde for (; immu; immu = list_next(&immu_list, immu)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde list_gfx = &(immu->immu_dvma_gfx_list);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (!list_is_empty(list_gfx)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = list_head(list_gfx);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde break;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi == NULL) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_WARN, rdip, "iommu: No GFX device. "
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde "Cannot redirect agpgart");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_LOG, rdip, "iommu: GFX redirect to %s",
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_node_name(immu_devi->imd_dip));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (immu_devi->imd_dip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic immu_flags_t
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdedma_to_immu_flags(struct ddi_dma_req *dmareq)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_flags_t flags = 0;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (dmareq->dmar_fp == DDI_DMA_SLEEP) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde flags |= IMMU_FLAGS_SLEEP;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde flags |= IMMU_FLAGS_NOSLEEP;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#ifdef BUGGY_DRIVERS
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde flags |= (IMMU_FLAGS_READ | IMMU_FLAGS_WRITE);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#else
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Read and write flags need to be reversed.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * DMA_READ means read from device and write
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * to memory. So DMA read means DVMA write.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (dmareq->dmar_flags & DDI_DMA_READ)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde flags |= IMMU_FLAGS_WRITE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (dmareq->dmar_flags & DDI_DMA_WRITE)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde flags |= IMMU_FLAGS_READ;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Some buggy drivers specify neither READ or WRITE
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * For such drivers set both read and write permissions
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if ((dmareq->dmar_flags & (DDI_DMA_READ | DDI_DMA_WRITE)) == 0) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde flags |= (IMMU_FLAGS_READ | IMMU_FLAGS_WRITE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#endif
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdeint
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdepgtable_ctor(void *buf, void *arg, int kmflag)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde size_t actual_size = 0;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *pgtable;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int (*dmafp)(caddr_t);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde caddr_t vaddr;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde void *next;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint_t flags;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_t *immu = arg;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde pgtable = (pgtable_t *)buf;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dmafp = (kmflag & KM_NOSLEEP) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde next = kmem_zalloc(IMMU_PAGESIZE, kmflag);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (next == NULL) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return (-1);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (ddi_dma_alloc_handle(root_devinfo, &immu_dma_attr,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dmafp, NULL, &pgtable->hwpg_dmahdl) != DDI_SUCCESS) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde kmem_free(next, IMMU_PAGESIZE);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return (-1);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden flags = DDI_DMA_CONSISTENT;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (!immu->immu_dvma_coherent)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden flags |= IOMEM_DATA_UC_WR_COMBINE;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (ddi_dma_mem_alloc(pgtable->hwpg_dmahdl, IMMU_PAGESIZE,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden &immu_acc_attr, flags,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dmafp, NULL, &vaddr, &actual_size,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde &pgtable->hwpg_memhdl) != DDI_SUCCESS) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_dma_free_handle(&pgtable->hwpg_dmahdl);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde kmem_free(next, IMMU_PAGESIZE);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return (-1);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Memory allocation failure. Maybe a temporary condition
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * so return error rather than panic, so we can try again
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (actual_size < IMMU_PAGESIZE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_dma_mem_free(&pgtable->hwpg_memhdl);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_dma_free_handle(&pgtable->hwpg_dmahdl);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde kmem_free(next, IMMU_PAGESIZE);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return (-1);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable->hwpg_paddr = pfn_to_pa(hat_getpfnum(kas.a_hat, vaddr));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable->hwpg_vaddr = vaddr;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde pgtable->swpg_next_array = next;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_init(&(pgtable->swpg_rwlock), NULL, RW_DEFAULT, NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return (0);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdevoid
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdepgtable_dtor(void *buf, void *arg)
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde{
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde pgtable_t *pgtable;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde pgtable = (pgtable_t *)buf;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /* destroy will panic if lock is held. */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_destroy(&(pgtable->swpg_rwlock));
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde ddi_dma_mem_free(&pgtable->hwpg_memhdl);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde ddi_dma_free_handle(&pgtable->hwpg_dmahdl);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde kmem_free(pgtable->swpg_next_array, IMMU_PAGESIZE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde/*
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * pgtable_alloc()
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * alloc a IOMMU pgtable structure.
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * This same struct is used for root and context tables as well.
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * This routine allocs the f/ollowing:
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * - a pgtable_t struct
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * - a HW page which holds PTEs/entries which is accesssed by HW
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * so we set up DMA for this page
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * - a SW page which is only for our bookeeping
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * (for example to hold pointers to the next level pgtable).
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * So a simple kmem_alloc suffices
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdestatic pgtable_t *
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdepgtable_alloc(immu_t *immu, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde pgtable_t *pgtable;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde int kmflags;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde kmflags = (immu_flags & IMMU_FLAGS_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pgtable = kmem_cache_alloc(immu->immu_pgtable_cache, kmflags);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (pgtable == NULL) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return (NULL);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return (pgtable);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdestatic void
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenpgtable_zero(pgtable_t *pgtable)
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde bzero(pgtable->hwpg_vaddr, IMMU_PAGESIZE);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde bzero(pgtable->swpg_next_array, IMMU_PAGESIZE);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde}
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdestatic void
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdepgtable_free(immu_t *immu, pgtable_t *pgtable)
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden kmem_cache_free(immu->immu_pgtable_cache, pgtable);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Function to identify a display device from the PCI class code
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic boolean_t
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdedevice_is_display(uint_t classcode)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde static uint_t disp_classes[] = {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 0x000100,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 0x030000,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 0x030001
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde };
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int i, nclasses = sizeof (disp_classes) / sizeof (uint_t);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde for (i = 0; i < nclasses; i++) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (classcode == disp_classes[i])
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_TRUE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Function that determines if device is PCIEX and/or PCIEX bridge
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic boolean_t
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdedevice_is_pciex(
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uchar_t bus, uchar_t dev, uchar_t func, boolean_t *is_pcib)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ushort_t cap;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ushort_t capsp;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ushort_t cap_count = PCI_CAP_MAX_PTR;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ushort_t status;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde boolean_t is_pciex = B_FALSE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *is_pcib = B_FALSE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde status = pci_getw_func(bus, dev, func, PCI_CONF_STAT);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (!(status & PCI_STAT_CAP))
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde capsp = pci_getb_func(bus, dev, func, PCI_CONF_CAP_PTR);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde while (cap_count-- && capsp >= PCI_CAP_PTR_OFF) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde capsp &= PCI_CAP_PTR_MASK;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde cap = pci_getb_func(bus, dev, func, capsp);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (cap == PCI_CAP_ID_PCI_E) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde status = pci_getw_func(bus, dev, func, capsp + 2);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * See section 7.8.2 of PCI-Express Base Spec v1.0a
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * for Device/Port Type.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * PCIE_PCIECAP_DEV_TYPE_PCIE2PCI implies that the
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * device is a PCIE2PCI bridge
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *is_pcib =
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ((status & PCIE_PCIECAP_DEV_TYPE_MASK) ==
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) ? B_TRUE : B_FALSE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde is_pciex = B_TRUE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde capsp = (*pci_getb_func)(bus, dev, func,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde capsp + PCI_CAP_NEXT_PTR);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (is_pciex);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic boolean_t
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindendevice_use_premap(uint_t classcode)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (IMMU_PCI_CLASS2BASE(classcode) == PCI_CLASS_NET)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (B_TRUE);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (B_FALSE);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * immu_dvma_get_immu()
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * get the immu unit structure for a dev_info node
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeimmu_t *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeimmu_dvma_get_immu(dev_info_t *dip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_t *immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * check if immu unit was already found earlier.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * If yes, then it will be stashed in immu_devi struct.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = immu_devi_get(dip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi_set(dip, immu_flags) != DDI_SUCCESS) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * May fail because of low memory. Return error rather
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * than panic as we want driver to rey again later
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_PANIC, dip, "immu_dvma_get_immu: "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "No immu_devi structure");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*NOTREACHED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = immu_devi_get(dip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(DEVI(dip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi->imd_immu) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu = immu_devi->imd_immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(DEVI(dip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (immu);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(DEVI(dip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu = immu_dmar_get_immu(dip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_PANIC, dip, "immu_dvma_get_immu: "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "Cannot find immu_t for device");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*NOTREACHED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Check if some other thread found immu
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * while lock was not held
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = immu_devi_get(dip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* immu_devi should be present as we found it earlier */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_PANIC, dip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "immu_dvma_get_immu: No immu_devi structure");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*NOTREACHED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(DEVI(dip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi->imd_immu == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* nobody else set it, so we should do it */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_immu = immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_set_spclist(dip, immu);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * if some other thread got immu before
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * us, it should get the same results
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi->imd_immu != immu) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_PANIC, dip, "Multiple "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "immu units found for device. Expected (%p), "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "actual (%p)", (void *)immu,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (void *)immu_devi->imd_immu);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(DEVI(dip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*NOTREACHED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(DEVI(dip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (immu);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* ############################# IMMU_DEVI code ############################ */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Allocate a immu_devi structure and initialize it
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic immu_devi_t *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdecreate_immu_devi(dev_info_t *rdip, int bus, int dev, int func,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uchar_t baseclass, subclass;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint_t classcode, revclass;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde boolean_t pciex = B_FALSE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int kmflags;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde boolean_t is_pcib = B_FALSE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* bus == -1 indicate non-PCI device (no BDF) */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(bus == -1 || bus >= 0);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(dev >= 0);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(func >= 0);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde kmflags = (immu_flags & IMMU_FLAGS_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = kmem_zalloc(sizeof (immu_devi_t), kmflags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_WARN, rdip, "Failed to allocate memory for "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "Intel IOMMU immu_devi structure");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_dip = rdip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_seg = 0; /* Currently seg can only be 0 */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_bus = bus;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_pcib_type = IMMU_PCIB_BAD;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (bus == -1) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_pcib_type = IMMU_PCIB_NOBDF;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (immu_devi);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_devfunc = IMMU_PCI_DEVFUNC(dev, func);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_sec = 0;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_sub = 0;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde revclass = pci_getl_func(bus, dev, func, PCI_CONF_REVID);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde classcode = IMMU_PCI_REV2CLASS(revclass);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde baseclass = IMMU_PCI_CLASS2BASE(classcode);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde subclass = IMMU_PCI_CLASS2SUB(classcode);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (baseclass == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_sec = pci_getb_func(bus, dev, func,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PCI_BCNF_SECBUS);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_sub = pci_getb_func(bus, dev, func,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PCI_BCNF_SUBBUS);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pciex = device_is_pciex(bus, dev, func, &is_pcib);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (pciex == B_TRUE && is_pcib == B_TRUE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_pcib_type = IMMU_PCIB_PCIE_PCI;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else if (pciex == B_TRUE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_pcib_type = IMMU_PCIB_PCIE_PCIE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_pcib_type = IMMU_PCIB_PCI_PCI;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_pcib_type = IMMU_PCIB_ENDPOINT;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* check for certain special devices */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_display = device_is_display(classcode);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_lpc = ((baseclass == PCI_CLASS_BRIDGE) &&
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (subclass == PCI_BRIDGE_ISA)) ? B_TRUE : B_FALSE;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_devi->imd_use_premap = device_use_premap(classcode);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_domain = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
9e986f0e5fb5e5ac09af90cd3b63f7836d983f9dFrank Van Der Linden immu_devi->imd_dvma_flags = immu_global_dvma_flags;
9e986f0e5fb5e5ac09af90cd3b63f7836d983f9dFrank Van Der Linden
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (immu_devi);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdedestroy_immu_devi(immu_devi_t *immu_devi)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde kmem_free(immu_devi, sizeof (immu_devi_t));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic domain_t *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeimmu_devi_domain(dev_info_t *rdip, dev_info_t **ddipp)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain_t *domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *ddipp = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = immu_devi_get(rdip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(DEVI(rdip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = immu_devi->imd_domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddip = immu_devi->imd_ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(DEVI(rdip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (domain)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *ddipp = ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* ############################# END IMMU_DEVI code ######################## */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* ############################# DOMAIN code ############################### */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * This routine always succeeds
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic int
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdedid_alloc(immu_t *immu, dev_info_t *rdip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *ddip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int did;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde did = (uintptr_t)vmem_alloc(immu->immu_did_arena, 1,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (immu_flags & IMMU_FLAGS_NOSLEEP) ? VM_NOSLEEP : VM_SLEEP);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (did == 0) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_WARN, rdip, "device domain-id alloc error"
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde " domain-device: %s%d. immu unit is %s. Using "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "unity domain with domain-id (%d)",
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_driver_name(ddip), ddi_get_instance(ddip),
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_name, immu->immu_unity_domain->dom_did);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde did = immu->immu_unity_domain->dom_did;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (did);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic int
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeget_branch_domain(dev_info_t *pdip, void *arg)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain_t *domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_t *immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvma_arg_t *dvp = (dvma_arg_t *)arg;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * The field dvp->dva_rdip is a work-in-progress
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * and gets updated as we walk up the ancestor
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * tree. The final ddip is set only when we reach
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * the top of the tree. So the dvp->dva_ddip field cannot
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * be relied on until we reach the top of the field.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* immu_devi may not be set. */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = immu_devi_get(pdip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi_set(pdip, dvp->dva_flags) != DDI_SUCCESS) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvp->dva_error = DDI_FAILURE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_TERMINATE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = immu_devi_get(pdip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu = immu_devi->imd_immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (immu == NULL)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu = immu_dvma_get_immu(pdip, dvp->dva_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * If we encounter a PCIE_PCIE bridge *ANCESTOR* we need to
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * terminate the walk (since the device under the PCIE bridge
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * is a PCIE device and has an independent entry in the
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * root/context table)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (dvp->dva_rdip != pdip &&
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_pcib_type == IMMU_PCIB_PCIE_PCIE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_TERMINATE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * In order to be a domain-dim, it must be a PCI device i.e.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * must have valid BDF. This also eliminates the root complex.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi->imd_pcib_type != IMMU_PCIB_BAD &&
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_pcib_type != IMMU_PCIB_NOBDF) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(immu_devi->imd_bus >= 0);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(immu_devi->imd_devfunc >= 0);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvp->dva_ddip = pdip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi->imd_display == B_TRUE ||
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (dvp->dva_flags & IMMU_FLAGS_UNITY)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvp->dva_domain = immu->immu_unity_domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* continue walking to find ddip */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_CONTINUE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(DEVI(pdip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = immu_devi->imd_domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddip = immu_devi->imd_ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(DEVI(pdip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (domain && ddip) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* if domain is set, it must be the same */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (dvp->dva_domain) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(domain == dvp->dva_domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvp->dva_domain = domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvp->dva_ddip = ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_TERMINATE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Domain may already be set, continue walking so that ddip gets set */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (dvp->dva_domain) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_CONTINUE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* domain is not set in either immu_devi or dvp */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = bdf_domain_lookup(immu_devi);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (domain == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_CONTINUE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* ok, the BDF hash had a domain for this BDF. */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Grab lock again to check if something else set immu_devi fields */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(DEVI(pdip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi->imd_domain != NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvp->dva_domain = domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvp->dva_domain = domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(DEVI(pdip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * walk upwards until the topmost PCI bridge is found
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_CONTINUE);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdemap_unity_domain(domain_t *domain)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde struct memlist *mp;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t start;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t npages;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_dcookie_t dcookies[1] = {0};
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde int dcount = 0;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * UNITY arenas are a mirror of the physical memory
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * installed on the system.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#ifdef BUGGY_DRIVERS
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Dont skip page0. Some broken HW/FW access it.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_paddr = 0;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_npages = 1;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcount = 1;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void) dvma_map(domain, 0, 1, dcookies, dcount, NULL,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde IMMU_FLAGS_READ | IMMU_FLAGS_WRITE | IMMU_FLAGS_PAGE1);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#endif
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde memlist_read_lock();
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mp = phys_install;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (mp->ml_address == 0) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* since we already mapped page1 above */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde start = IMMU_PAGESIZE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde start = mp->ml_address;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde npages = mp->ml_size/IMMU_PAGESIZE + 1;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_paddr = start;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_npages = npages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcount = 1;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void) dvma_map(domain, start, npages, dcookies,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcount, NULL, IMMU_FLAGS_READ | IMMU_FLAGS_WRITE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_LOG, domain->dom_dip, "iommu: mapping PHYS span [0x%" PRIx64
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde " - 0x%" PRIx64 "]", start, start + mp->ml_size);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mp = mp->ml_next;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde while (mp) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_LOG, domain->dom_dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "iommu: mapping PHYS span [0x%" PRIx64 " - 0x%" PRIx64 "]",
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden mp->ml_address, mp->ml_address + mp->ml_size);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde start = mp->ml_address;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde npages = mp->ml_size/IMMU_PAGESIZE + 1;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_paddr = start;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_npages = npages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcount = 1;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void) dvma_map(domain, start, npages,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies, dcount, NULL, IMMU_FLAGS_READ | IMMU_FLAGS_WRITE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mp = mp->ml_next;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mp = bios_rsvd;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde while (mp) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_LOG, domain->dom_dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "iommu: mapping PHYS span [0x%" PRIx64 " - 0x%" PRIx64 "]",
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden mp->ml_address, mp->ml_address + mp->ml_size);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde start = mp->ml_address;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde npages = mp->ml_size/IMMU_PAGESIZE + 1;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_paddr = start;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_npages = npages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcount = 1;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void) dvma_map(domain, start, npages,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies, dcount, NULL, IMMU_FLAGS_READ | IMMU_FLAGS_WRITE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mp = mp->ml_next;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde memlist_read_unlock();
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * create_xlate_arena()
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Create the dvma arena for a domain with translation
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * mapping
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdecreate_xlate_arena(immu_t *immu, domain_t *domain,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *rdip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde char *arena_name;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde struct memlist *mp;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int vmem_flags;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t start;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint_t mgaw;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t size;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t maxaddr;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde void *vmem_ret;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde arena_name = domain->dom_dvma_arena_name;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Note, don't do sizeof (arena_name) - it is just a pointer */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (void) snprintf(arena_name,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde sizeof (domain->dom_dvma_arena_name),
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "%s-domain-%d-xlate-DVMA-arena", immu->immu_name,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain->dom_did);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde vmem_flags = (immu_flags & IMMU_FLAGS_NOSLEEP) ? VM_NOSLEEP : VM_SLEEP;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Restrict mgaddr (max guest addr) to MGAW */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mgaw = IMMU_CAP_MGAW(immu->immu_regs_cap);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * To ensure we avoid ioapic and PCI MMIO ranges we just
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * use the physical memory address range of the system as the
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * range
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde maxaddr = ((uint64_t)1 << mgaw);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde memlist_read_lock();
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde mp = phys_install;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (mp->ml_address == 0)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde start = MMU_PAGESIZE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde else
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde start = mp->ml_address;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (start + mp->ml_size > maxaddr)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde size = maxaddr - start;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde else
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde size = mp->ml_size;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde ddi_err(DER_VERB, rdip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "iommu: %s: Creating dvma vmem arena [0x%" PRIx64
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde " - 0x%" PRIx64 "]", arena_name, start, start + size);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * We always allocate in quanta of IMMU_PAGESIZE
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde domain->dom_dvma_arena = vmem_create(arena_name,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde (void *)(uintptr_t)start, /* start addr */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde size, /* size */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde IMMU_PAGESIZE, /* quantum */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde NULL, /* afunc */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde NULL, /* ffunc */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde NULL, /* source */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde 0, /* qcache_max */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde vmem_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (domain->dom_dvma_arena == NULL) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde ddi_err(DER_PANIC, rdip,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde "Failed to allocate DVMA arena(%s) "
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde "for domain ID (%d)", arena_name, domain->dom_did);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*NOTREACHED*/
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde mp = mp->ml_next;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde while (mp) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (mp->ml_address == 0)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde start = MMU_PAGESIZE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde else
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde start = mp->ml_address;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (start + mp->ml_size > maxaddr)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde size = maxaddr - start;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde else
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde size = mp->ml_size;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_VERB, rdip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "iommu: %s: Adding dvma vmem span [0x%" PRIx64
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde " - 0x%" PRIx64 "]", arena_name, start,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde start + size);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde vmem_ret = vmem_add(domain->dom_dvma_arena,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde (void *)(uintptr_t)start, size, vmem_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (vmem_ret == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_PANIC, rdip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "Failed to allocate DVMA arena(%s) "
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde "for domain ID (%d)",
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde arena_name, domain->dom_did);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*NOTREACHED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mp = mp->ml_next;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde memlist_read_unlock();
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* ################################### DOMAIN CODE ######################### */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Set the domain and domain-dip for a dip
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeset_domain(
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *dip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *ddip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain_t *domain)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain_t *fdomain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *fddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = immu_devi_get(dip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(DEVI(dip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde fddip = immu_devi->imd_ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde fdomain = immu_devi->imd_domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (fddip) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(fddip == ddip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_ddip = ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (fdomain) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(fdomain == domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi->imd_domain = domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(DEVI(dip)->devi_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * device_domain()
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Get domain for a device. The domain may be global in which case it
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * is shared between all IOMMU units. Due to potential AGAW differences
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * between IOMMU units, such global domains *have to be* UNITY mapping
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * domains. Alternatively, the domain may be local to a IOMMU unit.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Local domains may be shared or immu_devi, although the
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * scope of sharing
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * is restricted to devices controlled by the IOMMU unit to
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * which the domain
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * belongs. If shared, they (currently) have to be UNITY domains. If
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * immu_devi a domain may be either UNITY or translation (XLATE) domain.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic domain_t *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdedevice_domain(dev_info_t *rdip, dev_info_t **ddipp, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *ddip; /* topmost dip in domain i.e. domain owner */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_t *immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain_t *domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvma_arg_t dvarg = {0};
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int level;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *ddipp = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Check if the domain is already set. This is usually true
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * if this is not the first DVMA transaction.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddip = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = immu_devi_domain(rdip, &ddip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (domain) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *ddipp = ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu = immu_dvma_get_immu(rdip, immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * possible that there is no IOMMU unit for this device
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * - BIOS bugs are one example.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_WARN, rdip, "No iommu unit found for device");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
9e986f0e5fb5e5ac09af90cd3b63f7836d983f9dFrank Van Der Linden immu_flags |= immu_devi_get(rdip)->imd_dvma_flags;
9e986f0e5fb5e5ac09af90cd3b63f7836d983f9dFrank Van Der Linden
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dvarg.dva_rdip = rdip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvarg.dva_ddip = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvarg.dva_domain = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvarg.dva_flags = immu_flags;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde level = 0;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (immu_walk_ancestor(rdip, NULL, get_branch_domain,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde &dvarg, &level, immu_flags) != DDI_SUCCESS) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * maybe low memory. return error,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * so driver tries again later
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* should have walked at least 1 dip (i.e. edip) */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(level > 0);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddip = dvarg.dva_ddip; /* must be present */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = dvarg.dva_domain; /* may be NULL */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * We may find the domain during our ancestor walk on any one of our
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * ancestor dips, If the domain is found then the domain-dip
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * (i.e. ddip) will also be found in the same immu_devi struct.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * The domain-dip is the highest ancestor dip which shares the
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * same domain with edip.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * The domain may or may not be found, but the domain dip must
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * be found.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (ddip == NULL) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde ddi_err(DER_MODE, rdip, "Cannot find domain dip for device.");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Did we find a domain ?
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (domain) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde goto found;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* nope, so allocate */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = domain_create(immu, ddip, rdip, immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (domain == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*FALLTHROUGH*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdefound:
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * We know *domain *is* the right domain, so panic if
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * another domain is set for either the request-dip or
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * effective dip.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde set_domain(ddip, ddip, domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde set_domain(rdip, ddip, domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *ddipp = ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdecreate_unity_domain(immu_t *immu)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain_t *domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* domain created during boot and always use sleep flag */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = kmem_zalloc(sizeof (domain_t), KM_SLEEP);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde rw_init(&(domain->dom_pgtable_rwlock), NULL, RW_DEFAULT, NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain->dom_did = IMMU_UNITY_DID;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain->dom_maptype = IMMU_MAPTYPE_UNITY;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain->dom_immu = immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_unity_domain = domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Setup the domain's initial page table
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * should never fail.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde domain->dom_pgtable_root = pgtable_alloc(immu, IMMU_FLAGS_SLEEP);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pgtable_zero(domain->dom_pgtable_root);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden /*
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden * Only map all physical memory in to the unity domain
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden * if passthrough is not supported. If it is supported,
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden * passthrough is set in the context entry instead.
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden */
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden if (!IMMU_ECAP_GET_PT(immu->immu_regs_excap))
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden map_unity_domain(domain);
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * put it on the system-wide UNITY domain list
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(immu_domain_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde list_insert_tail(&immu_unity_domain_list, domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(immu_domain_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * ddip is the domain-dip - the topmost dip in a domain
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * rdip is the requesting-dip - the device which is
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * requesting DVMA setup
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * if domain is a non-shared domain rdip == ddip
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic domain_t *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdedomain_create(immu_t *immu, dev_info_t *ddip, dev_info_t *rdip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int kmflags;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain_t *domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde char mod_hash_name[128];
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int did;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_dcookie_t dcookies[1] = {0};
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde int dcount = 0;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = immu_devi_get(rdip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * First allocate a domainid.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * This routine will never fail, since if we run out
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * of domains the unity domain will be allocated.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde did = did_alloc(immu, rdip, ddip, immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (did == IMMU_UNITY_DID) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* domain overflow */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(immu->immu_unity_domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (immu->immu_unity_domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde kmflags = (immu_flags & IMMU_FLAGS_NOSLEEP) ? KM_NOSLEEP : KM_SLEEP;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = kmem_zalloc(sizeof (domain_t), kmflags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (domain == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_PANIC, rdip, "Failed to alloc DVMA domain "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "structure for device. IOMMU unit: %s", immu->immu_name);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*NOTREACHED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde rw_init(&(domain->dom_pgtable_rwlock), NULL, RW_DEFAULT, NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (void) snprintf(mod_hash_name, sizeof (mod_hash_name),
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "immu%s-domain%d-pava-hash", immu->immu_name, did);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain->dom_did = did;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain->dom_immu = immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain->dom_maptype = IMMU_MAPTYPE_XLATE;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain->dom_dip = ddip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Create xlate DVMA arena for this domain.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde create_xlate_arena(immu, domain, rdip, immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Setup the domain's initial page table
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde domain->dom_pgtable_root = pgtable_alloc(immu, immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (domain->dom_pgtable_root == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_PANIC, rdip, "Failed to alloc root "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "pgtable for domain (%d). IOMMU unit: %s",
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain->dom_did, immu->immu_name);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*NOTREACHED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pgtable_zero(domain->dom_pgtable_root);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Since this is a immu unit-specific domain, put it on
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * the per-immu domain list.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(immu->immu_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde list_insert_head(&immu->immu_domain_list, domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(immu->immu_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Also put it on the system-wide xlate domain list
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&(immu_domain_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde list_insert_head(&immu_xlate_domain_list, domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&(immu_domain_lock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde bdf_domain_insert(immu_devi, domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#ifdef BUGGY_DRIVERS
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Map page0. Some broken HW/FW access it.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_paddr = 0;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_npages = 1;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcount = 1;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void) dvma_map(domain, 0, 1, dcookies, dcount, NULL,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde IMMU_FLAGS_READ | IMMU_FLAGS_WRITE | IMMU_FLAGS_PAGE1);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#endif
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Create domainid arena.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Domainid 0 is reserved by Vt-d spec and cannot be used by
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * system software.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Domainid 1 is reserved by solaris and used for *all* of the following:
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * as the "uninitialized" domain - For devices not yet controlled
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * by Solaris
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * as the "unity" domain - For devices that will always belong
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * to the unity domain
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * as the "overflow" domain - Used for any new device after we
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * run out of domains
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * All of the above domains map into a single domain with
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * domainid 1 and UNITY DVMA mapping
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Each IMMU unity has its own unity/uninit/overflow domain
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdedid_init(immu_t *immu)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (void) snprintf(immu->immu_did_arena_name,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde sizeof (immu->immu_did_arena_name),
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "%s_domainid_arena", immu->immu_name);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_VERB, immu->immu_dip, "creating domainid arena %s",
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu->immu_did_arena_name);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_did_arena = vmem_create(
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_did_arena_name,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (void *)(uintptr_t)(IMMU_UNITY_DID + 1), /* start addr */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_max_domains - IMMU_UNITY_DID,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 1, /* quantum */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde NULL, /* afunc */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde NULL, /* ffunc */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde NULL, /* source */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde 0, /* qcache_max */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde VM_SLEEP);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Even with SLEEP flag, vmem_create() can fail */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu->immu_did_arena == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_PANIC, NULL, "%s: Failed to create Intel "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "IOMMU domainid allocator: %s", immu->immu_name,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_did_arena_name);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* ######################### CONTEXT CODE ################################# */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdecontext_set(immu_t *immu, domain_t *domain, pgtable_t *root_table,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int bus, int devfunc)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *context;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *pgtable_root;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_rce_t *hw_rent;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_rce_t *hw_cent;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_rce_t *ctxp;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde int sid;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde krw_t rwtype;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde boolean_t fill_root;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde boolean_t fill_ctx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde pgtable_root = domain->dom_pgtable_root;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ctxp = (hw_rce_t *)(root_table->swpg_next_array);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde context = *(pgtable_t **)(ctxp + bus);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_rent = (hw_rce_t *)(root_table->hwpg_vaddr) + bus;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde fill_root = B_FALSE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde fill_ctx = B_FALSE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /* Check the most common case first with reader lock */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_enter(&(immu->immu_ctx_rwlock), RW_READER);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rwtype = RW_READER;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdeagain:
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (ROOT_GET_P(hw_rent)) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde hw_cent = (hw_rce_t *)(context->hwpg_vaddr) + devfunc;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (CONT_GET_AVAIL(hw_cent) == IMMU_CONT_INITED) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_exit(&(immu->immu_ctx_rwlock));
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde } else {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde fill_ctx = B_TRUE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde fill_root = B_TRUE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde fill_ctx = B_TRUE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (rwtype == RW_READER &&
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_tryupgrade(&(immu->immu_ctx_rwlock)) == 0) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_exit(&(immu->immu_ctx_rwlock));
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rwtype = RW_WRITER;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde goto again;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rwtype = RW_WRITER;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (fill_root == B_TRUE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ROOT_SET_CONT(hw_rent, context->hwpg_paddr);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ROOT_SET_P(hw_rent);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_regs_cpu_flush(immu, (caddr_t)hw_rent, sizeof (hw_rce_t));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (fill_ctx == B_TRUE) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde hw_cent = (hw_rce_t *)(context->hwpg_vaddr) + devfunc;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* need to disable context entry before reprogramming it */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde bzero(hw_cent, sizeof (hw_rce_t));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* flush caches */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_regs_cpu_flush(immu, (caddr_t)hw_cent, sizeof (hw_rce_t));
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde sid = ((bus << 8) | devfunc);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_flush_context_fsi(immu, 0, sid, domain->dom_did,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden &immu->immu_ctx_inv_wait);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde CONT_SET_AVAIL(hw_cent, IMMU_CONT_INITED);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde CONT_SET_DID(hw_cent, domain->dom_did);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde CONT_SET_AW(hw_cent, immu->immu_dvma_agaw);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde CONT_SET_ASR(hw_cent, pgtable_root->hwpg_paddr);
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden if (domain->dom_did == IMMU_UNITY_DID &&
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden IMMU_ECAP_GET_PT(immu->immu_regs_excap))
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden CONT_SET_TTYPE(hw_cent, TTYPE_PASSTHRU);
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden else
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden /*LINTED*/
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden CONT_SET_TTYPE(hw_cent, TTYPE_XLATE_ONLY);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde CONT_SET_P(hw_cent);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (IMMU_ECAP_GET_CH(immu->immu_regs_excap)) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden CONT_SET_EH(hw_cent);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (immu_use_alh)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden CONT_SET_ALH(hw_cent);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_regs_cpu_flush(immu, (caddr_t)hw_cent, sizeof (hw_rce_t));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_exit(&(immu->immu_ctx_rwlock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic pgtable_t *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdecontext_create(immu_t *immu)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int bus;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int devfunc;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *root_table;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *context;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *pgtable_root;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_rce_t *ctxp;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_rce_t *hw_rent;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_rce_t *hw_cent;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Allocate a zeroed root table (4K 256b entries) */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde root_table = pgtable_alloc(immu, IMMU_FLAGS_SLEEP);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pgtable_zero(root_table);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Setup context tables for all possible root table entries.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Start out with unity domains for all entries.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ctxp = (hw_rce_t *)(root_table->swpg_next_array);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_rent = (hw_rce_t *)(root_table->hwpg_vaddr);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde for (bus = 0; bus < IMMU_ROOT_NUM; bus++, ctxp++, hw_rent++) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde context = pgtable_alloc(immu, IMMU_FLAGS_SLEEP);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pgtable_zero(context);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ROOT_SET_P(hw_rent);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ROOT_SET_CONT(hw_rent, context->hwpg_paddr);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_cent = (hw_rce_t *)(context->hwpg_vaddr);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde for (devfunc = 0; devfunc < IMMU_CONT_NUM;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde devfunc++, hw_cent++) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_root =
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_unity_domain->dom_pgtable_root;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde CONT_SET_DID(hw_cent,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_unity_domain->dom_did);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde CONT_SET_AW(hw_cent, immu->immu_dvma_agaw);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde CONT_SET_ASR(hw_cent, pgtable_root->hwpg_paddr);
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden if (IMMU_ECAP_GET_PT(immu->immu_regs_excap))
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden CONT_SET_TTYPE(hw_cent, TTYPE_PASSTHRU);
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden else
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden /*LINTED*/
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden CONT_SET_TTYPE(hw_cent, TTYPE_XLATE_ONLY);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde CONT_SET_AVAIL(hw_cent, IMMU_CONT_UNINITED);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde CONT_SET_P(hw_cent);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_regs_cpu_flush(immu, context->hwpg_vaddr, IMMU_PAGESIZE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *((pgtable_t **)ctxp) = context;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (root_table);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Called during rootnex attach, so no locks needed
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdecontext_init(immu_t *immu)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde rw_init(&(immu->immu_ctx_rwlock), NULL, RW_DEFAULT, NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_init_inv_wait(&immu->immu_ctx_inv_wait, "ctxglobal", B_TRUE);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_regs_wbf_flush(immu);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_ctx_root = context_create(immu);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_regs_set_root_table(immu);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_flush_context_gbl(immu, &immu->immu_ctx_inv_wait);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_flush_iotlb_gbl(immu, &immu->immu_ctx_inv_wait);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde rw_exit(&(immu->immu_ctx_rwlock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Find top pcib
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic int
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdefind_top_pcib(dev_info_t *dip, void *arg)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t **pcibdipp = (dev_info_t **)arg;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi = immu_devi_get(dip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi->imd_pcib_type == IMMU_PCIB_PCI_PCI) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *pcibdipp = dip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_WALK_CONTINUE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic int
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeimmu_context_update(immu_t *immu, domain_t *domain, dev_info_t *ddip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *rdip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *r_immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_devi_t *d_immu_devi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int r_bus;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int d_bus;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int r_devfunc;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int d_devfunc;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_pcib_t d_pcib_type;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *pcibdip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (ddip == NULL || rdip == NULL ||
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddip == root_devinfo || rdip == root_devinfo) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "immu_contexts_update: domain-dip or "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "request-dip are NULL or are root devinfo");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_FAILURE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * We need to set the context fields
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * based on what type of device rdip and ddip are.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * To do that we need the immu_devi field.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Set the immu_devi field (if not already set)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi_set(ddip, immu_flags) == DDI_FAILURE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "immu_context_update: failed to set immu_devi for ddip");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_FAILURE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_devi_set(rdip, immu_flags) == DDI_FAILURE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "immu_context_update: failed to set immu_devi for rdip");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_FAILURE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde d_immu_devi = immu_devi_get(ddip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde r_immu_devi = immu_devi_get(rdip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde d_bus = d_immu_devi->imd_bus;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde d_devfunc = d_immu_devi->imd_devfunc;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde d_pcib_type = d_immu_devi->imd_pcib_type;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde r_bus = r_immu_devi->imd_bus;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde r_devfunc = r_immu_devi->imd_devfunc;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (rdip == ddip) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* rdip is a PCIE device. set context for it only */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde context_set(immu, domain, immu->immu_ctx_root, r_bus,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde r_devfunc);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#ifdef BUGGY_DRIVERS
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else if (r_immu_devi == d_immu_devi) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#ifdef TEST
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_WARN, rdip, "Driver bug: Devices 0x%lx and "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "0x%lx are identical", rdip, ddip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#endif
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* rdip is a PCIE device. set context for it only */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde context_set(immu, domain, immu->immu_ctx_root, r_bus,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde r_devfunc);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#endif
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else if (d_pcib_type == IMMU_PCIB_PCIE_PCI) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * ddip is a PCIE_PCI bridge. Set context for ddip's
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * secondary bus. If rdip is on ddip's secondary
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * bus, set context for rdip. Else, set context
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * for rdip's PCI bridge on ddip's secondary bus.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde context_set(immu, domain, immu->immu_ctx_root,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde d_immu_devi->imd_sec, 0);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (d_immu_devi->imd_sec == r_bus) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde context_set(immu, domain, immu->immu_ctx_root,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde r_bus, r_devfunc);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pcibdip = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_walk_ancestor(rdip, ddip, find_top_pcib,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde &pcibdip, NULL, immu_flags) == DDI_SUCCESS &&
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pcibdip != NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde r_immu_devi = immu_devi_get(pcibdip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde r_bus = r_immu_devi->imd_bus;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde r_devfunc = r_immu_devi->imd_devfunc;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde context_set(immu, domain, immu->immu_ctx_root,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde r_bus, r_devfunc);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_PANIC, rdip, "Failed to find PCI "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde " bridge for PCI device");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*NOTREACHED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else if (d_pcib_type == IMMU_PCIB_PCI_PCI) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde context_set(immu, domain, immu->immu_ctx_root, d_bus,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde d_devfunc);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else if (d_pcib_type == IMMU_PCIB_ENDPOINT) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * ddip is a PCIE device which has a non-PCI device under it
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * i.e. it is a PCI-nonPCI bridge. Example: pciicde-ata
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde context_set(immu, domain, immu->immu_ctx_root, d_bus,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde d_devfunc);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_PANIC, rdip, "unknown device type. Cannot "
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "set iommu context.");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*NOTREACHED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* XXX do we need a membar_producer() here */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_SUCCESS);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* ##################### END CONTEXT CODE ################################## */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* ##################### MAPPING CODE ################################## */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#ifdef DEBUG
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic boolean_t
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram HegdePDTE_check(immu_t *immu, hw_pdte_t pdte, pgtable_t *next, paddr_t paddr,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *rdip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* The PDTE must be set i.e. present bit is set */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (!PDTE_P(pdte)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "No present flag");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Just assert to check most significant system software field
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * (PDTE_SW4) as it is same as present bit and we
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * checked that above
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(PDTE_SW4(pdte));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * TM field should be clear if not reserved.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * non-leaf is always reserved
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (next == NULL && immu->immu_TM_reserved == B_FALSE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_TM(pdte)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "TM flag set");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * The SW3 field is not used and must be clear
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_SW3(pdte)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "SW3 set");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * PFN (for PTE) or next level pgtable-paddr (for PDE) must be set
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (next == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(paddr % IMMU_PAGESIZE == 0);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_PADDR(pdte) != paddr) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "PTE paddr mismatch: %lx != %lx",
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_PADDR(pdte), paddr);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_PADDR(pdte) != next->hwpg_paddr) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "PDE paddr mismatch: %lx != %lx",
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_PADDR(pdte), next->hwpg_paddr);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * SNP field should be clear if not reserved.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * non-leaf is always reserved
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (next == NULL && immu->immu_SNP_reserved == B_FALSE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_SNP(pdte)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "SNP set");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* second field available for system software should be clear */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_SW2(pdte)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "SW2 set");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Super pages field should be clear */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_SP(pdte)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "SP set");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * least significant field available for
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * system software should be clear
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_SW1(pdte)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "SW1 set");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if ((immu_flags & IMMU_FLAGS_READ) && !PDTE_READ(pdte)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "READ not set");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if ((immu_flags & IMMU_FLAGS_WRITE) && !PDTE_WRITE(pdte)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "WRITE not set");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_FALSE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (B_TRUE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#endif
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*ARGSUSED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
e03dceed3deb85ad561202c77277e701f763fa13Vikram HegdePTE_clear_all(immu_t *immu, domain_t *domain, xlate_t *xlate,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde uint64_t *dvma_ptr, uint64_t *npages_ptr, dev_info_t *rdip)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde uint64_t npages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde uint64_t dvma;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *pgtable;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde hw_pdte_t *hwp;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde hw_pdte_t *shwp;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable = xlate->xlt_pgtable;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde idx = xlate->xlt_idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dvma = *dvma_ptr;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde npages = *npages_ptr;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * since a caller gets a unique dvma for a physical address,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * no other concurrent thread will be writing to the same
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * PTE even if it has the same paddr. So no locks needed.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde shwp = (hw_pdte_t *)(pgtable->hwpg_vaddr) + idx;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde hwp = shwp;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde for (; npages > 0 && idx <= IMMU_PGTABLE_MAXIDX; idx++, hwp++) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden PDTE_CLEAR_P(*hwp);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dvma += IMMU_PAGESIZE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde npages--;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde *dvma_ptr = dvma;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde *npages_ptr = npages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde xlate->xlt_idx = idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenxlate_setup(uint64_t dvma, xlate_t *xlate, int nlevels)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int level;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t offbits;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Skip the first 12 bits which is the offset into
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * 4K PFN (phys page frame based on IMMU_PAGESIZE)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde offbits = dvma >> IMMU_PAGESHIFT;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* skip to level 1 i.e. leaf PTE */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde for (level = 1, xlate++; level <= nlevels; level++, xlate++) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde xlate->xlt_level = level;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde xlate->xlt_idx = (offbits & IMMU_PGTABLE_LEVEL_MASK);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(xlate->xlt_idx <= IMMU_PGTABLE_MAXIDX);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde xlate->xlt_pgtable = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde offbits >>= IMMU_PGTABLE_LEVEL_STRIDE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Read the pgtables
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic boolean_t
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der LindenPDE_lookup(domain_t *domain, xlate_t *xlate, int nlevels)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *pgtable;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *next;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint_t idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* start with highest level pgtable i.e. root */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde xlate += nlevels;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (xlate->xlt_pgtable == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde xlate->xlt_pgtable = domain->dom_pgtable_root;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde for (; xlate->xlt_level > 1; xlate--) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde idx = xlate->xlt_idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable = xlate->xlt_pgtable;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if ((xlate - 1)->xlt_pgtable) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde continue;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Lock the pgtable in read mode */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde rw_enter(&(pgtable->swpg_rwlock), RW_READER);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * since we are unmapping, the pgtable should
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * already point to a leafier pgtable.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde next = *(pgtable->swpg_next_array + idx);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (xlate - 1)->xlt_pgtable = next;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden rw_exit(&(pgtable->swpg_rwlock));
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (next == NULL)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (B_FALSE);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (B_TRUE);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic void
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_fault_walk(void *arg, void *base, size_t len)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t dvma, start;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma = *(uint64_t *)arg;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden start = (uint64_t)(uintptr_t)base;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (dvma >= start && dvma < (start + len)) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_WARN, NULL,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "faulting DVMA address is in vmem arena "
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "(%" PRIx64 "-%" PRIx64 ")",
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden start, start + len);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden *(uint64_t *)arg = ~0ULL;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenvoid
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_print_fault_info(uint_t sid, uint64_t dvma)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden int nlevels;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xlate_t xlate[IMMU_PGTABLE_MAX_LEVELS + 1] = {0};
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xlate_t *xlatep;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden hw_pdte_t pte;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain_t *domain;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_t *immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t dvma_arg;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (mod_hash_find(bdf_domain_hash,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void *)(uintptr_t)sid, (void *)&domain) != 0) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_WARN, NULL,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "no domain for faulting SID %08x", sid);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu = domain->dom_immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma_arg = dvma;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden vmem_walk(domain->dom_dvma_arena, VMEM_ALLOC, immu_fault_walk,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void *)&dvma_arg);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (dvma_arg != ~0ULL)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_WARN, domain->dom_dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "faulting DVMA address is not in vmem arena");
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden nlevels = immu->immu_dvma_nlevels;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xlate_setup(dvma, xlate, nlevels);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (!PDE_lookup(domain, xlate, nlevels)) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_WARN, domain->dom_dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "pte not found in domid %d for faulting addr %" PRIx64,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain->dom_did, dvma);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xlatep = &xlate[1];
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pte = *((hw_pdte_t *)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (xlatep->xlt_pgtable->hwpg_vaddr) + xlatep->xlt_idx);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_WARN, domain->dom_dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "domid %d pte: %" PRIx64 "(paddr %" PRIx64 ")", domain->dom_did,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (unsigned long long)pte, (unsigned long long)PDTE_PADDR(pte));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde/*ARGSUSED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram HegdePTE_set_one(immu_t *immu, hw_pdte_t *hwp, paddr_t paddr,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *rdip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_pdte_t pte;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#ifndef DEBUG
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pte = immu->immu_ptemask;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde PDTE_SET_PADDR(pte, paddr);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#else
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pte = *hwp;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_P(pte)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_PADDR(pte) != paddr) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "PTE paddr %lx != paddr %lx",
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_PADDR(pte), paddr);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#ifdef BUGGY_DRIVERS
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#else
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde goto out;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#endif
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* clear TM field if not reserved */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (immu->immu_TM_reserved == B_FALSE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_TM(pte);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Clear 3rd field for system software - not used */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_SW3(pte);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Set paddr */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(paddr % IMMU_PAGESIZE == 0);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_PADDR(pte);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_SET_PADDR(pte, paddr);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* clear SNP field if not reserved. */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (immu->immu_SNP_reserved == B_FALSE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_SNP(pte);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Clear SW2 field available for software */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_SW2(pte);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* SP is don't care for PTEs. Clear it for cleanliness */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_SP(pte);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Clear SW1 field available for software */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_SW1(pte);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Now that we are done writing the PTE
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * set the "present" flag. Note this present
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * flag is a bit in the PDE/PTE that the
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * spec says is available for system software.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * This is an implementation detail of Solaris
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * bare-metal Intel IOMMU.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * The present field in a PDE/PTE is not defined
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * by the Vt-d spec
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_SET_P(pte);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pte |= immu->immu_ptemask;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeout:
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#endif /* DEBUG */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#ifdef BUGGY_DRIVERS
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde PDTE_SET_READ(pte);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde PDTE_SET_WRITE(pte);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#else
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_flags & IMMU_FLAGS_READ)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_SET_READ(pte);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_flags & IMMU_FLAGS_WRITE)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_SET_WRITE(pte);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#endif /* BUGGY_DRIVERS */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *hwp = pte;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*ARGSUSED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram HegdePTE_set_all(immu_t *immu, domain_t *domain, xlate_t *xlate,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t *dvma_ptr, uint64_t *nvpages_ptr, immu_dcookie_t *dcookies,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde int dcount, dev_info_t *rdip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde paddr_t paddr;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde uint64_t nvpages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde uint64_t nppages;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t dvma;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *pgtable;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_pdte_t *hwp;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_pdte_t *shwp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden int idx, nset;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde int j;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable = xlate->xlt_pgtable;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde idx = xlate->xlt_idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvma = *dvma_ptr;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde nvpages = *nvpages_ptr;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * since a caller gets a unique dvma for a physical address,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * no other concurrent thread will be writing to the same
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * PTE even if it has the same paddr. So no locks needed.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde shwp = (hw_pdte_t *)(pgtable->hwpg_vaddr) + idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hwp = shwp;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde for (j = dcount - 1; j >= 0; j--) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (nvpages <= dcookies[j].dck_npages)
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde break;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde nvpages -= dcookies[j].dck_npages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde nppages = nvpages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde paddr = dcookies[j].dck_paddr +
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde (dcookies[j].dck_npages - nppages) * IMMU_PAGESIZE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde nvpages = *nvpages_ptr;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden nset = 0;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde for (; nvpages > 0 && idx <= IMMU_PGTABLE_MAXIDX; idx++, hwp++) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PTE_set_one(immu, hwp, paddr, rdip, immu_flags);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden nset++;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(PDTE_check(immu, *hwp, NULL, paddr, rdip, immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde == B_TRUE);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde nppages--;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde nvpages--;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde paddr += IMMU_PAGESIZE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvma += IMMU_PAGESIZE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (nppages == 0) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde j++;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (j == dcount)
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde break;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (nppages == 0) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde nppages = dcookies[j].dck_npages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde paddr = dcookies[j].dck_paddr;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (nvpages) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde *dvma_ptr = dvma;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde *nvpages_ptr = nvpages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde } else {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde *dvma_ptr = 0;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde *nvpages_ptr = 0;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde xlate->xlt_idx = idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*ARGSUSED*/
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram HegdePDE_set_one(immu_t *immu, hw_pdte_t *hwp, pgtable_t *next,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *rdip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_pdte_t pde;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pde = *hwp;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* if PDE is already set, make sure it is correct */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (PDTE_P(pde)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(PDTE_PADDR(pde) == next->hwpg_paddr);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#ifdef BUGGY_DRIVERS
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#else
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde goto out;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#endif
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Dont touch SW4, it is the present bit */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* don't touch TM field it is reserved for PDEs */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* 3rd field available for system software is not used */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_SW3(pde);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Set next level pgtable-paddr for PDE */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_PADDR(pde);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_SET_PADDR(pde, next->hwpg_paddr);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* don't touch SNP field it is reserved for PDEs */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Clear second field available for system software */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_SW2(pde);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* No super pages for PDEs */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_SP(pde);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Clear SW1 for software */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_CLEAR_SW1(pde);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Now that we are done writing the PDE
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * set the "present" flag. Note this present
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * flag is a bit in the PDE/PTE that the
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * spec says is available for system software.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * This is an implementation detail of Solaris
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * base-metal Intel IOMMU.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * The present field in a PDE/PTE is not defined
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * by the Vt-d spec
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdeout:
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#ifdef BUGGY_DRIVERS
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde PDTE_SET_READ(pde);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde PDTE_SET_WRITE(pde);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde#else
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_flags & IMMU_FLAGS_READ)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_SET_READ(pde);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_flags & IMMU_FLAGS_WRITE)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_SET_WRITE(pde);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde#endif
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_SET_P(pde);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *hwp = pde;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Used to set PDEs
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdestatic boolean_t
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram HegdePDE_set_all(immu_t *immu, domain_t *domain, xlate_t *xlate, int nlevels,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *rdip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *pgtable;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *new;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable_t *next;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_pdte_t *hwp;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int level;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint_t idx;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde krw_t rwtype;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde boolean_t set = B_FALSE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* start with highest level pgtable i.e. root */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde xlate += nlevels;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde new = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde xlate->xlt_pgtable = domain->dom_pgtable_root;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde for (level = nlevels; level > 1; level--, xlate--) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde idx = xlate->xlt_idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pgtable = xlate->xlt_pgtable;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /* Lock the pgtable in READ mode first */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_enter(&(pgtable->swpg_rwlock), RW_READER);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rwtype = RW_READER;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdeagain:
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hwp = (hw_pdte_t *)(pgtable->hwpg_vaddr) + idx;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde next = (pgtable->swpg_next_array)[idx];
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * check if leafier level already has a pgtable
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * if yes, verify
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (next == NULL) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (new == NULL) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden IMMU_DPROBE2(immu__pdp__alloc, dev_info_t *,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden rdip, int, level);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden new = pgtable_alloc(immu, immu_flags);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (new == NULL) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_PANIC, rdip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "pgtable alloc err");
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pgtable_zero(new);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /* Change to a write lock */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (rwtype == RW_READER &&
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_tryupgrade(&(pgtable->swpg_rwlock)) == 0) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_exit(&(pgtable->swpg_rwlock));
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_enter(&(pgtable->swpg_rwlock), RW_WRITER);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rwtype = RW_WRITER;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde goto again;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rwtype = RW_WRITER;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde next = new;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (pgtable->swpg_next_array)[idx] = next;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden new = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDE_set_one(immu, hwp, next, rdip, immu_flags);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde set = B_TRUE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rw_downgrade(&(pgtable->swpg_rwlock));
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rwtype = RW_READER;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#ifndef BUGGY_DRIVERS
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde hw_pdte_t pde = *hwp;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * If buggy driver we already set permission
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * READ+WRITE so nothing to do for that case
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * XXX Check that read writer perms change before
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * actually setting perms. Also need to hold lock
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_flags & IMMU_FLAGS_READ)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_SET_READ(pde);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_flags & IMMU_FLAGS_WRITE)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde PDTE_SET_WRITE(pde);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *hwp = pde;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#endif
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ASSERT(PDTE_check(immu, *hwp, next, 0, rdip, immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde == B_TRUE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde (xlate - 1)->xlt_pgtable = next;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde rw_exit(&(pgtable->swpg_rwlock));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (new) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde pgtable_free(immu, new);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return (set);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * dvma_map()
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * map a contiguous range of DVMA pages
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * immu: IOMMU unit for which we are generating DVMA cookies
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * domain: domain
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * sdvma: Starting dvma
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * spaddr: Starting paddr
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * npages: Number of pages
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * rdip: requesting device
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * immu_flags: flags
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegdestatic boolean_t
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindendvma_map(domain_t *domain, uint64_t sdvma, uint64_t snvpages,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_dcookie_t *dcookies, int dcount, dev_info_t *rdip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t dvma;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t n;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_t *immu = domain->dom_immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int nlevels = immu->immu_dvma_nlevels;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde xlate_t xlate[IMMU_PGTABLE_MAX_LEVELS + 1] = {0};
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde boolean_t pde_set = B_FALSE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde n = snvpages;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvma = sdvma;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde while (n > 0) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xlate_setup(dvma, xlate, nlevels);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Lookup or allocate PGDIRs and PGTABLEs if necessary */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (PDE_set_all(immu, domain, xlate, nlevels, rdip, immu_flags)
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde == B_TRUE) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde pde_set = B_TRUE;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* set all matching ptes that fit into this leaf pgtable */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde PTE_set_all(immu, domain, &xlate[1], &dvma, &n, dcookies,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcount, rdip, immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return (pde_set);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * dvma_unmap()
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * unmap a range of DVMAs
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde *
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * immu: IOMMU unit state
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * domain: domain for requesting device
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * ddip: domain-dip
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * dvma: starting DVMA
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * npages: Number of IMMU pages to be unmapped
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * rdip: requesting device
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindendvma_unmap(domain_t *domain, uint64_t sdvma, uint64_t snpages,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dev_info_t *rdip)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_t *immu = domain->dom_immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde int nlevels = immu->immu_dvma_nlevels;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde xlate_t xlate[IMMU_PGTABLE_MAX_LEVELS + 1] = {0};
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde uint64_t n;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde uint64_t dvma;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dvma = sdvma;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde n = snpages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde while (n > 0) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* setup the xlate array */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xlate_setup(dvma, xlate, nlevels);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* just lookup existing pgtables. Should never fail */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (!PDE_lookup(domain, xlate, nlevels))
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_PANIC, rdip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "PTE not found for addr %" PRIx64,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (unsigned long long)dvma);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /* clear all matching ptes that fit into this leaf pgtable */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde PTE_clear_all(immu, domain, &xlate[1], &dvma, &n, rdip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /* No need to flush IOTLB after unmap */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic uint64_t
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindendvma_alloc(domain_t *domain, ddi_dma_attr_t *dma_attr, uint_t npages, int kmf)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t dvma;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde size_t xsize, align;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t minaddr, maxaddr;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* parameters */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde xsize = npages * IMMU_PAGESIZE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde align = MAX((size_t)(dma_attr->dma_attr_align), IMMU_PAGESIZE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde minaddr = dma_attr->dma_attr_addr_lo;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde maxaddr = dma_attr->dma_attr_addr_hi + 1;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* handle the rollover cases */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (maxaddr < dma_attr->dma_attr_addr_hi) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde maxaddr = dma_attr->dma_attr_addr_hi;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * allocate from vmem arena.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde dvma = (uint64_t)(uintptr_t)vmem_xalloc(domain->dom_dvma_arena,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde xsize, align, 0, 0, (void *)(uintptr_t)minaddr,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void *)(uintptr_t)maxaddr, kmf);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (dvma);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindendvma_prealloc(dev_info_t *rdip, immu_hdl_priv_t *ihp, ddi_dma_attr_t *dma_attr)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden int nlevels;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xlate_t xlate[IMMU_PGTABLE_MAX_LEVELS + 1] = {0}, *xlp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t dvma, n;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden size_t xsize, align;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t minaddr, maxaddr, dmamax;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden int on, npte, pindex;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden hw_pdte_t *shwp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_t *immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain_t *domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden /* parameters */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain = IMMU_DEVI(rdip)->imd_domain;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu = domain->dom_immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden nlevels = immu->immu_dvma_nlevels;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xsize = IMMU_NPREPTES * IMMU_PAGESIZE;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden align = MAX((size_t)(dma_attr->dma_attr_align), IMMU_PAGESIZE);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden minaddr = dma_attr->dma_attr_addr_lo;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (dma_attr->dma_attr_flags & _DDI_DMA_BOUNCE_ON_SEG)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dmamax = dma_attr->dma_attr_seg;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden else
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dmamax = dma_attr->dma_attr_addr_hi;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden maxaddr = dmamax + 1;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (maxaddr < dmamax)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden maxaddr = dmamax;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma = (uint64_t)(uintptr_t)vmem_xalloc(domain->dom_dvma_arena,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xsize, align, 0, dma_attr->dma_attr_seg + 1,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void *)(uintptr_t)minaddr, (void *)(uintptr_t)maxaddr, VM_NOSLEEP);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp->ihp_predvma = dvma;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp->ihp_npremapped = 0;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (dvma == 0)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden n = IMMU_NPREPTES;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pindex = 0;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * Set up a mapping at address 0, just so that all PDPs get allocated
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * now. Although this initial mapping should never be used,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * explicitly set it to read-only, just to be safe.
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden while (n > 0) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xlate_setup(dvma, xlate, nlevels);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void) PDE_set_all(immu, domain, xlate, nlevels, rdip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden IMMU_FLAGS_READ | IMMU_FLAGS_WRITE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden xlp = &xlate[1];
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden shwp = (hw_pdte_t *)(xlp->xlt_pgtable->hwpg_vaddr)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden + xlp->xlt_idx;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden on = n;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden PTE_set_all(immu, domain, xlp, &dvma, &n, &immu_precookie,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden 1, rdip, IMMU_FLAGS_READ);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden npte = on - n;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden while (npte > 0) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp->ihp_preptes[pindex++] = shwp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#ifdef BUGGY_DRIVERS
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden PDTE_CLEAR_WRITE(*shwp);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#endif
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden shwp++;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden npte--;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic void
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindendvma_prefree(dev_info_t *rdip, immu_hdl_priv_t *ihp)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain_t *domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain = IMMU_DEVI(rdip)->imd_domain;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (ihp->ihp_predvma != 0) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma_unmap(domain, ihp->ihp_predvma, IMMU_NPREPTES, rdip);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden vmem_free(domain->dom_dvma_arena,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void *)(uintptr_t)ihp->ihp_predvma,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden IMMU_NPREPTES * IMMU_PAGESIZE);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdestatic void
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindendvma_free(domain_t *domain, uint64_t dvma, uint64_t npages)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t size = npages * IMMU_PAGESIZE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (domain->dom_maptype != IMMU_MAPTYPE_XLATE)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden vmem_free(domain->dom_dvma_arena, (void *)(uintptr_t)dvma, size);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_map_dvmaseg(dev_info_t *rdip, ddi_dma_handle_t handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_hdl_priv_t *ihp, struct ddi_dma_req *dmareq,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_dma_obj_t *dma_out)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain_t *domain;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_t *immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_flags_t immu_flags;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_dma_atyp_t buftype;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_dma_obj_t *dmar_object;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_dma_attr_t *attrp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t offset, paddr, dvma, sdvma, rwmask;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden size_t npages, npgalloc;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint_t psize, size, pcnt, dmax;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden page_t **pparray;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden caddr_t vaddr;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden page_t *page;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden struct as *vas;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_dcookie_t *dcookies;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden int pde_set;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain = IMMU_DEVI(rdip)->imd_domain;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu = domain->dom_immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_flags = dma_to_immu_flags(dmareq);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden attrp = &((ddi_dma_impl_t *)handle)->dmai_attr;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dmar_object = &dmareq->dmar_object;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pparray = dmar_object->dmao_obj.virt_obj.v_priv;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde vaddr = dmar_object->dmao_obj.virt_obj.v_addr;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde buftype = dmar_object->dmao_type;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde size = dmar_object->dmao_size;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden IMMU_DPROBE3(immu__map__dvma, dev_info_t *, rdip, ddi_dma_atyp_t,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden buftype, uint_t, size);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dcookies = &ihp->ihp_dcookies[0];
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pcnt = dmax = 0;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* retrieve paddr, psize, offset from dmareq */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (buftype == DMA_OTYP_PAGES) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde page = dmar_object->dmao_obj.pp_obj.pp_pp;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde offset = dmar_object->dmao_obj.pp_obj.pp_offset &
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde MMU_PAGEOFFSET;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde paddr = pfn_to_pa(page->p_pagenum) + offset;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde psize = MIN((MMU_PAGESIZE - offset), size);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde page = page->p_next;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden vas = dmar_object->dmao_obj.virt_obj.v_as;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (vas == NULL) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden vas = &kas;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde offset = (uintptr_t)vaddr & MMU_PAGEOFFSET;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (pparray != NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde paddr = pfn_to_pa(pparray[pcnt]->p_pagenum) + offset;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde psize = MIN((MMU_PAGESIZE - offset), size);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pcnt++;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden paddr = pfn_to_pa(hat_getpfnum(vas->a_hat,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde vaddr)) + offset;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde psize = MIN(size, (MMU_PAGESIZE - offset));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde vaddr += psize;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden npgalloc = IMMU_BTOPR(size + offset);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (npgalloc <= IMMU_NPREPTES && ihp->ihp_predvma != 0) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#ifdef BUGGY_DRIVERS
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden rwmask = PDTE_MASK_R | PDTE_MASK_W | immu->immu_ptemask;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#else
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden rwmask = immu->immu_ptemask;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (immu_flags & IMMU_FLAGS_READ)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden rwmask |= PDTE_MASK_R;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (immu_flags & IMMU_FLAGS_WRITE)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden rwmask |= PDTE_MASK_W;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#endif
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#ifdef DEBUG
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden rwmask |= PDTE_MASK_P;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#endif
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden sdvma = ihp->ihp_predvma;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp->ihp_npremapped = npgalloc;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden *ihp->ihp_preptes[0] =
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden PDTE_PADDR(paddr & ~MMU_PAGEOFFSET) | rwmask;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden } else {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp->ihp_npremapped = 0;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden sdvma = dvma_alloc(domain, attrp, npgalloc,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dmareq->dmar_fp == DDI_DMA_SLEEP ? VM_SLEEP : VM_NOSLEEP);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (sdvma == 0)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_DMA_NORESOURCES);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dcookies[0].dck_paddr = (paddr & ~MMU_PAGEOFFSET);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dcookies[0].dck_npages = 1;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden IMMU_DPROBE3(immu__dvma__alloc, dev_info_t *, rdip, uint64_t, npgalloc,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t, sdvma);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma = sdvma;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pde_set = 0;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden npages = 1;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde size -= psize;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde while (size > 0) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* get the size for this page (i.e. partial or full page) */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde psize = MIN(size, MMU_PAGESIZE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (buftype == DMA_OTYP_PAGES) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* get the paddr from the page_t */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde paddr = pfn_to_pa(page->p_pagenum);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde page = page->p_next;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else if (pparray != NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* index into the array of page_t's to get the paddr */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde paddr = pfn_to_pa(pparray[pcnt]->p_pagenum);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde pcnt++;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde } else {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* call into the VM to get the paddr */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden paddr = pfn_to_pa(hat_getpfnum(vas->a_hat, vaddr));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde vaddr += psize;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden npages++;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (ihp->ihp_npremapped > 0) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden *ihp->ihp_preptes[npages - 1] =
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden PDTE_PADDR(paddr) | rwmask;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden } else if (IMMU_CONTIG_PADDR(dcookies[dmax], paddr)) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dcookies[dmax].dck_npages++;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden } else {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden /* No, we need a new dcookie */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (dmax == (IMMU_NDCK - 1)) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden /*
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * Ran out of dcookies. Map them now.
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (dvma_map(domain, dvma,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden npages, dcookies, dmax + 1, rdip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_flags))
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pde_set++;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden IMMU_DPROBE4(immu__dvmamap__early,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *, rdip, uint64_t, dvma,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint_t, npages, uint_t, dmax+1);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma += (npages << IMMU_PAGESHIFT);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden npages = 0;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dmax = 0;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden } else
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dmax++;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dcookies[dmax].dck_paddr = paddr;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dcookies[dmax].dck_npages = 1;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde size -= psize;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden /*
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * Finish up, mapping all, or all of the remaining,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * physical memory ranges.
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (ihp->ihp_npremapped == 0 && npages > 0) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden IMMU_DPROBE4(immu__dvmamap__late, dev_info_t *, rdip, \
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t, dvma, uint_t, npages, uint_t, dmax+1);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (dvma_map(domain, dvma, npages, dcookies,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dmax + 1, rdip, immu_flags))
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pde_set++;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden /* Invalidate the IOTLB */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_flush_iotlb_psi(immu, domain->dom_did, sdvma, npgalloc,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pde_set > 0 ? TLB_IVA_WHOLE : TLB_IVA_LEAF,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden &ihp->ihp_inv_wait);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp->ihp_ndvseg = 1;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp->ihp_dvseg[0].dvs_start = sdvma;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp->ihp_dvseg[0].dvs_len = dmar_object->dmao_size;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dma_out->dmao_size = dmar_object->dmao_size;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dma_out->dmao_obj.dvma_obj.dv_off = offset & IMMU_PAGEOFFSET;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dma_out->dmao_obj.dvma_obj.dv_nseg = 1;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dma_out->dmao_obj.dvma_obj.dv_seg = &ihp->ihp_dvseg[0];
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dma_out->dmao_type = DMA_OTYP_DVADDR;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_DMA_MAPPED);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_unmap_dvmaseg(dev_info_t *rdip, ddi_dma_obj_t *dmao)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t dvma, npages;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain_t *domain;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden struct dvmaseg *dvs;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain = IMMU_DEVI(rdip)->imd_domain;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvs = dmao->dmao_obj.dvma_obj.dv_seg;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma = dvs[0].dvs_start;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden npages = IMMU_BTOPR(dvs[0].dvs_len + dmao->dmao_obj.dvma_obj.dv_off);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#ifdef DEBUG
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden /* Unmap only in DEBUG mode */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma_unmap(domain, dvma, npages, rdip);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#endif
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma_free(domain, dvma, npages);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden IMMU_DPROBE3(immu__dvma__free, dev_info_t *, rdip, uint_t, npages,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint64_t, dvma);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#ifdef DEBUG
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden /*
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * In the DEBUG case, the unmap was actually done,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * but an IOTLB flush was not done. So, an explicit
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * write back flush is needed.
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_regs_wbf_flush(domain->dom_immu);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden#endif
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_SUCCESS);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/* ############################# Functions exported ######################## */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * setup the DVMA subsystem
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * this code runs only for the first IOMMU unit
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdevoid
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeimmu_dvma_setup(list_t *listp)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_t *immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint_t kval;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde size_t nchains;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* locks */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_init(&immu_domain_lock, NULL, MUTEX_DEFAULT, NULL);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Create lists */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde list_create(&immu_unity_domain_list, sizeof (domain_t),
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde offsetof(domain_t, dom_maptype_node));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde list_create(&immu_xlate_domain_list, sizeof (domain_t),
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde offsetof(domain_t, dom_maptype_node));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* Setup BDF domain hash */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde nchains = 0xff;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde kval = mod_hash_iddata_gen(nchains);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde bdf_domain_hash = mod_hash_create_extended("BDF-DOMAIN_HASH",
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde nchains, mod_hash_null_keydtor, mod_hash_null_valdtor,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mod_hash_byid, (void *)(uintptr_t)kval, mod_hash_idkey_cmp,
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde KM_NOSLEEP);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu = list_head(listp);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde for (; immu; immu = list_next(listp, immu)) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde create_unity_domain(immu);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde did_init(immu);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde context_init(immu);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_dvma_setup = B_TRUE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Startup up one DVMA unit
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdevoid
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeimmu_dvma_startup(immu_t *immu)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_gfxdvma_enable == B_FALSE &&
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_dvma_gfx_only == B_TRUE) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * DVMA will start once IOMMU is "running"
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu->immu_dvma_running = B_TRUE;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde/*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * immu_dvma_physmem_update()
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * called when the installed memory on a
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * system increases, to expand domain DVMA
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * for domains with UNITY mapping
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdevoid
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeimmu_dvma_physmem_update(uint64_t addr, uint64_t size)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t start;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde uint64_t npages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde int dcount;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_dcookie_t dcookies[1] = {0};
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain_t *domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Just walk the system-wide list of domains with
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * UNITY mapping. Both the list of *all* domains
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * and *UNITY* domains is protected by the same
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * single lock
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_enter(&immu_domain_lock);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = list_head(&immu_unity_domain_list);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde for (; domain; domain = list_next(&immu_unity_domain_list, domain)) {
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden /*
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden * Nothing to do if the IOMMU supports passthrough.
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden */
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden if (IMMU_ECAP_GET_PT(domain->dom_immu->immu_regs_excap))
be56ae3626e635d164d03331df68da0fea8a8862Frank Van Der Linden continue;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /* There is no vmem_arena for unity domains. Just map it */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_LOG, domain->dom_dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden "iommu: unity-domain: Adding map "
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde "[0x%" PRIx64 " - 0x%" PRIx64 "]", addr, addr + size);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde start = IMMU_ROUNDOWN(addr);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde npages = (IMMU_ROUNDUP(size) / IMMU_PAGESIZE) + 1;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_paddr = start;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies[0].dck_npages = npages;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcount = 1;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void) dvma_map(domain, start, npages,
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde dcookies, dcount, NULL, IMMU_FLAGS_READ | IMMU_FLAGS_WRITE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde mutex_exit(&immu_domain_lock);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeint
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_dvma_device_setup(dev_info_t *rdip, immu_flags_t immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *ddip, *odip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_t *immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain_t *domain;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden odip = rdip;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde immu = immu_dvma_get_immu(rdip, immu_flags);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (immu == NULL) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * possible that there is no IOMMU unit for this device
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * - BIOS bugs are one example.
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_WARN, rdip, "No iommu unit found for device");
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde return (DDI_DMA_NORESOURCES);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * redirect isa devices attached under lpc to lpc dip
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (strcmp(ddi_node_name(ddi_get_parent(rdip)), "isa") == 0) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rdip = get_lpc_devinfo(immu, rdip, immu_flags);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (rdip == NULL) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_PANIC, rdip, "iommu redirect failed");
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*NOTREACHED*/
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /* Reset immu, as redirection can change IMMU */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde immu = NULL;
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde * for gart, redirect to the real graphic devinfo
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde */
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (strcmp(ddi_node_name(rdip), "agpgart") == 0) {
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde rdip = get_gfx_devinfo(rdip);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde if (rdip == NULL) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ddi_err(DER_PANIC, rdip, "iommu redirect failed");
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*NOTREACHED*/
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Setup DVMA domain for the device. This does
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * work only the first time we do DVMA for a
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * device.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddip = NULL;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain = device_domain(rdip, &ddip, immu_flags);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (domain == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "Intel IOMMU setup failed for device");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_DMA_NORESOURCES);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu = domain->dom_immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * If a domain is found, we must also have a domain dip
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * which is the topmost ancestor dip of rdip that shares
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * the same domain with rdip.
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (domain->dom_did == 0 || ddip == NULL) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "domain did 0(%d) or ddip NULL(%p)",
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde domain->dom_did, ddip);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_DMA_NORESOURCES);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (odip != rdip)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden set_domain(odip, ddip, domain);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde /*
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde * Update the root and context entries
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde */
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde if (immu_context_update(immu, domain, ddip, rdip, immu_flags)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde != DDI_SUCCESS) {
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde ddi_err(DER_MODE, rdip, "DVMA map: context update failed");
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde return (DDI_DMA_NORESOURCES);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_SUCCESS);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegdeint
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_map_memrange(dev_info_t *rdip, memrng_t *mrng)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_dcookie_t dcookies[1] = {0};
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden boolean_t pde_set;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde immu_t *immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain_t *domain;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_inv_wait_t iw;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dcookies[0].dck_paddr = mrng->mrng_start;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dcookies[0].dck_npages = mrng->mrng_npages;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden domain = IMMU_DEVI(rdip)->imd_domain;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu = domain->dom_immu;
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden pde_set = dvma_map(domain, mrng->mrng_start,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden mrng->mrng_npages, dcookies, 1, rdip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden IMMU_FLAGS_READ | IMMU_FLAGS_WRITE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_init_inv_wait(&iw, "memrange", B_TRUE);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_flush_iotlb_psi(immu, domain->dom_did, mrng->mrng_start,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden mrng->mrng_npages, pde_set == B_TRUE ?
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden TLB_IVA_WHOLE : TLB_IVA_LEAF, &iw);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_SUCCESS);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_devi_t *
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_devi_get(dev_info_t *rdip)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_devi_t *immu_devi;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden volatile uintptr_t *vptr = (uintptr_t *)&(DEVI(rdip)->devi_iommu);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden /* Just want atomic reads. No need for lock */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_devi = (immu_devi_t *)(uintptr_t)atomic_or_64_nv((uint64_t *)vptr,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden 0);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (immu_devi);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenint
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_hdl_priv_ctor(void *buf, void *arg, int kmf)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_hdl_priv_t *ihp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp = buf;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_init_inv_wait(&ihp->ihp_inv_wait, "dmahandle", B_FALSE);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (0);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * iommulib interface functions
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_probe(iommulib_handle_t handle, dev_info_t *dip)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_devi_t *immu_devi;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden int ret;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (!immu_enable)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_FAILURE);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * Make sure the device has all the IOMMU structures
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * initialized. If this device goes through an IOMMU
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * unit (e.g. this probe function returns success),
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * this will be called at most N times, with N being
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * the number of IOMMUs in the system.
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden *
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * After that, when iommulib_nex_open succeeds,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * we can always assume that this device has all
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * the structures initialized. IOMMU_USED(dip) will
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * be true. There is no need to find the controlling
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * IOMMU/domain again.
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ret = immu_dvma_device_setup(dip, IMMU_FLAGS_NOSLEEP);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (ret != DDI_SUCCESS)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (ret);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_devi = IMMU_DEVI(dip);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde /*
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * For unity domains, there is no need to call in to
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden * the IOMMU code.
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde */
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (immu_devi->imd_domain->dom_did == IMMU_UNITY_DID)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_FAILURE);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (immu_devi->imd_immu->immu_dip == iommulib_iommu_getdip(handle))
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_SUCCESS);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_FAILURE);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_allochdl(iommulib_handle_t handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *dma_handlep)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden int ret;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_hdl_priv_t *ihp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_t *immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ret = iommulib_iommu_dma_allochdl(dip, rdip, attr, waitfp,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden arg, dma_handlep);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (ret == DDI_SUCCESS) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu = IMMU_DEVI(rdip)->imd_immu;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp = kmem_cache_alloc(immu->immu_hdl_cache,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden waitfp == DDI_DMA_SLEEP ? KM_SLEEP : KM_NOSLEEP);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (ihp == NULL) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden (void) iommulib_iommu_dma_freehdl(dip, rdip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden *dma_handlep);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_DMA_NORESOURCES);
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde }
e03dceed3deb85ad561202c77277e701f763fa13Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (IMMU_DEVI(rdip)->imd_use_premap)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma_prealloc(rdip, ihp, attr);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden else {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp->ihp_npremapped = 0;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp->ihp_predvma = 0;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ret = iommulib_iommu_dmahdl_setprivate(dip, rdip, *dma_handlep,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (ret);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_freehdl(iommulib_handle_t handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_hdl_priv_t *ihp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp = iommulib_iommu_dmahdl_getprivate(dip, rdip, dma_handle);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (ihp != NULL) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (IMMU_DEVI(rdip)->imd_use_premap)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dvma_prefree(rdip, ihp);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden kmem_cache_free(IMMU_DEVI(rdip)->imd_immu->immu_hdl_cache, ihp);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (iommulib_iommu_dma_freehdl(dip, rdip, dma_handle));
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_bindhdl(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden struct ddi_dma_req *dma_req, ddi_dma_cookie_t *cookiep,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint_t *ccountp)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden int ret;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_hdl_priv_t *ihp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ret = iommulib_iommu_dma_bindhdl(dip, rdip, dma_handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dma_req, cookiep, ccountp);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (ret == DDI_DMA_MAPPED) {
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp = iommulib_iommu_dmahdl_getprivate(dip, rdip, dma_handle);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_flush_wait(IMMU_DEVI(rdip)->imd_immu, &ihp->ihp_inv_wait);
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde }
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (ret);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_unbindhdl(iommulib_handle_t handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (iommulib_iommu_dma_unbindhdl(dip, rdip, dma_handle));
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_sync(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle, off_t off,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden size_t len, uint_t cachefl)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (iommulib_iommu_dma_sync(dip, rdip, dma_handle, off, len,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden cachefl));
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_win(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle, uint_t win,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden uint_t *ccountp)
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (iommulib_iommu_dma_win(dip, rdip, dma_handle, win, offp,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden lenp, cookiep, ccountp));
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
3a634bfc9a31448c742688c603d3e76b83b041a0Vikram Hegde
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_mapobject(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden struct ddi_dma_req *dmareq, ddi_dma_obj_t *dmao)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_hdl_priv_t *ihp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp = iommulib_iommu_dmahdl_getprivate(dip, rdip, dma_handle);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (immu_map_dvmaseg(rdip, dma_handle, ihp, dmareq, dmao));
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenimmu_unmapobject(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden immu_hdl_priv_t *ihp;
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden ihp = iommulib_iommu_dmahdl_getprivate(dip, rdip, dma_handle);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden if (ihp->ihp_npremapped > 0)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_SUCCESS);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (immu_unmap_dvmaseg(rdip, dmao));
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}