diff --git a/common/recipes-kernel/linux/6.6/0300-To-support-MCP9600-temperature-driver.patch b/common/recipes-kernel/linux/6.6/0300-To-support-MCP9600-temperature-driver.patch new file mode 100644 index 000000000000..c3cfd61a43b8 --- /dev/null +++ b/common/recipes-kernel/linux/6.6/0300-To-support-MCP9600-temperature-driver.patch @@ -0,0 +1,272 @@ +From 6730a3fc30df7be7f6a5bf66f65e9a25915b5b2f Mon Sep 17 00:00:00 2001 +From: Peter Yin +Date: Thu, 2 Nov 2023 14:52:04 +0800 +Subject: [PATCH 300/303] To support MCP9600 temperature driver + +LF-Kernel link: +link:https://lore.kernel.org/all/20231025233153.5454-1-andrew.hepp@ahepp.dev/ +link:https://lore.kernel.org/all/20231025233153.5454-2-andrew.hepp@ahepp.dev/ +--- + .../iio/temperature/microchip,mcp9600.yaml | 70 +++++++++ + drivers/iio/temperature/Kconfig | 10 ++ + drivers/iio/temperature/Makefile | 1 + + drivers/iio/temperature/mcp9600.c | 139 ++++++++++++++++++ + 4 files changed, 220 insertions(+) + create mode 100644 Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml + create mode 100644 drivers/iio/temperature/mcp9600.c + +diff --git a/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml b/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +new file mode 100644 +index 000000000000..d2cafa38a544 +--- /dev/null ++++ b/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml +@@ -0,0 +1,70 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/iio/temperature/microchip,mcp9600.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Microchip MCP9600 thermocouple EMF converter ++ ++maintainers: ++ - Andrew Hepp ++ ++description: ++ https://ww1.microchip.com/downloads/en/DeviceDoc/MCP960X-Data-Sheet-20005426.pdf ++ ++properties: ++ compatible: ++ const: microchip,mcp9600 ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ minItems: 1 ++ maxItems: 6 ++ ++ interrupt-names: ++ minItems: 1 ++ maxItems: 6 ++ items: ++ enum: ++ - open-circuit ++ - short-circuit ++ - alert1 ++ - alert2 ++ - alert3 ++ - alert4 ++ ++ thermocouple-type: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ Type of thermocouple (THERMOCOUPLE_TYPE_K if omitted). ++ Use defines in dt-bindings/iio/temperature/thermocouple.h. ++ Supported types are B, E, J, K, N, R, S, T. ++ ++ vdd-supply: true ++ ++required: ++ - compatible ++ - reg ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ temperature-sensor@60 { ++ compatible = "microchip,mcp9600"; ++ reg = <0x60>; ++ interrupt-parent = <&gpio>; ++ interrupts = <25 IRQ_TYPE_EDGE_RISING>; ++ interrupt-names = "open-circuit"; ++ thermocouple-type = ; ++ vdd-supply = <&vdd>; ++ }; ++ }; +diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig +index ed384f33e0c7..ea2ce364b2e9 100644 +--- a/drivers/iio/temperature/Kconfig ++++ b/drivers/iio/temperature/Kconfig +@@ -158,4 +158,14 @@ config MAX31865 + This driver can also be build as a module. If so, the module + will be called max31865. + ++config MCP9600 ++ tristate "MCP9600 thermocouple EMF converter" ++ depends on I2C ++ help ++ If you say yes here you get support for MCP9600 ++ thermocouple EMF converter connected via I2C. ++ ++ This driver can also be built as a module. If so, the module ++ will be called mcp9600. ++ + endmenu +diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile +index dfec8c6d3019..9330d4a39598 100644 +--- a/drivers/iio/temperature/Makefile ++++ b/drivers/iio/temperature/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o + obj-$(CONFIG_MAX30208) += max30208.o + obj-$(CONFIG_MAX31856) += max31856.o + obj-$(CONFIG_MAX31865) += max31865.o ++obj-$(CONFIG_MCP9600) += mcp9600.o + obj-$(CONFIG_MLX90614) += mlx90614.o + obj-$(CONFIG_MLX90632) += mlx90632.o + obj-$(CONFIG_TMP006) += tmp006.o +diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c +new file mode 100644 +index 000000000000..46845804292b +--- /dev/null ++++ b/drivers/iio/temperature/mcp9600.c +@@ -0,0 +1,139 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * mcp9600.c - Support for Microchip MCP9600 thermocouple EMF converter ++ * ++ * Copyright (c) 2022 Andrew Hepp ++ * Author: ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* MCP9600 registers */ ++#define MCP9600_HOT_JUNCTION 0x0 ++#define MCP9600_COLD_JUNCTION 0x2 ++#define MCP9600_DEVICE_ID 0x20 ++ ++/* MCP9600 device id value */ ++#define MCP9600_DEVICE_ID_MCP9600 0x40 ++ ++static const struct iio_chan_spec mcp9600_channels[] = { ++ { ++ .type = IIO_TEMP, ++ .address = MCP9600_HOT_JUNCTION, ++ .info_mask_separate = ++ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ++ }, ++ { ++ .type = IIO_TEMP, ++ .address = MCP9600_COLD_JUNCTION, ++ .channel2 = IIO_MOD_TEMP_AMBIENT, ++ .modified = 1, ++ .info_mask_separate = ++ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), ++ }, ++}; ++ ++struct mcp9600_data { ++ struct i2c_client *client; ++}; ++ ++static int mcp9600_read(struct mcp9600_data *data, ++ struct iio_chan_spec const *chan, int *val) ++{ ++ int ret; ++ ++ ret = i2c_smbus_read_word_swapped(data->client, chan->address); ++ ++ if (ret < 0) ++ return ret; ++ *val = ret; ++ ++ return 0; ++} ++ ++static int mcp9600_read_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, int *val, ++ int *val2, long mask) ++{ ++ struct mcp9600_data *data = iio_priv(indio_dev); ++ int ret; ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_RAW: ++ ret = mcp9600_read(data, chan, val); ++ if (ret) ++ return ret; ++ return IIO_VAL_INT; ++ case IIO_CHAN_INFO_SCALE: ++ *val = 62; ++ *val2 = 500000; ++ return IIO_VAL_INT_PLUS_MICRO; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static const struct iio_info mcp9600_info = { ++ .read_raw = mcp9600_read_raw, ++}; ++ ++static int mcp9600_probe(struct i2c_client *client) ++{ ++ struct iio_dev *indio_dev; ++ struct mcp9600_data *data; ++ int ret; ++ ++ ret = i2c_smbus_read_byte_data(client, MCP9600_DEVICE_ID); ++ if (ret < 0) ++ return dev_err_probe(&client->dev, ret, "Failed to read device ID\n"); ++ if (ret != MCP9600_DEVICE_ID_MCP9600) ++ dev_warn(&client->dev, "Expected ID %x, got %x\n", ++ MCP9600_DEVICE_ID_MCP9600, ret); ++ ++ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); ++ if (!indio_dev) ++ return -ENOMEM; ++ ++ data = iio_priv(indio_dev); ++ data->client = client; ++ ++ indio_dev->info = &mcp9600_info; ++ indio_dev->name = "mcp9600"; ++ indio_dev->modes = INDIO_DIRECT_MODE; ++ indio_dev->channels = mcp9600_channels; ++ indio_dev->num_channels = ARRAY_SIZE(mcp9600_channels); ++ ++ return devm_iio_device_register(&client->dev, indio_dev); ++} ++ ++static const struct i2c_device_id mcp9600_id[] = { ++ { "mcp9600" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, mcp9600_id); ++ ++static const struct of_device_id mcp9600_of_match[] = { ++ { .compatible = "microchip,mcp9600" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, mcp9600_of_match); ++ ++static struct i2c_driver mcp9600_driver = { ++ .driver = { ++ .name = "mcp9600", ++ .of_match_table = mcp9600_of_match, ++ }, ++ .probe = mcp9600_probe, ++ .id_table = mcp9600_id ++}; ++module_i2c_driver(mcp9600_driver); ++ ++MODULE_AUTHOR("Andrew Hepp "); ++MODULE_DESCRIPTION("Microchip MCP9600 thermocouple EMF converter driver"); ++MODULE_LICENSE("GPL"); +-- +2.41.0 + diff --git a/common/recipes-kernel/linux/6.6/0301-To-support-MP2856-VR-driver.patch b/common/recipes-kernel/linux/6.6/0301-To-support-MP2856-VR-driver.patch new file mode 100644 index 000000000000..8f6e466d8c83 --- /dev/null +++ b/common/recipes-kernel/linux/6.6/0301-To-support-MP2856-VR-driver.patch @@ -0,0 +1,521 @@ +From 15b91b16d378d68eda6e4c4e5489f335b57be6e3 Mon Sep 17 00:00:00 2001 +From: Peter Yin +Date: Wed, 8 Nov 2023 09:27:35 +0800 +Subject: [PATCH 301/303] To-support-MP2856-VR-driver + +LF-Kernel link: +link:https://lore.kernel.org/all/20231108024222.2026546-2-peter.yin@quantatw.com/ +link:https://lore.kernel.org/all/20231108024222.2026546-3-peter.yin@quantatw.com/ +--- + .../devicetree/bindings/trivial-devices.yaml | 4 + + Documentation/hwmon/index.rst | 1 + + Documentation/hwmon/mp2856.rst | 101 ++++++ + drivers/hwmon/pmbus/Kconfig | 9 + + drivers/hwmon/pmbus/Makefile | 1 + + drivers/hwmon/pmbus/mp2856.c | 327 ++++++++++++++++++ + 6 files changed, 443 insertions(+) + create mode 100644 Documentation/hwmon/mp2856.rst + create mode 100644 drivers/hwmon/pmbus/mp2856.c + +diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml +index 386ebd1471d0..c847a532283d 100644 +--- a/Documentation/devicetree/bindings/trivial-devices.yaml ++++ b/Documentation/devicetree/bindings/trivial-devices.yaml +@@ -119,6 +119,10 @@ properties: + - fsl,mpl3115 + # MPR121: Proximity Capacitive Touch Sensor Controller + - fsl,mpr121 ++ # Monolithic Power Systems Inc. multi-phase controller mp2856 ++ - mps,mp2856 ++ # Monolithic Power Systems Inc. multi-phase controller mp2857 ++ - mps,mp2857 + # Monolithic Power Systems Inc. multi-phase controller mp2888 + - mps,mp2888 + # Monolithic Power Systems Inc. multi-phase controller mp2971 +diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst +index fac861e2a8ab..e45999f8e674 100644 +--- a/Documentation/hwmon/index.rst ++++ b/Documentation/hwmon/index.rst +@@ -156,6 +156,7 @@ Hardware Monitoring Kernel Drivers + mcp3021 + menf21bmc + mlxreg-fan ++ mp2856 + mp2888 + mp2975 + mp5023 +diff --git a/Documentation/hwmon/mp2856.rst b/Documentation/hwmon/mp2856.rst +new file mode 100644 +index 000000000000..6bd8392f6994 +--- /dev/null ++++ b/Documentation/hwmon/mp2856.rst +@@ -0,0 +1,101 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++Kernel driver mp2856 ++==================== ++ ++Supported chips: ++ ++ * MPS MP2856 ++ ++ Prefix: 'mp2856' ++ ++ * MPS MP2857 ++ ++ Prefix: 'mp2857' ++ ++Author: ++ ++ Peter Yin ++ ++Description ++----------- ++ ++This driver implements support for Monolithic Power Systems, Inc. (MPS) ++vendor dual-loop, digital, multi-phase controller MP2856/MP2857 ++ ++This device: ++ ++- Supports up to two power rail. ++- Supports two pages 0 and 1 for and also pages 2 for configuration. ++- Can configured VOUT readout in direct or VID format and allows ++ setting of different formats on rails 1 and 2. For VID the following ++ protocols are available: AMD SVI3 mode with 5-mV/LSB. ++ ++Device supports: ++ ++- SVID interface. ++- AVSBus interface. ++ ++Device complaint with: ++ ++- PMBus rev 1.3 interface. ++ ++Device supports direct format for reading output current, output voltage, ++input and output power and temperature. ++Device supports linear format for reading input voltage and input power. ++Device supports VID and direct formats for reading output voltage. ++The below VID modes are supported: AMD SVI3. ++ ++The driver provides the next attributes for the current: ++The driver exports the following attributes via the 'sysfs' files, where ++ ++- indexes 1 for "iin"; ++- indexes 2, 3 for "iout"; ++ ++**curr[1-3]_alarm** ++ ++**curr[1-3]_input** ++ ++**curr[1-3]_label** ++ ++The driver provides the next attributes for the voltage: ++The driver exports the following attributes via the 'sysfs' files, where ++ ++- indexes 1 for "vin"; ++- indexes 2, 3 for "vout"; ++ ++**in[1-3]_crit** ++ ++**in[1-3]_crit_alarm** ++ ++**in[1-3]_input** ++ ++**in[1-3]_label** ++ ++**in[1-3]_lcrit** ++ ++**in[1-3]_lcrit_alarm** ++ ++The driver provides the next attributes for the power: ++The driver exports the following attributes via the 'sysfs' files, where ++ ++- indexes 1 for "pin"; ++- indexes 2, 3 for "pout"; ++ ++**power[1-3]_alarm** ++ ++**power[1-3]_input** ++ ++**power[1-3]_label** ++ ++The driver provides the next attributes for the temperature: ++ ++**temp[1-2]_crit** ++ ++**temp[1-2]_crit_alarm** ++ ++**temp[1-2]_input** ++ ++**temp[1-2]_max** ++ ++**temp[1-2]_max_alarm** +diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig +index 17c98fca5bb6..ad0e66e67bde 100644 +--- a/drivers/hwmon/pmbus/Kconfig ++++ b/drivers/hwmon/pmbus/Kconfig +@@ -299,6 +299,15 @@ config SENSORS_MAX8688 + This driver can also be built as a module. If so, the module will + be called max8688. + ++config SENSORS_MP2856 ++ tristate "MPS MP2856" ++ help ++ If you say yes here you get hardware monitoring support for MPS ++ MP2856 MP2857 Dual Loop Digital Multi-Phase Controller. ++ ++ This driver can also be built as a module. If so, the module will ++ be called mp2856. ++ + config SENSORS_MP2888 + tristate "MPS MP2888" + help +diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile +index 212d9ca0acc9..f53b51b250ff 100644 +--- a/drivers/hwmon/pmbus/Makefile ++++ b/drivers/hwmon/pmbus/Makefile +@@ -32,6 +32,7 @@ obj-$(CONFIG_SENSORS_MAX20751) += max20751.o + obj-$(CONFIG_SENSORS_MAX31785) += max31785.o + obj-$(CONFIG_SENSORS_MAX34440) += max34440.o + obj-$(CONFIG_SENSORS_MAX8688) += max8688.o ++obj-$(CONFIG_SENSORS_MP2856) += mp2856.o + obj-$(CONFIG_SENSORS_MP2888) += mp2888.o + obj-$(CONFIG_SENSORS_MP2975) += mp2975.o + obj-$(CONFIG_SENSORS_MP5023) += mp5023.o +diff --git a/drivers/hwmon/pmbus/mp2856.c b/drivers/hwmon/pmbus/mp2856.c +new file mode 100644 +index 000000000000..b72a46cb6e9b +--- /dev/null ++++ b/drivers/hwmon/pmbus/mp2856.c +@@ -0,0 +1,327 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Hardware monitoring driver for MPS2856/2857 ++ * Monolithic Power Systems VR Controllers ++ * ++ * Copyright (C) 2023 Quanta Computer lnc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pmbus.h" ++ ++/* Vendor specific registers. */ ++#define MP2856_MFR_SLOPE_TRIM3 0x1d ++#define MP2856_MFR_VR_MULTI_CONFIG_R1 0x0d ++#define MP2856_MFR_VR_MULTI_CONFIG_R2 0x1d ++#define MP2856_MUL1_CUR_SCALE_R1 0x0b ++#define MP2856_MUL1_CUR_SCALE_R2 0x1b ++#define MP2856_MFR_DC_LOOP_CTRL 0x59 ++#define MP2856_MFR_VR_CONFIG1 0x68 ++#define MP2856_MFR_READ_IOUT_PK 0x90 ++#define MP2856_MFR_READ_POUT_PK 0x91 ++#define MP2856_MFR_PROTECT_SET 0xc5 ++#define MP2856_MFR_RESO_SET 0x5e ++#define MP2856_MFR_OVP_TH_SET 0xe5 ++#define MP2856_MFR_UVP_SET 0xe6 ++ ++#define MP2856_VID_EN BIT(11) ++#define MP2856_DRMOS_KCS GENMASK(15, 12) ++#define MP2856_VID_SCALE 5 ++#define MP2856_VIN_UV_LIMIT_UNIT 8 ++#define MP2856_PWR_EXPONENT_BIT GENMASK(10, 6) ++ ++#define MP2856_MAX_PHASE_RAIL1 12 ++#define MP2856_MAX_PHASE_RAIL2 6 ++#define MP2856_PAGE_NUM 2 ++ ++#define MP2856_RAIL2_FUNC (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \ ++ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \ ++ PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP) ++ ++#define MP2856_RAIL2_MAX_PHASE 4 ++ ++struct mp2856_data { ++ struct pmbus_driver_info info; ++ int vout_format[MP2856_PAGE_NUM]; ++}; ++ ++#define to_mp2856_data(x) container_of(x, struct mp2856_data, info) ++ ++static int ++mp2856_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg, ++ u16 mask) ++{ ++ int ret = pmbus_read_word_data(client, page, phase, reg); ++ ++ return (ret > 0) ? ret & mask : ret; ++} ++ ++static int ++mp2856_vid2linear(int val) ++{ ++ return 500 + (val - 1) * 10; ++} ++ ++static int mp2856_read_word_data(struct i2c_client *client, int page, ++ int phase, int reg) ++{ ++ const struct pmbus_driver_info *info = pmbus_get_driver_info(client); ++ struct mp2856_data *data = to_mp2856_data(info); ++ int ret; ++ ++ switch (reg) { ++ case PMBUS_READ_VOUT: ++ ret = mp2856_read_word_helper(client, page, phase, reg, ++ GENMASK(11, 0)); ++ if (ret < 0) ++ return ret; ++ ++ /* ++ * READ_VOUT can be provided in VID or linear format. This ++ * provided in a linear format. In case format is VID - convert ++ * to linear. ++ */ ++ if (data->vout_format[page] == vid) ++ ret = mp2856_vid2linear(ret); ++ break; ++ default: ++ return -ENODATA; ++ } ++ ++ return ret; ++} ++ ++static int mp2856_identify_multiphase_rail2(struct i2c_client *client) ++{ ++ int ret; ++ ++ /* ++ * Identify multiphase for rail 2 - could be from 0 to 1. ++ * In case phase number is zero – only page zero is supported ++ */ ++ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); ++ if (ret < 0) ++ return ret; ++ ++ /* Identify multiphase for rail 2 - could be from 0 to 1. */ ++ ret = i2c_smbus_read_word_data(client, MP2856_MFR_VR_MULTI_CONFIG_R2); ++ if (ret < 0) ++ return ret; ++ ++ ret &= GENMASK(2, 0); ++ return (ret >= MP2856_RAIL2_MAX_PHASE) ? MP2856_RAIL2_MAX_PHASE : ret; ++} ++ ++static int ++mp2856_identify_vid(struct i2c_client *client, struct mp2856_data *data, ++ struct pmbus_driver_info *info, u32 reg, int page, ++ u32 imvp_bit) ++{ ++ int ret; ++ ++ /* Identify VID mode and step selection. */ ++ ret = i2c_smbus_read_word_data(client, reg); ++ if (ret < 0) ++ return ret; ++ ++ if (ret & imvp_bit) { ++ info->vrm_version[page] = vr13; ++ } else { ++ //workaround for chip power scale issue ++ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); ++ if (ret < 0) ++ return ret; ++ ++ ret = i2c_smbus_read_word_data(client, ++ MP2856_MUL1_CUR_SCALE_R1); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~MP2856_PWR_EXPONENT_BIT; ++ ret = i2c_smbus_write_word_data(client, ++ MP2856_MUL1_CUR_SCALE_R1, ret); ++ if (ret < 0) ++ return ret; ++ ++ ret = i2c_smbus_read_word_data(client, ++ MP2856_MUL1_CUR_SCALE_R2); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~MP2856_PWR_EXPONENT_BIT; ++ ret = i2c_smbus_write_word_data(client, ++ MP2856_MUL1_CUR_SCALE_R2, ret); ++ if (ret < 0) ++ return ret; ++ } ++ return 0; ++} ++ ++static int ++mp2856_identify_rails_vid(struct i2c_client *client, struct mp2856_data *data, ++ struct pmbus_driver_info *info) ++{ ++ int ret; ++ ++ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); ++ if (ret < 0) ++ return ret; ++ ++ /* Identify VID mode for rail 1. */ ++ ret = mp2856_identify_vid(client, data, info, ++ MP2856_MFR_RESO_SET, 0, ++ MP2856_VID_EN); ++ if (ret < 0) ++ return ret; ++ ++ /* Identify VID mode for rail 2, if connected. */ ++ if (info->phases[1]) ++ ret = mp2856_identify_vid(client, data, info, ++ MP2856_MFR_RESO_SET, 1, ++ MP2856_VID_EN); ++ return ret; ++} ++ ++static int ++mp2856_identify_vout_format(struct i2c_client *client, ++ struct mp2856_data *data, int page) ++{ ++ int ret; ++ int val; ++ ++ ret = i2c_smbus_read_word_data(client, MP2856_MFR_RESO_SET); ++ if (ret < 0) ++ return ret; ++ ++ val = (ret & GENMASK(11, 11)) >> 11; ++ switch (val) { ++ case 0: ++ data->vout_format[page] = vid; ++ break; ++ default: ++ data->vout_format[page] = linear; ++ break; ++ } ++ return 0; ++} ++ ++static int ++mp2856_vout_per_rail_config_get(struct i2c_client *client, ++ struct mp2856_data *data, ++ struct pmbus_driver_info *info) ++{ ++ int i, ret; ++ ++ for (i = 0; i < data->info.pages; i++) { ++ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); ++ if (ret < 0) ++ return ret; ++ ++ /* ++ * Get VOUT format for READ_VOUT command : VID or direct. ++ * Pages on same device can be configured with different ++ * formats. ++ */ ++ ret = mp2856_identify_vout_format(client, data, i); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static struct pmbus_driver_info mp2856_info = { ++ .pages = 1, ++ .format[PSC_VOLTAGE_IN] = linear, ++ .format[PSC_VOLTAGE_OUT] = linear, ++ .format[PSC_TEMPERATURE] = linear, ++ .format[PSC_CURRENT_IN] = linear, ++ .format[PSC_CURRENT_OUT] = linear, ++ .format[PSC_POWER] = linear, ++ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ++ PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ++ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT | ++ PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, ++ .read_word_data = mp2856_read_word_data, ++}; ++ ++static int mp2856_probe(struct i2c_client *client) ++{ ++ struct pmbus_driver_info *info; ++ struct mp2856_data *data; ++ int ret; ++ ++ /* ++ * MP2856/MP2857 devices may not stay in page 0 during device ++ * probe which leads to probe failure (read status word failed). ++ * So let's set the device to page 0 at the beginning. ++ */ ++ i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); ++ ++ data = devm_kzalloc(&client->dev, sizeof(struct mp2856_data), ++ GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ memcpy(&data->info, &mp2856_info, sizeof(*info)); ++ info = &data->info; ++ ++ /* Identify multiphase configuration for rail 2. */ ++ ret = mp2856_identify_multiphase_rail2(client); ++ if (ret < 0) ++ return ret; ++ ++ if (ret) { ++ /* Two rails are connected. */ ++ data->info.pages = MP2856_PAGE_NUM; ++ data->info.phases[1] = ret; ++ data->info.func[1] = MP2856_RAIL2_FUNC; ++ } ++ ++ ret = mp2856_identify_rails_vid(client, data, info); ++ if (ret < 0) ++ return ret; ++ ++ /* Obtain offsets, maximum and format for vout. */ ++ ret = mp2856_vout_per_rail_config_get(client, data, info); ++ if (ret) ++ return ret; ++ ++ return pmbus_do_probe(client, info); ++} ++ ++static const struct i2c_device_id mp2856_id[] = { ++ {"mp2856", 0}, ++ {"mp2857", 0}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, mp2856_id); ++ ++static const struct of_device_id __maybe_unused mp2856_of_match[] = { ++ {.compatible = "mps,mp2856"}, ++ {.compatible = "mps,mp2857"}, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, mp2856_of_match); ++ ++static struct i2c_driver mp2856_driver = { ++ .driver = { ++ .name = "mp2856", ++ .of_match_table = mp2856_of_match, ++ }, ++ .probe = mp2856_probe, ++ .id_table = mp2856_id, ++}; ++ ++module_i2c_driver(mp2856_driver); ++ ++MODULE_AUTHOR("Peter Yin "); ++MODULE_DESCRIPTION("PMBus driver for MPS MP2856/MP2857 device"); ++MODULE_LICENSE("GPL"); ++MODULE_IMPORT_NS(PMBUS); +-- +2.41.0 + diff --git a/common/recipes-kernel/linux/6.6/0302-To-support-LTC4286-LTC4287-driver.patch b/common/recipes-kernel/linux/6.6/0302-To-support-LTC4286-LTC4287-driver.patch new file mode 100644 index 000000000000..c1d9104cc623 --- /dev/null +++ b/common/recipes-kernel/linux/6.6/0302-To-support-LTC4286-LTC4287-driver.patch @@ -0,0 +1,422 @@ +From 1551ecad1f3872e2ac646d1893da885cdc8025e3 Mon Sep 17 00:00:00 2001 +From: Delphine CC Chiu +Date: Mon, 24 Jul 2023 11:58:51 +0800 +Subject: [PATCH 302/303] To support LTC4286 LTC4287 driver + +LF-Kernel link: +link:https://lore.kernel.org/all/20231116023027.24855-2-Delphine_CC_Chiu@Wiwynn.com/ +link:https://lore.kernel.org/all/20231116023027.24855-3-Delphine_CC_Chiu@Wiwynn.com/ +--- + .../bindings/hwmon/lltc,ltc4286.yaml | 50 ++++++ + Documentation/hwmon/index.rst | 1 + + Documentation/hwmon/ltc4286.rst | 95 ++++++++++ + MAINTAINERS | 10 ++ + drivers/hwmon/pmbus/Kconfig | 10 ++ + drivers/hwmon/pmbus/Makefile | 1 + + drivers/hwmon/pmbus/ltc4286.c | 169 ++++++++++++++++++ + 7 files changed, 336 insertions(+) + create mode 100644 Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml + create mode 100644 Documentation/hwmon/ltc4286.rst + create mode 100644 drivers/hwmon/pmbus/ltc4286.c + +diff --git a/Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml b/Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml +new file mode 100644 +index 000000000000..98ca163d3486 +--- /dev/null ++++ b/Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml +@@ -0,0 +1,50 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/hwmon/lltc,ltc4286.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: LTC4286 power monitors ++ ++maintainers: ++ - Delphine CC Chiu ++ ++properties: ++ compatible: ++ enum: ++ - lltc,ltc4286 ++ - lltc,ltc4287 ++ ++ reg: ++ maxItems: 1 ++ ++ adi,vrange-low-enable: ++ description: ++ This property is a bool parameter to represent the ++ voltage range is 25.6 volts or 102.4 volts for this chip. ++ The default is 102.4 volts. ++ type: boolean ++ ++ shunt-resistor-micro-ohms: ++ description: ++ Resistor value micro-ohms. ++ ++required: ++ - compatible ++ - reg ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ power-monitor@40 { ++ compatible = "lltc,ltc4286"; ++ reg = <0x40>; ++ adi,vrange-low-enable; ++ shunt-resistor-micro-ohms = <300>; ++ }; ++ }; +diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst +index e45999f8e674..a637730ce8ed 100644 +--- a/Documentation/hwmon/index.rst ++++ b/Documentation/hwmon/index.rst +@@ -128,6 +128,7 @@ Hardware Monitoring Kernel Drivers + ltc4245 + ltc4260 + ltc4261 ++ ltc4286 + max127 + max15301 + max16064 +diff --git a/Documentation/hwmon/ltc4286.rst b/Documentation/hwmon/ltc4286.rst +new file mode 100644 +index 000000000000..2cd149676d86 +--- /dev/null ++++ b/Documentation/hwmon/ltc4286.rst +@@ -0,0 +1,95 @@ ++.. SPDX-License-Identifier: GPL-2.0-or-later ++ ++Kernel driver ltc4286 ++===================== ++ ++Supported chips: ++ ++ * Analog Devices LTC4286 ++ ++ Prefix: 'ltc4286' ++ ++ Addresses scanned: - ++ ++ Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ltc4286.pdf ++ ++ * Analog Devices LTC4287 ++ ++ Prefix: 'ltc4287' ++ ++ Addresses scanned: - ++ ++ Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ltc4287.pdf ++ ++Author: Delphine CC Chiu ++ ++ ++Description ++----------- ++ ++This driver supports hardware monitoring for Analog Devices LTC4286 ++and LTC4287 Hot-Swap Controller and Digital Power Monitors. ++ ++LTC4286 and LTC4287 are hot-swap controllers that allow a circuit board ++to be removed from or inserted into a live backplane. They also feature ++current and voltage readback via an integrated 12 bit analog-to-digital ++converter (ADC), accessed using a PMBus interface. ++ ++The driver is a client driver to the core PMBus driver. Please see ++Documentation/hwmon/pmbus.rst for details on PMBus client drivers. ++ ++ ++Usage Notes ++----------- ++ ++This driver does not auto-detect devices. You will have to instantiate the ++devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for ++details. ++ ++The shunt value in micro-ohms can be set via device tree at compile-time. Please ++refer to the Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml for bindings ++if the device tree is used. ++ ++ ++Platform data support ++--------------------- ++ ++The driver supports standard PMBus driver platform data. Please see ++Documentation/hwmon/pmbus.rst for details. ++ ++ ++Sysfs entries ++------------- ++ ++The following attributes are supported. Limits are read-write, history reset ++attributes are write-only, all other attributes are read-only. ++ ++======================= ======================================================= ++in1_label "vin" ++in1_input Measured voltage. ++in1_alarm Input voltage alarm. ++in1_min Minimum input voltage. ++in1_max Maximum input voltage. ++ ++in2_label "vout1" ++in2_input Measured voltage. ++in2_alarm Output voltage alarm. ++in2_min Minimum output voltage. ++in2_max Maximum output voltage. ++ ++curr1_label "iout1" ++curr1_input Measured current. ++curr1_alarm Output current alarm. ++curr1_max Maximum current. ++ ++power1_label "pin" ++power1_input Input power. ++power1_alarm Input power alarm. ++power1_max Maximum poewr. ++ ++temp1_input Chip temperature. ++temp1_min Minimum chip temperature. ++temp1_max Maximum chip temperature. ++temp1_crit Critical chip temperature. ++temp1_alarm Chip temperature alarm. ++======================= ======================================================= +diff --git a/MAINTAINERS b/MAINTAINERS +index 2955ed8af791..d5c141cb1b10 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -12497,6 +12497,16 @@ S: Maintained + F: Documentation/hwmon/ltc4261.rst + F: drivers/hwmon/ltc4261.c + ++LTC4286 HARDWARE MONITOR DRIVER ++M: Delphine CC Chiu ++L: linux-i2c@vger.kernel.org ++S: Maintained ++F: Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml ++F: Documentation/devicetree/bindings/hwmon/ltc4286.rst ++F: drivers/hwmon/pmbus/Kconfig ++F: drivers/hwmon/pmbus/Makefile ++F: drivers/hwmon/pmbus/ltc4286.c ++ + LTC4306 I2C MULTIPLEXER DRIVER + M: Michael Hennerich + L: linux-i2c@vger.kernel.org +diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig +index ad0e66e67bde..294808f5240a 100644 +--- a/drivers/hwmon/pmbus/Kconfig ++++ b/drivers/hwmon/pmbus/Kconfig +@@ -227,6 +227,16 @@ config SENSORS_LTC3815 + This driver can also be built as a module. If so, the module will + be called ltc3815. + ++config SENSORS_LTC4286 ++ bool "Analog Devices LTC4286" ++ help ++ LTC4286 is an integrated solution for hot swap applications that ++ allows a board to be safely inserted and removed from a live ++ backplane. ++ This chip could be used to monitor voltage, current, ...etc. ++ If you say yes here you get hardware monitoring support for Analog ++ Devices LTC4286. ++ + config SENSORS_MAX15301 + tristate "Maxim MAX15301" + help +diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile +index f53b51b250ff..cf8a76744545 100644 +--- a/drivers/hwmon/pmbus/Makefile ++++ b/drivers/hwmon/pmbus/Makefile +@@ -24,6 +24,7 @@ obj-$(CONFIG_SENSORS_LM25066) += lm25066.o + obj-$(CONFIG_SENSORS_LT7182S) += lt7182s.o + obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o + obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o ++obj-$(CONFIG_SENSORS_LTC4286) += ltc4286.o + obj-$(CONFIG_SENSORS_MAX15301) += max15301.o + obj-$(CONFIG_SENSORS_MAX16064) += max16064.o + obj-$(CONFIG_SENSORS_MAX16601) += max16601.o +diff --git a/drivers/hwmon/pmbus/ltc4286.c b/drivers/hwmon/pmbus/ltc4286.c +new file mode 100644 +index 000000000000..32cf3946388e +--- /dev/null ++++ b/drivers/hwmon/pmbus/ltc4286.c +@@ -0,0 +1,169 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pmbus.h" ++ ++/* LTC4286 register */ ++#define LTC4286_MFR_CONFIG1 0xF2 ++ ++/* LTC4286 configuration */ ++#define VRANGE_SELECT_BIT BIT(1) ++ ++#define LTC4286_MFR_ID_SIZE 3 ++#define VRANGE_25P6 0 ++ ++/* ++ * Initialize the MBR as default settings which is referred to LTC4286 datasheet ++ * (March 22, 2022 version) table 3 page 16 ++ */ ++static struct pmbus_driver_info ltc4286_info = { ++ .pages = 1, ++ .format[PSC_VOLTAGE_IN] = direct, ++ .format[PSC_VOLTAGE_OUT] = direct, ++ .format[PSC_CURRENT_OUT] = direct, ++ .format[PSC_POWER] = direct, ++ .format[PSC_TEMPERATURE] = direct, ++ .m[PSC_VOLTAGE_IN] = 32, ++ .b[PSC_VOLTAGE_IN] = 0, ++ .R[PSC_VOLTAGE_IN] = 1, ++ .m[PSC_VOLTAGE_OUT] = 32, ++ .b[PSC_VOLTAGE_OUT] = 0, ++ .R[PSC_VOLTAGE_OUT] = 1, ++ .m[PSC_CURRENT_OUT] = 1024, ++ .b[PSC_CURRENT_OUT] = 0, ++ /* ++ * The rsense value used in MBR formula in LTC4286 datasheet should be ohm unit. ++ * However, the rsense value that user input is micro ohm. ++ * Thus, the MBR setting which involves rsense should be shifted by 6 digits. ++ */ ++ .R[PSC_CURRENT_OUT] = 3 - 6, ++ .m[PSC_POWER] = 1, ++ .b[PSC_POWER] = 0, ++ /* ++ * The rsense value used in MBR formula in LTC4286 datasheet should be ohm unit. ++ * However, the rsense value that user input is micro ohm. ++ * Thus, the MBR setting which involves rsense should be shifted by 6 digits. ++ */ ++ .R[PSC_POWER] = 4 - 6, ++ .m[PSC_TEMPERATURE] = 1, ++ .b[PSC_TEMPERATURE] = 273, ++ .R[PSC_TEMPERATURE] = 0, ++ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | ++ PMBUS_HAVE_PIN | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_VOUT | ++ PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_TEMP, ++}; ++ ++static const struct i2c_device_id ltc4286_id[] = { ++ { "ltc4286", 0 }, ++ { "ltc4287", 1 }, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, ltc4286_id); ++ ++static int ltc4286_probe(struct i2c_client *client) ++{ ++ int ret; ++ const struct i2c_device_id *mid; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; ++ struct pmbus_driver_info *info; ++ u32 rsense; ++ ++ ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); ++ if (ret < 0) { ++ return dev_err_probe(&client->dev, ret, ++ "Failed to read manufacturer id\n"); ++ } ++ ++ /* ++ * Refer to ltc4286 datasheet page 20 ++ * the manufacturer id is LTC ++ */ ++ if (ret != LTC4286_MFR_ID_SIZE || ++ strncmp(block_buffer, "LTC", LTC4286_MFR_ID_SIZE)) { ++ return dev_err_probe(&client->dev, ret, ++ "Manufacturer id mismatch\n"); ++ } ++ ++ ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); ++ if (ret < 0) { ++ return dev_err_probe(&client->dev, ret, ++ "Failed to read manufacturer model\n"); ++ } ++ ++ for (mid = ltc4286_id; mid->name[0]; mid++) { ++ if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) ++ break; ++ } ++ if (!mid->name[0]) ++ return dev_err_probe(&client->dev, -ENODEV, ++ "Unsupported device\n"); ++ ++ if (of_property_read_u32(client->dev.of_node, ++ "shunt-resistor-micro-ohms", &rsense)) ++ rsense = 300; /* 0.3 mOhm if not set via DT */ ++ ++ if (rsense == 0) ++ return -EINVAL; ++ ++ /* Check for the latter MBR value won't overflow */ ++ if (rsense > (INT_MAX / 1024)) ++ return -EINVAL; ++ ++ info = devm_kmemdup(&client->dev, <c4286_info, sizeof(*info), ++ GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ /* Default of VRANGE_SELECT = 1, 102.4V */ ++ if (device_property_read_bool(&client->dev, "adi,vrange-low-enable")) { ++ /* Setup MFR1 CONFIG register bit 1 VRANGE_SELECT */ ++ ret = i2c_smbus_read_word_data(client, LTC4286_MFR_CONFIG1); ++ if (ret < 0) ++ return dev_err_probe( ++ &client->dev, ret, ++ "Failed to read manufacturer configuration one\n"); ++ ++ ret &= ~VRANGE_SELECT_BIT; /* VRANGE_SELECT = 0, 25.6V */ ++ ret = i2c_smbus_write_word_data(client, LTC4286_MFR_CONFIG1, ++ ret); ++ if (ret < 0) ++ return dev_err_probe(&client->dev, ret, ++ "Failed to set vrange\n"); ++ ++ info->m[PSC_VOLTAGE_IN] = 128; ++ info->m[PSC_VOLTAGE_OUT] = 128; ++ info->m[PSC_POWER] = 4 * rsense; ++ } else { ++ info->m[PSC_POWER] = rsense; ++ } ++ ++ info->m[PSC_CURRENT_OUT] = 1024 * rsense; ++ ++ return pmbus_do_probe(client, info); ++} ++ ++static const struct of_device_id ltc4286_of_match[] = { ++ { .compatible = "lltc,ltc4286" }, ++ { .compatible = "lltc,ltc4287" }, ++ {} ++}; ++ ++static struct i2c_driver ltc4286_driver = { ++ .driver = { ++ .name = "ltc4286", ++ .of_match_table = ltc4286_of_match, ++ }, ++ .probe = ltc4286_probe, ++ .id_table = ltc4286_id, ++}; ++ ++module_i2c_driver(ltc4286_driver); ++ ++MODULE_AUTHOR("Delphine CC Chiu "); ++MODULE_DESCRIPTION("PMBUS driver for LTC4286 and compatibles"); ++MODULE_LICENSE("GPL"); +-- +2.41.0 + diff --git a/common/recipes-kernel/linux/6.6/0303-Kernel6v5-Support-apml-driver.patch b/common/recipes-kernel/linux/6.6/0303-Kernel6v5-Support-apml-driver.patch new file mode 100644 index 000000000000..b7db7225cd53 --- /dev/null +++ b/common/recipes-kernel/linux/6.6/0303-Kernel6v5-Support-apml-driver.patch @@ -0,0 +1,2758 @@ +From 6d3d8333e412f2bc3393c55eea95b7cfeb342454 Mon Sep 17 00:00:00 2001 +From: Peter Yin +Date: Fri, 24 Nov 2023 15:54:07 +0800 +Subject: [PATCH 303/303] Kernel6v5: Support apml driver + +https://github.com/AMDESE/OpenBMC/blob/master/meta-amd/meta-common/recipes-kernel/linux/linux-aspeed/0057-apml_sbrmi-Add-support-to-identify-register-address-.patch + +Link:https://github.com/AMDESE/OpenBMC/blob/master/meta-amd/meta-common/recipes-kernel/linux/linux-aspeed/0056-apml_sbrmi-Add-New-member-sock_num-to-the-rmi-device.patch + +Link:https://github.com/AMDESE/OpenBMC/blob/master/meta-amd/meta-common/recipes-kernel/linux/linux-aspeed/0055-apml_sbrmi-Use-API-provided-by-linux-to-set-and-clea.patch + +Link:https://github.com/AMDESE/OpenBMC/blob/master/meta-amd/meta-common/recipes-kernel/linux/linux-aspeed/0039-apml_sbrmi-Wait-for-fops-to-complete-cleanly-on-devi.patch + +Link: https://github.com/AMDESE/OpenBMC/blob/master/meta-amd/meta-common/recipes-kernel/linux/linux-aspeed/0015-drivers-misc-Add-APML-SB-TSI-and-SB-RMI-drivers.patc +--- + drivers/hwmon/Kconfig | 22 + + drivers/hwmon/Makefile | 2 + + drivers/hwmon/sbrmi-i3c.c | 363 +++++++++++ + drivers/hwmon/sbtsi-i3c.c | 272 ++++++++ + drivers/misc/Kconfig | 1 + + drivers/misc/Makefile | 1 + + drivers/misc/amd-apml/Kconfig | 28 + + drivers/misc/amd-apml/Makefile | 9 + + drivers/misc/amd-apml/apml_sbtsi.c | 433 +++++++++++++ + drivers/misc/amd-apml/sbrmi-common.c | 490 +++++++++++++++ + drivers/misc/amd-apml/sbrmi-common.h | 38 ++ + drivers/misc/amd-apml/sbrmi.c | 885 +++++++++++++++++++++++++++ + include/uapi/linux/amd-apml.h | 74 +++ + 13 files changed, 2618 insertions(+) + create mode 100644 drivers/hwmon/sbrmi-i3c.c + create mode 100644 drivers/hwmon/sbtsi-i3c.c + create mode 100644 drivers/misc/amd-apml/Kconfig + create mode 100644 drivers/misc/amd-apml/Makefile + create mode 100644 drivers/misc/amd-apml/apml_sbtsi.c + create mode 100644 drivers/misc/amd-apml/sbrmi-common.c + create mode 100644 drivers/misc/amd-apml/sbrmi-common.h + create mode 100644 drivers/misc/amd-apml/sbrmi.c + create mode 100644 include/uapi/linux/amd-apml.h + +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 67f8f2e6633c..cdde5a2a4d90 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1745,6 +1745,28 @@ config SENSORS_SBRMI + This driver can also be built as a module. If so, the module will + be called sbrmi. + ++config SENSORS_SBRMI_I3C ++ tristate "Emulated SB-RMI sensor over I3C" ++ depends on I3C ++ select REGMAP_I3C ++ default n ++ help ++ If you say yes here you get support for emulated RMI ++ sensors on AMD SoCs with APML interface connected to a BMC device. ++ This driver can also be built as a module. If so, the module will ++ be called sbrmi_i3c. ++ ++config SENSORS_SBTSI_I3C ++ tristate "Emulated SB-TSI temperature sensor over I3C" ++ depends on I3C ++ select REGMAP_I3C ++ default n ++ help ++ If you say yes here you get support for emulated temperature ++ sensors on AMD SoCs with SB-TSI interface connected to a BMC device. ++ This driver can also be built as a module. If so, the module will ++ be called sbtsi_i3c. ++ + config SENSORS_SHT15 + tristate "Sensiron humidity and temperature sensors. SHT15 and compat." + depends on GPIOLIB || COMPILE_TEST +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index 6415bf756c10..774eba4960d6 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -182,6 +182,8 @@ obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o + obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o + obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o + obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o ++obj-$(CONFIG_SENSORS_SBTSI_I3C) += sbtsi-i3c.o ++obj-$(CONFIG_SENSORS_SBRMI_I3C) += sbrmi-i3c.o + obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o + obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o + obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o +diff --git a/drivers/hwmon/sbrmi-i3c.c b/drivers/hwmon/sbrmi-i3c.c +new file mode 100644 +index 000000000000..be2ef58803c8 +--- /dev/null ++++ b/drivers/hwmon/sbrmi-i3c.c +@@ -0,0 +1,363 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * sbrmi-i3c.c - hwmon driver for a SB-RMI mailbox ++ * compliant AMD SoC device. ++ * ++ * Copyright (C) 2020-2021 Advanced Micro Devices, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Do not allow setting negative power limit */ ++#define SBRMI_PWR_MIN 0 ++ ++/* Mask for Status Register bit[1] */ ++#define SW_ALERT_MASK 0x2 ++ ++/* Software Interrupt for triggering */ ++#define START_CMD 0x80 ++#define TRIGGER_MAILBOX 0x01 ++ ++/* ++ * SB-RMI supports soft mailbox service request to MP1 (power management ++ * firmware) through SBRMI inbound/outbound message registers. ++ * SB-RMI message IDs ++ */ ++enum sbrmi_msg_id { ++ SBRMI_READ_PKG_PWR_CONSUMPTION = 0x1, ++ SBRMI_WRITE_PKG_PWR_LIMIT, ++ SBRMI_READ_PKG_PWR_LIMIT, ++ SBRMI_READ_PKG_MAX_PWR_LIMIT, ++}; ++ ++/* SB-RMI registers */ ++enum sbrmi_reg { ++ SBRMI_CTRL = 0x01, ++ SBRMI_STATUS, ++ SBRMI_OUTBNDMSG0 = 0x30, ++ SBRMI_OUTBNDMSG1, ++ SBRMI_OUTBNDMSG2, ++ SBRMI_OUTBNDMSG3, ++ SBRMI_OUTBNDMSG4, ++ SBRMI_OUTBNDMSG5, ++ SBRMI_OUTBNDMSG6, ++ SBRMI_OUTBNDMSG7, ++ SBRMI_INBNDMSG0, ++ SBRMI_INBNDMSG1, ++ SBRMI_INBNDMSG2, ++ SBRMI_INBNDMSG3, ++ SBRMI_INBNDMSG4, ++ SBRMI_INBNDMSG5, ++ SBRMI_INBNDMSG6, ++ SBRMI_INBNDMSG7, ++ SBRMI_SW_INTERRUPT, ++}; ++ ++/* Each client has this additional data */ ++struct sbrmi_i3c_data { ++ struct regmap *regmap; ++ struct mutex lock; ++ u32 pwr_limit_max; ++}; ++ ++struct sbrmi_mailbox_msg { ++ u8 cmd; ++ bool read; ++ u32 data_in; ++ u32 data_out; ++}; ++ ++static int sbrmi_enable_alert(struct sbrmi_i3c_data *data) ++{ ++ int ctrl, ret; ++ ++ /* ++ * Enable the SB-RMI Software alert status ++ * by writing 0 to bit 4 of Control register(0x1) ++ */ ++ ret = regmap_read(data->regmap, SBRMI_CTRL, &ctrl); ++ if (ret) ++ return ret; ++ ++ if (ctrl & 0x10) { ++ ctrl &= ~0x10; ++ ret = regmap_write(data->regmap, SBRMI_CTRL, ctrl); ++ if (ret) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static int rmi_mailbox_xfer(struct sbrmi_i3c_data *data, ++ struct sbrmi_mailbox_msg *msg) ++{ ++ unsigned int bytes; ++ int i, ret, retry = 10; ++ int sw_status; ++ u8 byte; ++ ++ mutex_lock(&data->lock); ++ ++ /* Indicate firmware a command is to be serviced */ ++ ret = regmap_write(data->regmap, SBRMI_INBNDMSG7, START_CMD); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ /* Write the command to SBRMI::InBndMsg_inst0 */ ++ ret = regmap_write(data->regmap, SBRMI_INBNDMSG0, msg->cmd); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ /* ++ * For both read and write the initiator (BMC) writes ++ * Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1] ++ * SBRMI_x3C(MSB):SBRMI_x39(LSB) ++ */ ++ for (i = 0; i < 4; i++) { ++ byte = (msg->data_in >> i * 8) & 0xff; ++ ret = regmap_write(data->regmap, SBRMI_INBNDMSG1 + i, byte); ++ if (ret < 0) ++ goto exit_unlock; ++ } ++ ++ /* ++ * Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to ++ * perform the requested read or write command ++ */ ++ ret = regmap_write(data->regmap, SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ /* ++ * Firmware will write SBRMI::Status[SwAlertSts]=1 to generate ++ * an ALERT (if enabled) to initiator (BMC) to indicate completion ++ * of the requested command ++ */ ++ do { ++ ret = regmap_read(data->regmap, SBRMI_STATUS, &sw_status); ++ if (ret) ++ goto exit_unlock; ++ if (sw_status & SW_ALERT_MASK) ++ break; ++ usleep_range(50, 100); ++ } while (retry--); ++ ++ if (retry < 0) { ++ ret = -EIO; ++ goto exit_unlock; ++ } ++ ++ /* ++ * For a read operation, the initiator (BMC) reads the firmware ++ * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1] ++ * {SBRMI_x34(MSB):SBRMI_x31(LSB)}. ++ */ ++ if (msg->read) { ++ for (i = 0; i < 4; i++) { ++ ret = regmap_read(data->regmap, SBRMI_OUTBNDMSG1 + i, &bytes); ++ if (ret) ++ goto exit_unlock; ++ msg->data_out |= bytes << i * 8; ++ } ++ } ++ ++ /* ++ * BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the ++ * ALERT to initiator ++ */ ++ ret = regmap_write(data->regmap, SBRMI_STATUS, ++ sw_status | SW_ALERT_MASK); ++ ++exit_unlock: ++ mutex_unlock(&data->lock); ++ return ret; ++} ++ ++static int sbrmi_i3c_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct sbrmi_i3c_data *data = dev_get_drvdata(dev); ++ struct sbrmi_mailbox_msg msg = { 0 }; ++ int ret; ++ ++ if (type != hwmon_power) ++ return -EINVAL; ++ ++ msg.read = true; ++ switch (attr) { ++ case hwmon_power_input: ++ msg.cmd = SBRMI_READ_PKG_PWR_CONSUMPTION; ++ ret = rmi_mailbox_xfer(data, &msg); ++ break; ++ case hwmon_power_cap: ++ msg.cmd = SBRMI_READ_PKG_PWR_LIMIT; ++ ret = rmi_mailbox_xfer(data, &msg); ++ break; ++ case hwmon_power_cap_max: ++ msg.data_out = data->pwr_limit_max; ++ ret = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (ret < 0) ++ return ret; ++ /* hwmon power attributes are in microWatt */ ++ *val = (long)msg.data_out * 1000; ++ return ret; ++} ++ ++static int sbrmi_i3c_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ struct sbrmi_i3c_data *data = dev_get_drvdata(dev); ++ struct sbrmi_mailbox_msg msg = { 0 }; ++ ++ if (type != hwmon_power && attr != hwmon_power_cap) ++ return -EINVAL; ++ /* ++ * hwmon power attributes are in microWatt ++ * mailbox read/write is in mWatt ++ */ ++ val /= 1000; ++ ++ val = clamp_val(val, SBRMI_PWR_MIN, data->pwr_limit_max); ++ ++ msg.cmd = SBRMI_WRITE_PKG_PWR_LIMIT; ++ msg.data_in = val; ++ msg.read = false; ++ ++ return rmi_mailbox_xfer(data, &msg); ++} ++ ++static umode_t sbrmi_i3c_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ switch (type) { ++ case hwmon_power: ++ switch (attr) { ++ case hwmon_power_input: ++ case hwmon_power_cap_max: ++ return 0444; ++ case hwmon_power_cap: ++ return 0644; ++ } ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static const struct hwmon_channel_info *sbrmi_i3c_info[] = { ++ HWMON_CHANNEL_INFO(power, ++ HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX), ++ NULL ++}; ++ ++static const struct hwmon_ops sbrmi_i3c_hwmon_ops = { ++ .is_visible = sbrmi_i3c_is_visible, ++ .read = sbrmi_i3c_read, ++ .write = sbrmi_i3c_write, ++}; ++ ++static const struct hwmon_chip_info sbrmi_i3c_chip_info = { ++ .ops = &sbrmi_i3c_hwmon_ops, ++ .info = sbrmi_i3c_info, ++}; ++ ++static int sbrmi_get_max_pwr_limit(struct sbrmi_i3c_data *data) ++{ ++ struct sbrmi_mailbox_msg msg = { 0 }; ++ int ret; ++ ++ msg.cmd = SBRMI_READ_PKG_MAX_PWR_LIMIT; ++ msg.read = true; ++ ret = rmi_mailbox_xfer(data, &msg); ++ if (ret < 0) ++ return ret; ++ data->pwr_limit_max = msg.data_out; ++ ++ return ret; ++} ++ ++static int sbrmi_i3c_probe(struct i3c_device *i3cdev) ++{ ++ struct device *dev = &i3cdev->dev; ++ struct device *hwmon_dev; ++ struct sbrmi_i3c_data *data; ++ struct regmap_config sbrmi_i3c_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ }; ++ struct regmap *regmap; ++ int ret; ++ ++ regmap = devm_regmap_init_i3c(i3cdev, &sbrmi_i3c_regmap_config); ++ if (IS_ERR(regmap)) { ++ dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", ++ (int)PTR_ERR(regmap)); ++ return PTR_ERR(regmap); ++ } ++ data = devm_kzalloc(dev, sizeof(struct sbrmi_i3c_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->regmap = regmap; ++ mutex_init(&data->lock); ++ ++ dev_set_drvdata(dev, (void *)data); ++ ++ /* Enable alert for SB-RMI sequence */ ++ ret = sbrmi_enable_alert(data); ++ if (ret < 0) ++ return ret; ++ ++ /* Cache maximum power limit */ ++ ret = sbrmi_get_max_pwr_limit(data); ++ if (ret < 0) ++ return ret; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbrmi_i3c", data, ++ &sbrmi_i3c_chip_info, NULL); ++ ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++} ++ ++static int sbrmi_i3c_remove(struct i3c_device *i3cdev) ++{ ++ dev_info(&i3cdev->dev, "Removed sbrmi_i3c driver\n"); ++ return 0; ++} ++ ++static const struct i3c_device_id sbrmi_i3c_id[] = { ++ I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x2, NULL), ++ {} ++}; ++MODULE_DEVICE_TABLE(i3c, sbrmi_i3c_id); ++ ++static struct i3c_driver sbrmi_i3c_driver = { ++ .driver = { ++ .name = "sbrmi_i3c", ++ }, ++ .probe = sbrmi_i3c_probe, ++ .remove = sbrmi_i3c_remove, ++ .id_table = sbrmi_i3c_id, ++}; ++ ++module_i3c_driver(sbrmi_i3c_driver); ++ ++MODULE_AUTHOR("Akshay Gupta "); ++MODULE_DESCRIPTION("Hwmon driver for AMD SB-RMI emulated sensor"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hwmon/sbtsi-i3c.c b/drivers/hwmon/sbtsi-i3c.c +new file mode 100644 +index 000000000000..b7b499aa33ef +--- /dev/null ++++ b/drivers/hwmon/sbtsi-i3c.c +@@ -0,0 +1,272 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * sbtsi-i3c.c - hwmon driver for a SB-TSI mailbox ++ * compliant AMD SoC device. ++ * ++ * Copyright (C) 2021-2022 Advanced Micro Devices, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * SB-TSI registers only support SMBus byte data access. "_INT" registers are ++ * the integer part of a temperature value or limit, and "_DEC" registers are ++ * corresponding decimal parts. ++ */ ++#define SBTSI_REG_TEMP_INT 0x01 /* RO */ ++#define SBTSI_REG_STATUS 0x02 /* RO */ ++#define SBTSI_REG_CONFIG 0x03 /* RO */ ++#define SBTSI_REG_TEMP_HIGH_INT 0x07 /* RW */ ++#define SBTSI_REG_TEMP_LOW_INT 0x08 /* RW */ ++#define SBTSI_REG_TEMP_DEC 0x10 /* RW */ ++#define SBTSI_REG_TEMP_HIGH_DEC 0x13 /* RW */ ++#define SBTSI_REG_TEMP_LOW_DEC 0x14 /* RW */ ++ ++#define SBTSI_CONFIG_READ_ORDER_SHIFT 5 ++ ++#define SBTSI_TEMP_MIN 0 ++#define SBTSI_TEMP_MAX 255875 ++ ++/* ++ * SBTSI_STEP_INC Fractional portion of temperature ++ * One increment of these bits is equivalent to a step of 0.125 °C ++ * ++ * SBTSI_INT_OFFSET Integer offset for temperature value ++ * ++ * SBTSI_DEC_OFFSET offset for decimal bits in register[7:5] ++ * ++ * SBTSI_DEC_MASK Mask for decimal value ++ */ ++#define SBTSI_STEP_INC 125 ++#define SBTSI_INT_OFFSET 3 ++#define SBTSI_DEC_OFFSET 5 ++#define SBTSI_DEC_MASK 0x7 ++/* Each device has this additional data */ ++struct sbtsi_i3c_data { ++ struct regmap *regmap; ++ struct mutex lock; ++}; ++ ++/* ++ * From SB-TSI spec: CPU temperature readings and limit registers encode the ++ * temperature in increments of 0.125 from 0 to 255.875. The "high byte" ++ * register encodes the base-2 of the integer portion, and the upper 3 bits of ++ * the "low byte" encode in base-2 the decimal portion. ++ * ++ * e.g. INT=0x19, DEC=0x20 represents 25.125 degrees Celsius ++ * ++ * Therefore temperature in millidegree Celsius = ++ * (INT + DEC / 256) * 1000 = (INT * 8 + DEC / 32) * 125 ++ */ ++static inline int sbtsi_reg_to_mc(s32 integer, s32 decimal) ++{ ++ return ((integer << SBTSI_INT_OFFSET) + ++ (decimal >> SBTSI_DEC_OFFSET)) * SBTSI_STEP_INC; ++} ++ ++/* ++ * Inversely, given temperature in millidegree Celsius ++ * INT = (TEMP / 125) / 8 ++ * DEC = ((TEMP / 125) % 8) * 32 ++ * Caller have to make sure temp doesn't exceed 255875, the max valid value. ++ */ ++static inline void sbtsi_mc_to_reg(s32 temp, unsigned int *integer, unsigned int *decimal) ++{ ++ temp /= SBTSI_STEP_INC; ++ *integer = temp >> SBTSI_INT_OFFSET; ++ *decimal = (temp & SBTSI_DEC_MASK) << SBTSI_DEC_OFFSET; ++} ++ ++static int sbtsi_i3c_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct sbtsi_i3c_data *data = dev_get_drvdata(dev); ++ unsigned int temp_int, temp_dec, cfg; ++ int ret; ++ ++ switch (attr) { ++ case hwmon_temp_input: ++ /* ++ * ReadOrder bit specifies the reading order of integer and ++ * decimal part of CPU temp for atomic reads. If bit == 0, ++ * reading integer part triggers latching of the decimal part, ++ * so integer part should be read first. If bit == 1, read ++ * order should be reversed. ++ */ ++ ret = regmap_read(data->regmap, SBTSI_REG_CONFIG, &cfg); ++ if (ret < 0) ++ return ret; ++ ++ mutex_lock(&data->lock); ++ if (cfg & BIT(SBTSI_CONFIG_READ_ORDER_SHIFT)) { ++ ret = regmap_read(data->regmap, SBTSI_REG_TEMP_DEC, &temp_dec); ++ ret = regmap_read(data->regmap, SBTSI_REG_TEMP_INT, &temp_int); ++ } else { ++ ret = regmap_read(data->regmap, SBTSI_REG_TEMP_INT, &temp_int); ++ ret = regmap_read(data->regmap, SBTSI_REG_TEMP_DEC, &temp_dec); ++ } ++ mutex_unlock(&data->lock); ++ break; ++ case hwmon_temp_max: ++ mutex_lock(&data->lock); ++ ret = regmap_read(data->regmap, SBTSI_REG_TEMP_HIGH_INT, &temp_int); ++ ret = regmap_read(data->regmap, SBTSI_REG_TEMP_HIGH_DEC, &temp_dec); ++ mutex_unlock(&data->lock); ++ break; ++ case hwmon_temp_min: ++ mutex_lock(&data->lock); ++ ret = regmap_read(data->regmap, SBTSI_REG_TEMP_LOW_INT, &temp_int); ++ ret = regmap_read(data->regmap, SBTSI_REG_TEMP_LOW_DEC, &temp_dec); ++ mutex_unlock(&data->lock); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (ret < 0) ++ return ret; ++ ++ *val = sbtsi_reg_to_mc(temp_int, temp_dec); ++ ++ return 0; ++} ++ ++static int sbtsi_i3c_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ struct sbtsi_i3c_data *data = dev_get_drvdata(dev); ++ unsigned int temp_int, temp_dec; ++ int reg_int, reg_dec, err; ++ ++ switch (attr) { ++ case hwmon_temp_max: ++ reg_int = SBTSI_REG_TEMP_HIGH_INT; ++ reg_dec = SBTSI_REG_TEMP_HIGH_DEC; ++ break; ++ case hwmon_temp_min: ++ reg_int = SBTSI_REG_TEMP_LOW_INT; ++ reg_dec = SBTSI_REG_TEMP_LOW_DEC; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ val = clamp_val(val, SBTSI_TEMP_MIN, SBTSI_TEMP_MAX); ++ sbtsi_mc_to_reg(val, &temp_int, &temp_dec); ++ ++ mutex_lock(&data->lock); ++ err = regmap_write(data->regmap, reg_int, temp_int); ++ if (err) ++ goto exit; ++ ++ err = regmap_write(data->regmap, reg_dec, temp_dec); ++exit: ++ mutex_unlock(&data->lock); ++ return err; ++} ++ ++static umode_t sbtsi_i3c_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ switch (type) { ++ case hwmon_temp: ++ switch (attr) { ++ case hwmon_temp_input: ++ return 0444; ++ case hwmon_temp_min: ++ return 0644; ++ case hwmon_temp_max: ++ return 0644; ++ } ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static const struct hwmon_channel_info *sbtsi_i3c_info[] = { ++ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX), ++ NULL ++}; ++ ++static const struct hwmon_ops sbtsi_i3c_hwmon_ops = { ++ .is_visible = sbtsi_i3c_is_visible, ++ .read = sbtsi_i3c_read, ++ .write = sbtsi_i3c_write, ++}; ++ ++static const struct hwmon_chip_info sbtsi_i3c_chip_info = { ++ .ops = &sbtsi_i3c_hwmon_ops, ++ .info = sbtsi_i3c_info, ++}; ++ ++static int sbtsi_i3c_probe(struct i3c_device *i3cdev) ++{ ++ struct device *dev = &i3cdev->dev; ++ struct device *hwmon_dev; ++ struct sbtsi_i3c_data *data; ++ struct regmap_config sbtsi_i3c_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ }; ++ struct regmap *regmap; ++ ++ regmap = devm_regmap_init_i3c(i3cdev, &sbtsi_i3c_regmap_config); ++ if (IS_ERR(regmap)) { ++ dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", ++ (int)PTR_ERR(regmap)); ++ return PTR_ERR(regmap); ++ } ++ ++ data = devm_kzalloc(dev, sizeof(struct sbtsi_i3c_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->regmap = regmap; ++ mutex_init(&data->lock); ++ ++ dev_set_drvdata(dev, (void *)data); ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbtsi_i3c", data, ++ &sbtsi_i3c_chip_info, NULL); ++ ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++} ++ ++static int sbtsi_i3c_remove(struct i3c_device *i3cdev) ++{ ++ dev_info(&i3cdev->dev, "Removed sbtsi-i3c driver\n"); ++ return 0; ++} ++ ++static const struct i3c_device_id sbtsi_i3c_id[] = { ++ I3C_DEVICE_EXTRA_INFO(0x112, 0, 0x1, NULL), ++ {} ++}; ++MODULE_DEVICE_TABLE(i3c, sbtsi_i3c_id); ++ ++static struct i3c_driver sbtsi_i3c_driver = { ++ .driver = { ++ .name = "sbtsi_i3c", ++ }, ++ .probe = sbtsi_i3c_probe, ++ .remove = sbtsi_i3c_remove, ++ .id_table = sbtsi_i3c_id, ++}; ++ ++module_i3c_driver(sbtsi_i3c_driver); ++ ++MODULE_AUTHOR("Akshay Gupta "); ++MODULE_DESCRIPTION("Hwmon driver for AMD SB-TSI emulated sensor"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index cadd4a820c03..499d5baacdbc 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -562,6 +562,7 @@ config TPS6594_PFSM + This driver can also be built as a module. If so, the module + will be called tps6594-pfsm. + ++source "drivers/misc/amd-apml/Kconfig" + source "drivers/misc/c2port/Kconfig" + source "drivers/misc/eeprom/Kconfig" + source "drivers/misc/cb710/Kconfig" +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index f2a4d1ff65d4..5afe961975d5 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -3,6 +3,7 @@ + # Makefile for misc devices that really don't fit anywhere else. + # + ++obj-y += amd-apml/ + obj-$(CONFIG_IBM_ASM) += ibmasm/ + obj-$(CONFIG_IBMVMC) += ibmvmc.o + obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o +diff --git a/drivers/misc/amd-apml/Kconfig b/drivers/misc/amd-apml/Kconfig +new file mode 100644 +index 000000000000..bc9bd7ece0a8 +--- /dev/null ++++ b/drivers/misc/amd-apml/Kconfig +@@ -0,0 +1,28 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# AMD APML BMC interface drivers ++# ++ ++config APML_SBRMI ++ tristate "Emulated SB-RMI interface driver over i2c or i3c bus" ++ depends on I2C || I3C ++ select REGMAP_I3C if I3C ++ select REGMAP_I2C if I2C ++ help ++ If you say yes here you get support for emulated RMI ++ interface on AMD SoCs with APML interface connected to a BMC device. ++ ++ This driver can also be built as a module. If so, the module will ++ be called apml_sbrmi. ++ ++config APML_SBTSI ++ tristate "Emulated SB-TSI interface driver over i2c or i3c bus" ++ depends on I2C || I3C ++ select REGMAP_I3C if I3C ++ select REGMAP_I2C if I2C ++ help ++ If you say yes here you get support for emulated TSI ++ interface on AMD SoCs with APML interface connected to a BMC device. ++ ++ This driver can also be built as a module. If so, the module will ++ be called apml_sbtsi. +diff --git a/drivers/misc/amd-apml/Makefile b/drivers/misc/amd-apml/Makefile +new file mode 100644 +index 000000000000..a73ca261f08c +--- /dev/null ++++ b/drivers/misc/amd-apml/Makefile +@@ -0,0 +1,9 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for linux/drivers/platform/x86/amd-apml ++# AMD APML BMC interface drivers ++# ++ ++obj-$(CONFIG_APML_SBRMI) += apml_sbrmi.o ++apml_sbrmi-objs = sbrmi.o sbrmi-common.o ++obj-$(CONFIG_APML_SBTSI) += apml_sbtsi.o +diff --git a/drivers/misc/amd-apml/apml_sbtsi.c b/drivers/misc/amd-apml/apml_sbtsi.c +new file mode 100644 +index 000000000000..10bb9ae0ae7c +--- /dev/null ++++ b/drivers/misc/amd-apml/apml_sbtsi.c +@@ -0,0 +1,433 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * apml_sbtsi.c - hwmon driver for a SBI Temperature Sensor Interface (SB-TSI) ++ * compliant AMD SoC temperature device. ++ * Also register to misc driver with an IOCTL. ++ * ++ * Copyright (c) 2020, Google Inc. ++ * Copyright (c) 2020, Kun Yi ++ * Copyright (C) 2022 Advanced Micro Devices, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define SOCK_0_ADDR 0x4C ++#define SOCK_1_ADDR 0x48 ++/* ++ * SB-TSI registers only support SMBus byte data access. "_INT" registers are ++ * the integer part of a temperature value or limit, and "_DEC" registers are ++ * corresponding decimal parts. ++ */ ++#define SBTSI_REG_TEMP_INT 0x01 /* RO */ ++#define SBTSI_REG_STATUS 0x02 /* RO */ ++#define SBTSI_REG_CONFIG 0x03 /* RO */ ++#define SBTSI_REG_TEMP_HIGH_INT 0x07 /* RW */ ++#define SBTSI_REG_TEMP_LOW_INT 0x08 /* RW */ ++#define SBTSI_REG_TEMP_DEC 0x10 /* RW */ ++#define SBTSI_REG_TEMP_HIGH_DEC 0x13 /* RW */ ++#define SBTSI_REG_TEMP_LOW_DEC 0x14 /* RW */ ++ ++#define SBTSI_CONFIG_READ_ORDER_SHIFT 5 ++ ++#define SBTSI_TEMP_MIN 0 ++#define SBTSI_TEMP_MAX 255875 ++ ++/* ++ * SBTSI_STEP_INC Fractional portion of temperature ++ * One increment of these bits is equivalent to a step of 0.125 °C ++ * ++ * SBTSI_INT_OFFSET Integer offset for temperature value ++ * ++ * SBTSI_DEC_OFFSET offset for decimal bits in register[7:5] ++ * ++ * SBTSI_DEC_MASK Mask for decimal value ++ */ ++#define SBTSI_STEP_INC 125 ++#define SBTSI_INT_OFFSET 3 ++#define SBTSI_DEC_OFFSET 5 ++#define SBTSI_DEC_MASK 0x7 ++ ++struct apml_sbtsi_device { ++ struct miscdevice sbtsi_misc_dev; ++ struct regmap *regmap; ++ struct mutex lock; ++} __packed; ++ ++/* ++ * From SB-TSI spec: CPU temperature readings and limit registers encode the ++ * temperature in increments of 0.125 from 0 to 255.875. The "high byte" ++ * register encodes the base-2 of the integer portion, and the upper 3 bits of ++ * the "low byte" encode in base-2 the decimal portion. ++ * ++ * e.g. INT=0x19, DEC=0x20 represents 25.125 degrees Celsius ++ * ++ * Therefore temperature in millidegree Celsius = ++ * (INT + DEC / 256) * 1000 = (INT * 8 + DEC / 32) * 125 ++ */ ++static inline int sbtsi_reg_to_mc(s32 integer, s32 decimal) ++{ ++ return ((integer << SBTSI_INT_OFFSET) + ++ (decimal >> SBTSI_DEC_OFFSET)) * SBTSI_STEP_INC; ++} ++ ++/* ++ * Inversely, given temperature in millidegree Celsius ++ * INT = (TEMP / 125) / 8 ++ * DEC = ((TEMP / 125) % 8) * 32 ++ * Caller have to make sure temp doesn't exceed 255875, the max valid value. ++ */ ++static inline void sbtsi_mc_to_reg(s32 temp, u8 *integer, u8 *decimal) ++{ ++ temp /= SBTSI_STEP_INC; ++ *integer = temp >> SBTSI_INT_OFFSET; ++ *decimal = (temp & SBTSI_DEC_MASK) << SBTSI_DEC_OFFSET; ++} ++ ++static int sbtsi_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct apml_sbtsi_device *tsi_dev = dev_get_drvdata(dev); ++ unsigned int temp_int, temp_dec, cfg; ++ int ret; ++ ++ switch (attr) { ++ case hwmon_temp_input: ++ /* ++ * ReadOrder bit specifies the reading order of integer and ++ * decimal part of CPU temp for atomic reads. If bit == 0, ++ * reading integer part triggers latching of the decimal part, ++ * so integer part should be read first. If bit == 1, read ++ * order should be reversed. ++ */ ++ ret = regmap_read(tsi_dev->regmap, SBTSI_REG_CONFIG, &cfg); ++ if (ret < 0) ++ return ret; ++ ++ mutex_lock(&tsi_dev->lock); ++ if (cfg & BIT(SBTSI_CONFIG_READ_ORDER_SHIFT)) { ++ ret = regmap_read(tsi_dev->regmap, SBTSI_REG_TEMP_DEC, &temp_dec); ++ ret = regmap_read(tsi_dev->regmap, SBTSI_REG_TEMP_INT, &temp_int); ++ } else { ++ ret = regmap_read(tsi_dev->regmap, SBTSI_REG_TEMP_INT, &temp_int); ++ ret = regmap_read(tsi_dev->regmap, SBTSI_REG_TEMP_DEC, &temp_dec); ++ } ++ mutex_unlock(&tsi_dev->lock); ++ break; ++ case hwmon_temp_max: ++ mutex_lock(&tsi_dev->lock); ++ ret = regmap_read(tsi_dev->regmap, SBTSI_REG_TEMP_HIGH_INT, &temp_int); ++ ret = regmap_read(tsi_dev->regmap, SBTSI_REG_TEMP_HIGH_DEC, &temp_dec); ++ mutex_unlock(&tsi_dev->lock); ++ break; ++ case hwmon_temp_min: ++ mutex_lock(&tsi_dev->lock); ++ ret = regmap_read(tsi_dev->regmap, SBTSI_REG_TEMP_LOW_INT, &temp_int); ++ ret = regmap_read(tsi_dev->regmap, SBTSI_REG_TEMP_LOW_DEC, &temp_dec); ++ mutex_unlock(&tsi_dev->lock); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (ret < 0) ++ return ret; ++ ++ *val = sbtsi_reg_to_mc(temp_int, temp_dec); ++ ++ return 0; ++} ++ ++static int sbtsi_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ struct apml_sbtsi_device *tsi_dev = dev_get_drvdata(dev); ++ unsigned int temp_int, temp_dec; ++ int reg_int, reg_dec, err; ++ ++ switch (attr) { ++ case hwmon_temp_max: ++ reg_int = SBTSI_REG_TEMP_HIGH_INT; ++ reg_dec = SBTSI_REG_TEMP_HIGH_DEC; ++ break; ++ case hwmon_temp_min: ++ reg_int = SBTSI_REG_TEMP_LOW_INT; ++ reg_dec = SBTSI_REG_TEMP_LOW_DEC; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ val = clamp_val(val, SBTSI_TEMP_MIN, SBTSI_TEMP_MAX); ++ sbtsi_mc_to_reg(val, (u8 *)&temp_int, (u8 *)&temp_dec); ++ ++ mutex_lock(&tsi_dev->lock); ++ err = regmap_write(tsi_dev->regmap, reg_int, temp_int); ++ if (err) ++ goto exit; ++ ++ err = regmap_write(tsi_dev->regmap, reg_dec, temp_dec); ++exit: ++ mutex_unlock(&tsi_dev->lock); ++ return err; ++} ++ ++static umode_t sbtsi_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ switch (type) { ++ case hwmon_temp: ++ switch (attr) { ++ case hwmon_temp_input: ++ return 0444; ++ case hwmon_temp_min: ++ return 0644; ++ case hwmon_temp_max: ++ return 0644; ++ } ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static const struct hwmon_channel_info *sbtsi_info[] = { ++ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), ++ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX), ++ NULL ++}; ++ ++static const struct hwmon_ops sbtsi_hwmon_ops = { ++ .is_visible = sbtsi_is_visible, ++ .read = sbtsi_read, ++ .write = sbtsi_write, ++}; ++ ++static const struct hwmon_chip_info sbtsi_chip_info = { ++ .ops = &sbtsi_hwmon_ops, ++ .info = sbtsi_info, ++}; ++ ++static long sbtsi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++{ ++ int __user *arguser = (int __user *)arg; ++ struct apml_message msg = { 0 }; ++ struct apml_sbtsi_device *tsi_dev; ++ int ret; ++ ++ if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct apml_message))) ++ return -EFAULT; ++ ++ if (msg.cmd != APML_REG) ++ return -EINVAL; ++ ++ tsi_dev = container_of(fp->private_data, struct apml_sbtsi_device, sbtsi_misc_dev); ++ if (!tsi_dev) ++ return -EFAULT; ++ ++ mutex_lock(&tsi_dev->lock); ++ ++ if (!msg.data_in.reg_in[RD_FLAG_INDEX]) { ++ ret = regmap_write(tsi_dev->regmap, ++ msg.data_in.reg_in[REG_OFF_INDEX], ++ msg.data_in.reg_in[REG_VAL_INDEX]); ++ } else { ++ ret = regmap_read(tsi_dev->regmap, ++ msg.data_in.reg_in[REG_OFF_INDEX], ++ (int *)&msg.data_out.reg_out[RD_WR_DATA_INDEX]); ++ if (ret) ++ goto out; ++ ++ if (copy_to_user(arguser, &msg, sizeof(struct apml_message))) ++ ret = -EFAULT; ++ } ++out: ++ mutex_unlock(&tsi_dev->lock); ++ return ret; ++} ++ ++static const struct file_operations sbtsi_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = sbtsi_ioctl, ++ .compat_ioctl = sbtsi_ioctl, ++}; ++ ++static int create_misc_tsi_device(struct apml_sbtsi_device *tsi_dev, ++ struct device *dev, int id) ++{ ++ int ret; ++ ++ tsi_dev->sbtsi_misc_dev.name = devm_kasprintf(dev, GFP_KERNEL, "apml_tsi%d", id); ++ tsi_dev->sbtsi_misc_dev.minor = MISC_DYNAMIC_MINOR; ++ tsi_dev->sbtsi_misc_dev.fops = &sbtsi_fops; ++ tsi_dev->sbtsi_misc_dev.parent = dev; ++ tsi_dev->sbtsi_misc_dev.nodename = devm_kasprintf(dev, GFP_KERNEL, "sbtsi%d", id); ++ tsi_dev->sbtsi_misc_dev.mode = 0600; ++ ++ ret = misc_register(&tsi_dev->sbtsi_misc_dev); ++ if (ret) ++ return ret; ++ ++ dev_info(dev, "register %s device\n", tsi_dev->sbtsi_misc_dev.name); ++ return ret; ++} ++ ++static int sbtsi_i3c_probe(struct i3c_device *i3cdev) ++{ ++ struct device *dev = &i3cdev->dev; ++ struct device *hwmon_dev; ++ struct apml_sbtsi_device *tsi_dev; ++ struct regmap_config sbtsi_i3c_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ }; ++ struct regmap *regmap; ++ int id; ++ ++ regmap = devm_regmap_init_i3c(i3cdev, &sbtsi_i3c_regmap_config); ++ if (IS_ERR(regmap)) { ++ dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n", ++ (int)PTR_ERR(regmap)); ++ return PTR_ERR(regmap); ++ } ++ ++ tsi_dev = devm_kzalloc(dev, sizeof(struct apml_sbtsi_device), GFP_KERNEL); ++ if (!tsi_dev) ++ return -ENOMEM; ++ ++ tsi_dev->regmap = regmap; ++ mutex_init(&tsi_dev->lock); ++ ++ dev_set_drvdata(dev, (void *)tsi_dev); ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbtsi_i3c", tsi_dev, ++ &sbtsi_chip_info, NULL); ++ ++ if (!hwmon_dev) ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++ ++ if (i3cdev->desc->info.static_addr == SOCK_0_ADDR) ++ id = 0; ++ if (i3cdev->desc->info.static_addr == SOCK_1_ADDR) ++ id = 1; ++ ++ return create_misc_tsi_device(tsi_dev, dev, id); ++} ++ ++static int sbtsi_i2c_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct device *hwmon_dev; ++ struct apml_sbtsi_device *tsi_dev; ++ struct regmap_config sbtsi_i2c_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ }; ++ int id; ++ ++ tsi_dev = devm_kzalloc(dev, sizeof(struct apml_sbtsi_device), GFP_KERNEL); ++ if (!tsi_dev) ++ return -ENOMEM; ++ ++ mutex_init(&tsi_dev->lock); ++ tsi_dev->regmap = devm_regmap_init_i2c(client, &sbtsi_i2c_regmap_config); ++ if (IS_ERR(tsi_dev->regmap)) ++ return PTR_ERR(tsi_dev->regmap); ++ ++ dev_set_drvdata(dev, (void *)tsi_dev); ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ++ tsi_dev, ++ &sbtsi_chip_info, ++ NULL); ++ ++ if (!hwmon_dev) ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++ ++ if (client->addr == SOCK_0_ADDR) ++ id = 0; ++ if (client->addr == SOCK_1_ADDR) ++ id = 1; ++ ++ return create_misc_tsi_device(tsi_dev, dev, id); ++} ++ ++static void sbtsi_i3c_remove(struct i3c_device *i3cdev) ++{ ++ struct apml_sbtsi_device *tsi_dev = dev_get_drvdata(&i3cdev->dev); ++ ++ if (tsi_dev) ++ misc_deregister(&tsi_dev->sbtsi_misc_dev); ++ ++ dev_info(&i3cdev->dev, "Removed sbtsi-i3c driver\n"); ++} ++ ++static void sbtsi_i2c_remove(struct i2c_client *client) ++{ ++ struct apml_sbtsi_device *tsi_dev = dev_get_drvdata(&client->dev); ++ ++ if (tsi_dev) ++ misc_deregister(&tsi_dev->sbtsi_misc_dev); ++ ++ dev_info(&client->dev, "Removed sbtsi driver\n"); ++} ++ ++static const struct i3c_device_id sbtsi_i3c_id[] = { ++ I3C_DEVICE_EXTRA_INFO(0x112, 0, 0x1, NULL), ++ {} ++}; ++MODULE_DEVICE_TABLE(i3c, sbtsi_i3c_id); ++ ++static struct i3c_driver sbtsi_i3c_driver = { ++ .driver = { ++ .name = "sbtsi_i3c", ++ }, ++ .probe = sbtsi_i3c_probe, ++ .remove = sbtsi_i3c_remove, ++ .id_table = sbtsi_i3c_id, ++}; ++ ++static const struct i2c_device_id sbtsi_id[] = { ++ {"sbtsi", 0}, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, sbtsi_id); ++ ++static const struct of_device_id __maybe_unused sbtsi_of_match[] = { ++ { ++ .compatible = "amd,sbtsi", ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, sbtsi_of_match); ++ ++static struct i2c_driver sbtsi_driver = { ++ .class = I2C_CLASS_HWMON, ++ .driver = { ++ .name = "sbtsi", ++ .of_match_table = of_match_ptr(sbtsi_of_match), ++ }, ++ .probe = sbtsi_i2c_probe, ++ .remove = sbtsi_i2c_remove, ++ .id_table = sbtsi_id, ++}; ++ ++module_i3c_i2c_driver(sbtsi_i3c_driver, &sbtsi_driver) ++ ++MODULE_AUTHOR("Kun Yi "); ++MODULE_DESCRIPTION("Hwmon driver for AMD SB-TSI emulated sensor"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/misc/amd-apml/sbrmi-common.c b/drivers/misc/amd-apml/sbrmi-common.c +new file mode 100644 +index 000000000000..7527c186adb3 +--- /dev/null ++++ b/drivers/misc/amd-apml/sbrmi-common.c +@@ -0,0 +1,490 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * sbrmi-common.c - file defining SB-RMI protocols ++ * compliant AMD SoC device. ++ * ++ * Copyright (C) 2021-2022 Advanced Micro Devices, Inc. ++ */ ++#include ++#include ++#include ++#include ++ ++#include "sbrmi-common.h" ++ ++/* Mask for Status Register bit[1] */ ++#define SW_ALERT_MASK 0x2 ++/* Mask to check H/W Alert status bit */ ++#define HW_ALERT_MASK 0x80 ++ ++/* Software Interrupt for triggering */ ++#define START_CMD 0x80 ++#define TRIGGER_MAILBOX 0x01 ++ ++/* Default message lengths as per APML command protocol */ ++/* MSR */ ++#define MSR_RD_REG_LEN 0xa ++#define MSR_WR_REG_LEN 0x8 ++#define MSR_WR_REG_LEN_v21 0x9 ++#define MSR_RD_DATA_LEN 0x8 ++#define MSR_WR_DATA_LEN 0x7 ++#define MSR_WR_DATA_LEN_v21 0x8 ++/* CPUID */ ++#define CPUID_RD_DATA_LEN 0x8 ++#define CPUID_WR_DATA_LEN 0x8 ++#define CPUID_WR_DATA_LEN_v21 0x9 ++#define CPUID_RD_REG_LEN 0xa ++#define CPUID_WR_REG_LEN 0x9 ++#define CPUID_WR_REG_LEN_v21 0xa ++ ++/* CPUID MSR Command Ids */ ++#define CPUID_MCA_CMD 0x73 ++#define RD_CPUID_CMD 0x91 ++#define RD_MCA_CMD 0x86 ++ ++/* SB-RMI registers */ ++enum sbrmi_reg { ++ SBRMI_REV = 0x0, ++ SBRMI_CTRL = 0x01, ++ SBRMI_STATUS, ++ SBRMI_OUTBNDMSG0 = 0x30, ++ SBRMI_OUTBNDMSG1, ++ SBRMI_OUTBNDMSG2, ++ SBRMI_OUTBNDMSG3, ++ SBRMI_OUTBNDMSG4, ++ SBRMI_OUTBNDMSG5, ++ SBRMI_OUTBNDMSG6, ++ SBRMI_OUTBNDMSG7, ++ SBRMI_INBNDMSG0, ++ SBRMI_INBNDMSG1, ++ SBRMI_INBNDMSG2, ++ SBRMI_INBNDMSG3, ++ SBRMI_INBNDMSG4, ++ SBRMI_INBNDMSG5, ++ SBRMI_INBNDMSG6, ++ SBRMI_INBNDMSG7, ++ SBRMI_SW_INTERRUPT, ++ SBRMI_THREAD128CS = 0x4b, ++}; ++ ++/* input for bulk write to v21 of CPUID and MSR protocol */ ++struct cpu_msr_indata_v21 { ++ u8 wr_len; /* const value */ ++ u8 rd_len; /* const value */ ++ u8 proto_cmd; /* const value */ ++ u16 thread; /* thread number */ ++ union { ++ u8 reg_offset[4]; /* input value */ ++ u32 value; ++ }; ++ u8 ext; /* extended function */ ++} __packed; ++ ++/* input for bulk write to v20 of CPUID and MSR protocol */ ++struct cpu_msr_indata { ++ u8 wr_len; /* const value */ ++ u8 rd_len; /* const value */ ++ u8 proto_cmd; /* const value */ ++ u8 thread; /* thread number */ ++ union { ++ u8 reg_offset[4]; /* input value */ ++ u32 value; ++ }; ++ u8 ext; /* extended function */ ++} __packed; ++ ++/* output for bulk read from CPUID and MSR protocol */ ++struct cpu_msr_outdata { ++ u8 num_bytes; /* number of bytes return */ ++ u8 status; /* Protocol status code */ ++ union { ++ u64 value; ++ u8 reg_data[8]; ++ }; ++} __packed; ++ ++#define prepare_mca_msr_input_message(input, thread_id, data_in, wr_data_len) \ ++ input.rd_len = MSR_RD_DATA_LEN, \ ++ input.wr_len = wr_data_len, \ ++ input.proto_cmd = RD_MCA_CMD, \ ++ input.thread = thread_id << 1, \ ++ input.value = data_in ++ ++#define prepare_cpuid_input_message(input, thread_id, func, ext_func, wr_data_len) \ ++ input.rd_len = CPUID_RD_DATA_LEN, \ ++ input.wr_len = wr_data_len, \ ++ input.proto_cmd = RD_CPUID_CMD, \ ++ input.thread = thread_id << 1, \ ++ input.value = func, \ ++ input.ext = ext_func ++ ++static int sbrmi_get_rev(struct apml_sbrmi_device *rmi_dev) ++{ ++ struct apml_message msg = { 0 }; ++ int ret; ++ ++ msg.data_in.reg_in[REG_OFF_INDEX] = SBRMI_REV; ++ msg.data_in.reg_in[RD_FLAG_INDEX] = 1; ++ ret = regmap_read(rmi_dev->regmap, ++ msg.data_in.reg_in[REG_OFF_INDEX], ++ &msg.data_out.mb_out[RD_WR_DATA_INDEX]); ++ if (ret < 0) ++ return ret; ++ ++ rmi_dev->rev = msg.data_out.reg_out[RD_WR_DATA_INDEX]; ++ return 0; ++} ++ ++/* ++ * For Mailbox command software alert status bit is set by firmware ++ * to indicate command completion ++ * For RMI Rev 0x20, new h/w status bit is introduced. which is used ++ * by firmware to indicate completion of commands (0x71, 0x72, 0x73). ++ * wait for the status bit to be set by the firmware before ++ * reading the data out. ++ */ ++static int sbrmi_wait_status(struct apml_sbrmi_device *rmi_dev, ++ int *status, int mask) ++{ ++ int ret, retry = 100; ++ ++ do { ++ ret = regmap_read(rmi_dev->regmap, SBRMI_STATUS, status); ++ if (ret < 0) ++ return ret; ++ ++ if (*status & mask) ++ break; ++ ++ /* Wait 1~2 second for firmware to return data out */ ++ if (retry > 95) ++ usleep_range(50, 100); ++ else ++ usleep_range(10000, 20000); ++ } while (retry--); ++ ++ if (retry < 0) ++ ret = -ETIMEDOUT; ++ return ret; ++} ++ ++static int msr_datain_v20(struct apml_sbrmi_device *rmi_dev, ++ struct apml_message *msg) ++{ ++ struct cpu_msr_indata input = {0}; ++ int ret, val = 0; ++ u16 thread; ++ ++ thread = msg->data_in.reg_in[THREAD_LOW_INDEX] | ++ msg->data_in.reg_in[THREAD_HI_INDEX] << 8; ++ ++ /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */ ++ if (thread > 127) { ++ thread -= 128; ++ val = 1; ++ } ++ ret = regmap_write(rmi_dev->regmap, SBRMI_THREAD128CS, val); ++ if (ret < 0) ++ return ret; ++ ++ prepare_mca_msr_input_message(input, thread, ++ msg->data_in.mb_in[RD_WR_DATA_INDEX], ++ MSR_WR_DATA_LEN); ++ ++ ret = regmap_bulk_write(rmi_dev->regmap, CPUID_MCA_CMD, ++ &input, MSR_WR_REG_LEN); ++ return ret; ++} ++ ++static int msr_datain_v21(struct apml_sbrmi_device *rmi_dev, ++ struct apml_message *msg) ++{ ++ struct cpu_msr_indata_v21 input = {0}; ++ int ret; ++ u16 thread; ++ ++ thread = msg->data_in.reg_in[THREAD_LOW_INDEX] | ++ msg->data_in.reg_in[THREAD_HI_INDEX] << 8; ++ ++ prepare_mca_msr_input_message(input, thread, ++ msg->data_in.mb_in[RD_WR_DATA_INDEX], ++ MSR_WR_DATA_LEN_v21); ++ ++ ret = regmap_bulk_write(rmi_dev->regmap, CPUID_MCA_CMD, ++ &input, MSR_WR_REG_LEN_v21); ++ return ret; ++} ++ ++/* MCA MSR protocol */ ++int rmi_mca_msr_read(struct apml_sbrmi_device *rmi_dev, ++ struct apml_message *msg) ++{ ++ struct cpu_msr_outdata output = {0}; ++ int ret; ++ int hw_status; ++ ++ /* cache the rev value to identify if protocol is supported or not */ ++ if (!rmi_dev->rev) { ++ ret = sbrmi_get_rev(rmi_dev); ++ if (ret < 0) ++ return ret; ++ } ++ ++ switch(rmi_dev->rev) { ++ /* MCA MSR protocol for REV 0x10 is not supported*/ ++ case 0x10: ++ return -EOPNOTSUPP; ++ case 0x20: ++ ret = msr_datain_v20(rmi_dev, msg); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ break; ++ case 0x21: ++ ret = msr_datain_v21(rmi_dev, msg); ++ if (ret < 0) ++ goto exit_unlock; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ ret = sbrmi_wait_status(rmi_dev, &hw_status, HW_ALERT_MASK); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ ret = regmap_bulk_read(rmi_dev->regmap, CPUID_MCA_CMD, ++ &output, MSR_RD_REG_LEN); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ ret = regmap_write(rmi_dev->regmap, SBRMI_STATUS, ++ hw_status | HW_ALERT_MASK); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ if (output.num_bytes != MSR_RD_REG_LEN - 1) { ++ ret = -EMSGSIZE; ++ goto exit_unlock; ++ } ++ if (output.status) { ++ ret = -EPROTOTYPE; ++ msg->fw_ret_code = output.status; ++ goto exit_unlock; ++ } ++ msg->data_out.cpu_msr_out = output.value; ++ ++exit_unlock: ++ return ret; ++} ++ ++/* CPUID protocol */ ++static int cpuid_datain_v20(struct apml_sbrmi_device *rmi_dev, ++ struct apml_message *msg) ++{ ++ struct cpu_msr_indata input = {0}; ++ int ret, val = 0; ++ u16 thread; ++ ++ thread = msg->data_in.reg_in[THREAD_LOW_INDEX] | ++ msg->data_in.reg_in[THREAD_HI_INDEX] << 8; ++ ++ /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */ ++ if (thread > 127) { ++ thread -= 128; ++ val = 1; ++ } ++ ret = regmap_write(rmi_dev->regmap, SBRMI_THREAD128CS, val); ++ if (ret < 0) ++ return ret; ++ prepare_cpuid_input_message(input, thread, ++ msg->data_in.mb_in[RD_WR_DATA_INDEX], ++ msg->data_in.reg_in[EXT_FUNC_INDEX], ++ CPUID_WR_DATA_LEN); ++ ++ ret = regmap_bulk_write(rmi_dev->regmap, CPUID_MCA_CMD, ++ &input, CPUID_WR_REG_LEN); ++ return ret; ++} ++ ++static int cpuid_datain_v21(struct apml_sbrmi_device *rmi_dev, ++ struct apml_message *msg) ++{ ++ struct cpu_msr_indata_v21 input = {0}; ++ int ret; ++ u16 thread; ++ ++ thread = msg->data_in.reg_in[THREAD_LOW_INDEX] | ++ msg->data_in.reg_in[THREAD_HI_INDEX] << 8; ++ ++ prepare_cpuid_input_message(input, thread, ++ msg->data_in.mb_in[RD_WR_DATA_INDEX], ++ msg->data_in.reg_in[EXT_FUNC_INDEX], ++ CPUID_WR_DATA_LEN_v21); ++ ++ ret = regmap_bulk_write(rmi_dev->regmap, CPUID_MCA_CMD, ++ &input, CPUID_WR_REG_LEN_v21); ++ return ret; ++} ++ ++/* CPUID protocol */ ++int rmi_cpuid_read(struct apml_sbrmi_device *rmi_dev, ++ struct apml_message *msg) ++{ ++ struct cpu_msr_outdata output = {0}; ++ int ret, hw_status; ++ ++ /* cache the rev value to identify if protocol is supported or not */ ++ if (!rmi_dev->rev) { ++ ret = sbrmi_get_rev(rmi_dev); ++ if (ret < 0) ++ return ret; ++ } ++ ++ switch(rmi_dev->rev) { ++ /* CPUID protocol for REV 0x10 is not supported*/ ++ case 0x10: ++ return -EOPNOTSUPP; ++ case 0x20: ++ ret = cpuid_datain_v20(rmi_dev, msg); ++ if (ret < 0) ++ goto exit_unlock; ++ break; ++ case 0x21: ++ ret = cpuid_datain_v21(rmi_dev, msg); ++ if (ret < 0) ++ goto exit_unlock; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ ret = sbrmi_wait_status(rmi_dev, &hw_status, HW_ALERT_MASK); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ ret = regmap_bulk_read(rmi_dev->regmap, CPUID_MCA_CMD, ++ &output, CPUID_RD_REG_LEN); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ ret = regmap_write(rmi_dev->regmap, SBRMI_STATUS, ++ hw_status | HW_ALERT_MASK); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ if (output.num_bytes != CPUID_RD_REG_LEN - 1) { ++ ret = -EMSGSIZE; ++ goto exit_unlock; ++ } ++ if (output.status) { ++ ret = -EPROTOTYPE; ++ msg->fw_ret_code = output.status; ++ goto exit_unlock; ++ } ++ msg->data_out.cpu_msr_out = output.value; ++exit_unlock: ++ return ret; ++} ++ ++static int esmi_oob_clear_status_alert(struct apml_sbrmi_device *rmi_dev) ++{ ++ int sw_status, ret; ++ ++ ret = regmap_read(rmi_dev->regmap, SBRMI_STATUS, ++ &sw_status); ++ if (ret < 0) ++ return ret; ++ ++ if (!(sw_status & SW_ALERT_MASK)) ++ return 0; ++ ++ return regmap_write(rmi_dev->regmap, SBRMI_STATUS, ++ sw_status | SW_ALERT_MASK); ++} ++ ++int rmi_mailbox_xfer(struct apml_sbrmi_device *rmi_dev, ++ struct apml_message *msg) ++{ ++ unsigned int bytes = 0, ec = 0; ++ int i, ret; ++ int sw_status; ++ u8 byte = 0; ++ ++ msg->fw_ret_code = 0; ++ ++ ret = esmi_oob_clear_status_alert(rmi_dev); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ /* Indicate firmware a command is to be serviced */ ++ ret = regmap_write(rmi_dev->regmap, SBRMI_INBNDMSG7, START_CMD); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ /* Write the command to SBRMI::InBndMsg_inst0 */ ++ ret = regmap_write(rmi_dev->regmap, SBRMI_INBNDMSG0, msg->cmd); ++ if (ret < 0) ++ goto exit_unlock; ++ ++ /* ++ * For both read and write the initiator (BMC) writes ++ * Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1] ++ * SBRMI_x3C(MSB):SBRMI_x39(LSB) ++ */ ++ for (i = 0; i < MB_DATA_SIZE; i++) { ++ byte = msg->data_in.reg_in[i]; ++ ret = regmap_write(rmi_dev->regmap, SBRMI_INBNDMSG1 + i, byte); ++ if (ret < 0) ++ goto exit_unlock; ++ } ++ ++ /* ++ * Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to ++ * perform the requested read or write command ++ */ ++ ret = regmap_write(rmi_dev->regmap, SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX); ++ if (ret) ++ goto exit_unlock; ++ ++ /* ++ * Firmware will write SBRMI::Status[SwAlertSts]=1 to generate ++ * an ALERT (if enabled) to initiator (BMC) to indicate completion ++ * of the requested command ++ */ ++ ret = sbrmi_wait_status(rmi_dev, &sw_status, SW_ALERT_MASK); ++ if (ret) ++ goto exit_unlock; ++ ++ ret = regmap_read(rmi_dev->regmap, SBRMI_OUTBNDMSG7, &ec); ++ if (ret || ec) ++ goto exit_clear_alert; ++ ++ /* ++ * For a read operation, the initiator (BMC) reads the firmware ++ * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1] ++ * {SBRMI_x34(MSB):SBRMI_x31(LSB)}. ++ */ ++ if (msg->data_in.reg_in[RD_FLAG_INDEX]) { ++ for (i = 0; i < MB_DATA_SIZE; i++) { ++ ret = regmap_read(rmi_dev->regmap, ++ SBRMI_OUTBNDMSG1 + i, &bytes); ++ if (ret < 0) ++ break; ++ msg->data_out.reg_out[i] = bytes; ++ } ++ } ++exit_clear_alert: ++ /* ++ * BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the ++ * ALERT to initiator ++ */ ++ ret = regmap_write(rmi_dev->regmap, SBRMI_STATUS, ++ sw_status | SW_ALERT_MASK); ++ if (ec) { ++ ret = -EPROTOTYPE; ++ msg->fw_ret_code = ec; ++ } ++exit_unlock: ++ return ret; ++} +diff --git a/drivers/misc/amd-apml/sbrmi-common.h b/drivers/misc/amd-apml/sbrmi-common.h +new file mode 100644 +index 000000000000..6f1aea480509 +--- /dev/null ++++ b/drivers/misc/amd-apml/sbrmi-common.h +@@ -0,0 +1,38 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (C) 2021-2022 Advanced Micro Devices, Inc. ++ */ ++ ++#ifndef _AMD_APML_SBRMI_H_ ++#define _AMD_APML_SBRMI_H_ ++ ++#include ++#include ++ ++/* Each client has this additional data */ ++/* in_progress: Variable is set if any transaction is in ++ * progress in IOCTL ++ * no_new_trans: Variable is set if rmmmod/unbind is called ++ */ ++struct apml_sbrmi_device { ++ struct miscdevice sbrmi_misc_dev; ++ struct completion misc_fops_done; ++ struct i3c_device *i3cdev; ++ struct i2c_client *client; ++ struct regmap *regmap; ++ struct mutex lock; ++ u32 *dimm_id; ++ u32 pwr_limit_max; ++ atomic_t in_progress; ++ atomic_t no_new_trans; ++ u8 rev; ++ u8 sock_num; ++} __packed; ++ ++int rmi_mca_msr_read(struct apml_sbrmi_device *rmi_dev, ++ struct apml_message *msg); ++int rmi_cpuid_read(struct apml_sbrmi_device *rmi_dev, ++ struct apml_message *msg); ++int rmi_mailbox_xfer(struct apml_sbrmi_device *rmi_dev, ++ struct apml_message *msg); ++#endif /*_AMD_APML_SBRMI_H_*/ +diff --git a/drivers/misc/amd-apml/sbrmi.c b/drivers/misc/amd-apml/sbrmi.c +new file mode 100644 +index 000000000000..3ea6a63d1ba0 +--- /dev/null ++++ b/drivers/misc/amd-apml/sbrmi.c +@@ -0,0 +1,885 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * sbrmi.c - hwmon driver for a SB-RMI mailbox ++ * compliant AMD SoC device. ++ * ++ * Copyright (C) 2021-2022 Advanced Micro Devices, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sbrmi-common.h" ++ ++#define SOCK_0_ADDR 0x3C ++#define SOCK_1_ADDR 0x38 ++ ++/* Do not allow setting negative power limit */ ++#define SBRMI_PWR_MIN 0 ++ ++/* SBRMI REVISION REG */ ++#define SBRMI_REV 0x0 ++#define SBRMI_REV_BRTH (0x21) ++ ++#define DIMM_BASE_ID (0x80) ++#define MAX_DIMM_COUNT (12) ++#define DIMM_POWER_OFFSET (17) ++#define DIMM_TEMP_OFFSET (21) ++#define DIMM_TEMP_SCALE 1/4 ++#define MAX_WAIT_TIME_SEC (3) ++ ++/* SBRMI registers data out is 1 byte */ ++#define SBRMI_REG_DATA_SIZE 0x1 ++/* Default SBRMI register address is 1 byte */ ++#define SBRMI_REG_ADDR_SIZE_DEF 0x1 ++/* TURIN SBRMI register address is 2 byte */ ++#define SBRMI_REG_ADDR_SIZE_TWO_BYTE 0x2 ++ ++/* Two xfers, one write and one read require to read the data */ ++#define I3C_I2C_MSG_XFER_SIZE 0x2 ++ ++static int configure_regmap(struct apml_sbrmi_device *rmi_dev); ++ ++enum sbrmi_msg_id { ++ SBRMI_READ_PKG_PWR_CONSUMPTION = 0x1, ++ SBRMI_WRITE_PKG_PWR_LIMIT, ++ SBRMI_READ_PKG_PWR_LIMIT, ++ SBRMI_READ_PKG_MAX_PWR_LIMIT, ++ SBRMI_READ_DIMM_POWER_CONSUMPTION = 0x47, ++ SBRMI_READ_DIMM_THERMAL_SENSOR = 0x48, ++}; ++ ++static int sbrmi_get_max_pwr_limit(struct apml_sbrmi_device *rmi_dev) ++{ ++ struct apml_message msg = { 0 }; ++ int ret; ++ ++ msg.cmd = SBRMI_READ_PKG_MAX_PWR_LIMIT; ++ msg.data_in.reg_in[RD_FLAG_INDEX] = 1; ++ ret = rmi_mailbox_xfer(rmi_dev, &msg); ++ if (ret < 0) ++ return ret; ++ rmi_dev->pwr_limit_max = msg.data_out.mb_out[RD_WR_DATA_INDEX]; ++ ++ return ret; ++} ++ ++static int sbrmi_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct apml_sbrmi_device *rmi_dev = dev_get_drvdata(dev); ++ struct apml_message msg = { 0 }; ++ int ret; ++ ++ if (type != hwmon_power && type != hwmon_temp) ++ return -EINVAL; ++ ++ if (!rmi_dev->regmap) { ++ ret = configure_regmap(rmi_dev); ++ if (ret < 0) { ++ pr_err("regmap configuration failed with return value:%d in sbrmi_read\n", ret); ++ return ret; ++ } ++ } ++ ++ mutex_lock(&rmi_dev->lock); ++ msg.data_in.reg_in[RD_FLAG_INDEX] = 1; ++ ++ switch (attr) { ++ case hwmon_power_input: ++ if (channel > 0) { ++ msg.cmd = SBRMI_READ_DIMM_POWER_CONSUMPTION; ++ msg.data_in.mb_in[RD_WR_DATA_INDEX] = rmi_dev->dimm_id[channel-1]; ++ } else { ++ msg.cmd = SBRMI_READ_PKG_PWR_CONSUMPTION; ++ } ++ ret = rmi_mailbox_xfer(rmi_dev, &msg); ++ break; ++ case hwmon_power_cap: ++ msg.cmd = SBRMI_READ_PKG_PWR_LIMIT; ++ ret = rmi_mailbox_xfer(rmi_dev, &msg); ++ break; ++ case hwmon_temp_input: ++ msg.cmd = SBRMI_READ_DIMM_THERMAL_SENSOR; ++ msg.data_in.mb_in[RD_WR_DATA_INDEX] = rmi_dev->dimm_id[channel]; ++ ret = rmi_mailbox_xfer(rmi_dev, &msg); ++ break; ++ case hwmon_power_cap_max: ++ /* Cache maximum power limit */ ++ if (!rmi_dev->pwr_limit_max) { ++ ret = sbrmi_get_max_pwr_limit(rmi_dev); ++ if (ret < 0) ++ goto out; ++ } ++ msg.data_out.mb_out[RD_WR_DATA_INDEX] = rmi_dev->pwr_limit_max; ++ ret = 0; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ if (ret < 0) ++ goto out; ++ ++ if (type == hwmon_power) { ++ /* hwmon power attributes are in microWatt */ ++ if (channel > 0) { ++ *val = (msg.data_out.mb_out[RD_WR_DATA_INDEX] >> DIMM_POWER_OFFSET) * 1000; ++ } else { ++ *val = (long)msg.data_out.mb_out[RD_WR_DATA_INDEX] * 1000; ++ } ++ } else if (type == hwmon_temp) { ++ /* sbrmi temp is floating point, convert to deg C rational num */ ++ *val = (msg.data_out.mb_out[RD_WR_DATA_INDEX] >> DIMM_TEMP_OFFSET) * 1000 * DIMM_TEMP_SCALE; ++ } ++out: ++ mutex_unlock(&rmi_dev->lock); ++ return ret; ++} ++ ++static int sbrmi_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ struct apml_sbrmi_device *rmi_dev = dev_get_drvdata(dev); ++ struct apml_message msg = { 0 }; ++ int ret; ++ ++ if (type != hwmon_power && attr != hwmon_power_cap) ++ return -EINVAL; ++ ++ if (!rmi_dev->regmap) { ++ ret = configure_regmap(rmi_dev); ++ if (ret < 0) { ++ pr_err("regmap configuration failed with return value:%d in sbrmi_write\n", ret); ++ return ret; ++ } ++ } ++ ++ /* ++ * hwmon power attributes are in microWatt ++ * mailbox read/write is in mWatt ++ */ ++ val /= 1000; ++ ++ val = clamp_val(val, SBRMI_PWR_MIN, rmi_dev->pwr_limit_max); ++ ++ msg.cmd = SBRMI_WRITE_PKG_PWR_LIMIT; ++ msg.data_in.mb_in[RD_WR_DATA_INDEX] = val; ++ msg.data_in.reg_in[RD_FLAG_INDEX] = 0; ++ ++ mutex_lock(&rmi_dev->lock); ++ ret = rmi_mailbox_xfer(rmi_dev, &msg); ++ mutex_unlock(&rmi_dev->lock); ++ return ret; ++} ++ ++static umode_t sbrmi_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ switch (type) { ++ case hwmon_power: ++ switch (attr) { ++ case hwmon_power_input: ++ case hwmon_power_cap_max: ++ return 0444; ++ case hwmon_power_cap: ++ return 0644; ++ } ++ break; ++ case hwmon_temp: ++ switch (attr) { ++ case hwmon_temp_input: ++ return 0444; ++ } ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static struct hwmon_channel_info sbrmi_power_info = { ++ hwmon_power, ++ NULL ++}; ++ ++static struct hwmon_channel_info sbrmi_temp_info = { ++ hwmon_temp, ++ NULL ++}; ++ ++static const struct hwmon_channel_info *sbrmi_info[] = { ++ &sbrmi_power_info, ++ &sbrmi_temp_info, ++ NULL ++}; ++ ++static const struct hwmon_ops sbrmi_hwmon_ops = { ++ .is_visible = sbrmi_is_visible, ++ .read = sbrmi_read, ++ .write = sbrmi_write, ++}; ++ ++static const struct hwmon_chip_info sbrmi_chip_info = { ++ .ops = &sbrmi_hwmon_ops, ++ .info = sbrmi_info, ++}; ++ ++static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++{ ++ int __user *arguser = (int __user *)arg; ++ struct apml_message msg = { 0 }; ++ struct apml_sbrmi_device *rmi_dev; ++ bool read = false; ++ int ret = -EFAULT; ++ ++ rmi_dev = fp->private_data; ++ if (!rmi_dev) ++ return ret; ++ ++ /* ++ * If device remove/unbind is called do not allow new transaction ++ * Tickets: https://ontrack-internal.amd.com/browse/PLAT-122500 ++ * https://ontrack-internal.amd.com/browse/DCSM-154 ++ */ ++ if (atomic_read(&rmi_dev->no_new_trans)) ++ return -EBUSY; ++ ++ /* Copy the structure from user */ ++ if (copy_struct_from_user(&msg, sizeof(msg), arguser, ++ sizeof(struct apml_message))) ++ return ret; ++ ++ /* ++ * Only one I2C/I3C transaction can happen at ++ * one time. Take lock across so no two protocol is ++ * invoked at same time, modifying the register value. ++ */ ++ mutex_lock(&rmi_dev->lock); ++ ++ /* Verify device unbind/remove is not invoked */ ++ if (atomic_read(&rmi_dev->no_new_trans)) { ++ mutex_unlock(&rmi_dev->lock); ++ return -EBUSY; ++ } ++ /* Is this a read/monitor/get request */ ++ if (msg.data_in.reg_in[RD_FLAG_INDEX]) ++ read = true; ++ /* ++ * Set the in_progress variable to true, to wait for ++ * completion during unbind/remove of driver ++ */ ++ atomic_set(&rmi_dev->in_progress, 1); ++ switch (msg.cmd) { ++ case 0 ... 0x999: ++ /* Mailbox protocol */ ++ ret = rmi_mailbox_xfer(rmi_dev, &msg); ++ break; ++ case APML_CPUID: ++ /* CPUID protocol */ ++ ret = rmi_cpuid_read(rmi_dev, &msg); ++ break; ++ case APML_MCA_MSR: ++ /* MCAMSR protocol */ ++ ret = rmi_mca_msr_read(rmi_dev, &msg); ++ break; ++ case APML_REG: ++ /* REG R/W */ ++ if (read) { ++ ret = regmap_read(rmi_dev->regmap, ++ msg.data_in.mb_in[REG_OFF_INDEX], ++ &msg.data_out.mb_out[RD_WR_DATA_INDEX]); ++ } else { ++ ret = regmap_write(rmi_dev->regmap, ++ msg.data_in.reg_in[REG_OFF_INDEX], ++ msg.data_in.reg_in[REG_VAL_INDEX]); ++ } ++ break; ++ default: ++ break; ++ } ++ ++ /* Send complete only if device is unbinded/remove */ ++ if (atomic_read(&rmi_dev->no_new_trans)) ++ complete(&rmi_dev->misc_fops_done); ++ atomic_set(&rmi_dev->in_progress, 0); ++ mutex_unlock(&rmi_dev->lock); ++ ++ /* Copy results back to user only for get/monitor commands and firmware failures */ ++ if ((read && !ret) || ret == -EPROTOTYPE) { ++ if (copy_to_user(arguser, &msg, sizeof(struct apml_message))) ++ ret = -EFAULT; ++ } ++ return ret; ++} ++ ++static int sbrmi_open(struct inode *inode, struct file *filp) ++{ ++ struct miscdevice *mdev = filp->private_data; ++ struct apml_sbrmi_device *rmi_dev = container_of(mdev, struct apml_sbrmi_device, ++ sbrmi_misc_dev); ++ int ret = 0; ++ ++ if (!rmi_dev) ++ return -ENODEV; ++ ++ if (!rmi_dev->regmap) { ++ ret = configure_regmap(rmi_dev); ++ if (ret < 0) { ++ pr_err("regmap configuration failed with return value:%d in misc dev open\n", ret); ++ return ret; ++ } ++ } ++ filp->private_data = rmi_dev; ++ return 0; ++} ++ ++static int sbrmi_release(struct inode *inode, struct file *filp) ++{ ++ filp->private_data = NULL; ++ ++ return 0; ++} ++ ++static const struct file_operations sbrmi_fops = { ++ .owner = THIS_MODULE, ++ .open = sbrmi_open, ++ .release = sbrmi_release, ++ .unlocked_ioctl = sbrmi_ioctl, ++ .compat_ioctl = sbrmi_ioctl, ++}; ++ ++static int create_misc_rmi_device(struct apml_sbrmi_device *rmi_dev, ++ struct device *dev) ++{ ++ int ret; ++ ++ rmi_dev->sbrmi_misc_dev.name = devm_kasprintf(dev, GFP_KERNEL, "apml_rmi%d", rmi_dev->sock_num); ++ rmi_dev->sbrmi_misc_dev.minor = MISC_DYNAMIC_MINOR; ++ rmi_dev->sbrmi_misc_dev.fops = &sbrmi_fops; ++ rmi_dev->sbrmi_misc_dev.parent = dev; ++ rmi_dev->sbrmi_misc_dev.nodename = devm_kasprintf(dev, GFP_KERNEL, "sbrmi%d", rmi_dev->sock_num); ++ rmi_dev->sbrmi_misc_dev.mode = 0600; ++ ++ ret = misc_register(&rmi_dev->sbrmi_misc_dev); ++ if (ret) ++ return ret; ++ ++ dev_info(dev, "register %s device\n", rmi_dev->sbrmi_misc_dev.name); ++ return ret; ++} ++ ++static int sbrmi_i2c_identify_reg_addr_size(struct i2c_client *i2cdev, u32 *size, u32 *rev) ++{ ++ struct i2c_msg xfer[I3C_I2C_MSG_XFER_SIZE]; ++ int reg = SBRMI_REV; ++ int val_size = SBRMI_REG_DATA_SIZE; ++ int ret; ++ int probe = 3; ++ ++ do ++ { ++ // Attempt two byte addressing mode ++ xfer[0].addr = i2cdev->addr; ++ xfer[0].flags = 0; ++ xfer[0].len = SBRMI_REG_ADDR_SIZE_TWO_BYTE; ++ xfer[0].buf = (void *)® ++ ++ xfer[1].addr = i2cdev->addr; ++ xfer[1].flags = I2C_M_RD; ++ xfer[1].len = val_size; ++ xfer[1].buf = (void *)rev; ++ ++ ret = i2c_transfer(i2cdev->adapter, xfer, I3C_I2C_MSG_XFER_SIZE); ++ ++ if (ret >= 0) ++ { ++ pr_err("I2C SBRMI_REV command returned value: %d\n", *rev); ++ if(*rev == SBRMI_REV_BRTH) ++ *size = SBRMI_REG_ADDR_SIZE_TWO_BYTE; ++ else ++ *size = SBRMI_REG_ADDR_SIZE_DEF; ++ ++ return 0; ++ } ++ else ++ { ++ probe--; ++ continue; ++ } ++ } while (probe > 0); ++ ++ probe = 3; ++ do ++ { ++ // Attempt one byte addressing mode ++ xfer[0].addr = i2cdev->addr; ++ xfer[0].flags = 0; ++ xfer[0].len = SBRMI_REG_ADDR_SIZE_DEF; ++ xfer[0].buf = (void *)® ++ ++ xfer[1].addr = i2cdev->addr; ++ xfer[1].flags = I2C_M_RD; ++ xfer[1].len = val_size; ++ xfer[1].buf = (void *)rev; ++ ++ ret = i2c_transfer(i2cdev->adapter, xfer, I3C_I2C_MSG_XFER_SIZE); ++ if (ret >= 0) ++ { ++ pr_err("I2C SBRMI_REV command returned value: %d\n", *rev); ++ if(*rev == SBRMI_REV_BRTH) ++ *size = SBRMI_REG_ADDR_SIZE_TWO_BYTE; ++ else ++ *size = SBRMI_REG_ADDR_SIZE_DEF; ++ ++ return 0; ++ } ++ else ++ { ++ probe--; ++ continue; ++ } ++ } while (probe > 0); ++ ++ pr_err("I2C SBRMI_REV error code value: %d\n", ret); ++ return ret; ++} ++ ++static int sbrmi_hwmon_add_chan_info(struct device *dev, int num) ++{ ++ u32 *cfg; ++ int i; ++ ++ cfg = devm_kcalloc(dev, num + 2, sizeof(*cfg), GFP_KERNEL); ++ if (!cfg) ++ return -ENOMEM; ++ ++ // power1: PKG_PWR ++ // power2 ~ powerN+1: DIMM_PWR ++ cfg[0] = HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX; ++ for (i = 1; i <= num; i++) { ++ cfg[i] = HWMON_P_INPUT; ++ } ++ sbrmi_power_info.config = cfg; ++ ++ cfg = devm_kcalloc(dev, num + 1, sizeof(*cfg), GFP_KERNEL); ++ if (!cfg) { ++ devm_kfree(dev, sbrmi_power_info.config); ++ sbrmi_power_info.config = NULL; ++ return -ENOMEM; ++ } ++ ++ // temp1 ~ tempN: DIMM_TEMP ++ for (i = 0; i < num; i++) { ++ cfg[i] = HWMON_T_INPUT; ++ } ++ sbrmi_temp_info.config = cfg; ++ ++ return 0; ++} ++ ++static int sbrmi_i2c_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct device *hwmon_dev; ++ struct apml_sbrmi_device *rmi_dev; ++ int ret; ++ int i; ++ u32 dimm_cnt; ++ u32 *dimm_id; ++ ++ rmi_dev = devm_kzalloc(dev, sizeof(struct apml_sbrmi_device), GFP_KERNEL); ++ if (!rmi_dev) ++ return -ENOMEM; ++ ++ atomic_set(&rmi_dev->in_progress, 0); ++ atomic_set(&rmi_dev->no_new_trans, 0); ++ rmi_dev->client = client; ++ ++ ret = configure_regmap(rmi_dev); ++ if (ret < 0) { ++ pr_err("regmap configuration failed with return value:%d in Probe\n", ret); ++ } ++ mutex_init(&rmi_dev->lock); ++ ++ dev_set_drvdata(dev, (void *)rmi_dev); ++ ++ dimm_id = (u32 *)devm_kzalloc(dev, sizeof(u32) * MAX_DIMM_COUNT, GFP_KERNEL); ++ if (!dimm_id) ++ return -ENOMEM; ++ ++ dimm_cnt = 0; ++ // Read DIMM Count ++ ret = of_property_read_u32(dev->of_node, "dimm-count", &dimm_cnt); ++ ++ if ( (dimm_cnt == 0) || (dimm_cnt > MAX_DIMM_COUNT) ) ++ { ++ dev_info(&client->dev, "SBRMI: Cannot read DIMM Count or exceeds max, default it to %d\n", MAX_DIMM_COUNT); ++ dimm_cnt = MAX_DIMM_COUNT; ++ } ++ ++ // Read DIMM ID ++ ret = of_property_read_u32_array(dev->of_node, "dimm-ids", dimm_id, dimm_cnt); ++ if (ret) { ++ dev_info(&client->dev, "SBRMI: Cannot read DIMM IDs, set them to base address\n"); ++ ++ for (i = 0; i < dimm_cnt; i++) ++ dimm_id[i] = DIMM_BASE_ID + i; ++ } ++ rmi_dev->dimm_id = dimm_id; ++ ++ ret = sbrmi_hwmon_add_chan_info(dev, dimm_cnt); ++ if (ret) ++ return ret; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ++ rmi_dev, ++ &sbrmi_chip_info, ++ NULL); ++ ++ if (!hwmon_dev) ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++ ++ if (client->addr == SOCK_0_ADDR) ++ rmi_dev->sock_num = 0; ++ if (client->addr == SOCK_1_ADDR) ++ rmi_dev->sock_num = 1; ++ ++ init_completion(&rmi_dev->misc_fops_done); ++ return create_misc_rmi_device(rmi_dev, dev); ++} ++ ++static int sbrmi_i3c_identify_reg_addr_size(struct i3c_device *i3cdev, u32 *size, u32 *rev) ++{ ++ struct i3c_priv_xfer xfers[I3C_I2C_MSG_XFER_SIZE]; ++ int reg = SBRMI_REV; ++ int val_size = SBRMI_REG_DATA_SIZE; ++ int ret; ++ int probe = 3; ++ ++ do ++ { ++ // Attempt two byte addressing mode ++ xfers[0].rnw = false; ++ xfers[0].len = SBRMI_REG_ADDR_SIZE_TWO_BYTE; ++ xfers[0].data.out = ® ++ ++ xfers[1].rnw = true; ++ xfers[1].len = val_size; ++ xfers[1].data.in = rev; ++ ++ ret = i3c_device_do_priv_xfers(i3cdev, xfers, I3C_I2C_MSG_XFER_SIZE); ++ ++ if (ret >= 0) ++ { ++ pr_err("I3C SBRMI_REV command returned value: %d\n", *rev); ++ if(*rev == SBRMI_REV_BRTH) ++ *size = SBRMI_REG_ADDR_SIZE_TWO_BYTE; ++ else ++ *size = SBRMI_REG_ADDR_SIZE_DEF; ++ ++ return 0; ++ } ++ else ++ { ++ probe--; ++ continue; ++ } ++ } while (probe > 0); ++ ++ probe = 3; ++ do ++ { ++ // Attempt one byte addressing mode ++ xfers[0].rnw = false; ++ xfers[0].len = SBRMI_REG_ADDR_SIZE_DEF; ++ xfers[0].data.out = ® ++ ++ xfers[1].rnw = true; ++ xfers[1].len = val_size; ++ xfers[1].data.in = rev; ++ ++ ret = i3c_device_do_priv_xfers(i3cdev, xfers, I3C_I2C_MSG_XFER_SIZE); ++ ++ if (ret >= 0) ++ { ++ pr_err("I3C SBRMI_REV command returned value: %d\n", *rev); ++ if(*rev == SBRMI_REV_BRTH) ++ *size = SBRMI_REG_ADDR_SIZE_TWO_BYTE; ++ else ++ *size = SBRMI_REG_ADDR_SIZE_DEF; ++ ++ return 0; ++ } ++ else ++ { ++ probe--; ++ continue; ++ } ++ } while (probe > 0); ++ ++ pr_err("I3C SBRMI_REV error code value: %d\n", ret); ++ return ret; ++} ++ ++static int init_rmi_regmap(struct apml_sbrmi_device *rmi_dev, u32 size, u32 rev) ++{ ++ struct regmap_config sbrmi_regmap_config = { ++ .reg_bits = 8 * size, ++ .val_bits = 8, ++ .reg_format_endian = REGMAP_ENDIAN_LITTLE, ++ }; ++ struct regmap *regmap; ++ ++ if (rmi_dev->i3cdev) { ++ regmap = devm_regmap_init_i3c(rmi_dev->i3cdev, ++ &sbrmi_regmap_config); ++ if (IS_ERR(regmap)) { ++ dev_err(&rmi_dev->i3cdev->dev, ++ "Failed to register i3c regmap %d\n", ++ (int)PTR_ERR(regmap)); ++ return PTR_ERR(regmap); ++ } ++ } else if (rmi_dev->client) { ++ regmap = devm_regmap_init_i2c(rmi_dev->client, ++ &sbrmi_regmap_config); ++ if (IS_ERR(regmap)) ++ return PTR_ERR(rmi_dev->regmap); ++ } else { ++ return -ENODEV; ++ } ++ ++ rmi_dev->regmap = regmap; ++ rmi_dev->rev = rev; ++ return 0; ++} ++ ++/* ++ * configure_regmap call should happen in probe, currently for Turin ++ * the I3C APML client controllers are not initialized and also ++ * Efuse need to be done so move the config to first transaction ++ * https://ontrack-internal.amd.com/browse/PLAT-126960 ++ */ ++static int configure_regmap(struct apml_sbrmi_device *rmi_dev) ++{ ++ u32 size = 2; ++ u32 rev = 0; ++ int ret = 0; ++ ++ if (rmi_dev->i3cdev) { ++ ret = sbrmi_i3c_identify_reg_addr_size(rmi_dev->i3cdev, &size, &rev); ++ if (ret < 0) { ++ pr_err("Reg size identification failed with return value:%d\n", ret); ++ return ret; ++ } ++ } else if (rmi_dev->client) { ++ ret = sbrmi_i2c_identify_reg_addr_size(rmi_dev->client, &size, &rev); ++ if (ret < 0) { ++ pr_err("Reg size identification failed with return value:%d\n", ret); ++ return ret; ++ } ++ } else { ++ return ret; ++ } ++ ret = init_rmi_regmap(rmi_dev, size, rev); ++ return ret; ++} ++ ++static int sbrmi_i3c_probe(struct i3c_device *i3cdev) ++{ ++ struct device *dev = &i3cdev->dev; ++ struct device *hwmon_dev; ++ struct apml_sbrmi_device *rmi_dev; ++ int ret; ++ int i; ++ u32 dimm_cnt; ++ u32 *dimm_id; ++ ++ rmi_dev = devm_kzalloc(dev, sizeof(struct apml_sbrmi_device), GFP_KERNEL); ++ if (!rmi_dev) ++ return -ENOMEM; ++ ++ atomic_set(&rmi_dev->in_progress, 0); ++ atomic_set(&rmi_dev->no_new_trans, 0); ++ rmi_dev->i3cdev = i3cdev; ++ ++ ret = configure_regmap(rmi_dev); ++ if (ret < 0) { ++ pr_err("regmap configuration failed with return value:%d in Probe\n", ret); ++ } ++ mutex_init(&rmi_dev->lock); ++ ++ dev_set_drvdata(dev, (void *)rmi_dev); ++ ++ dimm_id = (u32 *)devm_kzalloc(dev, sizeof(u32) * MAX_DIMM_COUNT, GFP_KERNEL); ++ if (!dimm_id) ++ return -ENOMEM; ++ ++ dimm_cnt = 0; ++ // Read DIMM Count ++ ret = of_property_read_u32(dev->of_node, "dimm-count", &dimm_cnt); ++ ++ if ( (dimm_cnt == 0) || (dimm_cnt > MAX_DIMM_COUNT) ) ++ { ++ dev_info(&i3cdev->dev, "SBRMI: Cannot read DIMM Count or exceeds max, default it to %d\n", MAX_DIMM_COUNT); ++ dimm_cnt = MAX_DIMM_COUNT; ++ } ++ ++ // Read DIMM ID ++ ret = of_property_read_u32_array(dev->of_node, "dimm-ids", dimm_id, dimm_cnt); ++ if (ret) { ++ dev_info(&i3cdev->dev, "SBRMI: Cannot read DIMM IDs, set them to base address\n"); ++ ++ for (i = 0; i < dimm_cnt; i++) ++ dimm_id[i] = DIMM_BASE_ID + i; ++ } ++ rmi_dev->dimm_id = dimm_id; ++ ++ ret = sbrmi_hwmon_add_chan_info(dev, dimm_cnt); ++ if (ret) ++ return ret; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbrmi_i3c", rmi_dev, ++ &sbrmi_chip_info, NULL); ++ ++ if (!hwmon_dev) ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++ ++ if (i3cdev->desc->info.static_addr == SOCK_0_ADDR) ++ rmi_dev->sock_num = 0; ++ if (i3cdev->desc->info.static_addr == SOCK_1_ADDR) ++ rmi_dev->sock_num = 1; ++ ++ init_completion(&rmi_dev->misc_fops_done); ++ return create_misc_rmi_device(rmi_dev, dev); ++} ++ ++static void sbrmi_i2c_remove(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct apml_sbrmi_device *rmi_dev = dev_get_drvdata(&client->dev); ++ ++ if (!rmi_dev) ++ return; ++ /* ++ * Set the no_new_trans so no new transaction can ++ * occur in sbrmi_ioctl ++ */ ++ atomic_set(&rmi_dev->no_new_trans, 1); ++ /* ++ * If any transaction is in progress wait for the ++ * transaction to get complete ++ * Max wait is 3 sec for any pending transaction to ++ * complete, https://ontrack-internal.amd.com/browse/DCSM-84 ++ */ ++ if (atomic_read(&rmi_dev->in_progress)) ++ wait_for_completion_timeout(&rmi_dev->misc_fops_done, ++ MAX_WAIT_TIME_SEC * HZ); ++ misc_deregister(&rmi_dev->sbrmi_misc_dev); ++ /* Assign fops and parent of misc dev to NULL */ ++ rmi_dev->sbrmi_misc_dev.fops = NULL; ++ rmi_dev->sbrmi_misc_dev.parent = NULL; ++ ++ if (rmi_dev->dimm_id) ++ devm_kfree(dev, rmi_dev->dimm_id); ++ if (sbrmi_power_info.config) ++ devm_kfree(dev, sbrmi_power_info.config); ++ if (sbrmi_temp_info.config) ++ devm_kfree(dev, sbrmi_temp_info.config); ++ ++ dev_info(&client->dev, "Removed sbrmi driver\n"); ++} ++ ++static void sbrmi_i3c_remove(struct i3c_device *i3cdev) ++{ ++ struct device *dev = &i3cdev->dev; ++ struct apml_sbrmi_device *rmi_dev = dev_get_drvdata(&i3cdev->dev); ++ ++ if (!rmi_dev) ++ return; ++ /* ++ * Set the no_new_trans so no new transaction can ++ * occur in sbrmi_ioctl ++ */ ++ atomic_set(&rmi_dev->no_new_trans, 1); ++ /* ++ * If any transaction is in progress wait for the ++ * transaction to get complete ++ * Max wait is 3 sec for any pending transaction to ++ * complete, https://ontrack-internal.amd.com/browse/DCSM-84 ++ */ ++ if (atomic_read(&rmi_dev->in_progress)) ++ wait_for_completion_timeout(&rmi_dev->misc_fops_done, ++ MAX_WAIT_TIME_SEC * HZ); ++ misc_deregister(&rmi_dev->sbrmi_misc_dev); ++ /* Assign fops and parent of misc dev to NULL */ ++ rmi_dev->sbrmi_misc_dev.fops = NULL; ++ rmi_dev->sbrmi_misc_dev.parent = NULL; ++ ++ if (rmi_dev->dimm_id) ++ devm_kfree(dev, rmi_dev->dimm_id); ++ if (sbrmi_power_info.config) ++ devm_kfree(dev, sbrmi_power_info.config); ++ if (sbrmi_temp_info.config) ++ devm_kfree(dev, sbrmi_temp_info.config); ++ ++ dev_info(&i3cdev->dev, "Removed sbrmi_i3c driver\n"); ++} ++ ++static const struct i2c_device_id sbrmi_id[] = { ++ {"sbrmi", 0}, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, sbrmi_id); ++ ++static const struct of_device_id __maybe_unused sbrmi_of_match[] = { ++ { ++ .compatible = "amd,sbrmi", ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, sbrmi_of_match); ++ ++static const struct i3c_device_id sbrmi_i3c_id[] = { ++ I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x2, NULL), ++ {} ++}; ++MODULE_DEVICE_TABLE(i3c, sbrmi_i3c_id); ++ ++static struct i2c_driver sbrmi_driver = { ++ .class = I2C_CLASS_HWMON, ++ .driver = { ++ .name = "sbrmi", ++ .of_match_table = of_match_ptr(sbrmi_of_match), ++ }, ++ .probe = sbrmi_i2c_probe, ++ .remove = sbrmi_i2c_remove, ++ .id_table = sbrmi_id, ++}; ++ ++static struct i3c_driver sbrmi_i3c_driver = { ++ .driver = { ++ .name = "sbrmi_i3c", ++ }, ++ .probe = sbrmi_i3c_probe, ++ .remove = sbrmi_i3c_remove, ++ .id_table = sbrmi_i3c_id, ++}; ++ ++module_i3c_i2c_driver(sbrmi_i3c_driver, &sbrmi_driver) ++ ++MODULE_AUTHOR("Akshay Gupta "); ++MODULE_AUTHOR("Naveenkrishna Chatradhi "); ++MODULE_DESCRIPTION("Hwmon driver for AMD SB-RMI emulated sensor"); ++MODULE_LICENSE("GPL"); +diff --git a/include/uapi/linux/amd-apml.h b/include/uapi/linux/amd-apml.h +new file mode 100644 +index 000000000000..041610925fad +--- /dev/null ++++ b/include/uapi/linux/amd-apml.h +@@ -0,0 +1,74 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Copyright (C) 2021-2022 Advanced Micro Devices, Inc. ++ */ ++#ifndef _AMD_APML_H_ ++#define _AMD_APML_H_ ++ ++#include ++ ++enum apml_protocol { ++ APML_CPUID = 0x1000, ++ APML_MCA_MSR, ++ APML_REG, ++}; ++ ++/* These are byte indexes into data_in and data_out arrays */ ++#define RD_WR_DATA_INDEX 0 ++#define REG_OFF_INDEX 0 ++#define REG_VAL_INDEX 4 ++#define THREAD_LOW_INDEX 4 ++#define THREAD_HI_INDEX 5 ++#define EXT_FUNC_INDEX 6 ++#define RD_FLAG_INDEX 7 ++ ++#define MB_DATA_SIZE 4 ++ ++struct apml_message { ++ /* message ids: ++ * Mailbox Messages: 0x0 ... 0x999 ++ * APML_CPUID: 0x1000 ++ * APML_MCA_MSR: 0x1001 ++ * APML_REG: 0x1002 (RMI & TSI reg access) ++ */ ++ __u32 cmd; ++ ++ /* ++ * 8 bit data for reg read, ++ * 32 bit data in case of mailbox, ++ * upto 64 bit in case of cpuid and mca msr ++ */ ++ union { ++ __u64 cpu_msr_out; ++ __u32 mb_out[2]; ++ __u8 reg_out[8]; ++ } data_out; ++ ++ /* ++ * [0]...[3] mailbox 32bit input ++ * cpuid & mca msr, ++ * rmi rd/wr: reg_offset ++ * [4][5] cpuid & mca msr: thread ++ * [4] rmi reg wr: value ++ * [6] cpuid: ext function & read eax/ebx or ecx/edx ++ * [7:0] -> bits [7:4] -> ext function & ++ * bit [0] read eax/ebx or ecx/edx ++ * [7] read/write functionality ++ */ ++ union { ++ __u64 cpu_msr_in; ++ __u32 mb_in[2]; ++ __u8 reg_in[8]; ++ } data_in; ++ /* ++ * Status code is returned in case of CPUID/MCA access ++ * Error code is returned in case of soft mailbox ++ */ ++ __u32 fw_ret_code; ++} __attribute__((packed)); ++ ++/* ioctl command for mailbox msgs using generic _IOWR */ ++#define SBRMI_BASE_IOCTL_NR 0xF9 ++#define SBRMI_IOCTL_CMD _IOWR(SBRMI_BASE_IOCTL_NR, 0, struct apml_message) ++ ++#endif /*_AMD_APML_H_*/ +-- +2.41.0 + diff --git a/common/recipes-kernel/linux/linux-aspeed_%.bbappend b/common/recipes-kernel/linux/linux-aspeed_%.bbappend index 7b45af410905..90df29139520 100644 --- a/common/recipes-kernel/linux/linux-aspeed_%.bbappend +++ b/common/recipes-kernel/linux/linux-aspeed_%.bbappend @@ -1,6 +1,6 @@ -FILESEXTRAPATHS:prepend := "${THISDIR}/6.5:" +FILESEXTRAPATHS:prepend := "${THISDIR}/6.6:" LINUX_ASPEED_PATCHES_INC ?= "" -LINUX_ASPEED_PATCHES_INC:openbmc-fb-lf = "linux-patches-6.5.inc" +LINUX_ASPEED_PATCHES_INC:openbmc-fb-lf = "linux-patches-6.6.inc" include ${LINUX_ASPEED_PATCHES_INC} diff --git a/common/recipes-kernel/linux/linux-patches-6.6.inc b/common/recipes-kernel/linux/linux-patches-6.6.inc index fdc5724e1d8b..daf4a8359b16 100644 --- a/common/recipes-kernel/linux/linux-patches-6.6.inc +++ b/common/recipes-kernel/linux/linux-patches-6.6.inc @@ -84,3 +84,12 @@ SRC_URI:append = " \ SRC_URI:append = " \ file://0200-mmc-sdhci-of-aspeed-add-skip_probe-module-parameter.patch \ " +# +# Device drvier for OpenBMC platforms. +# +SRC_URI:append = " \ + file://0300-To-support-MCP9600-temperature-driver.patch \ + file://0301-To-support-MP2856-VR-driver.patch \ + file://0302-To-support-LTC4286-LTC4287-driver.patch \ + file://0303-Kernel6v5-Support-apml-driver.patch \ +" diff --git a/meta-facebook/meta-bletchley/recipes-kernel/linux/linux-aspeed/0500-ARM-dts-aspeed-bletchley-enable-PWM-and-TACH-support.patch b/meta-facebook/meta-bletchley/recipes-kernel/linux/linux-aspeed/0500-ARM-dts-aspeed-bletchley-enable-PWM-and-TACH-support.patch index 4c23558c7f4b..81e4a8d94a4f 100644 --- a/meta-facebook/meta-bletchley/recipes-kernel/linux/linux-aspeed/0500-ARM-dts-aspeed-bletchley-enable-PWM-and-TACH-support.patch +++ b/meta-facebook/meta-bletchley/recipes-kernel/linux/linux-aspeed/0500-ARM-dts-aspeed-bletchley-enable-PWM-and-TACH-support.patch @@ -1,7 +1,8 @@ -From edd0a5bc27b6397fc1c1b990bd7f116d063e9f9d Mon Sep 17 00:00:00 2001 +From 0b37032450f5254d0ba11e92347c37449b35dabe Mon Sep 17 00:00:00 2001 From: Potin Lai Date: Thu, 31 Aug 2023 16:55:58 +0800 -Subject: [PATCH 1/1] ARM: dts: aspeed: bletchley: enable PWM and TACH support +Subject: [PATCH 500/501] ARM: dts: aspeed: bletchley: enable PWM and TACH + support Enable pwm and tach support, add pwm-fan for fan controlling. @@ -14,7 +15,7 @@ Signed-off-by: Potin Lai 1 file changed, 73 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts -index 72ad59e3e8a57..a69ecfa17cb54 100644 +index e899de681f47..f8564644cc70 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts @@ -280,6 +280,26 @@ vbus_sled6: vbus_sled6 { @@ -102,5 +103,5 @@ index 72ad59e3e8a57..a69ecfa17cb54 100644 + }; +}; -- -2.31.1 +2.41.0 diff --git a/meta-facebook/meta-bletchley/recipes-kernel/linux/linux-aspeed/0501-ARM-dts-aspeed-bletchley-set-manual-clock-for-i2c13.patch b/meta-facebook/meta-bletchley/recipes-kernel/linux/linux-aspeed/0501-ARM-dts-aspeed-bletchley-set-manual-clock-for-i2c13.patch index ab815846ed83..1d99ed6518a3 100644 --- a/meta-facebook/meta-bletchley/recipes-kernel/linux/linux-aspeed/0501-ARM-dts-aspeed-bletchley-set-manual-clock-for-i2c13.patch +++ b/meta-facebook/meta-bletchley/recipes-kernel/linux/linux-aspeed/0501-ARM-dts-aspeed-bletchley-set-manual-clock-for-i2c13.patch @@ -1,4 +1,4 @@ -From 9af2f06e6404d776c11a0e24841bafb86eda451d Mon Sep 17 00:00:00 2001 +From 809d0a876ea899e397f9758a1d092cbfa5cd607a Mon Sep 17 00:00:00 2001 From: Potin Lai Date: Mon, 30 May 2022 13:45:10 +0800 Subject: [PATCH 501/501] ARM: dts: aspeed: bletchley: set manual clock for @@ -10,7 +10,7 @@ Signed-off-by: Potin Lai 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts -index 832eff30d193..f6d2452d41f4 100644 +index f8564644cc70..a69ecfa17cb5 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts @@ -960,7 +960,7 @@ fan_leds: pca9552@67 { diff --git a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0500-add-meta-yv4-bmc-dts-setting.patch b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0500-add-meta-yv4-bmc-dts-setting.patch index 0db1532ed6d9..b41808c1f426 100644 --- a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0500-add-meta-yv4-bmc-dts-setting.patch +++ b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0500-add-meta-yv4-bmc-dts-setting.patch @@ -1,17 +1,17 @@ -From be58d1477074ad2c8cdaf22a4925bd2007295c05 Mon Sep 17 00:00:00 2001 +From 6c395147da338eec4a38007f5a84ed8650906f9a Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 24 Oct 2023 17:43:44 +0800 -Subject: [PATCH] add meta yv4 bmc dts setting +Subject: [PATCH 500/506] add meta yv4 bmc dts setting This commit depends on the patch below: [1] https://lore.kernel.org/all/20230922064127.283625-1-Delphine_CC_Chiu@wiwynn.com/ [2] https://lore.kernel.org/all/20230922064127.283625-2-Delphine_CC_Chiu@wiwynn.com/ --- - .../aspeed/aspeed-bmc-facebook-yosemite4.dts | 1098 +++++++++++++++-- - 1 file changed, 1011 insertions(+), 87 deletions(-) + .../aspeed/aspeed-bmc-facebook-yosemite4.dts | 1083 +++++++++++++++-- + 1 file changed, 1011 insertions(+), 72 deletions(-) diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts -index a6777efc78b8..6cfbba121fba 100644 +index 64075cc41d92..6cfbba121fba 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-yosemite4.dts @@ -17,6 +17,25 @@ aliases { @@ -67,7 +67,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -83,34 +120,27 @@ &wdt1 { +@@ -83,6 +120,13 @@ &wdt1 { aspeed,ext-pulse-duration = <256>; }; @@ -81,35 +81,7 @@ index a6777efc78b8..6cfbba121fba 100644 &mac2 { status = "okay"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_rmii3_default>; -- no-hw-checksum; - use-ncsi; - mlx,multi-host; -- ncsi-ctrl,start-redo-probe; -- ncsi-ctrl,no-channel-monitor; -- ncsi-package = <1>; -- ncsi-channel = <1>; -- ncsi-rexmit = <1>; -- ncsi-timeout = <2>; - }; - - &mac3 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_rmii4_default>; -- no-hw-checksum; - use-ncsi; - mlx,multi-host; -- ncsi-ctrl,start-redo-probe; -- ncsi-ctrl,no-channel-monitor; -- ncsi-package = <1>; -- ncsi-channel = <1>; -- ncsi-rexmit = <1>; -- ncsi-timeout = <2>; - }; - - &fmc { -@@ -119,15 +149,17 @@ flash@0 { +@@ -105,15 +149,17 @@ flash@0 { status = "okay"; m25p,fast-read; label = "bmc"; @@ -130,7 +102,7 @@ index a6777efc78b8..6cfbba121fba 100644 spi-max-frequency = <50000000>; }; }; -@@ -143,9 +175,38 @@ mctp@10 { +@@ -129,9 +175,38 @@ mctp@10 { reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; }; @@ -170,7 +142,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -160,9 +221,38 @@ mctp@10 { +@@ -146,9 +221,38 @@ mctp@10 { reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; }; @@ -210,7 +182,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -177,9 +267,38 @@ mctp@10 { +@@ -163,9 +267,38 @@ mctp@10 { reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; }; @@ -250,7 +222,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -194,9 +313,38 @@ mctp@10 { +@@ -180,9 +313,38 @@ mctp@10 { reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; }; @@ -290,7 +262,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -211,9 +359,38 @@ mctp@10 { +@@ -197,9 +359,38 @@ mctp@10 { reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; }; @@ -330,7 +302,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -228,9 +405,38 @@ mctp@10 { +@@ -214,9 +405,38 @@ mctp@10 { reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; }; @@ -370,7 +342,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -245,9 +451,38 @@ mctp@10 { +@@ -231,9 +451,38 @@ mctp@10 { reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; }; @@ -410,7 +382,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -262,9 +497,38 @@ mctp@10 { +@@ -248,9 +497,38 @@ mctp@10 { reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; }; @@ -450,7 +422,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -273,9 +537,109 @@ &i2c8 { +@@ -259,9 +537,109 @@ &i2c8 { bus-frequency = <400000>; i2c-mux@70 { compatible = "nxp,pca9544"; @@ -561,7 +533,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -284,56 +648,267 @@ &i2c9 { +@@ -270,55 +648,267 @@ &i2c9 { bus-frequency = <400000>; i2c-mux@71 { compatible = "nxp,pca9544"; @@ -738,7 +710,6 @@ index a6777efc78b8..6cfbba121fba 100644 &i2c11 { status = "okay"; -- bus-frequency = <400000>; power-sensor@10 { - compatible = "adi, adm1272"; + compatible = "adi,adm1272"; @@ -841,7 +812,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; temperature-sensor@48 { -@@ -346,19 +921,29 @@ temperature-sensor@49 { +@@ -331,19 +921,29 @@ temperature-sensor@49 { reg = <0x49>; }; @@ -880,7 +851,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; }; -@@ -376,6 +961,11 @@ eeprom@50 { +@@ -361,6 +961,11 @@ eeprom@50 { reg = <0x50>; }; @@ -892,7 +863,7 @@ index a6777efc78b8..6cfbba121fba 100644 rtc@6f { compatible = "nuvoton,nct3018y"; reg = <0x6f>; -@@ -385,6 +975,33 @@ rtc@6f { +@@ -370,6 +975,33 @@ rtc@6f { &i2c13 { status = "okay"; bus-frequency = <400000>; @@ -926,7 +897,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; &i2c14 { -@@ -393,44 +1010,54 @@ &i2c14 { +@@ -378,44 +1010,54 @@ &i2c14 { adc@1d { compatible = "ti,adc128d818"; reg = <0x1d>; @@ -991,7 +962,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; temperature-sensor@4e { -@@ -448,16 +1075,14 @@ eeprom@51 { +@@ -433,16 +1075,14 @@ eeprom@51 { reg = <0x51>; }; @@ -1012,7 +983,7 @@ index a6777efc78b8..6cfbba121fba 100644 #address-cells = <1>; #size-cells = <0>; reg = <0>; -@@ -465,26 +1090,46 @@ i2c@0 { +@@ -450,26 +1090,46 @@ i2c@0 { adc@1f { compatible = "ti,adc128d818"; reg = <0x1f>; @@ -1065,7 +1036,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; adc@33 { -@@ -507,34 +1152,54 @@ gpio@61 { +@@ -492,34 +1152,54 @@ gpio@61 { }; }; @@ -1128,7 +1099,7 @@ index a6777efc78b8..6cfbba121fba 100644 }; adc@33 { -@@ -562,12 +1227,10 @@ i2c-mux@73 { +@@ -547,12 +1227,10 @@ i2c-mux@73 { compatible = "nxp,pca9544"; #address-cells = <1>; #size-cells = <0>; @@ -1142,7 +1113,7 @@ index a6777efc78b8..6cfbba121fba 100644 #address-cells = <1>; #size-cells = <0>; reg = <0>; -@@ -578,10 +1241,10 @@ adc@35 { +@@ -563,10 +1241,10 @@ adc@35 { }; }; @@ -1155,7 +1126,7 @@ index a6777efc78b8..6cfbba121fba 100644 adc@35 { compatible = "maxim,max11617"; -@@ -604,12 +1267,75 @@ mctp@10 { +@@ -589,12 +1267,75 @@ mctp@10 { i2c-mux@72 { compatible = "nxp,pca9544"; @@ -1233,7 +1204,7 @@ index a6777efc78b8..6cfbba121fba 100644 &adc0 { ref_voltage = <2500>; status = "okay"; -@@ -622,10 +1348,10 @@ &pinctrl_adc4_default &pinctrl_adc5_default +@@ -607,10 +1348,10 @@ &pinctrl_adc4_default &pinctrl_adc5_default &adc1 { ref_voltage = <2500>; status = "okay"; @@ -1246,7 +1217,7 @@ index a6777efc78b8..6cfbba121fba 100644 &ehci0 { status = "okay"; }; -@@ -637,3 +1363,201 @@ &ehci1 { +@@ -622,3 +1363,201 @@ &ehci1 { &uhci { status = "okay"; }; @@ -1449,5 +1420,5 @@ index a6777efc78b8..6cfbba121fba 100644 + }; +}; -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0501-hwmon-ina233-Add-ina233-driver.patch b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0501-hwmon-ina233-Add-ina233-driver.patch index 193e619f7d1c..839c29067ef2 100644 --- a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0501-hwmon-ina233-Add-ina233-driver.patch +++ b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0501-hwmon-ina233-Add-ina233-driver.patch @@ -1,7 +1,7 @@ -From 09aad67d89c5b7bc007d5c8fd2505696dba63dc1 Mon Sep 17 00:00:00 2001 +From 89ffe8d94dd9c47c7d9e85dd3681f0c4682b5e6f Mon Sep 17 00:00:00 2001 From: DelphineCCChiu Date: Thu, 21 Sep 2023 18:35:19 +0800 -Subject: [PATCH 2/4] hwmon: (ina233) Add ina233 driver +Subject: [PATCH 501/506] hwmon: (ina233) Add ina233 driver This commit depends on the patch below: [1] https://lore.kernel.org/all/20230920054739.1561080-1-Delphine_CC_Chiu@wiwynn.com/ @@ -15,10 +15,10 @@ This commit depends on the patch below: create mode 100644 drivers/hwmon/pmbus/ina233.c diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig -index 270b6336b76d..4e3776702d7f 100644 +index 294808f5240a..02809fe6331c 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig -@@ -502,4 +502,13 @@ config SENSORS_ZL6100 +@@ -537,4 +537,13 @@ config SENSORS_ZL6100 This driver can also be built as a module. If so, the module will be called zl6100. @@ -33,17 +33,17 @@ index 270b6336b76d..4e3776702d7f 100644 + endif # PMBUS diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile -index 84ee960a6c2d..51d54f444cec 100644 +index cf8a76744545..7aa0d4548a15 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile -@@ -51,3 +51,4 @@ obj-$(CONFIG_SENSORS_XDPE122) += xdpe12284.o +@@ -54,3 +54,4 @@ obj-$(CONFIG_SENSORS_XDPE122) += xdpe12284.o obj-$(CONFIG_SENSORS_XDPE152) += xdpe152c4.o obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o obj-$(CONFIG_SENSORS_PIM4328) += pim4328.o +obj-$(CONFIG_SENSORS_INA233) += ina233.o diff --git a/drivers/hwmon/pmbus/ina233.c b/drivers/hwmon/pmbus/ina233.c new file mode 100644 -index 000000000000..393b595344c5 +index 000000000000..d5c7d7408ac3 --- /dev/null +++ b/drivers/hwmon/pmbus/ina233.c @@ -0,0 +1,89 @@ @@ -125,7 +125,7 @@ index 000000000000..393b595344c5 + .name = "ina233", + .of_match_table = of_match_ptr(ina233_of_match), + }, -+ .probe_new = ina233_probe, ++ .probe = ina233_probe, + .id_table = ina233_id, +}; + @@ -137,5 +137,5 @@ index 000000000000..393b595344c5 +MODULE_IMPORT_NS(PMBUS); + -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0502-hwmon-max31790-support-to-config-PWM-as-TACH.patch b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0502-hwmon-max31790-support-to-config-PWM-as-TACH.patch index 86e160afbb7f..ac531a680304 100644 --- a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0502-hwmon-max31790-support-to-config-PWM-as-TACH.patch +++ b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0502-hwmon-max31790-support-to-config-PWM-as-TACH.patch @@ -1,7 +1,7 @@ -From bfe96e683394e9c870957d306dc9f7df9b2452ff Mon Sep 17 00:00:00 2001 +From cad1d70b18851c04e6fc90a6810a19feeba971f1 Mon Sep 17 00:00:00 2001 From: Delphine CC Chiu Date: Wed, 6 Sep 2023 16:19:16 +0800 -Subject: [PATCH v4 1/3] hwmon: max31790: support to config PWM as TACH +Subject: [PATCH 502/506] hwmon: max31790: support to config PWM as TACH The PWM outputs of max31790 could be used as tachometer inputs by setting the fan configuration register, but the driver doesn't support @@ -123,5 +123,5 @@ index 0cd44c1e998a..378ff32c7c1e 100644 * Initialize the max31790 chip */ -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0503-Add-adm1281-driver.patch b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0503-Add-adm1281-driver.patch index 24790be78f6a..3cb190ed68b2 100644 --- a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0503-Add-adm1281-driver.patch +++ b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0503-Add-adm1281-driver.patch @@ -1,7 +1,7 @@ -From b2933bf064187183a13bdd5ad3c75a78f826386e Mon Sep 17 00:00:00 2001 +From 33f96a211e6b5a96aa0125c043ee20de438feaae Mon Sep 17 00:00:00 2001 From: Eli_Huang Date: Tue, 26 Sep 2023 10:20:13 +0800 -Subject: [PATCH 4/4] Add adm1281 driver +Subject: [PATCH 503/506] Add adm1281 driver --- Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml | 2 ++ @@ -96,5 +96,5 @@ index e2c61d6fa521..979474ba6bd3 100644 data->have_pin_max = true; data->have_temp_max = true; -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0504-hwmon-max31790-add-fanN_enable-for-all-fans.patch b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0504-hwmon-max31790-add-fanN_enable-for-all-fans.patch index 77e6c5f4f48f..2428af6df646 100644 --- a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0504-hwmon-max31790-add-fanN_enable-for-all-fans.patch +++ b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0504-hwmon-max31790-add-fanN_enable-for-all-fans.patch @@ -1,7 +1,7 @@ -From f47d48f71be0eca9f482ef2b6af77a3063541d0a Mon Sep 17 00:00:00 2001 +From c6f35d436cc5070e744664605224a69d471d70ef Mon Sep 17 00:00:00 2001 From: Delphine CC Chiu Date: Wed, 1 Nov 2023 18:18:29 +0800 -Subject: [PATCH v4 3/3] hwmon: max31790: add fanN_enable for all fans +Subject: [PATCH 504/506] hwmon: max31790: add fanN_enable for all fans The fanN_enable will be set in dbus-sensors service according to the index of TACH that filled in the configuration of entity-manager. @@ -133,5 +133,5 @@ index 378ff32c7c1e..fa31e108c7ce 100644 HWMON_PWM_INPUT | HWMON_PWM_ENABLE, HWMON_PWM_INPUT | HWMON_PWM_ENABLE, -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0505-support-mux-to-cpld.patch b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0505-ARM-dts-aspeed-yosemite4-support-mux-to-cpld.patch similarity index 93% rename from meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0505-support-mux-to-cpld.patch rename to meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0505-ARM-dts-aspeed-yosemite4-support-mux-to-cpld.patch index d6e6c525fcf8..2e44defbbaef 100644 --- a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0505-support-mux-to-cpld.patch +++ b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0505-ARM-dts-aspeed-yosemite4-support-mux-to-cpld.patch @@ -1,7 +1,7 @@ -From 21f5dd11362398d2ff1719faf873a871ee00bfaa Mon Sep 17 00:00:00 2001 +From 9bcd542f390a43e815422c6242280d249351b00c Mon Sep 17 00:00:00 2001 From: Delphine CC Chiu Date: Mon, 11 Dec 2023 10:22:47 +0800 -Subject: [PATCH 1/2] ARM: dts: aspeed: yosemite4: support mux to cpld +Subject: [PATCH 505/506] ARM: dts: aspeed: yosemite4: support mux to cpld Mux pca9544 to cpld was added on EVT HW schematic design, so add dts setting for devices behind mux pca9544 to cpld @@ -100,5 +100,5 @@ index 6cfbba121fba..4ea0df54546d 100644 }; -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0506-revise-gpio-name.patch b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0506-ARM-dts-aspeed-yosemite4-Revise-gpio-name.patch similarity index 95% rename from meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0506-revise-gpio-name.patch rename to meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0506-ARM-dts-aspeed-yosemite4-Revise-gpio-name.patch index a344584962d5..8f044dba2ec2 100644 --- a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0506-revise-gpio-name.patch +++ b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed/0506-ARM-dts-aspeed-yosemite4-Revise-gpio-name.patch @@ -1,7 +1,7 @@ -From a6f6f743e16185d9abdb140ab7e2abf0afdd0570 Mon Sep 17 00:00:00 2001 +From 94c6883838f9a9bf8a765ec9ed28f6c3602e84fd Mon Sep 17 00:00:00 2001 From: Delphine CC Chiu Date: Mon, 11 Dec 2023 10:29:27 +0800 -Subject: [PATCH 2/2] ARM: dts: aspeed: yosemite4: Revise gpio name +Subject: [PATCH 506/506] ARM: dts: aspeed: yosemite4: Revise gpio name Revise gpio name for EVT schematic changes @@ -59,5 +59,5 @@ index 4ea0df54546d..46684c40a244 100644 "FM_RESBTN_SLOT7_BMC_N","FM_RESBTN_SLOT8_BMC_N", "","","","", -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed_%.bbappend index 3c4ac25aff8b..e470032d8e1b 100644 --- a/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed_%.bbappend +++ b/meta-facebook/meta-yosemite4/recipes-kernel/linux/linux-aspeed_%.bbappend @@ -5,7 +5,7 @@ SRC_URI += " \ file://0502-hwmon-max31790-support-to-config-PWM-as-TACH.patch \ file://0503-Add-adm1281-driver.patch \ file://0504-hwmon-max31790-add-fanN_enable-for-all-fans.patch \ - file://0505-support-mux-to-cpld.patch \ - file://0506-revise-gpio-name.patch \ + file://0505-ARM-dts-aspeed-yosemite4-support-mux-to-cpld.patch \ + file://0506-ARM-dts-aspeed-yosemite4-Revise-gpio-name.patch \ " diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/entity-manager/entity-manager_git.bbappend b/meta-facebook/meta-yosemite4/recipes-phosphor/entity-manager/entity-manager_git.bbappend deleted file mode 100644 index 6ec990f6c4b4..000000000000 --- a/meta-facebook/meta-yosemite4/recipes-phosphor/entity-manager/entity-manager_git.bbappend +++ /dev/null @@ -1,5 +0,0 @@ -FILESEXTRAPATHS:prepend := "${THISDIR}/files:" - -SRC_URI += " \ - file://0001-Add-mctp-eids-configuration-for-Yosemite-4.patch \ -" diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/entity-manager/files/0001-Add-mctp-eids-configuration-for-Yosemite-4.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/entity-manager/files/0001-Add-mctp-eids-configuration-for-Yosemite-4.patch deleted file mode 100644 index 6e8c07c6e283..000000000000 --- a/meta-facebook/meta-yosemite4/recipes-phosphor/entity-manager/files/0001-Add-mctp-eids-configuration-for-Yosemite-4.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 4a4e16d24af126bd62f7b6a3270484e9c72fa6d5 Mon Sep 17 00:00:00 2001 -From: Delphine CC Chiu -Date: Mon, 25 Sep 2023 11:10:46 +0800 -Subject: [PATCH] Add mctp eids configuration for Yosemite 4 - -The MCTP specification is defined in DSP0236. As describe in section -8.17.2, we need a configuration for static EIDs. The `mctpd` from -CodeConstuct/mctp will be able to know where those static EIDs located. -The other services will be able to know what those EIDs stand for by the -"Name" as well. - -schemas: add `EndpointId` with type `string` and `number`. - -Tested: check D-Bus path for configuration. -Change-Id: I587f5a69051f783753f5855d2f51242aa1cd5bc4 -Signed-off-by: Delphine CC Chiu ---- - configurations/yosemite4_floatingfalls.json | 17 ++++++++++++++- - configurations/yosemite4_sentineldome.json | 10 ++++++++- - configurations/yosemite4_wailuafalls.json | 24 ++++++++++++++++++++- - schemas/legacy.json | 6 ++++++ - 4 files changed, 54 insertions(+), 3 deletions(-) - -diff --git a/configurations/yosemite4_floatingfalls.json b/configurations/yosemite4_floatingfalls.json -index e51624f..e0075c4 100644 ---- a/configurations/yosemite4_floatingfalls.json -+++ b/configurations/yosemite4_floatingfalls.json -@@ -1,5 +1,20 @@ - { -- "Exposes": [], -+ "Exposes": [ -+ { -+ "Address": "0x20", -+ "Bus": "$bus % 16", -+ "EndpointId": "$bus % 15 * 10 + 1", -+ "Name": "BIC", -+ "Type": "MCTPEndpoint" -+ }, -+ { -+ "Address": "0x20", -+ "Bus": "$bus % 16", -+ "EndpointId": "$bus % 15 * 10 + 3", -+ "Name": "CXL", -+ "Type": "MCTPEndpoint" -+ } -+ ], - "Name": "Yosemite 4 Floating Falls Slot $bus % 15", - "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'Floating Falls', 'PRODUCT_PRODUCT_NAME': 'Yosemite V4'})", - "Type": "Board", -diff --git a/configurations/yosemite4_sentineldome.json b/configurations/yosemite4_sentineldome.json -index d18bf4c..cdfe8bd 100644 ---- a/configurations/yosemite4_sentineldome.json -+++ b/configurations/yosemite4_sentineldome.json -@@ -1,5 +1,13 @@ - { -- "Exposes": [], -+ "Exposes": [ -+ { -+ "Address": "0x20", -+ "Bus": "$bus % 16", -+ "EndpointId": "$bus % 15 * 10", -+ "Name": "BIC", -+ "Type": "MCTPEndpoint" -+ } -+ ], - "Name": "Yosemite 4 Sentinel Dome Slot $bus % 15", - "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'Sentinel Dome', 'PRODUCT_PRODUCT_NAME': 'Yosemite V4'})", - "Type": "Board", -diff --git a/configurations/yosemite4_wailuafalls.json b/configurations/yosemite4_wailuafalls.json -index 6f8a85b..97dfae1 100644 ---- a/configurations/yosemite4_wailuafalls.json -+++ b/configurations/yosemite4_wailuafalls.json -@@ -1,5 +1,27 @@ - { -- "Exposes": [], -+ "Exposes": [ -+ { -+ "Address": "0x20", -+ "Bus": "$bus % 16", -+ "EndpointId": "$bus % 15 * 10 + 2", -+ "Name": "BIC", -+ "Type": "MCTPEndpoint" -+ }, -+ { -+ "Address": "0x20", -+ "Bus": "$bus % 16", -+ "EndpointId": "$bus % 15 * 10 + 4", -+ "Name": "CXL1", -+ "Type": "MCTPEndpoint" -+ }, -+ { -+ "Address": "0x20", -+ "Bus": "$bus % 16", -+ "EndpointId": "$bus % 15 * 10 + 5", -+ "Name": "CXL2", -+ "Type": "MCTPEndpoint" -+ } -+ ], - "Name": "Yosemite 4 Wailua Falls Slot $bus % 15", - "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'Wailua Falls', 'PRODUCT_PRODUCT_NAME': 'Yosemite V4'})", - "Type": "Board", -diff --git a/schemas/legacy.json b/schemas/legacy.json -index 86dd16d..e1c259e 100644 ---- a/schemas/legacy.json -+++ b/schemas/legacy.json -@@ -69,6 +69,9 @@ - "EntityInstance": { - "$ref": "#/definitions/Types/EntityInstance" - }, -+ "EndpointId": { -+ "$ref": "#/definitions/Types/EndpointId" -+ }, - "FaultIndex": { - "$ref": "#/definitions/Types/FaultIndex" - }, -@@ -650,6 +653,9 @@ - "EntityInstance": { - "type": "number" - }, -+ "EndpointId": { -+ "type": ["string", "number"] -+ }, - "FaultIndex": { - "type": "number" - }, --- -2.25.1 - diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0001-requester-Modified-MctpDiscovery-class.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0001-requester-Modified-MctpDiscovery-class.patch index a17913ba800c..b1595eb933a8 100644 --- a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0001-requester-Modified-MctpDiscovery-class.patch +++ b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0001-requester-Modified-MctpDiscovery-class.patch @@ -1,7 +1,7 @@ -From 9d4be95847af736a28026e7c85eeabcf066a0a52 Mon Sep 17 00:00:00 2001 +From 9fe3b0fa5fbdce5fe15c5acd679a40701257fbf0 Mon Sep 17 00:00:00 2001 From: Gilbert Chen Date: Mon, 14 Feb 2022 12:12:25 +0000 -Subject: [PATCH 1/7] requester: Modified MctpDiscovery class +Subject: [PATCH 1/9] requester: Modified MctpDiscovery class Modified MctpDiscovery class to take list of managers instead of single fwManager. The change is for adding platform-mc manager. @@ -14,10 +14,8 @@ https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/47252 Signed-off-by: Gilbert Chen Signed-off-by: Thu Nguyen Change-Id: I1e1673504583a87f2a9bc3adf76fb49c2dc30254 - -%% original patch: 0001-requester-Modified-MctpDiscovery-class.patch --- - common/types.hpp | 7 + + common/types.hpp | 6 + fw-update/manager.hpp | 25 +- meson.build | 1 + pldmd/pldmd.cpp | 4 +- @@ -27,16 +25,16 @@ Change-Id: I1e1673504583a87f2a9bc3adf76fb49c2dc30254 requester/test/meson.build | 7 + .../test/mock_mctp_discovery_handler_intf.hpp | 20 ++ requester/test/static_eid_table.json | 14 + - 10 files changed, 426 insertions(+), 47 deletions(-) + 10 files changed, 425 insertions(+), 47 deletions(-) create mode 100644 requester/test/mctp_endpoint_discovery_test.cpp create mode 100644 requester/test/mock_mctp_discovery_handler_intf.hpp create mode 100644 requester/test/static_eid_table.json diff --git a/common/types.hpp b/common/types.hpp -index 6f06ecc..2c5dcdb 100644 +index 6f06ecc..138c48e 100644 --- a/common/types.hpp +++ b/common/types.hpp -@@ -16,10 +16,17 @@ namespace pldm +@@ -16,10 +16,16 @@ namespace pldm { using eid = uint8_t; @@ -49,13 +47,12 @@ index 6f06ecc..2c5dcdb 100644 +using NetworkId = uint32_t; +using MctpInfo = std::tuple; +using MctpInfos = std::vector; -+using tid_t = uint8_t; + namespace dbus { diff --git a/fw-update/manager.hpp b/fw-update/manager.hpp -index 018a703..e750571 100644 +index 018a703..06440b5 100644 --- a/fw-update/manager.hpp +++ b/fw-update/manager.hpp @@ -6,6 +6,7 @@ @@ -103,7 +100,7 @@ index 018a703..e750571 100644 + * + * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise + */ -+ void handleRemovedMctpEndpoints([[maybe_unused]] const MctpInfos& mctpInfos) ++ void handleRemovedMctpEndpoints(const MctpInfos&) + { + return; + } @@ -112,7 +109,7 @@ index 018a703..e750571 100644 * specification * diff --git a/meson.build b/meson.build -index 310f987..78f8aa4 100644 +index 3430735..b5476cf 100644 --- a/meson.build +++ b/meson.build @@ -70,6 +70,7 @@ if get_option('transport-implementation') == 'mctp-demux' @@ -124,10 +121,10 @@ index 310f987..78f8aa4 100644 configuration: conf_data ) diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp -index 23499e4..35aa265 100644 +index c1ba345..75330a6 100644 --- a/pldmd/pldmd.cpp +++ b/pldmd/pldmd.cpp -@@ -296,7 +296,9 @@ int main(int argc, char** argv) +@@ -295,7 +295,9 @@ int main(int argc, char** argv) std::unique_ptr fwManager = std::make_unique(event, reqHandler, instanceIdDb); std::unique_ptr mctpDiscoveryHandler = @@ -139,7 +136,7 @@ index 23499e4..35aa265 100644 TID](IO& io, int fd, uint32_t revents) mutable { if (!(revents & EPOLLIN)) diff --git a/requester/mctp_endpoint_discovery.cpp b/requester/mctp_endpoint_discovery.cpp -index c766a70..5fd2404 100644 +index c766a70..1004e50 100644 --- a/requester/mctp_endpoint_discovery.cpp +++ b/requester/mctp_endpoint_discovery.cpp @@ -1,9 +1,15 @@ @@ -217,8 +214,8 @@ index c766a70..5fd2404 100644 - "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); - auto reply = bus.call(method, dbusTimeout); - reply.read(objects); -+ auto mapperResponseMsg = bus.call(mapper, dbusTimeout); -+ mapperResponseMsg.read(mapperResponse); ++ auto reply = bus.call(mapper, dbusTimeout); ++ reply.read(mapperResponse); } - catch (const std::exception& e) + catch (const sdbusplus::exception_t& e) @@ -648,7 +645,7 @@ index 0000000..9f65171 + "./static_eid_table.json"); +} diff --git a/requester/test/meson.build b/requester/test/meson.build -index b7a929f..f80799d 100644 +index 328bacf..80c27c1 100644 --- a/requester/test/meson.build +++ b/requester/test/meson.build @@ -1,6 +1,12 @@ @@ -719,5 +716,5 @@ index 0000000..54146a1 + ] +} -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0002-requester-Added-coroutine-APIs.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0002-requester-Added-coroutine-APIs.patch index 14dc06c51e24..b910d50ff53e 100644 --- a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0002-requester-Added-coroutine-APIs.patch +++ b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0002-requester-Added-coroutine-APIs.patch @@ -1,7 +1,7 @@ -From a043d460a299363f3d36b71438abe655058d2fba Mon Sep 17 00:00:00 2001 +From a7753c788b4def2552f8693ec5e2a8af85f9db18 Mon Sep 17 00:00:00 2001 From: Gilbert Chen Date: Sun, 29 May 2022 18:44:19 +0100 -Subject: [PATCH 2/6] requester: Added coroutine APIs +Subject: [PATCH 2/9] requester: Added coroutine APIs Added Coroutine struct and SendRecvPldmMsg awaiter struct to send PLDM command and receive response in the same function instead of handling @@ -34,7 +34,7 @@ Change-Id: I7b47d15ac15f6ae661ec94dca6a281844b939a44 2 files changed, 295 insertions(+) diff --git a/requester/handler.hpp b/requester/handler.hpp -index 02c5d02..b358d82 100644 +index 5fc5f7b..435ed1a 100644 --- a/requester/handler.hpp +++ b/requester/handler.hpp @@ -15,6 +15,7 @@ @@ -355,5 +355,5 @@ index 3b003a0..a61fd49 100644 + EXPECT_EQ(tid, respTid); +} -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0003-platform-mc-Added-Terminus-TerminusManager-class.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0003-platform-mc-Added-Terminus-TerminusManager-class.patch index c490a2001be7..76602984f78c 100644 --- a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0003-platform-mc-Added-Terminus-TerminusManager-class.patch +++ b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0003-platform-mc-Added-Terminus-TerminusManager-class.patch @@ -1,7 +1,7 @@ -From 17bd935fbd6fe1a090e43719a5aaedcddc925cd9 Mon Sep 17 00:00:00 2001 +From bec663ad8aa64d1155d3d043da2ea9723a781e31 Mon Sep 17 00:00:00 2001 From: Gilbert Chen Date: Tue, 22 Feb 2022 15:40:17 +0000 -Subject: [PATCH 3/6] platform-mc: Added Terminus/TerminusManager class +Subject: [PATCH 3/9] platform-mc: Added Terminus/TerminusManager class Added requester::sendRecvPldmMsg awaiter type to be able to send and receive PLDM message by coroutine. @@ -43,10 +43,10 @@ Change-Id: Ifa5bdfff50648f1d7fba8710e160de662e8f9e06 create mode 100644 platform-mc/test/terminus_test.cpp diff --git a/meson.build b/meson.build -index 78f8aa4..572b0fc 100644 +index b5476cf..4045e72 100644 --- a/meson.build +++ b/meson.build -@@ -185,6 +185,9 @@ executable( +@@ -181,6 +181,9 @@ executable( 'fw-update/device_updater.cpp', 'fw-update/watch.cpp', 'fw-update/update_manager.cpp', @@ -56,7 +56,7 @@ index 78f8aa4..572b0fc 100644 'requester/mctp_endpoint_discovery.cpp', implicit_include_directories: false, dependencies: deps, -@@ -223,5 +226,6 @@ if get_option('tests').enabled() +@@ -219,5 +222,6 @@ if get_option('tests').allowed() subdir('fw-update/test') subdir('host-bmc/test') subdir('requester/test') @@ -141,7 +141,7 @@ index 0000000..f60d974 +} // namespace pldm diff --git a/platform-mc/platform_manager.cpp b/platform-mc/platform_manager.cpp new file mode 100644 -index 0000000..034fc22 +index 0000000..7e77732 --- /dev/null +++ b/platform-mc/platform_manager.cpp @@ -0,0 +1,220 @@ @@ -235,9 +235,9 @@ index 0000000..034fc22 + co_return rc; + } + -+ if (transferFlag == PLDM_START || transferFlag == PLDM_START_AND_END) ++ if (transferFlag == PLDM_START_AND_END) + { -+ // single-part or first-part transfer ++ // single-part + terminus->pdrs.emplace_back(std::vector( + recvBuf.begin(), recvBuf.begin() + responseCnt)); + recordHndl = nextRecordHndl; @@ -1161,7 +1161,7 @@ index 0000000..9722c5d +} // namespace pldm diff --git a/platform-mc/test/meson.build b/platform-mc/test/meson.build new file mode 100644 -index 0000000..73868ad +index 0000000..357df26 --- /dev/null +++ b/platform-mc/test/meson.build @@ -0,0 +1,31 @@ @@ -1188,7 +1188,7 @@ index 0000000..73868ad + gmock, + libpldm_dep, + libpldmutils, -+ nlohmann_json, ++ nlohmann_json_dep, + phosphor_dbus_interfaces, + phosphor_logging_dep, + sdbusplus, @@ -1556,7 +1556,7 @@ index 0000000..b2783c3 + EXPECT_EQ(tid, t1.getTid()); +} diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp -index 35aa265..d544c87 100644 +index 75330a6..531f439 100644 --- a/pldmd/pldmd.cpp +++ b/pldmd/pldmd.cpp @@ -6,6 +6,7 @@ @@ -1567,7 +1567,7 @@ index 35aa265..d544c87 100644 #include "requester/handler.hpp" #include "requester/mctp_endpoint_discovery.hpp" #include "requester/request.hpp" -@@ -295,10 +296,12 @@ int main(int argc, char** argv) +@@ -294,10 +295,12 @@ int main(int argc, char** argv) std::unique_ptr fwManager = std::make_unique(event, reqHandler, instanceIdDb); @@ -1583,5 +1583,5 @@ index 35aa265..d544c87 100644 TID](IO& io, int fd, uint32_t revents) mutable { if (!(revents & EPOLLIN)) -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0004-platform-mc-PDR-handling.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0004-platform-mc-PDR-handling.patch index 501dd2b4d55d..795049d23fd2 100644 --- a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0004-platform-mc-PDR-handling.patch +++ b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0004-platform-mc-PDR-handling.patch @@ -1,7 +1,7 @@ -From 3d438bef4390c4d2f3deef8421ba3c5c9b2852da Mon Sep 17 00:00:00 2001 +From ca47781ad5ac3b9cc4dae0026bc70faa796beee1 Mon Sep 17 00:00:00 2001 From: Gilbert Chen Date: Tue, 24 May 2022 15:35:21 +0100 -Subject: [PATCH 4/6] platform-mc: PDR handling +Subject: [PATCH 4/9] platform-mc: PDR handling Added parse PDR member functions to terminus class for parsing Numeric sensor PDR and sensor auxiliary names PDR. @@ -22,7 +22,7 @@ Change-Id: I30a0cc594a3c08fc17f2dad861b5c5d41c80ebdd create mode 100644 platform-mc/test/platform_manager_test.cpp diff --git a/platform-mc/platform_manager.cpp b/platform-mc/platform_manager.cpp -index 034fc22..0fbfc66 100644 +index 7e77732..f4298e0 100644 --- a/platform-mc/platform_manager.cpp +++ b/platform-mc/platform_manager.cpp @@ -18,7 +18,11 @@ requester::Coroutine PlatformManager::initTerminus() @@ -312,7 +312,7 @@ index 7b3aa53..0d4f58c 100644 } // namespace platform_mc } // namespace pldm diff --git a/platform-mc/test/meson.build b/platform-mc/test/meson.build -index 73868ad..3403753 100644 +index 357df26..bd6e880 100644 --- a/platform-mc/test/meson.build +++ b/platform-mc/test/meson.build @@ -9,6 +9,7 @@ test_src = declare_dependency( @@ -586,5 +586,5 @@ index b2783c3..7f84042 100644 + EXPECT_EQ("TEMP1", names[0][0].second); +} -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0005-platform-mc-Sensor-handling.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0005-platform-mc-Sensor-handling.patch index 50284146d46f..0740e1110536 100644 --- a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0005-platform-mc-Sensor-handling.patch +++ b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0005-platform-mc-Sensor-handling.patch @@ -1,7 +1,7 @@ -From 95c7bb3f0bd3676f86dcfe7f4ef04c16bb4a4686 Mon Sep 17 00:00:00 2001 +From 9cd7e36c546f6a3abacf0effb76edecd94156968 Mon Sep 17 00:00:00 2001 From: Gilbert Chen Date: Wed, 23 Feb 2022 20:56:19 +0000 -Subject: [PATCH 5/6] platform-mc: Sensor handling +Subject: [PATCH 5/9] platform-mc: Sensor handling Added sensor_manager and numeric_sensor class. The sensor_manager class manages the timing of sensor polling. The NumericSensor class @@ -42,7 +42,7 @@ Change-Id: I4257f823ea26d7fdb322cc82d847e94db056258c create mode 100644 platform-mc/test/sensor_manager_test.cpp diff --git a/meson.build b/meson.build -index 572b0fc..14a2e89 100644 +index 4045e72..3e5988b 100644 --- a/meson.build +++ b/meson.build @@ -71,6 +71,8 @@ elif get_option('transport-implementation') == 'af-mctp' @@ -54,7 +54,7 @@ index 572b0fc..14a2e89 100644 config = configure_file(output: 'config.h', configuration: conf_data ) -@@ -188,6 +190,8 @@ executable( +@@ -184,6 +186,8 @@ executable( 'platform-mc/terminus_manager.cpp', 'platform-mc/terminus.cpp', 'platform-mc/platform_manager.cpp', @@ -64,10 +64,10 @@ index 572b0fc..14a2e89 100644 implicit_include_directories: false, dependencies: deps, diff --git a/meson.options b/meson.options -index b11c0fb..12c5ff5 100644 +index 9e2339f..3f24007 100644 --- a/meson.options +++ b/meson.options -@@ -172,3 +172,15 @@ option( +@@ -173,3 +173,15 @@ option( value: 8384512, description: 'OEM-IBM: max DMA size' ) @@ -1626,7 +1626,7 @@ index 70293c8..90d73d6 100644 termini.erase(it); } diff --git a/platform-mc/test/meson.build b/platform-mc/test/meson.build -index 3403753..5e757c1 100644 +index bd6e880..ae23397 100644 --- a/platform-mc/test/meson.build +++ b/platform-mc/test/meson.build @@ -3,6 +3,8 @@ test_src = declare_dependency( @@ -2059,7 +2059,7 @@ index 0000000..56e1d36 + runEventLoopForSeconds(seconds); +} diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp -index d544c87..a5b57bc 100644 +index 531f439..a8ba89a 100644 --- a/pldmd/pldmd.cpp +++ b/pldmd/pldmd.cpp @@ -182,7 +182,7 @@ int main(int argc, char** argv) @@ -2072,5 +2072,5 @@ index d544c87..a5b57bc 100644 InstanceIdDb instanceIdDb; dbus_api::Requester dbusImplReq(bus, "/xyz/openbmc_project/pldm", -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0006-platform-mc-Added-EventManager.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0006-platform-mc-Added-EventManager.patch index ffa89754d7c3..ccd3cbc3314b 100644 --- a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0006-platform-mc-Added-EventManager.patch +++ b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0006-platform-mc-Added-EventManager.patch @@ -1,7 +1,7 @@ -From d5de56ee447a6116d3bcddc841f3500ef34dbc23 Mon Sep 17 00:00:00 2001 +From f1d6830fee98fc183902255289bbf480486278e2 Mon Sep 17 00:00:00 2001 From: Gilbert Chen Date: Tue, 2 May 2023 10:20:10 +0000 -Subject: [PATCH 6/6] platform-mc: Added EventManager +Subject: [PATCH 6/9] platform-mc: Added EventManager Added eventManager to handle sensor event class(00h), pldmMessagePollEvent class(05h) and OEM CPER event class(FAh) @@ -19,8 +19,8 @@ Signed-off-by: Gilbert Chen platform-mc/event_manager.cpp | 660 +++++++++++++++++++++ platform-mc/event_manager.hpp | 130 ++++ platform-mc/manager.hpp | 56 +- - platform-mc/platform_manager.cpp | 145 ++++- - platform-mc/platform_manager.hpp | 41 +- + platform-mc/platform_manager.cpp | 182 +++++- + platform-mc/platform_manager.hpp | 46 +- platform-mc/sensor_manager.cpp | 14 +- platform-mc/sensor_manager.hpp | 5 +- platform-mc/terminus.cpp | 6 +- @@ -35,14 +35,14 @@ Signed-off-by: Gilbert Chen platform-mc/test/sensor_manager_test.cpp | 4 +- platform-mc/test/terminus_manager_test.cpp | 2 +- pldmd/pldmd.cpp | 31 +- - 22 files changed, 1598 insertions(+), 23 deletions(-) + 22 files changed, 1640 insertions(+), 23 deletions(-) create mode 100644 platform-mc/event_manager.cpp create mode 100644 platform-mc/event_manager.hpp create mode 100644 platform-mc/test/event_manager_test.cpp create mode 100644 platform-mc/test/mock_event_manager.hpp diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp -index 5f71252..275bc24 100644 +index 67264c8..6c39016 100644 --- a/libpldmresponder/platform.cpp +++ b/libpldmresponder/platform.cpp @@ -342,15 +342,20 @@ Response Handler::platformEventMessage(const pldm_msg* request, @@ -69,7 +69,7 @@ index 5f71252..275bc24 100644 catch (const std::out_of_range& e) { diff --git a/meson.build b/meson.build -index 14a2e89..9c2297a 100644 +index 3e5988b..6d27668 100644 --- a/meson.build +++ b/meson.build @@ -73,6 +73,7 @@ endif @@ -80,7 +80,7 @@ index 14a2e89..9c2297a 100644 config = configure_file(output: 'config.h', configuration: conf_data ) -@@ -192,6 +193,7 @@ executable( +@@ -188,6 +189,7 @@ executable( 'platform-mc/platform_manager.cpp', 'platform-mc/sensor_manager.cpp', 'platform-mc/numeric_sensor.cpp', @@ -89,10 +89,10 @@ index 14a2e89..9c2297a 100644 implicit_include_directories: false, dependencies: deps, diff --git a/meson.options b/meson.options -index 12c5ff5..7acc3a7 100644 +index 3f24007..b5e1064 100644 --- a/meson.options +++ b/meson.options -@@ -184,3 +184,12 @@ option( +@@ -185,3 +185,12 @@ option( description: 'The interval time of sensor polling in milliseconds', value: 249 ) @@ -997,7 +997,7 @@ index 69464e3..8f8d27a 100644 } // namespace platform_mc } // namespace pldm diff --git a/platform-mc/platform_manager.cpp b/platform-mc/platform_manager.cpp -index 0fbfc66..06fb506 100644 +index f4298e0..26883be 100644 --- a/platform-mc/platform_manager.cpp +++ b/platform-mc/platform_manager.cpp @@ -9,6 +9,10 @@ namespace platform_mc @@ -1011,7 +1011,7 @@ index 0fbfc66..06fb506 100644 for (auto& [tid, terminus] : termini) { if (terminus->initalized) -@@ -18,11 +22,46 @@ requester::Coroutine PlatformManager::initTerminus() +@@ -18,11 +22,82 @@ requester::Coroutine PlatformManager::initTerminus() if (terminus->doesSupport(PLDM_PLATFORM)) { @@ -1036,6 +1036,7 @@ index 0fbfc66..06fb506 100644 + numberEventClassReturned, eventClass); + if (rc) + { ++ synchronyConfiguration = 0; + terminus->synchronyConfigurationSupported.byte = 0; + } + @@ -1045,11 +1046,46 @@ index 0fbfc66..06fb506 100644 terminus->parsePDRs(); } + ++ pldm_event_message_global_enable eventMessageGlobalEnable = ++ PLDM_EVENT_MESSAGE_GLOBAL_DISABLE; ++ uint16_t heartbeatTimer = 0; ++ /* Use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE when ++ * for eventMessageGlobalEnable when the terminus supports that type ++ */ + if (terminus->synchronyConfigurationSupported.byte & -+ (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC)) ++ (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE)) ++ { ++ heartbeatTimer = 0x78; ++ eventMessageGlobalEnable = ++ PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE; ++ } ++ /* Use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC when ++ * for eventMessageGlobalEnable when the terminus does not support ++ * PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE ++ * and supports PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC type ++ */ ++ else if (terminus->synchronyConfigurationSupported.byte & ++ (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC)) ++ { ++ eventMessageGlobalEnable = ++ PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC; ++ } ++ /* Only use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING ++ * for eventMessageGlobalEnable when the terminus only supports ++ * this type ++ */ ++ else if (terminus->synchronyConfigurationSupported.byte & ++ (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING)) ++ { ++ eventMessageGlobalEnable = ++ PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING; ++ } ++ ++ if (eventMessageGlobalEnable != PLDM_EVENT_MESSAGE_GLOBAL_DISABLE) + { + rc = co_await setEventReceiver( -+ tid, PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC); ++ tid, eventMessageGlobalEnable, ++ PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP, heartbeatTimer); + if (rc) + { + std::cerr << "setEventReceiver failed, rc=" @@ -1059,7 +1095,7 @@ index 0fbfc66..06fb506 100644 } terminus->initalized = true; } -@@ -220,5 +259,109 @@ requester::Coroutine PlatformManager::getPDRRepositoryInfo( +@@ -220,5 +295,110 @@ requester::Coroutine PlatformManager::getPDRRepositoryInfo( co_return completionCode; } @@ -1096,13 +1132,14 @@ index 0fbfc66..06fb506 100644 +} + +requester::Coroutine PlatformManager::setEventReceiver( -+ tid_t tid, pldm_event_message_global_enable eventMessageGlobalEnable) ++ tid_t tid, pldm_event_message_global_enable eventMessageGlobalEnable, ++ pldm_transport_protocol_type protocalType, uint16_t heartbeatTimer) +{ + Request request(sizeof(pldm_msg_hdr) + PLDM_SET_EVENT_RECEIVER_REQ_BYTES); + auto requestMsg = reinterpret_cast(request.data()); -+ auto rc = encode_set_event_receiver_req(0, eventMessageGlobalEnable, 0x0, -+ terminusManager.getLocalEid(), 0x0, -+ requestMsg); ++ auto rc = encode_set_event_receiver_req( ++ 0, eventMessageGlobalEnable, protocalType, ++ terminusManager.getLocalEid(), heartbeatTimer, requestMsg); + if (rc) + { + co_return rc; @@ -1170,10 +1207,10 @@ index 0fbfc66..06fb506 100644 } // namespace platform_mc } // namespace pldm diff --git a/platform-mc/platform_manager.hpp b/platform-mc/platform_manager.hpp -index ee8a498..9db1af0 100644 +index ee8a498..11c178a 100644 --- a/platform-mc/platform_manager.hpp +++ b/platform-mc/platform_manager.hpp -@@ -88,7 +88,46 @@ class PlatformManager +@@ -88,7 +88,51 @@ class PlatformManager uint32_t& repositorySize, uint32_t& largestRecordSize); @@ -1185,10 +1222,15 @@ index ee8a498..9db1af0 100644 + * generation from the terminus + * @param[in] eventReceiverEid - The EID of eventReceiver that terminus + * should send event message to ++ * @param[in] protocalType - Provided in the request to help the responder ++ * verify that the content of the eventReceiverAddressInfo field ++ * @param[in] heartbeatTimer - Amount of time in seconds after each ++ * elapsing of which the terminus shall emit a heartbeat event. + * @return coroutine return_value - PLDM completion code + */ + requester::Coroutine setEventReceiver( -+ tid_t tid, pldm_event_message_global_enable eventMessageGlobalEnable); ++ tid_t tid, pldm_event_message_global_enable eventMessageGlobalEnable, ++ pldm_transport_protocol_type protocalType, uint16_t heartbeatTimer); + + /** @brief send eventMessageBufferSize + * @param[in] tid - Destination TID @@ -1795,7 +1837,7 @@ index 0000000..a3bc204 + eventManager.pollForPlatformEventTask(tid); +} diff --git a/platform-mc/test/meson.build b/platform-mc/test/meson.build -index 5e757c1..0366482 100644 +index ae23397..abf990d 100644 --- a/platform-mc/test/meson.build +++ b/platform-mc/test/meson.build @@ -5,6 +5,7 @@ test_src = declare_dependency( @@ -1947,10 +1989,10 @@ index b77a197..2fb3f1e 100644 {} diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp -index a5b57bc..6e23e78 100644 +index a8ba89a..6cb129b 100644 --- a/pldmd/pldmd.cpp +++ b/pldmd/pldmd.cpp -@@ -270,10 +270,37 @@ int main(int argc, char** argv) +@@ -269,10 +269,37 @@ int main(int argc, char** argv) // FRU table is built lazily when a FRU command or Get PDR command is // handled. To enable building FRU table, the FRU handler is passed to the // Platform handler. @@ -1989,7 +2031,7 @@ index a5b57bc..6e23e78 100644 #ifdef OEM_IBM pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = dynamic_cast( -@@ -296,8 +323,6 @@ int main(int argc, char** argv) +@@ -295,8 +322,6 @@ int main(int argc, char** argv) std::unique_ptr fwManager = std::make_unique(event, reqHandler, instanceIdDb); @@ -1999,5 +2041,5 @@ index a5b57bc..6e23e78 100644 std::make_unique( bus, std::initializer_list{ -- -2.25.1 +2.41.0 diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0007-Support-OEM-META-write-file-request-for-post-code-hi.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0007-Support-OEM-META-write-file-request-for-post-code-hi.patch deleted file mode 100644 index cf7e03119ee7..000000000000 --- a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0007-Support-OEM-META-write-file-request-for-post-code-hi.patch +++ /dev/null @@ -1,526 +0,0 @@ -From dbc574cf1a050fb72dfbe7b8bbf04444895a0051 Mon Sep 17 00:00:00 2001 -From: Delphine CC Chiu -Date: Mon, 23 Oct 2023 17:06:54 +0800 -Subject: [PATCH] Support OEM-META write file request for post code history - -Summary: - - Support write file req when BIC sends postcode to BMC. - Also, set up TID to slot mapping table at the beginning of - the oem mata handler to correspond to the post code - belonging to which slot. - - Extend the handler with TID parameter to know which request is sent from. - -Change-Id: I56d303a5bc2f059451ee207a1de591be0d9993ac -Signed-off-by: Delphine CC Chiu ---- - libpldmresponder/meson.build | 10 ++ - meson.build | 4 + - meson.options | 8 ++ - oem/meta/libpldmresponder/file_io.cpp | 126 ++++++++++++++++++ - oem/meta/libpldmresponder/file_io.hpp | 62 +++++++++ - oem/meta/libpldmresponder/file_io_by_type.hpp | 28 ++++ - .../file_io_type_post_code.cpp | 59 ++++++++ - .../file_io_type_post_code.hpp | 42 ++++++ - pldmd/handler.hpp | 11 ++ - pldmd/invoker.hpp | 7 +- - pldmd/pldmd.cpp | 11 +- - 11 files changed, 365 insertions(+), 3 deletions(-) - create mode 100644 oem/meta/libpldmresponder/file_io.cpp - create mode 100644 oem/meta/libpldmresponder/file_io.hpp - create mode 100644 oem/meta/libpldmresponder/file_io_by_type.hpp - create mode 100644 oem/meta/libpldmresponder/file_io_type_post_code.cpp - create mode 100644 oem/meta/libpldmresponder/file_io_type_post_code.hpp - -diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build -index f949db9..9558433 100644 ---- a/libpldmresponder/meson.build -+++ b/libpldmresponder/meson.build -@@ -54,6 +54,16 @@ if get_option('oem-ibm').allowed() - ] - endif - -+if get_option('oem-meta').enabled() -+ responder_headers += [ -+ '../oem/meta/', -+ ] -+ sources += [ -+ '../oem/meta/libpldmresponder/file_io.cpp', -+ '../oem/meta/libpldmresponder/file_io_type_post_code.cpp', -+ ] -+endif -+ - libpldmresponder = library( - 'pldmresponder', - sources, -diff --git a/meson.build b/meson.build -index 2e4d8fd..c62ce37 100644 ---- a/meson.build -+++ b/meson.build -@@ -59,6 +59,10 @@ if get_option('oem-ibm').allowed() - add_project_arguments('-DOEM_IBM', language : 'c') - add_project_arguments('-DOEM_IBM', language : 'cpp') - endif -+if get_option('oem-meta').enabled() -+ add_project_arguments('-DOEM_META', language : 'c') -+ add_project_arguments('-DOEM_META', language : 'cpp') -+endif - conf_data.set('NUMBER_OF_REQUEST_RETRIES', get_option('number-of-request-retries')) - conf_data.set('INSTANCE_ID_EXPIRATION_INTERVAL',get_option('instance-id-expiration-interval')) - conf_data.set('RESPONSE_TIME_OUT',get_option('response-time-out')) -diff --git a/meson.options b/meson.options -index 9e2339f..34f69e8 100644 ---- a/meson.options -+++ b/meson.options -@@ -41,6 +41,14 @@ option( - description: 'transport via af-mctp or mctp-demux' - ) - -+# OEM Options -+option( -+ 'oem-meta', -+ type: 'feature', -+ value: 'enabled', -+ description: 'Enable Meta OEM PLDM' -+) -+ - # As per PLDM spec DSP0240 version 1.1.0, in Timing Specification for PLDM messages (Table 6), - # the instance ID for a given response will expire and become reusable if a response has not been - # received within a maximum of 6 seconds after a request is sent. By setting the dbus timeout -diff --git a/oem/meta/libpldmresponder/file_io.cpp b/oem/meta/libpldmresponder/file_io.cpp -new file mode 100644 -index 0000000..04186bc ---- /dev/null -+++ b/oem/meta/libpldmresponder/file_io.cpp -@@ -0,0 +1,126 @@ -+#include "file_io.hpp" -+ -+#include "file_io_type_post_code.hpp" -+#include "xyz/openbmc_project/Common/error.hpp" -+ -+#include -+ -+#include -+namespace pldm -+{ -+namespace responder -+{ -+ -+namespace oem_meta -+{ -+ -+using namespace sdbusplus::xyz::openbmc_project::Common::Error; -+ -+static constexpr auto mctpEndpointInterface = -+ "xyz.openbmc_project.Configuration.MCTPEndpoint"; -+ -+int setupTidToSlotMappingTable() -+{ -+ static constexpr auto searchpath = "/xyz/openbmc_project/"; -+ int depth = 0; -+ std::vector mctpInterface = {mctpEndpointInterface}; -+ pldm::utils::GetSubTreeResponse response; -+ try -+ { -+ response = pldm::utils::DBusHandler().getSubtree(searchpath, depth, -+ mctpInterface); -+ } -+ catch (const sdbusplus::exception_t& e) -+ { -+ error( -+ "getSubtree call failed with, ERROR={ERROR} PATH={PATH} INTERFACE={INTERFACE}", -+ "ERROR", e, "PATH", searchpath, "INTERFACE", mctpEndpointInterface); -+ return PLDM_ERROR; -+ } -+ -+ static constexpr auto endpointIdsProperty = "EndpointId"; -+ -+ for (const auto& [objectPath, serviceMap] : response) -+ { -+ // Split the objectPath to get the correspond slot. -+ // e.g Yosemite_4_Wailua_Falls_Slot3/BIC; -+ int slotNum = std::filesystem::path(objectPath.c_str()) -+ .parent_path() -+ .string() -+ .back() - -+ '0'; -+ -+ try -+ { -+ auto value = pldm::utils::DBusHandler().getDbusProperty( -+ objectPath.c_str(), endpointIdsProperty, mctpEndpointInterface); -+ -+ tidToSlotMap.insert({value, slotNum}); -+ } -+ catch (const sdbusplus::exception_t& e) -+ { -+ error( -+ "Error getting Names property, ERROR={ERROR} PATH={PATH} INTERFACE={INTERFACE}", -+ "ERROR", e, "PATH", searchpath, "INTERFACE", -+ mctpEndpointInterface); -+ return PLDM_ERROR; -+ } -+ } -+ -+ return PLDM_SUCCESS; -+} -+ -+std::unique_ptr Handler::getHandlerByType(uint8_t fileIOType) -+{ -+ switch (fileIOType) -+ { -+ case POST_CODE: -+ { -+ return std::make_unique(this->getTID(), -+ tidToSlotMap); -+ } -+ default: -+ { -+ error("Get invalid file io type, FILEIOTYPE={FILEIOTYPE}", -+ "FILEIOTYPE", fileIOType); -+ break; -+ } -+ } -+ return nullptr; -+} -+ -+Response Handler::writeFileIO(const pldm_msg* request, size_t payloadLength) -+{ -+ uint8_t fileIOType; -+ uint32_t length; -+ -+ std::array retDataField{}; -+ -+ auto rc = decode_oem_meta_file_io_req(request, payloadLength, &fileIOType, -+ &length, retDataField.data()); -+ -+ if (rc != PLDM_SUCCESS) -+ { -+ return ccOnlyResponse(request, rc); -+ } -+ -+ std::unique_ptr handler{}; -+ handler = getHandlerByType(fileIOType); -+ -+ if (handler == nullptr) -+ { -+ return ccOnlyResponse(request, PLDM_ERROR_UNSUPPORTED_PLDM_CMD); -+ } -+ -+ // Set requstData to vector for each handler easy to use. -+ std::vector data(std::begin(retDataField), -+ std::begin(retDataField) + length); -+ -+ rc = handler->write(data); -+ -+ return ccOnlyResponse(request, rc); -+} -+} // namespace oem_meta -+ -+} // namespace responder -+} // namespace pldm -diff --git a/oem/meta/libpldmresponder/file_io.hpp b/oem/meta/libpldmresponder/file_io.hpp -new file mode 100644 -index 0000000..9d1da9f ---- /dev/null -+++ b/oem/meta/libpldmresponder/file_io.hpp -@@ -0,0 +1,62 @@ -+#pragma once -+ -+#include "common/utils.hpp" -+#include "file_io_by_type.hpp" -+#include "pldmd/handler.hpp" -+ -+#include -+ -+#include -+ -+PHOSPHOR_LOG2_USING; -+ -+namespace pldm -+{ -+namespace responder -+{ -+namespace oem_meta -+{ -+ -+static std::map tidToSlotMap; -+ -+constexpr auto decodeDataMaxLength = 32; -+ -+enum pldm_oem_meta_file_io_type : uint8_t -+{ -+ POST_CODE = 0x00, -+}; -+ -+int setupTidToSlotMappingTable(); -+ -+class Handler : public CmdHandler -+{ -+ public: -+ Handler() -+ { -+ handlers.emplace(PLDM_OEM_META_FILEIO_CMD_WRITE_FILE, -+ [this](const pldm_msg* request, size_t payloadLength) { -+ return this->writeFileIO(request, payloadLength); -+ }); -+ -+ if (setupTidToSlotMappingTable() != PLDM_SUCCESS) -+ { -+ error("Fail to setup tid to slot mapping table"); -+ } -+ } -+ -+ private: -+ /** @brief Handler for writeFileIO command -+ * -+ * @param[in] request - pointer to PLDM request payload -+ * @param[in] payloadLength - length of the message -+ * -+ * @return PLDM response message -+ */ -+ Response writeFileIO(const pldm_msg* request, size_t payloadLength); -+ -+ std::unique_ptr getHandlerByType(uint8_t fileIOType); -+}; -+ -+} // namespace oem_meta -+} // namespace responder -+} // namespace pldm -diff --git a/oem/meta/libpldmresponder/file_io_by_type.hpp b/oem/meta/libpldmresponder/file_io_by_type.hpp -new file mode 100644 -index 0000000..2c27d42 ---- /dev/null -+++ b/oem/meta/libpldmresponder/file_io_by_type.hpp -@@ -0,0 +1,28 @@ -+#pragma once -+#include -+#include -+ -+namespace pldm -+{ -+namespace responder -+{ -+namespace oem_meta -+{ -+ -+/** -+ * @class FileHandler -+ * -+ * Base class to handle read/write of all oem file types -+ */ -+class FileHandler -+{ -+ public: -+ virtual int write(const std::vector& data) = 0; -+ virtual int read(const std::vector& data) = 0; -+ virtual ~FileHandler() {} -+}; -+ -+} // namespace oem_meta -+ -+} // namespace responder -+} // namespace pldm -diff --git a/oem/meta/libpldmresponder/file_io_type_post_code.cpp b/oem/meta/libpldmresponder/file_io_type_post_code.cpp -new file mode 100644 -index 0000000..04c92ba ---- /dev/null -+++ b/oem/meta/libpldmresponder/file_io_type_post_code.cpp -@@ -0,0 +1,59 @@ -+#include "file_io_type_post_code.hpp" -+ -+#include -+ -+PHOSPHOR_LOG2_USING; -+namespace pldm -+{ -+namespace responder -+{ -+namespace oem_meta -+{ -+using postcode_t = std::tuple>; -+ -+int PostCodeHandler::write(const std::vector& postCodeList) -+{ -+ static constexpr auto dbusService = "xyz.openbmc_project.State.Boot.Raw"; -+ static constexpr auto dbusObj = "/xyz/openbmc_project/state/boot/raw"; -+ -+ int slot = tidToSlotMap.at(tid); -+ -+ std::string dbusObjStr = dbusObj + std::to_string(slot); -+ -+ uint64_t primaryPostCode = 0; -+ -+ // Putting list of the bytes together to form a meaningful postcode -+ // AMD platform send four bytes as a post code unit -+ size_t index = 0; -+ std::for_each(postCodeList.begin(), postCodeList.end(), -+ [&primaryPostCode, &index](uint8_t postcode) { -+ primaryPostCode |= std::uint64_t(postcode) << (8 * index); -+ index++; -+ }); -+ -+ try -+ { -+ auto& bus = pldm::utils::DBusHandler::getBus(); -+ auto method = bus.new_method_call(dbusService, dbusObjStr.c_str(), -+ "org.freedesktop.DBus.Properties", -+ "Set"); -+ -+ method.append( -+ dbusService, "Value", -+ std::variant(postcode_t(primaryPostCode, {}))); -+ -+ auto reply = bus.call(method); -+ } -+ catch (const std::exception& e) -+ { -+ error("Set Post code error. ERROR={ERROR}", "ERROR", e); -+ return PLDM_ERROR; -+ } -+ -+ return PLDM_SUCCESS; -+} -+ -+} // namespace oem_meta -+ -+} // namespace responder -+} // namespace pldm -diff --git a/oem/meta/libpldmresponder/file_io_type_post_code.hpp b/oem/meta/libpldmresponder/file_io_type_post_code.hpp -new file mode 100644 -index 0000000..4458db9 ---- /dev/null -+++ b/oem/meta/libpldmresponder/file_io_type_post_code.hpp -@@ -0,0 +1,42 @@ -+#pragma once -+ -+#include "common/utils.hpp" -+#include "file_io_by_type.hpp" -+ -+namespace pldm -+{ -+namespace responder -+{ -+namespace oem_meta -+{ -+/** @class PostCodeHandler -+ * -+ * @brief Inherits and implements FileHandler. This class is used -+ * to store incoming postcode -+ */ -+class PostCodeHandler : public FileHandler -+{ -+ public: -+ PostCodeHandler(uint8_t tid, const std::map& tidToSlotMap) : -+ tid(tid), tidToSlotMap(tidToSlotMap) -+ {} -+ -+ /** @brief Method to store postcode list -+ * @param[in] data - post code -+ * @return PLDM status code -+ */ -+ int write(const std::vector& data); -+ -+ int read([[maybe_unused]] const std::vector& data) -+ { -+ return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; -+ } -+ -+ private: -+ uint8_t tid = 0; -+ const std::map tidToSlotMap; -+}; -+ -+} // namespace oem_meta -+} // namespace responder -+} // namespace pldm -diff --git a/pldmd/handler.hpp b/pldmd/handler.hpp -index cfa95eb..0cd14ba 100644 ---- a/pldmd/handler.hpp -+++ b/pldmd/handler.hpp -@@ -55,11 +55,22 @@ class CmdHandler - return response; - } - -+ void setTID(uint8_t tid) -+ { -+ this->tid = tid; -+ } -+ -+ uint8_t getTID() -+ { -+ return this->tid; -+ } -+ - protected: - /** @brief map of PLDM command code to handler - to be populated by derived - * classes. - */ - std::map handlers; -+ uint8_t tid = 0; - }; - - } // namespace responder -diff --git a/pldmd/invoker.hpp b/pldmd/invoker.hpp -index 9903e7f..094eaf1 100644 ---- a/pldmd/invoker.hpp -+++ b/pldmd/invoker.hpp -@@ -30,15 +30,18 @@ class Invoker - - /** @brief Invoke a PLDM command handler - * -+ * @param[in] tid - PLDM request TID - * @param[in] pldmType - PLDM type code - * @param[in] pldmCommand - PLDM command code - * @param[in] request - PLDM request message - * @param[in] reqMsgLen - PLDM request message size - * @return PLDM response message - */ -- Response handle(Type pldmType, Command pldmCommand, const pldm_msg* request, -- size_t reqMsgLen) -+ -+ Response handle(uint8_t tid, Type pldmType, Command pldmCommand, -+ const pldm_msg* request, size_t reqMsgLen) - { -+ handlers.at(pldmType)->setTID(tid); - return handlers.at(pldmType)->handle(pldmCommand, request, reqMsgLen); - } - -diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp -index a85157f..e302f99 100644 ---- a/pldmd/pldmd.cpp -+++ b/pldmd/pldmd.cpp -@@ -65,6 +65,10 @@ PHOSPHOR_LOG2_USING; - #include "libpldmresponder/oem_ibm_handler.hpp" - #endif - -+#ifdef OEM_META -+#include "libpldmresponder/file_io.hpp" -+#endif -+ - constexpr uint8_t MCTP_MSG_TYPE_PLDM = 1; - - using namespace pldm; -@@ -107,7 +111,7 @@ static std::optional - { - if (hdrFields.pldm_type != PLDM_FWUP) - { -- response = invoker.handle(hdrFields.pldm_type, -+ response = invoker.handle(tid, hdrFields.pldm_type, - hdrFields.command, request, - requestLen); - } -@@ -259,6 +263,11 @@ int main(int argc, char** argv) - dbusToPLDMEventHandler = std::make_unique( - pldmTransport.getEventSource(), hostEID, instanceIdDb, &reqHandler); - } -+ -+#ifdef OEM_META -+ invoker.registerHandler(PLDM_OEM, std::make_unique()); -+#endif -+ - auto biosHandler = std::make_unique( - pldmTransport.getEventSource(), hostEID, &instanceIdDb, &reqHandler, - oemBiosHandler.get()); --- -2.25.1 - diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0007-requester-support-multi-host-MCTP-devices-hot-plug.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0007-requester-support-multi-host-MCTP-devices-hot-plug.patch new file mode 100644 index 000000000000..fc1608853c0e --- /dev/null +++ b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0007-requester-support-multi-host-MCTP-devices-hot-plug.patch @@ -0,0 +1,611 @@ +From bb3c049d560b2b8c115c03200d06c2daabf6fb52 Mon Sep 17 00:00:00 2001 +From: Delphine CC Chiu +Date: Mon, 18 Dec 2023 18:40:23 +0800 +Subject: [PATCH 7/9] requester: support multi-host MCTP devices hot plug + +Currently, pldmd listens for new MCTP endpoint exposed by mctpd, but +they only shows their EID, Network Id, and SupportedMessageTypes, which +cannot fulfill some requirements, e.g., get the device's name or check +the host slot number which contains the MCTP endpoint in multi-host +system. + +In openbmc, the additional information are exposed by Entity Manager, +so that we add ConfigurationDiscoveryHandler, search for Entity +Manager's configuration when a new MCTP endpoint has been register by +mctpd. + +Objects who want to obtain the configuration can include the +ConfigurationDiscoveryHandler as their attribute, get the configuration +when needed. + +TESTED: +A series of unit test case to simulate the response of dbus call, +confirm that the configurations are succesfully stored. + +Change-Id: I59b8bf434576cbdea651848a8da11e5b870e2dfa +Signed-off-by: Delphine CC Chiu +--- + common/test/mocked_utils.hpp | 4 + + common/utils.cpp | 17 ++ + common/utils.hpp | 7 + + meson.build | 1 + + pldmd/pldmd.cpp | 7 +- + requester/configuration_discovery_handler.cpp | 165 ++++++++++++++++++ + requester/configuration_discovery_handler.hpp | 133 ++++++++++++++ + .../configuration_discovery_handler_test.cpp | 114 ++++++++++++ + requester/test/meson.build | 3 + + 9 files changed, 450 insertions(+), 1 deletion(-) + create mode 100644 requester/configuration_discovery_handler.cpp + create mode 100644 requester/configuration_discovery_handler.hpp + create mode 100644 requester/test/configuration_discovery_handler_test.cpp + +diff --git a/common/test/mocked_utils.hpp b/common/test/mocked_utils.hpp +index 71bc6e7..baaeecb 100644 +--- a/common/test/mocked_utils.hpp ++++ b/common/test/mocked_utils.hpp +@@ -39,4 +39,8 @@ class MockdBusHandler : public pldm::utils::DBusHandler + MOCK_METHOD(pldm::utils::GetSubTreeResponse, getSubtree, + (const std::string&, int, const std::vector&), + (const override)); ++ ++ MOCK_METHOD(pldm::utils::PropertyMap, getAll, ++ (const std::string&, const std::string&, const std::string&), ++ (const override)); + }; +diff --git a/common/utils.cpp b/common/utils.cpp +index 8afa1f4..446f7e9 100644 +--- a/common/utils.cpp ++++ b/common/utils.cpp +@@ -558,6 +558,23 @@ PropertyValue DBusHandler::getDbusPropertyVariant( + return value; + } + ++PropertyMap DBusHandler::getAll(const std::string& service, ++ const std::string& objPath, ++ const std::string& dbusInterface) const ++{ ++ auto& bus = DBusHandler::getBus(); ++ auto method = bus.new_method_call(service.c_str(), objPath.c_str(), ++ "org.freedesktop.DBus.Properties", ++ "GetAll"); ++ method.append(dbusInterface); ++ ++ auto response = bus.call(method); ++ PropertyMap result{}; ++ response.read(result); ++ ++ return result; ++} ++ + PropertyValue jsonEntryToDbusVal(std::string_view type, + const nlohmann::json& value) + { +diff --git a/common/utils.hpp b/common/utils.hpp +index cdc539b..dda1b10 100644 +--- a/common/utils.hpp ++++ b/common/utils.hpp +@@ -213,6 +213,10 @@ class DBusHandlerInterface + virtual PropertyValue + getDbusPropertyVariant(const char* objPath, const char* dbusProp, + const char* dbusInterface) const = 0; ++ ++ virtual PropertyMap getAll(const std::string& service, ++ const std::string& objPath, ++ const std::string& dbusInterface) const = 0; + }; + + /** +@@ -277,6 +281,9 @@ class DBusHandler : public DBusHandlerInterface + getDbusPropertyVariant(const char* objPath, const char* dbusProp, + const char* dbusInterface) const override; + ++ PropertyMap getAll(const std::string& service, const std::string& objPath, ++ const std::string& dbusInterface) const override; ++ + /** @brief The template function to get property from the requested dbus + * path + * +diff --git a/meson.build b/meson.build +index 6d27668..5e1d362 100644 +--- a/meson.build ++++ b/meson.build +@@ -191,6 +191,7 @@ executable( + 'platform-mc/numeric_sensor.cpp', + 'platform-mc/event_manager.cpp', + 'requester/mctp_endpoint_discovery.cpp', ++ 'requester/configuration_discovery_handler.cpp', + implicit_include_directories: false, + dependencies: deps, + install: true, +diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp +index 6cb129b..9296460 100644 +--- a/pldmd/pldmd.cpp ++++ b/pldmd/pldmd.cpp +@@ -7,6 +7,7 @@ + #include "fw-update/manager.hpp" + #include "invoker.hpp" + #include "platform-mc/manager.hpp" ++#include "requester/configuration_discovery_handler.hpp" + #include "requester/handler.hpp" + #include "requester/mctp_endpoint_discovery.hpp" + #include "requester/request.hpp" +@@ -226,6 +227,9 @@ int main(int argc, char** argv) + hostEffecterParser; + std::unique_ptr dbusToPLDMEventHandler; + DBusHandler dbusHandler; ++ auto configurationDiscovery = ++ std::make_unique(&dbusHandler); ++ + std::unique_ptr oemPlatformHandler{}; + std::unique_ptr oemBiosHandler{}; + +@@ -325,7 +329,8 @@ int main(int argc, char** argv) + std::unique_ptr mctpDiscoveryHandler = + std::make_unique( + bus, std::initializer_list{ +- fwManager.get(), platformManager.get()}); ++ fwManager.get(), configurationDiscovery.get()}); ++ + auto callback = [verbose, &invoker, &reqHandler, &fwManager, &pldmTransport, + TID](IO& io, int fd, uint32_t revents) mutable { + if (!(revents & EPOLLIN)) +diff --git a/requester/configuration_discovery_handler.cpp b/requester/configuration_discovery_handler.cpp +new file mode 100644 +index 0000000..4e43d2c +--- /dev/null ++++ b/requester/configuration_discovery_handler.cpp +@@ -0,0 +1,165 @@ ++#include "configuration_discovery_handler.hpp" ++ ++#include ++ ++#include ++ ++PHOSPHOR_LOG2_USING; ++ ++namespace pldm ++{ ++ ++void ConfigurationDiscoveryHandler::handleMctpEndpoints( ++ const MctpInfos& newMctpInfos) ++{ ++ for (const auto& newMctpInfo : newMctpInfos) ++ { ++ searchConfigurationFor(newMctpInfo); ++ } ++} ++ ++void ConfigurationDiscoveryHandler::handleRemovedMctpEndpoints( ++ const MctpInfos& removedMctpInfos) ++{ ++ for (const auto& removedMctpInfo : removedMctpInfos) ++ { ++ removeConfigByEid(std::get<0>(removedMctpInfo)); ++ } ++} ++ ++std::map& ++ ConfigurationDiscoveryHandler::getConfigurations() ++{ ++ return configurations; ++} ++ ++void ConfigurationDiscoveryHandler::searchConfigurationFor(MctpInfo mctpInfo) ++{ ++ constexpr auto inventoryPath = "/xyz/openbmc_project/inventory/"; ++ constexpr auto depthWithDownstreamDevices = std::ranges::count( ++ "/inventory/system/{BOARD_OR_CHASSIS}/{DEVICE}/{DOWNSTREAM_DEVICE}", ++ '/'); ++ ++ const std::vector mctpEndpoint = { ++ "xyz.openbmc_project.Configuration.MCTPEndpoint"}; ++ ++ try ++ { ++ auto response = dBusIntf->getSubtree( ++ inventoryPath, depthWithDownstreamDevices, mctpEndpoint); ++ ++ for (const auto& [objectPath, serviceMap] : response) ++ { ++ appendConfigIfEidMatch(std::get<0>(mctpInfo), objectPath, ++ serviceMap); ++ } ++ } ++ catch (const sdbusplus::exception_t& e) ++ { ++ error("{FUNC}: Failed to getSubtree with MCTPEndpoint, error={ERROR}", ++ "FUNC", std::string(__func__), "ERROR", e.what()); ++ return; ++ } ++ catch (const std::exception& e) ++ { ++ error("{FUNC}: Unpredicted error occured, error={ERROR}", "FUNC", ++ std::string(__func__), "ERROR", e.what()); ++ return; ++ } ++} ++ ++void ConfigurationDiscoveryHandler::appendConfigIfEidMatch( ++ uint8_t targetEid, const std::string& configPath, ++ const pldm::utils::MapperServiceMap& serviceMap) ++{ ++ if (!configurations.contains(configPath)) ++ { ++ const auto& serviceName = serviceMap.at(0).first; ++ ++ /** mctpEndpointInterface should be ++ * "xyz.openbmc_project.Configuration.MCTPEndpoint". ++ */ ++ const auto& mctpEndpointInterface = serviceMap.at(0).second.at(0); ++ try ++ { ++ auto response = dBusIntf->getAll(serviceName, configPath, ++ mctpEndpointInterface); ++ appendIfEidMatch(targetEid, configPath, ++ parseMctpEndpointFromResponse(response)); ++ } ++ catch (const sdbusplus::exception_t& e) ++ { ++ error( ++ "{FUNC}: Failed to getAll of interface={INTERFACE} in path={PATH}, error={ERROR}", ++ "FUNC", std::string(__func__), "INTERFACE", ++ mctpEndpointInterface, "PATH", configPath, "ERROR", e.what()); ++ return; ++ } ++ catch (const NoSuchPropertiesException& e) ++ { ++ error("{FUNC}: Insufficient properties in {PATH}, error={ERROR}", ++ "FUNC", std::string(__func__), "PATH", configPath, "ERROR", ++ e.what()); ++ return; ++ } ++ catch (const std::exception& e) ++ { ++ error("{FUNC}: Unpredicted error occured, error={ERROR}", "FUNC", ++ std::string(__func__), "ERROR", e.what()); ++ return; ++ } ++ } ++} ++ ++MctpEndpoint ConfigurationDiscoveryHandler::parseMctpEndpointFromResponse( ++ const pldm::utils::PropertyMap& response) ++{ ++ if (response.contains("Address") && response.contains("Bus") && ++ response.contains("EndpointId") && response.contains("Name")) ++ { ++ auto address = std::get(response.at("Address")); ++ auto eid = std::get(response.at("EndpointId")); ++ auto bus = std::get(response.at("Bus")); ++ auto componentName = std::get(response.at("Name")); ++ ++ return MctpEndpoint{address, eid, bus, componentName}; ++ } ++ else ++ { ++ std::vector missingProperties{}; ++ if (response.contains("Address")) ++ missingProperties.emplace_back("Address"); ++ if (response.contains("Bus")) ++ missingProperties.emplace_back("Bus"); ++ if (response.contains("EndpointId")) ++ missingProperties.emplace_back("EndpointId"); ++ if (response.contains("Name")) ++ missingProperties.emplace_back("Name"); ++ ++ throw NoSuchPropertiesException(missingProperties); ++ } ++} ++ ++void ConfigurationDiscoveryHandler::appendIfEidMatch( ++ uint8_t targetEid, const std::string& configPath, ++ const MctpEndpoint& endpoint) ++{ ++ if (endpoint.EndpointId == targetEid) ++ { ++ configurations.emplace(configPath, endpoint); ++ } ++} ++ ++void ConfigurationDiscoveryHandler::removeConfigByEid(uint8_t eid) ++{ ++ for (const auto& [configDbusPath, mctpEndpoint] : configurations) ++ { ++ if (mctpEndpoint.EndpointId == eid) ++ { ++ configurations.erase(configDbusPath); ++ return; ++ } ++ } ++} ++ ++} // namespace pldm +diff --git a/requester/configuration_discovery_handler.hpp b/requester/configuration_discovery_handler.hpp +new file mode 100644 +index 0000000..59bc384 +--- /dev/null ++++ b/requester/configuration_discovery_handler.hpp +@@ -0,0 +1,133 @@ ++#pragma once ++ ++#include "common/utils.hpp" ++#include "mctp_endpoint_discovery.hpp" ++ ++#include ++ ++namespace pldm ++{ ++ ++struct MctpEndpoint ++{ ++ uint64_t address; ++ uint64_t EndpointId; ++ uint64_t bus; ++ std::string name; ++}; ++ ++class ConfigurationDiscoveryHandler : public MctpDiscoveryHandlerIntf ++{ ++ public: ++ ConfigurationDiscoveryHandler() = delete; ++ ConfigurationDiscoveryHandler(const ConfigurationDiscoveryHandler&) = ++ delete; ++ ConfigurationDiscoveryHandler(ConfigurationDiscoveryHandler&&) = delete; ++ ConfigurationDiscoveryHandler& ++ operator=(const ConfigurationDiscoveryHandler&) = delete; ++ ConfigurationDiscoveryHandler& ++ operator=(ConfigurationDiscoveryHandler&&) = delete; ++ ~ConfigurationDiscoveryHandler() = default; ++ ++ explicit ConfigurationDiscoveryHandler( ++ const pldm::utils::DBusHandler* dBusIntf) : ++ dBusIntf(dBusIntf) ++ {} ++ ++ /** @brief Discover configuration associated with the new MCTP endpoints. ++ * ++ * @param[in] newMctpInfos - information of discovered MCTP endpoint ++ */ ++ void handleMctpEndpoints(const MctpInfos& newMctpInfos); ++ ++ /** @brief Remove configuration associated with the removed MCTP endpoints. ++ * ++ * @param[in] removedMctpInfos - the removed MCTP endpoints ++ */ ++ void handleRemovedMctpEndpoints(const MctpInfos& removedMctpInfos); ++ ++ /** @brief Get existing configurations. ++ * ++ * @return The configurations. ++ */ ++ std::map& getConfigurations(); ++ ++ private: ++ /** @brief Search for associated configuration for the MctpInfo. ++ * ++ * @param[in] mctpInfo - information of discovered MCTP endpoint ++ */ ++ void searchConfigurationFor(MctpInfo mctpInfo); ++ ++ /** @brief Append to configurations if Endpoint Id is matched. ++ * ++ * @param[in] targetEid - discovered MCTP endpoint Id ++ * @param[in] configPath - the Dbus path of a configuration ++ * @param[in] serviceMap - the map contains the service's information who ++ * expose the configuration ++ */ ++ void ++ appendConfigIfEidMatch(uint8_t targetEid, const std::string& configPath, ++ const pldm::utils::MapperServiceMap& serviceMap); ++ ++ /** @brief Parse MctpEndpoint from the response of GetAll method. ++ * ++ * @param[in] response - Response data of GetAll method ++ * ++ * @return Parsed MctpEndpoint object. ++ */ ++ MctpEndpoint ++ parseMctpEndpointFromResponse(const pldm::utils::PropertyMap& response); ++ ++ /** @brief Append to configuration if the MctpEndpoint's EID matches ++ * targetEid. ++ * ++ * @param[in] targetEid - The target EID ++ * @param[in] configPath - Discovered configuration's Dbus path ++ * @param[in] endpoint - The configuration's MctpEndpoint information. ++ */ ++ void appendIfEidMatch(uint8_t targetEid, const std::string& configPath, ++ const MctpEndpoint& endpoint); ++ ++ /** @brief Remove configuration associated with the removed MCTP endpoint. ++ * ++ * @param[in] eid - endpoint Id of the removed MCTP Endpoint ++ */ ++ void removeConfigByEid(uint8_t eid); ++ ++ /** @brief The configuration contains Dbus path and the MCTP endpoint ++ * information. ++ */ ++ std::map configurations; ++ ++ /** @brief D-Bus Interface object*/ ++ const pldm::utils::DBusHandler* dBusIntf; ++}; ++ ++class NoSuchPropertiesException : public std::exception ++{ ++ public: ++ NoSuchPropertiesException() = delete; ++ ~NoSuchPropertiesException() = default; ++ ++ explicit NoSuchPropertiesException( ++ const std::vector properties) ++ { ++ std::string missingProperties{}; ++ for (const auto& property : properties) ++ { ++ missingProperties += std::string(property) + " "; ++ } ++ message = "Interface has no properties: " + missingProperties; ++ } ++ ++ const char* what() const noexcept override ++ { ++ return message.c_str(); ++ } ++ ++ private: ++ std::string message; ++}; ++ ++} // namespace pldm +diff --git a/requester/test/configuration_discovery_handler_test.cpp b/requester/test/configuration_discovery_handler_test.cpp +new file mode 100644 +index 0000000..2d23879 +--- /dev/null ++++ b/requester/test/configuration_discovery_handler_test.cpp +@@ -0,0 +1,114 @@ ++#include "config.h" ++ ++#include "common/test/mocked_utils.hpp" ++#include "common/types.hpp" ++#include "common/utils.hpp" ++#include "requester/configuration_discovery_handler.hpp" ++ ++#include ++#include ++ ++using ::testing::_; ++ ++TEST(ConfigurationDiscoveryHandlerTest, succesfullyDiscoverConfig) ++{ ++ constexpr uint8_t EID = 10; ++ constexpr auto mockedDbusPath = ++ "/xyz/openbmc_project/inventory/system/board/Mocked_Board_Slot_1/MockedDevice"; ++ constexpr auto mockedService = "xyz.openbmc_project.EntityManager"; ++ constexpr auto mockedInterface = ++ "xyz.openbmc_project.Configuration.MCTPEndpoint"; ++ MockdBusHandler mockedUtils; ++ auto handler = ++ std::make_unique(&mockedUtils); ++ ++ pldm::utils::GetSubTreeResponse mockedGetSubtreeResponse{std::make_pair( ++ mockedDbusPath, ++ pldm::utils::MapperServiceMap{std::make_pair( ++ mockedService, pldm::utils::Interfaces{mockedInterface})})}; ++ ++ EXPECT_CALL(mockedUtils, getSubtree(_, _, _)) ++ .Times(1) ++ .WillOnce(testing::Return(mockedGetSubtreeResponse)); ++ ++ pldm::utils::PropertyMap mockGetAllResponse{ ++ {"Address", uint64_t(0x1)}, ++ {"Bus", uint64_t(0)}, ++ {"EndpointId", uint64_t(EID)}, ++ {"Name", std::string("MockedDevice")}}; ++ ++ EXPECT_CALL(mockedUtils, ++ getAll(mockedService, mockedDbusPath, mockedInterface)) ++ .Times(1) ++ .WillOnce(testing::Return(mockGetAllResponse)); ++ ++ pldm::MctpInfos mctpInfos; ++ mctpInfos.emplace_back(pldm::MctpInfo(EID, "emptyUUID", "", 1)); ++ ++ // Act ++ handler->handleMctpEndpoints(mctpInfos); ++ ++ ASSERT_EQ(1, handler->getConfigurations().size()); ++} ++ ++TEST(ConfigurationDiscoveryHandlerTest, BlockedByNoSuchElement) ++{ ++ constexpr uint8_t EID = 10; ++ constexpr auto mockedDbusPath = ++ "/xyz/openbmc_project/inventory/system/board/Mocked_Board_Slot_1/MockedDevice"; ++ constexpr auto mockedService = "xyz.openbmc_project.EntityManager"; ++ constexpr auto mockedInterface = ++ "xyz.openbmc_project.Configuration.MCTPEndpoint"; ++ MockdBusHandler mockedUtils; ++ auto handler = ++ std::make_unique(&mockedUtils); ++ ++ pldm::utils::GetSubTreeResponse mockedGetSubtreeResponse{std::make_pair( ++ mockedDbusPath, ++ pldm::utils::MapperServiceMap{std::make_pair( ++ mockedService, pldm::utils::Interfaces{mockedInterface})})}; ++ ++ EXPECT_CALL(mockedUtils, getSubtree(_, _, _)) ++ .Times(1) ++ .WillOnce(testing::Return(mockedGetSubtreeResponse)); ++ ++ pldm::utils::PropertyMap mockGetAllResponse{ ++ {"Address", uint64_t(0x1)}, ++ {"Bus", uint64_t(0)}, ++ /* No EndpointId */ ++ {"Name", std::string("MockedDevice")}}; ++ ++ EXPECT_CALL(mockedUtils, ++ getAll(mockedService, mockedDbusPath, mockedInterface)) ++ .Times(1) ++ .WillOnce(testing::Return(mockGetAllResponse)); ++ ++ pldm::MctpInfos mctpInfos; ++ mctpInfos.emplace_back(pldm::MctpInfo(EID, "emptyUUID", "", 1)); ++ ++ // Act ++ EXPECT_NO_THROW(handler->handleMctpEndpoints(mctpInfos)); ++ ++ ASSERT_EQ(0, handler->getConfigurations().size()); ++} ++ ++TEST(ConfigurationDiscoveryHandlerTest, succesfullyRemoveConfig) ++{ ++ constexpr uint8_t EID = 10; ++ ++ MockdBusHandler mockedUtils; ++ auto handler = ++ std::make_unique(&mockedUtils); ++ ++ pldm::MctpEndpoint mockedMctpEndpoint = {uint64_t(0x1), uint64_t(EID), ++ uint64_t(0), "MockedDevice"}; ++ handler->getConfigurations().emplace( ++ "/xyz/openbmc_project/inventory/system/board/Mocked_Board_Slot_1/MockedDevice", ++ mockedMctpEndpoint); ++ ++ pldm::MctpInfos mctpInfos; ++ mctpInfos.emplace_back(pldm::MctpInfo(EID, "emptyUUID", "", 1)); ++ handler->handleRemovedMctpEndpoints(mctpInfos); ++ ++ ASSERT_EQ(0, handler->getConfigurations().size()); ++} +diff --git a/requester/test/meson.build b/requester/test/meson.build +index 80c27c1..6e89e1d 100644 +--- a/requester/test/meson.build ++++ b/requester/test/meson.build +@@ -1,12 +1,14 @@ + test_src = declare_dependency( + sources: [ + '../mctp_endpoint_discovery.cpp', ++ '../configuration_discovery_handler.cpp' + ]) + + tests = [ + 'handler_test', + 'request_test', + 'mctp_endpoint_discovery_test', ++ 'configuration_discovery_handler_test', + ] + + foreach t : tests +@@ -20,6 +22,7 @@ foreach t : tests + gmock, + libpldm_dep, + nlohmann_json_dep, ++ libpldmutils, + phosphor_dbus_interfaces, + phosphor_logging_dep, + sdbusplus, +-- +2.41.0 + diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0008-Support-OEM-META-write-file-request-for-post-code-hi.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0008-Support-OEM-META-write-file-request-for-post-code-hi.patch new file mode 100644 index 000000000000..386271457d33 --- /dev/null +++ b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0008-Support-OEM-META-write-file-request-for-post-code-hi.patch @@ -0,0 +1,548 @@ +From 633ae41a13ab7dab6c3c63e29a7953c852d22ade Mon Sep 17 00:00:00 2001 +From: Delphine CC Chiu +Date: Mon, 23 Oct 2023 17:06:54 +0800 +Subject: [PATCH 8/9] Support OEM-META write file request for post code history + +Support write file req when multiple hosts send postcode to BMC +and store its post code history. + +Change-Id: I56d303a5bc2f059451ee207a1de591be0d9993ac +Signed-off-by: Delphine CC Chiu +--- + common/utils.cpp | 14 ++ + common/utils.hpp | 20 +++ + libpldmresponder/meson.build | 11 ++ + meson.build | 3 + + meson.options | 8 ++ + .../libpldmresponder/oem_meta_file_io.cpp | 63 +++++++++ + .../libpldmresponder/oem_meta_file_io.hpp | 48 +++++++ + .../oem_meta_file_io_by_type.hpp | 30 ++++ + .../oem_meta_file_io_type_post_code.cpp | 131 ++++++++++++++++++ + .../oem_meta_file_io_type_post_code.hpp | 53 +++++++ + pldmd/pldmd.cpp | 11 ++ + 11 files changed, 392 insertions(+) + create mode 100644 oem/meta/libpldmresponder/oem_meta_file_io.cpp + create mode 100644 oem/meta/libpldmresponder/oem_meta_file_io.hpp + create mode 100644 oem/meta/libpldmresponder/oem_meta_file_io_by_type.hpp + create mode 100644 oem/meta/libpldmresponder/oem_meta_file_io_type_post_code.cpp + create mode 100644 oem/meta/libpldmresponder/oem_meta_file_io_type_post_code.hpp + +diff --git a/common/utils.cpp b/common/utils.cpp +index 446f7e9..ac705a7 100644 +--- a/common/utils.cpp ++++ b/common/utils.cpp +@@ -445,6 +445,20 @@ GetSubTreeResponse + return response; + } + ++GetAncestorsResponse ++ DBusHandler::getAncestors(const std::string& searchPath, ++ const std::vector& ifaceList) const ++{ ++ auto& bus = pldm::utils::DBusHandler::getBus(); ++ auto method = bus.new_method_call(mapperBusName, mapperPath, ++ mapperInterface, "GetAncestors"); ++ method.append(searchPath, ifaceList); ++ auto reply = bus.call(method, dbusTimeout); ++ GetAncestorsResponse response; ++ reply.read(response); ++ return response; ++} ++ + void reportError(const char* errorMsg) + { + static constexpr auto logObjPath = "/xyz/openbmc_project/logging"; +diff --git a/common/utils.hpp b/common/utils.hpp +index dda1b10..1d5fc69 100644 +--- a/common/utils.hpp ++++ b/common/utils.hpp +@@ -190,6 +190,8 @@ using ServiceName = std::string; + using Interfaces = std::vector; + using MapperServiceMap = std::vector>; + using GetSubTreeResponse = std::vector>; ++using GetAncestorsResponse = ++ std::vector>; + using PropertyMap = std::map; + using InterfaceMap = std::map; + +@@ -207,6 +209,10 @@ class DBusHandlerInterface + getSubtree(const std::string& path, int depth, + const std::vector& ifaceList) const = 0; + ++ virtual GetAncestorsResponse ++ getAncestors(const std::string& path, ++ const std::vector& ifaceList) const = 0; ++ + virtual void setDbusProperty(const DBusMapping& dBusMap, + const PropertyValue& value) const = 0; + +@@ -266,6 +272,20 @@ class DBusHandler : public DBusHandlerInterface + GetSubTreeResponse + getSubtree(const std::string& path, int depth, + const std::vector& ifaceList) const override; ++ /** ++ * @brief Get the Ancestors response from the mapper ++ * ++ * @param[in] path - DBUS object path ++ * @param[in] ifaceList - list of the interface that are being ++ * queried from the mapper ++ * ++ * @return GetAncestorsResponse - the mapper GetAncestors response ++ * ++ * @throw sdbusplus::exception_t when it fails ++ */ ++ GetAncestorsResponse ++ getAncestors(const std::string& path, ++ const std::vector& ifaceList) const override; + + /** @brief Get property(type: variant) from the requested dbus + * +diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build +index 687fa82..3f71b1f 100644 +--- a/libpldmresponder/meson.build ++++ b/libpldmresponder/meson.build +@@ -27,6 +27,7 @@ sources = [ + '../host-bmc/dbus_to_host_effecters.cpp', + '../host-bmc/host_condition.cpp', + '../host-bmc/custom_dbus.cpp', ++ '../requester/configuration_discovery_handler.cpp', + 'event_parser.cpp' + ] + +@@ -54,6 +55,16 @@ if get_option('oem-ibm').allowed() + ] + endif + ++if get_option('oem-meta').allowed() ++ responder_headers += [ ++ '../oem/meta/', ++ ] ++ sources += [ ++ '../oem/meta/libpldmresponder/oem_meta_file_io.cpp', ++ '../oem/meta/libpldmresponder/oem_meta_file_io_type_post_code.cpp', ++ ] ++endif ++ + libpldmresponder = library( + 'pldmresponder', + sources, +diff --git a/meson.build b/meson.build +index 5e1d362..58d5349 100644 +--- a/meson.build ++++ b/meson.build +@@ -59,6 +59,9 @@ if get_option('oem-ibm').allowed() + add_project_arguments('-DOEM_IBM', language : 'c') + add_project_arguments('-DOEM_IBM', language : 'cpp') + endif ++if get_option('oem-meta').allowed() ++ add_project_arguments('-DOEM_META', language : ['c','cpp']) ++endif + conf_data.set('NUMBER_OF_REQUEST_RETRIES', get_option('number-of-request-retries')) + conf_data.set('INSTANCE_ID_EXPIRATION_INTERVAL',get_option('instance-id-expiration-interval')) + conf_data.set('RESPONSE_TIME_OUT',get_option('response-time-out')) +diff --git a/meson.options b/meson.options +index b5e1064..74773c4 100644 +--- a/meson.options ++++ b/meson.options +@@ -165,6 +165,14 @@ option( + description: 'Enable IBM OEM PLDM' + ) + ++# OEM Meta Options ++option( ++ 'oem-meta', ++ type: 'feature', ++ value: 'enabled', ++ description: 'Enable Meta OEM PLDM' ++) ++ + option( + 'oem-ibm-dma-maxsize', + type: 'integer', +diff --git a/oem/meta/libpldmresponder/oem_meta_file_io.cpp b/oem/meta/libpldmresponder/oem_meta_file_io.cpp +new file mode 100644 +index 0000000..fbbc353 +--- /dev/null ++++ b/oem/meta/libpldmresponder/oem_meta_file_io.cpp +@@ -0,0 +1,63 @@ ++#include "oem_meta_file_io.hpp" ++ ++#include "oem_meta_file_io_type_post_code.hpp" ++#include "xyz/openbmc_project/Common/error.hpp" ++ ++#include ++ ++#include ++namespace pldm::responder::oem_meta ++{ ++ ++using namespace sdbusplus::xyz::openbmc_project::Common::Error; ++ ++static constexpr auto mctpEndpointInterface = ++ "xyz.openbmc_project.Configuration.MCTPEndpoint"; ++ ++std::unique_ptr FileIOHandler::getHandlerByType(uint8_t messageTid, ++ uint8_t fileIOType) ++{ ++ switch (fileIOType) ++ { ++ case POST_CODE: ++ return std::make_unique( ++ messageTid, configurationDescovery->getConfigurations()); ++ default: ++ error("Get invalid file io type, FILEIOTYPE={FILEIOTYPE}", ++ "FILEIOTYPE", fileIOType); ++ break; ++ } ++ return nullptr; ++} ++ ++Response FileIOHandler::writeFileIO(pldm_tid_t tid, const pldm_msg* request, ++ size_t payloadLength) ++{ ++ uint8_t fileIOType; ++ uint32_t length; ++ ++ std::array retDataField{}; ++ ++ auto rc = decode_oem_meta_file_io_req(request, payloadLength, &fileIOType, ++ &length, retDataField.data()); ++ ++ if (rc != PLDM_SUCCESS) ++ { ++ return ccOnlyResponse(request, rc); ++ } ++ ++ auto handler = getHandlerByType(tid, fileIOType); ++ ++ if (!handler) ++ { ++ return ccOnlyResponse(request, PLDM_ERROR_UNSUPPORTED_PLDM_CMD); ++ } ++ ++ auto data = std::span(std::begin(retDataField), length); ++ ++ rc = handler->write(data); ++ ++ return ccOnlyResponse(request, rc); ++} ++ ++} // namespace pldm::responder::oem_meta +diff --git a/oem/meta/libpldmresponder/oem_meta_file_io.hpp b/oem/meta/libpldmresponder/oem_meta_file_io.hpp +new file mode 100644 +index 0000000..19ec632 +--- /dev/null ++++ b/oem/meta/libpldmresponder/oem_meta_file_io.hpp +@@ -0,0 +1,48 @@ ++#pragma once ++ ++#include "common/utils.hpp" ++#include "oem_meta_file_io_by_type.hpp" ++#include "pldmd/handler.hpp" ++#include "requester/configuration_discovery_handler.hpp" ++ ++#include ++ ++#include ++ ++PHOSPHOR_LOG2_USING; ++ ++namespace pldm::responder::oem_meta ++{ ++ ++class FileIOHandler : public CmdHandler ++{ ++ public: ++ FileIOHandler(pldm::ConfigurationDiscoveryHandler* configurationDescovery) : ++ configurationDescovery(configurationDescovery) ++ { ++ handlers.emplace(PLDM_OEM_META_FILEIO_CMD_WRITE_FILE, ++ [this](pldm_tid_t tid, const pldm_msg* request, ++ size_t payloadLength) { ++ return this->writeFileIO(tid, request, payloadLength); ++ }); ++ } ++ ++ private: ++ /** @brief Handler for writeFileIO command ++ * ++ * @param[in] tid - the device tid ++ * @param[in] request - pointer to PLDM request payload ++ * @param[in] payloadLength - length of the message ++ * ++ * @return PLDM response message ++ */ ++ Response writeFileIO(pldm_tid_t tid, const pldm_msg* request, ++ size_t payloadLength); ++ ++ std::unique_ptr getHandlerByType(pldm_tid_t tid, ++ uint8_t fileIOType); ++ ++ pldm::ConfigurationDiscoveryHandler* configurationDescovery; ++}; ++ ++} // namespace pldm::responder::oem_meta +diff --git a/oem/meta/libpldmresponder/oem_meta_file_io_by_type.hpp b/oem/meta/libpldmresponder/oem_meta_file_io_by_type.hpp +new file mode 100644 +index 0000000..739b9cd +--- /dev/null ++++ b/oem/meta/libpldmresponder/oem_meta_file_io_by_type.hpp +@@ -0,0 +1,30 @@ ++#pragma once ++#include ++#include ++ ++namespace pldm::responder::oem_meta ++{ ++/** ++ * @class FileHandler ++ * ++ * Base class to handle read/write of all OEM file types ++ */ ++ ++using message = std::span; ++using configDbusPath = std::string; ++constexpr auto decodeDataMaxLength = 32; ++ ++enum pldm_oem_meta_file_io_type : uint8_t ++{ ++ POST_CODE = 0x00, ++}; ++ ++class FileHandler ++{ ++ public: ++ virtual int write(const message& data) = 0; ++ virtual int read(const message& data) = 0; ++ virtual ~FileHandler() {} ++}; ++ ++} // namespace pldm::responder::oem_meta +diff --git a/oem/meta/libpldmresponder/oem_meta_file_io_type_post_code.cpp b/oem/meta/libpldmresponder/oem_meta_file_io_type_post_code.cpp +new file mode 100644 +index 0000000..8ef5c0e +--- /dev/null ++++ b/oem/meta/libpldmresponder/oem_meta_file_io_type_post_code.cpp +@@ -0,0 +1,131 @@ ++#include "oem_meta_file_io_type_post_code.hpp" ++ ++#include ++ ++#include ++ ++PHOSPHOR_LOG2_USING; ++namespace pldm::responder::oem_meta ++{ ++ ++using postcode_t = std::tuple>; ++ ++void PostCodeHandler::parseObjectPathToGetSlot(uint64_t& slotNum) ++{ ++ static constexpr auto slotInterface = ++ "xyz.openbmc_project.Inventory.Decorator.Slot"; ++ static constexpr auto slotNumberProperty = "SlotNumber"; ++ ++ std::vector slotInterfaceList = {slotInterface}; ++ pldm::utils::GetAncestorsResponse response; ++ bool found = false; ++ ++ for (const auto& [configDbusPath, mctpEndpoint] : configurations) ++ { ++ if (mctpEndpoint.EndpointId == tid) ++ { ++ try ++ { ++ response = pldm::utils::DBusHandler().getAncestors( ++ configDbusPath.c_str(), slotInterfaceList); ++ } ++ catch (const sdbusplus::exception_t& e) ++ { ++ error( ++ "GetAncestors call failed with, ERROR={ERROR} PATH={PATH} INTERFACE={INTERFACE}", ++ "ERROR", e, "PATH", configDbusPath.c_str(), "INTERFACE", ++ slotInterface); ++ } ++ ++ // It should be only one of the slot property existed. ++ if (response.size() != 1) ++ { ++ error("Get invalide number of slot property, SIZE={SIZE}", ++ "SIZE", response.size()); ++ return; ++ } ++ ++ try ++ { ++ slotNum = pldm::utils::DBusHandler().getDbusProperty( ++ std::get<0>(response.front()).c_str(), slotNumberProperty, ++ slotInterface); ++ found = true; ++ } ++ catch (const sdbusplus::exception_t& e) ++ { ++ error( ++ "Error getting Names property, ERROR={ERROR} PATH={PATH} INTERFACE={INTERFACE}", ++ "ERROR", e, "PATH", std::get<0>(response.front()).c_str(), ++ "INTERFACE", slotInterface); ++ } ++ } ++ } ++ ++ if (!found) ++ { ++ throw std::invalid_argument("Configuration of TID not found."); ++ } ++} ++ ++int PostCodeHandler::write(const message& postCodeList) ++{ ++ static constexpr auto dbusService = "xyz.openbmc_project.State.Boot.Raw"; ++ static constexpr auto dbusObj = "/xyz/openbmc_project/state/boot/raw"; ++ uint64_t slot; ++ ++ try ++ { ++ parseObjectPathToGetSlot(slot); ++ } ++ catch (const std::exception& e) ++ { ++ error("Fail to get the corresponding slot. TID={TID}, ERROR={ERROR}", ++ "TID", tid, "ERROR", e); ++ return PLDM_ERROR; ++ } ++ ++ std::string dbusObjStr = dbusObj + std::to_string(slot); ++ ++ uint64_t primaryPostCode = 0; ++ ++ // Putting list of the bytes together to form a meaningful postcode ++ // AMD platform send four bytes as a post code unit ++ if (std::cmp_greater( ++ std::distance(std::begin(postCodeList), std::end(postCodeList)), ++ sizeof(primaryPostCode))) ++ { ++ error("Get invalid post code length"); ++ return PLDM_ERROR; ++ } ++ ++ size_t index = 0; ++ std::for_each(postCodeList.begin(), postCodeList.end(), ++ [&primaryPostCode, &index](auto postcode) { ++ primaryPostCode |= std::uint64_t(postcode) << (8 * index); ++ index++; ++ }); ++ ++ try ++ { ++ auto& bus = pldm::utils::DBusHandler::getBus(); ++ auto method = bus.new_method_call(dbusService, dbusObjStr.c_str(), ++ "org.freedesktop.DBus.Properties", ++ "Set"); ++ ++ method.append( ++ dbusService, "Value", ++ std::variant(postcode_t(primaryPostCode, {}))); ++ ++ bus.call(method); ++ } ++ catch (const std::exception& e) ++ { ++ error("Set Post code error. ERROR={ERROR}", "ERROR", e); ++ return PLDM_ERROR; ++ } ++ ++ return PLDM_SUCCESS; ++} ++ ++} // namespace pldm::responder::oem_meta +diff --git a/oem/meta/libpldmresponder/oem_meta_file_io_type_post_code.hpp b/oem/meta/libpldmresponder/oem_meta_file_io_type_post_code.hpp +new file mode 100644 +index 0000000..780f0ef +--- /dev/null ++++ b/oem/meta/libpldmresponder/oem_meta_file_io_type_post_code.hpp +@@ -0,0 +1,53 @@ ++#pragma once ++ ++#include "common/utils.hpp" ++#include "oem_meta_file_io_by_type.hpp" ++#include "requester/configuration_discovery_handler.hpp" ++ ++namespace pldm::responder::oem_meta ++{ ++/** @class PostCodeHandler ++ * ++ * @brief Inherits and implements FileHandler. This class is used ++ * to store incoming postcode ++ */ ++class PostCodeHandler : public FileHandler ++{ ++ public: ++ PostCodeHandler(pldm_tid_t tid, ++ const std::map& configurations) : ++ tid(tid), ++ configurations(configurations) ++ {} ++ ++ ~PostCodeHandler() = default; ++ ++ /** @brief Method to store postcode list ++ * @param[in] data - post code ++ * @return PLDM status code ++ */ ++ int write(const message& data); ++ ++ /** @brief Method to read postcode list ++ * @param[in] data - post code ++ * @return PLDM status code ++ */ ++ int read(const message&) ++ { ++ return PLDM_ERROR_UNSUPPORTED_PLDM_CMD; ++ } ++ ++ private: ++ /** @brief Parse object path to get correspond slot number ++ * @param[in] slot - slot number ++ */ ++ void parseObjectPathToGetSlot(uint64_t& slot); ++ ++ /** @brief The terminus ID of the message source*/ ++ pldm_tid_t tid = 0; ++ ++ /** @brief Get existing configurations with MctpEndpoint*/ ++ const std::map& configurations; ++}; ++ ++} // namespace pldm::responder::oem_meta +diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp +index 9296460..03a7570 100644 +--- a/pldmd/pldmd.cpp ++++ b/pldmd/pldmd.cpp +@@ -67,6 +67,10 @@ PHOSPHOR_LOG2_USING; + #include "libpldmresponder/oem_ibm_handler.hpp" + #endif + ++#ifdef OEM_META ++#include "libpldmresponder/oem_meta_file_io.hpp" ++#endif ++ + constexpr uint8_t MCTP_MSG_TYPE_PLDM = 1; + + using namespace pldm; +@@ -264,6 +268,13 @@ int main(int argc, char** argv) + dbusToPLDMEventHandler = std::make_unique( + pldmTransport.getEventSource(), hostEID, instanceIdDb, &reqHandler); + } ++ ++#ifdef OEM_META ++ invoker.registerHandler( ++ PLDM_OEM, std::make_unique( ++ configurationDiscovery.get())); ++#endif ++ + auto biosHandler = std::make_unique( + pldmTransport.getEventSource(), hostEID, &instanceIdDb, &reqHandler, + oemBiosHandler.get()); +-- +2.41.0 + diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0009-platform-mc-fix-up-tid_t-to-pldm_tid_t-conversions.patch b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0009-platform-mc-fix-up-tid_t-to-pldm_tid_t-conversions.patch new file mode 100644 index 000000000000..bbe9b6aa7dbd --- /dev/null +++ b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/files/0009-platform-mc-fix-up-tid_t-to-pldm_tid_t-conversions.patch @@ -0,0 +1,866 @@ +From 1c1bc3b03969f074dc8407c6dd4f624126f4b9b4 Mon Sep 17 00:00:00 2001 +From: Patrick Williams +Date: Wed, 3 Jan 2024 11:26:32 -0600 +Subject: [PATCH 9/9] platform-mc: fix up tid_t to pldm_tid_t conversions + +An earlier patch in this sequence had defined a typedef `tid_t` +at one point in its history and some later patches rely on it. + +Fixing those all up in a separate patch that won't be sent upstream. +I'm expecting the original author(s) will figure this out on their own +before the code gets submitted. + +Signed-off-by: Patrick Williams +Change-Id: I527d77fcd18cb69aa1e2ae0c5cef5929d25f6ede +--- + platform-mc/event_manager.cpp | 8 +++--- + platform-mc/event_manager.hpp | 19 +++++++------- + platform-mc/manager.hpp | 8 +++--- + platform-mc/numeric_sensor.cpp | 4 +-- + platform-mc/numeric_sensor.hpp | 6 ++--- + platform-mc/platform_manager.cpp | 26 ++++++++++--------- + platform-mc/platform_manager.hpp | 15 ++++++----- + platform-mc/sensor_manager.cpp | 10 ++++---- + platform-mc/sensor_manager.hpp | 22 ++++++++-------- + platform-mc/terminus.cpp | 2 +- + platform-mc/terminus.hpp | 6 ++--- + platform-mc/terminus_manager.cpp | 30 ++++++++++++---------- + platform-mc/terminus_manager.hpp | 30 +++++++++++----------- + platform-mc/test/event_manager_test.cpp | 4 +-- + platform-mc/test/mock_sensor_manager.hpp | 2 +- + platform-mc/test/mock_terminus_manager.hpp | 11 ++++---- + platform-mc/test/platform_manager_test.cpp | 2 +- + platform-mc/test/sensor_manager_test.cpp | 4 +-- + platform-mc/test/terminus_manager_test.cpp | 2 +- + platform-mc/test/terminus_test.cpp | 2 +- + 20 files changed, 110 insertions(+), 103 deletions(-) + +diff --git a/platform-mc/event_manager.cpp b/platform-mc/event_manager.cpp +index dcc39ca..75400a5 100644 +--- a/platform-mc/event_manager.cpp ++++ b/platform-mc/event_manager.cpp +@@ -79,7 +79,7 @@ int decode_pldm_cper_event_data(const uint8_t* event_data, + return PLDM_SUCCESS; + } + +-int EventManager::handlePlatformEvent(tid_t tid, uint8_t eventClass, ++int EventManager::handlePlatformEvent(pldm_tid_t tid, uint8_t eventClass, + const uint8_t* eventData, + size_t eventDataSize) + { +@@ -135,7 +135,7 @@ int EventManager::handlePlatformEvent(tid_t tid, uint8_t eventClass, + return PLDM_ERROR; + } + +-requester::Coroutine EventManager::pollForPlatformEventTask(tid_t tid) ++requester::Coroutine EventManager::pollForPlatformEventTask(pldm_tid_t tid) + { + uint8_t rc = 0; + uint8_t transferOperationFlag = PLDM_GET_FIRSTPART; +@@ -241,7 +241,7 @@ requester::Coroutine EventManager::pollForPlatformEventTask(tid_t tid) + } + + requester::Coroutine EventManager::pollForPlatformEventMessage( +- tid_t tid, uint8_t transferOperationFlag, uint32_t dataTransferHandle, ++ pldm_tid_t tid, uint8_t transferOperationFlag, uint32_t dataTransferHandle, + uint16_t eventIdToAcknowledge, uint8_t& completionCode, uint8_t& eventTid, + uint16_t& eventId, uint32_t& nextDataTransferHandle, uint8_t& transferFlag, + uint8_t& eventClass, uint32_t& eventDataSize, uint8_t*& eventData, +@@ -458,7 +458,7 @@ int EventManager::createSensorThresholdLogEntry(const std::string& messageId, + return PLDM_SUCCESS; + } + +-int EventManager::processNumericSensorEvent(tid_t tid, uint16_t sensorId, ++int EventManager::processNumericSensorEvent(pldm_tid_t tid, uint16_t sensorId, + const uint8_t* sensorData, + size_t sensorDataLength) + { +diff --git a/platform-mc/event_manager.hpp b/platform-mc/event_manager.hpp +index 170a55b..303a9ec 100644 +--- a/platform-mc/event_manager.hpp ++++ b/platform-mc/event_manager.hpp +@@ -67,7 +67,7 @@ class EventManager + * @return PLDM completion code + * + */ +- int handlePlatformEvent(tid_t tid, uint8_t eventClass, ++ int handlePlatformEvent(pldm_tid_t tid, uint8_t eventClass, + const uint8_t* eventData, size_t eventDataSize); + + std::string getSensorThresholdMessageId(uint8_t previousEventState, +@@ -77,7 +77,7 @@ class EventManager + * + * @param[in] dstTid - the destination TID + */ +- requester::Coroutine pollForPlatformEventTask(tid_t tid); ++ requester::Coroutine pollForPlatformEventTask(pldm_tid_t tid); + + protected: + /** @brief Send pollForPlatformEventMessage and return response +@@ -99,11 +99,12 @@ class EventManager + * + */ + requester::Coroutine pollForPlatformEventMessage( +- tid_t tid, uint8_t transferOperationFlag, uint32_t dataTransferHandle, +- uint16_t eventIdToAcknowledge, uint8_t& completionCode, +- uint8_t& eventTid, uint16_t& eventId, uint32_t& nextDataTransferHandle, +- uint8_t& transferFlag, uint8_t& eventClass, uint32_t& eventDataSize, +- uint8_t*& eventData, uint32_t& eventDataIntegrityChecksum); ++ pldm_tid_t tid, uint8_t transferOperationFlag, ++ uint32_t dataTransferHandle, uint16_t eventIdToAcknowledge, ++ uint8_t& completionCode, uint8_t& eventTid, uint16_t& eventId, ++ uint32_t& nextDataTransferHandle, uint8_t& transferFlag, ++ uint8_t& eventClass, uint32_t& eventDataSize, uint8_t*& eventData, ++ uint32_t& eventDataIntegrityChecksum); + + virtual int processCperEvent(const uint8_t* eventData, + size_t eventDataSize); +@@ -111,7 +112,7 @@ class EventManager + int createCperDumpEntry(const std::string& dataType, + const std::string& dataPath); + +- int processNumericSensorEvent(tid_t tid, uint16_t sensorId, ++ int processNumericSensorEvent(pldm_tid_t tid, uint16_t sensorId, + const uint8_t* sensorData, + size_t sensorDataLength); + +@@ -124,7 +125,7 @@ class EventManager + TerminusManager& terminusManager; + + /** @brief List of discovered termini */ +- std::map>& termini; ++ std::map>& termini; + }; + } // namespace platform_mc + } // namespace pldm +diff --git a/platform-mc/manager.hpp b/platform-mc/manager.hpp +index 8f8d27a..baaeb5c 100644 +--- a/platform-mc/manager.hpp ++++ b/platform-mc/manager.hpp +@@ -63,12 +63,12 @@ class Manager : public pldm::MctpDiscoveryHandlerIntf + terminusManager.removeMctpTerminus(mctpInfos); + } + +- void startSensorPolling(tid_t tid) ++ void startSensorPolling(pldm_tid_t tid) + { + sensorManager.startPolling(tid); + } + +- void stopSensorPolling(tid_t tid) ++ void stopSensorPolling(pldm_tid_t tid) + { + sensorManager.stopPolling(tid); + } +@@ -110,7 +110,7 @@ class Manager : public pldm::MctpDiscoveryHandlerIntf + return PLDM_SUCCESS; + } + +- requester::Coroutine pollForPlatformEvent(tid_t tid) ++ requester::Coroutine pollForPlatformEvent(pldm_tid_t tid) + { + auto it = termini.find(tid); + if (it != termini.end()) +@@ -124,7 +124,7 @@ class Manager : public pldm::MctpDiscoveryHandlerIntf + + private: + /** @brief List of discovered termini */ +- std::map> termini{}; ++ std::map> termini{}; + + TerminusManager terminusManager; + PlatformManager platformManager; +diff --git a/platform-mc/numeric_sensor.cpp b/platform-mc/numeric_sensor.cpp +index 7966ff6..0104c51 100644 +--- a/platform-mc/numeric_sensor.cpp ++++ b/platform-mc/numeric_sensor.cpp +@@ -13,7 +13,7 @@ namespace pldm + namespace platform_mc + { + +-NumericSensor::NumericSensor(const tid_t tid, const bool sensorDisabled, ++NumericSensor::NumericSensor(const pldm_tid_t tid, const bool sensorDisabled, + std::shared_ptr pdr, + std::string& sensorName, + std::string& associationPath) : +@@ -241,7 +241,7 @@ NumericSensor::NumericSensor(const tid_t tid, const bool sensorDisabled, + } + + NumericSensor::NumericSensor( +- const tid_t tid, const bool sensorDisabled, ++ const pldm_tid_t tid, const bool sensorDisabled, + std::shared_ptr pdr, + std::string& sensorName, std::string& associationPath) : + tid(tid), +diff --git a/platform-mc/numeric_sensor.hpp b/platform-mc/numeric_sensor.hpp +index 06239a2..91f3718 100644 +--- a/platform-mc/numeric_sensor.hpp ++++ b/platform-mc/numeric_sensor.hpp +@@ -44,11 +44,11 @@ using AssociationDefinitionsInft = sdbusplus::server::object_t< + class NumericSensor + { + public: +- NumericSensor(const tid_t tid, const bool sensorDisabled, ++ NumericSensor(const pldm_tid_t tid, const bool sensorDisabled, + std::shared_ptr pdr, + std::string& sensorName, std::string& associationPath); + +- NumericSensor(const tid_t tid, const bool sensorDisabled, ++ NumericSensor(const pldm_tid_t tid, const bool sensorDisabled, + std::shared_ptr pdr, + std::string& sensorName, std::string& associationPath); + +@@ -153,7 +153,7 @@ class NumericSensor + }; + + /** @brief Terminus ID which the sensor belongs to */ +- tid_t tid; ++ pldm_tid_t tid; + + /** @brief Sensor ID */ + uint16_t sensorId; +diff --git a/platform-mc/platform_manager.cpp b/platform-mc/platform_manager.cpp +index 26883be..6216a03 100644 +--- a/platform-mc/platform_manager.cpp ++++ b/platform-mc/platform_manager.cpp +@@ -107,7 +107,7 @@ requester::Coroutine PlatformManager::initTerminus() + requester::Coroutine + PlatformManager::getPDRs(std::shared_ptr terminus) + { +- tid_t tid = terminus->getTid(); ++ pldm_tid_t tid = terminus->getTid(); + + uint8_t repositoryState = 0; + uint32_t recordCount = 0; +@@ -219,12 +219,12 @@ requester::Coroutine + } + + requester::Coroutine PlatformManager::getPDR( +- const tid_t tid, const uint32_t recordHndl, const uint32_t dataTransferHndl, +- const uint8_t transferOpFlag, const uint16_t requestCnt, +- const uint16_t recordChgNum, uint32_t& nextRecordHndl, +- uint32_t& nextDataTransferHndl, uint8_t& transferFlag, +- uint16_t& responseCnt, std::vector& recordData, +- uint8_t& transferCrc) ++ const pldm_tid_t tid, const uint32_t recordHndl, ++ const uint32_t dataTransferHndl, const uint8_t transferOpFlag, ++ const uint16_t requestCnt, const uint16_t recordChgNum, ++ uint32_t& nextRecordHndl, uint32_t& nextDataTransferHndl, ++ uint8_t& transferFlag, uint16_t& responseCnt, ++ std::vector& recordData, uint8_t& transferCrc) + { + Request request(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES); + auto requestMsg = reinterpret_cast(request.data()); +@@ -258,7 +258,7 @@ requester::Coroutine PlatformManager::getPDR( + } + + requester::Coroutine PlatformManager::getPDRRepositoryInfo( +- const tid_t tid, uint8_t& repositoryState, uint32_t& recordCount, ++ const pldm_tid_t tid, uint8_t& repositoryState, uint32_t& recordCount, + uint32_t& repositorySize, uint32_t& largestRecordSize) + { + Request request(sizeof(pldm_msg_hdr) + sizeof(uint8_t)); +@@ -295,8 +295,10 @@ requester::Coroutine PlatformManager::getPDRRepositoryInfo( + co_return completionCode; + } + +-requester::Coroutine PlatformManager::eventMessageBufferSize( +- tid_t tid, uint16_t receiverMaxBufferSize, uint16_t& terminusBufferSize) ++requester::Coroutine ++ PlatformManager::eventMessageBufferSize(pldm_tid_t tid, ++ uint16_t receiverMaxBufferSize, ++ uint16_t& terminusBufferSize) + { + Request request(sizeof(pldm_msg_hdr) + + PLDM_EVENT_MESSAGE_BUFFER_SIZE_REQ_BYTES); +@@ -328,7 +330,7 @@ requester::Coroutine PlatformManager::eventMessageBufferSize( + } + + requester::Coroutine PlatformManager::setEventReceiver( +- tid_t tid, pldm_event_message_global_enable eventMessageGlobalEnable, ++ pldm_tid_t tid, pldm_event_message_global_enable eventMessageGlobalEnable, + pldm_transport_protocol_type protocalType, uint16_t heartbeatTimer) + { + Request request(sizeof(pldm_msg_hdr) + PLDM_SET_EVENT_RECEIVER_REQ_BYTES); +@@ -361,7 +363,7 @@ requester::Coroutine PlatformManager::setEventReceiver( + } + + requester::Coroutine PlatformManager::eventMessageSupported( +- tid_t tid, uint8_t formatVersion, uint8_t& synchronyConfiguration, ++ pldm_tid_t tid, uint8_t formatVersion, uint8_t& synchronyConfiguration, + bitfield8_t& synchronyConfigurationSupported, + uint8_t& numberEventClassReturned, std::vector& eventClass) + { +diff --git a/platform-mc/platform_manager.hpp b/platform-mc/platform_manager.hpp +index 11c178a..3e0e8a3 100644 +--- a/platform-mc/platform_manager.hpp ++++ b/platform-mc/platform_manager.hpp +@@ -30,7 +30,7 @@ class PlatformManager + + explicit PlatformManager( + TerminusManager& terminusManager, +- std::map>& termini) : ++ std::map>& termini) : + terminusManager(terminusManager), + termini(termini) + {} +@@ -65,7 +65,7 @@ class PlatformManager + * @return coroutine return_value - PLDM completion code + */ + requester::Coroutine +- getPDR(const tid_t tid, const uint32_t recordHndl, ++ getPDR(const pldm_tid_t tid, const uint32_t recordHndl, + const uint32_t dataTransferHndl, const uint8_t transferOpFlag, + const uint16_t requestCnt, const uint16_t recordChgNum, + uint32_t& nextRecordHndl, uint32_t& nextDataTransferHndl, +@@ -82,7 +82,7 @@ class PlatformManager + * * + * @return coroutine return_value - PLDM completion code + */ +- requester::Coroutine getPDRRepositoryInfo(const tid_t tid, ++ requester::Coroutine getPDRRepositoryInfo(const pldm_tid_t tid, + uint8_t& repositoryState, + uint32_t& recordCount, + uint32_t& repositorySize, +@@ -102,7 +102,8 @@ class PlatformManager + * @return coroutine return_value - PLDM completion code + */ + requester::Coroutine setEventReceiver( +- tid_t tid, pldm_event_message_global_enable eventMessageGlobalEnable, ++ pldm_tid_t tid, ++ pldm_event_message_global_enable eventMessageGlobalEnable, + pldm_transport_protocol_type protocalType, uint16_t heartbeatTimer); + + /** @brief send eventMessageBufferSize +@@ -111,7 +112,7 @@ class PlatformManager + * @param[out] terminusBufferSize + * @return coroutine return_value - PLDM completion code + */ +- requester::Coroutine eventMessageBufferSize(tid_t tid, ++ requester::Coroutine eventMessageBufferSize(pldm_tid_t tid, + uint16_t receiverMaxBufferSize, + uint16_t& terminusBufferSize); + +@@ -128,7 +129,7 @@ class PlatformManager + * @return coroutine return_value - PLDM completion code + */ + requester::Coroutine eventMessageSupported( +- tid_t tid, uint8_t formatVersion, uint8_t& synchronyConfiguration, ++ pldm_tid_t tid, uint8_t formatVersion, uint8_t& synchronyConfiguration, + bitfield8_t& synchronyConfigurationSupported, + uint8_t& numerEventClassReturned, std::vector& eventClass); + +@@ -136,7 +137,7 @@ class PlatformManager + TerminusManager& terminusManager; + + /** @brief Managed termini list */ +- std::map>& termini; ++ std::map>& termini; + }; + } // namespace platform_mc + } // namespace pldm +diff --git a/platform-mc/sensor_manager.cpp b/platform-mc/sensor_manager.cpp +index 949ba1c..98b20cf 100644 +--- a/platform-mc/sensor_manager.cpp ++++ b/platform-mc/sensor_manager.cpp +@@ -14,7 +14,7 @@ using namespace std::chrono; + + SensorManager::SensorManager( + sdeventplus::Event& event, TerminusManager& terminusManager, +- std::map>& termini, Manager* manager, ++ std::map>& termini, Manager* manager, + bool verbose, const std::filesystem::path& configJson) : + event(event), + terminusManager(terminusManager), termini(termini), +@@ -62,7 +62,7 @@ bool SensorManager::isPriority(std::shared_ptr sensor) + sensor->sensorNameSpace) != + prioritySensorNameSpaces.end()); + } +-void SensorManager::startPolling(tid_t tid) ++void SensorManager::startPolling(pldm_tid_t tid) + { + // initialize prioritySensors and roundRobinSensors list + for (const auto& [tId, terminus] : termini) +@@ -103,7 +103,7 @@ void SensorManager::startPolling(tid_t tid) + } + } + +-void SensorManager::stopPolling(tid_t tid) ++void SensorManager::stopPolling(pldm_tid_t tid) + { + if (prioritySensors.find(tid) != prioritySensors.end()) + { +@@ -131,7 +131,7 @@ void SensorManager::stopPolling(tid_t tid) + } + } + +-void SensorManager::doSensorPolling(tid_t tid) ++void SensorManager::doSensorPolling(pldm_tid_t tid) + { + if (doSensorPollingTaskHandles[tid]) + { +@@ -157,7 +157,7 @@ void SensorManager::doSensorPolling(tid_t tid) + } + } + +-requester::Coroutine SensorManager::doSensorPollingTask(tid_t tid) ++requester::Coroutine SensorManager::doSensorPollingTask(pldm_tid_t tid) + { + uint64_t t0 = 0; + uint64_t t1 = 0; +diff --git a/platform-mc/sensor_manager.hpp b/platform-mc/sensor_manager.hpp +index 94dc4f2..7191f57 100644 +--- a/platform-mc/sensor_manager.hpp ++++ b/platform-mc/sensor_manager.hpp +@@ -32,26 +32,26 @@ class SensorManager + + explicit SensorManager( + sdeventplus::Event& event, TerminusManager& terminusManager, +- std::map>& termini, Manager* manager, +- bool verbose = false, ++ std::map>& termini, ++ Manager* manager, bool verbose = false, + const std::filesystem::path& configJson = PLDM_T2_CONFIG_JSON); + + /** @brief starting sensor polling task + */ +- void startPolling(tid_t tid); ++ void startPolling(pldm_tid_t tid); + + /** @brief stopping sensor polling task + */ +- void stopPolling(tid_t tid); ++ void stopPolling(pldm_tid_t tid); + + protected: + /** @brief start a coroutine for polling all sensors. + */ +- virtual void doSensorPolling(tid_t tid); ++ virtual void doSensorPolling(pldm_tid_t tid); + + /** @brief polling all sensors in each terminus + */ +- requester::Coroutine doSensorPollingTask(tid_t tid); ++ requester::Coroutine doSensorPollingTask(pldm_tid_t tid); + + /** @brief Sending getSensorReading command for the sensor + * +@@ -73,16 +73,16 @@ class SensorManager + TerminusManager& terminusManager; + + /** @brief List of discovered termini */ +- std::map>& termini; ++ std::map>& termini; + + /** @brief sensor polling interval in ms. */ + uint32_t pollingTime; + + /** @brief sensor polling timers */ +- std::map> sensorPollTimers; ++ std::map> sensorPollTimers; + + /** @brief coroutine handle of doSensorPollingTasks */ +- std::map> doSensorPollingTaskHandles; ++ std::map> doSensorPollingTaskHandles; + + /** @brief force stop polling sensors*/ + bool forceStopPolling = false; +@@ -94,11 +94,11 @@ class SensorManager + std::vector prioritySensorNameSpaces; + + /** @brief priority sensor list */ +- std::map>> ++ std::map>> + prioritySensors; + + /** @brief round robin sensor list */ +- std::map>> ++ std::map>> + roundRobinSensors; + + /** @brief pointer to Manager */ +diff --git a/platform-mc/terminus.cpp b/platform-mc/terminus.cpp +index fd54e3b..81f18a6 100644 +--- a/platform-mc/terminus.cpp ++++ b/platform-mc/terminus.cpp +@@ -11,7 +11,7 @@ namespace platform_mc + /* default the max message buffer size BMC supported to 4K bytes */ + #define MAX_MESSAGE_BUFFER_SIZE 4096 + +-Terminus::Terminus(tid_t tid, uint64_t supportedTypes) : ++Terminus::Terminus(pldm_tid_t tid, uint64_t supportedTypes) : + initalized(false), maxBufferSize(MAX_MESSAGE_BUFFER_SIZE), + synchronyConfigurationSupported(0), pollEvent(false), tid(tid), + supportedTypes(supportedTypes) +diff --git a/platform-mc/terminus.hpp b/platform-mc/terminus.hpp +index 0aa3c92..30d2b25 100644 +--- a/platform-mc/terminus.hpp ++++ b/platform-mc/terminus.hpp +@@ -36,7 +36,7 @@ using InventoryItemBoardIntf = sdbusplus::server::object_t< + class Terminus + { + public: +- Terminus(tid_t tid, uint64_t supportedPLDMTypes); ++ Terminus(pldm_tid_t tid, uint64_t supportedPLDMTypes); + + /** @brief Check if the terminus supports the PLDM type message + * +@@ -51,7 +51,7 @@ class Terminus + bool parsePDRs(); + + /** @brief The getter to return terminus's TID */ +- tid_t getTid() ++ pldm_tid_t getTid() + { + return tid; + } +@@ -103,7 +103,7 @@ class Terminus + std::shared_ptr + parseCompactNumericSensorNames(const std::vector& pdrData); + +- tid_t tid; ++ pldm_tid_t tid; + + std::bitset<64> supportedTypes; + +diff --git a/platform-mc/terminus_manager.cpp b/platform-mc/terminus_manager.cpp +index 90d73d6..d87d93c 100644 +--- a/platform-mc/terminus_manager.cpp ++++ b/platform-mc/terminus_manager.cpp +@@ -7,7 +7,7 @@ namespace pldm + namespace platform_mc + { + +-std::optional TerminusManager::toMctpInfo(const tid_t& tid) ++std::optional TerminusManager::toMctpInfo(const pldm_tid_t& tid) + { + if (transportLayerTable[tid] != SupportedTransportLayer::MCTP) + { +@@ -23,7 +23,7 @@ std::optional TerminusManager::toMctpInfo(const tid_t& tid) + return it->second; + } + +-std::optional TerminusManager::toTid(const MctpInfo& mctpInfo) ++std::optional TerminusManager::toTid(const MctpInfo& mctpInfo) + { + auto mctpInfoTableIterator = std::find_if( + mctpInfoTable.begin(), mctpInfoTable.end(), [&mctpInfo](auto& v) { +@@ -37,8 +37,8 @@ std::optional TerminusManager::toTid(const MctpInfo& mctpInfo) + return mctpInfoTableIterator->first; + } + +-std::optional TerminusManager::mapTid(const MctpInfo& mctpInfo, +- tid_t tid) ++std::optional TerminusManager::mapTid(const MctpInfo& mctpInfo, ++ pldm_tid_t tid) + { + if (tidPool[tid]) + { +@@ -52,7 +52,7 @@ std::optional TerminusManager::mapTid(const MctpInfo& mctpInfo, + return tid; + } + +-std::optional TerminusManager::mapTid(const MctpInfo& mctpInfo) ++std::optional TerminusManager::mapTid(const MctpInfo& mctpInfo) + { + if (std::get<0>(mctpInfo) == 0 || std::get<0>(mctpInfo) == 0xff) + { +@@ -75,11 +75,11 @@ std::optional TerminusManager::mapTid(const MctpInfo& mctpInfo) + return std::nullopt; + } + +- tid_t tid = std::distance(tidPool.begin(), tidPoolIterator); ++ pldm_tid_t tid = std::distance(tidPool.begin(), tidPoolIterator); + return mapTid(mctpInfo, tid); + } + +-bool TerminusManager::unmapTid(const tid_t& tid) ++bool TerminusManager::unmapTid(const pldm_tid_t& tid) + { + if (tid == 0 || tid == PLDM_TID_RESERVED) + { +@@ -115,7 +115,7 @@ void TerminusManager::discoverMctpTerminus(const MctpInfos& mctpInfos) + } + } + +-std::map>::iterator ++std::map>::iterator + TerminusManager::findTeminusPtr(const MctpInfo& mctpInfo) + { + bool found = false; +@@ -143,7 +143,7 @@ std::map>::iterator + + requester::Coroutine TerminusManager::discoverMctpTerminusTask() + { +- std::vector addedTids; ++ std::vector addedTids; + while (!queuedMctpInfos.empty()) + { + if (manager) +@@ -208,7 +208,7 @@ void TerminusManager::removeMctpTerminus(const MctpInfos& mctpInfos) + requester::Coroutine TerminusManager::initMctpTerminus(const MctpInfo& mctpInfo) + { + mctp_eid_t eid = std::get<0>(mctpInfo); +- tid_t tid = 0; ++ pldm_tid_t tid = 0; + bool isMapped = false; + auto rc = co_await getTidOverMctp(eid, &tid); + if (rc || tid == PLDM_TID_RESERVED) +@@ -308,7 +308,8 @@ requester::Coroutine + co_return rc; + } + +-requester::Coroutine TerminusManager::getTidOverMctp(mctp_eid_t eid, tid_t* tid) ++requester::Coroutine TerminusManager::getTidOverMctp(mctp_eid_t eid, ++ pldm_tid_t* tid) + { + auto instanceId = instanceIdDb.next(eid); + Request request(sizeof(pldm_msg_hdr)); +@@ -343,7 +344,8 @@ requester::Coroutine TerminusManager::getTidOverMctp(mctp_eid_t eid, tid_t* tid) + co_return completionCode; + } + +-requester::Coroutine TerminusManager::setTidOverMctp(mctp_eid_t eid, tid_t tid) ++requester::Coroutine TerminusManager::setTidOverMctp(mctp_eid_t eid, ++ pldm_tid_t tid) + { + auto instanceId = instanceIdDb.next(eid); + Request request(sizeof(pldm_msg_hdr) + sizeof(pldm_set_tid_req)); +@@ -372,7 +374,7 @@ requester::Coroutine TerminusManager::setTidOverMctp(mctp_eid_t eid, tid_t tid) + co_return responseMsg->payload[0]; + } + +-requester::Coroutine TerminusManager::getPLDMTypes(tid_t tid, ++requester::Coroutine TerminusManager::getPLDMTypes(pldm_tid_t tid, + uint64_t& supportedTypes) + { + Request request(sizeof(pldm_msg_hdr)); +@@ -408,7 +410,7 @@ requester::Coroutine TerminusManager::getPLDMTypes(tid_t tid, + } + + requester::Coroutine +- TerminusManager::SendRecvPldmMsg(tid_t tid, Request& request, ++ TerminusManager::SendRecvPldmMsg(pldm_tid_t tid, Request& request, + const pldm_msg** responseMsg, + size_t* responseLen) + { +diff --git a/platform-mc/terminus_manager.hpp b/platform-mc/terminus_manager.hpp +index 15d643b..f881d70 100644 +--- a/platform-mc/terminus_manager.hpp ++++ b/platform-mc/terminus_manager.hpp +@@ -21,7 +21,7 @@ enum SupportedTransportLayer + + namespace platform_mc + { +-constexpr size_t tidPoolSize = std::numeric_limits::max() + 1; ++constexpr size_t tidPoolSize = std::numeric_limits::max() + 1; + using RequesterHandler = requester::Handler; + + class Manager; +@@ -44,7 +44,7 @@ class TerminusManager + sdeventplus::Event& event, + requester::Handler& handler, + pldm::InstanceIdDb& instanceIdDb, +- std::map>& termini, ++ std::map>& termini, + mctp_eid_t localEid, Manager* manager) : + event(event), + handler(handler), instanceIdDb(instanceIdDb), termini(termini), +@@ -76,7 +76,7 @@ class TerminusManager + * @param[out] responseLen - length of response PLDM message + * @return coroutine return_value - PLDM completion code + */ +- requester::Coroutine SendRecvPldmMsg(tid_t tid, Request& request, ++ requester::Coroutine SendRecvPldmMsg(pldm_tid_t tid, Request& request, + const pldm_msg** responseMsg, + size_t* responseLen); + +@@ -96,11 +96,11 @@ class TerminusManager + + /** @brief member functions to map/unmap tid + */ +- std::optional toMctpInfo(const tid_t& tid); +- std::optional toTid(const MctpInfo& mctpInfo); +- std::optional mapTid(const MctpInfo& mctpInfo); +- std::optional mapTid(const MctpInfo& mctpInfo, tid_t tid); +- bool unmapTid(const tid_t& tid); ++ std::optional toMctpInfo(const pldm_tid_t& tid); ++ std::optional toTid(const MctpInfo& mctpInfo); ++ std::optional mapTid(const MctpInfo& mctpInfo); ++ std::optional mapTid(const MctpInfo& mctpInfo, pldm_tid_t tid); ++ bool unmapTid(const pldm_tid_t& tid); + + /** @brief getter of local EID + * +@@ -132,13 +132,13 @@ class TerminusManager + * @param[out] tid - TID returned from terminus + * @return coroutine return_value - PLDM completion code + */ +- requester::Coroutine getTidOverMctp(mctp_eid_t eid, tid_t* tid); ++ requester::Coroutine getTidOverMctp(mctp_eid_t eid, pldm_tid_t* tid); + + /** @brief Find the terminus object pointer in termini list. + * + * @param[in] mctpInfos - information of removed MCTP endpoints + */ +- std::map>::iterator ++ std::map>::iterator + findTeminusPtr(const MctpInfo& mctpInfo); + + /** @brief Send setTID command to destination EID. +@@ -147,7 +147,7 @@ class TerminusManager + * @param[in] tid - Terminus ID + * @return coroutine return_value - PLDM completion code + */ +- requester::Coroutine setTidOverMctp(mctp_eid_t eid, tid_t tid); ++ requester::Coroutine setTidOverMctp(mctp_eid_t eid, pldm_tid_t tid); + + /** @brief Send getPLDMTypes command to destination TID and then return the + * value of supportedTypes in reference parameter. +@@ -156,22 +156,22 @@ class TerminusManager + * @param[out] supportedTypes - Supported Types returned from terminus + * @return coroutine return_value - PLDM completion code + */ +- requester::Coroutine getPLDMTypes(tid_t tid, uint64_t& supportedTypes); ++ requester::Coroutine getPLDMTypes(pldm_tid_t tid, uint64_t& supportedTypes); + + sdeventplus::Event& event; + RequesterHandler& handler; + pldm::InstanceIdDb& instanceIdDb; + + /** @brief Managed termini list */ +- std::map>& termini; ++ std::map>& termini; + + /** @brief local EID */ + mctp_eid_t localEid; + + /** @brief tables for maintaining assigned TID */ + std::vector tidPool; +- std::map transportLayerTable; +- std::map mctpInfoTable; ++ std::map transportLayerTable; ++ std::map mctpInfoTable; + + /** @brief A queue of MctpInfos to be discovered **/ + std::queue queuedMctpInfos{}; +diff --git a/platform-mc/test/event_manager_test.cpp b/platform-mc/test/event_manager_test.cpp +index a3bc204..abc00a4 100644 +--- a/platform-mc/test/event_manager_test.cpp ++++ b/platform-mc/test/event_manager_test.cpp +@@ -38,14 +38,14 @@ class EventManagerTest : public testing::Test + MockTerminusManager terminusManager; + MockEventManager eventManager; + PlatformManager platformManager; +- std::map> termini{}; ++ std::map> termini{}; + }; + + TEST_F(EventManagerTest, processNumericSensorEventTest) + { + #define SENSOR_READING 50 + #define WARNING_HIGH 45 +- pldm::tid_t tid = 1; ++ pldm_tid_t tid = 1; + termini[tid] = + std::make_shared(tid, 1 << PLDM_BASE | 1 << PLDM_PLATFORM); + std::vector pdr1{ +diff --git a/platform-mc/test/mock_sensor_manager.hpp b/platform-mc/test/mock_sensor_manager.hpp +index db3b1eb..4ec6300 100644 +--- a/platform-mc/test/mock_sensor_manager.hpp ++++ b/platform-mc/test/mock_sensor_manager.hpp +@@ -18,7 +18,7 @@ class MockSensorManager : public SensorManager + Manager* manager) : + SensorManager(event, terminusManager, termini, manager){}; + +- MOCK_METHOD(void, doSensorPolling, (tid_t tid), (override)); ++ MOCK_METHOD(void, doSensorPolling, (pldm_tid_t tid), (override)); + }; + + } // namespace platform_mc +diff --git a/platform-mc/test/mock_terminus_manager.hpp b/platform-mc/test/mock_terminus_manager.hpp +index 917f724..2a8f350 100644 +--- a/platform-mc/test/mock_terminus_manager.hpp ++++ b/platform-mc/test/mock_terminus_manager.hpp +@@ -14,11 +14,12 @@ namespace platform_mc + class MockTerminusManager : public TerminusManager + { + public: +- MockTerminusManager(sdeventplus::Event& event, +- requester::Handler& handler, +- pldm::InstanceIdDb& instanceIdDb, +- std::map>& termini, +- Manager* manager) : ++ MockTerminusManager( ++ sdeventplus::Event& event, ++ requester::Handler& handler, ++ pldm::InstanceIdDb& instanceIdDb, ++ std::map>& termini, ++ Manager* manager) : + TerminusManager(event, handler, instanceIdDb, termini, LOCAL_EID, + manager) + {} +diff --git a/platform-mc/test/platform_manager_test.cpp b/platform-mc/test/platform_manager_test.cpp +index eed03a2..81903e6 100644 +--- a/platform-mc/test/platform_manager_test.cpp ++++ b/platform-mc/test/platform_manager_test.cpp +@@ -29,7 +29,7 @@ class PlatformManagerTest : public testing::Test + pldm::requester::Handler reqHandler; + MockTerminusManager mockTerminusManager; + PlatformManager platformManager; +- std::map> termini; ++ std::map> termini; + }; + + TEST_F(PlatformManagerTest, initTerminusTest) +diff --git a/platform-mc/test/sensor_manager_test.cpp b/platform-mc/test/sensor_manager_test.cpp +index 2dc606b..60e2e22 100644 +--- a/platform-mc/test/sensor_manager_test.cpp ++++ b/platform-mc/test/sensor_manager_test.cpp +@@ -50,7 +50,7 @@ class SensorManagerTest : public testing::Test + pldm::requester::Handler reqHandler; + pldm::platform_mc::TerminusManager terminusManager; + pldm::platform_mc::MockSensorManager sensorManager; +- std::map> termini; ++ std::map> termini; + }; + + TEST_F(SensorManagerTest, sensorPollingTest) +@@ -58,7 +58,7 @@ TEST_F(SensorManagerTest, sensorPollingTest) + uint64_t seconds = 10; + uint64_t expectedTimes = (seconds * 1000) / SENSOR_POLLING_TIME; + +- pldm::tid_t tid = 1; ++ pldm_tid_t tid = 1; + termini[tid] = std::make_shared(tid, 0); + + EXPECT_CALL(sensorManager, doSensorPolling(tid)) +diff --git a/platform-mc/test/terminus_manager_test.cpp b/platform-mc/test/terminus_manager_test.cpp +index 2fb3f1e..bb3584f 100644 +--- a/platform-mc/test/terminus_manager_test.cpp ++++ b/platform-mc/test/terminus_manager_test.cpp +@@ -42,7 +42,7 @@ class TerminusManagerTest : public testing::Test + pldm::requester::Handler reqHandler; + pldm::platform_mc::TerminusManager terminusManager; + pldm::platform_mc::MockTerminusManager mockTerminusManager; +- std::map> termini; ++ std::map> termini; + }; + + TEST_F(TerminusManagerTest, mapTidTest) +diff --git a/platform-mc/test/terminus_test.cpp b/platform-mc/test/terminus_test.cpp +index 7f84042..311e35f 100644 +--- a/platform-mc/test/terminus_test.cpp ++++ b/platform-mc/test/terminus_test.cpp +@@ -19,7 +19,7 @@ TEST(TerminusTest, supportedTypeTest) + + TEST(TerminusTest, getTidTest) + { +- const pldm::tid_t tid = 1; ++ const pldm_tid_t tid = 1; + auto t1 = Terminus(tid, 1 << PLDM_BASE); + + EXPECT_EQ(tid, t1.getTid()); +-- +2.41.0 + diff --git a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/pldm_%.bbappend b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/pldm_%.bbappend index 412711b6c9c6..e4176e30d53b 100644 --- a/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/pldm_%.bbappend +++ b/meta-facebook/meta-yosemite4/recipes-phosphor/pldm/pldm_%.bbappend @@ -10,7 +10,9 @@ SRC_URI += " \ file://0004-platform-mc-PDR-handling.patch \ file://0005-platform-mc-Sensor-handling.patch \ file://0006-platform-mc-Added-EventManager.patch \ - file://0007-Support-OEM-META-write-file-request-for-post-code-hi.patch \ + file://0007-requester-support-multi-host-MCTP-devices-hot-plug.patch \ + file://0008-Support-OEM-META-write-file-request-for-post-code-hi.patch \ + file://0009-platform-mc-fix-up-tid_t-to-pldm_tid_t-conversions.patch \ file://pldm-restart.sh \ file://pldm-slow-restart.service \ " diff --git a/yocto_repos.sh b/yocto_repos.sh index cef1608d6a06..c46363ff04a2 100644 --- a/yocto_repos.sh +++ b/yocto_repos.sh @@ -12,7 +12,7 @@ rocko_repos=( ) rocko_poky_patch="0001-rocko-backport-support-for-override.patch 0002-Remove-checks-on-python.patch 0003-Add-support-to-build-on-centOS9.patch" lf_master_repos=( - lf-openbmc:418814925 + lf-openbmc:f8cfe2a83 ) lf_dunfell_repos=( lf-openbmc:c2858f16b