mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
Merge tag 'iommu-updates-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull iommu updates from Joerg Roedel:
"Core changes:
- Consolidate probe_device path
- Make the PCI-SAC IOVA allocation trick PCI-only
AMD IOMMU:
- Consolidate PPR log handling
- Interrupt handling improvements
- Refcount fixes for amd_iommu_v2 driver
Intel VT-d driver:
- Enable idxd device DMA with pasid through iommu dma ops
- Lift RESV_DIRECT check from VT-d driver to core
- Miscellaneous cleanups and fixes
ARM-SMMU drivers:
- Device-tree binding updates:
- Add additional compatible strings for Qualcomm SoCs
- Allow ASIDs to be configured in the DT to work around Qualcomm's
broken hypervisor
- Fix clocks for Qualcomm's MSM8998 SoC
- SMMUv2:
- Support for Qualcomm's legacy firmware implementation featured
on at least MSM8956 and MSM8976
- Match compatible strings for Qualcomm SM6350 and SM6375 SoC
variants
- SMMUv3:
- Use 'ida' instead of a bitmap for VMID allocation
- Rockchip IOMMU:
- Lift page-table allocation restrictions on newer hardware
- Mediatek IOMMU:
- Add MT8188 IOMMU Support
- Renesas IOMMU:
- Allow PCIe devices
.. and the usual set of cleanups an smaller fixes"
* tag 'iommu-updates-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (64 commits)
iommu: Explicitly include correct DT includes
iommu/amd: Remove unused declarations
iommu/arm-smmu-qcom: Add SM6375 SMMUv2
iommu/arm-smmu-qcom: Add SM6350 DPU compatible
iommu/arm-smmu-qcom: Add SM6375 DPU compatible
iommu/arm-smmu-qcom: Sort the compatible list alphabetically
dt-bindings: arm-smmu: Fix MSM8998 clocks description
iommu/vt-d: Remove unused extern declaration dmar_parse_dev_scope()
iommu/vt-d: Fix to convert mm pfn to dma pfn
iommu/vt-d: Fix to flush cache of PASID directory table
iommu/vt-d: Remove rmrr check in domain attaching device path
iommu: Prevent RESV_DIRECT devices from blocking domains
dmaengine/idxd: Re-enable kernel workqueue under DMA API
iommu/vt-d: Add set_dev_pasid callback for dma domain
iommu/vt-d: Prepare for set_dev_pasid callback
iommu/vt-d: Make prq draining code generic
iommu/vt-d: Remove pasid_mutex
iommu/vt-d: Add domain_flush_pasid_iotlb()
iommu: Move global PASID allocation from SVA to core
iommu: Generalize PASID 0 for normal DMA w/o PASID
...
This commit is contained in:
@@ -270,6 +270,47 @@ allOf:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,msm8998-smmu-v2
|
||||
then:
|
||||
anyOf:
|
||||
- properties:
|
||||
clock-names:
|
||||
items:
|
||||
- const: bus
|
||||
clocks:
|
||||
items:
|
||||
- description: bus clock required for downstream bus access and for
|
||||
the smmu ptw
|
||||
- properties:
|
||||
clock-names:
|
||||
items:
|
||||
- const: iface
|
||||
- const: mem
|
||||
- const: mem_iface
|
||||
clocks:
|
||||
items:
|
||||
- description: interface clock required to access smmu's registers
|
||||
through the TCU's programming interface.
|
||||
- description: bus clock required for memory access
|
||||
- description: bus clock required for GPU memory access
|
||||
- properties:
|
||||
clock-names:
|
||||
items:
|
||||
- const: iface-mm
|
||||
- const: iface-smmu
|
||||
- const: bus-smmu
|
||||
clocks:
|
||||
items:
|
||||
- description: interface clock required to access mnoc's registers
|
||||
through the TCU's programming interface.
|
||||
- description: interface clock required to access smmu's registers
|
||||
through the TCU's programming interface.
|
||||
- description: bus clock required for the smmu ptw
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sdm630-smmu-v2
|
||||
- qcom,sm6375-smmu-v2
|
||||
then:
|
||||
|
||||
@@ -78,6 +78,9 @@ properties:
|
||||
- mediatek,mt8173-m4u # generation two
|
||||
- mediatek,mt8183-m4u # generation two
|
||||
- mediatek,mt8186-iommu-mm # generation two
|
||||
- mediatek,mt8188-iommu-vdo # generation two
|
||||
- mediatek,mt8188-iommu-vpp # generation two
|
||||
- mediatek,mt8188-iommu-infra # generation two
|
||||
- mediatek,mt8192-m4u # generation two
|
||||
- mediatek,mt8195-iommu-vdo # generation two
|
||||
- mediatek,mt8195-iommu-vpp # generation two
|
||||
@@ -123,6 +126,7 @@ properties:
|
||||
description: |
|
||||
This is the mtk_m4u_id according to the HW. Specifies the mtk_m4u_id as
|
||||
defined in
|
||||
dt-binding/memory/mediatek,mt8188-memory-port.h for mt8188,
|
||||
dt-binding/memory/mt2701-larb-port.h for mt2701 and mt7623,
|
||||
dt-binding/memory/mt2712-larb-port.h for mt2712,
|
||||
dt-binding/memory/mt6779-larb-port.h for mt6779,
|
||||
@@ -155,6 +159,8 @@ allOf:
|
||||
- mediatek,mt6795-m4u
|
||||
- mediatek,mt8173-m4u
|
||||
- mediatek,mt8186-iommu-mm
|
||||
- mediatek,mt8188-iommu-vdo
|
||||
- mediatek,mt8188-iommu-vpp
|
||||
- mediatek,mt8192-m4u
|
||||
- mediatek,mt8195-iommu-vdo
|
||||
- mediatek,mt8195-iommu-vpp
|
||||
@@ -168,6 +174,8 @@ allOf:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8186-iommu-mm
|
||||
- mediatek,mt8188-iommu-vdo
|
||||
- mediatek,mt8188-iommu-vpp
|
||||
- mediatek,mt8192-m4u
|
||||
- mediatek,mt8195-iommu-vdo
|
||||
- mediatek,mt8195-iommu-vpp
|
||||
@@ -194,7 +202,9 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: mediatek,mt8195-iommu-infra
|
||||
enum:
|
||||
- mediatek,mt8188-iommu-infra
|
||||
- mediatek,mt8195-iommu-infra
|
||||
|
||||
then:
|
||||
required:
|
||||
|
||||
@@ -17,11 +17,16 @@ description: |
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- qcom,msm8916-iommu
|
||||
- qcom,msm8953-iommu
|
||||
- const: qcom,msm-iommu-v1
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,msm8916-iommu
|
||||
- qcom,msm8953-iommu
|
||||
- const: qcom,msm-iommu-v1
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,msm8976-iommu
|
||||
- const: qcom,msm-iommu-v2
|
||||
|
||||
clocks:
|
||||
items:
|
||||
@@ -64,6 +69,8 @@ patternProperties:
|
||||
enum:
|
||||
- qcom,msm-iommu-v1-ns
|
||||
- qcom,msm-iommu-v1-sec
|
||||
- qcom,msm-iommu-v2-ns
|
||||
- qcom,msm-iommu-v2-sec
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
@@ -71,6 +78,11 @@ patternProperties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
qcom,ctx-asid:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
The ASID number associated to the context bank.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- interrupts
|
||||
|
||||
@@ -13356,6 +13356,7 @@ L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/iommu/mediatek*
|
||||
F: drivers/iommu/mtk_iommu*
|
||||
F: include/dt-bindings/memory/mediatek,mt*-port.h
|
||||
F: include/dt-bindings/memory/mt*-port.h
|
||||
|
||||
MEDIATEK JPEG DRIVER
|
||||
|
||||
@@ -1584,7 +1584,7 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev,
|
||||
* If we have reason to believe the IOMMU driver missed the initial
|
||||
* iommu_probe_device() call for dev, replay it to get things in order.
|
||||
*/
|
||||
if (!err && dev->bus && !device_iommu_mapped(dev))
|
||||
if (!err && dev->bus)
|
||||
err = iommu_probe_device(dev);
|
||||
|
||||
/* Ignore all other errors apart from EPROBE_DEFER */
|
||||
|
||||
@@ -299,21 +299,6 @@ void idxd_wqs_unmap_portal(struct idxd_device *idxd)
|
||||
}
|
||||
}
|
||||
|
||||
static void __idxd_wq_set_priv_locked(struct idxd_wq *wq, int priv)
|
||||
{
|
||||
struct idxd_device *idxd = wq->idxd;
|
||||
union wqcfg wqcfg;
|
||||
unsigned int offset;
|
||||
|
||||
offset = WQCFG_OFFSET(idxd, wq->id, WQCFG_PRIVL_IDX);
|
||||
spin_lock(&idxd->dev_lock);
|
||||
wqcfg.bits[WQCFG_PRIVL_IDX] = ioread32(idxd->reg_base + offset);
|
||||
wqcfg.priv = priv;
|
||||
wq->wqcfg->bits[WQCFG_PRIVL_IDX] = wqcfg.bits[WQCFG_PRIVL_IDX];
|
||||
iowrite32(wqcfg.bits[WQCFG_PRIVL_IDX], idxd->reg_base + offset);
|
||||
spin_unlock(&idxd->dev_lock);
|
||||
}
|
||||
|
||||
static void __idxd_wq_set_pasid_locked(struct idxd_wq *wq, int pasid)
|
||||
{
|
||||
struct idxd_device *idxd = wq->idxd;
|
||||
@@ -1421,15 +1406,14 @@ int drv_enable_wq(struct idxd_wq *wq)
|
||||
}
|
||||
|
||||
/*
|
||||
* In the event that the WQ is configurable for pasid and priv bits.
|
||||
* For kernel wq, the driver should setup the pasid, pasid_en, and priv bit.
|
||||
* However, for non-kernel wq, the driver should only set the pasid_en bit for
|
||||
* shared wq. A dedicated wq that is not 'kernel' type will configure pasid and
|
||||
* In the event that the WQ is configurable for pasid, the driver
|
||||
* should setup the pasid, pasid_en bit. This is true for both kernel
|
||||
* and user shared workqueues. There is no need to setup priv bit in
|
||||
* that in-kernel DMA will also do user privileged requests.
|
||||
* A dedicated wq that is not 'kernel' type will configure pasid and
|
||||
* pasid_en later on so there is no need to setup.
|
||||
*/
|
||||
if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) {
|
||||
int priv = 0;
|
||||
|
||||
if (wq_pasid_enabled(wq)) {
|
||||
if (is_idxd_wq_kernel(wq) || wq_shared(wq)) {
|
||||
u32 pasid = wq_dedicated(wq) ? idxd->pasid : 0;
|
||||
@@ -1437,10 +1421,6 @@ int drv_enable_wq(struct idxd_wq *wq)
|
||||
__idxd_wq_set_pasid_locked(wq, pasid);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_idxd_wq_kernel(wq))
|
||||
priv = 1;
|
||||
__idxd_wq_set_priv_locked(wq, priv);
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
@@ -1548,6 +1528,15 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev)
|
||||
if (rc < 0)
|
||||
return -ENXIO;
|
||||
|
||||
/*
|
||||
* System PASID is preserved across device disable/enable cycle, but
|
||||
* genconfig register content gets cleared during device reset. We
|
||||
* need to re-enable user interrupts for kernel work queue completion
|
||||
* IRQ to function.
|
||||
*/
|
||||
if (idxd->pasid != IOMMU_PASID_INVALID)
|
||||
idxd_set_user_intr(idxd, 1);
|
||||
|
||||
rc = idxd_device_evl_setup(idxd);
|
||||
if (rc < 0) {
|
||||
idxd->cmd_status = IDXD_SCMD_DEV_EVL_ERR;
|
||||
|
||||
@@ -75,9 +75,10 @@ static inline void idxd_prep_desc_common(struct idxd_wq *wq,
|
||||
hw->xfer_size = len;
|
||||
/*
|
||||
* For dedicated WQ, this field is ignored and HW will use the WQCFG.priv
|
||||
* field instead. This field should be set to 1 for kernel descriptors.
|
||||
* field instead. This field should be set to 0 for kernel descriptors
|
||||
* since kernel DMA on VT-d supports "user" privilege only.
|
||||
*/
|
||||
hw->priv = 1;
|
||||
hw->priv = 0;
|
||||
hw->completion_addr = compl;
|
||||
}
|
||||
|
||||
|
||||
@@ -473,6 +473,15 @@ static inline struct idxd_device *ie_to_idxd(struct idxd_irq_entry *ie)
|
||||
return container_of(ie, struct idxd_device, ie);
|
||||
}
|
||||
|
||||
static inline void idxd_set_user_intr(struct idxd_device *idxd, bool enable)
|
||||
{
|
||||
union gencfg_reg reg;
|
||||
|
||||
reg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
|
||||
reg.user_int_en = enable;
|
||||
iowrite32(reg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET);
|
||||
}
|
||||
|
||||
extern struct bus_type dsa_bus_type;
|
||||
|
||||
extern bool support_enqcmd;
|
||||
|
||||
@@ -550,14 +550,59 @@ static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_d
|
||||
|
||||
static int idxd_enable_system_pasid(struct idxd_device *idxd)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
struct pci_dev *pdev = idxd->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct iommu_domain *domain;
|
||||
ioasid_t pasid;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Attach a global PASID to the DMA domain so that we can use ENQCMDS
|
||||
* to submit work on buffers mapped by DMA API.
|
||||
*/
|
||||
domain = iommu_get_domain_for_dev(dev);
|
||||
if (!domain)
|
||||
return -EPERM;
|
||||
|
||||
pasid = iommu_alloc_global_pasid(dev);
|
||||
if (pasid == IOMMU_PASID_INVALID)
|
||||
return -ENOSPC;
|
||||
|
||||
/*
|
||||
* DMA domain is owned by the driver, it should support all valid
|
||||
* types such as DMA-FQ, identity, etc.
|
||||
*/
|
||||
ret = iommu_attach_device_pasid(domain, dev, pasid);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to attach device pasid %d, domain type %d",
|
||||
pasid, domain->type);
|
||||
iommu_free_global_pasid(pasid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Since we set user privilege for kernel DMA, enable completion IRQ */
|
||||
idxd_set_user_intr(idxd, 1);
|
||||
idxd->pasid = pasid;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void idxd_disable_system_pasid(struct idxd_device *idxd)
|
||||
{
|
||||
struct pci_dev *pdev = idxd->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct iommu_domain *domain;
|
||||
|
||||
iommu_sva_unbind_device(idxd->sva);
|
||||
domain = iommu_get_domain_for_dev(dev);
|
||||
if (!domain)
|
||||
return;
|
||||
|
||||
iommu_detach_device_pasid(domain, dev, idxd->pasid);
|
||||
iommu_free_global_pasid(idxd->pasid);
|
||||
|
||||
idxd_set_user_intr(idxd, 0);
|
||||
idxd->sva = NULL;
|
||||
idxd->pasid = IOMMU_PASID_INVALID;
|
||||
}
|
||||
|
||||
static int idxd_enable_sva(struct pci_dev *pdev)
|
||||
@@ -600,8 +645,9 @@ static int idxd_probe(struct idxd_device *idxd)
|
||||
} else {
|
||||
set_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags);
|
||||
|
||||
if (idxd_enable_system_pasid(idxd))
|
||||
dev_warn(dev, "No in-kernel DMA with PASID.\n");
|
||||
rc = idxd_enable_system_pasid(idxd);
|
||||
if (rc)
|
||||
dev_warn(dev, "No in-kernel DMA with PASID. %d\n", rc);
|
||||
else
|
||||
set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
|
||||
}
|
||||
|
||||
@@ -948,13 +948,6 @@ static ssize_t wq_name_store(struct device *dev,
|
||||
if (strlen(buf) > WQ_NAME_SIZE || strlen(buf) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* This is temporarily placed here until we have SVM support for
|
||||
* dmaengine.
|
||||
*/
|
||||
if (wq->type == IDXD_WQT_KERNEL && device_pasid_enabled(wq->idxd))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
input = kstrndup(buf, count, GFP_KERNEL);
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -12,13 +12,14 @@
|
||||
#include "amd_iommu_types.h"
|
||||
|
||||
irqreturn_t amd_iommu_int_thread(int irq, void *data);
|
||||
irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data);
|
||||
irqreturn_t amd_iommu_int_thread_pprlog(int irq, void *data);
|
||||
irqreturn_t amd_iommu_int_thread_galog(int irq, void *data);
|
||||
irqreturn_t amd_iommu_int_handler(int irq, void *data);
|
||||
void amd_iommu_apply_erratum_63(struct amd_iommu *iommu, u16 devid);
|
||||
void amd_iommu_restart_event_logging(struct amd_iommu *iommu);
|
||||
void amd_iommu_restart_ga_log(struct amd_iommu *iommu);
|
||||
int amd_iommu_init_devices(void);
|
||||
void amd_iommu_uninit_devices(void);
|
||||
void amd_iommu_init_notifier(void);
|
||||
void amd_iommu_restart_ppr_log(struct amd_iommu *iommu);
|
||||
void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid);
|
||||
|
||||
#ifdef CONFIG_AMD_IOMMU_DEBUGFS
|
||||
|
||||
@@ -120,10 +120,13 @@
|
||||
#define PASID_MASK 0x0000ffff
|
||||
|
||||
/* MMIO status bits */
|
||||
#define MMIO_STATUS_EVT_OVERFLOW_INT_MASK BIT(0)
|
||||
#define MMIO_STATUS_EVT_OVERFLOW_MASK BIT(0)
|
||||
#define MMIO_STATUS_EVT_INT_MASK BIT(1)
|
||||
#define MMIO_STATUS_COM_WAIT_INT_MASK BIT(2)
|
||||
#define MMIO_STATUS_EVT_RUN_MASK BIT(3)
|
||||
#define MMIO_STATUS_PPR_OVERFLOW_MASK BIT(5)
|
||||
#define MMIO_STATUS_PPR_INT_MASK BIT(6)
|
||||
#define MMIO_STATUS_PPR_RUN_MASK BIT(7)
|
||||
#define MMIO_STATUS_GALOG_RUN_MASK BIT(8)
|
||||
#define MMIO_STATUS_GALOG_OVERFLOW_MASK BIT(9)
|
||||
#define MMIO_STATUS_GALOG_INT_MASK BIT(10)
|
||||
@@ -381,15 +384,15 @@
|
||||
*/
|
||||
#define DTE_FLAG_V BIT_ULL(0)
|
||||
#define DTE_FLAG_TV BIT_ULL(1)
|
||||
#define DTE_FLAG_GIOV BIT_ULL(54)
|
||||
#define DTE_FLAG_GV BIT_ULL(55)
|
||||
#define DTE_GLX_SHIFT (56)
|
||||
#define DTE_GLX_MASK (3)
|
||||
#define DTE_FLAG_IR BIT_ULL(61)
|
||||
#define DTE_FLAG_IW BIT_ULL(62)
|
||||
|
||||
#define DTE_FLAG_IOTLB BIT_ULL(32)
|
||||
#define DTE_FLAG_GIOV BIT_ULL(54)
|
||||
#define DTE_FLAG_GV BIT_ULL(55)
|
||||
#define DTE_FLAG_MASK (0x3ffULL << 32)
|
||||
#define DTE_GLX_SHIFT (56)
|
||||
#define DTE_GLX_MASK (3)
|
||||
#define DEV_DOMID_MASK 0xffffULL
|
||||
|
||||
#define DTE_GCR3_VAL_A(x) (((x) >> 12) & 0x00007ULL)
|
||||
@@ -702,12 +705,21 @@ struct amd_iommu {
|
||||
/* event buffer virtual address */
|
||||
u8 *evt_buf;
|
||||
|
||||
/* Name for event log interrupt */
|
||||
unsigned char evt_irq_name[16];
|
||||
|
||||
/* Base of the PPR log, if present */
|
||||
u8 *ppr_log;
|
||||
|
||||
/* Name for PPR log interrupt */
|
||||
unsigned char ppr_irq_name[16];
|
||||
|
||||
/* Base of the GA log, if present */
|
||||
u8 *ga_log;
|
||||
|
||||
/* Name for GA log interrupt */
|
||||
unsigned char ga_irq_name[16];
|
||||
|
||||
/* Tail of the GA log, if present */
|
||||
u8 *ga_log_tail;
|
||||
|
||||
|
||||
@@ -483,6 +483,10 @@ static void iommu_disable(struct amd_iommu *iommu)
|
||||
iommu_feature_disable(iommu, CONTROL_GALOG_EN);
|
||||
iommu_feature_disable(iommu, CONTROL_GAINT_EN);
|
||||
|
||||
/* Disable IOMMU PPR logging */
|
||||
iommu_feature_disable(iommu, CONTROL_PPRLOG_EN);
|
||||
iommu_feature_disable(iommu, CONTROL_PPRINT_EN);
|
||||
|
||||
/* Disable IOMMU hardware itself */
|
||||
iommu_feature_disable(iommu, CONTROL_IOMMU_EN);
|
||||
|
||||
@@ -752,38 +756,62 @@ static int __init alloc_command_buffer(struct amd_iommu *iommu)
|
||||
return iommu->cmd_buf ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt handler has processed all pending events and adjusted head
|
||||
* and tail pointer. Reset overflow mask and restart logging again.
|
||||
*/
|
||||
static void amd_iommu_restart_log(struct amd_iommu *iommu, const char *evt_type,
|
||||
u8 cntrl_intr, u8 cntrl_log,
|
||||
u32 status_run_mask, u32 status_overflow_mask)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
|
||||
if (status & status_run_mask)
|
||||
return;
|
||||
|
||||
pr_info_ratelimited("IOMMU %s log restarting\n", evt_type);
|
||||
|
||||
iommu_feature_disable(iommu, cntrl_log);
|
||||
iommu_feature_disable(iommu, cntrl_intr);
|
||||
|
||||
writel(status_overflow_mask, iommu->mmio_base + MMIO_STATUS_OFFSET);
|
||||
|
||||
iommu_feature_enable(iommu, cntrl_intr);
|
||||
iommu_feature_enable(iommu, cntrl_log);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function restarts event logging in case the IOMMU experienced
|
||||
* an event log buffer overflow.
|
||||
*/
|
||||
void amd_iommu_restart_event_logging(struct amd_iommu *iommu)
|
||||
{
|
||||
iommu_feature_disable(iommu, CONTROL_EVT_LOG_EN);
|
||||
iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
|
||||
amd_iommu_restart_log(iommu, "Event", CONTROL_EVT_INT_EN,
|
||||
CONTROL_EVT_LOG_EN, MMIO_STATUS_EVT_RUN_MASK,
|
||||
MMIO_STATUS_EVT_OVERFLOW_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function restarts event logging in case the IOMMU experienced
|
||||
* an GA log overflow.
|
||||
* GA log overflow.
|
||||
*/
|
||||
void amd_iommu_restart_ga_log(struct amd_iommu *iommu)
|
||||
{
|
||||
u32 status;
|
||||
amd_iommu_restart_log(iommu, "GA", CONTROL_GAINT_EN,
|
||||
CONTROL_GALOG_EN, MMIO_STATUS_GALOG_RUN_MASK,
|
||||
MMIO_STATUS_GALOG_OVERFLOW_MASK);
|
||||
}
|
||||
|
||||
status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
|
||||
if (status & MMIO_STATUS_GALOG_RUN_MASK)
|
||||
return;
|
||||
|
||||
pr_info_ratelimited("IOMMU GA Log restarting\n");
|
||||
|
||||
iommu_feature_disable(iommu, CONTROL_GALOG_EN);
|
||||
iommu_feature_disable(iommu, CONTROL_GAINT_EN);
|
||||
|
||||
writel(MMIO_STATUS_GALOG_OVERFLOW_MASK,
|
||||
iommu->mmio_base + MMIO_STATUS_OFFSET);
|
||||
|
||||
iommu_feature_enable(iommu, CONTROL_GAINT_EN);
|
||||
iommu_feature_enable(iommu, CONTROL_GALOG_EN);
|
||||
/*
|
||||
* This function restarts ppr logging in case the IOMMU experienced
|
||||
* PPR log overflow.
|
||||
*/
|
||||
void amd_iommu_restart_ppr_log(struct amd_iommu *iommu)
|
||||
{
|
||||
amd_iommu_restart_log(iommu, "PPR", CONTROL_PPRINT_EN,
|
||||
CONTROL_PPRLOG_EN, MMIO_STATUS_PPR_RUN_MASK,
|
||||
MMIO_STATUS_PPR_OVERFLOW_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -906,6 +934,8 @@ static void iommu_enable_ppr_log(struct amd_iommu *iommu)
|
||||
if (iommu->ppr_log == NULL)
|
||||
return;
|
||||
|
||||
iommu_feature_enable(iommu, CONTROL_PPR_EN);
|
||||
|
||||
entry = iommu_virt_to_phys(iommu->ppr_log) | PPR_LOG_SIZE_512;
|
||||
|
||||
memcpy_toio(iommu->mmio_base + MMIO_PPR_LOG_OFFSET,
|
||||
@@ -916,7 +946,7 @@ static void iommu_enable_ppr_log(struct amd_iommu *iommu)
|
||||
writel(0x00, iommu->mmio_base + MMIO_PPR_TAIL_OFFSET);
|
||||
|
||||
iommu_feature_enable(iommu, CONTROL_PPRLOG_EN);
|
||||
iommu_feature_enable(iommu, CONTROL_PPR_EN);
|
||||
iommu_feature_enable(iommu, CONTROL_PPRINT_EN);
|
||||
}
|
||||
|
||||
static void __init free_ppr_log(struct amd_iommu *iommu)
|
||||
@@ -2311,6 +2341,7 @@ static int intcapxt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq
|
||||
struct irq_data *irqd = irq_domain_get_irq_data(domain, i);
|
||||
|
||||
irqd->chip = &intcapxt_controller;
|
||||
irqd->hwirq = info->hwirq;
|
||||
irqd->chip_data = info->data;
|
||||
__irq_set_handler(i, handle_edge_irq, 0, "edge");
|
||||
}
|
||||
@@ -2337,22 +2368,14 @@ static void intcapxt_unmask_irq(struct irq_data *irqd)
|
||||
xt.destid_0_23 = cfg->dest_apicid & GENMASK(23, 0);
|
||||
xt.destid_24_31 = cfg->dest_apicid >> 24;
|
||||
|
||||
/**
|
||||
* Current IOMMU implementation uses the same IRQ for all
|
||||
* 3 IOMMU interrupts.
|
||||
*/
|
||||
writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_EVT_OFFSET);
|
||||
writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_PPR_OFFSET);
|
||||
writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_GALOG_OFFSET);
|
||||
writeq(xt.capxt, iommu->mmio_base + irqd->hwirq);
|
||||
}
|
||||
|
||||
static void intcapxt_mask_irq(struct irq_data *irqd)
|
||||
{
|
||||
struct amd_iommu *iommu = irqd->chip_data;
|
||||
|
||||
writeq(0, iommu->mmio_base + MMIO_INTCAPXT_EVT_OFFSET);
|
||||
writeq(0, iommu->mmio_base + MMIO_INTCAPXT_PPR_OFFSET);
|
||||
writeq(0, iommu->mmio_base + MMIO_INTCAPXT_GALOG_OFFSET);
|
||||
writeq(0, iommu->mmio_base + irqd->hwirq);
|
||||
}
|
||||
|
||||
|
||||
@@ -2415,7 +2438,8 @@ static struct irq_domain *iommu_get_irqdomain(void)
|
||||
return iommu_irqdomain;
|
||||
}
|
||||
|
||||
static int iommu_setup_intcapxt(struct amd_iommu *iommu)
|
||||
static int __iommu_setup_intcapxt(struct amd_iommu *iommu, const char *devname,
|
||||
int hwirq, irq_handler_t thread_fn)
|
||||
{
|
||||
struct irq_domain *domain;
|
||||
struct irq_alloc_info info;
|
||||
@@ -2429,6 +2453,7 @@ static int iommu_setup_intcapxt(struct amd_iommu *iommu)
|
||||
init_irq_alloc_info(&info, NULL);
|
||||
info.type = X86_IRQ_ALLOC_TYPE_AMDVI;
|
||||
info.data = iommu;
|
||||
info.hwirq = hwirq;
|
||||
|
||||
irq = irq_domain_alloc_irqs(domain, 1, node, &info);
|
||||
if (irq < 0) {
|
||||
@@ -2437,7 +2462,7 @@ static int iommu_setup_intcapxt(struct amd_iommu *iommu)
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(irq, amd_iommu_int_handler,
|
||||
amd_iommu_int_thread, 0, "AMD-Vi", iommu);
|
||||
thread_fn, 0, devname, iommu);
|
||||
if (ret) {
|
||||
irq_domain_free_irqs(irq, 1);
|
||||
irq_domain_remove(domain);
|
||||
@@ -2447,6 +2472,37 @@ static int iommu_setup_intcapxt(struct amd_iommu *iommu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iommu_setup_intcapxt(struct amd_iommu *iommu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
snprintf(iommu->evt_irq_name, sizeof(iommu->evt_irq_name),
|
||||
"AMD-Vi%d-Evt", iommu->index);
|
||||
ret = __iommu_setup_intcapxt(iommu, iommu->evt_irq_name,
|
||||
MMIO_INTCAPXT_EVT_OFFSET,
|
||||
amd_iommu_int_thread_evtlog);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
snprintf(iommu->ppr_irq_name, sizeof(iommu->ppr_irq_name),
|
||||
"AMD-Vi%d-PPR", iommu->index);
|
||||
ret = __iommu_setup_intcapxt(iommu, iommu->ppr_irq_name,
|
||||
MMIO_INTCAPXT_PPR_OFFSET,
|
||||
amd_iommu_int_thread_pprlog);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_IRQ_REMAP
|
||||
snprintf(iommu->ga_irq_name, sizeof(iommu->ga_irq_name),
|
||||
"AMD-Vi%d-GA", iommu->index);
|
||||
ret = __iommu_setup_intcapxt(iommu, iommu->ga_irq_name,
|
||||
MMIO_INTCAPXT_GALOG_OFFSET,
|
||||
amd_iommu_int_thread_galog);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iommu_init_irq(struct amd_iommu *iommu)
|
||||
{
|
||||
int ret;
|
||||
@@ -2472,8 +2528,6 @@ enable_faults:
|
||||
|
||||
iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
|
||||
|
||||
if (iommu->ppr_log != NULL)
|
||||
iommu_feature_enable(iommu, CONTROL_PPRINT_EN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2889,8 +2943,6 @@ static void enable_iommus_vapic(void)
|
||||
static void enable_iommus(void)
|
||||
{
|
||||
early_enable_iommus();
|
||||
enable_iommus_vapic();
|
||||
enable_iommus_v2();
|
||||
}
|
||||
|
||||
static void disable_iommus(void)
|
||||
@@ -3154,6 +3206,13 @@ static int amd_iommu_enable_interrupts(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt handler is ready to process interrupts. Enable
|
||||
* PPR and GA log interrupt for all IOMMUs.
|
||||
*/
|
||||
enable_iommus_vapic();
|
||||
enable_iommus_v2();
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -3233,8 +3292,6 @@ static int __init state_next(void)
|
||||
register_syscore_ops(&amd_iommu_syscore_ops);
|
||||
ret = amd_iommu_init_pci();
|
||||
init_state = ret ? IOMMU_INIT_ERROR : IOMMU_PCI_INIT;
|
||||
enable_iommus_vapic();
|
||||
enable_iommus_v2();
|
||||
break;
|
||||
case IOMMU_PCI_INIT:
|
||||
ret = amd_iommu_enable_interrupts();
|
||||
|
||||
@@ -841,50 +841,27 @@ static inline void
|
||||
amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { }
|
||||
#endif /* !CONFIG_IRQ_REMAP */
|
||||
|
||||
#define AMD_IOMMU_INT_MASK \
|
||||
(MMIO_STATUS_EVT_OVERFLOW_INT_MASK | \
|
||||
MMIO_STATUS_EVT_INT_MASK | \
|
||||
MMIO_STATUS_PPR_INT_MASK | \
|
||||
MMIO_STATUS_GALOG_OVERFLOW_MASK | \
|
||||
MMIO_STATUS_GALOG_INT_MASK)
|
||||
|
||||
irqreturn_t amd_iommu_int_thread(int irq, void *data)
|
||||
static void amd_iommu_handle_irq(void *data, const char *evt_type,
|
||||
u32 int_mask, u32 overflow_mask,
|
||||
void (*int_handler)(struct amd_iommu *),
|
||||
void (*overflow_handler)(struct amd_iommu *))
|
||||
{
|
||||
struct amd_iommu *iommu = (struct amd_iommu *) data;
|
||||
u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
|
||||
u32 mask = int_mask | overflow_mask;
|
||||
|
||||
while (status & AMD_IOMMU_INT_MASK) {
|
||||
while (status & mask) {
|
||||
/* Enable interrupt sources again */
|
||||
writel(AMD_IOMMU_INT_MASK,
|
||||
iommu->mmio_base + MMIO_STATUS_OFFSET);
|
||||
writel(mask, iommu->mmio_base + MMIO_STATUS_OFFSET);
|
||||
|
||||
if (status & MMIO_STATUS_EVT_INT_MASK) {
|
||||
pr_devel("Processing IOMMU Event Log\n");
|
||||
iommu_poll_events(iommu);
|
||||
if (int_handler) {
|
||||
pr_devel("Processing IOMMU (ivhd%d) %s Log\n",
|
||||
iommu->index, evt_type);
|
||||
int_handler(iommu);
|
||||
}
|
||||
|
||||
if (status & MMIO_STATUS_PPR_INT_MASK) {
|
||||
pr_devel("Processing IOMMU PPR Log\n");
|
||||
iommu_poll_ppr_log(iommu);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IRQ_REMAP
|
||||
if (status & (MMIO_STATUS_GALOG_INT_MASK |
|
||||
MMIO_STATUS_GALOG_OVERFLOW_MASK)) {
|
||||
pr_devel("Processing IOMMU GA Log\n");
|
||||
iommu_poll_ga_log(iommu);
|
||||
}
|
||||
|
||||
if (status & MMIO_STATUS_GALOG_OVERFLOW_MASK) {
|
||||
pr_info_ratelimited("IOMMU GA Log overflow\n");
|
||||
amd_iommu_restart_ga_log(iommu);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (status & MMIO_STATUS_EVT_OVERFLOW_INT_MASK) {
|
||||
pr_info_ratelimited("IOMMU event log overflow\n");
|
||||
amd_iommu_restart_event_logging(iommu);
|
||||
}
|
||||
if ((status & overflow_mask) && overflow_handler)
|
||||
overflow_handler(iommu);
|
||||
|
||||
/*
|
||||
* Hardware bug: ERBT1312
|
||||
@@ -901,6 +878,43 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
|
||||
*/
|
||||
status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data)
|
||||
{
|
||||
amd_iommu_handle_irq(data, "Evt", MMIO_STATUS_EVT_INT_MASK,
|
||||
MMIO_STATUS_EVT_OVERFLOW_MASK,
|
||||
iommu_poll_events, amd_iommu_restart_event_logging);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
irqreturn_t amd_iommu_int_thread_pprlog(int irq, void *data)
|
||||
{
|
||||
amd_iommu_handle_irq(data, "PPR", MMIO_STATUS_PPR_INT_MASK,
|
||||
MMIO_STATUS_PPR_OVERFLOW_MASK,
|
||||
iommu_poll_ppr_log, amd_iommu_restart_ppr_log);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
irqreturn_t amd_iommu_int_thread_galog(int irq, void *data)
|
||||
{
|
||||
#ifdef CONFIG_IRQ_REMAP
|
||||
amd_iommu_handle_irq(data, "GA", MMIO_STATUS_GALOG_INT_MASK,
|
||||
MMIO_STATUS_GALOG_OVERFLOW_MASK,
|
||||
iommu_poll_ga_log, amd_iommu_restart_ga_log);
|
||||
#endif
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
irqreturn_t amd_iommu_int_thread(int irq, void *data)
|
||||
{
|
||||
amd_iommu_int_thread_evtlog(irq, data);
|
||||
amd_iommu_int_thread_pprlog(irq, data);
|
||||
amd_iommu_int_thread_galog(irq, data);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
@@ -262,8 +262,8 @@ static void put_pasid_state(struct pasid_state *pasid_state)
|
||||
|
||||
static void put_pasid_state_wait(struct pasid_state *pasid_state)
|
||||
{
|
||||
refcount_dec(&pasid_state->count);
|
||||
wait_event(pasid_state->wq, !refcount_read(&pasid_state->count));
|
||||
if (!refcount_dec_and_test(&pasid_state->count))
|
||||
wait_event(pasid_state->wq, !refcount_read(&pasid_state->count));
|
||||
free_pasid_state(pasid_state);
|
||||
}
|
||||
|
||||
@@ -327,6 +327,9 @@ static void free_pasid_states(struct device_state *dev_state)
|
||||
|
||||
put_pasid_state(pasid_state);
|
||||
|
||||
/* Clear the pasid state so that the pasid can be re-used */
|
||||
clear_pasid_state(dev_state, pasid_state->pasid);
|
||||
|
||||
/*
|
||||
* This will call the mn_release function and
|
||||
* unbind the PASID
|
||||
|
||||
@@ -1276,7 +1276,7 @@ static __maybe_unused int apple_dart_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_DEV_PM_OPS(apple_dart_pm_ops, apple_dart_suspend, apple_dart_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(apple_dart_pm_ops, apple_dart_suspend, apple_dart_resume);
|
||||
|
||||
static const struct of_device_id apple_dart_of_match[] = {
|
||||
{ .compatible = "apple,t8103-dart", .data = &apple_dart_hw_t8103 },
|
||||
|
||||
@@ -80,7 +80,7 @@ arm_smmu_share_asid(struct mm_struct *mm, u16 asid)
|
||||
* be some overlap between use of both ASIDs, until we invalidate the
|
||||
* TLB.
|
||||
*/
|
||||
arm_smmu_write_ctx_desc(smmu_domain, 0, cd);
|
||||
arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, cd);
|
||||
|
||||
/* Invalidate TLB entries previously associated with that context */
|
||||
arm_smmu_tlb_inv_asid(smmu, asid);
|
||||
|
||||
@@ -1059,7 +1059,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
|
||||
/*
|
||||
* This function handles the following cases:
|
||||
*
|
||||
* (1) Install primary CD, for normal DMA traffic (SSID = 0).
|
||||
* (1) Install primary CD, for normal DMA traffic (SSID = IOMMU_NO_PASID = 0).
|
||||
* (2) Install a secondary CD, for SID+SSID traffic.
|
||||
* (3) Update ASID of a CD. Atomically write the first 64 bits of the
|
||||
* CD, then invalidate the old entry and mappings.
|
||||
@@ -1607,7 +1607,7 @@ static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
|
||||
|
||||
sid = FIELD_GET(PRIQ_0_SID, evt[0]);
|
||||
ssv = FIELD_GET(PRIQ_0_SSID_V, evt[0]);
|
||||
ssid = ssv ? FIELD_GET(PRIQ_0_SSID, evt[0]) : 0;
|
||||
ssid = ssv ? FIELD_GET(PRIQ_0_SSID, evt[0]) : IOMMU_NO_PASID;
|
||||
last = FIELD_GET(PRIQ_0_PRG_LAST, evt[0]);
|
||||
grpid = FIELD_GET(PRIQ_1_PRG_IDX, evt[1]);
|
||||
|
||||
@@ -1748,7 +1748,7 @@ arm_smmu_atc_inv_to_cmd(int ssid, unsigned long iova, size_t size,
|
||||
*/
|
||||
*cmd = (struct arm_smmu_cmdq_ent) {
|
||||
.opcode = CMDQ_OP_ATC_INV,
|
||||
.substream_valid = !!ssid,
|
||||
.substream_valid = (ssid != IOMMU_NO_PASID),
|
||||
.atc.ssid = ssid,
|
||||
};
|
||||
|
||||
@@ -1795,7 +1795,7 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master)
|
||||
struct arm_smmu_cmdq_ent cmd;
|
||||
struct arm_smmu_cmdq_batch cmds;
|
||||
|
||||
arm_smmu_atc_inv_to_cmd(0, 0, 0, &cmd);
|
||||
arm_smmu_atc_inv_to_cmd(IOMMU_NO_PASID, 0, 0, &cmd);
|
||||
|
||||
cmds.num = 0;
|
||||
for (i = 0; i < master->num_streams; i++) {
|
||||
@@ -1875,7 +1875,7 @@ static void arm_smmu_tlb_inv_context(void *cookie)
|
||||
cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid;
|
||||
arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
|
||||
}
|
||||
arm_smmu_atc_inv_domain(smmu_domain, 0, 0, 0);
|
||||
arm_smmu_atc_inv_domain(smmu_domain, IOMMU_NO_PASID, 0, 0);
|
||||
}
|
||||
|
||||
static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
|
||||
@@ -1968,7 +1968,7 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
|
||||
* Unfortunately, this can't be leaf-only since we may have
|
||||
* zapped an entire table.
|
||||
*/
|
||||
arm_smmu_atc_inv_domain(smmu_domain, 0, iova, size);
|
||||
arm_smmu_atc_inv_domain(smmu_domain, IOMMU_NO_PASID, iova, size);
|
||||
}
|
||||
|
||||
void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
|
||||
@@ -2055,24 +2055,6 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
|
||||
return &smmu_domain->domain;
|
||||
}
|
||||
|
||||
static int arm_smmu_bitmap_alloc(unsigned long *map, int span)
|
||||
{
|
||||
int idx, size = 1 << span;
|
||||
|
||||
do {
|
||||
idx = find_first_zero_bit(map, size);
|
||||
if (idx == size)
|
||||
return -ENOSPC;
|
||||
} while (test_and_set_bit(idx, map));
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static void arm_smmu_bitmap_free(unsigned long *map, int idx)
|
||||
{
|
||||
clear_bit(idx, map);
|
||||
}
|
||||
|
||||
static void arm_smmu_domain_free(struct iommu_domain *domain)
|
||||
{
|
||||
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
|
||||
@@ -2093,7 +2075,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
|
||||
} else {
|
||||
struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
|
||||
if (cfg->vmid)
|
||||
arm_smmu_bitmap_free(smmu->vmid_map, cfg->vmid);
|
||||
ida_free(&smmu->vmid_map, cfg->vmid);
|
||||
}
|
||||
|
||||
kfree(smmu_domain);
|
||||
@@ -2142,7 +2124,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
|
||||
* the master has been added to the devices list for this domain.
|
||||
* This isn't an issue because the STE hasn't been installed yet.
|
||||
*/
|
||||
ret = arm_smmu_write_ctx_desc(smmu_domain, 0, &cfg->cd);
|
||||
ret = arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, &cfg->cd);
|
||||
if (ret)
|
||||
goto out_free_cd_tables;
|
||||
|
||||
@@ -2167,7 +2149,9 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
|
||||
struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
|
||||
typeof(&pgtbl_cfg->arm_lpae_s2_cfg.vtcr) vtcr;
|
||||
|
||||
vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits);
|
||||
/* Reserve VMID 0 for stage-2 bypass STEs */
|
||||
vmid = ida_alloc_range(&smmu->vmid_map, 1, (1 << smmu->vmid_bits) - 1,
|
||||
GFP_KERNEL);
|
||||
if (vmid < 0)
|
||||
return vmid;
|
||||
|
||||
@@ -2328,7 +2312,7 @@ static void arm_smmu_enable_ats(struct arm_smmu_master *master)
|
||||
pdev = to_pci_dev(master->dev);
|
||||
|
||||
atomic_inc(&smmu_domain->nr_ats_masters);
|
||||
arm_smmu_atc_inv_domain(smmu_domain, 0, 0, 0);
|
||||
arm_smmu_atc_inv_domain(smmu_domain, IOMMU_NO_PASID, 0, 0);
|
||||
if (pci_enable_ats(pdev, stu))
|
||||
dev_err(master->dev, "Failed to enable ATS (STU %zu)\n", stu);
|
||||
}
|
||||
@@ -3098,8 +3082,8 @@ static int arm_smmu_init_strtab(struct arm_smmu_device *smmu)
|
||||
reg |= STRTAB_BASE_RA;
|
||||
smmu->strtab_cfg.strtab_base = reg;
|
||||
|
||||
/* Allocate the first VMID for stage-2 bypass STEs */
|
||||
set_bit(0, smmu->vmid_map);
|
||||
ida_init(&smmu->vmid_map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3923,6 +3907,7 @@ static void arm_smmu_device_remove(struct platform_device *pdev)
|
||||
iommu_device_sysfs_remove(&smmu->iommu);
|
||||
arm_smmu_device_disable(smmu);
|
||||
iopf_queue_free(smmu->evtq.iopf);
|
||||
ida_destroy(&smmu->vmid_map);
|
||||
}
|
||||
|
||||
static void arm_smmu_device_shutdown(struct platform_device *pdev)
|
||||
|
||||
@@ -670,7 +670,7 @@ struct arm_smmu_device {
|
||||
|
||||
#define ARM_SMMU_MAX_VMIDS (1 << 16)
|
||||
unsigned int vmid_bits;
|
||||
DECLARE_BITMAP(vmid_map, ARM_SMMU_MAX_VMIDS);
|
||||
struct ida vmid_map;
|
||||
|
||||
unsigned int ssid_bits;
|
||||
unsigned int sid_bits;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/firmware/qcom/qcom_scm.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user