mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-24 15:42:32 +00:00
Merge git://git.infradead.org/iommu-2.6
* git://git.infradead.org/iommu-2.6: intel-iommu: Set a more specific taint flag for invalid BIOS DMAR tables intel-iommu: Combine the BIOS DMAR table warning messages panic: Add taint flag TAINT_FIRMWARE_WORKAROUND ('I') panic: Allow warnings to set different taint flags intel-iommu: intel_iommu_map_range failed at very end of address space intel-iommu: errors with smaller iommu widths intel-iommu: Fix boot inside 64bit virtualbox with io-apic disabled intel-iommu: use physfn to search drhd for VF intel-iommu: Print out iommu seq_id intel-iommu: Don't complain that ACPI_DMAR_SCOPE_TYPE_IOAPIC is not supported intel-iommu: Avoid global flushes with caching mode. intel-iommu: Use correct domain ID when caching mode is enabled intel-iommu mistakenly uses offset_pfn when caching mode is enabled intel-iommu: use for_each_set_bit() intel-iommu: Fix section mismatch dmar_ir_support() uses dmar_tbl.
This commit is contained in:
commit
0961d6581c
13 changed files with 181 additions and 137 deletions
|
@ -256,9 +256,13 @@ characters, each representing a particular tainted value.
|
||||||
9: 'A' if the ACPI table has been overridden.
|
9: 'A' if the ACPI table has been overridden.
|
||||||
|
|
||||||
10: 'W' if a warning has previously been issued by the kernel.
|
10: 'W' if a warning has previously been issued by the kernel.
|
||||||
|
(Though some warnings may set more specific taint flags.)
|
||||||
|
|
||||||
11: 'C' if a staging driver has been loaded.
|
11: 'C' if a staging driver has been loaded.
|
||||||
|
|
||||||
|
12: 'I' if the kernel is working around a severe bug in the platform
|
||||||
|
firmware (BIOS or similar).
|
||||||
|
|
||||||
The primary reason for the 'Tainted: ' string is to tell kernel
|
The primary reason for the 'Tainted: ' string is to tell kernel
|
||||||
debuggers if this is a clean kernel or if anything unusual has
|
debuggers if this is a clean kernel or if anything unusual has
|
||||||
occurred. Tainting is permanent: even if an offending module is
|
occurred. Tainting is permanent: even if an offending module is
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||||
#define __WARN() \
|
#define __WARN_TAINT(taint) \
|
||||||
do { \
|
do { \
|
||||||
asm volatile("\n" \
|
asm volatile("\n" \
|
||||||
"1:\t" PARISC_BUG_BREAK_ASM "\n" \
|
"1:\t" PARISC_BUG_BREAK_ASM "\n" \
|
||||||
|
@ -54,11 +54,11 @@
|
||||||
"\t.org 2b+%c3\n" \
|
"\t.org 2b+%c3\n" \
|
||||||
"\t.popsection" \
|
"\t.popsection" \
|
||||||
: : "i" (__FILE__), "i" (__LINE__), \
|
: : "i" (__FILE__), "i" (__LINE__), \
|
||||||
"i" (BUGFLAG_WARNING), \
|
"i" (BUGFLAG_TAINT(taint)), \
|
||||||
"i" (sizeof(struct bug_entry)) ); \
|
"i" (sizeof(struct bug_entry)) ); \
|
||||||
} while(0)
|
} while(0)
|
||||||
#else
|
#else
|
||||||
#define __WARN() \
|
#define __WARN_TAINT(taint) \
|
||||||
do { \
|
do { \
|
||||||
asm volatile("\n" \
|
asm volatile("\n" \
|
||||||
"1:\t" PARISC_BUG_BREAK_ASM "\n" \
|
"1:\t" PARISC_BUG_BREAK_ASM "\n" \
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
"\t.short %c0\n" \
|
"\t.short %c0\n" \
|
||||||
"\t.org 2b+%c1\n" \
|
"\t.org 2b+%c1\n" \
|
||||||
"\t.popsection" \
|
"\t.popsection" \
|
||||||
: : "i" (BUGFLAG_WARNING), \
|
: : "i" (BUGFLAG_TAINT(taint)), \
|
||||||
"i" (sizeof(struct bug_entry)) ); \
|
"i" (sizeof(struct bug_entry)) ); \
|
||||||
} while(0)
|
} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -85,12 +85,12 @@
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define __WARN() do { \
|
#define __WARN_TAINT(taint) do { \
|
||||||
__asm__ __volatile__( \
|
__asm__ __volatile__( \
|
||||||
"1: twi 31,0,0\n" \
|
"1: twi 31,0,0\n" \
|
||||||
_EMIT_BUG_ENTRY \
|
_EMIT_BUG_ENTRY \
|
||||||
: : "i" (__FILE__), "i" (__LINE__), \
|
: : "i" (__FILE__), "i" (__LINE__), \
|
||||||
"i" (BUGFLAG_WARNING), \
|
"i" (BUGFLAG_TAINT(taint)), \
|
||||||
"i" (sizeof(struct bug_entry))); \
|
"i" (sizeof(struct bug_entry))); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@
|
||||||
"1: "PPC_TLNEI" %4,0\n" \
|
"1: "PPC_TLNEI" %4,0\n" \
|
||||||
_EMIT_BUG_ENTRY \
|
_EMIT_BUG_ENTRY \
|
||||||
: : "i" (__FILE__), "i" (__LINE__), \
|
: : "i" (__FILE__), "i" (__LINE__), \
|
||||||
"i" (BUGFLAG_WARNING), \
|
"i" (BUGFLAG_TAINT(TAINT_WARN)), \
|
||||||
"i" (sizeof(struct bug_entry)), \
|
"i" (sizeof(struct bug_entry)), \
|
||||||
"r" (__ret_warn_on)); \
|
"r" (__ret_warn_on)); \
|
||||||
} \
|
} \
|
||||||
|
|
|
@ -46,18 +46,18 @@
|
||||||
unreachable(); \
|
unreachable(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define __WARN() do { \
|
#define __WARN_TAINT(taint) do { \
|
||||||
__EMIT_BUG(BUGFLAG_WARNING); \
|
__EMIT_BUG(BUGFLAG_TAINT(taint)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define WARN_ON(x) ({ \
|
#define WARN_ON(x) ({ \
|
||||||
int __ret_warn_on = !!(x); \
|
int __ret_warn_on = !!(x); \
|
||||||
if (__builtin_constant_p(__ret_warn_on)) { \
|
if (__builtin_constant_p(__ret_warn_on)) { \
|
||||||
if (__ret_warn_on) \
|
if (__ret_warn_on) \
|
||||||
__EMIT_BUG(BUGFLAG_WARNING); \
|
__WARN(); \
|
||||||
} else { \
|
} else { \
|
||||||
if (unlikely(__ret_warn_on)) \
|
if (unlikely(__ret_warn_on)) \
|
||||||
__EMIT_BUG(BUGFLAG_WARNING); \
|
__WARN(); \
|
||||||
} \
|
} \
|
||||||
unlikely(__ret_warn_on); \
|
unlikely(__ret_warn_on); \
|
||||||
})
|
})
|
||||||
|
|
|
@ -48,7 +48,7 @@ do { \
|
||||||
"i" (sizeof(struct bug_entry))); \
|
"i" (sizeof(struct bug_entry))); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define __WARN() \
|
#define __WARN_TAINT(taint) \
|
||||||
do { \
|
do { \
|
||||||
__asm__ __volatile__ ( \
|
__asm__ __volatile__ ( \
|
||||||
"1:\t.short %O0\n" \
|
"1:\t.short %O0\n" \
|
||||||
|
@ -57,7 +57,7 @@ do { \
|
||||||
: "n" (TRAPA_BUG_OPCODE), \
|
: "n" (TRAPA_BUG_OPCODE), \
|
||||||
"i" (__FILE__), \
|
"i" (__FILE__), \
|
||||||
"i" (__LINE__), \
|
"i" (__LINE__), \
|
||||||
"i" (BUGFLAG_WARNING), \
|
"i" (BUGFLAG_TAINT(taint)), \
|
||||||
"i" (sizeof(struct bug_entry))); \
|
"i" (sizeof(struct bug_entry))); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
|
@ -131,9 +131,10 @@ static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
|
||||||
if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
|
if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
|
||||||
scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
|
scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
|
||||||
(*cnt)++;
|
(*cnt)++;
|
||||||
else
|
else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC) {
|
||||||
printk(KERN_WARNING PREFIX
|
printk(KERN_WARNING PREFIX
|
||||||
"Unsupported device scope\n");
|
"Unsupported device scope\n");
|
||||||
|
}
|
||||||
start += scope->length;
|
start += scope->length;
|
||||||
}
|
}
|
||||||
if (*cnt == 0)
|
if (*cnt == 0)
|
||||||
|
@ -309,6 +310,8 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
|
||||||
struct acpi_dmar_atsr *atsr;
|
struct acpi_dmar_atsr *atsr;
|
||||||
struct dmar_atsr_unit *atsru;
|
struct dmar_atsr_unit *atsru;
|
||||||
|
|
||||||
|
dev = pci_physfn(dev);
|
||||||
|
|
||||||
list_for_each_entry(atsru, &dmar_atsr_units, list) {
|
list_for_each_entry(atsru, &dmar_atsr_units, list) {
|
||||||
atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
|
atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
|
||||||
if (atsr->segment == pci_domain_nr(dev->bus))
|
if (atsr->segment == pci_domain_nr(dev->bus))
|
||||||
|
@ -358,7 +361,9 @@ dmar_parse_one_rhsa(struct acpi_dmar_header *header)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WARN(1, "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
|
WARN_TAINT(
|
||||||
|
1, TAINT_FIRMWARE_WORKAROUND,
|
||||||
|
"Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
|
||||||
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
||||||
drhd->reg_base_addr,
|
drhd->reg_base_addr,
|
||||||
dmi_get_system_info(DMI_BIOS_VENDOR),
|
dmi_get_system_info(DMI_BIOS_VENDOR),
|
||||||
|
@ -507,7 +512,7 @@ parse_dmar_table(void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
|
static int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
|
||||||
struct pci_dev *dev)
|
struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
@ -530,6 +535,8 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
|
||||||
struct dmar_drhd_unit *dmaru = NULL;
|
struct dmar_drhd_unit *dmaru = NULL;
|
||||||
struct acpi_dmar_hardware_unit *drhd;
|
struct acpi_dmar_hardware_unit *drhd;
|
||||||
|
|
||||||
|
dev = pci_physfn(dev);
|
||||||
|
|
||||||
list_for_each_entry(dmaru, &dmar_drhd_units, list) {
|
list_for_each_entry(dmaru, &dmar_drhd_units, list) {
|
||||||
drhd = container_of(dmaru->hdr,
|
drhd = container_of(dmaru->hdr,
|
||||||
struct acpi_dmar_hardware_unit,
|
struct acpi_dmar_hardware_unit,
|
||||||
|
@ -614,7 +621,17 @@ int __init dmar_table_init(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bios_warned;
|
static void warn_invalid_dmar(u64 addr, const char *message)
|
||||||
|
{
|
||||||
|
WARN_TAINT_ONCE(
|
||||||
|
1, TAINT_FIRMWARE_WORKAROUND,
|
||||||
|
"Your BIOS is broken; DMAR reported at address %llx%s!\n"
|
||||||
|
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
||||||
|
addr, message,
|
||||||
|
dmi_get_system_info(DMI_BIOS_VENDOR),
|
||||||
|
dmi_get_system_info(DMI_BIOS_VERSION),
|
||||||
|
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
||||||
|
}
|
||||||
|
|
||||||
int __init check_zero_address(void)
|
int __init check_zero_address(void)
|
||||||
{
|
{
|
||||||
|
@ -640,13 +657,7 @@ int __init check_zero_address(void)
|
||||||
|
|
||||||
drhd = (void *)entry_header;
|
drhd = (void *)entry_header;
|
||||||
if (!drhd->address) {
|
if (!drhd->address) {
|
||||||
/* Promote an attitude of violence to a BIOS engineer today */
|
warn_invalid_dmar(0, "");
|
||||||
WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
|
|
||||||
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
|
||||||
dmi_get_system_info(DMI_BIOS_VENDOR),
|
|
||||||
dmi_get_system_info(DMI_BIOS_VERSION),
|
|
||||||
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
|
||||||
bios_warned = 1;
|
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,14 +670,8 @@ int __init check_zero_address(void)
|
||||||
ecap = dmar_readq(addr + DMAR_ECAP_REG);
|
ecap = dmar_readq(addr + DMAR_ECAP_REG);
|
||||||
early_iounmap(addr, VTD_PAGE_SIZE);
|
early_iounmap(addr, VTD_PAGE_SIZE);
|
||||||
if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) {
|
if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) {
|
||||||
/* Promote an attitude of violence to a BIOS engineer today */
|
warn_invalid_dmar(drhd->address,
|
||||||
WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
|
" returns all ones");
|
||||||
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
|
||||||
drhd->address,
|
|
||||||
dmi_get_system_info(DMI_BIOS_VENDOR),
|
|
||||||
dmi_get_system_info(DMI_BIOS_VERSION),
|
|
||||||
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
|
||||||
bios_warned = 1;
|
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -731,14 +736,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
|
||||||
int msagaw = 0;
|
int msagaw = 0;
|
||||||
|
|
||||||
if (!drhd->reg_base_addr) {
|
if (!drhd->reg_base_addr) {
|
||||||
if (!bios_warned) {
|
warn_invalid_dmar(0, "");
|
||||||
WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n"
|
|
||||||
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
|
||||||
dmi_get_system_info(DMI_BIOS_VENDOR),
|
|
||||||
dmi_get_system_info(DMI_BIOS_VERSION),
|
|
||||||
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
|
||||||
bios_warned = 1;
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,16 +756,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
|
||||||
iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
|
iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
|
||||||
|
|
||||||
if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) {
|
if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) {
|
||||||
if (!bios_warned) {
|
warn_invalid_dmar(drhd->reg_base_addr, " returns all ones");
|
||||||
/* Promote an attitude of violence to a BIOS engineer today */
|
|
||||||
WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
|
|
||||||
"BIOS vendor: %s; Ver: %s; Product Version: %s\n",
|
|
||||||
drhd->reg_base_addr,
|
|
||||||
dmi_get_system_info(DMI_BIOS_VENDOR),
|
|
||||||
dmi_get_system_info(DMI_BIOS_VERSION),
|
|
||||||
dmi_get_system_info(DMI_PRODUCT_VERSION));
|
|
||||||
bios_warned = 1;
|
|
||||||
}
|
|
||||||
goto err_unmap;
|
goto err_unmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -806,7 +795,8 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
|
||||||
}
|
}
|
||||||
|
|
||||||
ver = readl(iommu->reg + DMAR_VER_REG);
|
ver = readl(iommu->reg + DMAR_VER_REG);
|
||||||
pr_info("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
|
pr_info("IOMMU %d: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n",
|
||||||
|
iommu->seq_id,
|
||||||
(unsigned long long)drhd->reg_base_addr,
|
(unsigned long long)drhd->reg_base_addr,
|
||||||
DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
|
DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
|
||||||
(unsigned long long)iommu->cap,
|
(unsigned long long)iommu->cap,
|
||||||
|
@ -1457,9 +1447,11 @@ int dmar_reenable_qi(struct intel_iommu *iommu)
|
||||||
/*
|
/*
|
||||||
* Check interrupt remapping support in DMAR table description.
|
* Check interrupt remapping support in DMAR table description.
|
||||||
*/
|
*/
|
||||||
int dmar_ir_support(void)
|
int __init dmar_ir_support(void)
|
||||||
{
|
{
|
||||||
struct acpi_table_dmar *dmar;
|
struct acpi_table_dmar *dmar;
|
||||||
dmar = (struct acpi_table_dmar *)dmar_tbl;
|
dmar = (struct acpi_table_dmar *)dmar_tbl;
|
||||||
|
if (!dmar)
|
||||||
|
return 0;
|
||||||
return dmar->flags & 0x1;
|
return dmar->flags & 0x1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -491,13 +491,11 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain)
|
||||||
|
|
||||||
domain->iommu_coherency = 1;
|
domain->iommu_coherency = 1;
|
||||||
|
|
||||||
i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
|
for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
|
||||||
for (; i < g_num_of_iommus; ) {
|
|
||||||
if (!ecap_coherent(g_iommus[i]->ecap)) {
|
if (!ecap_coherent(g_iommus[i]->ecap)) {
|
||||||
domain->iommu_coherency = 0;
|
domain->iommu_coherency = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,13 +505,11 @@ static void domain_update_iommu_snooping(struct dmar_domain *domain)
|
||||||
|
|
||||||
domain->iommu_snooping = 1;
|
domain->iommu_snooping = 1;
|
||||||
|
|
||||||
i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
|
for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
|
||||||
for (; i < g_num_of_iommus; ) {
|
|
||||||
if (!ecap_sc_support(g_iommus[i]->ecap)) {
|
if (!ecap_sc_support(g_iommus[i]->ecap)) {
|
||||||
domain->iommu_snooping = 0;
|
domain->iommu_snooping = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1068,7 +1064,7 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
|
static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
|
||||||
unsigned long pfn, unsigned int pages)
|
unsigned long pfn, unsigned int pages, int map)
|
||||||
{
|
{
|
||||||
unsigned int mask = ilog2(__roundup_pow_of_two(pages));
|
unsigned int mask = ilog2(__roundup_pow_of_two(pages));
|
||||||
uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
|
uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
|
||||||
|
@ -1089,10 +1085,10 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
|
||||||
DMA_TLB_PSI_FLUSH);
|
DMA_TLB_PSI_FLUSH);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In caching mode, domain ID 0 is reserved for non-present to present
|
* In caching mode, changes of pages from non-present to present require
|
||||||
* mapping flush. Device IOTLB doesn't need to be flushed in this case.
|
* flush. However, device IOTLB doesn't need to be flushed in this case.
|
||||||
*/
|
*/
|
||||||
if (!cap_caching_mode(iommu->cap) || did)
|
if (!cap_caching_mode(iommu->cap) || !map)
|
||||||
iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
|
iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1154,7 +1150,8 @@ static int iommu_init_domains(struct intel_iommu *iommu)
|
||||||
unsigned long nlongs;
|
unsigned long nlongs;
|
||||||
|
|
||||||
ndomains = cap_ndoms(iommu->cap);
|
ndomains = cap_ndoms(iommu->cap);
|
||||||
pr_debug("Number of Domains supportd <%ld>\n", ndomains);
|
pr_debug("IOMMU %d: Number of Domains supportd <%ld>\n", iommu->seq_id,
|
||||||
|
ndomains);
|
||||||
nlongs = BITS_TO_LONGS(ndomains);
|
nlongs = BITS_TO_LONGS(ndomains);
|
||||||
|
|
||||||
spin_lock_init(&iommu->lock);
|
spin_lock_init(&iommu->lock);
|
||||||
|
@ -1194,8 +1191,7 @@ void free_dmar_iommu(struct intel_iommu *iommu)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if ((iommu->domains) && (iommu->domain_ids)) {
|
if ((iommu->domains) && (iommu->domain_ids)) {
|
||||||
i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
|
for_each_set_bit(i, iommu->domain_ids, cap_ndoms(iommu->cap)) {
|
||||||
for (; i < cap_ndoms(iommu->cap); ) {
|
|
||||||
domain = iommu->domains[i];
|
domain = iommu->domains[i];
|
||||||
clear_bit(i, iommu->domain_ids);
|
clear_bit(i, iommu->domain_ids);
|
||||||
|
|
||||||
|
@ -1207,9 +1203,6 @@ void free_dmar_iommu(struct intel_iommu *iommu)
|
||||||
domain_exit(domain);
|
domain_exit(domain);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&domain->iommu_lock, flags);
|
spin_unlock_irqrestore(&domain->iommu_lock, flags);
|
||||||
|
|
||||||
i = find_next_bit(iommu->domain_ids,
|
|
||||||
cap_ndoms(iommu->cap), i+1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1292,14 +1285,11 @@ static void iommu_detach_domain(struct dmar_domain *domain,
|
||||||
|
|
||||||
spin_lock_irqsave(&iommu->lock, flags);
|
spin_lock_irqsave(&iommu->lock, flags);
|
||||||
ndomains = cap_ndoms(iommu->cap);
|
ndomains = cap_ndoms(iommu->cap);
|
||||||
num = find_first_bit(iommu->domain_ids, ndomains);
|
for_each_set_bit(num, iommu->domain_ids, ndomains) {
|
||||||
for (; num < ndomains; ) {
|
|
||||||
if (iommu->domains[num] == domain) {
|
if (iommu->domains[num] == domain) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
num = find_next_bit(iommu->domain_ids,
|
|
||||||
cap_ndoms(iommu->cap), num+1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
|
@ -1485,15 +1475,12 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
|
||||||
|
|
||||||
/* find an available domain id for this device in iommu */
|
/* find an available domain id for this device in iommu */
|
||||||
ndomains = cap_ndoms(iommu->cap);
|
ndomains = cap_ndoms(iommu->cap);
|
||||||
num = find_first_bit(iommu->domain_ids, ndomains);
|
for_each_set_bit(num, iommu->domain_ids, ndomains) {
|
||||||
for (; num < ndomains; ) {
|
|
||||||
if (iommu->domains[num] == domain) {
|
if (iommu->domains[num] == domain) {
|
||||||
id = num;
|
id = num;
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
num = find_next_bit(iommu->domain_ids,
|
|
||||||
cap_ndoms(iommu->cap), num+1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found == 0) {
|
if (found == 0) {
|
||||||
|
@ -1558,7 +1545,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
|
||||||
(((u16)bus) << 8) | devfn,
|
(((u16)bus) << 8) | devfn,
|
||||||
DMA_CCMD_MASK_NOBIT,
|
DMA_CCMD_MASK_NOBIT,
|
||||||
DMA_CCMD_DEVICE_INVL);
|
DMA_CCMD_DEVICE_INVL);
|
||||||
iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH);
|
iommu->flush.flush_iotlb(iommu, domain->id, 0, 0, DMA_TLB_DSI_FLUSH);
|
||||||
} else {
|
} else {
|
||||||
iommu_flush_write_buffer(iommu);
|
iommu_flush_write_buffer(iommu);
|
||||||
}
|
}
|
||||||
|
@ -2333,14 +2320,16 @@ int __init init_dmars(void)
|
||||||
*/
|
*/
|
||||||
iommu->flush.flush_context = __iommu_flush_context;
|
iommu->flush.flush_context = __iommu_flush_context;
|
||||||
iommu->flush.flush_iotlb = __iommu_flush_iotlb;
|
iommu->flush.flush_iotlb = __iommu_flush_iotlb;
|
||||||
printk(KERN_INFO "IOMMU 0x%Lx: using Register based "
|
printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
|
||||||
"invalidation\n",
|
"invalidation\n",
|
||||||
|
iommu->seq_id,
|
||||||
(unsigned long long)drhd->reg_base_addr);
|
(unsigned long long)drhd->reg_base_addr);
|
||||||
} else {
|
} else {
|
||||||
iommu->flush.flush_context = qi_flush_context;
|
iommu->flush.flush_context = qi_flush_context;
|
||||||
iommu->flush.flush_iotlb = qi_flush_iotlb;
|
iommu->flush.flush_iotlb = qi_flush_iotlb;
|
||||||
printk(KERN_INFO "IOMMU 0x%Lx: using Queued "
|
printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
|
||||||
"invalidation\n",
|
"invalidation\n",
|
||||||
|
iommu->seq_id,
|
||||||
(unsigned long long)drhd->reg_base_addr);
|
(unsigned long long)drhd->reg_base_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2621,7 +2610,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
|
||||||
|
|
||||||
/* it's a non-present to present mapping. Only flush if caching mode */
|
/* it's a non-present to present mapping. Only flush if caching mode */
|
||||||
if (cap_caching_mode(iommu->cap))
|
if (cap_caching_mode(iommu->cap))
|
||||||
iommu_flush_iotlb_psi(iommu, 0, mm_to_dma_pfn(iova->pfn_lo), size);
|
iommu_flush_iotlb_psi(iommu, domain->id, mm_to_dma_pfn(iova->pfn_lo), size, 1);
|
||||||
else
|
else
|
||||||
iommu_flush_write_buffer(iommu);
|
iommu_flush_write_buffer(iommu);
|
||||||
|
|
||||||
|
@ -2661,15 +2650,24 @@ static void flush_unmaps(void)
|
||||||
if (!deferred_flush[i].next)
|
if (!deferred_flush[i].next)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* In caching mode, global flushes turn emulation expensive */
|
||||||
|
if (!cap_caching_mode(iommu->cap))
|
||||||
iommu->flush.flush_iotlb(iommu, 0, 0, 0,
|
iommu->flush.flush_iotlb(iommu, 0, 0, 0,
|
||||||
DMA_TLB_GLOBAL_FLUSH);
|
DMA_TLB_GLOBAL_FLUSH);
|
||||||
for (j = 0; j < deferred_flush[i].next; j++) {
|
for (j = 0; j < deferred_flush[i].next; j++) {
|
||||||
unsigned long mask;
|
unsigned long mask;
|
||||||
struct iova *iova = deferred_flush[i].iova[j];
|
struct iova *iova = deferred_flush[i].iova[j];
|
||||||
|
struct dmar_domain *domain = deferred_flush[i].domain[j];
|
||||||
|
|
||||||
|
/* On real hardware multiple invalidations are expensive */
|
||||||
|
if (cap_caching_mode(iommu->cap))
|
||||||
|
iommu_flush_iotlb_psi(iommu, domain->id,
|
||||||
|
iova->pfn_lo, iova->pfn_hi - iova->pfn_lo + 1, 0);
|
||||||
|
else {
|
||||||
mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
|
mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
|
||||||
iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
|
iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
|
||||||
(uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
|
(uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
|
||||||
|
}
|
||||||
__free_iova(&deferred_flush[i].domain[j]->iovad, iova);
|
__free_iova(&deferred_flush[i].domain[j]->iovad, iova);
|
||||||
}
|
}
|
||||||
deferred_flush[i].next = 0;
|
deferred_flush[i].next = 0;
|
||||||
|
@ -2750,7 +2748,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
|
||||||
|
|
||||||
if (intel_iommu_strict) {
|
if (intel_iommu_strict) {
|
||||||
iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
|
iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
|
||||||
last_pfn - start_pfn + 1);
|
last_pfn - start_pfn + 1, 0);
|
||||||
/* free iova */
|
/* free iova */
|
||||||
__free_iova(&domain->iovad, iova);
|
__free_iova(&domain->iovad, iova);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2840,7 +2838,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
|
||||||
|
|
||||||
if (intel_iommu_strict) {
|
if (intel_iommu_strict) {
|
||||||
iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
|
iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
|
||||||
last_pfn - start_pfn + 1);
|
last_pfn - start_pfn + 1, 0);
|
||||||
/* free iova */
|
/* free iova */
|
||||||
__free_iova(&domain->iovad, iova);
|
__free_iova(&domain->iovad, iova);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2874,7 +2872,6 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
|
||||||
struct dmar_domain *domain;
|
struct dmar_domain *domain;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
int prot = 0;
|
int prot = 0;
|
||||||
size_t offset_pfn = 0;
|
|
||||||
struct iova *iova = NULL;
|
struct iova *iova = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
|
@ -2928,7 +2925,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
|
||||||
|
|
||||||
/* it's a non-present to present mapping. Only flush if caching mode */
|
/* it's a non-present to present mapping. Only flush if caching mode */
|
||||||
if (cap_caching_mode(iommu->cap))
|
if (cap_caching_mode(iommu->cap))
|
||||||
iommu_flush_iotlb_psi(iommu, 0, start_vpfn, offset_pfn);
|
iommu_flush_iotlb_psi(iommu, domain->id, start_vpfn, size, 1);
|
||||||
else
|
else
|
||||||
iommu_flush_write_buffer(iommu);
|
iommu_flush_write_buffer(iommu);
|
||||||
|
|
||||||
|
@ -3436,22 +3433,6 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
|
||||||
/* domain id for virtual machine, it won't be set in context */
|
/* domain id for virtual machine, it won't be set in context */
|
||||||
static unsigned long vm_domid;
|
static unsigned long vm_domid;
|
||||||
|
|
||||||
static int vm_domain_min_agaw(struct dmar_domain *domain)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int min_agaw = domain->agaw;
|
|
||||||
|
|
||||||
i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus);
|
|
||||||
for (; i < g_num_of_iommus; ) {
|
|
||||||
if (min_agaw > g_iommus[i]->agaw)
|
|
||||||
min_agaw = g_iommus[i]->agaw;
|
|
||||||
|
|
||||||
i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return min_agaw;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct dmar_domain *iommu_alloc_vm_domain(void)
|
static struct dmar_domain *iommu_alloc_vm_domain(void)
|
||||||
{
|
{
|
||||||
struct dmar_domain *domain;
|
struct dmar_domain *domain;
|
||||||
|
@ -3512,8 +3493,7 @@ static void iommu_free_vm_domain(struct dmar_domain *domain)
|
||||||
iommu = drhd->iommu;
|
iommu = drhd->iommu;
|
||||||
|
|
||||||
ndomains = cap_ndoms(iommu->cap);
|
ndomains = cap_ndoms(iommu->cap);
|
||||||
i = find_first_bit(iommu->domain_ids, ndomains);
|
for_each_set_bit(i, iommu->domain_ids, ndomains) {
|
||||||
for (; i < ndomains; ) {
|
|
||||||
if (iommu->domains[i] == domain) {
|
if (iommu->domains[i] == domain) {
|
||||||
spin_lock_irqsave(&iommu->lock, flags);
|
spin_lock_irqsave(&iommu->lock, flags);
|
||||||
clear_bit(i, iommu->domain_ids);
|
clear_bit(i, iommu->domain_ids);
|
||||||
|
@ -3521,7 +3501,6 @@ static void iommu_free_vm_domain(struct dmar_domain *domain)
|
||||||
spin_unlock_irqrestore(&iommu->lock, flags);
|
spin_unlock_irqrestore(&iommu->lock, flags);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i = find_next_bit(iommu->domain_ids, ndomains, i+1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3582,7 +3561,6 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
|
||||||
struct pci_dev *pdev = to_pci_dev(dev);
|
struct pci_dev *pdev = to_pci_dev(dev);
|
||||||
struct intel_iommu *iommu;
|
struct intel_iommu *iommu;
|
||||||
int addr_width;
|
int addr_width;
|
||||||
u64 end;
|
|
||||||
|
|
||||||
/* normally pdev is not mapped */
|
/* normally pdev is not mapped */
|
||||||
if (unlikely(domain_context_mapped(pdev))) {
|
if (unlikely(domain_context_mapped(pdev))) {
|
||||||
|
@ -3605,14 +3583,30 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
|
||||||
|
|
||||||
/* check if this iommu agaw is sufficient for max mapped address */
|
/* check if this iommu agaw is sufficient for max mapped address */
|
||||||
addr_width = agaw_to_width(iommu->agaw);
|
addr_width = agaw_to_width(iommu->agaw);
|
||||||
end = DOMAIN_MAX_ADDR(addr_width);
|
if (addr_width > cap_mgaw(iommu->cap))
|
||||||
end = end & VTD_PAGE_MASK;
|
addr_width = cap_mgaw(iommu->cap);
|
||||||
if (end < dmar_domain->max_addr) {
|
|
||||||
printk(KERN_ERR "%s: iommu agaw (%d) is not "
|
if (dmar_domain->max_addr > (1LL << addr_width)) {
|
||||||
|
printk(KERN_ERR "%s: iommu width (%d) is not "
|
||||||
"sufficient for the mapped address (%llx)\n",
|
"sufficient for the mapped address (%llx)\n",
|
||||||
__func__, iommu->agaw, dmar_domain->max_addr);
|
__func__, addr_width, dmar_domain->max_addr);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
dmar_domain->gaw = addr_width;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Knock out extra levels of page tables if necessary
|
||||||
|
*/
|
||||||
|
while (iommu->agaw < dmar_domain->agaw) {
|
||||||
|
struct dma_pte *pte;
|
||||||
|
|
||||||
|
pte = dmar_domain->pgd;
|
||||||
|
if (dma_pte_present(pte)) {
|
||||||
|
free_pgtable_page(dmar_domain->pgd);
|
||||||
|
dmar_domain->pgd = (struct dma_pte *)dma_pte_addr(pte);
|
||||||
|
}
|
||||||
|
dmar_domain->agaw--;
|
||||||
|
}
|
||||||
|
|
||||||
return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
|
return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
|
||||||
}
|
}
|
||||||
|
@ -3632,7 +3626,6 @@ static int intel_iommu_map(struct iommu_domain *domain,
|
||||||
{
|
{
|
||||||
struct dmar_domain *dmar_domain = domain->priv;
|
struct dmar_domain *dmar_domain = domain->priv;
|
||||||
u64 max_addr;
|
u64 max_addr;
|
||||||
int addr_width;
|
|
||||||
int prot = 0;
|
int prot = 0;
|
||||||
size_t size;
|
size_t size;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -3647,18 +3640,14 @@ static int intel_iommu_map(struct iommu_domain *domain,
|
||||||
size = PAGE_SIZE << gfp_order;
|
size = PAGE_SIZE << gfp_order;
|
||||||
max_addr = iova + size;
|
max_addr = iova + size;
|
||||||
if (dmar_domain->max_addr < max_addr) {
|
if (dmar_domain->max_addr < max_addr) {
|
||||||
int min_agaw;
|
|
||||||
u64 end;
|
u64 end;
|
||||||
|
|
||||||
/* check if minimum agaw is sufficient for mapped address */
|
/* check if minimum agaw is sufficient for mapped address */
|
||||||
min_agaw = vm_domain_min_agaw(dmar_domain);
|
end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
|
||||||
addr_width = agaw_to_width(min_agaw);
|
|
||||||
end = DOMAIN_MAX_ADDR(addr_width);
|
|
||||||
end = end & VTD_PAGE_MASK;
|
|
||||||
if (end < max_addr) {
|
if (end < max_addr) {
|
||||||
printk(KERN_ERR "%s: iommu agaw (%d) is not "
|
printk(KERN_ERR "%s: iommu width (%d) is not "
|
||||||
"sufficient for the mapped address (%llx)\n",
|
"sufficient for the mapped address (%llx)\n",
|
||||||
__func__, min_agaw, max_addr);
|
__func__, dmar_domain->gaw, max_addr);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
dmar_domain->max_addr = max_addr;
|
dmar_domain->max_addr = max_addr;
|
||||||
|
|
|
@ -833,8 +833,8 @@ static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header,
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(KERN_INFO "IOAPIC id %d under DRHD base "
|
printk(KERN_INFO "IOAPIC id %d under DRHD base "
|
||||||
" 0x%Lx\n", scope->enumeration_id,
|
" 0x%Lx IOMMU %d\n", scope->enumeration_id,
|
||||||
drhd->address);
|
drhd->address, iommu->seq_id);
|
||||||
|
|
||||||
ir_parse_one_ioapic_scope(scope, iommu);
|
ir_parse_one_ioapic_scope(scope, iommu);
|
||||||
} else if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_HPET) {
|
} else if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_HPET) {
|
||||||
|
|
|
@ -26,6 +26,9 @@ struct bug_entry {
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
#define BUGFLAG_WARNING (1 << 0)
|
#define BUGFLAG_WARNING (1 << 0)
|
||||||
|
#define BUGFLAG_TAINT(taint) (BUGFLAG_WARNING | ((taint) << 8))
|
||||||
|
#define BUG_GET_TAINT(bug) ((bug)->flags >> 8)
|
||||||
|
|
||||||
#endif /* CONFIG_GENERIC_BUG */
|
#endif /* CONFIG_GENERIC_BUG */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -56,17 +59,25 @@ struct bug_entry {
|
||||||
* appear at runtime. Use the versions with printk format strings
|
* appear at runtime. Use the versions with printk format strings
|
||||||
* to provide better diagnostics.
|
* to provide better diagnostics.
|
||||||
*/
|
*/
|
||||||
#ifndef __WARN
|
#ifndef __WARN_TAINT
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
extern void warn_slowpath_fmt(const char *file, const int line,
|
extern void warn_slowpath_fmt(const char *file, const int line,
|
||||||
const char *fmt, ...) __attribute__((format(printf, 3, 4)));
|
const char *fmt, ...) __attribute__((format(printf, 3, 4)));
|
||||||
|
extern void warn_slowpath_fmt_taint(const char *file, const int line,
|
||||||
|
unsigned taint, const char *fmt, ...)
|
||||||
|
__attribute__((format(printf, 4, 5)));
|
||||||
extern void warn_slowpath_null(const char *file, const int line);
|
extern void warn_slowpath_null(const char *file, const int line);
|
||||||
#define WANT_WARN_ON_SLOWPATH
|
#define WANT_WARN_ON_SLOWPATH
|
||||||
#endif
|
#endif
|
||||||
#define __WARN() warn_slowpath_null(__FILE__, __LINE__)
|
#define __WARN() warn_slowpath_null(__FILE__, __LINE__)
|
||||||
#define __WARN_printf(arg...) warn_slowpath_fmt(__FILE__, __LINE__, arg)
|
#define __WARN_printf(arg...) warn_slowpath_fmt(__FILE__, __LINE__, arg)
|
||||||
|
#define __WARN_printf_taint(taint, arg...) \
|
||||||
|
warn_slowpath_fmt_taint(__FILE__, __LINE__, taint, arg)
|
||||||
#else
|
#else
|
||||||
|
#define __WARN() __WARN_TAINT(TAINT_WARN)
|
||||||
#define __WARN_printf(arg...) do { printk(arg); __WARN(); } while (0)
|
#define __WARN_printf(arg...) do { printk(arg); __WARN(); } while (0)
|
||||||
|
#define __WARN_printf_taint(taint, arg...) \
|
||||||
|
do { printk(arg); __WARN_TAINT(taint); } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef WARN_ON
|
#ifndef WARN_ON
|
||||||
|
@ -87,6 +98,13 @@ extern void warn_slowpath_null(const char *file, const int line);
|
||||||
})
|
})
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define WARN_TAINT(condition, taint, format...) ({ \
|
||||||
|
int __ret_warn_on = !!(condition); \
|
||||||
|
if (unlikely(__ret_warn_on)) \
|
||||||
|
__WARN_printf_taint(taint, format); \
|
||||||
|
unlikely(__ret_warn_on); \
|
||||||
|
})
|
||||||
|
|
||||||
#else /* !CONFIG_BUG */
|
#else /* !CONFIG_BUG */
|
||||||
#ifndef HAVE_ARCH_BUG
|
#ifndef HAVE_ARCH_BUG
|
||||||
#define BUG() do {} while(0)
|
#define BUG() do {} while(0)
|
||||||
|
@ -110,6 +128,8 @@ extern void warn_slowpath_null(const char *file, const int line);
|
||||||
})
|
})
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define WARN_TAINT(condition, taint, format...) WARN_ON(condition)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WARN_ON_ONCE(condition) ({ \
|
#define WARN_ON_ONCE(condition) ({ \
|
||||||
|
@ -132,6 +152,16 @@ extern void warn_slowpath_null(const char *file, const int line);
|
||||||
unlikely(__ret_warn_once); \
|
unlikely(__ret_warn_once); \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#define WARN_TAINT_ONCE(condition, taint, format...) ({ \
|
||||||
|
static bool __warned; \
|
||||||
|
int __ret_warn_once = !!(condition); \
|
||||||
|
\
|
||||||
|
if (unlikely(__ret_warn_once)) \
|
||||||
|
if (WARN_TAINT(!__warned, taint, format)) \
|
||||||
|
__warned = true; \
|
||||||
|
unlikely(__ret_warn_once); \
|
||||||
|
})
|
||||||
|
|
||||||
#define WARN_ON_RATELIMIT(condition, state) \
|
#define WARN_ON_RATELIMIT(condition, state) \
|
||||||
WARN_ON((condition) && __ratelimit(state))
|
WARN_ON((condition) && __ratelimit(state))
|
||||||
|
|
||||||
|
|
|
@ -346,6 +346,7 @@ extern enum system_states {
|
||||||
#define TAINT_OVERRIDDEN_ACPI_TABLE 8
|
#define TAINT_OVERRIDDEN_ACPI_TABLE 8
|
||||||
#define TAINT_WARN 9
|
#define TAINT_WARN 9
|
||||||
#define TAINT_CRAP 10
|
#define TAINT_CRAP 10
|
||||||
|
#define TAINT_FIRMWARE_WORKAROUND 11
|
||||||
|
|
||||||
extern void dump_stack(void) __cold;
|
extern void dump_stack(void) __cold;
|
||||||
|
|
||||||
|
|
|
@ -334,6 +334,16 @@ struct pci_dev {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_PCI_IOV
|
||||||
|
if (dev->is_virtfn)
|
||||||
|
dev = dev->physfn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
extern struct pci_dev *alloc_pci_dev(void);
|
extern struct pci_dev *alloc_pci_dev(void);
|
||||||
|
|
||||||
#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
|
#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
|
||||||
|
|
|
@ -178,6 +178,7 @@ static const struct tnt tnts[] = {
|
||||||
{ TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
|
{ TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
|
||||||
{ TAINT_WARN, 'W', ' ' },
|
{ TAINT_WARN, 'W', ' ' },
|
||||||
{ TAINT_CRAP, 'C', ' ' },
|
{ TAINT_CRAP, 'C', ' ' },
|
||||||
|
{ TAINT_FIRMWARE_WORKAROUND, 'I', ' ' },
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -194,6 +195,7 @@ static const struct tnt tnts[] = {
|
||||||
* 'A' - ACPI table overridden.
|
* 'A' - ACPI table overridden.
|
||||||
* 'W' - Taint on warning.
|
* 'W' - Taint on warning.
|
||||||
* 'C' - modules from drivers/staging are loaded.
|
* 'C' - modules from drivers/staging are loaded.
|
||||||
|
* 'I' - Working around severe firmware bug.
|
||||||
*
|
*
|
||||||
* The string is overwritten by the next call to print_tainted().
|
* The string is overwritten by the next call to print_tainted().
|
||||||
*/
|
*/
|
||||||
|
@ -365,7 +367,8 @@ struct slowpath_args {
|
||||||
va_list args;
|
va_list args;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void warn_slowpath_common(const char *file, int line, void *caller, struct slowpath_args *args)
|
static void warn_slowpath_common(const char *file, int line, void *caller,
|
||||||
|
unsigned taint, struct slowpath_args *args)
|
||||||
{
|
{
|
||||||
const char *board;
|
const char *board;
|
||||||
|
|
||||||
|
@ -381,7 +384,7 @@ static void warn_slowpath_common(const char *file, int line, void *caller, struc
|
||||||
print_modules();
|
print_modules();
|
||||||
dump_stack();
|
dump_stack();
|
||||||
print_oops_end_marker();
|
print_oops_end_marker();
|
||||||
add_taint(TAINT_WARN);
|
add_taint(taint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
|
void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
|
||||||
|
@ -390,14 +393,29 @@ void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
|
||||||
|
|
||||||
args.fmt = fmt;
|
args.fmt = fmt;
|
||||||
va_start(args.args, fmt);
|
va_start(args.args, fmt);
|
||||||
warn_slowpath_common(file, line, __builtin_return_address(0), &args);
|
warn_slowpath_common(file, line, __builtin_return_address(0),
|
||||||
|
TAINT_WARN, &args);
|
||||||
va_end(args.args);
|
va_end(args.args);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(warn_slowpath_fmt);
|
EXPORT_SYMBOL(warn_slowpath_fmt);
|
||||||
|
|
||||||
|
void warn_slowpath_fmt_taint(const char *file, int line,
|
||||||
|
unsigned taint, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
struct slowpath_args args;
|
||||||
|
|
||||||
|
args.fmt = fmt;
|
||||||
|
va_start(args.args, fmt);
|
||||||
|
warn_slowpath_common(file, line, __builtin_return_address(0),
|
||||||
|
taint, &args);
|
||||||
|
va_end(args.args);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(warn_slowpath_fmt_taint);
|
||||||
|
|
||||||
void warn_slowpath_null(const char *file, int line)
|
void warn_slowpath_null(const char *file, int line)
|
||||||
{
|
{
|
||||||
warn_slowpath_common(file, line, __builtin_return_address(0), NULL);
|
warn_slowpath_common(file, line, __builtin_return_address(0),
|
||||||
|
TAINT_WARN, NULL);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(warn_slowpath_null);
|
EXPORT_SYMBOL(warn_slowpath_null);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -165,7 +165,7 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
|
||||||
(void *)bugaddr);
|
(void *)bugaddr);
|
||||||
|
|
||||||
show_regs(regs);
|
show_regs(regs);
|
||||||
add_taint(TAINT_WARN);
|
add_taint(BUG_GET_TAINT(bug));
|
||||||
return BUG_TRAP_TYPE_WARN;
|
return BUG_TRAP_TYPE_WARN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue