Commit b8fd76f4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'iommu-updates-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

Pull iommu updates from Joerg Roedel:
 "Core code:
   - map/unmap_pages() cleanup
   - SVA and IOPF refactoring
   - Clean up and document return codes from device/domain attachment

  AMD driver:
   - Rework and extend parsing code for ivrs_ioapic, ivrs_hpet and
     ivrs_acpihid command line options
   - Some smaller cleanups

  Intel driver:
   - Blocking domain support
   - Cleanups

  S390 driver:
   - Fixes and improvements for attach and aperture handling

  PAMU driver:
   - Resource leak fix and cleanup

  Rockchip driver:
   - Page table permission bit fix

  Mediatek driver:
   - Improve safety from invalid dts input
   - Smaller fixes and improvements

  Exynos driver:
   - Fix driver initialization sequence

  Sun50i driver:
   - Remove IOMMU_DOMAIN_IDENTITY as it has not been working forever
   - Various other fixes"

* tag 'iommu-updates-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (74 commits)
  iommu/mediatek: Fix forever loop in error handling
  iommu/mediatek: Fix crash on isr after kexec()
  iommu/sun50i: Remove IOMMU_DOMAIN_IDENTITY
  iommu/amd: Fix typo in macro parameter name
  iommu/mediatek: Remove unused "mapping" member from mtk_iommu_data
  iommu/mediatek: Improve safety for mediatek,smi property in larb nodes
  iommu/mediatek: Validate number of phandles associated with "mediatek,larbs"
  iommu/mediatek: Add error path for loop of mm_dts_parse
  iommu/mediatek: Use component_match_add
  iommu/mediatek: Add platform_device_put for recovering the device refcnt
  iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()
  iommu/vt-d: Use real field for indication of first level
  iommu/vt-d: Remove unnecessary domain_context_mapped()
  iommu/vt-d: Rename domain_add_dev_info()
  iommu/vt-d: Rename iommu_disable_dev_iotlb()
  iommu/vt-d: Add blocking domain support
  iommu/vt-d: Add device_block_translation() helper
  iommu/vt-d: Allocate pasid table in device probe path
  iommu/amd: Check return value of mmu_notifier_register()
  iommu/amd: Fix pci device refcount leak in ppr_notifier()
  ...
