* [PATCH 2/9] iommu/rockchip: Fix error handling in attach
From: Robin Murphy @ 2018-01-11 15:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180111082229.24011-3-jeffy.chen@rock-chips.com>
On 11/01/18 08:22, Jeffy Chen wrote:
> From: Tomasz Figa <tfiga@chromium.org>
>
> Currently if the driver encounters an error while attaching device, it
> will leave the IOMMU in an inconsistent state. Even though it shouldn't
> really happen in reality, let's just add proper error path to keep
> things consistent.
>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
> ---
>
> drivers/iommu/rockchip-iommu.c | 26 +++++++++++++++++---------
> 1 file changed, 17 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 9d991c2d8767..ee805e1dfba7 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -826,17 +826,10 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
>
> ret = rk_iommu_force_reset(iommu);
> if (ret)
> - return ret;
> + goto err_disable_stall;
>
> iommu->domain = domain;
>
> - for (i = 0; i < iommu->num_irq; i++) {
> - ret = devm_request_irq(iommu->dev, iommu->irq[i], rk_iommu_irq,
> - IRQF_SHARED, dev_name(dev), iommu);
> - if (ret)
> - return ret;
> - }
> -
> for (i = 0; i < iommu->num_mmu; i++) {
> rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR,
> rk_domain->dt_dma);
> @@ -844,9 +837,16 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, RK_MMU_IRQ_MASK);
> }
>
> + for (i = 0; i < iommu->num_irq; i++) {
> + ret = devm_request_irq(iommu->dev, iommu->irq[i], rk_iommu_irq,
> + IRQF_SHARED, dev_name(dev), iommu);
Why aren't we simply requesting the IRQ once in rk_iommu_probe()? Given
that the hardware doesn't handle multiple translation contexts, there
doesn't seem to be much point in being this dynamic about it.
Robin.
> + if (ret)
> + goto err_free_irq;
> + }
> +
> ret = rk_iommu_enable_paging(iommu);
> if (ret)
> - return ret;
> + goto err_free_irq;
>
> spin_lock_irqsave(&rk_domain->iommus_lock, flags);
> list_add_tail(&iommu->node, &rk_domain->iommus);
> @@ -857,6 +857,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
> rk_iommu_disable_stall(iommu);
>
> return 0;
> +
> +err_free_irq:
> + while (i--)
> + devm_free_irq(iommu->dev, iommu->irq[i], iommu);
> +err_disable_stall:
> + rk_iommu_disable_stall(iommu);
> +
> + return ret;
> }
>
> static void rk_iommu_detach_device(struct iommu_domain *domain,
>
^ permalink raw reply
* [PATCH 00/10] perf tools: Add support for CoreSight trace decoding
From: Mathieu Poirier @ 2018-01-11 15:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180111122317.GA7834@sirena.org.uk>
On 11 January 2018 at 05:23, Mark Brown <broonie@kernel.org> wrote:
> On Wed, Jan 10, 2018 at 06:08:21PM -0600, Kim Phillips wrote:
>> Mathieu Poirier <mathieu.poirier@linaro.org> wrote:
>
>> > Instructions on how to build and install the openCSD library are provided
>> > in the HOWTO.md of the project repository.
>
>> Usually when a perf builder sees something they need "on," they - or,
>> at least I - start querying the host's package manager for something
>> that provides it (e.g., apt search/install libopencsd), but since no
>> distro provides libopencsd, this is bad because it misleads the user.
>
> It's on the radar to push this at distros fairly soon. Part of the
> discussion was wanting to get things to the point where the tools using
> the library were far enough along that we could be reasonably sure that
> there weren't any problems that were going to require ABI breaks to fix
> before pushing the library at distros since ABI churn isn't nice for
> packagers to deal with. There's also a bit of a chicken and egg problem
> in that it's a lot easier to get distros to package libraries that have
> users available (some are not really bothered about this of course but
> it still helps).
Moreover including in the kernel tree every library that can
potentially be used by the perf tools simply doesn't scale. The perf
tools project has come up with a very cleaver way to deal with
external dependencies and I don't see why the OpenCSD library should
be different.
>
>> Keeping the library external will also inevitably introduce more
>> source level synchronization problems because the perf sources being
>> built may not be compatible with their version of the library, whether
>> due to new features like new trace hardware support, or API changes.
>
> Perf users installing from source rather than from a package (who do
> tend to the more technical side even for kernel developers) already have
> to cope with potentially installing at least dwarf, gtk2, libaudit,
> libbfd, libelf, libnuma, libperl, libpython, libslang, libcrypto,
> libunwind, libdw-dwarf-unwind, zlib, lzma, bpf and OpenJDK depending on
> which features they want. I'm not sure that adding one more library is
> going to be the end of the world here, especially once the packaging
> starts to filter through distros. Until that happens at least people
> are no worse off for not having the feature.
I completely agree. Just like any other package, people that want the
very latest code need to install from source.
>
>> As Mark Brown (cc'd) mentioned on the Coresight mailing list, this may
>> be able to be done the same way the dtc is incorporated into the
>> kernel, where only its relevant sources are included and updated as
>> needed: see linux/scripts/dtc/update-dtc-source.sh.
>
> Bear in mind that we need dtc for essentially all kernel development on
> ARM and when it was introduced it was a new requirement for existing
> systems, it's a bit of a different case here where it's an optional
> feature in an optional tool.
^ permalink raw reply
* [PATCH] clk: sunxi-ng: defaultly enable DE2 CCU for sun8i/sun50i
From: Maxime Ripard @ 2018-01-11 15:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180111030451.9217-1-icenowy@aosc.io>
On Thu, Jan 11, 2018 at 11:04:51AM +0800, Icenowy Zheng wrote:
> As DE2 support for more SoCs are introducing, there's many reports that
> the DE2 is not functional due to DE2 CCU code not included in kernel.
>
> Defaultly enable DE2 CCU for sun8i/sun50i to reduce this kind of
> problems.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
One way to avoid this would have been to add the symbol to the sunxi
and multi_v7 defconfigs...
You're also adding a depends on. This should be explained or at least
mentionned in your commit log.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180111/4c116c1c/attachment.sig>
^ permalink raw reply
* [PATCH v1 2/4] ARM: PWM: add allwinner sun8i R40/V40/T3 pwm support.
From: Claudiu Beznea @ 2018-01-11 15:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180111113241.GA21953@arx-s1>
On 11.01.2018 13:32, hao_zhang wrote:
> This patch add allwinner sun8i R40/V40/T3 pwm support.
>
> Signed-off-by: hao_zhang <hao5781286@gmail.com>
> ---
> drivers/pwm/Kconfig | 10 ++
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-sun8i-r40.c | 394 ++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 405 insertions(+)
> create mode 100644 drivers/pwm/pwm-sun8i-r40.c
>
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 763ee50..cde5a70 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -444,6 +444,16 @@ config PWM_SUN4I
> To compile this driver as a module, choose M here: the module
> will be called pwm-sun4i.
>
> +config PWM_SUN8I_R40
> + tristate "Allwinner PWM SUN8I R40 support"
> + depends on ARCH_SUNXI || COMPILE_TEST
> + depends on HAS_IOMEM && COMMON_CLK
> + help
> + Generic PWM framework driver for Allwinner SoCs R40, V40, T3.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called pwm-sun8i-r40.
> +
> config PWM_TEGRA
> tristate "NVIDIA Tegra PWM support"
> depends on ARCH_TEGRA
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 0258a74..026a55b 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -44,6 +44,7 @@ obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
> obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o
> obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o
> obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o
> +obj-$(CONFIG_PWM_SUN8I_R40) += pwm-sun8i-r40.o
> obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
> obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
> obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
> diff --git a/drivers/pwm/pwm-sun8i-r40.c b/drivers/pwm/pwm-sun8i-r40.c
> new file mode 100644
> index 0000000..3d34285
> --- /dev/null
> +++ b/drivers/pwm/pwm-sun8i-r40.c
> @@ -0,0 +1,394 @@
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/time.h>
> +#include <linux/regmap.h>
> +
> +#define PWM_IRQ_ENABLE_REG 0x0000
> +#define PCIE(ch) BIT(ch)
> +
> +#define PWM_IRQ_STATUS_REG 0x0004
> +#define PIS(ch) BIT(ch)
> +
> +#define CAPTURE_IRQ_ENABLE_REG 0x0010
> +#define CFIE(ch) BIT(ch << 1 + 1)
> +#define CRIE(ch) BIT(ch << 1)
> +
> +#define CAPTURE_IRQ_STATUS_REG 0x0014
> +#define CFIS(ch) BIT(ch << 1 + 1)
> +#define CRIS(ch) BIT(ch << 1)
> +
> +#define CLK_CFG_REG(ch) (0x0020 + (ch >> 1) * 4)
> +#define CLK_SRC BIT(7)
> +#define CLK_SRC_BYPASS_SEC BIT(6)
> +#define CLK_SRC_BYPASS_FIR BIT(5)
> +#define CLK_GATING BIT(4)
> +#define CLK_DIV_M GENMASK(3, 0)
> +
> +#define PWM_DZ_CTR_REG(ch) (0x0030 + (ch >> 1) * 4)
> +#define PWM_DZ_INTV GENMASK(15, 8)
> +#define PWM_DZ_EN BIT(0)
> +
> +#define PWM_ENABLE_REG 0x0040
> +#define PWM_EN(ch) BIT(ch)
> +
> +#define CAPTURE_ENABLE_REG 0x0044
> +#define CAP_EN(ch) BIT(ch)
> +
> +#define PWM_CTR_REG(ch) (0x0060 + ch * 0x20)
> +#define PWM_PERIOD_RDY BIT(11)
> +#define PWM_PUL_START BIT(10)
> +#define PWM_MODE BIT(9)
> +#define PWM_ACT_STA BIT(8)
> +#define PWM_PRESCAL_K GENMASK(7, 0)
> +
> +#define PWM_PERIOD_REG(ch) (0x0064 + ch * 0x20)
> +#define PWM_ENTIRE_CYCLE GENMASK(31, 16)
> +#define PWM_ACT_CYCLE GENMASK(15, 0)
> +
> +#define PWM_CNT_REG(ch) (0x0068 + ch * 0x20)
> +#define PWM_CNT_VAL GENMASK(15, 0)
> +
> +#define CAPTURE_CTR_REG(ch) (0x006c + ch * 0x20)
> +#define CAPTURE_CRLF BIT(2)
> +#define CAPTURE_CFLF BIT(1)
> +#define CAPINV BIT(0)
> +
> +#define CAPTURE_RISE_REG(ch) (0x0070 + ch * 0x20)
> +#define CAPTURE_CRLR GENMASK(15, 0)
> +
> +#define CAPTURE_FALL_REG(ch) (0x0074 + ch * 0x20)
> +#define CAPTURE_CFLR GENMASK(15, 0)
> +
> +struct sun8i_pwm_data {
> + bool has_prescaler_bypass;
> + bool has_rdy;
> + unsigned int npwm;
> +};
> +
> +struct sun8i_pwm_chip {
> + struct pwm_chip chip;
> + struct clk *clk;
> + void __iomem *base;
> + spinlock_t ctrl_lock;
> + const struct sun8i_pwm_data *data;
> + struct regmap *regmap;
> +};
> +
> +static const u16 div_m_table[] = {
> + 1,
> + 2,
> + 4,
> + 8,
> + 16,
> + 32,
> + 64,
> + 128,
> + 256
> +};
> +
> +static inline struct sun8i_pwm_chip *to_sun8i_pwm_chip(struct pwm_chip *chip)
> +{
> + return container_of(chip, struct sun8i_pwm_chip, chip);
> +}
> +
> +static u32 sun8i_pwm_read(struct sun8i_pwm_chip *sun8i_pwm,
> + unsigned long offset)
> +{
> + u32 val;
> +
> + regmap_read(sun8i_pwm->regmap, offset, &val);
> +
> + return val;
> +}
> +
> +static inline void sun8i_pwm_set_bit(struct sun8i_pwm_chip *sun8i_pwm,
> + unsigned long reg, u32 bit)
> +{
> + regmap_update_bits(sun8i_pwm->regmap, reg, bit, bit);
> +}
> +
> +static inline void sun8i_pwm_clear_bit(struct sun8i_pwm_chip *sun8i_pwm,
> + unsigned long reg, u32 bit)
> +{
> + regmap_update_bits(sun8i_pwm->regmap, reg, bit, 0);
> +}
> +
> +static inline void sun8i_pwm_set_value(struct sun8i_pwm_chip *sun8i_pwm,
> + unsigned long reg, u32 mask, u32 val)
> +{
> + regmap_update_bits(sun8i_pwm->regmap, reg, mask, val);
> +}
> +
> +static void sun8i_pwm_set_polarity(struct sun8i_pwm_chip *chip, u32 ch,
> + enum pwm_polarity polarity)
> +{
> + if (polarity == PWM_POLARITY_NORMAL)
> + sun8i_pwm_set_bit(chip, PWM_CTR_REG(ch), PWM_ACT_STA);
> + else
> + sun8i_pwm_clear_bit(chip, PWM_CTR_REG(ch), PWM_ACT_STA);
> +}
> +
> +static int sun8i_pwm_config(struct sun8i_pwm_chip *sun8i_pwm, u8 ch,
> + struct pwm_state *state)
> +{
> + u64 clk_rate, clk_div, val;
> + u16 prescaler = 0;
> + u8 id = 0;
> +
> + clk_rate = clk_get_rate(sun8i_pwm->clk);
> +
> + if (clk_rate == 24000000)
> + sun8i_pwm_clear_bit(sun8i_pwm, CLK_CFG_REG(ch), CLK_SRC);
> + else
> + sun8i_pwm_set_bit(sun8i_pwm, CLK_CFG_REG(ch), CLK_SRC);
> +
> + if (sun8i_pwm->data->has_prescaler_bypass) {
> + /* pwm output bypass */
> + if (ch % 2)
> + sun8i_pwm_set_bit(sun8i_pwm, CLK_CFG_REG(ch),
> + CLK_SRC_BYPASS_FIR);
> + else
> + sun8i_pwm_set_bit(sun8i_pwm, CLK_CFG_REG(ch),
> + CLK_SRC_BYPASS_SEC);
> + return 0;
> + }
> +
> + val = state->period * clk_rate;
> + do_div(val, NSEC_PER_SEC);
> + if (val < 1) {
> + dev_err(sun8i_pwm->chip.dev,
> + "period expects a larger value\n");
> + return -EINVAL;
> + }
> +
> + /* calculate and set prescalar, div table, pwn entrie cycle */
> + clk_div = val;
> +
> + while (clk_div > 65535) {
> + prescaler++;
> + clk_div = val;
> + do_div(clk_div, prescaler + 1);
> + do_div(clk_div, div_m_table[id]);
> +
> + if (prescaler == 255) {
> + prescaler = 0;
> + id++;
> + if (id == 9)
> + return -EINVAL;
> + }
> + }
> +
> + sun8i_pwm_set_value(sun8i_pwm, PWM_PERIOD_REG(ch),
> + PWM_ENTIRE_CYCLE, clk_div << 16);
> + sun8i_pwm_set_value(sun8i_pwm, PWM_CTR_REG(ch),
> + PWM_PRESCAL_K, prescaler << 0);
> + sun8i_pwm_set_value(sun8i_pwm, CLK_CFG_REG(ch),
> + CLK_DIV_M, id << 0);
> +
> + /* set duty cycle */
> + val = (prescaler + 1) * div_m_table[id] * clk_div;
> + val = state->period;
> + do_div(val, clk_div);
> + clk_div = state->duty_cycle;
> + do_div(clk_div, val);
> +
> + sun8i_pwm_set_value(sun8i_pwm, PWM_PERIOD_REG(ch),
> + PWM_ACT_CYCLE, clk_div << 0);
> +
> + return 0;
> +}
> +
> +static int sun8i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
> + struct pwm_state *state)
> +{
> + int ret;
> + struct sun8i_pwm_chip *sun8i_pwm = to_sun8i_pwm_chip(chip);
> + struct pwm_state cstate;
> +
> + pwm_get_state(pwm, &cstate);
> + if (!cstate.enabled) {
> + ret = clk_prepare_enable(sun8i_pwm->clk);
You call clk_prepare_enable() here, under !cstate.enabled condition.
> + if (ret) {
> + dev_err(chip->dev, "failed to enable PWM clock\n");
> + return ret;
> + }
> + }
> +
> + spin_lock(&sun8i_pwm->ctrl_lock);
> +
> + if ((cstate.period != state->period) ||
> + (cstate.duty_cycle != state->duty_cycle)) {
> + ret = sun8i_pwm_config(sun8i_pwm, pwm->hwpwm, state);
> + if (ret) > + clk_disable_unprepare(sun8i_pwm->clk);
You need to call clk_disable_unprepare() only if !cstate.enabled:
if (!cstate.enabled)
clk_disable_unprepare();
> + spin_unlock(&sun8i_pwm->ctrl_lock);
> + dev_err(chip->dev, "failed to config PWM\n");
> + return ret;
> + }
> + }
> +
> + if (state->polarity != cstate.polarity)
> + sun8i_pwm_set_polarity(sun8i_pwm, pwm->hwpwm, state->polarity);
> +
> + if (state->enabled) {
> + sun8i_pwm_set_bit(sun8i_pwm,
> + CLK_CFG_REG(pwm->hwpwm), CLK_GATING);
> +
> + sun8i_pwm_set_bit(sun8i_pwm,
> + PWM_ENABLE_REG, PWM_EN(pwm->hwpwm));
> + } else {
> + sun8i_pwm_clear_bit(sun8i_pwm,
> + CLK_CFG_REG(pwm->hwpwm), CLK_GATING);
> +
> + sun8i_pwm_clear_bit(sun8i_pwm,
> + PWM_ENABLE_REG, PWM_EN(pwm->hwpwm));
> + }
> +
> + spin_unlock(&sun8i_pwm->ctrl_lock);
> +
> + return 0;
> +}
> +
> +static void sun8i_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
> + struct pwm_state *state)
> +{
> + struct sun8i_pwm_chip *sun8i_pwm = to_sun8i_pwm_chip(chip);
> + u64 clk_rate, tmp;
> + u32 val;
> + u16 clk_div, act_cycle;
> + u8 prescal, id;
> +
> + clk_rate = clk_get_rate(sun8i_pwm->clk);
> +
> + val = sun8i_pwm_read(sun8i_pwm, PWM_CTR_REG(pwm->hwpwm));
> + if (PWM_ACT_STA & val)
> + state->polarity = PWM_POLARITY_NORMAL;
> + else
> + state->polarity = PWM_POLARITY_INVERSED;
> +
> + prescal = PWM_PRESCAL_K & val;
> +
> + val = sun8i_pwm_read(sun8i_pwm, PWM_ENABLE_REG);
> + if (PWM_EN(pwm->hwpwm) & val)
> + state->enabled = true;
> + else
> + state->enabled = false;
> +
> + val = sun8i_pwm_read(sun8i_pwm, PWM_PERIOD_REG(pwm->hwpwm));
> + act_cycle = PWM_ACT_CYCLE & val;
> + clk_div = val >> 16;
> +
> + val = sun8i_pwm_read(sun8i_pwm, CLK_CFG_REG(pwm->hwpwm));
> + id = CLK_DIV_M & val;
> +
> + tmp = act_cycle * prescal * div_m_table[id] * NSEC_PER_SEC;
> + state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
> + tmp = clk_div * prescal * div_m_table[id] * NSEC_PER_SEC;
> + state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
> +}
> +
> +static const struct regmap_config sun8i_pwm_regmap_config = {
> + .reg_bits = 32,
> + .reg_stride = 4,
> + .val_bits = 32,
> + .max_register = CAPTURE_FALL_REG(7),
> +};
> +
> +static const struct pwm_ops sun8i_pwm_ops = {
> + .apply = sun8i_pwm_apply,
> + .get_state = sun8i_pwm_get_state,
> + .owner = THIS_MODULE,
> +};
> +
> +static const struct sun8i_pwm_data sun8i_pwm_data_r40 = {
> + .has_prescaler_bypass = false,
> + .has_rdy = true,
> + .npwm = 8,
> +};
> +
> +static const struct of_device_id sun8i_pwm_dt_ids[] = {
> + {
> + .compatible = "allwinner,sun8i-r40-pwm",
> + .data = &sun8i_pwm_data_r40,
> + },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, sun8i_pwm_dt_ids);
> +
> +static int sun8i_pwm_probe(struct platform_device *pdev)
> +{
> + struct sun8i_pwm_chip *pwm;
> + struct resource *res;
> + int ret;
> + const struct of_device_id *match;
> +
> + match = of_match_device(sun8i_pwm_dt_ids, &pdev->dev);
check for !match
> +
> + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
> + if (!pwm)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + pwm->base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(pwm->base))
> + return PTR_ERR(pwm->base);
> +
> + pwm->regmap = devm_regmap_init_mmio(&pdev->dev, pwm->base,
> + &sun8i_pwm_regmap_config);
Check for IS_ERR(pwm->regmap)
> +
> + pwm->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(pwm->clk))
> + return PTR_ERR(pwm->clk);
> +
> + pwm->data = match->data;
> + pwm->chip.dev = &pdev->dev;
> + pwm->chip.ops = &sun8i_pwm_ops;
> + pwm->chip.base = -1;
> + pwm->chip.npwm = pwm->data->npwm;
> + pwm->chip.of_xlate = of_pwm_xlate_with_flags;
> + pwm->chip.of_pwm_n_cells = 3;
> +
> + spin_lock_init(&pwm->ctrl_lock);
> +
> + ret = pwmchip_add(&pwm->chip);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
> + return ret;
> + }
> +
> + platform_set_drvdata(pdev, pwm);
> +
> + return 0;
> +}
> +
> +static int sun8i_pwm_remove(struct platform_device *pdev)
> +{
> + struct sun8i_pwm_chip *pwm = platform_get_drvdata(pdev);
> +
> + return pwmchip_remove(&pwm->chip);
> +}
> +
> +static struct platform_driver sun8i_pwm_driver = {
> + .driver = {
> + .name = "sun8i-r40-pwm",
> + .of_match_table = sun8i_pwm_dt_ids,
> + },
> + .probe = sun8i_pwm_probe,
> + .remove = sun8i_pwm_remove,
> +};
> +module_platform_driver(sun8i_pwm_driver);
> +
> +MODULE_ALIAS("platform:sun8i-r40-pwm");
> +MODULE_AUTHOR("Hao Zhang <hao5781286@gmail.com>");
> +MODULE_DESCRIPTION("Allwinner sun8i-r40 PWM driver");
> +MODULE_LICENSE("GPL v2");
>
^ permalink raw reply
* [PATCH 2/2] kasan: clean up KASAN_SHADOW_SCALE_SHIFT usage
From: Andrey Konovalov @ 2018-01-11 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1515684162.git.andreyknvl@google.com>
Right now the fact that KASAN uses a single shadow byte for 8 bytes of
memory is scattered all over the code.
This change defines KASAN_SHADOW_SCALE_SHIFT early in asm include files
and makes use of this constant where necessary.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
arch/arm64/include/asm/kasan.h | 3 ++-
arch/arm64/include/asm/memory.h | 3 ++-
arch/arm64/mm/kasan_init.c | 3 ++-
arch/x86/include/asm/kasan.h | 8 ++++++--
include/linux/kasan.h | 2 --
5 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/include/asm/kasan.h b/arch/arm64/include/asm/kasan.h
index e266f80e45b7..811643fe7640 100644
--- a/arch/arm64/include/asm/kasan.h
+++ b/arch/arm64/include/asm/kasan.h
@@ -27,7 +27,8 @@
* should satisfy the following equation:
* KASAN_SHADOW_OFFSET = KASAN_SHADOW_END - (1ULL << 61)
*/
-#define KASAN_SHADOW_OFFSET (KASAN_SHADOW_END - (1ULL << (64 - 3)))
+#define KASAN_SHADOW_OFFSET (KASAN_SHADOW_END - (1ULL << \
+ (64 - KASAN_SHADOW_SCALE_SHIFT)))
void kasan_init(void);
void kasan_copy_shadow(pgd_t *pgdir);
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index d4bae7d6e0d8..50fa96a49792 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -85,7 +85,8 @@
* stack size when KASAN is in use.
*/
#ifdef CONFIG_KASAN
-#define KASAN_SHADOW_SIZE (UL(1) << (VA_BITS - 3))
+#define KASAN_SHADOW_SCALE_SHIFT 3
+#define KASAN_SHADOW_SIZE (UL(1) << (VA_BITS - KASAN_SHADOW_SCALE_SHIFT))
#define KASAN_THREAD_SHIFT 1
#else
#define KASAN_SHADOW_SIZE (0)
diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
index acba49fb5aac..6e02e6fb4c7b 100644
--- a/arch/arm64/mm/kasan_init.c
+++ b/arch/arm64/mm/kasan_init.c
@@ -135,7 +135,8 @@ static void __init kasan_pgd_populate(unsigned long addr, unsigned long end,
/* The early shadow maps everything to a single page of zeroes */
asmlinkage void __init kasan_early_init(void)
{
- BUILD_BUG_ON(KASAN_SHADOW_OFFSET != KASAN_SHADOW_END - (1UL << 61));
+ BUILD_BUG_ON(KASAN_SHADOW_OFFSET !=
+ KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT)));
BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_START, PGDIR_SIZE));
BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, PGDIR_SIZE));
kasan_pgd_populate(KASAN_SHADOW_START, KASAN_SHADOW_END, NUMA_NO_NODE,
diff --git a/arch/x86/include/asm/kasan.h b/arch/x86/include/asm/kasan.h
index b577dd0916aa..737b7ea9bea3 100644
--- a/arch/x86/include/asm/kasan.h
+++ b/arch/x86/include/asm/kasan.h
@@ -4,6 +4,7 @@
#include <linux/const.h>
#define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL)
+#define KASAN_SHADOW_SCALE_SHIFT 3
/*
* Compiler uses shadow offset assuming that addresses start
@@ -12,12 +13,15 @@
* 'kernel address space start' >> KASAN_SHADOW_SCALE_SHIFT
*/
#define KASAN_SHADOW_START (KASAN_SHADOW_OFFSET + \
- ((-1UL << __VIRTUAL_MASK_SHIFT) >> 3))
+ ((-1UL << __VIRTUAL_MASK_SHIFT) >> \
+ KASAN_SHADOW_SCALE_SHIFT))
/*
* 47 bits for kernel address -> (47 - 3) bits for shadow
* 56 bits for kernel address -> (56 - 3) bits for shadow
*/
-#define KASAN_SHADOW_END (KASAN_SHADOW_START + (1ULL << (__VIRTUAL_MASK_SHIFT - 3)))
+#define KASAN_SHADOW_END (KASAN_SHADOW_START + \
+ (1ULL << (__VIRTUAL_MASK_SHIFT - \
+ KASAN_SHADOW_SCALE_SHIFT)))
#ifndef __ASSEMBLY__
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index e3eb834c9a35..e9eaa964473a 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -11,8 +11,6 @@ struct task_struct;
#ifdef CONFIG_KASAN
-#define KASAN_SHADOW_SCALE_SHIFT 3
-
#include <asm/kasan.h>
#include <asm/pgtable.h>
--
2.16.0.rc1.238.g530d649a79-goog
^ permalink raw reply related
* [PATCH 1/2] kasan: fix prototype author email address
From: Andrey Konovalov @ 2018-01-11 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1515684162.git.andreyknvl@google.com>
Use the new one.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/kasan/kasan.c | 2 +-
mm/kasan/report.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index 405bba487df5..cb4065f31f7f 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -5,7 +5,7 @@
* Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
*
* Some code borrowed from https://github.com/xairy/kasan-prototype by
- * Andrey Konovalov <adech.fo@gmail.com>
+ * Andrey Konovalov <andreyknvl@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 410c8235e671..eee796a005ac 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -5,7 +5,7 @@
* Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
*
* Some code borrowed from https://github.com/xairy/kasan-prototype by
- * Andrey Konovalov <adech.fo@gmail.com>
+ * Andrey Konovalov <andreyknvl@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--
2.16.0.rc1.238.g530d649a79-goog
^ permalink raw reply related
* [PATCH 0/2] kasan: a few cleanups
From: Andrey Konovalov @ 2018-01-11 15:29 UTC (permalink / raw)
To: linux-arm-kernel
Clean up usage of KASAN_SHADOW_SCALE_SHIFT and fix prototype author email
address.
Andrey Konovalov (2):
kasan: fix prototype author email address
kasan: clean up KASAN_SHADOW_SCALE_SHIFT usage
arch/arm64/include/asm/kasan.h | 3 ++-
arch/arm64/include/asm/memory.h | 3 ++-
arch/arm64/mm/kasan_init.c | 3 ++-
arch/x86/include/asm/kasan.h | 8 ++++++--
include/linux/kasan.h | 2 --
mm/kasan/kasan.c | 2 +-
mm/kasan/report.c | 2 +-
7 files changed, 14 insertions(+), 9 deletions(-)
--
2.16.0.rc1.238.g530d649a79-goog
^ permalink raw reply
* [PATCH] phy: work around 'phys' references to usb-phy devices
From: Arnd Bergmann @ 2018-01-11 15:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6dd37865-9c71-29f9-16b4-26e51e6b1c70@ti.com>
On Thu, Jan 11, 2018 at 2:30 PM, Kishon Vijay Abraham I <kishon@ti.com> wrote:
> On Thursday 11 January 2018 02:27 AM, Arnd Bergmann wrote:
>> On Mon, Jan 8, 2018 at 7:32 PM, Kishon Vijay Abraham I <kishon@ti.com> wrote:
>>> On Monday 08 January 2018 06:31 PM, Arnd Bergmann wrote:
>>>> Stefan Wahren reports a problem with a warning fix that was merged
>>>> ---
>>>> This obviously needs to be tested, I wrote this up as a reply to
>>>> Stefan's bug report. I'm fairly sure that I covered all usb-phy
>>>> driver strings here. My goal is to have a fix merged into 4.15
>>>> rather than reverting all the DT fixes.
>>>
>>> Shouldn't the fix be in phy consumer drivers to not return error if it's able
>>> to find the phy either using usb-phy or generic phy?
>>
>> Stefan has posted a patch to that effect now, but I fear that might be
>> a little fragile, in particular this short before the release with the
>> regression
>> in place.
>>
>> The main problem is that we'd have to change the generic
>> usb_add_hcd() function in addition to dwc2 and dwc3 to ignore
>> -EPROBE_DEFER from phy_get() whenever usb_get_phy_dev()
>> has already succeeded.
>>
>> If there is any HCD that relies on usb_add_hcd() to get both the
>> usb_phy and the phy structures, and it may need to defer probing
>> when the latter one isn't ready yet, that fix would break another
>> driver.
>
> hmm.. IMO the better thing right now would be to revert the dt patch which adds
> #phy-cells.
> We have to see if there are better fixes in order to add #phy-cells warning fix
> in stable tree.
Let's see which patches that would be, I think this is the full list of
nodes that got an extra #phy-cells:
c22fe696157d ARM: dts: Fix dm814x missing phy-cells property
f0e11ff8ff65 ARM: dts: am33xx: Add missing #phy-cells to ti,am335x-usb-phy
c5bbf358b790 arm: dts: nspire: Add missing #phy-cells to usb-nop-xceiv
44e5dced2ef6 arm: dts: marvell: Add missing #phy-cells to usb-nop-xceiv
014d6da6cb25 ARM: dts: bcm283x: Fix DTC warnings about missing phy-cells
f568f6f554b8 ARM: dts: omap: Add missing #phy-cells to usb-nop-xceiv
plus a couple in linux-next:
d745d5f277bf ARM: dts: imx51-zii-rdu1: Add missing #phy-cells to usb-nop-xceiv
915fbe59cbf2 ARM: dts: imx: Add missing #phy-cells to usb-nop-xceiv
It's a lot of patches to revert, and I guess it would get us back to hundreds
of warnings in an allmodconfig build, so I'd first try to come up with
ways to prove that at least some of them can stay.
Almost all the warnings are about "usb-nop-xceiv" phys, the only exceptions
I could find are the OMAP ones (the first two patches), which use
"ti,am335x-usb-phy" and are referenced from a "ti,musb-am33xx". That
particular driver is not affected by the bug, so we can leave that in.
To deal with all the "usb-nop-xceiv" references including the one that
Stefan reported, we could use a much simpler version of my earlier
patch, do you think this is any better?
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index b4964b067aec..f056d8fb3921 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -410,6 +410,10 @@ static struct phy *_of_phy_get(struct device_node
*np, int index)
if (ret)
return ERR_PTR(-ENODEV);
+ /* This phy type handled by the usb-phy subsystem for now */
+ if (of_device_is_compatible("usb-nop-xceiv"))
+ return ERR_PTR(-ENODEV);
+
mutex_lock(&phy_provider_mutex);
phy_provider = of_phy_provider_lookup(args.np);
if (IS_ERR(phy_provider) || !try_module_get(phy_provider->owner)) {
^ permalink raw reply related
* [PATCH v5 03/20] firmware: arm_scmi: add basic driver infrastructure for SCMI
From: Sudeep Holla @ 2018-01-11 14:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1514904162-11201-4-git-send-email-sudeep.holla@arm.com>
On 02/01/18 14:42, Sudeep Holla wrote:
> The SCMI is intended to allow OSPM to manage various functions that are
> provided by the hardware platform it is running on, including power and
> performance functions. SCMI provides two levels of abstraction, protocols
> and transports. Protocols define individual groups of system control and
> management messages. A protocol specification describes the messages
> that it supports. Transports describe the method by which protocol
> messages are communicated between agents and the platform.
>
> This patch adds basic infrastructure to manage the message allocation,
> initialisation, packing/unpacking and shared memory management.
>
Any chance you could review patches 3-14 ? All the drivers (15-20) are
already acked by the maintainer. I know it's late for v4.16, I want it
to be ready for v4.17 ASAP. It's on the list without much progress for
few months now :(, hence the push. Sorry for the nag.
--
Regards,
Sudeep
^ permalink raw reply
* [PATCH 12/25] arm: socfpga: dts: Remove leading 0x and 0s from bindings notation
From: Dinh Nguyen @ 2018-01-11 14:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171215111620.20379-12-malat@debian.org>
On 12/15/2017 05:16 AM, Mathieu Malaterre wrote:
> Improve the DTS files by removing all the leading "0x" and zeros to fix the
> following dtc warnings:
>
> Warning (unit_address_format): Node /XXX unit name should not have leading "0x"
>
> and
>
> Warning (unit_address_format): Node /XXX unit name should not have leading 0s
>
> Converted using the following command:
>
> find . -type f \( -iname *.dts -o -iname *.dtsi \) -exec sed -i -e "s/@\([0-9a-fA-FxX\.;:#]+\)\s*{/@\L\1 {/g" -e "s/@0x\(.*\) {/@\1 {/g" -e "s/@0+\(.*\) {/@\1 {/g" {} +^C
>
> For simplicity, two sed expressions were used to solve each warnings separately.
>
> To make the regex expression more robust a few other issues were resolved,
> namely setting unit-address to lower case, and adding a whitespace before the
> the opening curly brace:
>
> https://elinux.org/Device_Tree_Linux#Linux_conventions
>
> This will solve as a side effect warning:
>
> Warning (simple_bus_reg): Node /XXX@<UPPER> simple-bus unit address format error, expected "<lower>"
>
> This is a follow up to commit 4c9847b7375a ("dt-bindings: Remove leading 0x from bindings notation")
>
> Reported-by: David Daney <ddaney@caviumnetworks.com>
> Suggested-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Mathieu Malaterre <malat@debian.org>
> ---
> arch/arm/boot/dts/socfpga.dtsi | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
Acked-by: Dinh Nguyen <dinguyen@kernel.org>
Dinh
^ permalink raw reply
* "perf record" leads to a watchdog reset on a SAMA5D2 SoC
From: Romain Izard @ 2018-01-11 14:36 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
While trying to use perf on a device based on a SAMA5D2 SoC, I encountered a
systematic watchdog reboot. Simply calling "perf record /bin/true" is enough
to trigger this condition.
I have reproduced the issue on a SAMA5D2 Xplained demo board, with a 4.14.11
kernel, leading to "rcu_preempt self-detected stall on CPU" kernel messages
once the watchdog was disabled. But this was depending on the kernel
configuration - the sama5_defconfig configuration would not show the issue,
but adding the following options to this defconfig was be enough:
+CONFIG_PERF_EVENTS=y
+CONFIG_PREEMPT=y
+CONFIG_FUNCTION_TRACER=y
+# CONFIG_DYNAMIC_FTRACE is not set
There are complex interactions between the options, and in the case of the
original device DYNAMIC_FTRACE was set. But when trying to reduce the number
of changed flags between the default and a configuration reproducing the
issue, I ended up in a situation where enabling or disabling DYNAMIC_FTRACE
is the difference that triggered the problem.
Here is an example of the error (repeated every 30s) in the kernel log:
8<----------------------------------------------------------------------
INFO: rcu_preempt self-detected stall on CPU
0-...: (1413 ticks this GP) idle=7fe/140000000000002/0
softirq=1011/1011 fqs=0
(t=2100 jiffies g=86 c=85 q=63)
rcu_preempt kthread starved for 2100 jiffies! g86 c85 f0x0
RCU_GP_WAIT_FQS(3) ->state=0x402 ->cpu=0
rcu_preempt I 0 8 2 0x00000000
[<c0824d60>] (__schedule) from [<c082519c>] (schedule+0x58/0xb8)
[<c082519c>] (schedule) from [<c0828bb8>] (schedule_timeout+0x1d8/0x3fc)
[<c0828bb8>] (schedule_timeout) from [<c0169d60>] (rcu_gp_kthread+0x628/0xab4)
[<c0169d60>] (rcu_gp_kthread) from [<c013d7c4>] (kthread+0x134/0x164)
[<c013d7c4>] (kthread) from [<c0108308>] (ret_from_fork+0x14/0x2c)
Task dump for CPU 0:
perf R running task 0 842 836 0x00000002
[<c010f6e4>] (unwind_backtrace) from [<c010c9c8>] (show_stack+0x20/0x24)
[<c010c9c8>] (show_stack) from [<c0145314>] (sched_show_task.part.22+0xc4/0xe0)
[<c0145314>] (sched_show_task.part.22) from [<c0148c4c>]
(dump_cpu_task+0x40/0x44)
[<c0148c4c>] (dump_cpu_task) from [<c016bfac>] (rcu_dump_cpu_stacks+0x8c/0xcc)
[<c016bfac>] (rcu_dump_cpu_stacks) from [<c016ad30>]
(rcu_check_callbacks+0x628/0xa5c)
[<c016ad30>] (rcu_check_callbacks) from [<c0170e0c>]
(update_process_times+0x40/0x6c)
[<c0170e0c>] (update_process_times) from [<c0181888>]
(tick_sched_handle+0x64/0x68)
[<c0181888>] (tick_sched_handle) from [<c0181adc>] (tick_sched_timer+0x58/0xb4)
[<c0181adc>] (tick_sched_timer) from [<c0171ca0>]
(__hrtimer_run_queues.constprop.5+0x174/0x330)
[<c0171ca0>] (__hrtimer_run_queues.constprop.5) from [<c0172154>]
(hrtimer_interrupt+0xa4/0x260)
[<c0172154>] (hrtimer_interrupt) from [<c05efd30>] (ch2_irq+0x38/0x40)
[<c05efd30>] (ch2_irq) from [<c015ab4c>] (__handle_irq_event_percpu+0x6c/0x258)
[<c015ab4c>] (__handle_irq_event_percpu) from [<c015ad64>]
(handle_irq_event_percpu+0x2c/0x68)
[<c015ad64>] (handle_irq_event_percpu) from [<c015adfc>]
(handle_irq_event+0x5c/0x94)
[<c015adfc>] (handle_irq_event) from [<c015e418>]
(handle_fasteoi_irq+0xbc/0x198)
[<c015e418>] (handle_fasteoi_irq) from [<c0159c7c>]
(generic_handle_irq+0x34/0x44)
[<c0159c7c>] (generic_handle_irq) from [<c015a390>]
(__handle_domain_irq+0x80/0xec)
[<c015a390>] (__handle_domain_irq) from [<c010157c>] (aic5_handle+0xd0/0xf8)
[<c010157c>] (aic5_handle) from [<c010d70c>] (__irq_svc+0x6c/0xa8)
Exception stack(0xde63fd18 to 0xde63fd60)
fd00: 00000000 c0a077dc
fd20: c0d86200 00000000 c0d86200 00000000 00000000 00000202 de63fe20 df007600
fd40: c0d7c3cc de63fdbc de63fd58 de63fd68 c03d3cb4 c0101648 200b0113 ffffffff
[<c010d70c>] (__irq_svc) from [<c0101648>] (__do_softirq+0xa0/0x350)
[<c0101648>] (__do_softirq) from [<c0122a4c>] (irq_exit+0xfc/0x138)
[<c0122a4c>] (irq_exit) from [<c015a394>] (__handle_domain_irq+0x84/0xec)
[<c015a394>] (__handle_domain_irq) from [<c010157c>] (aic5_handle+0xd0/0xf8)
[<c010157c>] (aic5_handle) from [<c010d70c>] (__irq_svc+0x6c/0xa8)
Exception stack(0xde63fe20 to 0xde63fe68)
fe20: 00000000 c01c265c 00000000 00000000 600b0013 c01c612c de57f600 de63e000
fe40: df284c00 00000000 00000000 de63fe8c de63fe08 de63fe70 c0145178 c0187214
fe60: 600b0013 ffffffff
[<c010d70c>] (__irq_svc) from [<c0187214>] (smp_call_function_single+0x38/0x60)
[<c0187214>] (smp_call_function_single) from [<c01c2fd4>]
(task_function_call+0x3c/0x54)
[<c01c2fd4>] (task_function_call) from [<c01c5754>]
(perf_install_in_context+0x5c/0x19c)
[<c01c5754>] (perf_install_in_context) from [<c01cf9f0>]
(SyS_perf_event_open+0xb88/0xdcc)
[<c01cf9f0>] (SyS_perf_event_open) from [<c0108220>] (ret_fast_syscall+0x0/0x54)
8<----------------------------------------------------------------------
I'm not sure of how to interpret the issue. Is it because the CPU is too
busy servicing the trace code during ticks to do anything else?
Best regards,
--
Romain Izard
^ permalink raw reply
* [PATCH] arm64: dts: socfpga: add missing interrupt-parent
From: Dinh Nguyen @ 2018-01-11 14:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110210431.2330267-1-arnd@arndb.de>
On 01/10/2018 03:04 PM, Arnd Bergmann wrote:
> The PMU node has no working interrupt, as shown by this dtc warning:
>
> arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dtb: Warning (interrupts_property): Missing interrupt-parent for /pmu
>
> This adds an interrupt-parent property so we can correct parse
> that interrupt number.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> If this looks ok, I'd apply it directly to the fixes branch
> for 4.15, as the warning is one that was introduced in this
> release.
Acked-by: Dinh Nguyen <dinguyen@kernel.org>
Yes, please feel free to apply it. And thanks alot!
Dinh
^ permalink raw reply
* [PATCH] IIO: ADC: stm32-dfsdm: avoid unused-variable warning
From: Robin Murphy @ 2018-01-11 14:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180111103510.1408292-1-arnd@arndb.de>
On 11/01/18 10:34, Arnd Bergmann wrote:
> Building with CONFIG_OF disabled produces a compiler warning:
>
> drivers/iio/adc/stm32-dfsdm-core.c: In function 'stm32_dfsdm_probe':
> drivers/iio/adc/stm32-dfsdm-core.c:245:22: error: unused variable 'pnode' [-Werror=unused-variable]
>
> This removes the variable and open-codes it in the only place
> it gets used to avoid that warning.
>
> Fixes: bed73904e76f ("IIO: ADC: add stm32 DFSDM core support")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> drivers/iio/adc/stm32-dfsdm-core.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
> index 72427414db7f..6cd655f8239b 100644
> --- a/drivers/iio/adc/stm32-dfsdm-core.c
> +++ b/drivers/iio/adc/stm32-dfsdm-core.c
> @@ -242,7 +242,6 @@ MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match);
> static int stm32_dfsdm_probe(struct platform_device *pdev)
> {
> struct dfsdm_priv *priv;
> - struct device_node *pnode = pdev->dev.of_node;
> const struct of_device_id *of_id;
> const struct stm32_dfsdm_dev_data *dev_data;
> struct stm32_dfsdm *dfsdm;
> @@ -254,7 +253,7 @@ static int stm32_dfsdm_probe(struct platform_device *pdev)
>
> priv->pdev = pdev;
>
> - of_id = of_match_node(stm32_dfsdm_of_match, pnode);
> + of_id = of_match_node(stm32_dfsdm_of_match, pdev->dev.of_node);
> if (!of_id->data) {
> dev_err(&pdev->dev, "Data associated to device is missing\n");
> return -EINVAL;
FWIW, it looks like this whole lot could be cleaned up by using
of_device_get_match_data().
Robin.
^ permalink raw reply
* [PATCH v4] perf tools: Add ARM Statistical Profiling Extensions (SPE) support
From: Adrian Hunter @ 2018-01-11 14:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171121173302.bead17a1178ed4583e68014e@arm.com>
On 22/11/17 01:33, Kim Phillips wrote:
> 'perf record' and 'perf report --dump-raw-trace' supported in this
> release.
>
> Example usage:
>
> $ ./perf record -e arm_spe_0/ts_enable=1,pa_enable=1/ \
> dd if=/dev/zero of=/dev/null count=10000
>
> perf report --dump-raw-trace
>
> Note that the perf.data file is portable, so the report can be run on
> another architecture host if necessary.
>
> Output will contain raw SPE data and its textual representation, such
> as:
>
> 0x550 [0x30]: PERF_RECORD_AUXTRACE size: 0xc408 offset: 0 ref: 0x30005619 idx: 3 tid: 2109 cpu: 3
> .
> . ... ARM SPE data: size 50184 bytes
> . 00000000: 49 00 LD
> . 00000002: b2 00 9c 7b 7a 00 80 ff ff VA 0xffff80007a7b9c00
> . 0000000b: 9a 00 00 LAT 0 XLAT
> . 0000000e: 42 16 EV RETIRED L1D-ACCESS TLB-ACCESS
> . 00000010: b0 b0 c9 15 08 00 00 ff ff PC 0xff00000815c9b0 el3 ns=1
> . 00000019: 98 00 00 LAT 0 TOT
> . 0000001c: 71 00 20 fa fd 16 00 00 00 TS 98750308352
> . 00000025: 49 01 ST
> . 00000027: b2 60 bc 0c 0f 00 00 ff ff VA 0xffff00000f0cbc60
> . 00000030: 9a 00 00 LAT 0 XLAT
> . 00000033: 42 16 EV RETIRED L1D-ACCESS TLB-ACCESS
> . 00000035: b0 48 cc 15 08 00 00 ff ff PC 0xff00000815cc48 el3 ns=1
> . 0000003e: 98 00 00 LAT 0 TOT
> . 00000041: 71 00 20 fa fd 16 00 00 00 TS 98750308352
> . 0000004a: 48 00 INSN-OTHER
> . 0000004c: 42 02 EV RETIRED
> . 0000004e: b0 ac 47 0c 08 00 00 ff ff PC 0xff0000080c47ac el3 ns=1
> . 00000057: 98 00 00 LAT 0 TOT
> . 0000005a: 71 00 20 fa fd 16 00 00 00 TS 98750308352
> . 00000063: 49 00 LD
> . 00000065: b2 18 48 e5 7a 00 80 ff ff VA 0xffff80007ae54818
> . 0000006e: 9a 00 00 LAT 0 XLAT
> . 00000071: 42 16 EV RETIRED L1D-ACCESS TLB-ACCESS
> . 00000073: b0 08 f8 15 08 00 00 ff ff PC 0xff00000815f808 el3 ns=1
> . 0000007c: 98 00 00 LAT 0 TOT
> . 0000007f: 71 00 20 fa fd 16 00 00 00 TS 98750308352
> ...
>
> Other release notes:
>
> - applies to acme's perf/{core,urgent} branches, likely elsewhere
>
> - Report is self-contained within the tool. Record requires enabling
> the kernel SPE driver by setting CONFIG_ARM_SPE_PMU.
>
> - the intel-bts implementation was used as a starting point; its
> min/default/max buffer sizes and power of 2 pages granularity need to be
> revisited for ARM SPE
>
> - recording across multiple SPE clusters/domains not supported
>
> - snapshot support (record -S), and conversion to native perf events
> (e.g., via 'perf inject --itrace'), are also not supported
>
> - technically both cs-etm and spe can be used simultaneously, however
> disabled for simplicity in this release
>
> Signed-off-by: Kim Phillips <kim.phillips@arm.com>
For what is there now, it looks fine from the auxtrace point of view. There
are a couple of minor points below but nevertheless:
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
> v4: rebased onto acme's perf/core, whitespace fixes.
>
> v3: trying to address comments from v2:
>
> - despite adding a find_all_arm_spe_pmus() function to scan for all
> arm_spe_<n> device instances, in order to ensure auxtrace_record__init
> successfully matches the evsel type with the correct arm_spe_pmu type,
> I am still having trouble running in multi-SPE PPI (heterogeneous)
> environments (mmap fails with EOPNOTSUPP, as does running with
> --per-thread on homogeneous systems).
>
> - arm_spe_reference: use gettime instead of direct cntvct register access
>
> - spe-decoder: add a comment for why SPE_EVENTS code sets packet->index.
>
> - added arm_spe_pmu_default_config that accesses the driver
> caps/min_interval and sets the default sampling period to it. This way
> users don't have to specify -c explicitly. Also set is_uncore to false.
>
> - set more sampling bits in the arm_spe and its tracking evsel. Still
> unsure if too liberal, and not sure whether it needs another context
> switch tracking evsel. Comments welcome!
>
> - https://www.spinics.net/lists/arm-kernel/msg614361.html
>
> v2: mostly addressing Mark Rutland's comments as much as possible without his
> feedback to my feedback:
>
> - decoder refactored with a get_payload, not extended to with-ext_len ones like
> get_addr, named the constants
>
> - 0x-ified %x output formats, but decided to not sign extend the addresses in
> the raw dump, rather do so if necessary in the synthesis stage:
> SPE implementations differ in this area, and raw dump should reflect that.
>
> - CPU mask / new record behaviour bisected to commit e3ba76deef23064 "perf
> tools: Force uncore events to system wide monitoring". Waiting to hear back
> on why driver can't do system wide monitoring, even across PPIs, by e.g.,
> sharing the SPE interrupts in one handler (SPE's don't differ in this record
> regard).
>
> - addressed off-list comment from M. Williams:
> "Instruction Type" packet was renamed as "Operation Type".
> so in the spe packet decoder: INSN_TYPE -> OP_TYPE
>
> - do_get_packet fixed to handle excessive, successive PADding from a new source
> of raw SPE data, so instead of:
>
> . 000011ae: 00 PAD
> . 000011af: 00 PAD
> . 000011b0: 00 PAD
> . 000011b1: 00 PAD
> . 000011b2: 00 PAD
> . 000011b3: 00 PAD
> . 000011b4: 00 PAD
> . 000011b5: 00 PAD
> . 000011b6: 00 PAD
>
> we now get:
>
> . 000011ae: 00 00 00 00 00 00 00 00 00 PAD
>
> - fixed 52 00 00 decoded with an empty events clause, adding 'EV' for all events
> clauses now. parser writers can detect for empty event clauses by finding
> nothing after it.
>
> tools/perf/arch/arm/util/auxtrace.c | 75 +++++-
> tools/perf/arch/arm/util/pmu.c | 5 +-
> tools/perf/arch/arm64/util/Build | 3 +-
> tools/perf/arch/arm64/util/arm-spe.c | 235 +++++++++++++++++
> tools/perf/util/Build | 2 +
> tools/perf/util/arm-spe-pkt-decoder.c | 471 ++++++++++++++++++++++++++++++++++
> tools/perf/util/arm-spe-pkt-decoder.h | 52 ++++
> tools/perf/util/arm-spe.c | 318 +++++++++++++++++++++++
> tools/perf/util/arm-spe.h | 42 +++
> tools/perf/util/auxtrace.c | 3 +
> tools/perf/util/auxtrace.h | 1 +
> 11 files changed, 1199 insertions(+), 8 deletions(-)
> create mode 100644 tools/perf/arch/arm64/util/arm-spe.c
> create mode 100644 tools/perf/util/arm-spe-pkt-decoder.c
> create mode 100644 tools/perf/util/arm-spe-pkt-decoder.h
> create mode 100644 tools/perf/util/arm-spe.c
> create mode 100644 tools/perf/util/arm-spe.h
>
> diff --git a/tools/perf/arch/arm/util/auxtrace.c b/tools/perf/arch/arm/util/auxtrace.c
> index 8edf2cb71564..8e7c1ad18224 100644
> --- a/tools/perf/arch/arm/util/auxtrace.c
> +++ b/tools/perf/arch/arm/util/auxtrace.c
> @@ -22,6 +22,42 @@
> #include "../../util/evlist.h"
> #include "../../util/pmu.h"
> #include "cs-etm.h"
> +#include "arm-spe.h"
> +
> +static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)
> +{
> + struct perf_pmu **arm_spe_pmus = NULL;
> + int ret, i, nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
> + /* arm_spe_xxxxxxxxx\0 */
> + char arm_spe_pmu_name[sizeof(ARM_SPE_PMU_NAME) + 10];
> +
> + arm_spe_pmus = zalloc(sizeof(struct perf_pmu *) * nr_cpus);
> + if (!arm_spe_pmus) {
> + pr_err("spes alloc failed\n");
> + *err = -ENOMEM;
> + return NULL;
> + }
> +
> + for (i = 0; i < nr_cpus; i++) {
> + ret = sprintf(arm_spe_pmu_name, "%s%d", ARM_SPE_PMU_NAME, i);
> + if (ret < 0) {
> + pr_err("sprintf failed\n");
> + *err = -ENOMEM;
> + return NULL;
> + }
> +
> + arm_spe_pmus[*nr_spes] = perf_pmu__find(arm_spe_pmu_name);
> + if (arm_spe_pmus[*nr_spes]) {
> + pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",
> + __func__, __LINE__, *nr_spes,
> + arm_spe_pmus[*nr_spes]->type,
> + arm_spe_pmus[*nr_spes]->name);
> + (*nr_spes)++;
> + }
> + }
> +
> + return arm_spe_pmus;
> +}
>
> struct auxtrace_record
> *auxtrace_record__init(struct perf_evlist *evlist, int *err)
> @@ -29,22 +65,49 @@ struct auxtrace_record
> struct perf_pmu *cs_etm_pmu;
> struct perf_evsel *evsel;
> bool found_etm = false;
> + bool found_spe = false;
> + static struct perf_pmu **arm_spe_pmus = NULL;
> + static int nr_spes = 0;
> + int i;
> +
> + if (!evlist)
> + return NULL;
>
> cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
>
> - if (evlist) {
> - evlist__for_each_entry(evlist, evsel) {
> - if (cs_etm_pmu &&
> - evsel->attr.type == cs_etm_pmu->type)
> - found_etm = true;
> + if (!arm_spe_pmus)
> + arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err);
> +
> + evlist__for_each_entry(evlist, evsel) {
> + if (cs_etm_pmu &&
> + evsel->attr.type == cs_etm_pmu->type)
> + found_etm = true;
> +
> + if (!nr_spes)
> + continue;
> +
> + for (i = 0; i < nr_spes; i++) {
> + if (evsel->attr.type == arm_spe_pmus[i]->type) {
> + found_spe = true;
> + break;
> + }
> }
> }
>
> + if (found_etm && found_spe) {
> + pr_err("Concurrent ARM Coresight ETM and SPE operation not currently supported\n");
> + *err = -EOPNOTSUPP;
> + return NULL;
> + }
> +
> if (found_etm)
> return cs_etm_record_init(err);
>
> + if (found_spe)
> + return arm_spe_recording_init(err, arm_spe_pmus[i]);
> +
> /*
> - * Clear 'err' even if we haven't found a cs_etm event - that way perf
> + * Clear 'err' even if we haven't found an event - that way perf
> * record can still be used even if tracers aren't present. The NULL
> * return value will take care of telling the infrastructure HW tracing
> * isn't available.
> diff --git a/tools/perf/arch/arm/util/pmu.c b/tools/perf/arch/arm/util/pmu.c
> index 98d67399a0d6..4c06a25ae6b1 100644
> --- a/tools/perf/arch/arm/util/pmu.c
> +++ b/tools/perf/arch/arm/util/pmu.c
> @@ -20,6 +20,7 @@
> #include <linux/perf_event.h>
>
> #include "cs-etm.h"
> +#include "arm-spe.h"
> #include "../../util/pmu.h"
>
> struct perf_event_attr
> @@ -30,7 +31,9 @@ struct perf_event_attr
> /* add ETM default config here */
> pmu->selectable = true;
> pmu->set_drv_config = cs_etm_set_drv_config;
> - }
> + } else
> + if (strstarts(pmu->name, ARM_SPE_PMU_NAME))
> + return arm_spe_pmu_default_config(pmu);
More conventional kernel style would be:
} else if (strstarts(pmu->name, ARM_SPE_PMU_NAME)) {
return arm_spe_pmu_default_config(pmu);
}
Also it looks like arm_spe_pmu_default_config() is only compiled for arm64
so what happens if you build for arm.
> #endif
> return NULL;
> }
> diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
> index cef6fb38d17e..f9969bb88ccb 100644
> --- a/tools/perf/arch/arm64/util/Build
> +++ b/tools/perf/arch/arm64/util/Build
> @@ -3,4 +3,5 @@ libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
>
> libperf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \
> ../../arm/util/auxtrace.o \
> - ../../arm/util/cs-etm.o
> + ../../arm/util/cs-etm.o \
> + arm-spe.o
> diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
> new file mode 100644
> index 000000000000..ef576b52c850
> --- /dev/null
> +++ b/tools/perf/arch/arm64/util/arm-spe.c
> @@ -0,0 +1,235 @@
> +/*
> + * ARM Statistical Profiling Extensions (SPE) support
> + * Copyright (c) 2017, ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
Might as well switch to SPDX license identifiers, here and elsewhere.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/bitops.h>
> +#include <linux/log2.h>
> +#include <time.h>
> +
> +#include "../../util/cpumap.h"
> +#include "../../util/evsel.h"
> +#include "../../util/evlist.h"
> +#include "../../util/session.h"
> +#include "../../util/util.h"
> +#include "../../util/pmu.h"
> +#include "../../util/debug.h"
> +#include "../../util/tsc.h"
tsc.h is not needed
> +#include "../../util/auxtrace.h"
> +#include "../../util/arm-spe.h"
> +
> +#define KiB(x) ((x) * 1024)
> +#define MiB(x) ((x) * 1024 * 1024)
> +
> +struct arm_spe_recording {
> + struct auxtrace_record itr;
> + struct perf_pmu *arm_spe_pmu;
> + struct perf_evlist *evlist;
> +};
> +
> +static size_t
> +arm_spe_info_priv_size(struct auxtrace_record *itr __maybe_unused,
> + struct perf_evlist *evlist __maybe_unused)
> +{
> + return ARM_SPE_AUXTRACE_PRIV_SIZE;
> +}
> +
> +static int arm_spe_info_fill(struct auxtrace_record *itr,
> + struct perf_session *session,
> + struct auxtrace_info_event *auxtrace_info,
> + size_t priv_size)
> +{
> + struct arm_spe_recording *sper =
> + container_of(itr, struct arm_spe_recording, itr);
> + struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu;
> +
> + if (priv_size != ARM_SPE_AUXTRACE_PRIV_SIZE)
> + return -EINVAL;
> +
> + if (!session->evlist->nr_mmaps)
> + return -EINVAL;
> +
> + auxtrace_info->type = PERF_AUXTRACE_ARM_SPE;
> + auxtrace_info->priv[ARM_SPE_PMU_TYPE] = arm_spe_pmu->type;
> +
> + return 0;
> +}
> +
> +static int arm_spe_recording_options(struct auxtrace_record *itr,
> + struct perf_evlist *evlist,
> + struct record_opts *opts)
> +{
> + struct arm_spe_recording *sper =
> + container_of(itr, struct arm_spe_recording, itr);
> + struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu;
> + struct perf_evsel *evsel, *arm_spe_evsel = NULL;
> + bool privileged = geteuid() == 0 || perf_event_paranoid() < 0;
> + struct perf_evsel *tracking_evsel;
> + int err;
> +
> + sper->evlist = evlist;
> +
> + evlist__for_each_entry(evlist, evsel) {
> + if (evsel->attr.type == arm_spe_pmu->type) {
> + if (arm_spe_evsel) {
> + pr_err("There may be only one " ARM_SPE_PMU_NAME "x event\n");
> + return -EINVAL;
> + }
> + evsel->attr.freq = 0;
> + evsel->attr.sample_period = 1;
> + arm_spe_evsel = evsel;
> + opts->full_auxtrace = true;
> + }
> + }
> +
> + if (!opts->full_auxtrace)
> + return 0;
> +
> + /* We are in full trace mode but '-m,xyz' wasn't specified */
> + if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
> + if (privileged) {
> + opts->auxtrace_mmap_pages = MiB(4) / page_size;
> + } else {
> + opts->auxtrace_mmap_pages = KiB(128) / page_size;
> + if (opts->mmap_pages == UINT_MAX)
> + opts->mmap_pages = KiB(256) / page_size;
> + }
> + }
> +
> + /* Validate auxtrace_mmap_pages */
> + if (opts->auxtrace_mmap_pages) {
> + size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
> + size_t min_sz = KiB(8);
> +
> + if (sz < min_sz || !is_power_of_2(sz)) {
> + pr_err("Invalid mmap size for ARM SPE: must be at least %zuKiB and a power of 2\n",
> + min_sz / 1024);
> + return -EINVAL;
> + }
> + }
> +
> +
> + /*
> + * To obtain the auxtrace buffer file descriptor, the auxtrace event
> + * must come first.
> + */
> + perf_evlist__to_front(evlist, arm_spe_evsel);
> +
> + perf_evsel__set_sample_bit(arm_spe_evsel, CPU);
> + perf_evsel__set_sample_bit(arm_spe_evsel, TIME);
> + perf_evsel__set_sample_bit(arm_spe_evsel, TID);
> +
> + /* Add dummy event to keep tracking */
> + err = parse_events(evlist, "dummy:u", NULL);
> + if (err)
> + return err;
> +
> + tracking_evsel = perf_evlist__last(evlist);
> + perf_evlist__set_tracking_event(evlist, tracking_evsel);
> +
> + tracking_evsel->attr.freq = 0;
> + tracking_evsel->attr.sample_period = 1;
> + perf_evsel__set_sample_bit(tracking_evsel, TIME);
> + perf_evsel__set_sample_bit(tracking_evsel, CPU);
> + perf_evsel__reset_sample_bit(tracking_evsel, BRANCH_STACK);
> +
> + return 0;
> +}
> +
> +static u64 arm_spe_reference(struct auxtrace_record *itr __maybe_unused)
> +{
> + struct timespec ts;
> +
> + clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
> +
> + return ts.tv_sec ^ ts.tv_nsec;
> +}
> +
> +static void arm_spe_recording_free(struct auxtrace_record *itr)
> +{
> + struct arm_spe_recording *sper =
> + container_of(itr, struct arm_spe_recording, itr);
> +
> + free(sper);
> +}
> +
> +static int arm_spe_read_finish(struct auxtrace_record *itr, int idx)
> +{
> + struct arm_spe_recording *sper =
> + container_of(itr, struct arm_spe_recording, itr);
> + struct perf_evsel *evsel;
> +
> + evlist__for_each_entry(sper->evlist, evsel) {
> + if (evsel->attr.type == sper->arm_spe_pmu->type)
> + return perf_evlist__enable_event_idx(sper->evlist,
> + evsel, idx);
> + }
> + return -EINVAL;
> +}
> +
> +struct auxtrace_record *arm_spe_recording_init(int *err,
> + struct perf_pmu *arm_spe_pmu)
> +{
> + struct arm_spe_recording *sper;
> +
> + if (!arm_spe_pmu) {
> + *err = -ENODEV;
> + return NULL;
> + }
> +
> + sper = zalloc(sizeof(struct arm_spe_recording));
> + if (!sper) {
> + *err = -ENOMEM;
> + return NULL;
> + }
> +
> + sper->arm_spe_pmu = arm_spe_pmu;
> + sper->itr.recording_options = arm_spe_recording_options;
> + sper->itr.info_priv_size = arm_spe_info_priv_size;
> + sper->itr.info_fill = arm_spe_info_fill;
> + sper->itr.free = arm_spe_recording_free;
> + sper->itr.reference = arm_spe_reference;
> + sper->itr.read_finish = arm_spe_read_finish;
> + sper->itr.alignment = 0;
> +
> + return &sper->itr;
> +}
> +
> +struct perf_event_attr
> +*arm_spe_pmu_default_config(struct perf_pmu *arm_spe_pmu)
> +{
> + struct perf_event_attr *attr;
> +
> + attr = zalloc(sizeof(struct perf_event_attr));
> + if (!attr) {
> + pr_err("arm_spe default config cannot allocate a perf_event_attr\n");
> + return NULL;
> + }
> +
> + /*
> + * If kernel driver doesn't advertise a minimum,
> + * use max allowable by PMSIDR_EL1.INTERVAL
> + */
> + if (perf_pmu__scan_file(arm_spe_pmu, "caps/min_interval", "%llu",
> + &attr->sample_period) != 1) {
> + pr_debug("arm_spe driver doesn't advertise a min. interval. Using 4096\n");
> + attr->sample_period = 4096;
> + }
> +
> + arm_spe_pmu->selectable = true;
> + arm_spe_pmu->is_uncore = false;
> +
> + return attr;
> +}
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index a3de7916fe63..7c6a8b461e24 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -86,6 +86,8 @@ libperf-$(CONFIG_AUXTRACE) += auxtrace.o
> libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
> libperf-$(CONFIG_AUXTRACE) += intel-pt.o
> libperf-$(CONFIG_AUXTRACE) += intel-bts.o
> +libperf-$(CONFIG_AUXTRACE) += arm-spe.o
> +libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o
> libperf-y += parse-branch-options.o
> libperf-y += dump-insn.o
> libperf-y += parse-regs-options.o
> diff --git a/tools/perf/util/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-pkt-decoder.c
> new file mode 100644
> index 000000000000..234943471d30
> --- /dev/null
> +++ b/tools/perf/util/arm-spe-pkt-decoder.c
> @@ -0,0 +1,471 @@
> +/*
> + * ARM Statistical Profiling Extensions (SPE) support
> + * Copyright (c) 2017, ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <endian.h>
> +#include <byteswap.h>
> +
> +#include "arm-spe-pkt-decoder.h"
> +
> +#define BIT(n) (1ULL << (n))
> +
> +#define NS_FLAG BIT(63)
> +#define EL_FLAG (BIT(62) | BIT(61))
> +
> +#define SPE_HEADER0_PAD 0x0
> +#define SPE_HEADER0_END 0x1
> +#define SPE_HEADER0_ADDRESS 0x30 /* address packet (short) */
> +#define SPE_HEADER0_ADDRESS_MASK 0x38
> +#define SPE_HEADER0_COUNTER 0x18 /* counter packet (short) */
> +#define SPE_HEADER0_COUNTER_MASK 0x38
> +#define SPE_HEADER0_TIMESTAMP 0x71
> +#define SPE_HEADER0_TIMESTAMP 0x71
> +#define SPE_HEADER0_EVENTS 0x2
> +#define SPE_HEADER0_EVENTS_MASK 0xf
> +#define SPE_HEADER0_SOURCE 0x3
> +#define SPE_HEADER0_SOURCE_MASK 0xf
> +#define SPE_HEADER0_CONTEXT 0x24
> +#define SPE_HEADER0_CONTEXT_MASK 0x3c
> +#define SPE_HEADER0_OP_TYPE 0x8
> +#define SPE_HEADER0_OP_TYPE_MASK 0x3c
> +#define SPE_HEADER1_ALIGNMENT 0x0
> +#define SPE_HEADER1_ADDRESS 0xb0 /* address packet (extended) */
> +#define SPE_HEADER1_ADDRESS_MASK 0xf8
> +#define SPE_HEADER1_COUNTER 0x98 /* counter packet (extended) */
> +#define SPE_HEADER1_COUNTER_MASK 0xf8
> +
> +#if __BYTE_ORDER == __BIG_ENDIAN
> +#define le16_to_cpu bswap_16
> +#define le32_to_cpu bswap_32
> +#define le64_to_cpu bswap_64
> +#define memcpy_le64(d, s, n) do { \
> + memcpy((d), (s), (n)); \
> + *(d) = le64_to_cpu(*(d)); \
> +} while (0)
> +#else
> +#define le16_to_cpu
> +#define le32_to_cpu
> +#define le64_to_cpu
> +#define memcpy_le64 memcpy
> +#endif
> +
> +static const char * const arm_spe_packet_name[] = {
> + [ARM_SPE_PAD] = "PAD",
> + [ARM_SPE_END] = "END",
> + [ARM_SPE_TIMESTAMP] = "TS",
> + [ARM_SPE_ADDRESS] = "ADDR",
> + [ARM_SPE_COUNTER] = "LAT",
> + [ARM_SPE_CONTEXT] = "CONTEXT",
> + [ARM_SPE_OP_TYPE] = "OP-TYPE",
> + [ARM_SPE_EVENTS] = "EVENTS",
> + [ARM_SPE_DATA_SOURCE] = "DATA-SOURCE",
> +};
> +
> +const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
> +{
> + return arm_spe_packet_name[type];
> +}
> +
> +/* return ARM SPE payload size from its encoding,
> + * which is in bits 5:4 of the byte.
> + * 00 : byte
> + * 01 : halfword (2)
> + * 10 : word (4)
> + * 11 : doubleword (8)
> + */
> +static int payloadlen(unsigned char byte)
> +{
> + return 1 << ((byte & 0x30) >> 4);
> +}
> +
> +static int arm_spe_get_payload(const unsigned char *buf, size_t len,
> + struct arm_spe_pkt *packet)
> +{
> + size_t payload_len = payloadlen(buf[0]);
> +
> + if (len < 1 + payload_len)
> + return ARM_SPE_NEED_MORE_BYTES;
> +
> + buf++;
> +
> + switch (payload_len) {
> + case 1: packet->payload = *(uint8_t *)buf; break;
> + case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break;
> + case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break;
> + case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break;
> + default: return ARM_SPE_BAD_PACKET;
> + }
> +
> + return 1 + payload_len;
> +}
> +
> +static int arm_spe_get_pad(struct arm_spe_pkt *packet)
> +{
> + packet->type = ARM_SPE_PAD;
> + return 1;
> +}
> +
> +static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
> + struct arm_spe_pkt *packet)
> +{
> + unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
> +
> + if (len < alignment)
> + return ARM_SPE_NEED_MORE_BYTES;
> +
> + packet->type = ARM_SPE_PAD;
> + return alignment - (((uint64_t)buf) & (alignment - 1));
> +}
> +
> +static int arm_spe_get_end(struct arm_spe_pkt *packet)
> +{
> + packet->type = ARM_SPE_END;
> + return 1;
> +}
> +
> +static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
> + struct arm_spe_pkt *packet)
> +{
> + packet->type = ARM_SPE_TIMESTAMP;
> + return arm_spe_get_payload(buf, len, packet);
> +}
> +
> +static int arm_spe_get_events(const unsigned char *buf, size_t len,
> + struct arm_spe_pkt *packet)
> +{
> + int ret = arm_spe_get_payload(buf, len, packet);
> +
> + packet->type = ARM_SPE_EVENTS;
> +
> + /* we use index to identify Events with a less number of
> + * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
> + * LLC-REFILL, and REMOTE-ACCESS events are identified iff
> + * index > 1.
> + */
> + packet->index = ret - 1;
> +
> + return ret;
> +}
> +
> +static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
> + struct arm_spe_pkt *packet)
> +{
> + packet->type = ARM_SPE_DATA_SOURCE;
> + return arm_spe_get_payload(buf, len, packet);
> +}
> +
> +static int arm_spe_get_context(const unsigned char *buf, size_t len,
> + struct arm_spe_pkt *packet)
> +{
> + packet->type = ARM_SPE_CONTEXT;
> + packet->index = buf[0] & 0x3;
> +
> + return arm_spe_get_payload(buf, len, packet);
> +}
> +
> +static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
> + struct arm_spe_pkt *packet)
> +{
> + packet->type = ARM_SPE_OP_TYPE;
> + packet->index = buf[0] & 0x3;
> + return arm_spe_get_payload(buf, len, packet);
> +}
> +
> +static int arm_spe_get_counter(const unsigned char *buf, size_t len,
> + const unsigned char ext_hdr, struct arm_spe_pkt *packet)
> +{
> + if (len < 2)
> + return ARM_SPE_NEED_MORE_BYTES;
> +
> + packet->type = ARM_SPE_COUNTER;
> + if (ext_hdr)
> + packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
> + else
> + packet->index = buf[0] & 0x7;
> +
> + packet->payload = le16_to_cpu(*(uint16_t *)(buf + 1));
> +
> + return 1 + ext_hdr + 2;
> +}
> +
> +static int arm_spe_get_addr(const unsigned char *buf, size_t len,
> + const unsigned char ext_hdr, struct arm_spe_pkt *packet)
> +{
> + if (len < 8)
> + return ARM_SPE_NEED_MORE_BYTES;
> +
> + packet->type = ARM_SPE_ADDRESS;
> + if (ext_hdr)
> + packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
> + else
> + packet->index = buf[0] & 0x7;
> +
> + memcpy_le64(&packet->payload, buf + 1, 8);
> +
> + return 1 + ext_hdr + 8;
> +}
> +
> +static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
> + struct arm_spe_pkt *packet)
> +{
> + unsigned int byte;
> +
> + memset(packet, 0, sizeof(struct arm_spe_pkt));
> +
> + if (!len)
> + return ARM_SPE_NEED_MORE_BYTES;
> +
> + byte = buf[0];
> + if (byte == SPE_HEADER0_PAD)
> + return arm_spe_get_pad(packet);
> + else if (byte == SPE_HEADER0_END) /* no timestamp at end of record */
> + return arm_spe_get_end(packet);
> + else if (byte & 0xc0 /* 0y11xxxxxx */) {
> + if (byte & 0x80) {
> + if ((byte & SPE_HEADER0_ADDRESS_MASK) == SPE_HEADER0_ADDRESS)
> + return arm_spe_get_addr(buf, len, 0, packet);
> + if ((byte & SPE_HEADER0_COUNTER_MASK) == SPE_HEADER0_COUNTER)
> + return arm_spe_get_counter(buf, len, 0, packet);
> + } else
> + if (byte == SPE_HEADER0_TIMESTAMP)
> + return arm_spe_get_timestamp(buf, len, packet);
> + else if ((byte & SPE_HEADER0_EVENTS_MASK) == SPE_HEADER0_EVENTS)
> + return arm_spe_get_events(buf, len, packet);
> + else if ((byte & SPE_HEADER0_SOURCE_MASK) == SPE_HEADER0_SOURCE)
> + return arm_spe_get_data_source(buf, len, packet);
> + else if ((byte & SPE_HEADER0_CONTEXT_MASK) == SPE_HEADER0_CONTEXT)
> + return arm_spe_get_context(buf, len, packet);
> + else if ((byte & SPE_HEADER0_OP_TYPE_MASK) == SPE_HEADER0_OP_TYPE)
> + return arm_spe_get_op_type(buf, len, packet);
> + } else if ((byte & 0xe0) == 0x20 /* 0y001xxxxx */) {
> + /* 16-bit header */
> + byte = buf[1];
> + if (byte == SPE_HEADER1_ALIGNMENT)
> + return arm_spe_get_alignment(buf, len, packet);
> + else if ((byte & SPE_HEADER1_ADDRESS_MASK) == SPE_HEADER1_ADDRESS)
> + return arm_spe_get_addr(buf, len, 1, packet);
> + else if ((byte & SPE_HEADER1_COUNTER_MASK) == SPE_HEADER1_COUNTER)
> + return arm_spe_get_counter(buf, len, 1, packet);
> + }
> +
> + return ARM_SPE_BAD_PACKET;
> +}
> +
> +int arm_spe_get_packet(const unsigned char *buf, size_t len,
> + struct arm_spe_pkt *packet)
> +{
> + int ret;
> +
> + ret = arm_spe_do_get_packet(buf, len, packet);
> + /* put multiple consecutive PADs on the same line, up to
> + * the fixed-width output format of 16 bytes per line.
> + */
> + if (ret > 0 && packet->type == ARM_SPE_PAD) {
> + while (ret < 16 && len > (size_t)ret && !buf[ret])
> + ret += 1;
> + }
> + return ret;
> +}
> +
> +int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
> + size_t buf_len)
> +{
> + int ret, ns, el, index = packet->index;
> + unsigned long long payload = packet->payload;
> + const char *name = arm_spe_pkt_name(packet->type);
> +
> + switch (packet->type) {
> + case ARM_SPE_BAD:
> + case ARM_SPE_PAD:
> + case ARM_SPE_END:
> + return snprintf(buf, buf_len, "%s", name);
> + case ARM_SPE_EVENTS: {
> + size_t blen = buf_len;
> +
> + ret = 0;
> + ret = snprintf(buf, buf_len, "EV");
> + buf += ret;
> + blen -= ret;
> + if (payload & 0x1) {
> + ret = snprintf(buf, buf_len, " EXCEPTION-GEN");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x2) {
> + ret = snprintf(buf, buf_len, " RETIRED");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x4) {
> + ret = snprintf(buf, buf_len, " L1D-ACCESS");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x8) {
> + ret = snprintf(buf, buf_len, " L1D-REFILL");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x10) {
> + ret = snprintf(buf, buf_len, " TLB-ACCESS");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x20) {
> + ret = snprintf(buf, buf_len, " TLB-REFILL");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x40) {
> + ret = snprintf(buf, buf_len, " NOT-TAKEN");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x80) {
> + ret = snprintf(buf, buf_len, " MISPRED");
> + buf += ret;
> + blen -= ret;
> + }
> + if (index > 1) {
> + if (payload & 0x100) {
> + ret = snprintf(buf, buf_len, " LLC-ACCESS");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x200) {
> + ret = snprintf(buf, buf_len, " LLC-REFILL");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x400) {
> + ret = snprintf(buf, buf_len, " REMOTE-ACCESS");
> + buf += ret;
> + blen -= ret;
> + }
> + }
> + if (ret < 0)
> + return ret;
> + blen -= ret;
> + return buf_len - blen;
> + }
> + case ARM_SPE_OP_TYPE:
> + switch (index) {
> + case 0: return snprintf(buf, buf_len, "%s", payload & 0x1 ?
> + "COND-SELECT" : "INSN-OTHER");
> + case 1: {
> + size_t blen = buf_len;
> +
> + if (payload & 0x1)
> + ret = snprintf(buf, buf_len, "ST");
> + else
> + ret = snprintf(buf, buf_len, "LD");
> + buf += ret;
> + blen -= ret;
> + if (payload & 0x2) {
> + if (payload & 0x4) {
> + ret = snprintf(buf, buf_len, " AT");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x8) {
> + ret = snprintf(buf, buf_len, " EXCL");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x10) {
> + ret = snprintf(buf, buf_len, " AR");
> + buf += ret;
> + blen -= ret;
> + }
> + } else if (payload & 0x4) {
> + ret = snprintf(buf, buf_len, " SIMD-FP");
> + buf += ret;
> + blen -= ret;
> + }
> + if (ret < 0)
> + return ret;
> + blen -= ret;
> + return buf_len - blen;
> + }
> + case 2: {
> + size_t blen = buf_len;
> +
> + ret = snprintf(buf, buf_len, "B");
> + buf += ret;
> + blen -= ret;
> + if (payload & 0x1) {
> + ret = snprintf(buf, buf_len, " COND");
> + buf += ret;
> + blen -= ret;
> + }
> + if (payload & 0x2) {
> + ret = snprintf(buf, buf_len, " IND");
> + buf += ret;
> + blen -= ret;
> + }
> + if (ret < 0)
> + return ret;
> + blen -= ret;
> + return buf_len - blen;
> + }
> + default: return 0;
> + }
> + case ARM_SPE_DATA_SOURCE:
> + case ARM_SPE_TIMESTAMP:
> + return snprintf(buf, buf_len, "%s %lld", name, payload);
> + case ARM_SPE_ADDRESS:
> + switch (index) {
> + case 0:
> + case 1: ns = !!(packet->payload & NS_FLAG);
> + el = (packet->payload & EL_FLAG) >> 61;
> + payload &= ~(0xffULL << 56);
> + return snprintf(buf, buf_len, "%s 0x%llx el%d ns=%d",
> + (index == 1) ? "TGT" : "PC", payload, el, ns);
> + case 2: return snprintf(buf, buf_len, "VA 0x%llx", payload);
> + case 3: ns = !!(packet->payload & NS_FLAG);
> + payload &= ~(0xffULL << 56);
> + return snprintf(buf, buf_len, "PA 0x%llx ns=%d",
> + payload, ns);
> + default: return 0;
> + }
> + case ARM_SPE_CONTEXT:
> + return snprintf(buf, buf_len, "%s 0x%lx el%d", name,
> + (unsigned long)payload, index + 1);
> + case ARM_SPE_COUNTER: {
> + size_t blen = buf_len;
> +
> + ret = snprintf(buf, buf_len, "%s %d ", name,
> + (unsigned short)payload);
> + buf += ret;
> + blen -= ret;
> + switch (index) {
> + case 0: ret = snprintf(buf, buf_len, "TOT"); break;
> + case 1: ret = snprintf(buf, buf_len, "ISSUE"); break;
> + case 2: ret = snprintf(buf, buf_len, "XLAT"); break;
> + default: ret = 0;
> + }
> + if (ret < 0)
> + return ret;
> + blen -= ret;
> + return buf_len - blen;
> + }
> + default:
> + break;
> + }
> +
> + return snprintf(buf, buf_len, "%s 0x%llx (%d)",
> + name, payload, packet->index);
> +}
> diff --git a/tools/perf/util/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-pkt-decoder.h
> new file mode 100644
> index 000000000000..f146f4143447
> --- /dev/null
> +++ b/tools/perf/util/arm-spe-pkt-decoder.h
> @@ -0,0 +1,52 @@
> +/*
> + * ARM Statistical Profiling Extensions (SPE) support
> + * Copyright (c) 2017, ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#ifndef INCLUDE__ARM_SPE_PKT_DECODER_H__
> +#define INCLUDE__ARM_SPE_PKT_DECODER_H__
> +
> +#include <stddef.h>
> +#include <stdint.h>
> +
> +#define ARM_SPE_PKT_DESC_MAX 256
> +
> +#define ARM_SPE_NEED_MORE_BYTES -1
> +#define ARM_SPE_BAD_PACKET -2
> +
> +enum arm_spe_pkt_type {
> + ARM_SPE_BAD,
> + ARM_SPE_PAD,
> + ARM_SPE_END,
> + ARM_SPE_TIMESTAMP,
> + ARM_SPE_ADDRESS,
> + ARM_SPE_COUNTER,
> + ARM_SPE_CONTEXT,
> + ARM_SPE_OP_TYPE,
> + ARM_SPE_EVENTS,
> + ARM_SPE_DATA_SOURCE,
> +};
> +
> +struct arm_spe_pkt {
> + enum arm_spe_pkt_type type;
> + unsigned char index;
> + uint64_t payload;
> +};
> +
> +const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
> +
> +int arm_spe_get_packet(const unsigned char *buf, size_t len,
> + struct arm_spe_pkt *packet);
> +
> +int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, size_t len);
> +#endif
> diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
> new file mode 100644
> index 000000000000..67965e26b5b1
> --- /dev/null
> +++ b/tools/perf/util/arm-spe.c
> @@ -0,0 +1,318 @@
> +/*
> + * ARM Statistical Profiling Extensions (SPE) support
> + * Copyright (c) 2017, ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#include <endian.h>
> +#include <errno.h>
> +#include <byteswap.h>
> +#include <inttypes.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/bitops.h>
> +#include <linux/log2.h>
> +
> +#include "cpumap.h"
> +#include "color.h"
> +#include "evsel.h"
> +#include "evlist.h"
> +#include "machine.h"
> +#include "session.h"
> +#include "util.h"
> +#include "thread.h"
> +#include "debug.h"
> +#include "auxtrace.h"
> +#include "arm-spe.h"
> +#include "arm-spe-pkt-decoder.h"
> +
> +struct arm_spe {
> + struct auxtrace auxtrace;
> + struct auxtrace_queues queues;
> + struct auxtrace_heap heap;
> + u32 auxtrace_type;
> + struct perf_session *session;
> + struct machine *machine;
> + u32 pmu_type;
> +};
> +
> +struct arm_spe_queue {
> + struct arm_spe *spe;
> + unsigned int queue_nr;
> + struct auxtrace_buffer *buffer;
> + bool on_heap;
> + bool done;
> + pid_t pid;
> + pid_t tid;
> + int cpu;
> +};
> +
> +static void arm_spe_dump(struct arm_spe *spe __maybe_unused,
> + unsigned char *buf, size_t len)
> +{
> + struct arm_spe_pkt packet;
> + size_t pos = 0;
> + int ret, pkt_len, i;
> + char desc[ARM_SPE_PKT_DESC_MAX];
> + const char *color = PERF_COLOR_BLUE;
> +
> + color_fprintf(stdout, color,
> + ". ... ARM SPE data: size %zu bytes\n",
> + len);
> +
> + while (len) {
> + ret = arm_spe_get_packet(buf, len, &packet);
> + if (ret > 0)
> + pkt_len = ret;
> + else
> + pkt_len = 1;
> + printf(".");
> + color_fprintf(stdout, color, " %08x: ", pos);
> + for (i = 0; i < pkt_len; i++)
> + color_fprintf(stdout, color, " %02x", buf[i]);
> + for (; i < 16; i++)
> + color_fprintf(stdout, color, " ");
> + if (ret > 0) {
> + ret = arm_spe_pkt_desc(&packet, desc,
> + ARM_SPE_PKT_DESC_MAX);
> + if (ret > 0)
> + color_fprintf(stdout, color, " %s\n", desc);
> + } else {
> + color_fprintf(stdout, color, " Bad packet!\n");
> + }
> + pos += pkt_len;
> + buf += pkt_len;
> + len -= pkt_len;
> + }
> +}
> +
> +static void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf,
> + size_t len)
> +{
> + printf(".\n");
> + arm_spe_dump(spe, buf, len);
> +}
> +
> +static struct arm_spe_queue *arm_spe_alloc_queue(struct arm_spe *spe,
> + unsigned int queue_nr)
> +{
> + struct arm_spe_queue *speq;
> +
> + speq = zalloc(sizeof(struct arm_spe_queue));
> + if (!speq)
> + return NULL;
> +
> + speq->spe = spe;
> + speq->queue_nr = queue_nr;
> + speq->pid = -1;
> + speq->tid = -1;
> + speq->cpu = -1;
> +
> + return speq;
> +}
> +
> +static int arm_spe_setup_queue(struct arm_spe *spe,
> + struct auxtrace_queue *queue,
> + unsigned int queue_nr)
> +{
> + struct arm_spe_queue *speq = queue->priv;
> +
> + if (list_empty(&queue->head))
> + return 0;
> +
> + if (!speq) {
> + speq = arm_spe_alloc_queue(spe, queue_nr);
> + if (!speq)
> + return -ENOMEM;
> + queue->priv = speq;
> +
> + if (queue->cpu != -1)
> + speq->cpu = queue->cpu;
> + speq->tid = queue->tid;
> + }
> +
> + if (!speq->on_heap && !speq->buffer) {
> + int ret;
> +
> + speq->buffer = auxtrace_buffer__next(queue, NULL);
> + if (!speq->buffer)
> + return 0;
> +
> + ret = auxtrace_heap__add(&spe->heap, queue_nr,
> + speq->buffer->reference);
> + if (ret)
> + return ret;
> + speq->on_heap = true;
> + }
> +
> + return 0;
> +}
> +
> +static int arm_spe_setup_queues(struct arm_spe *spe)
> +{
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < spe->queues.nr_queues; i++) {
> + ret = arm_spe_setup_queue(spe, &spe->queues.queue_array[i],
> + i);
> + if (ret)
> + return ret;
> + }
> + return 0;
> +}
> +
> +static inline int arm_spe_update_queues(struct arm_spe *spe)
> +{
> + if (spe->queues.new_data) {
> + spe->queues.new_data = false;
> + return arm_spe_setup_queues(spe);
> + }
> + return 0;
> +}
> +
> +static int arm_spe_process_event(struct perf_session *session __maybe_unused,
> + union perf_event *event __maybe_unused,
> + struct perf_sample *sample __maybe_unused,
> + struct perf_tool *tool __maybe_unused)
> +{
> + return 0;
> +}
> +
> +static int arm_spe_process_auxtrace_event(struct perf_session *session,
> + union perf_event *event,
> + struct perf_tool *tool __maybe_unused)
> +{
> + struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
> + auxtrace);
> + struct auxtrace_buffer *buffer;
> + off_t data_offset;
> + int fd = perf_data__fd(session->data);
> + int err;
> +
> + if (perf_data__is_pipe(session->data)) {
> + data_offset = 0;
> + } else {
> + data_offset = lseek(fd, 0, SEEK_CUR);
> + if (data_offset == -1)
> + return -errno;
> + }
> +
> + err = auxtrace_queues__add_event(&spe->queues, session, event,
> + data_offset, &buffer);
> + if (err)
> + return err;
> +
> + /* Dump here now we have copied a piped trace out of the pipe */
> + if (dump_trace) {
> + if (auxtrace_buffer__get_data(buffer, fd)) {
> + arm_spe_dump_event(spe, buffer->data,
> + buffer->size);
> + auxtrace_buffer__put_data(buffer);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int arm_spe_flush(struct perf_session *session __maybe_unused,
> + struct perf_tool *tool __maybe_unused)
> +{
> + return 0;
> +}
> +
> +static void arm_spe_free_queue(void *priv)
> +{
> + struct arm_spe_queue *speq = priv;
> +
> + if (!speq)
> + return;
> + free(speq);
> +}
> +
> +static void arm_spe_free_events(struct perf_session *session)
> +{
> + struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
> + auxtrace);
> + struct auxtrace_queues *queues = &spe->queues;
> + unsigned int i;
> +
> + for (i = 0; i < queues->nr_queues; i++) {
> + arm_spe_free_queue(queues->queue_array[i].priv);
> + queues->queue_array[i].priv = NULL;
> + }
> + auxtrace_queues__free(queues);
> +}
> +
> +static void arm_spe_free(struct perf_session *session)
> +{
> + struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
> + auxtrace);
> +
> + auxtrace_heap__free(&spe->heap);
> + arm_spe_free_events(session);
> + session->auxtrace = NULL;
> + free(spe);
> +}
> +
> +static const char * const arm_spe_info_fmts[] = {
> + [ARM_SPE_PMU_TYPE] = " PMU Type %"PRId64"\n",
> +};
> +
> +static void arm_spe_print_info(u64 *arr)
> +{
> + if (!dump_trace)
> + return;
> +
> + fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]);
> +}
> +
> +int arm_spe_process_auxtrace_info(union perf_event *event,
> + struct perf_session *session)
> +{
> + struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
> + size_t min_sz = sizeof(u64) * ARM_SPE_PMU_TYPE;
> + struct arm_spe *spe;
> + int err;
> +
> + if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) +
> + min_sz)
> + return -EINVAL;
> +
> + spe = zalloc(sizeof(struct arm_spe));
> + if (!spe)
> + return -ENOMEM;
> +
> + err = auxtrace_queues__init(&spe->queues);
> + if (err)
> + goto err_free;
> +
> + spe->session = session;
> + spe->machine = &session->machines.host; /* No kvm support */
> + spe->auxtrace_type = auxtrace_info->type;
> + spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE];
> +
> + spe->auxtrace.process_event = arm_spe_process_event;
> + spe->auxtrace.process_auxtrace_event = arm_spe_process_auxtrace_event;
> + spe->auxtrace.flush_events = arm_spe_flush;
> + spe->auxtrace.free_events = arm_spe_free_events;
> + spe->auxtrace.free = arm_spe_free;
> + session->auxtrace = &spe->auxtrace;
> +
> + arm_spe_print_info(&auxtrace_info->priv[0]);
> +
> + return 0;
> +
> +err_free:
> + free(spe);
> + return err;
> +}
> diff --git a/tools/perf/util/arm-spe.h b/tools/perf/util/arm-spe.h
> new file mode 100644
> index 000000000000..80752b20d850
> --- /dev/null
> +++ b/tools/perf/util/arm-spe.h
> @@ -0,0 +1,42 @@
> +/*
> + * ARM Statistical Profiling Extensions (SPE) support
> + * Copyright (c) 2017, ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#ifndef INCLUDE__PERF_ARM_SPE_H__
> +#define INCLUDE__PERF_ARM_SPE_H__
> +
> +#define ARM_SPE_PMU_NAME "arm_spe_"
> +
> +enum {
> + ARM_SPE_PMU_TYPE,
> + ARM_SPE_PER_CPU_MMAPS,
> + ARM_SPE_AUXTRACE_PRIV_MAX,
> +};
> +
> +#define ARM_SPE_AUXTRACE_PRIV_SIZE (ARM_SPE_AUXTRACE_PRIV_MAX * sizeof(u64))
> +
> +struct auxtrace_record;
> +struct perf_tool;
struct auxtrace_record and struct perf_tool are not used.
> +union perf_event;
> +struct perf_session;
> +struct perf_pmu;
> +
> +struct auxtrace_record *arm_spe_recording_init(int *err,
> + struct perf_pmu *arm_spe_pmu);
> +
> +int arm_spe_process_auxtrace_info(union perf_event *event,
> + struct perf_session *session);
> +
> +struct perf_event_attr *arm_spe_pmu_default_config(struct perf_pmu *arm_spe_pmu);
> +#endif
> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
> index a33491416400..f682f7a58a02 100644
> --- a/tools/perf/util/auxtrace.c
> +++ b/tools/perf/util/auxtrace.c
> @@ -57,6 +57,7 @@
>
> #include "intel-pt.h"
> #include "intel-bts.h"
> +#include "arm-spe.h"
>
> #include "sane_ctype.h"
> #include "symbol/kallsyms.h"
> @@ -913,6 +914,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
> return intel_pt_process_auxtrace_info(event, session);
> case PERF_AUXTRACE_INTEL_BTS:
> return intel_bts_process_auxtrace_info(event, session);
> + case PERF_AUXTRACE_ARM_SPE:
> + return arm_spe_process_auxtrace_info(event, session);
> case PERF_AUXTRACE_CS_ETM:
> case PERF_AUXTRACE_UNKNOWN:
> default:
> diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
> index d19e11b68de7..453c148d2158 100644
> --- a/tools/perf/util/auxtrace.h
> +++ b/tools/perf/util/auxtrace.h
> @@ -43,6 +43,7 @@ enum auxtrace_type {
> PERF_AUXTRACE_INTEL_PT,
> PERF_AUXTRACE_INTEL_BTS,
> PERF_AUXTRACE_CS_ETM,
> + PERF_AUXTRACE_ARM_SPE,
> };
>
> enum itrace_period_type {
>
^ permalink raw reply
* [PATCH] drivers: pwm: pwm-atmel: implement suspend/resume functions
From: Claudiu Beznea @ 2018-01-11 13:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171205090628.GA28700@ulmo>
On 05.12.2017 11:06, Thierry Reding wrote:
> On Tue, Apr 11, 2017 at 11:53:11AM +0200, Boris Brezillon wrote:
>> On Tue, 11 Apr 2017 12:41:59 +0300
>> m18063 <Claudiu.Beznea@microchip.com> wrote:
>>
>>> On 11.04.2017 11:56, Boris Brezillon wrote:
>>>> On Tue, 11 Apr 2017 11:22:39 +0300
>>>> m18063 <Claudiu.Beznea@microchip.com> wrote:
>>>>
>>>>> Hi Boris,
>>>>>
>>>>> On 10.04.2017 17:35, Boris Brezillon wrote:
>>>>>> On Mon, 10 Apr 2017 17:20:20 +0300
>>>>>> Claudiu Beznea <claudiu.beznea@microchip.com> wrote:
>>>>>>
>>>>>>> Implement suspend and resume power management specific
>>>>>>> function to allow PWM controller to correctly suspend
>>>>>>> and resume.
>>>>>>>
>>>>>>> Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
>>>>>>> ---
>>>>>>> drivers/pwm/pwm-atmel.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>> 1 file changed, 81 insertions(+)
>>>>>>>
>>>>>>> diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
>>>>>>> index 530d7dc..75177c6 100644
>>>>>>> --- a/drivers/pwm/pwm-atmel.c
>>>>>>> +++ b/drivers/pwm/pwm-atmel.c
>>>>>>> @@ -58,6 +58,8 @@
>>>>>>> #define PWM_MAX_PRD 0xFFFF
>>>>>>> #define PRD_MAX_PRES 10
>>>>>>>
>>>>>>> +#define PWM_MAX_CH_NUM (4)
>>>>>>> +
>>>>>>> struct atmel_pwm_registers {
>>>>>>> u8 period;
>>>>>>> u8 period_upd;
>>>>>>> @@ -65,11 +67,18 @@ struct atmel_pwm_registers {
>>>>>>> u8 duty_upd;
>>>>>>> };
>>>>>>>
>>>>>>> +struct atmel_pwm_pm_ctx {
>>>>>>> + u32 cmr;
>>>>>>> + u32 cdty;
>>>>>>> + u32 cprd;
>>>>>>> +};
>>>>>>> +
>>>>>>> struct atmel_pwm_chip {
>>>>>>> struct pwm_chip chip;
>>>>>>> struct clk *clk;
>>>>>>> void __iomem *base;
>>>>>>> const struct atmel_pwm_registers *regs;
>>>>>>> + struct atmel_pwm_pm_ctx ctx[PWM_MAX_CH_NUM];
>>>>>>
>>>>>> Hm, I'm pretty sure you can rely on the current PWM state and call
>>>>>> atmel_pwm_apply() at resume time instead of doing that. See what I did
>>>>>> here [1].
>>>>>
>>>>> I agree with the approach you propose but the thing is the atmel_pwm_apply()
>>>>> take care of both, current PWM state and the new state received as argument
>>>>> in order to change only duty factor without disabling the PWM channel (if
>>>>> channel is enabled) and then returns. Changing PWM duty and period and polarity
>>>>> in the same step without disabling + enabling the PWM channel (with atomic
>>>>> approach) may lead to intermediary unwanted output waveforms (the IP doesn't
>>>>> support this for ordinary PWM channels). To take advantage of atmel_pwm_apply()
>>>>> (in the formit is today) in resume() hook might need to first call it to disable
>>>>> channel and then to enable it. Or atmel_pwm_apply() should be changed to also
>>>>> disable + enable the channel when user changes the duty factor at runtime.
>>>>
>>>> Nope. Just save the state at suspend time, implement ->get_state() and
>>>> use it to retrieve the real PWM state when resuming before restoring
>>>> the state you saved during suspend.
>>> Ok.
>>>> But anyway, as Thierry explained, I'm not sure we should take the
>>>> 're-apply PWM state' action here. It's probably better to leave this
>>>> decision to the PWM user.
>>> Do you thinks we should proceed with restoring the registers behind
>>> the re-apply as other drivers does at this moment?
>>
>> Nope. IMO we'd better start patching PWM users to restore the states
>> rather than supporting suspend/resume in all PWM drivers.
>>
>> Thierry, what's your opinion?
>
> I just noticed this thread while cleaning up patchwork. I think I had
> already mentioned in an earlier reply that in my opinion we should leave
> PWM suspend/resume to users.
What about the case where PWM was requested via sysfs?
>
> I'm totally fine if we add helpers to the PWM core to help with that
> task. Maybe something like this would work:
>
> void pwm_suspend(struct pwm_device *pwm)
> {
> pwm_get_state(pwm, &pwm->suspend);
> pwm_disable(pwm);
> }
>
> void pwm_resume(struct pwm_device *pwm)
> {
> pwm_apply_state(pwm, &pwm->suspend);
> }
>
> Though, quite frankly, this is so trivial that drivers could just do
> that themselves. Also, the helpers above aren't flexible at all with
> respect to any special sequences the PWM might need to go through on
> suspend. I suspect that this doesn't matter at all in most cases but
> given how trivial they are we might as well just make drivers do it.
> Also we don't burden users that don't care about suspend/resume with
> the extra suspend state in struct pwm_device.
>
> Thierry
>
^ permalink raw reply
* [PATCH 1/3] arm: spear600: Add missing interrupt-parent of rtc
From: Rob Herring @ 2018-01-11 13:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <a062d9ed0d3365b578156a780202fa533e725374.1515650104.git.viresh.kumar@linaro.org>
On Wed, Jan 10, 2018 at 11:58 PM, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> The interrupt-parent of rtc was missing, add it.
>
> Fixes: 8113ba917dfa ("ARM: SPEAr: DT: Update device nodes")
> Cc: stable at vger.kernel.org # v3.8+
> Reported-by: Arnd Bergmann <arnd@arndb.de>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> ---
> arch/arm/boot/dts/spear600.dtsi | 1 +
> 1 file changed, 1 insertion(+)
For all three patches:
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* [PATCH V6 Resend 00/13] drivers: Boot Constraint core
From: Rob Herring @ 2018-01-11 13:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v66xUJn3KoOZW5d7zcU4BY+ZYJqpyJP1bxC_oir-V2+G=w@mail.gmail.com>
On Wed, Jan 10, 2018 at 8:07 PM, Chen-Yu Tsai <wens@csie.org> wrote:
> On Thu, Jan 11, 2018 at 7:13 AM, Rob Herring <robh+dt@kernel.org> wrote:
>> On Tue, Jan 9, 2018 at 9:47 PM, Viresh Kumar <viresh.kumar@linaro.org> wrote:
>>> Hi Greg,
>>>
>>> I am re-sending V6 as you suggested. There is no change from the patches
>>> sent on 14/15th of December, apart from rebasing on driver-core-next.
>>>
>>> I have tested the Hisilicon patches (again) on hikey 9660 board, IMX
>>> stuff was earlier tested by Sascha (Pengutronix) on i.MX6 and Qualcomm
>>> stuff was earlier tested by Rajendra (Qualcomm) on Dragonboard 410C
>>> (This required some more patches related to display driver which
>>> Rajendra should be sending separately later on).
>>>
>>>
>>> Problem statement:
>>>
>>> Some devices are powered ON by the bootloader before the bootloader
>>> handovers control to Linux. It maybe important for those devices to keep
>>> working until the time a Linux device driver probes the device and
>>> reconfigure its resources.
>>
>> Some devices are powered on by a bootloader, but only a small few have
>> to be maintained thru booting. Most you can just re-initialized.
>>
>>> A typical example of that can be the LCD controller, which is used by
>>> the bootloaders to show image(s) while the platform is booting into
>>> Linux. The LCD controller can be using some resources, like clk,
>>> regulators, etc, that are shared between several devices. These shared
>>> resources should be configured to satisfy need of all the users. If
>>> another device's (X) driver gets probed before the LCD controller driver
>>> in this case, then it may end up disabling or reconfiguring these
>>> resources to ranges satisfying the current users (only device X) and
>>> that can make the LCD screen unstable.
>>
>> We already have simple fb and a binding for it. It only handles clocks
>> I think, but could be extended to other things. I rather not extend
>> it, but it is there already and we don't need different solutions for
>> this.
>
> simplefb also handles regulators. This was added quite a while ago to
> keep LCD displays powered on Allwinner tablets. However in general it
> only grabs references to these resources and enables them so the kernel
> frameworks don't think they are unused and turn them off. It doesn't
> do clock rate or voltage constraints which Viresh wants. It should be
> easy to do for regulators, and AFAIK there is a clock rate protection
> mechanism for the clk framework in the works.
Why do we need constraints beyond taking a reference? The constraint
is don't change things. If it is more complex than that, then you need
something to parse the "real" DT nodes for the h/w blocks.
Rob
^ permalink raw reply
* [PATCH] phy: work around 'phys' references to usb-phy devices
From: Kishon Vijay Abraham I @ 2018-01-11 13:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAK8P3a0F4sK=ou8HXmSktq+0S22juYaCaY48RStDKwk8QGgviQ@mail.gmail.com>
Hi Arnd,
On Thursday 11 January 2018 02:27 AM, Arnd Bergmann wrote:
> On Mon, Jan 8, 2018 at 7:32 PM, Kishon Vijay Abraham I <kishon@ti.com> wrote:
>> Hi Arnd,
>>
>> On Monday 08 January 2018 06:31 PM, Arnd Bergmann wrote:
>>> Stefan Wahren reports a problem with a warning fix that was merged
>>> for v4.15: we had lots of device nodes with a 'phys' property pointing
>>> to a device node that is not compliant with the binding documented in
>>> Documentation/devicetree/bindings/phy/phy-bindings.txt
>>>
>>> This generally works because USB HCD drivers that support both the generic
>>> phy subsystem and the older usb-phy subsystem ignore most errors from
>>> phy_get() and related calls and then use the usb-phy driver instead.
>>>
>>> However, usb_add_hcd() (along with the respective functions in dwc2 and
>>> dwc3) propagate the EPROBE_DEFER return code so we can try again whenever
>>> the driver gets loaded. In case the driver is written for the usb-phy
>>> subsystem (like usb-generic-phy aka usb-nop-xceiv), we will never load
>>> a generic-phy driver for it, and keep failing here.
>>>
>>> There is only a small number of remaining usb-phy drivers that support
>>> device tree, so this adds a workaround by providing a full list of the
>>> potentially affected drivers, and always failing the probe with -ENODEV
>>> here, which is the same behavior that we used to get with incorrect
>>> device tree files. Since we generally want older kernels to also want
>>> to work with the fixed devicetree files, it would be good to backport
>>> the patch into stable kernels as well (3.13+ are possibly affected).
>>> Reverting back to the DTS sources that work would in theory fix USB
>>> support for now, but in the long run we'd run into the same problem
>>> again when the drivers get ported from usb-phy to generic-phy.
>>>
>>> Fixes: 014d6da6cb25 ("ARM: dts: bcm283x: Fix DTC warnings about missing phy-cells")
>>> Link: https://marc.info/?l=linux-usb&m=151518314314753&w=2
>>> Cc: stable at vger.kernel.org
>>> Cc: Stefan Wahren <stefan.wahren@i2se.com>
>>> Cc: Felipe Balbi <balbi@kernel.org>
>>> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>>> ---
>>> This obviously needs to be tested, I wrote this up as a reply to
>>> Stefan's bug report. I'm fairly sure that I covered all usb-phy
>>> driver strings here. My goal is to have a fix merged into 4.15
>>> rather than reverting all the DT fixes.
>>
>> Shouldn't the fix be in phy consumer drivers to not return error if it's able
>> to find the phy either using usb-phy or generic phy?
>
> Stefan has posted a patch to that effect now, but I fear that might be
> a little fragile, in particular this short before the release with the
> regression
> in place.
>
> The main problem is that we'd have to change the generic
> usb_add_hcd() function in addition to dwc2 and dwc3 to ignore
> -EPROBE_DEFER from phy_get() whenever usb_get_phy_dev()
> has already succeeded.
>
> If there is any HCD that relies on usb_add_hcd() to get both the
> usb_phy and the phy structures, and it may need to defer probing
> when the latter one isn't ready yet, that fix would break another
> driver.
hmm.. IMO the better thing right now would be to revert the dt patch which adds
#phy-cells.
We have to see if there are better fixes in order to add #phy-cells warning fix
in stable tree.
Thanks
Kishon
^ permalink raw reply
* [PATCH v5 2/2] media: V3s: Add support for Allwinner CSI.
From: Maxime Ripard @ 2018-01-11 13:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515639966-35902-1-git-send-email-yong.deng@magewell.com>
Hi Yong,
On Thu, Jan 11, 2018 at 11:06:06AM +0800, Yong Deng wrote:
> Allwinner V3s SoC features two CSI module. CSI0 is used for MIPI CSI-2
> interface and CSI1 is used for parallel interface. This is not
> documented in datasheet but by test and guess.
>
> This patch implement a v4l2 framework driver for it.
>
> Currently, the driver only support the parallel interface. MIPI-CSI2,
> ISP's support are not included in this patch.
>
> Signed-off-by: Yong Deng <yong.deng@magewell.com>
I've needed this patch in order to fix a NULL pointer dereference:
http://code.bulix.org/oz6gmb-257359?raw
This is needed because while it's ok to have a NULL pointer to
v4l2_subdev_pad_config when you call the subdev set_fmt with
V4L2_SUBDEV_FORMAT_ACTIVE, it's not with V4L2_SUBDEV_FORMAT_TRY, and
sensors will assume taht it's a valid pointer.
Otherwise,
Tested-by: Maxime Ripard <maxime.ripard@free-electrons.com>
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180111/7f6a1adb/attachment-0001.sig>
^ permalink raw reply
* [PATCH linux dev-4.10 6/6] drivers/hwmon: Add a driver for a generic PECI hwmon
From: Arnd Bergmann @ 2018-01-11 13:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <bdc0375d-c379-6c2e-b350-76741afe151d@linux.intel.com>
On Thu, Jan 11, 2018 at 12:45 AM, Jae Hyun Yoo
<jae.hyun.yoo@linux.intel.com> wrote:
> On 1/10/2018 4:29 AM, Arnd Bergmann wrote:
>>
>> On Tue, Jan 9, 2018 at 11:31 PM, Jae Hyun Yoo
>> <jae.hyun.yoo@linux.intel.com> wrote:
>>>
>>> This commit adds driver implementation for a generic PECI hwmon.
>>>
>>> Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
>>
>>
>>> +static int xfer_peci_msg(int cmd, void *pmsg)
>>> +{
>>> + int rc;
>>> +
>>> + mutex_lock(&peci_hwmon_lock);
>>> + rc = peci_ioctl(NULL, cmd, (unsigned long)pmsg);
>>> + mutex_unlock(&peci_hwmon_lock);
>>> +
>>> + return rc;
>>> +}
>>
>>
>> I said earlier that peci_ioctl() looked unused, that was obviously
>> wrong, but what you have here
>> is not a proper way to abstract a bus.
>>
>> Maybe this can be done more like an i2c bus: make the peci controller
>> a bus device
>> and register all known target/index pairs as devices with the peci bus
>> type, and have
>> them probed from DT. The driver can then bind to each of those
>> individually.
>> Not sure if that is getting to granular at that point, I'd have to
>> understand better
>> how it is expected to get used, and what the variances are between
>> implementations.
>>
>
> Thanks for sharing your opinion. In fact, this was also suggested by openbmc
> community so I should consider of redesigning it. I'm currently thinking
> about adding a new PECI device class as an abstract layer and any BMC
> chipset specific driver could be attached to the PECI class driver. Then,
> each CPU client could be registered as an individual device as you
> suggested. Will consider your suggestion.
Another idea might be to pretend that PECI was I2C. We already have a few
drivers for hardware that is not I2C but whose software interface looks
similar enough that it just works. No idea if that is the case for PECI, but
xfer_peci_msg might be close enough to i2c_xfer to make it work. If you
are able to do that, then the PECI controller would just register itself
as an i2c controller and it can be accessed using /dev/i2c from user space
or a high-level i2c_driver.
Arnd
^ permalink raw reply
* [linux-sunxi] [PATCH 1/7] pinctrl: sunxi: add support for pin controllers without bus gate
From: Icenowy Zheng @ 2018-01-11 13:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <ef82983f-6f91-46c2-1f67-7d4efc10c905@arm.com>
? 2018?1?11? GMT+08:00 ??7:48:40, Andre Przywara <andre.przywara@arm.com> ??:
>Hi,
>
>another take to avoid this patch at all, I just remembered this from an
>IRC discussion before:
>
>On 06/01/18 04:23, Icenowy Zheng wrote:
>> The Allwinner H6 pin controllers (both the main one and the CPUs one)
>> have no bus gate clocks.
>
>I don't think this is true. The pin controller *needs* an APB clock,
>it's just not gate-able or not exposed or documented.
>The "system bus tree" on page 90 in the manual shows that the "GPIO"
>block is located on the APB1 bus.
>So can't we just reference this apb clock directly? That would be much
>cleaner, "more" correct and require less changes: "The best patch is no
>patch":
I can accept this. (In fact I have considered this, but
I don't dare to directly use bus clock in a device, as it's not
exported before.
Maxime, Chen-Yu, can you agree the following code?
>
> clocks = <&ccu APB1>, <&osc24M>, <&osc32k>;
> /* or whatever this APB clock is actually called. */
> clock-names = "apb", "hosc", "losc";
>
>Cheers,
>Andre.
>
>>
>> Add support for this kind of pin controllers.
>>
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> ---
>> drivers/pinctrl/sunxi/pinctrl-sunxi.c | 30
>++++++++++++++++++++----------
>> drivers/pinctrl/sunxi/pinctrl-sunxi.h | 1 +
>> 2 files changed, 21 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> index 4b6cb25bc796..68cd505679d9 100644
>> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> @@ -1182,7 +1182,12 @@ static int sunxi_pinctrl_setup_debounce(struct
>sunxi_pinctrl *pctl,
>> unsigned int hosc_div, losc_div;
>> struct clk *hosc, *losc;
>> u8 div, src;
>> - int i, ret;
>> + int i, ret, clk_count;
>> +
>> + if (pctl->desc->without_bus_gate)
>> + clk_count = 2;
>> + else
>> + clk_count = 3;
>>
>> /* Deal with old DTs that didn't have the oscillators */
>> if (of_count_phandle_with_args(node, "clocks", "#clock-cells") !=
>3)
>> @@ -1360,15 +1365,19 @@ int sunxi_pinctrl_init_with_variant(struct
>platform_device *pdev,
>> goto gpiochip_error;
>> }
>>
>> - clk = devm_clk_get(&pdev->dev, NULL);
>> - if (IS_ERR(clk)) {
>> - ret = PTR_ERR(clk);
>> - goto gpiochip_error;
>> - }
>> + if (!desc->without_bus_gate) {
>> + clk = devm_clk_get(&pdev->dev, NULL);
>> + if (IS_ERR(clk)) {
>> + ret = PTR_ERR(clk);
>> + goto gpiochip_error;
>> + }
>>
>> - ret = clk_prepare_enable(clk);
>> - if (ret)
>> - goto gpiochip_error;
>> + ret = clk_prepare_enable(clk);
>> + if (ret)
>> + goto gpiochip_error;
>> + } else {
>> + clk = NULL;
>> + }
>>
>> pctl->irq = devm_kcalloc(&pdev->dev,
>> pctl->desc->irq_banks,
>> @@ -1425,7 +1434,8 @@ int sunxi_pinctrl_init_with_variant(struct
>platform_device *pdev,
>> return 0;
>>
>> clk_error:
>> - clk_disable_unprepare(clk);
>> + if (clk)
>> + clk_disable_unprepare(clk);
>> gpiochip_error:
>> gpiochip_remove(pctl->chip);
>> return ret;
>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
>b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
>> index 11b128f54ed2..ccb6230f0bb5 100644
>> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
>> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
>> @@ -113,6 +113,7 @@ struct sunxi_pinctrl_desc {
>> unsigned irq_bank_base;
>> bool irq_read_needs_mux;
>> bool disable_strict_mode;
>> + bool without_bus_gate;
>> };
>>
>> struct sunxi_pinctrl_function {
>>
>
>_______________________________________________
>linux-arm-kernel mailing list
>linux-arm-kernel at lists.infradead.org
>http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v1 4/4] ARM: dts: add pwm node for r40.
From: Maxime Ripard @ 2018-01-11 12:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180111113412.GA22008@arx-s1>
Hi,
On Thu, Jan 11, 2018 at 07:34:12PM +0800, hao_zhang wrote:
> This patch add pwm node for r40.
>
> Signed-off-by: hao_zhang <hao5781286@gmail.com>
> ---
> arch/arm/boot/dts/sun8i-r40.dtsi | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
> index 173dcc1..84c963c 100644
> --- a/arch/arm/boot/dts/sun8i-r40.dtsi
> +++ b/arch/arm/boot/dts/sun8i-r40.dtsi
> @@ -295,6 +295,11 @@
> bias-pull-up;
> };
>
> + pwm_pins: pwm-pins {
> + pins = "PB2", "PB3";
> + function = "pwm";
> + };
> +
Is it the only combination of pins that is usable?
If so, you can add the pinctrl-0 property directly in the pwm nodes.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180111/42ba49ea/attachment.sig>
^ permalink raw reply
* [PATCH v1 3/4] ARM: dts: add pwm pins for r40.
From: Maxime Ripard @ 2018-01-11 12:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180111113323.GA21976@arx-s1>
Hi,
On Thu, Jan 11, 2018 at 07:33:23PM +0800, hao_zhang wrote:
> This patch add pwm pins for r40.
>
> Signed-off-by: hao_zhang <hao5781286@gmail.com>
You should order your patches differently. We try to be as bisectable
as possible, and if we just apply this patch the DT will not compile
anymore.
Your patch 4 should come before this one.
Your commit title and log doesn't seem to match the content of the
patch either.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180111/48365930/attachment.sig>
^ permalink raw reply
* [PATCH v1 2/4] ARM: PWM: add allwinner sun8i R40/V40/T3 pwm support.
From: Maxime Ripard @ 2018-01-11 12:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180111113241.GA21953@arx-s1>
Hi,
On Thu, Jan 11, 2018 at 07:32:41PM +0800, hao_zhang wrote:
> This patch add allwinner sun8i R40/V40/T3 pwm support.
>
> Signed-off-by: hao_zhang <hao5781286@gmail.com>
I don't really know the PWM framework, so I'll obviously leave that
part to Thierry, but the DT and probe parts look ok.
You have a number of issues with checkpatch though still, please run
./scripts/checkpatch.pl --strict, and once all the issues have been
fixed:
Reviewed-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180111/75846209/attachment.sig>
^ permalink raw reply
* [PATCH v5 01/44] dt-bindings: clock: Add new bindings for TI Davinci PLL clocks
From: Adam Ford @ 2018-01-11 12:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <fd162516-cddc-e857-ce60-2cd89303971e@lechnology.com>
On Wed, Jan 10, 2018 at 8:50 PM, David Lechner <david@lechnology.com> wrote:
> On 01/10/2018 04:24 PM, Adam Ford wrote:
>>
>>
>> I am available tomorrow to build and test patches against the
>> da850-evm. I just need to know which version(s) to test.
>
>
> Great. As per the cover letter:
>
> You can find a working branch with everything included in the
> "common-clk-v5"
> branch of https://github.com/dlech/ev3dev-kernel.git.
I wasn't sure if things had changed after some of the dialog about the
bindings and device tree.
Here is my log with DEBUG_LL and CONFIG_EARLY_PRINTK set :
Starting kernel ...
Uncompressing Linux... done, booting the kernel.
Booting Linux on physical CPU 0x0
Linux version 4.15.0-rc4-g8564e0f (aford at ubuntu16) (gcc version 7.2.0
(Buildroot 2017.11.1-00021-g7b43660)) #2 PREEMPT Thu Jan 11 06:35:29
CST 2018
CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=0005317f
CPU: VIVT data cache, VIVT instruction cache
OF: fdt: Machine model: DA850/AM1808/OMAP-L138 EVM
Memory policy: Data cache writethrough
cma: Reserved 16 MiB at 0xc2c00000
DaVinci da850/omap-l138 variant 0x0
random: fast init done
Built 1 zonelists, mobility grouping on. Total pages: 16256
Kernel command line: console=ttyS2,115200n8 root=PARTUUID= rw
rootfstype=ext4 rootwait
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 42164K/65536K available (4548K kernel code, 280K rwdata, 1044K
rodata, 232K init, 143K bss, 6988K reserved, 16384K cma-reserved)
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
fixmap : 0xffc00000 - 0xfff00000 (3072 kB)
vmalloc : 0xc4800000 - 0xff800000 ( 944 MB)
lowmem : 0xc0000000 - 0xc4000000 ( 64 MB)
modules : 0xbf000000 - 0xc0000000 ( 16 MB)
.text : 0x(ptrval) - 0x(ptrval) (4550 kB)
.init : 0x(ptrval) - 0x(ptrval) ( 232 kB)
.data : 0x(ptrval) - 0x(ptrval) ( 281 kB)
.bss : 0x(ptrval) - 0x(ptrval) ( 144 kB)
SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
Preemptible hierarchical RCU implementation.
Tasks RCU enabled.
NR_IRQS: 245
clocksource: timer0_1: mask: 0xffffffff max_cycles: 0xffffffff,
max_idle_ns: 79635851949 ns
sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every
89478484971ns
Console: colour dummy device 80x30
Calibrating delay loop... 148.88 BogoMIPS (lpj=744448)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
CPU: Testing write buffer coherency: ok
Setting up static identity map for 0xc0008400 - 0xc0008458
Hierarchical SRCU implementation.
devtmpfs: initialized
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff,
max_idle_ns: 19112604462750000 ns
futex hash table entries: 256 (order: -1, 3072 bytes)
pinctrl core: initialized pinctrl subsystem
NET: Registered protocol family 16
DMA: preallocated 256 KiB pool for atomic coherent allocations
cpuidle: using governor menu
mux: initialized RTC_ALARM
mux: Setting register RTC_ALARM
mux: PINMUX0 (0x00000000) = 0x44080000 -> 0x24080000
edma 1c00000.edma: memcpy is disabled
edma 1c00000.edma: TI EDMA DMA engine driver
edma 1e30000.edma: memcpy is disabled
edma 1e30000.edma: TI EDMA DMA engine driver
i2c_davinci 1c22000.i2c: could not find pctldev for node
/soc at 1c00000/pinmux at 14120/pinmux_i2c0_pins, deferring probe
clocksource: Switched to clocksource timer0_1
NET: Registered protocol family 2
TCP established hash table entries: 1024 (order: 0, 4096 bytes)
TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
UDP hash table entries: 256 (order: 0, 4096 bytes)
UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
Initialise system trusted keyrings
workingset: timestamp_bits=30 max_order=14 bucket_order=0
Key type asymmetric registered
Asymmetric key parser 'x509' registered
Block layer SCSI generic (bsg) driver version 0.4 loaded (major 251)
io scheduler noop registered (default)
io scheduler mq-deadline registered
io scheduler kyber registered
pinctrl-single 1c14120.pinmux: 160 pins at pa fdfe34a6 size 80
Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled
1c42000.serial: ttyS0 at MMIO 0x1c42000 (irq = 25, base_baud =
9375000) is a TI DA8xx/66AK2x
1d0c000.serial: ttyS1 at MMIO 0x1d0c000 (irq = 53, base_baud =
8250000) is a TI DA8xx/66AK2x
1d0d000.serial: ttyS2 at MMIO 0x1d0d000 (irq = 61, base_baud =
8250000) is a TI DA8xx/66AK2x
console [ttyS2] enabled
brd: module loaded
libphy: Fixed MDIO Bus: probed
davinci_mdio 1e24000.mdio: failed to get device clock
davinci_mdio: probe of 1e24000.mdio failed with error -2
i2c /dev entries driver
davinci_mmc 1c40000.mmc: Using DMA, 4-bit mode
NET: Registered protocol family 10
Segment Routing with IPv6
sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
NET: Registered protocol family 17
Loading compiled-in X.509 certificates
mmc0: host does not support reading read-only switch, assuming
write-enable
mmc0: new high speed SDHC card at address b368
mmcblk0: mmc0:b368 00000 3.75 GiB
mmcblk0: p1 p2
pca953x 0-0020: 0-0020 supply vcc not found, using dummy regulator
pca953x 0-0020: failed reading register
pca953x: probe of 0-0020 failed with error -121
console [netcon0] enabled
netconsole: network logging started
davinci_emac 1e20000.ethernet: incompatible machine/device type for
reading mac address
hctosys: unable to open rtc device (rtc0)
>
^ 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