* [PATCH 4/4] ARM: dts: apq8064: Add ADM configuration node
From: Srinivas Kandagatla @ 2017-01-04 13:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536854-21389-1-git-send-email-srinivas.kandagatla@linaro.org>
From: "Ivan T. Ivanov" <ivan.ivanov@linaro.org>
Add Application Data Mover (DMA) device node.
Connect GSBI6 UARTDM RX and TX channels to it.
Signed-off-by: Ivan T. Ivanov <ivan.ivanov@linaro.org>
---
arch/arm/boot/dts/qcom-apq8064-ifc6410.dts | 4 ++++
arch/arm/boot/dts/qcom-apq8064.dtsi | 28 ++++++++++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
index 881ce70..eec67cd 100644
--- a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
@@ -234,6 +234,10 @@
};
};
+ adm: dma at 18320000 {
+ status = "okay";
+ };
+
sata_phy0: phy at 1b400000 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index e68a8a1..8a7c325 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -564,6 +564,7 @@
#address-cells = <1>;
#size-cells = <1>;
ranges;
+ syscon-tcsr = <&tcsr>;
gsbi6_serial: serial at 16540000 {
compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
@@ -572,6 +573,13 @@
interrupts = <0 156 0x0>;
clocks = <&gcc GSBI6_UART_CLK>, <&gcc GSBI6_H_CLK>;
clock-names = "core", "iface";
+
+ qcom,rx-crci = <11>;
+ qcom,tx-crci = <6>;
+
+ dmas = <&adm 6>, <&adm 7>;
+ dma-names = "rx", "tx";
+
status = "disabled";
};
@@ -1059,6 +1067,26 @@
};
};
+ adm: dma at 18320000 {
+ compatible = "qcom,adm";
+ reg = <0x18320000 0xE0000>;
+ interrupts = <GIC_SPI 171 IRQ_TYPE_NONE>;
+ #dma-cells = <1>;
+
+ clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>;
+ clock-names = "core", "iface";
+
+ resets = <&gcc ADM0_RESET>,
+ <&gcc ADM0_PBUS_RESET>,
+ <&gcc ADM0_C0_RESET>,
+ <&gcc ADM0_C1_RESET>,
+ <&gcc ADM0_C2_RESET>;
+ reset-names = "clk", "pbus", "c0", "c1", "c2";
+ qcom,ee = <1>;
+
+ status = "disabled";
+ };
+
tcsr: syscon at 1a400000 {
compatible = "qcom,tcsr-apq8064", "syscon";
reg = <0x1a400000 0x100>;
--
2.10.1
^ permalink raw reply related
* [PATCH 3/4] ARM: dts: sd-600eval: enable 1.8v regulator on LS expansion
From: Srinivas Kandagatla @ 2017-01-04 13:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536854-21389-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch enables 1.8v regulator on LS expansion, which should be
always on according to 96boards spec.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts b/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
index 4e908af..40f7168 100644
--- a/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
@@ -132,6 +132,16 @@
bias-pull-down;
};
+ /**
+ * 1.8v required on LS expansion
+ * for mezzanine boards
+ */
+ l15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
l23 {
regulator-min-microvolt = <1700000>;
regulator-max-microvolt = <1900000>;
--
2.10.1
^ permalink raw reply related
* [PATCH 2/4] ARM: dts: sd-600eval: add hdmi support
From: Srinivas Kandagatla @ 2017-01-04 13:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536854-21389-1-git-send-email-srinivas.kandagatla@linaro.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
.../arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts | 44 ++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts b/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
index 39ae2bc..4e908af 100644
--- a/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
@@ -39,6 +39,17 @@
};
+ hdmi-out {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con: endpoint {
+ remote-endpoint = <&hdmi_out>;
+ };
+ };
+ };
+
soc {
rpm at 108000 {
regulators {
@@ -347,5 +358,38 @@
cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_HIGH>;
};
};
+
+ hdmi-tx at 4a00000 {
+ status = "okay";
+ core-vdda-supply = <&pm8921_hdmi_switch>;
+ hdmi-mux-supply = <&vcc3v3>;
+
+ hpd-gpio = <&tlmm_pinmux 72 GPIO_ACTIVE_HIGH>;
+
+ ports {
+ port at 1 {
+ endpoint {
+ remote-endpoint = <&hdmi_con>;
+ };
+ };
+ };
+ };
+
+ hdmi-phy at 4a00400 {
+ status = "okay";
+ core-vdda-supply = <&pm8921_hdmi_switch>;
+ };
+
+ mdp at 5100000 {
+ status = "okay";
+
+ ports {
+ port at 3 {
+ endpoint {
+ remote-endpoint = <&hdmi_in>;
+ };
+ };
+ };
+ };
};
};
--
2.10.1
^ permalink raw reply related
* [PATCH 1/4] ARM: dts: move hdmi pinctrl out of board file.
From: Srinivas Kandagatla @ 2017-01-04 13:34 UTC (permalink / raw)
To: linux-arm-kernel
This patch moves hdmi pinctrl defination from board file to soc level
pinctrl file. If not this pinctrl setup will be duplicated across all
the apq8064 based board files.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
arch/arm/boot/dts/qcom-apq8064-ifc6410.dts | 22 ----------------------
arch/arm/boot/dts/qcom-apq8064-pins.dtsi | 19 +++++++++++++++++++
arch/arm/boot/dts/qcom-apq8064.dtsi | 2 ++
3 files changed, 21 insertions(+), 22 deletions(-)
diff --git a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
index 3d37cab..881ce70 100644
--- a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
@@ -75,25 +75,6 @@
bias-disable;
};
};
-
- hdmi_pinctrl: hdmi-pinctrl {
- mux {
- pins = "gpio70", "gpio71", "gpio72";
- function = "hdmi";
- };
-
- pinconf_ddc {
- pins = "gpio70", "gpio71";
- bias-pull-up;
- drive-strength = <2>;
- };
-
- pinconf_hpd {
- pins = "gpio72";
- bias-pull-down;
- drive-strength = <16>;
- };
- };
};
rpm at 108000 {
@@ -368,9 +349,6 @@
hpd-gpios = <&tlmm_pinmux 72 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_pinctrl>;
-
ports {
port at 0 {
endpoint {
diff --git a/arch/arm/boot/dts/qcom-apq8064-pins.dtsi b/arch/arm/boot/dts/qcom-apq8064-pins.dtsi
index 6b801e7..cba4450 100644
--- a/arch/arm/boot/dts/qcom-apq8064-pins.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064-pins.dtsi
@@ -284,4 +284,23 @@
bias-disable = <0>;
};
};
+
+ hdmi_pinctrl: hdmi-pinctrl {
+ mux {
+ pins = "gpio70", "gpio71", "gpio72";
+ function = "hdmi";
+ };
+
+ pinconf_ddc {
+ pins = "gpio70", "gpio71";
+ bias-pull-up;
+ drive-strength = <2>;
+ };
+
+ pinconf_hpd {
+ pins = "gpio72";
+ bias-pull-down;
+ drive-strength = <16>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index 407a461..e68a8a1 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -1327,6 +1327,8 @@
hdmi: hdmi-tx at 4a00000 {
compatible = "qcom,hdmi-tx-8960";
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_pinctrl>;
reg = <0x04a00000 0x2f0>;
reg-names = "core_physical";
interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
--
2.10.1
^ permalink raw reply related
* [PATCH v2 10/19] media: Add i.MX media core driver
From: Vladimir Zapolskiy @ 2017-01-04 13:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483477049-19056-11-git-send-email-steve_longerbeam@mentor.com>
Hi Steve,
On 01/03/2017 10:57 PM, Steve Longerbeam wrote:
> Add the core media driver for i.MX SOC.
>
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
> Documentation/devicetree/bindings/media/imx.txt | 205 +++++
v2 was sent before getting Rob's review comments, but still they
should be addressed in v3.
Also I would suggest to separate device tree binding documentation
change and place it as the first patch in the series, this should
make the following DTS changes valid.
> Documentation/media/v4l-drivers/imx.rst | 430 ++++++++++
> drivers/staging/media/Kconfig | 2 +
> drivers/staging/media/Makefile | 1 +
> drivers/staging/media/imx/Kconfig | 8 +
> drivers/staging/media/imx/Makefile | 6 +
> drivers/staging/media/imx/TODO | 18 +
> drivers/staging/media/imx/imx-media-common.c | 985 ++++++++++++++++++++++
> drivers/staging/media/imx/imx-media-dev.c | 479 +++++++++++
> drivers/staging/media/imx/imx-media-fim.c | 509 +++++++++++
> drivers/staging/media/imx/imx-media-internal-sd.c | 457 ++++++++++
> drivers/staging/media/imx/imx-media-of.c | 291 +++++++
> drivers/staging/media/imx/imx-media-of.h | 25 +
> drivers/staging/media/imx/imx-media.h | 299 +++++++
> include/media/imx.h | 15 +
> include/uapi/Kbuild | 1 +
> include/uapi/linux/v4l2-controls.h | 4 +
> include/uapi/media/Kbuild | 2 +
> include/uapi/media/imx.h | 30 +
Probably Greg should ack the UAPI changes, you may consider
to split them into a separate patch.
> 19 files changed, 3767 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/imx.txt
> create mode 100644 Documentation/media/v4l-drivers/imx.rst
> create mode 100644 drivers/staging/media/imx/Kconfig
> create mode 100644 drivers/staging/media/imx/Makefile
> create mode 100644 drivers/staging/media/imx/TODO
> create mode 100644 drivers/staging/media/imx/imx-media-common.c
> create mode 100644 drivers/staging/media/imx/imx-media-dev.c
> create mode 100644 drivers/staging/media/imx/imx-media-fim.c
> create mode 100644 drivers/staging/media/imx/imx-media-internal-sd.c
> create mode 100644 drivers/staging/media/imx/imx-media-of.c
> create mode 100644 drivers/staging/media/imx/imx-media-of.h
> create mode 100644 drivers/staging/media/imx/imx-media.h
> create mode 100644 include/media/imx.h
> create mode 100644 include/uapi/media/Kbuild
> create mode 100644 include/uapi/media/imx.h
>
[snip]
> +
> +struct imx_media_subdev *
> +imx_media_find_subdev_by_sd(struct imx_media_dev *imxmd,
> + struct v4l2_subdev *sd)
> +{
> + struct imx_media_subdev *imxsd;
> + int i, ret = -ENODEV;
> +
> + for (i = 0; i < imxmd->num_subdevs; i++) {
> + imxsd = &imxmd->subdev[i];
> + if (sd == imxsd->sd) {
This can be simplifed:
...
if (sd == imxsd->sd)
return imxsd;
}
return ERR_PTR(-ENODEV);
> + ret = 0;
> + break;
> + }
> + }
> +
> + return ret ? ERR_PTR(ret) : imxsd;
> +}
> +EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_sd);
> +
> +struct imx_media_subdev *
> +imx_media_find_subdev_by_id(struct imx_media_dev *imxmd, u32 grp_id)
> +{
> + struct imx_media_subdev *imxsd;
> + int i, ret = -ENODEV;
> +
> + for (i = 0; i < imxmd->num_subdevs; i++) {
> + imxsd = &imxmd->subdev[i];
> + if (imxsd->sd && imxsd->sd->grp_id == grp_id) {
> + ret = 0;
> + break;
This can be simplifed:
...
if (imxsd->sd && imxsd->sd->grp_id == grp_i)
return imxsd;
}
return ERR_PTR(-ENODEV);
> + }
> + }
> +
> + return ret ? ERR_PTR(ret) : imxsd;
> +}
> +EXPORT_SYMBOL_GPL(imx_media_find_subdev_by_id);
> +
[snip]
> diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
> new file mode 100644
> index 0000000..8d22730
> --- /dev/null
> +++ b/drivers/staging/media/imx/imx-media-dev.c
> @@ -0,0 +1,479 @@
> +/*
> + * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC
> + *
> + * Copyright (c) 2016 Mentor Graphics Inc.
> + *
> + * 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.
> + */
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/fs.h>
> +#include <linux/timer.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/platform_device.h>
> +#include <linux/pinctrl/consumer.h>
> +#include <linux/of_platform.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-mc.h>
Please sort out the list of headers alphabetically.
> +#include <video/imx-ipu-v3.h>
> +#include <media/imx.h>
> +#include "imx-media.h"
> +#include "imx-media-of.h"
> +
> +#define DEVICE_NAME "imx-media"
I suppose you don't need this macro.
[snip]
> + */
> +static int imx_media_create_links(struct imx_media_dev *imxmd)
> +{
> + struct imx_media_subdev *local_sd;
> + struct imx_media_subdev *remote_sd;
> + struct v4l2_subdev *source, *sink;
> + struct imx_media_link *link;
> + struct imx_media_pad *pad;
> + u16 source_pad, sink_pad;
> + int num_pads, i, j, k;
> + int ret = 0;
> +
> + for (i = 0; i < imxmd->num_subdevs; i++) {
> + local_sd = &imxmd->subdev[i];
> + num_pads = local_sd->num_sink_pads + local_sd->num_src_pads;
> +
> + for (j = 0; j < num_pads; j++) {
> + pad = &local_sd->pad[j];
> +
> + for (k = 0; k < pad->num_links; k++) {
> + link = &pad->link[k];
> +
> + remote_sd = imx_media_find_async_subdev(
> + imxmd, link->remote_sd_node,
> + link->remote_devname);
> + if (!remote_sd) {
> + v4l2_warn(&imxmd->v4l2_dev,
> + "%s: no remote for %s:%d\n",
> + __func__, local_sd->sd->name,
> + link->local_pad);
> + continue;
> + }
> +
> + /* only create the source->sink links */
> + if (pad->pad.flags & MEDIA_PAD_FL_SINK)
> + continue;
> +
> + source = local_sd->sd;
> + sink = remote_sd->sd;
> + source_pad = link->local_pad;
> + sink_pad = link->remote_pad;
> +
> + v4l2_info(&imxmd->v4l2_dev,
> + "%s: %s:%d -> %s:%d\n", __func__,
> + source->name, source_pad,
> + sink->name, sink_pad);
> +
> + ret = media_create_pad_link(&source->entity,
> + source_pad,
> + &sink->entity,
> + sink_pad,
> + 0);
> + if (ret) {
> + v4l2_err(&imxmd->v4l2_dev,
> + "create_pad_link failed: %d\n",
> + ret);
> + goto out;
Indentation depth is quite terrific.
> + }
> + }
> + }
> + }
> +
> +out:
> + return ret;
>
[snip]
> +
> +static const struct of_device_id imx_media_dt_ids[] = {
> + { .compatible = "fsl,imx-media" },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, imx_media_dt_ids);
> +
> +static struct platform_driver imx_media_pdrv = {
> + .probe = imx_media_probe,
> + .remove = imx_media_remove,
> + .driver = {
> + .name = DEVICE_NAME,
> + .owner = THIS_MODULE,
Setting of .owner is not needed nowadays IIRC.
> + .of_match_table = imx_media_dt_ids,
> + },
> +};
> +
> +module_platform_driver(imx_media_pdrv);
> +
> +MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
> +MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c
> new file mode 100644
> index 0000000..52bfa8d
> --- /dev/null
> +++ b/drivers/staging/media/imx/imx-media-fim.c
> @@ -0,0 +1,509 @@
> +/*
> + * Frame Interval Monitor.
> + *
> + * Copyright (c) 2016 Mentor Graphics Inc.
> + *
> + * 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.
> + */
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +#ifdef CONFIG_IMX_GPT_ICAP
> +#include <linux/mxc_icap.h>
> +#endif
This looks clumsy. Include it unconditionally, if needed
do #ifdef's inside the header file.
> +#include <media/v4l2-subdev.h>
> +#include <media/v4l2-of.h>
> +#include <media/v4l2-ctrls.h>
Please sort out the list alphabetically.
> +#include <media/imx.h>
> +#include "imx-media.h"
> +
[snip]
> +
> +static int of_parse_fim(struct imx_media_fim *fim, struct device_node *np)
> +{
> + struct device_node *fim_np;
> + u32 val, tol[2], icap[2];
> + int ret;
> +
> + fim_np = of_get_child_by_name(np, "fim");
> + if (!fim_np) {
> + /* set to the default defaults */
> + fim->of_defaults[FIM_CL_ENABLE] = FIM_CL_ENABLE_DEF;
> + fim->of_defaults[FIM_CL_NUM] = FIM_CL_NUM_DEF;
> + fim->of_defaults[FIM_CL_NUM_SKIP] = FIM_CL_NUM_SKIP_DEF;
> + fim->of_defaults[FIM_CL_TOLERANCE_MIN] =
> + FIM_CL_TOLERANCE_MIN_DEF;
> + fim->of_defaults[FIM_CL_TOLERANCE_MAX] =
> + FIM_CL_TOLERANCE_MAX_DEF;
> + fim->icap_channel = -1;
> + return 0;
> + }
> +
> + ret = of_property_read_u32(fim_np, "enable", &val);
> + if (ret)
> + val = FIM_CL_ENABLE_DEF;
> + fim->of_defaults[FIM_CL_ENABLE] = val;
> +
> + ret = of_property_read_u32(fim_np, "num-avg", &val);
> + if (ret)
> + val = FIM_CL_NUM_DEF;
> + fim->of_defaults[FIM_CL_NUM] = val;
> +
> + ret = of_property_read_u32(fim_np, "num-skip", &val);
> + if (ret)
> + val = FIM_CL_NUM_SKIP_DEF;
> + fim->of_defaults[FIM_CL_NUM_SKIP] = val;
> +
> + ret = of_property_read_u32_array(fim_np, "tolerance-range", tol, 2);
> + if (ret) {
> + tol[0] = FIM_CL_TOLERANCE_MIN_DEF;
> + tol[1] = FIM_CL_TOLERANCE_MAX_DEF;
> + }
> + fim->of_defaults[FIM_CL_TOLERANCE_MIN] = tol[0];
> + fim->of_defaults[FIM_CL_TOLERANCE_MAX] = tol[1];
> +
> + fim->icap_channel = -1;
> + if (IS_ENABLED(CONFIG_IMX_GPT_ICAP)) {
> + ret = of_property_read_u32_array(fim_np,
> + "input-capture-channel",
> + icap, 2);
> + if (!ret) {
> + fim->icap_channel = icap[0];
> + fim->icap_flags = icap[1];
> + }
Should you return error otherwise?
> + }
> +
> + of_node_put(fim_np);
> + return 0;
> +}
[snip]
> diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c
> new file mode 100644
> index 0000000..018d05a
> --- /dev/null
> +++ b/drivers/staging/media/imx/imx-media-of.c
> @@ -0,0 +1,291 @@
> +/*
> + * Media driver for Freescale i.MX5/6 SOC
> + *
> + * Open Firmware parsing.
> + *
> + * Copyright (c) 2016 Mentor Graphics Inc.
> + *
> + * 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.
> + */
> +#include <linux/of_platform.h>
> +#include <media/v4l2-device.h>
> +#include <media/videobuf2-dma-contig.h>
> +#include <media/v4l2-subdev.h>
> +#include <media/v4l2-of.h>
> +#include <media/v4l2-ctrls.h>
Please sort out the list alphabetically.
> +#include <video/imx-ipu-v3.h>
> +#include "imx-media.h"
> +
> +static int of_add_pad_link(struct imx_media_dev *imxmd,
> + struct imx_media_pad *pad,
> + struct device_node *local_sd_node,
> + struct device_node *remote_sd_node,
> + int local_pad, int remote_pad)
> +{
> + dev_dbg(imxmd->dev, "%s: adding %s:%d -> %s:%d\n", __func__,
> + local_sd_node->name, local_pad,
> + remote_sd_node->name, remote_pad);
> +
> + return imx_media_add_pad_link(imxmd, pad, remote_sd_node, NULL,
> + local_pad, remote_pad);
> +}
> +
> +/* parse inputs property from a sensor node */
> +static void of_parse_sensor_inputs(struct imx_media_dev *imxmd,
> + struct imx_media_subdev *sensor,
> + struct device_node *sensor_np)
> +{
> + struct imx_media_sensor_input *sinput = &sensor->input;
> + int ret, i;
> +
> + for (i = 0; i < IMX_MEDIA_MAX_SENSOR_INPUTS; i++) {
> + const char *input_name;
> + u32 val;
> +
> + ret = of_property_read_u32_index(sensor_np, "inputs", i, &val);
> + if (ret)
> + break;
> +
> + sinput->value[i] = val;
> +
> + ret = of_property_read_string_index(sensor_np, "input-names",
> + i, &input_name);
> + /*
> + * if input-names not provided, they will be set using
> + * the subdev name once the sensor is known during
> + * async bind
> + */
> + if (!ret)
> + strncpy(sinput->name[i], input_name,
> + sizeof(sinput->name[i]));
> + }
> +
> + sinput->num = i;
> +
> + /* if no inputs provided just assume a single input */
> + if (sinput->num == 0)
> + sinput->num = 1;
> +}
> +
> +static void of_parse_sensor(struct imx_media_dev *imxmd,
> + struct imx_media_subdev *sensor,
> + struct device_node *sensor_np)
> +{
> + struct device_node *endpoint;
> +
> + of_parse_sensor_inputs(imxmd, sensor, sensor_np);
> +
> + endpoint = of_graph_get_next_endpoint(sensor_np, NULL);
> + if (endpoint) {
> + v4l2_of_parse_endpoint(endpoint, &sensor->sensor_ep);
> + of_node_put(endpoint);
> + }
> +}
> +
> +static int of_get_port_count(const struct device_node *np)
> +{
> + struct device_node *child;
> + int num = 0;
> +
> + /* if this node is itself a port, return 1 */
> + if (of_node_cmp(np->name, "port") == 0)
> + return 1;
> +
> + for_each_child_of_node(np, child) {
> + if (of_node_cmp(child->name, "port") == 0)
> + num++;
> + }
Unneeded bracers.
> + return num;
> +}
> +
> +/*
> + * find the remote device node and remote port id (remote pad #)
> + * given local endpoint node
> + */
> +static void of_get_remote_pad(struct device_node *epnode,
> + struct device_node **remote_node,
> + int *remote_pad)
> +{
> + struct device_node *rp, *rpp;
> + struct device_node *remote;
> +
> + rp = of_graph_get_remote_port(epnode);
> + rpp = of_graph_get_remote_port_parent(epnode);
> +
> + if (of_device_is_compatible(rpp, "fsl,imx6q-ipu")) {
> + /* the remote is one of the CSI ports */
> + remote = rp;
> + *remote_pad = 0;
> + of_node_put(rpp);
> + } else {
> + remote = rpp;
> + of_property_read_u32(rp, "reg", remote_pad);
> + of_node_put(rp);
> + }
> +
> + if (!remote || !of_device_is_available(remote)) {
> + of_node_put(remote);
> + *remote_node = NULL;
> + } else {
> + *remote_node = remote;
> + }
> +}
> +
> +static struct imx_media_subdev *
> +of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
> + bool is_csi_port)
> +{
> + struct imx_media_subdev *imxsd;
> + int i, num_pads, ret;
> +
> + if (!of_device_is_available(sd_np)) {
> + dev_dbg(imxmd->dev, "%s: %s not enabled\n", __func__,
> + sd_np->name);
> + return NULL;
> + }
> +
> + /* register this subdev with async notifier */
> + imxsd = imx_media_add_async_subdev(imxmd, sd_np, NULL);
> + if (!imxsd)
> + return NULL;
> + if (IS_ERR(imxsd))
> + return imxsd;
if (IS_ERR_OR_NULL(imxsd))
return imxsd;
> +
> + if (is_csi_port) {
> + /*
> + * the ipu-csi has one sink port and one source port.
> + * The source port is not represented in the device tree,
> + * but is described by the internal pads and links later.
> + */
> + num_pads = 2;
> + imxsd->num_sink_pads = 1;
> + } else if (of_device_is_compatible(sd_np, "fsl,imx-mipi-csi2")) {
> + num_pads = of_get_port_count(sd_np);
> + /* the mipi csi2 receiver has only one sink port */
> + imxsd->num_sink_pads = 1;
> + } else if (of_device_is_compatible(sd_np, "imx-video-mux")) {
> + num_pads = of_get_port_count(sd_np);
> + /* for the video mux, all but the last port are sinks */
> + imxsd->num_sink_pads = num_pads - 1;
> + } else {
> + /* must be a sensor */
> + num_pads = 1;
> + imxsd->num_sink_pads = 0;
> + }
> +
> + if (imxsd->num_sink_pads >= num_pads)
> + return ERR_PTR(-EINVAL);
> +
> + imxsd->num_src_pads = num_pads - imxsd->num_sink_pads;
> +
> + dev_dbg(imxmd->dev, "%s: %s has %d pads (%d sink, %d src)\n",
> + __func__, sd_np->name, num_pads,
> + imxsd->num_sink_pads, imxsd->num_src_pads);
> +
> + if (imxsd->num_sink_pads == 0) {
> + /* this might be a sensor */
> + of_parse_sensor(imxmd, imxsd, sd_np);
> + }
Unneeded bracers.
> +
> + for (i = 0; i < num_pads; i++) {
> + struct device_node *epnode = NULL, *port, *remote_np;
> + struct imx_media_subdev *remote_imxsd;
> + struct imx_media_pad *pad;
> + int remote_pad;
Too deep indentation, may be move the cycle body into a separate function?
> +
> + /* init this pad */
> + pad = &imxsd->pad[i];
> + pad->pad.flags = (i < imxsd->num_sink_pads) ?
> + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
> +
> + if (is_csi_port)
> + port = (i < imxsd->num_sink_pads) ? sd_np : NULL;
> + else
> + port = of_graph_get_port_by_id(sd_np, i);
> + if (!port)
> + continue;
> +
> + while ((epnode = of_get_next_child(port, epnode))) {
Please reuse for_each_child_of_node() here.
> + of_get_remote_pad(epnode, &remote_np, &remote_pad);
> + if (!remote_np) {
> + of_node_put(epnode);
Please remove of_node_put() here, of_get_next_child() does it.
> + continue;
> + }
> +
> + ret = of_add_pad_link(imxmd, pad, sd_np, remote_np,
> + i, remote_pad);
> + if (ret) {
> + imxsd = ERR_PTR(ret);
> + break;
> + }
> +
> + if (i < imxsd->num_sink_pads) {
> + /* follow sink endpoints upstream */
> + remote_imxsd = of_parse_subdev(imxmd,
> + remote_np,
> + false);
> + if (IS_ERR(remote_imxsd)) {
> + imxsd = remote_imxsd;
> + break;
> + }
> + }
> +
> + of_node_put(remote_np);
> + of_node_put(epnode);
> + }
> +
> + if (port != sd_np)
> + of_node_put(port);
> + if (IS_ERR(imxsd)) {
> + of_node_put(remote_np);
> + of_node_put(epnode);
> + break;
> + }
> + }
> +
> + return imxsd;
> +}
> +
> +int imx_media_of_parse(struct imx_media_dev *imxmd,
> + struct imx_media_subdev *(*csi)[4],
> + struct device_node *np)
> +{
> + struct device_node *csi_np;
> + struct imx_media_subdev *lcsi;
Please swap two lines above to get the reverse christmas tree ordering.
> + u32 ipu_id, csi_id;
> + int i, ret;
> +
> + for (i = 0; ; i++) {
> + csi_np = of_parse_phandle(np, "ports", i);
> + if (!csi_np)
> + break;
> +
> + lcsi = of_parse_subdev(imxmd, csi_np, true);
> + if (IS_ERR(lcsi)) {
> + ret = PTR_ERR(lcsi);
> + goto err_put;
> + }
> +
> + of_property_read_u32(csi_np, "reg", &csi_id);
Not sure if it is safe enough to ignore return value and potentially
left csi_id uninitialized.
> + ipu_id = of_alias_get_id(csi_np->parent, "ipu");
> +
> + if (ipu_id > 1 || csi_id > 1) {
> + dev_err(imxmd->dev, "%s: invalid ipu/csi id (%u/%u)\n",
> + __func__, ipu_id, csi_id);
> + ret = -EINVAL;
> + goto err_put;
> + }
> +
> + of_node_put(csi_np);
You can put the node right after of_alias_get_id() call, then in case
of error return right from the if block and remove the goto label.
> +
> + (*csi)[ipu_id * 2 + csi_id] = lcsi;
> + }
> +
> + return 0;
> +err_put:
> + of_node_put(csi_np);
> + return ret;
> +}
> diff --git a/drivers/staging/media/imx/imx-media-of.h b/drivers/staging/media/imx/imx-media-of.h
> new file mode 100644
> index 0000000..0c61b05
> --- /dev/null
> +++ b/drivers/staging/media/imx/imx-media-of.h
> @@ -0,0 +1,25 @@
> +/*
> + * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC
> + *
> + * Open Firmware parsing.
> + *
> + * Copyright (c) 2016 Mentor Graphics Inc.
> + *
> + * 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.
> + */
> +#ifndef _IMX_MEDIA_OF_H
> +#define _IMX_MEDIA_OF_H
> +
I do believe you should include some headers or add declarations
of "struct imx_media_dev", "struct imx_media_subdev", "struct device_node".
> +struct imx_media_subdev *
> +imx_media_of_find_subdev(struct imx_media_dev *imxmd,
> + struct device_node *np,
> + const char *name);
> +
> +int imx_media_of_parse(struct imx_media_dev *dev,
> + struct imx_media_subdev *(*csi)[4],
> + struct device_node *np);
> +
> +#endif
> diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
> new file mode 100644
> index 0000000..6a018a9
> --- /dev/null
> +++ b/drivers/staging/media/imx/imx-media.h
> @@ -0,0 +1,299 @@
> +/*
> + * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC
> + *
> + * Copyright (c) 2016 Mentor Graphics Inc.
> + *
> + * 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.
> + */
> +#ifndef _IMX_MEDIA_H
> +#define _IMX_MEDIA_H
Please insert here an empty line to improve readability.
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-subdev.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-of.h>
Please sort out the list alphabetically.
> +#include <media/videobuf2-dma-contig.h>
> +#include <video/imx-ipu-v3.h>
> +
> +/*
> + * This is somewhat arbitrary, but we need at least:
> + * - 2 camera interface subdevs
> + * - 3 IC subdevs
> + * - 2 CSI subdevs
> + * - 1 mipi-csi2 receiver subdev
> + * - 2 video-mux subdevs
> + * - 3 camera sensor subdevs (2 parallel, 1 mipi-csi2)
> + *
> + * And double the above numbers for quad i.mx!
> + */
[snip]
--
With best wishes,
Vladimir
^ permalink raw reply
* [RFC PATCH] usb: dwc3: host: add support for OTG in DWC3 host driver
From: Felipe Balbi @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536181-22356-5-git-send-email-mnarani@xilinx.com>
Hi,
Manish Narani <manish.narani@xilinx.com> writes:
> This patch adds support for OTG host mode initialization in DWC3
> host driver. Before the host initialization sequence begins. The
> driver has to make sure the no OTG peripheral mode is enabled.
>
> Signed-off-by: Manish Narani <mnarani@xilinx.com>
> ---
> drivers/usb/dwc3/host.c | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
> index 487f0ff..4caa3fe 100644
> --- a/drivers/usb/dwc3/host.c
> +++ b/drivers/usb/dwc3/host.c
> @@ -16,6 +16,8 @@
> */
>
> #include <linux/platform_device.h>
> +#include <linux/usb.h>
> +#include <linux/usb/hcd.h>
>
> #include "core.h"
>
> @@ -111,6 +113,18 @@ int dwc3_host_init(struct dwc3 *dwc)
> phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy",
> dev_name(dwc->dev));
>
> + if (dwc->dr_mode == USB_DR_MODE_OTG) {
> + struct usb_phy *phy;
> + /* Switch otg to host mode */
> + phy = usb_get_phy(USB_PHY_TYPE_USB3);
> + if (!IS_ERR(phy)) {
> + if (phy && phy->otg)
> + otg_set_host(phy->otg,
> + (struct usb_bus *)(long)1);
> + usb_put_phy(phy);
> + }
> + }
NAK. Don't change default mode for everybody. Default mode should
actually be peripheral, but let's not touch whatever HW designer has
set; at least for now.
--
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 832 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170104/357ae1ce/attachment-0001.sig>
^ permalink raw reply
* [PATCH v5 17/17] iommu/arm-smmu: Do not advertise IOMMU_CAP_INTR_REMAP anymore
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
IOMMU_CAP_INTR_REMAP has been advertised in arm-smmu(-v3) although
on ARM this property is not attached to the IOMMU but rather is
implemented in the MSI controller (GICv3 ITS).
Now vfio_iommu_type1 takes into account the MSI domain MSI remapping
capability, let's correct this.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
drivers/iommu/arm-smmu-v3.c | 2 --
drivers/iommu/arm-smmu.c | 2 --
2 files changed, 4 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 6c4111c..d9cf6cb 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1375,8 +1375,6 @@ static bool arm_smmu_capable(enum iommu_cap cap)
switch (cap) {
case IOMMU_CAP_CACHE_COHERENCY:
return true;
- case IOMMU_CAP_INTR_REMAP:
- return true; /* MSIs are just memory writes */
case IOMMU_CAP_NOEXEC:
return true;
default:
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index a354572..13d2600 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1374,8 +1374,6 @@ static bool arm_smmu_capable(enum iommu_cap cap)
* requests.
*/
return true;
- case IOMMU_CAP_INTR_REMAP:
- return true; /* MSIs are just memory writes */
case IOMMU_CAP_NOEXEC:
return true;
default:
--
1.9.1
^ permalink raw reply related
* [PATCH v5 16/17] vfio/type1: Check MSI remapping at irq domain level
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
In case the IOMMU does not bypass MSI transactions (typical
case on ARM), we check all MSI controllers are IRQ remapping
capable. If not the IRQ assignment may be unsafe.
At this stage the arm-smmu-(v3) still advertise the
IOMMU_CAP_INTR_REMAP capability at IOMMU level. This will be
removed in subsequent patches.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
drivers/vfio/vfio_iommu_type1.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index b473ef80..efcf7c3 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -40,6 +40,7 @@
#include <linux/mdev.h>
#include <linux/notifier.h>
#include <linux/dma-iommu.h>
+#include <linux/irqdomain.h>
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
@@ -1285,7 +1286,8 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
list_add(&group->next, &domain->group_list);
if (!allow_unsafe_interrupts &&
- !iommu_capable(bus, IOMMU_CAP_INTR_REMAP)) {
+ !iommu_capable(bus, IOMMU_CAP_INTR_REMAP) &&
+ (resv_msi && !irq_domain_check_msi_remap())) {
pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n",
__func__);
ret = -EPERM;
--
1.9.1
^ permalink raw reply related
* [PATCH v5 15/17] vfio/type1: Allow transparent MSI IOVA allocation
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
When attaching a group to the container, check the group's
reserved regions and test whether the IOMMU translates MSI
transactions. If yes, we initialize an IOVA allocator through
the iommu_get_msi_cookie API. This will allow the MSI IOVAs
to be transparently allocated on MSI controller's compose().
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v3 -> v4:
- test region's type: IOMMU_RESV_MSI
- restructure the code to prepare for safety assessment
- reword title
---
drivers/vfio/vfio_iommu_type1.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index f3726ba..b473ef80 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -39,6 +39,7 @@
#include <linux/pid_namespace.h>
#include <linux/mdev.h>
#include <linux/notifier.h>
+#include <linux/dma-iommu.h>
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
@@ -1177,6 +1178,28 @@ static struct vfio_group *find_iommu_group(struct vfio_domain *domain,
return NULL;
}
+static bool vfio_iommu_has_resv_msi(struct iommu_group *group,
+ phys_addr_t *base)
+{
+ struct list_head group_resv_regions;
+ struct iommu_resv_region *region, *next;
+ bool ret = false;
+
+ INIT_LIST_HEAD(&group_resv_regions);
+ iommu_get_group_resv_regions(group, &group_resv_regions);
+ list_for_each_entry(region, &group_resv_regions, list) {
+ if (region->type & IOMMU_RESV_MSI) {
+ *base = region->start;
+ ret = true;
+ goto out;
+ }
+ }
+out:
+ list_for_each_entry_safe(region, next, &group_resv_regions, list)
+ kfree(region);
+ return ret;
+}
+
static int vfio_iommu_type1_attach_group(void *iommu_data,
struct iommu_group *iommu_group)
{
@@ -1185,6 +1208,8 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
struct vfio_domain *domain, *d;
struct bus_type *bus = NULL, *mdev_bus;
int ret;
+ bool resv_msi;
+ phys_addr_t resv_msi_base;
mutex_lock(&iommu->lock);
@@ -1254,6 +1279,8 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
if (ret)
goto out_domain;
+ resv_msi = vfio_iommu_has_resv_msi(iommu_group, &resv_msi_base);
+
INIT_LIST_HEAD(&domain->group_list);
list_add(&group->next, &domain->group_list);
@@ -1300,6 +1327,9 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
if (ret)
goto out_detach;
+ if (resv_msi && iommu_get_msi_cookie(domain->domain, resv_msi_base))
+ goto out_detach;
+
list_add(&domain->next, &iommu->domain_list);
mutex_unlock(&iommu->lock);
--
1.9.1
^ permalink raw reply related
* [PATCH v5 14/17] irqchip/gicv3-its: Sets IRQ_DOMAIN_FLAG_MSI_REMAP
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
The GICv3 ITS is MSI remapping capable. Let's advertise
this property so that VFIO passthrough can assess IRQ safety.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
drivers/irqchip/irq-gic-v3-its.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 69b040f..9d4fefc 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1642,6 +1642,7 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
inner_domain->parent = its_parent;
inner_domain->bus_token = DOMAIN_BUS_NEXUS;
+ inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_REMAP;
info->ops = &its_msi_domain_ops;
info->data = its;
inner_domain->host_data = info;
--
1.9.1
^ permalink raw reply related
* [PATCH v5 13/17] irqdomain: irq_domain_check_msi_remap
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
This new function checks whether all platform and PCI
MSI domains implement IRQ remapping. This is useful to
understand whether VFIO passthrough is safe with respect
to interrupts.
On ARM typically an MSI controller can sit downstream
to the IOMMU without preventing VFIO passthrough.
As such any assigned device can write into the MSI doorbell.
In case the MSI controller implements IRQ remapping, assigned
devices will not be able to trigger interrupts towards the
host. On the contrary, the assignment must be emphasized as
unsafe with respect to interrupts.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v4 -> v5:
- Handle DOMAIN_BUS_FSL_MC_MSI domains
- Check parents
---
include/linux/irqdomain.h | 1 +
kernel/irq/irqdomain.c | 41 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+)
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index ab017b2..281a40f 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -219,6 +219,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
void *host_data);
extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token);
+extern bool irq_domain_check_msi_remap(void);
extern void irq_set_default_host(struct irq_domain *host);
extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
irq_hw_number_t hwirq, int node,
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 8c0a0ae..700caea 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -278,6 +278,47 @@ struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
EXPORT_SYMBOL_GPL(irq_find_matching_fwspec);
/**
+ * irq_domain_is_msi_remap - Check if @domain or any parent
+ * has MSI remapping support
+ * @domain: domain pointer
+ */
+static bool irq_domain_is_msi_remap(struct irq_domain *domain)
+{
+ struct irq_domain *h = domain;
+
+ for (; h; h = h->parent) {
+ if (h->flags & IRQ_DOMAIN_FLAG_MSI_REMAP)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * irq_domain_check_msi_remap() - Checks whether all MSI
+ * irq domains implement IRQ remapping
+ */
+bool irq_domain_check_msi_remap(void)
+{
+ struct irq_domain *h;
+ bool ret = true;
+
+ mutex_lock(&irq_domain_mutex);
+ list_for_each_entry(h, &irq_domain_list, link) {
+ if (((h->bus_token & DOMAIN_BUS_PCI_MSI) ||
+ (h->bus_token & DOMAIN_BUS_PLATFORM_MSI) ||
+ (h->bus_token & DOMAIN_BUS_FSL_MC_MSI)) &&
+ !irq_domain_is_msi_remap(h)) {
+ ret = false;
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&irq_domain_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(irq_domain_check_msi_remap);
+
+/**
* irq_set_default_host() - Set a "default" irq domain
* @domain: default domain pointer
*
--
1.9.1
^ permalink raw reply related
* [PATCH v5 12/17] irqdomain: Add IRQ_DOMAIN_FLAG_MSI_REMAP value
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
This new enum value aims at indicating whether the irq domain
implements MSI remapping. This property is useful to assess
the IRQ assignment safety at VFIO level.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
---
include/linux/irqdomain.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index ffb8460..ab017b2 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -183,6 +183,9 @@ enum {
/* Irq domain is an IPI domain with single virq */
IRQ_DOMAIN_FLAG_IPI_SINGLE = (1 << 3),
+ /* Irq domain is MSI remapping capable */
+ IRQ_DOMAIN_FLAG_MSI_REMAP = (1 << 4),
+
/*
* Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
* for implementation specific purposes and ignored by the
--
1.9.1
^ permalink raw reply related
* [PATCH v5 11/17] iommu/arm-smmu-v3: Implement reserved region get/put callbacks
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
iommu/arm-smmu: Implement reserved region get/put callbacks
The get() populates the list with the MSI IOVA reserved window.
At the moment an arbitray MSI IOVA window is set at 0x8000000
of size 1MB. This will allow to report those info in iommu-group
sysfs.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v4: creation
---
drivers/iommu/arm-smmu-v3.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 4d6ec44..6c4111c 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -412,6 +412,9 @@
/* High-level queue structures */
#define ARM_SMMU_POLL_TIMEOUT_US 100
+#define MSI_IOVA_BASE 0x8000000
+#define MSI_IOVA_LENGTH 0x100000
+
static bool disable_bypass;
module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO);
MODULE_PARM_DESC(disable_bypass,
@@ -1883,6 +1886,29 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
return iommu_fwspec_add_ids(dev, args->args, 1);
}
+static void arm_smmu_get_resv_regions(struct device *dev,
+ struct list_head *head)
+{
+ struct iommu_resv_region *region;
+ int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+
+ region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
+ prot, IOMMU_RESV_MSI);
+ if (!region)
+ return;
+
+ list_add_tail(®ion->list, head);
+}
+
+static void arm_smmu_put_resv_regions(struct device *dev,
+ struct list_head *head)
+{
+ struct iommu_resv_region *entry, *next;
+
+ list_for_each_entry_safe(entry, next, head, list)
+ kfree(entry);
+}
+
static struct iommu_ops arm_smmu_ops = {
.capable = arm_smmu_capable,
.domain_alloc = arm_smmu_domain_alloc,
@@ -1898,6 +1924,8 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
.domain_get_attr = arm_smmu_domain_get_attr,
.domain_set_attr = arm_smmu_domain_set_attr,
.of_xlate = arm_smmu_of_xlate,
+ .get_resv_regions = arm_smmu_get_resv_regions,
+ .put_resv_regions = arm_smmu_put_resv_regions,
.pgsize_bitmap = -1UL, /* Restricted during device attach */
};
--
1.9.1
^ permalink raw reply related
* [PATCH v5 10/17] iommu/arm-smmu: Implement reserved region get/put callbacks
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
The get() populates the list with the MSI IOVA reserved window.
At the moment an arbitray MSI IOVA window is set at 0x8000000
of size 1MB. This will allow to report those info in iommu-group
sysfs.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v3 -> v4:
- do not handle PCI host bridge windows anymore
- encode prot
RFC v2 -> v3:
- use existing get/put_resv_regions
RFC v1 -> v2:
- use defines for MSI IOVA base and length
---
drivers/iommu/arm-smmu.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index a60cded..a354572 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -281,6 +281,9 @@ enum arm_smmu_s2cr_privcfg {
#define FSYNR0_WNR (1 << 4)
+#define MSI_IOVA_BASE 0x8000000
+#define MSI_IOVA_LENGTH 0x100000
+
static int force_stage;
module_param(force_stage, int, S_IRUGO);
MODULE_PARM_DESC(force_stage,
@@ -1549,6 +1552,29 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
return iommu_fwspec_add_ids(dev, &fwid, 1);
}
+static void arm_smmu_get_resv_regions(struct device *dev,
+ struct list_head *head)
+{
+ struct iommu_resv_region *region;
+ int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+
+ region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
+ prot, IOMMU_RESV_MSI);
+ if (!region)
+ return;
+
+ list_add_tail(®ion->list, head);
+}
+
+static void arm_smmu_put_resv_regions(struct device *dev,
+ struct list_head *head)
+{
+ struct iommu_resv_region *entry, *next;
+
+ list_for_each_entry_safe(entry, next, head, list)
+ kfree(entry);
+}
+
static struct iommu_ops arm_smmu_ops = {
.capable = arm_smmu_capable,
.domain_alloc = arm_smmu_domain_alloc,
@@ -1564,6 +1590,8 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
.domain_get_attr = arm_smmu_domain_get_attr,
.domain_set_attr = arm_smmu_domain_set_attr,
.of_xlate = arm_smmu_of_xlate,
+ .get_resv_regions = arm_smmu_get_resv_regions,
+ .put_resv_regions = arm_smmu_put_resv_regions,
.pgsize_bitmap = -1UL, /* Restricted during device attach */
};
--
1.9.1
^ permalink raw reply related
* [PATCH v5 09/17] iommu/amd: Declare MSI and HT regions as reserved IOVA regions
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
This patch registers the MSI and HT regions as non mappable
reserved regions. They will be exposed in the iommu-group sysfs.
For direct-mapped regions let's also use iommu_alloc_resv_region().
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v5: creation
---
drivers/iommu/amd_iommu.c | 37 ++++++++++++++++++++++++++-----------
1 file changed, 26 insertions(+), 11 deletions(-)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index c6c3f1e..24c752d 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3164,6 +3164,7 @@ static bool amd_iommu_capable(enum iommu_cap cap)
static void amd_iommu_get_resv_regions(struct device *dev,
struct list_head *head)
{
+ struct iommu_resv_region *region;
struct unity_map_entry *entry;
int devid;
@@ -3172,28 +3173,42 @@ static void amd_iommu_get_resv_regions(struct device *dev,
return;
list_for_each_entry(entry, &amd_iommu_unity_map, list) {
- struct iommu_resv_region *region;
+ size_t length;
+ int prot = 0;
if (devid < entry->devid_start || devid > entry->devid_end)
continue;
- region = kzalloc(sizeof(*region), GFP_KERNEL);
+ length = entry->address_end - entry->address_start;
+ if (entry->prot & IOMMU_PROT_IR)
+ prot |= IOMMU_READ;
+ if (entry->prot & IOMMU_PROT_IW)
+ prot |= IOMMU_WRITE;
+
+ region = iommu_alloc_resv_region(entry->address_start,
+ length, prot,
+ IOMMU_RESV_DIRECT);
if (!region) {
pr_err("Out of memory allocating dm-regions for %s\n",
dev_name(dev));
return;
}
-
- region->start = entry->address_start;
- region->length = entry->address_end - entry->address_start;
- region->type = IOMMU_RESV_DIRECT;
- if (entry->prot & IOMMU_PROT_IR)
- region->prot |= IOMMU_READ;
- if (entry->prot & IOMMU_PROT_IW)
- region->prot |= IOMMU_WRITE;
-
list_add_tail(®ion->list, head);
}
+
+ region = iommu_alloc_resv_region(MSI_RANGE_START,
+ MSI_RANGE_END - MSI_RANGE_START + 1,
+ 0, IOMMU_RESV_NOMAP);
+ if (!region)
+ return;
+ list_add_tail(®ion->list, head);
+
+ region = iommu_alloc_resv_region(HT_RANGE_START,
+ HT_RANGE_END - HT_RANGE_START + 1,
+ 0, IOMMU_RESV_NOMAP);
+ if (!region)
+ return;
+ list_add_tail(®ion->list, head);
}
static void amd_iommu_put_resv_regions(struct device *dev,
--
1.9.1
^ permalink raw reply related
* [PATCH v5 08/17] iommu/vt-d: Implement reserved region get/put callbacks
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
This patch registers the [FEE0_0000h - FEF0_000h] 1MB MSI range
as a reserved region. This will allow to report that range
in the iommu-group sysfs.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
RFCv2 -> RFCv3:
- use get/put_resv_region callbacks.
RFC v1 -> RFC v2:
- fix intel_iommu_add_reserved_regions name
- use IOAPIC_RANGE_START and IOAPIC_RANGE_END defines
- return if the MSI region is already registered;
---
drivers/iommu/intel-iommu.c | 50 +++++++++++++++++++++++++++++++++------------
1 file changed, 37 insertions(+), 13 deletions(-)
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c66c273..4080207 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -5184,6 +5184,28 @@ static void intel_iommu_remove_device(struct device *dev)
iommu_device_unlink(iommu->iommu_dev, dev);
}
+static void intel_iommu_get_resv_regions(struct device *device,
+ struct list_head *head)
+{
+ struct iommu_resv_region *reg;
+
+ reg = iommu_alloc_resv_region(IOAPIC_RANGE_START,
+ IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1,
+ 0, IOMMU_RESV_NOMAP);
+ if (!reg)
+ return;
+ list_add_tail(®->list, head);
+}
+
+static void intel_iommu_put_resv_regions(struct device *dev,
+ struct list_head *head)
+{
+ struct iommu_resv_region *entry, *next;
+
+ list_for_each_entry_safe(entry, next, head, list)
+ kfree(entry);
+}
+
#ifdef CONFIG_INTEL_IOMMU_SVM
int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev)
{
@@ -5293,19 +5315,21 @@ struct intel_iommu *intel_svm_device_to_iommu(struct device *dev)
#endif /* CONFIG_INTEL_IOMMU_SVM */
static const struct iommu_ops intel_iommu_ops = {
- .capable = intel_iommu_capable,
- .domain_alloc = intel_iommu_domain_alloc,
- .domain_free = intel_iommu_domain_free,
- .attach_dev = intel_iommu_attach_device,
- .detach_dev = intel_iommu_detach_device,
- .map = intel_iommu_map,
- .unmap = intel_iommu_unmap,
- .map_sg = default_iommu_map_sg,
- .iova_to_phys = intel_iommu_iova_to_phys,
- .add_device = intel_iommu_add_device,
- .remove_device = intel_iommu_remove_device,
- .device_group = pci_device_group,
- .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
+ .capable = intel_iommu_capable,
+ .domain_alloc = intel_iommu_domain_alloc,
+ .domain_free = intel_iommu_domain_free,
+ .attach_dev = intel_iommu_attach_device,
+ .detach_dev = intel_iommu_detach_device,
+ .map = intel_iommu_map,
+ .unmap = intel_iommu_unmap,
+ .map_sg = default_iommu_map_sg,
+ .iova_to_phys = intel_iommu_iova_to_phys,
+ .add_device = intel_iommu_add_device,
+ .remove_device = intel_iommu_remove_device,
+ .get_resv_regions = intel_iommu_get_resv_regions,
+ .put_resv_regions = intel_iommu_put_resv_regions,
+ .device_group = pci_device_group,
+ .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
};
static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
--
1.9.1
^ permalink raw reply related
* [PATCH v5 07/17] iommu: Implement reserved_regions iommu-group sysfs file
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
A new iommu-group sysfs attribute file is introduced. It contains
the list of reserved regions for the iommu-group. Each reserved
region is described on a separate line:
- first field is the start IOVA address,
- second is the end IOVA address,
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v3 -> v4:
- add cast to long long int when printing to avoid warning on
i386
- change S_IRUGO into 0444
- remove sort. The list is natively sorted now.
The file layout is inspired of /sys/bus/pci/devices/BDF/resource.
I also read Documentation/filesystems/sysfs.txt so I expect this
to be frowned upon.
---
drivers/iommu/iommu.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index a2d51b3..15756d8 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -211,8 +211,32 @@ int iommu_get_group_resv_regions(struct iommu_group *group,
}
EXPORT_SYMBOL_GPL(iommu_get_group_resv_regions);
+static ssize_t iommu_group_show_resv_regions(struct iommu_group *group,
+ char *buf)
+{
+ struct iommu_resv_region *region, *next;
+ struct list_head group_resv_regions;
+ char *str = buf;
+
+ INIT_LIST_HEAD(&group_resv_regions);
+ iommu_get_group_resv_regions(group, &group_resv_regions);
+
+ list_for_each_entry_safe(region, next, &group_resv_regions, list) {
+ str += sprintf(str, "0x%016llx 0x%016llx\n",
+ (long long int)region->start,
+ (long long int)(region->start +
+ region->length - 1));
+ kfree(region);
+ }
+
+ return (str - buf);
+}
+
static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL);
+static IOMMU_GROUP_ATTR(reserved_regions, 0444,
+ iommu_group_show_resv_regions, NULL);
+
static void iommu_group_release(struct kobject *kobj)
{
struct iommu_group *group = to_iommu_group(kobj);
@@ -227,6 +251,8 @@ static void iommu_group_release(struct kobject *kobj)
if (group->default_domain)
iommu_domain_free(group->default_domain);
+ iommu_group_remove_file(group, &iommu_group_attr_reserved_regions);
+
kfree(group->name);
kfree(group);
}
@@ -290,6 +316,11 @@ struct iommu_group *iommu_group_alloc(void)
*/
kobject_put(&group->kobj);
+ ret = iommu_group_create_file(group,
+ &iommu_group_attr_reserved_regions);
+ if (ret)
+ return ERR_PTR(ret);
+
pr_debug("Allocated group %d\n", group->id);
return group;
--
1.9.1
^ permalink raw reply related
* [PATCH v5 06/17] iommu: iommu_get_group_resv_regions
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
Introduce iommu_get_group_resv_regions whose role consists in
enumerating all devices from the group and collecting their
reserved regions. The list is sorted and overlaps are checked.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v3 -> v4:
- take the iommu_group lock in iommu_get_group_resv_regions
- the list now is sorted and overlaps are checked
NOTE:
- we do not move list elements from device to group list since
the iommu_put_resv_regions() could not be called.
- at the moment I did not introduce any iommu_put_group_resv_regions
since it simply consists in voiding/freeing the list
---
drivers/iommu/iommu.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/iommu.h | 8 ++++++
2 files changed, 86 insertions(+)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 41c1906..a2d51b3 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -133,6 +133,84 @@ static ssize_t iommu_group_show_name(struct iommu_group *group, char *buf)
return sprintf(buf, "%s\n", group->name);
}
+static int iommu_insert_resv_region(struct iommu_resv_region *new,
+ struct list_head *regions)
+{
+ struct iommu_resv_region *region;
+ phys_addr_t start = new->start;
+ phys_addr_t end = new->start + new->length - 1;
+ struct list_head *pos = regions->next;
+
+ while (pos != regions) {
+ struct iommu_resv_region *entry =
+ list_entry(pos, struct iommu_resv_region, list);
+ phys_addr_t a = entry->start;
+ phys_addr_t b = entry->start + entry->length - 1;
+
+ if (end < a) {
+ goto insert;
+ } else if (start > b) {
+ pos = pos->next;
+ } else if ((start >= a) && (end <= b)) {
+ goto done;
+ } else {
+ phys_addr_t new_start = min(a, start);
+ phys_addr_t new_end = max(b, end);
+
+ list_del(&entry->list);
+ entry->start = new_start;
+ entry->length = new_end - new_start + 1;
+ iommu_insert_resv_region(entry, regions);
+ }
+ }
+insert:
+ region = iommu_alloc_resv_region(new->start, new->length,
+ new->prot, new->type);
+ if (!region)
+ return -ENOMEM;
+
+ list_add_tail(®ion->list, pos);
+done:
+ return 0;
+}
+
+static int
+iommu_insert_device_resv_regions(struct list_head *dev_resv_regions,
+ struct list_head *group_resv_regions)
+{
+ struct iommu_resv_region *entry;
+ int ret;
+
+ list_for_each_entry(entry, dev_resv_regions, list) {
+ ret = iommu_insert_resv_region(entry, group_resv_regions);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+int iommu_get_group_resv_regions(struct iommu_group *group,
+ struct list_head *head)
+{
+ struct iommu_device *device;
+ int ret = 0;
+
+ mutex_lock(&group->mutex);
+ list_for_each_entry(device, &group->devices, list) {
+ struct list_head dev_resv_regions;
+
+ INIT_LIST_HEAD(&dev_resv_regions);
+ iommu_get_resv_regions(device->dev, &dev_resv_regions);
+ ret = iommu_insert_device_resv_regions(&dev_resv_regions, head);
+ iommu_put_resv_regions(device->dev, &dev_resv_regions);
+ if (ret)
+ break;
+ }
+ mutex_unlock(&group->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_get_group_resv_regions);
+
static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL);
static void iommu_group_release(struct kobject *kobj)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index e97a877..b5f8492 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -246,6 +246,8 @@ extern void iommu_set_fault_handler(struct iommu_domain *domain,
extern int iommu_request_dm_for_dev(struct device *dev);
extern struct iommu_resv_region *
iommu_alloc_resv_region(phys_addr_t start, size_t length, int prot, int type);
+extern int iommu_get_group_resv_regions(struct iommu_group *group,
+ struct list_head *head);
extern int iommu_attach_group(struct iommu_domain *domain,
struct iommu_group *group);
@@ -463,6 +465,12 @@ static inline void iommu_put_resv_regions(struct device *dev,
{
}
+static inline int iommu_get_group_resv_regions(struct iommu_group *group,
+ struct list_head *head)
+{
+ return -ENODEV;
+}
+
static inline int iommu_request_dm_for_dev(struct device *dev)
{
return -ENODEV;
--
1.9.1
^ permalink raw reply related
* [PATCH v5 05/17] iommu: Only map direct mapped regions
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
As we introduced new reserved region types which do not require
mapping, let's make sure we only map direct mapped regions.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v3 -> v4:
- use region's type and reword commit message and title
---
drivers/iommu/iommu.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 927878d..41c1906 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -343,6 +343,9 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group,
start = ALIGN(entry->start, pg_size);
end = ALIGN(entry->start + entry->length, pg_size);
+ if (entry->type != IOMMU_RESV_DIRECT)
+ continue;
+
for (addr = start; addr < end; addr += pg_size) {
phys_addr_t phys_addr;
--
1.9.1
^ permalink raw reply related
* [PATCH v5 04/17] iommu: iommu_alloc_resv_region
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
Introduce a new helper serving the purpose to allocate a reserved
region. This will be used in iommu driver implementing reserved
region callbacks.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v3 -> v4:
- add INIT_LIST_HEAD(®ion->list)
- use int for prot param and add int type param
- remove implementation outside of CONFIG_IOMMU_API
---
drivers/iommu/iommu.c | 18 ++++++++++++++++++
include/linux/iommu.h | 2 ++
2 files changed, 20 insertions(+)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 1cee5c3..927878d 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1575,6 +1575,24 @@ void iommu_put_resv_regions(struct device *dev, struct list_head *list)
ops->put_resv_regions(dev, list);
}
+struct iommu_resv_region *iommu_alloc_resv_region(phys_addr_t start,
+ size_t length,
+ int prot, int type)
+{
+ struct iommu_resv_region *region;
+
+ region = kzalloc(sizeof(*region), GFP_KERNEL);
+ if (!region)
+ return NULL;
+
+ INIT_LIST_HEAD(®ion->list);
+ region->start = start;
+ region->length = length;
+ region->prot = prot;
+ region->type = type;
+ return region;
+}
+
/* Request that a device is direct mapped by the IOMMU */
int iommu_request_dm_for_dev(struct device *dev)
{
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 9128a8d..e97a877 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -244,6 +244,8 @@ extern void iommu_set_fault_handler(struct iommu_domain *domain,
extern void iommu_get_resv_regions(struct device *dev, struct list_head *list);
extern void iommu_put_resv_regions(struct device *dev, struct list_head *list);
extern int iommu_request_dm_for_dev(struct device *dev);
+extern struct iommu_resv_region *
+iommu_alloc_resv_region(phys_addr_t start, size_t length, int prot, int type);
extern int iommu_attach_group(struct iommu_domain *domain,
struct iommu_group *group);
--
1.9.1
^ permalink raw reply related
* [PATCH v5 03/17] iommu: Add a new type field in iommu_resv_region
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
We introduce a new field to differentiate the reserved region
types and specialize the apply_resv_region implementation.
Legacy direct mapped regions have IOMMU_RESV_DIRECT type.
We introduce 2 new reserved memory types:
- IOMMU_RESV_MSI will characterize MSI regions
- IOMMU_RESV_NOMAP characterize regions that cannot by mapped.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
drivers/iommu/amd_iommu.c | 1 +
include/linux/iommu.h | 7 +++++++
2 files changed, 8 insertions(+)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 04334eb..c6c3f1e 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3186,6 +3186,7 @@ static void amd_iommu_get_resv_regions(struct device *dev,
region->start = entry->address_start;
region->length = entry->address_end - entry->address_start;
+ region->type = IOMMU_RESV_DIRECT;
if (entry->prot & IOMMU_PROT_IR)
region->prot |= IOMMU_READ;
if (entry->prot & IOMMU_PROT_IW)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index bfecb8b..9128a8d 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -117,18 +117,25 @@ enum iommu_attr {
DOMAIN_ATTR_MAX,
};
+/* These are the possible reserved region types */
+#define IOMMU_RESV_DIRECT (1 << 0)
+#define IOMMU_RESV_NOMAP (1 << 1)
+#define IOMMU_RESV_MSI (1 << 2)
+
/**
* struct iommu_resv_region - descriptor for a reserved memory region
* @list: Linked list pointers
* @start: System physical start address of the region
* @length: Length of the region in bytes
* @prot: IOMMU Protection flags (READ/WRITE/...)
+ * @type: Type of the reserved region
*/
struct iommu_resv_region {
struct list_head list;
phys_addr_t start;
size_t length;
int prot;
+ int type;
};
#ifdef CONFIG_IOMMU_API
--
1.9.1
^ permalink raw reply related
* [PATCH v5 02/17] iommu: Rename iommu_dm_regions into iommu_resv_regions
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
We want to extend the callbacks used for dm regions and
use them for reserved regions. Reserved regions can be
- directly mapped regions
- regions that cannot be iommu mapped (PCI host bridge windows, ...)
- MSI regions (because they belong to another address space or because
they are not translated by the IOMMU and need special handling)
So let's rename the struct and also the callbacks.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Robin Murphy <robin.murphy@arm.com>
---
v3 -> v4:
- add Robin's A-b
---
drivers/iommu/amd_iommu.c | 20 ++++++++++----------
drivers/iommu/iommu.c | 22 +++++++++++-----------
include/linux/iommu.h | 29 +++++++++++++++--------------
3 files changed, 36 insertions(+), 35 deletions(-)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 019e027..04334eb 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3161,8 +3161,8 @@ static bool amd_iommu_capable(enum iommu_cap cap)
return false;
}
-static void amd_iommu_get_dm_regions(struct device *dev,
- struct list_head *head)
+static void amd_iommu_get_resv_regions(struct device *dev,
+ struct list_head *head)
{
struct unity_map_entry *entry;
int devid;
@@ -3172,7 +3172,7 @@ static void amd_iommu_get_dm_regions(struct device *dev,
return;
list_for_each_entry(entry, &amd_iommu_unity_map, list) {
- struct iommu_dm_region *region;
+ struct iommu_resv_region *region;
if (devid < entry->devid_start || devid > entry->devid_end)
continue;
@@ -3195,18 +3195,18 @@ static void amd_iommu_get_dm_regions(struct device *dev,
}
}
-static void amd_iommu_put_dm_regions(struct device *dev,
+static void amd_iommu_put_resv_regions(struct device *dev,
struct list_head *head)
{
- struct iommu_dm_region *entry, *next;
+ struct iommu_resv_region *entry, *next;
list_for_each_entry_safe(entry, next, head, list)
kfree(entry);
}
-static void amd_iommu_apply_dm_region(struct device *dev,
+static void amd_iommu_apply_resv_region(struct device *dev,
struct iommu_domain *domain,
- struct iommu_dm_region *region)
+ struct iommu_resv_region *region)
{
struct dma_ops_domain *dma_dom = to_dma_ops_domain(to_pdomain(domain));
unsigned long start, end;
@@ -3230,9 +3230,9 @@ static void amd_iommu_apply_dm_region(struct device *dev,
.add_device = amd_iommu_add_device,
.remove_device = amd_iommu_remove_device,
.device_group = amd_iommu_device_group,
- .get_dm_regions = amd_iommu_get_dm_regions,
- .put_dm_regions = amd_iommu_put_dm_regions,
- .apply_dm_region = amd_iommu_apply_dm_region,
+ .get_resv_regions = amd_iommu_get_resv_regions,
+ .put_resv_regions = amd_iommu_put_resv_regions,
+ .apply_resv_region = amd_iommu_apply_resv_region,
.pgsize_bitmap = AMD_IOMMU_PGSIZES,
};
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index dbe7f65..1cee5c3 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -318,7 +318,7 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group,
struct device *dev)
{
struct iommu_domain *domain = group->default_domain;
- struct iommu_dm_region *entry;
+ struct iommu_resv_region *entry;
struct list_head mappings;
unsigned long pg_size;
int ret = 0;
@@ -331,14 +331,14 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group,
pg_size = 1UL << __ffs(domain->pgsize_bitmap);
INIT_LIST_HEAD(&mappings);
- iommu_get_dm_regions(dev, &mappings);
+ iommu_get_resv_regions(dev, &mappings);
/* We need to consider overlapping regions for different devices */
list_for_each_entry(entry, &mappings, list) {
dma_addr_t start, end, addr;
- if (domain->ops->apply_dm_region)
- domain->ops->apply_dm_region(dev, domain, entry);
+ if (domain->ops->apply_resv_region)
+ domain->ops->apply_resv_region(dev, domain, entry);
start = ALIGN(entry->start, pg_size);
end = ALIGN(entry->start + entry->length, pg_size);
@@ -358,7 +358,7 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group,
}
out:
- iommu_put_dm_regions(dev, &mappings);
+ iommu_put_resv_regions(dev, &mappings);
return ret;
}
@@ -1559,20 +1559,20 @@ int iommu_domain_set_attr(struct iommu_domain *domain,
}
EXPORT_SYMBOL_GPL(iommu_domain_set_attr);
-void iommu_get_dm_regions(struct device *dev, struct list_head *list)
+void iommu_get_resv_regions(struct device *dev, struct list_head *list)
{
const struct iommu_ops *ops = dev->bus->iommu_ops;
- if (ops && ops->get_dm_regions)
- ops->get_dm_regions(dev, list);
+ if (ops && ops->get_resv_regions)
+ ops->get_resv_regions(dev, list);
}
-void iommu_put_dm_regions(struct device *dev, struct list_head *list)
+void iommu_put_resv_regions(struct device *dev, struct list_head *list)
{
const struct iommu_ops *ops = dev->bus->iommu_ops;
- if (ops && ops->put_dm_regions)
- ops->put_dm_regions(dev, list);
+ if (ops && ops->put_resv_regions)
+ ops->put_resv_regions(dev, list);
}
/* Request that a device is direct mapped by the IOMMU */
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 0ff5111..bfecb8b 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -118,13 +118,13 @@ enum iommu_attr {
};
/**
- * struct iommu_dm_region - descriptor for a direct mapped memory region
+ * struct iommu_resv_region - descriptor for a reserved memory region
* @list: Linked list pointers
* @start: System physical start address of the region
* @length: Length of the region in bytes
* @prot: IOMMU Protection flags (READ/WRITE/...)
*/
-struct iommu_dm_region {
+struct iommu_resv_region {
struct list_head list;
phys_addr_t start;
size_t length;
@@ -150,9 +150,9 @@ struct iommu_dm_region {
* @device_group: find iommu group for a particular device
* @domain_get_attr: Query domain attributes
* @domain_set_attr: Change domain attributes
- * @get_dm_regions: Request list of direct mapping requirements for a device
- * @put_dm_regions: Free list of direct mapping requirements for a device
- * @apply_dm_region: Temporary helper call-back for iova reserved ranges
+ * @get_resv_regions: Request list of reserved regions for a device
+ * @put_resv_regions: Free list of reserved regions for a device
+ * @apply_resv_region: Temporary helper call-back for iova reserved ranges
* @domain_window_enable: Configure and enable a particular window for a domain
* @domain_window_disable: Disable a particular window for a domain
* @domain_set_windows: Set the number of windows for a domain
@@ -184,11 +184,12 @@ struct iommu_ops {
int (*domain_set_attr)(struct iommu_domain *domain,
enum iommu_attr attr, void *data);
- /* Request/Free a list of direct mapping requirements for a device */
- void (*get_dm_regions)(struct device *dev, struct list_head *list);
- void (*put_dm_regions)(struct device *dev, struct list_head *list);
- void (*apply_dm_region)(struct device *dev, struct iommu_domain *domain,
- struct iommu_dm_region *region);
+ /* Request/Free a list of reserved regions for a device */
+ void (*get_resv_regions)(struct device *dev, struct list_head *list);
+ void (*put_resv_regions)(struct device *dev, struct list_head *list);
+ void (*apply_resv_region)(struct device *dev,
+ struct iommu_domain *domain,
+ struct iommu_resv_region *region);
/* Window handling functions */
int (*domain_window_enable)(struct iommu_domain *domain, u32 wnd_nr,
@@ -233,8 +234,8 @@ extern size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long io
extern void iommu_set_fault_handler(struct iommu_domain *domain,
iommu_fault_handler_t handler, void *token);
-extern void iommu_get_dm_regions(struct device *dev, struct list_head *list);
-extern void iommu_put_dm_regions(struct device *dev, struct list_head *list);
+extern void iommu_get_resv_regions(struct device *dev, struct list_head *list);
+extern void iommu_put_resv_regions(struct device *dev, struct list_head *list);
extern int iommu_request_dm_for_dev(struct device *dev);
extern int iommu_attach_group(struct iommu_domain *domain,
@@ -443,12 +444,12 @@ static inline void iommu_set_fault_handler(struct iommu_domain *domain,
{
}
-static inline void iommu_get_dm_regions(struct device *dev,
+static inline void iommu_get_resv_regions(struct device *dev,
struct list_head *list)
{
}
-static inline void iommu_put_dm_regions(struct device *dev,
+static inline void iommu_put_resv_regions(struct device *dev,
struct list_head *list)
{
}
--
1.9.1
^ permalink raw reply related
* [PATCH v5 01/17] iommu/dma: Allow MSI-only cookies
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536746-2725-1-git-send-email-eric.auger@redhat.com>
IOMMU domain users such as VFIO face a similar problem to DMA API ops
with regard to mapping MSI messages in systems where the MSI write is
subject to IOMMU translation. With the relevant infrastructure now in
place for managed DMA domains, it's actually really simple for other
users to piggyback off that and reap the benefits without giving up
their own IOVA management, and without having to reinvent their own
wheel in the MSI layer.
Allow such users to opt into automatic MSI remapping by dedicating a
region of their IOVA space to a managed cookie, and extend the mapping
routine to implement a trivial linear allocator in such cases, to avoid
the needless overhead of a full-blown IOVA domain.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
[Eric] fixed 2 issues on MSI path
---
drivers/iommu/dma-iommu.c | 116 +++++++++++++++++++++++++++++++++++++---------
include/linux/dma-iommu.h | 7 +++
2 files changed, 101 insertions(+), 22 deletions(-)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 2db0d64..f2c47ad 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -37,10 +37,19 @@ struct iommu_dma_msi_page {
phys_addr_t phys;
};
+enum iommu_dma_cookie_type {
+ IOMMU_DMA_IOVA_COOKIE,
+ IOMMU_DMA_MSI_COOKIE,
+};
+
struct iommu_dma_cookie {
- struct iova_domain iovad;
- struct list_head msi_page_list;
- spinlock_t msi_lock;
+ union {
+ struct iova_domain iovad;
+ dma_addr_t msi_iova;
+ };
+ struct list_head msi_page_list;
+ spinlock_t msi_lock;
+ enum iommu_dma_cookie_type type;
};
static inline struct iova_domain *cookie_iovad(struct iommu_domain *domain)
@@ -53,6 +62,19 @@ int iommu_dma_init(void)
return iova_cache_get();
}
+static struct iommu_dma_cookie *__cookie_alloc(enum iommu_dma_cookie_type type)
+{
+ struct iommu_dma_cookie *cookie;
+
+ cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
+ if (cookie) {
+ spin_lock_init(&cookie->msi_lock);
+ INIT_LIST_HEAD(&cookie->msi_page_list);
+ cookie->type = type;
+ }
+ return cookie;
+}
+
/**
* iommu_get_dma_cookie - Acquire DMA-API resources for a domain
* @domain: IOMMU domain to prepare for DMA-API usage
@@ -62,25 +84,53 @@ int iommu_dma_init(void)
*/
int iommu_get_dma_cookie(struct iommu_domain *domain)
{
+ if (domain->iova_cookie)
+ return -EEXIST;
+
+ domain->iova_cookie = __cookie_alloc(IOMMU_DMA_IOVA_COOKIE);
+ if (!domain->iova_cookie)
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL(iommu_get_dma_cookie);
+
+/**
+ * iommu_get_msi_cookie - Acquire just MSI remapping resources
+ * @domain: IOMMU domain to prepare
+ * @base: Start address of IOVA region for MSI mappings
+ *
+ * Users who manage their own IOVA allocation and do not want DMA API support,
+ * but would still like to take advantage of automatic MSI remapping, can use
+ * this to initialise their own domain appropriately. Users should reserve a
+ * contiguous IOVA region, starting at @base, large enough to accommodate the
+ * number of PAGE_SIZE mappings necessary to cover every MSI doorbell address
+ * used by the devices attached to @domain.
+ */
+int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base)
+{
struct iommu_dma_cookie *cookie;
+ if (domain->type != IOMMU_DOMAIN_UNMANAGED)
+ return -EINVAL;
+
if (domain->iova_cookie)
return -EEXIST;
- cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
+ cookie = __cookie_alloc(IOMMU_DMA_MSI_COOKIE);
if (!cookie)
return -ENOMEM;
- spin_lock_init(&cookie->msi_lock);
- INIT_LIST_HEAD(&cookie->msi_page_list);
+ cookie->msi_iova = base;
domain->iova_cookie = cookie;
return 0;
}
-EXPORT_SYMBOL(iommu_get_dma_cookie);
+EXPORT_SYMBOL(iommu_get_msi_cookie);
/**
* iommu_put_dma_cookie - Release a domain's DMA mapping resources
- * @domain: IOMMU domain previously prepared by iommu_get_dma_cookie()
+ * @domain: IOMMU domain previously prepared by iommu_get_dma_cookie() or
+ * iommu_get_msi_cookie()
*
* IOMMU drivers should normally call this from their domain_free callback.
*/
@@ -92,7 +142,7 @@ void iommu_put_dma_cookie(struct iommu_domain *domain)
if (!cookie)
return;
- if (cookie->iovad.granule)
+ if (cookie->type == IOMMU_DMA_IOVA_COOKIE && cookie->iovad.granule)
put_iova_domain(&cookie->iovad);
list_for_each_entry_safe(msi, tmp, &cookie->msi_page_list, list) {
@@ -137,11 +187,12 @@ static void iova_reserve_pci_windows(struct pci_dev *dev,
int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
u64 size, struct device *dev)
{
- struct iova_domain *iovad = cookie_iovad(domain);
+ struct iommu_dma_cookie *cookie = domain->iova_cookie;
+ struct iova_domain *iovad = &cookie->iovad;
unsigned long order, base_pfn, end_pfn;
- if (!iovad)
- return -ENODEV;
+ if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE)
+ return -EINVAL;
/* Use the smallest supported page size for IOVA granularity */
order = __ffs(domain->pgsize_bitmap);
@@ -662,11 +713,21 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
{
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iommu_dma_msi_page *msi_page;
- struct iova_domain *iovad = &cookie->iovad;
+ struct iova_domain *iovad;
struct iova *iova;
int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+ size_t size;
+
+ if (cookie->type == IOMMU_DMA_IOVA_COOKIE) {
+ iovad = &cookie->iovad;
+ size = iovad->granule;
+ } else {
+ iovad = NULL;
+ size = PAGE_SIZE;
+ }
+
+ msi_addr &= ~(phys_addr_t)(size - 1);
- msi_addr &= ~(phys_addr_t)iova_mask(iovad);
list_for_each_entry(msi_page, &cookie->msi_page_list, list)
if (msi_page->phys == msi_addr)
return msi_page;
@@ -675,13 +736,18 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
if (!msi_page)
return NULL;
- iova = __alloc_iova(domain, iovad->granule, dma_get_mask(dev));
- if (!iova)
- goto out_free_page;
-
msi_page->phys = msi_addr;
- msi_page->iova = iova_dma_addr(iovad, iova);
- if (iommu_map(domain, msi_page->iova, msi_addr, iovad->granule, prot))
+ if (iovad) {
+ iova = __alloc_iova(domain, size, dma_get_mask(dev));
+ if (!iova)
+ goto out_free_page;
+ msi_page->iova = iova_dma_addr(iovad, iova);
+ } else {
+ msi_page->iova = cookie->msi_iova;
+ cookie->msi_iova += size;
+ }
+
+ if (iommu_map(domain, msi_page->iova, msi_addr, size, prot))
goto out_free_iova;
INIT_LIST_HEAD(&msi_page->list);
@@ -689,7 +755,10 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
return msi_page;
out_free_iova:
- __free_iova(iovad, iova);
+ if (iovad)
+ __free_iova(iovad, iova);
+ else
+ cookie->msi_iova -= size;
out_free_page:
kfree(msi_page);
return NULL;
@@ -730,7 +799,10 @@ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
msg->data = ~0U;
} else {
msg->address_hi = upper_32_bits(msi_page->iova);
- msg->address_lo &= iova_mask(&cookie->iovad);
+ if (cookie->type == IOMMU_DMA_IOVA_COOKIE)
+ msg->address_lo &= iova_mask(&cookie->iovad);
+ else
+ msg->address_lo &= (PAGE_SIZE - 1);
msg->address_lo += lower_32_bits(msi_page->iova);
}
}
diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h
index 7f7e9a7..c843461 100644
--- a/include/linux/dma-iommu.h
+++ b/include/linux/dma-iommu.h
@@ -27,6 +27,7 @@
/* Domain management interface for IOMMU drivers */
int iommu_get_dma_cookie(struct iommu_domain *domain);
+int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base);
void iommu_put_dma_cookie(struct iommu_domain *domain);
/* Setup call for arch DMA mapping code */
@@ -86,6 +87,12 @@ static inline int iommu_get_dma_cookie(struct iommu_domain *domain)
return -ENODEV;
}
+static inline int iommu_get_msi_cookie(struct iommu_domain *domain,
+ dma_addr_t base)
+{
+ return -ENODEV;
+}
+
static inline void iommu_put_dma_cookie(struct iommu_domain *domain)
{
}
--
1.9.1
^ permalink raw reply related
* [PATCH v5 00/17] KVM PCIe/MSI passthrough on ARM/ARM64 and IOVA reserved regions
From: Eric Auger @ 2017-01-04 13:32 UTC (permalink / raw)
To: linux-arm-kernel
Following LPC discussions, we now report reserved regions through
iommu-group sysfs reserved_regions attribute file.
Reserved regions are populated through the IOMMU get_resv_region
callback (former get_dm_regions), now implemented by amd-iommu,
intel-iommu and arm-smmu:
- the intel-iommu reports the [0xfee00000 - 0xfeefffff] MSI window
as an IOMMU_RESV_NOMAP reserved region.
- the amd-iommu reports device direct mapped regions, the MSI region
and HT regions.
- the arm-smmu reports the MSI window (arbitrarily located at
0x8000000 and 1MB large).
Unsafe interrupt assignment is tested by enumerating all MSI irq
domains and checking MSI remapping is supported in the above hierarchy.
This check is done in case we detect the iommu translates MSI
(an IOMMU_RESV_MSI window exists). Otherwise the IRQ remapping
capability is checked at IOMMU level. Obviously this is a defensive
IRQ safety assessment: Assuming there are several MSI controllers
in the system and at least one does not implement IRQ remapping,
the assignment will be considered as unsafe (even if this controller
is not acessible from the assigned devices).
The series integrates a not officially posted patch from Robin:
"iommu/dma: Allow MSI-only cookies".
Best Regards
Eric
Git: complete series available at
https://github.com/eauger/linux/tree/v4.10-rc2-reserved-v5
History:
RFCv4 -> PATCHv5
- fix IRQ security assessment by looking at irq domain parents
- check DOMAIN_BUS_FSL_MC_MSI irq domains
- AMD MSI and HT regions are exposed in iommu group sysfs
RFCv3 -> RFCv4:
- arm-smmu driver does not register PCI host bridge windows as
reserved regions anymore
- Implement reserved region get/put callbacks also in arm-smmuv3
- take the iommu_group lock on iommu_get_group_resv_regions
- add a type field in iommu_resv_region instead of using prot
- init the region list_head in iommu_alloc_resv_region, also
add type parameter
- iommu_insert_resv_region manage overlaps and sort reserved
windows
- address IRQ safety assessment by enumerating all the MSI irq
domains and checking the MSI_REMAP flag
- update Documentation/ABI/testing/sysfs-kernel-iommu_groups
RFC v2 -> v3:
- switch to an iommu-group sysfs API
- use new dummy allocator provided by Robin
- dummy allocator initialized by vfio-iommu-type1 after enumerating
the reserved regions
- at the moment ARM MSI base address/size is left unchanged compared
to v2
- we currently report reserved regions and not usable IOVA regions as
requested by Alex
RFC v1 -> v2:
- fix intel_add_reserved_regions
- add mutex lock/unlock in vfio_iommu_type1
Eric Auger (17):
iommu/dma: Allow MSI-only cookies
iommu: Rename iommu_dm_regions into iommu_resv_regions
iommu: Add a new type field in iommu_resv_region
iommu: iommu_alloc_resv_region
iommu: Only map direct mapped regions
iommu: iommu_get_group_resv_regions
iommu: Implement reserved_regions iommu-group sysfs file
iommu/vt-d: Implement reserved region get/put callbacks
iommu/amd: Declare MSI and HT regions as reserved IOVA regions
iommu/arm-smmu: Implement reserved region get/put callbacks
iommu/arm-smmu-v3: Implement reserved region get/put callbacks
irqdomain: Add IRQ_DOMAIN_FLAG_MSI_REMAP value
irqdomain: irq_domain_check_msi_remap
irqchip/gicv3-its: Sets IRQ_DOMAIN_FLAG_MSI_REMAP
vfio/type1: Allow transparent MSI IOVA allocation
vfio/type1: Check MSI remapping at irq domain level
iommu/arm-smmu: Do not advertise IOMMU_CAP_INTR_REMAP anymore
drivers/iommu/amd_iommu.c | 54 +++++++++-----
drivers/iommu/arm-smmu-v3.c | 30 +++++++-
drivers/iommu/arm-smmu.c | 30 +++++++-
drivers/iommu/dma-iommu.c | 116 ++++++++++++++++++++++++------
drivers/iommu/intel-iommu.c | 50 +++++++++----
drivers/iommu/iommu.c | 152 ++++++++++++++++++++++++++++++++++++---
drivers/irqchip/irq-gic-v3-its.c | 1 +
drivers/vfio/vfio_iommu_type1.c | 34 ++++++++-
include/linux/dma-iommu.h | 7 ++
include/linux/iommu.h | 46 ++++++++----
include/linux/irqdomain.h | 4 ++
kernel/irq/irqdomain.c | 41 +++++++++++
12 files changed, 481 insertions(+), 84 deletions(-)
--
1.9.1
^ permalink raw reply
* [RFC PATCH] usb: dwc3: add support for OTG driver compilation
From: Felipe Balbi @ 2017-01-04 13:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483536181-22356-2-git-send-email-mnarani@xilinx.com>
Hi,
Manish Narani <manish.narani@xilinx.com> writes:
> This patch adds support for OTG driver compilation and object
> file creation
>
> Signed-off-by: Manish Narani <mnarani@xilinx.com>
> ---
> drivers/usb/dwc3/Makefile | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
> index ffca340..2d269ad 100644
> --- a/drivers/usb/dwc3/Makefile
> +++ b/drivers/usb/dwc3/Makefile
> @@ -17,6 +17,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
> dwc3-y += gadget.o ep0.o
> endif
>
> +ifneq ($(CONFIG_USB_DWC3_DUAL_ROLE),)
> + dwc3-y += otg.o
> +endif
you just broke compilation
--
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 832 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170104/5e6aebb4/attachment.sig>
^ 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