Re: [PATCH v6 3/4] i2c: designware: Use PCI PSP driver for communication

Andy Shevchenko
2023-03-23T13:15:04Z

On Wed, Mar 22, 2023 at 04:02:25PM -0500, Mario Limonciello wrote:
> Currently the PSP semaphore communication base address is discovered
> by using an MSR that is not architecturally guaranteed for future
> platforms. Also the mailbox that is utilized for communication with
> the PSP may have other consumers in the kernel, so it's better to
> make all communication go through a single driver.

Fine by me,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
> v5->v6:
> * Drop now unnecessary asm/msr.h header
> * Fix IS_REACHABLE
> * Drop tags
> * Fix status code handling for Cezanne
> v4->v5:
> * Pick up tags
> v3->v4:
> * Pick up tags
> v1->v2:
> * Fix Kconfig to use imply
> * Use IS_REACHABLE
> ---
> drivers/i2c/busses/Kconfig | 2 +-
> drivers/i2c/busses/i2c-designware-amdpsp.c | 175 +++-----------------
> drivers/i2c/busses/i2c-designware-core.h | 1 -
> drivers/i2c/busses/i2c-designware-platdrv.c | 1 -
> include/linux/psp-platform-access.h | 1 +
> 5 files changed, 27 insertions(+), 153 deletions(-)
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 25eb4e8fd22f..d53bf716f97d 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -566,9 +566,9 @@ config I2C_DESIGNWARE_PLATFORM
>
> config I2C_DESIGNWARE_AMDPSP
> bool "AMD PSP I2C semaphore support"
> - depends on X86_MSR
> depends on ACPI
> depends on I2C_DESIGNWARE_PLATFORM
> + imply CRYPTO_DEV_SP_PSP
> help
> This driver enables managed host access to the selected I2C bus shared
> between AMD CPU and AMD PSP.
> diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c
> index 652e6b64bd5f..12870dc44bdb 100644
> --- a/drivers/i2c/busses/i2c-designware-amdpsp.c
> +++ b/drivers/i2c/busses/i2c-designware-amdpsp.c
> @@ -1,35 +1,20 @@
> // SPDX-License-Identifier: GPL-2.0
>
> -#include <linux/bitfield.h>
> -#include <linux/bits.h>
> #include <linux/i2c.h>
> -#include <linux/io-64-nonatomic-lo-hi.h>
> +#include <linux/psp-platform-access.h>
> #include <linux/psp.h>
> -#include <linux/types.h>
> #include <linux/workqueue.h>
>
> -#include <asm/msr.h>
> -
> #include "i2c-designware-core.h"
>
> -#define MSR_AMD_PSP_ADDR 0xc00110a2
> -#define PSP_MBOX_OFFSET 0x10570
> -#define PSP_CMD_TIMEOUT_US (500 * USEC_PER_MSEC)
> -
> #define PSP_I2C_RESERVATION_TIME_MS 100
>
> -#define PSP_I2C_REQ_BUS_CMD 0x64
> #define PSP_I2C_REQ_RETRY_CNT 400
> #define PSP_I2C_REQ_RETRY_DELAY_US (25 * USEC_PER_MSEC)
> #define PSP_I2C_REQ_STS_OK 0x0
> #define PSP_I2C_REQ_STS_BUS_BUSY 0x1
> #define PSP_I2C_REQ_STS_INV_PARAM 0x3
>
> -struct psp_req_buffer_hdr {
> - u32 total_size;
> - u32 status;
> -};
> -
> enum psp_i2c_req_type {
> PSP_I2C_REQ_ACQUIRE,
> PSP_I2C_REQ_RELEASE,
> @@ -41,119 +26,12 @@ struct psp_i2c_req {
> enum psp_i2c_req_type type;
> };
>
> -struct psp_mbox {
> - u32 cmd_fields;
> - u64 i2c_req_addr;
> -} __packed;
> -
> static DEFINE_MUTEX(psp_i2c_access_mutex);
> static unsigned long psp_i2c_sem_acquired;
> -static void __iomem *mbox_iomem;
> static u32 psp_i2c_access_count;
> static bool psp_i2c_mbox_fail;
> static struct device *psp_i2c_dev;
>
> -/*
> - * Implementation of PSP-x86 i2c-arbitration mailbox introduced for AMD Cezanne
> - * family of SoCs.
> - */
> -
> -static int psp_get_mbox_addr(unsigned long *mbox_addr)
> -{
> - unsigned long long psp_mmio;
> -
> - if (rdmsrl_safe(MSR_AMD_PSP_ADDR, &psp_mmio))
> - return -EIO;
> -
> - *mbox_addr = (unsigned long)(psp_mmio + PSP_MBOX_OFFSET);
> -
> - return 0;
> -}
> -
> -static int psp_mbox_probe(void)
> -{
> - unsigned long mbox_addr;
> - int ret;
> -
> - ret = psp_get_mbox_addr(&mbox_addr);
> - if (ret)
> - return ret;
> -
> - mbox_iomem = ioremap(mbox_addr, sizeof(struct psp_mbox));
> - if (!mbox_iomem)
> - return -ENOMEM;
> -
> - return 0;
> -}
> -
> -/* Recovery field should be equal 0 to start sending commands */
> -static int psp_check_mbox_recovery(struct psp_mbox __iomem *mbox)
> -{
> - u32 tmp;
> -
> - tmp = readl(&mbox->cmd_fields);
> -
> - return FIELD_GET(PSP_CMDRESP_RECOVERY, tmp);
> -}
> -
> -static int psp_wait_cmd(struct psp_mbox __iomem *mbox)
> -{
> - u32 tmp, expected;
> -
> - /* Expect mbox_cmd to be cleared and the response bit to be set by PSP */
> - expected = FIELD_PREP(PSP_CMDRESP_RESP, 1);
> -
> - /*
> - * Check for readiness of PSP mailbox in a tight loop in order to
> - * process further as soon as command was consumed.
> - */
> - return readl_poll_timeout(&mbox->cmd_fields, tmp, (tmp == expected),
> - 0, PSP_CMD_TIMEOUT_US);
> -}
> -
> -/* Status equal to 0 means that PSP succeed processing command */
> -static u32 psp_check_mbox_sts(struct psp_mbox __iomem *mbox)
> -{
> - u32 cmd_reg;
> -
> - cmd_reg = readl(&mbox->cmd_fields);
> -
> - return FIELD_GET(PSP_CMDRESP_STS, cmd_reg);
> -}
> -
> -static int psp_send_cmd(struct psp_i2c_req *req)
> -{
> - struct psp_mbox __iomem *mbox = mbox_iomem;
> - phys_addr_t req_addr;
> - u32 cmd_reg;
> -
> - if (psp_check_mbox_recovery(mbox))
> - return -EIO;
> -
> - if (psp_wait_cmd(mbox))
> - return -EBUSY;
> -
> - /*
> - * Fill mailbox with address of command-response buffer, which will be
> - * used for sending i2c requests as well as reading status returned by
> - * PSP. Use physical address of buffer, since PSP will map this region.
> - */
> - req_addr = __psp_pa((void *)req);
> - writeq(req_addr, &mbox->i2c_req_addr);
> -
> - /* Write command register to trigger processing */
> - cmd_reg = FIELD_PREP(PSP_CMDRESP_CMD, PSP_I2C_REQ_BUS_CMD);
> - writel(cmd_reg, &mbox->cmd_fields);
> -
> - if (psp_wait_cmd(mbox))
> - return -ETIMEDOUT;
> -
> - if (psp_check_mbox_sts(mbox))
> - return -EIO;
> -
> - return 0;
> -}
> -
> /* Helper to verify status returned by PSP */
> static int check_i2c_req_sts(struct psp_i2c_req *req)
> {
> @@ -173,22 +51,25 @@ static int check_i2c_req_sts(struct psp_i2c_req *req)
> }
> }
>
> -static int psp_send_check_i2c_req(struct psp_i2c_req *req)
> +/*
> + * Errors in x86-PSP i2c-arbitration protocol may occur at two levels:
> + * 1. mailbox communication - PSP is not operational or some IO errors with
> + * basic communication had happened.
> + * 2. i2c-requests - PSP refuses to grant i2c arbitration to x86 for too long.
> + *
> + * In order to distinguish between these in error handling code all mailbox
> + * communication errors on the first level (from CCP symbols) will be passed
> + * up and if -EIO is returned the second level will be checked.
> + */
> +static int psp_send_i2c_req_cezanne(struct psp_i2c_req *req)
> {
> - /*
> - * Errors in x86-PSP i2c-arbitration protocol may occur at two levels:
> - * 1. mailbox communication - PSP is not operational or some IO errors
> - * with basic communication had happened;
> - * 2. i2c-requests - PSP refuses to grant i2c arbitration to x86 for too
> - * long.
> - * In order to distinguish between these two in error handling code, all
> - * errors on the first level (returned by psp_send_cmd) are shadowed by
> - * -EIO.
> - */
> - if (psp_send_cmd(req))
> - return -EIO;
> + int ret;
>
> - return check_i2c_req_sts(req);
> + ret = psp_send_platform_access_msg(PSP_I2C_REQ_BUS_CMD, (struct psp_request *)req);
> + if (ret == -EIO)
> + return check_i2c_req_sts(req);
> +
> + return ret;
> }
>
> static int psp_send_i2c_req(enum psp_i2c_req_type i2c_req_type)
> @@ -202,11 +83,11 @@ static int psp_send_i2c_req(enum psp_i2c_req_type i2c_req_type)
> if (!req)
> return -ENOMEM;
>
> - req->hdr.total_size = sizeof(*req);
> + req->hdr.payload_size = sizeof(*req);
> req->type = i2c_req_type;
>
> start = jiffies;
> - ret = read_poll_timeout(psp_send_check_i2c_req, status,
> + ret = read_poll_timeout(psp_send_i2c_req_cezanne, status,
> (status != -EBUSY),
> PSP_I2C_REQ_RETRY_DELAY_US,
> PSP_I2C_REQ_RETRY_CNT * PSP_I2C_REQ_RETRY_DELAY_US,
> @@ -381,7 +262,8 @@ static const struct i2c_lock_operations i2c_dw_psp_lock_ops = {
>
> int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev)
> {
> - int ret;
> + if (!IS_REACHABLE(CONFIG_CRYPTO_DEV_CCP_DD))
> + return -ENODEV;
>
> if (!dev)
> return -ENODEV;
> @@ -393,11 +275,10 @@ int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev)
> if (psp_i2c_dev)
> return -EEXIST;
>
> - psp_i2c_dev = dev->dev;
> + if (psp_check_platform_access_status())
> + return -EPROBE_DEFER;
>
> - ret = psp_mbox_probe();
> - if (ret)
> - return ret;
> + psp_i2c_dev = dev->dev;
>
> dev_info(psp_i2c_dev, "I2C bus managed by AMD PSP\n");
>
> @@ -411,9 +292,3 @@ int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev)
>
> return 0;
> }
> -
> -/* Unmap area used as a mailbox with PSP */
> -void i2c_dw_amdpsp_remove_lock_support(struct dw_i2c_dev *dev)
> -{
> - iounmap(mbox_iomem);
> -}
> diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
> index 050d8c63ad3c..c5d87aae39c6 100644
> --- a/drivers/i2c/busses/i2c-designware-core.h
> +++ b/drivers/i2c/busses/i2c-designware-core.h
> @@ -383,7 +383,6 @@ int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev);
>
> #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_AMDPSP)
> int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev);
> -void i2c_dw_amdpsp_remove_lock_support(struct dw_i2c_dev *dev);
> #endif
>
> int i2c_dw_validate_speed(struct dw_i2c_dev *dev);
> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
> index 74182db03a88..89ad88c54754 100644
> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
> @@ -214,7 +214,6 @@ static const struct i2c_dw_semaphore_callbacks i2c_dw_semaphore_cb_table[] = {
> #ifdef CONFIG_I2C_DESIGNWARE_AMDPSP
> {
> .probe = i2c_dw_amdpsp_probe_lock_support,
> - .remove = i2c_dw_amdpsp_remove_lock_support,
> },
> #endif
> {}
> diff --git a/include/linux/psp-platform-access.h b/include/linux/psp-platform-access.h
> index 1b661341d8f3..75da8f5f7ad8 100644
> --- a/include/linux/psp-platform-access.h
> +++ b/include/linux/psp-platform-access.h
> @@ -7,6 +7,7 @@
>
> enum psp_platform_access_msg {
> PSP_CMD_NONE = 0x0,
> + PSP_I2C_REQ_BUS_CMD = 0x64,
> };
>
> struct psp_req_buffer_hdr {
> --
> 2.34.1
>

--
With Best Regards,
Andy Shevchenko