Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [QUESTION] Arm64: Query L3 cache info via DT
From: Tan Xiaojun @ 2017-01-10 10:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <536f64cc-357c-40a1-b2a0-1db0c4280fc0@arm.com>

On 2017/1/10 18:01, Sudeep Holla wrote:
> 
> 
> On 10/01/17 08:50, Tan Xiaojun wrote:
>> I add this patch, and test in Hisilicon D02/D03. It can work well.
>>
>> I'm sorry to reply so late. I took some time to debug, because I am not familiar with the code.
>>
>>> +	if (level < of_level) {
>>> +		/*
>>> +		 * some external caches not specified in CLIDR_EL1
>>> +		 * the information may be available in the device tree
>>> +		 * only unified external caches are considered here
>>> +		 */
>>> +		level = of_level;
>>> +		leaves += (of_level - level);
>>
>> The above two lines need to exchange the location.
>>
> 
> Ah crap, sorry for such a silly mistake.
> I will post proper patch(es) soon.
> 

OK. Wait for your new patch. ^_^

Thanks.
Xiaojun.

^ permalink raw reply

* [PATCH v4 8/9] ARM: dts: stm32f4: Add external I2S clock
From: Alexandre Torgue @ 2017-01-10 10:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481638820-29324-9-git-send-email-gabriel.fernandez@st.com>

Hi

On 12/13/2016 03:20 PM, Gabriel FERNANDEZ wrote:
> From: Gabriel Fernandez <gabriel.fernandez@st.com>
>
> This patch adds an external I2S clock in the DT.
> The I2S clock could be derived from an external I2S clock or by I2S pll.
>
> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
> ---
>  arch/arm/boot/dts/stm32f429.dtsi | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index e4dae0e..7c7dfbd 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -68,6 +68,12 @@
>  			compatible = "fixed-clock";
>  			clock-frequency = <32000>;
>  		};
> +
> +		clk_i2s_ckin: i2s-ckin {
> +			#clock-cells = <0>;
> +			compatible = "fixed-clock";
> +			clock-frequency = <0>;
> +		};
>  	};
>
>  	soc {
> @@ -362,7 +368,7 @@
>  			#clock-cells = <2>;
>  			compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
>  			reg = <0x40023800 0x400>;
> -			clocks = <&clk_hse>;
> +			clocks = <&clk_hse>, <&clk_i2s_ckin>;
>  			st,syscfg = <&pwrcfg>;
>  		};
>
>
Applied on stm32-dt-for-v4.11

Thanks

^ permalink raw reply

* [PATCH v4 9/9] ARM: dts: stm32f4: Include auxiliary stm32fx clock definition
From: Alexandre Torgue @ 2017-01-10 10:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481638820-29324-10-git-send-email-gabriel.fernandez@st.com>

hi

On 12/13/2016 03:20 PM, Gabriel FERNANDEZ wrote:
> From: Gabriel Fernandez <gabriel.fernandez@st.com>
>
> This patch include auxiliary clock definition (clocks which are not derived
> from system clock.
>
> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
> ---
>  arch/arm/boot/dts/stm32f429.dtsi | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index 7c7dfbd..041e3fc 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -48,6 +48,7 @@
>  #include "skeleton.dtsi"
>  #include "armv7-m.dtsi"
>  #include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
> +#include <dt-bindings/clock/stm32fx-clock.h>
>
>  / {
>  	clocks {
>
Applied on stm32-dt-for-v4.11

Thanks

^ permalink raw reply

* NVMe vs DMA addressing limitations
From: Arnd Bergmann @ 2017-01-10 11:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <c4fd007c-3f07-fc2a-8cbb-7152f578609d@cogentembedded.com>

On Tuesday, January 10, 2017 10:31:47 AM CET Nikita Yushchenko wrote:
> Christoph, thanks for clear input.
> 
> Arnd, I think that given this discussion, best short-term solution is
> indeed the patch I've submitted yesterday. That is, your version +
> coherent mask support.  With that, set_dma_mask(DMA_BIT_MASK(64)) will
> succeed and hardware with work with swiotlb.

Ok, good.

> Possible next step is to teach swiotlb to dynamically allocate bounce
> buffers within entire arm64's ZONE_DMA.

That seems reasonable, yes. We probably have to do both, as there are
cases where a device has dma_mask smaller than ZONE_DMA but the swiotlb
bounce area is low enough to work anyway.

Another workaround me might need is to limit amount of concurrent DMA
in the NVMe driver based on some platform quirk. The way that NVMe works,
it can have very large amounts of data that is concurrently mapped into
the device. SWIOTLB is one case where this currently fails, but another
example would be old PowerPC servers that have a 256MB window of virtual
I/O addresses per VM guest in their IOMMU. Those will likely fail the same
way that your does.

> Also there is some hope that R-Car *can* iommu-translate addresses that
> PCIe module issues to system bus.  Although previous attempts to make
> that working failed. Additional research is needed here.

Does this IOMMU support remapping data within a virtual machine? I believe
there are some that only do one of the two -- either you can have guest
machines with DMA access to their low memory, or you can remap data on
the fly in the host.

	Arnd

^ permalink raw reply

* [PATCH v2 2/2] media: rc: add driver for IR remote receiver on MT7623 SoC
From: Sean Young @ 2017-01-10 11:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484039631-25120-3-git-send-email-sean.wang@mediatek.com>

Hi Sean

Some more review comments. 

On Tue, Jan 10, 2017 at 05:13:51PM +0800, sean.wang at mediatek.com wrote:
> From: Sean Wang <sean.wang@mediatek.com>
> 
> This patch adds driver for IR controller on MT7623 SoC.
> and should also work on similar Mediatek SoC. Currently
> testing successfully on NEC and SONY remote controller
> only but it should work on others (lirc, rc-5 and rc-6).
> 
> Signed-off-by: Sean Wang <sean.wang@mediatek.com>
> Reviewed-by: Sean Young <sean@mess.org>
> ---
>  drivers/media/rc/Kconfig   |  11 ++
>  drivers/media/rc/Makefile  |   1 +
>  drivers/media/rc/mtk-cir.c | 326 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 338 insertions(+)
>  create mode 100644 drivers/media/rc/mtk-cir.c
> 
> diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
> index 629e8ca..9228479 100644
> --- a/drivers/media/rc/Kconfig
> +++ b/drivers/media/rc/Kconfig
> @@ -235,6 +235,17 @@ config IR_MESON
>  	   To compile this driver as a module, choose M here: the
>  	   module will be called meson-ir.
>  
> +config IR_MTK
> +	tristate "Mediatek IR remote receiver"
> +	depends on RC_CORE
> +	depends on ARCH_MEDIATEK || COMPILE_TEST
> +	---help---
> +	   Say Y if you want to use the IR remote receiver available
> +	   on Mediatek SoCs.
> +
> +	   To compile this driver as a module, choose M here: the
> +	   module will be called mtk-cir.
> +
>  config IR_NUVOTON
>  	tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
>  	depends on PNP
> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
> index 3a984ee..a78570b 100644
> --- a/drivers/media/rc/Makefile
> +++ b/drivers/media/rc/Makefile
> @@ -38,3 +38,4 @@ obj-$(CONFIG_RC_ST) += st_rc.o
>  obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o
>  obj-$(CONFIG_IR_IMG) += img-ir/
>  obj-$(CONFIG_IR_SERIAL) += serial_ir.o
> +obj-$(CONFIG_IR_MTK) += mtk-cir.o
> diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c
> new file mode 100644
> index 0000000..f752f63
> --- /dev/null
> +++ b/drivers/media/rc/mtk-cir.c
> @@ -0,0 +1,326 @@
> +/*
> + * Driver for Mediatek IR Receiver Controller
> + *
> + * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that 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 <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/reset.h>
> +#include <media/rc-core.h>
> +
> +#define MTK_IR_DEV KBUILD_MODNAME

You could remove this #define and just use KBUILD_MODNAME 
> +
> +/* Register to enable PWM and IR */
> +#define MTK_CONFIG_HIGH_REG       0x0c
> +/* Enable IR pulse width detection */
> +#define MTK_PWM_EN		  BIT(13)
> +/* Enable IR hardware function */
> +#define MTK_IR_EN		  BIT(0)
> +
> +/* Register to setting sample period */
> +#define MTK_CONFIG_LOW_REG        0x10
> +/* Field to set sample period */
> +#define CHK_PERIOD		  DIV_ROUND_CLOSEST(MTK_IR_SAMPLE,  \
> +						    MTK_IR_CLK_PERIOD)
> +#define MTK_CHK_PERIOD            (((CHK_PERIOD) << 8) & (GENMASK(20, 8)))
> +#define MTK_CHK_PERIOD_MASK	  (GENMASK(20, 8))
> +
> +/* Register to clear state of state machine */
> +#define MTK_IRCLR_REG             0x20
> +/* Bit to restart IR receiving */
> +#define MTK_IRCLR		  BIT(0)
> +
> +/* Register containing pulse width data */
> +#define MTK_CHKDATA_REG(i)        (0x88 + 4 * (i))
> +#define MTK_WIDTH_MASK		  (GENMASK(7, 0))
> +
> +/* Register to enable IR interrupt */
> +#define MTK_IRINT_EN_REG          0xcc
> +/* Bit to enable interrupt */
> +#define MTK_IRINT_EN		  BIT(0)
> +
> +/* Register to ack IR interrupt */
> +#define MTK_IRINT_CLR_REG         0xd0
> +/* Bit to clear interrupt status */
> +#define MTK_IRINT_CLR		  BIT(0)
> +
> +/* Maximum count of samples */
> +#define MTK_MAX_SAMPLES		  0xff
> +/* Indicate the end of IR message */
> +#define MTK_IR_END(v, p)	  ((v) == MTK_MAX_SAMPLES && (p) == 0)
> +/* Number of registers to record the pulse width */
> +#define MTK_CHKDATA_SZ		  17
> +/* Source clock frequency */
> +#define MTK_IR_BASE_CLK		  273000000
> +/* Frequency after IR internal divider */
> +#define MTK_IR_CLK_FREQ		  (MTK_IR_BASE_CLK / 4)
> +/* Period for MTK_IR_CLK in ns*/
> +#define MTK_IR_CLK_PERIOD	  DIV_ROUND_CLOSEST(1000000000ul,  \
> +						    MTK_IR_CLK_FREQ)
> +/* Sample period in ns */
> +#define MTK_IR_SAMPLE		  (MTK_IR_CLK_PERIOD * 0xc00)
> +
> +/* struct mtk_ir -	This is the main datasructure for holding the state
> + *			of the driver
> + * @dev:		The device pointer
> + * @rc:			The rc instrance
> + * @irq:		The IRQ that we are using
> + * @base:		The mapped register i/o base
> + * @clk:		The clock that we are using
> + */
> +struct mtk_ir {
> +	struct device	*dev;
> +	struct rc_dev	*rc;
> +	void __iomem	*base;
> +	int		irq;
> +	struct clk	*clk;
> +};
> +
> +static void mtk_w32_mask(struct mtk_ir *ir, u32 val, u32 mask, unsigned int reg)
> +{
> +	u32 tmp;
> +
> +	tmp = __raw_readl(ir->base + reg);
> +	tmp = (tmp & ~mask) | val;
> +	__raw_writel(tmp, ir->base + reg);
> +}
> +
> +static void mtk_w32(struct mtk_ir *ir, u32 val, unsigned int reg)
> +{
> +	__raw_writel(val, ir->base + reg);
> +}
> +
> +static u32 mtk_r32(struct mtk_ir *ir, unsigned int reg)
> +{
> +	return __raw_readl(ir->base + reg);
> +}
> +
> +static inline void mtk_irq_disable(struct mtk_ir *ir, u32 mask)
> +{
> +	u32 val;
> +
> +	val = mtk_r32(ir, MTK_IRINT_EN_REG);
> +	mtk_w32(ir, val & ~mask, MTK_IRINT_EN_REG);
> +}
> +
> +static inline void mtk_irq_enable(struct mtk_ir *ir, u32 mask)
> +{
> +	u32 val;
> +
> +	val = mtk_r32(ir, MTK_IRINT_EN_REG);
> +	mtk_w32(ir, val | mask, MTK_IRINT_EN_REG);
> +}
> +
> +static irqreturn_t mtk_ir_irq(int irqno, void *dev_id)
> +{
> +	struct mtk_ir *ir = dev_id;
> +	u8  wid = 0;
> +	u32 i, j, val;
> +	DEFINE_IR_RAW_EVENT(rawir);
> +
> +	mtk_irq_disable(ir, MTK_IRINT_EN);

The kernel guarantees that calls to the interrupt handler are serialised,
no need to disable the interrupt in the handler.

> +
> +	/* Reset decoder state machine */
> +	ir_raw_event_reset(ir->rc);

Not needed.

> +
> +	/* First message must be pulse */
> +	rawir.pulse = false;

pulse = true?

> +
> +	/* Handle all pulse and space IR controller captures */
> +	for (i = 0 ; i < MTK_CHKDATA_SZ ; i++) {
> +		val = mtk_r32(ir, MTK_CHKDATA_REG(i));
> +		dev_dbg(ir->dev, "@reg%d=0x%08x\n", i, val);
> +
> +		for (j = 0 ; j < 4 ; j++) {
> +			wid = (val & (MTK_WIDTH_MASK << j * 8)) >> j * 8;
> +			rawir.pulse = !rawir.pulse;
> +			rawir.duration = wid * (MTK_IR_SAMPLE + 1);
> +			ir_raw_event_store_with_filter(ir->rc, &rawir);
> +		}

In v1 you would break out of the loop if the ir message was shorter, but
now you are always passing on 68 pulses and spaces. Is that right?

> +	}
> +
> +	/* The maximum number of edges the IR controller can
> +	 * hold is MTK_CHKDATA_SZ * 4. So if received IR messages
> +	 * is over the limit, the last incomplete IR message would
> +	 * be appended trailing space and still would be sent into
> +	 * ir-rc-raw to decode. That helps it is possible that it
> +	 * has enough information to decode a scancode even if the
> +	 * trailing end of the message is missing.
> +	 */
> +	if (!MTK_IR_END(wid, rawir.pulse)) {
> +		rawir.pulse = false;
> +		rawir.duration = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1);
> +		ir_raw_event_store_with_filter(ir->rc, &rawir);
> +	}
> +
> +	ir_raw_event_handle(ir->rc);
> +
> +	/* Restart controller for the next receive */
> +	mtk_w32_mask(ir, 0x1, MTK_IRCLR, MTK_IRCLR_REG);
> +
> +	/* Clear interrupt status */
> +	mtk_w32_mask(ir, 0x1, MTK_IRINT_CLR, MTK_IRINT_CLR_REG);
> +
> +	/* Enable interrupt */
> +	mtk_irq_enable(ir, MTK_IRINT_EN);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int mtk_ir_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *dn = dev->of_node;
> +	struct resource *res;
> +	struct mtk_ir *ir;
> +	u32 val;
> +	int ret = 0;
> +	const char *map_name;
> +
> +	ir = devm_kzalloc(dev, sizeof(struct mtk_ir), GFP_KERNEL);
> +	if (!ir)
> +		return -ENOMEM;
> +
> +	ir->dev = dev;
> +
> +	if (!of_device_is_compatible(dn, "mediatek,mt7623-cir"))
> +		return -ENODEV;
> +
> +	ir->clk = devm_clk_get(dev, "clk");
> +	if (IS_ERR(ir->clk)) {
> +		dev_err(dev, "failed to get a ir clock.\n");
> +		return PTR_ERR(ir->clk);
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	ir->base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(ir->base)) {
> +		dev_err(dev, "failed to map registers\n");
> +		return PTR_ERR(ir->base);
> +	}
> +
> +	ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW);
> +	if (!ir->rc) {
> +		dev_err(dev, "failed to allocate device\n");
> +		return -ENOMEM;
> +	}
> +
> +	ir->rc->priv = ir;
> +	ir->rc->input_name = MTK_IR_DEV;
> +	ir->rc->input_phys = MTK_IR_DEV "/input0";
> +	ir->rc->input_id.bustype = BUS_HOST;
> +	ir->rc->input_id.vendor = 0x0001;
> +	ir->rc->input_id.product = 0x0001;
> +	ir->rc->input_id.version = 0x0001;
> +	map_name = of_get_property(dn, "linux,rc-map-name", NULL);
> +	ir->rc->map_name = map_name ?: RC_MAP_EMPTY;
> +	ir->rc->dev.parent = dev;
> +	ir->rc->driver_name = MTK_IR_DEV;
> +	ir->rc->allowed_protocols = RC_BIT_ALL;
> +	ir->rc->rx_resolution = MTK_IR_SAMPLE;
> +	ir->rc->timeout = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1);
> +
> +	ret = devm_rc_register_device(dev, ir->rc);

Here you do devm_rc_register_device()

> +	if (ret) {
> +		dev_err(dev, "failed to register rc device\n");
> +		return ret;
> +	}
> +
> +	platform_set_drvdata(pdev, ir);
> +
> +	ir->irq = platform_get_irq(pdev, 0);
> +	if (ir->irq < 0) {
> +		dev_err(dev, "no irq resource\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Enable interrupt after proper hardware
> +	 * setup and IRQ handler registration
> +	 */
> +	if (clk_prepare_enable(ir->clk)) {
> +		dev_err(dev, "try to enable ir_clk failed\n");
> +		ret = -EINVAL;
> +		goto exit_clkdisable_clk;
> +	}
> +
> +	mtk_irq_disable(ir, MTK_IRINT_EN);
> +
> +	ret = devm_request_irq(dev, ir->irq, mtk_ir_irq, 0, MTK_IR_DEV, ir);
> +	if (ret) {
> +		dev_err(dev, "failed request irq\n");
> +		goto exit_clkdisable_clk;
> +	}
> +
> +	/* Enable IR and PWM */
> +	val = mtk_r32(ir, MTK_CONFIG_HIGH_REG);
> +	val |= MTK_PWM_EN | MTK_IR_EN;
> +	mtk_w32(ir, val, MTK_CONFIG_HIGH_REG);
> +
> +	/* Setting sample period */
> +	mtk_w32_mask(ir, MTK_CHK_PERIOD, MTK_CHK_PERIOD_MASK,
> +		     MTK_CONFIG_LOW_REG);
> +
> +	mtk_irq_enable(ir, MTK_IRINT_EN);
> +
> +	dev_info(dev, "Initialized MT7623 IR driver, sample period = %luus\n",
> +		 DIV_ROUND_CLOSEST(MTK_IR_SAMPLE, 1000));
> +
> +	return 0;
> +
> +exit_clkdisable_clk:
> +	clk_disable_unprepare(ir->clk);
> +
> +	return ret;
> +}
> +
> +static int mtk_ir_remove(struct platform_device *pdev)
> +{
> +	struct mtk_ir *ir = platform_get_drvdata(pdev);
> +
> +	/* Avoid contention between remove handler and
> +	 * IRQ handler so that disabling IR interrupt and
> +	 * waiting for pending IRQ handler to complete
> +	 */
> +	mtk_irq_disable(ir, MTK_IRINT_EN);
> +	synchronize_irq(ir->irq);
> +
> +	clk_disable_unprepare(ir->clk);
> +
> +	rc_unregister_device(ir->rc);

Yet here you explicitly call rc_unregister_device(). Since it was registered
with the devm call, this call is not needed and will lead to double frees etc

> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mtk_ir_match[] = {
> +	{ .compatible = "mediatek,mt7623-cir" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, mtk_ir_match);
> +
> +static struct platform_driver mtk_ir_driver = {
> +	.probe          = mtk_ir_probe,
> +	.remove         = mtk_ir_remove,
> +	.driver = {
> +		.name = MTK_IR_DEV,
> +		.of_match_table = mtk_ir_match,
> +	},
> +};
> +
> +module_platform_driver(mtk_ir_driver);
> +
> +MODULE_DESCRIPTION("Mediatek IR Receiver Controller Driver");
> +MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
> +MODULE_LICENSE("GPL");
> -- 
> 2.7.4
> 

^ permalink raw reply

* [PATCH v29 9/9] Documentation: dt: chosen properties for arm64 kdump
From: Will Deacon @ 2017-01-10 11:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161228043734.27535-1-takahiro.akashi@linaro.org>

Hi James, Akashi,

On Wed, Dec 28, 2016 at 01:37:34PM +0900, AKASHI Takahiro wrote:
> From: James Morse <james.morse@arm.com>
> 
> Add documentation for
> 	linux,crashkernel-base and crashkernel-size,
> 	linux,usable-memory-range
> 	linux,elfcorehdr
> used by arm64 kdump to decribe the kdump reserved area, and
> the elfcorehdr's location within it.
> 
> Signed-off-by: James Morse <james.morse@arm.com>
> [takahiro.akashi at linaro.org: added "linux,crashkernel-base" and "-size" ]
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Cc: devicetree at vger.kernel.org
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> ---
>  Documentation/devicetree/bindings/chosen.txt | 50 ++++++++++++++++++++++++++++
>  1 file changed, 50 insertions(+)

I need an ack from Rob or Mark before I can merge this.

Will

^ permalink raw reply

* [PATCH v29 1/9] memblock: add memblock_cap_memory_range()
From: Will Deacon @ 2017-01-10 11:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161228043525.27420-1-takahiro.akashi@linaro.org>

[adding some more folks to cc]

On Wed, Dec 28, 2016 at 01:35:25PM +0900, AKASHI Takahiro wrote:
> Add memblock_cap_memory_range() which will remove all the memblock regions
> except the memory range specified in the arguments. In addition, rework is
> done on memblock_mem_limit_remove_map() to re-implement it using
> memblock_cap_memory_range().
> 
> This function, like memblock_mem_limit_remove_map(), will not remove
> memblocks with MEMMAP_NOMAP attribute as they may be mapped and accessed
> later as "device memory."
> See the commit a571d4eb55d8 ("mm/memblock.c: add new infrastructure to
> address the mem limit issue").
> 
> This function is used, in a succeeding patch in the series of arm64 kdump
> suuport, to limit the range of usable memory, or System RAM, on crash dump
> kernel.
> (Please note that "mem=" parameter is of little use for this purpose.)
> 
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Reviewed-by: Will Deacon <will.deacon@arm.com>
> Acked-by: Catalin Marinas <catalin.marinas@arm.com>
> Cc: linux-mm at kvack.org
> Cc: Andrew Morton <akpm@linux-foundation.org>
> ---
>  include/linux/memblock.h |  1 +
>  mm/memblock.c            | 44 +++++++++++++++++++++++++++++---------------
>  2 files changed, 30 insertions(+), 15 deletions(-)

Whilst this patch looks fine to me, it would be nice if Dennis (author of
memblock_mem_limit_remove_map) or one of the mm chaps could provide an ack
before I merge it via arm64.

Thanks,

Will

> diff --git a/include/linux/memblock.h b/include/linux/memblock.h
> index 5b759c9acf97..fbfcacc50c29 100644
> --- a/include/linux/memblock.h
> +++ b/include/linux/memblock.h
> @@ -333,6 +333,7 @@ phys_addr_t memblock_mem_size(unsigned long limit_pfn);
>  phys_addr_t memblock_start_of_DRAM(void);
>  phys_addr_t memblock_end_of_DRAM(void);
>  void memblock_enforce_memory_limit(phys_addr_t memory_limit);
> +void memblock_cap_memory_range(phys_addr_t base, phys_addr_t size);
>  void memblock_mem_limit_remove_map(phys_addr_t limit);
>  bool memblock_is_memory(phys_addr_t addr);
>  int memblock_is_map_memory(phys_addr_t addr);
> diff --git a/mm/memblock.c b/mm/memblock.c
> index 7608bc305936..fea1688fef60 100644
> --- a/mm/memblock.c
> +++ b/mm/memblock.c
> @@ -1514,11 +1514,37 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
>  			      (phys_addr_t)ULLONG_MAX);
>  }
>  
> +void __init memblock_cap_memory_range(phys_addr_t base, phys_addr_t size)
> +{
> +	int start_rgn, end_rgn;
> +	int i, ret;
> +
> +	if (!size)
> +		return;
> +
> +	ret = memblock_isolate_range(&memblock.memory, base, size,
> +						&start_rgn, &end_rgn);
> +	if (ret)
> +		return;
> +
> +	/* remove all the MAP regions */
> +	for (i = memblock.memory.cnt - 1; i >= end_rgn; i--)
> +		if (!memblock_is_nomap(&memblock.memory.regions[i]))
> +			memblock_remove_region(&memblock.memory, i);
> +
> +	for (i = start_rgn - 1; i >= 0; i--)
> +		if (!memblock_is_nomap(&memblock.memory.regions[i]))
> +			memblock_remove_region(&memblock.memory, i);
> +
> +	/* truncate the reserved regions */
> +	memblock_remove_range(&memblock.reserved, 0, base);
> +	memblock_remove_range(&memblock.reserved,
> +			base + size, (phys_addr_t)ULLONG_MAX);
> +}
> +
>  void __init memblock_mem_limit_remove_map(phys_addr_t limit)
>  {
> -	struct memblock_type *type = &memblock.memory;
>  	phys_addr_t max_addr;
> -	int i, ret, start_rgn, end_rgn;
>  
>  	if (!limit)
>  		return;
> @@ -1529,19 +1555,7 @@ void __init memblock_mem_limit_remove_map(phys_addr_t limit)
>  	if (max_addr == (phys_addr_t)ULLONG_MAX)
>  		return;
>  
> -	ret = memblock_isolate_range(type, max_addr, (phys_addr_t)ULLONG_MAX,
> -				&start_rgn, &end_rgn);
> -	if (ret)
> -		return;
> -
> -	/* remove all the MAP regions above the limit */
> -	for (i = end_rgn - 1; i >= start_rgn; i--) {
> -		if (!memblock_is_nomap(&type->regions[i]))
> -			memblock_remove_region(type, i);
> -	}
> -	/* truncate the reserved regions */
> -	memblock_remove_range(&memblock.reserved, max_addr,
> -			      (phys_addr_t)ULLONG_MAX);
> +	memblock_cap_memory_range(0, max_addr);
>  }
>  
>  static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
> -- 
> 2.11.0
> 

^ permalink raw reply

* [PATCH] usb: dwc3-exynos fix unspecified suspend clk error handling
From: Sergei Shtylyov @ 2017-01-10 11:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110022131.31042-1-shuahkh@osg.samsung.com>

Hello!

On 01/10/2017 05:21 AM, Shuah Khan wrote:

> Fix dwc3_exynos_probe() to call clk_prepare_enable() only when suspend
> clock is specified. Call clk_disable_unprepare() from remove and probe
> error path only when susp_clk has been set from remove and probe error
> paths.
>
> Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
> ---
>  drivers/usb/dwc3/dwc3-exynos.c | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
> index e27899b..f97a3d7 100644
> --- a/drivers/usb/dwc3/dwc3-exynos.c
> +++ b/drivers/usb/dwc3/dwc3-exynos.c
> @@ -131,8 +131,8 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
>  	if (IS_ERR(exynos->susp_clk)) {
>  		dev_info(dev, "no suspend clk specified\n");
>  		exynos->susp_clk = NULL;
> -	}
> -	clk_prepare_enable(exynos->susp_clk);
> +	} else
> +		clk_prepare_enable(exynos->susp_clk);

    CodingStyle: need {} here as well since another branch has them.

[...]

MBR, Sergei

^ permalink raw reply

* [PATCH v5 1/2] ARM: dts: at91: add devicetree for the Axentia TSE-850
From: Peter Rosin @ 2017-01-10 11:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110104248.iscurq55d7n26gfd@piout.net>

On 2017-01-10 11:42, Alexandre Belloni wrote:
> On 10/01/2017 at 10:52:56 +0100, Peter Rosin wrote :
>> On 2017-01-10 10:29, Alexandre Belloni wrote:
>>> Hi,
>>>
>>> This needs a commit message, please add one.
>>
>> There's not all that much to say, but ok, I'll add something.
>>
> 
> It doesn't have to be long but it has to be present.

Does it really? There are quite a few examples to contradict that,
and checkpatch doesn't complain. That's no proof of course...

As I said, I'll add something.

>>> On 10/01/2017 at 09:08:51 +0100, Peter Rosin wrote :
>> There's also the benefit of the increased chances of me getting
>> notified of changes. I don't mind...
>>
> 
> Do you expect changes coming from third parties? I'm fine with it
> anyway.

Ok, I'll remember this and blame you for everything :-)

>>>> +&main {
>>>> +	clock-frequency = <12000000>;
>>>> +};
>>>> +
>>>
>>> I don't think this is needed
>>>
>>>
>>
>> "this"? The &main frequency, or all of them?
>>
> 
> I meant just main

Ok, I'll test with that change and then resend. Thanks!

Cheers,
peda

^ permalink raw reply

* [PATCH] coresight: STM: Balance enable/disable
From: Suzuki K Poulose @ 2017-01-10 11:21 UTC (permalink / raw)
  To: linux-arm-kernel

The stm is automatically enabled when an application sets the policy
via ->link() call back by using coresight_enable(), which keeps the
refcount of the current users of the STM. However, the unlink() callback
issues stm_disable() directly, which leaves the STM turned off, without
the coresight layer knowing about it. This prevents any further uses
of the STM hardware as the coresight layer still thinks the STM is
turned on and doesn't issue an stm_enable(). Even manually enabling
the STM via sysfs can't really enable the hw.

e.g,

$ echo 1 > $CS_DEVS/$ETR/enable_sink
$ mkdir -p $CONFIG_FS/stp-policy/$source.0/stm_test/
$ echo 32768 65535 > $CONFIG_FS/stp-policy/$source.0/stm_test/channels
$ echo 64 > $CS_DEVS/$source/traceid
$ ./stm_app
Sending 64000 byte blocks of pattern 0 at 0us intervals
Success to map channel(32768~32783) to 0xffffa95fa000
Sending on channel 32768
$ dd if=/dev/$ETR of=~/trace.bin.1
597+1 records in
597+1 records out
305920 bytes (306 kB) copied, 0.399952 s, 765 kB/s
$ ./stm_app
Sending 64000 byte blocks of pattern 0 at 0us intervals
Success to map channel(32768~32783) to 0xffff7e9e2000
Sending on channel 32768
$ dd if=/dev/$ETR of=~/trace.bin.2
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.0232083 s, 0.0 kB/s

Note that we don't get any data from the ETR for the second session.

Also dmesg shows :

[   77.520458] coresight-tmc 20800000.etr: TMC-ETR enabled
[   77.537097] coresight-replicator etr_replicator at 20890000: REPLICATOR enabled
[   77.558828] coresight-replicator main_replicator at 208a0000: REPLICATOR enabled
[   77.581068] coresight-funnel 208c0000.main_funnel: FUNNEL inport 0 enabled
[   77.602217] coresight-tmc 20840000.etf: TMC-ETF enabled
[   77.618422] coresight-stm 20860000.stm: STM tracing enabled
[  139.554252] coresight-stm 20860000.stm: STM tracing disabled
 # End of first tracing session
[  146.351135] coresight-tmc 20800000.etr: TMC read start
[  146.514486] coresight-tmc 20800000.etr: TMC read end
 # Note that the STM is not turned on via stm_generic_link()->coresight_enable()
 # and hence none of the components are turned on.
[  152.479080] coresight-tmc 20800000.etr: TMC read start
[  152.542632] coresight-tmc 20800000.etr: TMC read end

This patch balances the unlink operation by using the coresight_disable(),
keeping the coresight layer in sync with the hardware state.

Fixes: commit 237483aa5cf43 ("coresight: stm: adding driver for CoreSight STM component")
Cc: Pratik Patel <pratikp@codeaurora.org>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Chunyan Zhang <zhang.chunyan@linaro.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: stable at vger.kernel.org # 4.7+
Reported-by: Robert Walker <robert.walker@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
 drivers/hwtracing/coresight/coresight-stm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index 3524452..57b7330 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -356,7 +356,7 @@ static void stm_generic_unlink(struct stm_data *stm_data,
 	if (!drvdata || !drvdata->csdev)
 		return;
 
-	stm_disable(drvdata->csdev, NULL);
+	coresight_disable(drvdata->csdev);
 }
 
 static phys_addr_t
-- 
2.7.4

^ permalink raw reply related

* [PATCH 1/2] memory: aemif: allow passing device lookup table as platform data
From: Sekhar Nori @ 2017-01-10 11:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483526167-24209-2-git-send-email-bgolaszewski@baylibre.com>

On Wednesday 04 January 2017 04:06 PM, Bartosz Golaszewski wrote:
> TI aemif driver creates its own subnodes of the device tree in order
> to guarantee that all child devices are probed after the AEMIF timing
> parameters are configured.
> 
> Some devices (e.g. da850) use struct of_dev_auxdata for clock lookup
> but nodes created from within the aemif driver can't access the lookup
> table.
> 
> Create a platform data structure that holds a pointer to
> of_dev_auxdata so that we can use it with of_platform_populate().
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

I did not really see any precedent to passing of_dev_auxdata as platform
data, but the idea looks fine to me, so:

Acked-by: Sekhar Nori <nsekhar@ti.com>

Thanks,
Sekhar

^ permalink raw reply

* [PATCH v29 4/9] arm64: kdump: implement machine_crash_shutdown()
From: Will Deacon @ 2017-01-10 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161228043605.27470-3-takahiro.akashi@linaro.org>

On Wed, Dec 28, 2016 at 01:36:01PM +0900, AKASHI Takahiro wrote:
> Primary kernel calls machine_crash_shutdown() to shut down non-boot cpus
> and save registers' status in per-cpu ELF notes before starting crash
> dump kernel. See kernel_kexec().
> Even if not all secondary cpus have shut down, we do kdump anyway.
> 
> As we don't have to make non-boot(crashed) cpus offline (to preserve
> correct status of cpus at crash dump) before shutting down, this patch
> also adds a variant of smp_send_stop().
> 
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Reviewed-by: James Morse <james.morse@arm.com>
> Acked-by: Catalin Marinas <catalin.marinas@arm.com>
> ---
>  arch/arm64/include/asm/hardirq.h  |  2 +-
>  arch/arm64/include/asm/kexec.h    | 42 +++++++++++++++++++++++++-
>  arch/arm64/include/asm/smp.h      |  2 ++
>  arch/arm64/kernel/machine_kexec.c | 56 ++++++++++++++++++++++++++++++++--
>  arch/arm64/kernel/smp.c           | 63 +++++++++++++++++++++++++++++++++++++++
>  5 files changed, 160 insertions(+), 5 deletions(-)

[...]

> diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
> index d050d720a1b4..cea009f2657d 100644
> --- a/arch/arm64/include/asm/smp.h
> +++ b/arch/arm64/include/asm/smp.h
> @@ -148,6 +148,8 @@ static inline void cpu_panic_kernel(void)
>   */
>  bool cpus_are_stuck_in_kernel(void);
>  
> +extern void smp_send_crash_stop(void);
> +
>  #endif /* ifndef __ASSEMBLY__ */
>  
>  #endif /* ifndef __ASM_SMP_H */
> diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
> index bc96c8a7fc79..c60346d33bb1 100644
> --- a/arch/arm64/kernel/machine_kexec.c
> +++ b/arch/arm64/kernel/machine_kexec.c
> @@ -9,6 +9,9 @@
>   * published by the Free Software Foundation.
>   */
>  
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/kernel.h>
>  #include <linux/kexec.h>
>  #include <linux/smp.h>
>  
> @@ -22,6 +25,7 @@
>  extern const unsigned char arm64_relocate_new_kernel[];
>  extern const unsigned long arm64_relocate_new_kernel_size;
>  
> +static bool in_crash_kexec;

Do you actually need this bool? Why not call kexec_crash_loaded() instead?

Will

^ permalink raw reply

* [PATCH v5 1/2] ARM: dts: at91: add devicetree for the Axentia TSE-850
From: Alexandre Belloni @ 2017-01-10 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <81d5b553-38db-5137-2eac-145cb2f76578@axentia.se>

On 10/01/2017 at 12:21:42 +0100, Peter Rosin wrote :
> On 2017-01-10 11:42, Alexandre Belloni wrote:
> > On 10/01/2017 at 10:52:56 +0100, Peter Rosin wrote :
> >> On 2017-01-10 10:29, Alexandre Belloni wrote:
> >>> Hi,
> >>>
> >>> This needs a commit message, please add one.
> >>
> >> There's not all that much to say, but ok, I'll add something.
> >>
> > 
> > It doesn't have to be long but it has to be present.
> 
> Does it really? There are quite a few examples to contradict that,
> and checkpatch doesn't complain. That's no proof of course...
> 
> As I said, I'll add something.
> 

There is public shaming for maintainers taking patches without a commit
message, that's enough for me to require a commit message ;)

https://lwn.net/Articles/560392/

