I got an AMD system which had a Ryzen Threadripper 1950X and MSI mainboard, and I had a problem with AMD's fTPM. My machine showed an error message below, and the fTPM didn't work because of it. [ 5.732084] tpm_crb MSFT0101:00: can't request region for resource [mem 0x79b4f000-0x79b4ffff] [ 5.732089] tpm_crb: probe of MSFT0101:00 failed with error -16 When I saw the iomem, I found two fTPM regions were in the ACPI NVS area. The regions are below. 79a39000-79b6afff : ACPI Non-volatile Storage 79b4b000-79b4bfff : MSFT0101:00 79b4f000-79b4ffff : MSFT0101:00 After analyzing this issue, I found that crb_map_io() function called devm_ioremap_resource() and it failed. The ACPI NVS didn't allow the TPM CRB driver to assign a resource in it because a busy bit was set to the ACPI NVS area. To support AMD's fTPM, I added a function to check intersects between the TPM region and ACPI NVS before it mapped the region. If some intersects are detected, the function just calls devm_ioremap() for a workaround. If there is no intersect, it calls devm_ioremap_resource(). Signed-off-by: Seunghun Han <kkamagui@xxxxxxxxx> --- Changes in v2: fix a warning of kbuild test robot. The link is below. https://lkml.org/lkml/2019/8/31/217 drivers/char/tpm/tpm_crb.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 14f486c23af2..6b98a3a995b7 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -450,6 +450,27 @@ static int crb_check_resource(struct acpi_resource *ares, void *data) return 1; } +static void __iomem *crb_ioremap_resource(struct device *dev, + const struct resource *res) +{ + int rc; + resource_size_t size = resource_size(res); + + /* Broken BIOS assigns command and response buffers in ACPI NVS region. + * Check intersections between a resource and ACPI NVS for W/A. + */ + rc = region_intersects(res->start, size, IORESOURCE_MEM | + IORESOURCE_BUSY, IORES_DESC_ACPI_NV_STORAGE); + if (rc != REGION_DISJOINT) { + dev_err(dev, + FW_BUG "Resource overlaps with a ACPI NVS. %pr\n", + res); + return devm_ioremap(dev, res->start, size); + } + + return devm_ioremap_resource(dev, res); +} + static void __iomem *crb_map_res(struct device *dev, struct crb_priv *priv, struct resource *io_res, u64 start, u32 size) { @@ -464,7 +485,7 @@ static void __iomem *crb_map_res(struct device *dev, struct crb_priv *priv, return (void __iomem *) ERR_PTR(-EINVAL); if (!resource_contains(io_res, &new_res)) - return devm_ioremap_resource(dev, &new_res); + return crb_ioremap_resource(dev, &new_res); return priv->iobase + (new_res.start - io_res->start); } @@ -536,7 +557,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, goto out_early; } - priv->iobase = devm_ioremap_resource(dev, &io_res); + priv->iobase = crb_ioremap_resource(dev, &io_res); if (IS_ERR(priv->iobase)) { ret = PTR_ERR(priv->iobase); goto out_early; -- 2.21.0