Message ID | 20190909090906.28700-3-kkamagui@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Enhance support for the AMD's fTPM | expand |
On Mon, Sep 09, 2019 at 06:09:06PM +0900, Seunghun Han wrote: > 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@gmail.com> This problem is still valid and not addressed by Vanya's patch (and should not be as it is a disjoint issue). However, calling devm_ioremap() is somewhat racy as the NVS driver is not aware of that. My take is that this should be fixed in the code that assigns regions to the NVS driver e.g. it could look up the regions assigned to the MSFT0101 and ignore those regions. In the end linux-acpi maintainers have the say on this but this would be the angle that I'd take to implement such patch probably. /Jarkko
On Tue, Sep 10, 2019 at 03:42:15PM +0100, Jarkko Sakkinen wrote: > On Mon, Sep 09, 2019 at 06:09:06PM +0900, Seunghun Han wrote: > > 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@gmail.com> > > This problem is still valid and not addressed by Vanya's patch (and > should not be as it is a disjoint issue). However, calling > devm_ioremap() is somewhat racy as the NVS driver is not aware of that. > > My take is that this should be fixed in the code that assigns regions to > the NVS driver e.g. it could look up the regions assigned to the > MSFT0101 and ignore those regions. In the end linux-acpi maintainers > have the say on this but this would be the angle that I'd take to > implement such patch probably. Matthew pointed out that having a hook in NVS driver is better solution because it is nil functionality if the TPM driver is loaded. We need functions to: 1. Request a region from the NVS driver (when tpm_crb loads) 2. Release a region back to the NVS Driver (when tpm_crb unloads). My proposal would unnecessarily duplicate code and also leave a side-effect when TPM is not used in the first place. I see this as the overally best solution. If you can come up with a patch for the NVS side and changes to CRB drivers to utilize the new hooks, then combined with Vanya's changes we have a sustainable solution for AMD fTPM. /Jarkko
> > On Tue, Sep 10, 2019 at 03:42:15PM +0100, Jarkko Sakkinen wrote: > > On Mon, Sep 09, 2019 at 06:09:06PM +0900, Seunghun Han wrote: > > > 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@gmail.com> > > > > This problem is still valid and not addressed by Vanya's patch (and > > should not be as it is a disjoint issue). However, calling > > devm_ioremap() is somewhat racy as the NVS driver is not aware of that. > > > > My take is that this should be fixed in the code that assigns regions to > > the NVS driver e.g. it could look up the regions assigned to the > > MSFT0101 and ignore those regions. In the end linux-acpi maintainers > > have the say on this but this would be the angle that I'd take to > > implement such patch probably. > > Matthew pointed out that having a hook in NVS driver is better solution > because it is nil functionality if the TPM driver is loaded. We need > functions to: > > 1. Request a region from the NVS driver (when tpm_crb loads) > 2. Release a region back to the NVS Driver (when tpm_crb unloads). > > My proposal would unnecessarily duplicate code and also leave a > side-effect when TPM is not used in the first place. > > I see this as the overally best solution. If you can come up with a > patch for the NVS side and changes to CRB drivers to utilize the new > hooks, then combined with Vanya's changes we have a sustainable solution > for AMD fTPM. It's a great solution. I will update this patch on your advice and send it to you soon. By the way, I have a question about your advice. If we handle the NVS region with NVS driver, calling devm_ioremap() function is fine like crb_ioremap_resource() function in this patch? > > /Jarkko
On Wed, Sep 11, 2019 at 12:28:18AM +0900, Seunghun Han wrote: > > Matthew pointed out that having a hook in NVS driver is better solution > > because it is nil functionality if the TPM driver is loaded. We need > > functions to: > > > > 1. Request a region from the NVS driver (when tpm_crb loads) > > 2. Release a region back to the NVS Driver (when tpm_crb unloads). > > > > My proposal would unnecessarily duplicate code and also leave a > > side-effect when TPM is not used in the first place. > > > > I see this as the overally best solution. If you can come up with a > > patch for the NVS side and changes to CRB drivers to utilize the new > > hooks, then combined with Vanya's changes we have a sustainable solution > > for AMD fTPM. > > It's a great solution. I will update this patch on your advice and > send it to you soon. > > By the way, I have a question about your advice. > If we handle the NVS region with NVS driver, calling devm_ioremap() > function is fine like crb_ioremap_resource() function in this patch? No, you should reclaim the resource that conflicts and return it back when tpm_crb is unregistered (e.g. rmmod tpm_crb). I would try something like enumerating iomem resources with walk_iomem_res_desc(). I would advice to peek at arch/x86/kernel/crash.c for an example how to use this for NVS regions (IORES_DESC_ACPI_NV_STORAGE). E.g. you could use a callback for it along the lines of: static int crb_find_iomem_res_cb(struct resource *res, void *io_res_ptr) { struct resource *io_res = io_res_ptr; if (res->start == io_res->start && res->end == io_res->end) { /* * Backup all resource data so that it can be inserted * later on with the flags it had etc. */ *io_res = *res; return 1; } return 0; } Then you could __release_region() to unallocate the source. When tpm_crb is removed you can then allocate and insert a resource with data matching it had. /Jarkko
> > > Matthew pointed out that having a hook in NVS driver is better solution > > > because it is nil functionality if the TPM driver is loaded. We need > > > functions to: > > > > > > 1. Request a region from the NVS driver (when tpm_crb loads) > > > 2. Release a region back to the NVS Driver (when tpm_crb unloads). > > > > > > My proposal would unnecessarily duplicate code and also leave a > > > side-effect when TPM is not used in the first place. > > > > > > I see this as the overally best solution. If you can come up with a > > > patch for the NVS side and changes to CRB drivers to utilize the new > > > hooks, then combined with Vanya's changes we have a sustainable solution > > > for AMD fTPM. > > > > It's a great solution. I will update this patch on your advice and > > send it to you soon. > > > > By the way, I have a question about your advice. > > If we handle the NVS region with NVS driver, calling devm_ioremap() > > function is fine like crb_ioremap_resource() function in this patch? > > No, you should reclaim the resource that conflicts and return it back > when tpm_crb is unregistered (e.g. rmmod tpm_crb). > > I would try something like enumerating iomem resources with > walk_iomem_res_desc(). I would advice to peek at arch/x86/kernel/crash.c > for an example how to use this for NVS regions > > Then you could __release_region() to unallocate the source. When tpm_crb > is removed you can then allocate and insert a resource with data > matching it had. Thank you for your sincere advice, and I have some questions about it. As you know, the core reason of this ACPI NVS problem is that a busy bit is set to the ACPI NVS area. So, devm_ioremap_resource() function fails because of it. If we want to call devm_ioremap_resource() for this case, we maybe need to rearrange the existing memory layout from the child relationship to the sibling relationship below. We also need to get back when tpm_crb unloads. [ ACPI NVS (parent) [ TPM CMD buffer (child of NVS) ] [ TPM RSP buffer (child of NVS) ] ] <---> [ ACPI NVS head ] [ CMD buffer ] [ NVS middle ] [ RSP buffer ] [ NVS tails ] Our concern is a race condition between NVS driver and TPM CRB driver. In my view, we could solve this problem if we only make and call the functions you said, requesting and releasing a region from NVS driver. NVS driver doesn't rely on iomem layout, and it relies on internal nvs_list data. Therefore, I added some details to your guide. How about this sequence? 1) When tpm_crb driver loads, the driver checks if command/response buffers are in ACPI NVS area. If so, it requests (or removes) the buffer regions from NVS driver's nvs_list (with suspend_nvs_unregister() function I will add to the nvs.c driver). 2) If command/response buffers are in ACPI NVS area, tpm_crb driver calls devm_ioremap() instead of devm_ioremap_resource() like this patch. 3) When tpm_crb driver unloads, the driver releases (or adds) the buffer regions to NVS driver's nvs_list (with existing suspend_nvs_register() function in the nvs.c driver). I think the sequence could solve the problem we concerned. What do you think about the sequence? Seunghun
Sorry for my mistake. I misunderstood some functions in nvs.c. So I have fixed it and sent my email again. My email is below. > > > Matthew pointed out that having a hook in NVS driver is better solution > > > because it is nil functionality if the TPM driver is loaded. We need > > > functions to: > > > > > > 1. Request a region from the NVS driver (when tpm_crb loads) > > > 2. Release a region back to the NVS Driver (when tpm_crb unloads). > > > > > > My proposal would unnecessarily duplicate code and also leave a > > > side-effect when TPM is not used in the first place. > > > > > > I see this as the overally best solution. If you can come up with a > > > patch for the NVS side and changes to CRB drivers to utilize the new > > > hooks, then combined with Vanya's changes we have a sustainable solution > > > for AMD fTPM. > > > > It's a great solution. I will update this patch on your advice and > > send it to you soon. > > > > By the way, I have a question about your advice. > > If we handle the NVS region with NVS driver, calling devm_ioremap() > > function is fine like crb_ioremap_resource() function in this patch? > > No, you should reclaim the resource that conflicts and return it back > when tpm_crb is unregistered (e.g. rmmod tpm_crb). > > I would try something like enumerating iomem resources with > walk_iomem_res_desc(). I would advice to peek at arch/x86/kernel/crash.c > for an example how to use this for NVS regions > > Then you could __release_region() to unallocate the source. When tpm_crb > is removed you can then allocate and insert a resource with data > matching it had. Thank you for your sincere advice, and I have some questions about it. As you know, the core reason of this ACPI NVS problem is that a busy bit is set to the ACPI NVS area. So, devm_ioremap_resource() function fails because of it. If we want to call devm_ioremap_resource() for this case, we maybe need to rearrange the existing memory layout from the child relationship to the sibling relationship below. We also need to get back when tpm_crb unloads. [ ACPI NVS (parent) [ TPM CMD buffer (child of NVS) ] [ TPM RSP buffer (child of NVS) ] ] <---> [ ACPI NVS head ] [ CMD buffer ] [ NVS middle ] [ RSP buffer ] [ NVS tails ] Our concern is a race condition between NVS driver and TPM CRB driver. In my view, we could solve this problem if we only make and call the functions you said, requesting and releasing a region from NVS driver. NVS driver doesn't rely on iomem layout, and it relies on internal nvs_region_list data. Therefore, I added some details to your guide. How about this sequence? 1) When tpm_crb driver loads, the driver checks if command/response buffers are in ACPI NVS area. If so, it requests (or removes) the buffer regions from NVS driver's nvs_region_list (with acpi_nvs_unregister() function I will add to the nvs.c driver). 2) If command/response buffers are in ACPI NVS area, tpm_crb driver calls devm_ioremap() instead of devm_ioremap_resource() like this patch. 3) When tpm_crb driver unloads, the driver releases (or adds) the buffer regions to NVS driver's nvs_region_list (with existing acpi_nvs_register() function in the nvs.c driver). I think the sequence could solve the problem we concerned. What do you think about the sequence? Seunghun
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;
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@gmail.com> --- 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(-)