> >>> On 10/01/2017 at 09:08:51 +0100, Peter Rosin wrote :
> >> There's also the benefit of the increased chances of me getting
> >> notified of changes. I don't mind...
> >>
> > 
> > Do you expect changes coming from third parties? I'm fine with it
> > anyway.
> 
> Ok, I'll remember this and blame you for everything :-)
> 

Well, you can let it there, I was just not sure whether you were
expecting to see patches or just trying to make checkpatch happy. As
said, I'm fine with it.

> >>>> +&main {
> >>>> +	clock-frequency = <12000000>;
> >>>> +};
> >>>> +
> >>>
> >>> I don't think this is needed
> >>>
> >>>
> >>
> >> "this"? The &main frequency, or all of them?
> >>
> > 
> > I meant just main
> 
> Ok, I'll test with that change and then resend. Thanks!
> 
> Cheers,
> peda

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH v3 0/9] Add support for monitoring guest TLB operations
From: Punit Agrawal @ 2017-01-10 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This is a new version of the patchset to monitor guest TLB
operations. The user interface has been re-written to incorporate
feedback from LPC'16 on the previous version - it now uses a software
PMU instead of relying on perf trace to track guest TLB operations
(Patch 6 and 7). Previous versions of the patches can be found at
[0][1][2][3].

Guest TLB operations can impact on system performance but these are
not exported as architected PMU events on arm/arm64. Instead the
architecture allows trapping of TLB operations to the hypervisor. This
patchset builds on this feature to monitor TLB operations.

To minimise the performance impact, trapping is enabled -
* on user request
* for the VM of interest

With this patchset, running 'perf' on the host can be used to monitor
the TLB operations. E.g., to monitor a VM with process id 2589 -

# perf stat -a -C 0 -e kvm/kvm_tlb_invalidate,vm=2589/ sleep 25

 Performance counter stats for 'system wide':

             3,386      kvm/tlb_invalidate,vm=2589/

      25.001086522 seconds time elapsed


The patches are based on v4.10-rc3 and have been tested on arm and
arm64.

Thanks,
Punit

[0] http://www.mail-archive.com/linux-kernel at vger.kernel.org/msg1210715.html
[1] http://www.mail-archive.com/linux-kernel at vger.kernel.org/msg1224353.html
[2] https://marc.info/?l=linux-kernel&m=147376184208258&w=2
[3] https://marc.info/?l=kvm&m=147750373716545&w=2

Changes:
v2 -> v3
* Replaced perf trace monitoring with software PMU
* Re-ordered patches as a result of the above re-write

v1 -> v2

* New (Patch 6) - Add support for trapping and emulating TLB
  operations to ARM hosts
* Move common code to handle perf trace notifications to virt/kvm/arm
* Move tracepoint to include/trace/events/kvm.h
* Drop patch to introduce __tlbi helper as it is now merged
* Reorder patches

RFC v2 -> v1
* Dropped the RFC tag
* Patch 2 - Use VM thread group id for identification
* Patch 4 - Update comment for clarity
* Patch 6 - Add comment explaining switch to hype-role when VHE is enabled
* Patch 7 - Add comment to clarify struct kvm_trace_hook

RFC -> RFC v2
* Patch 4 - Rename left-over TLBI macro to __TLBI
* Patch 6 - Replace individual TLB operation emulation with
  invalidating all stage 1 TLB for the VM. TLB monitoring is expected
  to be a debug feature and performance is not critical.



Mark Rutland (1):
  arm64/kvm: hyp: tlb: use __tlbi() helper

Punit Agrawal (8):
  KVM: Track the pid of the VM process
  KVM: Add event to trace tlb invalidations
  arm: KVM: Handle trappable TLB instructions
  arm64: KVM: Handle trappable TLB instructions
  kvm: arm/arm64: Add host pmu to support VM introspection
  kvm: host_pmu: Add support for tracking guest TLB operations
  arm: KVM: Enable support for host pmu
  arm64: KVM: Enable support for the host pmu

 arch/arm/include/asm/kvm_asm.h    |   2 +
 arch/arm/include/asm/kvm_host.h   |   9 ++
 arch/arm/kvm/Kconfig              |   4 +
 arch/arm/kvm/Makefile             |   1 +
 arch/arm/kvm/arm.c                |   2 +
 arch/arm/kvm/coproc.c             |  56 +++++++
 arch/arm/kvm/hyp/tlb.c            |  33 ++++
 arch/arm64/include/asm/kvm_asm.h  |   2 +
 arch/arm64/include/asm/kvm_host.h |   9 ++
 arch/arm64/kvm/Kconfig            |   4 +
 arch/arm64/kvm/Makefile           |   1 +
 arch/arm64/kvm/hyp/tlb.c          |  87 +++++++++-
 arch/arm64/kvm/sys_regs.c         |  83 ++++++++++
 include/linux/kvm_host.h          |   1 +
 include/trace/events/kvm.h        |  18 +++
 virt/kvm/arm/host_pmu.c           | 322 ++++++++++++++++++++++++++++++++++++++
 virt/kvm/kvm_main.c               |   2 +
 17 files changed, 630 insertions(+), 6 deletions(-)
 create mode 100644 virt/kvm/arm/host_pmu.c

-- 
2.11.0

^ permalink raw reply

* [PATCH v3 1/9] arm64/kvm: hyp: tlb: use __tlbi() helper
From: Punit Agrawal @ 2017-01-10 11:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110113856.7183-1-punit.agrawal@arm.com>

From: Mark Rutland <mark.rutland@arm.com>

Now that we have a __tlbi() helper, make use of this in the arm64 KVM hyp
code to get rid of asm() boilerplate. At the same time, we simplify
__tlb_flush_vm_context by using __flush_icache_all(), as this has the
appropriate instruction cache maintenance and barrier.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
[ rename tlbi -> __tlbi, convert additional sites, update commit log ]
Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/tlb.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
index 88e2f2b938f0..b2cfbedea582 100644
--- a/arch/arm64/kvm/hyp/tlb.c
+++ b/arch/arm64/kvm/hyp/tlb.c
@@ -16,6 +16,7 @@
  */
 
 #include <asm/kvm_hyp.h>
+#include <asm/tlbflush.h>
 
 void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
 {
@@ -32,7 +33,7 @@ void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
 	 * whole of Stage-1. Weep...
 	 */
 	ipa >>= 12;
-	asm volatile("tlbi ipas2e1is, %0" : : "r" (ipa));
+	__tlbi(ipas2e1is, ipa);
 
 	/*
 	 * We have to ensure completion of the invalidation at Stage-2,
@@ -41,7 +42,7 @@ void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
 	 * the Stage-1 invalidation happened first.
 	 */
 	dsb(ish);
-	asm volatile("tlbi vmalle1is" : : );
+	__tlbi(vmalle1is);
 	dsb(ish);
 	isb();
 
@@ -57,7 +58,7 @@ void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
 	write_sysreg(kvm->arch.vttbr, vttbr_el2);
 	isb();
 
-	asm volatile("tlbi vmalls12e1is" : : );
+	__tlbi(vmalls12e1is);
 	dsb(ish);
 	isb();
 
@@ -82,7 +83,6 @@ void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
 void __hyp_text __kvm_flush_vm_context(void)
 {
 	dsb(ishst);
-	asm volatile("tlbi alle1is	\n"
-		     "ic ialluis	  ": : );
-	dsb(ish);
+	__tlbi(alle1is);
+	__flush_icache_all(); /* contains a dsb(ish) */
 }
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 2/9] KVM: Track the pid of the VM process
From: Punit Agrawal @ 2017-01-10 11:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110113856.7183-1-punit.agrawal@arm.com>

Userspace tools such as perf can be used to profile individual
processes.

Track the PID of the virtual machine process to match profiling requests
targeted at it. This can be used to take appropriate action to enable
the requested profiling operations for the VMs of interest.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Kr?m??" <rkrcmar@redhat.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/kvm_host.h | 1 +
 virt/kvm/kvm_main.c      | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 1c5190dab2c1..c666926529ca 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -374,6 +374,7 @@ struct kvm_memslots {
 struct kvm {
 	spinlock_t mmu_lock;
 	struct mutex slots_lock;
+	struct pid *pid;
 	struct mm_struct *mm; /* userspace tied to this vm */
 	struct kvm_memslots *memslots[KVM_ADDRESS_SPACE_NUM];
 	struct srcu_struct srcu;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 482612b4e496..59d8a84da227 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -618,6 +618,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
 	spin_lock_init(&kvm->mmu_lock);
 	atomic_inc(&current->mm->mm_count);
 	kvm->mm = current->mm;
+	kvm->pid = get_task_pid(current->group_leader, PIDTYPE_PID);
 	kvm_eventfd_init(kvm);
 	mutex_init(&kvm->lock);
 	mutex_init(&kvm->irq_lock);
@@ -717,6 +718,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
 	int i;
 	struct mm_struct *mm = kvm->mm;
 
+	put_pid(kvm->pid);
 	kvm_destroy_vm_debugfs(kvm);
 	kvm_arch_sync_events(kvm);
 	spin_lock(&kvm_lock);
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 3/9] KVM: Add event to trace tlb invalidations
From: Punit Agrawal @ 2017-01-10 11:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110113856.7183-1-punit.agrawal@arm.com>

As TLB operations can have an impact on system performance, add a trace
event to enable monitoring of guest TLB maintenance operations.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
---
 include/trace/events/kvm.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h
index 8ade3eb6c640..fbe33089264c 100644
--- a/include/trace/events/kvm.h
+++ b/include/trace/events/kvm.h
@@ -393,6 +393,24 @@ TRACE_EVENT(kvm_halt_poll_ns,
 #define trace_kvm_halt_poll_ns_shrink(vcpu_id, new, old) \
 	trace_kvm_halt_poll_ns(false, vcpu_id, new, old)
 
+TRACE_EVENT(kvm_tlb_invalidate,
+	TP_PROTO(unsigned long vcpu_pc, u32 opcode),
+	TP_ARGS(vcpu_pc, opcode),
+
+	TP_STRUCT__entry(
+		__field(unsigned long, vcpu_pc)
+		__field(u32, opcode)
+	),
+
+	TP_fast_assign(
+		__entry->vcpu_pc = vcpu_pc;
+		__entry->opcode = opcode;
+	),
+
+	TP_printk("vcpu_pc=0x%16lx opcode=%08x", __entry->vcpu_pc,
+		  __entry->opcode)
+);
+
 #endif /* _TRACE_KVM_MAIN_H */
 
 /* This part must be outside protection */
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 4/9] arm: KVM: Handle trappable TLB instructions
From: Punit Agrawal @ 2017-01-10 11:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110113856.7183-1-punit.agrawal@arm.com>

It is possible to enable selective trapping of guest TLB maintenance
instructions executed in lower privilege levels to HYP mode. This
feature can be used to monitor guest TLB operations.

Add support to emulate the TLB instructions when their execution traps
to hyp mode. Also keep track of the number of emulated operations.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/include/asm/kvm_asm.h  |  2 ++
 arch/arm/include/asm/kvm_host.h |  1 +
 arch/arm/kvm/coproc.c           | 56 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/kvm/hyp/tlb.c          | 33 ++++++++++++++++++++++++
 4 files changed, 92 insertions(+)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 8ef05381984b..782034a5a3c3 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -67,6 +67,8 @@ extern void __kvm_flush_vm_context(void);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
 extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
 extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
+extern void __kvm_emulate_tlb_invalidate(struct kvm *kvm, u32 opcode,
+					 u64 regval);
 
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index d5423ab15ed5..26f0c8a0b790 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -205,6 +205,7 @@ struct kvm_vcpu_stat {
 	u64 mmio_exit_user;
 	u64 mmio_exit_kernel;
 	u64 exits;
+	u64 tlb_invalidate;
 };
 
 #define vcpu_cp15(v,r)	(v)->arch.ctxt.cp15[r]
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 3e5e4194ef86..b978b0bf211e 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -205,6 +205,24 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static bool emulate_tlb_invalidate(struct kvm_vcpu *vcpu,
+				   const struct coproc_params *p,
+				   const struct coproc_reg *r)
+{
+	/*
+	 * Based on system register encoding from ARM v8 ARM
+	 * (DDI 0487A.k F5.1.103)
+	 */
+	u32 opcode = p->Op1 << 21 | p->CRn << 16 | p->Op2 << 5 | p->CRm << 0;
+
+	kvm_call_hyp(__kvm_emulate_tlb_invalidate,
+		     vcpu->kvm, opcode, p->Rt1);
+	trace_kvm_tlb_invalidate(*vcpu_pc(vcpu), opcode);
+	++vcpu->stat.tlb_invalidate;
+
+	return true;
+}
+
 /*
  * Generic accessor for VM registers. Only called as long as HCR_TVM
  * is set.  If the guest enables the MMU, we stop trapping the VM
@@ -354,6 +372,44 @@ static const struct coproc_reg cp15_regs[] = {
 	{ CRn( 7), CRm( 6), Op1( 0), Op2( 2), is32, access_dcsw},
 	{ CRn( 7), CRm(10), Op1( 0), Op2( 2), is32, access_dcsw},
 	{ CRn( 7), CRm(14), Op1( 0), Op2( 2), is32, access_dcsw},
+
+	/* TLBIALLIS */
+	{ CRn( 8), CRm( 3), Op1( 0), Op2( 0), is32, emulate_tlb_invalidate},
+	/* TLBIMVAIS */
+	{ CRn( 8), CRm( 3), Op1( 0), Op2( 1), is32, emulate_tlb_invalidate},
+	/* TLBIASIDIS */
+	{ CRn( 8), CRm( 3), Op1( 0), Op2( 2), is32, emulate_tlb_invalidate},
+	/* TLBIMVAAIS */
+	{ CRn( 8), CRm( 3), Op1( 0), Op2( 3), is32, emulate_tlb_invalidate},
+	/* TLBIMVALIS */
+	{ CRn( 8), CRm( 3), Op1( 0), Op2( 5), is32, emulate_tlb_invalidate},
+	/* TLBIMVAALIS */
+	{ CRn( 8), CRm( 3), Op1( 0), Op2( 7), is32, emulate_tlb_invalidate},
+	/* ITLBIALL */
+	{ CRn( 8), CRm( 5), Op1( 0), Op2( 0), is32, emulate_tlb_invalidate},
+	/* ITLBIMVA */
+	{ CRn( 8), CRm( 5), Op1( 0), Op2( 1), is32, emulate_tlb_invalidate},
+	/* ITLBIASID */
+	{ CRn( 8), CRm( 5), Op1( 0), Op2( 2), is32, emulate_tlb_invalidate},
+	/* DTLBIALL */
+	{ CRn( 8), CRm( 6), Op1( 0), Op2( 0), is32, emulate_tlb_invalidate},
+	/* DTLBIMVA */
+	{ CRn( 8), CRm( 6), Op1( 0), Op2( 1), is32, emulate_tlb_invalidate},
+	/* DTLBIASID */
+	{ CRn( 8), CRm( 6), Op1( 0), Op2( 2), is32, emulate_tlb_invalidate},
+	/* TLBIALL */
+	{ CRn( 8), CRm( 7), Op1( 0), Op2( 0), is32, emulate_tlb_invalidate},
+	/* TLBIMVA */
+	{ CRn( 8), CRm( 7), Op1( 0), Op2( 1), is32, emulate_tlb_invalidate},
+	/* TLBIASID */
+	{ CRn( 8), CRm( 7), Op1( 0), Op2( 2), is32, emulate_tlb_invalidate},
+	/* TLBIMVAA */
+	{ CRn( 8), CRm( 7), Op1( 0), Op2( 3), is32, emulate_tlb_invalidate},
+	/* TLBIMVAL */
+	{ CRn( 8), CRm( 7), Op1( 0), Op2( 5), is32, emulate_tlb_invalidate},
+	/* TLBIMVAAL */
+	{ CRn( 8), CRm( 7), Op1( 0), Op2( 7), is32, emulate_tlb_invalidate},
+
 	/*
 	 * L2CTLR access (guest wants to know #CPUs).
 	 */
diff --git a/arch/arm/kvm/hyp/tlb.c b/arch/arm/kvm/hyp/tlb.c
index 6d810af2d9fd..d2b86100d1bb 100644
--- a/arch/arm/kvm/hyp/tlb.c
+++ b/arch/arm/kvm/hyp/tlb.c
@@ -76,3 +76,36 @@ void __hyp_text __kvm_flush_vm_context(void)
 	write_sysreg(0, ICIALLUIS);
 	dsb(ish);
 }
+
+static void __hyp_text __switch_to_guest_regime(struct kvm *kvm)
+{
+	write_sysreg(kvm->arch.vttbr, VTTBR);
+	isb();
+}
+
+static void __hyp_text __switch_to_host_regime(void)
+{
+	write_sysreg(0, VTTBR);
+}
+
+void __hyp_text
+__kvm_emulate_tlb_invalidate(struct kvm *kvm, u32 opcode, u64 regval)
+{
+	kvm = kern_hyp_va(kvm);
+
+	__switch_to_guest_regime(kvm);
+
+	/*
+	 *  TLB maintenance operations are broadcast to
+	 *  inner-shareable domain when HCR_FB is set (default for
+	 *  KVM).
+	 *
+	 *  Nuke all Stage 1 TLB entries for the VM. This will kill
+	 *  performance but it's always safe to do as we don't leave
+	 *  behind any strays in the TLB
+	 */
+	write_sysreg(0, TLBIALLIS);
+	isb();
+
+	__switch_to_host_regime();
+}
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 5/9] arm64: KVM: Handle trappable TLB instructions
From: Punit Agrawal @ 2017-01-10 11:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110113856.7183-1-punit.agrawal@arm.com>

The ARMv8 architecture allows trapping of TLB maintenane instructions
from EL0/EL1 to higher exception levels. On encountering a trappable TLB
instruction in a guest, an exception is taken to EL2.

Add support to handle emulating the TLB instructions. Also track the
number of emulated operations.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_asm.h  |  2 +
 arch/arm64/include/asm/kvm_host.h |  1 +
 arch/arm64/kvm/hyp/tlb.c          | 75 +++++++++++++++++++++++++++++++++++
 arch/arm64/kvm/sys_regs.c         | 83 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 161 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index ec3553eb9349..8b695785d454 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -55,6 +55,8 @@ extern void __kvm_flush_vm_context(void);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
 extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
 extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
+extern void __kvm_emulate_tlb_invalidate(struct kvm *kvm, u32 opcode,
+					 u64 regval);
 
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index e5050388e062..1e83b707f14c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -307,6 +307,7 @@ struct kvm_vcpu_stat {
 	u64 mmio_exit_user;
 	u64 mmio_exit_kernel;
 	u64 exits;
+	u64 tlb_invalidate;
 };
 
 int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init);
diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
index b2cfbedea582..c14237858d75 100644
--- a/arch/arm64/kvm/hyp/tlb.c
+++ b/arch/arm64/kvm/hyp/tlb.c
@@ -86,3 +86,78 @@ void __hyp_text __kvm_flush_vm_context(void)
 	__tlbi(alle1is);
 	__flush_icache_all(); /* contains a dsb(ish) */
 }
+
+/* Intentionally empty functions */
+static void __hyp_text __switch_to_hyp_role_nvhe(void) { }
+static void __hyp_text __switch_to_host_role_nvhe(void) { }
+
+static void __hyp_text __switch_to_hyp_role_vhe(void)
+{
+	u64 hcr = read_sysreg(hcr_el2);
+
+	/*
+	 * When VHE is enabled and HCR_EL2.TGE=1, EL1&0 TLB operations
+	 * apply to EL2&0 translation regime. As we prepare to emulate
+	 * guest TLB operation clear HCR_TGE to target TLB operations
+	 * to EL1&0 (guest).
+	 */
+	hcr &= ~HCR_TGE;
+	write_sysreg(hcr, hcr_el2);
+}
+
+static void __hyp_text __switch_to_host_role_vhe(void)
+{
+	u64 hcr = read_sysreg(hcr_el2);
+
+	hcr |= HCR_TGE;
+	write_sysreg(hcr, hcr_el2);
+}
+
+static hyp_alternate_select(__switch_to_hyp_role,
+			    __switch_to_hyp_role_nvhe,
+			    __switch_to_hyp_role_vhe,
+			    ARM64_HAS_VIRT_HOST_EXTN);
+
+static hyp_alternate_select(__switch_to_host_role,
+			    __switch_to_host_role_nvhe,
+			    __switch_to_host_role_vhe,
+			    ARM64_HAS_VIRT_HOST_EXTN);
+
+static void __hyp_text __switch_to_guest_regime(struct kvm *kvm)
+{
+	write_sysreg(kvm->arch.vttbr, vttbr_el2);
+	__switch_to_hyp_role();
+	isb();
+}
+
+static void __hyp_text __switch_to_host_regime(void)
+{
+	__switch_to_host_role();
+	write_sysreg(0, vttbr_el2);
+}
+
+void __hyp_text
+__kvm_emulate_tlb_invalidate(struct kvm *kvm, u32 opcode, u64 regval)
+{
+	kvm = kern_hyp_va(kvm);
+
+	/*
+	 * Switch to the guest before performing any TLB operations to
+	 * target the appropriate VMID
+	 */
+	__switch_to_guest_regime(kvm);
+
+	/*
+	 *  TLB maintenance operations are broadcast to
+	 *  inner-shareable domain when HCR_FB is set (default for
+	 *  KVM).
+	 *
+	 *  Nuke all Stage 1 TLB entries for the VM. This will kill
+	 *  performance but it's always safe to do as we don't leave
+	 *  behind any strays in the TLB
+	 */
+	__tlbi(vmalle1is);
+	isb();
+
+	__switch_to_host_regime();
+}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 87e7e6608cd8..12ff8cf9f18a 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -791,6 +791,20 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool emulate_tlb_invalidate(struct kvm_vcpu *vcpu,
+				   struct sys_reg_params *p,
+				   const struct sys_reg_desc *r)
+{
+	u32 opcode = sys_reg(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
+
+	kvm_call_hyp(__kvm_emulate_tlb_invalidate,
+		     vcpu->kvm, opcode, p->regval);
+	trace_kvm_tlb_invalidate(*vcpu_pc(vcpu), opcode);
+	++vcpu->stat.tlb_invalidate;
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -842,6 +856,35 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ Op0(0b01), Op1(0b000), CRn(0b0111), CRm(0b1110), Op2(0b010),
 	  access_dcsw },
 
+	/*
+	 * ARMv8 ARM: Table C5-4 TLB maintenance instructions
+	 * (Ref: ARMv8 ARM C5.1 version: ARM DDI 0487A.j)
+	 */
+	/* TLBI VMALLE1IS */
+	{ Op0(1), Op1(0), CRn(8), CRm(3), Op2(0), emulate_tlb_invalidate },
+	/* TLBI VAE1IS */
+	{ Op0(1), Op1(0), CRn(8), CRm(3), Op2(1), emulate_tlb_invalidate },
+	/* TLBI ASIDE1IS */
+	{ Op0(1), Op1(0), CRn(8), CRm(3), Op2(2), emulate_tlb_invalidate },
+	/* TLBI VAAE1IS */
+	{ Op0(1), Op1(0), CRn(8), CRm(3), Op2(3), emulate_tlb_invalidate },
+	/* TLBI VALE1IS */
+	{ Op0(1), Op1(0), CRn(8), CRm(3), Op2(5), emulate_tlb_invalidate },
+	/* TLBI VAALE1IS */
+	{ Op0(1), Op1(0), CRn(8), CRm(3), Op2(7), emulate_tlb_invalidate },
+	/* TLBI VMALLE1 */
+	{ Op0(1), Op1(0), CRn(8), CRm(7), Op2(0), emulate_tlb_invalidate },
+	/* TLBI VAE1 */
+	{ Op0(1), Op1(0), CRn(8), CRm(7), Op2(1), emulate_tlb_invalidate },
+	/* TLBI ASIDE1 */
+	{ Op0(1), Op1(0), CRn(8), CRm(7), Op2(2), emulate_tlb_invalidate },
+	/* TLBI VAAE1 */
+	{ Op0(1), Op1(0), CRn(8), CRm(7), Op2(3), emulate_tlb_invalidate },
+	/* TLBI VALE1 */
+	{ Op0(1), Op1(0), CRn(8), CRm(7), Op2(5), emulate_tlb_invalidate },
+	/* TLBI VAALE1 */
+	{ Op0(1), Op1(0), CRn(8), CRm(7), Op2(7), emulate_tlb_invalidate },
+
 	DBG_BCR_BVR_WCR_WVR_EL1(0),
 	DBG_BCR_BVR_WCR_WVR_EL1(1),
 	/* MDCCINT_EL1 */
@@ -1330,6 +1373,46 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 7), CRm(10), Op2( 2), access_dcsw },
 	{ Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
 
+	/*
+	 * TLB operations
+	 */
+	/* TLBIALLIS */
+	{ Op1( 0), CRn( 8), CRm( 3), Op2( 0), emulate_tlb_invalidate},
+	/* TLBIMVAIS */
+	{ Op1( 0), CRn( 8), CRm( 3), Op2( 1), emulate_tlb_invalidate},
+	/* TLBIASIDIS */
+	{ Op1( 0), CRn( 8), CRm( 3), Op2( 2), emulate_tlb_invalidate},
+	/* TLBIMVAAIS */
+	{ Op1( 0), CRn( 8), CRm( 3), Op2( 3), emulate_tlb_invalidate},
+	/* TLBIMVALIS */
+	{ Op1( 0), CRn( 8), CRm( 3), Op2( 5), emulate_tlb_invalidate},
+	/* TLBIMVAALIS */
+	{ Op1( 0), CRn( 8), CRm( 3), Op2( 7), emulate_tlb_invalidate},
+	/* ITLBIALL */
+	{ Op1( 0), CRn( 8), CRm( 5), Op2( 0), emulate_tlb_invalidate},
+	/* ITLBIMVA */
+	{ Op1( 0), CRn( 8), CRm( 5), Op2( 1), emulate_tlb_invalidate},
+	/* ITLBIASID */
+	{ Op1( 0), CRn( 8), CRm( 5), Op2( 2), emulate_tlb_invalidate},
+	/* DTLBIALL */
+	{ Op1( 0), CRn( 8), CRm( 6), Op2( 0), emulate_tlb_invalidate},
+	/* DTLBIMVA */
+	{ Op1( 0), CRn( 8), CRm( 6), Op2( 1), emulate_tlb_invalidate},
+	/* DTLBIASID */
+	{ Op1( 0), CRn( 8), CRm( 6), Op2( 2), emulate_tlb_invalidate},
+	/* TLBIALL */
+	{ Op1( 0), CRn( 8), CRm( 7), Op2( 0), emulate_tlb_invalidate},
+	/* TLBIMVA */
+	{ Op1( 0), CRn( 8), CRm( 7), Op2( 1), emulate_tlb_invalidate},
+	/* TLBIASID */
+	{ Op1( 0), CRn( 8), CRm( 7), Op2( 2), emulate_tlb_invalidate},
+	/* TLBIMVAA */
+	{ Op1( 0), CRn( 8), CRm( 7), Op2( 3), emulate_tlb_invalidate},
+	/* TLBIMVAL */
+	{ Op1( 0), CRn( 8), CRm( 7), Op2( 5), emulate_tlb_invalidate},
+	/* TLBIMVAAL */
+	{ Op1( 0), CRn( 8), CRm( 7), Op2( 7), emulate_tlb_invalidate},
+
 	/* PMU */
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcnten },
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 6/9] kvm: arm/arm64: Add host pmu to support VM introspection
From: Punit Agrawal @ 2017-01-10 11:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110113856.7183-1-punit.agrawal@arm.com>

