* [PATCH 2/3] ARM: imx: add cpu idle support for i.MX6SLL
From: kbuild test robot @ 2018-06-02 3:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527664358-17844-2-git-send-email-Anson.Huang@nxp.com>
Hi Anson,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on shawnguo/for-next]
[also build test ERROR on v4.17-rc7 next-20180601]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Anson-Huang/ARM-imx-add-L2-page-power-control-for-GPC/20180602-080503
base: https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git for-next
config: arm-arm67 (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm
All errors (new ones prefixed by >>):
arch/arm/mach-imx/mach-imx6sl.o: In function `imx6sl_init_late':
>> mach-imx6sl.c:(.init.text+0x2c): undefined reference to `imx6sx_cpuidle_init'
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 31074 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180602/b9cf1083/attachment-0001.gz>
^ permalink raw reply
* [PATCH v3 2/5] clk: imx6: add EPIT clock support
From: Stephen Boyd @ 2018-06-02 2:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180529170436.22711-3-peron.clem@gmail.com>
Quoting Cl?ment P?ron (2018-05-29 10:04:33)
> From: Colin Didier <colin.didier@devialet.com>
>
> Add EPIT clock support to the i.MX6Q clocking infrastructure.
>
> Signed-off-by: Colin Didier <colin.didier@devialet.com>
> Signed-off-by: Cl?ment Peron <clement.peron@devialet.com>
> Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
> ---
Applied to clk-next
^ permalink raw reply
* [PATCH v5 2/2] regulator: add QCOM RPMh regulator driver
From: David Collins @ 2018-06-02 1:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1527901471.git.collinsd@codeaurora.org>
Add the QCOM RPMh regulator driver to manage PMIC regulators
which are controlled via RPMh on some Qualcomm Technologies, Inc.
SoCs. RPMh is a hardware block which contains several
accelerators which are used to manage various hardware resources
that are shared between the processors of the SoC. The final
hardware state of a regulator is determined within RPMh by
performing max aggregation of the requests made by all of the
processors.
Add support for PMIC regulator control via the voltage regulator
manager (VRM) and oscillator buffer (XOB) RPMh accelerators.
VRM supports manipulation of enable state, voltage, and mode.
XOB supports manipulation of enable state.
Signed-off-by: David Collins <collinsd@codeaurora.org>
---
drivers/regulator/Kconfig | 9 +
drivers/regulator/Makefile | 1 +
drivers/regulator/qcom-rpmh-regulator.c | 770 ++++++++++++++++++++++++++++++++
3 files changed, 780 insertions(+)
create mode 100644 drivers/regulator/qcom-rpmh-regulator.c
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 5dbccf5..96b701f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -682,6 +682,15 @@ config REGULATOR_QCOM_RPM
Qualcomm RPM as a module. The module will be named
"qcom_rpm-regulator".
+config REGULATOR_QCOM_RPMH
+ tristate "Qualcomm Technologies, Inc. RPMh regulator driver"
+ depends on QCOM_RPMH || COMPILE_TEST
+ help
+ This driver supports control of PMIC regulators via the RPMh hardware
+ block found on Qualcomm Technologies Inc. SoCs. RPMh regulator
+ control allows for voting on regulator state between multiple
+ processors within the SoC.
+
config REGULATOR_QCOM_SMD_RPM
tristate "Qualcomm SMD based RPM regulator driver"
depends on QCOM_SMD_RPM
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index bd818ce..06e76a6 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
+obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
new file mode 100644
index 0000000..b2af35a
--- /dev/null
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -0,0 +1,770 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#include <soc/qcom/cmd-db.h>
+#include <soc/qcom/rpmh.h>
+
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+/**
+ * enum rpmh_regulator_type - supported RPMh accelerator types
+ * %VRM: RPMh VRM accelerator which supports voting on enable, voltage,
+ * and mode of LDO, SMPS, and BOB type PMIC regulators.
+ * %XOB: RPMh XOB accelerator which supports voting on the enable state
+ * of PMIC regulators.
+ */
+enum rpmh_regulator_type {
+ VRM,
+ XOB,
+};
+
+#define RPMH_VRM_HEADROOM_MAX_UV 511000
+
+#define RPMH_REGULATOR_REG_VRM_VOLTAGE 0x0
+#define RPMH_REGULATOR_REG_ENABLE 0x4
+#define RPMH_REGULATOR_REG_VRM_MODE 0x8
+#define RPMH_REGULATOR_REG_VRM_HEADROOM 0xC
+
+#define RPMH_REGULATOR_MODE_COUNT 4
+
+#define PMIC4_LDO_MODE_RETENTION 4
+#define PMIC4_LDO_MODE_LPM 5
+#define PMIC4_LDO_MODE_HPM 7
+
+#define PMIC4_SMPS_MODE_RETENTION 4
+#define PMIC4_SMPS_MODE_PFM 5
+#define PMIC4_SMPS_MODE_AUTO 6
+#define PMIC4_SMPS_MODE_PWM 7
+
+#define PMIC4_BOB_MODE_PASS 0
+#define PMIC4_BOB_MODE_PFM 1
+#define PMIC4_BOB_MODE_AUTO 2
+#define PMIC4_BOB_MODE_PWM 3
+
+/**
+ * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations
+ * @regulator_type: RPMh accelerator type used to manage this
+ * regulator
+ * @ops: Pointer to regulator ops callback structure
+ * @voltage_range: The single range of voltages supported by this
+ * PMIC regulator type
+ * @n_voltages: The number of unique voltage set points defined
+ * by voltage_range
+ * @hpm_min_load_uA: Minimum load current in microamps that requires
+ * high power mode (HPM) operation. This is used
+ * for LDO hardware type regulators only.
+ * @pmic_mode_map: Array indexed by regulator framework mode
+ * containing PMIC hardware modes. Must be large
+ * enough to index all framework modes supported
+ * by this regulator hardware type.
+ * @of_map_mode: Maps an RPMH_REGULATOR_MODE_* mode value defined
+ * in device tree to a regulator framework mode
+ */
+struct rpmh_vreg_hw_data {
+ enum rpmh_regulator_type regulator_type;
+ const struct regulator_ops *ops;
+ const struct regulator_linear_range voltage_range;
+ int n_voltages;
+ int hpm_min_load_uA;
+ const int *pmic_mode_map;
+ unsigned int (*of_map_mode)(unsigned int mode);
+};
+
+/**
+ * struct rpmh_vreg - individual RPMh regulator data structure encapsulating a
+ * single regulator device
+ * @dev: Device pointer for the top-level PMIC RPMh
+ * regulator parent device. This is used as a
+ * handle in RPMh write requests.
+ * @addr: Base address of the regulator resource within
+ * an RPMh accelerator
+ * @rdesc: Regulator descriptor
+ * @hw_data: PMIC regulator configuration data for this RPMh
+ * regulator
+ * @always_wait_for_ack: Boolean flag indicating if a request must always
+ * wait for an ACK from RPMh before continuing even
+ * if it corresponds to a strictly lower power
+ * state (e.g. enabled --> disabled).
+ * @enabled: Flag indicating if the regulator is enabled or
+ * not
+ * @bypassed: Boolean indicating if the regulator is in
+ * bypass (pass-through) mode or not. This is
+ * only used by BOB rpmh-regulator resources.
+ * @voltage_selector: Selector used for get_voltage_sel() and
+ * set_voltage_sel() callbacks
+ * @mode: RPMh VRM regulator current framework mode
+ */
+struct rpmh_vreg {
+ struct device *dev;
+ u32 addr;
+ struct regulator_desc rdesc;
+ const struct rpmh_vreg_hw_data *hw_data;
+ bool always_wait_for_ack;
+
+ int enabled;
+ bool bypassed;
+ int voltage_selector;
+ unsigned int mode;
+};
+
+/**
+ * struct rpmh_vreg_init_data - initialization data for an RPMh regulator
+ * @name: Name for the regulator which also corresponds
+ * to the device tree subnode name of the regulator
+ * @resource_name: RPMh regulator resource name format string.
+ * This must include exactly one field: '%s' which
+ * is filled at run-time with the PMIC ID provided
+ * by device tree property qcom,pmic-id. Example:
+ * "ldo%s1" for RPMh resource "ldoa1".
+ * @supply_name: Parent supply regulator name
+ * @hw_data: Configuration data for this PMIC regulator type
+ */
+struct rpmh_vreg_init_data {
+ const char *name;
+ const char *resource_name;
+ const char *supply_name;
+ const struct rpmh_vreg_hw_data *hw_data;
+};
+
+/**
+ * rpmh_regulator_send_request() - send the request to RPMh
+ * @vreg: Pointer to the RPMh regulator
+ * @cmd: RPMh commands to send
+ * @count: Size of cmd array
+ * @wait_for_ack: Boolean indicating if execution must wait until the
+ * request has been acknowledged as complete
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int rpmh_regulator_send_request(struct rpmh_vreg *vreg,
+ struct tcs_cmd *cmd, int count, bool wait_for_ack)
+{
+ int ret;
+
+ if (wait_for_ack || vreg->always_wait_for_ack)
+ ret = rpmh_write(vreg->dev, RPMH_ACTIVE_ONLY_STATE, cmd, count);
+ else
+ ret = rpmh_write_async(vreg->dev, RPMH_ACTIVE_ONLY_STATE, cmd,
+ count);
+
+ return ret;
+}
+
+static int _rpmh_regulator_vrm_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector, bool wait_for_ack)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct tcs_cmd cmd = {
+ .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_VOLTAGE,
+ };
+ int ret;
+
+ /* VRM voltage control register is set with voltage in millivolts. */
+ cmd.data = DIV_ROUND_UP(regulator_list_voltage_linear_range(rdev,
+ selector), 1000);
+
+ ret = rpmh_regulator_send_request(vreg, &cmd, 1, wait_for_ack);
+ if (!ret)
+ vreg->voltage_selector = selector;
+
+ return 0;
+}
+
+static int rpmh_regulator_vrm_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ if (vreg->enabled == -EINVAL) {
+ /*
+ * Cache the voltage and send it later when the regulator is
+ * enabled or disabled.
+ */
+ vreg->voltage_selector = selector;
+ return 0;
+ }
+
+ return _rpmh_regulator_vrm_set_voltage_sel(rdev, selector,
+ selector > vreg->voltage_selector);
+}
+
+static int rpmh_regulator_vrm_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->voltage_selector;
+}
+
+static int rpmh_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->enabled;
+}
+
+static int rpmh_regulator_enable(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct tcs_cmd cmd = {
+ .addr = vreg->addr + RPMH_REGULATOR_REG_ENABLE,
+ .data = 1,
+ };
+ int ret;
+
+ if (vreg->enabled == -EINVAL &&
+ vreg->voltage_selector != -ENOTRECOVERABLE) {
+ ret = _rpmh_regulator_vrm_set_voltage_sel(rdev,
+ vreg->voltage_selector, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = rpmh_regulator_send_request(vreg, &cmd, 1, true);
+ if (!ret)
+ vreg->enabled = true;
+
+ return ret;
+}
+
+static int rpmh_regulator_disable(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct tcs_cmd cmd = {
+ .addr = vreg->addr + RPMH_REGULATOR_REG_ENABLE,
+ .data = 0,
+ };
+ int ret;
+
+ if (vreg->enabled == -EINVAL &&
+ vreg->voltage_selector != -ENOTRECOVERABLE) {
+ ret = _rpmh_regulator_vrm_set_voltage_sel(rdev,
+ vreg->voltage_selector, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = rpmh_regulator_send_request(vreg, &cmd, 1, false);
+ if (!ret)
+ vreg->enabled = false;
+
+ return ret;
+}
+
+static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg,
+ unsigned int mode, bool bypassed)
+{
+ struct tcs_cmd cmd = {
+ .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE,
+ };
+ int pmic_mode;
+
+ if (mode > REGULATOR_MODE_STANDBY)
+ return -EINVAL;
+
+ pmic_mode = vreg->hw_data->pmic_mode_map[mode];
+ if (pmic_mode < 0)
+ return pmic_mode;
+
+ cmd.data = bypassed ? PMIC4_BOB_MODE_PASS : pmic_mode;
+
+ return rpmh_regulator_send_request(vreg, &cmd, 1, true);
+}
+
+static int rpmh_regulator_vrm_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (mode == vreg->mode)
+ return 0;
+
+ ret = rpmh_regulator_vrm_set_mode_bypass(vreg, mode, vreg->bypassed);
+ if (!ret)
+ vreg->mode = mode;
+
+ return ret;
+}
+
+static unsigned int rpmh_regulator_vrm_get_mode(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->mode;
+}
+
+/**
+ * rpmh_regulator_vrm_set_load() - set the regulator mode based upon the load
+ * current requested
+ * @rdev: Regulator device pointer for the rpmh-regulator
+ * @load_uA: Aggregated load current in microamps
+ *
+ * This function is used in the regulator_ops for VRM type RPMh regulator
+ * devices.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int rpmh_regulator_vrm_set_load(struct regulator_dev *rdev, int load_uA)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mode;
+
+ if (load_uA >= vreg->hw_data->hpm_min_load_uA)
+ mode = REGULATOR_MODE_FAST;
+ else
+ mode = REGULATOR_MODE_IDLE;
+
+ return rpmh_regulator_vrm_set_mode(rdev, mode);
+}
+
+static int rpmh_regulator_vrm_set_bypass(struct regulator_dev *rdev,
+ bool enable)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (vreg->bypassed == enable)
+ return 0;
+
+ ret = rpmh_regulator_vrm_set_mode_bypass(vreg, vreg->mode, enable);
+ if (!ret)
+ vreg->bypassed = enable;
+
+ return ret;
+}
+
+static int rpmh_regulator_vrm_get_bypass(struct regulator_dev *rdev,
+ bool *enable)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ *enable = vreg->bypassed;
+
+ return 0;
+}
+
+static const struct regulator_ops rpmh_regulator_vrm_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+ .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
+ .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_mode = rpmh_regulator_vrm_set_mode,
+ .get_mode = rpmh_regulator_vrm_get_mode,
+};
+
+static const struct regulator_ops rpmh_regulator_vrm_drms_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+ .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
+ .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_mode = rpmh_regulator_vrm_set_mode,
+ .get_mode = rpmh_regulator_vrm_get_mode,
+ .set_load = rpmh_regulator_vrm_set_load,
+};
+
+static const struct regulator_ops rpmh_regulator_vrm_bypass_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+ .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
+ .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_mode = rpmh_regulator_vrm_set_mode,
+ .get_mode = rpmh_regulator_vrm_get_mode,
+ .set_bypass = rpmh_regulator_vrm_set_bypass,
+ .get_bypass = rpmh_regulator_vrm_get_bypass,
+};
+
+static const struct regulator_ops rpmh_regulator_xob_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+};
+
+/**
+ * rpmh_regulator_init_vreg() - initialize all attributes of an rpmh-regulator
+ * vreg: Pointer to the individual rpmh-regulator resource
+ * dev: Pointer to the top level rpmh-regulator PMIC device
+ * node: Pointer to the individual rpmh-regulator resource
+ * device node
+ * pmic_id: String used to identify the top level rpmh-regulator
+ * PMIC device on the board
+ * rpmh_data: Pointer to a null-terminated array of rpmh-regulator
+ * resources defined for the top level PMIC device
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
+ struct device_node *node, const char *pmic_id,
+ const struct rpmh_vreg_init_data *rpmh_data)
+{
+ struct regulator_config reg_config = {};
+ char rpmh_resource_name[20] = "";
+ struct regulator_dev *rdev;
+ struct regulator_init_data *init_data;
+ int ret;
+
+ vreg->dev = dev;
+
+ for (; rpmh_data->name; rpmh_data++)
+ if (!strcmp(rpmh_data->name, node->name))
+ break;
+
+ if (!rpmh_data->name) {
+ dev_err(dev, "Unknown regulator %s\n", node->name);
+ return -EINVAL;
+ }
+
+ scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name),
+ rpmh_data->resource_name, pmic_id);
+
+ vreg->addr = cmd_db_read_addr(rpmh_resource_name);
+ if (!vreg->addr) {
+ dev_err(dev, "%s: could not find RPMh address for resource %s\n",
+ node->name, rpmh_resource_name);
+ return -ENODEV;
+ }
+
+ vreg->rdesc.name = rpmh_data->name;
+ vreg->rdesc.supply_name = rpmh_data->supply_name;
+ vreg->hw_data = rpmh_data->hw_data;
+
+ vreg->enabled = -EINVAL;
+ vreg->voltage_selector = -ENOTRECOVERABLE;
+ vreg->mode = REGULATOR_MODE_INVALID;
+
+ if (rpmh_data->hw_data->n_voltages) {
+ vreg->rdesc.linear_ranges = &rpmh_data->hw_data->voltage_range;
+ vreg->rdesc.n_linear_ranges = 1;
+ vreg->rdesc.n_voltages = rpmh_data->hw_data->n_voltages;
+ }
+
+ vreg->always_wait_for_ack = of_property_read_bool(node,
+ "qcom,always-wait-for-ack");
+
+ vreg->rdesc.owner = THIS_MODULE;
+ vreg->rdesc.type = REGULATOR_VOLTAGE;
+ vreg->rdesc.ops = vreg->hw_data->ops;
+ vreg->rdesc.of_map_mode = vreg->hw_data->of_map_mode;
+
+ init_data = of_get_regulator_init_data(dev, node, &vreg->rdesc);
+ if (!init_data)
+ return -ENOMEM;
+
+ if (rpmh_data->hw_data->regulator_type == XOB &&
+ init_data->constraints.min_uV &&
+ init_data->constraints.min_uV == init_data->constraints.max_uV) {
+ vreg->rdesc.fixed_uV = init_data->constraints.min_uV;
+ vreg->rdesc.n_voltages = 1;
+ }
+
+ reg_config.dev = dev;
+ reg_config.init_data = init_data;
+ reg_config.of_node = node;
+ reg_config.driver_data = vreg;
+
+ rdev = devm_regulator_register(dev, &vreg->rdesc, ®_config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ rdev = NULL;
+ dev_err(dev, "%s: devm_regulator_register() failed, ret=%d\n",
+ node->name, ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "%s regulator registered for RPMh resource %s @ 0x%05X\n",
+ node->name, rpmh_resource_name, vreg->addr);
+
+ return 0;
+}
+
+static const int pmic_mode_map_pmic4_ldo[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = PMIC4_LDO_MODE_RETENTION,
+ [REGULATOR_MODE_IDLE] = PMIC4_LDO_MODE_LPM,
+ [REGULATOR_MODE_NORMAL] = -EINVAL,
+ [REGULATOR_MODE_FAST] = PMIC4_LDO_MODE_HPM,
+};
+
+static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int mode)
+{
+ static const unsigned int of_mode_map[RPMH_REGULATOR_MODE_COUNT] = {
+ [RPMH_REGULATOR_MODE_RET] = REGULATOR_MODE_STANDBY,
+ [RPMH_REGULATOR_MODE_LPM] = REGULATOR_MODE_IDLE,
+ [RPMH_REGULATOR_MODE_AUTO] = REGULATOR_MODE_INVALID,
+ [RPMH_REGULATOR_MODE_HPM] = REGULATOR_MODE_FAST,
+ };
+
+ if (mode >= RPMH_REGULATOR_MODE_COUNT)
+ return -EINVAL;
+
+ return of_mode_map[mode];
+}
+
+static const int pmic_mode_map_pmic4_smps[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = PMIC4_SMPS_MODE_RETENTION,
+ [REGULATOR_MODE_IDLE] = PMIC4_SMPS_MODE_PFM,
+ [REGULATOR_MODE_NORMAL] = PMIC4_SMPS_MODE_AUTO,
+ [REGULATOR_MODE_FAST] = PMIC4_SMPS_MODE_PWM,
+};
+
+static unsigned int rpmh_regulator_pmic4_smps_of_map_mode(unsigned int mode)
+{
+ static const unsigned int of_mode_map[RPMH_REGULATOR_MODE_COUNT] = {
+ [RPMH_REGULATOR_MODE_RET] = REGULATOR_MODE_STANDBY,
+ [RPMH_REGULATOR_MODE_LPM] = REGULATOR_MODE_IDLE,
+ [RPMH_REGULATOR_MODE_AUTO] = REGULATOR_MODE_NORMAL,
+ [RPMH_REGULATOR_MODE_HPM] = REGULATOR_MODE_FAST,
+ };
+
+ if (mode >= RPMH_REGULATOR_MODE_COUNT)
+ return -EINVAL;
+
+ return of_mode_map[mode];
+}
+
+static const int pmic_mode_map_pmic4_bob[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = -EINVAL,
+ [REGULATOR_MODE_IDLE] = PMIC4_BOB_MODE_PFM,
+ [REGULATOR_MODE_NORMAL] = PMIC4_BOB_MODE_AUTO,
+ [REGULATOR_MODE_FAST] = PMIC4_BOB_MODE_PWM,
+};
+
+static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int mode)
+{
+ static const unsigned int of_mode_map[RPMH_REGULATOR_MODE_COUNT] = {
+ [RPMH_REGULATOR_MODE_RET] = REGULATOR_MODE_INVALID,
+ [RPMH_REGULATOR_MODE_LPM] = REGULATOR_MODE_IDLE,
+ [RPMH_REGULATOR_MODE_AUTO] = REGULATOR_MODE_NORMAL,
+ [RPMH_REGULATOR_MODE_HPM] = REGULATOR_MODE_FAST,
+ };
+
+ if (mode >= RPMH_REGULATOR_MODE_COUNT)
+ return -EINVAL;
+
+ return of_mode_map[mode];
+}
+
+static const struct rpmh_vreg_hw_data pmic4_pldo = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(1664000, 0, 255, 8000),
+ .n_voltages = 256,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic4_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_pldo_lv = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(1256000, 0, 127, 8000),
+ .n_voltages = 128,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic4_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_nldo = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
+ .n_voltages = 128,
+ .hpm_min_load_uA = 30000,
+ .pmic_mode_map = pmic_mode_map_pmic4_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_hfsmps3 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+ .n_voltages = 216,
+ .pmic_mode_map = pmic_mode_map_pmic4_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_ftsmps426 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 258, 4000),
+ .n_voltages = 259,
+ .pmic_mode_map = pmic_mode_map_pmic4_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_bob = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_bypass_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(1824000, 0, 83, 32000),
+ .n_voltages = 84,
+ .pmic_mode_map = pmic_mode_map_pmic4_bob,
+ .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_lvs = {
+ .regulator_type = XOB,
+ .ops = &rpmh_regulator_xob_ops,
+ /* LVS hardware does not support voltage or mode configuration. */
+};
+
+#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
+{ \
+ .name = _name, \
+ .resource_name = _resource_name, \
+ .hw_data = _hw_data, \
+ .supply_name = _supply_name, \
+}
+
+static const struct rpmh_vreg_init_data pm8998_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic4_hfsmps3, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic4_ftsmps426, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic4_ftsmps426, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic4_ftsmps426, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic4_ftsmps426, "vdd-s9"),
+ RPMH_VREG("smps10", "smp%s10", &pmic4_ftsmps426, "vdd-s10"),
+ RPMH_VREG("smps11", "smp%s11", &pmic4_ftsmps426, "vdd-s11"),
+ RPMH_VREG("smps12", "smp%s12", &pmic4_ftsmps426, "vdd-s12"),
+ RPMH_VREG("smps13", "smp%s13", &pmic4_ftsmps426, "vdd-s13"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l27"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l3-l11"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic4_nldo, "vdd-l4-l5"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l4-l5"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo, "vdd-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic4_nldo, "vdd-l3-l11"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l16-l28"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l18-l22"),
+ RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo20", "ldo%s20", &pmic4_pldo, "vdd-l20-l24"),
+ RPMH_VREG("ldo21", "ldo%s21", &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo22", "ldo%s22", &pmic4_pldo, "vdd-l18-l22"),
+ RPMH_VREG("ldo23", "ldo%s23", &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo24", "ldo%s24", &pmic4_pldo, "vdd-l20-l24"),
+ RPMH_VREG("ldo25", "ldo%s25", &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo26", "ldo%s26", &pmic4_nldo, "vdd-l26"),
+ RPMH_VREG("ldo27", "ldo%s27", &pmic4_nldo, "vdd-l1-l27"),
+ RPMH_VREG("ldo28", "ldo%s28", &pmic4_pldo, "vdd-l16-l28"),
+ RPMH_VREG("lvs1", "vs%s1", &pmic4_lvs, "vin-lvs-1-2"),
+ RPMH_VREG("lvs2", "vs%s2", &pmic4_lvs, "vin-lvs-1-2"),
+ {},
+};
+
+static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = {
+ RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
+ {},
+};
+
+static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic4_ftsmps426, "vdd-s4"),
+ {},
+};
+
+static int rpmh_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct rpmh_vreg_init_data *vreg_data;
+ struct device_node *node;
+ struct rpmh_vreg *vreg;
+ const char *pmic_id;
+ int ret;
+
+ ret = cmd_db_ready();
+ if (ret < 0) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Command DB not available, ret=%d\n", ret);
+ return ret;
+ }
+
+ vreg_data = of_device_get_match_data(dev);
+ if (!vreg_data)
+ return -ENODEV;
+
+ ret = of_property_read_string(dev->of_node, "qcom,pmic-id", &pmic_id);
+ if (ret < 0) {
+ dev_err(dev, "qcom,pmic-id missing in DT node\n");
+ return ret;
+ }
+
+ for_each_available_child_of_node(dev->of_node, node) {
+ vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+ if (!vreg) {
+ of_node_put(node);
+ return -ENOMEM;
+ }
+
+ ret = rpmh_regulator_init_vreg(vreg, dev, node, pmic_id,
+ vreg_data);
+ if (ret < 0) {
+ of_node_put(node);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct of_device_id rpmh_regulator_match_table[] = {
+ {
+ .compatible = "qcom,pm8998-rpmh-regulators",
+ .data = pm8998_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmi8998-rpmh-regulators",
+ .data = pmi8998_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8005-rpmh-regulators",
+ .data = pm8005_vreg_data,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table);
+
+static struct platform_driver rpmh_regulator_driver = {
+ .driver = {
+ .name = "qcom-rpmh-regulator",
+ .of_match_table = of_match_ptr(rpmh_regulator_match_table),
+ },
+ .probe = rpmh_regulator_probe,
+};
+module_platform_driver(rpmh_regulator_driver);
+
+MODULE_DESCRIPTION("Qualcomm RPMh regulator driver");
+MODULE_LICENSE("GPL v2");
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* [PATCH v5 1/2] regulator: dt-bindings: add QCOM RPMh regulator bindings
From: David Collins @ 2018-06-02 1:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1527901471.git.collinsd@codeaurora.org>
Introduce bindings for RPMh regulator devices found on some
Qualcomm Technlogies, Inc. SoCs. These devices allow a given
processor within the SoC to make PMIC regulator requests which
are aggregated within the RPMh hardware block along with requests
from other processors in the SoC to determine the final PMIC
regulator hardware state.
Signed-off-by: David Collins <collinsd@codeaurora.org>
---
.../bindings/regulator/qcom,rpmh-regulator.txt | 160 +++++++++++++++++++++
.../dt-bindings/regulator/qcom,rpmh-regulator.h | 36 +++++
2 files changed, 196 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
create mode 100644 include/dt-bindings/regulator/qcom,rpmh-regulator.h
diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
new file mode 100644
index 0000000..7ef2dbe
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
@@ -0,0 +1,160 @@
+Qualcomm Technologies, Inc. RPMh Regulators
+
+rpmh-regulator devices support PMIC regulator management via the Voltage
+Regulator Manager (VRM) and Oscillator Buffer (XOB) RPMh accelerators. The APPS
+processor communicates with these hardware blocks via a Resource State
+Coordinator (RSC) using command packets. The VRM allows changing three
+parameters for a given regulator: enable state, output voltage, and operating
+mode. The XOB allows changing only a single parameter for a given regulator:
+its enable state. Despite its name, the XOB is capable of controlling the
+enable state of any PMIC peripheral. It is used for clock buffers, low-voltage
+switches, and LDO/SMPS regulators which have a fixed voltage and mode.
+
+=======================
+Required Node Structure
+=======================
+
+RPMh regulators must be described in two levels of device nodes. The first
+level describes the PMIC containing the regulators and must reside within an
+RPMh device node. The second level describes each regulator within the PMIC
+which is to be used on the board. Each of these regulators maps to a single
+RPMh resource.
+
+The names used for regulator nodes must match those supported by a given PMIC.
+Supported regulator node names:
+ PM8998: smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2
+ PMI8998: bob
+ PM8005: smps1 - smps4
+
+========================
+First Level Nodes - PMIC
+========================
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must be one of: "qcom,pm8998-rpmh-regulators",
+ "qcom,pmi8998-rpmh-regulators" or
+ "qcom,pm8005-rpmh-regulators".
+
+- qcom,pmic-id
+ Usage: required
+ Value type: <string>
+ Definition: RPMh resource name suffix used for the regulators found on
+ this PMIC. Typical values: "a", "b", "c", "d", "e", "f".
+
+- vdd-s1-supply
+- vdd-s2-supply
+- vdd-s3-supply
+- vdd-s4-supply
+ Usage: optional (PM8998 and PM8005 only)
+ Value type: <phandle>
+ Definition: phandle of the parent supply regulator of one or more of the
+ regulators for this PMIC.
+
+- vdd-s5-supply
+- vdd-s6-supply
+- vdd-s7-supply
+- vdd-s8-supply
+- vdd-s9-supply
+- vdd-s10-supply
+- vdd-s11-supply
+- vdd-s12-supply
+- vdd-s13-supply
+- vdd-l1-l27-supply
+- vdd-l2-l8-l17-supply
+- vdd-l3-l11-supply
+- vdd-l4-l5-supply
+- vdd-l6-supply
+- vdd-l7-l12-l14-l15-supply
+- vdd-l9-supply
+- vdd-l10-l23-l25-supply
+- vdd-l13-l19-l21-supply
+- vdd-l16-l28-supply
+- vdd-l18-l22-supply
+- vdd-l20-l24-supply
+- vdd-l26-supply
+- vin-lvs-1-2-supply
+ Usage: optional (PM8998 only)
+ Value type: <phandle>
+ Definition: phandle of the parent supply regulator of one or more of the
+ regulators for this PMIC.
+
+- vdd-bob-supply
+ Usage: optional (PMI8998 only)
+ Value type: <phandle>
+ Definition: BOB regulator parent supply phandle
+
+===============================
+Second Level Nodes - Regulators
+===============================
+
+- qcom,always-wait-for-ack
+ Usage: optional
+ Value type: <empty>
+ Definition: Boolean flag which indicates that the application processor
+ must wait for an ACK or a NACK from RPMh for every request
+ sent for this regulator including those which are for a
+ strictly lower power state.
+
+Other properties defined in Documentation/devicetree/bindings/regulator.txt
+may also be used. regulator-initial-mode and regulator-allowed-modes may be
+specified for VRM regulators using mode values from
+include/dt-bindings/regulator/qcom,rpmh-regulator.h. regulator-allow-bypass
+may be specified for BOB type regulators managed via VRM.
+regulator-allow-set-load may be specified for LDO type regulators managed via
+VRM.
+
+========
+Examples
+========
+
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+&apps_rsc {
+ pm8998-rpmh-regulators {
+ compatible = "qcom,pm8998-rpmh-regulators";
+ qcom,pmic-id = "a";
+
+ vdd-l7-l12-l14-l15-supply = <&pm8998_s5>;
+
+ smps2 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ pm8998_s5: smps5 {
+ regulator-min-microvolt = <1904000>;
+ regulator-max-microvolt = <2040000>;
+ };
+
+ ldo7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allowed-modes =
+ <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ };
+
+ lvs1 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+
+ pmi8998-rpmh-regulators {
+ compatible = "qcom,pmi8998-rpmh-regulators";
+ qcom,pmic-id = "b";
+
+ bob {
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3600000>;
+ regulator-allowed-modes =
+ <RPMH_REGULATOR_MODE_AUTO
+ RPMH_REGULATOR_MODE_HPM>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
+ };
+ };
+};
diff --git a/include/dt-bindings/regulator/qcom,rpmh-regulator.h b/include/dt-bindings/regulator/qcom,rpmh-regulator.h
new file mode 100644
index 0000000..86713dc
--- /dev/null
+++ b/include/dt-bindings/regulator/qcom,rpmh-regulator.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
+
+#ifndef __QCOM_RPMH_REGULATOR_H
+#define __QCOM_RPMH_REGULATOR_H
+
+/*
+ * These mode constants may be used to specify modes for various RPMh regulator
+ * device tree properties (e.g. regulator-initial-mode). Each type of regulator
+ * supports a subset of the possible modes.
+ *
+ * %RPMH_REGULATOR_MODE_RET: Retention mode in which only an extremely small
+ * load current is allowed. This mode is supported
+ * by LDO and SMPS type regulators.
+ * %RPMH_REGULATOR_MODE_LPM: Low power mode in which a small load current is
+ * allowed. This mode corresponds to PFM for SMPS
+ * and BOB type regulators. This mode is supported
+ * by LDO, HFSMPS, BOB, and PMIC4 FTSMPS type
+ * regulators.
+ * %RPMH_REGULATOR_MODE_AUTO: Auto mode in which the regulator hardware
+ * automatically switches between LPM and HPM based
+ * upon the real-time load current. This mode is
+ * supported by HFSMPS, BOB, and PMIC4 FTSMPS type
+ * regulators.
+ * %RPMH_REGULATOR_MODE_HPM: High power mode in which the full rated current
+ * of the regulator is allowed. This mode
+ * corresponds to PWM for SMPS and BOB type
+ * regulators. This mode is supported by all types
+ * of regulators.
+ */
+#define RPMH_REGULATOR_MODE_RET 0
+#define RPMH_REGULATOR_MODE_LPM 1
+#define RPMH_REGULATOR_MODE_AUTO 2
+#define RPMH_REGULATOR_MODE_HPM 3
+
+#endif
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* [PATCH v5 0/2] regulator: add QCOM RPMh regulator driver
From: David Collins @ 2018-06-02 1:34 UTC (permalink / raw)
To: linux-arm-kernel
This patch series adds a driver and device tree binding documentation for
PMIC regulator control via Resource Power Manager-hardened (RPMh) on some
Qualcomm Technologies, Inc. SoCs such as SDM845. RPMh is a hardware block
which contains several accelerators which are used to manage various
hardware resources that are shared between the processors of the SoC. The
final hardware state of a regulator is determined within RPMh by performing
max aggregation of the requests made by all of the processors.
The RPMh regulator driver depends upon the RPMh driver [1] and command DB
driver [2] which are both still undergoing review. It also depends upon
three recent regulator changes: [3], [4], and [5].
Changes since v4 [6]:
- Removed support for DT properties qcom,regulator-drms-modes and
qcom,drms-mode-max-microamps
- Specified fixed DRMS high power mode minimum limits for LDO type
regulators
- Removed DRMS support for SMPS and BOB type regulators
- Simplified voltage caching logic
Changes since v3 [7]:
- Removed support for DT properties qcom,regulator-initial-microvolt
and qcom,headroom-microvolt
- Renamed DT property qcom,allowed-drms-modes to be
qcom,regulator-drms-modes
- Updated DT binding documentation to mention which common regulator
bindings can be used for qcom-rpmh-regulator devices
- Added voltage caching so that voltage requests are only sent to RPMh
after the regulator has been enabled at least once
- Changed 'voltage_selector' default value to be -ENOTRECOVERABLE to
interact with [5]
- Initialized 'enabled' to -EINVAL so that unused regulators are
disabled by regulator_late_cleanup()
- Removed rpmh_regulator_load_default_parameters() as it is no longer
needed
- Updated the mode usage description in qcom,rpmh-regulator.h
Changes since v2 [8]:
- Replaced '_' with '-' in device tree supply property names
- Renamed qcom_rpmh-regulator.c to be qcom-rpmh-regulator.c
- Updated various DT property names to use "microvolt" and "microamp"
- Moved allowed modes constraint specification out of the driver [4]
- Replaced rpmh_client with device pointer to match new RPMh API [1]
- Corrected drms mode threshold checking
- Initialized voltage_selector to -EINVAL when not specified in DT
- Added constants for PMIC regulator hardware modes
- Corrected type sign of mode mapping tables
- Made variable names for mode arrays plural
- Simplified Kconfig depends on
- Removed unnecessary constants and struct fields
- Added some descriptive comments
Changes since v1 [9]:
- Addressed review feedback from Doug, Mark, and Stephen
- Replaced set_voltage()/get_voltage() callbacks with set_voltage_sel()/
get_voltage_sel()
- Added set_bypass()/get_bypass() callbacks for BOB pass-through mode
control
- Removed top-level PMIC data structures
- Removed initialization variables from structs and passed them as
function parameters
- Removed various comments and error messages
- Simplified mode handling
- Refactored per-PMIC rpmh-regulator data specification
- Simplified probe function
- Moved header into DT patch
- Removed redundant property listings from DT binding documentation
[1]: https://lkml.org/lkml/2018/5/9/729
[2]: https://lkml.org/lkml/2018/4/10/714
[3]: https://lkml.org/lkml/2018/4/18/556
[4]: https://lkml.org/lkml/2018/5/11/696
[5]: https://lkml.org/lkml/2018/5/15/1005
[6]: https://lkml.org/lkml/2018/5/22/1168
[7]: https://lkml.org/lkml/2018/5/11/701
[8]: https://lkml.org/lkml/2018/4/13/687
[9]: https://lkml.org/lkml/2018/3/16/1431
David Collins (2):
regulator: dt-bindings: add QCOM RPMh regulator bindings
regulator: add QCOM RPMh regulator driver
.../bindings/regulator/qcom,rpmh-regulator.txt | 160 +++++
drivers/regulator/Kconfig | 9 +
drivers/regulator/Makefile | 1 +
drivers/regulator/qcom-rpmh-regulator.c | 770 +++++++++++++++++++++
.../dt-bindings/regulator/qcom,rpmh-regulator.h | 36 +
5 files changed, 976 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
create mode 100644 drivers/regulator/qcom-rpmh-regulator.c
create mode 100644 include/dt-bindings/regulator/qcom,rpmh-regulator.h
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH v3 3/3] arm64: dts: Update Stingray clock DT nodes
From: Ray Jui @ 2018-06-02 0:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527900968-12017-1-git-send-email-ray.jui@broadcom.com>
From: Pramod Kumar <pramod.kumar@broadcom.com>
Update clock output names in the Stingray clock DT nodes so they match
the binding document and the latest ASIC datasheet. Also add entries
for LCPLL2
Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
Signed-off-by: Ray Jui <ray.jui@broadcom.com>
---
.../boot/dts/broadcom/stingray/stingray-clock.dtsi | 26 ++++++++++++++++------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/boot/dts/broadcom/stingray/stingray-clock.dtsi b/arch/arm64/boot/dts/broadcom/stingray/stingray-clock.dtsi
index 3a4d452..10a106a 100644
--- a/arch/arm64/boot/dts/broadcom/stingray/stingray-clock.dtsi
+++ b/arch/arm64/boot/dts/broadcom/stingray/stingray-clock.dtsi
@@ -52,12 +52,24 @@
reg = <0x0001d104 0x32>,
<0x0001c854 0x4>;
clocks = <&osc>;
- clock-output-names = "genpll0", "clk_125", "clk_scr",
+ clock-output-names = "genpll0", "clk_125m", "clk_scr",
"clk_250", "clk_pcie_axi",
"clk_paxc_axi_x2",
"clk_paxc_axi";
};
+ genpll2: genpll2 at 1d1ac {
+ #clock-cells = <1>;
+ compatible = "brcm,sr-genpll2";
+ reg = <0x0001d1ac 0x32>,
+ <0x0001c854 0x4>;
+ clocks = <&osc>;
+ clock-output-names = "genpll2", "clk_nic",
+ "clk_ts_500_ref", "clk_125_nitro",
+ "clk_chimp", "clk_nic_flash",
+ "clk_fs";
+ };
+
genpll3: genpll3 at 1d1e0 {
#clock-cells = <1>;
compatible = "brcm,sr-genpll3";
@@ -75,8 +87,8 @@
<0x0001c854 0x4>;
clocks = <&osc>;
clock-output-names = "genpll4", "clk_ccn",
- "clk_tpiu_pll", "noc_clk",
- "pll_chclk_fs4",
+ "clk_tpiu_pll", "clk_noc",
+ "clk_chclk_fs4",
"clk_bridge_fscpu";
};
@@ -86,8 +98,8 @@
reg = <0x0001d248 0x32>,
<0x0001c870 0x4>;
clocks = <&osc>;
- clock-output-names = "genpll5", "fs4_hf_clk",
- "crypto_ae_clk", "raid_ae_clk";
+ clock-output-names = "genpll5", "clk_fs4_hf",
+ "clk_crypto_ae", "clk_raid_ae";
};
lcpll0: lcpll0 at 1d0c4 {
@@ -107,9 +119,9 @@
reg = <0x0001d138 0x3c>,
<0x0001c870 0x4>;
clocks = <&osc>;
- clock-output-names = "lcpll1", "clk_wanpn",
+ clock-output-names = "lcpll1", "clk_wan",
"clk_usb_ref",
- "timesync_evt_clk";
+ "clk_crmu_ts";
};
hsls_clk: hsls_clk {
--
2.1.4
^ permalink raw reply related
* [PATCH v3 2/3] clk: bcm: Update and add Stingray clock entries
From: Ray Jui @ 2018-06-02 0:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527900968-12017-1-git-send-email-ray.jui@broadcom.com>
From: Pramod Kumar <pramod.kumar@broadcom.com>
Update and add Stingray clock definitions and tables so they match the
binding document and the latest ASIC datasheet
Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
Signed-off-by: Ray Jui <ray.jui@broadcom.com>
---
drivers/clk/bcm/clk-sr.c | 135 +++++++++++++++++++++++++++++++++++++++++------
1 file changed, 120 insertions(+), 15 deletions(-)
diff --git a/drivers/clk/bcm/clk-sr.c b/drivers/clk/bcm/clk-sr.c
index adc74f4..7b9efc0 100644
--- a/drivers/clk/bcm/clk-sr.c
+++ b/drivers/clk/bcm/clk-sr.c
@@ -56,8 +56,8 @@ static const struct iproc_pll_ctrl sr_genpll0 = {
};
static const struct iproc_clk_ctrl sr_genpll0_clk[] = {
- [BCM_SR_GENPLL0_SATA_CLK] = {
- .channel = BCM_SR_GENPLL0_SATA_CLK,
+ [BCM_SR_GENPLL0_125M_CLK] = {
+ .channel = BCM_SR_GENPLL0_125M_CLK,
.flags = IPROC_CLK_AON,
.enable = ENABLE_VAL(0x4, 6, 0, 12),
.mdiv = REG_VAL(0x18, 0, 9),
@@ -102,6 +102,65 @@ static int sr_genpll0_clk_init(struct platform_device *pdev)
return 0;
}
+static const struct iproc_pll_ctrl sr_genpll2 = {
+ .flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
+ IPROC_CLK_PLL_NEEDS_SW_CFG,
+ .aon = AON_VAL(0x0, 1, 13, 12),
+ .reset = RESET_VAL(0x0, 12, 11),
+ .dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3),
+ .sw_ctrl = SW_CTRL_VAL(0x10, 31),
+ .ndiv_int = REG_VAL(0x10, 20, 10),
+ .ndiv_frac = REG_VAL(0x10, 0, 20),
+ .pdiv = REG_VAL(0x14, 0, 4),
+ .status = REG_VAL(0x30, 12, 1),
+};
+
+static const struct iproc_clk_ctrl sr_genpll2_clk[] = {
+ [BCM_SR_GENPLL2_NIC_CLK] = {
+ .channel = BCM_SR_GENPLL2_NIC_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x4, 6, 0, 12),
+ .mdiv = REG_VAL(0x18, 0, 9),
+ },
+ [BCM_SR_GENPLL2_TS_500_CLK] = {
+ .channel = BCM_SR_GENPLL2_TS_500_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x4, 7, 1, 13),
+ .mdiv = REG_VAL(0x18, 10, 9),
+ },
+ [BCM_SR_GENPLL2_125_NITRO_CLK] = {
+ .channel = BCM_SR_GENPLL2_125_NITRO_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x4, 8, 2, 14),
+ .mdiv = REG_VAL(0x18, 20, 9),
+ },
+ [BCM_SR_GENPLL2_CHIMP_CLK] = {
+ .channel = BCM_SR_GENPLL2_CHIMP_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x4, 9, 3, 15),
+ .mdiv = REG_VAL(0x1c, 0, 9),
+ },
+ [BCM_SR_GENPLL2_NIC_FLASH_CLK] = {
+ .channel = BCM_SR_GENPLL2_NIC_FLASH_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x4, 10, 4, 16),
+ .mdiv = REG_VAL(0x1c, 10, 9),
+ },
+ [BCM_SR_GENPLL2_FS4_CLK] = {
+ .channel = BCM_SR_GENPLL2_FS4_CLK,
+ .enable = ENABLE_VAL(0x4, 11, 5, 17),
+ .mdiv = REG_VAL(0x1c, 20, 9),
+ },
+};
+
+static int sr_genpll2_clk_init(struct platform_device *pdev)
+{
+ iproc_pll_clk_setup(pdev->dev.of_node,
+ &sr_genpll2, NULL, 0, sr_genpll2_clk,
+ ARRAY_SIZE(sr_genpll2_clk));
+ return 0;
+}
+
static const struct iproc_pll_ctrl sr_genpll3 = {
.flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
IPROC_CLK_PLL_NEEDS_SW_CFG,
@@ -157,6 +216,30 @@ static const struct iproc_clk_ctrl sr_genpll4_clk[] = {
.enable = ENABLE_VAL(0x4, 6, 0, 12),
.mdiv = REG_VAL(0x18, 0, 9),
},
+ [BCM_SR_GENPLL4_TPIU_PLL_CLK] = {
+ .channel = BCM_SR_GENPLL4_TPIU_PLL_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x4, 7, 1, 13),
+ .mdiv = REG_VAL(0x18, 10, 9),
+ },
+ [BCM_SR_GENPLL4_NOC_CLK] = {
+ .channel = BCM_SR_GENPLL4_NOC_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x4, 8, 2, 14),
+ .mdiv = REG_VAL(0x18, 20, 9),
+ },
+ [BCM_SR_GENPLL4_CHCLK_FS4_CLK] = {
+ .channel = BCM_SR_GENPLL4_CHCLK_FS4_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x4, 9, 3, 15),
+ .mdiv = REG_VAL(0x1c, 0, 9),
+ },
+ [BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK] = {
+ .channel = BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x4, 10, 4, 16),
+ .mdiv = REG_VAL(0x1c, 10, 9),
+ },
};
static int sr_genpll4_clk_init(struct platform_device *pdev)
@@ -181,18 +264,21 @@ static const struct iproc_pll_ctrl sr_genpll5 = {
};
static const struct iproc_clk_ctrl sr_genpll5_clk[] = {
- [BCM_SR_GENPLL5_FS_CLK] = {
- .channel = BCM_SR_GENPLL5_FS_CLK,
- .flags = IPROC_CLK_AON,
+ [BCM_SR_GENPLL5_FS4_HF_CLK] = {
+ .channel = BCM_SR_GENPLL5_FS4_HF_CLK,
.enable = ENABLE_VAL(0x4, 6, 0, 12),
.mdiv = REG_VAL(0x18, 0, 9),
},
- [BCM_SR_GENPLL5_SPU_CLK] = {
- .channel = BCM_SR_GENPLL5_SPU_CLK,
- .flags = IPROC_CLK_AON,
- .enable = ENABLE_VAL(0x4, 6, 0, 12),
+ [BCM_SR_GENPLL5_CRYPTO_AE_CLK] = {
+ .channel = BCM_SR_GENPLL5_CRYPTO_AE_CLK,
+ .enable = ENABLE_VAL(0x4, 7, 1, 12),
.mdiv = REG_VAL(0x18, 10, 9),
},
+ [BCM_SR_GENPLL5_RAID_AE_CLK] = {
+ .channel = BCM_SR_GENPLL5_RAID_AE_CLK,
+ .enable = ENABLE_VAL(0x4, 8, 2, 14),
+ .mdiv = REG_VAL(0x18, 20, 9),
+ },
};
static int sr_genpll5_clk_init(struct platform_device *pdev)
@@ -214,24 +300,30 @@ static const struct iproc_pll_ctrl sr_lcpll0 = {
};
static const struct iproc_clk_ctrl sr_lcpll0_clk[] = {
- [BCM_SR_LCPLL0_SATA_REF_CLK] = {
- .channel = BCM_SR_LCPLL0_SATA_REF_CLK,
+ [BCM_SR_LCPLL0_SATA_REFP_CLK] = {
+ .channel = BCM_SR_LCPLL0_SATA_REFP_CLK,
.flags = IPROC_CLK_AON,
.enable = ENABLE_VAL(0x0, 7, 1, 13),
.mdiv = REG_VAL(0x14, 0, 9),
},
- [BCM_SR_LCPLL0_USB_REF_CLK] = {
- .channel = BCM_SR_LCPLL0_USB_REF_CLK,
+ [BCM_SR_LCPLL0_SATA_REFN_CLK] = {
+ .channel = BCM_SR_LCPLL0_SATA_REFN_CLK,
.flags = IPROC_CLK_AON,
.enable = ENABLE_VAL(0x0, 8, 2, 14),
.mdiv = REG_VAL(0x14, 10, 9),
},
- [BCM_SR_LCPLL0_SATA_REFPN_CLK] = {
- .channel = BCM_SR_LCPLL0_SATA_REFPN_CLK,
+ [BCM_SR_LCPLL0_SATA_350_CLK] = {
+ .channel = BCM_SR_LCPLL0_SATA_350_CLK,
.flags = IPROC_CLK_AON,
.enable = ENABLE_VAL(0x0, 9, 3, 15),
.mdiv = REG_VAL(0x14, 20, 9),
},
+ [BCM_SR_LCPLL0_SATA_500_CLK] = {
+ .channel = BCM_SR_LCPLL0_SATA_500_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x0, 10, 4, 16),
+ .mdiv = REG_VAL(0x18, 0, 9),
+ },
};
static int sr_lcpll0_clk_init(struct platform_device *pdev)
@@ -259,6 +351,18 @@ static const struct iproc_clk_ctrl sr_lcpll1_clk[] = {
.enable = ENABLE_VAL(0x0, 7, 1, 13),
.mdiv = REG_VAL(0x14, 0, 9),
},
+ [BCM_SR_LCPLL1_USB_REF_CLK] = {
+ .channel = BCM_SR_LCPLL1_USB_REF_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x0, 8, 2, 14),
+ .mdiv = REG_VAL(0x14, 10, 9),
+ },
+ [BCM_SR_LCPLL1_CRMU_TS_CLK] = {
+ .channel = BCM_SR_LCPLL1_CRMU_TS_CLK,
+ .flags = IPROC_CLK_AON,
+ .enable = ENABLE_VAL(0x0, 9, 3, 15),
+ .mdiv = REG_VAL(0x14, 20, 9),
+ },
};
static int sr_lcpll1_clk_init(struct platform_device *pdev)
@@ -298,6 +402,7 @@ static int sr_lcpll_pcie_clk_init(struct platform_device *pdev)
static const struct of_device_id sr_clk_dt_ids[] = {
{ .compatible = "brcm,sr-genpll0", .data = sr_genpll0_clk_init },
+ { .compatible = "brcm,sr-genpll2", .data = sr_genpll2_clk_init },
{ .compatible = "brcm,sr-genpll4", .data = sr_genpll4_clk_init },
{ .compatible = "brcm,sr-genpll5", .data = sr_genpll5_clk_init },
{ .compatible = "brcm,sr-lcpll0", .data = sr_lcpll0_clk_init },
--
2.1.4
^ permalink raw reply related
* [PATCH v3 1/3] dt-bindings: clk: Update Stingray binding doc
From: Ray Jui @ 2018-06-02 0:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527900968-12017-1-git-send-email-ray.jui@broadcom.com>
From: Pramod Kumar <pramod.kumar@broadcom.com>
Update Stingray clock binding document to add additional clock entries
with names matching the latest ASIC datasheet. Also modify a few existing
entries to make their naming more consistent with the rest of the entries
Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
Signed-off-by: Ray Jui <ray.jui@broadcom.com>
---
.../bindings/clock/brcm,iproc-clocks.txt | 26 ++++++++++++----------
include/dt-bindings/clock/bcm-sr.h | 24 ++++++++++++++------
2 files changed, 31 insertions(+), 19 deletions(-)
diff --git a/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt b/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt
index f8e4a93..ab730ea 100644
--- a/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/brcm,iproc-clocks.txt
@@ -276,36 +276,38 @@ These clock IDs are defined in:
clk_ts_500_ref genpll2 2 BCM_SR_GENPLL2_TS_500_REF_CLK
clk_125_nitro genpll2 3 BCM_SR_GENPLL2_125_NITRO_CLK
clk_chimp genpll2 4 BCM_SR_GENPLL2_CHIMP_CLK
- clk_nic_flash genpll2 5 BCM_SR_GENPLL2_NIC_FLASH
+ clk_nic_flash genpll2 5 BCM_SR_GENPLL2_NIC_FLASH_CLK
+ clk_fs genpll2 6 BCM_SR_GENPLL2_FS_CLK
genpll3 crystal 0 BCM_SR_GENPLL3
clk_hsls genpll3 1 BCM_SR_GENPLL3_HSLS_CLK
clk_sdio genpll3 2 BCM_SR_GENPLL3_SDIO_CLK
genpll4 crystal 0 BCM_SR_GENPLL4
- ccn genpll4 1 BCM_SR_GENPLL4_CCN_CLK
+ clk_ccn genpll4 1 BCM_SR_GENPLL4_CCN_CLK
clk_tpiu_pll genpll4 2 BCM_SR_GENPLL4_TPIU_PLL_CLK
- noc_clk genpll4 3 BCM_SR_GENPLL4_NOC_CLK
+ clk_noc genpll4 3 BCM_SR_GENPLL4_NOC_CLK
clk_chclk_fs4 genpll4 4 BCM_SR_GENPLL4_CHCLK_FS4_CLK
clk_bridge_fscpu genpll4 5 BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK
-
genpll5 crystal 0 BCM_SR_GENPLL5
- fs4_hf_clk genpll5 1 BCM_SR_GENPLL5_FS4_HF_CLK
- crypto_ae_clk genpll5 2 BCM_SR_GENPLL5_CRYPTO_AE_CLK
- raid_ae_clk genpll5 3 BCM_SR_GENPLL5_RAID_AE_CLK
+ clk_fs4_hf genpll5 1 BCM_SR_GENPLL5_FS4_HF_CLK
+ clk_crypto_ae genpll5 2 BCM_SR_GENPLL5_CRYPTO_AE_CLK
+ clk_raid_ae genpll5 3 BCM_SR_GENPLL5_RAID_AE_CLK
genpll6 crystal 0 BCM_SR_GENPLL6
- 48_usb genpll6 1 BCM_SR_GENPLL6_48_USB_CLK
+ clk_48_usb genpll6 1 BCM_SR_GENPLL6_48_USB_CLK
lcpll0 crystal 0 BCM_SR_LCPLL0
clk_sata_refp lcpll0 1 BCM_SR_LCPLL0_SATA_REFP_CLK
clk_sata_refn lcpll0 2 BCM_SR_LCPLL0_SATA_REFN_CLK
- clk_usb_ref lcpll0 3 BCM_SR_LCPLL0_USB_REF_CLK
- sata_refpn lcpll0 3 BCM_SR_LCPLL0_SATA_REFPN_CLK
+ clk_sata_350 lcpll0 3 BCM_SR_LCPLL0_SATA_350_CLK
+ clk_sata_500 lcpll0 4 BCM_SR_LCPLL0_SATA_500_CLK
lcpll1 crystal 0 BCM_SR_LCPLL1
- wan lcpll1 1 BCM_SR_LCPLL0_WAN_CLK
+ clk_wan lcpll1 1 BCM_SR_LCPLL1_WAN_CLK
+ clk_usb_ref lcpll1 2 BCM_SR_LCPLL1_USB_REF_CLK
+ clk_crmu_ts lcpll1 3 BCM_SR_LCPLL1_CRMU_TS_CLK
lcpll_pcie crystal 0 BCM_SR_LCPLL_PCIE
- pcie_phy_ref lcpll1 1 BCM_SR_LCPLL_PCIE_PHY_REF_CLK
+ clk_pcie_phy_ref lcpll1 1 BCM_SR_LCPLL_PCIE_PHY_REF_CLK
diff --git a/include/dt-bindings/clock/bcm-sr.h b/include/dt-bindings/clock/bcm-sr.h
index cff6c6f..419011b 100644
--- a/include/dt-bindings/clock/bcm-sr.h
+++ b/include/dt-bindings/clock/bcm-sr.h
@@ -35,7 +35,7 @@
/* GENPLL 0 clock channel ID SCR HSLS FS PCIE */
#define BCM_SR_GENPLL0 0
-#define BCM_SR_GENPLL0_SATA_CLK 1
+#define BCM_SR_GENPLL0_125M_CLK 1
#define BCM_SR_GENPLL0_SCR_CLK 2
#define BCM_SR_GENPLL0_250M_CLK 3
#define BCM_SR_GENPLL0_PCIE_AXI_CLK 4
@@ -50,9 +50,11 @@
/* GENPLL 2 clock channel ID NITRO MHB*/
#define BCM_SR_GENPLL2 0
#define BCM_SR_GENPLL2_NIC_CLK 1
-#define BCM_SR_GENPLL2_250_NITRO_CLK 2
+#define BCM_SR_GENPLL2_TS_500_CLK 2
#define BCM_SR_GENPLL2_125_NITRO_CLK 3
#define BCM_SR_GENPLL2_CHIMP_CLK 4
+#define BCM_SR_GENPLL2_NIC_FLASH_CLK 5
+#define BCM_SR_GENPLL2_FS4_CLK 6
/* GENPLL 3 HSLS clock channel ID */
#define BCM_SR_GENPLL3 0
@@ -62,11 +64,16 @@
/* GENPLL 4 SCR clock channel ID */
#define BCM_SR_GENPLL4 0
#define BCM_SR_GENPLL4_CCN_CLK 1
+#define BCM_SR_GENPLL4_TPIU_PLL_CLK 2
+#define BCM_SR_GENPLL4_NOC_CLK 3
+#define BCM_SR_GENPLL4_CHCLK_FS4_CLK 4
+#define BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK 5
/* GENPLL 5 FS4 clock channel ID */
#define BCM_SR_GENPLL5 0
-#define BCM_SR_GENPLL5_FS_CLK 1
-#define BCM_SR_GENPLL5_SPU_CLK 2
+#define BCM_SR_GENPLL5_FS4_HF_CLK 1
+#define BCM_SR_GENPLL5_CRYPTO_AE_CLK 2
+#define BCM_SR_GENPLL5_RAID_AE_CLK 3
/* GENPLL 6 NITRO clock channel ID */
#define BCM_SR_GENPLL6 0
@@ -74,13 +81,16 @@
/* LCPLL0 clock channel ID */
#define BCM_SR_LCPLL0 0
-#define BCM_SR_LCPLL0_SATA_REF_CLK 1
-#define BCM_SR_LCPLL0_USB_REF_CLK 2
-#define BCM_SR_LCPLL0_SATA_REFPN_CLK 3
+#define BCM_SR_LCPLL0_SATA_REFP_CLK 1
+#define BCM_SR_LCPLL0_SATA_REFN_CLK 2
+#define BCM_SR_LCPLL0_SATA_350_CLK 3
+#define BCM_SR_LCPLL0_SATA_500_CLK 4
/* LCPLL1 clock channel ID */
#define BCM_SR_LCPLL1 0
#define BCM_SR_LCPLL1_WAN_CLK 1
+#define BCM_SR_LCPLL1_USB_REF_CLK 2
+#define BCM_SR_LCPLL1_CRMU_TS_CLK 3
/* LCPLL PCIE clock channel ID */
#define BCM_SR_LCPLL_PCIE 0
--
2.1.4
^ permalink raw reply related
* [PATCH v3 0/3] Update Broadcom Stingray clock entries
From: Ray Jui @ 2018-06-02 0:56 UTC (permalink / raw)
To: linux-arm-kernel
This patch series updates Broadcom Stingray clock entries so they match the
latest ASIC datasheet
This patch series is based off v4.17-rc5 and is available on GIHUB:
repo: https://github.com/Broadcom/arm64-linux.git
branch: sr-clk-v3
Changes since v2:
- Move dt-binding header change to the same patch with the binding doc
update
Changes since v1:
- Fix patch author to Pramod Kumar on all 3 patches
- Fix patch subject spelling error on patch 2/3
Pramod Kumar (3):
dt-bindings: clk: Update Stingray binding doc
clk: bcm: Update and add Stingray clock entries
arm64: dts: Update Stingray clock DT nodes
.../bindings/clock/brcm,iproc-clocks.txt | 26 ++--
.../boot/dts/broadcom/stingray/stingray-clock.dtsi | 26 ++--
drivers/clk/bcm/clk-sr.c | 135 ++++++++++++++++++---
include/dt-bindings/clock/bcm-sr.h | 24 ++--
4 files changed, 170 insertions(+), 41 deletions(-)
--
2.1.4
^ permalink raw reply
* [PATCH 2/3] clk: bcm: Update and add tingray clock entries
From: Ray Jui @ 2018-06-02 0:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAL_Jsq+YX01CwCycqeu5mxTUiWtnG3HKPJP5mvJO2OHcPF6v6g@mail.gmail.com>
On 6/1/2018 12:02 PM, Rob Herring wrote:
> On Fri, Jun 1, 2018 at 12:56 PM, Ray Jui <ray.jui@broadcom.com> wrote:
>> Hi Rob,
>>
>> On 5/31/2018 9:25 AM, Rob Herring wrote:
>>>
>>> On Fri, May 25, 2018 at 09:45:16AM -0700, Ray Jui wrote:
>>>>
>>>> Update and add Stingray clock definitions and tables so they match the
>>>> binding document and the latest ASIC datasheet
>>>>
>>>> Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
>>>> Signed-off-by: Ray Jui <ray.jui@broadcom.com>
>>>> ---
>>>> drivers/clk/bcm/clk-sr.c | 135
>>>> ++++++++++++++++++++++++++++++++-----
>>>> include/dt-bindings/clock/bcm-sr.h | 24 +++++--
>>>
>>>
>>> This goes in the 1st patch.
>>
>>
>> Please help to confirm. You want 1st patch and 2nd patch to be combined into
>> a single patch?
>
> No. include/dt-bindings/* is part of the DT binding, so it goes with
> patch 1. The driver in patch 2.
>
> Rob
>
Okay got it. Thanks!
^ permalink raw reply
* [PATCH V5] arm64: alternative:flush cache with unpatched code
From: Rohit Khanna @ 2018-06-02 0:41 UTC (permalink / raw)
To: linux-arm-kernel
In the current implementation, __apply_alternatives patches
flush_icache_range and then executes it without invalidating the icache.
Thus, icache can contain some of the old instructions for
flush_icache_range. This can cause unpredictable behavior as during
execution we can get a mix of old and new instructions for
flush_icache_range.
This patch :
1. Adds a new function clean_dcache_range_nopatch for flushing kernel
memory range. This function uses non hot-patched code and can be
safely used to flush cache during code patching.
2. Modifies __apply_alternatives so that it uses
clean_dcache_range_nopatch to flush the cache range after patching code.
Signed-off-by: Rohit Khanna <rokhanna@nvidia.com>
---
arch/arm64/include/asm/cache.h | 1 +
arch/arm64/kernel/alternative.c | 37 ++++++++++++++++++++++++++++++++++++-
2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index 5df5cfe1c143..9211ecd85b15 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -21,6 +21,7 @@
#define CTR_L1IP_SHIFT 14
#define CTR_L1IP_MASK 3
#define CTR_DMINLINE_SHIFT 16
+#define CTR_IMINLINE_SHIT 0
#define CTR_ERG_SHIFT 20
#define CTR_CWG_SHIFT 24
#define CTR_CWG_MASK 15
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index 5c4bce4ac381..da5815807aeb 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -122,6 +122,41 @@ static void patch_alternative(struct alt_instr *alt,
}
}
+/* This is used for flushing kernel memory range after
+ * __apply_alternatives has patched kernel code
+ */
+static void clean_dcache_range_nopatch(void *start, void *end)
+{
+ u64 cur, d_size, i_size, ctr_el0;
+
+ /* use sanitised value of ctr_el0 rather than raw value from CPU */
+ ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
+ /* size in bytes */
+ d_size = 4 << cpuid_feature_extract_unsigned_field(ctr_el0,
+ CTR_DMINLINE_SHIFT);
+ i_size = 4 << cpuid_feature_extract_unsigned_field(ctr_el0,
+ CTR_IMINLINE_SHIT);
+
+ cur = (u64)start & ~(d_size - 1);
+ /* Ensure compiler doesn't reorder this against patching code */
+ barrier();
+ do {
+ /* Use civac instead of cvau. This is required
+ * due to ARM errata 826319, 827319, 824069,
+ * 819472 on A53
+ */
+ asm volatile("dc civac, %0" : : "r" (cur));
+ } while (cur += d_size, cur < (u64)end);
+ dsb(ish);
+
+ cur = (u64)start & ~(i_size - 1);
+ do {
+ asm volatile("ic ivau, %0" : : "r" (cur));
+ } while (cur += i_size, cur < (u64)end);
+ dsb(ish);
+ isb();
+}
+
static void __apply_alternatives(void *alt_region, bool use_linear_alias)
{
struct alt_instr *alt;
@@ -155,7 +190,7 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
alt_cb(alt, origptr, updptr, nr_inst);
- flush_icache_range((uintptr_t)origptr,
+ clean_dcache_range_nopatch((uintptr_t)origptr,
(uintptr_t)(origptr + nr_inst));
}
}
--
2.1.4
^ permalink raw reply related
* [PATCH] arm64: alternative:flush cache with unpatched code
From: Rohit Khanna @ 2018-06-02 0:39 UTC (permalink / raw)
To: linux-arm-kernel
In the current implementation, __apply_alternatives patches
flush_icache_range and then executes it without invalidating the icache.
Thus, icache can contain some of the old instructions for
flush_icache_range. This can cause unpredictable behavior as during
execution we can get a mix of old and new instructions for
flush_icache_range.
This patch :
1. Adds a new function clean_dcache_range_nopatch for flushing kernel
memory range. This function uses non hot-patched code and can be
safely used to flush cache during code patching.
2. Modifies __apply_alternatives so that it uses
clean_dcache_range_nopatch to flush the cache range after patching code.
Signed-off-by: Rohit Khanna <rokhanna@nvidia.com>
---
arch/arm64/include/asm/cache.h | 1 +
arch/arm64/kernel/alternative.c | 37 ++++++++++++++++++++++++++++++++++++-
2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index 5df5cfe1c143..9211ecd85b15 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -21,6 +21,7 @@
#define CTR_L1IP_SHIFT 14
#define CTR_L1IP_MASK 3
#define CTR_DMINLINE_SHIFT 16
+#define CTR_IMINLINE_SHIT 0
#define CTR_ERG_SHIFT 20
#define CTR_CWG_SHIFT 24
#define CTR_CWG_MASK 15
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index 5c4bce4ac381..da5815807aeb 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -122,6 +122,41 @@ static void patch_alternative(struct alt_instr *alt,
}
}
+/* This is used for flushing kernel memory range after
+ * __apply_alternatives has patched kernel code
+ */
+static void clean_dcache_range_nopatch(void *start, void *end)
+{
+ u64 cur, d_size, i_size, ctr_el0;
+
+ /* use sanitised value of ctr_el0 rather than raw value from CPU */
+ ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
+ /* size in bytes */
+ d_size = 4 << cpuid_feature_extract_unsigned_field(ctr_el0,
+ CTR_DMINLINE_SHIFT);
+ i_size = 4 << cpuid_feature_extract_unsigned_field(ctr_el0,
+ CTR_IMINLINE_SHIT);
+
+ cur = (u64)start & ~(d_size - 1);
+ /* Ensure compiler doesn't reorder this against patching code */
+ barrier();
+ do {
+ /* Use civac instead of cvau. This is required
+ * due to ARM errata 826319, 827319, 824069,
+ * 819472 on A53
+ */
+ asm volatile("dc civac, %0" : : "r" (cur));
+ } while (cur += d_size, cur < (u64)end);
+ dsb(ish);
+
+ cur = (u64)start & ~(i_size - 1);
+ do {
+ asm volatile("ic ivau, %0" : : "r" (cur));
+ } while (cur += i_size, cur < (u64)end);
+ dsb(ish);
+ isb();
+}
+
static void __apply_alternatives(void *alt_region, bool use_linear_alias)
{
struct alt_instr *alt;
@@ -155,7 +190,7 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
alt_cb(alt, origptr, updptr, nr_inst);
- flush_icache_range((uintptr_t)origptr,
+ clean_dcache_range_nopatch((uintptr_t)origptr,
(uintptr_t)(origptr + nr_inst));
}
}
--
2.1.4
^ permalink raw reply related
* [PATCH v2] of: platform: stop accessing invalid dev in of_platform_device_destroy
From: Srinivas Kandagatla @ 2018-06-02 0:03 UTC (permalink / raw)
To: linux-arm-kernel
Immediately after the platform_device_unregister() the device will be cleaned up.
Accessing the freed pointer immediately after that will crash the system.
Found this bug when kernel is built with CONFIG_PAGE_POISONING and testing
loading/unloading audio drivers in a loop on Qcom platforms.
Fix this by removing accessing the dev pointer.
Below is the carsh trace:
Unable to handle kernel paging request at virtual address 6b6b6b6b6b6c03
Mem abort info:
ESR = 0x96000021
Exception class = DABT (current EL), IL = 32 bits
SET = 0, FnV = 0
EA = 0, S1PTW = 0
Data abort info:
ISV = 0, ISS = 0x00000021
CM = 0, WnR = 0
[006b6b6b6b6b6c03] address between user and kernel address ranges
Internal error: Oops: 96000021 [#1] PREEMPT SMP
Modules linked in:
CPU: 2 PID: 1784 Comm: sh Tainted: G W 4.17.0-rc7-02230-ge3a63a7ef641-dirty #204
Hardware name: Qualcomm Technologies, Inc. APQ 8016 SBC (DT)
pstate: 80000005 (Nzcv daif -PAN -UAO)
pc : clear_bit+0x18/0x2c
lr : of_platform_device_destroy+0x64/0xb8
sp : ffff00000c9c3930
x29: ffff00000c9c3930 x28: ffff80003d39b200
x27: ffff000008bb1000 x26: 0000000000000040
x25: 0000000000000124 x24: ffff80003a9a3080
x23: 0000000000000060 x22: ffff00000939f518
x21: ffff80003aa79e98 x20: ffff80003aa3dae0
x19: ffff80003aa3c890 x18: ffff800009feb794
x17: 0000000000000000 x16: 0000000000000000
x15: ffff800009feb790 x14: 0000000000000000
x13: ffff80003a058778 x12: ffff80003a058728
x11: ffff80003a058750 x10: 0000000000000000
x9 : 0000000000000006 x8 : ffff80003a825988
x7 : bbbbbbbbbbbbbbbb x6 : 0000000000000001
x5 : 0000000000000000 x4 : 0000000000000001
x3 : 0000000000000008 x2 : 0000000000000001
x1 : 6b6b6b6b6b6b6c03 x0 : 0000000000000000
Process sh (pid: 1784, stack limit = 0x (ptrval))
Call trace:
clear_bit+0x18/0x2c
q6afe_remove+0x20/0x38
apr_device_remove+0x30/0x70
device_release_driver_internal+0x170/0x208
device_release_driver+0x14/0x20
bus_remove_device+0xcc/0x150
device_del+0x10c/0x310
device_unregister+0x1c/0x70
apr_remove_device+0xc/0x18
device_for_each_child+0x50/0x80
apr_remove+0x18/0x20
rpmsg_dev_remove+0x38/0x68
device_release_driver_internal+0x170/0x208
device_release_driver+0x14/0x20
bus_remove_device+0xcc/0x150
device_del+0x10c/0x310
device_unregister+0x1c/0x70
qcom_smd_remove_device+0xc/0x18
device_for_each_child+0x50/0x80
qcom_smd_unregister_edge+0x3c/0x70
smd_subdev_remove+0x18/0x28
rproc_stop+0x48/0xd8
rproc_shutdown+0x60/0xe8
state_store+0xbc/0xf8
dev_attr_store+0x18/0x28
sysfs_kf_write+0x3c/0x50
kernfs_fop_write+0x118/0x1e0
__vfs_write+0x18/0x110
vfs_write+0xa4/0x1a8
ksys_write+0x48/0xb0
sys_write+0xc/0x18
el0_svc_naked+0x30/0x34
Code: d2800022 8b400c21 f9800031 9ac32043 (c85f7c22)
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
Changes since v1:
- fixed issue while reprobing.
drivers/of/platform.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index c00d81dfac0b..84c5c899187b 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -529,10 +529,13 @@ arch_initcall_sync(of_platform_default_populate_init);
int of_platform_device_destroy(struct device *dev, void *data)
{
+ struct device_node *np;
+
/* Do not touch devices not populated from the device tree */
if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED))
return 0;
+ np = dev->of_node;
/* Recurse for any nodes that were treated as busses */
if (of_node_check_flag(dev->of_node, OF_POPULATED_BUS))
device_for_each_child(dev, NULL, of_platform_device_destroy);
@@ -544,8 +547,8 @@ int of_platform_device_destroy(struct device *dev, void *data)
amba_device_unregister(to_amba_device(dev));
#endif
- of_node_clear_flag(dev->of_node, OF_POPULATED);
- of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
+ of_node_clear_flag(np, OF_POPULATED);
+ of_node_clear_flag(np, OF_POPULATED_BUS);
return 0;
}
EXPORT_SYMBOL_GPL(of_platform_device_destroy);
--
2.16.2
^ permalink raw reply related
* [PATCH] of: platform: stop accessing invalid dev in of_platform_device_destroy
From: Srinivas Kandagatla @ 2018-06-01 23:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601225822.23439-1-srinivas.kandagatla@linaro.org>
On 01/06/18 23:58, Srinivas Kandagatla wrote:
>
> - of_node_clear_flag(dev->of_node, OF_POPULATED);
> - of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
This change seems to have a side effect during re-probing. I will dig in
bit more to see how best it can be fixed.
thanks,
srini
^ permalink raw reply
* [PATCH] of: platform: stop accessing invalid dev in of_platform_device_destroy
From: Srinivas Kandagatla @ 2018-06-01 22:58 UTC (permalink / raw)
To: linux-arm-kernel
Immediately after the platform_device_unregister() the device will be cleaned up.
Accessing the freed pointer immediately after that will crash the system.
Found this bug when kernel is built with CONFIG_PAGE_POISONING and testing
loading/unloading audio drivers in a loop on Qcom platforms.
Fix this by removing accessing the dev pointer.
Below is the carsh trace:
Unable to handle kernel paging request at virtual address 6b6b6b6b6b6c03
Mem abort info:
ESR = 0x96000021
Exception class = DABT (current EL), IL = 32 bits
SET = 0, FnV = 0
EA = 0, S1PTW = 0
Data abort info:
ISV = 0, ISS = 0x00000021
CM = 0, WnR = 0
[006b6b6b6b6b6c03] address between user and kernel address ranges
Internal error: Oops: 96000021 [#1] PREEMPT SMP
Modules linked in:
CPU: 2 PID: 1784 Comm: sh Tainted: G W 4.17.0-rc7-02230-ge3a63a7ef641-dirty #204
Hardware name: Qualcomm Technologies, Inc. APQ 8016 SBC (DT)
pstate: 80000005 (Nzcv daif -PAN -UAO)
pc : clear_bit+0x18/0x2c
lr : of_platform_device_destroy+0x64/0xb8
sp : ffff00000c9c3930
x29: ffff00000c9c3930 x28: ffff80003d39b200
x27: ffff000008bb1000 x26: 0000000000000040
x25: 0000000000000124 x24: ffff80003a9a3080
x23: 0000000000000060 x22: ffff00000939f518
x21: ffff80003aa79e98 x20: ffff80003aa3dae0
x19: ffff80003aa3c890 x18: ffff800009feb794
x17: 0000000000000000 x16: 0000000000000000
x15: ffff800009feb790 x14: 0000000000000000
x13: ffff80003a058778 x12: ffff80003a058728
x11: ffff80003a058750 x10: 0000000000000000
x9 : 0000000000000006 x8 : ffff80003a825988
x7 : bbbbbbbbbbbbbbbb x6 : 0000000000000001
x5 : 0000000000000000 x4 : 0000000000000001
x3 : 0000000000000008 x2 : 0000000000000001
x1 : 6b6b6b6b6b6b6c03 x0 : 0000000000000000
Process sh (pid: 1784, stack limit = 0x (ptrval))
Call trace:
clear_bit+0x18/0x2c
q6afe_remove+0x20/0x38
apr_device_remove+0x30/0x70
device_release_driver_internal+0x170/0x208
device_release_driver+0x14/0x20
bus_remove_device+0xcc/0x150
device_del+0x10c/0x310
device_unregister+0x1c/0x70
apr_remove_device+0xc/0x18
device_for_each_child+0x50/0x80
apr_remove+0x18/0x20
rpmsg_dev_remove+0x38/0x68
device_release_driver_internal+0x170/0x208
device_release_driver+0x14/0x20
bus_remove_device+0xcc/0x150
device_del+0x10c/0x310
device_unregister+0x1c/0x70
qcom_smd_remove_device+0xc/0x18
device_for_each_child+0x50/0x80
qcom_smd_unregister_edge+0x3c/0x70
smd_subdev_remove+0x18/0x28
rproc_stop+0x48/0xd8
rproc_shutdown+0x60/0xe8
state_store+0xbc/0xf8
dev_attr_store+0x18/0x28
sysfs_kf_write+0x3c/0x50
kernfs_fop_write+0x118/0x1e0
__vfs_write+0x18/0x110
vfs_write+0xa4/0x1a8
ksys_write+0x48/0xb0
sys_write+0xc/0x18
el0_svc_naked+0x30/0x34
Code: d2800022 8b400c21 f9800031 9ac32043 (c85f7c22)
---[ end trace 32020935775616a2 ]---
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
drivers/of/platform.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index c00d81dfac0b..78c32b93c0e7 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -544,8 +544,6 @@ int of_platform_device_destroy(struct device *dev, void *data)
amba_device_unregister(to_amba_device(dev));
#endif
- of_node_clear_flag(dev->of_node, OF_POPULATED);
- of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
return 0;
}
EXPORT_SYMBOL_GPL(of_platform_device_destroy);
--
2.16.2
^ permalink raw reply related
* [PATCH] ASoC: dapm: delete dapm_kcontrol_data paths entry before freeing
From: Srinivas Kandagatla @ 2018-06-01 22:53 UTC (permalink / raw)
To: linux-arm-kernel
dapm_kcontrol_data is freed as part of dapm_kcontrol_free(), leaving the
paths list pointer dangling in the list.
This leads to system crash when we try to unload and reload sound card.
I hit this bug during ADSP crash/reboot test case on Dragon board DB410c.
Below is the kernel BUG with SLAB Poisoning
=============================================================================
BUG kmalloc-128 (Tainted: G W ): Poison overwritten
-----------------------------------------------------------------------------
Disabling lock debugging due to kernel taint
INFO: 0xffff80003cf1c310-0xffff80003cf1c31f. First byte 0x10 instead of 0x6b
INFO: Allocated in dapm_kcontrol_data_alloc.isra.37+0x34/0x2a8 age=6929 cpu=0 pid=50
__slab_alloc.isra.24+0x24/0x38
kmem_cache_alloc+0x190/0x1d8
dapm_kcontrol_data_alloc.isra.37+0x34/0x2a8
dapm_create_or_share_kcontrol+0x1d4/0x290
snd_soc_dapm_new_widgets+0x410/0x568
snd_soc_register_card+0xa58/0xcd0
apq8016_sbc_bind+0x31c/0x458
try_to_bring_up_master+0x204/0x2e8
component_add+0x94/0x178
q6pcm_routing_probe+0x38/0x48
platform_drv_probe+0x58/0xb8
driver_probe_device+0x324/0x478
__device_attach_driver+0xa8/0x160
bus_for_each_drv+0x48/0x98
__device_attach+0xc0/0x158
device_initial_probe+0x10/0x18
INFO: Freed in dapm_kcontrol_free+0x40/0x50 age=3135 cpu=1 pid=1792
kfree+0x1bc/0x1d0
dapm_kcontrol_free+0x40/0x50
snd_ctl_free_one+0x20/0x38
snd_ctl_remove+0xf0/0x108
snd_ctl_dev_free+0x3c/0x70
__snd_device_free+0x50/0x88
snd_device_free_all+0x2c/0x50
release_card_device+0x1c/0x78
device_release+0x34/0x98
kobject_put+0x90/0x1f0
put_device+0x14/0x20
snd_card_free+0x54/0x70
snd_soc_unregister_card+0x84/0x138
snd_soc_unregister_component+0xa4/0xd0
q6routing_dai_unbind+0x44/0x78
component_unbind.isra.4+0x28/0x50
INFO: Slab 0xffff7e0000f3c700 objects=25 used=0 fp=0xffff80003cf1fc80 flags=0xfffc00000008100
INFO: Object 0x (ptrval) @offset=768 fp=0x (ptrval)
Redzone (ptrval): bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb ................
Redzone (ptrval): bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb ................
Redzone (ptrval): bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb ................
Redzone (ptrval): bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb ................
Redzone (ptrval): bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb ................
Redzone (ptrval): bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb ................
Redzone (ptrval): bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb ................
Redzone (ptrval): bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb ................
Object (ptrval): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object (ptrval): 10 c3 f1 3c 00 80 ff ff 10 c3 f1 3c 00 80 ff ff ...<.......<....
Object (ptrval): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object (ptrval): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object (ptrval): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object (ptrval): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object (ptrval): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
Object (ptrval): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
Redzone (ptrval): bb bb bb bb bb bb bb bb ........
Padding (ptrval): 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding (ptrval): 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding (ptrval): 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Padding (ptrval): 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
CPU: 1 PID: 1792 Comm: sh Tainted: G B W 4.17.0-rc7-02229-gb429ee402d16-dirty #202
Hardware name: Qualcomm Technologies, Inc. APQ 8016 SBC (DT)
Call trace:
dump_backtrace+0x0/0x1b0
show_stack+0x14/0x20
dump_stack+0x9c/0xbc
print_trailer+0x124/0x1d8
check_bytes_and_report+0xe8/0x120
check_object+0x24c/0x288
__free_slab+0x9c/0x2f0
discard_slab+0x60/0x88
__slab_free+0x35c/0x3e8
kfree+0x1bc/0x1d0
snd_soc_dapm_free_widget+0xac/0xd0
snd_soc_dapm_free+0x64/0xb8
soc_remove_component+0x50/0x80
soc_remove_dai_links+0x110/0x208
snd_soc_unregister_card+0x9c/0x138
snd_soc_unregister_component+0xa4/0xd0
q6routing_dai_unbind+0x44/0x78
component_unbind.isra.4+0x28/0x50
component_unbind_all+0xc0/0xe8
apq8016_sbc_unbind+0x50/0xa0
take_down_master+0x24/0x48
component_del+0x90/0x130
q6afe_dai_dev_remove+0x40/0x68
platform_drv_remove+0x24/0x50
device_release_driver_internal+0x170/0x208
device_release_driver+0x14/0x20
bus_remove_device+0xcc/0x150
device_del+0x10c/0x310
platform_device_del.part.3+0x24/0x90
platform_device_unregister+0x18/0x30
of_platform_device_destroy+0x94/0x98
q6afe_remove+0x20/0x38
apr_device_remove+0x30/0x70
device_release_driver_internal+0x170/0x208
device_release_driver+0x14/0x20
bus_remove_device+0xcc/0x150
device_del+0x10c/0x310
device_unregister+0x1c/0x70
apr_remove_device+0xc/0x18
device_for_each_child+0x50/0x80
apr_remove+0x18/0x20
rpmsg_dev_remove+0x38/0x68
device_release_driver_internal+0x170/0x208
device_release_driver+0x14/0x20
bus_remove_device+0xcc/0x150
device_del+0x10c/0x310
device_unregister+0x1c/0x70
qcom_smd_remove_device+0xc/0x18
device_for_each_child+0x50/0x80
qcom_smd_unregister_edge+0x3c/0x70
smd_subdev_remove+0x18/0x28
rproc_stop+0x48/0xd8
rproc_shutdown+0x60/0xe8
state_store+0xbc/0xf8
dev_attr_store+0x18/0x28
sysfs_kf_write+0x3c/0x50
kernfs_fop_write+0x118/0x1e0
__vfs_write+0x18/0x110
vfs_write+0xa4/0x1a8
ksys_write+0x48/0xb0
sys_write+0xc/0x18
el0_svc_naked+0x30/0x34
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
sound/soc/soc-dapm.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1e9a36389667..36a39ba30226 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -433,6 +433,8 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
+
+ list_del(&data->paths);
kfree(data->wlist);
kfree(data);
}
--
2.16.2
^ permalink raw reply related
* [PATCH v3 2/8] dt-bindings: media: Document data-enable-active property
From: Sakari Ailus @ 2018-06-01 22:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180601145827.GG10472@w540>
On Fri, Jun 01, 2018 at 04:58:27PM +0200, jacopo mondi wrote:
> Hi Sakari,
>
> On Fri, Jun 01, 2018 at 01:29:10PM +0300, Sakari Ailus wrote:
> > Hi Jacopo,
> >
> > Thanks for the patch.
> >
> > On Tue, May 29, 2018 at 05:05:53PM +0200, Jacopo Mondi wrote:
> > > Add 'data-enable-active' property to endpoint node properties list.
> > >
> > > The property allows to specify the polarity of the data-enable signal, which
> > > when in active state determinates when data lanes have to sampled for valid
> > > pixel data.
> >
> > Lanes or lines? I understand this is forthe parallel interface.
> >
>
> Now I'm confused. Are the parallel data 'lines' and the CSI-2 one
> 'lanes'? I thought 'lanes' applies to both.. am I wrong?
"Lane" is conventionally refer to a differential pair of wires on a serial
bus such as CSI-2. "Line" is used of a wire on a parallel bus.
--
Sakari Ailus
sakari.ailus at linux.intel.com
^ permalink raw reply
* [Query] PAGE_OFFSET on KASLR enabled ARM64 kernel
From: Bhupesh Sharma @ 2018-06-01 21:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5c78224a-528d-7aa5-58ba-858681f03b6a@redhat.com>
On Sat, Jun 2, 2018 at 3:11 AM, Bhupesh Sharma <bhsharma@redhat.com> wrote:
> On 05/31/2018 10:21 AM, Bhupesh Sharma wrote:
>>
>> Hi Ard,
>>
>> Sorry I was out for most of the day yesterday. Please see my responses
>> inline.
>>
>> On Mon, May 28, 2018 at 12:16 PM, Ard Biesheuvel
>> <ard.biesheuvel@linaro.org> wrote:
>>>
>>> On 27 May 2018 at 23:03, Bhupesh Sharma <bhsharma@redhat.com> wrote:
>>>>
>>>> Hi ARM64 maintainers,
>>>>
>>>> I am confused about the PAGE_OFFSET value (or the start of the linear
>>>> map) on a KASLR enabled ARM64 kernel that I am seeing on a board which
>>>> supports a compatible EFI firmware (with EFI_RNG_PROTOCOL support).
>>>>
>>>> 1. 'arch/arm64/include/asm/memory.h' defines PAGE_OFFSET as:
>>>>
>>>> /*
>>>> * PAGE_OFFSET - the virtual address of the start of the linear map
>>>> (top
>>>> * (VA_BITS - 1))
>>>> */
>>>> #define PAGE_OFFSET (UL(0xffffffffffffffff) - \
>>>> (UL(1) << (VA_BITS - 1)) + 1)
>>>>
>>>> So for example on a platform with VA_BITS=48, we have:
>>>> PAGE_OFFSET = 0xffff800000000000
>>>>
>>>> 2. However, for the KASLR case, we set the 'memstart_offset_seed ' to
>>>> use the 16-bits of the 'kaslr-seed' to randomize the linear region in
>>>> 'arch/arm64/kernel/kaslr.c' :
>>>>
>>>> u64 __init kaslr_early_init(u64 dt_phys)
>>>> {
>>>> <snip..>
>>>> /* use the top 16 bits to randomize the linear region */
>>>> memstart_offset_seed = seed >> 48;
>>>> <snip..>
>>>> }
>>>>
>>>> 3. Now, we use the 'memstart_offset_seed' value to randomize the
>>>> 'memstart_addr' value in 'arch/arm64/mm/init.c':
>>>>
>>>> void __init arm64_memblock_init(void)
>>>> {
>>>> <snip..>
>>>>
>>>> if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
>>>> extern u16 memstart_offset_seed;
>>>> u64 range = linear_region_size -
>>>> (memblock_end_of_DRAM() - memblock_start_of_DRAM());
>>>>
>>>> /*
>>>> * If the size of the linear region exceeds, by a sufficient
>>>> * margin, the size of the region that the available physical
>>>> * memory spans, randomize the linear region as well.
>>>> */
>>>> if (memstart_offset_seed > 0 && range >= ARM64_MEMSTART_ALIGN)
>>>> {
>>>> range = range / ARM64_MEMSTART_ALIGN + 1;
>>>> memstart_addr -= ARM64_MEMSTART_ALIGN *
>>>> ((range * memstart_offset_seed) >> 16);
>>>> }
>>>> }
>>>> <snip..>
>>>> }
>>>>
>>>> 4. Since 'memstart_addr' indicates the start of physical RAM, we
>>>> randomize the same on basis of 'memstart_offset_seed' value above.
>>>> Also the 'memstart_addr' value is available in '/proc/kallsyms' and
>>>> hence can be accessed by user-space applications to read the
>>>> 'memstart_addr' value.
>>>>
>>>> 5. Now since the PAGE_OFFSET value is also used by several user space
>>>> tools (for e.g. makedumpfile tool uses the same to determine the start
>>>> of linear region and hence to read PT_NOTE fields from /proc/kcore), I
>>>> am not sure how to read the randomized value of the same in the KASLR
>>>> enabled case.
>>>>
>>>> 6. Reading the code further and adding some debug prints, it seems the
>>>> 'memblock_start_of_DRAM()' value is more closer to the actual start of
>>>> linear region rather than 'memstart_addr' and 'PAGE_OFFSET" in case of
>>>> KASLR enabled kernel:
>>>>
>>>> [root at qualcomm-amberwing] # dmesg | grep -i "arm64_memblock_init" -A 5
>>>>
>>>> [ 0.000000] inside arm64_memblock_init, memstart_addr =
>>>> ffff976a00000000,
>>>> linearstart_addr = ffffe89600200000, memblock_start_of_DRAM =
>>>> ffffe89600200000,
>>>> PHYS_OFFSET = ffff976a00000000, PAGE_OFFSET = ffff800000000000,
>>>> KIMAGE_VADDR = ffff000008000000, kimage_vaddr = ffff20c2d7800000
>>>>
>>>> [root at qualcomm-amberwing] # dmesg | grep -i "Virtual kernel memory
>>>> layout" -A 15
>>>> [ 0.000000] Virtual kernel memory layout:
>>>> [ 0.000000] modules : 0xffff000000000000 - 0xffff000008000000
>>>> ( 128 MB)
>>>> [ 0.000000] vmalloc : 0xffff000008000000 - 0xffff7bdfffff0000
>>>> (126847 GB)
>>>> [ 0.000000] .text : 0xffff20c2d7880000 - 0xffff20c2d8040000
>>>> ( 7936 KB)
>>>> [ 0.000000] .rodata : 0xffff20c2d8040000 - 0xffff20c2d83a0000
>>>> ( 3456 KB)
>>>> [ 0.000000] .init : 0xffff20c2d83a0000 - 0xffff20c2d8750000
>>>> ( 3776 KB)
>>>> [ 0.000000] .data : 0xffff20c2d8750000 - 0xffff20c2d891b200
>>>> ( 1837 KB)
>>>> [ 0.000000] .bss : 0xffff20c2d891b200 - 0xffff20c2d90a5198
>>>> ( 7720 KB)
>>>> [ 0.000000] fixed : 0xffff7fdffe790000 - 0xffff7fdffec00000
>>>> ( 4544 KB)
>>>> [ 0.000000] PCI I/O : 0xffff7fdffee00000 - 0xffff7fdfffe00000
>>>> ( 16 MB)
>>>> [ 0.000000] vmemmap : 0xffff7fe000000000 - 0xffff800000000000
>>>> ( 128 GB maximum)
>>>> [ 0.000000] 0xffff7ffa25800800 - 0xffff7ffa2b800000
>>>> ( 95 MB actual)
>>>> [ 0.000000] memory : 0xffffe89600200000 - 0xffffe8ae00000000
>>>> ( 98302 MB)
>>>>
>>>> As one can see above, the 'memblock_start_of_DRAM()' value of
>>>> 0xffffe89600200000 represents the start of linear region:
>>>>
>>>> [ 0.000000] memory : 0xffffe89600200000 - 0xffffe8ae00000000
>>>> ( 98302 MB)
>>>>
>>>> So, my question is to access the start of linear region (which was
>>>> earlier determinable via PAGE_OFFSET macro), whether I should:
>>>>
>>>> - do some back-computation for the start of linear region from the
>>>> 'memstart_addr' in user-space, or
>>>> - use a new global variable in kernel which is assigned the value of
>>>> memblock_start_of_DRAM()' and assign it to '/proc/kallsyms', so that
>>>> it can be read by user-space tools, or
>>>> - whether we should rather look at removing the PAGE_OFFSET usage from
>>>> the kernel and replace it with a global variable instead which is
>>>> properly updated for KASLR case as well.
>>>>
>>>> Kindly share your opinions on what can be a suitable solution in this
>>>> case.
>>>>
>>>> Thanks for your help.
>>>>
>>>
>>> Hello Bhupesh,
>>>
>>> Could you explain what the relevance is of PAGE_OFFSET to userland?
>>> The only thing that should matter is where the actual linear mapping
>>> of DRAM is, and I am not sure I understand why we care about where it
>>> resides relative to the base of the linear region.
>>
>>
>> Actually certain user-space tools like makedumpfile (which is used to
>> generate and compress the vmcore) and crash-utility (which is used to
>> debug the vmcore), rely on the PAGE_OFFSET value (which denotes the
>> base of the linear map region) to determine virtual to physical
>> mapping of the addresses lying in the linear region .
>>
>> One specific use case that I am working on at the moment is the
>> makedumpfile '--mem-usage', which allows one to see the page numbers
>> of current system (1st kernel) in different use (please see
>> MAKEDUMPFILE(8) for more details).
>>
>> Using this we can know how many pages are dumpable when different
>> dump_level is specified when invoking the makedumpfile.
>>
>> Normally, makedumpfile analyses the contents of '/proc/kcore' (while
>> excluding the crashkernel range), and then calculates the page number
>> of different kind per vmcoreinfo.
>>
>> For e.g. here is an output from my arm64 board (a non KASLR boot):
>>
>> TYPE PAGES EXCLUDABLE DESCRIPTION
>>
>> ----------------------------------------------------------------------
>> ZERO 49524 yes Pages
>> filled with zero
>> NON_PRI_CACHE 15143 yes Cache
>> pages without private flag
>> PRI_CACHE 29147 yes Cache
>> pages with private flag
>> USER 3684 yes User process
>> pages
>> FREE 1450569 yes Free pages
>> KERN_DATA 14243 no Dumpable
>> kernel data
>>
>> page size: 65536
>> Total pages on system: 1562310
>> Total size on system: 102387548160 Byte
>>
>> This use case requires directly reading the '/proc/kcore' and the
>> hence the PAGE_OFFSET value is used to determine the base address of
>> the linear region, whose value is not static in case of KASLR boot.
>>
>> Another use-case is where the crash-utility uses the PAGE_OFFSET value
>> to perform a virtual-to-physical conversion for the address lying in
>> the linear region:
>>
>> ulong
>> arm64_VTOP(ulong addr)
>> {
>> if (machdep->flags & NEW_VMEMMAP) {
>> if (addr >= machdep->machspec->page_offset)
>> return machdep->machspec->phys_offset
>> + (addr - machdep->machspec->page_offset);
>>
>> <..snip..>
>> }
>>
>
> Another confusing concept is the rounded-up value of 'memstart_addr' in
> 'arch/arm64/mm/init.c' when booting a non-KASLR_ kernel and when the value
> of memblock_start_of_DRAM() < ARM64_MEMSTART_ALIGN:
>
> void __init arm64_memblock_init(void)
> {
>
> <..snip..>
> /*
> * Select a suitable value for the base of physical memory.
> */
> memstart_addr = round_down(memblock_start_of_DRAM(),
> ARM64_MEMSTART_ALIGN);
> <..snip..>
> }
>
> For example, let's consider a case (which I see on my qualcomm board) where
> memblock_start_of_DRAM() = 0x200000 and ARM64_MEMSTART_ALIGN = 0x40000000 (I
> am using VA_BITS = 48 and a 64K page size), in this case
> memstart_addr is calculated at 0, as the round_down results in a value of 0.
>
> This is in contrast with the definition of the 'memblock_start_of_DRAM':
>
> /* lowest address */
> phys_addr_t __init_memblock memblock_start_of_DRAM(void)
> {
> return memblock.memory.regions[0].base;
> }
>
> As indicated by logs below, the first memblock region base starts from
> 0x200000 rather than the 'memstart_addr' value (which is 0)
>
> # dmesg | grep -i "Processing" -A 5
> [ 0.000000] efi: Processing EFI memory map:
> [ 0.000000] efi: 0x000000200000-0x00000021ffff [Runtime Data |RUN| |
> | | | | | |WB|WT|WC|UC]
> [ 0.000000] efi: 0x000000400000-0x0000005fffff [ACPI Memory NVS | |
> | | | | | | | | | |UC]
>
> # head -1 /proc/iomem
> 00200000-0021ffff : reserved
>
> Since we define 'PHYS_OFFSET' as the physical address of the start of memory
> it would be 0 in this case:
>
> /* PHYS_OFFSET - the physical address of the start of memory. */
> #define PHYS_OFFSET ({ VM_BUG_ON(memstart_addr & 1);
> memstart_addr; })
>
> On the other hand, the first memblock starts from 0x200000, so my question
> is whether we should update the user-space tools which use the memblocks
> listed in '/proc/iomem' to obtain the value of PHY_OFFSET (by reading the
> base of the 1st memblock) and read the value of 'memstart_addr' somehow in
> user-space to get the PHY_OFFSET, or should the change be done at the kernel
> end to calculate 'memstart_addr' as:
>
>
> /*
> * Select a suitable value for the base of physical memory.
> */
> memstart_addr = round_down(memblock_start_of_DRAM(),
> ARM64_MEMSTART_ALIGN);
> if (memstart_addr)
Sorry for the typo: I meant if (!memstart_addr) above
Regards,
Bhupesh
> memstart_addr = memblock_start_of_DRAM();
>
> Please share your views.
>
> Thanks,
> Bhupesh
^ permalink raw reply
* [PATCH] arm64: alternative:flush cache with unpatched code
From: Rohit Khanna @ 2018-06-01 21:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527882765869.38555@nvidia.com>
1 more comment inline.
Thanks
Rohit
________________________________________
From: linux-arm-kernel <linux-arm-kernel-bounces@lists.infradead.org> on behalf of Rohit Khanna <rokhanna@nvidia.com>
Sent: Friday, June 1, 2018 12:52 PM
To: Mark Rutland
Cc: Suzuki.Poulose at arm.com; catalin.marinas at arm.com; will.deacon at arm.com; Bo Yan; robin.murphy at arm.com; Alexander Van Brunt; linux-arm-kernel at lists.infradead.org
Subject: Re: [PATCH] arm64: alternative:flush cache with unpatched code
[RK] - Thanks for the comments Mark. Reply inlined.
Thanks
Rohit
________________________________________
From: Mark Rutland <mark.rutland@arm.com>
Sent: Friday, June 1, 2018 2:03 AM
To: Rohit Khanna
Cc: catalin.marinas at arm.com; robin.murphy at arm.com; Suzuki.Poulose at arm.com; linux-arm-kernel at lists.infradead.org; Alexander Van Brunt; Bo Yan; will.deacon at arm.com
Subject: Re: [PATCH] arm64: alternative:flush cache with unpatched code
Hi,
As a general thing, could you please add a version number to patches in future?
i.e. this should be PATCHv4.
It really helps keeping track of patches, distinguishing versions, etc.
On Thu, May 31, 2018 at 01:37:34PM -0700, Rohit Khanna wrote:
> In the current implementation, __apply_alternatives patches
> flush_icache_range and then executes it without invalidating the icache.
> Thus, icache can contain some of the old instructions for
> flush_icache_range. This can cause unpredictable behavior as during
> execution we can get a mix of old and new instructions for
> flush_icache_range.
>
> This patch :
>
> 1. Adds a new function clean_dcache_range_nopatch for flushing kernel
> memory range. This function uses non hot-patched code and can be
> safely used to flush cache during code patching.
>
> 2. Modifies __apply_alternatives so that it uses
> clean_dcache_range_nopatch to flush the cache range after patching code.
>
> Signed-off-by: Rohit Khanna <rokhanna@nvidia.com>
> ---
> arch/arm64/include/asm/sysreg.h | 3 +++
> arch/arm64/kernel/alternative.c | 37 ++++++++++++++++++++++++++++++++++++-
> 2 files changed, 39 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 6171178075dc..9d1aee7c9aba 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -617,6 +617,9 @@
> #define MVFR1_FPDNAN_SHIFT 4
> #define MVFR1_FPFTZ_SHIFT 0
>
> +/* SYS_CTR_EL0 */
> +#define SYS_CTR_ISIZE_SHIFT 0
> +#define SYS_CTR_DSIZE_SHIFT 16
We already have CTR_DMINLINE_SHIFT in <asm/cache.h>
Can we please add CTR_IMINLIN_SHIFT there too?
Maybe those should be moved into sysreg.h, but that can be a separate cleanup.
[RK] - <asm/cache.h> doesnt contain CTR_DMINLINE_SHIFT.
[RK ] - Sorry, I was looking at kernel-4.14 and couldnt find it there. I can find it in linux-next repo.
> #define ID_AA64MMFR0_TGRAN4_SHIFT 28
> #define ID_AA64MMFR0_TGRAN64_SHIFT 24
> diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
> index 5c4bce4ac381..6b8c5438b37b 100644
> --- a/arch/arm64/kernel/alternative.c
> +++ b/arch/arm64/kernel/alternative.c
> @@ -122,6 +122,41 @@ static void patch_alternative(struct alt_instr *alt,
> }
> }
>
> +/* This is used for flushing kernel memory range after
> + * __apply_alternatives has patched kernel code
> + */
> +static void clean_dcache_range_nopatch(void *start, void *end)
> +{
> + u64 d_start, i_start, d_size, i_size, ctr_el0;
I don't think we need separate i_start and d_start variables. A 'start' or
'cur' variable could be used for both.
[RK] - ok.
> +
> + /* use sanitised value of ctr_el0 rather than raw value from CPU */
> + ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
> + /* size in bytes */
> + d_size = cpuid_feature_extract_unsigned_field(ctr_el0,
> + SYS_CTR_DSIZE_SHIFT);
> + i_size = cpuid_feature_extract_unsigned_field(ctr_el0,
> + SYS_CTR_ISIZE_SHIFT);
This isn't the size in bytes. Each is log2 the number of (4-byte) words.
i.e. the size in bytes is (xMinLine << 2).
[RK] - This doesnt seem right. For eg if IMinLine = 4 or 0b100
then with above formula ICacheSize in Bytes = 4 << 2 = 16
The correct formula should be (4 << xMinLine).
So in case IMinLine = 4 or 0b100,
ICacheSizeBytes = 4 << 4 = 64B
> +
> + d_start = (u64)start & ~(d_size - 1);
> + while (d_start <= (u64)end) {
> + /* Use civac instead of cvau. This is required
> + * due to ARM errata 826319, 827319, 824069,
> + * 819472 on A53
> + */
> + asm volatile("dc civac, %0" : : "r" (d_start));
Either this needs a memory clobber, or we need barrier() first, to ensure that
the compiler doesn't re-order this against some of the patching code, however
unlikely that may be.
[RK] - So add barrier() before calling clean_dcache_range_nopatch() ?
> + d_start += d_size;
> + }
The loop can be simplified to:
do {
asm ( ... );
} while (d_start += d_size, d_start < (u64)end)
[RK] - ok
> + dsb(ish);
> +
> + i_start = (u64)start & ~(i_size - 1);
> + while (i_start <= (u64)end) {
> + asm volatile("ic ivau, %0" : : "r" (i_start));
> + i_start += i_size;
> + }
Likewise here.
[RK] - ok
Thanks,
Mark.
> + dsb(ish);
> + isb();
> +}
> +
> static void __apply_alternatives(void *alt_region, bool use_linear_alias)
> {
> struct alt_instr *alt;
> @@ -155,7 +190,7 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
>
> alt_cb(alt, origptr, updptr, nr_inst);
>
> - flush_icache_range((uintptr_t)origptr,
> + clean_dcache_range_nopatch((uintptr_t)origptr,
> (uintptr_t)(origptr + nr_inst));
> }
> }
> --
> 2.1.4
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [Query] PAGE_OFFSET on KASLR enabled ARM64 kernel
From: Bhupesh Sharma @ 2018-06-01 21:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACi5LpN=fSGhgNFOQysJWWzFarchFa1q2R_-J05uQs3wxrANRA@mail.gmail.com>
On 05/31/2018 10:21 AM, Bhupesh Sharma wrote:
> Hi Ard,
>
> Sorry I was out for most of the day yesterday. Please see my responses inline.
>
> On Mon, May 28, 2018 at 12:16 PM, Ard Biesheuvel
> <ard.biesheuvel@linaro.org> wrote:
>> On 27 May 2018 at 23:03, Bhupesh Sharma <bhsharma@redhat.com> wrote:
>>> Hi ARM64 maintainers,
>>>
>>> I am confused about the PAGE_OFFSET value (or the start of the linear
>>> map) on a KASLR enabled ARM64 kernel that I am seeing on a board which
>>> supports a compatible EFI firmware (with EFI_RNG_PROTOCOL support).
>>>
>>> 1. 'arch/arm64/include/asm/memory.h' defines PAGE_OFFSET as:
>>>
>>> /*
>>> * PAGE_OFFSET - the virtual address of the start of the linear map (top
>>> * (VA_BITS - 1))
>>> */
>>> #define PAGE_OFFSET (UL(0xffffffffffffffff) - \
>>> (UL(1) << (VA_BITS - 1)) + 1)
>>>
>>> So for example on a platform with VA_BITS=48, we have:
>>> PAGE_OFFSET = 0xffff800000000000
>>>
>>> 2. However, for the KASLR case, we set the 'memstart_offset_seed ' to
>>> use the 16-bits of the 'kaslr-seed' to randomize the linear region in
>>> 'arch/arm64/kernel/kaslr.c' :
>>>
>>> u64 __init kaslr_early_init(u64 dt_phys)
>>> {
>>> <snip..>
>>> /* use the top 16 bits to randomize the linear region */
>>> memstart_offset_seed = seed >> 48;
>>> <snip..>
>>> }
>>>
>>> 3. Now, we use the 'memstart_offset_seed' value to randomize the
>>> 'memstart_addr' value in 'arch/arm64/mm/init.c':
>>>
>>> void __init arm64_memblock_init(void)
>>> {
>>> <snip..>
>>>
>>> if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
>>> extern u16 memstart_offset_seed;
>>> u64 range = linear_region_size -
>>> (memblock_end_of_DRAM() - memblock_start_of_DRAM());
>>>
>>> /*
>>> * If the size of the linear region exceeds, by a sufficient
>>> * margin, the size of the region that the available physical
>>> * memory spans, randomize the linear region as well.
>>> */
>>> if (memstart_offset_seed > 0 && range >= ARM64_MEMSTART_ALIGN) {
>>> range = range / ARM64_MEMSTART_ALIGN + 1;
>>> memstart_addr -= ARM64_MEMSTART_ALIGN *
>>> ((range * memstart_offset_seed) >> 16);
>>> }
>>> }
>>> <snip..>
>>> }
>>>
>>> 4. Since 'memstart_addr' indicates the start of physical RAM, we
>>> randomize the same on basis of 'memstart_offset_seed' value above.
>>> Also the 'memstart_addr' value is available in '/proc/kallsyms' and
>>> hence can be accessed by user-space applications to read the
>>> 'memstart_addr' value.
>>>
>>> 5. Now since the PAGE_OFFSET value is also used by several user space
>>> tools (for e.g. makedumpfile tool uses the same to determine the start
>>> of linear region and hence to read PT_NOTE fields from /proc/kcore), I
>>> am not sure how to read the randomized value of the same in the KASLR
>>> enabled case.
>>>
>>> 6. Reading the code further and adding some debug prints, it seems the
>>> 'memblock_start_of_DRAM()' value is more closer to the actual start of
>>> linear region rather than 'memstart_addr' and 'PAGE_OFFSET" in case of
>>> KASLR enabled kernel:
>>>
>>> [root at qualcomm-amberwing] # dmesg | grep -i "arm64_memblock_init" -A 5
>>>
>>> [ 0.000000] inside arm64_memblock_init, memstart_addr = ffff976a00000000,
>>> linearstart_addr = ffffe89600200000, memblock_start_of_DRAM = ffffe89600200000,
>>> PHYS_OFFSET = ffff976a00000000, PAGE_OFFSET = ffff800000000000,
>>> KIMAGE_VADDR = ffff000008000000, kimage_vaddr = ffff20c2d7800000
>>>
>>> [root at qualcomm-amberwing] # dmesg | grep -i "Virtual kernel memory layout" -A 15
>>> [ 0.000000] Virtual kernel memory layout:
>>> [ 0.000000] modules : 0xffff000000000000 - 0xffff000008000000
>>> ( 128 MB)
>>> [ 0.000000] vmalloc : 0xffff000008000000 - 0xffff7bdfffff0000
>>> (126847 GB)
>>> [ 0.000000] .text : 0xffff20c2d7880000 - 0xffff20c2d8040000
>>> ( 7936 KB)
>>> [ 0.000000] .rodata : 0xffff20c2d8040000 - 0xffff20c2d83a0000
>>> ( 3456 KB)
>>> [ 0.000000] .init : 0xffff20c2d83a0000 - 0xffff20c2d8750000
>>> ( 3776 KB)
>>> [ 0.000000] .data : 0xffff20c2d8750000 - 0xffff20c2d891b200
>>> ( 1837 KB)
>>> [ 0.000000] .bss : 0xffff20c2d891b200 - 0xffff20c2d90a5198
>>> ( 7720 KB)
>>> [ 0.000000] fixed : 0xffff7fdffe790000 - 0xffff7fdffec00000
>>> ( 4544 KB)
>>> [ 0.000000] PCI I/O : 0xffff7fdffee00000 - 0xffff7fdfffe00000
>>> ( 16 MB)
>>> [ 0.000000] vmemmap : 0xffff7fe000000000 - 0xffff800000000000
>>> ( 128 GB maximum)
>>> [ 0.000000] 0xffff7ffa25800800 - 0xffff7ffa2b800000
>>> ( 95 MB actual)
>>> [ 0.000000] memory : 0xffffe89600200000 - 0xffffe8ae00000000
>>> ( 98302 MB)
>>>
>>> As one can see above, the 'memblock_start_of_DRAM()' value of
>>> 0xffffe89600200000 represents the start of linear region:
>>>
>>> [ 0.000000] memory : 0xffffe89600200000 - 0xffffe8ae00000000
>>> ( 98302 MB)
>>>
>>> So, my question is to access the start of linear region (which was
>>> earlier determinable via PAGE_OFFSET macro), whether I should:
>>>
>>> - do some back-computation for the start of linear region from the
>>> 'memstart_addr' in user-space, or
>>> - use a new global variable in kernel which is assigned the value of
>>> memblock_start_of_DRAM()' and assign it to '/proc/kallsyms', so that
>>> it can be read by user-space tools, or
>>> - whether we should rather look at removing the PAGE_OFFSET usage from
>>> the kernel and replace it with a global variable instead which is
>>> properly updated for KASLR case as well.
>>>
>>> Kindly share your opinions on what can be a suitable solution in this case.
>>>
>>> Thanks for your help.
>>>
>>
>> Hello Bhupesh,
>>
>> Could you explain what the relevance is of PAGE_OFFSET to userland?
>> The only thing that should matter is where the actual linear mapping
>> of DRAM is, and I am not sure I understand why we care about where it
>> resides relative to the base of the linear region.
>
> Actually certain user-space tools like makedumpfile (which is used to
> generate and compress the vmcore) and crash-utility (which is used to
> debug the vmcore), rely on the PAGE_OFFSET value (which denotes the
> base of the linear map region) to determine virtual to physical
> mapping of the addresses lying in the linear region .
>
> One specific use case that I am working on at the moment is the
> makedumpfile '--mem-usage', which allows one to see the page numbers
> of current system (1st kernel) in different use (please see
> MAKEDUMPFILE(8) for more details).
>
> Using this we can know how many pages are dumpable when different
> dump_level is specified when invoking the makedumpfile.
>
> Normally, makedumpfile analyses the contents of '/proc/kcore' (while
> excluding the crashkernel range), and then calculates the page number
> of different kind per vmcoreinfo.
>
> For e.g. here is an output from my arm64 board (a non KASLR boot):
>
> TYPE PAGES EXCLUDABLE DESCRIPTION
> ----------------------------------------------------------------------
> ZERO 49524 yes Pages
> filled with zero
> NON_PRI_CACHE 15143 yes Cache
> pages without private flag
> PRI_CACHE 29147 yes Cache
> pages with private flag
> USER 3684 yes User process pages
> FREE 1450569 yes Free pages
> KERN_DATA 14243 no Dumpable kernel data
>
> page size: 65536
> Total pages on system: 1562310
> Total size on system: 102387548160 Byte
>
> This use case requires directly reading the '/proc/kcore' and the
> hence the PAGE_OFFSET value is used to determine the base address of
> the linear region, whose value is not static in case of KASLR boot.
>
> Another use-case is where the crash-utility uses the PAGE_OFFSET value
> to perform a virtual-to-physical conversion for the address lying in
> the linear region:
>
> ulong
> arm64_VTOP(ulong addr)
> {
> if (machdep->flags & NEW_VMEMMAP) {
> if (addr >= machdep->machspec->page_offset)
> return machdep->machspec->phys_offset
> + (addr - machdep->machspec->page_offset);
>
> <..snip..>
> }
>
Another confusing concept is the rounded-up value of 'memstart_addr' in
'arch/arm64/mm/init.c' when booting a non-KASLR_ kernel and when the
value of memblock_start_of_DRAM() < ARM64_MEMSTART_ALIGN:
void __init arm64_memblock_init(void)
{
<..snip..>
/*
* Select a suitable value for the base of physical memory.
*/
memstart_addr = round_down(memblock_start_of_DRAM(),
ARM64_MEMSTART_ALIGN);
<..snip..>
}
For example, let's consider a case (which I see on my qualcomm board)
where memblock_start_of_DRAM() = 0x200000 and ARM64_MEMSTART_ALIGN =
0x40000000 (I am using VA_BITS = 48 and a 64K page size), in this case
memstart_addr is calculated at 0, as the round_down results in a value of 0.
This is in contrast with the definition of the 'memblock_start_of_DRAM':
/* lowest address */
phys_addr_t __init_memblock memblock_start_of_DRAM(void)
{
return memblock.memory.regions[0].base;
}
As indicated by logs below, the first memblock region base starts from
0x200000 rather than the 'memstart_addr' value (which is 0)
# dmesg | grep -i "Processing" -A 5
[ 0.000000] efi: Processing EFI memory map:
[ 0.000000] efi: 0x000000200000-0x00000021ffff [Runtime Data
|RUN| | | | | | | |WB|WT|WC|UC]
[ 0.000000] efi: 0x000000400000-0x0000005fffff [ACPI Memory NVS
| | | | | | | | | | | |UC]
# head -1 /proc/iomem
00200000-0021ffff : reserved
Since we define 'PHYS_OFFSET' as the physical address of the start of
memory it would be 0 in this case:
/* PHYS_OFFSET - the physical address of the start of memory. */
#define PHYS_OFFSET ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; })
On the other hand, the first memblock starts from 0x200000, so my
question is whether we should update the user-space tools which use the
memblocks listed in '/proc/iomem' to obtain the value of PHY_OFFSET (by
reading the base of the 1st memblock) and read the value of
'memstart_addr' somehow in user-space to get the PHY_OFFSET, or should
the change be done at the kernel end to calculate 'memstart_addr' as:
/*
* Select a suitable value for the base of physical memory.
*/
memstart_addr = round_down(memblock_start_of_DRAM(),
ARM64_MEMSTART_ALIGN);
if (memstart_addr)
memstart_addr = memblock_start_of_DRAM();
Please share your views.
Thanks,
Bhupesh
^ permalink raw reply
* [PATCH v4 1/2] regulator: dt-bindings: add QCOM RPMh regulator bindings
From: David Collins @ 2018-06-01 21:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180531114816.GC13319@sirena.org.uk>
Hello Mark,
On 05/31/2018 04:48 AM, Mark Brown wrote:
> On Wed, May 30, 2018 at 04:39:10PM -0700, David Collins wrote:
>> The DRMS modes to use and max allowed current per mode need to be
>> specified at the board level in device tree instead of hard-coded per
>> regulator type in the driver. There are at least two use cases driving
>> this need: LDOs shared between RPMh client processors and SMPSes requiring
>> PWM mode in certain circumstances.
>
> Is there really no way to improve the RPM firmware?
This aggregation takes place in a discrete hardware block, not in a
general purpose processor. Theoretically, future chips could have
redesigned VRM hardware; however, there is no plan to make such a change.
>> Consider the case of a regulator with physical 10 mA LPM max current. Say
>> that modem and application processors each have a load on the regulator
>> that draws 9 mA. If they each respect the 10 mA limit, then they'd each
>> vote for LPM. The VRM block in RPMh hardware will aggregate these requests
>
> This is, of course, why the regulator API aggregates this stuff based on
> the current not based on having every individual user select a mode.
>
>> together using a max function which will result in the regulator being set
>> to LPM, even though the total load is 18 mA (which would require high
>> power mode (HPM)). To get around this corner case, a LPM max current of 1
>> uA can be used for all LDO supplies that have non-application processor
>> consumers. Thus, any non-zero regulator_set_load() current request will
>> result in setting the regulator to HPM (which is always safe).
>
> That's obviously just never going to work well, the best you can do here
> is just pretend that the other components are always operating at full
> power (which I assume all the other components are doing too...) or not
> try to use load based mode switching in the first place.
I will remove the DT-based mode and max load current mapping support. In
its place, I'll implement hard coded LPM current limits for LDOs of 10 mA
or 30 mA (depending upon subtype) like is done in other regulator drivers.
If we actually encounter an issue caused by the APPS processor and another
RPMh client both voting for LPM when HPM is needed for the combination,
then we can disable load-based mode control for the affected regulator in
DT and configure its initial mode as HPM.
>> The second situation that needs board-level DRMS mode and current limit
>> specification is SMPS regulator AUTO mode to PWM (HPM) mode switching.
>> SMPS regulators should theoretically always be able to operate in AUTO
>> mode as it switches automatically between PWM mode (which can provide the
>> maximum current) and PFM mode (which supports lower current but has higher
>> efficiency). However, there may be board/system issues that require
>> switching to PWM mode for certain use cases as it has better load
>> regulation (i.e. no PFM ripple for lower loads) and supports more
>> aggressive load current steps (i.e. greater A/ns).
>
>> If a Linux consumer requires the ability to force a given SMPS regulator
>> from AUTO mode into PWM mode and that SMPS is shared by other Linux
>> consumers (which may be the case, but at least must be guaranteed to work
>> architecturally), then regulator_set_load() is the only option since it
>> provides aggregation, where as regulator_set_mode() does not.
>
> That's obviously broken though, what you're describing is just clearly
> nothing to do with load so trying to configure it using load is just
> going to lead to problems later on. Honestly it sounds like you just
> want to force the regulator into forced PWM mode all the time, otherwise
> you need to look into implementing support for describing the thing
> you're actually trying to do and add a mechanism for per consumer mode
> configuration.
>
> This has been a frequent pattern with these RPM drivers, trying to find
> some way to shoehorn something that happens to work right now into the
> code. That's going to make things fragile and hard to maintain, we need
> code that does the thing it's saying it does so that it's easier to
> understand and work with - getting things running isn't enough, they
> need to be clear.
I agree that using regulator_set_load() to handle SMPS AUTO mode to PWM
mode switching is hacky. Since there is no natural way to pick SMPS modes
based on load current, I will remove the functionality completely. In its
place, we can configure the SMPSes to have an initial mode of AUTO. If a
use case requiring PWM mode arises, then the consumer driver responsible
for it can call regulator_set_mode() to switch between AUTO and PWM modes
explicitly.
Since regulator_set_mode() does not support aggregation currently, this
technique would work only if there is exactly one consumer per regulator
that needs explicit mode control. Should we hit a situation that needs
multiple consumers to have such mode control, then we could simply default
the SMPS to PWM mode.
I'll also start looking into per-consumer mode configuration and
regulator_set_mode() aggregation within the regulator framework. I think
that we should be able to function without it for now; however, it would
be good to have going forward.
Take care,
David
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH v1 2/2] arm/arm64: KVM: Add KVM_GET/SET_VCPU_EVENTS
From: Eric Northup @ 2018-06-01 21:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527772139-19665-3-git-send-email-gengdongjiu@huawei.com>
On Wed, May 30, 2018 at 10:04 PM Dongjiu Geng <gengdongjiu@huawei.com> wrote:
>
> For the migrating VMs, user space may need to know the exception
> state. For example, in the machine A, KVM make an SError pending,
> when migrate to B, KVM also needs to pend an SError.
>
> This new IOCTL exports user-invisible states related to SError.
> Together with appropriate user space changes, user space can get/set
> the SError exception state to do migrate/snapshot/suspend.
>
> Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
> --
> this series patch is separated from https://www.spinics.net/lists/kvm/msg168917.html
> change since V12:
> 1. change (vcpu->arch.hcr_el2 & HCR_VSE) to !!(vcpu->arch.hcr_el2 & HCR_VSE) in kvm_arm_vcpu_get_events()
>
> Change since V11:
> Address James's comments, thanks James
> 1. Align the struct of kvm_vcpu_events to 64 bytes
> 2. Avoid exposing the stale ESR value in the kvm_arm_vcpu_get_events()
> 3. Change variables 'injected' name to 'serror_pending' in the kvm_arm_vcpu_set_events()
> 4. Change to sizeof(events) from sizeof(struct kvm_vcpu_events) in kvm_arch_vcpu_ioctl()
>
> Change since V10:
> Address James's comments, thanks James
> 1. Merge the helper function with the user.
> 2. Move the ISS_MASK into pend_guest_serror() to clear top bits
> 3. Make kvm_vcpu_events struct align to 4 bytes
> 4. Add something check in the kvm_arm_vcpu_set_events()
> 5. Check kvm_arm_vcpu_get/set_events()'s return value.
> 6. Initialise kvm_vcpu_events to 0 so that padding transferred to user-space doesn't
> contain kernel stack.
> ---
> Documentation/virtual/kvm/api.txt | 31 ++++++++++++++++++++++++++++---
> arch/arm/include/asm/kvm_host.h | 6 ++++++
> arch/arm/kvm/guest.c | 12 ++++++++++++
> arch/arm64/include/asm/kvm_emulate.h | 5 +++++
> arch/arm64/include/asm/kvm_host.h | 7 +++++++
> arch/arm64/include/uapi/asm/kvm.h | 13 +++++++++++++
> arch/arm64/kvm/guest.c | 36 ++++++++++++++++++++++++++++++++++++
> arch/arm64/kvm/inject_fault.c | 7 ++++++-
> arch/arm64/kvm/reset.c | 1 +
> virt/kvm/arm/arm.c | 21 +++++++++++++++++++++
> 10 files changed, 135 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index fdac969..8896737 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -835,11 +835,13 @@ struct kvm_clock_data {
>
> Capability: KVM_CAP_VCPU_EVENTS
> Extended by: KVM_CAP_INTR_SHADOW
> -Architectures: x86
> +Architectures: x86, arm, arm64
> Type: vm ioctl
> Parameters: struct kvm_vcpu_event (out)
> Returns: 0 on success, -1 on error
>
> +X86:
> +
> Gets currently pending exceptions, interrupts, and NMIs as well as related
> states of the vcpu.
>
> @@ -881,15 +883,32 @@ Only two fields are defined in the flags field:
> - KVM_VCPUEVENT_VALID_SMM may be set in the flags field to signal that
> smi contains a valid state.
>
> +ARM, ARM64:
> +
> +Gets currently pending SError exceptions as well as related states of the vcpu.
> +
> +struct kvm_vcpu_events {
> + struct {
> + __u8 serror_pending;
> + __u8 serror_has_esr;
> + /* Align it to 8 bytes */
> + __u8 pad[6];
> + __u64 serror_esr;
> + } exception;
> + __u32 reserved[12];
>
> +};
> +
> 4.32 KVM_SET_VCPU_EVENTS
>
> -Capability: KVM_CAP_VCPU_EVENTS
> +Capebility: KVM_CAP_VCPU_EVENTS
> Extended by: KVM_CAP_INTR_SHADOW
> -Architectures: x86
> +Architectures: x86, arm, arm64
> Type: vm ioctl
> Parameters: struct kvm_vcpu_event (in)
> Returns: 0 on success, -1 on error
>
> +X86:
> +
> Set pending exceptions, interrupts, and NMIs as well as related states of the
> vcpu.
>
> @@ -910,6 +929,12 @@ shall be written into the VCPU.
>
> KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
>
> +ARM, ARM64:
> +
> +Set pending SError exceptions as well as related states of the vcpu.
> +
> +See KVM_GET_VCPU_EVENTS for the data structure.
> +
>
> 4.33 KVM_GET_DEBUGREGS
>
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index c7c28c8..39f9901 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -213,6 +213,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
> int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
> int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
> + struct kvm_vcpu_events *events);
> +
> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
> + struct kvm_vcpu_events *events);
> +
> unsigned long kvm_call_hyp(void *hypfn, ...);
> void force_vm_exit(const cpumask_t *mask);
>
> diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
> index a18f33e..c685f0e 100644
> --- a/arch/arm/kvm/guest.c
> +++ b/arch/arm/kvm/guest.c
> @@ -261,6 +261,18 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
> return -EINVAL;
> }
>
> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
> + struct kvm_vcpu_events *events)
> +{
> + return -EINVAL;
> +}
> +
> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
> + struct kvm_vcpu_events *events)
> +{
> + return -EINVAL;
> +}
> +
> int __attribute_const__ kvm_target_cpu(void)
> {
> switch (read_cpuid_part()) {
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 1dab3a9..18f61ff 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -81,6 +81,11 @@ static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
> return (unsigned long *)&vcpu->arch.hcr_el2;
> }
>
> +static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
> +{
> + return vcpu->arch.vsesr_el2;
> +}
> +
> static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
> {
> vcpu->arch.vsesr_el2 = vsesr;
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 469de8a..357304a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -335,6 +335,11 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
> int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
> int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
> + struct kvm_vcpu_events *events);
> +
> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
> + struct kvm_vcpu_events *events);
>
> #define KVM_ARCH_WANT_MMU_NOTIFIER
> int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
> @@ -363,6 +368,8 @@ void handle_exit_early(struct kvm_vcpu *vcpu, struct kvm_run *run,
> int kvm_perf_init(void);
> int kvm_perf_teardown(void);
>
> +void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome);
> +
> struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
>
> void __kvm_set_tpidr_el2(u64 tpidr_el2);
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 04b3256..df4faee 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -39,6 +39,7 @@
> #define __KVM_HAVE_GUEST_DEBUG
> #define __KVM_HAVE_IRQ_LINE
> #define __KVM_HAVE_READONLY_MEM
> +#define __KVM_HAVE_VCPU_EVENTS
>
> #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>
> @@ -153,6 +154,18 @@ struct kvm_sync_regs {
> struct kvm_arch_memory_slot {
> };
>
> +/* for KVM_GET/SET_VCPU_EVENTS */
> +struct kvm_vcpu_events {
> + struct {
> + __u8 serror_pending;
> + __u8 serror_has_esr;
> + /* Align it to 8 bytes */
> + __u8 pad[6];
> + __u64 serror_esr;
> + } exception;
> + __u32 reserved[12];
It will be easier to re-purpose this in the future if the field is
reserved and is checked that it must be zero. SET_VCPU_EVENTS would
return EINVAL if reserved fields get used until a later meaning is
defined for them.
> +};
> +
> /* If you need to interpret the index values, here is the key: */
> #define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
> #define KVM_REG_ARM_COPROC_SHIFT 16
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 56a0260..71d3841 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -289,6 +289,42 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
> return -EINVAL;
> }
>
> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
> + struct kvm_vcpu_events *events)
> +{
> + events->exception.serror_pending = !!(vcpu->arch.hcr_el2 & HCR_VSE);
> + events->exception.serror_has_esr =
> + cpus_have_const_cap(ARM64_HAS_RAS_EXTN) &&
> + (!!vcpu_get_vsesr(vcpu));
> +
> + if (events->exception.serror_pending &&
> + events->exception.serror_has_esr)
> + events->exception.serror_esr = vcpu_get_vsesr(vcpu);
> + else
> + events->exception.serror_esr = 0;
> +
> + return 0;
> +}
> +
> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
> + struct kvm_vcpu_events *events)
> +{
> + bool serror_pending = events->exception.serror_pending;
> + bool has_esr = events->exception.serror_has_esr;
> +
> + if (serror_pending && has_esr) {
> + if (!cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
> + return -EINVAL;
> +
> + kvm_set_sei_esr(vcpu, events->exception.serror_esr);
> +
> + } else if (serror_pending) {
> + kvm_inject_vabt(vcpu);
> + }
> +
> + return 0;
> +}
> +
> int __attribute_const__ kvm_target_cpu(void)
> {
> unsigned long implementor = read_cpuid_implementor();
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index d8e7165..9e0ca56 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -166,7 +166,7 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
>
> static void pend_guest_serror(struct kvm_vcpu *vcpu, u64 esr)
> {
> - vcpu_set_vsesr(vcpu, esr);
> + vcpu_set_vsesr(vcpu, esr & ESR_ELx_ISS_MASK);
> *vcpu_hcr(vcpu) |= HCR_VSE;
> }
>
> @@ -186,3 +186,8 @@ void kvm_inject_vabt(struct kvm_vcpu *vcpu)
> {
> pend_guest_serror(vcpu, ESR_ELx_ISV);
> }
> +
> +void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome)
> +{
> + pend_guest_serror(vcpu, syndrome);
> +}
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index 38c8a64..20e919a 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -82,6 +82,7 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
> break;
> case KVM_CAP_SET_GUEST_DEBUG:
> case KVM_CAP_VCPU_ATTRIBUTES:
> + case KVM_CAP_VCPU_EVENTS:
> r = 1;
> break;
> default:
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index a4c1b76..8b43968 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -1107,6 +1107,27 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> r = kvm_arm_vcpu_has_attr(vcpu, &attr);
> break;
> }
> + case KVM_GET_VCPU_EVENTS: {
> + struct kvm_vcpu_events events;
> +
> + memset(&events, 0, sizeof(events));
> + if (kvm_arm_vcpu_get_events(vcpu, &events))
> + return -EINVAL;
> +
> + if (copy_to_user(argp, &events, sizeof(events)))
> + return -EFAULT;
> +
> + return 0;
> + }
> + case KVM_SET_VCPU_EVENTS: {
> + struct kvm_vcpu_events events;
> +
> + if (copy_from_user(&events, argp,
> + sizeof(struct kvm_vcpu_events)))
> + return -EFAULT;
> +
> + return kvm_arm_vcpu_set_events(vcpu, &events);
> + }
> default:
> r = -EINVAL;
> }
> --
> 2.7.4
>
^ permalink raw reply
* [RFC PATCH 0/8] coresight: Update device tree bindings
From: Mathieu Poirier @ 2018-06-01 21:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527858967-16047-1-git-send-email-suzuki.poulose@arm.com>
On Fri, Jun 01, 2018 at 02:15:59PM +0100, Suzuki K Poulose wrote:
> Coresight uses DT graph bindings to describe the connections of the
> components. However we have some undocumented usage of the bindings
> to describe some of the properties of the connections.
>
> The coresight driver needs to know the hardware ports invovled
> in the connection and the direction of data flow to effectively
> manage the trace sessions. So far we have relied on the "port"
> address (as described by the generic graph bindings) to represent
> the hardware port of the component for a connection.
>
> The hardware uses separate numbering scheme for input and output
> ports, which implies, we could have two different (input and output)
> ports with the same port number. This could create problems in the
> graph bindings where the label of the port wouldn't match the address.
>
> e.g, with the existing bindings we get :
>
> port at 0{ // Output port 0
> reg = <0>;
> ...
> };
>
> port at 1{
> reg = <0>; // Input port 0
> endpoint {
> slave-mode;
> ...
> };
> };
>
> With the new enforcement in the DT rules, mismatches in label and address
> are not allowed (as see in the case for port at 1). So, we need a new mechanism
> to describe the hardware port number reliably.
>
> Also, we relied on an undocumented "slave-mode" property (see the above
> example) to indicate if the port is an input port. Let us formalise and
> switch to a new property to describe the direction of data flow.
>
> There were three options considered for the hardware port number scheme:
>
> 1) Use natural ordering in the DT to infer the hardware port number.
> i.e, Mandate that the all ports are listed in the DT and in the ascending
> order for each class (input and output respectively).
> Pros :
> - We don't need new properties and if the existing DTS list them in
> order (which most of them do), they work out of the box.
> Cons :
> - We must list all the ports even if the system cannot/shouldn't use
> it.
> - It is prone to human errors (if the order is not kept).
>
> 2) Use an explicit property to list both the direction and the hw port
> number and direction. Define "coresight,hwid" as 2 member array of u32,
> where the members are port number and the direction respectively.
> e.g
>
> port at 0{
> reg = <0>;
> endpoint {
> coresight,hwid = <0 1>; // Port # 0, Output
> }
> };
>
> port at 1{
> reg = <1>;
> endpoint {
> coresight,hwid = <0 0>; // Port # 0, Input
> };
> };
>
> Pros:
> - The bindings are formal but not so reader friendly and could potentially
> lead to human errors.
> Cons:
> - Backward compatiblity is lost.
> 3) Use explicit properties (implemented in the series) for the hardware
> port id and direction. We define a new property "coresight,hwid" for
> each endpoint in coresight devices to specify the hardware port number
> explicitly. Also use a separate property "direction" to specify the
> direction of the data flow.
>
> e.g,
>
> port at 0{
> reg = <0>;
> endpoint {
> direction = <1>; // Output
> coresight,hwid = <0>; // Port # 0
> }
> };
>
> port at 1{
> reg = <1>;
> endpoint {
> direction = <0>; // Input
> coresight,hwid = <0>; // Port # 0
> };
> };
>
> Pros:
> - The bindings are formal and reader friendly, and less prone to errors.
> Cons:
> - Backward compatibility is lost.
>
>
> This series achieves implements Option (3) listed above while still retaining
> the backward compatibility. The driver now issues a warning (once) when it
> encounters the old bindings.
> It also cleans up the platform parsing code to reduce the memory usage by
> reusing the platform description. The series also includes the
> changes for Juno platform as an example. If there are no objections
> to the approach, I could post the series, converting all the
> in-kernel DTS to the new binding.
>
> Suzuki K Poulose (8):
> dts: binding: coresight: Document graph bindings
> coresight: Fix remote endpoint parsing
> coresight: Cleanup platform description data
> coresight: platform: Cleanup coresight connection handling
> coresight: Handle errors in finding input/output ports
> dts: coresight: Clean up the device tree graph bindings
> dts: coresight: Define new bindings for direction of data flow
> dts: juno: Update coresight bindings for hw port
>
> .../devicetree/bindings/arm/coresight.txt | 52 ++++++++--
> arch/arm64/boot/dts/arm/juno-base.dtsi | 82 +++++++++++----
> arch/arm64/boot/dts/arm/juno.dts | 5 +-
> drivers/hwtracing/coresight/coresight.c | 28 ++----
> drivers/hwtracing/coresight/of_coresight.c | 111 ++++++++++++---------
> include/linux/coresight.h | 11 +-
> 6 files changed, 181 insertions(+), 108 deletions(-)
Aside from the comments I've already posted I'm pretty much good with this set.
Please rebase the next revision on my "next" branch and run checkpatch.pl on the
set. Patch 6/8 and 7/8 are generating warnings.
Thanks,
Mathieu
>
> --
> 2.7.4
>
^ permalink raw reply
* [RFC PATCH 8/8] dts: juno: Update coresight bindings for hw port
From: Mathieu Poirier @ 2018-06-01 20:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527858967-16047-9-git-send-email-suzuki.poulose@arm.com>
On Fri, Jun 01, 2018 at 02:16:07PM +0100, Suzuki K Poulose wrote:
> Switch to updated coresight bindings for hw ports.
>
> Cc: Sudeep Holla <sudeep.holla@arm.com>
> Cc: Liviu Dudau <liviu.dudau@arm.com>
> Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Reviewed-and-tested-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
> arch/arm64/boot/dts/arm/juno-base.dtsi | 82 +++++++++++++++++++++++++---------
> arch/arm64/boot/dts/arm/juno.dts | 5 ++-
> 2 files changed, 63 insertions(+), 24 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi
> index eb749c5..33b41ba 100644
> --- a/arch/arm64/boot/dts/arm/juno-base.dtsi
> +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi
> @@ -122,15 +122,18 @@
> port at 0 {
> reg = <0>;
> etf0_in_port: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&main_funnel_out_port>;
> + coresight,hwid = <0>;
> };
> };
>
> /* output port */
> port at 1 {
> - reg = <0>;
> + reg = <1>;
> etf0_out_port: endpoint {
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
> };
> @@ -145,8 +148,9 @@
> power-domains = <&scpi_devpd 0>;
> port {
> tpiu_in_port: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&replicator_out_port0>;
> + coresight,hwid = <0>;
> };
> };
> };
> @@ -168,23 +172,27 @@
> reg = <0>;
> main_funnel_out_port: endpoint {
> remote-endpoint = <&etf0_in_port>;
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
>
> /* input ports */
> port at 1 {
> - reg = <0>;
> + reg = <1>;
> main_funnel_in_port0: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&cluster0_funnel_out_port>;
> + coresight,hwid = <0>;
> };
> };
>
> port at 2 {
> - reg = <1>;
> + reg = <2>;
> main_funnel_in_port1: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&cluster1_funnel_out_port>;
> + coresight,hwid = <1>;
> };
> };
> };
> @@ -200,8 +208,9 @@
> power-domains = <&scpi_devpd 0>;
> port {
> etr_in_port: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&replicator_out_port1>;
> + coresight,hwid = <0>;
> };
> };
> };
> @@ -217,6 +226,8 @@
> power-domains = <&scpi_devpd 0>;
> port {
> stm_out_port: endpoint {
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
> };
> @@ -240,6 +251,8 @@
> port {
> cluster0_etm0_out_port: endpoint {
> remote-endpoint = <&cluster0_funnel_in_port0>;
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
> };
> @@ -259,22 +272,26 @@
> reg = <0>;
> cluster0_funnel_out_port: endpoint {
> remote-endpoint = <&main_funnel_in_port0>;
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
>
> port at 1 {
> - reg = <0>;
> + reg = <1>;
> cluster0_funnel_in_port0: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&cluster0_etm0_out_port>;
> + coresight,hwid = <0>;
> };
> };
>
> port at 2 {
> - reg = <1>;
> + reg = <2>;
> cluster0_funnel_in_port1: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&cluster0_etm1_out_port>;
> + coresight,hwid = <1>;
> };
> };
> };
> @@ -299,6 +316,8 @@
> port {
> cluster0_etm1_out_port: endpoint {
> remote-endpoint = <&cluster0_funnel_in_port1>;
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
> };
> @@ -322,6 +341,8 @@
> port {
> cluster1_etm0_out_port: endpoint {
> remote-endpoint = <&cluster1_funnel_in_port0>;
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
> };
> @@ -341,36 +362,42 @@
> reg = <0>;
> cluster1_funnel_out_port: endpoint {
> remote-endpoint = <&main_funnel_in_port1>;
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
>
> port at 1 {
> - reg = <0>;
> + reg = <1>;
> cluster1_funnel_in_port0: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&cluster1_etm0_out_port>;
> + coresight,hwid = <0>;
> };
> };
>
> port at 2 {
> - reg = <1>;
> + reg = <2>;
> cluster1_funnel_in_port1: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&cluster1_etm1_out_port>;
> + coresight,hwid = <1>;
> };
> };
> port at 3 {
> - reg = <2>;
> + reg = <3>;
> cluster1_funnel_in_port2: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&cluster1_etm2_out_port>;
> + coresight,hwid = <2>;
> };
> };
> port at 4 {
> - reg = <3>;
> + reg = <4>;
> cluster1_funnel_in_port3: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&cluster1_etm3_out_port>;
> + coresight,hwid = <3>;
> };
> };
> };
> @@ -395,6 +422,8 @@
> port {
> cluster1_etm1_out_port: endpoint {
> remote-endpoint = <&cluster1_funnel_in_port1>;
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
> };
> @@ -418,6 +447,8 @@
> port {
> cluster1_etm2_out_port: endpoint {
> remote-endpoint = <&cluster1_funnel_in_port2>;
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
> };
> @@ -441,6 +472,8 @@
> port {
> cluster1_etm3_out_port: endpoint {
> remote-endpoint = <&cluster1_funnel_in_port3>;
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
> };
> @@ -462,6 +495,8 @@
> reg = <0>;
> replicator_out_port0: endpoint {
> remote-endpoint = <&tpiu_in_port>;
> + coresight,hwid = <0>;
> + direction = <1>;
> };
> };
>
> @@ -469,14 +504,17 @@
> reg = <1>;
> replicator_out_port1: endpoint {
> remote-endpoint = <&etr_in_port>;
> + coresight,hwid = <1>;
> + direction = <1>;
> };
> };
>
> /* replicator input port */
> port at 2 {
> - reg = <0>;
> + reg = <2>;
> replicator_in_port0: endpoint {
> - slave-mode;
> + direction = <0>;
> + coresight,hwid = <0>;
> };
> };
> };
> diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
> index c9236c4..27b8036 100644
> --- a/arch/arm64/boot/dts/arm/juno.dts
> +++ b/arch/arm64/boot/dts/arm/juno.dts
> @@ -260,10 +260,11 @@
> &main_funnel {
> ports {
> port at 3 {
> - reg = <2>;
> + reg = <3>;
> main_funnel_in_port2: endpoint {
> - slave-mode;
> + direction = <0>;
> remote-endpoint = <&stm_out_port>;
> + coresight,hwid = <2>;
> };
> };
> };
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH V4] scsi: hpsa: drop shutdown callback
From: Don Brace @ 2018-06-01 20:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527860768-11367-1-git-send-email-okaya@codeaurora.org>
> -----Original Message-----
> From: Sinan Kaya [mailto:okaya at codeaurora.org]
> Sent: Friday, June 01, 2018 8:46 AM
> To: linux-pci at vger.kernel.org; ryan at finnie.org; timur at codeaurora.org
> Cc: linux-arm-msm at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> Sinan Kaya <okaya@codeaurora.org>; stable at vger.kernel.org; Don Brace
> <don.brace@microsemi.com>; James E.J. Bottomley
> <jejb@linux.vnet.ibm.com>; Martin K. Petersen <martin.petersen@oracle.com>;
> esc.storagedev <esc.storagedev@microsemi.com>; open list:HEWLETT-
> PACKARD SMART ARRAY RAID DRIVER (hpsa) <linux-scsi@vger.kernel.org>; open
> list <linux-kernel@vger.kernel.org>
> Subject: [PATCH V4] scsi: hpsa: drop shutdown callback
>
> EXTERNAL EMAIL
>
>
> 'Commit cc27b735ad3a ("PCI/portdrv: Turn off PCIe services during
> shutdown")' has been added to kernel to shutdown pending PCIe port
> service interrupts during reboot so that a newly started kexec kernel
> wouldn't observe pending interrupts.
>
> pcie_port_device_remove() is disabling the root port and switches by
> calling pci_disable_device() after all PCIe service drivers are shutdown.
>
> This has been found to cause crashes on HP DL360 Gen9 machines during
> reboot due to hpsa driver not clearing the bus master bit during the
> shutdown procedure by calling pci_disable_device().
>
> Disable device as part of the shutdown sequence.
>
> Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
Looks good. Thanks for your patch
Thanks for changing the patch name also.
Tested-by: Don Brace <don.brace@microsemi.com>
Acked-by: Don Brace <don.brace@microsemi.com>
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=199779
> Fixes: cc27b735ad3a ("PCI/portdrv: Turn off PCIe services during shutdown")
> Cc: stable at vger.kernel.org
> Reported-by: Ryan Finnie <ryan@finnie.org>
> ---
> drivers/scsi/hpsa.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
> index 3a9eca1..b92f86a 100644
> --- a/drivers/scsi/hpsa.c
> +++ b/drivers/scsi/hpsa.c
> @@ -8869,7 +8869,7 @@ static void hpsa_disable_rld_caching(struct ctlr_info
> *h)
> kfree(options);
> }
>
> -static void hpsa_shutdown(struct pci_dev *pdev)
> +static void __hpsa_shutdown(struct pci_dev *pdev)
> {
> struct ctlr_info *h;
>
> @@ -8884,6 +8884,12 @@ static void hpsa_shutdown(struct pci_dev *pdev)
> hpsa_disable_interrupt_mode(h); /* pci_init 2 */
> }
>
> +static void hpsa_shutdown(struct pci_dev *pdev)
> +{
> + __hpsa_shutdown(pdev);
> + pci_disable_device(pdev);
> +}
> +
> static void hpsa_free_device_info(struct ctlr_info *h)
> {
> int i;
> @@ -8927,7 +8933,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
> scsi_remove_host(h->scsi_host); /* init_one 8 */
> /* includes hpsa_free_irqs - init_one 4 */
> /* includes hpsa_disable_interrupt_mode - pci_init 2 */
> - hpsa_shutdown(pdev);
> + __hpsa_shutdown(pdev);
>
> hpsa_free_device_info(h); /* scan */
>
> --
> 2.7.4
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox