diff options
Diffstat (limited to 'drivers/iommu/amd_iommu_init.c')
-rw-r--r-- | drivers/iommu/amd_iommu_init.c | 173 |
1 files changed, 109 insertions, 64 deletions
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 53828b61e9ac..500e7f15f5c2 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c | |||
@@ -187,7 +187,23 @@ static u32 dev_table_size; /* size of the device table */ | |||
187 | static u32 alias_table_size; /* size of the alias table */ | 187 | static u32 alias_table_size; /* size of the alias table */ |
188 | static u32 rlookup_table_size; /* size if the rlookup table */ | 188 | static u32 rlookup_table_size; /* size if the rlookup table */ |
189 | 189 | ||
190 | enum iommu_init_state { | ||
191 | IOMMU_START_STATE, | ||
192 | IOMMU_IVRS_DETECTED, | ||
193 | IOMMU_ACPI_FINISHED, | ||
194 | IOMMU_ENABLED, | ||
195 | IOMMU_PCI_INIT, | ||
196 | IOMMU_INTERRUPTS_EN, | ||
197 | IOMMU_DMA_OPS, | ||
198 | IOMMU_INITIALIZED, | ||
199 | IOMMU_NOT_FOUND, | ||
200 | IOMMU_INIT_ERROR, | ||
201 | }; | ||
202 | |||
203 | static enum iommu_init_state init_state = IOMMU_START_STATE; | ||
204 | |||
190 | static int amd_iommu_enable_interrupts(void); | 205 | static int amd_iommu_enable_interrupts(void); |
206 | static int __init iommu_go_to_state(enum iommu_init_state state); | ||
191 | 207 | ||
192 | static inline void update_last_devid(u16 devid) | 208 | static inline void update_last_devid(u16 devid) |
193 | { | 209 | { |
@@ -1104,7 +1120,7 @@ static void print_iommu_info(void) | |||
1104 | } | 1120 | } |
1105 | } | 1121 | } |
1106 | 1122 | ||
1107 | static int amd_iommu_init_pci(void) | 1123 | static int __init amd_iommu_init_pci(void) |
1108 | { | 1124 | { |
1109 | struct amd_iommu *iommu; | 1125 | struct amd_iommu *iommu; |
1110 | int ret = 0; | 1126 | int ret = 0; |
@@ -1516,11 +1532,6 @@ static int __init early_amd_iommu_init(void) | |||
1516 | if (!amd_iommu_detected) | 1532 | if (!amd_iommu_detected) |
1517 | return -ENODEV; | 1533 | return -ENODEV; |
1518 | 1534 | ||
1519 | if (amd_iommu_dev_table != NULL) { | ||
1520 | /* Hardware already initialized */ | ||
1521 | return 0; | ||
1522 | } | ||
1523 | |||
1524 | status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size); | 1535 | status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size); |
1525 | if (status == AE_NOT_FOUND) | 1536 | if (status == AE_NOT_FOUND) |
1526 | return -ENODEV; | 1537 | return -ENODEV; |
@@ -1535,7 +1546,8 @@ static int __init early_amd_iommu_init(void) | |||
1535 | * we need to handle. Upon this information the shared data | 1546 | * we need to handle. Upon this information the shared data |
1536 | * structures for the IOMMUs in the system will be allocated | 1547 | * structures for the IOMMUs in the system will be allocated |
1537 | */ | 1548 | */ |
1538 | if (find_last_devid_acpi(ivrs_base)) | 1549 | ret = find_last_devid_acpi(ivrs_base); |
1550 | if (ret) | ||
1539 | goto out; | 1551 | goto out; |
1540 | 1552 | ||
1541 | dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE); | 1553 | dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE); |
@@ -1556,20 +1568,20 @@ static int __init early_amd_iommu_init(void) | |||
1556 | amd_iommu_alias_table = (void *)__get_free_pages(GFP_KERNEL, | 1568 | amd_iommu_alias_table = (void *)__get_free_pages(GFP_KERNEL, |
1557 | get_order(alias_table_size)); | 1569 | get_order(alias_table_size)); |
1558 | if (amd_iommu_alias_table == NULL) | 1570 | if (amd_iommu_alias_table == NULL) |
1559 | goto free; | 1571 | goto out; |
1560 | 1572 | ||
1561 | /* IOMMU rlookup table - find the IOMMU for a specific device */ | 1573 | /* IOMMU rlookup table - find the IOMMU for a specific device */ |
1562 | amd_iommu_rlookup_table = (void *)__get_free_pages( | 1574 | amd_iommu_rlookup_table = (void *)__get_free_pages( |
1563 | GFP_KERNEL | __GFP_ZERO, | 1575 | GFP_KERNEL | __GFP_ZERO, |
1564 | get_order(rlookup_table_size)); | 1576 | get_order(rlookup_table_size)); |
1565 | if (amd_iommu_rlookup_table == NULL) | 1577 | if (amd_iommu_rlookup_table == NULL) |
1566 | goto free; | 1578 | goto out; |
1567 | 1579 | ||
1568 | amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages( | 1580 | amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages( |
1569 | GFP_KERNEL | __GFP_ZERO, | 1581 | GFP_KERNEL | __GFP_ZERO, |
1570 | get_order(MAX_DOMAIN_ID/8)); | 1582 | get_order(MAX_DOMAIN_ID/8)); |
1571 | if (amd_iommu_pd_alloc_bitmap == NULL) | 1583 | if (amd_iommu_pd_alloc_bitmap == NULL) |
1572 | goto free; | 1584 | goto out; |
1573 | 1585 | ||
1574 | /* init the device table */ | 1586 | /* init the device table */ |
1575 | init_device_table(); | 1587 | init_device_table(); |
@@ -1594,11 +1606,11 @@ static int __init early_amd_iommu_init(void) | |||
1594 | */ | 1606 | */ |
1595 | ret = init_iommu_all(ivrs_base); | 1607 | ret = init_iommu_all(ivrs_base); |
1596 | if (ret) | 1608 | if (ret) |
1597 | goto free; | 1609 | goto out; |
1598 | 1610 | ||
1599 | ret = init_memory_definitions(ivrs_base); | 1611 | ret = init_memory_definitions(ivrs_base); |
1600 | if (ret) | 1612 | if (ret) |
1601 | goto free; | 1613 | goto out; |
1602 | 1614 | ||
1603 | out: | 1615 | out: |
1604 | /* Don't leak any ACPI memory */ | 1616 | /* Don't leak any ACPI memory */ |
@@ -1606,30 +1618,6 @@ out: | |||
1606 | ivrs_base = NULL; | 1618 | ivrs_base = NULL; |
1607 | 1619 | ||
1608 | return ret; | 1620 | return ret; |
1609 | |||
1610 | free: | ||
1611 | free_on_init_error(); | ||
1612 | |||
1613 | goto out; | ||
1614 | } | ||
1615 | |||
1616 | int __init amd_iommu_init_hardware(void) | ||
1617 | { | ||
1618 | int ret = 0; | ||
1619 | |||
1620 | ret = early_amd_iommu_init(); | ||
1621 | if (ret) | ||
1622 | return ret; | ||
1623 | |||
1624 | ret = amd_iommu_init_pci(); | ||
1625 | if (ret) | ||
1626 | return ret; | ||
1627 | |||
1628 | enable_iommus(); | ||
1629 | |||
1630 | register_syscore_ops(&amd_iommu_syscore_ops); | ||
1631 | |||
1632 | return ret; | ||
1633 | } | 1621 | } |
1634 | 1622 | ||
1635 | static int amd_iommu_enable_interrupts(void) | 1623 | static int amd_iommu_enable_interrupts(void) |
@@ -1686,44 +1674,99 @@ static int amd_iommu_init_dma(void) | |||
1686 | return 0; | 1674 | return 0; |
1687 | } | 1675 | } |
1688 | 1676 | ||
1689 | /* | 1677 | /**************************************************************************** |
1690 | * This is the core init function for AMD IOMMU hardware in the system. | ||
1691 | * This function is called from the generic x86 DMA layer initialization | ||
1692 | * code. | ||
1693 | * | 1678 | * |
1694 | * The function calls amd_iommu_init_hardware() to setup and enable the | 1679 | * AMD IOMMU Initialization State Machine |
1695 | * IOMMU hardware if this has not happened yet. After that the driver | 1680 | * |
1696 | * registers for the DMA-API and for the IOMMU-API as necessary. | 1681 | ****************************************************************************/ |
1697 | */ | 1682 | |
1698 | static int __init amd_iommu_init(void) | 1683 | static int __init state_next(void) |
1699 | { | 1684 | { |
1700 | int ret = 0; | 1685 | int ret = 0; |
1701 | 1686 | ||
1702 | ret = amd_iommu_init_hardware(); | 1687 | switch (init_state) { |
1703 | if (ret) | 1688 | case IOMMU_START_STATE: |
1704 | goto out; | 1689 | if (!detect_ivrs()) { |
1705 | 1690 | init_state = IOMMU_NOT_FOUND; | |
1706 | ret = amd_iommu_enable_interrupts(); | 1691 | ret = -ENODEV; |
1707 | if (ret) | 1692 | } else { |
1708 | goto free; | 1693 | init_state = IOMMU_IVRS_DETECTED; |
1694 | } | ||
1695 | break; | ||
1696 | case IOMMU_IVRS_DETECTED: | ||
1697 | ret = early_amd_iommu_init(); | ||
1698 | init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED; | ||
1699 | break; | ||
1700 | case IOMMU_ACPI_FINISHED: | ||
1701 | early_enable_iommus(); | ||
1702 | register_syscore_ops(&amd_iommu_syscore_ops); | ||
1703 | x86_platform.iommu_shutdown = disable_iommus; | ||
1704 | init_state = IOMMU_ENABLED; | ||
1705 | break; | ||
1706 | case IOMMU_ENABLED: | ||
1707 | ret = amd_iommu_init_pci(); | ||
1708 | init_state = ret ? IOMMU_INIT_ERROR : IOMMU_PCI_INIT; | ||
1709 | enable_iommus_v2(); | ||
1710 | break; | ||
1711 | case IOMMU_PCI_INIT: | ||
1712 | ret = amd_iommu_enable_interrupts(); | ||
1713 | init_state = ret ? IOMMU_INIT_ERROR : IOMMU_INTERRUPTS_EN; | ||
1714 | break; | ||
1715 | case IOMMU_INTERRUPTS_EN: | ||
1716 | ret = amd_iommu_init_dma(); | ||
1717 | init_state = ret ? IOMMU_INIT_ERROR : IOMMU_DMA_OPS; | ||
1718 | break; | ||
1719 | case IOMMU_DMA_OPS: | ||
1720 | init_state = IOMMU_INITIALIZED; | ||
1721 | break; | ||
1722 | case IOMMU_INITIALIZED: | ||
1723 | /* Nothing to do */ | ||
1724 | break; | ||
1725 | case IOMMU_NOT_FOUND: | ||
1726 | case IOMMU_INIT_ERROR: | ||
1727 | /* Error states => do nothing */ | ||
1728 | ret = -EINVAL; | ||
1729 | break; | ||
1730 | default: | ||
1731 | /* Unknown state */ | ||
1732 | BUG(); | ||
1733 | } | ||
1709 | 1734 | ||
1710 | ret = amd_iommu_init_dma(); | 1735 | return ret; |
1711 | if (ret) | 1736 | } |
1712 | goto free; | ||
1713 | 1737 | ||
1714 | amd_iommu_init_api(); | 1738 | static int __init iommu_go_to_state(enum iommu_init_state state) |
1739 | { | ||
1740 | int ret = 0; | ||
1715 | 1741 | ||
1716 | x86_platform.iommu_shutdown = disable_iommus; | 1742 | while (init_state != state) { |
1743 | ret = state_next(); | ||
1744 | if (init_state == IOMMU_NOT_FOUND || | ||
1745 | init_state == IOMMU_INIT_ERROR) | ||
1746 | break; | ||
1747 | } | ||
1717 | 1748 | ||
1718 | out: | ||
1719 | return ret; | 1749 | return ret; |
1750 | } | ||
1720 | 1751 | ||
1721 | free: | ||
1722 | disable_iommus(); | ||
1723 | 1752 | ||
1724 | free_on_init_error(); | ||
1725 | 1753 | ||
1726 | goto out; | 1754 | /* |
1755 | * This is the core init function for AMD IOMMU hardware in the system. | ||
1756 | * This function is called from the generic x86 DMA layer initialization | ||
1757 | * code. | ||
1758 | */ | ||
1759 | static int __init amd_iommu_init(void) | ||
1760 | { | ||
1761 | int ret; | ||
1762 | |||
1763 | ret = iommu_go_to_state(IOMMU_INITIALIZED); | ||
1764 | if (ret) { | ||
1765 | disable_iommus(); | ||
1766 | free_on_init_error(); | ||
1767 | } | ||
1768 | |||
1769 | return ret; | ||
1727 | } | 1770 | } |
1728 | 1771 | ||
1729 | /**************************************************************************** | 1772 | /**************************************************************************** |
@@ -1735,6 +1778,7 @@ free: | |||
1735 | ****************************************************************************/ | 1778 | ****************************************************************************/ |
1736 | int __init amd_iommu_detect(void) | 1779 | int __init amd_iommu_detect(void) |
1737 | { | 1780 | { |
1781 | int ret; | ||
1738 | 1782 | ||
1739 | if (no_iommu || (iommu_detected && !gart_iommu_aperture)) | 1783 | if (no_iommu || (iommu_detected && !gart_iommu_aperture)) |
1740 | return -ENODEV; | 1784 | return -ENODEV; |
@@ -1742,8 +1786,9 @@ int __init amd_iommu_detect(void) | |||
1742 | if (amd_iommu_disabled) | 1786 | if (amd_iommu_disabled) |
1743 | return -ENODEV; | 1787 | return -ENODEV; |
1744 | 1788 | ||
1745 | if (!detect_ivrs()) | 1789 | ret = iommu_go_to_state(IOMMU_IVRS_DETECTED); |
1746 | return -ENODEV; | 1790 | if (ret) |
1791 | return ret; | ||
1747 | 1792 | ||
1748 | amd_iommu_detected = true; | 1793 | amd_iommu_detected = true; |
1749 | iommu_detected = 1; | 1794 | iommu_detected = 1; |