Both AArch32 and AArch64 mode of the ARMv8 architecture support trapping
certain VM operations, e.g, TLB and cache maintenance
operations. Selective trapping of these operations for specific VMs can
be used to track the frequency with which these occur during execution.

Add a software PMU on the host that can support tracking VM
operations (in the form of PMU events). Supporting new events requires
providing callbacks to configure the VM to enable/disable the trapping
and read a count of the frequency.

The host PMU events can be controlled by tools like perf that use
standard kernel perf interfaces.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm/include/asm/kvm_host.h   |   8 ++
 arch/arm/kvm/arm.c                |   2 +
 arch/arm64/include/asm/kvm_host.h |   8 ++
 virt/kvm/arm/host_pmu.c           | 272 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 290 insertions(+)
 create mode 100644 virt/kvm/arm/host_pmu.c

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 26f0c8a0b790..b988f8801b86 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -289,6 +289,14 @@ static inline int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
 int kvm_perf_init(void);
 int kvm_perf_teardown(void);
 
+#if !defined(CONFIG_KVM_HOST_PMU)
+static inline int kvm_host_pmu_init(void) { return 0; }
+static inline void kvm_host_pmu_teardown(void) { }
+#else
+int kvm_host_pmu_init(void);
+void kvm_host_pmu_teardown(void);
+#endif
+
 void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
 
 struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 11676787ad49..058626b65b8d 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -1263,6 +1263,7 @@ static int init_subsystems(void)
 		goto out;
 
 	kvm_perf_init();
+	kvm_host_pmu_init();
 	kvm_coproc_table_init();
 
 out:
@@ -1453,6 +1454,7 @@ int kvm_arch_init(void *opaque)
 void kvm_arch_exit(void)
 {
 	kvm_perf_teardown();
+	kvm_host_pmu_teardown();
 }
 
 static int arm_init(void)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 1e83b707f14c..018f887e8964 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -349,6 +349,14 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 int kvm_perf_init(void);
 int kvm_perf_teardown(void);
 
+#if !defined(CONFIG_KVM_HOST_PMU)
+static inline int kvm_host_pmu_init(void) { return 0; }
+static inline void kvm_host_pmu_teardown(void) { }
+#else
+int kvm_host_pmu_init(void);
+void kvm_host_pmu_teardown(void);
+#endif
+
 struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
 
 static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
diff --git a/virt/kvm/arm/host_pmu.c b/virt/kvm/arm/host_pmu.c
new file mode 100644
index 000000000000..fc610ccc169a
--- /dev/null
+++ b/virt/kvm/arm/host_pmu.c
@@ -0,0 +1,272 @@
+#include <linux/cpumask.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/kvm_host.h>
+#include <linux/list.h>
+#include <linux/perf_event.h>
+#include <linux/pid.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock_types.h>
+#include <linux/sysfs.h>
+
+#include <asm/kvm_emulate.h>
+
+enum host_pmu_events {
+	KVM_HOST_MAX_EVENTS,
+};
+
+struct host_pmu {
+	struct pmu pmu;
+	spinlock_t event_list_lock;
+	struct list_head event_list_head;
+} host_pmu;
+#define to_host_pmu(p) (container_of(p, struct host_pmu, pmu))
+
+typedef void (*configure_event_fn)(struct kvm *kvm, bool enable);
+typedef u64 (*get_event_count_fn)(struct kvm *kvm);
+
+struct kvm_event_cb {
+	enum host_pmu_events event;
+	get_event_count_fn get_event_count;
+	configure_event_fn configure_event;
+};
+
+struct event_data {
+	bool enable;
+	struct kvm *kvm;
+	struct kvm_event_cb *cb;
+	struct work_struct work;
+	struct list_head event_list;
+};
+
+static struct kvm_event_cb event_callbacks[] = {
+};
+
+static struct attribute *event_attrs[] = {
+	NULL,
+};
+
+static struct attribute_group events_attr_group = {
+	.name	= "events",
+	.attrs	= event_attrs,
+};
+
+
+#define VM_MASK	GENMASK_ULL(31, 0)
+#define EVENT_MASK	GENMASK_ULL(32, 39)
+#define EVENT_SHIFT	(32)
+
+#define to_pid(cfg)	((cfg) & VM_MASK)
+#define to_event(cfg)	(((cfg) & EVENT_MASK) >> EVENT_SHIFT)
+
+PMU_FORMAT_ATTR(vm, "config:0-31");
+PMU_FORMAT_ATTR(event, "config:32-39");
+
+static struct attribute *format_attrs[] = {
+	&format_attr_vm.attr,
+	&format_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group format_attr_group = {
+	.name	= "format",
+	.attrs	= format_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+	&events_attr_group,
+	&format_attr_group,
+	NULL,
+};
+
+static void host_event_destroy(struct perf_event *event)
+{
+	struct host_pmu *host_pmu = to_host_pmu(event->pmu);
+	struct event_data *e_data = event->pmu_private;
+
+	/*
+	 * Ensure outstanding work items related to this event are
+	 * completed before freeing resources.
+	 */
+	flush_work(&e_data->work);
+
+	kvm_put_kvm(e_data->kvm);
+
+	spin_lock(&host_pmu->event_list_lock);
+	list_del(&e_data->event_list);
+	spin_unlock(&host_pmu->event_list_lock);
+	kfree(e_data);
+}
+
+void host_event_work(struct work_struct *work)
+{
+	struct event_data *e_data = container_of(work, struct event_data, work);
+	struct kvm *kvm = e_data->kvm;
+
+	e_data->cb->configure_event(kvm, e_data->enable);
+}
+
+static int host_event_init(struct perf_event *event)
+{
+	struct host_pmu *host_pmu = to_host_pmu(event->pmu);
+	int event_id = to_event(event->attr.config);
+	pid_t task_pid = to_pid(event->attr.config);
+	struct event_data *e_data, *pos;
+	bool found = false;
+	struct pid *pid;
+	struct kvm *kvm;
+	int ret = 0;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	if (has_branch_stack(event)	||
+	    is_sampling_event(event)	||
+	    event->attr.exclude_user	||
+	    event->attr.exclude_kernel	||
+	    event->attr.exclude_hv	||
+	    event->attr.exclude_idle	||
+	    event->attr.exclude_guest) {
+		return -EINVAL;
+	}
+
+	if (event->attach_state == PERF_ATTACH_TASK)
+		return -EOPNOTSUPP;
+
+	if (event->cpu < 0)
+		return -EINVAL;
+
+	if (event_id >= KVM_HOST_MAX_EVENTS)
+		return -EINVAL;
+
+	pid = find_get_pid(task_pid);
+	spin_lock(&kvm_lock);
+	list_for_each_entry(kvm, &vm_list, vm_list) {
+		if (kvm->pid == pid) {
+			kvm_get_kvm(kvm);
+			found = true;
+			break;
+		}
+	}
+	spin_unlock(&kvm_lock);
+	put_pid(pid);
+
+	if (!found)
+		return -EINVAL;
+
+	spin_lock(&host_pmu->event_list_lock);
+	/* Make sure we don't already have the (event_id, kvm) pair */
+	list_for_each_entry(pos, &host_pmu->event_list_head, event_list) {
+		if (pos->cb->event == event_id &&
+		    pos->kvm->pid == pid) {
+			kvm_put_kvm(kvm);
+			ret = -EOPNOTSUPP;
+			goto unlock;
+		}
+	}
+
+	e_data = kzalloc(sizeof(*e_data), GFP_KERNEL);
+	e_data->kvm = kvm;
+	e_data->cb = &event_callbacks[event_id];
+	INIT_WORK(&e_data->work, host_event_work);
+	event->pmu_private = e_data;
+	event->cpu = cpumask_first(cpu_online_mask);
+	event->destroy = host_event_destroy;
+
+	list_add_tail(&e_data->event_list, &host_pmu->event_list_head);
+
+unlock:
+	spin_unlock(&host_pmu->event_list_lock);
+
+	return ret;
+}
+
+static void host_event_update(struct perf_event *event)
+{
+	struct event_data *e_data = event->pmu_private;
+	struct kvm_event_cb *cb = e_data->cb;
+	struct kvm *kvm = e_data->kvm;
+	struct hw_perf_event *hw = &event->hw;
+	u64 prev_count, new_count;
+
+	do {
+		prev_count = local64_read(&hw->prev_count);
+		new_count = cb->get_event_count(kvm);
+	} while (local64_xchg(&hw->prev_count, new_count) != prev_count);
+
+	local64_add(new_count - prev_count, &event->count);
+}
+
+static void host_event_start(struct perf_event *event, int flags)
+{
+	struct event_data *e_data = event->pmu_private;
+	struct kvm_event_cb *cb = e_data->cb;
+	struct kvm *kvm = e_data->kvm;
+	u64 val;
+
+	val = cb->get_event_count(kvm);
+	local64_set(&event->hw.prev_count, val);
+
+	e_data->enable = true;
+	schedule_work(&e_data->work);
+}
+
+static void host_event_stop(struct perf_event *event, int flags)
+{
+	struct event_data *e_data = event->pmu_private;
+
+	e_data->enable = false;
+	schedule_work(&e_data->work);
+
+	if (flags & PERF_EF_UPDATE)
+		host_event_update(event);
+}
+
+static int host_event_add(struct perf_event *event, int flags)
+{
+	if (flags & PERF_EF_START)
+		host_event_start(event, flags);
+
+	return 0;
+}
+
+static void host_event_del(struct perf_event *event, int flags)
+{
+	host_event_stop(event, PERF_EF_UPDATE);
+}
+
+static void host_event_read(struct perf_event *event)
+{
+	host_event_update(event);
+}
+
+static void init_host_pmu(struct host_pmu *host_pmu)
+{
+	host_pmu->pmu = (struct pmu) {
+		.task_ctx_nr	= perf_sw_context,
+		.attr_groups	= attr_groups,
+		.event_init	= host_event_init,
+		.add		= host_event_add,
+		.del		= host_event_del,
+		.start		= host_event_start,
+		.stop		= host_event_stop,
+		.read		= host_event_read,
+		.capabilities	= PERF_PMU_CAP_NO_INTERRUPT,
+	};
+
+	INIT_LIST_HEAD(&host_pmu->event_list_head);
+	spin_lock_init(&host_pmu->event_list_lock);
+}
+
+int kvm_host_pmu_init(void)
+{
+	init_host_pmu(&host_pmu);
+
+	return perf_pmu_register(&host_pmu.pmu, "kvm", -1);
+}
+
+void kvm_host_pmu_teardown(void)
+{
+	perf_pmu_unregister(&host_pmu.pmu);
+}
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 7/9] kvm: host_pmu: Add support for tracking guest TLB operations
From: Punit Agrawal @ 2017-01-10 11:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110113856.7183-1-punit.agrawal@arm.com>