parents 2f26e424 e3eca2e4
...@@ -2313,7 +2313,13 @@ ...@@ -2313,7 +2313,13 @@
Provide an override to the IOAPIC-ID<->DEVICE-ID Provide an override to the IOAPIC-ID<->DEVICE-ID
mapping provided in the IVRS ACPI table. mapping provided in the IVRS ACPI table.
By default, PCI segment is 0, and can be omitted. By default, PCI segment is 0, and can be omitted.
For example:
For example, to map IOAPIC-ID decimal 10 to
PCI segment 0x1 and PCI device 00:14.0,
write the parameter as:
ivrs_ioapic=10@0001:00:14.0
Deprecated formats:
* To map IOAPIC-ID decimal 10 to PCI device 00:14.0 * To map IOAPIC-ID decimal 10 to PCI device 00:14.0
write the parameter as: write the parameter as:
ivrs_ioapic[10]=00:14.0 ivrs_ioapic[10]=00:14.0
...@@ -2325,7 +2331,13 @@ ...@@ -2325,7 +2331,13 @@
Provide an override to the HPET-ID<->DEVICE-ID Provide an override to the HPET-ID<->DEVICE-ID
mapping provided in the IVRS ACPI table. mapping provided in the IVRS ACPI table.
By default, PCI segment is 0, and can be omitted. By default, PCI segment is 0, and can be omitted.
For example:
For example, to map HPET-ID decimal 10 to
PCI segment 0x1 and PCI device 00:14.0,
write the parameter as:
ivrs_hpet=10@0001:00:14.0
Deprecated formats:
* To map HPET-ID decimal 0 to PCI device 00:14.0 * To map HPET-ID decimal 0 to PCI device 00:14.0
write the parameter as: write the parameter as:
ivrs_hpet[0]=00:14.0 ivrs_hpet[0]=00:14.0
...@@ -2336,15 +2348,20 @@ ...@@ -2336,15 +2348,20 @@
ivrs_acpihid [HW,X86-64] ivrs_acpihid [HW,X86-64]
Provide an override to the ACPI-HID:UID<->DEVICE-ID Provide an override to the ACPI-HID:UID<->DEVICE-ID
mapping provided in the IVRS ACPI table. mapping provided in the IVRS ACPI table.
By default, PCI segment is 0, and can be omitted.
For example, to map UART-HID:UID AMD0020:0 to For example, to map UART-HID:UID AMD0020:0 to
PCI segment 0x1 and PCI device ID 00:14.5, PCI segment 0x1 and PCI device ID 00:14.5,
write the parameter as: write the parameter as:
ivrs_acpihid[0001:00:14.5]=AMD0020:0 ivrs_acpihid=AMD0020:0@0001:00:14.5
By default, PCI segment is 0, and can be omitted. Deprecated formats:
For example, PCI device 00:14.5 write the parameter as: * To map UART-HID:UID AMD0020:0 to PCI segment is 0,
PCI device ID 00:14.5, write the parameter as:
ivrs_acpihid[00:14.5]=AMD0020:0 ivrs_acpihid[00:14.5]=AMD0020:0
* To map UART-HID:UID AMD0020:0 to PCI segment 0x1 and
PCI device ID 00:14.5, write the parameter as:
ivrs_acpihid[0001:00:14.5]=AMD0020:0
js= [HW,JOY] Analog joystick js= [HW,JOY] Analog joystick
See Documentation/input/joydev/joystick.rst. See Documentation/input/joydev/joystick.rst.
......
...@@ -28,19 +28,50 @@ properties: ...@@ -28,19 +28,50 @@ properties:
- enum: - enum:
- qcom,msm8996-smmu-v2 - qcom,msm8996-smmu-v2
- qcom,msm8998-smmu-v2 - qcom,msm8998-smmu-v2
- qcom,sdm630-smmu-v2
- const: qcom,smmu-v2 - const: qcom,smmu-v2
- description: Qcom SoCs implementing "arm,mmu-500" - description: Qcom SoCs implementing "qcom,smmu-500" and "arm,mmu-500"
items: items:
- enum: - enum:
- qcom,qcm2290-smmu-500 - qcom,qcm2290-smmu-500
- qcom,qdu1000-smmu-500
- qcom,sc7180-smmu-500 - qcom,sc7180-smmu-500
- qcom,sc7280-smmu-500 - qcom,sc7280-smmu-500
- qcom,sc8180x-smmu-500 - qcom,sc8180x-smmu-500
- qcom,sc8280xp-smmu-500 - qcom,sc8280xp-smmu-500
- qcom,sdm670-smmu-500
- qcom,sdm845-smmu-500 - qcom,sdm845-smmu-500
- qcom,sm6115-smmu-500
- qcom,sm6350-smmu-500
- qcom,sm6375-smmu-500
- qcom,sm8150-smmu-500
- qcom,sm8250-smmu-500
- qcom,sm8350-smmu-500
- qcom,sm8450-smmu-500
- const: qcom,smmu-500
- const: arm,mmu-500
- description: Qcom SoCs implementing "arm,mmu-500" (non-qcom implementation)
deprecated: true
items:
- enum:
- qcom,sdx55-smmu-500 - qcom,sdx55-smmu-500
- qcom,sdx65-smmu-500 - qcom,sdx65-smmu-500
- const: arm,mmu-500
- description: Qcom SoCs implementing "arm,mmu-500" (legacy binding)
deprecated: true
items:
# Do not add additional SoC to this list. Instead use two previous lists.
- enum:
- qcom,qcm2290-smmu-500
- qcom,sc7180-smmu-500
- qcom,sc7280-smmu-500
- qcom,sc8180x-smmu-500
- qcom,sc8280xp-smmu-500
- qcom,sdm845-smmu-500
- qcom,sm6115-smmu-500
- qcom,sm6350-smmu-500 - qcom,sm6350-smmu-500
- qcom,sm6375-smmu-500 - qcom,sm6375-smmu-500
- qcom,sm8150-smmu-500 - qcom,sm8150-smmu-500
...@@ -48,13 +79,28 @@ properties: ...@@ -48,13 +79,28 @@ properties:
- qcom,sm8350-smmu-500 - qcom,sm8350-smmu-500
- qcom,sm8450-smmu-500 - qcom,sm8450-smmu-500
- const: arm,mmu-500 - const: arm,mmu-500
- description: Qcom Adreno GPUs implementing "arm,smmu-500"
items:
- enum:
- qcom,sc7280-smmu-500
- qcom,sm8250-smmu-500
- const: qcom,adreno-smmu
- const: arm,mmu-500
- description: Qcom Adreno GPUs implementing "arm,smmu-v2" - description: Qcom Adreno GPUs implementing "arm,smmu-v2"
items: items:
- enum: - enum:
- qcom,msm8996-smmu-v2
- qcom,sc7180-smmu-v2 - qcom,sc7180-smmu-v2
- qcom,sdm630-smmu-v2
- qcom,sdm845-smmu-v2 - qcom,sdm845-smmu-v2
- qcom,sm6350-smmu-v2
- const: qcom,adreno-smmu - const: qcom,adreno-smmu
- const: qcom,smmu-v2 - const: qcom,smmu-v2
- description: Qcom Adreno GPUs on Google Cheza platform
items:
- const: qcom,sdm845-smmu-v2
- const: qcom,smmu-v2
- description: Marvell SoCs implementing "arm,mmu-500" - description: Marvell SoCs implementing "arm,mmu-500"
items: items:
- const: marvell,ap806-smmu-500 - const: marvell,ap806-smmu-500
...@@ -147,16 +193,12 @@ properties: ...@@ -147,16 +193,12 @@ properties:
present in such cases. present in such cases.
clock-names: clock-names:
items: minItems: 1
- const: bus maxItems: 7
- const: iface
clocks: clocks:
items: minItems: 1
- description: bus clock required for downstream bus access and for the maxItems: 7
smmu ptw
- description: interface clock required to access smmu's registers
through the TCU's programming interface.
power-domains: power-domains:
maxItems: 1 maxItems: 1
...@@ -206,6 +248,124 @@ allOf: ...@@ -206,6 +248,124 @@ allOf:
reg: reg:
maxItems: 1 maxItems: 1
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8998-smmu-v2
- qcom,sdm630-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-mm
- 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 downstream bus access
- description: bus clock required for the smmu ptw
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8996-smmu-v2
- qcom,sc7180-smmu-v2
- qcom,sdm845-smmu-v2
then:
properties:
clock-names:
items:
- const: bus
- const: iface
clocks:
items:
- description: bus clock required for downstream bus access and for
the smmu ptw
- description: interface clock required to access smmu's registers
through the TCU's programming interface.
- if:
properties:
compatible:
contains:
const: qcom,sc7280-smmu-500
then:
properties:
clock-names:
items:
- const: gcc_gpu_memnoc_gfx_clk
- const: gcc_gpu_snoc_dvm_gfx_clk
- const: gpu_cc_ahb_clk
- const: gpu_cc_hlos1_vote_gpu_smmu_clk
- const: gpu_cc_cx_gmu_clk
- const: gpu_cc_hub_cx_int_clk
- const: gpu_cc_hub_aon_clk
clocks:
items:
- description: GPU memnoc_gfx clock
- description: GPU snoc_dvm_gfx clock
- description: GPU ahb clock
- description: GPU hlos1_vote_GPU smmu clock
- description: GPU cx_gmu clock
- description: GPU hub_cx_int clock
- description: GPU hub_aon clock
- if:
properties:
compatible:
contains:
enum:
- qcom,sm6350-smmu-v2
- qcom,sm8150-smmu-500
- qcom,sm8250-smmu-500
then:
properties:
clock-names:
items:
- const: ahb
- const: bus
- const: iface
clocks:
items:
- description: bus clock required for AHB bus access
- description: bus clock required for downstream bus access and for
the smmu ptw
- description: interface clock required to access smmu's registers
through the TCU's programming interface.
examples: examples:
- |+ - |+
/* SMMU with stream matching or stream indexing */ /* SMMU with stream matching or stream indexing */
......
...@@ -82,6 +82,7 @@ properties: ...@@ -82,6 +82,7 @@ properties:
- mediatek,mt8195-iommu-vdo # generation two - mediatek,mt8195-iommu-vdo # generation two
- mediatek,mt8195-iommu-vpp # generation two - mediatek,mt8195-iommu-vpp # generation two
- mediatek,mt8195-iommu-infra # generation two - mediatek,mt8195-iommu-infra # generation two
- mediatek,mt8365-m4u # generation two
- description: mt7623 generation one - description: mt7623 generation one
items: items:
...@@ -132,6 +133,7 @@ properties: ...@@ -132,6 +133,7 @@ properties:
dt-binding/memory/mt8186-memory-port.h for mt8186, dt-binding/memory/mt8186-memory-port.h for mt8186,
dt-binding/memory/mt8192-larb-port.h for mt8192. dt-binding/memory/mt8192-larb-port.h for mt8192.
dt-binding/memory/mt8195-memory-port.h for mt8195. dt-binding/memory/mt8195-memory-port.h for mt8195.
dt-binding/memory/mediatek,mt8365-larb-port.h for mt8365.
power-domains: power-domains:
maxItems: 1 maxItems: 1
......
...@@ -117,7 +117,9 @@ struct zpci_bus { ...@@ -117,7 +117,9 @@ struct zpci_bus {
struct zpci_dev { struct zpci_dev {
struct zpci_bus *zbus; struct zpci_bus *zbus;
struct list_head entry; /* list of all zpci_devices, needed for hotplug, etc. */ struct list_head entry; /* list of all zpci_devices, needed for hotplug, etc. */
struct list_head iommu_list;
struct kref kref; struct kref kref;
struct rcu_head rcu;
struct hotplug_slot hotplug_slot; struct hotplug_slot hotplug_slot;
enum zpci_state state; enum zpci_state state;
...@@ -155,7 +157,6 @@ struct zpci_dev { ...@@ -155,7 +157,6 @@ struct zpci_dev {
/* DMA stuff */ /* DMA stuff */
unsigned long *dma_table; unsigned long *dma_table;
spinlock_t dma_table_lock;
int tlb_refresh; int tlb_refresh;
spinlock_t iommu_bitmap_lock; spinlock_t iommu_bitmap_lock;
...@@ -220,7 +221,7 @@ void zpci_device_reserved(struct zpci_dev *zdev); ...@@ -220,7 +221,7 @@ void zpci_device_reserved(struct zpci_dev *zdev);
bool zpci_is_device_configured(struct zpci_dev *zdev); bool zpci_is_device_configured(struct zpci_dev *zdev);
int zpci_hot_reset_device(struct zpci_dev *zdev); int zpci_hot_reset_device(struct zpci_dev *zdev);
int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64); int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64, u8 *);
int zpci_unregister_ioat(struct zpci_dev *, u8); int zpci_unregister_ioat(struct zpci_dev *, u8);
void zpci_remove_reserved_devices(void); void zpci_remove_reserved_devices(void);
void zpci_update_fh(struct zpci_dev *zdev, u32 fh); void zpci_update_fh(struct zpci_dev *zdev, u32 fh);
......
...@@ -434,6 +434,7 @@ static void kvm_s390_pci_dev_release(struct zpci_dev *zdev) ...@@ -434,6 +434,7 @@ static void kvm_s390_pci_dev_release(struct zpci_dev *zdev)
static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm) static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm)
{ {
struct zpci_dev *zdev = opaque; struct zpci_dev *zdev = opaque;
u8 status;
int rc; int rc;
if (!zdev) if (!zdev)
...@@ -486,7 +487,7 @@ static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm) ...@@ -486,7 +487,7 @@ static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm)
/* Re-register the IOMMU that was already created */ /* Re-register the IOMMU that was already created */
rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
virt_to_phys(zdev->dma_table)); virt_to_phys(zdev->dma_table), &status);
if (rc) if (rc)
goto clear_gisa; goto clear_gisa;
...@@ -516,6 +517,7 @@ static void kvm_s390_pci_unregister_kvm(void *opaque) ...@@ -516,6 +517,7 @@ static void kvm_s390_pci_unregister_kvm(void *opaque)
{ {
struct zpci_dev *zdev = opaque; struct zpci_dev *zdev = opaque;
struct kvm *kvm; struct kvm *kvm;
u8 status;
if (!zdev) if (!zdev)
return; return;
...@@ -554,7 +556,7 @@ static void kvm_s390_pci_unregister_kvm(void *opaque) ...@@ -554,7 +556,7 @@ static void kvm_s390_pci_unregister_kvm(void *opaque)
/* Re-register the IOMMU that was already created */ /* Re-register the IOMMU that was already created */
zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
virt_to_phys(zdev->dma_table)); virt_to_phys(zdev->dma_table), &status);
out: out:
spin_lock(&kvm->arch.kzdev_list_lock); spin_lock(&kvm->arch.kzdev_list_lock);
......
...@@ -116,20 +116,20 @@ EXPORT_SYMBOL_GPL(pci_proc_domain); ...@@ -116,20 +116,20 @@ EXPORT_SYMBOL_GPL(pci_proc_domain);
/* Modify PCI: Register I/O address translation parameters */ /* Modify PCI: Register I/O address translation parameters */
int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas, int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
u64 base, u64 limit, u64 iota) u64 base, u64 limit, u64 iota, u8 *status)
{ {
u64 req = ZPCI_CREATE_REQ(zdev->fh, dmaas, ZPCI_MOD_FC_REG_IOAT); u64 req = ZPCI_CREATE_REQ(zdev->fh, dmaas, ZPCI_MOD_FC_REG_IOAT);
struct zpci_fib fib = {0}; struct zpci_fib fib = {0};
u8 cc, status; u8 cc;
WARN_ON_ONCE(iota & 0x3fff); WARN_ON_ONCE(iota & 0x3fff);
fib.pba = base; fib.pba = base;
fib.pal = limit; fib.pal = limit;
fib.iota = iota | ZPCI_IOTA_RTTO_FLAG; fib.iota = iota | ZPCI_IOTA_RTTO_FLAG;
fib.gd = zdev->gisa; fib.gd = zdev->gisa;
cc = zpci_mod_fc(req, &fib, &status); cc = zpci_mod_fc(req, &fib, status);
if (cc) if (cc)
zpci_dbg(3, "reg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, status); zpci_dbg(3, "reg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, *status);
return cc; return cc;
} }
EXPORT_SYMBOL_GPL(zpci_register_ioat); EXPORT_SYMBOL_GPL(zpci_register_ioat);
...@@ -764,6 +764,7 @@ EXPORT_SYMBOL_GPL(zpci_disable_device); ...@@ -764,6 +764,7 @@ EXPORT_SYMBOL_GPL(zpci_disable_device);
*/ */
int zpci_hot_reset_device(struct zpci_dev *zdev) int zpci_hot_reset_device(struct zpci_dev *zdev)
{ {
u8 status;
int rc; int rc;
zpci_dbg(3, "rst fid:%x, fh:%x\n", zdev->fid, zdev->fh); zpci_dbg(3, "rst fid:%x, fh:%x\n", zdev->fid, zdev->fh);
...@@ -787,7 +788,7 @@ int zpci_hot_reset_device(struct zpci_dev *zdev) ...@@ -787,7 +788,7 @@ int zpci_hot_reset_device(struct zpci_dev *zdev)
if (zdev->dma_table) if (zdev->dma_table)
rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
virt_to_phys(zdev->dma_table)); virt_to_phys(zdev->dma_table), &status);
else else
rc = zpci_dma_init_device(zdev); rc = zpci_dma_init_device(zdev);
if (rc) { if (rc) {
...@@ -995,7 +996,7 @@ void zpci_release_device(struct kref *kref) ...@@ -995,7 +996,7 @@ void zpci_release_device(struct kref *kref)
break; break;
} }
zpci_dbg(3, "rem fid:%x\n", zdev->fid); zpci_dbg(3, "rem fid:%x\n", zdev->fid);
kfree(zdev); kfree_rcu(zdev, rcu);
} }
int zpci_report_error(struct pci_dev *pdev, int zpci_report_error(struct pci_dev *pdev,
......
...@@ -63,37 +63,55 @@ static void dma_free_page_table(void *table) ...@@ -63,37 +63,55 @@ static void dma_free_page_table(void *table)
kmem_cache_free(dma_page_table_cache, table); kmem_cache_free(dma_page_table_cache, table);
} }
static unsigned long *dma_get_seg_table_origin(unsigned long *entry) static unsigned long *dma_get_seg_table_origin(unsigned long *rtep)
{ {
unsigned long old_rte, rte;
unsigned long *sto; unsigned long *sto;
if (reg_entry_isvalid(*entry)) rte = READ_ONCE(*rtep);
sto = get_rt_sto(*entry); if (reg_entry_isvalid(rte)) {
else { sto = get_rt_sto(rte);
} else {
sto = dma_alloc_cpu_table(); sto = dma_alloc_cpu_table();
if (!sto) if (!sto)
return NULL; return NULL;
set_rt_sto(entry, virt_to_phys(sto)); set_rt_sto(&rte, virt_to_phys(sto));
validate_rt_entry(entry); validate_rt_entry(&rte);
entry_clr_protected(entry); entry_clr_protected(&rte);
old_rte = cmpxchg(rtep, ZPCI_TABLE_INVALID, rte);
if (old_rte != ZPCI_TABLE_INVALID) {
/* Somone else was faster, use theirs */
dma_free_cpu_table(sto);
sto = get_rt_sto(old_rte);
}
} }
return sto; return sto;
} }
static unsigned long *dma_get_page_table_origin(unsigned long *entry) static unsigned long *dma_get_page_table_origin(unsigned long *step)
{ {
unsigned long old_ste, ste;
unsigned long *pto; unsigned long *pto;
if (reg_entry_isvalid(*entry)) ste = READ_ONCE(*step);
pto = get_st_pto(*entry); if (reg_entry_isvalid(ste)) {
else { pto = get_st_pto(ste);
} else {
pto = dma_alloc_page_table(); pto = dma_alloc_page_table();
if (!pto) if (!pto)
return NULL; return NULL;
set_st_pto(entry, virt_to_phys(pto)); set_st_pto(&ste, virt_to_phys(pto));
validate_st_entry(entry); validate_st_entry(&ste);
entry_clr_protected(entry); entry_clr_protected(&ste);
old_ste = cmpxchg(step, ZPCI_TABLE_INVALID, ste);
if (old_ste != ZPCI_TABLE_INVALID) {
/* Somone else was faster, use theirs */
dma_free_page_table(pto);
pto = get_st_pto(old_ste);
}
} }
return pto; return pto;
} }
...@@ -117,19 +135,24 @@ unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr) ...@@ -117,19 +135,24 @@ unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr)
return &pto[px]; return &pto[px];
} }
void dma_update_cpu_trans(unsigned long *entry, phys_addr_t page_addr, int flags) void dma_update_cpu_trans(unsigned long *ptep, phys_addr_t page_addr, int flags)
{ {
unsigned long pte;
pte = READ_ONCE(*ptep);
if (flags & ZPCI_PTE_INVALID) { if (flags & ZPCI_PTE_INVALID) {
invalidate_pt_entry(entry); invalidate_pt_entry(&pte);
} else { } else {
set_pt_pfaa(entry, page_addr); set_pt_pfaa(&pte, page_addr);
validate_pt_entry(entry); validate_pt_entry(&pte);
} }
if (flags & ZPCI_TABLE_PROTECTED) if (flags & ZPCI_TABLE_PROTECTED)
entry_set_protected(entry); entry_set_protected(&pte);
else else
entry_clr_protected(entry); entry_clr_protected(&pte);
xchg(ptep, pte);
} }
static int __dma_update_trans(struct zpci_dev *zdev, phys_addr_t pa, static int __dma_update_trans(struct zpci_dev *zdev, phys_addr_t pa,
...@@ -137,18 +160,14 @@ static int __dma_update_trans(struct zpci_dev *zdev, phys_addr_t pa, ...@@ -137,18 +160,14 @@ static int __dma_update_trans(struct zpci_dev *zdev, phys_addr_t pa,
{ {
unsigned int nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; unsigned int nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
phys_addr_t page_addr = (pa & PAGE_MASK); phys_addr_t page_addr = (pa & PAGE_MASK);
unsigned long irq_flags;
unsigned long *entry; unsigned long *entry;
int i, rc = 0; int i, rc = 0;
if (!nr_pages) if (!nr_pages)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&zdev->dma_table_lock, irq_flags); if (!zdev->dma_table)
if (!zdev->dma_table) { return -EINVAL;
rc = -EINVAL;
goto out_unlock;
}
for (i = 0; i < nr_pages; i++) { for (i = 0; i < nr_pages; i++) {
entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr); entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr);
...@@ -173,8 +192,6 @@ static int __dma_update_trans(struct zpci_dev *zdev, phys_addr_t pa, ...@@ -173,8 +192,6 @@ static int __dma_update_trans(struct zpci_dev *zdev, phys_addr_t pa,
dma_update_cpu_trans(entry, page_addr, flags); dma_update_cpu_trans(entry, page_addr, flags);
} }
} }
out_unlock:
spin_unlock_irqrestore(&zdev->dma_table_lock, irq_flags);
return rc; return rc;
} }
...@@ -547,6 +564,7 @@ static void s390_dma_unmap_sg(struct device *dev, struct scatterlist *sg, ...@@ -547,6 +564,7 @@ static void s390_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
int zpci_dma_init_device(struct zpci_dev *zdev) int zpci_dma_init_device(struct zpci_dev *zdev)
{ {
u8 status;
int rc; int rc;
/* /*
...@@ -557,7 +575,6 @@ int zpci_dma_init_device(struct zpci_dev *zdev) ...@@ -557,7 +575,6 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
WARN_ON(zdev->s390_domain); WARN_ON(zdev->s390_domain);
spin_lock_init(&zdev->iommu_bitmap_lock); spin_lock_init(&zdev->iommu_bitmap_lock);
spin_lock_init(&zdev->dma_table_lock);
zdev->dma_table = dma_alloc_cpu_table(); zdev->dma_table = dma_alloc_cpu_table();
if (!zdev->dma_table) { if (!zdev->dma_table) {
...@@ -598,7 +615,7 @@ int zpci_dma_init_device(struct zpci_dev *zdev) ...@@ -598,7 +615,7 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
} }
if (zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, if (zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
virt_to_phys(zdev->dma_table))) { virt_to_phys(zdev->dma_table), &status)) {
rc = -EIO; rc = -EIO;
goto free_bitmap; goto free_bitmap;
} }
......
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
#define LOOP_TIMEOUT 2000000 #define LOOP_TIMEOUT 2000000
#define IVRS_GET_SBDF_ID(seg, bus, dev, fd) (((seg & 0xffff) << 16) | ((bus & 0xff) << 8) \ #define IVRS_GET_SBDF_ID(seg, bus, dev, fn) (((seg & 0xffff) << 16) | ((bus & 0xff) << 8) \
| ((dev & 0x1f) << 3) | (fn & 0x7)) | ((dev & 0x1f) << 3) | (fn & 0x7))
/* /*
...@@ -3402,18 +3402,24 @@ static int __init parse_amd_iommu_options(char *str) ...@@ -3402,18 +3402,24 @@ static int __init parse_amd_iommu_options(char *str)
static int __init parse_ivrs_ioapic(char *str) static int __init parse_ivrs_ioapic(char *str)
{ {
u32 seg = 0, bus, dev, fn; u32 seg = 0, bus, dev, fn;
int ret, id, i; int id, i;
u32 devid; u32 devid;
ret = sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn); if (sscanf(str, "=%d@%x:%x.%x", &id, &bus, &dev, &fn) == 4 ||
if (ret != 4) { sscanf(str, "=%d@%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5)
ret = sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn); goto found;
if (ret != 5) {
if (sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn) == 4 ||
sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5) {
pr_warn("ivrs_ioapic%s option format deprecated; use ivrs_ioapic=%d@%04x:%02x:%02x.%d instead\n",
str, id, seg, bus, dev, fn);
goto found;
}
pr_err("Invalid command line: ivrs_ioapic%s\n", str); pr_err("Invalid command line: ivrs_ioapic%s\n", str);
return 1; return 1;
}
}
found:
if (early_ioapic_map_size == EARLY_MAP_SIZE) { if (early_ioapic_map_size == EARLY_MAP_SIZE) {
pr_err("Early IOAPIC map overflow - ignoring ivrs_ioapic%s\n", pr_err("Early IOAPIC map overflow - ignoring ivrs_ioapic%s\n",
str); str);
...@@ -3434,18 +3440,24 @@ static int __init parse_ivrs_ioapic(char *str) ...@@ -3434,18 +3440,24 @@ static int __init parse_ivrs_ioapic(char *str)
static int __init parse_ivrs_hpet(char *str) static int __init parse_ivrs_hpet(char *str)
{ {
u32 seg = 0, bus, dev, fn; u32 seg = 0, bus, dev, fn;
int ret, id, i; int id, i;
u32 devid; u32 devid;
ret = sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn); if (sscanf(str, "=%d@%x:%x.%x", &id, &bus, &dev, &fn) == 4 ||
if (ret != 4) { sscanf(str, "=%d@%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5)
ret = sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn); goto found;
if (ret != 5) {
if (sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn) == 4 ||
sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5) {
pr_warn("ivrs_hpet%s option format deprecated; use ivrs_hpet=%d@%04x:%02x:%02x.%d instead\n",
str, id, seg, bus, dev, fn);
goto found;
}
pr_err("Invalid command line: ivrs_hpet%s\n", str); pr_err("Invalid command line: ivrs_hpet%s\n", str);
return 1; return 1;
}
}
found:
if (early_hpet_map_size == EARLY_MAP_SIZE) { if (early_hpet_map_size == EARLY_MAP_SIZE) {
pr_err("Early HPET map overflow - ignoring ivrs_hpet%s\n", pr_err("Early HPET map overflow - ignoring ivrs_hpet%s\n",
str); str);
...@@ -3466,19 +3478,36 @@ static int __init parse_ivrs_hpet(char *str) ...@@ -3466,19 +3478,36 @@ static int __init parse_ivrs_hpet(char *str)
static int __init parse_ivrs_acpihid(char *str) static int __init parse_ivrs_acpihid(char *str)
{ {
u32 seg = 0, bus, dev, fn; u32 seg = 0, bus, dev, fn;
char *hid, *uid, *p; char *hid, *uid, *p, *addr;
char acpiid[ACPIHID_UID_LEN + ACPIHID_HID_LEN] = {0}; char acpiid[ACPIHID_UID_LEN + ACPIHID_HID_LEN] = {0};
int ret, i; int i;
ret = sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid); addr = strchr(str, '@');
if (ret != 4) { if (!addr) {
ret = sscanf(str, "[%x:%x:%x.%x]=%s", &seg, &bus, &dev, &fn, acpiid); if (sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid) == 4 ||
if (ret != 5) { sscanf(str, "[%x:%x:%x.%x]=%s", &seg, &bus, &dev, &fn, acpiid) == 5) {
pr_err("Invalid command line: ivrs_acpihid(%s)\n", str); pr_warn("ivrs_acpihid%s option format deprecated; use ivrs_acpihid=%s@%04x:%02x:%02x.%d instead\n",
return 1; str, acpiid, seg, bus, dev, fn);
goto found;
} }
goto not_found;
} }
/* We have the '@', make it the terminator to get just the acpiid */
*addr++ = 0;
if (sscanf(str, "=%s", acpiid) != 1)
goto not_found;
if (sscanf(addr, "%x:%x.%x", &bus, &dev, &fn) == 3 ||
sscanf(addr, "%x:%x:%x.%x", &seg, &bus, &dev, &fn) == 4)
goto found;
not_found:
pr_err("Invalid command line: ivrs_acpihid%s\n", str);
return 1;
found:
p = acpiid; p = acpiid;
hid = strsep(&p, ":"); hid = strsep(&p, ":");
uid = p; uid = p;
...@@ -3488,6 +3517,13 @@ static int __init parse_ivrs_acpihid(char *str) ...@@ -3488,6 +3517,13 @@ static int __init parse_ivrs_acpihid(char *str)
return 1; return 1;
} }
/*
* Ignore leading zeroes after ':', so e.g., AMDI0095:00
* will match AMDI0095:0 in the second strcmp in acpi_dev_hid_uid_match
*/
while (*uid == '0' && *(uid + 1))
uid++;
i = early_acpihid_map_size++; i = early_acpihid_map_size++;
memcpy(early_acpihid_map[i].hid, hid, strlen(hid)); memcpy(early_acpihid_map[i].hid, hid, strlen(hid));
memcpy(early_acpihid_map[i].uid, uid, strlen(uid)); memcpy(early_acpihid_map[i].uid, uid, strlen(uid));
......
...@@ -767,7 +767,7 @@ EXPORT_SYMBOL(amd_iommu_register_ga_log_notifier); ...@@ -767,7 +767,7 @@ EXPORT_SYMBOL(amd_iommu_register_ga_log_notifier);
static void iommu_poll_ga_log(struct amd_iommu *iommu) static void iommu_poll_ga_log(struct amd_iommu *iommu)
{ {
u32 head, tail, cnt = 0; u32 head, tail;
if (iommu->ga_log == NULL) if (iommu->ga_log == NULL)
return; return;
...@@ -780,7 +780,6 @@ static void iommu_poll_ga_log(struct amd_iommu *iommu) ...@@ -780,7 +780,6 @@ static void iommu_poll_ga_log(struct amd_iommu *iommu)
u64 log_entry; u64 log_entry;
raw = (u64 *)(iommu->ga_log + head); raw = (u64 *)(iommu->ga_log + head);
cnt++;
/* Avoid memcpy function-call overhead */ /* Avoid memcpy function-call overhead */
log_entry = *raw; log_entry = *raw;
......
...@@ -587,6 +587,7 @@ static int ppr_notifier(struct notifier_block *nb, unsigned long e, void *data) ...@@ -587,6 +587,7 @@ static int ppr_notifier(struct notifier_block *nb, unsigned long e, void *data)
put_device_state(dev_state); put_device_state(dev_state);
out: out:
pci_dev_put(pdev);
return ret; return ret;
} }
...@@ -639,7 +640,9 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid, ...@@ -639,7 +640,9 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
if (pasid_state->mm == NULL) if (pasid_state->mm == NULL)
goto out_free; goto out_free;
mmu_notifier_register(&pasid_state->mn, mm); ret = mmu_notifier_register(&pasid_state->mn, mm);
if (ret)
goto out_free;
ret = set_pasid_state(dev_state, pasid_state, pasid); ret = set_pasid_state(dev_state, pasid_state, pasid);
if (ret) if (ret)
......
...@@ -136,6 +136,9 @@ int arm_mmu500_reset(struct arm_smmu_device *smmu) ...@@ -136,6 +136,9 @@ int arm_mmu500_reset(struct arm_smmu_device *smmu)
reg = arm_smmu_cb_read(smmu, i, ARM_SMMU_CB_ACTLR); reg = arm_smmu_cb_read(smmu, i, ARM_SMMU_CB_ACTLR);
reg &= ~ARM_MMU500_ACTLR_CPRE; reg &= ~ARM_MMU500_ACTLR_CPRE;
arm_smmu_cb_write(smmu, i, ARM_SMMU_CB_ACTLR, reg); arm_smmu_cb_write(smmu, i, ARM_SMMU_CB_ACTLR, reg);
reg = arm_smmu_cb_read(smmu, i, ARM_SMMU_CB_ACTLR);
if (reg & ARM_MMU500_ACTLR_CPRE)
dev_warn_once(smmu->dev, "Failed to disable prefetcher [errata #841119 and #826419], check ACR.CACHE_LOCK\n");
} }
return 0; return 0;
......
...@@ -10,16 +10,6 @@ ...@@ -10,16 +10,6 @@
#include "arm-smmu.h" #include "arm-smmu.h"
#include "arm-smmu-qcom.h" #include "arm-smmu-qcom.h"
enum qcom_smmu_impl_reg_offset {
QCOM_SMMU_TBU_PWR_STATUS,
QCOM_SMMU_STATS_SYNC_INV_TBU_ACK,
QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR,
};
struct qcom_smmu_config {
const u32 *reg_offset;
};
void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu) void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu)
{ {
int ret; int ret;
...@@ -59,84 +49,3 @@ void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu) ...@@ -59,84 +49,3 @@ void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu)
tbu_pwr_status, sync_inv_ack, sync_inv_progress); tbu_pwr_status, sync_inv_ack, sync_inv_progress);
} }
} }
/* Implementation Defined Register Space 0 register offsets */
static const u32 qcom_smmu_impl0_reg_offset[] = {
[QCOM_SMMU_TBU_PWR_STATUS] = 0x2204,
[QCOM_SMMU_STATS_SYNC_INV_TBU_ACK] = 0x25dc,
[QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR] = 0x2670,
};
static const struct qcom_smmu_config qcm2290_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct qcom_smmu_config sc7180_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct qcom_smmu_config sc7280_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct qcom_smmu_config sc8180x_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct qcom_smmu_config sc8280xp_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct qcom_smmu_config sm6125_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct qcom_smmu_config sm6350_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct qcom_smmu_config sm8150_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct qcom_smmu_config sm8250_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct qcom_smmu_config sm8350_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct qcom_smmu_config sm8450_smmu_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
static const struct of_device_id __maybe_unused qcom_smmu_impl_debug_match[] = {
{ .compatible = "qcom,msm8998-smmu-v2" },
{ .compatible = "qcom,qcm2290-smmu-500", .data = &qcm2290_smmu_cfg },
{ .compatible = "qcom,sc7180-smmu-500", .data = &sc7180_smmu_cfg },
{ .compatible = "qcom,sc7280-smmu-500", .data = &sc7280_smmu_cfg},
{ .compatible = "qcom,sc8180x-smmu-500", .data = &sc8180x_smmu_cfg },
{ .compatible = "qcom,sc8280xp-smmu-500", .data = &sc8280xp_smmu_cfg },
{ .compatible = "qcom,sdm630-smmu-v2" },
{ .compatible = "qcom,sdm845-smmu-500" },
{ .compatible = "qcom,sm6125-smmu-500", .data = &sm6125_smmu_cfg},
{ .compatible = "qcom,sm6350-smmu-500", .data = &sm6350_smmu_cfg},
{ .compatible = "qcom,sm8150-smmu-500", .data = &sm8150_smmu_cfg },
{ .compatible = "qcom,sm8250-smmu-500", .data = &sm8250_smmu_cfg },
{ .compatible = "qcom,sm8350-smmu-500", .data = &sm8350_smmu_cfg },
{ .compatible = "qcom,sm8450-smmu-500", .data = &sm8450_smmu_cfg },
{ }
};
const void *qcom_smmu_impl_data(struct arm_smmu_device *smmu)
{
const struct of_device_id *match;
const struct device_node *np = smmu->dev->of_node;
match = of_match_node(qcom_smmu_impl_debug_match, np);
if (!match)
return NULL;
return match->data;
}
...@@ -361,6 +361,8 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu) ...@@ -361,6 +361,8 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
{ {
int ret; int ret;
arm_mmu500_reset(smmu);
/* /*
* To address performance degradation in non-real time clients, * To address performance degradation in non-real time clients,
* such as USB and UFS, turn off wait-for-safe on sdm845 based boards, * such as USB and UFS, turn off wait-for-safe on sdm845 based boards,
...@@ -374,41 +376,67 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu) ...@@ -374,41 +376,67 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
return ret; return ret;
} }
static int qcom_smmu500_reset(struct arm_smmu_device *smmu) static const struct arm_smmu_impl qcom_smmu_v2_impl = {
{ .init_context = qcom_smmu_init_context,
const struct device_node *np = smmu->dev->of_node; .cfg_probe = qcom_smmu_cfg_probe,
.def_domain_type = qcom_smmu_def_domain_type,
arm_mmu500_reset(smmu); .write_s2cr = qcom_smmu_write_s2cr,
.tlb_sync = qcom_smmu_tlb_sync,
if (of_device_is_compatible(np, "qcom,sdm845-smmu-500")) };
return qcom_sdm845_smmu500_reset(smmu);
return 0; static const struct arm_smmu_impl qcom_smmu_500_impl = {
} .init_context = qcom_smmu_init_context,
.cfg_probe = qcom_smmu_cfg_probe,
.def_domain_type = qcom_smmu_def_domain_type,
.reset = arm_mmu500_reset,
.write_s2cr = qcom_smmu_write_s2cr,
.tlb_sync = qcom_smmu_tlb_sync,
};
static const struct arm_smmu_impl qcom_smmu_impl = { static const struct arm_smmu_impl sdm845_smmu_500_impl = {
.init_context = qcom_smmu_init_context, .init_context = qcom_smmu_init_context,
.cfg_probe = qcom_smmu_cfg_probe, .cfg_probe = qcom_smmu_cfg_probe,
.def_domain_type = qcom_smmu_def_domain_type, .def_domain_type = qcom_smmu_def_domain_type,
.reset = qcom_smmu500_reset, .reset = qcom_sdm845_smmu500_reset,
.write_s2cr = qcom_smmu_write_s2cr, .write_s2cr = qcom_smmu_write_s2cr,
.tlb_sync = qcom_smmu_tlb_sync, .tlb_sync = qcom_smmu_tlb_sync,
}; };
static const struct arm_smmu_impl qcom_adreno_smmu_impl = { static const struct arm_smmu_impl qcom_adreno_smmu_v2_impl = {
.init_context = qcom_adreno_smmu_init_context,
.def_domain_type = qcom_smmu_def_domain_type,
.alloc_context_bank = qcom_adreno_smmu_alloc_context_bank,
.write_sctlr = qcom_adreno_smmu_write_sctlr,
.tlb_sync = qcom_smmu_tlb_sync,
};
static const struct arm_smmu_impl qcom_adreno_smmu_500_impl = {
.init_context = qcom_adreno_smmu_init_context, .init_context = qcom_adreno_smmu_init_context,
.def_domain_type = qcom_smmu_def_domain_type, .def_domain_type = qcom_smmu_def_domain_type,
.reset = qcom_smmu500_reset, .reset = arm_mmu500_reset,
.alloc_context_bank = qcom_adreno_smmu_alloc_context_bank, .alloc_context_bank = qcom_adreno_smmu_alloc_context_bank,
.write_sctlr = qcom_adreno_smmu_write_sctlr, .write_sctlr = qcom_adreno_smmu_write_sctlr,
.tlb_sync = qcom_smmu_tlb_sync, .tlb_sync = qcom_smmu_tlb_sync,
}; };
static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu, static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
const struct arm_smmu_impl *impl) const struct qcom_smmu_match_data *data)
{ {
const struct device_node *np = smmu->dev->of_node;
const struct arm_smmu_impl *impl;
struct qcom_smmu *qsmmu; struct qcom_smmu *qsmmu;
if (!data)
return ERR_PTR(-EINVAL);
if (np && of_device_is_compatible(np, "qcom,adreno-smmu"))
impl = data->adreno_impl;
else
impl = data->impl;
if (!impl)
return smmu;
/* Check to make sure qcom_scm has finished probing */ /* Check to make sure qcom_scm has finished probing */
if (!qcom_scm_is_available()) if (!qcom_scm_is_available())
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
...@@ -418,27 +446,77 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu, ...@@ -418,27 +446,77 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
qsmmu->smmu.impl = impl; qsmmu->smmu.impl = impl;
qsmmu->cfg = qcom_smmu_impl_data(smmu); qsmmu->cfg = data->cfg;
return &qsmmu->smmu; return &qsmmu->smmu;
} }
/* Implementation Defined Register Space 0 register offsets */
static const u32 qcom_smmu_impl0_reg_offset[] = {
[QCOM_SMMU_TBU_PWR_STATUS] = 0x2204,
[QCOM_SMMU_STATS_SYNC_INV_TBU_ACK] = 0x25dc,
[QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR] = 0x2670,
};
static const struct qcom_smmu_config qcom_smmu_impl0_cfg = {
.reg_offset = qcom_smmu_impl0_reg_offset,
};
/*
* It is not yet possible to use MDP SMMU with the bypass quirk on the msm8996,
* there are not enough context banks.
*/
static const struct qcom_smmu_match_data msm8996_smmu_data = {
.impl = NULL,
.adreno_impl = &qcom_adreno_smmu_v2_impl,
};
static const struct qcom_smmu_match_data qcom_smmu_v2_data = {
.impl = &qcom_smmu_v2_impl,
.adreno_impl = &qcom_adreno_smmu_v2_impl,
};
static const struct qcom_smmu_match_data sdm845_smmu_500_data = {
.impl = &sdm845_smmu_500_impl,
/*
* No need for adreno impl here. On sdm845 the Adreno SMMU is handled
* by the separate sdm845-smmu-v2 device.
*/
/* Also no debug configuration. */
};
static const struct qcom_smmu_match_data qcom_smmu_500_impl0_data = {
.impl = &qcom_smmu_500_impl,
.adreno_impl = &qcom_adreno_smmu_500_impl,
.cfg = &qcom_smmu_impl0_cfg,
};
/*
* Do not add any more qcom,SOC-smmu-500 entries to this list, unless they need
* special handling and can not be covered by the qcom,smmu-500 entry.
*/
static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = { static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = {
{ .compatible = "qcom,msm8998-smmu-v2" }, { .compatible = "qcom,msm8996-smmu-v2", .data = &msm8996_smmu_data },
{ .compatible = "qcom,qcm2290-smmu-500" }, { .compatible = "qcom,msm8998-smmu-v2", .data = &qcom_smmu_v2_data },
{ .compatible = "qcom,sc7180-smmu-500" }, { .compatible = "qcom,qcm2290-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sc7280-smmu-500" }, { .compatible = "qcom,qdu1000-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sc8180x-smmu-500" }, { .compatible = "qcom,sc7180-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sc8280xp-smmu-500" }, { .compatible = "qcom,sc7280-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sdm630-smmu-v2" }, { .compatible = "qcom,sc8180x-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sdm845-smmu-500" }, { .compatible = "qcom,sc8280xp-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sm6125-smmu-500" }, { .compatible = "qcom,sdm630-smmu-v2", .data = &qcom_smmu_v2_data },
{ .compatible = "qcom,sm6350-smmu-500" }, { .compatible = "qcom,sdm845-smmu-v2", .data = &qcom_smmu_v2_data },
{ .compatible = "qcom,sm6375-smmu-500" }, { .compatible = "qcom,sdm845-smmu-500", .data = &sdm845_smmu_500_data },
{ .compatible = "qcom,sm8150-smmu-500" }, { .compatible = "qcom,sm6115-smmu-500", .data = &qcom_smmu_500_impl0_data},
{ .compatible = "qcom,sm8250-smmu-500" }, { .compatible = "qcom,sm6125-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sm8350-smmu-500" }, { .compatible = "qcom,sm6350-smmu-v2", .data = &qcom_smmu_v2_data },
{ .compatible = "qcom,sm8450-smmu-500" }, { .compatible = "qcom,sm6350-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sm6375-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sm8150-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sm8250-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sm8350-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,sm8450-smmu-500", .data = &qcom_smmu_500_impl0_data },
{ .compatible = "qcom,smmu-500", .data = &qcom_smmu_500_impl0_data },
{ } { }
}; };
...@@ -453,26 +531,19 @@ static struct acpi_platform_list qcom_acpi_platlist[] = { ...@@ -453,26 +531,19 @@ static struct acpi_platform_list qcom_acpi_platlist[] = {
struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu) struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu)
{ {
const struct device_node *np = smmu->dev->of_node; const struct device_node *np = smmu->dev->of_node;
const struct of_device_id *match;
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
if (np == NULL) { if (np == NULL) {
/* Match platform for ACPI boot */ /* Match platform for ACPI boot */
if (acpi_match_platform_list(qcom_acpi_platlist) >= 0) if (acpi_match_platform_list(qcom_acpi_platlist) >= 0)
return qcom_smmu_create(smmu, &qcom_smmu_impl); return qcom_smmu_create(smmu, &qcom_smmu_500_impl0_data);
} }
#endif #endif
/* match = of_match_node(qcom_smmu_impl_of_match, np);
* Do not change this order of implementation, i.e., first adreno if (match)
* smmu impl and then apss smmu since we can have both implementing return qcom_smmu_create(smmu, match->data);
* arm,mmu-500 in which case we will miss setting adreno smmu specific
* features if the order is changed.
*/
if (of_device_is_compatible(np, "qcom,adreno-smmu"))
return qcom_smmu_create(smmu, &qcom_adreno_smmu_impl);
if (of_match_node(qcom_smmu_impl_of_match, np))
return qcom_smmu_create(smmu, &qcom_smmu_impl);
return smmu; return smmu;
} }
...@@ -14,15 +14,26 @@ struct qcom_smmu { ...@@ -14,15 +14,26 @@ struct qcom_smmu {
u32 stall_enabled; u32 stall_enabled;
}; };
enum qcom_smmu_impl_reg_offset {
QCOM_SMMU_TBU_PWR_STATUS,
QCOM_SMMU_STATS_SYNC_INV_TBU_ACK,
QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR,
};
struct qcom_smmu_config {
const u32 *reg_offset;
};
struct qcom_smmu_match_data {
const struct qcom_smmu_config *cfg;
const struct arm_smmu_impl *impl;
const struct arm_smmu_impl *adreno_impl;
};
#ifdef CONFIG_ARM_SMMU_QCOM_DEBUG #ifdef CONFIG_ARM_SMMU_QCOM_DEBUG
void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu); void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu);
const void *qcom_smmu_impl_data(struct arm_smmu_device *smmu);
#else #else
static inline void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu) { } static inline void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu) { }
static inline const void *qcom_smmu_impl_data(struct arm_smmu_device *smmu)
{
return NULL;
}
#endif #endif
#endif /* _ARM_SMMU_QCOM_H */ #endif /* _ARM_SMMU_QCOM_H */
...@@ -410,7 +410,8 @@ static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *de ...@@ -410,7 +410,8 @@ static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *de
} }
static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova, static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot, gfp_t gfp) phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
{ {
int ret; int ret;
unsigned long flags; unsigned long flags;
...@@ -421,13 +422,14 @@ static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova, ...@@ -421,13 +422,14 @@ static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova,
return -ENODEV; return -ENODEV;
spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags);
ret = ops->map(ops, iova, paddr, size, prot, GFP_ATOMIC); ret = ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, GFP_ATOMIC, mapped);
spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags);
return ret; return ret;
} }
static size_t qcom_iommu_unmap(struct iommu_domain *domain, unsigned long iova, static size_t qcom_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size, struct iommu_iotlb_gather *gather) size_t pgsize, size_t pgcount,
struct iommu_iotlb_gather *gather)
{ {
size_t ret; size_t ret;
unsigned long flags; unsigned long flags;
...@@ -444,7 +446,7 @@ static size_t qcom_iommu_unmap(struct iommu_domain *domain, unsigned long iova, ...@@ -444,7 +446,7 @@ static size_t qcom_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
*/ */
pm_runtime_get_sync(qcom_domain->iommu->dev); pm_runtime_get_sync(qcom_domain->iommu->dev);
spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags); spin_lock_irqsave(&qcom_domain->pgtbl_lock, flags);
ret = ops->unmap(ops, iova, size, gather); ret = ops->unmap_pages(ops, iova, pgsize, pgcount, gather);
spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags); spin_unlock_irqrestore(&qcom_domain->pgtbl_lock, flags);
pm_runtime_put_sync(qcom_domain->iommu->dev); pm_runtime_put_sync(qcom_domain->iommu->dev);
...@@ -582,8 +584,8 @@ static const struct iommu_ops qcom_iommu_ops = { ...@@ -582,8 +584,8 @@ static const struct iommu_ops qcom_iommu_ops = {
.default_domain_ops = &(const struct iommu_domain_ops) { .default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = qcom_iommu_attach_dev, .attach_dev = qcom_iommu_attach_dev,
.detach_dev = qcom_iommu_detach_dev, .detach_dev = qcom_iommu_detach_dev,
.map = qcom_iommu_map, .map_pages = qcom_iommu_map,
.unmap = qcom_iommu_unmap, .unmap_pages = qcom_iommu_unmap,
.flush_iotlb_all = qcom_iommu_flush_iotlb_all, .flush_iotlb_all = qcom_iommu_flush_iotlb_all,
.iotlb_sync = qcom_iommu_iotlb_sync, .iotlb_sync = qcom_iommu_iotlb_sync,
.iova_to_phys = qcom_iommu_iova_to_phys, .iova_to_phys = qcom_iommu_iova_to_phys,
......
...@@ -708,10 +708,6 @@ static int exynos_sysmmu_probe(struct platform_device *pdev) ...@@ -708,10 +708,6 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
ret = iommu_device_register(&data->iommu, &exynos_iommu_ops, dev);
if (ret)
goto err_iommu_register;
platform_set_drvdata(pdev, data); platform_set_drvdata(pdev, data);
if (PG_ENT_SHIFT < 0) { if (PG_ENT_SHIFT < 0) {
...@@ -743,11 +739,13 @@ static int exynos_sysmmu_probe(struct platform_device *pdev) ...@@ -743,11 +739,13 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
pm_runtime_enable(dev); pm_runtime_enable(dev);
ret = iommu_device_register(&data->iommu, &exynos_iommu_ops, dev);
if (ret)
goto err_dma_set_mask;
return 0; return 0;
err_dma_set_mask: err_dma_set_mask:
iommu_device_unregister(&data->iommu);
err_iommu_register:
iommu_device_sysfs_remove(&data->iommu); iommu_device_sysfs_remove(&data->iommu);
return ret; return ret;
} }
...@@ -1432,12 +1430,6 @@ static int __init exynos_iommu_init(void) ...@@ -1432,12 +1430,6 @@ static int __init exynos_iommu_init(void)
return -ENOMEM; return -ENOMEM;
} }
ret = platform_driver_register(&exynos_sysmmu_driver);
if (ret) {
pr_err("%s: Failed to register driver\n", __func__);
goto err_reg_driver;
}
zero_lv2_table = kmem_cache_zalloc(lv2table_kmem_cache, GFP_KERNEL); zero_lv2_table = kmem_cache_zalloc(lv2table_kmem_cache, GFP_KERNEL);
if (zero_lv2_table == NULL) { if (zero_lv2_table == NULL) {
pr_err("%s: Failed to allocate zero level2 page table\n", pr_err("%s: Failed to allocate zero level2 page table\n",
...@@ -1446,10 +1438,16 @@ static int __init exynos_iommu_init(void) ...@@ -1446,10 +1438,16 @@ static int __init exynos_iommu_init(void)
goto err_zero_lv2; goto err_zero_lv2;
} }
ret = platform_driver_register(&exynos_sysmmu_driver);
if (ret) {
pr_err("%s: Failed to register driver\n", __func__);
goto err_reg_driver;
}
return 0; return 0;
err_zero_lv2:
platform_driver_unregister(&exynos_sysmmu_driver);
err_reg_driver: err_reg_driver:
platform_driver_unregister(&exynos_sysmmu_driver);
err_zero_lv2:
kmem_cache_destroy(lv2table_kmem_cache); kmem_cache_destroy(lv2table_kmem_cache);
return ret; return ret;
} }
......
...@@ -779,7 +779,7 @@ static int fsl_pamu_probe(struct platform_device *pdev) ...@@ -779,7 +779,7 @@ static int fsl_pamu_probe(struct platform_device *pdev)
of_get_address(dev->of_node, 0, &size, NULL); of_get_address(dev->of_node, 0, &size, NULL);
irq = irq_of_parse_and_map(dev->of_node, 0); irq = irq_of_parse_and_map(dev->of_node, 0);
if (irq == NO_IRQ) { if (!irq) {
dev_warn(dev, "no interrupts listed in PAMU node\n"); dev_warn(dev, "no interrupts listed in PAMU node\n");
goto error; goto error;
} }
...@@ -868,7 +868,7 @@ static int fsl_pamu_probe(struct platform_device *pdev) ...@@ -868,7 +868,7 @@ static int fsl_pamu_probe(struct platform_device *pdev)
ret = create_csd(ppaact_phys, mem_size, csd_port_id); ret = create_csd(ppaact_phys, mem_size, csd_port_id);
if (ret) { if (ret) {
dev_err(dev, "could not create coherence subdomain\n"); dev_err(dev, "could not create coherence subdomain\n");
return ret; goto error;
} }
} }
...@@ -903,7 +903,7 @@ static int fsl_pamu_probe(struct platform_device *pdev) ...@@ -903,7 +903,7 @@ static int fsl_pamu_probe(struct platform_device *pdev)
return 0; return 0;
error: error:
if (irq != NO_IRQ) if (irq)
free_irq(irq, data); free_irq(irq, data);
kfree_sensitive(data); kfree_sensitive(data);
......
...@@ -277,7 +277,8 @@ static LIST_HEAD(dmar_satc_units); ...@@ -277,7 +277,8 @@ static LIST_HEAD(dmar_satc_units);
#define for_each_rmrr_units(rmrr) \ #define for_each_rmrr_units(rmrr) \
list_for_each_entry(rmrr, &dmar_rmrr_units, list) list_for_each_entry(rmrr, &dmar_rmrr_units, list)
static void dmar_remove_one_dev_info(struct device *dev); static void device_block_translation(struct device *dev);
static void intel_iommu_domain_free(struct iommu_domain *domain);
int dmar_disabled = !IS_ENABLED(CONFIG_INTEL_IOMMU_DEFAULT_ON); int dmar_disabled = !IS_ENABLED(CONFIG_INTEL_IOMMU_DEFAULT_ON);
int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON);
...@@ -382,11 +383,6 @@ static inline int domain_type_is_si(struct dmar_domain *domain) ...@@ -382,11 +383,6 @@ static inline int domain_type_is_si(struct dmar_domain *domain)
return domain->domain.type == IOMMU_DOMAIN_IDENTITY; return domain->domain.type == IOMMU_DOMAIN_IDENTITY;
} }
static inline bool domain_use_first_level(struct dmar_domain *domain)
{
return domain->flags & DOMAIN_FLAG_USE_FIRST_LEVEL;
}
static inline int domain_pfn_supported(struct dmar_domain *domain, static inline int domain_pfn_supported(struct dmar_domain *domain,
unsigned long pfn) unsigned long pfn)
{ {
...@@ -500,7 +496,7 @@ static int domain_update_iommu_superpage(struct dmar_domain *domain, ...@@ -500,7 +496,7 @@ static int domain_update_iommu_superpage(struct dmar_domain *domain,
rcu_read_lock(); rcu_read_lock();
for_each_active_iommu(iommu, drhd) { for_each_active_iommu(iommu, drhd) {
if (iommu != skip) { if (iommu != skip) {
if (domain && domain_use_first_level(domain)) { if (domain && domain->use_first_level) {
if (!cap_fl1gp_support(iommu->cap)) if (!cap_fl1gp_support(iommu->cap))
mask = 0x1; mask = 0x1;
} else { } else {
...@@ -578,7 +574,7 @@ static void domain_update_iommu_cap(struct dmar_domain *domain) ...@@ -578,7 +574,7 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)
* paging and 57-bits with 5-level paging). Hence, skip bit * paging and 57-bits with 5-level paging). Hence, skip bit
* [N-1]. * [N-1].
*/ */
if (domain_use_first_level(domain)) if (domain->use_first_level)
domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw - 1); domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw - 1);
else else
domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw); domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw);
...@@ -779,19 +775,6 @@ static void domain_flush_cache(struct dmar_domain *domain, ...@@ -779,19 +775,6 @@ static void domain_flush_cache(struct dmar_domain *domain,
clflush_cache_range(addr, size); clflush_cache_range(addr, size);
} }
static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
{
struct context_entry *context;
int ret = 0;
spin_lock(&iommu->lock);
context = iommu_context_addr(iommu, bus, devfn, 0);
if (context)
ret = context_present(context);
spin_unlock(&iommu->lock);
return ret;
}
static void free_context_table(struct intel_iommu *iommu) static void free_context_table(struct intel_iommu *iommu)
{ {
struct context_entry *context; struct context_entry *context;
...@@ -959,7 +942,7 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain, ...@@ -959,7 +942,7 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE); domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE; pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
if (domain_use_first_level(domain)) if (domain->use_first_level)
pteval |= DMA_FL_PTE_XD | DMA_FL_PTE_US | DMA_FL_PTE_ACCESS; pteval |= DMA_FL_PTE_XD | DMA_FL_PTE_US | DMA_FL_PTE_ACCESS;
if (cmpxchg64(&pte->val, 0ULL, pteval)) if (cmpxchg64(&pte->val, 0ULL, pteval))
...@@ -1418,7 +1401,7 @@ static void iommu_enable_pci_caps(struct device_domain_info *info) ...@@ -1418,7 +1401,7 @@ static void iommu_enable_pci_caps(struct device_domain_info *info)
{ {
struct pci_dev *pdev; struct pci_dev *pdev;
if (!info || !dev_is_pci(info->dev)) if (!dev_is_pci(info->dev))
return; return;
pdev = to_pci_dev(info->dev); pdev = to_pci_dev(info->dev);
...@@ -1458,7 +1441,7 @@ static void iommu_enable_pci_caps(struct device_domain_info *info) ...@@ -1458,7 +1441,7 @@ static void iommu_enable_pci_caps(struct device_domain_info *info)
} }
} }
static void iommu_disable_dev_iotlb(struct device_domain_info *info) static void iommu_disable_pci_caps(struct device_domain_info *info)
{ {
struct pci_dev *pdev; struct pci_dev *pdev;
...@@ -1529,7 +1512,7 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, ...@@ -1529,7 +1512,7 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
if (ih) if (ih)
ih = 1 << 6; ih = 1 << 6;
if (domain_use_first_level(domain)) { if (domain->use_first_level) {
qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr, pages, ih); qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr, pages, ih);
} else { } else {
unsigned long bitmask = aligned_pages - 1; unsigned long bitmask = aligned_pages - 1;
...@@ -1583,7 +1566,7 @@ static inline void __mapping_notify_one(struct intel_iommu *iommu, ...@@ -1583,7 +1566,7 @@ static inline void __mapping_notify_one(struct intel_iommu *iommu,
* It's a non-present to present mapping. Only flush if caching mode * It's a non-present to present mapping. Only flush if caching mode
* and second level. * and second level.
*/ */
if (cap_caching_mode(iommu->cap) && !domain_use_first_level(domain)) if (cap_caching_mode(iommu->cap) && !domain->use_first_level)
iommu_flush_iotlb_psi(iommu, domain, pfn, pages, 0, 1); iommu_flush_iotlb_psi(iommu, domain, pfn, pages, 0, 1);
else else
iommu_flush_write_buffer(iommu); iommu_flush_write_buffer(iommu);
...@@ -1599,7 +1582,7 @@ static void intel_flush_iotlb_all(struct iommu_domain *domain) ...@@ -1599,7 +1582,7 @@ static void intel_flush_iotlb_all(struct iommu_domain *domain)
struct intel_iommu *iommu = info->iommu; struct intel_iommu *iommu = info->iommu;
u16 did = domain_id_iommu(dmar_domain, iommu); u16 did = domain_id_iommu(dmar_domain, iommu);
if (domain_use_first_level(dmar_domain)) if (dmar_domain->use_first_level)
qi_flush_piotlb(iommu, did, PASID_RID2PASID, 0, -1, 0); qi_flush_piotlb(iommu, did, PASID_RID2PASID, 0, -1, 0);
else else
iommu->flush.flush_iotlb(iommu, did, 0, 0, iommu->flush.flush_iotlb(iommu, did, 0, 0,
...@@ -1772,7 +1755,7 @@ static struct dmar_domain *alloc_domain(unsigned int type) ...@@ -1772,7 +1755,7 @@ static struct dmar_domain *alloc_domain(unsigned int type)
domain->nid = NUMA_NO_NODE; domain->nid = NUMA_NO_NODE;
if (first_level_by_default(type)) if (first_level_by_default(type))
domain->flags |= DOMAIN_FLAG_USE_FIRST_LEVEL; domain->use_first_level = true;
domain->has_iotlb_device = false; domain->has_iotlb_device = false;
INIT_LIST_HEAD(&domain->devices); INIT_LIST_HEAD(&domain->devices);
spin_lock_init(&domain->lock); spin_lock_init(&domain->lock);
...@@ -2064,7 +2047,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain, ...@@ -2064,7 +2047,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
} else { } else {
iommu_flush_write_buffer(iommu); iommu_flush_write_buffer(iommu);
} }
iommu_enable_pci_caps(info);
ret = 0; ret = 0;
...@@ -2116,30 +2098,6 @@ domain_context_mapping(struct dmar_domain *domain, struct device *dev) ...@@ -2116,30 +2098,6 @@ domain_context_mapping(struct dmar_domain *domain, struct device *dev)
&domain_context_mapping_cb, &data); &domain_context_mapping_cb, &data);
} }
static int domain_context_mapped_cb(struct pci_dev *pdev,
u16 alias, void *opaque)
{
struct intel_iommu *iommu = opaque;
return !device_context_mapped(iommu, PCI_BUS_NUM(alias), alias & 0xff);
}
static int domain_context_mapped(struct device *dev)
{
struct intel_iommu *iommu;
u8 bus, devfn;
iommu = device_to_iommu(dev, &bus, &devfn);
if (!iommu)
return -ENODEV;
if (!dev_is_pci(dev))
return device_context_mapped(iommu, bus, devfn);
return !pci_for_each_dma_alias(to_pci_dev(dev),
domain_context_mapped_cb, iommu);
}
/* Returns a number of VTD pages, but aligned to MM page size */ /* Returns a number of VTD pages, but aligned to MM page size */
static inline unsigned long aligned_nrpages(unsigned long host_addr, static inline unsigned long aligned_nrpages(unsigned long host_addr,
size_t size) size_t size)
...@@ -2229,7 +2187,7 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, ...@@ -2229,7 +2187,7 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
attr = prot & (DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP); attr = prot & (DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP);
attr |= DMA_FL_PTE_PRESENT; attr |= DMA_FL_PTE_PRESENT;
if (domain_use_first_level(domain)) { if (domain->use_first_level) {
attr |= DMA_FL_PTE_XD | DMA_FL_PTE_US | DMA_FL_PTE_ACCESS; attr |= DMA_FL_PTE_XD | DMA_FL_PTE_US | DMA_FL_PTE_ACCESS;
if (prot & DMA_PTE_WRITE) if (prot & DMA_PTE_WRITE)
attr |= DMA_FL_PTE_DIRTY; attr |= DMA_FL_PTE_DIRTY;
...@@ -2472,7 +2430,8 @@ static int __init si_domain_init(int hw) ...@@ -2472,7 +2430,8 @@ static int __init si_domain_init(int hw)
return 0; return 0;
} }
static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev) static int dmar_domain_attach_device(struct dmar_domain *domain,
struct device *dev)
{ {
struct device_domain_info *info = dev_iommu_priv_get(dev); struct device_domain_info *info = dev_iommu_priv_get(dev);
struct intel_iommu *iommu; struct intel_iommu *iommu;
...@@ -2494,18 +2453,11 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev) ...@@ -2494,18 +2453,11 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)
/* PASID table is mandatory for a PCI device in scalable mode. */ /* PASID table is mandatory for a PCI device in scalable mode. */
if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) { if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
ret = intel_pasid_alloc_table(dev);
if (ret) {
dev_err(dev, "PASID table allocation failed\n");
dmar_remove_one_dev_info(dev);
return ret;
}
/* Setup the PASID entry for requests without PASID: */ /* Setup the PASID entry for requests without PASID: */
if (hw_pass_through && domain_type_is_si(domain)) if (hw_pass_through && domain_type_is_si(domain))
ret = intel_pasid_setup_pass_through(iommu, domain, ret = intel_pasid_setup_pass_through(iommu, domain,
dev, PASID_RID2PASID); dev, PASID_RID2PASID);
else if (domain_use_first_level(domain)) else if (domain->use_first_level)
ret = domain_setup_first_level(iommu, domain, dev, ret = domain_setup_first_level(iommu, domain, dev,
PASID_RID2PASID); PASID_RID2PASID);
else else
...@@ -2513,7 +2465,7 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev) ...@@ -2513,7 +2465,7 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)
dev, PASID_RID2PASID); dev, PASID_RID2PASID);
if (ret) { if (ret) {
dev_err(dev, "Setup RID2PASID failed\n"); dev_err(dev, "Setup RID2PASID failed\n");
dmar_remove_one_dev_info(dev); device_block_translation(dev);
return ret; return ret;
} }
} }
...@@ -2521,10 +2473,12 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev) ...@@ -2521,10 +2473,12 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)
ret = domain_context_mapping(domain, dev); ret = domain_context_mapping(domain, dev);
if (ret) { if (ret) {
dev_err(dev, "Domain context map failed\n"); dev_err(dev, "Domain context map failed\n");
dmar_remove_one_dev_info(dev); device_block_translation(dev);
return ret; return ret;
} }
iommu_enable_pci_caps(info);
return 0; return 0;
} }
...@@ -4125,9 +4079,8 @@ static void dmar_remove_one_dev_info(struct device *dev) ...@@ -4125,9 +4079,8 @@ static void dmar_remove_one_dev_info(struct device *dev)
intel_pasid_tear_down_entry(iommu, info->dev, intel_pasid_tear_down_entry(iommu, info->dev,
PASID_RID2PASID, false); PASID_RID2PASID, false);
iommu_disable_dev_iotlb(info); iommu_disable_pci_caps(info);
domain_context_clear(info); domain_context_clear(info);
intel_pasid_free_table(info->dev);
} }
spin_lock_irqsave(&domain->lock, flags); spin_lock_irqsave(&domain->lock, flags);
...@@ -4138,6 +4091,37 @@ static void dmar_remove_one_dev_info(struct device *dev) ...@@ -4138,6 +4091,37 @@ static void dmar_remove_one_dev_info(struct device *dev)
info->domain = NULL; info->domain = NULL;
} }
/*
* Clear the page table pointer in context or pasid table entries so that
* all DMA requests without PASID from the device are blocked. If the page
* table has been set, clean up the data structures.
*/
static void device_block_translation(struct device *dev)
{
struct device_domain_info *info = dev_iommu_priv_get(dev);
struct intel_iommu *iommu = info->iommu;
unsigned long flags;
iommu_disable_pci_caps(info);
if (!dev_is_real_dma_subdevice(dev)) {
if (sm_supported(iommu))
intel_pasid_tear_down_entry(iommu, dev,
PASID_RID2PASID, false);
else
domain_context_clear(info);
}
if (!info->domain)
return;
spin_lock_irqsave(&info->domain->lock, flags);
list_del(&info->link);
spin_unlock_irqrestore(&info->domain->lock, flags);
domain_detach_iommu(info->domain, iommu);
info->domain = NULL;
}
static int md_domain_init(struct dmar_domain *domain, int guest_width) static int md_domain_init(struct dmar_domain *domain, int guest_width)
{ {
int adjust_width; int adjust_width;
...@@ -4159,12 +4143,28 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width) ...@@ -4159,12 +4143,28 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
return 0; return 0;
} }
static int blocking_domain_attach_dev(struct iommu_domain *domain,
struct device *dev)
{
device_block_translation(dev);
return 0;
}
static struct iommu_domain blocking_domain = {
.ops = &(const struct iommu_domain_ops) {
.attach_dev = blocking_domain_attach_dev,
.free = intel_iommu_domain_free
}
};
static struct iommu_domain *intel_iommu_domain_alloc(unsigned type) static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
{ {
struct dmar_domain *dmar_domain; struct dmar_domain *dmar_domain;
struct iommu_domain *domain; struct iommu_domain *domain;
switch (type) { switch (type) {
case IOMMU_DOMAIN_BLOCKED:
return &blocking_domain;
case IOMMU_DOMAIN_DMA: case IOMMU_DOMAIN_DMA:
case IOMMU_DOMAIN_DMA_FQ: case IOMMU_DOMAIN_DMA_FQ:
case IOMMU_DOMAIN_UNMANAGED: case IOMMU_DOMAIN_UNMANAGED:
...@@ -4199,7 +4199,7 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type) ...@@ -4199,7 +4199,7 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
static void intel_iommu_domain_free(struct iommu_domain *domain) static void intel_iommu_domain_free(struct iommu_domain *domain)
{ {
if (domain != &si_domain->domain) if (domain != &si_domain->domain && domain != &blocking_domain)
domain_exit(to_dmar_domain(domain)); domain_exit(to_dmar_domain(domain));
} }
...@@ -4246,6 +4246,7 @@ static int prepare_domain_attach_device(struct iommu_domain *domain, ...@@ -4246,6 +4246,7 @@ static int prepare_domain_attach_device(struct iommu_domain *domain,
static int intel_iommu_attach_device(struct iommu_domain *domain, static int intel_iommu_attach_device(struct iommu_domain *domain,
struct device *dev) struct device *dev)
{ {
struct device_domain_info *info = dev_iommu_priv_get(dev);
int ret; int ret;
if (domain->type == IOMMU_DOMAIN_UNMANAGED && if (domain->type == IOMMU_DOMAIN_UNMANAGED &&
...@@ -4254,25 +4255,14 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, ...@@ -4254,25 +4255,14 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
return -EPERM; return -EPERM;
} }
/* normally dev is not mapped */
if (unlikely(domain_context_mapped(dev))) {
struct device_domain_info *info = dev_iommu_priv_get(dev);
if (info->domain) if (info->domain)
dmar_remove_one_dev_info(dev); device_block_translation(dev);
}
ret = prepare_domain_attach_device(domain, dev); ret = prepare_domain_attach_device(domain, dev);
if (ret) if (ret)
return ret; return ret;
return domain_add_dev_info(to_dmar_domain(domain), dev); return dmar_domain_attach_device(to_dmar_domain(domain), dev);
}
static void intel_iommu_detach_device(struct iommu_domain *domain,
struct device *dev)
{
dmar_remove_one_dev_info(dev);
} }
static int intel_iommu_map(struct iommu_domain *domain, static int intel_iommu_map(struct iommu_domain *domain,
...@@ -4436,7 +4426,7 @@ static void domain_set_force_snooping(struct dmar_domain *domain) ...@@ -4436,7 +4426,7 @@ static void domain_set_force_snooping(struct dmar_domain *domain)
* Second level page table supports per-PTE snoop control. The * Second level page table supports per-PTE snoop control. The
* iommu_map() interface will handle this by setting SNP bit. * iommu_map() interface will handle this by setting SNP bit.
*/ */
if (!domain_use_first_level(domain)) { if (!domain->use_first_level) {
domain->set_pte_snp = true; domain->set_pte_snp = true;
return; return;
} }
...@@ -4491,6 +4481,7 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev) ...@@ -4491,6 +4481,7 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
struct device_domain_info *info; struct device_domain_info *info;
struct intel_iommu *iommu; struct intel_iommu *iommu;
u8 bus, devfn; u8 bus, devfn;
int ret;
iommu = device_to_iommu(dev, &bus, &devfn); iommu = device_to_iommu(dev, &bus, &devfn);
if (!iommu || !iommu->iommu.ops) if (!iommu || !iommu->iommu.ops)
...@@ -4535,6 +4526,16 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev) ...@@ -4535,6 +4526,16 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
dev_iommu_priv_set(dev, info); dev_iommu_priv_set(dev, info);
if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
ret = intel_pasid_alloc_table(dev);
if (ret) {
dev_err(dev, "PASID table allocation failed\n");
dev_iommu_priv_set(dev, NULL);
kfree(info);
return ERR_PTR(ret);
}
}
return &iommu->iommu; return &iommu->iommu;
} }
...@@ -4543,6 +4544,7 @@ static void intel_iommu_release_device(struct device *dev) ...@@ -4543,6 +4544,7 @@ static void intel_iommu_release_device(struct device *dev)
struct device_domain_info *info = dev_iommu_priv_get(dev); struct device_domain_info *info = dev_iommu_priv_get(dev);
dmar_remove_one_dev_info(dev); dmar_remove_one_dev_info(dev);
intel_pasid_free_table(dev);
dev_iommu_priv_set(dev, NULL); dev_iommu_priv_set(dev, NULL);
kfree(info); kfree(info);
set_dma_ops(dev, NULL); set_dma_ops(dev, NULL);
...@@ -4777,7 +4779,6 @@ const struct iommu_ops intel_iommu_ops = { ...@@ -4777,7 +4779,6 @@ const struct iommu_ops intel_iommu_ops = {
#endif #endif
.default_domain_ops = &(const struct iommu_domain_ops) { .default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = intel_iommu_attach_device, .attach_dev = intel_iommu_attach_device,
.detach_dev = intel_iommu_detach_device,
.map_pages = intel_iommu_map_pages, .map_pages = intel_iommu_map_pages,
.unmap_pages = intel_iommu_unmap_pages, .unmap_pages = intel_iommu_unmap_pages,
.iotlb_sync_map = intel_iommu_iotlb_sync_map, .iotlb_sync_map = intel_iommu_iotlb_sync_map,
......
...@@ -515,14 +515,6 @@ struct context_entry { ...@@ -515,14 +515,6 @@ struct context_entry {
u64 hi; u64 hi;
}; };
/*
* When VT-d works in the scalable mode, it allows DMA translation to
* happen through either first level or second level page table. This
* bit marks that the DMA translation for the domain goes through the
* first level page table, otherwise, it goes through the second level.
*/
#define DOMAIN_FLAG_USE_FIRST_LEVEL BIT(1)
struct iommu_domain_info { struct iommu_domain_info {
struct intel_iommu *iommu; struct intel_iommu *iommu;
unsigned int refcnt; /* Refcount of devices per iommu */ unsigned int refcnt; /* Refcount of devices per iommu */
...@@ -539,6 +531,11 @@ struct dmar_domain { ...@@ -539,6 +531,11 @@ struct dmar_domain {
u8 iommu_coherency: 1; /* indicate coherency of iommu access */ u8 iommu_coherency: 1; /* indicate coherency of iommu access */
u8 force_snooping : 1; /* Create IOPTEs with snoop control */ u8 force_snooping : 1; /* Create IOPTEs with snoop control */
u8 set_pte_snp:1; u8 set_pte_snp:1;
u8 use_first_level:1; /* DMA translation for the domain goes
* through the first level page table,
* otherwise, goes through the second
* level.
*/
spinlock_t lock; /* Protect device tracking lists */ spinlock_t lock; /* Protect device tracking lists */
struct list_head devices; /* all devices' list */ struct list_head devices; /* all devices' list */
...@@ -548,8 +545,6 @@ struct dmar_domain { ...@@ -548,8 +545,6 @@ struct dmar_domain {
/* adjusted guest address width, 0 is level 2 30-bit */ /* adjusted guest address width, 0 is level 2 30-bit */
int agaw; int agaw;
int flags; /* flags to find out type of domain */
int iommu_superpage;/* Level of superpages supported: int iommu_superpage;/* Level of superpages supported:
0 == 4KiB (no superpages), 1 == 2MiB, 0 == 4KiB (no superpages), 1 == 2MiB,
2 == 1GiB, 3 == 512GiB, 4 == 1TiB */ 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
......
...@@ -564,7 +564,6 @@ static int arm_v7s_map_pages(struct io_pgtable_ops *ops, unsigned long iova, ...@@ -564,7 +564,6 @@ static int arm_v7s_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
iova += pgsize; iova += pgsize;
paddr += pgsize; paddr += pgsize;
if (mapped)
*mapped += pgsize; *mapped += pgsize;
} }
/* /*
...@@ -576,12 +575,6 @@ static int arm_v7s_map_pages(struct io_pgtable_ops *ops, unsigned long iova, ...@@ -576,12 +575,6 @@ static int arm_v7s_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
return ret; return ret;
} }
static int arm_v7s_map(struct io_pgtable_ops *ops, unsigned long iova,
phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
{
return arm_v7s_map_pages(ops, iova, paddr, size, 1, prot, gfp, NULL);
}
static void arm_v7s_free_pgtable(struct io_pgtable *iop) static void arm_v7s_free_pgtable(struct io_pgtable *iop)
{ {
struct arm_v7s_io_pgtable *data = io_pgtable_to_data(iop); struct arm_v7s_io_pgtable *data = io_pgtable_to_data(iop);
...@@ -764,12 +757,6 @@ static size_t arm_v7s_unmap_pages(struct io_pgtable_ops *ops, unsigned long iova ...@@ -764,12 +757,6 @@ static size_t arm_v7s_unmap_pages(struct io_pgtable_ops *ops, unsigned long iova
return unmapped; return unmapped;
} }
static size_t arm_v7s_unmap(struct io_pgtable_ops *ops, unsigned long iova,
size_t size, struct iommu_iotlb_gather *gather)
{
return arm_v7s_unmap_pages(ops, iova, size, 1, gather);
}
static phys_addr_t arm_v7s_iova_to_phys(struct io_pgtable_ops *ops, static phys_addr_t arm_v7s_iova_to_phys(struct io_pgtable_ops *ops,
unsigned long iova) unsigned long iova)
{ {
...@@ -842,9 +829,7 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg, ...@@ -842,9 +829,7 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg,
goto out_free_data; goto out_free_data;
data->iop.ops = (struct io_pgtable_ops) { data->iop.ops = (struct io_pgtable_ops) {
.map = arm_v7s_map,
.map_pages = arm_v7s_map_pages, .map_pages = arm_v7s_map_pages,
.unmap = arm_v7s_unmap,
.unmap_pages = arm_v7s_unmap_pages, .unmap_pages = arm_v7s_unmap_pages,
.iova_to_phys = arm_v7s_iova_to_phys, .iova_to_phys = arm_v7s_iova_to_phys,
}; };
...@@ -954,6 +939,7 @@ static int __init arm_v7s_do_selftests(void) ...@@ -954,6 +939,7 @@ static int __init arm_v7s_do_selftests(void)
}; };
unsigned int iova, size, iova_start; unsigned int iova, size, iova_start;
unsigned int i, loopnr = 0; unsigned int i, loopnr = 0;
size_t mapped;
selftest_running = true; selftest_running = true;
...@@ -984,15 +970,16 @@ static int __init arm_v7s_do_selftests(void) ...@@ -984,15 +970,16 @@ static int __init arm_v7s_do_selftests(void)
iova = 0; iova = 0;
for_each_set_bit(i, &cfg.pgsize_bitmap, BITS_PER_LONG) { for_each_set_bit(i, &cfg.pgsize_bitmap, BITS_PER_LONG) {
size = 1UL << i; size = 1UL << i;
if (ops->map(ops, iova, iova, size, IOMMU_READ | if (ops->map_pages(ops, iova, iova, size, 1,
IOMMU_WRITE | IOMMU_READ | IOMMU_WRITE |
IOMMU_NOEXEC | IOMMU_NOEXEC | IOMMU_CACHE,
IOMMU_CACHE, GFP_KERNEL)) GFP_KERNEL, &mapped))
return __FAIL(ops); return __FAIL(ops);
/* Overlapping mappings */ /* Overlapping mappings */
if (!ops->map(ops, iova, iova + size, size, if (!ops->map_pages(ops, iova, iova + size, size, 1,
IOMMU_READ | IOMMU_NOEXEC, GFP_KERNEL)) IOMMU_READ | IOMMU_NOEXEC, GFP_KERNEL,
&mapped))
return __FAIL(ops); return __FAIL(ops);
if (ops->iova_to_phys(ops, iova + 42) != (iova + 42)) if (ops->iova_to_phys(ops, iova + 42) != (iova + 42))
...@@ -1007,11 +994,12 @@ static int __init arm_v7s_do_selftests(void) ...@@ -1007,11 +994,12 @@ static int __init arm_v7s_do_selftests(void)
size = 1UL << __ffs(cfg.pgsize_bitmap); size = 1UL << __ffs(cfg.pgsize_bitmap);
while (i < loopnr) { while (i < loopnr) {
iova_start = i * SZ_16M; iova_start = i * SZ_16M;
if (ops->unmap(ops, iova_start + size, size, NULL) != size) if (ops->unmap_pages(ops, iova_start + size, size, 1, NULL) != size)
return __FAIL(ops); return __FAIL(ops);
/* Remap of partial unmap */ /* Remap of partial unmap */
if (ops->map(ops, iova_start + size, size, size, IOMMU_READ, GFP_KERNEL)) if (ops->map_pages(ops, iova_start + size, size, size, 1,
IOMMU_READ, GFP_KERNEL, &mapped))
return __FAIL(ops); return __FAIL(ops);
if (ops->iova_to_phys(ops, iova_start + size + 42) if (ops->iova_to_phys(ops, iova_start + size + 42)
...@@ -1025,14 +1013,15 @@ static int __init arm_v7s_do_selftests(void) ...@@ -1025,14 +1013,15 @@ static int __init arm_v7s_do_selftests(void)
for_each_set_bit(i, &cfg.pgsize_bitmap, BITS_PER_LONG) { for_each_set_bit(i, &cfg.pgsize_bitmap, BITS_PER_LONG) {
size = 1UL << i; size = 1UL << i;
if (ops->unmap(ops, iova, size, NULL) != size) if (ops->unmap_pages(ops, iova, size, 1, NULL) != size)
return __FAIL(ops); return __FAIL(ops);
if (ops->iova_to_phys(ops, iova + 42)) if (ops->iova_to_phys(ops, iova + 42))
return __FAIL(ops); return __FAIL(ops);
/* Remap full block */ /* Remap full block */
if (ops->map(ops, iova, iova, size, IOMMU_WRITE, GFP_KERNEL)) if (ops->map_pages(ops, iova, iova, size, 1, IOMMU_WRITE,
GFP_KERNEL, &mapped))
return __FAIL(ops); return __FAIL(ops);
if (ops->iova_to_phys(ops, iova + 42) != (iova + 42)) if (ops->iova_to_phys(ops, iova + 42) != (iova + 42))
......
...@@ -360,7 +360,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, ...@@ -360,7 +360,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
max_entries = ARM_LPAE_PTES_PER_TABLE(data) - map_idx_start; max_entries = ARM_LPAE_PTES_PER_TABLE(data) - map_idx_start;
num_entries = min_t(int, pgcount, max_entries); num_entries = min_t(int, pgcount, max_entries);
ret = arm_lpae_init_pte(data, iova, paddr, prot, lvl, num_entries, ptep); ret = arm_lpae_init_pte(data, iova, paddr, prot, lvl, num_entries, ptep);
if (!ret && mapped) if (!ret)
*mapped += num_entries * size; *mapped += num_entries * size;
return ret; return ret;
...@@ -496,13 +496,6 @@ static int arm_lpae_map_pages(struct io_pgtable_ops *ops, unsigned long iova, ...@@ -496,13 +496,6 @@ static int arm_lpae_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
return ret; return ret;
} }
static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
phys_addr_t paddr, size_t size, int iommu_prot, gfp_t gfp)
{
return arm_lpae_map_pages(ops, iova, paddr, size, 1, iommu_prot, gfp,
NULL);
}
static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl, static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl,
arm_lpae_iopte *ptep) arm_lpae_iopte *ptep)
{ {
...@@ -682,12 +675,6 @@ static size_t arm_lpae_unmap_pages(struct io_pgtable_ops *ops, unsigned long iov ...@@ -682,12 +675,6 @@ static size_t arm_lpae_unmap_pages(struct io_pgtable_ops *ops, unsigned long iov
data->start_level, ptep); data->start_level, ptep);
} }
static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
size_t size, struct iommu_iotlb_gather *gather)
{
return arm_lpae_unmap_pages(ops, iova, size, 1, gather);
}
static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
unsigned long iova) unsigned long iova)
{ {
...@@ -799,9 +786,7 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) ...@@ -799,9 +786,7 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg)
data->pgd_bits = va_bits - (data->bits_per_level * (levels - 1)); data->pgd_bits = va_bits - (data->bits_per_level * (levels - 1));
data->iop.ops = (struct io_pgtable_ops) { data->iop.ops = (struct io_pgtable_ops) {
.map = arm_lpae_map,
.map_pages = arm_lpae_map_pages, .map_pages = arm_lpae_map_pages,
.unmap = arm_lpae_unmap,
.unmap_pages = arm_lpae_unmap_pages, .unmap_pages = arm_lpae_unmap_pages,
.iova_to_phys = arm_lpae_iova_to_phys, .iova_to_phys = arm_lpae_iova_to_phys,
}; };
...@@ -1176,7 +1161,7 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) ...@@ -1176,7 +1161,7 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg)
int i, j; int i, j;
unsigned long iova; unsigned long iova;
size_t size; size_t size, mapped;
struct io_pgtable_ops *ops; struct io_pgtable_ops *ops;
selftest_running = true; selftest_running = true;
...@@ -1209,15 +1194,16 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) ...@@ -1209,15 +1194,16 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg)
for_each_set_bit(j, &cfg->pgsize_bitmap, BITS_PER_LONG) { for_each_set_bit(j, &cfg->pgsize_bitmap, BITS_PER_LONG) {
size = 1UL << j; size = 1UL << j;
if (ops->map(ops, iova, iova, size, IOMMU_READ | if (ops->map_pages(ops, iova, iova, size, 1,
IOMMU_WRITE | IOMMU_READ | IOMMU_WRITE |
IOMMU_NOEXEC | IOMMU_NOEXEC | IOMMU_CACHE,
IOMMU_CACHE, GFP_KERNEL)) GFP_KERNEL, &mapped))
return __FAIL(ops, i); return __FAIL(ops, i);
/* Overlapping mappings */ /* Overlapping mappings */
if (!ops->map(ops, iova, iova + size, size, if (!ops->map_pages(ops, iova, iova + size, size, 1,
IOMMU_READ | IOMMU_NOEXEC, GFP_KERNEL)) IOMMU_READ | IOMMU_NOEXEC,
GFP_KERNEL, &mapped))
return __FAIL(ops, i); return __FAIL(ops, i);
if (ops->iova_to_phys(ops, iova + 42) != (iova + 42)) if (ops->iova_to_phys(ops, iova + 42) != (iova + 42))
...@@ -1228,11 +1214,12 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) ...@@ -1228,11 +1214,12 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg)
/* Partial unmap */ /* Partial unmap */
size = 1UL << __ffs(cfg->pgsize_bitmap); size = 1UL << __ffs(cfg->pgsize_bitmap);
if (ops->unmap(ops, SZ_1G + size, size, NULL) != size) if (ops->unmap_pages(ops, SZ_1G + size, size, 1, NULL) != size)
return __FAIL(ops, i); return __FAIL(ops, i);
/* Remap of partial unmap */ /* Remap of partial unmap */
if (ops->map(ops, SZ_1G + size, size, size, IOMMU_READ, GFP_KERNEL)) if (ops->map_pages(ops, SZ_1G + size, size, size, 1,
IOMMU_READ, GFP_KERNEL, &mapped))
return __FAIL(ops, i); return __FAIL(ops, i);
if (ops->iova_to_phys(ops, SZ_1G + size + 42) != (size + 42)) if (ops->iova_to_phys(ops, SZ_1G + size + 42) != (size + 42))
...@@ -1243,14 +1230,15 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) ...@@ -1243,14 +1230,15 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg)
for_each_set_bit(j, &cfg->pgsize_bitmap, BITS_PER_LONG) { for_each_set_bit(j, &cfg->pgsize_bitmap, BITS_PER_LONG) {
size = 1UL << j; size = 1UL << j;
if (ops->unmap(ops, iova, size, NULL) != size) if (ops->unmap_pages(ops, iova, size, 1, NULL) != size)
return __FAIL(ops, i); return __FAIL(ops, i);
if (ops->iova_to_phys(ops, iova + 42)) if (ops->iova_to_phys(ops, iova + 42))
return __FAIL(ops, i); return __FAIL(ops, i);
/* Remap full block */ /* Remap full block */
if (ops->map(ops, iova, iova, size, IOMMU_WRITE, GFP_KERNEL)) if (ops->map_pages(ops, iova, iova, size, 1,
IOMMU_WRITE, GFP_KERNEL, &mapped))
return __FAIL(ops, i); return __FAIL(ops, i);
if (ops->iova_to_phys(ops, iova + 42) != (iova + 42)) if (ops->iova_to_phys(ops, iova + 42) != (iova + 42))
......
...@@ -306,13 +306,23 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list ...@@ -306,13 +306,23 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
const struct iommu_ops *ops = dev->bus->iommu_ops; const struct iommu_ops *ops = dev->bus->iommu_ops;
struct iommu_device *iommu_dev; struct iommu_device *iommu_dev;
struct iommu_group *group; struct iommu_group *group;
static DEFINE_MUTEX(iommu_probe_device_lock);
int ret; int ret;
if (!ops) if (!ops)
return -ENODEV; return -ENODEV;
/*
if (!dev_iommu_get(dev)) * Serialise to avoid races between IOMMU drivers registering in
return -ENOMEM; * parallel and/or the "replay" calls from ACPI/OF code via client
* driver probe. Once the latter have been cleaned up we should
* probably be able to use device_lock() here to minimise the scope,
* but for now enforcing a simple global ordering is fine.
*/
mutex_lock(&iommu_probe_device_lock);
if (!dev_iommu_get(dev)) {
ret = -ENOMEM;
goto err_unlock;
}
if (!try_module_get(ops->owner)) { if (!try_module_get(ops->owner)) {
ret = -EINVAL; ret = -EINVAL;
...@@ -333,11 +343,14 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list ...@@ -333,11 +343,14 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
ret = PTR_ERR(group); ret = PTR_ERR(group);
goto out_release; goto out_release;
} }
iommu_group_put(group);
mutex_lock(&group->mutex);
if (group_list && !group->default_domain && list_empty(&group->entry)) if (group_list && !group->default_domain && list_empty(&group->entry))
list_add_tail(&group->entry, group_list); list_add_tail(&group->entry, group_list);
mutex_unlock(&group->mutex);
iommu_group_put(group);
mutex_unlock(&iommu_probe_device_lock);
iommu_device_link(iommu_dev, dev); iommu_device_link(iommu_dev, dev);
return 0; return 0;
...@@ -352,6 +365,9 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list ...@@ -352,6 +365,9 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
err_free: err_free:
dev_iommu_free(dev); dev_iommu_free(dev);
err_unlock:
mutex_unlock(&iommu_probe_device_lock);
return ret; return ret;
} }
...@@ -1824,11 +1840,11 @@ int bus_iommu_probe(struct bus_type *bus) ...@@ -1824,11 +1840,11 @@ int bus_iommu_probe(struct bus_type *bus)
return ret; return ret;
list_for_each_entry_safe(group, next, &group_list, entry) { list_for_each_entry_safe(group, next, &group_list, entry) {
mutex_lock(&group->mutex);
/* Remove item from the list */ /* Remove item from the list */
list_del_init(&group->entry); list_del_init(&group->entry);
mutex_lock(&group->mutex);
/* Try to allocate default domain */ /* Try to allocate default domain */
probe_alloc_default_domain(bus, group); probe_alloc_default_domain(bus, group);
......
...@@ -659,22 +659,22 @@ static void ipmmu_detach_device(struct iommu_domain *io_domain, ...@@ -659,22 +659,22 @@ static void ipmmu_detach_device(struct iommu_domain *io_domain,
} }
static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova, static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot, gfp_t gfp) phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
{ {
struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
if (!domain) return domain->iop->map_pages(domain->iop, iova, paddr, pgsize, pgcount,
return -ENODEV; prot, gfp, mapped);
return domain->iop->map(domain->iop, iova, paddr, size, prot, gfp);
} }
static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova, static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova,
size_t size, struct iommu_iotlb_gather *gather) size_t pgsize, size_t pgcount,
struct iommu_iotlb_gather *gather)
{ {
struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
return domain->iop->unmap(domain->iop, iova, size, gather); return domain->iop->unmap_pages(domain->iop, iova, pgsize, pgcount, gather);
} }
static void ipmmu_flush_iotlb_all(struct iommu_domain *io_domain) static void ipmmu_flush_iotlb_all(struct iommu_domain *io_domain)
...@@ -877,8 +877,8 @@ static const struct iommu_ops ipmmu_ops = { ...@@ -877,8 +877,8 @@ static const struct iommu_ops ipmmu_ops = {
.default_domain_ops = &(const struct iommu_domain_ops) { .default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = ipmmu_attach_device, .attach_dev = ipmmu_attach_device,
.detach_dev = ipmmu_detach_device, .detach_dev = ipmmu_detach_device,
.map = ipmmu_map, .map_pages = ipmmu_map,
.unmap = ipmmu_unmap, .unmap_pages = ipmmu_unmap,
.flush_iotlb_all = ipmmu_flush_iotlb_all, .flush_iotlb_all = ipmmu_flush_iotlb_all,
.iotlb_sync = ipmmu_iotlb_sync, .iotlb_sync = ipmmu_iotlb_sync,
.iova_to_phys = ipmmu_iova_to_phys, .iova_to_phys = ipmmu_iova_to_phys,
......
...@@ -471,14 +471,16 @@ static void msm_iommu_detach_dev(struct iommu_domain *domain, ...@@ -471,14 +471,16 @@ static void msm_iommu_detach_dev(struct iommu_domain *domain,
} }
static int msm_iommu_map(struct iommu_domain *domain, unsigned long iova, static int msm_iommu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t pa, size_t len, int prot, gfp_t gfp) phys_addr_t pa, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
{ {
struct msm_priv *priv = to_msm_priv(domain); struct msm_priv *priv = to_msm_priv(domain);
unsigned long flags; unsigned long flags;
int ret; int ret;
spin_lock_irqsave(&priv->pgtlock, flags); spin_lock_irqsave(&priv->pgtlock, flags);
ret = priv->iop->map(priv->iop, iova, pa, len, prot, GFP_ATOMIC); ret = priv->iop->map_pages(priv->iop, iova, pa, pgsize, pgcount, prot,
GFP_ATOMIC, mapped);
spin_unlock_irqrestore(&priv->pgtlock, flags); spin_unlock_irqrestore(&priv->pgtlock, flags);
return ret; return ret;
...@@ -493,16 +495,18 @@ static void msm_iommu_sync_map(struct iommu_domain *domain, unsigned long iova, ...@@ -493,16 +495,18 @@ static void msm_iommu_sync_map(struct iommu_domain *domain, unsigned long iova,
} }
static size_t msm_iommu_unmap(struct iommu_domain *domain, unsigned long iova, static size_t msm_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t len, struct iommu_iotlb_gather *gather) size_t pgsize, size_t pgcount,
struct iommu_iotlb_gather *gather)
{ {
struct msm_priv *priv = to_msm_priv(domain); struct msm_priv *priv = to_msm_priv(domain);
unsigned long flags; unsigned long flags;
size_t ret;
spin_lock_irqsave(&priv->pgtlock, flags); spin_lock_irqsave(&priv->pgtlock, flags);
len = priv->iop->unmap(priv->iop, iova, len, gather); ret = priv->iop->unmap_pages(priv->iop, iova, pgsize, pgcount, gather);
spin_unlock_irqrestore(&priv->pgtlock, flags); spin_unlock_irqrestore(&priv->pgtlock, flags);
return len; return ret;
} }
static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain, static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
...@@ -679,8 +683,8 @@ static struct iommu_ops msm_iommu_ops = { ...@@ -679,8 +683,8 @@ static struct iommu_ops msm_iommu_ops = {
.default_domain_ops = &(const struct iommu_domain_ops) { .default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = msm_iommu_attach_dev, .attach_dev = msm_iommu_attach_dev,
.detach_dev = msm_iommu_detach_dev, .detach_dev = msm_iommu_detach_dev,
.map = msm_iommu_map, .map_pages = msm_iommu_map,
.unmap = msm_iommu_unmap, .unmap_pages = msm_iommu_unmap,
/* /*
* Nothing is needed here, the barrier to guarantee * Nothing is needed here, the barrier to guarantee
* completion of the tlb sync operation is implicitly * completion of the tlb sync operation is implicitly
......
...@@ -108,8 +108,12 @@ ...@@ -108,8 +108,12 @@
#define F_MMU_INT_ID_SUB_COMM_ID(a) (((a) >> 7) & 0x3) #define F_MMU_INT_ID_SUB_COMM_ID(a) (((a) >> 7) & 0x3)
#define F_MMU_INT_ID_COMM_ID_EXT(a) (((a) >> 10) & 0x7) #define F_MMU_INT_ID_COMM_ID_EXT(a) (((a) >> 10) & 0x7)
#define F_MMU_INT_ID_SUB_COMM_ID_EXT(a) (((a) >> 7) & 0x7) #define F_MMU_INT_ID_SUB_COMM_ID_EXT(a) (((a) >> 7) & 0x7)
/* Macro for 5 bits length port ID field (default) */
#define F_MMU_INT_ID_LARB_ID(a) (((a) >> 7) & 0x7) #define F_MMU_INT_ID_LARB_ID(a) (((a) >> 7) & 0x7)
#define F_MMU_INT_ID_PORT_ID(a) (((a) >> 2) & 0x1f) #define F_MMU_INT_ID_PORT_ID(a) (((a) >> 2) & 0x1f)
/* Macro for 6 bits length port ID field */
#define F_MMU_INT_ID_LARB_ID_WID_6(a) (((a) >> 8) & 0x7)
#define F_MMU_INT_ID_PORT_ID_WID_6(a) (((a) >> 2) & 0x3f)
#define MTK_PROTECT_PA_ALIGN 256 #define MTK_PROTECT_PA_ALIGN 256
#define MTK_IOMMU_BANK_SZ 0x1000 #define MTK_IOMMU_BANK_SZ 0x1000
...@@ -139,6 +143,7 @@ ...@@ -139,6 +143,7 @@
#define IFA_IOMMU_PCIE_SUPPORT BIT(16) #define IFA_IOMMU_PCIE_SUPPORT BIT(16)
#define PGTABLE_PA_35_EN BIT(17) #define PGTABLE_PA_35_EN BIT(17)
#define TF_PORT_TO_ADDR_MT8173 BIT(18) #define TF_PORT_TO_ADDR_MT8173 BIT(18)
#define INT_ID_PORT_WIDTH_6 BIT(19)
#define MTK_IOMMU_HAS_FLAG_MASK(pdata, _x, mask) \ #define MTK_IOMMU_HAS_FLAG_MASK(pdata, _x, mask) \
((((pdata)->flags) & (mask)) == (_x)) ((((pdata)->flags) & (mask)) == (_x))
...@@ -165,6 +170,7 @@ enum mtk_iommu_plat { ...@@ -165,6 +170,7 @@ enum mtk_iommu_plat {
M4U_MT8186, M4U_MT8186,
M4U_MT8192, M4U_MT8192,
M4U_MT8195, M4U_MT8195,
M4U_MT8365,
}; };
struct mtk_iommu_iova_region { struct mtk_iommu_iova_region {
...@@ -223,10 +229,7 @@ struct mtk_iommu_data { ...@@ -223,10 +229,7 @@ struct mtk_iommu_data {
struct device *smicomm_dev; struct device *smicomm_dev;
struct mtk_iommu_bank_data *bank; struct mtk_iommu_bank_data *bank;
struct dma_iommu_mapping *mapping; /* For mtk_iommu_v1.c */
struct regmap *pericfg; struct regmap *pericfg;
struct mutex mutex; /* Protect m4u_group/m4u_dom above */ struct mutex mutex; /* Protect m4u_group/m4u_dom above */
/* /*
...@@ -441,20 +444,25 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id) ...@@ -441,20 +444,25 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
fault_pa |= (u64)pa34_32 << 32; fault_pa |= (u64)pa34_32 << 32;
if (MTK_IOMMU_IS_TYPE(plat_data, MTK_IOMMU_TYPE_MM)) { if (MTK_IOMMU_IS_TYPE(plat_data, MTK_IOMMU_TYPE_MM)) {
fault_port = F_MMU_INT_ID_PORT_ID(regval);
if (MTK_IOMMU_HAS_FLAG(plat_data, HAS_SUB_COMM_2BITS)) { if (MTK_IOMMU_HAS_FLAG(plat_data, HAS_SUB_COMM_2BITS)) {
fault_larb = F_MMU_INT_ID_COMM_ID(regval); fault_larb = F_MMU_INT_ID_COMM_ID(regval);
sub_comm = F_MMU_INT_ID_SUB_COMM_ID(regval); sub_comm = F_MMU_INT_ID_SUB_COMM_ID(regval);
fault_port = F_MMU_INT_ID_PORT_ID(regval);
} else if (MTK_IOMMU_HAS_FLAG(plat_data, HAS_SUB_COMM_3BITS)) { } else if (MTK_IOMMU_HAS_FLAG(plat_data, HAS_SUB_COMM_3BITS)) {
fault_larb = F_MMU_INT_ID_COMM_ID_EXT(regval); fault_larb = F_MMU_INT_ID_COMM_ID_EXT(regval);
sub_comm = F_MMU_INT_ID_SUB_COMM_ID_EXT(regval); sub_comm = F_MMU_INT_ID_SUB_COMM_ID_EXT(regval);
fault_port = F_MMU_INT_ID_PORT_ID(regval);
} else if (MTK_IOMMU_HAS_FLAG(plat_data, INT_ID_PORT_WIDTH_6)) {
fault_port = F_MMU_INT_ID_PORT_ID_WID_6(regval);
fault_larb = F_MMU_INT_ID_LARB_ID_WID_6(regval);
} else { } else {
fault_port = F_MMU_INT_ID_PORT_ID(regval);
fault_larb = F_MMU_INT_ID_LARB_ID(regval); fault_larb = F_MMU_INT_ID_LARB_ID(regval);
} }
fault_larb = data->plat_data->larbid_remap[fault_larb][sub_comm]; fault_larb = data->plat_data->larbid_remap[fault_larb][sub_comm];
} }
if (report_iommu_fault(&dom->domain, bank->parent_dev, fault_iova, if (!dom || report_iommu_fault(&dom->domain, bank->parent_dev, fault_iova,
write ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ)) { write ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ)) {
dev_err_ratelimited( dev_err_ratelimited(
bank->parent_dev, bank->parent_dev,
...@@ -711,7 +719,8 @@ static void mtk_iommu_detach_device(struct iommu_domain *domain, ...@@ -711,7 +719,8 @@ static void mtk_iommu_detach_device(struct iommu_domain *domain,
} }
static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova, static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot, gfp_t gfp) phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
{ {
struct mtk_iommu_domain *dom = to_mtk_domain(domain); struct mtk_iommu_domain *dom = to_mtk_domain(domain);
...@@ -720,17 +729,17 @@ static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova, ...@@ -720,17 +729,17 @@ static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
paddr |= BIT_ULL(32); paddr |= BIT_ULL(32);
/* Synchronize with the tlb_lock */ /* Synchronize with the tlb_lock */
return dom->iop->map(dom->iop, iova, paddr, size, prot, gfp); return dom->iop->map_pages(dom->iop, iova, paddr, pgsize, pgcount, prot, gfp, mapped);
} }
static size_t mtk_iommu_unmap(struct iommu_domain *domain, static size_t mtk_iommu_unmap(struct iommu_domain *domain,
unsigned long iova, size_t size, unsigned long iova, size_t pgsize, size_t pgcount,
struct iommu_iotlb_gather *gather) struct iommu_iotlb_gather *gather)
{ {
struct mtk_iommu_domain *dom = to_mtk_domain(domain); struct mtk_iommu_domain *dom = to_mtk_domain(domain);
iommu_iotlb_gather_add_range(gather, iova, size); iommu_iotlb_gather_add_range(gather, iova, pgsize * pgcount);
return dom->iop->unmap(dom->iop, iova, size, gather); return dom->iop->unmap_pages(dom->iop, iova, pgsize, pgcount, gather);
} }
static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain) static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain)
...@@ -938,8 +947,8 @@ static const struct iommu_ops mtk_iommu_ops = { ...@@ -938,8 +947,8 @@ static const struct iommu_ops mtk_iommu_ops = {
.default_domain_ops = &(const struct iommu_domain_ops) { .default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = mtk_iommu_attach_device, .attach_dev = mtk_iommu_attach_device,
.detach_dev = mtk_iommu_detach_device, .detach_dev = mtk_iommu_detach_device,
.map = mtk_iommu_map, .map_pages = mtk_iommu_map,
.unmap = mtk_iommu_unmap, .unmap_pages = mtk_iommu_unmap,
.flush_iotlb_all = mtk_iommu_flush_iotlb_all, .flush_iotlb_all = mtk_iommu_flush_iotlb_all,
.iotlb_sync = mtk_iommu_iotlb_sync, .iotlb_sync = mtk_iommu_iotlb_sync,
.iotlb_sync_map = mtk_iommu_sync_map, .iotlb_sync_map = mtk_iommu_sync_map,
...@@ -1043,21 +1052,26 @@ static const struct component_master_ops mtk_iommu_com_ops = { ...@@ -1043,21 +1052,26 @@ static const struct component_master_ops mtk_iommu_com_ops = {
static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match **match, static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match **match,
struct mtk_iommu_data *data) struct mtk_iommu_data *data)
{ {
struct device_node *larbnode, *smicomm_node, *smi_subcomm_node; struct device_node *larbnode, *frst_avail_smicomm_node = NULL;
struct platform_device *plarbdev; struct platform_device *plarbdev, *pcommdev;
struct device_link *link; struct device_link *link;
int i, larb_nr, ret; int i, larb_nr, ret;
larb_nr = of_count_phandle_with_args(dev->of_node, "mediatek,larbs", NULL); larb_nr = of_count_phandle_with_args(dev->of_node, "mediatek,larbs", NULL);
if (larb_nr < 0) if (larb_nr < 0)
return larb_nr; return larb_nr;
if (larb_nr == 0 || larb_nr > MTK_LARB_NR_MAX)
return -EINVAL;
for (i = 0; i < larb_nr; i++) { for (i = 0; i < larb_nr; i++) {
struct device_node *smicomm_node, *smi_subcomm_node;
u32 id; u32 id;
larbnode = of_parse_phandle(dev->of_node, "mediatek,larbs", i); larbnode = of_parse_phandle(dev->of_node, "mediatek,larbs", i);
if (!larbnode) if (!larbnode) {
return -EINVAL; ret = -EINVAL;
goto err_larbdev_put;
}
if (!of_device_is_available(larbnode)) { if (!of_device_is_available(larbnode)) {
of_node_put(larbnode); of_node_put(larbnode);
...@@ -1067,26 +1081,36 @@ static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match **m ...@@ -1067,26 +1081,36 @@ static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match **m
ret = of_property_read_u32(larbnode, "mediatek,larb-id", &id); ret = of_property_read_u32(larbnode, "mediatek,larb-id", &id);
if (ret)/* The id is consecutive if there is no this property */ if (ret)/* The id is consecutive if there is no this property */
id = i; id = i;
if (id >= MTK_LARB_NR_MAX) {
of_node_put(larbnode);
ret = -EINVAL;
goto err_larbdev_put;
}
plarbdev = of_find_device_by_node(larbnode); plarbdev = of_find_device_by_node(larbnode);
if (!plarbdev) {
of_node_put(larbnode); of_node_put(larbnode);
return -ENODEV; if (!plarbdev) {
ret = -ENODEV;
goto err_larbdev_put;
} }
if (!plarbdev->dev.driver) { if (data->larb_imu[id].dev) {
of_node_put(larbnode); platform_device_put(plarbdev);
return -EPROBE_DEFER; ret = -EEXIST;
goto err_larbdev_put;
} }
data->larb_imu[id].dev = &plarbdev->dev; data->larb_imu[id].dev = &plarbdev->dev;
component_match_add_release(dev, match, component_release_of, if (!plarbdev->dev.driver) {
component_compare_of, larbnode); ret = -EPROBE_DEFER;
goto err_larbdev_put;
} }
/* Get smi-(sub)-common dev from the last larb. */ /* Get smi-(sub)-common dev from the last larb. */
smi_subcomm_node = of_parse_phandle(larbnode, "mediatek,smi", 0); smi_subcomm_node = of_parse_phandle(larbnode, "mediatek,smi", 0);
if (!smi_subcomm_node) if (!smi_subcomm_node) {
return -EINVAL; ret = -EINVAL;
goto err_larbdev_put;
}
/* /*
* It may have two level smi-common. the node is smi-sub-common if it * It may have two level smi-common. the node is smi-sub-common if it
...@@ -1098,17 +1122,50 @@ static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match **m ...@@ -1098,17 +1122,50 @@ static int mtk_iommu_mm_dts_parse(struct device *dev, struct component_match **m
else else
smicomm_node = smi_subcomm_node; smicomm_node = smi_subcomm_node;
plarbdev = of_find_device_by_node(smicomm_node); /*
* All the larbs that connect to one IOMMU must connect with the same
* smi-common.
*/
if (!frst_avail_smicomm_node) {
frst_avail_smicomm_node = smicomm_node;
} else if (frst_avail_smicomm_node != smicomm_node) {
dev_err(dev, "mediatek,smi property is not right @larb%d.", id);
of_node_put(smicomm_node); of_node_put(smicomm_node);
data->smicomm_dev = &plarbdev->dev; ret = -EINVAL;
goto err_larbdev_put;
} else {
of_node_put(smicomm_node);
}
component_match_add(dev, match, component_compare_dev, &plarbdev->dev);
platform_device_put(plarbdev);
}
if (!frst_avail_smicomm_node)
return -EINVAL;
pcommdev = of_find_device_by_node(frst_avail_smicomm_node);
of_node_put(frst_avail_smicomm_node);
if (!pcommdev)
return -ENODEV;
data->smicomm_dev = &pcommdev->dev;
link = device_link_add(data->smicomm_dev, dev, link = device_link_add(data->smicomm_dev, dev,
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME); DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
platform_device_put(pcommdev);
if (!link) { if (!link) {
dev_err(dev, "Unable to link %s.\n", dev_name(data->smicomm_dev)); dev_err(dev, "Unable to link %s.\n", dev_name(data->smicomm_dev));
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
err_larbdev_put:
for (i = MTK_LARB_NR_MAX - 1; i >= 0; i--) {
if (!data->larb_imu[i].dev)
continue;
put_device(data->larb_imu[i].dev);
}
return ret;
} }
static int mtk_iommu_probe(struct platform_device *pdev) static int mtk_iommu_probe(struct platform_device *pdev)
...@@ -1173,6 +1230,8 @@ static int mtk_iommu_probe(struct platform_device *pdev) ...@@ -1173,6 +1230,8 @@ static int mtk_iommu_probe(struct platform_device *pdev)
banks_num = data->plat_data->banks_num; banks_num = data->plat_data->banks_num;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
if (resource_size(res) < banks_num * MTK_IOMMU_BANK_SZ) { if (resource_size(res) < banks_num * MTK_IOMMU_BANK_SZ) {
dev_err(dev, "banknr %d. res %pR is not enough.\n", banks_num, res); dev_err(dev, "banknr %d. res %pR is not enough.\n", banks_num, res);
return -EINVAL; return -EINVAL;
...@@ -1516,6 +1575,17 @@ static const struct mtk_iommu_plat_data mt8195_data_vpp = { ...@@ -1516,6 +1575,17 @@ static const struct mtk_iommu_plat_data mt8195_data_vpp = {
{4, MTK_INVALID_LARBID, MTK_INVALID_LARBID, MTK_INVALID_LARBID, 6}}, {4, MTK_INVALID_LARBID, MTK_INVALID_LARBID, MTK_INVALID_LARBID, 6}},
}; };
static const struct mtk_iommu_plat_data mt8365_data = {
.m4u_plat = M4U_MT8365,
.flags = RESET_AXI | INT_ID_PORT_WIDTH_6,
.inv_sel_reg = REG_MMU_INV_SEL_GEN1,
.banks_num = 1,
.banks_enable = {true},
.iova_region = single_domain,
.iova_region_nr = ARRAY_SIZE(single_domain),
.larbid_remap = {{0}, {1}, {2}, {3}, {4}, {5}}, /* Linear mapping. */
};
static const struct of_device_id mtk_iommu_of_ids[] = { static const struct of_device_id mtk_iommu_of_ids[] = {
{ .compatible = "mediatek,mt2712-m4u", .data = &mt2712_data}, { .compatible = "mediatek,mt2712-m4u", .data = &mt2712_data},
{ .compatible = "mediatek,mt6779-m4u", .data = &mt6779_data}, { .compatible = "mediatek,mt6779-m4u", .data = &mt6779_data},
...@@ -1528,6 +1598,7 @@ static const struct of_device_id mtk_iommu_of_ids[] = { ...@@ -1528,6 +1598,7 @@ static const struct of_device_id mtk_iommu_of_ids[] = {
{ .compatible = "mediatek,mt8195-iommu-infra", .data = &mt8195_data_infra}, { .compatible = "mediatek,mt8195-iommu-infra", .data = &mt8195_data_infra},
{ .compatible = "mediatek,mt8195-iommu-vdo", .data = &mt8195_data_vdo}, { .compatible = "mediatek,mt8195-iommu-vdo", .data = &mt8195_data_vdo},
{ .compatible = "mediatek,mt8195-iommu-vpp", .data = &mt8195_data_vpp}, { .compatible = "mediatek,mt8195-iommu-vpp", .data = &mt8195_data_vpp},
{ .compatible = "mediatek,mt8365-m4u", .data = &mt8365_data},
{} {}
}; };
......
...@@ -327,44 +327,42 @@ static void mtk_iommu_v1_detach_device(struct iommu_domain *domain, struct devic ...@@ -327,44 +327,42 @@ static void mtk_iommu_v1_detach_device(struct iommu_domain *domain, struct devic
} }
static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova, static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot, gfp_t gfp) phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
{ {
struct mtk_iommu_v1_domain *dom = to_mtk_domain(domain); struct mtk_iommu_v1_domain *dom = to_mtk_domain(domain);
unsigned int page_num = size >> MT2701_IOMMU_PAGE_SHIFT;
unsigned long flags; unsigned long flags;
unsigned int i; unsigned int i;
u32 *pgt_base_iova = dom->pgt_va + (iova >> MT2701_IOMMU_PAGE_SHIFT); u32 *pgt_base_iova = dom->pgt_va + (iova >> MT2701_IOMMU_PAGE_SHIFT);
u32 pabase = (u32)paddr; u32 pabase = (u32)paddr;
int map_size = 0;
spin_lock_irqsave(&dom->pgtlock, flags); spin_lock_irqsave(&dom->pgtlock, flags);
for (i = 0; i < page_num; i++) { for (i = 0; i < pgcount; i++) {
if (pgt_base_iova[i]) { if (pgt_base_iova[i])
memset(pgt_base_iova, 0, i * sizeof(u32));
break; break;
}
pgt_base_iova[i] = pabase | F_DESC_VALID | F_DESC_NONSEC; pgt_base_iova[i] = pabase | F_DESC_VALID | F_DESC_NONSEC;
pabase += MT2701_IOMMU_PAGE_SIZE; pabase += MT2701_IOMMU_PAGE_SIZE;
map_size += MT2701_IOMMU_PAGE_SIZE;
} }
spin_unlock_irqrestore(&dom->pgtlock, flags); spin_unlock_irqrestore(&dom->pgtlock, flags);
mtk_iommu_v1_tlb_flush_range(dom->data, iova, size); *mapped = i * MT2701_IOMMU_PAGE_SIZE;
mtk_iommu_v1_tlb_flush_range(dom->data, iova, *mapped);
return map_size == size ? 0 : -EEXIST; return i == pgcount ? 0 : -EEXIST;
} }
static size_t mtk_iommu_v1_unmap(struct iommu_domain *domain, unsigned long iova, static size_t mtk_iommu_v1_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size, struct iommu_iotlb_gather *gather) size_t pgsize, size_t pgcount,
struct iommu_iotlb_gather *gather)
{ {
struct mtk_iommu_v1_domain *dom = to_mtk_domain(domain); struct mtk_iommu_v1_domain *dom = to_mtk_domain(domain);
unsigned long flags; unsigned long flags;
u32 *pgt_base_iova = dom->pgt_va + (iova >> MT2701_IOMMU_PAGE_SHIFT); u32 *pgt_base_iova = dom->pgt_va + (iova >> MT2701_IOMMU_PAGE_SHIFT);
unsigned int page_num = size >> MT2701_IOMMU_PAGE_SHIFT; size_t size = pgcount * MT2701_IOMMU_PAGE_SIZE;
spin_lock_irqsave(&dom->pgtlock, flags); spin_lock_irqsave(&dom->pgtlock, flags);
memset(pgt_base_iova, 0, page_num * sizeof(u32)); memset(pgt_base_iova, 0, pgcount * sizeof(u32));
spin_unlock_irqrestore(&dom->pgtlock, flags); spin_unlock_irqrestore(&dom->pgtlock, flags);
mtk_iommu_v1_tlb_flush_range(dom->data, iova, size); mtk_iommu_v1_tlb_flush_range(dom->data, iova, size);
...@@ -586,13 +584,13 @@ static const struct iommu_ops mtk_iommu_v1_ops = { ...@@ -586,13 +584,13 @@ static const struct iommu_ops mtk_iommu_v1_ops = {
.release_device = mtk_iommu_v1_release_device, .release_device = mtk_iommu_v1_release_device,
.def_domain_type = mtk_iommu_v1_def_domain_type, .def_domain_type = mtk_iommu_v1_def_domain_type,
.device_group = generic_device_group, .device_group = generic_device_group,
.pgsize_bitmap = ~0UL << MT2701_IOMMU_PAGE_SHIFT, .pgsize_bitmap = MT2701_IOMMU_PAGE_SIZE,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.default_domain_ops = &(const struct iommu_domain_ops) { .default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = mtk_iommu_v1_attach_device, .attach_dev = mtk_iommu_v1_attach_device,
.detach_dev = mtk_iommu_v1_detach_device, .detach_dev = mtk_iommu_v1_detach_device,
.map = mtk_iommu_v1_map, .map_pages = mtk_iommu_v1_map,
.unmap = mtk_iommu_v1_unmap, .unmap_pages = mtk_iommu_v1_unmap,
.iova_to_phys = mtk_iommu_v1_iova_to_phys, .iova_to_phys = mtk_iommu_v1_iova_to_phys,
.free = mtk_iommu_v1_domain_free, .free = mtk_iommu_v1_domain_free,
} }
......
...@@ -280,19 +280,17 @@ static u32 rk_mk_pte(phys_addr_t page, int prot) ...@@ -280,19 +280,17 @@ static u32 rk_mk_pte(phys_addr_t page, int prot)
* 11:9 - Page address bit 34:32 * 11:9 - Page address bit 34:32
* 8:4 - Page address bit 39:35 * 8:4 - Page address bit 39:35
* 3 - Security * 3 - Security
* 2 - Readable * 2 - Writable
* 1 - Writable * 1 - Readable
* 0 - 1 if Page @ Page address is valid * 0 - 1 if Page @ Page address is valid
*/ */
#define RK_PTE_PAGE_READABLE_V2 BIT(2)
#define RK_PTE_PAGE_WRITABLE_V2 BIT(1)
static u32 rk_mk_pte_v2(phys_addr_t page, int prot) static u32 rk_mk_pte_v2(phys_addr_t page, int prot)
{ {
u32 flags = 0; u32 flags = 0;
flags |= (prot & IOMMU_READ) ? RK_PTE_PAGE_READABLE_V2 : 0; flags |= (prot & IOMMU_READ) ? RK_PTE_PAGE_READABLE : 0;
flags |= (prot & IOMMU_WRITE) ? RK_PTE_PAGE_WRITABLE_V2 : 0; flags |= (prot & IOMMU_WRITE) ? RK_PTE_PAGE_WRITABLE : 0;
return rk_mk_dte_v2(page) | flags; return rk_mk_dte_v2(page) | flags;
} }
......
...@@ -10,28 +10,18 @@ ...@@ -10,28 +10,18 @@
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/iommu-helper.h> #include <linux/iommu-helper.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>
#include <asm/pci_dma.h> #include <asm/pci_dma.h>
/*
* Physically contiguous memory regions can be mapped with 4 KiB alignment,
* we allow all page sizes that are an order of 4KiB (no special large page
* support so far).
*/
#define S390_IOMMU_PGSIZES (~0xFFFUL)
static const struct iommu_ops s390_iommu_ops; static const struct iommu_ops s390_iommu_ops;
struct s390_domain { struct s390_domain {
struct iommu_domain domain; struct iommu_domain domain;
struct list_head devices; struct list_head devices;
unsigned long *dma_table; unsigned long *dma_table;
spinlock_t dma_table_lock;
spinlock_t list_lock; spinlock_t list_lock;
}; struct rcu_head rcu;
struct s390_domain_device {
struct list_head list;
struct zpci_dev *zdev;
}; };
static struct s390_domain *to_s390_domain(struct iommu_domain *dom) static struct s390_domain *to_s390_domain(struct iommu_domain *dom)
...@@ -67,119 +57,125 @@ static struct iommu_domain *s390_domain_alloc(unsigned domain_type) ...@@ -67,119 +57,125 @@ static struct iommu_domain *s390_domain_alloc(unsigned domain_type)
kfree(s390_domain); kfree(s390_domain);
return NULL; return NULL;
} }
s390_domain->domain.geometry.force_aperture = true;
s390_domain->domain.geometry.aperture_start = 0;
s390_domain->domain.geometry.aperture_end = ZPCI_TABLE_SIZE_RT - 1;
spin_lock_init(&s390_domain->dma_table_lock);
spin_lock_init(&s390_domain->list_lock); spin_lock_init(&s390_domain->list_lock);
INIT_LIST_HEAD(&s390_domain->devices); INIT_LIST_HEAD_RCU(&s390_domain->devices);
return &s390_domain->domain; return &s390_domain->domain;
} }
static void s390_domain_free(struct iommu_domain *domain) static void s390_iommu_rcu_free_domain(struct rcu_head *head)
{ {
struct s390_domain *s390_domain = to_s390_domain(domain); struct s390_domain *s390_domain = container_of(head, struct s390_domain, rcu);
dma_cleanup_tables(s390_domain->dma_table); dma_cleanup_tables(s390_domain->dma_table);
kfree(s390_domain); kfree(s390_domain);
} }
static void s390_domain_free(struct iommu_domain *domain)
{
struct s390_domain *s390_domain = to_s390_domain(domain);
rcu_read_lock();
WARN_ON(!list_empty(&s390_domain->devices));
rcu_read_unlock();
call_rcu(&s390_domain->rcu, s390_iommu_rcu_free_domain);
}
static void __s390_iommu_detach_device(struct zpci_dev *zdev)
{
struct s390_domain *s390_domain = zdev->s390_domain;
unsigned long flags;
if (!s390_domain)
return;
spin_lock_irqsave(&s390_domain->list_lock, flags);
list_del_rcu(&zdev->iommu_list);
spin_unlock_irqrestore(&s390_domain->list_lock, flags);
zpci_unregister_ioat(zdev, 0);
zdev->s390_domain = NULL;
zdev->dma_table = NULL;
}
static int s390_iommu_attach_device(struct iommu_domain *domain, static int s390_iommu_attach_device(struct iommu_domain *domain,
struct device *dev) struct device *dev)
{ {
struct s390_domain *s390_domain = to_s390_domain(domain); struct s390_domain *s390_domain = to_s390_domain(domain);
struct zpci_dev *zdev = to_zpci_dev(dev); struct zpci_dev *zdev = to_zpci_dev(dev);
struct s390_domain_device *domain_device;
unsigned long flags; unsigned long flags;
int cc, rc; u8 status;
int cc;
if (!zdev) if (!zdev)
return -ENODEV; return -ENODEV;
domain_device = kzalloc(sizeof(*domain_device), GFP_KERNEL); if (WARN_ON(domain->geometry.aperture_start > zdev->end_dma ||
if (!domain_device) domain->geometry.aperture_end < zdev->start_dma))
return -ENOMEM; return -EINVAL;
if (zdev->dma_table && !zdev->s390_domain) {
cc = zpci_dma_exit_device(zdev);
if (cc) {
rc = -EIO;
goto out_free;
}
}
if (zdev->s390_domain) if (zdev->s390_domain)
zpci_unregister_ioat(zdev, 0); __s390_iommu_detach_device(zdev);
else if (zdev->dma_table)
zpci_dma_exit_device(zdev);
zdev->dma_table = s390_domain->dma_table;
cc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, cc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
virt_to_phys(zdev->dma_table)); virt_to_phys(s390_domain->dma_table), &status);
if (cc) { /*
rc = -EIO; * If the device is undergoing error recovery the reset code
goto out_restore; * will re-establish the new domain.
} */
if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL)
return -EIO;
zdev->dma_table = s390_domain->dma_table;
spin_lock_irqsave(&s390_domain->list_lock, flags); zdev->dma_table = s390_domain->dma_table;
/* First device defines the DMA range limits */
if (list_empty(&s390_domain->devices)) {
domain->geometry.aperture_start = zdev->start_dma;
domain->geometry.aperture_end = zdev->end_dma;
domain->geometry.force_aperture = true;
/* Allow only devices with identical DMA range limits */
} else if (domain->geometry.aperture_start != zdev->start_dma ||
domain->geometry.aperture_end != zdev->end_dma) {
rc = -EINVAL;
spin_unlock_irqrestore(&s390_domain->list_lock, flags);
goto out_restore;
}
domain_device->zdev = zdev;
zdev->s390_domain = s390_domain; zdev->s390_domain = s390_domain;
list_add(&domain_device->list, &s390_domain->devices);
spin_lock_irqsave(&s390_domain->list_lock, flags);
list_add_rcu(&zdev->iommu_list, &s390_domain->devices);
spin_unlock_irqrestore(&s390_domain->list_lock, flags); spin_unlock_irqrestore(&s390_domain->list_lock, flags);
return 0; return 0;
out_restore:
if (!zdev->s390_domain) {
zpci_dma_init_device(zdev);
} else {
zdev->dma_table = zdev->s390_domain->dma_table;
zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
virt_to_phys(zdev->dma_table));
}
out_free:
kfree(domain_device);
return rc;
} }
static void s390_iommu_detach_device(struct iommu_domain *domain, static void s390_iommu_detach_device(struct iommu_domain *domain,
struct device *dev) struct device *dev)
{ {
struct s390_domain *s390_domain = to_s390_domain(domain);
struct zpci_dev *zdev = to_zpci_dev(dev); struct zpci_dev *zdev = to_zpci_dev(dev);
struct s390_domain_device *domain_device, *tmp;
unsigned long flags;
int found = 0;
if (!zdev) WARN_ON(zdev->s390_domain != to_s390_domain(domain));
return;
spin_lock_irqsave(&s390_domain->list_lock, flags); __s390_iommu_detach_device(zdev);
list_for_each_entry_safe(domain_device, tmp, &s390_domain->devices, zpci_dma_init_device(zdev);
list) { }
if (domain_device->zdev == zdev) {
list_del(&domain_device->list); static void s390_iommu_get_resv_regions(struct device *dev,
kfree(domain_device); struct list_head *list)
found = 1; {
break; struct zpci_dev *zdev = to_zpci_dev(dev);
} struct iommu_resv_region *region;
if (zdev->start_dma) {
region = iommu_alloc_resv_region(0, zdev->start_dma, 0,
IOMMU_RESV_RESERVED, GFP_KERNEL);
if (!region)
return;
list_add_tail(&region->list, list);
} }
spin_unlock_irqrestore(&s390_domain->list_lock, flags);
if (found && (zdev->s390_domain == s390_domain)) { if (zdev->end_dma < ZPCI_TABLE_SIZE_RT - 1) {
zdev->s390_domain = NULL; region = iommu_alloc_resv_region(zdev->end_dma + 1,
zpci_unregister_ioat(zdev, 0); ZPCI_TABLE_SIZE_RT - zdev->end_dma - 1,
zpci_dma_init_device(zdev); 0, IOMMU_RESV_RESERVED, GFP_KERNEL);
if (!region)
return;
list_add_tail(&region->list, list);
} }
} }
...@@ -192,55 +188,88 @@ static struct iommu_device *s390_iommu_probe_device(struct device *dev) ...@@ -192,55 +188,88 @@ static struct iommu_device *s390_iommu_probe_device(struct device *dev)
zdev = to_zpci_dev(dev); zdev = to_zpci_dev(dev);
if (zdev->start_dma > zdev->end_dma ||
zdev->start_dma > ZPCI_TABLE_SIZE_RT - 1)
return ERR_PTR(-EINVAL);
if (zdev->end_dma > ZPCI_TABLE_SIZE_RT - 1)
zdev->end_dma = ZPCI_TABLE_SIZE_RT - 1;
return &zdev->iommu_dev; return &zdev->iommu_dev;
} }
static void s390_iommu_release_device(struct device *dev) static void s390_iommu_release_device(struct device *dev)
{ {
struct zpci_dev *zdev = to_zpci_dev(dev); struct zpci_dev *zdev = to_zpci_dev(dev);
struct iommu_domain *domain;
/* /*
* This is a workaround for a scenario where the IOMMU API common code * release_device is expected to detach any domain currently attached
* "forgets" to call the detach_dev callback: After binding a device * to the device, but keep it attached to other devices in the group.
* to vfio-pci and completing the VFIO_SET_IOMMU ioctl (which triggers
* the attach_dev), removing the device via
* "echo 1 > /sys/bus/pci/devices/.../remove" won't trigger detach_dev,
* only release_device will be called via the BUS_NOTIFY_REMOVED_DEVICE
* notifier.
*
* So let's call detach_dev from here if it hasn't been called before.
*/ */
if (zdev && zdev->s390_domain) { if (zdev)
domain = iommu_get_domain_for_dev(dev); __s390_iommu_detach_device(zdev);
if (domain) }
s390_iommu_detach_device(domain, dev);
static void s390_iommu_flush_iotlb_all(struct iommu_domain *domain)
{
struct s390_domain *s390_domain = to_s390_domain(domain);
struct zpci_dev *zdev;
rcu_read_lock();
list_for_each_entry_rcu(zdev, &s390_domain->devices, iommu_list) {
zpci_refresh_trans((u64)zdev->fh << 32, zdev->start_dma,
zdev->end_dma - zdev->start_dma + 1);
}
rcu_read_unlock();
}
static void s390_iommu_iotlb_sync(struct iommu_domain *domain,
struct iommu_iotlb_gather *gather)
{
struct s390_domain *s390_domain = to_s390_domain(domain);
size_t size = gather->end - gather->start + 1;
struct zpci_dev *zdev;
/* If gather was never added to there is nothing to flush */
if (!gather->end)
return;
rcu_read_lock();
list_for_each_entry_rcu(zdev, &s390_domain->devices, iommu_list) {
zpci_refresh_trans((u64)zdev->fh << 32, gather->start,
size);
} }
rcu_read_unlock();
} }
static int s390_iommu_update_trans(struct s390_domain *s390_domain, static void s390_iommu_iotlb_sync_map(struct iommu_domain *domain,
unsigned long iova, size_t size)
{
struct s390_domain *s390_domain = to_s390_domain(domain);
struct zpci_dev *zdev;
rcu_read_lock();
list_for_each_entry_rcu(zdev, &s390_domain->devices, iommu_list) {
if (!zdev->tlb_refresh)
continue;
zpci_refresh_trans((u64)zdev->fh << 32,
iova, size);
}
rcu_read_unlock();
}
static int s390_iommu_validate_trans(struct s390_domain *s390_domain,
phys_addr_t pa, dma_addr_t dma_addr, phys_addr_t pa, dma_addr_t dma_addr,
size_t size, int flags) unsigned long nr_pages, int flags)
{ {
struct s390_domain_device *domain_device;
phys_addr_t page_addr = pa & PAGE_MASK; phys_addr_t page_addr = pa & PAGE_MASK;
dma_addr_t start_dma_addr = dma_addr;
unsigned long irq_flags, nr_pages, i;
unsigned long *entry; unsigned long *entry;
int rc = 0; unsigned long i;
int rc;
if (dma_addr < s390_domain->domain.geometry.aperture_start ||
dma_addr + size > s390_domain->domain.geometry.aperture_end)
return -EINVAL;
nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
if (!nr_pages)
return 0;
spin_lock_irqsave(&s390_domain->dma_table_lock, irq_flags);
for (i = 0; i < nr_pages; i++) { for (i = 0; i < nr_pages; i++) {
entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr); entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr);
if (!entry) { if (unlikely(!entry)) {
rc = -ENOMEM; rc = -ENOMEM;
goto undo_cpu_trans; goto undo_cpu_trans;
} }
...@@ -249,47 +278,70 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain, ...@@ -249,47 +278,70 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain,
dma_addr += PAGE_SIZE; dma_addr += PAGE_SIZE;
} }
spin_lock(&s390_domain->list_lock); return 0;
list_for_each_entry(domain_device, &s390_domain->devices, list) {
rc = zpci_refresh_trans((u64) domain_device->zdev->fh << 32,
start_dma_addr, nr_pages * PAGE_SIZE);
if (rc)
break;
}
spin_unlock(&s390_domain->list_lock);
undo_cpu_trans: undo_cpu_trans:
if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) {
flags = ZPCI_PTE_INVALID;
while (i-- > 0) { while (i-- > 0) {
page_addr -= PAGE_SIZE;
dma_addr -= PAGE_SIZE; dma_addr -= PAGE_SIZE;
entry = dma_walk_cpu_trans(s390_domain->dma_table, entry = dma_walk_cpu_trans(s390_domain->dma_table,
dma_addr); dma_addr);
if (!entry) if (!entry)
break; break;
dma_update_cpu_trans(entry, page_addr, flags); dma_update_cpu_trans(entry, 0, ZPCI_PTE_INVALID);
} }
return rc;
}
static int s390_iommu_invalidate_trans(struct s390_domain *s390_domain,
dma_addr_t dma_addr, unsigned long nr_pages)
{
unsigned long *entry;
unsigned long i;
int rc = 0;
for (i = 0; i < nr_pages; i++) {
entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr);
if (unlikely(!entry)) {
rc = -EINVAL;
break;
}
dma_update_cpu_trans(entry, 0, ZPCI_PTE_INVALID);
dma_addr += PAGE_SIZE;
} }
spin_unlock_irqrestore(&s390_domain->dma_table_lock, irq_flags);
return rc; return rc;
} }
static int s390_iommu_map(struct iommu_domain *domain, unsigned long iova, static int s390_iommu_map_pages(struct iommu_domain *domain,
phys_addr_t paddr, size_t size, int prot, gfp_t gfp) unsigned long iova, phys_addr_t paddr,
size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
{ {
struct s390_domain *s390_domain = to_s390_domain(domain); struct s390_domain *s390_domain = to_s390_domain(domain);
size_t size = pgcount << __ffs(pgsize);
int flags = ZPCI_PTE_VALID, rc = 0; int flags = ZPCI_PTE_VALID, rc = 0;
if (pgsize != SZ_4K)
return -EINVAL;
if (iova < s390_domain->domain.geometry.aperture_start ||
(iova + size - 1) > s390_domain->domain.geometry.aperture_end)
return -EINVAL;
if (!IS_ALIGNED(iova | paddr, pgsize))
return -EINVAL;
if (!(prot & IOMMU_READ)) if (!(prot & IOMMU_READ))
return -EINVAL; return -EINVAL;
if (!(prot & IOMMU_WRITE)) if (!(prot & IOMMU_WRITE))
flags |= ZPCI_TABLE_PROTECTED; flags |= ZPCI_TABLE_PROTECTED;
rc = s390_iommu_update_trans(s390_domain, paddr, iova, rc = s390_iommu_validate_trans(s390_domain, paddr, iova,
size, flags); pgcount, flags);
if (!rc)
*mapped = size;
return rc; return rc;
} }
...@@ -298,7 +350,8 @@ static phys_addr_t s390_iommu_iova_to_phys(struct iommu_domain *domain, ...@@ -298,7 +350,8 @@ static phys_addr_t s390_iommu_iova_to_phys(struct iommu_domain *domain,
dma_addr_t iova) dma_addr_t iova)
{ {
struct s390_domain *s390_domain = to_s390_domain(domain); struct s390_domain *s390_domain = to_s390_domain(domain);
unsigned long *sto, *pto, *rto, flags; unsigned long *rto, *sto, *pto;
unsigned long ste, pte, rte;
unsigned int rtx, sx, px; unsigned int rtx, sx, px;
phys_addr_t phys = 0; phys_addr_t phys = 0;
...@@ -311,38 +364,40 @@ static phys_addr_t s390_iommu_iova_to_phys(struct iommu_domain *domain, ...@@ -311,38 +364,40 @@ static phys_addr_t s390_iommu_iova_to_phys(struct iommu_domain *domain,
px = calc_px(iova); px = calc_px(iova);
rto = s390_domain->dma_table; rto = s390_domain->dma_table;
spin_lock_irqsave(&s390_domain->dma_table_lock, flags); rte = READ_ONCE(rto[rtx]);
if (rto && reg_entry_isvalid(rto[rtx])) { if (reg_entry_isvalid(rte)) {
sto = get_rt_sto(rto[rtx]); sto = get_rt_sto(rte);
if (sto && reg_entry_isvalid(sto[sx])) { ste = READ_ONCE(sto[sx]);
pto = get_st_pto(sto[sx]); if (reg_entry_isvalid(ste)) {
if (pto && pt_entry_isvalid(pto[px])) pto = get_st_pto(ste);
phys = pto[px] & ZPCI_PTE_ADDR_MASK; pte = READ_ONCE(pto[px]);
if (pt_entry_isvalid(pte))
phys = pte & ZPCI_PTE_ADDR_MASK;
} }
} }
spin_unlock_irqrestore(&s390_domain->dma_table_lock, flags);
return phys; return phys;
} }
static size_t s390_iommu_unmap(struct iommu_domain *domain, static size_t s390_iommu_unmap_pages(struct iommu_domain *domain,
unsigned long iova, size_t size, unsigned long iova,
size_t pgsize, size_t pgcount,
struct iommu_iotlb_gather *gather) struct iommu_iotlb_gather *gather)
{ {
struct s390_domain *s390_domain = to_s390_domain(domain); struct s390_domain *s390_domain = to_s390_domain(domain);
int flags = ZPCI_PTE_INVALID; size_t size = pgcount << __ffs(pgsize);
phys_addr_t paddr;
int rc; int rc;
paddr = s390_iommu_iova_to_phys(domain, iova); if (WARN_ON(iova < s390_domain->domain.geometry.aperture_start ||
if (!paddr) (iova + size - 1) > s390_domain->domain.geometry.aperture_end))
return 0; return 0;
rc = s390_iommu_update_trans(s390_domain, paddr, iova, rc = s390_iommu_invalidate_trans(s390_domain, iova, pgcount);
size, flags);
if (rc) if (rc)
return 0; return 0;
iommu_iotlb_gather_add_range(gather, iova, size);
return size; return size;
} }
...@@ -380,12 +435,16 @@ static const struct iommu_ops s390_iommu_ops = { ...@@ -380,12 +435,16 @@ static const struct iommu_ops s390_iommu_ops = {
.probe_device = s390_iommu_probe_device, .probe_device = s390_iommu_probe_device,
.release_device = s390_iommu_release_device, .release_device = s390_iommu_release_device,
.device_group = generic_device_group, .device_group = generic_device_group,
.pgsize_bitmap = S390_IOMMU_PGSIZES, .pgsize_bitmap = SZ_4K,
.get_resv_regions = s390_iommu_get_resv_regions,
.default_domain_ops = &(const struct iommu_domain_ops) { .default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = s390_iommu_attach_device, .attach_dev = s390_iommu_attach_device,
.detach_dev = s390_iommu_detach_device, .detach_dev = s390_iommu_detach_device,
.map = s390_iommu_map, .map_pages = s390_iommu_map_pages,
.unmap = s390_iommu_unmap, .unmap_pages = s390_iommu_unmap_pages,
.flush_iotlb_all = s390_iommu_flush_iotlb_all,
.iotlb_sync = s390_iommu_iotlb_sync,
.iotlb_sync_map = s390_iommu_iotlb_sync_map,
.iova_to_phys = s390_iommu_iova_to_phys, .iova_to_phys = s390_iommu_iova_to_phys,
.free = s390_domain_free, .free = s390_domain_free,
} }
......
...@@ -271,10 +271,11 @@ static void sprd_iommu_detach_device(struct iommu_domain *domain, ...@@ -271,10 +271,11 @@ static void sprd_iommu_detach_device(struct iommu_domain *domain,
} }
static int sprd_iommu_map(struct iommu_domain *domain, unsigned long iova, static int sprd_iommu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot, gfp_t gfp) phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
{ {
struct sprd_iommu_domain *dom = to_sprd_domain(domain); struct sprd_iommu_domain *dom = to_sprd_domain(domain);
unsigned int page_num = size >> SPRD_IOMMU_PAGE_SHIFT; size_t size = pgcount * SPRD_IOMMU_PAGE_SIZE;
unsigned long flags; unsigned long flags;
unsigned int i; unsigned int i;
u32 *pgt_base_iova; u32 *pgt_base_iova;
...@@ -296,35 +297,37 @@ static int sprd_iommu_map(struct iommu_domain *domain, unsigned long iova, ...@@ -296,35 +297,37 @@ static int sprd_iommu_map(struct iommu_domain *domain, unsigned long iova,
pgt_base_iova = dom->pgt_va + ((iova - start) >> SPRD_IOMMU_PAGE_SHIFT); pgt_base_iova = dom->pgt_va + ((iova - start) >> SPRD_IOMMU_PAGE_SHIFT);
spin_lock_irqsave(&dom->pgtlock, flags); spin_lock_irqsave(&dom->pgtlock, flags);
for (i = 0; i < page_num; i++) { for (i = 0; i < pgcount; i++) {
pgt_base_iova[i] = pabase >> SPRD_IOMMU_PAGE_SHIFT; pgt_base_iova[i] = pabase >> SPRD_IOMMU_PAGE_SHIFT;
pabase += SPRD_IOMMU_PAGE_SIZE; pabase += SPRD_IOMMU_PAGE_SIZE;
} }
spin_unlock_irqrestore(&dom->pgtlock, flags); spin_unlock_irqrestore(&dom->pgtlock, flags);
*mapped = size;
return 0; return 0;
} }
static size_t sprd_iommu_unmap(struct iommu_domain *domain, unsigned long iova, static size_t sprd_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size, struct iommu_iotlb_gather *iotlb_gather) size_t pgsize, size_t pgcount,
struct iommu_iotlb_gather *iotlb_gather)
{ {
struct sprd_iommu_domain *dom = to_sprd_domain(domain); struct sprd_iommu_domain *dom = to_sprd_domain(domain);
unsigned long flags; unsigned long flags;
u32 *pgt_base_iova; u32 *pgt_base_iova;
unsigned int page_num = size >> SPRD_IOMMU_PAGE_SHIFT; size_t size = pgcount * SPRD_IOMMU_PAGE_SIZE;
unsigned long start = domain->geometry.aperture_start; unsigned long start = domain->geometry.aperture_start;
unsigned long end = domain->geometry.aperture_end; unsigned long end = domain->geometry.aperture_end;
if (iova < start || (iova + size) > (end + 1)) if (iova < start || (iova + size) > (end + 1))
return -EINVAL; return 0;
pgt_base_iova = dom->pgt_va + ((iova - start) >> SPRD_IOMMU_PAGE_SHIFT); pgt_base_iova = dom->pgt_va + ((iova - start) >> SPRD_IOMMU_PAGE_SHIFT);
spin_lock_irqsave(&dom->pgtlock, flags); spin_lock_irqsave(&dom->pgtlock, flags);
memset(pgt_base_iova, 0, page_num * sizeof(u32)); memset(pgt_base_iova, 0, pgcount * sizeof(u32));
spin_unlock_irqrestore(&dom->pgtlock, flags); spin_unlock_irqrestore(&dom->pgtlock, flags);
return 0; return size;
} }
static void sprd_iommu_sync_map(struct iommu_domain *domain, static void sprd_iommu_sync_map(struct iommu_domain *domain,
...@@ -407,13 +410,13 @@ static const struct iommu_ops sprd_iommu_ops = { ...@@ -407,13 +410,13 @@ static const struct iommu_ops sprd_iommu_ops = {
.probe_device = sprd_iommu_probe_device, .probe_device = sprd_iommu_probe_device,
.device_group = sprd_iommu_device_group, .device_group = sprd_iommu_device_group,
.of_xlate = sprd_iommu_of_xlate, .of_xlate = sprd_iommu_of_xlate,
.pgsize_bitmap = ~0UL << SPRD_IOMMU_PAGE_SHIFT, .pgsize_bitmap = SPRD_IOMMU_PAGE_SIZE,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.default_domain_ops = &(const struct iommu_domain_ops) { .default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = sprd_iommu_attach_device, .attach_dev = sprd_iommu_attach_device,
.detach_dev = sprd_iommu_detach_device, .detach_dev = sprd_iommu_detach_device,
.map = sprd_iommu_map, .map_pages = sprd_iommu_map,
.unmap = sprd_iommu_unmap, .unmap_pages = sprd_iommu_unmap,
.iotlb_sync_map = sprd_iommu_sync_map, .iotlb_sync_map = sprd_iommu_sync_map,
.iotlb_sync = sprd_iommu_sync, .iotlb_sync = sprd_iommu_sync,
.iova_to_phys = sprd_iommu_iova_to_phys, .iova_to_phys = sprd_iommu_iova_to_phys,
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/types.h> #include <linux/types.h>
#define IOMMU_RESET_REG 0x010 #define IOMMU_RESET_REG 0x010
#define IOMMU_RESET_RELEASE_ALL 0xffffffff
#define IOMMU_ENABLE_REG 0x020 #define IOMMU_ENABLE_REG 0x020
#define IOMMU_ENABLE_ENABLE BIT(0) #define IOMMU_ENABLE_ENABLE BIT(0)
...@@ -92,6 +93,8 @@ ...@@ -92,6 +93,8 @@
#define NUM_PT_ENTRIES 256 #define NUM_PT_ENTRIES 256
#define PT_SIZE (NUM_PT_ENTRIES * PT_ENTRY_SIZE) #define PT_SIZE (NUM_PT_ENTRIES * PT_ENTRY_SIZE)
#define SPAGE_SIZE 4096
struct sun50i_iommu { struct sun50i_iommu {
struct iommu_device iommu; struct iommu_device iommu;
...@@ -270,7 +273,7 @@ static u32 sun50i_mk_pte(phys_addr_t page, int prot) ...@@ -270,7 +273,7 @@ static u32 sun50i_mk_pte(phys_addr_t page, int prot)
enum sun50i_iommu_aci aci; enum sun50i_iommu_aci aci;
u32 flags = 0; u32 flags = 0;
if (prot & (IOMMU_READ | IOMMU_WRITE)) if ((prot & (IOMMU_READ | IOMMU_WRITE)) == (IOMMU_READ | IOMMU_WRITE))
aci = SUN50I_IOMMU_ACI_RD_WR; aci = SUN50I_IOMMU_ACI_RD_WR;
else if (prot & IOMMU_READ) else if (prot & IOMMU_READ)
aci = SUN50I_IOMMU_ACI_RD; aci = SUN50I_IOMMU_ACI_RD;
...@@ -294,6 +297,62 @@ static void sun50i_table_flush(struct sun50i_iommu_domain *sun50i_domain, ...@@ -294,6 +297,62 @@ static void sun50i_table_flush(struct sun50i_iommu_domain *sun50i_domain,
dma_sync_single_for_device(iommu->dev, dma, size, DMA_TO_DEVICE); dma_sync_single_for_device(iommu->dev, dma, size, DMA_TO_DEVICE);
} }
static void sun50i_iommu_zap_iova(struct sun50i_iommu *iommu,
unsigned long iova)
{
u32 reg;
int ret;
iommu_write(iommu, IOMMU_TLB_IVLD_ADDR_REG, iova);
iommu_write(iommu, IOMMU_TLB_IVLD_ADDR_MASK_REG, GENMASK(31, 12));
iommu_write(iommu, IOMMU_TLB_IVLD_ENABLE_REG,
IOMMU_TLB_IVLD_ENABLE_ENABLE);
ret = readl_poll_timeout_atomic(iommu->base + IOMMU_TLB_IVLD_ENABLE_REG,
reg, !reg, 1, 2000);
if (ret)
dev_warn(iommu->dev, "TLB invalidation timed out!\n");
}
static void sun50i_iommu_zap_ptw_cache(struct sun50i_iommu *iommu,
unsigned long iova)
{
u32 reg;
int ret;
iommu_write(iommu, IOMMU_PC_IVLD_ADDR_REG, iova);
iommu_write(iommu, IOMMU_PC_IVLD_ENABLE_REG,
IOMMU_PC_IVLD_ENABLE_ENABLE);
ret = readl_poll_timeout_atomic(iommu->base + IOMMU_PC_IVLD_ENABLE_REG,
reg, !reg, 1, 2000);
if (ret)
dev_warn(iommu->dev, "PTW cache invalidation timed out!\n");
}
static void sun50i_iommu_zap_range(struct sun50i_iommu *iommu,
unsigned long iova, size_t size)
{
assert_spin_locked(&iommu->iommu_lock);
iommu_write(iommu, IOMMU_AUTO_GATING_REG, 0);
sun50i_iommu_zap_iova(iommu, iova);
sun50i_iommu_zap_iova(iommu, iova + SPAGE_SIZE);
if (size > SPAGE_SIZE) {
sun50i_iommu_zap_iova(iommu, iova + size);
sun50i_iommu_zap_iova(iommu, iova + size + SPAGE_SIZE);
}
sun50i_iommu_zap_ptw_cache(iommu, iova);
sun50i_iommu_zap_ptw_cache(iommu, iova + SZ_1M);
if (size > SZ_1M) {
sun50i_iommu_zap_ptw_cache(iommu, iova + size);
sun50i_iommu_zap_ptw_cache(iommu, iova + size + SZ_1M);
}
iommu_write(iommu, IOMMU_AUTO_GATING_REG, IOMMU_AUTO_GATING_ENABLE);
}
static int sun50i_iommu_flush_all_tlb(struct sun50i_iommu *iommu) static int sun50i_iommu_flush_all_tlb(struct sun50i_iommu *iommu)
{ {
u32 reg; u32 reg;
...@@ -343,6 +402,18 @@ static void sun50i_iommu_flush_iotlb_all(struct iommu_domain *domain) ...@@ -343,6 +402,18 @@ static void sun50i_iommu_flush_iotlb_all(struct iommu_domain *domain)
spin_unlock_irqrestore(&iommu->iommu_lock, flags); spin_unlock_irqrestore(&iommu->iommu_lock, flags);
} }
static void sun50i_iommu_iotlb_sync_map(struct iommu_domain *domain,
unsigned long iova, size_t size)
{
struct sun50i_iommu_domain *sun50i_domain = to_sun50i_domain(domain);
struct sun50i_iommu *iommu = sun50i_domain->iommu;
unsigned long flags;
spin_lock_irqsave(&iommu->iommu_lock, flags);
sun50i_iommu_zap_range(iommu, iova, size);
spin_unlock_irqrestore(&iommu->iommu_lock, flags);
}
static void sun50i_iommu_iotlb_sync(struct iommu_domain *domain, static void sun50i_iommu_iotlb_sync(struct iommu_domain *domain,
struct iommu_iotlb_gather *gather) struct iommu_iotlb_gather *gather)
{ {
...@@ -511,7 +582,7 @@ static u32 *sun50i_dte_get_page_table(struct sun50i_iommu_domain *sun50i_domain, ...@@ -511,7 +582,7 @@ static u32 *sun50i_dte_get_page_table(struct sun50i_iommu_domain *sun50i_domain,
sun50i_iommu_free_page_table(iommu, drop_pt); sun50i_iommu_free_page_table(iommu, drop_pt);
} }
sun50i_table_flush(sun50i_domain, page_table, PT_SIZE); sun50i_table_flush(sun50i_domain, page_table, NUM_PT_ENTRIES);
sun50i_table_flush(sun50i_domain, dte_addr, 1); sun50i_table_flush(sun50i_domain, dte_addr, 1);
return page_table; return page_table;
...@@ -601,7 +672,6 @@ static struct iommu_domain *sun50i_iommu_domain_alloc(unsigned type) ...@@ -601,7 +672,6 @@ static struct iommu_domain *sun50i_iommu_domain_alloc(unsigned type)
struct sun50i_iommu_domain *sun50i_domain; struct sun50i_iommu_domain *sun50i_domain;
if (type != IOMMU_DOMAIN_DMA && if (type != IOMMU_DOMAIN_DMA &&
type != IOMMU_DOMAIN_IDENTITY &&
type != IOMMU_DOMAIN_UNMANAGED) type != IOMMU_DOMAIN_UNMANAGED)
return NULL; return NULL;
...@@ -766,6 +836,7 @@ static const struct iommu_ops sun50i_iommu_ops = { ...@@ -766,6 +836,7 @@ static const struct iommu_ops sun50i_iommu_ops = {
.attach_dev = sun50i_iommu_attach_device, .attach_dev = sun50i_iommu_attach_device,
.detach_dev = sun50i_iommu_detach_device, .detach_dev = sun50i_iommu_detach_device,
.flush_iotlb_all = sun50i_iommu_flush_iotlb_all, .flush_iotlb_all = sun50i_iommu_flush_iotlb_all,
.iotlb_sync_map = sun50i_iommu_iotlb_sync_map,
.iotlb_sync = sun50i_iommu_iotlb_sync, .iotlb_sync = sun50i_iommu_iotlb_sync,
.iova_to_phys = sun50i_iommu_iova_to_phys, .iova_to_phys = sun50i_iommu_iova_to_phys,
.map = sun50i_iommu_map, .map = sun50i_iommu_map,
...@@ -785,6 +856,8 @@ static void sun50i_iommu_report_fault(struct sun50i_iommu *iommu, ...@@ -785,6 +856,8 @@ static void sun50i_iommu_report_fault(struct sun50i_iommu *iommu,
report_iommu_fault(iommu->domain, iommu->dev, iova, prot); report_iommu_fault(iommu->domain, iommu->dev, iova, prot);
else else
dev_err(iommu->dev, "Page fault while iommu not attached to any domain?\n"); dev_err(iommu->dev, "Page fault while iommu not attached to any domain?\n");
sun50i_iommu_zap_range(iommu, iova, SPAGE_SIZE);
} }
static phys_addr_t sun50i_iommu_handle_pt_irq(struct sun50i_iommu *iommu, static phys_addr_t sun50i_iommu_handle_pt_irq(struct sun50i_iommu *iommu,
...@@ -868,8 +941,8 @@ static phys_addr_t sun50i_iommu_handle_perm_irq(struct sun50i_iommu *iommu) ...@@ -868,8 +941,8 @@ static phys_addr_t sun50i_iommu_handle_perm_irq(struct sun50i_iommu *iommu)
static irqreturn_t sun50i_iommu_irq(int irq, void *dev_id) static irqreturn_t sun50i_iommu_irq(int irq, void *dev_id)
{ {
u32 status, l1_status, l2_status, resets;
struct sun50i_iommu *iommu = dev_id; struct sun50i_iommu *iommu = dev_id;
u32 status;
spin_lock(&iommu->iommu_lock); spin_lock(&iommu->iommu_lock);
...@@ -879,6 +952,9 @@ static irqreturn_t sun50i_iommu_irq(int irq, void *dev_id) ...@@ -879,6 +952,9 @@ static irqreturn_t sun50i_iommu_irq(int irq, void *dev_id)
return IRQ_NONE; return IRQ_NONE;
} }
l1_status = iommu_read(iommu, IOMMU_L1PG_INT_REG);
l2_status = iommu_read(iommu, IOMMU_L2PG_INT_REG);
if (status & IOMMU_INT_INVALID_L2PG) if (status & IOMMU_INT_INVALID_L2PG)
sun50i_iommu_handle_pt_irq(iommu, sun50i_iommu_handle_pt_irq(iommu,
IOMMU_INT_ERR_ADDR_L2_REG, IOMMU_INT_ERR_ADDR_L2_REG,
...@@ -892,8 +968,9 @@ static irqreturn_t sun50i_iommu_irq(int irq, void *dev_id) ...@@ -892,8 +968,9 @@ static irqreturn_t sun50i_iommu_irq(int irq, void *dev_id)
iommu_write(iommu, IOMMU_INT_CLR_REG, status); iommu_write(iommu, IOMMU_INT_CLR_REG, status);
iommu_write(iommu, IOMMU_RESET_REG, ~status); resets = (status | l1_status | l2_status) & IOMMU_INT_MASTER_MASK;
iommu_write(iommu, IOMMU_RESET_REG, status); iommu_write(iommu, IOMMU_RESET_REG, ~resets);
iommu_write(iommu, IOMMU_RESET_REG, IOMMU_RESET_RELEASE_ALL);
spin_unlock(&iommu->iommu_lock); spin_unlock(&iommu->iommu_lock);
......
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Yong Wu <yong.wu@mediatek.com>
*/
#ifndef _DT_BINDINGS_MEMORY_MT8365_LARB_PORT_H_
#define _DT_BINDINGS_MEMORY_MT8365_LARB_PORT_H_
#include <dt-bindings/memory/mtk-memory-port.h>
#define M4U_LARB0_ID 0
#define M4U_LARB1_ID 1
#define M4U_LARB2_ID 2
#define M4U_LARB3_ID 3
/* larb0 */
#define M4U_PORT_DISP_OVL0 MTK_M4U_ID(M4U_LARB0_ID, 0)
#define M4U_PORT_DISP_OVL0_2L MTK_M4U_ID(M4U_LARB0_ID, 1)
#define M4U_PORT_DISP_RDMA0 MTK_M4U_ID(M4U_LARB0_ID, 2)
#define M4U_PORT_DISP_WDMA0 MTK_M4U_ID(M4U_LARB0_ID, 3)
#define M4U_PORT_DISP_RDMA1 MTK_M4U_ID(M4U_LARB0_ID, 4)
#define M4U_PORT_MDP_RDMA0 MTK_M4U_ID(M4U_LARB0_ID, 5)
#define M4U_PORT_MDP_WROT1 MTK_M4U_ID(M4U_LARB0_ID, 6)
#define M4U_PORT_MDP_WROT0 MTK_M4U_ID(M4U_LARB0_ID, 7)
#define M4U_PORT_MDP_RDMA1 MTK_M4U_ID(M4U_LARB0_ID, 8)
#define M4U_PORT_DISP_FAKE0 MTK_M4U_ID(M4U_LARB0_ID, 9)
#define M4U_PORT_APU_READ MTK_M4U_ID(M4U_LARB0_ID, 10)
#define M4U_PORT_APU_WRITE MTK_M4U_ID(M4U_LARB0_ID, 11)
/* larb1 */
#define M4U_PORT_VENC_RCPU MTK_M4U_ID(M4U_LARB1_ID, 0)
#define M4U_PORT_VENC_REC MTK_M4U_ID(M4U_LARB1_ID, 1)
#define M4U_PORT_VENC_BSDMA MTK_M4U_ID(M4U_LARB1_ID, 2)
#define M4U_PORT_VENC_SV_COMV MTK_M4U_ID(M4U_LARB1_ID, 3)
#define M4U_PORT_VENC_RD_COMV MTK_M4U_ID(M4U_LARB1_ID, 4)
#define M4U_PORT_VENC_NBM_RDMA MTK_M4U_ID(M4U_LARB1_ID, 5)
#define M4U_PORT_VENC_NBM_RDMA_LITE MTK_M4U_ID(M4U_LARB1_ID, 6)
#define M4U_PORT_JPGENC_Y_RDMA MTK_M4U_ID(M4U_LARB1_ID, 7)
#define M4U_PORT_JPGENC_C_RDMA MTK_M4U_ID(M4U_LARB1_ID, 8)
#define M4U_PORT_JPGENC_Q_TABLE MTK_M4U_ID(M4U_LARB1_ID, 9)
#define M4U_PORT_JPGENC_BSDMA MTK_M4U_ID(M4U_LARB1_ID, 10)
#define M4U_PORT_JPGDEC_WDMA MTK_M4U_ID(M4U_LARB1_ID, 11)
#define M4U_PORT_JPGDEC_BSDMA MTK_M4U_ID(M4U_LARB1_ID, 12)
#define M4U_PORT_VENC_NBM_WDMA MTK_M4U_ID(M4U_LARB1_ID, 13)
#define M4U_PORT_VENC_NBM_WDMA_LITE MTK_M4U_ID(M4U_LARB1_ID, 14)
#define M4U_PORT_VENC_CUR_LUMA MTK_M4U_ID(M4U_LARB1_ID, 15)
#define M4U_PORT_VENC_CUR_CHROMA MTK_M4U_ID(M4U_LARB1_ID, 16)
#define M4U_PORT_VENC_REF_LUMA MTK_M4U_ID(M4U_LARB1_ID, 17)
#define M4U_PORT_VENC_REF_CHROMA MTK_M4U_ID(M4U_LARB1_ID, 18)
/* larb2 */
#define M4U_PORT_CAM_IMGO MTK_M4U_ID(M4U_LARB2_ID, 0)
#define M4U_PORT_CAM_RRZO MTK_M4U_ID(M4U_LARB2_ID, 1)
#define M4U_PORT_CAM_AAO MTK_M4U_ID(M4U_LARB2_ID, 2)
#define M4U_PORT_CAM_LCS MTK_M4U_ID(M4U_LARB2_ID, 3)
#define M4U_PORT_CAM_ESFKO MTK_M4U_ID(M4U_LARB2_ID, 4)
#define M4U_PORT_CAM_CAM_SV0 MTK_M4U_ID(M4U_LARB2_ID, 5)
#define M4U_PORT_CAM_CAM_SV1 MTK_M4U_ID(M4U_LARB2_ID, 6)
#define M4U_PORT_CAM_LSCI MTK_M4U_ID(M4U_LARB2_ID, 7)
#define M4U_PORT_CAM_LSCI_D MTK_M4U_ID(M4U_LARB2_ID, 8)
#define M4U_PORT_CAM_AFO MTK_M4U_ID(M4U_LARB2_ID, 9)
#define M4U_PORT_CAM_SPARE MTK_M4U_ID(M4U_LARB2_ID, 10)
#define M4U_PORT_CAM_BPCI MTK_M4U_ID(M4U_LARB2_ID, 11)
#define M4U_PORT_CAM_BPCI_D MTK_M4U_ID(M4U_LARB2_ID, 12)
#define M4U_PORT_CAM_UFDI MTK_M4U_ID(M4U_LARB2_ID, 13)
#define M4U_PORT_CAM_IMGI MTK_M4U_ID(M4U_LARB2_ID, 14)
#define M4U_PORT_CAM_IMG2O MTK_M4U_ID(M4U_LARB2_ID, 15)
#define M4U_PORT_CAM_IMG3O MTK_M4U_ID(M4U_LARB2_ID, 16)
#define M4U_PORT_CAM_WPE0_I MTK_M4U_ID(M4U_LARB2_ID, 17)
#define M4U_PORT_CAM_WPE1_I MTK_M4U_ID(M4U_LARB2_ID, 18)
#define M4U_PORT_CAM_WPE_O MTK_M4U_ID(M4U_LARB2_ID, 19)
#define M4U_PORT_CAM_FD0_I MTK_M4U_ID(M4U_LARB2_ID, 20)
#define M4U_PORT_CAM_FD1_I MTK_M4U_ID(M4U_LARB2_ID, 21)
#define M4U_PORT_CAM_FD0_O MTK_M4U_ID(M4U_LARB2_ID, 22)
#define M4U_PORT_CAM_FD1_O MTK_M4U_ID(M4U_LARB2_ID, 23)
/* larb3 */
#define M4U_PORT_HW_VDEC_MC_EXT MTK_M4U_ID(M4U_LARB3_ID, 0)
#define M4U_PORT_HW_VDEC_UFO_EXT MTK_M4U_ID(M4U_LARB3_ID, 1)
#define M4U_PORT_HW_VDEC_PP_EXT MTK_M4U_ID(M4U_LARB3_ID, 2)
#define M4U_PORT_HW_VDEC_PRED_RD_EXT MTK_M4U_ID(M4U_LARB3_ID, 3)
#define M4U_PORT_HW_VDEC_PRED_WR_EXT MTK_M4U_ID(M4U_LARB3_ID, 4)
#define M4U_PORT_HW_VDEC_PPWRAP_EXT MTK_M4U_ID(M4U_LARB3_ID, 5)
#define M4U_PORT_HW_VDEC_TILE_EXT MTK_M4U_ID(M4U_LARB3_ID, 6)
#define M4U_PORT_HW_VDEC_VLD_EXT MTK_M4U_ID(M4U_LARB3_ID, 7)
#define M4U_PORT_HW_VDEC_VLD2_EXT MTK_M4U_ID(M4U_LARB3_ID, 8)
#define M4U_PORT_HW_VDEC_AVC_MV_EXT MTK_M4U_ID(M4U_LARB3_ID, 9)
#define M4U_PORT_HW_VDEC_RG_CTRL_DMA_EXT MTK_M4U_ID(M4U_LARB3_ID, 10)
#endif
...@@ -150,9 +150,7 @@ struct io_pgtable_cfg { ...@@ -150,9 +150,7 @@ struct io_pgtable_cfg {
/** /**
* struct io_pgtable_ops - Page table manipulation API for IOMMU drivers. * struct io_pgtable_ops - Page table manipulation API for IOMMU drivers.
* *
* @map: Map a physically contiguous memory region.
* @map_pages: Map a physically contiguous range of pages of the same size. * @map_pages: Map a physically contiguous range of pages of the same size.
* @unmap: Unmap a physically contiguous memory region.
* @unmap_pages: Unmap a range of virtually contiguous pages of the same size. * @unmap_pages: Unmap a range of virtually contiguous pages of the same size.
* @iova_to_phys: Translate iova to physical address. * @iova_to_phys: Translate iova to physical address.
* *
...@@ -160,13 +158,9 @@ struct io_pgtable_cfg { ...@@ -160,13 +158,9 @@ struct io_pgtable_cfg {
* the same names. * the same names.
*/ */
struct io_pgtable_ops { struct io_pgtable_ops {
int (*map)(struct io_pgtable_ops *ops, unsigned long iova,
phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
int (*map_pages)(struct io_pgtable_ops *ops, unsigned long iova, int (*map_pages)(struct io_pgtable_ops *ops, unsigned long iova,
phys_addr_t paddr, size_t pgsize, size_t pgcount, phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped); int prot, gfp_t gfp, size_t *mapped);
size_t (*unmap)(struct io_pgtable_ops *ops, unsigned long iova,
size_t size, struct iommu_iotlb_gather *gather);
size_t (*unmap_pages)(struct io_pgtable_ops *ops, unsigned long iova, size_t (*unmap_pages)(struct io_pgtable_ops *ops, unsigned long iova,
size_t pgsize, size_t pgcount, size_t pgsize, size_t pgcount,
struct iommu_iotlb_gather *gather); struct iommu_iotlb_gather *gather);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment