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
nexedi
linux
Commits
b364776a
Commit
b364776a
authored
Oct 20, 2008
by
David Woodhouse
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: drivers/pci/intel-iommu.c
parents
6da0b38f
6c8909b4
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
306 additions
and
199 deletions
+306
-199
MAINTAINERS
MAINTAINERS
+7
-0
arch/x86/kernel/amd_iommu_init.c
arch/x86/kernel/amd_iommu_init.c
+1
-1
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-dma.c
+0
-16
drivers/pci/dmar.c
drivers/pci/dmar.c
+87
-32
drivers/pci/intel-iommu.c
drivers/pci/intel-iommu.c
+129
-121
drivers/pci/quirks.c
drivers/pci/quirks.c
+14
-0
include/asm-x86/iommu.h
include/asm-x86/iommu.h
+4
-0
include/linux/dma_remapping.h
include/linux/dma_remapping.h
+13
-14
include/linux/intel-iommu.h
include/linux/intel-iommu.h
+51
-15
No files found.
MAINTAINERS
View file @
b364776a
...
...
@@ -2176,6 +2176,13 @@ M: maciej.sosnowski@intel.com
L: linux-kernel@vger.kernel.org
S: Supported
INTEL IOMMU (VT-d)
P: David Woodhouse
M: dwmw2@infradead.org
L: iommu@lists.linux-foundation.org
T: git://git.infradead.org/iommu-2.6.git
S: Supported
INTEL IOP-ADMA DMA DRIVER
P: Dan Williams
M: dan.j.williams@intel.com
...
...
arch/x86/kernel/amd_iommu_init.c
View file @
b364776a
...
...
@@ -212,7 +212,7 @@ static void __init iommu_set_exclusion_range(struct amd_iommu *iommu)
/* Programs the physical address of the device table into the IOMMU hardware */
static
void
__init
iommu_set_device_table
(
struct
amd_iommu
*
iommu
)
{
u
32
entry
;
u
64
entry
;
BUG_ON
(
iommu
->
mmio_base
==
NULL
);
...
...
arch/x86/kernel/pci-dma.c
View file @
b364776a
...
...
@@ -9,8 +9,6 @@
#include <asm/calgary.h>
#include <asm/amd_iommu.h>
static
int
forbid_dac
__read_mostly
;
struct
dma_mapping_ops
*
dma_ops
;
EXPORT_SYMBOL
(
dma_ops
);
...
...
@@ -293,17 +291,3 @@ void pci_iommu_shutdown(void)
}
/* Must execute after PCI subsystem */
fs_initcall
(
pci_iommu_init
);
#ifdef CONFIG_PCI
/* Many VIA bridges seem to corrupt data for DAC. Disable it here */
static
__devinit
void
via_no_dac
(
struct
pci_dev
*
dev
)
{
if
((
dev
->
class
>>
8
)
==
PCI_CLASS_BRIDGE_PCI
&&
forbid_dac
==
0
)
{
printk
(
KERN_INFO
"PCI: VIA PCI bridge detected."
"Disabling DAC.
\n
"
);
forbid_dac
=
1
;
}
}
DECLARE_PCI_FIXUP_FINAL
(
PCI_VENDOR_ID_VIA
,
PCI_ANY_ID
,
via_no_dac
);
#endif
drivers/pci/dmar.c
View file @
b364776a
...
...
@@ -188,12 +188,11 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
return
0
;
}
static
int
__init
dmar_parse_dev
(
struct
dmar_drhd_unit
*
dmaru
)
static
int
__init
dmar_parse_dev
(
struct
dmar_drhd_unit
*
dmaru
)
{
struct
acpi_dmar_hardware_unit
*
drhd
;
static
int
include_all
;
int
ret
;
int
ret
=
0
;
drhd
=
(
struct
acpi_dmar_hardware_unit
*
)
dmaru
->
hdr
;
...
...
@@ -277,14 +276,15 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
drhd
=
(
struct
acpi_dmar_hardware_unit
*
)
header
;
printk
(
KERN_INFO
PREFIX
"DRHD (flags: 0x%08x)base: 0x%016Lx
\n
"
,
drhd
->
flags
,
drhd
->
address
);
drhd
->
flags
,
(
unsigned
long
long
)
drhd
->
address
);
break
;
case
ACPI_DMAR_TYPE_RESERVED_MEMORY
:
rmrr
=
(
struct
acpi_dmar_reserved_memory
*
)
header
;
printk
(
KERN_INFO
PREFIX
"RMRR base: 0x%016Lx end: 0x%016Lx
\n
"
,
rmrr
->
base_address
,
rmrr
->
end_address
);
(
unsigned
long
long
)
rmrr
->
base_address
,
(
unsigned
long
long
)
rmrr
->
end_address
);
break
;
}
}
...
...
@@ -304,7 +304,7 @@ parse_dmar_table(void)
if
(
!
dmar
)
return
-
ENODEV
;
if
(
dmar
->
width
<
PAGE_SHIFT
_4K
-
1
)
{
if
(
dmar
->
width
<
PAGE_SHIFT
-
1
)
{
printk
(
KERN_WARNING
PREFIX
"Invalid DMAR haw
\n
"
);
return
-
EINVAL
;
}
...
...
@@ -455,8 +455,8 @@ void __init detect_intel_iommu(void)
ret
=
early_dmar_detect
();
#ifdef CONFIG_DMAR
{
#ifdef CONFIG_INTR_REMAP
struct
acpi_table_dmar
*
dmar
;
/*
* for now we will disable dma-remapping when interrupt
...
...
@@ -465,28 +465,18 @@ void __init detect_intel_iommu(void)
* is added, we will not need this any more.
*/
dmar
=
(
struct
acpi_table_dmar
*
)
dmar_tbl
;
if
(
ret
&&
cpu_has_x2apic
&&
dmar
->
flags
&
0x1
)
{
if
(
ret
&&
cpu_has_x2apic
&&
dmar
->
flags
&
0x1
)
printk
(
KERN_INFO
"Queued invalidation will be enabled to support "
"x2apic and Intr-remapping.
\n
"
);
printk
(
KERN_INFO
"Disabling IOMMU detection, because of missing "
"queued invalidation support for IOTLB "
"invalidation
\n
"
);
printk
(
KERN_INFO
"Use
\"
nox2apic
\"
, if you want to use Intel "
" IOMMU for DMA-remapping and don't care about "
" x2apic support
\n
"
);
dmar_disabled
=
1
;
return
;
}
#endif
#ifdef CONFIG_DMAR
if
(
ret
&&
!
no_iommu
&&
!
iommu_detected
&&
!
swiotlb
&&
!
dmar_disabled
)
iommu_detected
=
1
;
}
#endif
}
}
...
...
@@ -503,7 +493,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
iommu
->
seq_id
=
iommu_allocated
++
;
iommu
->
reg
=
ioremap
(
drhd
->
reg_base_addr
,
PAGE_SIZE_4K
);
iommu
->
reg
=
ioremap
(
drhd
->
reg_base_addr
,
VTD_PAGE_SIZE
);
if
(
!
iommu
->
reg
)
{
printk
(
KERN_ERR
"IOMMU: can't map the region
\n
"
);
goto
error
;
...
...
@@ -514,8 +504,8 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
/* the registers might be more than one page */
map_size
=
max_t
(
int
,
ecap_max_iotlb_offset
(
iommu
->
ecap
),
cap_max_fault_reg_offset
(
iommu
->
cap
));
map_size
=
PAGE_ALIGN_4K
(
map_size
);
if
(
map_size
>
PAGE_SIZE_4K
)
{
map_size
=
VTD_PAGE_ALIGN
(
map_size
);
if
(
map_size
>
VTD_PAGE_SIZE
)
{
iounmap
(
iommu
->
reg
);
iommu
->
reg
=
ioremap
(
drhd
->
reg_base_addr
,
map_size
);
if
(
!
iommu
->
reg
)
{
...
...
@@ -526,8 +516,10 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
ver
=
readl
(
iommu
->
reg
+
DMAR_VER_REG
);
pr_debug
(
"IOMMU %llx: ver %d:%d cap %llx ecap %llx
\n
"
,
drhd
->
reg_base_addr
,
DMAR_VER_MAJOR
(
ver
),
DMAR_VER_MINOR
(
ver
),
iommu
->
cap
,
iommu
->
ecap
);
(
unsigned
long
long
)
drhd
->
reg_base_addr
,
DMAR_VER_MAJOR
(
ver
),
DMAR_VER_MINOR
(
ver
),
(
unsigned
long
long
)
iommu
->
cap
,
(
unsigned
long
long
)
iommu
->
ecap
);
spin_lock_init
(
&
iommu
->
register_lock
);
...
...
@@ -580,11 +572,11 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
hw
=
qi
->
desc
;
spin_lock
(
&
qi
->
q_lock
);
spin_lock
_irqsave
(
&
qi
->
q_lock
,
flags
);
while
(
qi
->
free_cnt
<
3
)
{
spin_unlock
(
&
qi
->
q_lock
);
spin_unlock
_irqrestore
(
&
qi
->
q_lock
,
flags
);
cpu_relax
();
spin_lock
(
&
qi
->
q_lock
);
spin_lock
_irqsave
(
&
qi
->
q_lock
,
flags
);
}
index
=
qi
->
free_head
;
...
...
@@ -605,15 +597,22 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
qi
->
free_head
=
(
qi
->
free_head
+
2
)
%
QI_LENGTH
;
qi
->
free_cnt
-=
2
;
spin_lock
_irqsave
(
&
iommu
->
register_lock
,
flags
);
spin_lock
(
&
iommu
->
register_lock
);
/*
* update the HW tail register indicating the presence of
* new descriptors.
*/
writel
(
qi
->
free_head
<<
4
,
iommu
->
reg
+
DMAR_IQT_REG
);
spin_unlock
_irqrestore
(
&
iommu
->
register_lock
,
flags
);
spin_unlock
(
&
iommu
->
register_lock
);
while
(
qi
->
desc_status
[
wait_index
]
!=
QI_DONE
)
{
/*
* We will leave the interrupts disabled, to prevent interrupt
* context to queue another cmd while a cmd is already submitted
* and waiting for completion on this cpu. This is to avoid
* a deadlock where the interrupt context can wait indefinitely
* for free slots in the queue.
*/
spin_unlock
(
&
qi
->
q_lock
);
cpu_relax
();
spin_lock
(
&
qi
->
q_lock
);
...
...
@@ -622,7 +621,7 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
qi
->
desc_status
[
index
]
=
QI_DONE
;
reclaim_free_desc
(
qi
);
spin_unlock
(
&
qi
->
q_lock
);
spin_unlock
_irqrestore
(
&
qi
->
q_lock
,
flags
);
}
/*
...
...
@@ -638,6 +637,62 @@ void qi_global_iec(struct intel_iommu *iommu)
qi_submit_sync
(
&
desc
,
iommu
);
}
int
qi_flush_context
(
struct
intel_iommu
*
iommu
,
u16
did
,
u16
sid
,
u8
fm
,
u64
type
,
int
non_present_entry_flush
)
{
struct
qi_desc
desc
;
if
(
non_present_entry_flush
)
{
if
(
!
cap_caching_mode
(
iommu
->
cap
))
return
1
;
else
did
=
0
;
}
desc
.
low
=
QI_CC_FM
(
fm
)
|
QI_CC_SID
(
sid
)
|
QI_CC_DID
(
did
)
|
QI_CC_GRAN
(
type
)
|
QI_CC_TYPE
;
desc
.
high
=
0
;
qi_submit_sync
(
&
desc
,
iommu
);
return
0
;
}
int
qi_flush_iotlb
(
struct
intel_iommu
*
iommu
,
u16
did
,
u64
addr
,
unsigned
int
size_order
,
u64
type
,
int
non_present_entry_flush
)
{
u8
dw
=
0
,
dr
=
0
;
struct
qi_desc
desc
;
int
ih
=
0
;
if
(
non_present_entry_flush
)
{
if
(
!
cap_caching_mode
(
iommu
->
cap
))
return
1
;
else
did
=
0
;
}
if
(
cap_write_drain
(
iommu
->
cap
))
dw
=
1
;
if
(
cap_read_drain
(
iommu
->
cap
))
dr
=
1
;
desc
.
low
=
QI_IOTLB_DID
(
did
)
|
QI_IOTLB_DR
(
dr
)
|
QI_IOTLB_DW
(
dw
)
|
QI_IOTLB_GRAN
(
type
)
|
QI_IOTLB_TYPE
;
desc
.
high
=
QI_IOTLB_ADDR
(
addr
)
|
QI_IOTLB_IH
(
ih
)
|
QI_IOTLB_AM
(
size_order
);
qi_submit_sync
(
&
desc
,
iommu
);
return
0
;
}
/*
* Enable Queued Invalidation interface. This is a must to support
* interrupt-remapping. Also used by DMA-remapping, which replaces
...
...
drivers/pci/intel-iommu.c
View file @
b364776a
...
...
@@ -18,6 +18,7 @@
* Author: Ashok Raj <ashok.raj@intel.com>
* Author: Shaohua Li <shaohua.li@intel.com>
* Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
* Author: Fenghua Yu <fenghua.yu@intel.com>
*/
#include <linux/init.h>
...
...
@@ -35,11 +36,13 @@
#include <linux/timer.h>
#include <linux/iova.h>
#include <linux/intel-iommu.h>
#include <asm/proto.h>
/* force_iommu in this header in x86-64*/
#include <asm/cacheflush.h>
#include <asm/iommu.h>
#include "pci.h"
#define ROOT_SIZE VTD_PAGE_SIZE
#define CONTEXT_SIZE VTD_PAGE_SIZE
#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
...
...
@@ -199,7 +202,7 @@ static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
return
NULL
;
}
__iommu_flush_cache
(
iommu
,
(
void
*
)
context
,
PAGE_SIZE_4K
);
__iommu_flush_cache
(
iommu
,
(
void
*
)
context
,
CONTEXT_SIZE
);
phy_addr
=
virt_to_phys
((
void
*
)
context
);
set_root_value
(
root
,
phy_addr
);
set_root_present
(
root
);
...
...
@@ -345,7 +348,7 @@ static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
return
NULL
;
}
__iommu_flush_cache
(
domain
->
iommu
,
tmp_page
,
PAGE_SIZE
_4K
);
PAGE_SIZE
);
dma_set_pte_addr
(
*
pte
,
virt_to_phys
(
tmp_page
));
/*
* high level table always sets r/w, last level page
...
...
@@ -408,13 +411,13 @@ static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
start
&=
(((
u64
)
1
)
<<
addr_width
)
-
1
;
end
&=
(((
u64
)
1
)
<<
addr_width
)
-
1
;
/* in case it's partial page */
start
=
PAGE_ALIGN
_4K
(
start
);
end
&=
PAGE_MASK
_4K
;
start
=
PAGE_ALIGN
(
start
);
end
&=
PAGE_MASK
;
/* we don't need lock here, nobody else touches the iova range */
while
(
start
<
end
)
{
dma_pte_clear_one
(
domain
,
start
);
start
+=
PAGE_SIZE_4K
;
start
+=
VTD_PAGE_SIZE
;
}
}
...
...
@@ -468,7 +471,7 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu)
if
(
!
root
)
return
-
ENOMEM
;
__iommu_flush_cache
(
iommu
,
root
,
PAGE_SIZE_4K
);
__iommu_flush_cache
(
iommu
,
root
,
ROOT_SIZE
);
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
iommu
->
root_entry
=
root
;
...
...
@@ -567,27 +570,6 @@ static int __iommu_flush_context(struct intel_iommu *iommu,
return
0
;
}
static
int
inline
iommu_flush_context_global
(
struct
intel_iommu
*
iommu
,
int
non_present_entry_flush
)
{
return
__iommu_flush_context
(
iommu
,
0
,
0
,
0
,
DMA_CCMD_GLOBAL_INVL
,
non_present_entry_flush
);
}
static
int
inline
iommu_flush_context_domain
(
struct
intel_iommu
*
iommu
,
u16
did
,
int
non_present_entry_flush
)
{
return
__iommu_flush_context
(
iommu
,
did
,
0
,
0
,
DMA_CCMD_DOMAIN_INVL
,
non_present_entry_flush
);
}
static
int
inline
iommu_flush_context_device
(
struct
intel_iommu
*
iommu
,
u16
did
,
u16
source_id
,
u8
function_mask
,
int
non_present_entry_flush
)
{
return
__iommu_flush_context
(
iommu
,
did
,
source_id
,
function_mask
,
DMA_CCMD_DEVICE_INVL
,
non_present_entry_flush
);
}
/* return value determine if we need a write buffer flush */
static
int
__iommu_flush_iotlb
(
struct
intel_iommu
*
iommu
,
u16
did
,
u64
addr
,
unsigned
int
size_order
,
u64
type
,
...
...
@@ -655,37 +637,25 @@ static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
printk
(
KERN_ERR
"IOMMU: flush IOTLB failed
\n
"
);
if
(
DMA_TLB_IAIG
(
val
)
!=
DMA_TLB_IIRG
(
type
))
pr_debug
(
"IOMMU: tlb flush request %Lx, actual %Lx
\n
"
,
DMA_TLB_IIRG
(
type
),
DMA_TLB_IAIG
(
val
));
(
unsigned
long
long
)
DMA_TLB_IIRG
(
type
),
(
unsigned
long
long
)
DMA_TLB_IAIG
(
val
));
/* flush iotlb entry will implicitly flush write buffer */
return
0
;
}
static
int
inline
iommu_flush_iotlb_global
(
struct
intel_iommu
*
iommu
,
int
non_present_entry_flush
)
{
return
__iommu_flush_iotlb
(
iommu
,
0
,
0
,
0
,
DMA_TLB_GLOBAL_FLUSH
,
non_present_entry_flush
);
}
static
int
inline
iommu_flush_iotlb_dsi
(
struct
intel_iommu
*
iommu
,
u16
did
,
int
non_present_entry_flush
)
{
return
__iommu_flush_iotlb
(
iommu
,
did
,
0
,
0
,
DMA_TLB_DSI_FLUSH
,
non_present_entry_flush
);
}
static
int
iommu_flush_iotlb_psi
(
struct
intel_iommu
*
iommu
,
u16
did
,
u64
addr
,
unsigned
int
pages
,
int
non_present_entry_flush
)
{
unsigned
int
mask
;
BUG_ON
(
addr
&
(
~
PAGE_MASK_4
K
));
BUG_ON
(
addr
&
(
~
VTD_PAGE_MAS
K
));
BUG_ON
(
pages
==
0
);
/* Fallback to domain selective flush if no PSI support */
if
(
!
cap_pgsel_inv
(
iommu
->
cap
))
return
iommu_flush_iotlb_dsi
(
iommu
,
did
,
non_present_entry_flush
);
return
iommu
->
flush
.
flush_iotlb
(
iommu
,
did
,
0
,
0
,
DMA_TLB_DSI_FLUSH
,
non_present_entry_flush
);
/*
* PSI requires page size to be 2 ^ x, and the base address is naturally
...
...
@@ -694,11 +664,12 @@ static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
mask
=
ilog2
(
__roundup_pow_of_two
(
pages
));
/* Fallback to domain selective flush if size is too big */
if
(
mask
>
cap_max_amask_val
(
iommu
->
cap
))
return
iommu
_flush_iotlb_dsi
(
iommu
,
did
,
non_present_entry_flush
);
return
iommu
->
flush
.
flush_iotlb
(
iommu
,
did
,
0
,
0
,
DMA_TLB_DSI_FLUSH
,
non_present_entry_flush
);
return
__iommu_flush_iotlb
(
iommu
,
did
,
addr
,
mask
,
DMA_TLB_PSI_FLUSH
,
non_present_entry_flush
);
return
iommu
->
flush
.
flush_iotlb
(
iommu
,
did
,
addr
,
mask
,
DMA_TLB_PSI_FLUSH
,
non_present_entry_flush
);
}
static
void
iommu_disable_protect_mem_regions
(
struct
intel_iommu
*
iommu
)
...
...
@@ -831,7 +802,7 @@ void dmar_msi_read(int irq, struct msi_msg *msg)
}
static
int
iommu_page_fault_do_one
(
struct
intel_iommu
*
iommu
,
int
type
,
u8
fault_reason
,
u16
source_id
,
u
64
addr
)
u8
fault_reason
,
u16
source_id
,
u
nsigned
long
long
addr
)
{
const
char
*
reason
;
...
...
@@ -1084,9 +1055,9 @@ static void dmar_init_reserved_ranges(void)
if
(
!
r
->
flags
||
!
(
r
->
flags
&
IORESOURCE_MEM
))
continue
;
addr
=
r
->
start
;
addr
&=
PAGE_MASK
_4K
;
addr
&=
PAGE_MASK
;
size
=
r
->
end
-
addr
;
size
=
PAGE_ALIGN
_4K
(
size
);
size
=
PAGE_ALIGN
(
size
);
iova
=
reserve_iova
(
&
reserved_iova_list
,
IOVA_PFN
(
addr
),
IOVA_PFN
(
size
+
addr
)
-
1
);
if
(
!
iova
)
...
...
@@ -1148,7 +1119,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
domain
->
pgd
=
(
struct
dma_pte
*
)
alloc_pgtable_page
();
if
(
!
domain
->
pgd
)
return
-
ENOMEM
;
__iommu_flush_cache
(
iommu
,
domain
->
pgd
,
PAGE_SIZE
_4K
);
__iommu_flush_cache
(
iommu
,
domain
->
pgd
,
PAGE_SIZE
);
return
0
;
}
...
...
@@ -1164,7 +1135,7 @@ static void domain_exit(struct dmar_domain *domain)
/* destroy iovas */
put_iova_domain
(
&
domain
->
iovad
);
end
=
DOMAIN_MAX_ADDR
(
domain
->
gaw
);
end
=
end
&
(
~
PAGE_MASK
_4K
);
end
=
end
&
(
~
PAGE_MASK
);
/* clear ptes */
dma_pte_clear_range
(
domain
,
0
,
end
);
...
...
@@ -1204,11 +1175,13 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
__iommu_flush_cache
(
iommu
,
context
,
sizeof
(
*
context
));
/* it's a non-present to present mapping */
if
(
iommu_flush_context_device
(
iommu
,
domain
->
id
,
(((
u16
)
bus
)
<<
8
)
|
devfn
,
DMA_CCMD_MASK_NOBIT
,
1
))
if
(
iommu
->
flush
.
flush_context
(
iommu
,
domain
->
id
,
(((
u16
)
bus
)
<<
8
)
|
devfn
,
DMA_CCMD_MASK_NOBIT
,
DMA_CCMD_DEVICE_INVL
,
1
))
iommu_flush_write_buffer
(
iommu
);
else
iommu_flush_iotlb_dsi
(
iommu
,
0
,
0
);
iommu
->
flush
.
flush_iotlb
(
iommu
,
0
,
0
,
0
,
DMA_TLB_DSI_FLUSH
,
0
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
return
0
;
}
...
...
@@ -1283,22 +1256,25 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
u64
start_pfn
,
end_pfn
;
struct
dma_pte
*
pte
;
int
index
;
int
addr_width
=
agaw_to_width
(
domain
->
agaw
);
hpa
&=
(((
u64
)
1
)
<<
addr_width
)
-
1
;
if
((
prot
&
(
DMA_PTE_READ
|
DMA_PTE_WRITE
))
==
0
)
return
-
EINVAL
;
iova
&=
PAGE_MASK
_4K
;
start_pfn
=
((
u64
)
hpa
)
>>
PAGE_SHIFT_4K
;
end_pfn
=
(
PAGE_ALIGN_4K
(((
u64
)
hpa
)
+
size
))
>>
PAGE_SHIFT_4K
;
iova
&=
PAGE_MASK
;
start_pfn
=
((
u64
)
hpa
)
>>
VTD_PAGE_SHIFT
;
end_pfn
=
(
VTD_PAGE_ALIGN
(((
u64
)
hpa
)
+
size
))
>>
VTD_PAGE_SHIFT
;
index
=
0
;
while
(
start_pfn
<
end_pfn
)
{
pte
=
addr_to_dma_pte
(
domain
,
iova
+
PAGE_SIZE_4K
*
index
);
pte
=
addr_to_dma_pte
(
domain
,
iova
+
VTD_PAGE_SIZE
*
index
);
if
(
!
pte
)
return
-
ENOMEM
;
/* We don't need lock here, nobody else
* touches the iova range
*/
BUG_ON
(
dma_pte_addr
(
*
pte
));
dma_set_pte_addr
(
*
pte
,
start_pfn
<<
PAGE_SHIFT_4K
);
dma_set_pte_addr
(
*
pte
,
start_pfn
<<
VTD_PAGE_SHIFT
);
dma_set_pte_prot
(
*
pte
,
prot
);
__iommu_flush_cache
(
domain
->
iommu
,
pte
,
sizeof
(
*
pte
));
start_pfn
++
;
...
...
@@ -1310,8 +1286,10 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
static
void
detach_domain_for_dev
(
struct
dmar_domain
*
domain
,
u8
bus
,
u8
devfn
)
{
clear_context_table
(
domain
->
iommu
,
bus
,
devfn
);
iommu_flush_context_global
(
domain
->
iommu
,
0
);
iommu_flush_iotlb_global
(
domain
->
iommu
,
0
);
domain
->
iommu
->
flush
.
flush_context
(
domain
->
iommu
,
0
,
0
,
0
,
DMA_CCMD_GLOBAL_INVL
,
0
);
domain
->
iommu
->
flush
.
flush_iotlb
(
domain
->
iommu
,
0
,
0
,
0
,
DMA_TLB_GLOBAL_FLUSH
,
0
);
}
static
void
domain_remove_dev_info
(
struct
dmar_domain
*
domain
)
...
...
@@ -1474,11 +1452,13 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
return
find_domain
(
pdev
);
}
static
int
iommu_prepare_identity_map
(
struct
pci_dev
*
pdev
,
u64
start
,
u64
end
)
static
int
iommu_prepare_identity_map
(
struct
pci_dev
*
pdev
,
unsigned
long
long
start
,
unsigned
long
long
end
)
{
struct
dmar_domain
*
domain
;
unsigned
long
size
;
u
64
base
;
u
nsigned
long
long
base
;
int
ret
;
printk
(
KERN_INFO
...
...
@@ -1490,9 +1470,9 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev, u64 start, u64 end)
return
-
ENOMEM
;
/* The address might not be aligned */
base
=
start
&
PAGE_MASK
_4K
;
base
=
start
&
PAGE_MASK
;
size
=
end
-
base
;
size
=
PAGE_ALIGN
_4K
(
size
);
size
=
PAGE_ALIGN
(
size
);
if
(
!
reserve_iova
(
&
domain
->
iovad
,
IOVA_PFN
(
base
),
IOVA_PFN
(
base
+
size
)
-
1
))
{
printk
(
KERN_ERR
"IOMMU: reserve iova failed
\n
"
);
...
...
@@ -1662,6 +1642,28 @@ int __init init_dmars(void)
}
}
for_each_drhd_unit
(
drhd
)
{
if
(
drhd
->
ignored
)
continue
;
iommu
=
drhd
->
iommu
;
if
(
dmar_enable_qi
(
iommu
))
{
/*
* Queued Invalidate not enabled, use Register Based
* Invalidate
*/
iommu
->
flush
.
flush_context
=
__iommu_flush_context
;
iommu
->
flush
.
flush_iotlb
=
__iommu_flush_iotlb
;
printk
(
KERN_INFO
"IOMMU 0x%Lx: using Register based "
"invalidation
\n
"
,
drhd
->
reg_base_addr
);
}
else
{
iommu
->
flush
.
flush_context
=
qi_flush_context
;
iommu
->
flush
.
flush_iotlb
=
qi_flush_iotlb
;
printk
(
KERN_INFO
"IOMMU 0x%Lx: using Queued "
"invalidation
\n
"
,
drhd
->
reg_base_addr
);
}
}
/*
* For each rmrr
* for each dev attached to rmrr
...
...
@@ -1714,9 +1716,10 @@ int __init init_dmars(void)
iommu_set_root_entry
(
iommu
);
iommu_flush_context_global
(
iommu
,
0
);
iommu_flush_iotlb_global
(
iommu
,
0
);
iommu
->
flush
.
flush_context
(
iommu
,
0
,
0
,
0
,
DMA_CCMD_GLOBAL_INVL
,
0
);
iommu
->
flush
.
flush_iotlb
(
iommu
,
0
,
0
,
0
,
DMA_TLB_GLOBAL_FLUSH
,
0
);
iommu_disable_protect_mem_regions
(
iommu
);
ret
=
iommu_enable_translation
(
iommu
);
...
...
@@ -1738,8 +1741,8 @@ int __init init_dmars(void)
static
inline
u64
aligned_size
(
u64
host_addr
,
size_t
size
)
{
u64
addr
;
addr
=
(
host_addr
&
(
~
PAGE_MASK
_4K
))
+
size
;
return
PAGE_ALIGN
_4K
(
addr
);
addr
=
(
host_addr
&
(
~
PAGE_MASK
))
+
size
;
return
PAGE_ALIGN
(
addr
);
}
struct
iova
*
...
...
@@ -1753,20 +1756,20 @@ iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end)
return
NULL
;
piova
=
alloc_iova
(
&
domain
->
iovad
,
size
>>
PAGE_SHIFT
_4K
,
IOVA_PFN
(
end
),
1
);
size
>>
PAGE_SHIFT
,
IOVA_PFN
(
end
),
1
);
return
piova
;
}
static
struct
iova
*
__intel_alloc_iova
(
struct
device
*
dev
,
struct
dmar_domain
*
domain
,
size_t
size
)
size_t
size
,
u64
dma_mask
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
dev
);
struct
iova
*
iova
=
NULL
;
if
(
(
pdev
->
dma_mask
<=
DMA_32BIT_MASK
)
||
(
dmar_forcedac
))
{
iova
=
iommu_alloc_iova
(
domain
,
size
,
pdev
->
dma_mask
);
}
else
{
if
(
dma_mask
<=
DMA_32BIT_MASK
||
dmar_forcedac
)
iova
=
iommu_alloc_iova
(
domain
,
size
,
dma_mask
);
else
{
/*
* First try to allocate an io virtual address in
* DMA_32BIT_MASK and if that fails then try allocating
...
...
@@ -1774,7 +1777,7 @@ __intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
*/
iova
=
iommu_alloc_iova
(
domain
,
size
,
DMA_32BIT_MASK
);
if
(
!
iova
)
iova
=
iommu_alloc_iova
(
domain
,
size
,
pdev
->
dma_mask
);
iova
=
iommu_alloc_iova
(
domain
,
size
,
dma_mask
);
}
if
(
!
iova
)
{
...
...
@@ -1813,12 +1816,12 @@ get_valid_domain_for_dev(struct pci_dev *pdev)
return
domain
;
}
static
dma_addr_t
intel_map_single
(
struct
device
*
hwdev
,
phys_addr_t
paddr
,
size_t
size
,
int
dir
)
static
dma_addr_t
__intel_map_single
(
struct
device
*
hwdev
,
phys_addr_t
paddr
,
size_t
size
,
int
dir
,
u64
dma_mask
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
hwdev
);
struct
dmar_domain
*
domain
;
unsigned
long
start_paddr
;
phys_addr_t
start_paddr
;
struct
iova
*
iova
;
int
prot
=
0
;
int
ret
;
...
...
@@ -1833,11 +1836,11 @@ intel_map_single(struct device *hwdev, phys_addr_t paddr, size_t size, int dir)
size
=
aligned_size
((
u64
)
paddr
,
size
);
iova
=
__intel_alloc_iova
(
hwdev
,
domain
,
size
);
iova
=
__intel_alloc_iova
(
hwdev
,
domain
,
size
,
pdev
->
dma_mask
);
if
(
!
iova
)
goto
error
;
start_paddr
=
iova
->
pfn_lo
<<
PAGE_SHIFT_4K
;
start_paddr
=
(
phys_addr_t
)
iova
->
pfn_lo
<<
PAGE_SHIFT
;
/*
* Check if DMAR supports zero-length reads on write only
...
...
@@ -1855,30 +1858,33 @@ intel_map_single(struct device *hwdev, phys_addr_t paddr, size_t size, int dir)
* is not a big problem
*/
ret
=
domain_page_mapping
(
domain
,
start_paddr
,
((
u64
)
paddr
)
&
PAGE_MASK
_4K
,
size
,
prot
);
((
u64
)
paddr
)
&
PAGE_MASK
,
size
,
prot
);
if
(
ret
)
goto
error
;
pr_debug
(
"Device %s request: %lx@%llx mapping: %lx@%llx, dir %d
\n
"
,
pci_name
(
pdev
),
size
,
(
u64
)
paddr
,
size
,
(
u64
)
start_paddr
,
dir
);
/* it's a non-present to present mapping */
ret
=
iommu_flush_iotlb_psi
(
domain
->
iommu
,
domain
->
id
,
start_paddr
,
size
>>
PAGE_SHIFT_4K
,
1
);
start_paddr
,
size
>>
VTD_PAGE_SHIFT
,
1
);
if
(
ret
)
iommu_flush_write_buffer
(
domain
->
iommu
);
return
(
start_paddr
+
((
u64
)
paddr
&
(
~
PAGE_MASK_4K
)
));
return
start_paddr
+
((
u64
)
paddr
&
(
~
PAGE_MASK
));
error:
if
(
iova
)
__free_iova
(
&
domain
->
iovad
,
iova
);
printk
(
KERN_ERR
"Device %s request: %lx@%llx dir %d --- failed
\n
"
,
pci_name
(
pdev
),
size
,
(
u
64
)
paddr
,
dir
);
pci_name
(
pdev
),
size
,
(
u
nsigned
long
long
)
paddr
,
dir
);
return
0
;
}
dma_addr_t
intel_map_single
(
struct
device
*
hwdev
,
phys_addr_t
paddr
,
size_t
size
,
int
dir
)
{
return
__intel_map_single
(
hwdev
,
paddr
,
size
,
dir
,
to_pci_dev
(
hwdev
)
->
dma_mask
);
}
static
void
flush_unmaps
(
void
)
{
int
i
,
j
;
...
...
@@ -1891,7 +1897,8 @@ static void flush_unmaps(void)
struct
intel_iommu
*
iommu
=
deferred_flush
[
i
].
domain
[
0
]
->
iommu
;
iommu_flush_iotlb_global
(
iommu
,
0
);
iommu
->
flush
.
flush_iotlb
(
iommu
,
0
,
0
,
0
,
DMA_TLB_GLOBAL_FLUSH
,
0
);
for
(
j
=
0
;
j
<
deferred_flush
[
i
].
next
;
j
++
)
{
__free_iova
(
&
deferred_flush
[
i
].
domain
[
j
]
->
iovad
,
deferred_flush
[
i
].
iova
[
j
]);
...
...
@@ -1936,8 +1943,8 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova)
spin_unlock_irqrestore
(
&
async_umap_flush_lock
,
flags
);
}
static
void
intel_unmap_single
(
struct
device
*
dev
,
dma_addr_t
dev_addr
,
size_t
size
,
int
dir
)
void
intel_unmap_single
(
struct
device
*
dev
,
dma_addr_t
dev_addr
,
size_t
size
,
int
dir
)
{
struct
pci_dev
*
pdev
=
to_pci_dev
(
dev
);
struct
dmar_domain
*
domain
;
...
...
@@ -1953,11 +1960,11 @@ static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
if
(
!
iova
)
return
;
start_addr
=
iova
->
pfn_lo
<<
PAGE_SHIFT
_4K
;
start_addr
=
iova
->
pfn_lo
<<
PAGE_SHIFT
;
size
=
aligned_size
((
u64
)
dev_addr
,
size
);
pr_debug
(
"Device %s unmapping: %lx@%llx
\n
"
,
pci_name
(
pdev
),
size
,
(
u
64
)
start_addr
);
pci_name
(
pdev
),
size
,
(
u
nsigned
long
long
)
start_addr
);
/* clear the whole page */
dma_pte_clear_range
(
domain
,
start_addr
,
start_addr
+
size
);
...
...
@@ -1965,7 +1972,7 @@ static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
dma_pte_free_pagetable
(
domain
,
start_addr
,
start_addr
+
size
);
if
(
intel_iommu_strict
)
{
if
(
iommu_flush_iotlb_psi
(
domain
->
iommu
,
domain
->
id
,
start_addr
,
size
>>
PAGE_SHIFT_4K
,
0
))
domain
->
id
,
start_addr
,
size
>>
VTD_PAGE_SHIFT
,
0
))
iommu_flush_write_buffer
(
domain
->
iommu
);
/* free iova */
__free_iova
(
&
domain
->
iovad
,
iova
);
...
...
@@ -1978,13 +1985,13 @@ static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
}
}
static
void
*
intel_alloc_coherent
(
struct
device
*
hwdev
,
size_t
size
,
dma_addr_t
*
dma_handle
,
gfp_t
flags
)
void
*
intel_alloc_coherent
(
struct
device
*
hwdev
,
size_t
size
,
dma_addr_t
*
dma_handle
,
gfp_t
flags
)
{
void
*
vaddr
;
int
order
;
size
=
PAGE_ALIGN
_4K
(
size
);
size
=
PAGE_ALIGN
(
size
);
order
=
get_order
(
size
);
flags
&=
~
(
GFP_DMA
|
GFP_DMA32
);
...
...
@@ -1993,19 +2000,21 @@ static void * intel_alloc_coherent(struct device *hwdev, size_t size,
return
NULL
;
memset
(
vaddr
,
0
,
size
);
*
dma_handle
=
intel_map_single
(
hwdev
,
virt_to_bus
(
vaddr
),
size
,
DMA_BIDIRECTIONAL
);
*
dma_handle
=
__intel_map_single
(
hwdev
,
virt_to_bus
(
vaddr
),
size
,
DMA_BIDIRECTIONAL
,
hwdev
->
coherent_dma_mask
);
if
(
*
dma_handle
)
return
vaddr
;
free_pages
((
unsigned
long
)
vaddr
,
order
);
return
NULL
;
}
static
void
intel_free_coherent
(
struct
device
*
hwdev
,
size_t
size
,
void
*
vaddr
,
dma_addr_t
dma_handle
)
void
intel_free_coherent
(
struct
device
*
hwdev
,
size_t
size
,
void
*
vaddr
,
dma_addr_t
dma_handle
)
{
int
order
;
size
=
PAGE_ALIGN
_4K
(
size
);
size
=
PAGE_ALIGN
(
size
);
order
=
get_order
(
size
);
intel_unmap_single
(
hwdev
,
dma_handle
,
size
,
DMA_BIDIRECTIONAL
);
...
...
@@ -2013,8 +2022,9 @@ static void intel_free_coherent(struct device *hwdev, size_t size,
}
#define SG_ENT_VIRT_ADDRESS(sg) (sg_virt((sg)))
static
void
intel_unmap_sg
(
struct
device
*
hwdev
,
struct
scatterlist
*
sglist
,
int
nelems
,
int
dir
)
void
intel_unmap_sg
(
struct
device
*
hwdev
,
struct
scatterlist
*
sglist
,
int
nelems
,
int
dir
)
{
int
i
;
struct
pci_dev
*
pdev
=
to_pci_dev
(
hwdev
);
...
...
@@ -2038,7 +2048,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
size
+=
aligned_size
((
u64
)
addr
,
sg
->
length
);
}
start_addr
=
iova
->
pfn_lo
<<
PAGE_SHIFT
_4K
;
start_addr
=
iova
->
pfn_lo
<<
PAGE_SHIFT
;
/* clear the whole page */
dma_pte_clear_range
(
domain
,
start_addr
,
start_addr
+
size
);
...
...
@@ -2046,7 +2056,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
dma_pte_free_pagetable
(
domain
,
start_addr
,
start_addr
+
size
);
if
(
iommu_flush_iotlb_psi
(
domain
->
iommu
,
domain
->
id
,
start_addr
,
size
>>
PAGE_SHIFT_4K
,
0
))
size
>>
VTD_PAGE_SHIFT
,
0
))
iommu_flush_write_buffer
(
domain
->
iommu
);
/* free iova */
...
...
@@ -2067,8 +2077,8 @@ static int intel_nontranslate_map_sg(struct device *hddev,
return
nelems
;
}
static
int
intel_map_sg
(
struct
device
*
hwdev
,
struct
scatterlist
*
sglist
,
int
nelems
,
int
dir
)
int
intel_map_sg
(
struct
device
*
hwdev
,
struct
scatterlist
*
sglist
,
int
nelems
,
int
dir
)
{
void
*
addr
;
int
i
;
...
...
@@ -2096,7 +2106,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist,
size
+=
aligned_size
((
u64
)
addr
,
sg
->
length
);
}
iova
=
__intel_alloc_iova
(
hwdev
,
domain
,
size
);
iova
=
__intel_alloc_iova
(
hwdev
,
domain
,
size
,
pdev
->
dma_mask
);
if
(
!
iova
)
{
sglist
->
dma_length
=
0
;
return
0
;
...
...
@@ -2112,14 +2122,14 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist,
if
(
dir
==
DMA_FROM_DEVICE
||
dir
==
DMA_BIDIRECTIONAL
)
prot
|=
DMA_PTE_WRITE
;
start_addr
=
iova
->
pfn_lo
<<
PAGE_SHIFT
_4K
;
start_addr
=
iova
->
pfn_lo
<<
PAGE_SHIFT
;
offset
=
0
;
for_each_sg
(
sglist
,
sg
,
nelems
,
i
)
{
addr
=
SG_ENT_VIRT_ADDRESS
(
sg
);
addr
=
(
void
*
)
virt_to_phys
(
addr
);
size
=
aligned_size
((
u64
)
addr
,
sg
->
length
);
ret
=
domain_page_mapping
(
domain
,
start_addr
+
offset
,
((
u64
)
addr
)
&
PAGE_MASK
_4K
,
((
u64
)
addr
)
&
PAGE_MASK
,
size
,
prot
);
if
(
ret
)
{
/* clear the page */
...
...
@@ -2133,14 +2143,14 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist,
return
0
;
}
sg
->
dma_address
=
start_addr
+
offset
+
((
u64
)
addr
&
(
~
PAGE_MASK
_4K
));
((
u64
)
addr
&
(
~
PAGE_MASK
));
sg
->
dma_length
=
sg
->
length
;
offset
+=
size
;
}
/* it's a non-present to present mapping */
if
(
iommu_flush_iotlb_psi
(
domain
->
iommu
,
domain
->
id
,
start_addr
,
offset
>>
PAGE_SHIFT_4K
,
1
))
start_addr
,
offset
>>
VTD_PAGE_SHIFT
,
1
))
iommu_flush_write_buffer
(
domain
->
iommu
);
return
nelems
;
}
...
...
@@ -2180,7 +2190,6 @@ static inline int iommu_devinfo_cache_init(void)
sizeof
(
struct
device_domain_info
),
0
,
SLAB_HWCACHE_ALIGN
,
NULL
);
if
(
!
iommu_devinfo_cache
)
{
printk
(
KERN_ERR
"Couldn't create devinfo cache
\n
"
);
...
...
@@ -2198,7 +2207,6 @@ static inline int iommu_iova_cache_init(void)
sizeof
(
struct
iova
),
0
,
SLAB_HWCACHE_ALIGN
,
NULL
);
if
(
!
iommu_iova_cache
)
{
printk
(
KERN_ERR
"Couldn't create iova cache
\n
"
);
...
...
@@ -2327,7 +2335,7 @@ void intel_iommu_domain_exit(struct dmar_domain *domain)
return
;
end
=
DOMAIN_MAX_ADDR
(
domain
->
gaw
);
end
=
end
&
(
~
PAGE_MASK_4
K
);
end
=
end
&
(
~
VTD_PAGE_MAS
K
);
/* clear ptes */
dma_pte_clear_range
(
domain
,
0
,
end
);
...
...
@@ -2423,6 +2431,6 @@ u64 intel_iommu_iova_to_pfn(struct dmar_domain *domain, u64 iova)
if
(
pte
)
pfn
=
dma_pte_addr
(
*
pte
);
return
pfn
>>
PAGE_SHIFT_4K
;
return
pfn
>>
VTD_PAGE_SHIFT
;
}
EXPORT_SYMBOL_GPL
(
intel_iommu_iova_to_pfn
);
drivers/pci/quirks.c
View file @
b364776a
...
...
@@ -35,6 +35,20 @@ static void __devinit quirk_mellanox_tavor(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL
(
PCI_VENDOR_ID_MELLANOX
,
PCI_DEVICE_ID_MELLANOX_TAVOR
,
quirk_mellanox_tavor
);
DECLARE_PCI_FIXUP_FINAL
(
PCI_VENDOR_ID_MELLANOX
,
PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE
,
quirk_mellanox_tavor
);
/* Many VIA bridges seem to corrupt data for DAC. Disable it here */
int
forbid_dac
__read_mostly
;
EXPORT_SYMBOL
(
forbid_dac
);
static
__devinit
void
via_no_dac
(
struct
pci_dev
*
dev
)
{
if
((
dev
->
class
>>
8
)
==
PCI_CLASS_BRIDGE_PCI
&&
forbid_dac
==
0
)
{
dev_info
(
&
dev
->
dev
,
"VIA PCI bridge detected. Disabling DAC.
\n
"
);
forbid_dac
=
1
;
}
}
DECLARE_PCI_FIXUP_FINAL
(
PCI_VENDOR_ID_VIA
,
PCI_ANY_ID
,
via_no_dac
);
/* Deal with broken BIOS'es that neglect to enable passive release,
which can cause problems in combination with the 82441FX/PPro MTRRs */
static
void
quirk_passive_release
(
struct
pci_dev
*
dev
)
...
...
include/asm-x86/iommu.h
View file @
b364776a
...
...
@@ -7,9 +7,13 @@ extern struct dma_mapping_ops nommu_dma_ops;
extern
int
force_iommu
,
no_iommu
;
extern
int
iommu_detected
;
extern
int
dmar_disabled
;
extern
int
forbid_dac
;
extern
unsigned
long
iommu_nr_pages
(
unsigned
long
addr
,
unsigned
long
len
);
/* 10 seconds */
#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
#ifdef CONFIG_GART_IOMMU
extern
int
gart_iommu_aperture
;
extern
int
gart_iommu_aperture_allowed
;
...
...
include/linux/dma_remapping.h
View file @
b364776a
...
...
@@ -2,15 +2,14 @@
#define _DMA_REMAPPING_H
/*
* We need a fixed PAGE_SIZE of 4K irrespective of
* arch PAGE_SIZE for IOMMU page tables.
* VT-d hardware uses 4KiB page size regardless of host page size.
*/
#define
PAGE_SHIFT_4K
(12)
#define
PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K
)
#define
PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K
)
#define
PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4
K)
#define
VTD_PAGE_SHIFT
(12)
#define
VTD_PAGE_SIZE (1UL << VTD_PAGE_SHIFT
)
#define
VTD_PAGE_MASK (((u64)-1) << VTD_PAGE_SHIFT
)
#define
VTD_PAGE_ALIGN(addr) (((addr) + VTD_PAGE_SIZE - 1) & VTD_PAGE_MAS
K)
#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT
_4K
)
#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
...
...
@@ -25,7 +24,7 @@ struct root_entry {
u64
val
;
u64
rsvd1
;
};
#define ROOT_ENTRY_NR (
PAGE_SIZE_4K
/sizeof(struct root_entry))
#define ROOT_ENTRY_NR (
VTD_PAGE_SIZE
/sizeof(struct root_entry))
static
inline
bool
root_present
(
struct
root_entry
*
root
)
{
return
(
root
->
val
&
1
);
...
...
@@ -36,7 +35,7 @@ static inline void set_root_present(struct root_entry *root)
}
static
inline
void
set_root_value
(
struct
root_entry
*
root
,
unsigned
long
value
)
{
root
->
val
|=
value
&
PAGE_MASK_4
K
;
root
->
val
|=
value
&
VTD_PAGE_MAS
K
;
}
struct
context_entry
;
...
...
@@ -45,7 +44,7 @@ get_context_addr_from_root(struct root_entry *root)
{
return
(
struct
context_entry
*
)
(
root_present
(
root
)
?
phys_to_virt
(
root
->
val
&
PAGE_MASK_4K
)
:
root
->
val
&
VTD_PAGE_MASK
)
:
NULL
);
}
...
...
@@ -67,7 +66,7 @@ struct context_entry {
#define context_present(c) ((c).lo & 1)
#define context_fault_disable(c) (((c).lo >> 1) & 1)
#define context_translation_type(c) (((c).lo >> 2) & 3)
#define context_address_root(c) ((c).lo &
PAGE_MASK_4
K)
#define context_address_root(c) ((c).lo &
VTD_PAGE_MAS
K)
#define context_address_width(c) ((c).hi & 7)
#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
...
...
@@ -81,7 +80,7 @@ struct context_entry {
} while (0)
#define CONTEXT_TT_MULTI_LEVEL 0
#define context_set_address_root(c, val) \
do {(c).lo |= (val) &
PAGE_MASK_4K;
} while (0)
do {(c).lo |= (val) &
VTD_PAGE_MASK;
} while (0)
#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0)
#define context_set_domain_id(c, val) \
do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0)
...
...
@@ -107,9 +106,9 @@ struct dma_pte {
#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0)
#define dma_set_pte_prot(p, prot) \
do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0)
#define dma_pte_addr(p) ((p).val &
PAGE_MASK_4
K)
#define dma_pte_addr(p) ((p).val &
VTD_PAGE_MAS
K)
#define dma_set_pte_addr(p, addr) do {\
(p).val |= ((addr) &
PAGE_MASK_4
K); } while (0)
(p).val |= ((addr) &
VTD_PAGE_MAS
K); } while (0)
#define dma_pte_present(p) (((p).val & 3) != 0)
struct
intel_iommu
;
...
...
include/linux/intel-iommu.h
View file @
b364776a
...
...
@@ -29,6 +29,7 @@
#include <linux/io.h>
#include <linux/dma_remapping.h>
#include <asm/cacheflush.h>
#include <asm/iommu.h>
/*
* Intel IOMMU register specification per version 1.0 public spec.
...
...
@@ -127,6 +128,7 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
/* IOTLB_REG */
#define DMA_TLB_FLUSH_GRANU_OFFSET 60
#define DMA_TLB_GLOBAL_FLUSH (((u64)1) << 60)
#define DMA_TLB_DSI_FLUSH (((u64)2) << 60)
#define DMA_TLB_PSI_FLUSH (((u64)3) << 60)
...
...
@@ -140,6 +142,7 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define DMA_TLB_MAX_SIZE (0x3f)
/* INVALID_DESC */
#define DMA_CCMD_INVL_GRANU_OFFSET 61
#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 3)
#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 3)
#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 3)
...
...
@@ -200,22 +203,21 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define dma_frcd_type(d) ((d >> 30) & 1)
#define dma_frcd_fault_reason(c) (c & 0xff)
#define dma_frcd_source_id(c) (c & 0xffff)
#define dma_frcd_page_addr(d) (d & (((u64)-1) << 12))
/* low 64 bit */
#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
/* 10sec */
#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
{\
cycles_t start_time = get_cycles();\
while (1) {\
sts = op (iommu->reg + offset);\
if (cond)\
break;\
/* low 64 bit */
#define dma_frcd_page_addr(d) (d & (((u64)-1) << PAGE_SHIFT))
#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
do { \
cycles_t start_time = get_cycles(); \
while (1) { \
sts = op(iommu->reg + offset); \
if (cond) \
break; \
if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
panic("DMAR hardware is malfunctioning\n");\
cpu_relax();\
}\
}
panic("DMAR hardware is malfunctioning\n");
\
cpu_relax();
\
}
\
}
while (0)
#define QI_LENGTH 256
/* queue length */
...
...
@@ -238,6 +240,19 @@ enum {
#define QI_IWD_STATUS_DATA(d) (((u64)d) << 32)
#define QI_IWD_STATUS_WRITE (((u64)1) << 5)
#define QI_IOTLB_DID(did) (((u64)did) << 16)
#define QI_IOTLB_DR(dr) (((u64)dr) << 7)
#define QI_IOTLB_DW(dw) (((u64)dw) << 6)
#define QI_IOTLB_GRAN(gran) (((u64)gran) >> (DMA_TLB_FLUSH_GRANU_OFFSET-4))
#define QI_IOTLB_ADDR(addr) (((u64)addr) & VTD_PAGE_MASK)
#define QI_IOTLB_IH(ih) (((u64)ih) << 6)
#define QI_IOTLB_AM(am) (((u8)am))
#define QI_CC_FM(fm) (((u64)fm) << 48)
#define QI_CC_SID(sid) (((u64)sid) << 32)
#define QI_CC_DID(did) (((u64)did) << 16)
#define QI_CC_GRAN(gran) (((u64)gran) >> (DMA_CCMD_INVL_GRANU_OFFSET-4))
struct
qi_desc
{
u64
low
,
high
;
};
...
...
@@ -263,6 +278,13 @@ struct ir_table {
};
#endif
struct
iommu_flush
{
int
(
*
flush_context
)(
struct
intel_iommu
*
iommu
,
u16
did
,
u16
sid
,
u8
fm
,
u64
type
,
int
non_present_entry_flush
);
int
(
*
flush_iotlb
)(
struct
intel_iommu
*
iommu
,
u16
did
,
u64
addr
,
unsigned
int
size_order
,
u64
type
,
int
non_present_entry_flush
);
};
struct
intel_iommu
{
void
__iomem
*
reg
;
/* Pointer to hardware regs, virtual addr */
u64
cap
;
...
...
@@ -282,6 +304,7 @@ struct intel_iommu {
unsigned
char
name
[
7
];
/* Device Name */
struct
msi_msg
saved_msg
;
struct
sys_device
sysdev
;
struct
iommu_flush
flush
;
#endif
struct
q_inval
*
qi
;
/* Queued invalidation info */
#ifdef CONFIG_INTR_REMAP
...
...
@@ -303,6 +326,12 @@ extern void free_iommu(struct intel_iommu *iommu);
extern
int
dmar_enable_qi
(
struct
intel_iommu
*
iommu
);
extern
void
qi_global_iec
(
struct
intel_iommu
*
iommu
);
extern
int
qi_flush_context
(
struct
intel_iommu
*
iommu
,
u16
did
,
u16
sid
,
u8
fm
,
u64
type
,
int
non_present_entry_flush
);
extern
int
qi_flush_iotlb
(
struct
intel_iommu
*
iommu
,
u16
did
,
u64
addr
,
unsigned
int
size_order
,
u64
type
,
int
non_present_entry_flush
);
extern
void
qi_submit_sync
(
struct
qi_desc
*
desc
,
struct
intel_iommu
*
iommu
);
void
intel_iommu_domain_exit
(
struct
dmar_domain
*
domain
);
...
...
@@ -324,4 +353,11 @@ static inline int intel_iommu_found(void)
}
#endif
/* CONFIG_DMAR */
extern
void
*
intel_alloc_coherent
(
struct
device
*
,
size_t
,
dma_addr_t
*
,
gfp_t
);
extern
void
intel_free_coherent
(
struct
device
*
,
size_t
,
void
*
,
dma_addr_t
);
extern
dma_addr_t
intel_map_single
(
struct
device
*
,
phys_addr_t
,
size_t
,
int
);
extern
void
intel_unmap_single
(
struct
device
*
,
dma_addr_t
,
size_t
,
int
);
extern
int
intel_map_sg
(
struct
device
*
,
struct
scatterlist
*
,
int
,
int
);
extern
void
intel_unmap_sg
(
struct
device
*
,
struct
scatterlist
*
,
int
,
int
);
#endif
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