From e2fae7b237632fe361786fa1dbe734a5bc6f6d4e Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Tue, 8 Feb 2022 15:12:18 +0100 Subject: [PATCH 01/31] i2c: designware: Add AMD PSP I2C bus support mainline inclusion from mainline-v5.18-rc1 commit 78d5e9e299e31bc2deaaa94a45bf8ea024f27e8c category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/78d5e9e299e31bc2deaaa94a45bf8ea024f27e8c -------------------------------- commit 78d5e9e299e31bc2deaaa94a45bf8ea024f27e8c upstream Implement an I2C controller sharing mechanism between the host (kernel) and PSP co-processor on some platforms equipped with AMD Cezanne SoC. On these platforms we need to implement "software" i2c arbitration. Default arbitration owner is PSP and kernel asks for acquire as well as inform about release of the i2c bus via mailbox mechanism. +---------+ <- ACQUIRE | | +---------| CPU |\ | | | \ +----------+ SDA | +---------+ \ | |------- MAILBOX +--> | I2C-DW | SCL | +---------+ | |------- | | | +----------+ +---------| PSP | <- ACK | | +---------+ +---------+ <- RELEASE | | +---------| CPU | | | | +----------+ SDA | +---------+ | |------- MAILBOX +--> | I2C-DW | SCL | +---------+ / | |------- | | | / +----------+ +---------| PSP |/ <- ACK | | +---------+ The solution is similar to i2c-designware-baytrail.c implementation, where we are using a generic i2c-designware-* driver with a small "wrapper". In contrary to baytrail semaphore implementation, beside internal acquire_lock() and release_lock() methods we are also applying quirks to lock_bus() and unlock_bus() global adapter methods. With this in place all i2c clients drivers may lock i2c bus for a desired number of i2c transactions (e.g. write-wait-read) without being aware of that such bus is shared with another entity. Modify i2c_dw_probe_lock_support() to select correct semaphore implementation at runtime, since now we have more than one available. Configure new matching ACPI ID "AMDI0019" and register ARBITRATION_SEMAPHORE flag in order to distinguish setup with PSP arbitration. Add myself as a reviewer for I2C DesignWare in order to help with reviewing and testing possible changes touching new i2c-designware-amdpsp.c module. Signed-off-by: Jan Dabros Reviewed-by: Andy Shevchenko Acked-by: Jarkko Nikula Tested-by: Jarkko Nikula [wsa: removed unneeded blank line and curly braces] Signed-off-by: Wolfram Sang Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- MAINTAINERS | 1 + drivers/acpi/acpi_apd.c | 7 +- drivers/i2c/busses/Kconfig | 11 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-designware-amdpsp.c | 392 +++++++++++++++++++ drivers/i2c/busses/i2c-designware-baytrail.c | 12 +- drivers/i2c/busses/i2c-designware-core.h | 18 +- drivers/i2c/busses/i2c-designware-platdrv.c | 60 +++ 8 files changed, 490 insertions(+), 12 deletions(-) create mode 100644 drivers/i2c/busses/i2c-designware-amdpsp.c diff --git a/MAINTAINERS b/MAINTAINERS index e15f6cc90b64..84bc453b4fd0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17074,6 +17074,7 @@ SYNOPSYS DESIGNWARE I2C DRIVER M: Jarkko Nikula R: Andy Shevchenko R: Mika Westerberg +R: Jan Dabros L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/busses/i2c-designware-* diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index c1f68fdb31bf..dde6bafca32a 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -238,12 +238,13 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { /* Generic apd devices */ #ifdef CONFIG_X86_AMD_PLATFORM_DEVICE { "AMD0010", APD_ADDR(cz_i2c_desc) }, - { "AMDI0010", APD_ADDR(wt_i2c_desc) }, { "AMD0020", APD_ADDR(cz_uart_desc) }, - { "AMDI0020", APD_ADDR(cz_uart_desc) }, - { "AMDI0022", APD_ADDR(cz_uart_desc) }, { "AMD0030", }, { "AMD0040", APD_ADDR(fch_misc_desc)}, + { "AMDI0010", APD_ADDR(wt_i2c_desc) }, + { "AMDI0019", APD_ADDR(wt_i2c_desc) }, + { "AMDI0020", APD_ADDR(cz_uart_desc) }, + { "AMDI0022", APD_ADDR(cz_uart_desc) }, { "HYGO0010", APD_ADDR(wt_i2c_desc) }, #endif #ifdef CONFIG_ARM64 diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d3f48f6160ff..f745cd6d440f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -563,6 +563,17 @@ config I2C_SUNWAY_SW6 Synopsys DesignWare I2C adapter in MCU of CHIP3. Only master mode is supported. +config I2C_DESIGNWARE_AMDPSP + bool "AMD PSP I2C semaphore support" + depends on X86_MSR + depends on ACPI + depends on I2C_DESIGNWARE_PLATFORM + help + This driver enables managed host access to the selected I2C bus shared + between AMD CPU and AMD PSP. + + You should say Y if running on an AMD system equipped with the PSP. + config I2C_DESIGNWARE_BAYTRAIL bool "Intel Baytrail I2C semaphore support" depends on ACPI diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 280e05622d50..1271a7511750 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -58,6 +58,7 @@ i2c-sunway-sw6-y += i2c-sunway-sw6-platdrv.o i2c-designware-core-$(CONFIG_I2C_DESIGNWARE_SLAVE) += i2c-designware-slave.o obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o i2c-designware-platform-y := i2c-designware-platdrv.o +i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_AMDPSP) += i2c-designware-amdpsp.o i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o i2c-designware-pci-y := i2c-designware-pcidrv.o diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c new file mode 100644 index 000000000000..752e0024db03 --- /dev/null +++ b/drivers/i2c/busses/i2c-designware-amdpsp.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include + +#include + +#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_REQ_BUS_CMD 0x64 +#define PSP_I2C_REQ_RETRY_CNT 10 +#define PSP_I2C_REQ_RETRY_DELAY_US (50 * 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 + +#define PSP_MBOX_FIELDS_STS GENMASK(15, 0) +#define PSP_MBOX_FIELDS_CMD GENMASK(23, 16) +#define PSP_MBOX_FIELDS_RESERVED GENMASK(29, 24) +#define PSP_MBOX_FIELDS_RECOVERY BIT(30) +#define PSP_MBOX_FIELDS_READY BIT(31) + +struct psp_req_buffer_hdr { + u32 total_size; + u32 status; +}; + +enum psp_i2c_req_type { + PSP_I2C_REQ_ACQUIRE, + PSP_I2C_REQ_RELEASE, + PSP_I2C_REQ_MAX +}; + +struct psp_i2c_req { + struct psp_req_buffer_hdr hdr; + 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_MBOX_FIELDS_RECOVERY, tmp); +} + +static int psp_wait_cmd(struct psp_mbox __iomem *mbox) +{ + u32 tmp, expected; + + /* Expect mbox_cmd to be cleared and ready bit to be set by PSP */ + expected = FIELD_PREP(PSP_MBOX_FIELDS_READY, 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_MBOX_FIELDS_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_MBOX_FIELDS_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) +{ + int status; + + status = readl(&req->hdr.status); + + switch (status) { + case PSP_I2C_REQ_STS_OK: + return 0; + case PSP_I2C_REQ_STS_BUS_BUSY: + return -EBUSY; + case PSP_I2C_REQ_STS_INV_PARAM: + default: + return -EIO; + }; +} + +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 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; + + return check_i2c_req_sts(req); +} + +static int psp_send_i2c_req(enum psp_i2c_req_type i2c_req_type) +{ + struct psp_i2c_req *req; + unsigned long start; + int status, ret; + + /* Allocate command-response buffer */ + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->hdr.total_size = sizeof(*req); + req->type = i2c_req_type; + + start = jiffies; + ret = read_poll_timeout(psp_send_check_i2c_req, status, + (status != -EBUSY), + PSP_I2C_REQ_RETRY_DELAY_US, + PSP_I2C_REQ_RETRY_CNT * PSP_I2C_REQ_RETRY_DELAY_US, + 0, req); + if (ret) + goto cleanup; + + ret = status; + if (ret) + goto cleanup; + + dev_dbg(psp_i2c_dev, "Request accepted by PSP after %ums\n", + jiffies_to_msecs(jiffies - start)); + +cleanup: + kfree(req); + return ret; +} + +static int psp_acquire_i2c_bus(void) +{ + int status; + + mutex_lock(&psp_i2c_access_mutex); + + /* Return early if mailbox malfunctioned */ + if (psp_i2c_mbox_fail) + goto cleanup; + + /* + * Simply increment usage counter and return if PSP semaphore was + * already taken by kernel. + */ + if (psp_i2c_access_count) { + psp_i2c_access_count++; + goto cleanup; + }; + + status = psp_send_i2c_req(PSP_I2C_REQ_ACQUIRE); + if (status) { + if (status == -ETIMEDOUT) + dev_err(psp_i2c_dev, "Timed out waiting for PSP to release I2C bus\n"); + else + dev_err(psp_i2c_dev, "PSP communication error\n"); + + dev_err(psp_i2c_dev, "Assume i2c bus is for exclusive host usage\n"); + psp_i2c_mbox_fail = true; + goto cleanup; + } + + psp_i2c_sem_acquired = jiffies; + psp_i2c_access_count++; + + /* + * In case of errors with PSP arbitrator psp_i2c_mbox_fail variable is + * set above. As a consequence consecutive calls to acquire will bypass + * communication with PSP. At any case i2c bus is granted to the caller, + * thus always return success. + */ +cleanup: + mutex_unlock(&psp_i2c_access_mutex); + return 0; +} + +static void psp_release_i2c_bus(void) +{ + int status; + + mutex_lock(&psp_i2c_access_mutex); + + /* Return early if mailbox was malfunctional */ + if (psp_i2c_mbox_fail) + goto cleanup; + + /* + * If we are last owner of PSP semaphore, need to release aribtration + * via mailbox. + */ + psp_i2c_access_count--; + if (psp_i2c_access_count) + goto cleanup; + + /* Send a release command to PSP */ + status = psp_send_i2c_req(PSP_I2C_REQ_RELEASE); + if (status) { + if (status == -ETIMEDOUT) + dev_err(psp_i2c_dev, "Timed out waiting for PSP to acquire I2C bus\n"); + else + dev_err(psp_i2c_dev, "PSP communication error\n"); + + dev_err(psp_i2c_dev, "Assume i2c bus is for exclusive host usage\n"); + psp_i2c_mbox_fail = true; + goto cleanup; + } + + dev_dbg(psp_i2c_dev, "PSP semaphore held for %ums\n", + jiffies_to_msecs(jiffies - psp_i2c_sem_acquired)); + +cleanup: + mutex_unlock(&psp_i2c_access_mutex); +} + +/* + * Locking methods are based on the default implementation from + * drivers/i2c/i2c-core-base.c, but with psp acquire and release operations + * added. With this in place we can ensure that i2c clients on the bus shared + * with psp are able to lock HW access to the bus for arbitrary number of + * operations - that is e.g. write-wait-read. + */ +static void i2c_adapter_dw_psp_lock_bus(struct i2c_adapter *adapter, + unsigned int flags) +{ + psp_acquire_i2c_bus(); + rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter)); +} + +static int i2c_adapter_dw_psp_trylock_bus(struct i2c_adapter *adapter, + unsigned int flags) +{ + int ret; + + ret = rt_mutex_trylock(&adapter->bus_lock); + if (ret) + return ret; + + psp_acquire_i2c_bus(); + + return ret; +} + +static void i2c_adapter_dw_psp_unlock_bus(struct i2c_adapter *adapter, + unsigned int flags) +{ + psp_release_i2c_bus(); + rt_mutex_unlock(&adapter->bus_lock); +} + +static const struct i2c_lock_operations i2c_dw_psp_lock_ops = { + .lock_bus = i2c_adapter_dw_psp_lock_bus, + .trylock_bus = i2c_adapter_dw_psp_trylock_bus, + .unlock_bus = i2c_adapter_dw_psp_unlock_bus, +}; + +int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev) +{ + int ret; + + if (!dev) + return -ENODEV; + + if (!(dev->flags & ARBITRATION_SEMAPHORE)) + return -ENODEV; + + /* Allow to bind only one instance of a driver */ + if (psp_i2c_dev) + return -EEXIST; + + psp_i2c_dev = dev->dev; + + ret = psp_mbox_probe(); + if (ret) + return ret; + + dev_info(psp_i2c_dev, "I2C bus managed by AMD PSP\n"); + + /* + * Install global locking callbacks for adapter as well as internal i2c + * controller locks. + */ + dev->adapter.lock_ops = &i2c_dw_psp_lock_ops; + dev->acquire_lock = psp_acquire_i2c_bus; + dev->release_lock = psp_release_i2c_bus; + + 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-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c index c6a7a00e1d52..45774aa47c28 100644 --- a/drivers/i2c/busses/i2c-designware-baytrail.c +++ b/drivers/i2c/busses/i2c-designware-baytrail.c @@ -12,25 +12,25 @@ #include "i2c-designware-core.h" -int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) +int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev) { acpi_status status; unsigned long long shared_host = 0; acpi_handle handle; - if (!dev || !dev->dev) - return 0; + if (!dev) + return -ENODEV; handle = ACPI_HANDLE(dev->dev); if (!handle) - return 0; + return -ENODEV; status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host); if (ACPI_FAILURE(status)) - return 0; + return -ENODEV; if (!shared_host) - return 0; + return -ENODEV; if (!iosf_mbi_available()) return -EPROBE_DEFER; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index eb5ef4d0f463..9b51f3300d47 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -222,6 +222,8 @@ struct reset_control; * @hs_lcnt: high speed LCNT value * @acquire_lock: function to acquire a hardware lock on the bus * @release_lock: function to release a hardware lock on the bus + * @semaphore_idx: Index of table with semaphore type attached to the bus. It's + * -1 if there is no semaphore. * @shared_with_punit: true if this bus is shared with the SoCs PUNIT * @disable: function to disable the controller * @disable_int: function to disable all interrupts @@ -278,6 +280,7 @@ struct dw_i2c_dev { u16 hs_lcnt; int (*acquire_lock)(void); void (*release_lock)(void); + int semaphore_idx; bool shared_with_punit; void (*disable)(struct dw_i2c_dev *dev); void (*disable_int)(struct dw_i2c_dev *dev); @@ -290,11 +293,17 @@ struct dw_i2c_dev { #define ACCESS_INTR_MASK 0x00000001 #define ACCESS_NO_IRQ_SUSPEND 0x00000002 +#define ARBITRATION_SEMAPHORE BIT(2) #define MODEL_MSCC_OCELOT 0x00000100 #define MODEL_BAIKAL_BT1 0x00000200 #define MODEL_MASK 0x00000f00 +struct i2c_dw_semaphore_callbacks { + int (*probe)(struct dw_i2c_dev *dev); + void (*remove)(struct dw_i2c_dev *dev); +}; + int i2c_dw_init_regmap(struct dw_i2c_dev *dev); u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset); u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); @@ -355,9 +364,12 @@ static inline void i2c_dw_configure(struct dw_i2c_dev *dev) } #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL) -extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev); -#else -static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; } +int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev); +#endif + +#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 474754151725..c0d4f2b990c5 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -51,6 +51,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { { "808622C1", ACCESS_NO_IRQ_SUSPEND }, { "AMD0010", ACCESS_INTR_MASK }, { "AMDI0010", ACCESS_INTR_MASK }, + { "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE }, { "AMDI0510", 0 }, { "APMC0D0F", 0 }, { "HISI02A1", 0 }, @@ -205,6 +206,63 @@ static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = { { } /* terminate list */ }; +static const struct i2c_dw_semaphore_callbacks i2c_dw_semaphore_cb_table[] = { +#ifdef CONFIG_I2C_DESIGNWARE_BAYTRAIL + { + .probe = i2c_dw_baytrail_probe_lock_support, + }, +#endif +#ifdef CONFIG_I2C_DESIGNWARE_AMDPSP + { + .probe = i2c_dw_amdpsp_probe_lock_support, + .remove = i2c_dw_amdpsp_remove_lock_support, + }, +#endif + {} +}; + +static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) +{ + const struct i2c_dw_semaphore_callbacks *ptr; + int i = 0; + int ret; + + ptr = i2c_dw_semaphore_cb_table; + + dev->semaphore_idx = -1; + + while (ptr->probe) { + ret = ptr->probe(dev); + if (ret) { + /* + * If there is no semaphore device attached to this + * controller, we shouldn't abort general i2c_controller + * probe. + */ + if (ret != -ENODEV) + return ret; + + i++; + ptr++; + continue; + } + + dev->semaphore_idx = i; + break; + } + + return 0; +} + +static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) +{ + if (dev->semaphore_idx < 0) + return; + + if (i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove) + i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove(dev); +} + static int dw_i2c_plat_probe(struct platform_device *pdev) { struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -346,6 +404,8 @@ static int dw_i2c_plat_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); dw_i2c_plat_pm_cleanup(dev); + i2c_dw_remove_lock_support(dev); + reset_control_assert(dev->rst); return 0; -- Gitee From f42ce78a19dd89a7da243265404bc950fd39884a Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Fri, 18 Feb 2022 14:33:48 +0100 Subject: [PATCH 02/31] i2c: designware: Fix improper usage of readl mainline inclusion from mainline-v5.18-rc1 commit 17ba1e87fca9e6bad7eacbb1ef042c83358d245e category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/17ba1e87fca9e6bad7eacbb1ef042c83358d245e -------------------------------- commit 17ba1e87fca9e6bad7eacbb1ef042c83358d245e upstream Kernel test robot reported incorrect type in argument 1 of readl(), but more importantly it brought attention that MMIO accessor shouldn't be used in this case, since req->hdr.status is part of a command-response buffer in system memory. Since its value may be altered by PSP outside of the scope of current thread (somehow similar to IRQ handler case), we need to use READ_ONCE() to ensure compiler won't optimize this call. Fix also 'status' variable type to reflect that corresponding field in command-response buffer is platform-independent u32. Fixes: 78d5e9e299e3 ("i2c: designware: Add AMD PSP I2C bus support") Signed-off-by: Jan Dabros Reported-by: kernel test robot Reviewed-by: Andy Shevchenko Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang Signed-off-by: PvsNarasimha --- drivers/i2c/busses/i2c-designware-amdpsp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c index 752e0024db03..c64e459afb5c 100644 --- a/drivers/i2c/busses/i2c-designware-amdpsp.c +++ b/drivers/i2c/busses/i2c-designware-amdpsp.c @@ -160,9 +160,10 @@ static int psp_send_cmd(struct psp_i2c_req *req) /* Helper to verify status returned by PSP */ static int check_i2c_req_sts(struct psp_i2c_req *req) { - int status; + u32 status; - status = readl(&req->hdr.status); + /* Status field in command-response buffer is updated by PSP */ + status = READ_ONCE(req->hdr.status); switch (status) { case PSP_I2C_REQ_STS_OK: -- Gitee From 6e49d9747b629377b76e53802d47b9265312dc95 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 19 Jul 2022 11:13:28 -0500 Subject: [PATCH 03/31] crypto: ccp - Add support for new CCP/PSP device ID mainline inclusion from mainline-v6.0-rc1 commit 96ec8dfdd094b7b2b015e092d581835a732949ff category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/96ec8dfdd094b7b2b015e092d581835a732949ff -------------------------------- commit 96ec8dfdd094b7b2b015e092d581835a732949ff upstream Add a new CCP/PSP PCI device ID. This uses same register offsets as the previously supported structure. Signed-off-by: Mario Limonciello Acked-by: Tom Lendacky Acked-by: Rijo Thomas Signed-off-by: Herbert Xu Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/crypto/ccp/sp-pci.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index c13181431d9d..c4b4e233dc35 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -366,6 +366,12 @@ static const struct sp_dev_vdata dev_vdata[] = { .bar = 2, #ifdef CONFIG_CRYPTO_DEV_SP_PSP .psp_vdata = &pspv2, +#endif + }, + { /* 6 */ + .bar = 2, +#ifdef CONFIG_CRYPTO_DEV_SP_PSP + .psp_vdata = &pspv3, #endif }, }; @@ -376,6 +382,7 @@ static const struct pci_device_id sp_pci_table[] = { { PCI_VDEVICE(AMD, 0x1486), (kernel_ulong_t)&dev_vdata[3] }, { PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] }, { PCI_VDEVICE(AMD, 0x14CA), (kernel_ulong_t)&dev_vdata[5] }, + { PCI_VDEVICE(AMD, 0x15C7), (kernel_ulong_t)&dev_vdata[6] }, /* Last entry must be zero */ { 0, } }; -- Gitee From 5b744a0163d1ece0d580c5363f6730e89ed9cfbf Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 10 Mar 2023 15:19:45 -0600 Subject: [PATCH 04/31] crypto: ccp - Add a header for multiple drivers to use `__psp_pa` mainline inclusion from mainline-v6.4-rc1 commit ae7d45fb7ca75e94b478e2404709ba3024774334 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/ae7d45fb7ca75e94b478e2404709ba3024774334 -------------------------------- commit ae7d45fb7ca75e94b478e2404709ba3024774334 upstream The TEE subdriver for CCP, the amdtee driver and the i2c-designware-amdpsp drivers all include `psp-sev.h` even though they don't use SEV functionality. Move the definition of `__psp_pa` into a common header to be included by all of these drivers. Reviewed-by: Jan Dabros Acked-by: Jarkko Nikula # For the drivers/i2c/busses/i2c-designware-amdpsp.c Acked-by: Sumit Garg # For TEE subsystem bits Acked-by: Tom Lendacky Acked-by: Sean Christopherson # KVM Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- arch/x86/kvm/svm/sev.c | 1 + drivers/crypto/ccp/sev-dev.c | 1 + drivers/crypto/ccp/tee-dev.c | 2 +- drivers/i2c/busses/i2c-designware-amdpsp.c | 2 +- drivers/tee/amdtee/call.c | 2 +- drivers/tee/amdtee/shm_pool.c | 2 +- include/linux/psp-sev.h | 8 -------- include/linux/psp.h | 14 ++++++++++++++ 8 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 include/linux/psp.h diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index b39d725077af..966dca28f835 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 055cbb2ad75e..67d7ef6a7905 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c index bcb81fef4211..84e2a512135d 100644 --- a/drivers/crypto/ccp/tee-dev.c +++ b/drivers/crypto/ccp/tee-dev.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include "psp-dev.h" diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c index c64e459afb5c..7235c68c3172 100644 --- a/drivers/i2c/busses/i2c-designware-amdpsp.c +++ b/drivers/i2c/busses/i2c-designware-amdpsp.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/tee/amdtee/call.c b/drivers/tee/amdtee/call.c index 63d428423e90..cfc428a7b988 100644 --- a/drivers/tee/amdtee/call.c +++ b/drivers/tee/amdtee/call.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include "amdtee_if.h" #include "amdtee_private.h" diff --git a/drivers/tee/amdtee/shm_pool.c b/drivers/tee/amdtee/shm_pool.c index 065854e2db18..f05a87bcdd57 100644 --- a/drivers/tee/amdtee/shm_pool.c +++ b/drivers/tee/amdtee/shm_pool.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include "amdtee_private.h" static int pool_op_alloc(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm, diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h index 49d155cd2dfe..42b30c1792dd 100644 --- a/include/linux/psp-sev.h +++ b/include/linux/psp-sev.h @@ -14,14 +14,6 @@ #include -#ifdef CONFIG_X86 -#include - -#define __psp_pa(x) __sme_pa(x) -#else -#define __psp_pa(x) __pa(x) -#endif - #define SEV_FW_BLOB_MAX_SIZE 0x4000 /* 16KB */ /** diff --git a/include/linux/psp.h b/include/linux/psp.h new file mode 100644 index 000000000000..202162487ec3 --- /dev/null +++ b/include/linux/psp.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __PSP_H +#define __PSP_H + +#ifdef CONFIG_X86 +#include + +#define __psp_pa(x) __sme_pa(x) +#else +#define __psp_pa(x) __pa(x) +#endif + +#endif /* __PSP_H */ -- Gitee From 6346e378e137f4449833a23725a0c8451be99c1f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 10 Mar 2023 15:19:46 -0600 Subject: [PATCH 05/31] crypto: ccp - Move some PSP mailbox bit definitions into common header mainline inclusion from mainline-v6.4-rc1 commit 1c5c1daf04d13916867ef68c6ba7ae4f5e73801f category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/1c5c1daf04d13916867ef68c6ba7ae4f5e73801f -------------------------------- commit 1c5c1daf04d13916867ef68c6ba7ae4f5e73801f upstream Some of the bits and fields used for mailboxes communicating with the PSP are common across all mailbox implementations (SEV, TEE, etc). Move these bits into the common `linux/psp.h` so they don't need to be re-defined for each implementation. Acked-by: Rijo Thomas Acked-by: Tom Lendacky Signed-off-by: Mario Limonciello Acked-by: Jarkko Nikula Signed-off-by: Herbert Xu Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/crypto/ccp/psp-dev.h | 3 --- drivers/crypto/ccp/sev-dev.c | 15 +++++++-------- drivers/crypto/ccp/sev-dev.h | 2 +- drivers/crypto/ccp/tee-dev.c | 15 ++++++++------- drivers/i2c/busses/i2c-designware-amdpsp.c | 16 +++++----------- include/linux/psp.h | 12 ++++++++++++ 6 files changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h index ef38e4135d81..a86b0ae33467 100644 --- a/drivers/crypto/ccp/psp-dev.h +++ b/drivers/crypto/ccp/psp-dev.h @@ -17,9 +17,6 @@ #include "sp-dev.h" -#define PSP_CMDRESP_RESP BIT(31) -#define PSP_CMDRESP_ERR_MASK 0xffff - #define MAX_PSP_NAME_LEN 16 extern struct psp_device *psp_master; diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 67d7ef6a7905..e7abd71df0b2 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -7,6 +7,7 @@ * Author: Brijesh Singh */ +#include #include #include #include @@ -83,7 +84,7 @@ static void sev_irq_handler(int irq, void *data, unsigned int status) /* Check if it is SEV command completion: */ reg = ioread32(sev->io_regs + sev->vdata->cmdresp_reg); - if (reg & PSP_CMDRESP_RESP) { + if (FIELD_GET(PSP_CMDRESP_RESP, reg)) { sev->int_rcvd = 1; wake_up(&sev->int_queue); } @@ -194,9 +195,7 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret) sev->int_rcvd = 0; - reg = cmd; - reg <<= SEV_CMDRESP_CMD_SHIFT; - reg |= SEV_CMDRESP_IOC; + reg = FIELD_PREP(SEV_CMDRESP_CMD, cmd) | SEV_CMDRESP_IOC; iowrite32(reg, sev->io_regs + sev->vdata->cmdresp_reg); /* wait for command completion */ @@ -214,11 +213,11 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret) psp_timeout = psp_cmd_timeout; if (psp_ret) - *psp_ret = reg & PSP_CMDRESP_ERR_MASK; + *psp_ret = FIELD_GET(PSP_CMDRESP_STS, reg); - if (reg & PSP_CMDRESP_ERR_MASK) { - dev_dbg(sev->dev, "sev command %#x failed (%#010x)\n", - cmd, reg & PSP_CMDRESP_ERR_MASK); + if (FIELD_GET(PSP_CMDRESP_STS, reg)) { + dev_dbg(sev->dev, "sev command %#x failed (%#010lx)\n", + cmd, FIELD_GET(PSP_CMDRESP_STS, reg)); ret = -EIO; } diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h index 0fd21433f627..c3d22231e1de 100644 --- a/drivers/crypto/ccp/sev-dev.h +++ b/drivers/crypto/ccp/sev-dev.h @@ -25,8 +25,8 @@ #include #include +#define SEV_CMDRESP_CMD GENMASK(26, 16) #define SEV_CMD_COMPLETE BIT(1) -#define SEV_CMDRESP_CMD_SHIFT 16 #define SEV_CMDRESP_IOC BIT(0) struct sev_misc_dev { diff --git a/drivers/crypto/ccp/tee-dev.c b/drivers/crypto/ccp/tee-dev.c index 84e2a512135d..e2b014f16284 100644 --- a/drivers/crypto/ccp/tee-dev.c +++ b/drivers/crypto/ccp/tee-dev.c @@ -8,6 +8,7 @@ * Copyright 2019 Advanced Micro Devices, Inc. */ +#include #include #include #include @@ -69,7 +70,7 @@ static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout, while (--nloop) { *reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg); - if (*reg & PSP_CMDRESP_RESP) + if (FIELD_GET(PSP_CMDRESP_RESP, *reg)) return 0; usleep_range(10000, 10100); @@ -149,9 +150,9 @@ static int tee_init_ring(struct psp_tee_device *tee) goto free_buf; } - if (reg & PSP_CMDRESP_ERR_MASK) { - dev_err(tee->dev, "tee: ring init command failed (%#010x)\n", - reg & PSP_CMDRESP_ERR_MASK); + if (FIELD_GET(PSP_CMDRESP_STS, reg)) { + dev_err(tee->dev, "tee: ring init command failed (%#010lx)\n", + FIELD_GET(PSP_CMDRESP_STS, reg)); tee_free_ring(tee); ret = -EIO; } @@ -179,9 +180,9 @@ static void tee_destroy_ring(struct psp_tee_device *tee) ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, ®); if (ret) { dev_err(tee->dev, "tee: ring destroy command timed out\n"); - } else if (reg & PSP_CMDRESP_ERR_MASK) { - dev_err(tee->dev, "tee: ring destroy command failed (%#010x)\n", - reg & PSP_CMDRESP_ERR_MASK); + } else if (FIELD_GET(PSP_CMDRESP_STS, reg)) { + dev_err(tee->dev, "tee: ring destroy command failed (%#010lx)\n", + FIELD_GET(PSP_CMDRESP_STS, reg)); } free_ring: diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c index 7235c68c3172..6acc000232c8 100644 --- a/drivers/i2c/busses/i2c-designware-amdpsp.c +++ b/drivers/i2c/busses/i2c-designware-amdpsp.c @@ -22,12 +22,6 @@ #define PSP_I2C_REQ_STS_BUS_BUSY 0x1 #define PSP_I2C_REQ_STS_INV_PARAM 0x3 -#define PSP_MBOX_FIELDS_STS GENMASK(15, 0) -#define PSP_MBOX_FIELDS_CMD GENMASK(23, 16) -#define PSP_MBOX_FIELDS_RESERVED GENMASK(29, 24) -#define PSP_MBOX_FIELDS_RECOVERY BIT(30) -#define PSP_MBOX_FIELDS_READY BIT(31) - struct psp_req_buffer_hdr { u32 total_size; u32 status; @@ -96,15 +90,15 @@ static int psp_check_mbox_recovery(struct psp_mbox __iomem *mbox) tmp = readl(&mbox->cmd_fields); - return FIELD_GET(PSP_MBOX_FIELDS_RECOVERY, tmp); + 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 ready bit to be set by PSP */ - expected = FIELD_PREP(PSP_MBOX_FIELDS_READY, 1); + /* 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 @@ -121,7 +115,7 @@ static u32 psp_check_mbox_sts(struct psp_mbox __iomem *mbox) cmd_reg = readl(&mbox->cmd_fields); - return FIELD_GET(PSP_MBOX_FIELDS_STS, cmd_reg); + return FIELD_GET(PSP_CMDRESP_STS, cmd_reg); } static int psp_send_cmd(struct psp_i2c_req *req) @@ -145,7 +139,7 @@ static int psp_send_cmd(struct psp_i2c_req *req) writeq(req_addr, &mbox->i2c_req_addr); /* Write command register to trigger processing */ - cmd_reg = FIELD_PREP(PSP_MBOX_FIELDS_CMD, PSP_I2C_REQ_BUS_CMD); + cmd_reg = FIELD_PREP(PSP_CMDRESP_CMD, PSP_I2C_REQ_BUS_CMD); writel(cmd_reg, &mbox->cmd_fields); if (psp_wait_cmd(mbox)) diff --git a/include/linux/psp.h b/include/linux/psp.h index 202162487ec3..d3424790a70e 100644 --- a/include/linux/psp.h +++ b/include/linux/psp.h @@ -11,4 +11,16 @@ #define __psp_pa(x) __pa(x) #endif +/* + * Fields and bits used by most PSP mailboxes + * + * Note: Some mailboxes (such as SEV) have extra bits or different meanings + * and should include an appropriate local definition in their source file. + */ +#define PSP_CMDRESP_STS GENMASK(15, 0) +#define PSP_CMDRESP_CMD GENMASK(23, 16) +#define PSP_CMDRESP_RESERVED GENMASK(29, 24) +#define PSP_CMDRESP_RECOVERY BIT(30) +#define PSP_CMDRESP_RESP BIT(31) + #endif /* __PSP_H */ -- Gitee From 6e85aca0613c7470efe98eed59d947c96df44025 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 10 Mar 2023 15:19:47 -0600 Subject: [PATCH 06/31] crypto: ccp - Add support for an interface for platform features mainline inclusion from mainline-v6.4-rc1 commit 7ccc4f4e2e50e4a29f9ee8f5c9e187f8491bb6e7 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/7ccc4f4e2e50e4a29f9ee8f5c9e187f8491bb6e7 -------------------------------- commit 7ccc4f4e2e50e4a29f9ee8f5c9e187f8491bb6e7 upstream Some platforms with a PSP support an interface for features that interact directly with the PSP instead of through a SEV or TEE environment. Initialize this interface so that other drivers can consume it. These drivers may either be subdrivers for the ccp module or external modules. For external modules, export a symbol for them to utilize. Acked-by: Tom Lendacky Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/crypto/ccp/Makefile | 3 +- drivers/crypto/ccp/platform-access.c | 166 +++++++++++++++++++++++++++ drivers/crypto/ccp/platform-access.h | 34 ++++++ drivers/crypto/ccp/psp-dev.c | 17 +++ drivers/crypto/ccp/psp-dev.h | 1 + drivers/crypto/ccp/sp-dev.h | 7 ++ include/linux/psp-platform-access.h | 49 ++++++++ 7 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 drivers/crypto/ccp/platform-access.c create mode 100644 drivers/crypto/ccp/platform-access.h create mode 100644 include/linux/psp-platform-access.h diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile index db362fe472ea..f6196495e862 100644 --- a/drivers/crypto/ccp/Makefile +++ b/drivers/crypto/ccp/Makefile @@ -10,7 +10,8 @@ ccp-$(CONFIG_CRYPTO_DEV_CCP_DEBUGFS) += ccp-debugfs.o ccp-$(CONFIG_PCI) += sp-pci.o ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o \ sev-dev.o \ - tee-dev.o + tee-dev.o \ + platform-access.o obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o ccp-crypto-objs := ccp-crypto-main.o \ diff --git a/drivers/crypto/ccp/platform-access.c b/drivers/crypto/ccp/platform-access.c new file mode 100644 index 000000000000..9cc0c60bbf7b --- /dev/null +++ b/drivers/crypto/ccp/platform-access.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Platform Security Processor (PSP) Platform Access interface + * + * Copyright (C) 2023 Advanced Micro Devices, Inc. + * + * Author: Mario Limonciello + * + * Some of this code is adapted from drivers/i2c/busses/i2c-designware-amdpsp.c + * developed by Jan Dabros and Copyright (C) 2022 Google Inc. + * + */ + +#include +#include +#include +#include + +#include "platform-access.h" + +#define PSP_CMD_TIMEOUT_US (500 * USEC_PER_MSEC) + +/* Recovery field should be equal 0 to start sending commands */ +static int check_recovery(u32 __iomem *cmd) +{ + return FIELD_GET(PSP_CMDRESP_RECOVERY, ioread32(cmd)); +} + +static int wait_cmd(u32 __iomem *cmd) +{ + u32 tmp, expected; + + /* Expect mbox_cmd to be cleared and ready 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(cmd, tmp, (tmp & expected), 0, + PSP_CMD_TIMEOUT_US); +} + +int psp_check_platform_access_status(void) +{ + struct psp_device *psp = psp_get_master_device(); + + if (!psp || !psp->platform_access_data) + return -ENODEV; + + return 0; +} +EXPORT_SYMBOL(psp_check_platform_access_status); + +int psp_send_platform_access_msg(enum psp_platform_access_msg msg, + struct psp_request *req) +{ + struct psp_device *psp = psp_get_master_device(); + u32 __iomem *cmd, *lo, *hi; + struct psp_platform_access_device *pa_dev; + phys_addr_t req_addr; + u32 cmd_reg; + int ret; + + if (!psp || !psp->platform_access_data) + return -ENODEV; + + pa_dev = psp->platform_access_data; + cmd = psp->io_regs + pa_dev->vdata->cmdresp_reg; + lo = psp->io_regs + pa_dev->vdata->cmdbuff_addr_lo_reg; + hi = psp->io_regs + pa_dev->vdata->cmdbuff_addr_hi_reg; + + mutex_lock(&pa_dev->mailbox_mutex); + + if (check_recovery(cmd)) { + dev_dbg(psp->dev, "platform mailbox is in recovery\n"); + ret = -EBUSY; + goto unlock; + } + + if (wait_cmd(cmd)) { + dev_dbg(psp->dev, "platform mailbox is not done processing command\n"); + ret = -EBUSY; + goto unlock; + } + + /* + * 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(req); + iowrite32(lower_32_bits(req_addr), lo); + iowrite32(upper_32_bits(req_addr), hi); + + print_hex_dump_debug("->psp ", DUMP_PREFIX_OFFSET, 16, 2, req, + req->header.payload_size, false); + + /* Write command register to trigger processing */ + cmd_reg = FIELD_PREP(PSP_CMDRESP_CMD, msg); + iowrite32(cmd_reg, cmd); + + if (wait_cmd(cmd)) { + ret = -ETIMEDOUT; + goto unlock; + } + + /* Ensure it was triggered by this driver */ + if (ioread32(lo) != lower_32_bits(req_addr) || + ioread32(hi) != upper_32_bits(req_addr)) { + ret = -EBUSY; + goto unlock; + } + + /* Store the status in request header for caller to investigate */ + cmd_reg = ioread32(cmd); + req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg); + if (req->header.status) { + ret = -EIO; + goto unlock; + } + + print_hex_dump_debug("<-psp ", DUMP_PREFIX_OFFSET, 16, 2, req, + req->header.payload_size, false); + + ret = 0; + +unlock: + mutex_unlock(&pa_dev->mailbox_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(psp_send_platform_access_msg); + +void platform_access_dev_destroy(struct psp_device *psp) +{ + struct psp_platform_access_device *pa_dev = psp->platform_access_data; + + if (!pa_dev) + return; + + mutex_destroy(&pa_dev->mailbox_mutex); + psp->platform_access_data = NULL; +} + +int platform_access_dev_init(struct psp_device *psp) +{ + struct device *dev = psp->dev; + struct psp_platform_access_device *pa_dev; + + pa_dev = devm_kzalloc(dev, sizeof(*pa_dev), GFP_KERNEL); + if (!pa_dev) + return -ENOMEM; + + psp->platform_access_data = pa_dev; + pa_dev->psp = psp; + pa_dev->dev = dev; + + pa_dev->vdata = (struct platform_access_vdata *)psp->vdata->platform_access; + + mutex_init(&pa_dev->mailbox_mutex); + + dev_dbg(dev, "platform access enabled\n"); + + return 0; +} diff --git a/drivers/crypto/ccp/platform-access.h b/drivers/crypto/ccp/platform-access.h new file mode 100644 index 000000000000..c3a97893320d --- /dev/null +++ b/drivers/crypto/ccp/platform-access.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * AMD Platform Security Processor (PSP) Platform Access interface + * + * Copyright (C) 2023 Advanced Micro Devices, Inc. + * + * Author: Mario Limonciello + */ + +#ifndef __PSP_PLATFORM_ACCESS_H__ +#define __PSP_PLATFORM_ACCESS_H__ + +#include +#include +#include +#include + +#include "psp-dev.h" + +struct psp_platform_access_device { + struct device *dev; + struct psp_device *psp; + + struct platform_access_vdata *vdata; + + struct mutex mailbox_mutex; + + void *platform_access_data; +}; + +void platform_access_dev_destroy(struct psp_device *psp); +int platform_access_dev_init(struct psp_device *psp); + +#endif /* __PSP_PLATFORM_ACCESS_H__ */ diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index 4bf9eaab4456..b56f16e373ed 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -14,6 +14,7 @@ #include "psp-dev.h" #include "sev-dev.h" #include "tee-dev.h" +#include "platform-access.h" struct psp_device *psp_master; @@ -113,6 +114,17 @@ static int psp_check_support(struct psp_device *psp, return 0; } +static void psp_init_platform_access(struct psp_device *psp) +{ + int ret; + + ret = platform_access_dev_init(psp); + if (ret) { + dev_warn(psp->dev, "platform access init failed: %d\n", ret); + return; + } +} + static int psp_init(struct psp_device *psp, unsigned int capability) { int ret; @@ -129,6 +141,9 @@ static int psp_init(struct psp_device *psp, unsigned int capability) return ret; } + if (psp->vdata->platform_access) + psp_init_platform_access(psp); + return 0; } @@ -214,6 +229,8 @@ void psp_dev_destroy(struct sp_device *sp) tee_dev_destroy(psp); + platform_access_dev_destroy(psp); + sp_free_psp_irq(sp, psp); if (sp->clear_psp_master_device) diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h index a86b0ae33467..61291d670277 100644 --- a/drivers/crypto/ccp/psp-dev.h +++ b/drivers/crypto/ccp/psp-dev.h @@ -42,6 +42,7 @@ struct psp_device { void *sev_data; void *tee_data; + void *platform_access_data; }; void psp_set_sev_irq_handler(struct psp_device *psp, psp_irq_handler_t handler, diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h index 0218d0670eee..8b3691f90a23 100644 --- a/drivers/crypto/ccp/sp-dev.h +++ b/drivers/crypto/ccp/sp-dev.h @@ -53,9 +53,16 @@ struct tee_vdata { const unsigned int ring_rptr_reg; }; +struct platform_access_vdata { + const unsigned int cmdresp_reg; + const unsigned int cmdbuff_addr_lo_reg; + const unsigned int cmdbuff_addr_hi_reg; +}; + struct psp_vdata { const struct sev_vdata *sev; const struct tee_vdata *tee; + const struct platform_access_vdata *platform_access; const unsigned int feature_reg; const unsigned int inten_reg; const unsigned int intsts_reg; diff --git a/include/linux/psp-platform-access.h b/include/linux/psp-platform-access.h new file mode 100644 index 000000000000..977df5cfd494 --- /dev/null +++ b/include/linux/psp-platform-access.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __PSP_PLATFORM_ACCESS_H +#define __PSP_PLATFORM_ACCESS_H + +#include + +enum psp_platform_access_msg { + PSP_CMD_NONE = 0x0, +}; + +struct psp_req_buffer_hdr { + u32 payload_size; + u32 status; +} __packed; + +struct psp_request { + struct psp_req_buffer_hdr header; + void *buf; +} __packed; + +/** + * psp_send_platform_access_msg() - Send a message to control platform features + * + * This function is intended to be used by drivers outside of ccp to communicate + * with the platform. + * + * Returns: + * 0: success + * -%EBUSY: mailbox in recovery or in use + * -%ENODEV: driver not bound with PSP device + * -%ETIMEDOUT: request timed out + * -%EIO: unknown error (see kernel log) + */ +int psp_send_platform_access_msg(enum psp_platform_access_msg, struct psp_request *req); + +/** + * psp_check_platform_access_status() - Checks whether platform features is ready + * + * This function is intended to be used by drivers outside of ccp to determine + * if platform features has initialized. + * + * Returns: + * 0 platform features is ready + * -%ENODEV platform features is not ready or present + */ +int psp_check_platform_access_status(void); + +#endif /* __PSP_PLATFORM_ACCESS_H */ -- Gitee From 8bd4b6ebab03533e7d5432f877aa5a7c2da42f27 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 13 Feb 2024 11:34:28 -0600 Subject: [PATCH 07/31] crypto: ccp - Avoid discarding errors in psp_send_platform_access_msg() mainline inclusion from mainline-v6.9-rc1 commit 0e8fca2f12ceb77c3a6b6f210135031f264aa612 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/0e8fca2f12ceb77c3a6b6f210135031f264aa612 -------------------------------- commit 0e8fca2f12ceb77c3a6b6f210135031f264aa612 upstream Errors can potentially occur in the "processing" of PSP commands or commands can be processed successfully but still return an error code in the header. This second case was being discarded because PSP communication worked but the command returned an error code in the payload header. Capture both cases and return them to the caller as -EIO for the caller to investigate. The caller can detect the latter by looking at `req->header->status`. Reported-and-tested-by: Tim Van Patten Fixes: 7ccc4f4e2e50 ("crypto: ccp - Add support for an interface for platform features") Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu Signed-off-by: PvsNarasimha --- drivers/crypto/ccp/platform-access.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/ccp/platform-access.c b/drivers/crypto/ccp/platform-access.c index 9cc0c60bbf7b..3ba43ca4d1b0 100644 --- a/drivers/crypto/ccp/platform-access.c +++ b/drivers/crypto/ccp/platform-access.c @@ -112,9 +112,16 @@ int psp_send_platform_access_msg(enum psp_platform_access_msg msg, goto unlock; } - /* Store the status in request header for caller to investigate */ + /* + * Read status from PSP. If status is non-zero, it indicates an error + * occurred during "processing" of the command. + * If status is zero, it indicates the command was "processed" + * successfully, but the result of the command is in the payload. + * Return both cases to the caller as -EIO to investigate. + */ cmd_reg = ioread32(cmd); - req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg); + if (FIELD_GET(PSP_CMDRESP_STS, cmd_reg)) + req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg); if (req->header.status) { ret = -EIO; goto unlock; -- Gitee From 8824fc6f09f61a9a75fdc6e5f98e5c2b8a1d448d Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 10 Mar 2023 15:19:48 -0600 Subject: [PATCH 08/31] crypto: ccp - Enable platform access interface on client PSP parts mainline inclusion from mainline-v6.4-rc1 commit 22351239247b30978d06eb2ab5c258e6b344949f category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/22351239247b30978d06eb2ab5c258e6b344949f -------------------------------- commit 22351239247b30978d06eb2ab5c258e6b344949f upstream Client PSP parts support the platform access interface. Add the register offsets so that client parts will initialize this interface. Acked-by: Tom Lendacky Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/crypto/ccp/sp-pci.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index c4b4e233dc35..35e04c51b4f6 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -300,6 +300,12 @@ static const struct tee_vdata teev1 = { .ring_rptr_reg = 0x10554, }; +static const struct platform_access_vdata pa_v1 = { + .cmdresp_reg = 0x10570, /* C2PMSG_28 */ + .cmdbuff_addr_lo_reg = 0x10574, /* C2PMSG_29 */ + .cmdbuff_addr_hi_reg = 0x10578, /* C2PMSG_30 */ +}; + static const struct psp_vdata pspv1 = { .sev = &sevv1, .feature_reg = 0x105fc, @@ -319,6 +325,7 @@ static const struct psp_vdata pspv3 = { .feature_reg = 0x109fc, .inten_reg = 0x10690, .intsts_reg = 0x10694, + .platform_access = &pa_v1, }; #endif -- Gitee From 54a2a298fbe8a64db5feca0306a5f6fd0b3de755 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 10 Mar 2023 15:19:50 -0600 Subject: [PATCH 09/31] crypto: ccp - Add support for ringing a platform doorbell mainline inclusion from mainline-v6.4-rc1 commit d5812571f594b03438d0d7acd0dc044f73c1719e category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/d5812571f594b03438d0d7acd0dc044f73c1719e -------------------------------- commit d5812571f594b03438d0d7acd0dc044f73c1719e upstream Some platforms support using a doorbell to communicate. Export this feature for other drivers to utilize as well. Link: https://lore.kernel.org/linux-i2c/20220916131854.687371-3-jsd@semihalf.com/ Suggested-by: Jan Dabros Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/crypto/ccp/platform-access.c | 66 ++++++++++++++++++++++++++++ drivers/crypto/ccp/platform-access.h | 1 + drivers/crypto/ccp/sp-dev.h | 3 ++ drivers/crypto/ccp/sp-pci.c | 2 + include/linux/psp-platform-access.h | 15 +++++++ include/linux/psp.h | 3 ++ 6 files changed, 90 insertions(+) diff --git a/drivers/crypto/ccp/platform-access.c b/drivers/crypto/ccp/platform-access.c index 3ba43ca4d1b0..0c383fa2be3f 100644 --- a/drivers/crypto/ccp/platform-access.c +++ b/drivers/crypto/ccp/platform-access.c @@ -20,6 +20,14 @@ #define PSP_CMD_TIMEOUT_US (500 * USEC_PER_MSEC) +/* Doorbell shouldn't be ringing */ +static int check_doorbell(u32 __iomem *doorbell) +{ + u32 tmp; + + return readl_poll_timeout(doorbell, tmp, tmp != 0, 0, PSP_CMD_TIMEOUT_US); +} + /* Recovery field should be equal 0 to start sending commands */ static int check_recovery(u32 __iomem *cmd) { @@ -139,6 +147,62 @@ int psp_send_platform_access_msg(enum psp_platform_access_msg msg, } EXPORT_SYMBOL_GPL(psp_send_platform_access_msg); +int psp_ring_platform_doorbell(int msg) +{ + struct psp_device *psp = psp_get_master_device(); + struct psp_platform_access_device *pa_dev; + u32 __iomem *button, *cmd; + int ret, val; + + if (!psp || !psp->platform_access_data) + return -ENODEV; + + pa_dev = psp->platform_access_data; + button = psp->io_regs + pa_dev->vdata->doorbell_button_reg; + cmd = psp->io_regs + pa_dev->vdata->doorbell_cmd_reg; + + mutex_lock(&pa_dev->doorbell_mutex); + + if (check_doorbell(button)) { + dev_dbg(psp->dev, "doorbell is not ready\n"); + ret = -EBUSY; + goto unlock; + } + + if (check_recovery(cmd)) { + dev_dbg(psp->dev, "doorbell command in recovery\n"); + ret = -EBUSY; + goto unlock; + } + + if (wait_cmd(cmd)) { + dev_dbg(psp->dev, "doorbell command not done processing\n"); + ret = -EBUSY; + goto unlock; + } + + iowrite32(FIELD_PREP(PSP_DRBL_MSG, msg), cmd); + iowrite32(PSP_DRBL_RING, button); + + if (wait_cmd(cmd)) { + ret = -ETIMEDOUT; + goto unlock; + } + + val = FIELD_GET(PSP_CMDRESP_STS, ioread32(cmd)); + if (val) { + ret = -EIO; + goto unlock; + } + + ret = 0; +unlock: + mutex_unlock(&pa_dev->doorbell_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(psp_ring_platform_doorbell); + void platform_access_dev_destroy(struct psp_device *psp) { struct psp_platform_access_device *pa_dev = psp->platform_access_data; @@ -147,6 +211,7 @@ void platform_access_dev_destroy(struct psp_device *psp) return; mutex_destroy(&pa_dev->mailbox_mutex); + mutex_destroy(&pa_dev->doorbell_mutex); psp->platform_access_data = NULL; } @@ -166,6 +231,7 @@ int platform_access_dev_init(struct psp_device *psp) pa_dev->vdata = (struct platform_access_vdata *)psp->vdata->platform_access; mutex_init(&pa_dev->mailbox_mutex); + mutex_init(&pa_dev->doorbell_mutex); dev_dbg(dev, "platform access enabled\n"); diff --git a/drivers/crypto/ccp/platform-access.h b/drivers/crypto/ccp/platform-access.h index c3a97893320d..a83f03beb869 100644 --- a/drivers/crypto/ccp/platform-access.h +++ b/drivers/crypto/ccp/platform-access.h @@ -24,6 +24,7 @@ struct psp_platform_access_device { struct platform_access_vdata *vdata; struct mutex mailbox_mutex; + struct mutex doorbell_mutex; void *platform_access_data; }; diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h index 8b3691f90a23..ed6433597ff9 100644 --- a/drivers/crypto/ccp/sp-dev.h +++ b/drivers/crypto/ccp/sp-dev.h @@ -57,6 +57,9 @@ struct platform_access_vdata { const unsigned int cmdresp_reg; const unsigned int cmdbuff_addr_lo_reg; const unsigned int cmdbuff_addr_hi_reg; + const unsigned int doorbell_button_reg; + const unsigned int doorbell_cmd_reg; + }; struct psp_vdata { diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index 35e04c51b4f6..7d06a4972d3b 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -304,6 +304,8 @@ static const struct platform_access_vdata pa_v1 = { .cmdresp_reg = 0x10570, /* C2PMSG_28 */ .cmdbuff_addr_lo_reg = 0x10574, /* C2PMSG_29 */ .cmdbuff_addr_hi_reg = 0x10578, /* C2PMSG_30 */ + .doorbell_button_reg = 0x10a24, /* C2PMSG_73 */ + .doorbell_cmd_reg = 0x10a40, /* C2PMSG_80 */ }; static const struct psp_vdata pspv1 = { diff --git a/include/linux/psp-platform-access.h b/include/linux/psp-platform-access.h index 977df5cfd494..89df4549fada 100644 --- a/include/linux/psp-platform-access.h +++ b/include/linux/psp-platform-access.h @@ -34,6 +34,21 @@ struct psp_request { */ int psp_send_platform_access_msg(enum psp_platform_access_msg, struct psp_request *req); +/** + * psp_ring_platform_doorbell() - Ring platform doorbell + * + * This function is intended to be used by drivers outside of ccp to ring the + * platform doorbell with a message. + * + * Returns: + * 0: success + * -%EBUSY: mailbox in recovery or in use + * -%ENODEV: driver not bound with PSP device + * -%ETIMEDOUT: request timed out + * -%EIO: unknown error (see kernel log) + */ +int psp_ring_platform_doorbell(int msg); + /** * psp_check_platform_access_status() - Checks whether platform features is ready * diff --git a/include/linux/psp.h b/include/linux/psp.h index d3424790a70e..92e60aeef21e 100644 --- a/include/linux/psp.h +++ b/include/linux/psp.h @@ -23,4 +23,7 @@ #define PSP_CMDRESP_RECOVERY BIT(30) #define PSP_CMDRESP_RESP BIT(31) +#define PSP_DRBL_MSG PSP_CMDRESP_CMD +#define PSP_DRBL_RING BIT(0) + #endif /* __PSP_H */ -- Gitee From 1321337c6ba3de27d63d6d8c5955e373707f5b59 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 18 May 2023 22:24:13 -0500 Subject: [PATCH 10/31] crypto: ccp - Add support for PCI device 0x17E0 mainline inclusion from mainline-v6.4-rc2 commit 4aa0931be8f0a2b1571dd24611b26602d2285a1a category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/4aa0931be8f0a2b1571dd24611b26602d2285a1a -------------------------------- commit 4aa0931be8f0a2b1571dd24611b26602d2285a1a upstream PCI device 0x17E0 includes new TEE offsets, doesn't support a platform mailbox, and does support platform doorbell so introduce a new structure to represent it. Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/crypto/ccp/sp-pci.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index 7d06a4972d3b..a11a42d33250 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -300,6 +300,14 @@ static const struct tee_vdata teev1 = { .ring_rptr_reg = 0x10554, }; +static const struct tee_vdata teev2 = { + .cmdresp_reg = 0x10944, /* C2PMSG_17 */ + .cmdbuff_addr_lo_reg = 0x10948, /* C2PMSG_18 */ + .cmdbuff_addr_hi_reg = 0x1094c, /* C2PMSG_19 */ + .ring_wptr_reg = 0x10950, /* C2PMSG_20 */ + .ring_rptr_reg = 0x10954, /* C2PMSG_21 */ +}; + static const struct platform_access_vdata pa_v1 = { .cmdresp_reg = 0x10570, /* C2PMSG_28 */ .cmdbuff_addr_lo_reg = 0x10574, /* C2PMSG_29 */ @@ -308,6 +316,11 @@ static const struct platform_access_vdata pa_v1 = { .doorbell_cmd_reg = 0x10a40, /* C2PMSG_80 */ }; +static const struct platform_access_vdata pa_v2 = { + .doorbell_button_reg = 0x10a24, /* C2PMSG_73 */ + .doorbell_cmd_reg = 0x10a40, /* C2PMSG_80 */ +}; + static const struct psp_vdata pspv1 = { .sev = &sevv1, .feature_reg = 0x105fc, @@ -329,6 +342,14 @@ static const struct psp_vdata pspv3 = { .intsts_reg = 0x10694, .platform_access = &pa_v1, }; +static const struct psp_vdata pspv5 = { + .tee = &teev2, + .platform_access = &pa_v2, + .feature_reg = 0x109fc, /* C2PMSG_63 */ + .inten_reg = 0x10510, /* P2CMSG_INTEN */ + .intsts_reg = 0x10514, /* P2CMSG_INTSTS */ +}; + #endif static const struct sp_dev_vdata dev_vdata[] = { @@ -381,6 +402,12 @@ static const struct sp_dev_vdata dev_vdata[] = { .bar = 2, #ifdef CONFIG_CRYPTO_DEV_SP_PSP .psp_vdata = &pspv3, +#endif + }, + { /* 7 */ + .bar = 2, +#ifdef CONFIG_CRYPTO_DEV_SP_PSP + .psp_vdata = &pspv5, #endif }, }; @@ -392,6 +419,7 @@ static const struct pci_device_id sp_pci_table[] = { { PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] }, { PCI_VDEVICE(AMD, 0x14CA), (kernel_ulong_t)&dev_vdata[5] }, { PCI_VDEVICE(AMD, 0x15C7), (kernel_ulong_t)&dev_vdata[6] }, + { PCI_VDEVICE(AMD, 0x17E0), (kernel_ulong_t)&dev_vdata[7] }, /* Last entry must be zero */ { 0, } }; -- Gitee From 6021024e2333fb37e152f9aaa1b561b73d9a76c7 Mon Sep 17 00:00:00 2001 From: John Allen Date: Thu, 18 May 2023 22:24:14 -0500 Subject: [PATCH 11/31] crypto: ccp - Add support for PCI device 0x156E mainline inclusion from mainline-v6.4-rc2 commit bb4185e595e476d4ceccd366bca39762823c5a2e category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/bb4185e595e476d4ceccd366bca39762823c5a2e -------------------------------- commit bb4185e595e476d4ceccd366bca39762823c5a2e upstream Add a new CCP/PSP PCI device ID and new PSP register offsets. Signed-off-by: John Allen Signed-off-by: Mario Limonciello Signed-off-by: Herbert Xu Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/crypto/ccp/sp-pci.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index a11a42d33250..cb9bc9174aa2 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -350,6 +350,14 @@ static const struct psp_vdata pspv5 = { .intsts_reg = 0x10514, /* P2CMSG_INTSTS */ }; +static const struct psp_vdata pspv6 = { + .sev = &sevv2, + .tee = &teev2, + .feature_reg = 0x109fc, /* C2PMSG_63 */ + .inten_reg = 0x10510, /* P2CMSG_INTEN */ + .intsts_reg = 0x10514, /* P2CMSG_INTSTS */ +}; + #endif static const struct sp_dev_vdata dev_vdata[] = { @@ -408,6 +416,12 @@ static const struct sp_dev_vdata dev_vdata[] = { .bar = 2, #ifdef CONFIG_CRYPTO_DEV_SP_PSP .psp_vdata = &pspv5, +#endif + }, + { /* 8 */ + .bar = 2, +#ifdef CONFIG_CRYPTO_DEV_SP_PSP + .psp_vdata = &pspv6, #endif }, }; @@ -420,6 +434,7 @@ static const struct pci_device_id sp_pci_table[] = { { PCI_VDEVICE(AMD, 0x14CA), (kernel_ulong_t)&dev_vdata[5] }, { PCI_VDEVICE(AMD, 0x15C7), (kernel_ulong_t)&dev_vdata[6] }, { PCI_VDEVICE(AMD, 0x17E0), (kernel_ulong_t)&dev_vdata[7] }, + { PCI_VDEVICE(AMD, 0x156E), (kernel_ulong_t)&dev_vdata[8] }, /* Last entry must be zero */ { 0, } }; -- Gitee From 3e76781c71f59f8bff4ec5a87a7cb7cb2833c51a Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 19 Dec 2022 22:06:55 +0100 Subject: [PATCH 12/31] x86/microcode/AMD: Rename a couple of functions mainline inclusion from mainline-v6.3-rc1 commit 61de9b7036f26448a1916291c456f62dd6bf07ea category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/61de9b7036f26448a1916291c456f62dd6bf07ea -------------------------------- commit 61de9b7036f26448a1916291c456f62dd6bf07ea upstream - Rename apply_microcode_early_amd() to early_apply_microcode(): simplify the name so that it is clear what it does and when does it do it. - Rename __load_ucode_amd() to find_blobs_in_containers(): the new name actually explains what it does. Document some. No functional changes. Signed-off-by: Borislav Petkov Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20221219210656.5140-1-bp@alien8.de Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- arch/x86/kernel/cpu/microcode/amd.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 28e3fc548eeb..cd7d2a628c6a 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -415,8 +415,7 @@ static int __apply_microcode_amd(struct microcode_amd *mc) * * Returns true if container found (sets @desc), false otherwise. */ -static bool -apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size, bool save_patch) +static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size, bool save_patch) { struct cont_desc desc = { 0 }; u8 (*patch)[PATCH_MAX_SIZE]; @@ -479,7 +478,7 @@ static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family) #endif } -static void __load_ucode_amd(unsigned int cpuid_1_eax, struct cpio_data *ret) +static void find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data *ret) { struct ucode_cpu_info *uci; struct cpio_data cp; @@ -516,11 +515,11 @@ void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax) { struct cpio_data cp = { }; - __load_ucode_amd(cpuid_1_eax, &cp); + find_blobs_in_containers(cpuid_1_eax, &cp); if (!(cp.data && cp.size)) return; - apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, true); + early_apply_microcode(cpuid_1_eax, cp.data, cp.size, true); } void load_ucode_amd_ap(unsigned int cpuid_1_eax) @@ -551,11 +550,11 @@ void load_ucode_amd_ap(unsigned int cpuid_1_eax) } } - __load_ucode_amd(cpuid_1_eax, &cp); + find_blobs_in_containers(cpuid_1_eax, &cp); if (!(cp.data && cp.size)) return; - apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, false); + early_apply_microcode(cpuid_1_eax, cp.data, cp.size, false); } static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size); @@ -826,6 +825,7 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover, return 0; } +/* Scan the blob in @data and add microcode patches to the cache. */ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, size_t size) { -- Gitee From 8263d3a6c315081c41156ab1f21e19f5333d1c36 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Thu, 26 Jan 2023 00:08:03 +0100 Subject: [PATCH 13/31] x86/microcode/AMD: Add a @cpu parameter to the reloading functions mainline inclusion from mainline-v6.3-rc1 commit a5ad92134bd153a9ccdcddf09a95b088f36c3cce category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/a5ad92134bd153a9ccdcddf09a95b088f36c3cce -------------------------------- commit a5ad92134bd153a9ccdcddf09a95b088f36c3cce upstream Will be used in a subsequent change. [Backport changes] 1. In `arch/x86/kernel/cpu/microcode/core.c` file, the `X86_VENDOR_HYGON` case is required for the current kernel. Since, signature of `reload_ucode_amd()` is changed as per the upstream patch, changing `reload_ucode_amd()` to take `cpu` argument. Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230130161709.11615-3-bp@alien8.de Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- arch/x86/include/asm/microcode.h | 4 ++-- arch/x86/include/asm/microcode_amd.h | 4 ++-- arch/x86/kernel/cpu/microcode/amd.c | 2 +- arch/x86/kernel/cpu/microcode/core.c | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 29563f76f1b5..ae48472bd37c 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h @@ -144,7 +144,7 @@ static inline unsigned int x86_cpuid_family(void) int __init microcode_init(void); extern void __init load_ucode_bsp(void); extern void load_ucode_ap(void); -void reload_early_microcode(void); +void reload_early_microcode(unsigned int cpu); extern bool get_builtin_firmware(struct cpio_data *cd, const char *name); extern bool initrd_gone; void microcode_bsp_resume(void); @@ -152,7 +152,7 @@ void microcode_bsp_resume(void); static inline int __init microcode_init(void) { return 0; }; static inline void __init load_ucode_bsp(void) { } static inline void load_ucode_ap(void) { } -static inline void reload_early_microcode(void) { } +static inline void reload_early_microcode(unsigned int cpu) { } static inline void microcode_bsp_resume(void) { } static inline bool get_builtin_firmware(struct cpio_data *cd, const char *name) { return false; } diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h index b56a1c0d5f60..403a8e76b310 100644 --- a/arch/x86/include/asm/microcode_amd.h +++ b/arch/x86/include/asm/microcode_amd.h @@ -47,14 +47,14 @@ struct microcode_amd { extern void __init load_ucode_amd_bsp(unsigned int family); extern void load_ucode_amd_ap(unsigned int family); extern int __init save_microcode_in_initrd_amd(unsigned int family); -void reload_ucode_amd(void); +void reload_ucode_amd(unsigned int cpu); extern void amd_check_microcode(void); #else static inline void __init load_ucode_amd_bsp(unsigned int family) {} static inline void load_ucode_amd_ap(unsigned int family) {} static inline int __init save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; } -static inline void reload_ucode_amd(void) {} +static inline void reload_ucode_amd(unsigned int cpu) {} static inline void amd_check_microcode(void) {} #endif #endif /* _ASM_X86_MICROCODE_AMD_H */ diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index cd7d2a628c6a..c637626347e0 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -588,7 +588,7 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax) return 0; } -void reload_ucode_amd(void) +void reload_ucode_amd(unsigned int cpu) { struct microcode_amd *mc; u32 rev, dummy __always_unused; diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 259be1d775e0..7b2fb753abef 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -330,7 +330,7 @@ struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa) #endif } -void reload_early_microcode(void) +void reload_early_microcode(unsigned int cpu) { int vendor, family; @@ -344,10 +344,10 @@ void reload_early_microcode(void) break; case X86_VENDOR_AMD: if (family >= 0x10) - reload_ucode_amd(); + reload_ucode_amd(cpu); break; case X86_VENDOR_HYGON: - reload_ucode_amd(); + reload_ucode_amd(cpu); break; default: break; @@ -817,7 +817,7 @@ void microcode_bsp_resume(void) if (uci->valid && uci->mc) microcode_ops->apply_microcode(cpu); else if (!uci->mc) - reload_early_microcode(); + reload_early_microcode(cpu); } static struct syscore_ops mc_syscore_ops = { -- Gitee From 0c5822df9c6e0953cbaf892fec937c13134a1698 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Thu, 26 Jan 2023 16:26:17 +0100 Subject: [PATCH 14/31] x86/microcode/AMD: Fix mixed steppings support mainline inclusion from mainline-v6.3-rc1 commit 7ff6edf4fef38ab404ee7861f257e28eaaeed35f category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/7ff6edf4fef38ab404ee7861f257e28eaaeed35f -------------------------------- commit 7ff6edf4fef38ab404ee7861f257e28eaaeed35f upstream The AMD side of the loader has always claimed to support mixed steppings. But somewhere along the way, it broke that by assuming that the cached patch blob is a single one instead of it being one per *node*. So turn it into a per-node one so that each node can stash the blob relevant for it. [ NB: Fixes tag is not really the exactly correct one but it is good enough. ] Fixes: fe055896c040 ("x86/microcode: Merge the early microcode loader") Signed-off-by: Borislav Petkov (AMD) Cc: # 2355370cd941 ("x86/microcode/amd: Remove load_microcode_amd()'s bsp parameter") Cc: # a5ad92134bd1 ("x86/microcode/AMD: Add a @cpu parameter to the reloading functions") Link: https://lore.kernel.org/r/20230130161709.11615-4-bp@alien8.de Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- arch/x86/kernel/cpu/microcode/amd.c | 34 ++++++++++++++++++----------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index c637626347e0..8311b7c504d1 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -55,7 +55,9 @@ struct cont_desc { }; static u32 ucode_new_rev; -static u8 amd_ucode_patch[PATCH_MAX_SIZE]; + +/* One blob per node. */ +static u8 amd_ucode_patch[MAX_NUMNODES][PATCH_MAX_SIZE]; /* * Microcode patch container file is prepended to the initrd in cpio @@ -428,7 +430,7 @@ static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size, boo patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch); #else new_rev = &ucode_new_rev; - patch = &amd_ucode_patch; + patch = &amd_ucode_patch[0]; #endif desc.cpuid_1_eax = cpuid_1_eax; @@ -590,10 +592,10 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax) void reload_ucode_amd(unsigned int cpu) { - struct microcode_amd *mc; u32 rev, dummy __always_unused; + struct microcode_amd *mc; - mc = (struct microcode_amd *)amd_ucode_patch; + mc = (struct microcode_amd *)amd_ucode_patch[cpu_to_node(cpu)]; rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); @@ -862,6 +864,8 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size) { + struct cpuinfo_x86 *c; + unsigned int nid, cpu; struct ucode_patch *p; enum ucode_state ret; @@ -874,18 +878,22 @@ static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t siz return ret; } - p = find_patch(0); - if (!p) { - return ret; - } else { - if (boot_cpu_data.microcode >= p->patch_id) - return ret; + for_each_node(nid) { + cpu = cpumask_first(cpumask_of_node(nid)); + c = &cpu_data(cpu); + + p = find_patch(cpu); + if (!p) + continue; + + if (c->microcode >= p->patch_id) + continue; ret = UCODE_NEW; - } - memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); - memcpy(amd_ucode_patch, p->data, min_t(u32, p->size, PATCH_MAX_SIZE)); + memset(&amd_ucode_patch[nid], 0, PATCH_MAX_SIZE); + memcpy(&amd_ucode_patch[nid], p->data, min_t(u32, p->size, PATCH_MAX_SIZE)); + } return ret; } -- Gitee From b5610a314930c74fd1b5860f1572696268a450e8 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Wed, 7 Jun 2023 21:01:06 +0200 Subject: [PATCH 15/31] x86/microcode/AMD: Rip out static buffers mainline inclusion from mainline-v6.6-rc1 commit 05e91e72113833385fb8c9a33bda9dbd93e27609 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/05e91e72113833385fb8c9a33bda9dbd93e27609 -------------------------------- commit 05e91e72113833385fb8c9a33bda9dbd93e27609 upstream Load straight from the containers (initrd or builtin, for example). There's no need to cache the patch per node. This even simplifies the code a bit with the opportunity for more cleanups later. [Backport changes] 1. In `arch/x86/kernel/cpu/microcode/core.c` file, the `X86_VENDOR_HYGON` case is required for the current kernel. Since, the old call `load_ucode_amd_ap()` is replaced by `load_ucode_amd_early()` as per the upstream patch, changing `load_ucode_amd_ap()` to `load_ucode_amd_early()`. Signed-off-by: Borislav Petkov (AMD) Tested-by: John Allen Link: https://lore.kernel.org/r/20230720202813.3269888-1-john.allen@amd.com Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- arch/x86/include/asm/microcode_amd.h | 6 +- arch/x86/kernel/cpu/microcode/amd.c | 90 +++++++++------------------- arch/x86/kernel/cpu/microcode/core.c | 6 +- 3 files changed, 32 insertions(+), 70 deletions(-) diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h index 403a8e76b310..9b88ce7ed40c 100644 --- a/arch/x86/include/asm/microcode_amd.h +++ b/arch/x86/include/asm/microcode_amd.h @@ -44,14 +44,12 @@ struct microcode_amd { #define PATCH_MAX_SIZE (3 * PAGE_SIZE) #ifdef CONFIG_MICROCODE_AMD -extern void __init load_ucode_amd_bsp(unsigned int family); -extern void load_ucode_amd_ap(unsigned int family); +extern void load_ucode_amd_early(unsigned int cpuid_1_eax); extern int __init save_microcode_in_initrd_amd(unsigned int family); void reload_ucode_amd(unsigned int cpu); extern void amd_check_microcode(void); #else -static inline void __init load_ucode_amd_bsp(unsigned int family) {} -static inline void load_ucode_amd_ap(unsigned int family) {} +static inline void load_ucode_amd_early(unsigned int cpuid_1_eax) {} static inline int __init save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; } static inline void reload_ucode_amd(unsigned int cpu) {} diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 8311b7c504d1..90719dd252c6 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -56,9 +56,6 @@ struct cont_desc { static u32 ucode_new_rev; -/* One blob per node. */ -static u8 amd_ucode_patch[MAX_NUMNODES][PATCH_MAX_SIZE]; - /* * Microcode patch container file is prepended to the initrd in cpio * format. See Documentation/x86/microcode.rst @@ -417,20 +414,17 @@ static int __apply_microcode_amd(struct microcode_amd *mc) * * Returns true if container found (sets @desc), false otherwise. */ -static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size, bool save_patch) +static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size) { struct cont_desc desc = { 0 }; - u8 (*patch)[PATCH_MAX_SIZE]; struct microcode_amd *mc; u32 rev, dummy, *new_rev; bool ret = false; #ifdef CONFIG_X86_32 new_rev = (u32 *)__pa_nodebug(&ucode_new_rev); - patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch); #else new_rev = &ucode_new_rev; - patch = &amd_ucode_patch[0]; #endif desc.cpuid_1_eax = cpuid_1_eax; @@ -454,9 +448,6 @@ static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size, boo if (!__apply_microcode_amd(mc)) { *new_rev = mc->hdr.patch_id; ret = true; - - if (save_patch) - memcpy(patch, mc, min_t(u32, desc.psize, PATCH_MAX_SIZE)); } return ret; @@ -513,7 +504,7 @@ static void find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data *ret = cp; } -void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax) +static void apply_ucode_from_containers(unsigned int cpuid_1_eax) { struct cpio_data cp = { }; @@ -521,42 +512,12 @@ void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax) if (!(cp.data && cp.size)) return; - early_apply_microcode(cpuid_1_eax, cp.data, cp.size, true); + early_apply_microcode(cpuid_1_eax, cp.data, cp.size); } -void load_ucode_amd_ap(unsigned int cpuid_1_eax) +void load_ucode_amd_early(unsigned int cpuid_1_eax) { - struct microcode_amd *mc; - struct cpio_data cp; - u32 *new_rev, rev, dummy; - - if (IS_ENABLED(CONFIG_X86_32)) { - mc = (struct microcode_amd *)__pa_nodebug(amd_ucode_patch); - new_rev = (u32 *)__pa_nodebug(&ucode_new_rev); - } else { - mc = (struct microcode_amd *)amd_ucode_patch; - new_rev = &ucode_new_rev; - } - - native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); - - /* - * Check whether a new patch has been saved already. Also, allow application of - * the same revision in order to pick up SMT-thread-specific configuration even - * if the sibling SMT thread already has an up-to-date revision. - */ - if (*new_rev && rev <= mc->hdr.patch_id) { - if (!__apply_microcode_amd(mc)) { - *new_rev = mc->hdr.patch_id; - return; - } - } - - find_blobs_in_containers(cpuid_1_eax, &cp); - if (!(cp.data && cp.size)) - return; - - early_apply_microcode(cpuid_1_eax, cp.data, cp.size, false); + return apply_ucode_from_containers(cpuid_1_eax); } static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size); @@ -590,22 +551,6 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax) return 0; } -void reload_ucode_amd(unsigned int cpu) -{ - u32 rev, dummy __always_unused; - struct microcode_amd *mc; - - mc = (struct microcode_amd *)amd_ucode_patch[cpu_to_node(cpu)]; - - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); - - if (rev < mc->hdr.patch_id) { - if (!__apply_microcode_amd(mc)) { - ucode_new_rev = mc->hdr.patch_id; - pr_info("reload patch_level=0x%08x\n", ucode_new_rev); - } - } -} static u16 __find_equiv_id(unsigned int cpu) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; @@ -670,6 +615,28 @@ static struct ucode_patch *find_patch(unsigned int cpu) return cache_find_patch(equiv_id); } +void reload_ucode_amd(unsigned int cpu) +{ + u32 rev, dummy __always_unused; + struct microcode_amd *mc; + struct ucode_patch *p; + + p = find_patch(cpu); + if (!p) + return; + + mc = p->data; + + rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); + + if (rev < mc->hdr.patch_id) { + if (!__apply_microcode_amd(mc)) { + ucode_new_rev = mc->hdr.patch_id; + pr_info("reload patch_level=0x%08x\n", ucode_new_rev); + } + } +} + static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) { struct cpuinfo_x86 *c = &cpu_data(cpu); @@ -890,9 +857,6 @@ static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t siz continue; ret = UCODE_NEW; - - memset(&amd_ucode_patch[nid], 0, PATCH_MAX_SIZE); - memcpy(&amd_ucode_patch[nid], p->data, min_t(u32, p->size, PATCH_MAX_SIZE)); } return ret; diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 7b2fb753abef..723e2035d959 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -198,7 +198,7 @@ void __init load_ucode_bsp(void) if (intel) load_ucode_intel_bsp(); else - load_ucode_amd_bsp(cpuid_1_eax); + load_ucode_amd_early(cpuid_1_eax); } static bool check_loader_disabled_ap(void) @@ -226,10 +226,10 @@ void load_ucode_ap(void) break; case X86_VENDOR_AMD: if (x86_family(cpuid_1_eax) >= 0x10) - load_ucode_amd_ap(cpuid_1_eax); + load_ucode_amd_early(cpuid_1_eax); break; case X86_VENDOR_HYGON: - load_ucode_amd_ap(cpuid_1_eax); + load_ucode_amd_early(cpuid_1_eax); break; default: break; -- Gitee From f531b91d9a859a63bc88761aeab26a5885b1b480 Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Fri, 5 Apr 2024 23:33:08 +0200 Subject: [PATCH 16/31] x86/microcode/AMD: Remove unused PATCH_MAX_SIZE macro mainline inclusion from mainline-v6.10-rc1 commit 3287c22957b401903e4933a81eea9191788da33b category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/3287c22957b401903e4933a81eea9191788da33b -------------------------------- commit 3287c22957b401903e4933a81eea9191788da33b upstream Orphaned after 05e91e721138 ("x86/microcode/AMD: Rip out static buffers") No functional changes. Signed-off-by: Borislav Petkov (AMD) Signed-off-by: PvsNarasimha --- arch/x86/include/asm/microcode_amd.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h index 9b88ce7ed40c..5a1ed74fce83 100644 --- a/arch/x86/include/asm/microcode_amd.h +++ b/arch/x86/include/asm/microcode_amd.h @@ -41,8 +41,6 @@ struct microcode_amd { unsigned int mpb[0]; }; -#define PATCH_MAX_SIZE (3 * PAGE_SIZE) - #ifdef CONFIG_MICROCODE_AMD extern void load_ucode_amd_early(unsigned int cpuid_1_eax); extern int __init save_microcode_in_initrd_amd(unsigned int family); -- Gitee From 1f75e2ffa77a6c729b3bb82295b3e8bac1d87065 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Thu, 28 Oct 2021 17:56:57 +0000 Subject: [PATCH 17/31] x86/amd_nb, EDAC/amd64: Move DF Indirect Read to AMD64 EDAC mainline inclusion from mainline-v5.17-rc1 commit b3218ae47771f943b3e222f35fc46afacba39929 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/b3218ae47771f943b3e222f35fc46afacba39929 -------------------------------- commit b3218ae47771f943b3e222f35fc46afacba39929 upstream df_indirect_read() is used only for address translation. Move it to EDAC along with the translation code. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov Link: https://lkml.kernel.org/r/20211028175728.121452-3-yazen.ghannam@amd.com Signed-off-by: PvsNarasimha --- arch/x86/include/asm/amd_nb.h | 1 - arch/x86/kernel/amd_nb.c | 49 +--------------------------------- drivers/edac/amd64_edac.c | 50 +++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 49 deletions(-) diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index f53447965d39..39fe8afdede9 100644 --- a/arch/x86/include/asm/amd_nb.h +++ b/arch/x86/include/asm/amd_nb.h @@ -24,7 +24,6 @@ extern int amd_set_subcaches(int, unsigned long); extern int amd_smn_read(u16 node, u32 address, u32 *value); extern int amd_smn_write(u16 node, u32 address, u32 value); -extern int amd_df_indirect_read(u16 node, u8 func, u16 reg, u8 instance_id, u32 *lo); struct amd_l3_cache { unsigned indices; diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 4b0d6736e08b..817399fc3d20 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -39,7 +39,7 @@ #define PCI_DEVICE_ID_HYGON_18H_M10H_DF_F4 0x14d4 #define PCI_DEVICE_ID_HYGON_18H_M06H_DF_F5 0x14b5 -/* Protect the PCI config register pairs used for SMN and DF indirect access. */ +/* Protect the PCI config register pairs used for SMN. */ static DEFINE_MUTEX(smn_mutex); static u32 *flush_words; @@ -205,53 +205,6 @@ int amd_smn_write(u16 node, u32 address, u32 value) } EXPORT_SYMBOL_GPL(amd_smn_write); -/* - * Data Fabric Indirect Access uses FICAA/FICAD. - * - * Fabric Indirect Configuration Access Address (FICAA): Constructed based - * on the device's Instance Id and the PCI function and register offset of - * the desired register. - * - * Fabric Indirect Configuration Access Data (FICAD): There are FICAD LO - * and FICAD HI registers but so far we only need the LO register. - */ -int amd_df_indirect_read(u16 node, u8 func, u16 reg, u8 instance_id, u32 *lo) -{ - struct pci_dev *F4; - u32 ficaa; - int err = -ENODEV; - - if (node >= amd_northbridges.num) - goto out; - - F4 = node_to_amd_nb(node)->link; - if (!F4) - goto out; - - ficaa = 1; - ficaa |= reg & 0x3FC; - ficaa |= (func & 0x7) << 11; - ficaa |= instance_id << 16; - - mutex_lock(&smn_mutex); - - err = pci_write_config_dword(F4, 0x5C, ficaa); - if (err) { - pr_warn("Error writing DF Indirect FICAA, FICAA=0x%x\n", ficaa); - goto out_unlock; - } - - err = pci_read_config_dword(F4, 0x98, lo); - if (err) - pr_warn("Error reading DF Indirect FICAD LO, FICAA=0x%x.\n", ficaa); - -out_unlock: - mutex_unlock(&smn_mutex); - -out: - return err; -} -EXPORT_SYMBOL_GPL(amd_df_indirect_read); bool hygon_f18h_m4h(void) { diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index bf00ed579e66..b59c965ec5ea 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -735,6 +735,56 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr) return csrow; } +/* Protect the PCI config register pairs used for DF indirect access. */ +static DEFINE_MUTEX(df_indirect_mutex); + +/* + * Data Fabric Indirect Access uses FICAA/FICAD. + * + * Fabric Indirect Configuration Access Address (FICAA): Constructed based + * on the device's Instance Id and the PCI function and register offset of + * the desired register. + * + * Fabric Indirect Configuration Access Data (FICAD): There are FICAD LO + * and FICAD HI registers but so far we only need the LO register. + */ +static int amd_df_indirect_read(u16 node, u8 func, u16 reg, u8 instance_id, u32 *lo) +{ + struct pci_dev *F4; + u32 ficaa; + int err = -ENODEV; + + if (node >= amd_nb_num()) + goto out; + + F4 = node_to_amd_nb(node)->link; + if (!F4) + goto out; + + ficaa = 1; + ficaa |= reg & 0x3FC; + ficaa |= (func & 0x7) << 11; + ficaa |= instance_id << 16; + + mutex_lock(&df_indirect_mutex); + + err = pci_write_config_dword(F4, 0x5C, ficaa); + if (err) { + pr_warn("Error writing DF Indirect FICAA, FICAA=0x%x\n", ficaa); + goto out_unlock; + } + + err = pci_read_config_dword(F4, 0x98, lo); + if (err) + pr_warn("Error reading DF Indirect FICAD LO, FICAA=0x%x.\n", ficaa); + +out_unlock: + mutex_unlock(&df_indirect_mutex); + +out: + return err; +} + static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) { u64 dram_base_addr, dram_limit_addr, dram_hole_base; -- Gitee From 751b4a276c7a7e9632f5a6f2611df666c73e15d8 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Fri, 27 Jan 2023 17:03:58 +0000 Subject: [PATCH 18/31] EDAC/amd64: Don't set up EDAC PCI control on Family 17h+ mainline inclusion from mainline-v6.3-rc1 commit fdce765a13384cf411d456472d396d8db2b3114f category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/fdce765a13384cf411d456472d396d8db2b3114f -------------------------------- commit fdce765a13384cf411d456472d396d8db2b3114f upstream EDAC PCI control is used to detect/report legacy PCI errors like "Parity" and "SERROR". Modern AMD systems use PCIe Advanced Error Reporting (AER), and legacy PCI errors should not be reported. Remove EDAC PCI control setup on AMD Family 17h and later systems. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230127170419.1824692-2-yazen.ghannam@amd.com Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index b59c965ec5ea..5555eedc6654 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -4182,12 +4182,12 @@ static int __init amd64_edac_init(void) } /* register stuff with EDAC MCE */ - if (boot_cpu_data.x86 >= 0x17) + if (boot_cpu_data.x86 >= 0x17) { amd_register_ecc_decoder(decode_umc_error); - else + } else { amd_register_ecc_decoder(decode_bus_error); - - setup_pci_device(); + setup_pci_device(); + } #ifdef CONFIG_X86_32 amd64_err("%s on 32-bit is unsupported. USE AT YOUR OWN RISK!\n", EDAC_MOD_STR); -- Gitee From 6bf5571a14f921b11b75abcea5bbac3319743219 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Fri, 27 Jan 2023 17:03:59 +0000 Subject: [PATCH 19/31] EDAC/amd64: Remove scrub rate control for Family 17h and later mainline inclusion from mainline-v6.3-rc1 commit 6e241bc93c9f0ae6f76ed65b44132948ca70fd76 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/6e241bc93c9f0ae6f76ed65b44132948ca70fd76 -------------------------------- commit 6e241bc93c9f0ae6f76ed65b44132948ca70fd76 upstream The scrub registers on AMD Family 17h and later may be inaccessible to the OS. Furthermore, hardware designers recommend that the scrubbing feature is managed by the firmware. Remove support for the sdram_scrub_rate interface for AMD Family 17h systems and later by not setting the scrub function pointers. The EDAC MC core will then not expose the scrub files in sysfs. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230127170419.1824692-3-yazen.ghannam@amd.com Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 33 +++++---------------------------- drivers/edac/amd64_edac.h | 2 -- 2 files changed, 5 insertions(+), 30 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 5555eedc6654..9980b2e7be8b 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -193,21 +193,6 @@ static inline int amd64_read_dct_pci_cfg(struct amd64_pvt *pvt, u8 dct, * other archs, we might not have access to the caches directly. */ -static inline void __f17h_set_scrubval(struct amd64_pvt *pvt, u32 scrubval) -{ - /* - * Fam17h supports scrub values between 0x5 and 0x14. Also, the values - * are shifted down by 0x5, so scrubval 0x5 is written to the register - * as 0x0, scrubval 0x6 as 0x1, etc. - */ - if (scrubval >= 0x5 && scrubval <= 0x14) { - scrubval -= 0x5; - pci_write_bits32(pvt->F6, F17H_SCR_LIMIT_ADDR, scrubval, 0xF); - pci_write_bits32(pvt->F6, F17H_SCR_BASE_ADDR, 1, 0x1); - } else { - pci_write_bits32(pvt->F6, F17H_SCR_BASE_ADDR, 0, 0x1); - } -} /* * Scan the scrub rate mapping table for a close or matching bandwidth value to * issue. If requested is too big, then use last maximum value found. @@ -240,9 +225,7 @@ static int __set_scrub_rate(struct amd64_pvt *pvt, u32 new_bw, u32 min_rate) scrubval = scrubrates[i].scrubval; - if (pvt->umc) { - __f17h_set_scrubval(pvt, scrubval); - } else if (pvt->fam == 0x15 && pvt->model == 0x60) { + if (pvt->fam == 0x15 && pvt->model == 0x60) { f15h_select_dct(pvt, 0); pci_write_bits32(pvt->F2, F15H_M60H_SCRCTRL, scrubval, 0x001F); f15h_select_dct(pvt, 1); @@ -282,16 +265,7 @@ static int get_scrub_rate(struct mem_ctl_info *mci) int i, retval = -EINVAL; u32 scrubval = 0; - if (pvt->umc) { - amd64_read_pci_cfg(pvt->F6, F17H_SCR_BASE_ADDR, &scrubval); - if (scrubval & BIT(0)) { - amd64_read_pci_cfg(pvt->F6, F17H_SCR_LIMIT_ADDR, &scrubval); - scrubval &= 0xF; - scrubval += 0x5; - } else { - scrubval = 0; - } - } else if (pvt->fam == 0x15) { + if (pvt->fam == 0x15) { /* Erratum #505 */ if (pvt->model < 0x10) f15h_select_dct(pvt, 0); @@ -3753,6 +3727,9 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci) mci->dev_name = pci_name(pvt->F3); mci->ctl_page_to_phys = NULL; + if (pvt->fam >= 0x17) + return; + /* memory scrubber interface */ mci->set_sdram_scrub_rate = set_scrub_rate; mci->get_sdram_scrub_rate = get_scrub_rate; diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index ac2d939fb984..9510158f308f 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -218,8 +218,6 @@ #define DCT_SEL_HI 0x114 #define F15H_M60H_SCRCTRL 0x1C8 -#define F17H_SCR_BASE_ADDR 0x48 -#define F17H_SCR_LIMIT_ADDR 0x4C /* * Function 3 - Misc Control -- Gitee From 999665f4866f47645af4ac82e1e87e4ec56b742d Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Fri, 27 Jan 2023 17:04:00 +0000 Subject: [PATCH 20/31] EDAC/amd64: Remove PCI Function 6 mainline inclusion from mainline-v6.3-rc1 commit 6229235f7c6616c96ac06fd1094520b037410f46 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/6229235f7c6616c96ac06fd1094520b037410f46 -------------------------------- commit 6229235f7c6616c96ac06fd1094520b037410f46 upstream PCI Function 6 is used on Family 17h and later to access scrub registers. With scrub access removed, this function has no other use. Remove all Function 6 PCI IDs and related code. [Backport changes] 1. Since all the Function 6 PCI IDs have been removed, the macros PCI_DEVICE_ID_HYGON_18H_M06H_DF_F6 and PCI_DEVICE_ID_HYGON_18H_M10H_DF_F6 have also been removed as per the upstream commit. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230127170419.1824692-4-yazen.ghannam@amd.com Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 23 +---------------------- drivers/edac/amd64_edac.h | 13 ++----------- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 9980b2e7be8b..250b03d9850f 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2644,7 +2644,6 @@ static struct amd64_family_type family_types[] = { [F17_CPUS] = { .ctl_name = "F17h", .f0_id = PCI_DEVICE_ID_AMD_17H_DF_F0, - .f6_id = PCI_DEVICE_ID_AMD_17H_DF_F6, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2654,7 +2653,6 @@ static struct amd64_family_type family_types[] = { [F17_M10H_CPUS] = { .ctl_name = "F17h_M10h", .f0_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F0, - .f6_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F6, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2664,7 +2662,6 @@ static struct amd64_family_type family_types[] = { [F17_M30H_CPUS] = { .ctl_name = "F17h_M30h", .f0_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F0, - .f6_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F6, .max_mcs = 8, .ops = { .early_channel_count = f17_early_channel_count, @@ -2674,7 +2671,6 @@ static struct amd64_family_type family_types[] = { [F17_M60H_CPUS] = { .ctl_name = "F17h_M60h", .f0_id = PCI_DEVICE_ID_AMD_17H_M60H_DF_F0, - .f6_id = PCI_DEVICE_ID_AMD_17H_M60H_DF_F6, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2684,7 +2680,6 @@ static struct amd64_family_type family_types[] = { [F17_M70H_CPUS] = { .ctl_name = "F17h_M70h", .f0_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F0, - .f6_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F6, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2694,7 +2689,6 @@ static struct amd64_family_type family_types[] = { [F18_M06H_CPUS] = { .ctl_name = "F18h_M06h", .f0_id = PCI_DEVICE_ID_HYGON_18H_M06H_DF_F0, - .f6_id = PCI_DEVICE_ID_HYGON_18H_M06H_DF_F6, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2704,7 +2698,6 @@ static struct amd64_family_type family_types[] = { [F18_M10H_CPUS] = { .ctl_name = "F18h_M10h", .f0_id = PCI_DEVICE_ID_HYGON_18H_M10H_DF_F0, - .f6_id = PCI_DEVICE_ID_HYGON_18H_M10H_DF_F6, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2714,7 +2707,6 @@ static struct amd64_family_type family_types[] = { [F19_CPUS] = { .ctl_name = "F19h", .f0_id = PCI_DEVICE_ID_AMD_19H_DF_F0, - .f6_id = PCI_DEVICE_ID_AMD_19H_DF_F6, .max_mcs = 8, .ops = { .early_channel_count = f17_early_channel_count, @@ -2724,7 +2716,6 @@ static struct amd64_family_type family_types[] = { [F19_M10H_CPUS] = { .ctl_name = "F19h_M10h", .f0_id = PCI_DEVICE_ID_AMD_19H_M10H_DF_F0, - .f6_id = PCI_DEVICE_ID_AMD_19H_M10H_DF_F6, .max_mcs = 12, .flags.zn_regs_v2 = 1, .ops = { @@ -3055,7 +3046,7 @@ static void decode_umc_error(int node_id, struct mce *m) /* * Use pvt->F3 which contains the F3 CPU PCI device to get the related * F1 (AddrMap) and F2 (Dct) devices. Return negative value on error. - * Reserve F0 and F6 on systems with a UMC. + * Reserve F0 on systems with a UMC. */ static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2) @@ -3067,21 +3058,11 @@ reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2) return -ENODEV; } - pvt->F6 = pci_get_related_function(pvt->F3->vendor, pci_id2, pvt->F3); - if (!pvt->F6) { - pci_dev_put(pvt->F0); - pvt->F0 = NULL; - - amd64_err("F6 not found: device 0x%x (broken BIOS?)\n", pci_id2); - return -ENODEV; - } - if (!pci_ctl_dev) pci_ctl_dev = &pvt->F0->dev; edac_dbg(1, "F0: %s\n", pci_name(pvt->F0)); edac_dbg(1, "F3: %s\n", pci_name(pvt->F3)); - edac_dbg(1, "F6: %s\n", pci_name(pvt->F6)); return 0; } @@ -3117,7 +3098,6 @@ static void free_mc_sibling_devs(struct amd64_pvt *pvt) { if (pvt->umc) { pci_dev_put(pvt->F0); - pci_dev_put(pvt->F6); } else { pci_dev_put(pvt->F1); pci_dev_put(pvt->F2); @@ -3893,7 +3873,6 @@ static int hw_info_get(struct amd64_pvt *pvt) return -ENOMEM; pci_id1 = fam_type->f0_id; - pci_id2 = fam_type->f6_id; } else { pci_id1 = fam_type->f1_id; pci_id2 = fam_type->f2_id; diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 9510158f308f..16606c82df4c 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -115,24 +115,15 @@ #define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581 #define PCI_DEVICE_ID_AMD_16H_M30H_NB_F2 0x1582 #define PCI_DEVICE_ID_AMD_17H_DF_F0 0x1460 -#define PCI_DEVICE_ID_AMD_17H_DF_F6 0x1466 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F0 0x15e8 -#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F6 0x15ee #define PCI_DEVICE_ID_AMD_17H_M30H_DF_F0 0x1490 -#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F6 0x1496 #define PCI_DEVICE_ID_AMD_17H_M60H_DF_F0 0x1448 -#define PCI_DEVICE_ID_AMD_17H_M60H_DF_F6 0x144e #define PCI_DEVICE_ID_AMD_17H_M70H_DF_F0 0x1440 -#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F6 0x1446 #define PCI_DEVICE_ID_AMD_19H_DF_F0 0x1650 -#define PCI_DEVICE_ID_AMD_19H_DF_F6 0x1656 #define PCI_DEVICE_ID_AMD_19H_M10H_DF_F0 0x14ad -#define PCI_DEVICE_ID_AMD_19H_M10H_DF_F6 0x14b3 #define PCI_DEVICE_ID_HYGON_18H_M06H_DF_F0 0x14b0 -#define PCI_DEVICE_ID_HYGON_18H_M06H_DF_F6 0x14b6 #define PCI_DEVICE_ID_HYGON_18H_M10H_DF_F0 0x14d0 -#define PCI_DEVICE_ID_HYGON_18H_M10H_DF_F6 0x14d6 /* * Function 1 - Address Map @@ -358,7 +349,7 @@ struct amd64_pvt { struct low_ops *ops; /* pci_device handles which we utilize */ - struct pci_dev *F0, *F1, *F2, *F3, *F6; + struct pci_dev *F0, *F1, *F2, *F3; u16 mc_node_id; /* MC index of this MC node */ u8 fam; /* CPU family */ @@ -513,7 +504,7 @@ struct amd64_family_flags { struct amd64_family_type { const char *ctl_name; - u16 f0_id, f1_id, f2_id, f6_id; + u16 f0_id, f1_id, f2_id; /* Maximum number of memory controllers per die/node. */ u8 max_mcs; struct amd64_family_flags flags; -- Gitee From e7540f68b0ccd6831f6c5698efbd39740b367f3c Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Fri, 27 Jan 2023 17:04:01 +0000 Subject: [PATCH 21/31] EDAC/amd64: Remove PCI Function 0 mainline inclusion from mainline-v6.3-rc1 commit cf981562e6270397a2b0dc871a1f11ccc2a687e8 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/cf981562e6270397a2b0dc871a1f11ccc2a687e8 -------------------------------- commit cf981562e6270397a2b0dc871a1f11ccc2a687e8 upstream PCI Function 0 is used on Family 17h and later only to read the "dhar" value. This value is printed and provided through a module-specific debug sysfs file. The value is not used for any Family 17h and later code, and it does not have any apparent debug value on these systems. Remove "dhar", Function 0 PCI IDs, and all related code. [Backport changes] 1. Since all the Function 0 PCI IDs have been removed, the macros PCI_DEVICE_ID_HYGON_18H_M06H_DF_F0 and PCI_DEVICE_ID_HYGON_18H_M10H_DF_F0 have also been removed as per the upstream commit. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230127170419.1824692-5-yazen.ghannam@amd.com Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 39 +++++---------------------------------- drivers/edac/amd64_edac.h | 14 ++------------ 2 files changed, 7 insertions(+), 46 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 250b03d9850f..5d95332d3f63 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1159,9 +1159,6 @@ static void __dump_misc_regs_df(struct amd64_pvt *pvt) debug_display_dimm_sizes_df(pvt, i); } - - edac_dbg(1, "F0x104 (DRAM Hole Address): 0x%08x, base: 0x%08x\n", - pvt->dhar, dhar_base(pvt)); } /* Display and decode various NB registers for debug purposes. */ @@ -1196,6 +1193,8 @@ static void __dump_misc_regs(struct amd64_pvt *pvt) /* Only if NOT ganged does dclr1 have valid info */ if (!dct_ganging_enabled(pvt)) debug_dump_dramcfg_low(pvt, pvt->dclr1, 1); + + edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no"); } /* Display and decode various NB registers for debug purposes. */ @@ -1206,8 +1205,6 @@ static void dump_misc_regs(struct amd64_pvt *pvt) else __dump_misc_regs(pvt); - edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no"); - amd64_info("using x%u syndromes.\n", pvt->ecc_sym_sz); } @@ -2643,7 +2640,6 @@ static struct amd64_family_type family_types[] = { }, [F17_CPUS] = { .ctl_name = "F17h", - .f0_id = PCI_DEVICE_ID_AMD_17H_DF_F0, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2652,7 +2648,6 @@ static struct amd64_family_type family_types[] = { }, [F17_M10H_CPUS] = { .ctl_name = "F17h_M10h", - .f0_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F0, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2661,7 +2656,6 @@ static struct amd64_family_type family_types[] = { }, [F17_M30H_CPUS] = { .ctl_name = "F17h_M30h", - .f0_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F0, .max_mcs = 8, .ops = { .early_channel_count = f17_early_channel_count, @@ -2670,7 +2664,6 @@ static struct amd64_family_type family_types[] = { }, [F17_M60H_CPUS] = { .ctl_name = "F17h_M60h", - .f0_id = PCI_DEVICE_ID_AMD_17H_M60H_DF_F0, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2679,7 +2672,6 @@ static struct amd64_family_type family_types[] = { }, [F17_M70H_CPUS] = { .ctl_name = "F17h_M70h", - .f0_id = PCI_DEVICE_ID_AMD_17H_M70H_DF_F0, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2688,7 +2680,6 @@ static struct amd64_family_type family_types[] = { }, [F18_M06H_CPUS] = { .ctl_name = "F18h_M06h", - .f0_id = PCI_DEVICE_ID_HYGON_18H_M06H_DF_F0, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2697,7 +2688,6 @@ static struct amd64_family_type family_types[] = { }, [F18_M10H_CPUS] = { .ctl_name = "F18h_M10h", - .f0_id = PCI_DEVICE_ID_HYGON_18H_M10H_DF_F0, .max_mcs = 2, .ops = { .early_channel_count = f17_early_channel_count, @@ -2706,7 +2696,6 @@ static struct amd64_family_type family_types[] = { }, [F19_CPUS] = { .ctl_name = "F19h", - .f0_id = PCI_DEVICE_ID_AMD_19H_DF_F0, .max_mcs = 8, .ops = { .early_channel_count = f17_early_channel_count, @@ -2715,7 +2704,6 @@ static struct amd64_family_type family_types[] = { }, [F19_M10H_CPUS] = { .ctl_name = "F19h_M10h", - .f0_id = PCI_DEVICE_ID_AMD_19H_M10H_DF_F0, .max_mcs = 12, .flags.zn_regs_v2 = 1, .ops = { @@ -3046,26 +3034,12 @@ static void decode_umc_error(int node_id, struct mce *m) /* * Use pvt->F3 which contains the F3 CPU PCI device to get the related * F1 (AddrMap) and F2 (Dct) devices. Return negative value on error. - * Reserve F0 on systems with a UMC. */ static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2) { - if (pvt->umc) { - pvt->F0 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3); - if (!pvt->F0) { - amd64_err("F0 not found, device 0x%x (broken BIOS?)\n", pci_id1); - return -ENODEV; - } - - if (!pci_ctl_dev) - pci_ctl_dev = &pvt->F0->dev; - - edac_dbg(1, "F0: %s\n", pci_name(pvt->F0)); - edac_dbg(1, "F3: %s\n", pci_name(pvt->F3)); - + if (pvt->umc) return 0; - } /* Reserve the ADDRESS MAP Device */ pvt->F1 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3); @@ -3097,7 +3071,7 @@ reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2) static void free_mc_sibling_devs(struct amd64_pvt *pvt) { if (pvt->umc) { - pci_dev_put(pvt->F0); + return; } else { pci_dev_put(pvt->F1); pci_dev_put(pvt->F2); @@ -3207,7 +3181,6 @@ static void read_mc_regs(struct amd64_pvt *pvt) if (pvt->umc) { __read_mc_regs_df(pvt); - amd64_read_pci_cfg(pvt->F0, DF_DHAR, &pvt->dhar); goto skip; } @@ -3871,8 +3844,6 @@ static int hw_info_get(struct amd64_pvt *pvt) pvt->umc = kcalloc(fam_type->max_mcs, sizeof(struct amd64_umc), GFP_KERNEL); if (!pvt->umc) return -ENOMEM; - - pci_id1 = fam_type->f0_id; } else { pci_id1 = fam_type->f1_id; pci_id2 = fam_type->f2_id; @@ -3889,7 +3860,7 @@ static int hw_info_get(struct amd64_pvt *pvt) static void hw_info_put(struct amd64_pvt *pvt) { - if (pvt->F0 || pvt->F1) + if (pvt->F1) free_mc_sibling_devs(pvt); kfree(pvt->umc); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 16606c82df4c..54181576d28d 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -114,16 +114,6 @@ #define PCI_DEVICE_ID_AMD_16H_NB_F2 0x1532 #define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581 #define PCI_DEVICE_ID_AMD_16H_M30H_NB_F2 0x1582 -#define PCI_DEVICE_ID_AMD_17H_DF_F0 0x1460 -#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F0 0x15e8 -#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F0 0x1490 -#define PCI_DEVICE_ID_AMD_17H_M60H_DF_F0 0x1448 -#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F0 0x1440 -#define PCI_DEVICE_ID_AMD_19H_DF_F0 0x1650 -#define PCI_DEVICE_ID_AMD_19H_M10H_DF_F0 0x14ad - -#define PCI_DEVICE_ID_HYGON_18H_M06H_DF_F0 0x14b0 -#define PCI_DEVICE_ID_HYGON_18H_M10H_DF_F0 0x14d0 /* * Function 1 - Address Map @@ -349,7 +339,7 @@ struct amd64_pvt { struct low_ops *ops; /* pci_device handles which we utilize */ - struct pci_dev *F0, *F1, *F2, *F3; + struct pci_dev *F1, *F2, *F3; u16 mc_node_id; /* MC index of this MC node */ u8 fam; /* CPU family */ @@ -504,7 +494,7 @@ struct amd64_family_flags { struct amd64_family_type { const char *ctl_name; - u16 f0_id, f1_id, f2_id; + u16 f1_id, f2_id; /* Maximum number of memory controllers per die/node. */ u8 max_mcs; struct amd64_family_flags flags; -- Gitee From 82ed1b6bd1b9e01620f44b5b9da456b2f5f8a949 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Fri, 27 Jan 2023 17:04:02 +0000 Subject: [PATCH 22/31] EDAC/amd64: Remove early_channel_count() mainline inclusion from mainline-v6.3-rc1 commit c4605bde334367b22bbf43cbbef0d1b7c75433dc category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/c4605bde334367b22bbf43cbbef0d1b7c75433dc -------------------------------- commit c4605bde334367b22bbf43cbbef0d1b7c75433dc upstream The early_channel_count() function seems to have been useful in the past for knowing how many EDAC mci structures to populate. However, this is no longer needed as the maximum channel count for a system is used instead. Remove the early_channel_count() helper functions and related code. Use the size of the channel layer when iterating over channel structures. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230127170419.1824692-6-yazen.ghannam@amd.com Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 117 +------------------------------------- drivers/edac/amd64_edac.h | 2 - 2 files changed, 2 insertions(+), 117 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 5d95332d3f63..4384f29c608e 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1441,24 +1441,6 @@ static void determine_memory_type(struct amd64_pvt *pvt) pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3; } -/* Get the number of DCT channels the memory controller is using. */ -static int k8_early_channel_count(struct amd64_pvt *pvt) -{ - int flag; - - if (pvt->ext_model >= K8_REV_F) - /* RevF (NPT) and later */ - flag = pvt->dclr0 & WIDTH_128; - else - /* RevE and earlier */ - flag = pvt->dclr0 & REVE_WIDTH_128; - - /* not used */ - pvt->dclr1 = 0; - - return (flag) ? 2 : 1; -} - /* On F10h and later ErrAddr is MC4_ADDR[47:1] */ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m) { @@ -1710,69 +1692,6 @@ static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, } } -/* - * Get the number of DCT channels in use. - * - * Return: - * number of Memory Channels in operation - * Pass back: - * contents of the DCL0_LOW register - */ -static int f1x_early_channel_count(struct amd64_pvt *pvt) -{ - int i, j, channels = 0; - - /* On F10h, if we are in 128 bit mode, then we are using 2 channels */ - if (pvt->fam == 0x10 && (pvt->dclr0 & WIDTH_128)) - return 2; - - /* - * Need to check if in unganged mode: In such, there are 2 channels, - * but they are not in 128 bit mode and thus the above 'dclr0' status - * bit will be OFF. - * - * Need to check DCT0[0] and DCT1[0] to see if only one of them has - * their CSEnable bit on. If so, then SINGLE DIMM case. - */ - edac_dbg(0, "Data width is not 128 bits - need more decoding\n"); - - /* - * Check DRAM Bank Address Mapping values for each DIMM to see if there - * is more than just one DIMM present in unganged mode. Need to check - * both controllers since DIMMs can be placed in either one. - */ - for (i = 0; i < 2; i++) { - u32 dbam = (i ? pvt->dbam1 : pvt->dbam0); - - for (j = 0; j < 4; j++) { - if (DBAM_DIMM(j, dbam) > 0) { - channels++; - break; - } - } - } - - if (channels > 2) - channels = 2; - - amd64_info("MCT channel count: %d\n", channels); - - return channels; -} - -static int f17_early_channel_count(struct amd64_pvt *pvt) -{ - int i, channels = 0; - - /* SDP Control bit 31 (SdpInit) is clear for unused UMC channels */ - for_each_umc(i) - channels += !!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT); - - amd64_info("MCT channel count: %d\n", channels); - - return channels; -} - static int ddr3_cs_size(unsigned i, bool dct_width) { unsigned shift = 0; @@ -2567,7 +2486,6 @@ static struct amd64_family_type family_types[] = { .f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL, .max_mcs = 2, .ops = { - .early_channel_count = k8_early_channel_count, .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow, .dbam_to_cs = k8_dbam_to_chip_select, } @@ -2578,7 +2496,6 @@ static struct amd64_family_type family_types[] = { .f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM, .max_mcs = 2, .ops = { - .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f10_dbam_to_chip_select, } @@ -2589,7 +2506,6 @@ static struct amd64_family_type family_types[] = { .f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2, .max_mcs = 2, .ops = { - .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f15_dbam_to_chip_select, } @@ -2600,7 +2516,6 @@ static struct amd64_family_type family_types[] = { .f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2, .max_mcs = 2, .ops = { - .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f16_dbam_to_chip_select, } @@ -2611,7 +2526,6 @@ static struct amd64_family_type family_types[] = { .f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2, .max_mcs = 2, .ops = { - .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f15_m60h_dbam_to_chip_select, } @@ -2622,7 +2536,6 @@ static struct amd64_family_type family_types[] = { .f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2, .max_mcs = 2, .ops = { - .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f16_dbam_to_chip_select, } @@ -2633,7 +2546,6 @@ static struct amd64_family_type family_types[] = { .f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2, .max_mcs = 2, .ops = { - .early_channel_count = f1x_early_channel_count, .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f16_dbam_to_chip_select, } @@ -2642,7 +2554,6 @@ static struct amd64_family_type family_types[] = { .ctl_name = "F17h", .max_mcs = 2, .ops = { - .early_channel_count = f17_early_channel_count, .dbam_to_cs = f17_addr_mask_to_cs_size, } }, @@ -2650,7 +2561,6 @@ static struct amd64_family_type family_types[] = { .ctl_name = "F17h_M10h", .max_mcs = 2, .ops = { - .early_channel_count = f17_early_channel_count, .dbam_to_cs = f17_addr_mask_to_cs_size, } }, @@ -2658,7 +2568,6 @@ static struct amd64_family_type family_types[] = { .ctl_name = "F17h_M30h", .max_mcs = 8, .ops = { - .early_channel_count = f17_early_channel_count, .dbam_to_cs = f17_addr_mask_to_cs_size, } }, @@ -2666,7 +2575,6 @@ static struct amd64_family_type family_types[] = { .ctl_name = "F17h_M60h", .max_mcs = 2, .ops = { - .early_channel_count = f17_early_channel_count, .dbam_to_cs = f17_addr_mask_to_cs_size, } }, @@ -2674,7 +2582,6 @@ static struct amd64_family_type family_types[] = { .ctl_name = "F17h_M70h", .max_mcs = 2, .ops = { - .early_channel_count = f17_early_channel_count, .dbam_to_cs = f17_addr_mask_to_cs_size, } }, @@ -2682,7 +2589,6 @@ static struct amd64_family_type family_types[] = { .ctl_name = "F18h_M06h", .max_mcs = 2, .ops = { - .early_channel_count = f17_early_channel_count, .dbam_to_cs = f17_addr_mask_to_cs_size, } }, @@ -2690,7 +2596,6 @@ static struct amd64_family_type family_types[] = { .ctl_name = "F18h_M10h", .max_mcs = 2, .ops = { - .early_channel_count = f17_early_channel_count, .dbam_to_cs = f17_addr_mask_to_cs_size, } }, @@ -2698,7 +2603,6 @@ static struct amd64_family_type family_types[] = { .ctl_name = "F19h", .max_mcs = 8, .ops = { - .early_channel_count = f17_early_channel_count, .dbam_to_cs = f17_addr_mask_to_cs_size, } }, @@ -2707,7 +2611,6 @@ static struct amd64_family_type family_types[] = { .max_mcs = 12, .flags.zn_regs_v2 = 1, .ops = { - .early_channel_count = f17_early_channel_count, .dbam_to_cs = f17_addr_mask_to_cs_size, } }, @@ -3403,7 +3306,7 @@ static int init_csrows(struct mem_ctl_info *mci) : EDAC_SECDED; } - for (j = 0; j < pvt->channel_count; j++) { + for (j = 0; j < fam_type->max_mcs; j++) { dimm = csrow->channels[j]->dimm; dimm->mtype = pvt->dram_type; dimm->edac_mode = edac_mode; @@ -3870,28 +3773,12 @@ static int init_one_instance(struct amd64_pvt *pvt) { struct mem_ctl_info *mci = NULL; struct edac_mc_layer layers[2]; - int ret = -EINVAL; + int ret = -ENOMEM; - /* - * We need to determine how many memory channels there are. Then use - * that information for calculating the size of the dynamic instance - * tables in the 'mci' structure. - */ - pvt->channel_count = pvt->ops->early_channel_count(pvt); - if (pvt->channel_count < 0) - return ret; - - ret = -ENOMEM; layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; layers[0].size = pvt->csels[0].b_cnt; layers[0].is_virt_csrow = true; layers[1].type = EDAC_MC_LAYER_CHANNEL; - - /* - * Always allocate two channels since we can have setups with DIMMs on - * only one channel. Also, this simplifies handling later for the price - * of a couple of KBs tops. - */ layers[1].size = fam_type->max_mcs; layers[1].is_virt_csrow = false; diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 54181576d28d..705d895e88d3 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -347,7 +347,6 @@ struct amd64_pvt { u8 stepping; /* ... stepping */ int ext_model; /* extended model value of this node */ - int channel_count; /* Raw registers */ u32 dclr0; /* DRAM Configuration Low DCT0 reg */ @@ -475,7 +474,6 @@ extern const struct attribute_group amd64_edac_inj_group; * functions and per device encoding/decoding logic. */ struct low_ops { - int (*early_channel_count) (struct amd64_pvt *pvt); void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr, struct err_info *); int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, -- Gitee From 1a4ae6d65cb8699ce3c7111c29f8315398ec7820 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Fri, 27 Jan 2023 17:04:03 +0000 Subject: [PATCH 23/31] EDAC/amd64: Rename debug_display_dimm_sizes() mainline inclusion from mainline-v6.4-rc1 commit 00e4feb8c0476bbde3c8bf4a593e0f82ca9a4df6 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/00e4feb8c0476bbde3c8bf4a593e0f82ca9a4df6 -------------------------------- commit 00e4feb8c0476bbde3c8bf4a593e0f82ca9a4df6 upstream Use the "dct" and "umc" prefixes for legacy and modern versions respectively. Also, move the "dct" version to avoid a forward declaration, and fixup some checkpatch warnings in the process. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230127170419.1824692-7-yazen.ghannam@amd.com Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 128 +++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 65 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 4384f29c608e..c4f63bbb5f30 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1019,7 +1019,65 @@ static unsigned long determine_edac_cap(struct amd64_pvt *pvt) return edac_cap; } -static void debug_display_dimm_sizes(struct amd64_pvt *, u8); +/* + * debug routine to display the memory sizes of all logical DIMMs and its + * CSROWs + */ +static void dct_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) +{ + u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases; + u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0; + int dimm, size0, size1; + + if (pvt->fam == 0xf) { + /* K8 families < revF not supported yet */ + if (pvt->ext_model < K8_REV_F) + return; + + WARN_ON(ctrl != 0); + } + + if (pvt->fam == 0x10) { + dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 + : pvt->dbam0; + dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? + pvt->csels[1].csbases : + pvt->csels[0].csbases; + } else if (ctrl) { + dbam = pvt->dbam0; + dcsb = pvt->csels[1].csbases; + } + edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", + ctrl, dbam); + + edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl); + + /* Dump memory sizes for DIMM and its CSROWs */ + for (dimm = 0; dimm < 4; dimm++) { + size0 = 0; + if (dcsb[dimm * 2] & DCSB_CS_ENABLE) + /* + * For F15m60h, we need multiplier for LRDIMM cs_size + * calculation. We pass dimm value to the dbam_to_cs + * mapper so we can find the multiplier from the + * corresponding DCSM. + */ + size0 = pvt->ops->dbam_to_cs(pvt, ctrl, + DBAM_DIMM(dimm, dbam), + dimm); + + size1 = 0; + if (dcsb[dimm * 2 + 1] & DCSB_CS_ENABLE) + size1 = pvt->ops->dbam_to_cs(pvt, ctrl, + DBAM_DIMM(dimm, dbam), + dimm); + + amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", + dimm * 2, size0, + dimm * 2 + 1, size1); + } +} + static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan) { @@ -1094,7 +1152,7 @@ static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt) return cs_mode; } -static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl) +static void umc_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) { int dimm, size0, size1, cs0, cs1, cs_mode; @@ -1157,7 +1215,7 @@ static void __dump_misc_regs_df(struct amd64_pvt *pvt) i, 1 << ((tmp >> 4) & 0x3)); } - debug_display_dimm_sizes_df(pvt, i); + umc_debug_display_dimm_sizes(pvt, i); } } @@ -1182,13 +1240,13 @@ static void __dump_misc_regs(struct amd64_pvt *pvt) (pvt->fam == 0xf) ? k8_dhar_offset(pvt) : f10_dhar_offset(pvt)); - debug_display_dimm_sizes(pvt, 0); + dct_debug_display_dimm_sizes(pvt, 0); /* everything below this point is Fam10h and above */ if (pvt->fam == 0xf) return; - debug_display_dimm_sizes(pvt, 1); + dct_debug_display_dimm_sizes(pvt, 1); /* Only if NOT ganged does dclr1 have valid info */ if (!dct_ganging_enabled(pvt)) @@ -2419,66 +2477,6 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome); } -/* - * debug routine to display the memory sizes of all logical DIMMs and its - * CSROWs - */ -static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) -{ - int dimm, size0, size1; - u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases; - u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0; - - if (pvt->fam == 0xf) { - /* K8 families < revF not supported yet */ - if (pvt->ext_model < K8_REV_F) - return; - else - WARN_ON(ctrl != 0); - } - - if (pvt->fam == 0x10) { - dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 - : pvt->dbam0; - dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? - pvt->csels[1].csbases : - pvt->csels[0].csbases; - } else if (ctrl) { - dbam = pvt->dbam0; - dcsb = pvt->csels[1].csbases; - } - edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", - ctrl, dbam); - - edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl); - - /* Dump memory sizes for DIMM and its CSROWs */ - for (dimm = 0; dimm < 4; dimm++) { - - size0 = 0; - if (dcsb[dimm*2] & DCSB_CS_ENABLE) - /* - * For F15m60h, we need multiplier for LRDIMM cs_size - * calculation. We pass dimm value to the dbam_to_cs - * mapper so we can find the multiplier from the - * corresponding DCSM. - */ - size0 = pvt->ops->dbam_to_cs(pvt, ctrl, - DBAM_DIMM(dimm, dbam), - dimm); - - size1 = 0; - if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE) - size1 = pvt->ops->dbam_to_cs(pvt, ctrl, - DBAM_DIMM(dimm, dbam), - dimm); - - amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", - dimm * 2, size0, - dimm * 2 + 1, size1); - } -} - static struct amd64_family_type family_types[] = { [K8_CPUS] = { .ctl_name = "K8", -- Gitee From 958394d8edcef7cd19813cdbdc97b0482200721a Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Fri, 27 Jan 2023 17:04:05 +0000 Subject: [PATCH 24/31] EDAC/amd64: Drop dbam_to_cs() for Family 17h and later mainline inclusion from mainline-v6.4-rc1 commit a2e59ab8e93301466cb3ff3f2b7b65eb1a4e8786 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/a2e59ab8e93301466cb3ff3f2b7b65eb1a4e8786 -------------------------------- commit a2e59ab8e93301466cb3ff3f2b7b65eb1a4e8786 upstream The same function is used to calculate chip select size for all Zen-based family/models. Therefore, a family/model function pointer is not necessary. Drop the dbam_to_cs() function pointer for Family 17h and later systems. Also, move the Family 17h function to avoid a forward declaration. Rename it to indicate that the UMC Address Mask is used rather than the legacy DBAM value. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230127170419.1824692-9-yazen.ghannam@amd.com Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 189 ++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 108 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index c4f63bbb5f30..6a20e71f6aac 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1152,6 +1152,84 @@ static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt) return cs_mode; } +static int umc_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc, + unsigned int cs_mode, int csrow_nr) +{ + u32 addr_mask_orig, addr_mask_deinterleaved; + u32 msb, weight, num_zero_bits; + int cs_mask_nr = csrow_nr; + int dimm, size = 0; + + /* No Chip Selects are enabled. */ + if (!cs_mode) + return size; + + /* Requested size of an even CS but none are enabled. */ + if (!(cs_mode & CS_EVEN) && !(csrow_nr & 1)) + return size; + + /* Requested size of an odd CS but none are enabled. */ + if (!(cs_mode & CS_ODD) && (csrow_nr & 1)) + return size; + + /* + * Family 17h introduced systems with one mask per DIMM, + * and two Chip Selects per DIMM. + * + * CS0 and CS1 -> MASK0 / DIMM0 + * CS2 and CS3 -> MASK1 / DIMM1 + * + * Family 19h Model 10h introduced systems with one mask per Chip Select, + * and two Chip Selects per DIMM. + * + * CS0 -> MASK0 -> DIMM0 + * CS1 -> MASK1 -> DIMM0 + * CS2 -> MASK2 -> DIMM1 + * CS3 -> MASK3 -> DIMM1 + * + * Keep the mask number equal to the Chip Select number for newer systems, + * and shift the mask number for older systems. + */ + dimm = csrow_nr >> 1; + + if (!fam_type->flags.zn_regs_v2) + cs_mask_nr >>= 1; + + /* Asymmetric dual-rank DIMM support. */ + if ((csrow_nr & 1) && (cs_mode & CS_ODD_SECONDARY)) + addr_mask_orig = pvt->csels[umc].csmasks_sec[cs_mask_nr]; + else + addr_mask_orig = pvt->csels[umc].csmasks[cs_mask_nr]; + + /* + * The number of zero bits in the mask is equal to the number of bits + * in a full mask minus the number of bits in the current mask. + * + * The MSB is the number of bits in the full mask because BIT[0] is + * always 0. + * + * In the special 3 Rank interleaving case, a single bit is flipped + * without swapping with the most significant bit. This can be handled + * by keeping the MSB where it is and ignoring the single zero bit. + */ + msb = fls(addr_mask_orig) - 1; + weight = hweight_long(addr_mask_orig); + num_zero_bits = msb - weight - !!(cs_mode & CS_3R_INTERLEAVE); + + /* Take the number of zero bits off from the top of the mask. */ + addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1); + + edac_dbg(1, "CS%d DIMM%d AddrMasks:\n", csrow_nr, dimm); + edac_dbg(1, " Original AddrMask: 0x%x\n", addr_mask_orig); + edac_dbg(1, " Deinterleaved AddrMask: 0x%x\n", addr_mask_deinterleaved); + + /* Register [31:1] = Address [39:9]. Size is in kBs here. */ + size = (addr_mask_deinterleaved >> 2) + 1; + + /* Return size in MBs. */ + return size >> 10; +} + static void umc_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) { int dimm, size0, size1, cs0, cs1, cs_mode; @@ -1164,8 +1242,8 @@ static void umc_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) cs_mode = f17_get_cs_mode(dimm, ctrl, pvt); - size0 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs0); - size1 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs1); + size0 = umc_addr_mask_to_cs_size(pvt, ctrl, cs_mode, cs0); + size1 = umc_addr_mask_to_cs_size(pvt, ctrl, cs_mode, cs1); amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", cs0, size0, @@ -1877,84 +1955,6 @@ static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, return ddr3_cs_size(cs_mode, false); } -static int f17_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc, - unsigned int cs_mode, int csrow_nr) -{ - u32 addr_mask_orig, addr_mask_deinterleaved; - u32 msb, weight, num_zero_bits; - int cs_mask_nr = csrow_nr; - int dimm, size = 0; - - /* No Chip Selects are enabled. */ - if (!cs_mode) - return size; - - /* Requested size of an even CS but none are enabled. */ - if (!(cs_mode & CS_EVEN) && !(csrow_nr & 1)) - return size; - - /* Requested size of an odd CS but none are enabled. */ - if (!(cs_mode & CS_ODD) && (csrow_nr & 1)) - return size; - - /* - * Family 17h introduced systems with one mask per DIMM, - * and two Chip Selects per DIMM. - * - * CS0 and CS1 -> MASK0 / DIMM0 - * CS2 and CS3 -> MASK1 / DIMM1 - * - * Family 19h Model 10h introduced systems with one mask per Chip Select, - * and two Chip Selects per DIMM. - * - * CS0 -> MASK0 -> DIMM0 - * CS1 -> MASK1 -> DIMM0 - * CS2 -> MASK2 -> DIMM1 - * CS3 -> MASK3 -> DIMM1 - * - * Keep the mask number equal to the Chip Select number for newer systems, - * and shift the mask number for older systems. - */ - dimm = csrow_nr >> 1; - - if (!fam_type->flags.zn_regs_v2) - cs_mask_nr >>= 1; - - /* Asymmetric dual-rank DIMM support. */ - if ((csrow_nr & 1) && (cs_mode & CS_ODD_SECONDARY)) - addr_mask_orig = pvt->csels[umc].csmasks_sec[cs_mask_nr]; - else - addr_mask_orig = pvt->csels[umc].csmasks[cs_mask_nr]; - - /* - * The number of zero bits in the mask is equal to the number of bits - * in a full mask minus the number of bits in the current mask. - * - * The MSB is the number of bits in the full mask because BIT[0] is - * always 0. - * - * In the special 3 Rank interleaving case, a single bit is flipped - * without swapping with the most significant bit. This can be handled - * by keeping the MSB where it is and ignoring the single zero bit. - */ - msb = fls(addr_mask_orig) - 1; - weight = hweight_long(addr_mask_orig); - num_zero_bits = msb - weight - !!(cs_mode & CS_3R_INTERLEAVE); - - /* Take the number of zero bits off from the top of the mask. */ - addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1); - - edac_dbg(1, "CS%d DIMM%d AddrMasks:\n", csrow_nr, dimm); - edac_dbg(1, " Original AddrMask: 0x%x\n", addr_mask_orig); - edac_dbg(1, " Deinterleaved AddrMask: 0x%x\n", addr_mask_deinterleaved); - - /* Register [31:1] = Address [39:9]. Size is in kBs here. */ - size = (addr_mask_deinterleaved >> 2) + 1; - - /* Return size in MBs. */ - return size >> 10; -} - static void read_dram_ctl_register(struct amd64_pvt *pvt) { @@ -2551,66 +2551,39 @@ static struct amd64_family_type family_types[] = { [F17_CPUS] = { .ctl_name = "F17h", .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } }, [F17_M10H_CPUS] = { .ctl_name = "F17h_M10h", .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } }, [F17_M30H_CPUS] = { .ctl_name = "F17h_M30h", .max_mcs = 8, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } }, [F17_M60H_CPUS] = { .ctl_name = "F17h_M60h", .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } }, [F17_M70H_CPUS] = { .ctl_name = "F17h_M70h", .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } }, [F18_M06H_CPUS] = { .ctl_name = "F18h_M06h", .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } }, [F18_M10H_CPUS] = { .ctl_name = "F18h_M10h", .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } }, [F19_CPUS] = { .ctl_name = "F19h", .max_mcs = 8, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } }, [F19_M10H_CPUS] = { .ctl_name = "F19h_M10h", .max_mcs = 12, .flags.zn_regs_v2 = 1, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } }, }; @@ -3184,7 +3157,7 @@ static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig) cs_mode = f17_get_cs_mode(csrow_nr >> 1, dct, pvt); } - nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, csrow_nr); + nr_pages = umc_addr_mask_to_cs_size(pvt, dct, cs_mode, csrow_nr); nr_pages <<= 20 - PAGE_SHIFT; edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n", -- Gitee From 9ed9678f8358effd5fd58f589f7a5fb893ad00c2 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 13 Jan 2021 20:13:30 +0100 Subject: [PATCH 25/31] EDAC/amd64: Issue probing messages only on properly detected hardware mainline inclusion from mainline-v5.12-rc1 commit 4cbcb73b1c7a73a13b336e0c048601d6e8eecaa8 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/4cbcb73b1c7a73a13b336e0c048601d6e8eecaa8 -------------------------------- commit 4cbcb73b1c7a73a13b336e0c048601d6e8eecaa8 upstream amd64_edac was converted to CPU family autoprobing (from PCI device IDs) to not have to add a new PCI device ID each time a new platform is shipped but to support the whole family out-of-the-box. However, this caused a lot of noise in dmesg even when the machine doesn't have ECC DIMMs or ECC has been disabled in the BIOS: EDAC MC: Ver: 3.0.0 EDAC amd64: F17h detected (node 0). EDAC amd64: Node 0: DRAM ECC disabled. EDAC amd64: F17h detected (node 1). EDAC amd64: Node 1: DRAM ECC disabled. EDAC amd64: F17h detected (node 2). EDAC amd64: Node 2: DRAM ECC disabled. EDAC amd64: F17h detected (node 3). EDAC amd64: Node 3: DRAM ECC disabled. EDAC amd64: F17h detected (node 4). EDAC amd64: Node 4: DRAM ECC disabled. EDAC amd64: F17h detected (node 5). EDAC amd64: Node 5: DRAM ECC disabled. EDAC amd64: F17h detected (node 6). EDAC amd64: Node 6: DRAM ECC disabled. EDAC amd64: F17h detected (node 7). EDAC amd64: Node 7: DRAM ECC disabled. or even $ grep EDAC dmesg.log | sed 's/\[.*\] //' | sort | uniq -c 128 EDAC amd64: F17h detected (node 0). 128 EDAC amd64: Node 0: DRAM ECC disabled. 1 EDAC MC: Ver: 3.0.0 on a big machine. Yap, that's once per CPU for 128 of them. So move the init messages after all probing has succeeded to avoid unnecessary spew in dmesg. Signed-off-by: Borislav Petkov Link: https://lkml.kernel.org/r/20210119164141.17417-1-bp@alien8.de Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 6a20e71f6aac..5a04209bfcc3 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -3491,8 +3491,7 @@ static bool ecc_enabled(struct amd64_pvt *pvt) MSR_IA32_MCG_CTL, nid); } - amd64_info("Node %d: DRAM ECC %s.\n", - nid, (ecc_en ? "enabled" : "disabled")); + edac_dbg(3, "Node %d: DRAM ECC %s.\n", nid, (ecc_en ? "enabled" : "disabled")); if (!ecc_en || !nb_mce_en) return false; @@ -3691,11 +3690,6 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt) return NULL; } - amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name, - (pvt->fam == 0xf ? - (pvt->ext_model >= K8_REV_F ? "revF or later " - : "revE or earlier ") - : ""), pvt->mc_node_id); return fam_type; } @@ -3850,6 +3844,12 @@ static int probe_one_instance(unsigned int nid) goto err_enable; } + amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name, + (pvt->fam == 0xf ? + (pvt->ext_model >= K8_REV_F ? "revF or later " + : "revE or earlier ") + : ""), pvt->mc_node_id); + dump_misc_regs(pvt); return ret; -- Gitee From f53aa5cf1c234b6ac03ad99acf34f34906bb9ce1 Mon Sep 17 00:00:00 2001 From: Muralidhara M K Date: Fri, 27 Jan 2023 17:04:07 +0000 Subject: [PATCH 26/31] EDAC/amd64: Merge struct amd64_family_type into struct amd64_pvt mainline inclusion from mainline-v6.4-rc1 commit ed623d55eef46d0ca7557b9665b4693931bfb507 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/ed623d55eef46d0ca7557b9665b4693931bfb507 -------------------------------- commit ed623d55eef46d0ca7557b9665b4693931bfb507 uptream Future AMD systems will support heterogeneous "AMD Node" types, e.g. CPU and GPU types. Therefore, a global family type shared across all AMD nodes is no longer appropriate. Move struct low_ops routines and members of struct amd64_family_type to struct amd64_pvt. Currently, there are many code branches that split between "modern" and "legacy" systems. Another code branch will be needed in order to cover GPU cases. However, rather than introduce another branching case in multiple functions, the current branching code should be switched to a set of function pointers. This change makes the code more readable and simplifies adding support for new families/models. In order to reuse code, define two sets of function pointers. Use one for modern systems (Family 17h and later). This will not change between current CPU families. Use another set of function pointers for legacy systems (before Family 17h). Use the Family 16h versions as default for the legacy ops since these are the latest, and adjust the function pointers as needed for older families. [ Yazen: rebased/reworked patch and reworded commit message. ] [ bp: Fix rev8 or later check. ] [Backport changes] 1. In `drivers/edac/amd64_edac.c` file, in `read_umc_base_mask()` the variable umc_base was retained according to changes done in 55b0166 to maintain code changes done for hygon hardwares. 2. In `if` condition the variable changed from `fam_type` to `pvt` in `determine_memory_type_df()` in `drivers/edac/amd64_edac.c` as per upstream patch and to retain the code changes done for hygon hardwares. 3. In `drivers/edac/amd64_edac.c` file, in `per_family_init()` and in `struct amd64_family_type family_types[]`, changes for the Hygon are done as per the upstream patch. Signed-off-by: Muralidhara M K Co-developed-by: Naveen Krishna Chatradhi Signed-off-by: Naveen Krishna Chatradhi Co-developed-by: Yazen Ghannam Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230127170419.1824692-11-yazen.ghannam@amd.com Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 334 ++++++++++++++------------------------ drivers/edac/amd64_edac.h | 63 +++---- 2 files changed, 138 insertions(+), 259 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 5a04209bfcc3..b9cec0c90151 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -13,11 +13,9 @@ module_param(ecc_enable_override, int, 0644); static struct msr __percpu *msrs; -static struct amd64_family_type *fam_type; - -static inline u32 get_umc_reg(u32 reg) +static inline u32 get_umc_reg(struct amd64_pvt *pvt, u32 reg) { - if (!fam_type->flags.zn_regs_v2) + if (!pvt->flags.zn_regs_v2) return reg; switch (reg) { @@ -448,7 +446,7 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, for (i = 0; i < pvt->csels[dct].m_cnt; i++) #define for_each_umc(i) \ - for (i = 0; i < fam_type->max_mcs; i++) + for (i = 0; i < pvt->max_mcs; i++) /* * @input_addr is an InputAddr associated with the node given by mci. Return the @@ -1192,7 +1190,7 @@ static int umc_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc, */ dimm = csrow_nr >> 1; - if (!fam_type->flags.zn_regs_v2) + if (!pvt->flags.zn_regs_v2) cs_mask_nr >>= 1; /* Asymmetric dual-rank DIMM support. */ @@ -1287,7 +1285,7 @@ static void __dump_misc_regs_df(struct amd64_pvt *pvt) if (umc->dram_type == MEM_LRDDR4 || umc->dram_type == MEM_LRDDR5) { amd_smn_read(pvt->mc_node_id, - umc_base + get_umc_reg(UMCCH_ADDR_CFG), + umc_base + get_umc_reg(pvt, UMCCH_ADDR_CFG), &tmp); edac_dbg(1, "UMC%d LRDIMM %dx rank multiply\n", i, 1 << ((tmp >> 4) & 0x3)); @@ -1360,7 +1358,7 @@ static void prep_chip_selects(struct amd64_pvt *pvt) for_each_umc(umc) { pvt->csels[umc].b_cnt = 4; - pvt->csels[umc].m_cnt = fam_type->flags.zn_regs_v2 ? 4 : 2; + pvt->csels[umc].m_cnt = pvt->flags.zn_regs_v2 ? 4 : 2; } } else { @@ -1406,7 +1404,7 @@ static void read_umc_base_mask(struct amd64_pvt *pvt) } umc_mask_reg = umc_base + UMCCH_ADDR_MASK; - umc_mask_reg_sec = umc_base + get_umc_reg(UMCCH_ADDR_MASK_SEC); + umc_mask_reg_sec = umc_base + get_umc_reg(pvt, UMCCH_ADDR_MASK_SEC); for_each_chip_select_mask(cs, umc, pvt) { mask = &pvt->csels[umc].csmasks[cs]; @@ -1494,7 +1492,7 @@ static void determine_memory_type_df(struct amd64_pvt *pvt) * Check if the system supports the "DDR Type" field in UMC Config * and has DDR5 DIMMs in use. */ - if ((fam_type->flags.zn_regs_v2 || hygon_f18h_m4h()) && + if ((pvt->flags.zn_regs_v2 || hygon_f18h_m4h()) && ((umc->umc_cfg & GENMASK(2, 0)) == 0x1)) { if (umc->dimm_cfg & BIT(5)) umc->dram_type = MEM_LRDDR5; @@ -2477,116 +2475,6 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome); } -static struct amd64_family_type family_types[] = { - [K8_CPUS] = { - .ctl_name = "K8", - .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP, - .f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow, - .dbam_to_cs = k8_dbam_to_chip_select, - } - }, - [F10_CPUS] = { - .ctl_name = "F10h", - .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP, - .f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f10_dbam_to_chip_select, - } - }, - [F15_CPUS] = { - .ctl_name = "F15h", - .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1, - .f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f15_dbam_to_chip_select, - } - }, - [F15_M30H_CPUS] = { - .ctl_name = "F15h_M30h", - .f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1, - .f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f16_dbam_to_chip_select, - } - }, - [F15_M60H_CPUS] = { - .ctl_name = "F15h_M60h", - .f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1, - .f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f15_m60h_dbam_to_chip_select, - } - }, - [F16_CPUS] = { - .ctl_name = "F16h", - .f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1, - .f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f16_dbam_to_chip_select, - } - }, - [F16_M30H_CPUS] = { - .ctl_name = "F16h_M30h", - .f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1, - .f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f16_dbam_to_chip_select, - } - }, - [F17_CPUS] = { - .ctl_name = "F17h", - .max_mcs = 2, - }, - [F17_M10H_CPUS] = { - .ctl_name = "F17h_M10h", - .max_mcs = 2, - }, - [F17_M30H_CPUS] = { - .ctl_name = "F17h_M30h", - .max_mcs = 8, - }, - [F17_M60H_CPUS] = { - .ctl_name = "F17h_M60h", - .max_mcs = 2, - }, - [F17_M70H_CPUS] = { - .ctl_name = "F17h_M70h", - .max_mcs = 2, - }, - [F18_M06H_CPUS] = { - .ctl_name = "F18h_M06h", - .max_mcs = 2, - }, - [F18_M10H_CPUS] = { - .ctl_name = "F18h_M10h", - .max_mcs = 2, - }, - [F19_CPUS] = { - .ctl_name = "F19h", - .max_mcs = 8, - }, - [F19_M10H_CPUS] = { - .ctl_name = "F19h_M10h", - .max_mcs = 12, - .flags.zn_regs_v2 = 1, - }, -}; - /* * These are tables of eigenvectors (one per line) which can be used for the * construction of the syndrome tables. The modified syndrome search algorithm @@ -3020,7 +2908,7 @@ static void __read_mc_regs_df(struct amd64_pvt *pvt) umc = &pvt->umc[i]; - amd_smn_read(nid, umc_base + get_umc_reg(UMCCH_DIMM_CFG), &umc->dimm_cfg); + amd_smn_read(nid, umc_base + get_umc_reg(pvt, UMCCH_DIMM_CFG), &umc->dimm_cfg); amd_smn_read(nid, umc_base + UMCCH_UMC_CFG, &umc->umc_cfg); amd_smn_read(nid, umc_base + UMCCH_SDP_CTRL, &umc->sdp_ctrl); amd_smn_read(nid, umc_base + UMCCH_ECC_CTRL, &umc->ecc_ctrl); @@ -3277,7 +3165,7 @@ static int init_csrows(struct mem_ctl_info *mci) : EDAC_SECDED; } - for (j = 0; j < fam_type->max_mcs; j++) { + for (j = 0; j < pvt->max_mcs; j++) { dimm = csrow->channels[j]->dimm; dimm->mtype = pvt->dram_type; dimm->edac_mode = edac_mode; @@ -3549,7 +3437,7 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci) mci->edac_cap = determine_edac_cap(pvt); mci->mod_name = EDAC_MOD_STR; - mci->ctl_name = fam_type->ctl_name; + mci->ctl_name = pvt->ctl_name; mci->dev_name = pci_name(pvt->F3); mci->ctl_page_to_phys = NULL; @@ -3561,136 +3449,155 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci) mci->get_sdram_scrub_rate = get_scrub_rate; } -/* - * returns a pointer to the family descriptor on success, NULL otherwise. - */ -static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt) +static struct low_ops umc_ops = { +}; + +/* Use Family 16h versions for defaults and adjust as needed below. */ +static struct low_ops dct_ops = { + .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, + .dbam_to_cs = f16_dbam_to_chip_select, +}; + +static int per_family_init(struct amd64_pvt *pvt) { pvt->ext_model = boot_cpu_data.x86_model >> 4; pvt->stepping = boot_cpu_data.x86_stepping; pvt->model = boot_cpu_data.x86_model; pvt->fam = boot_cpu_data.x86; + pvt->max_mcs = 2; + + /* + * Decide on which ops group to use here and do any family/model + * overrides below. + */ + if (pvt->fam >= 0x17) + pvt->ops = &umc_ops; + else + pvt->ops = &dct_ops; switch (pvt->fam) { case 0xf: - fam_type = &family_types[K8_CPUS]; - pvt->ops = &family_types[K8_CPUS].ops; + pvt->ctl_name = (pvt->ext_model >= K8_REV_F) ? + "K8 revF or later" : "K8 revE or earlier"; + pvt->f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP; + pvt->f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL; + pvt->ops->map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow; + pvt->ops->dbam_to_cs = k8_dbam_to_chip_select; break; case 0x10: - fam_type = &family_types[F10_CPUS]; - pvt->ops = &family_types[F10_CPUS].ops; + pvt->ctl_name = "F10h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP; + pvt->f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM; + pvt->ops->dbam_to_cs = f10_dbam_to_chip_select; break; case 0x15: - if (pvt->model == 0x30) { - fam_type = &family_types[F15_M30H_CPUS]; - pvt->ops = &family_types[F15_M30H_CPUS].ops; + switch (pvt->model) { + case 0x30: + pvt->ctl_name = "F15h_M30h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1; + pvt->f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2; break; - } else if (pvt->model == 0x60) { - fam_type = &family_types[F15_M60H_CPUS]; - pvt->ops = &family_types[F15_M60H_CPUS].ops; + case 0x60: + pvt->ctl_name = "F15h_M60h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1; + pvt->f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2; + pvt->ops->dbam_to_cs = f15_m60h_dbam_to_chip_select; + break; + case 0x13: + /* Richland is only client */ + return -ENODEV; + default: + pvt->ctl_name = "F15h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1; + pvt->f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2; + pvt->ops->dbam_to_cs = f15_dbam_to_chip_select; break; - /* Richland is only client */ - } else if (pvt->model == 0x13) { - return NULL; - } else { - fam_type = &family_types[F15_CPUS]; - pvt->ops = &family_types[F15_CPUS].ops; } break; case 0x16: - if (pvt->model == 0x30) { - fam_type = &family_types[F16_M30H_CPUS]; - pvt->ops = &family_types[F16_M30H_CPUS].ops; + switch (pvt->model) { + case 0x30: + pvt->ctl_name = "F16h_M30h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1; + pvt->f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2; + break; + default: + pvt->ctl_name = "F16h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1; + pvt->f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2; break; } - fam_type = &family_types[F16_CPUS]; - pvt->ops = &family_types[F16_CPUS].ops; break; case 0x17: - if (pvt->model >= 0x10 && pvt->model <= 0x2f) { - fam_type = &family_types[F17_M10H_CPUS]; - pvt->ops = &family_types[F17_M10H_CPUS].ops; + switch (pvt->model) { + case 0x10 ... 0x2f: + pvt->ctl_name = "F17h_M10h"; + break; + case 0x30 ... 0x3f: + pvt->ctl_name = "F17h_M30h"; + pvt->max_mcs = 8; break; - } else if (pvt->model >= 0x30 && pvt->model <= 0x3f) { - fam_type = &family_types[F17_M30H_CPUS]; - pvt->ops = &family_types[F17_M30H_CPUS].ops; + case 0x60 ... 0x6f: + pvt->ctl_name = "F17h_M60h"; break; - } else if (pvt->model >= 0x60 && pvt->model <= 0x6f) { - fam_type = &family_types[F17_M60H_CPUS]; - pvt->ops = &family_types[F17_M60H_CPUS].ops; + case 0x70 ... 0x7f: + pvt->ctl_name = "F17h_M70h"; break; - } else if (pvt->model >= 0x70 && pvt->model <= 0x7f) { - fam_type = &family_types[F17_M70H_CPUS]; - pvt->ops = &family_types[F17_M70H_CPUS].ops; + default: + pvt->ctl_name = "F17h"; break; } - fam_type = &family_types[F17_CPUS]; - pvt->ops = &family_types[F17_CPUS].ops; break; case 0x18: - if (pvt->model == 0x4) { - fam_type = &family_types[F17_M30H_CPUS]; - pvt->ops = &family_types[F17_M30H_CPUS].ops; - family_types[F17_M30H_CPUS].max_mcs = 3; - family_types[F17_M30H_CPUS].ctl_name = "F18h_M04h"; - break; - } else if (pvt->model == 0x5) { - fam_type = &family_types[F17_M30H_CPUS]; - pvt->ops = &family_types[F17_M30H_CPUS].ops; - family_types[F17_M30H_CPUS].max_mcs = 1; - family_types[F17_M30H_CPUS].ctl_name = "F18h_M05h"; - break; - } else if (pvt->model == 0x6) { - fam_type = &family_types[F18_M06H_CPUS]; - pvt->ops = &family_types[F18_M06H_CPUS].ops; + switch (pvt->model) { + case 0x06: + pvt->ctl_name = "F18h_M06h"; break; - } else if (pvt->model == 0x7) { - fam_type = &family_types[F18_M06H_CPUS]; - pvt->ops = &family_types[F18_M06H_CPUS].ops; - family_types[F18_M06H_CPUS].ctl_name = "F18h_M07h"; + case 0x10: + pvt->ctl_name = "F18h_M10h"; break; - } else if (pvt->model == 0x10) { - fam_type = &family_types[F18_M10H_CPUS]; - pvt->ops = &family_types[F18_M10H_CPUS].ops; + default: + pvt->ctl_name = "F18h"; break; } - fam_type = &family_types[F17_CPUS]; - pvt->ops = &family_types[F17_CPUS].ops; - family_types[F17_CPUS].ctl_name = "F18h"; break; case 0x19: - if (pvt->model >= 0x10 && pvt->model <= 0x1f) { - fam_type = &family_types[F19_M10H_CPUS]; - pvt->ops = &family_types[F19_M10H_CPUS].ops; + switch (pvt->model) { + case 0x00 ... 0x0f: + pvt->ctl_name = "F19h"; + pvt->max_mcs = 8; + break; + case 0x10 ... 0x1f: + pvt->ctl_name = "F19h_M10h"; + pvt->max_mcs = 12; + pvt->flags.zn_regs_v2 = 1; break; - } else if (pvt->model >= 0x20 && pvt->model <= 0x2f) { - fam_type = &family_types[F17_M70H_CPUS]; - pvt->ops = &family_types[F17_M70H_CPUS].ops; - fam_type->ctl_name = "F19h_M20h"; + case 0x20 ... 0x2f: + pvt->ctl_name = "F19h_M20h"; break; - } else if (pvt->model >= 0xa0 && pvt->model <= 0xaf) { - fam_type = &family_types[F19_M10H_CPUS]; - pvt->ops = &family_types[F19_M10H_CPUS].ops; - fam_type->ctl_name = "F19h_MA0h"; + case 0x50 ... 0x5f: + pvt->ctl_name = "F19h_M50h"; + break; + case 0xa0 ... 0xaf: + pvt->ctl_name = "F19h_MA0h"; + pvt->max_mcs = 12; + pvt->flags.zn_regs_v2 = 1; break; } - fam_type = &family_types[F19_CPUS]; - pvt->ops = &family_types[F19_CPUS].ops; - family_types[F19_CPUS].ctl_name = "F19h"; break; default: amd64_err("Unsupported family!\n"); - return NULL; + return -ENODEV; } - return fam_type; + return 0; } static const struct attribute_group *amd64_edac_attr_groups[] = { @@ -3709,12 +3616,12 @@ static int hw_info_get(struct amd64_pvt *pvt) int ret; if (pvt->fam >= 0x17) { - pvt->umc = kcalloc(fam_type->max_mcs, sizeof(struct amd64_umc), GFP_KERNEL); + pvt->umc = kcalloc(pvt->max_mcs, sizeof(struct amd64_umc), GFP_KERNEL); if (!pvt->umc) return -ENOMEM; } else { - pci_id1 = fam_type->f1_id; - pci_id2 = fam_type->f2_id; + pci_id1 = pvt->f1_id; + pci_id2 = pvt->f2_id; } ret = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2); @@ -3744,7 +3651,7 @@ static int init_one_instance(struct amd64_pvt *pvt) layers[0].size = pvt->csels[0].b_cnt; layers[0].is_virt_csrow = true; layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = fam_type->max_mcs; + layers[1].size = pvt->max_mcs; layers[1].is_virt_csrow = false; mci = edac_mc_alloc(pvt->mc_node_id, ARRAY_SIZE(layers), layers, 0); @@ -3774,7 +3681,7 @@ static bool instance_has_memory(struct amd64_pvt *pvt) bool cs_enabled = false; int cs = 0, dct = 0; - for (dct = 0; dct < fam_type->max_mcs; dct++) { + for (dct = 0; dct < pvt->max_mcs; dct++) { for_each_chip_select(cs, dct, pvt) cs_enabled |= csrow_enabled(cs, dct, pvt); } @@ -3803,9 +3710,8 @@ static int probe_one_instance(unsigned int nid) pvt->mc_node_id = nid; pvt->F3 = F3; - ret = -ENODEV; - fam_type = per_family_init(pvt); - if (!fam_type) + ret = per_family_init(pvt); + if (ret < 0) goto err_enable; ret = hw_info_get(pvt); @@ -3844,11 +3750,7 @@ static int probe_one_instance(unsigned int nid) goto err_enable; } - amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name, - (pvt->fam == 0xf ? - (pvt->ext_model >= K8_REV_F ? "revF or later " - : "revE or earlier ") - : ""), pvt->mc_node_id); + amd64_info("%s detected (node %d).\n", pvt->ctl_name, pvt->mc_node_id); dump_misc_regs(pvt); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 705d895e88d3..2bb817940727 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -273,26 +273,6 @@ #define UMC_SDP_INIT BIT(31) -enum amd_families { - K8_CPUS = 0, - F10_CPUS, - F15_CPUS, - F15_M30H_CPUS, - F15_M60H_CPUS, - F16_CPUS, - F16_M30H_CPUS, - F17_CPUS, - F17_M10H_CPUS, - F17_M30H_CPUS, - F17_M60H_CPUS, - F17_M70H_CPUS, - F18_M06H_CPUS, - F18_M10H_CPUS, - F19_CPUS, - F19_M10H_CPUS, - NUM_FAMILIES, -}; - /* Error injection control structure */ struct error_injection { u32 section; @@ -335,6 +315,16 @@ struct amd64_umc { enum mem_type dram_type; }; +struct amd64_family_flags { + /* + * Indicates that the system supports the new register offsets, etc. + * first introduced with Family 19h Model 10h. + */ + __u64 zn_regs_v2 : 1, + + __reserved : 63; +}; + struct amd64_pvt { struct low_ops *ops; @@ -376,6 +366,12 @@ struct amd64_pvt { /* x4, x8, or x16 syndromes in use */ u8 ecc_sym_sz; + const char *ctl_name; + u16 f1_id, f2_id; + /* Maximum number of memory controllers per die/node. */ + u8 max_mcs; + + struct amd64_family_flags flags; /* place to store error injection parameters prior to issue */ struct error_injection injection; @@ -474,29 +470,10 @@ extern const struct attribute_group amd64_edac_inj_group; * functions and per device encoding/decoding logic. */ struct low_ops { - void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr, - struct err_info *); - int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, - unsigned cs_mode, int cs_mask_nr); -}; - -struct amd64_family_flags { - /* - * Indicates that the system supports the new register offsets, etc. - * first introduced with Family 19h Model 10h. - */ - __u64 zn_regs_v2 : 1, - - __reserved : 63; -}; - -struct amd64_family_type { - const char *ctl_name; - u16 f1_id, f2_id; - /* Maximum number of memory controllers per die/node. */ - u8 max_mcs; - struct amd64_family_flags flags; - struct low_ops ops; + void (*map_sysaddr_to_csrow)(struct mem_ctl_info *mci, u64 sys_addr, + struct err_info *err); + int (*dbam_to_cs)(struct amd64_pvt *pvt, u8 dct, + unsigned int cs_mode, int cs_mask_nr); }; int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, -- Gitee From c406e1efbc1e06fae2b3cda499c60197a3b0786c Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Fri, 27 Jan 2023 17:04:08 +0000 Subject: [PATCH 27/31] EDAC/amd64: Rework hw_info_{get,put} mainline inclusion from mainline-v6.4-rc1 commit 9a97a7f4d7b26cb61cdbb328b9d8982d94c99170 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/9a97a7f4d7b26cb61cdbb328b9d8982d94c99170 -------------------------------- commit 9a97a7f4d7b26cb61cdbb328b9d8982d94c99170 upstream The bulk of system-specific information is gathered at init time with hw_info_get(). This function calls a number of helper functions, and many of these helper functions are split between a modern UMC/DF path and a legacy DCT path. Split hw_info_get() into legacy and modern versions. This creates two separate code paths early on, and legacy and modern helper functions can be called directly in the appropriate code path. Also, simplify hw_info_put() and share it between legacy and modern systems. NULL pointer checks are done in pci_dev_put() and kfree(), so they can be called unconditionally. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230127170419.1824692-12-yazen.ghannam@amd.com Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 78 +++++++++++++++++---------------------- drivers/edac/amd64_edac.h | 1 + 2 files changed, 34 insertions(+), 45 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index b9cec0c90151..c48e14b08175 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2800,9 +2800,6 @@ static void decode_umc_error(int node_id, struct mce *m) static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2) { - if (pvt->umc) - return 0; - /* Reserve the ADDRESS MAP Device */ pvt->F1 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3); if (!pvt->F1) { @@ -2830,16 +2827,6 @@ reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2) return 0; } -static void free_mc_sibling_devs(struct amd64_pvt *pvt) -{ - if (pvt->umc) { - return; - } else { - pci_dev_put(pvt->F1); - pci_dev_put(pvt->F2); - } -} - static void determine_ecc_sym_sz_f18h_m4h(struct amd64_pvt *pvt, int channel) { if (pvt->umc[channel].ecc_ctrl & BIT(8)) @@ -3449,13 +3436,45 @@ static void setup_mci_misc_attrs(struct mem_ctl_info *mci) mci->get_sdram_scrub_rate = get_scrub_rate; } +static int dct_hw_info_get(struct amd64_pvt *pvt) +{ + int ret = reserve_mc_sibling_devs(pvt, pvt->f1_id, pvt->f2_id); + + if (ret) + return ret; + + read_mc_regs(pvt); + + return 0; +} + +static int umc_hw_info_get(struct amd64_pvt *pvt) +{ + pvt->umc = kcalloc(pvt->max_mcs, sizeof(struct amd64_umc), GFP_KERNEL); + if (!pvt->umc) + return -ENOMEM; + + read_mc_regs(pvt); + + return 0; +} + +static void hw_info_put(struct amd64_pvt *pvt) +{ + pci_dev_put(pvt->F1); + pci_dev_put(pvt->F2); + kfree(pvt->umc); +} + static struct low_ops umc_ops = { + .hw_info_get = umc_hw_info_get, }; /* Use Family 16h versions for defaults and adjust as needed below. */ static struct low_ops dct_ops = { .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, .dbam_to_cs = f16_dbam_to_chip_select, + .hw_info_get = dct_hw_info_get, }; static int per_family_init(struct amd64_pvt *pvt) @@ -3610,37 +3629,6 @@ static const struct attribute_group *amd64_edac_attr_groups[] = { NULL }; -static int hw_info_get(struct amd64_pvt *pvt) -{ - u16 pci_id1, pci_id2; - int ret; - - if (pvt->fam >= 0x17) { - pvt->umc = kcalloc(pvt->max_mcs, sizeof(struct amd64_umc), GFP_KERNEL); - if (!pvt->umc) - return -ENOMEM; - } else { - pci_id1 = pvt->f1_id; - pci_id2 = pvt->f2_id; - } - - ret = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2); - if (ret) - return ret; - - read_mc_regs(pvt); - - return 0; -} - -static void hw_info_put(struct amd64_pvt *pvt) -{ - if (pvt->F1) - free_mc_sibling_devs(pvt); - - kfree(pvt->umc); -} - static int init_one_instance(struct amd64_pvt *pvt) { struct mem_ctl_info *mci = NULL; @@ -3714,7 +3702,7 @@ static int probe_one_instance(unsigned int nid) if (ret < 0) goto err_enable; - ret = hw_info_get(pvt); + ret = pvt->ops->hw_info_get(pvt); if (ret < 0) goto err_enable; diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 2bb817940727..c2781764a6ab 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -474,6 +474,7 @@ struct low_ops { struct err_info *err); int (*dbam_to_cs)(struct amd64_pvt *pvt, u8 dct, unsigned int cs_mode, int cs_mask_nr); + int (*hw_info_get)(struct amd64_pvt *pvt); }; int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, -- Gitee From a86cc7651f0ff02aeca427b11e9070a87b6b620e Mon Sep 17 00:00:00 2001 From: Avadhut Naik Date: Tue, 8 Aug 2023 22:52:42 -0500 Subject: [PATCH 28/31] x86/amd_nb: Add PCI IDs for AMD Family 1Ah-based models mainline inclusion from mainline-v6.6-rc1 commit c64016609b6f66b753b5f37929a191477fa584c0 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/c64016609b6f66b753b5f37929a191477fa584c0 -------------------------------- commit c64016609b6f66b753b5f37929a191477fa584c0 upstream Add new PCI Device IDs required to support AMD's new Family 1Ah-based models 00h-1Fh, 20h and 40h-4Fh. [ bp: Zap a useless sentence. ] Co-developed-by: Mario Limonciello Signed-off-by: Mario Limonciello Signed-off-by: Avadhut Naik Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230809035244.2722455-2-avadhut.naik@amd.com Signed-off-by: PvsNarasimha --- arch/x86/kernel/amd_nb.c | 8 ++++++++ include/linux/pci_ids.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 817399fc3d20..8c64dc3a94d1 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -38,6 +38,9 @@ #define PCI_DEVICE_ID_HYGON_18H_M05H_DF_F4 0x14b4 #define PCI_DEVICE_ID_HYGON_18H_M10H_DF_F4 0x14d4 #define PCI_DEVICE_ID_HYGON_18H_M06H_DF_F5 0x14b5 +#define PCI_DEVICE_ID_AMD_1AH_M00H_ROOT 0x153a +#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507 +#define PCI_DEVICE_ID_AMD_1AH_M00H_DF_F4 0x12c4 /* Protect the PCI config register pairs used for SMN. */ static DEFINE_MUTEX(smn_mutex); @@ -52,6 +55,8 @@ static const struct pci_device_id amd_root_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M10H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_ROOT) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M00H_ROOT) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, {} }; @@ -76,6 +81,8 @@ static const struct pci_device_id amd_nb_misc_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_DF_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F3) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M00H_DF_F3) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_DF_F3) }, {} }; @@ -95,6 +102,7 @@ static const struct pci_device_id amd_nb_link_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M40H_DF_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M00H_DF_F4) }, {} }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 4ab10befc462..ccd2fb524000 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -560,6 +560,8 @@ #define PCI_DEVICE_ID_AMD_19H_M10H_DF_F3 0x14b0 #define PCI_DEVICE_ID_AMD_19H_M40H_DF_F3 0x167c #define PCI_DEVICE_ID_AMD_19H_M50H_DF_F3 0x166d +#define PCI_DEVICE_ID_AMD_1AH_M00H_DF_F3 0x12c3 +#define PCI_DEVICE_ID_AMD_1AH_M20H_DF_F3 0x16fb #define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703 #define PCI_DEVICE_ID_AMD_LANCE 0x2000 #define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 -- Gitee From 20fc2c6e19f6e6e58ba0421765c30ed2b8738d15 Mon Sep 17 00:00:00 2001 From: Avadhut Naik Date: Tue, 8 Aug 2023 22:52:43 -0500 Subject: [PATCH 29/31] hwmon: (k10temp) Add thermal support for AMD Family 1Ah-based models mainline inclusion from mainline-v6.6-rc1 commit 3cd9da416d5b625d52053c816ee91daf4e97007c category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/3cd9da416d5b625d52053c816ee91daf4e97007c -------------------------------- commit 3cd9da416d5b625d52053c816ee91daf4e97007c upstream Add thermal info support for AMD Family 1Ah-based models. Support is provided on a per-socket granularity. Co-developed-by: Mario Limonciello Signed-off-by: Mario Limonciello Signed-off-by: Avadhut Naik Signed-off-by: Borislav Petkov (AMD) Acked-by: Guenter Roeck Link: https://lore.kernel.org/r/20230809035244.2722455-3-avadhut.naik@amd.com Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/hwmon/k10temp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index e9f60bd46ff1..e2b7694e339d 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -65,7 +65,7 @@ static DEFINE_MUTEX(nb_smu_ind_mutex); #define F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET 0xd8200c64 #define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4 -/* Common for Zen CPU families (Family 17h and 18h and 19h) */ +/* Common for Zen CPU families (Family 17h and 18h and 19h and 1Ah) */ #define ZEN_REPORTED_TEMP_CTRL_BASE 0x00059800 #define ZEN_CCD_TEMP(offset, x) (ZEN_REPORTED_TEMP_CTRL_BASE + \ @@ -532,6 +532,10 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) k10temp_get_ccd_support(pdev, data, 12); break; } + } else if (boot_cpu_data.x86 == 0x1a) { + data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK; + data->read_tempreg = read_tempreg_nb_zen; + data->is_zen = true; } else { data->read_htcreg = read_htcreg_pci; data->read_tempreg = read_tempreg_pci; @@ -574,6 +578,8 @@ static const struct pci_device_id k10temp_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M40H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_1AH_M00H_DF_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_1AH_M20H_DF_F3) }, { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) }, { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_HYGON_18H_M05H_DF_F3) }, -- Gitee From ea36a57089b484a67188c0ba9f4fd58744780214 Mon Sep 17 00:00:00 2001 From: Avadhut Naik Date: Tue, 8 Aug 2023 22:52:44 -0500 Subject: [PATCH 30/31] EDAC/amd64: Add support for AMD family 1Ah models 00h-1Fh and 40h-4Fh mainline inclusion from mainline-v6.6-rc1 commit c4d07c371283cb0453c8ce187551e4d064cc407e category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD Reference: https://github.com/torvalds/linux/commit/c4d07c371283cb0453c8ce187551e4d064cc407e -------------------------------- commit c4d07c371283cb0453c8ce187551e4d064cc407e upstream Add support for family 1Ah-based models 00h-1Fh and 40h-4Fh. [ bp: Simplify. ] Signed-off-by: Avadhut Naik Signed-off-by: Borislav Petkov (AMD) Link: https://lore.kernel.org/r/20230809035244.2722455-4-avadhut.naik@amd.com Signed-off-by: Hemanth Selam Signed-off-by: PvsNarasimha --- drivers/edac/amd64_edac.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index c48e14b08175..ce947c4bf967 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -3611,6 +3611,20 @@ static int per_family_init(struct amd64_pvt *pvt) } break; + case 0x1A: + switch (pvt->model) { + case 0x00 ... 0x1f: + pvt->ctl_name = "F1Ah"; + pvt->max_mcs = 12; + pvt->flags.zn_regs_v2 = 1; + break; + case 0x40 ... 0x4f: + pvt->ctl_name = "F1Ah_M40h"; + pvt->flags.zn_regs_v2 = 1; + break; + } + break; + default: amd64_err("Unsupported family!\n"); return -ENODEV; @@ -3803,6 +3817,7 @@ static const struct x86_cpu_id amd64_cpuids[] = { X86_MATCH_VENDOR_FAM(AMD, 0x17, NULL), X86_MATCH_VENDOR_FAM(HYGON, 0x18, NULL), X86_MATCH_VENDOR_FAM(AMD, 0x19, NULL), + X86_MATCH_VENDOR_FAM(AMD, 0x1A, NULL), { } }; MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids); -- Gitee From b6c66f173831376bed6532744b8c327075347dcd Mon Sep 17 00:00:00 2001 From: PvsNarasimha Date: Mon, 25 Nov 2024 17:12:40 +0530 Subject: [PATCH 31/31] config: enable CONFIG_I2C_DESIGNWARE_AMDPSP by default on x86 amd inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IAU6ZD -------------------------------- This commit updates the openeuler_defconfig file to include necessary configuration options that were missing, causing CI test failures. The modifications ensure compatibility with the AMD Genoa and Turin platforms, enabling the features required for proper functionality. Key changes: * Added CONFIG_I2C_DESIGNWARE_AMDPSP This configuration Enables managed host access to the selected I2C bus shared between AMD CPUs and the AMD Platform security processor(PSP). You should set this option to Y if running on an AMD system equipped with the PSP. These changes resolve the CI test failures and ensure that the kernel is properly configured for the AMD Genoa and Turin platforms. Signed-off-by: PvsNarasimha --- arch/x86/configs/openeuler_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index bfaadb4b298f..5ba9d95ed62f 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -3731,6 +3731,7 @@ CONFIG_I2C_SCMI=m CONFIG_I2C_DESIGNWARE_CORE=m # CONFIG_I2C_DESIGNWARE_SLAVE is not set CONFIG_I2C_DESIGNWARE_PLATFORM=m +CONFIG_I2C_DESIGNWARE_AMDPSP=y CONFIG_I2C_DESIGNWARE_BAYTRAIL=y # CONFIG_I2C_DESIGNWARE_PCI is not set # CONFIG_I2C_EMEV2 is not set -- Gitee