iommu/amd: enable ACPI hardware ID device support
Subsystems (2)
v2 cover iommu/amd: enable ACPI hardware ID device support
From: Wan Zongshun <[email protected]>
There are some devices indentified using ACPI HID format in AMD chip. This patch series enable iommu support for those ACPI HID device, since the existing AMD iommu only supports PCI bus based device.
The latest public version of AMD IOMMU specification that describes the support for IVHD type 40h and ACPI HID IVHD device type, implemented by this patch series, is available here:
http://support.amd.com/TechDocs/48882_IOMMU.pdf
The V2 adds two new patches: patch 5 and patch 8 according to Joerg's comments.
There is a little modification in patch 6 to distinguish pci and none pci.
Suravee Suthikulpanit (3):
iommu/amd: Modify ivhd_header structure to support type 11h and 40h iommu/amd: Use the most comprehensive IVHD type that the driver can
support
iommu/amd: Introduces ivrs_acpihid kernel parameter
Wan Zongshun (5):
iommu/amd: Add new map for storing IVHD dev entry type HID iommu/amd: Make call-sites of get_device_id aware of its return value iommu/amd: Add iommu support for ACPI HID devices iommu/amd: Manage iommu_group for ACPI HID devices iommu/amd: Set AMD iommu callbacks for amba bus
Documentation/kernel-parameters.txt | 7 + drivers/iommu/amd_iommu.c | 167 ++++++++++++++++--- drivers/iommu/amd_iommu_init.c | 309 +++++++++++++++++++++++++++++++----- drivers/iommu/amd_iommu_types.h | 14 ++ 4 files changed, 440 insertions(+), 57 deletions(-)
Signature · 1 line
1.9.1
PATCH v2 1/8 iommu/amd: Modify ivhd_header structure to support type 11h and 40h
From: Suravee Suthikulpanit <[email protected]>
This patch modifies the existing struct ivhd_header, which currently only support IVHD type 0x10, to add new fields from IVHD type 11h and 40h. It also modifies the pointer calculation to allow support for IVHD type 11h and 40h
--- drivers/iommu/amd_iommu_init.c | 47 +++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-)
drivers/iommu/amd_iommu_init.c +40 -7
@@ -88,7 +88,7 @@/* * structure describing one IOMMU in the ACPI table. Typically followed by one -* or more ivhd_entrys. +* or more ivhd_entrys. This struct supports both IVHD type 10h, 11h and 40h. */ struct ivhd_header {u8 type;
@@ -99,7 +99,11 @@ struct ivhd_header {u64 mmio_phys;u16 pci_seg;u16 info; -u32 efr; +u32 efr_attr; + +/* Following only valid on IVHD type 11h and 40h */ +u64 efr_reg_img;/* Exact copy of MMIO_EXT_FEATURES */ +u64 res; } __attribute__((packed));/*
@@ -399,6 +403,22 @@ static void __init iommu_unmap_mmio_space(struct amd_iommu *iommu)* ****************************************************************************/ +static inline u32 get_ivhd_header_size (struct ivhd_header *h) +{ +u32 size =0 ; + +switch (h->type) { +case 0x10 : + size =24 ; +break ; +case 0x11 : +case 0x40 : + size =40 ; +break ; + } +return size; +} +/* * This function calculates the length of a given IVHD entry */
@@ -415,8 +435,14 @@ static int __init find_last_devid_from_ivhd(struct ivhd_header *h) {u8 *p = (void *)h, *end = (void *)h;struct ivhd_entry *dev; +u32 ivhd_size =get_ivhd_header_size (h); + +if (!ivhd_size) { +pr_err ("AMD-Vi: Unsupported IVHD type %#x\n" , h->type); +return -EINVAL ; + } - p +=sizeof (*h); + p += ivhd_size; end += h->length;while (p < end) {
@@ -781,6 +807,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,u32 dev_i, ext_flags =0 ;bool alias = false;struct ivhd_entry *e; +u32 ivhd_size;int ret;
@@ -796,7 +823,13 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,/* * Done. Now parse the device entries */ - p +=sizeof (struct ivhd_header ); + ivhd_size =get_ivhd_header_size (h); +if (!ivhd_size) { +pr_err ("AMD-Vi: Unsupported IVHD type %#x\n" , h->type); +return -EINVAL ; + } + + p += ivhd_size; end += h->length;
@@ -1047,9 +1080,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) iommu->mmio_phys = h->mmio_phys;/* Check if IVHD EFR contains proper max banks/counters */ -if ((h->efr !=0 ) && - ((h->efr & (0xF <<13 )) !=0 ) && - ((h->efr & (0x3F <<17 )) !=0 )) { +if ((h->efr_attr !=0 ) && + ((h->efr_attr & (0xF <<13 )) !=0 ) && + ((h->efr_attr & (0x3F <<17 )) !=0 )) { iommu->mmio_phys_end =MMIO_REG_END_OFFSET ; }else { iommu->mmio_phys_end =MMIO_CNTR_CONF_OFFSET ;
Signature · 1 line
1.9.1
PATCH v2 2/8 iommu/amd: Use the most comprehensive IVHD type that the driver can support
In reply to Wan ZongshunFrom: Suravee Suthikulpanit <[email protected]>
The IVRS in more recent AMD system usually contains multiple IVHD block types (e.g. 0x10, 0x11, and 0x40) for each IOMMU. The newer IVHD types provide more information (e.g. new features specified in the IOMMU spec), while maintain compatibility with the older IVHD type.
Having multiple IVHD type allows older IOMMU drivers to still function (e.g. using the older IVHD type 0x10) while the newer IOMMU driver can use the newer IVHD types (e.g. 0x11 and 0x40). Therefore, the IOMMU driver should only make use of the newest IVHD type that it can support.
This patch adds new logic to determine the highest level of IVHD type it can support, and use it throughout the to initialize the driver. This requires adding another pass to the IVRS parsing to determine appropriate IVHD type (see function get_highest_supported_ivhd_type()) before parsing the contents.
[Vincent: fix the build error of IVHD_DEV_ACPI_HID flag not found]
--- drivers/iommu/amd_iommu_init.c | 107 ++++++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 29 deletions(-)
drivers/iommu/amd_iommu_init.c +78 -29
@@ -44,7 +44,7 @@*/ #define IVRS_HEADER_LENGTH 48 -#define ACPI_IVHD_TYPE 0x10 +#define ACPI_IVHD_TYPE_MAX_SUPPORTED 0x40#define ACPI_IVMD_TYPE_ALL 0x20#define ACPI_IVMD_TYPE 0x21#define ACPI_IVMD_TYPE_RANGE 0x22
@@ -58,6 +58,7 @@#define IVHD_DEV_EXT_SELECT 0x46#define IVHD_DEV_EXT_SELECT_RANGE 0x47#define IVHD_DEV_SPECIAL 0x48 +#define IVHD_DEV_ACPI_HID 0xf0#define IVHD_SPECIAL_IOAPIC 1#define IVHD_SPECIAL_HPET 2
@@ -137,6 +138,7 @@ bool amd_iommu_irq_remap __read_mostly;static bool amd_iommu_detected;static bool __initdata amd_iommu_disabled; +static int amd_iommu_target_ivhd_type;u16 amd_iommu_last_bdf;/* largest PCI device id we have to handle */
@@ -424,7 +426,15 @@ static inline u32 get_ivhd_header_size(struct ivhd_header *h)*/ static inline int ivhd_entry_length (u8 *ivhd) { -return 0x04 << (*ivhd >>6 ); +u32 type = ((struct ivhd_entry *)ivhd)->type; + +if (type <0x80 ) { +return 0x04 << (*ivhd >>6 ); + }else if (type ==IVHD_DEV_ACPI_HID ) { +/* For ACPI_HID, offset 21 is uid len */ +return *((u8 *)ivhd +21 ) +22 ; + } +return 0 ; }/*
@@ -470,6 +480,22 @@ static int __init find_last_devid_from_ivhd(struct ivhd_header *h)return 0 ; } +static int __init check_ivrs_checksum (struct acpi_table_header *table) +{ +int i; +u8 checksum =0 , *p = (u8 *)table; + +for (i =0 ; i < table->length; ++i) + checksum += p[i]; +if (checksum !=0 ) { +/* ACPI table corrupt */ +pr_err (FW_BUG "AMD-Vi: IVRS invalid checksum\n" ); +return -ENODEV ; + } + +return 0 ; +} +/* * Iterate over all IVHD entries in the ACPI table and find the highest device * id which we need to handle. This is the first of three functions which parse
@@ -477,31 +503,19 @@ static int __init find_last_devid_from_ivhd(struct ivhd_header *h)*/ static int __init find_last_devid_acpi (struct acpi_table_header *table) { -int i; -u8 checksum =0 , *p = (u8 *)table, *end = (u8 *)table; +u8 *p = (u8 *)table, *end = (u8 *)table;struct ivhd_header *h; -/* -* Validate checksum here so we don't need to do it when -* we actually parse the table -*/ -for (i =0 ; i < table->length; ++i) - checksum += p[i]; -if (checksum !=0 ) -/* ACPI table corrupt */ -return -ENODEV ; - p +=IVRS_HEADER_LENGTH ; end += table->length;while (p < end) { h = (struct ivhd_header *)p; -switch (h->type) { -case ACPI_IVHD_TYPE : -find_last_devid_from_ivhd (h); -break ; -default : -break ; +if (h->type == amd_iommu_target_ivhd_type) { +int ret =find_last_devid_from_ivhd (h); + +if (ret) +return ret; } p += h->length; }
@@ -1118,6 +1132,32 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)return 0 ; } +/** +* get_highest_supported_ivhd_type - Look up the appropriate IVHD type +* @ivrs Pointer to the IVRS header +* +* This function search through all IVDB of the maximum supported IVHD +*/ +static u8 get_highest_supported_ivhd_type (struct acpi_table_header *ivrs) +{ +u8 *base = (u8 *)ivrs; +struct ivhd_header *ivhd = (struct ivhd_header *) + (base +IVRS_HEADER_LENGTH ); +u8 last_type = ivhd->type; +u16 devid = ivhd->devid; + +while (((u8 *)ivhd - base < ivrs->length) && + (ivhd->type <=ACPI_IVHD_TYPE_MAX_SUPPORTED )) { +u8 *p = (u8 *) ivhd; + +if (ivhd->devid == devid) + last_type = ivhd->type; + ivhd = (struct ivhd_header *)(p + ivhd->length); + } + +return last_type; +} +/* * Iterates over all IOMMU entries in the ACPI table, allocates the * IOMMU structure and initializes it with init_iommu_one()
@@ -1134,8 +1174,7 @@ static int __init init_iommu_all(struct acpi_table_header *table)while (p < end) { h = (struct ivhd_header *)p; -switch (*p) { -case ACPI_IVHD_TYPE : +if (*p == amd_iommu_target_ivhd_type) { DUMP_printk("device: %02x:%02x.%01x cap: %04x " "seg: %d flags: %01x info %04x\n",
@@ -1152,9 +1191,6 @@ static int __init init_iommu_all(struct acpi_table_header *table) ret =init_iommu_one (iommu, h);if (ret)return ret; -break ; -default : -break ; } p += h->length;
@@ -1818,18 +1854,20 @@ static void __init free_dma_resources(void)* remapping setup code. * * This function basically parses the ACPI table for AMD IOMMU (IVRS) -* three times: +* four times: * -* 1 pass) Find the highest PCI device id the driver has to handle. +* 1 pass) Discover the most comprehensive IVHD type to use. +* +* 2 pass) Find the highest PCI device id the driver has to handle. * Upon this information the size of the data structures is * determined that needs to be allocated. * -* 2 pass) Initialize the data structures just allocated with the +* 3 pass) Initialize the data structures just allocated with the * information in the ACPI table about available AMD IOMMUs * in the system. It also maps the PCI devices in the * system to specific IOMMUs * -* 3 pass) After the basic data structures are allocated and +* 4 pass) After the basic data structures are allocated and * initialized we update them with information about memory * remapping requirements parsed out of the ACPI table in * this last pass.
@@ -1857,6 +1895,17 @@ static int __init early_amd_iommu_init(void) }/* +* Validate checksum here so we don't need to do it when +* we actually parse the table +*/ + ret =check_ivrs_checksum (ivrs_base); +if (ret) +return ret; + + amd_iommu_target_ivhd_type =get_highest_supported_ivhd_type (ivrs_base); +DUMP_printk ("Using IVHD type %#x\n" , amd_iommu_target_ivhd_type); + +/* * First parse ACPI tables to find the largest Bus/Dev/Func * we need to handle. Upon this information the shared data * structures for the IOMMUs in the system will be allocated
Signature · 1 line
1.9.1
PATCH v2 3/8 iommu/amd: Add new map for storing IVHD dev entry type HID
In reply to Wan ZongshunFrom: Wan Zongshun <[email protected]>
This patch introduces acpihid_map, which is used to store the new IVHD device entry extracted from BIOS IVRS table.
It also provides a utility function add_acpi_hid_device(), to add this types of devices to the map.
--- drivers/iommu/amd_iommu.c | 1 + drivers/iommu/amd_iommu_init.c | 122 ++++++++++++++++++++++++++++++++++++++++ drivers/iommu/amd_iommu_types.h | 14 +++++ 3 files changed, 137 insertions(+)
drivers/iommu/amd_iommu.c +1 -0
@@ -72,6 +72,7 @@ static DEFINE_SPINLOCK(dev_data_list_lock);LIST_HEAD (ioapic_map);LIST_HEAD (hpet_map); +LIST_HEAD (acpihid_map);/* * Domain for untranslated devices - only allocated
drivers/iommu/amd_iommu_init.c +122 -0
160 lines not on this page · raw message
drivers/iommu/amd_iommu_types.h +14 -0
@@ -527,6 +527,19 @@ struct amd_iommu {#endif }; +#define ACPIHID_UID_LEN 256 +#define ACPIHID_HID_LEN 9 + +struct acpihid_map_entry { +struct list_head list; +u8 uid[ACPIHID_UID_LEN ]; +u8 hid[ACPIHID_HID_LEN ]; +u16 devid; +u16 root_devid; +bool cmd_line; +struct iommu_group *group; +}; +struct devid_map {struct list_head list;u8 id;
@@ -537,6 +550,7 @@ struct devid_map {/* Map HPET and IOAPIC ids to the devid used by the IOMMU */ extern struct list_head ioapic_map;extern struct list_head hpet_map; +extern struct list_head acpihid_map;/* * List with all IOMMUs in the system. This list is not locked because it is
Signature · 1 line
1.9.1
PATCH v2 4/8 iommu/amd: Introduces ivrs_acpihid kernel parameter
In reply to Wan ZongshunFrom: Suravee Suthikulpanit <[email protected]>
This patch introduces a new kernel parameter, ivrs_acpihid. This is used to override existing ACPI-HID IVHD device entry, or add an entry in case it is missing in the IVHD.
--- Documentation/kernel-parameters.txt | 7 +++++++ drivers/iommu/amd_iommu_init.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+)
Documentation/kernel-parameters.txt +7 -0
@@ -1680,6 +1680,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. PCI device 00:14.0 write the parameter as: ivrs_hpet[0]=00:14.0 + ivrs_acpihid [HW,X86_64] + Provide an override to the ACPI-HID:UID<->DEVICE-ID + mapping provided in the IVRS ACPI table. For + example, to map UART-HID:UID AMD0020:0 to + PCI device 00:14.5 write the parameter as: + ivrs_acpihid[00:14.5]=AMD0020:0 + js= [HW,JOY] Analog joystick See Documentation/input/joystick.txt.
drivers/iommu/amd_iommu_init.c +33 -0
@@ -2430,10 +2430,43 @@ static int __init parse_ivrs_hpet(char *str)return 1 ; } +static int __init parse_ivrs_acpihid (char *str) +{ +u32 bus, dev, fn; +char *hid, *uid, *p; +char acpiid[ACPIHID_UID_LEN +ACPIHID_HID_LEN ] = {0 }; +int ret, i; + + ret =sscanf (str,"[%x:%x.%x]=%s" , &bus, &dev, &fn, acpiid); +if (ret !=4 ) { +pr_err ("AMD-Vi: Invalid command line: ivrs_acpihid(%s)\n" , str); +return 1 ; + } + + p = acpiid; + hid =strsep (&p,":" ); + uid = p; + +if (!hid || !(*hid) || !uid) { +pr_err ("AMD-Vi: Invalid command line: hid or uid\n" ); +return 1 ; + } + + i = early_acpihid_map_size++; +memcpy (early_acpihid_map[i].hid, hid,strlen (hid)); +memcpy (early_acpihid_map[i].uid, uid,strlen (uid)); + early_acpihid_map[i].devid = + ((bus &0xff ) <<8 ) | ((dev &0x1f ) <<3 ) | (fn &0x7 ); + early_acpihid_map[i].cmd_line = true; + +return 1 ; +} +__setup ("amd_iommu_dump" , parse_amd_iommu_dump);__setup ("amd_iommu=" , parse_amd_iommu_options);__setup ("ivrs_ioapic" , parse_ivrs_ioapic);__setup ("ivrs_hpet" , parse_ivrs_hpet); +__setup ("ivrs_acpihid" , parse_ivrs_acpihid); IOMMU_INIT_FINISH(amd_iommu_detect, gart_iommu_hole_init,
Signature · 1 line
1.9.1
PATCH v2 5/8 iommu/amd: Make call-sites of get_device_id aware of its return value
In reply to Wan ZongshunFrom: Wan Zongshun <[email protected]>
This patch is to make the call-sites of get_device_id aware of its return value.
--- drivers/iommu/amd_iommu.c | 51 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-)
drivers/iommu/amd_iommu.c +41 -10
@@ -278,9 +278,11 @@ static void init_unity_mappings_for_device(struct device *dev, struct dma_ops_domain *dma_dom) {struct unity_map_entry *e; -u16 devid; +int devid; devid =get_device_id (dev); +if (IS_ERR_VALUE (devid)) +return ;list_for_each_entry (e, &amd_iommu_unity_map, list) {if (!(devid >= e->devid_start && devid <= e->devid_end))
@@ -295,7 +297,7 @@ static void init_unity_mappings_for_device(struct device *dev,*/ static bool check_device (struct device *dev) { -u16 devid; +int devid;if (!dev || !dev->dma_mask)return false;
@@ -305,6 +307,8 @@ static bool check_device(struct device *dev)return false; devid =get_device_id (dev); +if (IS_ERR_VALUE (devid)) +return false;/* Out of our scope? */ if (devid > amd_iommu_last_bdf)
@@ -341,11 +345,16 @@ static int iommu_init_device(struct device *dev) {struct pci_dev *pdev =to_pci_dev (dev);struct iommu_dev_data *dev_data; +int devid;if (dev->archdata.iommu)return 0 ; - dev_data =find_dev_data (get_device_id (dev)); + devid =get_device_id (dev); +if (IS_ERR_VALUE (devid)) +return devid; + + dev_data =find_dev_data (devid);if (!dev_data)return -ENOMEM ;
@@ -366,9 +375,13 @@ static int iommu_init_device(struct device *dev)static void iommu_ignore_device (struct device *dev) { -u16 devid, alias; +u16 alias; +int devid; devid =get_device_id (dev); +if (IS_ERR_VALUE (devid)) +return ; + alias = amd_iommu_alias_table[devid];memset (&amd_iommu_dev_table[devid],0 ,sizeof (struct dev_table_entry ));
@@ -380,8 +393,14 @@ static void iommu_ignore_device(struct device *dev)static void iommu_uninit_device (struct device *dev) { -struct iommu_dev_data *dev_data =search_dev_data (get_device_id (dev)); +int devid; +struct iommu_dev_data *dev_data; + + devid =get_device_id (dev); +if (IS_ERR_VALUE (devid)) +return ; + dev_data =search_dev_data (devid);if (!dev_data)return ;
@@ -2310,13 +2329,15 @@ static int amd_iommu_add_device(struct device *dev)struct iommu_dev_data *dev_data;struct iommu_domain *domain;struct amd_iommu *iommu; -u16 devid; -int ret; +int ret, devid;if (!check_device (dev) ||get_dev_data (dev))return 0 ; devid =get_device_id (dev); +if (IS_ERR_VALUE (devid)) +return devid; + iommu = amd_iommu_rlookup_table[devid]; ret =iommu_init_device (dev);
@@ -2354,12 +2375,15 @@ out:static void amd_iommu_remove_device (struct device *dev) {struct amd_iommu *iommu; -u16 devid; +int devid;if (!check_device (dev))return ; devid =get_device_id (dev); +if (IS_ERR_VALUE (devid)) +return ; + iommu = amd_iommu_rlookup_table[devid];iommu_uninit_device (dev);
@@ -3031,12 +3055,14 @@ static void amd_iommu_detach_device(struct iommu_domain *dom, {struct iommu_dev_data *dev_data = dev->archdata.iommu;struct amd_iommu *iommu; -u16 devid; +int devid;if (!check_device (dev))return ; devid =get_device_id (dev); +if (IS_ERR_VALUE (devid)) +return ;if (dev_data->domain !=NULL )detach_device (dev);
@@ -3154,9 +3180,11 @@ static void amd_iommu_get_dm_regions(struct device *dev, struct list_head *head) {struct unity_map_entry *entry; -u16 devid; +int devid; devid =get_device_id (dev); +if (IS_ERR_VALUE (devid)) +return ;list_for_each_entry (entry, &amd_iommu_unity_map, list) {struct iommu_dm_region *region;
@@ -3858,6 +3886,9 @@ static struct irq_domain *get_irq_domain(struct irq_alloc_info *info)case X86_IRQ_ALLOC_TYPE_MSI :case X86_IRQ_ALLOC_TYPE_MSIX : devid =get_device_id (&info->msi_dev->dev); +if (IS_ERR_VALUE (devid)) +return NULL ; + iommu = amd_iommu_rlookup_table[devid];if (iommu)return iommu->msi_domain;
Signature · 1 line
1.9.1
PATCH v2 6/8 iommu/amd: Add iommu support for ACPI HID devices
In reply to Wan ZongshunFrom: Wan Zongshun <[email protected]>
Current IOMMU driver make assumption that the downstream devices are PCI. With the newly added ACPI-HID IVHD device entry support, this is no longer true. This patch is to add dev type check and to distinguish the pci and acpihid device code path.
--- drivers/iommu/amd_iommu.c | 69 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 9 deletions(-)
drivers/iommu/amd_iommu.c +60 -9
@@ -19,6 +19,7 @@#include <linux/ratelimit.h> #include <linux/pci.h> +#include <linux/acpi.h> #include <linux/pci-ats.h> #include <linux/bitmap.h> #include <linux/slab.h>
@@ -215,13 +216,60 @@ static struct iommu_dev_data *find_dev_data(u16 devid)return dev_data; } -static inline u16 get_device_id (struct device *dev) +static inline int match_hid_uid (struct device *dev, +struct acpihid_map_entry *entry) +{ +const char *hid, *uid; + + hid =acpi_device_hid (ACPI_COMPANION (dev)); + uid =acpi_device_uid (ACPI_COMPANION (dev)); + +if (!hid || !(*hid)) +return -ENODEV ; + +if (!uid || !(*uid)) +return strcmp (hid, entry->hid); + +if (!(*entry->uid)) +return strcmp (hid, entry->hid); + +return (strcmp (hid, entry->hid) ||strcmp (uid, entry->uid)); +} + +static inline u16 get_pci_device_id (struct device *dev) {struct pci_dev *pdev =to_pci_dev (dev);return PCI_DEVID (pdev->bus->number, pdev->devfn); } +static inline int get_acpihid_device_id (struct device *dev, +struct acpihid_map_entry **entry) +{ +struct acpihid_map_entry *p; + +list_for_each_entry (p, &acpihid_map, list) { +if (!match_hid_uid (dev, p)) { +if (entry) + *entry = p; +return p->devid; + } + } +return -EINVAL ; +} + +static inline int get_device_id (struct device *dev) +{ +int devid; + +if (dev_is_pci (dev)) + devid =get_pci_device_id (dev); +else + devid =get_acpihid_device_id (dev,NULL ); + +return devid; +} +static struct iommu_dev_data *get_dev_data (struct device *dev) {return dev->archdata.iommu;
@@ -302,10 +350,6 @@ static bool check_device(struct device *dev)if (!dev || !dev->dma_mask)return false; -/* No PCI device */ -if (!dev_is_pci (dev)) -return false; - devid =get_device_id (dev);if (IS_ERR_VALUE (devid))return false;
@@ -343,7 +387,6 @@ out:static int iommu_init_device (struct device *dev) { -struct pci_dev *pdev =to_pci_dev (dev);struct iommu_dev_data *dev_data;int devid;
@@ -358,10 +401,10 @@ static int iommu_init_device(struct device *dev)if (!dev_data)return -ENOMEM ; -if (pci_iommuv2_capable (pdev)) { +if (dev_is_pci (dev) &&pci_iommuv2_capable (to_pci_dev (dev))) {struct amd_iommu *iommu; - iommu = amd_iommu_rlookup_table[dev_data->devid]; + iommu = amd_iommu_rlookup_table[dev_data->devid]; dev_data->iommu_v2 = iommu->is_iommu_v2; }
@@ -2235,13 +2278,17 @@ static bool pci_pri_tlp_required(struct pci_dev *pdev)static int attach_device (struct device *dev,struct protection_domain *domain) { -struct pci_dev *pdev =to_pci_dev (dev); +struct pci_dev *pdev;struct iommu_dev_data *dev_data;unsigned long flags;int ret; dev_data =get_dev_data (dev); +if (!dev_is_pci (dev)) + goto skip_ats_check; + + pdev =to_pci_dev (dev);if (domain->flags &PD_IOMMUV2_MASK ) {if (!dev_data->passthrough)return -EINVAL ;
@@ -2260,6 +2307,7 @@ static int attach_device(struct device *dev, dev_data->ats.qdep =pci_ats_queue_depth (pdev); } +skip_ats_check:write_lock_irqsave (&amd_iommu_devtable_lock, flags); ret =__attach_device (dev_data, domain);write_unlock_irqrestore (&amd_iommu_devtable_lock, flags);
@@ -2316,6 +2364,9 @@ static void detach_device(struct device *dev)__detach_device (dev_data);write_unlock_irqrestore (&amd_iommu_devtable_lock, flags); +if (!dev_is_pci (dev)) +return ; +if (domain->flags &PD_IOMMUV2_MASK && dev_data->iommu_v2)pdev_iommuv2_disable (to_pci_dev (dev));else if (dev_data->ats.enabled)
Signature · 1 line
1.9.1
PATCH v2 7/8 iommu/amd: Manage iommu_group for ACPI HID devices
In reply to Wan ZongshunFrom: Wan Zongshun <[email protected]>
This patch creates a new function for finding or creating an IOMMU group for acpihid(ACPI Hardware ID) device.
The acpihid devices with the same devid will be put into same group and there will have the same domain id and share the same page table.
--- drivers/iommu/amd_iommu.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-)
drivers/iommu/amd_iommu.c +32 -1
@@ -275,6 +275,29 @@ static struct iommu_dev_data *get_dev_data(struct device *dev)return dev->archdata.iommu; } +/* +* Find or create an IOMMU group for a acpihid device. +*/ +static struct iommu_group *acpihid_device_group (struct device *dev) +{ +struct acpihid_map_entry *p, *entry =NULL ; +u16 devid; + + devid =get_acpihid_device_id (dev, &entry); +if (devid <0 ) +return ERR_PTR (devid); + +list_for_each_entry (p, &acpihid_map, list) { +if ((devid == p->devid) && p->group) + entry->group = p->group; + } + +if (!entry->group) + entry->group =generic_device_group (dev); + +return entry->group; +} +static bool pci_iommuv2_capable (struct pci_dev *pdev) {static const int caps[] = {
@@ -2441,6 +2464,14 @@ static void amd_iommu_remove_device(struct device *dev)iommu_completion_wait (iommu); } +static struct iommu_group *amd_iommu_device_group (struct device *dev) +{ +if (dev_is_pci (dev)) +return pci_device_group (dev); + +return acpihid_device_group (dev); +} +/***************************************************************************** * * The next functions belong to the dma_ops mapping/unmapping code.
@@ -3282,7 +3313,7 @@ static const struct iommu_ops amd_iommu_ops = { .iova_to_phys = amd_iommu_iova_to_phys, .add_device = amd_iommu_add_device, .remove_device = amd_iommu_remove_device, - .device_group = pci_device_group, + .device_group = amd_iommu_device_group, .get_dm_regions = amd_iommu_get_dm_regions, .put_dm_regions = amd_iommu_put_dm_regions, .pgsize_bitmap = AMD_IOMMU_PGSIZES,
Signature · 1 line
1.9.1
PATCH v2 8/8 iommu/amd: Set AMD iommu callbacks for amba bus
In reply to Wan ZongshunFrom: Wan Zongshun <[email protected]>
AMD Uart DMA belongs to ACPI HID type device, and its driver is basing on AMBA Bus, need also IOMMU support.
This patch is just to set the AMD iommu callbacks for amba bus.
--- drivers/iommu/amd_iommu.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/iommu/amd_iommu.c +12 -1
@@ -20,6 +20,7 @@#include <linux/ratelimit.h> #include <linux/pci.h> #include <linux/acpi.h> +#include <linux/amba/bus.h> #include <linux/pci-ats.h> #include <linux/bitmap.h> #include <linux/slab.h>
@@ -2965,7 +2966,17 @@ static struct dma_map_ops amd_iommu_dma_ops = {int __init amd_iommu_init_api (void ) { -return bus_set_iommu (&pci_bus_type, &amd_iommu_ops); +int err =0 ; + + err =bus_set_iommu (&pci_bus_type, &amd_iommu_ops); +if (err) +return err; +#ifdef CONFIG_ARM_AMBA + err =bus_set_iommu (&amba_bustype, &amd_iommu_ops); +if (err) +return err; +#endif +return 0 ; }int __init amd_iommu_init_dma_ops (void )
Signature · 1 line
1.9.1
Joerg Roedel
maintainerQuoted 6 lines · Wan Zongshun
Suravee Suthikulpanit (3):
iommu/amd: Modifyivhd_headerstructure to support type 11h and 40h iommu/amd: Use the most comprehensive IVHD type that the driver can
support
iommu/amd: Introducesivrs_acpihidkernel parameter
Quoted 6 lines
Wan Zongshun (5):
iommu/amd: Add new map for storing IVHD dev entry type HID iommu/amd: Make call-sites ofget_device_idaware of its return value iommu/amd: Add iommu support for ACPI HID devices iommu/amd: Manageiommu_groupfor ACPI HID devices iommu/amd: Set AMD iommu callbacks for amba bus
These patches fail to boot on my Carrizo system. Unfortunatly it fails before console is initialized and the box has no serial port to grab the early panic.
Joerg
Thanks!
Vincent Wan.
Quoted 24 lines
-----Original Message-----
From: Joerg Roedel [mailto:[email protected]]
Sent: Friday, February 26, 2016 10:45 PM
To: Wan, Vincent
Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org; Suthikulpanit, Suravee; Borislav Petkov; Huang, Ray; Xue, Ken; [email protected]; [email protected]; linux- [email protected]
Subject: Re: [PATCH V2 0/8] iommu/amd: enable ACPI hardware ID device
supportQuoted 6 lines · Wan Zongshun
Suravee Suthikulpanit (3):
iommu/amd: Modifyivhd_headerstructure to support type 11h and 40h iommu/amd: Use the most comprehensive IVHD type that the driver can
support
iommu/amd: Introducesivrs_acpihidkernel parameterQuoted 6 lines
Wan Zongshun (5):
iommu/amd: Add new map for storing IVHD dev entry type HID iommu/amd: Make call-sites ofget_device_idaware of its return value iommu/amd: Add iommu support for ACPI HID devices iommu/amd: Manageiommu_groupfor ACPI HID devices iommu/amd: Set AMD iommu callbacks for amba bus
Quoted 3 lines
These patches fail to boot on my Carrizo system. Unfortunatly it fails before console is initialized and the box has no serial port to grab the early panic.
Joerg,
Can you provide me which branch you are using to test those patches.
We are validating the patches in v4.5.0-rc6, and no issues like your description.
Vincent.
Quoted 3 lines
Joerg
Joerg Roedel
maintainerQuoted 7 lines · Vincent
Quoted 3 lines
These patches fail to boot on my Carrizo system. Unfortunatly it fails before console is initialized and the box has no serial port to grab the early panic.
Joerg,
Can you provide me which branch you are using to test those patches.We are validating the patches in v4.5.0-rc6, and no issues like your description.
I tested them on v4.5-rc5.
Joerg
Quoted 8 lines
Quoted 4 lines
Joerg,
Can you provide me which branch you are using to test those patches.We are validating the patches in v4.5.0-rc6, and no issues like your
description.
I tested them on v4.5-rc5.
Thanks!
We will test the patches basing on this v4.5-rc5 version again.
Vincent.
Quoted 2 lines
Joerg
Hi Joerg,
Quoted 4 lines · Vincent
Quoted 4 lines
Quoted 4 lines
Joerg,
Can you provide me which branch you are using to test those patches.We are validating the patches in v4.5.0-rc6, and no issues like your
Quoted 11 lines
Quoted 4 lines
description.
I tested them on v4.5-rc5.
Thanks!
We will test the patches basing on this v4.5-rc5 version again.Vincent.
Quoted 2 lines
Joerg
I found the issue now. I'll work with Vincent to send out V3.
The problem is because in the information in the IOMMU Attributes field of the IVHD header type 40h (offset byte 20 = struct ivhd_header.efr_attr) is incorrect. It was correct in the IVHD type 10h.... Sigh :(
However, the same information in the MMIO offset 4000h Counter configuration Register is correct. So, I'll try to have the patch get information from here instead.
Earlier, we had another issue with IOMMU PERF intialization, and it was disabled. So, it hides this bug when we were testing the patch earlier. Now that we had a workaround for that bug n v4.5-rc5, it bombs in the init_iommu_perf_ctr().
So, if you want to test out the rest of this patch series, just simply comment out this function, and it should boot.
Regards,
Suravee