Add the callbacks required by host PMU to support monitoring guest TLB
operations.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/host_pmu.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/virt/kvm/arm/host_pmu.c b/virt/kvm/arm/host_pmu.c
index fc610ccc169a..22c3aef17ec4 100644
--- a/virt/kvm/arm/host_pmu.c
+++ b/virt/kvm/arm/host_pmu.c
@@ -13,6 +13,7 @@
 #include <asm/kvm_emulate.h>
 
 enum host_pmu_events {
+	tlb_invalidate,
 	KVM_HOST_MAX_EVENTS,
 };
 
@@ -40,10 +41,59 @@ struct event_data {
 	struct list_head event_list;
 };
 
+static u64 get_tlb_invalidate_count(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	u64 val = 0;
+	int i;
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		val += vcpu->stat.tlb_invalidate;
+
+	return val;
+}
+
+static void configure_tlb_invalidate(struct kvm *kvm, bool enable)
+{
+	struct kvm_vcpu *vcpu;
+	int i;
+
+	kvm_arm_halt_guest(kvm);
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		unsigned long hcr = vcpu_get_hcr(vcpu);
+
+		if (enable)
+			hcr |= HCR_TTLB;
+		else
+			hcr &= ~HCR_TTLB;
+
+		vcpu_set_hcr(vcpu, hcr);
+	}
+	kvm_arm_resume_guest(kvm);
+}
+
 static struct kvm_event_cb event_callbacks[] = {
+	{
+		.event			= tlb_invalidate,
+		.get_event_count	= get_tlb_invalidate_count,
+		.configure_event	= configure_tlb_invalidate,
+	}
 };
 
+static ssize_t events_sysfs_show(struct device *dev,
+				 struct device_attribute *attr, char *page)
+{
+	struct perf_pmu_events_attr *pmu_attr;
+
+	pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
+
+	return sprintf(page, "event=0x%03llx,vm=?\n", pmu_attr->id);
+}
+PMU_EVENT_ATTR(tlb_invalidate, event_attr_tlb_invalidate, tlb_invalidate,
+	       events_sysfs_show);
+
 static struct attribute *event_attrs[] = {
+	&event_attr_tlb_invalidate.attr.attr,
 	NULL,
 };
 
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 8/9] arm: KVM: Enable support for host pmu
From: Punit Agrawal @ 2017-01-10 11:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110113856.7183-1-punit.agrawal@arm.com>

Add the Kconfig option and Makefile updates to enable the recently added
support for host pmu.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Russell King <linux@armlinux.org.uk>
---
 arch/arm/kvm/Kconfig  | 4 ++++
 arch/arm/kvm/Makefile | 1 +
 2 files changed, 5 insertions(+)

diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index 90d0176fb30d..198d16c36220 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -16,6 +16,9 @@ menuconfig VIRTUALIZATION
 
 if VIRTUALIZATION
 
+config KVM_HOST_PMU
+	bool
+
 config KVM
 	bool "Kernel-based Virtual Machine (KVM) support"
 	depends on MMU && OF
@@ -30,6 +33,7 @@ config KVM
 	select SRCU
 	select MMU_NOTIFIER
 	select KVM_VFIO
+	select KVM_HOST_PMU if PERF_EVENTS
 	select HAVE_KVM_EVENTFD
 	select HAVE_KVM_IRQFD
 	select HAVE_KVM_IRQCHIP
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index d571243ab4d1..09d358499ce1 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -35,3 +35,4 @@ obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
 obj-y += $(KVM)/arm/vgic/vgic-its.o
 obj-y += $(KVM)/irqchip.o
 obj-y += $(KVM)/arm/arch_timer.o
+obj-$(CONFIG_KVM_HOST_PMU) += $(KVM)/arm/host_pmu.o
-- 
2.11.0

^ permalink raw reply related

* [PATCH v3 9/9] arm64: KVM: Enable support for the host pmu
From: Punit Agrawal @ 2017-01-10 11:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170110113856.7183-1-punit.agrawal@arm.com>

Add the Kconfig option and Makefile update the enable the recently added
host pmu.

Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/Kconfig  | 4 ++++
 arch/arm64/kvm/Makefile | 1 +
 2 files changed, 5 insertions(+)

diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 52cb7ad9b2fd..c147a3077dab 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -16,6 +16,9 @@ menuconfig VIRTUALIZATION
 
 if VIRTUALIZATION
 
+config KVM_HOST_PMU
+        bool
+
 config KVM
 	bool "Kernel-based Virtual Machine (KVM) support"
 	depends on OF
@@ -31,6 +34,7 @@ config KVM
 	select KVM_VFIO
 	select HAVE_KVM_EVENTFD
 	select HAVE_KVM_IRQFD
+	select KVM_HOST_PMU if PERF_EVENTS
 	select KVM_ARM_PMU if HW_PERF_EVENTS
 	select HAVE_KVM_MSI
 	select HAVE_KVM_IRQCHIP
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index d50a82a16ff6..3bdac93784e2 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -34,3 +34,4 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
 kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
+kvm-$(CONFIG_KVM_HOST_PMU) += $(KVM)/arm/host_pmu.o
-- 
2.11.0

^ permalink raw reply related

* [RFC PATCH v3 3/5] ARM: NOMMU: Introduce dma operations for noMMU
From: Vladimir Murzin @ 2017-01-10 11:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b6ab1436-9a80-a694-e825-b9c23b62add8@arm.com>

On 09/01/17 16:59, Robin Murphy wrote:
> On 09/01/17 16:51, Vladimir Murzin wrote:
>> Hi Robin,
>>
>> On 09/01/17 16:43, Robin Murphy wrote:
>>> Hi Vladimir,
>>>
>>> On 09/01/17 13:47, Vladimir Murzin wrote:
>>>> R/M classes of cpus can have memory covered by MPU which in turn might
>>>> configure RAM as Normal i.e. bufferable and cacheable. It breaks
>>>> dma_alloc_coherent() and friends, since data can stuck in caches now
>>>> or be buffered.
>>>>
>>>> This patch factors out DMA support for NOMMU configuration into
>>>> separate entity which provides dedicated dma_ops. We have to handle
>>>> there several cases:
>>>> - configurations with MMU/MPU setup
>>>> - configurations without MMU/MPU setup
>>>> - special case for M-class, since caches and MPU there are optional
>>>>
>>>> In general we rely on default DMA area for coherent allocations or/and
>>>> per-device memory reserves suitable for coherent DMA, so if such
>>>> regions are set coherent allocations go from there.
>>>>
>>>> In case MPU/MPU was not setup we fallback to normal page allocator for
>>>> DMA memory allocation.
>>>>
>>>> In case we run M-class cpus, for configuration without cache support
>>>> (like Cortex-M3/M4) dma operations are forced to be coherent and wired
>>>> with dma-noop (such decision is made based on cacheid global
>>>> variable); however, if caches are detected there and no DMA coherent
>>>> region is given (either default or per-device), dma is disallowed even
>>>> MPU is not set - it is because M-class implement system memory map
>>>> which defines part of address space as Normal memory.
>>>>
>>>> Reported-by: Alexandre Torgue <alexandre.torgue@st.com>
>>>> Reported-by: Andras Szemzo <sza@esh.hu>
>>>> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
>>>> ---
>>>>  arch/arm/include/asm/dma-mapping.h |   3 +-
>>>>  arch/arm/mm/Makefile               |   5 +-
>>>>  arch/arm/mm/dma-mapping-nommu.c    | 252 +++++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 256 insertions(+), 4 deletions(-)
>>>>  create mode 100644 arch/arm/mm/dma-mapping-nommu.c
>>>>
>>>> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
>>>> index bf02dbd..559faad 100644
>>>> --- a/arch/arm/include/asm/dma-mapping.h
>>>> +++ b/arch/arm/include/asm/dma-mapping.h
>>>> @@ -20,7 +20,8 @@ static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
>>>>  {
>>>>  	if (dev && dev->archdata.dma_ops)
>>>>  		return dev->archdata.dma_ops;
>>>> -	return &arm_dma_ops;
>>>> +
>>>> +	return IS_ENABLED(CONFIG_MMU) ? &arm_dma_ops : &dma_noop_ops;
>>>>  }
>>>>  
>>>>  static inline struct dma_map_ops *get_dma_ops(struct device *dev)
>>>> diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
>>>> index 2ac7988..5796357 100644
>>>> --- a/arch/arm/mm/Makefile
>>>> +++ b/arch/arm/mm/Makefile
>>>> @@ -2,9 +2,8 @@
>>>>  # Makefile for the linux arm-specific parts of the memory manager.
>>>>  #
>>>>  
>>>> -obj-y				:= dma-mapping.o extable.o fault.o init.o \
>>>> -				   iomap.o
>>>> -
>>>> +obj-y				:= extable.o fault.o init.o iomap.o
>>>> +obj-y				+= dma-mapping$(MMUEXT).o
>>>>  obj-$(CONFIG_MMU)		+= fault-armv.o flush.o idmap.o ioremap.o \
>>>>  				   mmap.o pgd.o mmu.o pageattr.o
>>>>  
>>>> diff --git a/arch/arm/mm/dma-mapping-nommu.c b/arch/arm/mm/dma-mapping-nommu.c
>>>> new file mode 100644
>>>> index 0000000..a5c50fb
>>>> --- /dev/null
>>>> +++ b/arch/arm/mm/dma-mapping-nommu.c
>>>> @@ -0,0 +1,252 @@
>>>> +/*
>>>> + *  Based on linux/arch/arm/mm/dma-mapping.c
>>>> + *
>>>> + *  Copyright (C) 2000-2004 Russell King
>>>> + *
>>>> + * 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
>>>> + * published by the Free Software Foundation.
>>>> + *
>>>> + */
>>>> +
>>>> +#include <linux/export.h>
>>>> +#include <linux/mm.h>
>>>> +#include <linux/dma-mapping.h>
>>>> +#include <linux/scatterlist.h>
>>>> +
>>>> +#include <asm/cachetype.h>
>>>> +#include <asm/cacheflush.h>
>>>> +#include <asm/outercache.h>
>>>> +#include <asm/cp15.h>
>>>> +
>>>> +#include "dma.h"
>>>> +
>>>> +/*
>>>> + *  dma_noop_ops is used if
>>>> + *   - MMU/MPU is off
>>>> + *   - cpu is v7m w/o cache support
>>>> + *   - device is coherent
>>>> + *  otherwise arm_nommu_dma_ops is used.
>>>> + *
>>>> + *  arm_nommu_dma_ops rely on consistent DMA memory (please, refer to
>>>> + *  [1] on how to declare such memory).
>>>> + *
>>>> + *  [1] Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
>>>> + */
>>>> +
>>>> +static void *arm_nommu_dma_alloc(struct device *dev, size_t size,
>>>> +				 dma_addr_t *dma_handle, gfp_t gfp,
>>>> +				 unsigned long attrs)
>>>> +
>>>> +{
>>>> +	struct dma_map_ops *ops = &dma_noop_ops;
>>>> +
>>>> +	/*
>>>> +	 * We are here because:
>>>> +	 * - no consistent DMA region has been defined, so we can't
>>>> +	 *   continue.
>>>> +	 * - there is no space left in consistent DMA region, so we
>>>> +	 *   only can fallback to generic allocator if we are
>>>> +	 *   advertised that consistency is not required.
>>>> +	 */
>>>> +
>>>> +	if (attrs & DMA_ATTR_NON_CONSISTENT)
>>>> +		return ops->alloc(dev, size, dma_handle, gfp, attrs);
>>>> +
>>>> +	WARN_ON_ONCE(1);
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +static void arm_nommu_dma_free(struct device *dev, size_t size,
>>>> +			       void *cpu_addr, dma_addr_t dma_addr,
>>>> +			       unsigned long attrs)
>>>> +{
>>>> +	struct dma_map_ops *ops = &dma_noop_ops;
>>>> +
>>>> +	if (attrs & DMA_ATTR_NON_CONSISTENT)
>>>> +		ops->free(dev, size, cpu_addr, dma_addr, attrs);
>>>> +
>>>> +	WARN_ON_ONCE(1);
>>>> +	return;
>>>> +}
>>>> +
>>>> +static int arm_nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
>>>> +			      void *cpu_addr, dma_addr_t dma_addr, size_t size,
>>>> +			      unsigned long attrs)
>>>> +{
>>>> +	struct dma_map_ops *ops = &dma_noop_ops;
>>>> +	int ret;
>>>> +
>>>> +	if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
>>>> +		return ret;
>>>> +
>>>> +	if (attrs & DMA_ATTR_NON_CONSISTENT)
>>>> +		return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
>>>> +
>>>> +	WARN_ON_ONCE(1);
>>>> +	return -ENXIO;
>>>> +}
>>>> +
>>>> +static void __dma_page_cpu_to_dev(dma_addr_t handle, size_t size,
>>>> +				  enum dma_data_direction dir)
>>>> +{
>>>> +	dmac_unmap_area(__va(handle), size, dir);
>>>> +
>>>> +	if (dir == DMA_FROM_DEVICE)
>>>> +		outer_inv_range(handle, handle + size);
>>>> +	else
>>>> +		outer_clean_range(handle, handle + size);
>>>> +}
>>>> +
>>>> +static void __dma_page_dev_to_cpu(dma_addr_t handle, size_t size,
>>>> +				  enum dma_data_direction dir)
>>>> +{
>>>> +	if (dir != DMA_TO_DEVICE) {
>>>> +		outer_inv_range(handle, handle + size);
>>>> +		dmac_unmap_area(__va(handle), size, dir);
>>>> +	}
>>>> +}
>>>
>>> Nit: I appreciate that the situation here makes it OK by construction,
>>> but CPU cache maintenance on a DMA address just looks *so* wrong :)
>>> Could we pass either the "virtual" or physical version of the address as
>>> the argument to these helpers so that the code looks less crazy at a glance?
>>
>> Something like bellow?
>>
>> static void __dma_page_dev_to_cpu(dma_addr_t paddr, size_t size,
>                                     ^
> I meant more in terms of this being a const void* or phys_addr_t ;)
> 

