Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
66dc1b79
Commit
66dc1b79
authored
Jan 04, 2022
by
Joerg Roedel
Browse files
Options
Browse Files
Download
Plain Diff
Merge branches 'arm/smmu', 'virtio', 'x86/amd', 'x86/vt-d' and 'core' into next
parents
c9e6606c
91d69885
4cb3600e
664c0b58
c95a9c27
aade40b6
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
493 additions
and
570 deletions
+493
-570
Documentation/devicetree/bindings/iommu/arm,smmu.yaml
Documentation/devicetree/bindings/iommu/arm,smmu.yaml
+2
-0
drivers/iommu/amd/amd_iommu_types.h
drivers/iommu/amd/amd_iommu_types.h
+0
-2
drivers/iommu/amd/init.c
drivers/iommu/amd/init.c
+59
-50
drivers/iommu/amd/io_pgtable.c
drivers/iommu/amd/io_pgtable.c
+41
-69
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+1
-1
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+2
-3
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+2
-1
drivers/iommu/dma-iommu.c
drivers/iommu/dma-iommu.c
+217
-57
drivers/iommu/intel/iommu.c
drivers/iommu/intel/iommu.c
+37
-74
drivers/iommu/io-pgtable-arm-v7s.c
drivers/iommu/io-pgtable-arm-v7s.c
+5
-1
drivers/iommu/io-pgtable-arm.c
drivers/iommu/io-pgtable-arm.c
+5
-4
drivers/iommu/iommu.c
drivers/iommu/iommu.c
+2
-1
drivers/iommu/iova.c
drivers/iommu/iova.c
+9
-200
drivers/iommu/virtio-iommu.c
drivers/iommu/virtio-iommu.c
+95
-20
drivers/vdpa/vdpa_user/iova_domain.c
drivers/vdpa/vdpa_user/iova_domain.c
+0
-8
include/linux/intel-svm.h
include/linux/intel-svm.h
+0
-6
include/linux/iommu.h
include/linux/iommu.h
+2
-1
include/linux/iova.h
include/linux/iova.h
+1
-67
include/trace/events/iommu.h
include/trace/events/iommu.h
+6
-4
include/uapi/linux/virtio_iommu.h
include/uapi/linux/virtio_iommu.h
+7
-1
No files found.
Documentation/devicetree/bindings/iommu/arm,smmu.yaml
View file @
66dc1b79
...
...
@@ -38,10 +38,12 @@ properties:
-
qcom,sc7280-smmu-500
-
qcom,sc8180x-smmu-500
-
qcom,sdm845-smmu-500
-
qcom,sdx55-smmu-500
-
qcom,sm6350-smmu-500
-
qcom,sm8150-smmu-500
-
qcom,sm8250-smmu-500
-
qcom,sm8350-smmu-500
-
qcom,sm8450-smmu-500
-
const
:
arm,mmu-500
-
description
:
Qcom Adreno GPUs implementing "arm,smmu-v2"
items
:
...
...
drivers/iommu/amd/amd_iommu_types.h
View file @
66dc1b79
...
...
@@ -645,8 +645,6 @@ struct amd_iommu {
/* DebugFS Info */
struct
dentry
*
debugfs
;
#endif
/* IRQ notifier for IntCapXT interrupt */
struct
irq_affinity_notify
intcapxt_notify
;
};
static
inline
struct
amd_iommu
*
dev_to_amd_iommu
(
struct
device
*
dev
)
...
...
drivers/iommu/amd/init.c
View file @
66dc1b79
...
...
@@ -806,16 +806,27 @@ static int iommu_ga_log_enable(struct amd_iommu *iommu)
{
#ifdef CONFIG_IRQ_REMAP
u32
status
,
i
;
u64
entry
;
if
(
!
iommu
->
ga_log
)
return
-
EINVAL
;
status
=
readl
(
iommu
->
mmio_base
+
MMIO_STATUS_OFFSET
);
/* Check if already running */
if
(
status
&
(
MMIO_STATUS_GALOG_RUN_MASK
))
status
=
readl
(
iommu
->
mmio_base
+
MMIO_STATUS_OFFSET
);
if
(
WARN_ON
(
status
&
(
MMIO_STATUS_GALOG_RUN_MASK
)))
return
0
;
entry
=
iommu_virt_to_phys
(
iommu
->
ga_log
)
|
GA_LOG_SIZE_512
;
memcpy_toio
(
iommu
->
mmio_base
+
MMIO_GA_LOG_BASE_OFFSET
,
&
entry
,
sizeof
(
entry
));
entry
=
(
iommu_virt_to_phys
(
iommu
->
ga_log_tail
)
&
(
BIT_ULL
(
52
)
-
1
))
&
~
7ULL
;
memcpy_toio
(
iommu
->
mmio_base
+
MMIO_GA_LOG_TAIL_OFFSET
,
&
entry
,
sizeof
(
entry
));
writel
(
0x00
,
iommu
->
mmio_base
+
MMIO_GA_HEAD_OFFSET
);
writel
(
0x00
,
iommu
->
mmio_base
+
MMIO_GA_TAIL_OFFSET
);
iommu_feature_enable
(
iommu
,
CONTROL_GAINT_EN
);
iommu_feature_enable
(
iommu
,
CONTROL_GALOG_EN
);
...
...
@@ -825,7 +836,7 @@ static int iommu_ga_log_enable(struct amd_iommu *iommu)
break
;
}
if
(
i
>=
LOOP_TIMEOUT
)
if
(
WARN_ON
(
i
>=
LOOP_TIMEOUT
)
)
return
-
EINVAL
;
#endif
/* CONFIG_IRQ_REMAP */
return
0
;
...
...
@@ -834,8 +845,6 @@ static int iommu_ga_log_enable(struct amd_iommu *iommu)
static
int
iommu_init_ga_log
(
struct
amd_iommu
*
iommu
)
{
#ifdef CONFIG_IRQ_REMAP
u64
entry
;
if
(
!
AMD_IOMMU_GUEST_IR_VAPIC
(
amd_iommu_guest_ir
))
return
0
;
...
...
@@ -849,16 +858,6 @@ static int iommu_init_ga_log(struct amd_iommu *iommu)
if
(
!
iommu
->
ga_log_tail
)
goto
err_out
;
entry
=
iommu_virt_to_phys
(
iommu
->
ga_log
)
|
GA_LOG_SIZE_512
;
memcpy_toio
(
iommu
->
mmio_base
+
MMIO_GA_LOG_BASE_OFFSET
,
&
entry
,
sizeof
(
entry
));
entry
=
(
iommu_virt_to_phys
(
iommu
->
ga_log_tail
)
&
(
BIT_ULL
(
52
)
-
1
))
&
~
7ULL
;
memcpy_toio
(
iommu
->
mmio_base
+
MMIO_GA_LOG_TAIL_OFFSET
,
&
entry
,
sizeof
(
entry
));
writel
(
0x00
,
iommu
->
mmio_base
+
MMIO_GA_HEAD_OFFSET
);
writel
(
0x00
,
iommu
->
mmio_base
+
MMIO_GA_TAIL_OFFSET
);
return
0
;
err_out:
free_ga_log
(
iommu
);
...
...
@@ -1523,7 +1522,7 @@ static void amd_iommu_ats_write_check_workaround(struct amd_iommu *iommu)
}
/*
* This function
c
lues the initialization function for one IOMMU
* This function
g
lues the initialization function for one IOMMU
* together and also allocates the command buffer and programs the
* hardware. It does NOT enable the IOMMU. This is done afterwards.
*/
...
...
@@ -2016,48 +2015,18 @@ union intcapxt {
};
}
__attribute__
((
packed
));
/*
* There isn't really any need to mask/unmask at the irqchip level because
* the 64-bit INTCAPXT registers can be updated atomically without tearing
* when the affinity is being updated.
*/
static
void
intcapxt_unmask_irq
(
struct
irq_data
*
data
)
{
}
static
void
intcapxt_mask_irq
(
struct
irq_data
*
data
)
{
}
static
struct
irq_chip
intcapxt_controller
;
static
int
intcapxt_irqdomain_activate
(
struct
irq_domain
*
domain
,
struct
irq_data
*
irqd
,
bool
reserve
)
{
struct
amd_iommu
*
iommu
=
irqd
->
chip_data
;
struct
irq_cfg
*
cfg
=
irqd_cfg
(
irqd
);
union
intcapxt
xt
;
xt
.
capxt
=
0ULL
;
xt
.
dest_mode_logical
=
apic
->
dest_mode_logical
;
xt
.
vector
=
cfg
->
vector
;
xt
.
destid_0_23
=
cfg
->
dest_apicid
&
GENMASK
(
23
,
0
);
xt
.
destid_24_31
=
cfg
->
dest_apicid
>>
24
;
/**
* Current IOMMU implemtation uses the same IRQ for all
* 3 IOMMU interrupts.
*/
writeq
(
xt
.
capxt
,
iommu
->
mmio_base
+
MMIO_INTCAPXT_EVT_OFFSET
);
writeq
(
xt
.
capxt
,
iommu
->
mmio_base
+
MMIO_INTCAPXT_PPR_OFFSET
);
writeq
(
xt
.
capxt
,
iommu
->
mmio_base
+
MMIO_INTCAPXT_GALOG_OFFSET
);
return
0
;
}
static
void
intcapxt_irqdomain_deactivate
(
struct
irq_domain
*
domain
,
struct
irq_data
*
irqd
)
{
intcapxt_mask_irq
(
irqd
);
}
...
...
@@ -2091,6 +2060,38 @@ static void intcapxt_irqdomain_free(struct irq_domain *domain, unsigned int virq
irq_domain_free_irqs_top
(
domain
,
virq
,
nr_irqs
);
}
static
void
intcapxt_unmask_irq
(
struct
irq_data
*
irqd
)
{
struct
amd_iommu
*
iommu
=
irqd
->
chip_data
;
struct
irq_cfg
*
cfg
=
irqd_cfg
(
irqd
);
union
intcapxt
xt
;
xt
.
capxt
=
0ULL
;
xt
.
dest_mode_logical
=
apic
->
dest_mode_logical
;
xt
.
vector
=
cfg
->
vector
;
xt
.
destid_0_23
=
cfg
->
dest_apicid
&
GENMASK
(
23
,
0
);
xt
.
destid_24_31
=
cfg
->
dest_apicid
>>
24
;
/**
* Current IOMMU implementation uses the same IRQ for all
* 3 IOMMU interrupts.
*/
writeq
(
xt
.
capxt
,
iommu
->
mmio_base
+
MMIO_INTCAPXT_EVT_OFFSET
);
writeq
(
xt
.
capxt
,
iommu
->
mmio_base
+
MMIO_INTCAPXT_PPR_OFFSET
);
writeq
(
xt
.
capxt
,
iommu
->
mmio_base
+
MMIO_INTCAPXT_GALOG_OFFSET
);
}
static
void
intcapxt_mask_irq
(
struct
irq_data
*
irqd
)
{
struct
amd_iommu
*
iommu
=
irqd
->
chip_data
;
writeq
(
0
,
iommu
->
mmio_base
+
MMIO_INTCAPXT_EVT_OFFSET
);
writeq
(
0
,
iommu
->
mmio_base
+
MMIO_INTCAPXT_PPR_OFFSET
);
writeq
(
0
,
iommu
->
mmio_base
+
MMIO_INTCAPXT_GALOG_OFFSET
);
}
static
int
intcapxt_set_affinity
(
struct
irq_data
*
irqd
,
const
struct
cpumask
*
mask
,
bool
force
)
{
...
...
@@ -2100,8 +2101,12 @@ static int intcapxt_set_affinity(struct irq_data *irqd,
ret
=
parent
->
chip
->
irq_set_affinity
(
parent
,
mask
,
force
);
if
(
ret
<
0
||
ret
==
IRQ_SET_MASK_OK_DONE
)
return
ret
;
return
0
;
}
return
intcapxt_irqdomain_activate
(
irqd
->
domain
,
irqd
,
false
);
static
int
intcapxt_set_wake
(
struct
irq_data
*
irqd
,
unsigned
int
on
)
{
return
on
?
-
EOPNOTSUPP
:
0
;
}
static
struct
irq_chip
intcapxt_controller
=
{
...
...
@@ -2111,7 +2116,8 @@ static struct irq_chip intcapxt_controller = {
.
irq_ack
=
irq_chip_ack_parent
,
.
irq_retrigger
=
irq_chip_retrigger_hierarchy
,
.
irq_set_affinity
=
intcapxt_set_affinity
,
.
flags
=
IRQCHIP_SKIP_SET_WAKE
,
.
irq_set_wake
=
intcapxt_set_wake
,
.
flags
=
IRQCHIP_MASK_ON_SUSPEND
,
};
static
const
struct
irq_domain_ops
intcapxt_domain_ops
=
{
...
...
@@ -2173,7 +2179,6 @@ static int iommu_setup_intcapxt(struct amd_iommu *iommu)
return
ret
;
}
iommu_feature_enable
(
iommu
,
CONTROL_INTCAPXT_EN
);
return
0
;
}
...
...
@@ -2196,6 +2201,10 @@ static int iommu_init_irq(struct amd_iommu *iommu)
iommu
->
int_enabled
=
true
;
enable_faults:
if
(
amd_iommu_xt_mode
==
IRQ_REMAP_X2APIC_MODE
)
iommu_feature_enable
(
iommu
,
CONTROL_INTCAPXT_EN
);
iommu_feature_enable
(
iommu
,
CONTROL_EVT_INT_EN
);
if
(
iommu
->
ppr_log
!=
NULL
)
...
...
drivers/iommu/amd/io_pgtable.c
View file @
66dc1b79
...
...
@@ -74,87 +74,61 @@ static u64 *first_pte_l7(u64 *pte, unsigned long *page_size,
*
****************************************************************************/
static
void
free_p
age_list
(
struct
page
*
freelist
)
static
void
free_p
t_page
(
u64
*
pt
,
struct
list_head
*
freelist
)
{
while
(
freelist
!=
NULL
)
{
unsigned
long
p
=
(
unsigned
long
)
page_address
(
freelist
);
struct
page
*
p
=
virt_to_page
(
pt
);
freelist
=
freelist
->
freelist
;
free_page
(
p
);
}
list_add_tail
(
&
p
->
lru
,
freelist
);
}
static
struct
page
*
free_pt_page
(
unsigned
long
pt
,
struct
page
*
freelist
)
static
void
free_pt_lvl
(
u64
*
pt
,
struct
list_head
*
freelist
,
int
lvl
)
{
struct
page
*
p
=
virt_to_page
((
void
*
)
pt
);
u64
*
p
;
int
i
;
p
->
freelist
=
freelist
;
for
(
i
=
0
;
i
<
512
;
++
i
)
{
/* PTE present? */
if
(
!
IOMMU_PTE_PRESENT
(
pt
[
i
]))
continue
;
return
p
;
}
/* Large PTE? */
if
(
PM_PTE_LEVEL
(
pt
[
i
])
==
0
||
PM_PTE_LEVEL
(
pt
[
i
])
==
7
)
continue
;
#define DEFINE_FREE_PT_FN(LVL, FN) \
static struct page *free_pt_##LVL (unsigned long __pt, struct page *freelist) \
{ \
unsigned long p; \
u64 *pt; \
int i; \
\
pt = (u64 *)__pt; \
\
for (i = 0; i < 512; ++i) { \
/* PTE present? */
\
if (!IOMMU_PTE_PRESENT(pt[i])) \
continue; \
\
/* Large PTE? */
\
if (PM_PTE_LEVEL(pt[i]) == 0 || \
PM_PTE_LEVEL(pt[i]) == 7) \
continue; \
\
p = (unsigned long)IOMMU_PTE_PAGE(pt[i]); \
freelist = FN(p, freelist); \
} \
\
return free_pt_page((unsigned long)pt, freelist); \
}
/*
* Free the next level. No need to look at l1 tables here since
* they can only contain leaf PTEs; just free them directly.
*/
p
=
IOMMU_PTE_PAGE
(
pt
[
i
]);
if
(
lvl
>
2
)
free_pt_lvl
(
p
,
freelist
,
lvl
-
1
);
else
free_pt_page
(
p
,
freelist
);
}
DEFINE_FREE_PT_FN
(
l2
,
free_pt_page
)
DEFINE_FREE_PT_FN
(
l3
,
free_pt_l2
)
DEFINE_FREE_PT_FN
(
l4
,
free_pt_l3
)
DEFINE_FREE_PT_FN
(
l5
,
free_pt_l4
)
DEFINE_FREE_PT_FN
(
l6
,
free_pt_l5
)
free_pt_page
(
pt
,
freelist
);
}
static
struct
page
*
free_sub_pt
(
unsigned
long
root
,
int
mode
,
struct
page
*
freelist
)
static
void
free_sub_pt
(
u64
*
root
,
int
mode
,
struct
list_head
*
freelist
)
{
switch
(
mode
)
{
case
PAGE_MODE_NONE
:
case
PAGE_MODE_7_LEVEL
:
break
;
case
PAGE_MODE_1_LEVEL
:
free
list
=
free
_pt_page
(
root
,
freelist
);
free_pt_page
(
root
,
freelist
);
break
;
case
PAGE_MODE_2_LEVEL
:
freelist
=
free_pt_l2
(
root
,
freelist
);
break
;
case
PAGE_MODE_3_LEVEL
:
freelist
=
free_pt_l3
(
root
,
freelist
);
break
;
case
PAGE_MODE_4_LEVEL
:
freelist
=
free_pt_l4
(
root
,
freelist
);
break
;
case
PAGE_MODE_5_LEVEL
:
freelist
=
free_pt_l5
(
root
,
freelist
);
break
;
case
PAGE_MODE_6_LEVEL
:
free
list
=
free_pt_l6
(
root
,
freelist
);
free
_pt_lvl
(
root
,
freelist
,
mode
);
break
;
default:
BUG
();
}
return
freelist
;
}
void
amd_iommu_domain_set_pgtable
(
struct
protection_domain
*
domain
,
...
...
@@ -362,9 +336,9 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable,
return
pte
;
}
static
struct
page
*
free_clear_pte
(
u64
*
pte
,
u64
pteval
,
struct
page
*
freelist
)
static
void
free_clear_pte
(
u64
*
pte
,
u64
pteval
,
struct
list_head
*
freelist
)
{
u
nsigned
long
pt
;
u
64
*
pt
;
int
mode
;
while
(
cmpxchg64
(
pte
,
pteval
,
0
)
!=
pteval
)
{
...
...
@@ -373,12 +347,12 @@ static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
}
if
(
!
IOMMU_PTE_PRESENT
(
pteval
))
return
freelist
;
return
;
pt
=
(
unsigned
long
)
IOMMU_PTE_PAGE
(
pteval
);
pt
=
IOMMU_PTE_PAGE
(
pteval
);
mode
=
IOMMU_PTE_MODE
(
pteval
);
return
free_sub_pt
(
pt
,
mode
,
freelist
);
free_sub_pt
(
pt
,
mode
,
freelist
);
}
/*
...
...
@@ -392,7 +366,7 @@ static int iommu_v1_map_page(struct io_pgtable_ops *ops, unsigned long iova,
phys_addr_t
paddr
,
size_t
size
,
int
prot
,
gfp_t
gfp
)
{
struct
protection_domain
*
dom
=
io_pgtable_ops_to_domain
(
ops
);
struct
page
*
freelist
=
NULL
;
LIST_HEAD
(
freelist
)
;
bool
updated
=
false
;
u64
__pte
,
*
pte
;
int
ret
,
i
,
count
;
...
...
@@ -412,9 +386,9 @@ static int iommu_v1_map_page(struct io_pgtable_ops *ops, unsigned long iova,
goto
out
;
for
(
i
=
0
;
i
<
count
;
++
i
)
free
list
=
free_clear_pte
(
&
pte
[
i
],
pte
[
i
],
freelist
);
free
_clear_pte
(
&
pte
[
i
],
pte
[
i
],
&
freelist
);
if
(
freelist
!=
NULL
)
if
(
!
list_empty
(
&
freelist
)
)
updated
=
true
;
if
(
count
>
1
)
{
...
...
@@ -449,7 +423,7 @@ static int iommu_v1_map_page(struct io_pgtable_ops *ops, unsigned long iova,
}
/* Everything flushed out, free pages now */
free_page_list
(
freelist
);
put_pages_list
(
&
freelist
);
return
ret
;
}
...
...
@@ -511,8 +485,7 @@ static void v1_free_pgtable(struct io_pgtable *iop)
{
struct
amd_io_pgtable
*
pgtable
=
container_of
(
iop
,
struct
amd_io_pgtable
,
iop
);
struct
protection_domain
*
dom
;
struct
page
*
freelist
=
NULL
;
unsigned
long
root
;
LIST_HEAD
(
freelist
);
if
(
pgtable
->
mode
==
PAGE_MODE_NONE
)
return
;
...
...
@@ -529,10 +502,9 @@ static void v1_free_pgtable(struct io_pgtable *iop)
BUG_ON
(
pgtable
->
mode
<
PAGE_MODE_NONE
||
pgtable
->
mode
>
PAGE_MODE_6_LEVEL
);
root
=
(
unsigned
long
)
pgtable
->
root
;
freelist
=
free_sub_pt
(
root
,
pgtable
->
mode
,
freelist
);
free_sub_pt
(
pgtable
->
root
,
pgtable
->
mode
,
&
freelist
);
free_page_list
(
freelist
);
put_pages_list
(
&
freelist
);
}
static
struct
io_pgtable
*
v1_alloc_pgtable
(
struct
io_pgtable_cfg
*
cfg
,
void
*
cookie
)
...
...
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
View file @
66dc1b79
...
...
@@ -220,7 +220,7 @@ static void arm_smmu_mmu_notifier_free(struct mmu_notifier *mn)
kfree
(
mn_to_smmu
(
mn
));
}
static
struct
mmu_notifier_ops
arm_smmu_mmu_notifier_ops
=
{
static
const
struct
mmu_notifier_ops
arm_smmu_mmu_notifier_ops
=
{
.
invalidate_range
=
arm_smmu_mm_invalidate_range
,
.
release
=
arm_smmu_mm_release
,
.
free_notifier
=
arm_smmu_mmu_notifier_free
,
...
...
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
View file @
66dc1b79
...
...
@@ -184,7 +184,6 @@
#else
#define Q_MAX_SZ_SHIFT (PAGE_SHIFT + MAX_ORDER - 1)
#endif
#define Q_MIN_SZ_SHIFT (PAGE_SHIFT)
/*
* Stream table.
...
...
@@ -374,7 +373,7 @@
/* Event queue */
#define EVTQ_ENT_SZ_SHIFT 5
#define EVTQ_ENT_DWORDS ((1 << EVTQ_ENT_SZ_SHIFT) >> 3)
#define EVTQ_MAX_SZ_SHIFT (Q_M
IN
_SZ_SHIFT - EVTQ_ENT_SZ_SHIFT)
#define EVTQ_MAX_SZ_SHIFT (Q_M
AX
_SZ_SHIFT - EVTQ_ENT_SZ_SHIFT)
#define EVTQ_0_ID GENMASK_ULL(7, 0)
...
...
@@ -400,7 +399,7 @@
/* PRI queue */
#define PRIQ_ENT_SZ_SHIFT 4
#define PRIQ_ENT_DWORDS ((1 << PRIQ_ENT_SZ_SHIFT) >> 3)
#define PRIQ_MAX_SZ_SHIFT (Q_M
IN
_SZ_SHIFT - PRIQ_ENT_SZ_SHIFT)
#define PRIQ_MAX_SZ_SHIFT (Q_M
AX
_SZ_SHIFT - PRIQ_ENT_SZ_SHIFT)
#define PRIQ_0_SID GENMASK_ULL(31, 0)
#define PRIQ_0_SSID GENMASK_ULL(51, 32)
...
...
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
View file @
66dc1b79
...
...
@@ -51,7 +51,7 @@ static void qcom_adreno_smmu_get_fault_info(const void *cookie,
info
->
fsynr1
=
arm_smmu_cb_read
(
smmu
,
cfg
->
cbndx
,
ARM_SMMU_CB_FSYNR1
);
info
->
far
=
arm_smmu_cb_readq
(
smmu
,
cfg
->
cbndx
,
ARM_SMMU_CB_FAR
);
info
->
cbfrsynra
=
arm_smmu_gr1_read
(
smmu
,
ARM_SMMU_GR1_CBFRSYNRA
(
cfg
->
cbndx
));
info
->
ttbr0
=
arm_smmu_cb_read
(
smmu
,
cfg
->
cbndx
,
ARM_SMMU_CB_TTBR0
);
info
->
ttbr0
=
arm_smmu_cb_read
q
(
smmu
,
cfg
->
cbndx
,
ARM_SMMU_CB_TTBR0
);
info
->
contextidr
=
arm_smmu_cb_read
(
smmu
,
cfg
->
cbndx
,
ARM_SMMU_CB_CONTEXTIDR
);
}
...
...
@@ -415,6 +415,7 @@ static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = {
{
.
compatible
=
"qcom,sm8150-smmu-500"
},
{
.
compatible
=
"qcom,sm8250-smmu-500"
},
{
.
compatible
=
"qcom,sm8350-smmu-500"
},
{
.
compatible
=
"qcom,sm8450-smmu-500"
},
{
}
};
...
...
drivers/iommu/dma-iommu.c
View file @
66dc1b79
...
...
@@ -9,9 +9,12 @@
*/
#include <linux/acpi_iort.h>
#include <linux/atomic.h>
#include <linux/crash_dump.h>
#include <linux/device.h>
#include <linux/dma-
map-ops
.h>
#include <linux/dma-
direct
.h>
#include <linux/dma-iommu.h>
#include <linux/dma-map-ops.h>
#include <linux/gfp.h>
#include <linux/huge_mm.h>
#include <linux/iommu.h>
...
...
@@ -20,11 +23,10 @@
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/swiotlb.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
#include <linux/swiotlb.h>
#include <linux/vmalloc.h>
#include <linux/crash_dump.h>
#include <linux/dma-direct.h>
struct
iommu_dma_msi_page
{
struct
list_head
list
;
...
...
@@ -41,7 +43,19 @@ struct iommu_dma_cookie {
enum
iommu_dma_cookie_type
type
;
union
{
/* Full allocator for IOMMU_DMA_IOVA_COOKIE */
struct
iova_domain
iovad
;
struct
{
struct
iova_domain
iovad
;
struct
iova_fq
__percpu
*
fq
;
/* Flush queue */
/* Number of TLB flushes that have been started */
atomic64_t
fq_flush_start_cnt
;
/* Number of TLB flushes that have been finished */
atomic64_t
fq_flush_finish_cnt
;
/* Timer to regularily empty the flush queues */
struct
timer_list
fq_timer
;
/* 1 when timer is active, 0 when not */
atomic_t
fq_timer_on
;
};
/* Trivial linear page allocator for IOMMU_DMA_MSI_COOKIE */
dma_addr_t
msi_iova
;
};
...
...
@@ -64,16 +78,203 @@ static int __init iommu_dma_forcedac_setup(char *str)
}
early_param
(
"iommu.forcedac"
,
iommu_dma_forcedac_setup
);
static
void
iommu_dma_entry_dtor
(
unsigned
long
data
)
/* Number of entries per flush queue */
#define IOVA_FQ_SIZE 256
/* Timeout (in ms) after which entries are flushed from the queue */
#define IOVA_FQ_TIMEOUT 10
/* Flush queue entry for deferred flushing */
struct
iova_fq_entry
{
unsigned
long
iova_pfn
;
unsigned
long
pages
;
struct
list_head
freelist
;
u64
counter
;
/* Flush counter when this entry was added */
};
/* Per-CPU flush queue structure */
struct
iova_fq
{
struct
iova_fq_entry
entries
[
IOVA_FQ_SIZE
];
unsigned
int
head
,
tail
;
spinlock_t
lock
;
};
#define fq_ring_for_each(i, fq) \
for ((i) = (fq)->head; (i) != (fq)->tail; (i) = ((i) + 1) % IOVA_FQ_SIZE)
static
inline
bool
fq_full
(
struct
iova_fq
*
fq
)
{
assert_spin_locked
(
&
fq
->
lock
);
return
(((
fq
->
tail
+
1
)
%
IOVA_FQ_SIZE
)
==
fq
->
head
);
}
static
inline
unsigned
int
fq_ring_add
(
struct
iova_fq
*
fq
)
{
unsigned
int
idx
=
fq
->
tail
;
assert_spin_locked
(
&
fq
->
lock
);
fq
->
tail
=
(
idx
+
1
)
%
IOVA_FQ_SIZE
;
return
idx
;
}
static
void
fq_ring_free
(
struct
iommu_dma_cookie
*
cookie
,
struct
iova_fq
*
fq
)
{
u64
counter
=
atomic64_read
(
&
cookie
->
fq_flush_finish_cnt
);
unsigned
int
idx
;
assert_spin_locked
(
&
fq
->
lock
);
fq_ring_for_each
(
idx
,
fq
)
{
if
(
fq
->
entries
[
idx
].
counter
>=
counter
)
break
;
put_pages_list
(
&
fq
->
entries
[
idx
].
freelist
);
free_iova_fast
(
&
cookie
->
iovad
,
fq
->
entries
[
idx
].
iova_pfn
,
fq
->
entries
[
idx
].
pages
);
fq
->
head
=
(
fq
->
head
+
1
)
%
IOVA_FQ_SIZE
;
}
}
static
void
fq_flush_iotlb
(
struct
iommu_dma_cookie
*
cookie
)
{
struct
page
*
freelist
=
(
struct
page
*
)
data
;
atomic64_inc
(
&
cookie
->
fq_flush_start_cnt
);
cookie
->
fq_domain
->
ops
->
flush_iotlb_all
(
cookie
->
fq_domain
);
atomic64_inc
(
&
cookie
->
fq_flush_finish_cnt
);
}
static
void
fq_flush_timeout
(
struct
timer_list
*
t
)
{
struct
iommu_dma_cookie
*
cookie
=
from_timer
(
cookie
,
t
,
fq_timer
);
int
cpu
;
atomic_set
(
&
cookie
->
fq_timer_on
,
0
);
fq_flush_iotlb
(
cookie
);
for_each_possible_cpu
(
cpu
)
{
unsigned
long
flags
;
struct
iova_fq
*
fq
;
fq
=
per_cpu_ptr
(
cookie
->
fq
,
cpu
);
spin_lock_irqsave
(
&
fq
->
lock
,
flags
);
fq_ring_free
(
cookie
,
fq
);
spin_unlock_irqrestore
(
&
fq
->
lock
,
flags
);
}
}
static
void
queue_iova
(
struct
iommu_dma_cookie
*
cookie
,
unsigned
long
pfn
,
unsigned
long
pages
,
struct
list_head
*
freelist
)
{
struct
iova_fq
*
fq
;
unsigned
long
flags
;
unsigned
int
idx
;
/*
* Order against the IOMMU driver's pagetable update from unmapping
* @pte, to guarantee that fq_flush_iotlb() observes that if called
* from a different CPU before we release the lock below. Full barrier
* so it also pairs with iommu_dma_init_fq() to avoid seeing partially
* written fq state here.
*/
smp_mb
();
while
(
freelist
)
{
unsigned
long
p
=
(
unsigned
long
)
page_address
(
freelist
);
fq
=
raw_cpu_ptr
(
cookie
->
fq
);
spin_lock_irqsave
(
&
fq
->
lock
,
flags
);
/*
* First remove all entries from the flush queue that have already been
* flushed out on another CPU. This makes the fq_full() check below less
* likely to be true.
*/
fq_ring_free
(
cookie
,
fq
);
freelist
=
freelist
->
freelist
;
free_page
(
p
);
if
(
fq_full
(
fq
))
{
fq_flush_iotlb
(
cookie
);
fq_ring_free
(
cookie
,
fq
);
}
idx
=
fq_ring_add
(
fq
);
fq
->
entries
[
idx
].
iova_pfn
=
pfn
;
fq
->
entries
[
idx
].
pages
=
pages
;
fq
->
entries
[
idx
].
counter
=
atomic64_read
(
&
cookie
->
fq_flush_start_cnt
);
list_splice
(
freelist
,
&
fq
->
entries
[
idx
].
freelist
);
spin_unlock_irqrestore
(
&
fq
->
lock
,
flags
);
/* Avoid false sharing as much as possible. */
if
(
!
atomic_read
(
&
cookie
->
fq_timer_on
)
&&
!
atomic_xchg
(
&
cookie
->
fq_timer_on
,
1
))
mod_timer
(
&
cookie
->
fq_timer
,
jiffies
+
msecs_to_jiffies
(
IOVA_FQ_TIMEOUT
));
}
static
void
iommu_dma_free_fq
(
struct
iommu_dma_cookie
*
cookie
)
{
int
cpu
,
idx
;
if
(
!
cookie
->
fq
)
return
;
del_timer_sync
(
&
cookie
->
fq_timer
);
/* The IOVAs will be torn down separately, so just free our queued pages */
for_each_possible_cpu
(
cpu
)
{
struct
iova_fq
*
fq
=
per_cpu_ptr
(
cookie
->
fq
,
cpu
);
fq_ring_for_each
(
idx
,
fq
)
put_pages_list
(
&
fq
->
entries
[
idx
].
freelist
);
}
free_percpu
(
cookie
->
fq
);
}
/* sysfs updates are serialised by the mutex of the group owning @domain */
int
iommu_dma_init_fq
(
struct
iommu_domain
*
domain
)
{
struct
iommu_dma_cookie
*
cookie
=
domain
->
iova_cookie
;
struct
iova_fq
__percpu
*
queue
;
int
i
,
cpu
;
if
(
cookie
->
fq_domain
)
return
0
;
atomic64_set
(
&
cookie
->
fq_flush_start_cnt
,
0
);
atomic64_set
(
&
cookie
->
fq_flush_finish_cnt
,
0
);
queue
=
alloc_percpu
(
struct
iova_fq
);
if
(
!
queue
)
{
pr_warn
(
"iova flush queue initialization failed
\n
"
);
return
-
ENOMEM
;
}
for_each_possible_cpu
(
cpu
)
{
struct
iova_fq
*
fq
=
per_cpu_ptr
(
queue
,
cpu
);
fq
->
head
=
0
;
fq
->
tail
=
0
;
spin_lock_init
(
&
fq
->
lock
);
for
(
i
=
0
;
i
<
IOVA_FQ_SIZE
;
i
++
)
INIT_LIST_HEAD
(
&
fq
->
entries
[
i
].
freelist
);
}
cookie
->
fq
=
queue
;
timer_setup
(
&
cookie
->
fq_timer
,
fq_flush_timeout
,
0
);
atomic_set
(
&
cookie
->
fq_timer_on
,
0
);
/*
* Prevent incomplete fq state being observable. Pairs with path from
* __iommu_dma_unmap() through iommu_dma_free_iova() to queue_iova()
*/
smp_wmb
();
WRITE_ONCE
(
cookie
->
fq_domain
,
domain
);
return
0
;
}
static
inline
size_t
cookie_msi_granule
(
struct
iommu_dma_cookie
*
cookie
)
...
...
@@ -156,8 +357,10 @@ void iommu_put_dma_cookie(struct iommu_domain *domain)
if
(
!
cookie
)
return
;
if
(
cookie
->
type
==
IOMMU_DMA_IOVA_COOKIE
&&
cookie
->
iovad
.
granule
)
if
(
cookie
->
type
==
IOMMU_DMA_IOVA_COOKIE
&&
cookie
->
iovad
.
granule
)
{
iommu_dma_free_fq
(
cookie
);
put_iova_domain
(
&
cookie
->
iovad
);
}
list_for_each_entry_safe
(
msi
,
tmp
,
&
cookie
->
msi_page_list
,
list
)
{
list_del
(
&
msi
->
list
);
...
...
@@ -294,17 +497,6 @@ static int iova_reserve_iommu_regions(struct device *dev,
return
ret
;
}
static
void
iommu_dma_flush_iotlb_all
(
struct
iova_domain
*
iovad
)
{
struct
iommu_dma_cookie
*
cookie
;
struct
iommu_domain
*
domain
;
cookie
=
container_of
(
iovad
,
struct
iommu_dma_cookie
,
iovad
);
domain
=
cookie
->
fq_domain
;
domain
->
ops
->
flush_iotlb_all
(
domain
);
}
static
bool
dev_is_untrusted
(
struct
device
*
dev
)
{
return
dev_is_pci
(
dev
)
&&
to_pci_dev
(
dev
)
->
untrusted
;
...
...
@@ -315,30 +507,6 @@ static bool dev_use_swiotlb(struct device *dev)
return
IS_ENABLED
(
CONFIG_SWIOTLB
)
&&
dev_is_untrusted
(
dev
);
}
/* sysfs updates are serialised by the mutex of the group owning @domain */
int
iommu_dma_init_fq
(
struct
iommu_domain
*
domain
)
{
struct
iommu_dma_cookie
*
cookie
=
domain
->
iova_cookie
;
int
ret
;
if
(
cookie
->
fq_domain
)
return
0
;
ret
=
init_iova_flush_queue
(
&
cookie
->
iovad
,
iommu_dma_flush_iotlb_all
,
iommu_dma_entry_dtor
);
if
(
ret
)
{
pr_warn
(
"iova flush queue initialization failed
\n
"
);
return
ret
;
}
/*
* Prevent incomplete iovad->fq being observable. Pairs with path from
* __iommu_dma_unmap() through iommu_dma_free_iova() to queue_iova()
*/
smp_wmb
();
WRITE_ONCE
(
cookie
->
fq_domain
,
domain
);
return
0
;
}
/**
* iommu_dma_init_domain - Initialise a DMA mapping domain
* @domain: IOMMU domain previously prepared by iommu_get_dma_cookie()
...
...
@@ -442,14 +610,6 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
shift
=
iova_shift
(
iovad
);
iova_len
=
size
>>
shift
;
/*
* Freeing non-power-of-two-sized allocations back into the IOVA caches
* will come back to bite us badly, so we have to waste a bit of space
* rounding up anything cacheable to make sure that can't happen. The
* order of the unadjusted size will still match upon freeing.
*/
if
(
iova_len
<
(
1
<<
(
IOVA_RANGE_CACHE_MAX_SIZE
-
1
)))
iova_len
=
roundup_pow_of_two
(
iova_len
);
dma_limit
=
min_not_zero
(
dma_limit
,
dev
->
bus_dma_limit
);
...
...
@@ -477,9 +637,9 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie,
if
(
cookie
->
type
==
IOMMU_DMA_MSI_COOKIE
)
cookie
->
msi_iova
-=
size
;
else
if
(
gather
&&
gather
->
queued
)
queue_iova
(
iovad
,
iova_pfn
(
iovad
,
iova
),
queue_iova
(
cookie
,
iova_pfn
(
iovad
,
iova
),
size
>>
iova_shift
(
iovad
),
(
unsigned
long
)
gather
->
freelist
);
&
gather
->
freelist
);
else
free_iova_fast
(
iovad
,
iova_pfn
(
iovad
,
iova
),
size
>>
iova_shift
(
iovad
));
...
...
drivers/iommu/intel/iommu.c
View file @
66dc1b79
...
...
@@ -133,11 +133,6 @@ static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
are never going to work. */
static
inline
unsigned
long
dma_to_mm_pfn
(
unsigned
long
dma_pfn
)
{
return
dma_pfn
>>
(
PAGE_SHIFT
-
VTD_PAGE_SHIFT
);
}
static
inline
unsigned
long
mm_to_dma_pfn
(
unsigned
long
mm_pfn
)
{
return
mm_pfn
<<
(
PAGE_SHIFT
-
VTD_PAGE_SHIFT
);
...
...
@@ -1280,10 +1275,6 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
unsigned
long
last_pfn
,
int
retain_level
)
{
BUG_ON
(
!
domain_pfn_supported
(
domain
,
start_pfn
));
BUG_ON
(
!
domain_pfn_supported
(
domain
,
last_pfn
));
BUG_ON
(
start_pfn
>
last_pfn
);
dma_pte_clear_range
(
domain
,
start_pfn
,
last_pfn
);
/* We don't need lock here; nobody else touches the iova range */
...
...
@@ -1303,35 +1294,30 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
know the hardware page-walk will no longer touch them.
The 'pte' argument is the *parent* PTE, pointing to the page that is to
be freed. */
static
struct
page
*
dma_pte_list_pagetables
(
struct
dmar_domain
*
domain
,
int
level
,
struct
dma_pte
*
pte
,
struct
page
*
freelist
)
static
void
dma_pte_list_pagetables
(
struct
dmar_domain
*
domain
,
int
level
,
struct
dma_pte
*
pte
,
struct
list_head
*
freelist
)
{
struct
page
*
pg
;
pg
=
pfn_to_page
(
dma_pte_addr
(
pte
)
>>
PAGE_SHIFT
);
pg
->
freelist
=
freelist
;
freelist
=
pg
;
list_add_tail
(
&
pg
->
lru
,
freelist
);
if
(
level
==
1
)
return
freelist
;
return
;
pte
=
page_address
(
pg
);
do
{
if
(
dma_pte_present
(
pte
)
&&
!
dma_pte_superpage
(
pte
))
freelist
=
dma_pte_list_pagetables
(
domain
,
level
-
1
,
pte
,
freelist
);
dma_pte_list_pagetables
(
domain
,
level
-
1
,
pte
,
freelist
);
pte
++
;
}
while
(
!
first_pte_in_page
(
pte
));
return
freelist
;
}
static
struct
page
*
dma_pte_clear_level
(
struct
dmar_domain
*
domain
,
int
level
,
struct
dma_pte
*
pte
,
unsigned
long
pfn
,
unsigned
long
start_pfn
,
unsigned
long
last_pfn
,
struct
page
*
freelist
)
static
void
dma_pte_clear_level
(
struct
dmar_domain
*
domain
,
int
level
,
struct
dma_pte
*
pte
,
unsigned
long
pfn
,
unsigned
long
start_pfn
,
unsigned
long
last_pfn
,
struct
list_head
*
freelist
)
{
struct
dma_pte
*
first_pte
=
NULL
,
*
last_pte
=
NULL
;
...
...
@@ -1350,7 +1336,7 @@ static struct page *dma_pte_clear_level(struct dmar_domain *domain, int level,
/* These suborbinate page tables are going away entirely. Don't
bother to clear them; we're just going to *free* them. */
if
(
level
>
1
&&
!
dma_pte_superpage
(
pte
))
freelist
=
dma_pte_list_pagetables
(
domain
,
level
-
1
,
pte
,
freelist
);
dma_pte_list_pagetables
(
domain
,
level
-
1
,
pte
,
freelist
);
dma_clear_pte
(
pte
);
if
(
!
first_pte
)
...
...
@@ -1358,10 +1344,10 @@ static struct page *dma_pte_clear_level(struct dmar_domain *domain, int level,
last_pte
=
pte
;
}
else
if
(
level
>
1
)
{
/* Recurse down into a level that isn't *entirely* obsolete */
freelist
=
dma_pte_clear_level
(
domain
,
level
-
1
,
phys_to_virt
(
dma_pte_addr
(
pte
)),
level_pfn
,
start_pfn
,
last_pfn
,
freelist
);
dma_pte_clear_level
(
domain
,
level
-
1
,
phys_to_virt
(
dma_pte_addr
(
pte
)),
level_pfn
,
start_pfn
,
last_pfn
,
freelist
);
}
next:
pfn
=
level_pfn
+
level_size
(
level
);
...
...
@@ -1370,47 +1356,28 @@ static struct page *dma_pte_clear_level(struct dmar_domain *domain, int level,
if
(
first_pte
)
domain_flush_cache
(
domain
,
first_pte
,
(
void
*
)
++
last_pte
-
(
void
*
)
first_pte
);
return
freelist
;
}
/* We can't just free the pages because the IOMMU may still be walking
the page tables, and may have cached the intermediate levels. The
pages can only be freed after the IOTLB flush has been done. */
static
struct
page
*
domain_unmap
(
struct
dmar_domain
*
domain
,
unsigned
long
start_pfn
,
unsigned
long
last_pfn
,
struct
page
*
freelist
)
static
void
domain_unmap
(
struct
dmar_domain
*
domain
,
unsigned
long
start_pfn
,
unsigned
long
last_pfn
,
struct
list_head
*
freelist
)
{
BUG_ON
(
!
domain_pfn_supported
(
domain
,
start_pfn
));
BUG_ON
(
!
domain_pfn_supported
(
domain
,
last_pfn
));
BUG_ON
(
start_pfn
>
last_pfn
);
/* we don't need lock here; nobody else touches the iova range */
freelist
=
dma_pte_clear_level
(
domain
,
agaw_to_level
(
domain
->
agaw
),
domain
->
pgd
,
0
,
start_pfn
,
last_pfn
,
freelist
);
dma_pte_clear_level
(
domain
,
agaw_to_level
(
domain
->
agaw
),
domain
->
pgd
,
0
,
start_pfn
,
last_pfn
,
freelist
);
/* free pgd */
if
(
start_pfn
==
0
&&
last_pfn
==
DOMAIN_MAX_PFN
(
domain
->
gaw
))
{
struct
page
*
pgd_page
=
virt_to_page
(
domain
->
pgd
);
pgd_page
->
freelist
=
freelist
;
freelist
=
pgd_page
;
list_add_tail
(
&
pgd_page
->
lru
,
freelist
);
domain
->
pgd
=
NULL
;
}
return
freelist
;
}
static
void
dma_free_pagelist
(
struct
page
*
freelist
)
{
struct
page
*
pg
;
while
((
pg
=
freelist
))
{
freelist
=
pg
->
freelist
;
free_pgtable_page
(
page_address
(
pg
));
}
}
/* iommu handling */
...
...
@@ -1878,17 +1845,16 @@ static void iommu_disable_translation(struct intel_iommu *iommu)
static
int
iommu_init_domains
(
struct
intel_iommu
*
iommu
)
{
u32
ndomains
,
nlongs
;
u32
ndomains
;
size_t
size
;
ndomains
=
cap_ndoms
(
iommu
->
cap
);
pr_debug
(
"%s: Number of Domains supported <%d>
\n
"
,
iommu
->
name
,
ndomains
);
nlongs
=
BITS_TO_LONGS
(
ndomains
);
spin_lock_init
(
&
iommu
->
lock
);
iommu
->
domain_ids
=
kcalloc
(
nlongs
,
sizeof
(
unsigned
long
)
,
GFP_KERNEL
);
iommu
->
domain_ids
=
bitmap_zalloc
(
ndomains
,
GFP_KERNEL
);
if
(
!
iommu
->
domain_ids
)
return
-
ENOMEM
;
...
...
@@ -1903,7 +1869,7 @@ static int iommu_init_domains(struct intel_iommu *iommu)
if
(
!
iommu
->
domains
||
!
iommu
->
domains
[
0
])
{
pr_err
(
"%s: Allocating domain array failed
\n
"
,
iommu
->
name
);
k
free
(
iommu
->
domain_ids
);
bitmap_
free
(
iommu
->
domain_ids
);
kfree
(
iommu
->
domains
);
iommu
->
domain_ids
=
NULL
;
iommu
->
domains
=
NULL
;
...
...
@@ -1964,7 +1930,7 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
for
(
i
=
0
;
i
<
elems
;
i
++
)
kfree
(
iommu
->
domains
[
i
]);
kfree
(
iommu
->
domains
);
k
free
(
iommu
->
domain_ids
);
bitmap_
free
(
iommu
->
domain_ids
);
iommu
->
domains
=
NULL
;
iommu
->
domain_ids
=
NULL
;
}
...
...
@@ -2095,11 +2061,10 @@ static void domain_exit(struct dmar_domain *domain)
domain_remove_dev_info
(
domain
);
if
(
domain
->
pgd
)
{
struct
page
*
freelist
;
LIST_HEAD
(
freelist
)
;
freelist
=
domain_unmap
(
domain
,
0
,
DOMAIN_MAX_PFN
(
domain
->
gaw
),
NULL
);
dma_free_pagelist
(
freelist
);
domain_unmap
(
domain
,
0
,
DOMAIN_MAX_PFN
(
domain
->
gaw
),
&
freelist
);
put_pages_list
(
&
freelist
);
}
free_domain_mem
(
domain
);
...
...
@@ -2112,10 +2077,10 @@ static void domain_exit(struct dmar_domain *domain)
*/
static
inline
unsigned
long
context_get_sm_pds
(
struct
pasid_table
*
table
)
{
int
pds
,
max_pde
;
unsigned
long
pds
,
max_pde
;
max_pde
=
table
->
max_pasid
>>
PASID_PDE_SHIFT
;
pds
=
find_first_bit
(
(
unsigned
long
*
)
&
max_pde
,
MAX_NR_PASID_BITS
);
pds
=
find_first_bit
(
&
max_pde
,
MAX_NR_PASID_BITS
);
if
(
pds
<
7
)
return
0
;
...
...
@@ -4192,19 +4157,17 @@ static int intel_iommu_memory_notifier(struct notifier_block *nb,
{
struct
dmar_drhd_unit
*
drhd
;
struct
intel_iommu
*
iommu
;
struct
page
*
freelist
;
LIST_HEAD
(
freelist
)
;
freelist
=
domain_unmap
(
si_domain
,
start_vpfn
,
last_vpfn
,
NULL
);
domain_unmap
(
si_domain
,
start_vpfn
,
last_vpfn
,
&
freelist
);
rcu_read_lock
();
for_each_active_iommu
(
iommu
,
drhd
)
iommu_flush_iotlb_psi
(
iommu
,
si_domain
,
start_vpfn
,
mhp
->
nr_pages
,
!
freelist
,
0
);
list_empty
(
&
freelist
)
,
0
);
rcu_read_unlock
();
dma_free_pagelist
(
freelist
);
put_pages_list
(
&
freelist
);
}
break
;
}
...
...
@@ -5211,8 +5174,7 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain,
start_pfn
=
iova
>>
VTD_PAGE_SHIFT
;
last_pfn
=
(
iova
+
size
-
1
)
>>
VTD_PAGE_SHIFT
;
gather
->
freelist
=
domain_unmap
(
dmar_domain
,
start_pfn
,
last_pfn
,
gather
->
freelist
);
domain_unmap
(
dmar_domain
,
start_pfn
,
last_pfn
,
&
gather
->
freelist
);
if
(
dmar_domain
->
max_addr
==
iova
+
size
)
dmar_domain
->
max_addr
=
iova
;
...
...
@@ -5248,9 +5210,10 @@ static void intel_iommu_tlb_sync(struct iommu_domain *domain,
for_each_domain_iommu
(
iommu_id
,
dmar_domain
)
iommu_flush_iotlb_psi
(
g_iommus
[
iommu_id
],
dmar_domain
,
start_pfn
,
nrpages
,
!
gather
->
freelist
,
0
);
start_pfn
,
nrpages
,
list_empty
(
&
gather
->
freelist
),
0
);
dma_free_pagelist
(
gather
->
freelist
);
put_pages_list
(
&
gather
->
freelist
);
}
static
phys_addr_t
intel_iommu_iova_to_phys
(
struct
iommu_domain
*
domain
,
...
...
drivers/iommu/io-pgtable-arm-v7s.c
View file @
66dc1b79
...
...
@@ -246,13 +246,17 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp,
__GFP_ZERO
|
ARM_V7S_TABLE_GFP_DMA
,
get_order
(
size
));
else
if
(
lvl
==
2
)
table
=
kmem_cache_zalloc
(
data
->
l2_tables
,
gfp
);
if
(
!
table
)
return
NULL
;
phys
=
virt_to_phys
(
table
);
if
(
phys
!=
(
arm_v7s_iopte
)
phys
)
{
/* Doesn't fit in PTE */
dev_err
(
dev
,
"Page table does not fit in PTE: %pa"
,
&
phys
);
goto
out_free
;
}
if
(
table
&&
!
cfg
->
coherent_walk
)
{
if
(
!
cfg
->
coherent_walk
)
{
dma
=
dma_map_single
(
dev
,
table
,
size
,
DMA_TO_DEVICE
);
if
(
dma_mapping_error
(
dev
,
dma
))
goto
out_free
;
...
...
drivers/iommu/io-pgtable-arm.c
View file @
66dc1b79
...
...
@@ -315,11 +315,12 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data,
static
arm_lpae_iopte
arm_lpae_install_table
(
arm_lpae_iopte
*
table
,
arm_lpae_iopte
*
ptep
,
arm_lpae_iopte
curr
,
struct
io_pgtable_cfg
*
cfg
)
struct
arm_lpae_io_pgtable
*
data
)
{
arm_lpae_iopte
old
,
new
;
struct
io_pgtable_cfg
*
cfg
=
&
data
->
iop
.
cfg
;
new
=
__pa
(
table
)
|
ARM_LPAE_PTE_TYPE_TABLE
;
new
=
paddr_to_iopte
(
__pa
(
table
),
data
)
|
ARM_LPAE_PTE_TYPE_TABLE
;
if
(
cfg
->
quirks
&
IO_PGTABLE_QUIRK_ARM_NS
)
new
|=
ARM_LPAE_PTE_NSTABLE
;
...
...
@@ -380,7 +381,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
if
(
!
cptep
)
return
-
ENOMEM
;
pte
=
arm_lpae_install_table
(
cptep
,
ptep
,
0
,
cfg
);
pte
=
arm_lpae_install_table
(
cptep
,
ptep
,
0
,
data
);
if
(
pte
)
__arm_lpae_free_pages
(
cptep
,
tblsz
,
cfg
);
}
else
if
(
!
cfg
->
coherent_walk
&&
!
(
pte
&
ARM_LPAE_PTE_SW_SYNC
))
{
...
...
@@ -592,7 +593,7 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
__arm_lpae_init_pte
(
data
,
blk_paddr
,
pte
,
lvl
,
1
,
&
tablep
[
i
]);
}
pte
=
arm_lpae_install_table
(
tablep
,
ptep
,
blk_pte
,
cfg
);
pte
=
arm_lpae_install_table
(
tablep
,
ptep
,
blk_pte
,
data
);
if
(
pte
!=
blk_pte
)
{
__arm_lpae_free_pages
(
tablep
,
tablesz
,
cfg
);
/*
...
...
drivers/iommu/iommu.c
View file @
66dc1b79
...
...
@@ -288,11 +288,11 @@ int iommu_probe_device(struct device *dev)
*/
mutex_lock
(
&
group
->
mutex
);
iommu_alloc_default_domain
(
group
,
dev
);
mutex_unlock
(
&
group
->
mutex
);
if
(
group
->
default_domain
)
{
ret
=
__iommu_attach_device
(
group
->
default_domain
,
dev
);
if
(
ret
)
{
mutex_unlock
(
&
group
->
mutex
);
iommu_group_put
(
group
);
goto
err_release
;
}
...
...
@@ -300,6 +300,7 @@ int iommu_probe_device(struct device *dev)
iommu_create_device_direct_mappings
(
group
,
dev
);
mutex_unlock
(
&
group
->
mutex
);
iommu_group_put
(
group
);
if
(
ops
->
probe_finalize
)
...
...
drivers/iommu/iova.c
View file @
66dc1b79
...
...
@@ -24,8 +24,6 @@ static unsigned long iova_rcache_get(struct iova_domain *iovad,
static
void
init_iova_rcaches
(
struct
iova_domain
*
iovad
);
static
void
free_cpu_cached_iovas
(
unsigned
int
cpu
,
struct
iova_domain
*
iovad
);
static
void
free_iova_rcaches
(
struct
iova_domain
*
iovad
);
static
void
fq_destroy_all_entries
(
struct
iova_domain
*
iovad
);
static
void
fq_flush_timeout
(
struct
timer_list
*
t
);
static
int
iova_cpuhp_dead
(
unsigned
int
cpu
,
struct
hlist_node
*
node
)
{
...
...
@@ -63,8 +61,6 @@ init_iova_domain(struct iova_domain *iovad, unsigned long granule,
iovad
->
start_pfn
=
start_pfn
;
iovad
->
dma_32bit_pfn
=
1UL
<<
(
32
-
iova_shift
(
iovad
));
iovad
->
max32_alloc_size
=
iovad
->
dma_32bit_pfn
;
iovad
->
flush_cb
=
NULL
;
iovad
->
fq
=
NULL
;
iovad
->
anchor
.
pfn_lo
=
iovad
->
anchor
.
pfn_hi
=
IOVA_ANCHOR
;
rb_link_node
(
&
iovad
->
anchor
.
node
,
NULL
,
&
iovad
->
rbroot
.
rb_node
);
rb_insert_color
(
&
iovad
->
anchor
.
node
,
&
iovad
->
rbroot
);
...
...
@@ -73,62 +69,6 @@ init_iova_domain(struct iova_domain *iovad, unsigned long granule,
}
EXPORT_SYMBOL_GPL
(
init_iova_domain
);
static
bool
has_iova_flush_queue
(
struct
iova_domain
*
iovad
)
{
return
!!
iovad
->
fq
;
}
static
void
free_iova_flush_queue
(
struct
iova_domain
*
iovad
)
{
if
(
!
has_iova_flush_queue
(
iovad
))
return
;
if
(
timer_pending
(
&
iovad
->
fq_timer
))
del_timer
(
&
iovad
->
fq_timer
);
fq_destroy_all_entries
(
iovad
);
free_percpu
(
iovad
->
fq
);
iovad
->
fq
=
NULL
;
iovad
->
flush_cb
=
NULL
;
iovad
->
entry_dtor
=
NULL
;
}
int
init_iova_flush_queue
(
struct
iova_domain
*
iovad
,
iova_flush_cb
flush_cb
,
iova_entry_dtor
entry_dtor
)
{
struct
iova_fq
__percpu
*
queue
;
int
cpu
;
atomic64_set
(
&
iovad
->
fq_flush_start_cnt
,
0
);
atomic64_set
(
&
iovad
->
fq_flush_finish_cnt
,
0
);
queue
=
alloc_percpu
(
struct
iova_fq
);
if
(
!
queue
)
return
-
ENOMEM
;
iovad
->
flush_cb
=
flush_cb
;
iovad
->
entry_dtor
=
entry_dtor
;
for_each_possible_cpu
(
cpu
)
{
struct
iova_fq
*
fq
;
fq
=
per_cpu_ptr
(
queue
,
cpu
);
fq
->
head
=
0
;
fq
->
tail
=
0
;
spin_lock_init
(
&
fq
->
lock
);
}
iovad
->
fq
=
queue
;
timer_setup
(
&
iovad
->
fq_timer
,
fq_flush_timeout
,
0
);
atomic_set
(
&
iovad
->
fq_timer_on
,
0
);
return
0
;
}
static
struct
rb_node
*
__get_cached_rbnode
(
struct
iova_domain
*
iovad
,
unsigned
long
limit_pfn
)
{
...
...
@@ -497,6 +437,15 @@ alloc_iova_fast(struct iova_domain *iovad, unsigned long size,
unsigned
long
iova_pfn
;
struct
iova
*
new_iova
;
/*
* Freeing non-power-of-two-sized allocations back into the IOVA caches
* will come back to bite us badly, so we have to waste a bit of space
* rounding up anything cacheable to make sure that can't happen. The
* order of the unadjusted size will still match upon freeing.
*/
if
(
size
<
(
1
<<
(
IOVA_RANGE_CACHE_MAX_SIZE
-
1
)))
size
=
roundup_pow_of_two
(
size
);
iova_pfn
=
iova_rcache_get
(
iovad
,
size
,
limit_pfn
+
1
);
if
(
iova_pfn
)
return
iova_pfn
;
...
...
@@ -539,144 +488,6 @@ free_iova_fast(struct iova_domain *iovad, unsigned long pfn, unsigned long size)
}
EXPORT_SYMBOL_GPL
(
free_iova_fast
);
#define fq_ring_for_each(i, fq) \
for ((i) = (fq)->head; (i) != (fq)->tail; (i) = ((i) + 1) % IOVA_FQ_SIZE)
static
inline
bool
fq_full
(
struct
iova_fq
*
fq
)
{
assert_spin_locked
(
&
fq
->
lock
);
return
(((
fq
->
tail
+
1
)
%
IOVA_FQ_SIZE
)
==
fq
->
head
);
}
static
inline
unsigned
fq_ring_add
(
struct
iova_fq
*
fq
)
{
unsigned
idx
=
fq
->
tail
;
assert_spin_locked
(
&
fq
->
lock
);
fq
->
tail
=
(
idx
+
1
)
%
IOVA_FQ_SIZE
;
return
idx
;
}
static
void
fq_ring_free
(
struct
iova_domain
*
iovad
,
struct
iova_fq
*
fq
)
{
u64
counter
=
atomic64_read
(
&
iovad
->
fq_flush_finish_cnt
);
unsigned
idx
;
assert_spin_locked
(
&
fq
->
lock
);
fq_ring_for_each
(
idx
,
fq
)
{
if
(
fq
->
entries
[
idx
].
counter
>=
counter
)
break
;
if
(
iovad
->
entry_dtor
)
iovad
->
entry_dtor
(
fq
->
entries
[
idx
].
data
);
free_iova_fast
(
iovad
,
fq
->
entries
[
idx
].
iova_pfn
,
fq
->
entries
[
idx
].
pages
);
fq
->
head
=
(
fq
->
head
+
1
)
%
IOVA_FQ_SIZE
;
}
}
static
void
iova_domain_flush
(
struct
iova_domain
*
iovad
)
{
atomic64_inc
(
&
iovad
->
fq_flush_start_cnt
);
iovad
->
flush_cb
(
iovad
);
atomic64_inc
(
&
iovad
->
fq_flush_finish_cnt
);
}
static
void
fq_destroy_all_entries
(
struct
iova_domain
*
iovad
)
{
int
cpu
;
/*
* This code runs when the iova_domain is being detroyed, so don't
* bother to free iovas, just call the entry_dtor on all remaining
* entries.
*/
if
(
!
iovad
->
entry_dtor
)
return
;
for_each_possible_cpu
(
cpu
)
{
struct
iova_fq
*
fq
=
per_cpu_ptr
(
iovad
->
fq
,
cpu
);
int
idx
;
fq_ring_for_each
(
idx
,
fq
)
iovad
->
entry_dtor
(
fq
->
entries
[
idx
].
data
);
}
}
static
void
fq_flush_timeout
(
struct
timer_list
*
t
)
{
struct
iova_domain
*
iovad
=
from_timer
(
iovad
,
t
,
fq_timer
);
int
cpu
;
atomic_set
(
&
iovad
->
fq_timer_on
,
0
);
iova_domain_flush
(
iovad
);
for_each_possible_cpu
(
cpu
)
{
unsigned
long
flags
;
struct
iova_fq
*
fq
;
fq
=
per_cpu_ptr
(
iovad
->
fq
,
cpu
);
spin_lock_irqsave
(
&
fq
->
lock
,
flags
);
fq_ring_free
(
iovad
,
fq
);
spin_unlock_irqrestore
(
&
fq
->
lock
,
flags
);
}
}
void
queue_iova
(
struct
iova_domain
*
iovad
,
unsigned
long
pfn
,
unsigned
long
pages
,
unsigned
long
data
)
{
struct
iova_fq
*
fq
;
unsigned
long
flags
;
unsigned
idx
;
/*
* Order against the IOMMU driver's pagetable update from unmapping
* @pte, to guarantee that iova_domain_flush() observes that if called
* from a different CPU before we release the lock below. Full barrier
* so it also pairs with iommu_dma_init_fq() to avoid seeing partially
* written fq state here.
*/
smp_mb
();
fq
=
raw_cpu_ptr
(
iovad
->
fq
);
spin_lock_irqsave
(
&
fq
->
lock
,
flags
);
/*
* First remove all entries from the flush queue that have already been
* flushed out on another CPU. This makes the fq_full() check below less
* likely to be true.
*/
fq_ring_free
(
iovad
,
fq
);
if
(
fq_full
(
fq
))
{
iova_domain_flush
(
iovad
);
fq_ring_free
(
iovad
,
fq
);
}
idx
=
fq_ring_add
(
fq
);
fq
->
entries
[
idx
].
iova_pfn
=
pfn
;
fq
->
entries
[
idx
].
pages
=
pages
;
fq
->
entries
[
idx
].
data
=
data
;
fq
->
entries
[
idx
].
counter
=
atomic64_read
(
&
iovad
->
fq_flush_start_cnt
);
spin_unlock_irqrestore
(
&
fq
->
lock
,
flags
);
/* Avoid false sharing as much as possible. */
if
(
!
atomic_read
(
&
iovad
->
fq_timer_on
)
&&
!
atomic_xchg
(
&
iovad
->
fq_timer_on
,
1
))
mod_timer
(
&
iovad
->
fq_timer
,
jiffies
+
msecs_to_jiffies
(
IOVA_FQ_TIMEOUT
));
}
/**
* put_iova_domain - destroys the iova domain
* @iovad: - iova domain in question.
...
...
@@ -688,8 +499,6 @@ void put_iova_domain(struct iova_domain *iovad)
cpuhp_state_remove_instance_nocalls
(
CPUHP_IOMMU_IOVA_DEAD
,
&
iovad
->
cpuhp_dead
);
free_iova_flush_queue
(
iovad
);
free_iova_rcaches
(
iovad
);
rbtree_postorder_for_each_entry_safe
(
iova
,
tmp
,
&
iovad
->
rbroot
,
node
)
free_iova_mem
(
iova
);
...
...
drivers/iommu/virtio-iommu.c
View file @
66dc1b79
...
...
@@ -71,6 +71,7 @@ struct viommu_domain {
struct
rb_root_cached
mappings
;
unsigned
long
nr_endpoints
;
bool
bypass
;
};
struct
viommu_endpoint
{
...
...
@@ -310,8 +311,8 @@ static int viommu_send_req_sync(struct viommu_dev *viommu, void *buf,
*
* On success, return the new mapping. Otherwise return NULL.
*/
static
int
viommu_add_mapping
(
struct
viommu_domain
*
vdomain
,
u
nsigned
long
iova
,
phys_addr_t
paddr
,
size_t
size
,
u32
flags
)
static
int
viommu_add_mapping
(
struct
viommu_domain
*
vdomain
,
u
64
iova
,
u64
end
,
phys_addr_t
paddr
,
u32
flags
)
{
unsigned
long
irqflags
;
struct
viommu_mapping
*
mapping
;
...
...
@@ -322,7 +323,7 @@ static int viommu_add_mapping(struct viommu_domain *vdomain, unsigned long iova,
mapping
->
paddr
=
paddr
;
mapping
->
iova
.
start
=
iova
;
mapping
->
iova
.
last
=
iova
+
size
-
1
;
mapping
->
iova
.
last
=
end
;
mapping
->
flags
=
flags
;
spin_lock_irqsave
(
&
vdomain
->
mappings_lock
,
irqflags
);
...
...
@@ -337,26 +338,24 @@ static int viommu_add_mapping(struct viommu_domain *vdomain, unsigned long iova,
*
* @vdomain: the domain
* @iova: start of the range
* @size: size of the range. A size of 0 corresponds to the entire address
* space.
* @end: end of the range
*
* On success, returns the number of unmapped bytes
(>= size)
* On success, returns the number of unmapped bytes
*/
static
size_t
viommu_del_mappings
(
struct
viommu_domain
*
vdomain
,
u
nsigned
long
iova
,
size_t
size
)
u
64
iova
,
u64
end
)
{
size_t
unmapped
=
0
;
unsigned
long
flags
;
unsigned
long
last
=
iova
+
size
-
1
;
struct
viommu_mapping
*
mapping
=
NULL
;
struct
interval_tree_node
*
node
,
*
next
;
spin_lock_irqsave
(
&
vdomain
->
mappings_lock
,
flags
);
next
=
interval_tree_iter_first
(
&
vdomain
->
mappings
,
iova
,
last
);
next
=
interval_tree_iter_first
(
&
vdomain
->
mappings
,
iova
,
end
);
while
(
next
)
{
node
=
next
;
mapping
=
container_of
(
node
,
struct
viommu_mapping
,
iova
);
next
=
interval_tree_iter_next
(
node
,
iova
,
last
);
next
=
interval_tree_iter_next
(
node
,
iova
,
end
);
/* Trying to split a mapping? */
if
(
mapping
->
iova
.
start
<
iova
)
...
...
@@ -376,6 +375,55 @@ static size_t viommu_del_mappings(struct viommu_domain *vdomain,
return
unmapped
;
}
/*
* Fill the domain with identity mappings, skipping the device's reserved
* regions.
*/
static
int
viommu_domain_map_identity
(
struct
viommu_endpoint
*
vdev
,
struct
viommu_domain
*
vdomain
)
{
int
ret
;
struct
iommu_resv_region
*
resv
;
u64
iova
=
vdomain
->
domain
.
geometry
.
aperture_start
;
u64
limit
=
vdomain
->
domain
.
geometry
.
aperture_end
;
u32
flags
=
VIRTIO_IOMMU_MAP_F_READ
|
VIRTIO_IOMMU_MAP_F_WRITE
;
unsigned
long
granule
=
1UL
<<
__ffs
(
vdomain
->
domain
.
pgsize_bitmap
);
iova
=
ALIGN
(
iova
,
granule
);
limit
=
ALIGN_DOWN
(
limit
+
1
,
granule
)
-
1
;
list_for_each_entry
(
resv
,
&
vdev
->
resv_regions
,
list
)
{
u64
resv_start
=
ALIGN_DOWN
(
resv
->
start
,
granule
);
u64
resv_end
=
ALIGN
(
resv
->
start
+
resv
->
length
,
granule
)
-
1
;
if
(
resv_end
<
iova
||
resv_start
>
limit
)
/* No overlap */
continue
;
if
(
resv_start
>
iova
)
{
ret
=
viommu_add_mapping
(
vdomain
,
iova
,
resv_start
-
1
,
(
phys_addr_t
)
iova
,
flags
);
if
(
ret
)
goto
err_unmap
;
}
if
(
resv_end
>=
limit
)
return
0
;
iova
=
resv_end
+
1
;
}
ret
=
viommu_add_mapping
(
vdomain
,
iova
,
limit
,
(
phys_addr_t
)
iova
,
flags
);
if
(
ret
)
goto
err_unmap
;
return
0
;
err_unmap:
viommu_del_mappings
(
vdomain
,
0
,
iova
);
return
ret
;
}
/*
* viommu_replay_mappings - re-send MAP requests
*
...
...
@@ -422,7 +470,7 @@ static int viommu_add_resv_mem(struct viommu_endpoint *vdev,
size_t
size
;
u64
start64
,
end64
;
phys_addr_t
start
,
end
;
struct
iommu_resv_region
*
region
=
NULL
;
struct
iommu_resv_region
*
region
=
NULL
,
*
next
;
unsigned
long
prot
=
IOMMU_WRITE
|
IOMMU_NOEXEC
|
IOMMU_MMIO
;
start
=
start64
=
le64_to_cpu
(
mem
->
start
);
...
...
@@ -453,7 +501,12 @@ static int viommu_add_resv_mem(struct viommu_endpoint *vdev,
if
(
!
region
)
return
-
ENOMEM
;
list_add
(
&
region
->
list
,
&
vdev
->
resv_regions
);
/* Keep the list sorted */
list_for_each_entry
(
next
,
&
vdev
->
resv_regions
,
list
)
{
if
(
next
->
start
>
region
->
start
)
break
;
}
list_add_tail
(
&
region
->
list
,
&
next
->
list
);
return
0
;
}
...
...
@@ -587,7 +640,9 @@ static struct iommu_domain *viommu_domain_alloc(unsigned type)
{
struct
viommu_domain
*
vdomain
;
if
(
type
!=
IOMMU_DOMAIN_UNMANAGED
&&
type
!=
IOMMU_DOMAIN_DMA
)
if
(
type
!=
IOMMU_DOMAIN_UNMANAGED
&&
type
!=
IOMMU_DOMAIN_DMA
&&
type
!=
IOMMU_DOMAIN_IDENTITY
)
return
NULL
;
vdomain
=
kzalloc
(
sizeof
(
*
vdomain
),
GFP_KERNEL
);
...
...
@@ -630,6 +685,21 @@ static int viommu_domain_finalise(struct viommu_endpoint *vdev,
vdomain
->
map_flags
=
viommu
->
map_flags
;
vdomain
->
viommu
=
viommu
;
if
(
domain
->
type
==
IOMMU_DOMAIN_IDENTITY
)
{
if
(
virtio_has_feature
(
viommu
->
vdev
,
VIRTIO_IOMMU_F_BYPASS_CONFIG
))
{
vdomain
->
bypass
=
true
;
return
0
;
}
ret
=
viommu_domain_map_identity
(
vdev
,
vdomain
);
if
(
ret
)
{
ida_free
(
&
viommu
->
domain_ids
,
vdomain
->
id
);
vdomain
->
viommu
=
NULL
;
return
-
EOPNOTSUPP
;
}
}
return
0
;
}
...
...
@@ -637,8 +707,8 @@ static void viommu_domain_free(struct iommu_domain *domain)
{
struct
viommu_domain
*
vdomain
=
to_viommu_domain
(
domain
);
/* Free all remaining mappings
(size 2^64)
*/
viommu_del_mappings
(
vdomain
,
0
,
0
);
/* Free all remaining mappings */
viommu_del_mappings
(
vdomain
,
0
,
ULLONG_MAX
);
if
(
vdomain
->
viommu
)
ida_free
(
&
vdomain
->
viommu
->
domain_ids
,
vdomain
->
id
);
...
...
@@ -673,7 +743,7 @@ static int viommu_attach_dev(struct iommu_domain *domain, struct device *dev)
/*
* In the virtio-iommu device, when attaching the endpoint to a new
* domain, it is detached from the old one and, if as a
s a
result the
* domain, it is detached from the old one and, if as a result the
* old domain isn't attached to any endpoint, all mappings are removed
* from the old domain and it is freed.
*
...
...
@@ -691,6 +761,9 @@ static int viommu_attach_dev(struct iommu_domain *domain, struct device *dev)
.
domain
=
cpu_to_le32
(
vdomain
->
id
),
};
if
(
vdomain
->
bypass
)
req
.
flags
|=
cpu_to_le32
(
VIRTIO_IOMMU_ATTACH_F_BYPASS
);
for
(
i
=
0
;
i
<
fwspec
->
num_ids
;
i
++
)
{
req
.
endpoint
=
cpu_to_le32
(
fwspec
->
ids
[
i
]);
...
...
@@ -720,6 +793,7 @@ static int viommu_map(struct iommu_domain *domain, unsigned long iova,
{
int
ret
;
u32
flags
;
u64
end
=
iova
+
size
-
1
;
struct
virtio_iommu_req_map
map
;
struct
viommu_domain
*
vdomain
=
to_viommu_domain
(
domain
);
...
...
@@ -730,7 +804,7 @@ static int viommu_map(struct iommu_domain *domain, unsigned long iova,
if
(
flags
&
~
vdomain
->
map_flags
)
return
-
EINVAL
;
ret
=
viommu_add_mapping
(
vdomain
,
iova
,
paddr
,
size
,
flags
);
ret
=
viommu_add_mapping
(
vdomain
,
iova
,
end
,
paddr
,
flags
);
if
(
ret
)
return
ret
;
...
...
@@ -739,7 +813,7 @@ static int viommu_map(struct iommu_domain *domain, unsigned long iova,
.
domain
=
cpu_to_le32
(
vdomain
->
id
),
.
virt_start
=
cpu_to_le64
(
iova
),
.
phys_start
=
cpu_to_le64
(
paddr
),
.
virt_end
=
cpu_to_le64
(
iova
+
size
-
1
),
.
virt_end
=
cpu_to_le64
(
end
),
.
flags
=
cpu_to_le32
(
flags
),
};
...
...
@@ -748,7 +822,7 @@ static int viommu_map(struct iommu_domain *domain, unsigned long iova,
ret
=
viommu_send_req_sync
(
vdomain
->
viommu
,
&
map
,
sizeof
(
map
));
if
(
ret
)
viommu_del_mappings
(
vdomain
,
iova
,
size
);
viommu_del_mappings
(
vdomain
,
iova
,
end
);
return
ret
;
}
...
...
@@ -761,7 +835,7 @@ static size_t viommu_unmap(struct iommu_domain *domain, unsigned long iova,
struct
virtio_iommu_req_unmap
unmap
;
struct
viommu_domain
*
vdomain
=
to_viommu_domain
(
domain
);
unmapped
=
viommu_del_mappings
(
vdomain
,
iova
,
size
);
unmapped
=
viommu_del_mappings
(
vdomain
,
iova
,
iova
+
size
-
1
);
if
(
unmapped
<
size
)
return
0
;
...
...
@@ -1132,6 +1206,7 @@ static unsigned int features[] = {
VIRTIO_IOMMU_F_DOMAIN_RANGE
,
VIRTIO_IOMMU_F_PROBE
,
VIRTIO_IOMMU_F_MMIO
,
VIRTIO_IOMMU_F_BYPASS_CONFIG
,
};
static
struct
virtio_device_id
id_table
[]
=
{
...
...
drivers/vdpa/vdpa_user/iova_domain.c
View file @
66dc1b79
...
...
@@ -292,14 +292,6 @@ vduse_domain_alloc_iova(struct iova_domain *iovad,
unsigned
long
iova_len
=
iova_align
(
iovad
,
size
)
>>
shift
;
unsigned
long
iova_pfn
;
/*
* Freeing non-power-of-two-sized allocations back into the IOVA caches
* will come back to bite us badly, so we have to waste a bit of space
* rounding up anything cacheable to make sure that can't happen. The
* order of the unadjusted size will still match upon freeing.
*/
if
(
iova_len
<
(
1
<<
(
IOVA_RANGE_CACHE_MAX_SIZE
-
1
)))
iova_len
=
roundup_pow_of_two
(
iova_len
);
iova_pfn
=
alloc_iova_fast
(
iovad
,
iova_len
,
limit
>>
shift
,
true
);
return
iova_pfn
<<
shift
;
...
...
include/linux/intel-svm.h
View file @
66dc1b79
...
...
@@ -8,12 +8,6 @@
#ifndef __INTEL_SVM_H__
#define __INTEL_SVM_H__
/* Values for rxwp in fault_cb callback */
#define SVM_REQ_READ (1<<3)
#define SVM_REQ_WRITE (1<<2)
#define SVM_REQ_EXEC (1<<1)
#define SVM_REQ_PRIV (1<<0)
/* Page Request Queue depth */
#define PRQ_ORDER 2
#define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x20)
...
...
include/linux/iommu.h
View file @
66dc1b79
...
...
@@ -186,7 +186,7 @@ struct iommu_iotlb_gather {
unsigned
long
start
;
unsigned
long
end
;
size_t
pgsize
;
struct
page
*
freelist
;
struct
list_head
freelist
;
bool
queued
;
};
...
...
@@ -399,6 +399,7 @@ static inline void iommu_iotlb_gather_init(struct iommu_iotlb_gather *gather)
{
*
gather
=
(
struct
iommu_iotlb_gather
)
{
.
start
=
ULONG_MAX
,
.
freelist
=
LIST_HEAD_INIT
(
gather
->
freelist
),
};
}
...
...
include/linux/iova.h
View file @
66dc1b79
...
...
@@ -12,7 +12,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/rbtree.h>
#include <linux/atomic.h>
#include <linux/dma-mapping.h>
/* iova structure */
...
...
@@ -35,35 +34,6 @@ struct iova_rcache {
struct
iova_cpu_rcache
__percpu
*
cpu_rcaches
;
};
struct
iova_domain
;
/* Call-Back from IOVA code into IOMMU drivers */
typedef
void
(
*
iova_flush_cb
)(
struct
iova_domain
*
domain
);
/* Destructor for per-entry data */
typedef
void
(
*
iova_entry_dtor
)(
unsigned
long
data
);
/* Number of entries per Flush Queue */
#define IOVA_FQ_SIZE 256
/* Timeout (in ms) after which entries are flushed from the Flush-Queue */
#define IOVA_FQ_TIMEOUT 10
/* Flush Queue entry for defered flushing */
struct
iova_fq_entry
{
unsigned
long
iova_pfn
;
unsigned
long
pages
;
unsigned
long
data
;
u64
counter
;
/* Flush counter when this entrie was added */
};
/* Per-CPU Flush Queue structure */
struct
iova_fq
{
struct
iova_fq_entry
entries
[
IOVA_FQ_SIZE
];
unsigned
head
,
tail
;
spinlock_t
lock
;
};
/* holds all the iova translations for a domain */
struct
iova_domain
{
spinlock_t
iova_rbtree_lock
;
/* Lock to protect update of rbtree */
...
...
@@ -74,27 +44,9 @@ struct iova_domain {
unsigned
long
start_pfn
;
/* Lower limit for this domain */
unsigned
long
dma_32bit_pfn
;
unsigned
long
max32_alloc_size
;
/* Size of last failed allocation */
struct
iova_fq
__percpu
*
fq
;
/* Flush Queue */
atomic64_t
fq_flush_start_cnt
;
/* Number of TLB flushes that
have been started */
atomic64_t
fq_flush_finish_cnt
;
/* Number of TLB flushes that
have been finished */
struct
iova
anchor
;
/* rbtree lookup anchor */
struct
iova_rcache
rcaches
[
IOVA_RANGE_CACHE_MAX_SIZE
];
/* IOVA range caches */
iova_flush_cb
flush_cb
;
/* Call-Back function to flush IOMMU
TLBs */
iova_entry_dtor
entry_dtor
;
/* IOMMU driver specific destructor for
iova entry */
struct
timer_list
fq_timer
;
/* Timer to regularily empty the
flush-queues */
atomic_t
fq_timer_on
;
/* 1 when timer is active, 0
when not */
struct
iova_rcache
rcaches
[
IOVA_RANGE_CACHE_MAX_SIZE
];
/* IOVA range caches */
struct
hlist_node
cpuhp_dead
;
};
...
...
@@ -144,17 +96,12 @@ struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size,
bool
size_aligned
);
void
free_iova_fast
(
struct
iova_domain
*
iovad
,
unsigned
long
pfn
,
unsigned
long
size
);
void
queue_iova
(
struct
iova_domain
*
iovad
,
unsigned
long
pfn
,
unsigned
long
pages
,
unsigned
long
data
);
unsigned
long
alloc_iova_fast
(
struct
iova_domain
*
iovad
,
unsigned
long
size
,
unsigned
long
limit_pfn
,
bool
flush_rcache
);
struct
iova
*
reserve_iova
(
struct
iova_domain
*
iovad
,
unsigned
long
pfn_lo
,
unsigned
long
pfn_hi
);
void
init_iova_domain
(
struct
iova_domain
*
iovad
,
unsigned
long
granule
,
unsigned
long
start_pfn
);
int
init_iova_flush_queue
(
struct
iova_domain
*
iovad
,
iova_flush_cb
flush_cb
,
iova_entry_dtor
entry_dtor
);
struct
iova
*
find_iova
(
struct
iova_domain
*
iovad
,
unsigned
long
pfn
);
void
put_iova_domain
(
struct
iova_domain
*
iovad
);
#else
...
...
@@ -189,12 +136,6 @@ static inline void free_iova_fast(struct iova_domain *iovad,
{
}
static
inline
void
queue_iova
(
struct
iova_domain
*
iovad
,
unsigned
long
pfn
,
unsigned
long
pages
,
unsigned
long
data
)
{
}
static
inline
unsigned
long
alloc_iova_fast
(
struct
iova_domain
*
iovad
,
unsigned
long
size
,
unsigned
long
limit_pfn
,
...
...
@@ -216,13 +157,6 @@ static inline void init_iova_domain(struct iova_domain *iovad,
{
}
static
inline
int
init_iova_flush_queue
(
struct
iova_domain
*
iovad
,
iova_flush_cb
flush_cb
,
iova_entry_dtor
entry_dtor
)
{
return
-
ENODEV
;
}
static
inline
struct
iova
*
find_iova
(
struct
iova_domain
*
iovad
,
unsigned
long
pfn
)
{
...
...
include/trace/events/iommu.h
View file @
66dc1b79
...
...
@@ -101,8 +101,9 @@ TRACE_EVENT(map,
__entry
->
size
=
size
;
),
TP_printk
(
"IOMMU: iova=0x%016llx paddr=0x%016llx size=%zu"
,
__entry
->
iova
,
__entry
->
paddr
,
__entry
->
size
TP_printk
(
"IOMMU: iova=0x%016llx - 0x%016llx paddr=0x%016llx size=%zu"
,
__entry
->
iova
,
__entry
->
iova
+
__entry
->
size
,
__entry
->
paddr
,
__entry
->
size
)
);
...
...
@@ -124,8 +125,9 @@ TRACE_EVENT(unmap,
__entry
->
unmapped_size
=
unmapped_size
;
),
TP_printk
(
"IOMMU: iova=0x%016llx size=%zu unmapped_size=%zu"
,
__entry
->
iova
,
__entry
->
size
,
__entry
->
unmapped_size
TP_printk
(
"IOMMU: iova=0x%016llx - 0x%016llx size=%zu unmapped_size=%zu"
,
__entry
->
iova
,
__entry
->
iova
+
__entry
->
size
,
__entry
->
size
,
__entry
->
unmapped_size
)
);
...
...
include/uapi/linux/virtio_iommu.h
View file @
66dc1b79
...
...
@@ -16,6 +16,7 @@
#define VIRTIO_IOMMU_F_BYPASS 3
#define VIRTIO_IOMMU_F_PROBE 4
#define VIRTIO_IOMMU_F_MMIO 5
#define VIRTIO_IOMMU_F_BYPASS_CONFIG 6
struct
virtio_iommu_range_64
{
__le64
start
;
...
...
@@ -36,6 +37,8 @@ struct virtio_iommu_config {
struct
virtio_iommu_range_32
domain_range
;
/* Probe buffer size */
__le32
probe_size
;
__u8
bypass
;
__u8
reserved
[
3
];
};
/* Request types */
...
...
@@ -66,11 +69,14 @@ struct virtio_iommu_req_tail {
__u8
reserved
[
3
];
};
#define VIRTIO_IOMMU_ATTACH_F_BYPASS (1 << 0)
struct
virtio_iommu_req_attach
{
struct
virtio_iommu_req_head
head
;
__le32
domain
;
__le32
endpoint
;
__u8
reserved
[
8
];
__le32
flags
;
__u8
reserved
[
4
];
struct
virtio_iommu_req_tail
tail
;
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment