diff options
Diffstat (limited to 'drivers/iommu/amd_iommu.c')
| -rw-r--r-- | drivers/iommu/amd_iommu.c | 125 |
1 files changed, 73 insertions, 52 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 18405314168b..505a9adac2d5 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
| @@ -88,6 +88,27 @@ int amd_iommu_max_glx_val = -1; | |||
| 88 | static struct dma_map_ops amd_iommu_dma_ops; | 88 | static struct dma_map_ops amd_iommu_dma_ops; |
| 89 | 89 | ||
| 90 | /* | 90 | /* |
| 91 | * This struct contains device specific data for the IOMMU | ||
| 92 | */ | ||
| 93 | struct iommu_dev_data { | ||
| 94 | struct list_head list; /* For domain->dev_list */ | ||
| 95 | struct list_head dev_data_list; /* For global dev_data_list */ | ||
| 96 | struct list_head alias_list; /* Link alias-groups together */ | ||
| 97 | struct iommu_dev_data *alias_data;/* The alias dev_data */ | ||
| 98 | struct protection_domain *domain; /* Domain the device is bound to */ | ||
| 99 | u16 devid; /* PCI Device ID */ | ||
| 100 | bool iommu_v2; /* Device can make use of IOMMUv2 */ | ||
| 101 | bool passthrough; /* Default for device is pt_domain */ | ||
| 102 | struct { | ||
| 103 | bool enabled; | ||
| 104 | int qdep; | ||
| 105 | } ats; /* ATS state */ | ||
| 106 | bool pri_tlp; /* PASID TLB required for | ||
| 107 | PPR completions */ | ||
| 108 | u32 errata; /* Bitmap for errata to apply */ | ||
| 109 | }; | ||
| 110 | |||
| 111 | /* | ||
| 91 | * general struct to manage commands send to an IOMMU | 112 | * general struct to manage commands send to an IOMMU |
| 92 | */ | 113 | */ |
| 93 | struct iommu_cmd { | 114 | struct iommu_cmd { |
| @@ -114,8 +135,9 @@ static struct iommu_dev_data *alloc_dev_data(u16 devid) | |||
| 114 | if (!dev_data) | 135 | if (!dev_data) |
| 115 | return NULL; | 136 | return NULL; |
| 116 | 137 | ||
| 138 | INIT_LIST_HEAD(&dev_data->alias_list); | ||
| 139 | |||
| 117 | dev_data->devid = devid; | 140 | dev_data->devid = devid; |
| 118 | atomic_set(&dev_data->bind, 0); | ||
| 119 | 141 | ||
| 120 | spin_lock_irqsave(&dev_data_list_lock, flags); | 142 | spin_lock_irqsave(&dev_data_list_lock, flags); |
| 121 | list_add_tail(&dev_data->dev_data_list, &dev_data_list); | 143 | list_add_tail(&dev_data->dev_data_list, &dev_data_list); |
| @@ -260,17 +282,13 @@ static bool check_device(struct device *dev) | |||
| 260 | return true; | 282 | return true; |
| 261 | } | 283 | } |
| 262 | 284 | ||
| 263 | static int init_iommu_group(struct device *dev) | 285 | static void init_iommu_group(struct device *dev) |
| 264 | { | 286 | { |
| 265 | struct iommu_group *group; | 287 | struct iommu_group *group; |
| 266 | 288 | ||
| 267 | group = iommu_group_get_for_dev(dev); | 289 | group = iommu_group_get_for_dev(dev); |
| 268 | 290 | if (!IS_ERR(group)) | |
| 269 | if (IS_ERR(group)) | 291 | iommu_group_put(group); |
| 270 | return PTR_ERR(group); | ||
| 271 | |||
| 272 | iommu_group_put(group); | ||
| 273 | return 0; | ||
| 274 | } | 292 | } |
| 275 | 293 | ||
| 276 | static int __last_alias(struct pci_dev *pdev, u16 alias, void *data) | 294 | static int __last_alias(struct pci_dev *pdev, u16 alias, void *data) |
| @@ -340,7 +358,6 @@ static int iommu_init_device(struct device *dev) | |||
| 340 | struct pci_dev *pdev = to_pci_dev(dev); | 358 | struct pci_dev *pdev = to_pci_dev(dev); |
| 341 | struct iommu_dev_data *dev_data; | 359 | struct iommu_dev_data *dev_data; |
| 342 | u16 alias; | 360 | u16 alias; |
| 343 | int ret; | ||
| 344 | 361 | ||
| 345 | if (dev->archdata.iommu) | 362 | if (dev->archdata.iommu) |
| 346 | return 0; | 363 | return 0; |
| @@ -362,12 +379,9 @@ static int iommu_init_device(struct device *dev) | |||
| 362 | return -ENOTSUPP; | 379 | return -ENOTSUPP; |
| 363 | } | 380 | } |
| 364 | dev_data->alias_data = alias_data; | 381 | dev_data->alias_data = alias_data; |
| 365 | } | ||
| 366 | 382 | ||
| 367 | ret = init_iommu_group(dev); | 383 | /* Add device to the alias_list */ |
| 368 | if (ret) { | 384 | list_add(&dev_data->alias_list, &alias_data->alias_list); |
| 369 | free_dev_data(dev_data); | ||
| 370 | return ret; | ||
| 371 | } | 385 | } |
| 372 | 386 | ||
| 373 | if (pci_iommuv2_capable(pdev)) { | 387 | if (pci_iommuv2_capable(pdev)) { |
| @@ -455,6 +469,15 @@ int __init amd_iommu_init_devices(void) | |||
| 455 | goto out_free; | 469 | goto out_free; |
| 456 | } | 470 | } |
| 457 | 471 | ||
| 472 | /* | ||
| 473 | * Initialize IOMMU groups only after iommu_init_device() has | ||
| 474 | * had a chance to populate any IVRS defined aliases. | ||
| 475 | */ | ||
| 476 | for_each_pci_dev(pdev) { | ||
| 477 | if (check_device(&pdev->dev)) | ||
| 478 | init_iommu_group(&pdev->dev); | ||
| 479 | } | ||
| 480 | |||
| 458 | return 0; | 481 | return 0; |
| 459 | 482 | ||
| 460 | out_free: | 483 | out_free: |
| @@ -1368,6 +1391,9 @@ static int iommu_map_page(struct protection_domain *dom, | |||
| 1368 | count = PAGE_SIZE_PTE_COUNT(page_size); | 1391 | count = PAGE_SIZE_PTE_COUNT(page_size); |
| 1369 | pte = alloc_pte(dom, bus_addr, page_size, NULL, GFP_KERNEL); | 1392 | pte = alloc_pte(dom, bus_addr, page_size, NULL, GFP_KERNEL); |
| 1370 | 1393 | ||
| 1394 | if (!pte) | ||
| 1395 | return -ENOMEM; | ||
| 1396 | |||
| 1371 | for (i = 0; i < count; ++i) | 1397 | for (i = 0; i < count; ++i) |
| 1372 | if (IOMMU_PTE_PRESENT(pte[i])) | 1398 | if (IOMMU_PTE_PRESENT(pte[i])) |
| 1373 | return -EBUSY; | 1399 | return -EBUSY; |
| @@ -2122,35 +2148,29 @@ static void do_detach(struct iommu_dev_data *dev_data) | |||
| 2122 | static int __attach_device(struct iommu_dev_data *dev_data, | 2148 | static int __attach_device(struct iommu_dev_data *dev_data, |
| 2123 | struct protection_domain *domain) | 2149 | struct protection_domain *domain) |
| 2124 | { | 2150 | { |
| 2151 | struct iommu_dev_data *head, *entry; | ||
| 2125 | int ret; | 2152 | int ret; |
| 2126 | 2153 | ||
| 2127 | /* lock domain */ | 2154 | /* lock domain */ |
| 2128 | spin_lock(&domain->lock); | 2155 | spin_lock(&domain->lock); |
| 2129 | 2156 | ||
| 2130 | if (dev_data->alias_data != NULL) { | 2157 | head = dev_data; |
| 2131 | struct iommu_dev_data *alias_data = dev_data->alias_data; | ||
| 2132 | 2158 | ||
| 2133 | /* Some sanity checks */ | 2159 | if (head->alias_data != NULL) |
| 2134 | ret = -EBUSY; | 2160 | head = head->alias_data; |
| 2135 | if (alias_data->domain != NULL && | ||
| 2136 | alias_data->domain != domain) | ||
| 2137 | goto out_unlock; | ||
| 2138 | 2161 | ||
| 2139 | if (dev_data->domain != NULL && | 2162 | /* Now we have the root of the alias group, if any */ |
| 2140 | dev_data->domain != domain) | ||
| 2141 | goto out_unlock; | ||
| 2142 | 2163 | ||
| 2143 | /* Do real assignment */ | 2164 | ret = -EBUSY; |
| 2144 | if (alias_data->domain == NULL) | 2165 | if (head->domain != NULL) |
| 2145 | do_attach(alias_data, domain); | 2166 | goto out_unlock; |
| 2146 | |||
| 2147 | atomic_inc(&alias_data->bind); | ||
| 2148 | } | ||
| 2149 | 2167 | ||
| 2150 | if (dev_data->domain == NULL) | 2168 | /* Attach alias group root */ |
| 2151 | do_attach(dev_data, domain); | 2169 | do_attach(head, domain); |
| 2152 | 2170 | ||
| 2153 | atomic_inc(&dev_data->bind); | 2171 | /* Attach other devices in the alias group */ |
| 2172 | list_for_each_entry(entry, &head->alias_list, alias_list) | ||
| 2173 | do_attach(entry, domain); | ||
| 2154 | 2174 | ||
| 2155 | ret = 0; | 2175 | ret = 0; |
| 2156 | 2176 | ||
| @@ -2298,6 +2318,7 @@ static int attach_device(struct device *dev, | |||
| 2298 | */ | 2318 | */ |
| 2299 | static void __detach_device(struct iommu_dev_data *dev_data) | 2319 | static void __detach_device(struct iommu_dev_data *dev_data) |
| 2300 | { | 2320 | { |
| 2321 | struct iommu_dev_data *head, *entry; | ||
| 2301 | struct protection_domain *domain; | 2322 | struct protection_domain *domain; |
| 2302 | unsigned long flags; | 2323 | unsigned long flags; |
| 2303 | 2324 | ||
| @@ -2307,15 +2328,14 @@ static void __detach_device(struct iommu_dev_data *dev_data) | |||
| 2307 | 2328 | ||
| 2308 | spin_lock_irqsave(&domain->lock, flags); | 2329 | spin_lock_irqsave(&domain->lock, flags); |
| 2309 | 2330 | ||
| 2310 | if (dev_data->alias_data != NULL) { | 2331 | head = dev_data; |
| 2311 | struct iommu_dev_data *alias_data = dev_data->alias_data; | 2332 | if (head->alias_data != NULL) |
| 2333 | head = head->alias_data; | ||
| 2312 | 2334 | ||
| 2313 | if (atomic_dec_and_test(&alias_data->bind)) | 2335 | list_for_each_entry(entry, &head->alias_list, alias_list) |
| 2314 | do_detach(alias_data); | 2336 | do_detach(entry); |
| 2315 | } | ||
| 2316 | 2337 | ||
| 2317 | if (atomic_dec_and_test(&dev_data->bind)) | 2338 | do_detach(head); |
| 2318 | do_detach(dev_data); | ||
| 2319 | 2339 | ||
| 2320 | spin_unlock_irqrestore(&domain->lock, flags); | 2340 | spin_unlock_irqrestore(&domain->lock, flags); |
| 2321 | 2341 | ||
| @@ -2415,6 +2435,7 @@ static int device_change_notifier(struct notifier_block *nb, | |||
| 2415 | case BUS_NOTIFY_ADD_DEVICE: | 2435 | case BUS_NOTIFY_ADD_DEVICE: |
| 2416 | 2436 | ||
| 2417 | iommu_init_device(dev); | 2437 | iommu_init_device(dev); |
| 2438 | init_iommu_group(dev); | ||
| 2418 | 2439 | ||
| 2419 | /* | 2440 | /* |
| 2420 | * dev_data is still NULL and | 2441 | * dev_data is still NULL and |
| @@ -3149,14 +3170,15 @@ free_domains: | |||
| 3149 | 3170 | ||
| 3150 | static void cleanup_domain(struct protection_domain *domain) | 3171 | static void cleanup_domain(struct protection_domain *domain) |
| 3151 | { | 3172 | { |
| 3152 | struct iommu_dev_data *dev_data, *next; | 3173 | struct iommu_dev_data *entry; |
| 3153 | unsigned long flags; | 3174 | unsigned long flags; |
| 3154 | 3175 | ||
| 3155 | write_lock_irqsave(&amd_iommu_devtable_lock, flags); | 3176 | write_lock_irqsave(&amd_iommu_devtable_lock, flags); |
| 3156 | 3177 | ||
| 3157 | list_for_each_entry_safe(dev_data, next, &domain->dev_list, list) { | 3178 | while (!list_empty(&domain->dev_list)) { |
| 3158 | __detach_device(dev_data); | 3179 | entry = list_first_entry(&domain->dev_list, |
| 3159 | atomic_set(&dev_data->bind, 0); | 3180 | struct iommu_dev_data, list); |
| 3181 | __detach_device(entry); | ||
| 3160 | } | 3182 | } |
| 3161 | 3183 | ||
| 3162 | write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); | 3184 | write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); |
| @@ -3382,20 +3404,20 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom, | |||
| 3382 | return paddr; | 3404 | return paddr; |
| 3383 | } | 3405 | } |
| 3384 | 3406 | ||
| 3385 | static int amd_iommu_domain_has_cap(struct iommu_domain *domain, | 3407 | static bool amd_iommu_capable(enum iommu_cap cap) |
| 3386 | unsigned long cap) | ||
| 3387 | { | 3408 | { |
| 3388 | switch (cap) { | 3409 | switch (cap) { |
| 3389 | case IOMMU_CAP_CACHE_COHERENCY: | 3410 | case IOMMU_CAP_CACHE_COHERENCY: |
| 3390 | return 1; | 3411 | return true; |
| 3391 | case IOMMU_CAP_INTR_REMAP: | 3412 | case IOMMU_CAP_INTR_REMAP: |
| 3392 | return irq_remapping_enabled; | 3413 | return (irq_remapping_enabled == 1); |
| 3393 | } | 3414 | } |
| 3394 | 3415 | ||
| 3395 | return 0; | 3416 | return false; |
| 3396 | } | 3417 | } |
| 3397 | 3418 | ||
| 3398 | static const struct iommu_ops amd_iommu_ops = { | 3419 | static const struct iommu_ops amd_iommu_ops = { |
| 3420 | .capable = amd_iommu_capable, | ||
| 3399 | .domain_init = amd_iommu_domain_init, | 3421 | .domain_init = amd_iommu_domain_init, |
| 3400 | .domain_destroy = amd_iommu_domain_destroy, | 3422 | .domain_destroy = amd_iommu_domain_destroy, |
| 3401 | .attach_dev = amd_iommu_attach_device, | 3423 | .attach_dev = amd_iommu_attach_device, |
| @@ -3403,7 +3425,6 @@ static const struct iommu_ops amd_iommu_ops = { | |||
| 3403 | .map = amd_iommu_map, | 3425 | .map = amd_iommu_map, |
| 3404 | .unmap = amd_iommu_unmap, | 3426 | .unmap = amd_iommu_unmap, |
| 3405 | .iova_to_phys = amd_iommu_iova_to_phys, | 3427 | .iova_to_phys = amd_iommu_iova_to_phys, |
| 3406 | .domain_has_cap = amd_iommu_domain_has_cap, | ||
| 3407 | .pgsize_bitmap = AMD_IOMMU_PGSIZES, | 3428 | .pgsize_bitmap = AMD_IOMMU_PGSIZES, |
| 3408 | }; | 3429 | }; |
| 3409 | 3430 | ||
| @@ -4233,7 +4254,7 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq, | |||
| 4233 | return 0; | 4254 | return 0; |
| 4234 | } | 4255 | } |
| 4235 | 4256 | ||
| 4236 | static int setup_hpet_msi(unsigned int irq, unsigned int id) | 4257 | static int alloc_hpet_msi(unsigned int irq, unsigned int id) |
| 4237 | { | 4258 | { |
| 4238 | struct irq_2_irte *irte_info; | 4259 | struct irq_2_irte *irte_info; |
| 4239 | struct irq_cfg *cfg; | 4260 | struct irq_cfg *cfg; |
| @@ -4272,6 +4293,6 @@ struct irq_remap_ops amd_iommu_irq_ops = { | |||
| 4272 | .compose_msi_msg = compose_msi_msg, | 4293 | .compose_msi_msg = compose_msi_msg, |
| 4273 | .msi_alloc_irq = msi_alloc_irq, | 4294 | .msi_alloc_irq = msi_alloc_irq, |
| 4274 | .msi_setup_irq = msi_setup_irq, | 4295 | .msi_setup_irq = msi_setup_irq, |
| 4275 | .setup_hpet_msi = setup_hpet_msi, | 4296 | .alloc_hpet_msi = alloc_hpet_msi, |
| 4276 | }; | 4297 | }; |
| 4277 | #endif | 4298 | #endif |
