Commit be98eb2c authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.infradead.org/iommu-2.6

* git://git.infradead.org/iommu-2.6:
  Intel-IOMMU, intr-remap: source-id checking
  Intel-IOMMU, intr-remap: set the whole 128bits of irte when modify/free it
  IOMMU Identity Mapping Support (drivers/pci/intel_iommu.c)
parents cf5434e8 f007e99c
...@@ -1414,6 +1414,9 @@ int setup_ioapic_entry(int apic_id, int irq, ...@@ -1414,6 +1414,9 @@ int setup_ioapic_entry(int apic_id, int irq,
irte.vector = vector; irte.vector = vector;
irte.dest_id = IRTE_DEST(destination); irte.dest_id = IRTE_DEST(destination);
/* Set source-id of interrupt request */
set_ioapic_sid(&irte, apic_id);
modify_irte(irq, &irte); modify_irte(irq, &irte);
ir_entry->index2 = (index >> 15) & 0x1; ir_entry->index2 = (index >> 15) & 0x1;
...@@ -3290,6 +3293,9 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms ...@@ -3290,6 +3293,9 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
irte.vector = cfg->vector; irte.vector = cfg->vector;
irte.dest_id = IRTE_DEST(dest); irte.dest_id = IRTE_DEST(dest);
/* Set source-id of interrupt request */
set_msi_sid(&irte, pdev);
modify_irte(irq, &irte); modify_irte(irq, &irte);
msg->address_hi = MSI_ADDR_BASE_HI; msg->address_hi = MSI_ADDR_BASE_HI;
......
This diff is collapsed.
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <linux/intel-iommu.h> #include <linux/intel-iommu.h>
#include "intr_remapping.h" #include "intr_remapping.h"
#include <acpi/acpi.h> #include <acpi/acpi.h>
#include <asm/pci-direct.h>
#include "pci.h"
static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
static int ir_ioapic_num; static int ir_ioapic_num;
...@@ -314,7 +316,8 @@ int modify_irte(int irq, struct irte *irte_modified) ...@@ -314,7 +316,8 @@ int modify_irte(int irq, struct irte *irte_modified)
index = irq_iommu->irte_index + irq_iommu->sub_handle; index = irq_iommu->irte_index + irq_iommu->sub_handle;
irte = &iommu->ir_table->base[index]; irte = &iommu->ir_table->base[index];
set_64bit((unsigned long *)irte, irte_modified->low); set_64bit((unsigned long *)&irte->low, irte_modified->low);
set_64bit((unsigned long *)&irte->high, irte_modified->high);
__iommu_flush_cache(iommu, irte, sizeof(*irte)); __iommu_flush_cache(iommu, irte, sizeof(*irte));
rc = qi_flush_iec(iommu, index, 0); rc = qi_flush_iec(iommu, index, 0);
...@@ -369,12 +372,32 @@ struct intel_iommu *map_dev_to_ir(struct pci_dev *dev) ...@@ -369,12 +372,32 @@ struct intel_iommu *map_dev_to_ir(struct pci_dev *dev)
return drhd->iommu; return drhd->iommu;
} }
static int clear_entries(struct irq_2_iommu *irq_iommu)
{
struct irte *start, *entry, *end;
struct intel_iommu *iommu;
int index;
if (irq_iommu->sub_handle)
return 0;
iommu = irq_iommu->iommu;
index = irq_iommu->irte_index + irq_iommu->sub_handle;
start = iommu->ir_table->base + index;
end = start + (1 << irq_iommu->irte_mask);
for (entry = start; entry < end; entry++) {
set_64bit((unsigned long *)&entry->low, 0);
set_64bit((unsigned long *)&entry->high, 0);
}
return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
}
int free_irte(int irq) int free_irte(int irq)
{ {
int rc = 0; int rc = 0;
int index, i;
struct irte *irte;
struct intel_iommu *iommu;
struct irq_2_iommu *irq_iommu; struct irq_2_iommu *irq_iommu;
unsigned long flags; unsigned long flags;
...@@ -385,16 +408,7 @@ int free_irte(int irq) ...@@ -385,16 +408,7 @@ int free_irte(int irq)
return -1; return -1;
} }
iommu = irq_iommu->iommu; rc = clear_entries(irq_iommu);
index = irq_iommu->irte_index + irq_iommu->sub_handle;
irte = &iommu->ir_table->base[index];
if (!irq_iommu->sub_handle) {
for (i = 0; i < (1 << irq_iommu->irte_mask); i++)
set_64bit((unsigned long *)(irte + i), 0);
rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask);
}
irq_iommu->iommu = NULL; irq_iommu->iommu = NULL;
irq_iommu->irte_index = 0; irq_iommu->irte_index = 0;
...@@ -406,6 +420,91 @@ int free_irte(int irq) ...@@ -406,6 +420,91 @@ int free_irte(int irq)
return rc; return rc;
} }
/*
* source validation type
*/
#define SVT_NO_VERIFY 0x0 /* no verification is required */
#define SVT_VERIFY_SID_SQ 0x1 /* verify using SID and SQ fiels */
#define SVT_VERIFY_BUS 0x2 /* verify bus of request-id */
/*
* source-id qualifier
*/
#define SQ_ALL_16 0x0 /* verify all 16 bits of request-id */
#define SQ_13_IGNORE_1 0x1 /* verify most significant 13 bits, ignore
* the third least significant bit
*/
#define SQ_13_IGNORE_2 0x2 /* verify most significant 13 bits, ignore
* the second and third least significant bits
*/
#define SQ_13_IGNORE_3 0x3 /* verify most significant 13 bits, ignore
* the least three significant bits
*/
/*
* set SVT, SQ and SID fields of irte to verify
* source ids of interrupt requests
*/
static void set_irte_sid(struct irte *irte, unsigned int svt,
unsigned int sq, unsigned int sid)
{
irte->svt = svt;
irte->sq = sq;
irte->sid = sid;
}
int set_ioapic_sid(struct irte *irte, int apic)
{
int i;
u16 sid = 0;
if (!irte)
return -1;
for (i = 0; i < MAX_IO_APICS; i++) {
if (ir_ioapic[i].id == apic) {
sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn;
break;
}
}
if (sid == 0) {
pr_warning("Failed to set source-id of IOAPIC (%d)\n", apic);
return -1;
}
set_irte_sid(irte, 1, 0, sid);
return 0;
}
int set_msi_sid(struct irte *irte, struct pci_dev *dev)
{
struct pci_dev *bridge;
if (!irte || !dev)
return -1;
/* PCIe device or Root Complex integrated PCI device */
if (dev->is_pcie || !dev->bus->parent) {
set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
(dev->bus->number << 8) | dev->devfn);
return 0;
}
bridge = pci_find_upstream_pcie_bridge(dev);
if (bridge) {
if (bridge->is_pcie) /* this is a PCIE-to-PCI/PCIX bridge */
set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16,
(bridge->bus->number << 8) | dev->bus->number);
else /* this is a legacy PCI bridge */
set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
(bridge->bus->number << 8) | bridge->devfn);
}
return 0;
}
static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
{ {
u64 addr; u64 addr;
...@@ -612,6 +711,35 @@ int __init enable_intr_remapping(int eim) ...@@ -612,6 +711,35 @@ int __init enable_intr_remapping(int eim)
return -1; return -1;
} }
static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
struct intel_iommu *iommu)
{
struct acpi_dmar_pci_path *path;
u8 bus;
int count;
bus = scope->bus;
path = (struct acpi_dmar_pci_path *)(scope + 1);
count = (scope->length - sizeof(struct acpi_dmar_device_scope))
/ sizeof(struct acpi_dmar_pci_path);
while (--count > 0) {
/*
* Access PCI directly due to the PCI
* subsystem isn't initialized yet.
*/
bus = read_pci_config_byte(bus, path->dev, path->fn,
PCI_SECONDARY_BUS);
path++;
}
ir_ioapic[ir_ioapic_num].bus = bus;
ir_ioapic[ir_ioapic_num].devfn = PCI_DEVFN(path->dev, path->fn);
ir_ioapic[ir_ioapic_num].iommu = iommu;
ir_ioapic[ir_ioapic_num].id = scope->enumeration_id;
ir_ioapic_num++;
}
static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
struct intel_iommu *iommu) struct intel_iommu *iommu)
{ {
...@@ -636,9 +764,7 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, ...@@ -636,9 +764,7 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
" 0x%Lx\n", scope->enumeration_id, " 0x%Lx\n", scope->enumeration_id,
drhd->address); drhd->address);
ir_ioapic[ir_ioapic_num].iommu = iommu; ir_parse_one_ioapic_scope(scope, iommu);
ir_ioapic[ir_ioapic_num].id = scope->enumeration_id;
ir_ioapic_num++;
} }
start += scope->length; start += scope->length;
} }
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
struct ioapic_scope { struct ioapic_scope {
struct intel_iommu *iommu; struct intel_iommu *iommu;
unsigned int id; unsigned int id;
unsigned int bus; /* PCI bus number */
unsigned int devfn; /* PCI devfn number */
}; };
#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
...@@ -126,6 +126,8 @@ extern int free_irte(int irq); ...@@ -126,6 +126,8 @@ extern int free_irte(int irq);
extern int irq_remapped(int irq); extern int irq_remapped(int irq);
extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev); extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev);
extern struct intel_iommu *map_ioapic_to_ir(int apic); extern struct intel_iommu *map_ioapic_to_ir(int apic);
extern int set_ioapic_sid(struct irte *irte, int apic);
extern int set_msi_sid(struct irte *irte, struct pci_dev *dev);
#else #else
static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
{ {
...@@ -156,6 +158,15 @@ static inline struct intel_iommu *map_ioapic_to_ir(int apic) ...@@ -156,6 +158,15 @@ static inline struct intel_iommu *map_ioapic_to_ir(int apic)
{ {
return NULL; return NULL;
} }
static inline int set_ioapic_sid(struct irte *irte, int apic)
{
return 0;
}
static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev)
{
return 0;
}
#define irq_remapped(irq) (0) #define irq_remapped(irq) (0)
#define enable_intr_remapping(mode) (-1) #define enable_intr_remapping(mode) (-1)
#define disable_intr_remapping() (0) #define disable_intr_remapping() (0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment