aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/amd_iommu.c
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2009-11-26 08:49:59 -0500
committerJoerg Roedel <joerg.roedel@amd.com>2009-11-27 08:20:35 -0500
commit7f760ddd702d162d693bc79f62c3bdd7fe55bd9d (patch)
tree82ee348a6777d500d9744595864169fcc6279c79 /arch/x86/kernel/amd_iommu.c
parent7c392cbe984d904f7c89a6a75b2ac245254e8da5 (diff)
x86/amd-iommu: Cleanup attach/detach_device code
This patch cleans up the attach_device and detach_device paths and fixes reference counting while at it. Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'arch/x86/kernel/amd_iommu.c')
-rw-r--r--arch/x86/kernel/amd_iommu.c102
1 files changed, 58 insertions, 44 deletions
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 530d6080940f..e3363fd5eef5 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -1329,7 +1329,6 @@ static bool dma_ops_domain(struct protection_domain *domain)
1329 1329
1330static void set_dte_entry(u16 devid, struct protection_domain *domain) 1330static void set_dte_entry(u16 devid, struct protection_domain *domain)
1331{ 1331{
1332 struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
1333 u64 pte_root = virt_to_phys(domain->pt_root); 1332 u64 pte_root = virt_to_phys(domain->pt_root);
1334 1333
1335 BUG_ON(amd_iommu_pd_table[devid] != NULL); 1334 BUG_ON(amd_iommu_pd_table[devid] != NULL);
@@ -1344,18 +1343,11 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain)
1344 1343
1345 amd_iommu_pd_table[devid] = domain; 1344 amd_iommu_pd_table[devid] = domain;
1346 1345
1347 /* Do reference counting */
1348 domain->dev_iommu[iommu->index] += 1;
1349 domain->dev_cnt += 1;
1350
1351 /* Flush the changes DTE entry */
1352 iommu_queue_inv_dev_entry(iommu, devid);
1353} 1346}
1354 1347
1355static void clear_dte_entry(u16 devid) 1348static void clear_dte_entry(u16 devid)
1356{ 1349{
1357 struct protection_domain *domain = amd_iommu_pd_table[devid]; 1350 struct protection_domain *domain = amd_iommu_pd_table[devid];
1358 struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
1359 1351
1360 BUG_ON(domain == NULL); 1352 BUG_ON(domain == NULL);
1361 1353
@@ -1368,11 +1360,51 @@ static void clear_dte_entry(u16 devid)
1368 amd_iommu_dev_table[devid].data[2] = 0; 1360 amd_iommu_dev_table[devid].data[2] = 0;
1369 1361
1370 amd_iommu_apply_erratum_63(devid); 1362 amd_iommu_apply_erratum_63(devid);
1363}
1364
1365static void do_attach(struct device *dev, struct protection_domain *domain)
1366{
1367 struct iommu_dev_data *dev_data;
1368 struct amd_iommu *iommu;
1369 u16 devid;
1370
1371 devid = get_device_id(dev);
1372 iommu = amd_iommu_rlookup_table[devid];
1373 dev_data = get_dev_data(dev);
1374
1375 /* Update data structures */
1376 dev_data->domain = domain;
1377 list_add(&dev_data->list, &domain->dev_list);
1378 set_dte_entry(devid, domain);
1379
1380 /* Do reference counting */
1381 domain->dev_iommu[iommu->index] += 1;
1382 domain->dev_cnt += 1;
1383
1384 /* Flush the DTE entry */
1385 iommu_queue_inv_dev_entry(iommu, devid);
1386}
1387
1388static void do_detach(struct device *dev)
1389{
1390 struct iommu_dev_data *dev_data;
1391 struct amd_iommu *iommu;
1392 u16 devid;
1393
1394 devid = get_device_id(dev);
1395 iommu = amd_iommu_rlookup_table[devid];
1396 dev_data = get_dev_data(dev);
1371 1397
1372 /* decrease reference counters */ 1398 /* decrease reference counters */
1373 domain->dev_iommu[iommu->index] -= 1; 1399 dev_data->domain->dev_iommu[iommu->index] -= 1;
1374 domain->dev_cnt -= 1; 1400 dev_data->domain->dev_cnt -= 1;
1401
1402 /* Update data structures */
1403 dev_data->domain = NULL;
1404 list_del(&dev_data->list);
1405 clear_dte_entry(devid);
1375 1406
1407 /* Flush the DTE entry */
1376 iommu_queue_inv_dev_entry(iommu, devid); 1408 iommu_queue_inv_dev_entry(iommu, devid);
1377} 1409}
1378 1410
@@ -1384,12 +1416,10 @@ static int __attach_device(struct device *dev,
1384 struct protection_domain *domain) 1416 struct protection_domain *domain)
1385{ 1417{
1386 struct iommu_dev_data *dev_data, *alias_data; 1418 struct iommu_dev_data *dev_data, *alias_data;
1387 u16 devid, alias;
1388 1419
1389 devid = get_device_id(dev);
1390 alias = amd_iommu_alias_table[devid];
1391 dev_data = get_dev_data(dev); 1420 dev_data = get_dev_data(dev);
1392 alias_data = get_dev_data(dev_data->alias); 1421 alias_data = get_dev_data(dev_data->alias);
1422
1393 if (!alias_data) 1423 if (!alias_data)
1394 return -EINVAL; 1424 return -EINVAL;
1395 1425
@@ -1406,21 +1436,16 @@ static int __attach_device(struct device *dev,
1406 return -EBUSY; 1436 return -EBUSY;
1407 1437
1408 /* Do real assignment */ 1438 /* Do real assignment */
1409 if (alias != devid) { 1439 if (dev_data->alias != dev) {
1410 if (alias_data->domain == NULL) { 1440 alias_data = get_dev_data(dev_data->alias);
1411 alias_data->domain = domain; 1441 if (alias_data->domain == NULL)
1412 list_add(&alias_data->list, &domain->dev_list); 1442 do_attach(dev_data->alias, domain);
1413 set_dte_entry(alias, domain);
1414 }
1415 1443
1416 atomic_inc(&alias_data->bind); 1444 atomic_inc(&alias_data->bind);
1417 } 1445 }
1418 1446
1419 if (dev_data->domain == NULL) { 1447 if (dev_data->domain == NULL)
1420 dev_data->domain = domain; 1448 do_attach(dev, domain);
1421 list_add(&dev_data->list, &domain->dev_list);
1422 set_dte_entry(devid, domain);
1423 }
1424 1449
1425 atomic_inc(&dev_data->bind); 1450 atomic_inc(&dev_data->bind);
1426 1451
@@ -1459,35 +1484,24 @@ static int attach_device(struct device *dev,
1459 */ 1484 */
1460static void __detach_device(struct device *dev) 1485static void __detach_device(struct device *dev)
1461{ 1486{
1462 u16 devid = get_device_id(dev), alias;
1463 struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
1464 struct iommu_dev_data *dev_data = get_dev_data(dev); 1487 struct iommu_dev_data *dev_data = get_dev_data(dev);
1465 struct iommu_dev_data *alias_data; 1488 struct iommu_dev_data *alias_data;
1466 unsigned long flags; 1489 unsigned long flags;
1467 1490
1468 BUG_ON(!iommu); 1491 BUG_ON(!dev_data->domain);
1469 1492
1470 devid = get_device_id(dev); 1493 spin_lock_irqsave(&dev_data->domain->lock, flags);
1471 alias = get_device_id(dev_data->alias);
1472 1494
1473 if (devid != alias) { 1495 if (dev_data->alias != dev) {
1474 alias_data = get_dev_data(dev_data->alias); 1496 alias_data = get_dev_data(dev_data->alias);
1475 if (atomic_dec_and_test(&alias_data->bind)) { 1497 if (atomic_dec_and_test(&alias_data->bind))
1476 spin_lock_irqsave(&alias_data->domain->lock, flags); 1498 do_detach(dev_data->alias);
1477 clear_dte_entry(alias);
1478 list_del(&alias_data->list);
1479 spin_unlock_irqrestore(&alias_data->domain->lock, flags);
1480 alias_data->domain = NULL;
1481 }
1482 } 1499 }
1483 1500
1484 if (atomic_dec_and_test(&dev_data->bind)) { 1501 if (atomic_dec_and_test(&dev_data->bind))
1485 spin_lock_irqsave(&dev_data->domain->lock, flags); 1502 do_detach(dev);
1486 clear_dte_entry(devid); 1503
1487 list_del(&dev_data->list); 1504 spin_unlock_irqrestore(&dev_data->domain->lock, flags);
1488 spin_unlock_irqrestore(&dev_data->domain->lock, flags);
1489 dev_data->domain = NULL;
1490 }
1491 1505
1492 /* 1506 /*
1493 * If we run in passthrough mode the device must be assigned to the 1507 * If we run in passthrough mode the device must be assigned to the