|
@@ -2,6 +2,7 @@
|
|
|
#include <linux/dmar.h>
|
|
|
#include <linux/spinlock.h>
|
|
|
#include <linux/jiffies.h>
|
|
|
+#include <linux/hpet.h>
|
|
|
#include <linux/pci.h>
|
|
|
#include <linux/irq.h>
|
|
|
#include <asm/io_apic.h>
|
|
@@ -14,7 +15,8 @@
|
|
|
#include "pci.h"
|
|
|
|
|
|
static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
|
|
|
-static int ir_ioapic_num;
|
|
|
+static struct hpet_scope ir_hpet[MAX_HPET_TBS];
|
|
|
+static int ir_ioapic_num, ir_hpet_num;
|
|
|
int intr_remapping_enabled;
|
|
|
|
|
|
static int disable_intremap;
|
|
@@ -351,6 +353,16 @@ int flush_irte(int irq)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < MAX_HPET_TBS; i++)
|
|
|
+ if (ir_hpet[i].id == hpet_id)
|
|
|
+ return ir_hpet[i].iommu;
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
struct intel_iommu *map_ioapic_to_ir(int apic)
|
|
|
{
|
|
|
int i;
|
|
@@ -478,6 +490,36 @@ int set_ioapic_sid(struct irte *irte, int apic)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int set_hpet_sid(struct irte *irte, u8 id)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ u16 sid = 0;
|
|
|
+
|
|
|
+ if (!irte)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ for (i = 0; i < MAX_HPET_TBS; i++) {
|
|
|
+ if (ir_hpet[i].id == id) {
|
|
|
+ sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sid == 0) {
|
|
|
+ pr_warning("Failed to set source-id of HPET block (%d)\n", id);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Should really use SQ_ALL_16. Some platforms are broken.
|
|
|
+ * While we figure out the right quirks for these broken platforms, use
|
|
|
+ * SQ_13_IGNORE_3 for now.
|
|
|
+ */
|
|
|
+ set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_13_IGNORE_3, sid);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int set_msi_sid(struct irte *irte, struct pci_dev *dev)
|
|
|
{
|
|
|
struct pci_dev *bridge;
|
|
@@ -711,6 +753,34 @@ error:
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+static void ir_parse_one_hpet_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_hpet[ir_hpet_num].bus = bus;
|
|
|
+ ir_hpet[ir_hpet_num].devfn = PCI_DEVFN(path->dev, path->fn);
|
|
|
+ ir_hpet[ir_hpet_num].iommu = iommu;
|
|
|
+ ir_hpet[ir_hpet_num].id = scope->enumeration_id;
|
|
|
+ ir_hpet_num++;
|
|
|
+}
|
|
|
+
|
|
|
static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
|
|
|
struct intel_iommu *iommu)
|
|
|
{
|
|
@@ -740,8 +810,8 @@ static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
|
|
|
ir_ioapic_num++;
|
|
|
}
|
|
|
|
|
|
-static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
|
|
|
- struct intel_iommu *iommu)
|
|
|
+static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header,
|
|
|
+ struct intel_iommu *iommu)
|
|
|
{
|
|
|
struct acpi_dmar_hardware_unit *drhd;
|
|
|
struct acpi_dmar_device_scope *scope;
|
|
@@ -765,6 +835,17 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
|
|
|
drhd->address);
|
|
|
|
|
|
ir_parse_one_ioapic_scope(scope, iommu);
|
|
|
+ } else if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_HPET) {
|
|
|
+ if (ir_hpet_num == MAX_HPET_TBS) {
|
|
|
+ printk(KERN_WARNING "Exceeded Max HPET blocks\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ printk(KERN_INFO "HPET id %d under DRHD base"
|
|
|
+ " 0x%Lx\n", scope->enumeration_id,
|
|
|
+ drhd->address);
|
|
|
+
|
|
|
+ ir_parse_one_hpet_scope(scope, iommu);
|
|
|
}
|
|
|
start += scope->length;
|
|
|
}
|
|
@@ -785,7 +866,7 @@ int __init parse_ioapics_under_ir(void)
|
|
|
struct intel_iommu *iommu = drhd->iommu;
|
|
|
|
|
|
if (ecap_ir_support(iommu->ecap)) {
|
|
|
- if (ir_parse_ioapic_scope(drhd->hdr, iommu))
|
|
|
+ if (ir_parse_ioapic_hpet_scope(drhd->hdr, iommu))
|
|
|
return -1;
|
|
|
|
|
|
ir_supported = 1;
|