diff options
Diffstat (limited to 'drivers/iommu/amd_iommu.c')
-rw-r--r-- | drivers/iommu/amd_iommu.c | 196 |
1 files changed, 143 insertions, 53 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 55074cba20e..c1c74e030a5 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
@@ -57,17 +57,9 @@ | |||
57 | * physically contiguous memory regions it is mapping into page sizes | 57 | * physically contiguous memory regions it is mapping into page sizes |
58 | * that we support. | 58 | * that we support. |
59 | * | 59 | * |
60 | * Traditionally the IOMMU core just handed us the mappings directly, | 60 | * 512GB Pages are not supported due to a hardware bug |
61 | * after making sure the size is an order of a 4KiB page and that the | ||
62 | * mapping has natural alignment. | ||
63 | * | ||
64 | * To retain this behavior, we currently advertise that we support | ||
65 | * all page sizes that are an order of 4KiB. | ||
66 | * | ||
67 | * If at some point we'd like to utilize the IOMMU core's new behavior, | ||
68 | * we could change this to advertise the real page sizes we support. | ||
69 | */ | 61 | */ |
70 | #define AMD_IOMMU_PGSIZES (~0xFFFUL) | 62 | #define AMD_IOMMU_PGSIZES ((~0xFFFUL) & ~(2ULL << 38)) |
71 | 63 | ||
72 | static DEFINE_RWLOCK(amd_iommu_devtable_lock); | 64 | static DEFINE_RWLOCK(amd_iommu_devtable_lock); |
73 | 65 | ||
@@ -140,6 +132,9 @@ static void free_dev_data(struct iommu_dev_data *dev_data) | |||
140 | list_del(&dev_data->dev_data_list); | 132 | list_del(&dev_data->dev_data_list); |
141 | spin_unlock_irqrestore(&dev_data_list_lock, flags); | 133 | spin_unlock_irqrestore(&dev_data_list_lock, flags); |
142 | 134 | ||
135 | if (dev_data->group) | ||
136 | iommu_group_put(dev_data->group); | ||
137 | |||
143 | kfree(dev_data); | 138 | kfree(dev_data); |
144 | } | 139 | } |
145 | 140 | ||
@@ -274,41 +269,23 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) | |||
274 | *from = to; | 269 | *from = to; |
275 | } | 270 | } |
276 | 271 | ||
277 | #define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) | 272 | static struct pci_bus *find_hosted_bus(struct pci_bus *bus) |
278 | |||
279 | static int iommu_init_device(struct device *dev) | ||
280 | { | 273 | { |
281 | struct pci_dev *dma_pdev = NULL, *pdev = to_pci_dev(dev); | 274 | while (!bus->self) { |
282 | struct iommu_dev_data *dev_data; | 275 | if (!pci_is_root_bus(bus)) |
283 | struct iommu_group *group; | 276 | bus = bus->parent; |
284 | u16 alias; | 277 | else |
285 | int ret; | 278 | return ERR_PTR(-ENODEV); |
286 | 279 | } | |
287 | if (dev->archdata.iommu) | ||
288 | return 0; | ||
289 | |||
290 | dev_data = find_dev_data(get_device_id(dev)); | ||
291 | if (!dev_data) | ||
292 | return -ENOMEM; | ||
293 | |||
294 | alias = amd_iommu_alias_table[dev_data->devid]; | ||
295 | if (alias != dev_data->devid) { | ||
296 | struct iommu_dev_data *alias_data; | ||
297 | 280 | ||
298 | alias_data = find_dev_data(alias); | 281 | return bus; |
299 | if (alias_data == NULL) { | 282 | } |
300 | pr_err("AMD-Vi: Warning: Unhandled device %s\n", | ||
301 | dev_name(dev)); | ||
302 | free_dev_data(dev_data); | ||
303 | return -ENOTSUPP; | ||
304 | } | ||
305 | dev_data->alias_data = alias_data; | ||
306 | 283 | ||
307 | dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); | 284 | #define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) |
308 | } | ||
309 | 285 | ||
310 | if (dma_pdev == NULL) | 286 | static struct pci_dev *get_isolation_root(struct pci_dev *pdev) |
311 | dma_pdev = pci_dev_get(pdev); | 287 | { |
288 | struct pci_dev *dma_pdev = pdev; | ||
312 | 289 | ||
313 | /* Account for quirked devices */ | 290 | /* Account for quirked devices */ |
314 | swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); | 291 | swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); |
@@ -330,14 +307,9 @@ static int iommu_init_device(struct device *dev) | |||
330 | * Finding the next device may require skipping virtual buses. | 307 | * Finding the next device may require skipping virtual buses. |
331 | */ | 308 | */ |
332 | while (!pci_is_root_bus(dma_pdev->bus)) { | 309 | while (!pci_is_root_bus(dma_pdev->bus)) { |
333 | struct pci_bus *bus = dma_pdev->bus; | 310 | struct pci_bus *bus = find_hosted_bus(dma_pdev->bus); |
334 | 311 | if (IS_ERR(bus)) | |
335 | while (!bus->self) { | 312 | break; |
336 | if (!pci_is_root_bus(bus)) | ||
337 | bus = bus->parent; | ||
338 | else | ||
339 | goto root_bus; | ||
340 | } | ||
341 | 313 | ||
342 | if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) | 314 | if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) |
343 | break; | 315 | break; |
@@ -345,19 +317,137 @@ static int iommu_init_device(struct device *dev) | |||
345 | swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); | 317 | swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); |
346 | } | 318 | } |
347 | 319 | ||
348 | root_bus: | 320 | return dma_pdev; |
349 | group = iommu_group_get(&dma_pdev->dev); | 321 | } |
350 | pci_dev_put(dma_pdev); | 322 | |
323 | static int use_pdev_iommu_group(struct pci_dev *pdev, struct device *dev) | ||
324 | { | ||
325 | struct iommu_group *group = iommu_group_get(&pdev->dev); | ||
326 | int ret; | ||
327 | |||
351 | if (!group) { | 328 | if (!group) { |
352 | group = iommu_group_alloc(); | 329 | group = iommu_group_alloc(); |
353 | if (IS_ERR(group)) | 330 | if (IS_ERR(group)) |
354 | return PTR_ERR(group); | 331 | return PTR_ERR(group); |
332 | |||
333 | WARN_ON(&pdev->dev != dev); | ||
355 | } | 334 | } |
356 | 335 | ||
357 | ret = iommu_group_add_device(group, dev); | 336 | ret = iommu_group_add_device(group, dev); |
358 | |||
359 | iommu_group_put(group); | 337 | iommu_group_put(group); |
338 | return ret; | ||
339 | } | ||
340 | |||
341 | static int use_dev_data_iommu_group(struct iommu_dev_data *dev_data, | ||
342 | struct device *dev) | ||
343 | { | ||
344 | if (!dev_data->group) { | ||
345 | struct iommu_group *group = iommu_group_alloc(); | ||
346 | if (IS_ERR(group)) | ||
347 | return PTR_ERR(group); | ||
348 | |||
349 | dev_data->group = group; | ||
350 | } | ||
351 | |||
352 | return iommu_group_add_device(dev_data->group, dev); | ||
353 | } | ||
354 | |||
355 | static int init_iommu_group(struct device *dev) | ||
356 | { | ||
357 | struct iommu_dev_data *dev_data; | ||
358 | struct iommu_group *group; | ||
359 | struct pci_dev *dma_pdev; | ||
360 | int ret; | ||
361 | |||
362 | group = iommu_group_get(dev); | ||
363 | if (group) { | ||
364 | iommu_group_put(group); | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | dev_data = find_dev_data(get_device_id(dev)); | ||
369 | if (!dev_data) | ||
370 | return -ENOMEM; | ||
371 | |||
372 | if (dev_data->alias_data) { | ||
373 | u16 alias; | ||
374 | struct pci_bus *bus; | ||
375 | |||
376 | if (dev_data->alias_data->group) | ||
377 | goto use_group; | ||
378 | |||
379 | /* | ||
380 | * If the alias device exists, it's effectively just a first | ||
381 | * level quirk for finding the DMA source. | ||
382 | */ | ||
383 | alias = amd_iommu_alias_table[dev_data->devid]; | ||
384 | dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); | ||
385 | if (dma_pdev) { | ||
386 | dma_pdev = get_isolation_root(dma_pdev); | ||
387 | goto use_pdev; | ||
388 | } | ||
389 | |||
390 | /* | ||
391 | * If the alias is virtual, try to find a parent device | ||
392 | * and test whether the IOMMU group is actualy rooted above | ||
393 | * the alias. Be careful to also test the parent device if | ||
394 | * we think the alias is the root of the group. | ||
395 | */ | ||
396 | bus = pci_find_bus(0, alias >> 8); | ||
397 | if (!bus) | ||
398 | goto use_group; | ||
399 | |||
400 | bus = find_hosted_bus(bus); | ||
401 | if (IS_ERR(bus) || !bus->self) | ||
402 | goto use_group; | ||
403 | |||
404 | dma_pdev = get_isolation_root(pci_dev_get(bus->self)); | ||
405 | if (dma_pdev != bus->self || (dma_pdev->multifunction && | ||
406 | !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))) | ||
407 | goto use_pdev; | ||
408 | |||
409 | pci_dev_put(dma_pdev); | ||
410 | goto use_group; | ||
411 | } | ||
412 | |||
413 | dma_pdev = get_isolation_root(pci_dev_get(to_pci_dev(dev))); | ||
414 | use_pdev: | ||
415 | ret = use_pdev_iommu_group(dma_pdev, dev); | ||
416 | pci_dev_put(dma_pdev); | ||
417 | return ret; | ||
418 | use_group: | ||
419 | return use_dev_data_iommu_group(dev_data->alias_data, dev); | ||
420 | } | ||
421 | |||
422 | static int iommu_init_device(struct device *dev) | ||
423 | { | ||
424 | struct pci_dev *pdev = to_pci_dev(dev); | ||
425 | struct iommu_dev_data *dev_data; | ||
426 | u16 alias; | ||
427 | int ret; | ||
428 | |||
429 | if (dev->archdata.iommu) | ||
430 | return 0; | ||
431 | |||
432 | dev_data = find_dev_data(get_device_id(dev)); | ||
433 | if (!dev_data) | ||
434 | return -ENOMEM; | ||
435 | |||
436 | alias = amd_iommu_alias_table[dev_data->devid]; | ||
437 | if (alias != dev_data->devid) { | ||
438 | struct iommu_dev_data *alias_data; | ||
439 | |||
440 | alias_data = find_dev_data(alias); | ||
441 | if (alias_data == NULL) { | ||
442 | pr_err("AMD-Vi: Warning: Unhandled device %s\n", | ||
443 | dev_name(dev)); | ||
444 | free_dev_data(dev_data); | ||
445 | return -ENOTSUPP; | ||
446 | } | ||
447 | dev_data->alias_data = alias_data; | ||
448 | } | ||
360 | 449 | ||
450 | ret = init_iommu_group(dev); | ||
361 | if (ret) | 451 | if (ret) |
362 | return ret; | 452 | return ret; |
363 | 453 | ||