Skip to content

Commit 2c0ae17

Browse files
committed
iommu/amd: Convert iommu initialization to state machine
This step makes it very easy to keep track about the current intialization state of the iommu driver. With this change we can initialize the IOMMU hardware to a point where it can remap interrupts and later resume the initializion to enable dma remapping. Signed-off-by: Joerg Roedel <[email protected]>
1 parent b9b1ce7 commit 2c0ae17

File tree

1 file changed

+109
-64
lines changed

1 file changed

+109
-64
lines changed

drivers/iommu/amd_iommu_init.c

Lines changed: 109 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,23 @@ static u32 dev_table_size; /* size of the device table */
187187
static u32 alias_table_size; /* size of the alias table */
188188
static u32 rlookup_table_size; /* size if the rlookup table */
189189

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+
190205
static int amd_iommu_enable_interrupts(void);
206+
static int __init iommu_go_to_state(enum iommu_init_state state);
191207

192208
static inline void update_last_devid(u16 devid)
193209
{
@@ -1104,7 +1120,7 @@ static void print_iommu_info(void)
11041120
}
11051121
}
11061122

1107-
static int amd_iommu_init_pci(void)
1123+
static int __init amd_iommu_init_pci(void)
11081124
{
11091125
struct amd_iommu *iommu;
11101126
int ret = 0;
@@ -1516,11 +1532,6 @@ static int __init early_amd_iommu_init(void)
15161532
if (!amd_iommu_detected)
15171533
return -ENODEV;
15181534

1519-
if (amd_iommu_dev_table != NULL) {
1520-
/* Hardware already initialized */
1521-
return 0;
1522-
}
1523-
15241535
status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size);
15251536
if (status == AE_NOT_FOUND)
15261537
return -ENODEV;
@@ -1535,7 +1546,8 @@ static int __init early_amd_iommu_init(void)
15351546
* we need to handle. Upon this information the shared data
15361547
* structures for the IOMMUs in the system will be allocated
15371548
*/
1538-
if (find_last_devid_acpi(ivrs_base))
1549+
ret = find_last_devid_acpi(ivrs_base);
1550+
if (ret)
15391551
goto out;
15401552

15411553
dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
@@ -1556,20 +1568,20 @@ static int __init early_amd_iommu_init(void)
15561568
amd_iommu_alias_table = (void *)__get_free_pages(GFP_KERNEL,
15571569
get_order(alias_table_size));
15581570
if (amd_iommu_alias_table == NULL)
1559-
goto free;
1571+
goto out;
15601572

15611573
/* IOMMU rlookup table - find the IOMMU for a specific device */
15621574
amd_iommu_rlookup_table = (void *)__get_free_pages(
15631575
GFP_KERNEL | __GFP_ZERO,
15641576
get_order(rlookup_table_size));
15651577
if (amd_iommu_rlookup_table == NULL)
1566-
goto free;
1578+
goto out;
15671579

15681580
amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages(
15691581
GFP_KERNEL | __GFP_ZERO,
15701582
get_order(MAX_DOMAIN_ID/8));
15711583
if (amd_iommu_pd_alloc_bitmap == NULL)
1572-
goto free;
1584+
goto out;
15731585

15741586
/* init the device table */
15751587
init_device_table();
@@ -1594,41 +1606,17 @@ static int __init early_amd_iommu_init(void)
15941606
*/
15951607
ret = init_iommu_all(ivrs_base);
15961608
if (ret)
1597-
goto free;
1609+
goto out;
15981610

15991611
ret = init_memory_definitions(ivrs_base);
16001612
if (ret)
1601-
goto free;
1613+
goto out;
16021614

16031615
out:
16041616
/* Don't leak any ACPI memory */
16051617
early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size);
16061618
ivrs_base = NULL;
16071619

1608-
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-
16321620
return ret;
16331621
}
16341622

@@ -1686,44 +1674,99 @@ static int amd_iommu_init_dma(void)
16861674
return 0;
16871675
}
16881676

1689-
/*
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.
1677+
/****************************************************************************
16931678
*
1694-
* The function calls amd_iommu_init_hardware() to setup and enable the
1695-
* IOMMU hardware if this has not happened yet. After that the driver
1696-
* registers for the DMA-API and for the IOMMU-API as necessary.
1697-
*/
1698-
static int __init amd_iommu_init(void)
1679+
* AMD IOMMU Initialization State Machine
1680+
*
1681+
****************************************************************************/
1682+
1683+
static int __init state_next(void)
16991684
{
17001685
int ret = 0;
17011686

1702-
ret = amd_iommu_init_hardware();
1703-
if (ret)
1704-
goto out;
1705-
1706-
ret = amd_iommu_enable_interrupts();
1707-
if (ret)
1708-
goto free;
1687+
switch (init_state) {
1688+
case IOMMU_START_STATE:
1689+
if (!detect_ivrs()) {
1690+
init_state = IOMMU_NOT_FOUND;
1691+
ret = -ENODEV;
1692+
} else {
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+
}
17091734

1710-
ret = amd_iommu_init_dma();
1711-
if (ret)
1712-
goto free;
1735+
return ret;
1736+
}
17131737

1714-
amd_iommu_init_api();
1738+
static int __init iommu_go_to_state(enum iommu_init_state state)
1739+
{
1740+
int ret = 0;
17151741

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+
}
17171748

1718-
out:
17191749
return ret;
1750+
}
17201751

1721-
free:
1722-
disable_iommus();
17231752

1724-
free_on_init_error();
17251753

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;
17271770
}
17281771

17291772
/****************************************************************************
@@ -1735,15 +1778,17 @@ static int __init amd_iommu_init(void)
17351778
****************************************************************************/
17361779
int __init amd_iommu_detect(void)
17371780
{
1781+
int ret;
17381782

17391783
if (no_iommu || (iommu_detected && !gart_iommu_aperture))
17401784
return -ENODEV;
17411785

17421786
if (amd_iommu_disabled)
17431787
return -ENODEV;
17441788

1745-
if (!detect_ivrs())
1746-
return -ENODEV;
1789+
ret = iommu_go_to_state(IOMMU_IVRS_DETECTED);
1790+
if (ret)
1791+
return ret;
17471792

17481793
amd_iommu_detected = true;
17491794
iommu_detected = 1;

0 commit comments

Comments
 (0)