Fixed locally with "phys_addr_t".

>> 				  enum dma_data_direction dir)
>> {
>> 	if (dir != DMA_TO_DEVICE) {
>> 		outer_inv_range(paddr, paddr + size);
>> 		dmac_unmap_area(__va(paddr), size, dir);
>> 	}
>>
>> Btw, thanks for having a look!
> 
> Otherwise, I think the rest of the series looks OK, thanks for
> respinning it.

I'll wait for a while for more feedback and tests before submitting updated
version. 

Cheers
Vladimir

> 
> Robin.
> 
>> Cheers
>> Vladimir
>>
>>>
>>> Robin.
>>>
>>>> +static dma_addr_t arm_nommu_dma_map_page(struct device *dev, struct page *page,
>>>> +					 unsigned long offset, size_t size,
>>>> +					 enum dma_data_direction dir,
>>>> +					 unsigned long attrs)
>>>> +{
>>>> +	dma_addr_t handle = page_to_phys(page) + offset;
>>>> +
>>>> +	__dma_page_cpu_to_dev(handle, size, dir);
>>>> +
>>>> +	return handle;
>>>> +}
>>>> +
>>>> +static void arm_nommu_dma_unmap_page(struct device *dev, dma_addr_t handle,
>>>> +				     size_t size, enum dma_data_direction dir,
>>>> +				     unsigned long attrs)
>>>> +{
>>>> +	__dma_page_dev_to_cpu(handle, size, dir);
>>>> +}
>>>> +
>>>> +
>>>> +static int arm_nommu_dma_map_sg(struct device *dev, struct scatterlist *sgl,
>>>> +				int nents, enum dma_data_direction dir,
>>>> +				unsigned long attrs)
>>>> +{
>>>> +	int i;
>>>> +	struct scatterlist *sg;
>>>> +
>>>> +	for_each_sg(sgl, sg, nents, i) {
>>>> +		sg_dma_address(sg) = sg_phys(sg);
>>>> +		sg_dma_len(sg) = sg->length;
>>>> +		__dma_page_cpu_to_dev(sg_dma_address(sg), sg_dma_len(sg), dir);
>>>> +	}
>>>> +
>>>> +	return nents;
>>>> +}
>>>> +
>>>> +static void arm_nommu_dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
>>>> +				   int nents, enum dma_data_direction dir,
>>>> +				   unsigned long attrs)
>>>> +{
>>>> +	struct scatterlist *sg;
>>>> +	int i;
>>>> +
>>>> +	for_each_sg(sgl, sg, nents, i)
>>>> +		__dma_page_dev_to_cpu(sg_dma_address(sg), sg_dma_len(sg), dir);
>>>> +}
>>>> +
>>>> +static void arm_nommu_dma_sync_single_for_device(struct device *dev,
>>>> +		dma_addr_t handle, size_t size, enum dma_data_direction dir)
>>>> +{
>>>> +	__dma_page_cpu_to_dev(handle, size, dir);
>>>> +}
>>>> +
>>>> +static void arm_nommu_dma_sync_single_for_cpu(struct device *dev,
>>>> +		dma_addr_t handle, size_t size, enum dma_data_direction dir)
>>>> +{
>>>> +	__dma_page_cpu_to_dev(handle, size, dir);
>>>> +}
>>>> +
>>>> +static void arm_nommu_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
>>>> +					     int nents, enum dma_data_direction dir)
>>>> +{
>>>> +	struct scatterlist *sg;
>>>> +	int i;
>>>> +
>>>> +	for_each_sg(sgl, sg, nents, i)
>>>> +		__dma_page_cpu_to_dev(sg_dma_address(sg), sg_dma_len(sg), dir);
>>>> +}
>>>> +
>>>> +static void arm_nommu_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
>>>> +					  int nents, enum dma_data_direction dir)
>>>> +{
>>>> +	struct scatterlist *sg;
>>>> +	int i;
>>>> +
>>>> +	for_each_sg(sgl, sg, nents, i)
>>>> +		__dma_page_dev_to_cpu(sg_dma_address(sg), sg_dma_len(sg), dir);
>>>> +}
>>>> +
>>>> +struct dma_map_ops arm_nommu_dma_ops = {
>>>> +	.alloc			= arm_nommu_dma_alloc,
>>>> +	.free			= arm_nommu_dma_free,
>>>> +	.mmap			= arm_nommu_dma_mmap,
>>>> +	.map_page		= arm_nommu_dma_map_page,
>>>> +	.unmap_page		= arm_nommu_dma_unmap_page,
>>>> +	.map_sg			= arm_nommu_dma_map_sg,
>>>> +	.unmap_sg		= arm_nommu_dma_unmap_sg,
>>>> +	.sync_single_for_device	= arm_nommu_dma_sync_single_for_device,
>>>> +	.sync_single_for_cpu	= arm_nommu_dma_sync_single_for_cpu,
>>>> +	.sync_sg_for_device	= arm_nommu_dma_sync_sg_for_device,
>>>> +	.sync_sg_for_cpu	= arm_nommu_dma_sync_sg_for_cpu,
>>>> +};
>>>> +EXPORT_SYMBOL(arm_nommu_dma_ops);
>>>> +
>>>> +static struct dma_map_ops *arm_nommu_get_dma_map_ops(bool coherent)
>>>> +{
>>>> +	return coherent ? &dma_noop_ops : &arm_nommu_dma_ops;
>>>> +}
>>>> +
>>>> +void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
>>>> +			const struct iommu_ops *iommu, bool coherent)
>>>> +{
>>>> +	struct dma_map_ops *dma_ops;
>>>> +
>>>> +	if (IS_ENABLED(CONFIG_CPU_V7M)) {
>>>> +		/*
>>>> +		 * Cache support for v7m is optional, so can be treated as
>>>> +		 * coherent if no cache has been detected. Note that it is not
>>>> +		 * enough to check if MPU is in use or not since in absense of
>>>> +		 * MPU system memory map is used.
>>>> +		 */
>>>> +		dev->archdata.dma_coherent = (cacheid) ? coherent : true;
>>>> +	} else {
>>>> +		/*
>>>> +		 * Assume coherent DMA in case MMU/MPU has not been set up.
>>>> +		 */
>>>> +		dev->archdata.dma_coherent = (get_cr() & CR_M) ? coherent : true;
>>>> +	}
>>>> +
>>>> +	dma_ops = arm_nommu_get_dma_map_ops(dev->archdata.dma_coherent);
>>>> +
>>>> +	set_dma_ops(dev, dma_ops);
>>>> +}
>>>> +
>>>> +void arch_teardown_dma_ops(struct device *dev)
>>>> +{
>>>> +}
>>>> +
>>>> +int dma_supported(struct device *dev, u64 mask)
>>>> +{
>>>> +	return 1;
>>>> +}
>>>> +
>>>> +EXPORT_SYMBOL(dma_supported);
>>>> +
>>>> +#define PREALLOC_DMA_DEBUG_ENTRIES	4096
>>>> +
>>>> +static int __init dma_debug_do_init(void)
>>>> +{
>>>> +	dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
>>>> +	return 0;
>>>> +}
>>>> +core_initcall(dma_debug_do_init);
>>>>
>>>
>>>
>>
>>
>> _______________________________________________
>> 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 1/2] of: base: add support to get the number of cache levels
From: Sudeep Holla @ 2017-01-10 11:41 UTC (permalink / raw)
  To: linux-arm-kernel

It is useful to have helper function just to get the number of cache
levels for a given logical cpu. This patch adds the support for the
same.

It will be used on ARM64 platform where the device tree provides the
information for the additional non-architected/transparent/external
last level caches that are not integrated with the processors.

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
---
 drivers/of/base.c  | 22 ++++++++++++++++++++++
 include/linux/of.h |  1 +
 2 files changed, 23 insertions(+)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index d4bea3c797d6..f7a2b47b3c77 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -2268,6 +2268,28 @@ struct device_node *of_find_next_cache_node(const struct device_node *np)
 }
 
 /**
+ * of_count_cache_levels - Find the total number of cache levels for the
+ *			   given logical cpu
+ *
+ * @cpu: cpu number(logical index) for which cache levels is being counted
+ *
+ * Returns the total number of cache levels for the given logical cpu
+ */
+int of_count_cache_levels(unsigned int cpu)
+{
+	int level = 0;
+	struct device_node *np = of_cpu_device_node_get(cpu);
+
+	while (np) {
+		level++;
+		of_node_put(np);
+		np = of_find_next_cache_node(np);
+	}
+
+	return level;
+}
+
+/**
  * of_graph_parse_endpoint() - parse common endpoint node properties
  * @node: pointer to endpoint device_node
  * @endpoint: pointer to the OF endpoint data structure
diff --git a/include/linux/of.h b/include/linux/of.h
index d72f01009297..c8597ae71ff3 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -280,6 +280,7 @@ extern struct device_node *of_get_child_by_name(const struct device_node *node,
 
 /* cache lookup */
 extern struct device_node *of_find_next_cache_node(const struct device_node *);
+extern int of_count_cache_levels(unsigned int cpu);
 extern struct device_node *of_find_node_with_property(
 	struct device_node *from, const char *prop_name);
 
-- 
2.7.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox