* [PATCH v4 0/2] ARM: dts: sun6i: hummingbird-a31: Enable display output through VGA bridge
From: Chen-Yu Tsai @ 2016-11-16 15:42 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This is v4 of my sun6i DRM/KMS display enablement series. It adds
regulator support to the dumb-vga-dac bridge and enables the VGA
output on the A31 Hummingbird.
Changes since v3:
- Add Rob's Ack.
- Fix up enable/disable callbacks as Archit suggested.
- Dropped pinmux settings for GPIO pin.
Changes since v2:
- Changed the enable-gpio of dumb-vga-dac to vdd-supply regulator.
This better matches the hardware that I have: the DAC has a fixed
regulator dropping the voltage from the board-wide 5V to 3.3V the
DAC uses. The regulator is controlled through a GPIO pin.
- Renamed the node of the VGA connector from "vga" to "vga-connector".
- Renamed the node of the VGA DAC from "bridge" to "vga-dac".
Regards
ChenYu
Chen-Yu Tsai (2):
drm/bridge: dumb-vga-dac: Support a VDD regulator supply
ARM: dts: sun6i: hummingbird-a31: Enable display output through VGA
bridge
.../bindings/display/bridge/dumb-vga-dac.txt | 2 +
arch/arm/boot/dts/sun6i-a31-hummingbird.dts | 67 ++++++++++++++++++++++
drivers/gpu/drm/bridge/dumb-vga-dac.c | 35 +++++++++++
3 files changed, 104 insertions(+)
--
2.10.2
^ permalink raw reply
* [PATCH v7 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
From: Sean Paul @ 2016-11-16 15:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479303831-74134-2-git-send-email-zourongrong@gmail.com>
On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add DRM master driver for Hisilicon Hibmc SoC which used for
> Out-of-band management. Blow is the general hardware connection,
> both the Hibmc and the host CPU are on the same mother board.
>
> +----------+ +----------+
> | | PCIe | Hibmc |
> |host CPU( |<----->| display |
> |arm64,x86)| |subsystem |
> +----------+ +----------+
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
> ---
In the future, please keep track of the differences between patch
versions. I noticed you have a short changelog in the cover letter,
but it really helps to add one per-patch as well, it makes reviewing
much simpler.
Reviewed-by: Sean Paul <seanpaul@chromium.org>
> drivers/gpu/drm/hisilicon/Kconfig | 1 +
> drivers/gpu/drm/hisilicon/Makefile | 1 +
> drivers/gpu/drm/hisilicon/hibmc/Kconfig | 9 +
> drivers/gpu/drm/hisilicon/hibmc/Makefile | 4 +
> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 308 +++++++++++++++++++++++
> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 41 +++
> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 196 +++++++++++++++
> 7 files changed, 560 insertions(+)
> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>
> diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
> index 558c61b..2fd2724 100644
> --- a/drivers/gpu/drm/hisilicon/Kconfig
> +++ b/drivers/gpu/drm/hisilicon/Kconfig
> @@ -2,4 +2,5 @@
> # hisilicon drm device configuration.
> # Please keep this list sorted alphabetically
>
> +source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
> source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
> diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
> index e3f6d49..c8155bf 100644
> --- a/drivers/gpu/drm/hisilicon/Makefile
> +++ b/drivers/gpu/drm/hisilicon/Makefile
> @@ -2,4 +2,5 @@
> # Makefile for hisilicon drm drivers.
> # Please keep this list sorted alphabetically
>
> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
> obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> new file mode 100644
> index 0000000..380622a
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> @@ -0,0 +1,9 @@
> +config DRM_HISI_HIBMC
> + tristate "DRM Support for Hisilicon Hibmc"
> + depends on DRM && PCI
> + select DRM_KMS_HELPER
> + select DRM_TTM
> +
> + help
> + Choose this option if you have a Hisilicon Hibmc soc chipset.
> + If M is selected the module will be called hibmc-drm.
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> new file mode 100644
> index 0000000..47962a0
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -0,0 +1,4 @@
> +ccflags-y := -Iinclude/drm
> +hibmc-drm-y := hibmc_drm_drv.o
> +
> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> new file mode 100644
> index 0000000..6d20580
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -0,0 +1,308 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + * Rongrong Zou <zourongrong@huawei.com>
> + * Rongrong Zou <zourongrong@gmail.com>
> + * Jianhua Li <lijianhua@huawei.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.
> + *
> + */
> +
> +#include <linux/console.h>
> +#include <linux/module.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +static const struct file_operations hibmc_fops = {
> + .owner = THIS_MODULE,
> + .open = drm_open,
> + .release = drm_release,
> + .unlocked_ioctl = drm_ioctl,
> + .compat_ioctl = drm_compat_ioctl,
> + .poll = drm_poll,
> + .read = drm_read,
> + .llseek = no_llseek,
> +};
> +
> +static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
> +{
> + return 0;
> +}
> +
> +static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
> +{
> +}
> +
> +static struct drm_driver hibmc_driver = {
> + .fops = &hibmc_fops,
> + .name = "hibmc",
> + .date = "20160828",
> + .desc = "hibmc drm driver",
> + .major = 1,
> + .minor = 0,
> + .get_vblank_counter = drm_vblank_no_hw_counter,
> + .enable_vblank = hibmc_enable_vblank,
> + .disable_vblank = hibmc_disable_vblank,
> +};
> +
> +static int hibmc_pm_suspend(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static int hibmc_pm_resume(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static const struct dev_pm_ops hibmc_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
> + hibmc_pm_resume)
> +};
> +
> +/*
> + * It can operate in one of three modes: 0, 1 or Sleep.
> + */
> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
> + unsigned int power_mode)
> +{
> + unsigned int control_value = 0;
> + void __iomem *mmio = priv->mmio;
> + unsigned int input = 1;
> +
> + if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
> + return;
> +
> + if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
> + input = 0;
> +
> + control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
> + control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
> + HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
> + control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
> + control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
> + writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
> +}
> +
> +void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
> +{
> + unsigned int gate_reg;
> + unsigned int mode;
> + void __iomem *mmio = priv->mmio;
> +
> + /* Get current power mode. */
> + mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
> + HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
> +
> + switch (mode) {
> + case HIBMC_PW_MODE_CTL_MODE_MODE0:
> + gate_reg = HIBMC_MODE0_GATE;
> + break;
> +
> + case HIBMC_PW_MODE_CTL_MODE_MODE1:
> + gate_reg = HIBMC_MODE1_GATE;
> + break;
> +
> + default:
> + gate_reg = HIBMC_MODE0_GATE;
> + break;
> + }
> + writel(gate, mmio + gate_reg);
> +}
> +
> +static void hibmc_hw_config(struct hibmc_drm_private *priv)
> +{
> + unsigned int reg;
> +
> + /* On hardware reset, power mode 0 is default. */
> + hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> + /* Enable display power gate & LOCALMEM power gate*/
> + reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> + reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> + reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> + reg |= HIBMC_CURR_GATE_DISPLAY(1);
> + reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +
> + hibmc_set_current_gate(priv, reg);
> +
> + /*
> + * Reset the memory controller. If the memory controller
> + * is not reset in chip,the system might hang when sw accesses
> + * the memory.The memory should be resetted after
> + * changing the MXCLK.
> + */
> + reg = readl(priv->mmio + HIBMC_MISC_CTRL);
> + reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> + reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
> + writel(reg, priv->mmio + HIBMC_MISC_CTRL);
> +
> + reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> + reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
> +
> + writel(reg, priv->mmio + HIBMC_MISC_CTRL);
> +}
> +
> +static int hibmc_hw_map(struct hibmc_drm_private *priv)
> +{
> + struct drm_device *dev = priv->dev;
> + struct pci_dev *pdev = dev->pdev;
> + resource_size_t addr, size, ioaddr, iosize;
> +
> + ioaddr = pci_resource_start(pdev, 1);
> + iosize = pci_resource_len(pdev, 1);
> + priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize);
> + if (!priv->mmio) {
> + DRM_ERROR("Cannot map mmio region\n");
> + return -ENOMEM;
> + }
> +
> + addr = pci_resource_start(pdev, 0);
> + size = pci_resource_len(pdev, 0);
> + priv->fb_map = devm_ioremap(dev->dev, addr, size);
> + if (!priv->fb_map) {
> + DRM_ERROR("Cannot map framebuffer\n");
> + return -ENOMEM;
> + }
> + priv->fb_base = addr;
> + priv->fb_size = size;
> +
> + return 0;
> +}
> +
> +static int hibmc_hw_init(struct hibmc_drm_private *priv)
> +{
> + int ret;
> +
> + ret = hibmc_hw_map(priv);
> + if (ret)
> + return ret;
> +
> + hibmc_hw_config(priv);
> +
> + return 0;
> +}
> +
> +static int hibmc_unload(struct drm_device *dev)
> +{
> + return 0;
> +}
> +
> +static int hibmc_load(struct drm_device *dev)
> +{
> + struct hibmc_drm_private *priv;
> + int ret;
> +
> + priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv) {
> + DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
> + return -ENOMEM;
> + }
> + dev->dev_private = priv;
> + priv->dev = dev;
> +
> + ret = hibmc_hw_init(priv);
> + if (ret)
> + goto err;
> +
> + return 0;
> +
> +err:
> + hibmc_unload(dev);
> + DRM_ERROR("failed to initialize drm driver: %d\n", ret);
> + return ret;
> +}
> +
> +static int hibmc_pci_probe(struct pci_dev *pdev,
> + const struct pci_device_id *ent)
> +{
> + struct drm_device *dev;
> + int ret;
> +
> + dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
> + if (!dev) {
> + DRM_ERROR("failed to allocate drm_device\n");
> + return -ENOMEM;
> + }
> +
> + dev->pdev = pdev;
> + pci_set_drvdata(pdev, dev);
> +
> + ret = pci_enable_device(pdev);
> + if (ret) {
> + DRM_ERROR("failed to enable pci device: %d\n", ret);
> + goto err_free;
> + }
> +
> + ret = hibmc_load(dev);
> + if (ret) {
> + DRM_ERROR("failed to load hibmc: %d\n", ret);
> + goto err_disable;
> + }
> +
> + ret = drm_dev_register(dev, 0);
> + if (ret) {
> + DRM_ERROR("failed to register drv for userspace access: %d\n",
> + ret);
> + goto err_unload;
> + }
> + return 0;
> +
> +err_unload:
> + hibmc_unload(dev);
> +err_disable:
> + pci_disable_device(pdev);
> +err_free:
> + drm_dev_unref(dev);
> +
> + return ret;
> +}
> +
> +static void hibmc_pci_remove(struct pci_dev *pdev)
> +{
> + struct drm_device *dev = pci_get_drvdata(pdev);
> +
> + drm_dev_unregister(dev);
> + hibmc_unload(dev);
> + drm_dev_unref(dev);
> +}
> +
> +static struct pci_device_id hibmc_pci_table[] = {
> + {0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
> + {0,}
> +};
> +
> +static struct pci_driver hibmc_pci_driver = {
> + .name = "hibmc-drm",
> + .id_table = hibmc_pci_table,
> + .probe = hibmc_pci_probe,
> + .remove = hibmc_pci_remove,
> + .driver.pm = &hibmc_pm_ops,
> +};
> +
> +static int __init hibmc_init(void)
> +{
> + return pci_register_driver(&hibmc_pci_driver);
> +}
> +
> +static void __exit hibmc_exit(void)
> +{
> + return pci_unregister_driver(&hibmc_pci_driver);
> +}
> +
> +module_init(hibmc_init);
> +module_exit(hibmc_exit);
> +
> +MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
> +MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
> +MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> new file mode 100644
> index 0000000..840cd5a
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -0,0 +1,41 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + * Rongrong Zou <zourongrong@huawei.com>
> + * Rongrong Zou <zourongrong@gmail.com>
> + * Jianhua Li <lijianhua@huawei.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.
> + *
> + */
> +
> +#ifndef HIBMC_DRM_DRV_H
> +#define HIBMC_DRM_DRV_H
> +
> +#include <drm/drmP.h>
> +
> +struct hibmc_drm_private {
> + /* hw */
> + void __iomem *mmio;
> + void __iomem *fb_map;
> + unsigned long fb_base;
> + unsigned long fb_size;
> +
> + /* drm */
> + struct drm_device *dev;
> +
> +};
> +
> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
> + unsigned int power_mode);
> +void hibmc_set_current_gate(struct hibmc_drm_private *priv,
> + unsigned int gate);
> +
> +#endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
> new file mode 100644
> index 0000000..f7035bf
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
> @@ -0,0 +1,196 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + * Rongrong Zou <zourongrong@huawei.com>
> + * Rongrong Zou <zourongrong@gmail.com>
> + * Jianhua Li <lijianhua@huawei.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.
> + *
> + */
> +
> +#ifndef HIBMC_DRM_HW_H
> +#define HIBMC_DRM_HW_H
> +
> +/* register definition */
> +#define HIBMC_MISC_CTRL 0x4
> +
> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x) ((x) << 6)
> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK 0x40
> +
> +#define HIBMC_CURRENT_GATE 0x000040
> +#define HIBMC_CURR_GATE_DISPLAY(x) ((x) << 2)
> +#define HIBMC_CURR_GATE_DISPLAY_MASK 0x4
> +
> +#define HIBMC_CURR_GATE_LOCALMEM(x) ((x) << 1)
> +#define HIBMC_CURR_GATE_LOCALMEM_MASK 0x2
> +
> +#define HIBMC_MODE0_GATE 0x000044
> +#define HIBMC_MODE1_GATE 0x000048
> +#define HIBMC_POWER_MODE_CTRL 0x00004C
> +
> +#define HIBMC_PW_MODE_CTL_OSC_INPUT(x) ((x) << 3)
> +#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK 0x8
> +
> +#define HIBMC_PW_MODE_CTL_MODE(x) ((x) << 0)
> +#define HIBMC_PW_MODE_CTL_MODE_MASK 0x03
> +#define HIBMC_PW_MODE_CTL_MODE_SHIFT 0
> +
> +#define HIBMC_PW_MODE_CTL_MODE_MODE0 0
> +#define HIBMC_PW_MODE_CTL_MODE_MODE1 1
> +#define HIBMC_PW_MODE_CTL_MODE_SLEEP 2
> +
> +#define HIBMC_PANEL_PLL_CTRL 0x00005C
> +#define HIBMC_CRT_PLL_CTRL 0x000060
> +
> +#define HIBMC_PLL_CTRL_BYPASS(x) ((x) << 18)
> +#define HIBMC_PLL_CTRL_BYPASS_MASK 0x40000
> +
> +#define HIBMC_PLL_CTRL_POWER(x) ((x) << 17)
> +#define HIBMC_PLL_CTRL_POWER_MASK 0x20000
> +
> +#define HIBMC_PLL_CTRL_INPUT(x) ((x) << 16)
> +#define HIBMC_PLL_CTRL_INPUT_MASK 0x10000
> +
> +#define HIBMC_PLL_CTRL_POD(x) ((x) << 14)
> +#define HIBMC_PLL_CTRL_POD_MASK 0xC000
> +
> +#define HIBMC_PLL_CTRL_OD(x) ((x) << 12)
> +#define HIBMC_PLL_CTRL_OD_MASK 0x3000
> +
> +#define HIBMC_PLL_CTRL_N(x) ((x) << 8)
> +#define HIBMC_PLL_CTRL_N_MASK 0xF00
> +
> +#define HIBMC_PLL_CTRL_M(x) ((x) << 0)
> +#define HIBMC_PLL_CTRL_M_MASK 0xFF
> +
> +#define HIBMC_CRT_DISP_CTL 0x80200
> +
> +#define HIBMC_CRT_DISP_CTL_CRTSELECT(x) ((x) << 25)
> +#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK 0x2000000
> +
> +#define HIBMC_CRTSELECT_CRT 1
> +
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x) ((x) << 14)
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK 0x4000
> +
> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x) ((x) << 13)
> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK 0x2000
> +
> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x) ((x) << 12)
> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK 0x1000
> +
> +#define HIBMC_CRT_DISP_CTL_TIMING(x) ((x) << 8)
> +#define HIBMC_CRT_DISP_CTL_TIMING_MASK 0x100
> +
> +#define HIBMC_CRT_DISP_CTL_PLANE(x) ((x) << 2)
> +#define HIBMC_CRT_DISP_CTL_PLANE_MASK 4
> +
> +#define HIBMC_CRT_DISP_CTL_FORMAT(x) ((x) << 0)
> +#define HIBMC_CRT_DISP_CTL_FORMAT_MASK 0x03
> +
> +#define HIBMC_CRT_FB_ADDRESS 0x080204
> +
> +#define HIBMC_CRT_FB_WIDTH 0x080208
> +#define HIBMC_CRT_FB_WIDTH_WIDTH(x) ((x) << 16)
> +#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK 0x3FFF0000
> +#define HIBMC_CRT_FB_WIDTH_OFFS(x) ((x) << 0)
> +#define HIBMC_CRT_FB_WIDTH_OFFS_MASK 0x3FFF
> +
> +#define HIBMC_CRT_HORZ_TOTAL 0x08020C
> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x) ((x) << 16)
> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK 0xFFF0000
> +
> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END(x) ((x) << 0)
> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END_MASK 0xFFF
> +
> +#define HIBMC_CRT_HORZ_SYNC 0x080210
> +#define HIBMC_CRT_HORZ_SYNC_WIDTH(x) ((x) << 16)
> +#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK 0xFF0000
> +
> +#define HIBMC_CRT_HORZ_SYNC_START(x) ((x) << 0)
> +#define HIBMC_CRT_HORZ_SYNC_START_MASK 0xFFF
> +
> +#define HIBMC_CRT_VERT_TOTAL 0x080214
> +#define HIBMC_CRT_VERT_TOTAL_TOTAL(x) ((x) << 16)
> +#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK 0x7FFF0000
> +
> +#define HIBMC_CRT_VERT_TOTAL_DISP_END(x) ((x) << 0)
> +#define HIBMC_CRT_VERT_TOTAL_DISP_END_MASK 0x7FF
> +
> +#define HIBMC_CRT_VERT_SYNC 0x080218
> +#define HIBMC_CRT_VERT_SYNC_HEIGHT(x) ((x) << 16)
> +#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK 0x3F0000
> +
> +#define HIBMC_CRT_VERT_SYNC_START(x) ((x) << 0)
> +#define HIBMC_CRT_VERT_SYNC_START_MASK 0x7FF
> +
> +/* Auto Centering */
> +#define HIBMC_CRT_AUTO_CENTERING_TL 0x080280
> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x) ((x) << 16)
> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MASK 0x7FF0000
> +
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x) ((x) << 0)
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MASK 0x7FF
> +
> +#define HIBMC_CRT_AUTO_CENTERING_BR 0x080284
> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x) ((x) << 16)
> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK 0x7FF0000
> +
> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x) ((x) << 0)
> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK 0x7FF
> +
> +/* register to control panel output */
> +#define HIBMC_DISPLAY_CONTROL_HISILE 0x80288
> +#define HIBMC_DISPLAY_CONTROL_FPVDDEN(x) ((x) << 0)
> +#define HIBMC_DISPLAY_CONTROL_PANELDATE(x) ((x) << 1)
> +#define HIBMC_DISPLAY_CONTROL_FPEN(x) ((x) << 2)
> +#define HIBMC_DISPLAY_CONTROL_VBIASEN(x) ((x) << 3)
> +
> +#define HIBMC_RAW_INTERRUPT 0x80290
> +#define HIBMC_RAW_INTERRUPT_VBLANK(x) ((x) << 2)
> +#define HIBMC_RAW_INTERRUPT_VBLANK_MASK 0x4
> +
> +#define HIBMC_RAW_INTERRUPT_EN 0x80298
> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK(x) ((x) << 2)
> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK_MASK 0x4
> +
> +/* register and values for PLL control */
> +#define CRT_PLL1_HS 0x802a8
> +#define CRT_PLL1_HS_OUTER_BYPASS(x) ((x) << 30)
> +#define CRT_PLL1_HS_INTER_BYPASS(x) ((x) << 29)
> +#define CRT_PLL1_HS_POWERON(x) ((x) << 24)
> +
> +#define CRT_PLL1_HS_25MHZ 0x23d40f02
> +#define CRT_PLL1_HS_40MHZ 0x23940801
> +#define CRT_PLL1_HS_65MHZ 0x23940d01
> +#define CRT_PLL1_HS_78MHZ 0x23540F82
> +#define CRT_PLL1_HS_74MHZ 0x23941dc2
> +#define CRT_PLL1_HS_80MHZ 0x23941001
> +#define CRT_PLL1_HS_80MHZ_1152 0x23540fc2
> +#define CRT_PLL1_HS_108MHZ 0x23b41b01
> +#define CRT_PLL1_HS_162MHZ 0x23480681
> +#define CRT_PLL1_HS_148MHZ 0x23541dc2
> +#define CRT_PLL1_HS_193MHZ 0x234807c1
> +
> +#define CRT_PLL2_HS 0x802ac
> +#define CRT_PLL2_HS_25MHZ 0x206B851E
> +#define CRT_PLL2_HS_40MHZ 0x30000000
> +#define CRT_PLL2_HS_65MHZ 0x40000000
> +#define CRT_PLL2_HS_78MHZ 0x50E147AE
> +#define CRT_PLL2_HS_74MHZ 0x602B6AE7
> +#define CRT_PLL2_HS_80MHZ 0x70000000
> +#define CRT_PLL2_HS_108MHZ 0x80000000
> +#define CRT_PLL2_HS_162MHZ 0xA0000000
> +#define CRT_PLL2_HS_148MHZ 0xB0CCCCCD
> +#define CRT_PLL2_HS_193MHZ 0xC0872B02
> +
> +#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
> +#endif
> --
> 1.9.1
>
^ permalink raw reply
* [PATCH 2/2] staging: vc04_services: clarify firmware dependency
From: Arnd Bergmann @ 2016-11-16 15:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116154139.3703209-1-arnd@arndb.de>
The raspberrypi-firmware driver may be built as a loadable module,
which causes a link-time failure if the vc04_services driver is
built-in during compile-testing:
drivers/staging/vc04_services/vchiq.o: In function `vchiq_probe':
vchiq_connected.c:(.text.vchiq_probe+0x2c): undefined reference to `rpi_firmware_get'
drivers/staging/vc04_services/vchiq.o: In function `vchiq_platform_init':
vchiq_connected.c:(.text.vchiq_platform_init+0x1f0): undefined reference to `rpi_firmware_property'
This extends the dependency list to ensure the firmware is either
reachable, or completely disabled in case of compile-testing.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/staging/vc04_services/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/vc04_services/Kconfig b/drivers/staging/vc04_services/Kconfig
index 660dcedc2820..061ffd261086 100644
--- a/drivers/staging/vc04_services/Kconfig
+++ b/drivers/staging/vc04_services/Kconfig
@@ -1,6 +1,6 @@
config BCM2835_VCHIQ
tristate "Videocore VCHIQ"
- depends on RASPBERRYPI_FIRMWARE || COMPILE_TEST
+ depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
default y
help
Kernel to VideoCore communication interface for the
--
2.9.0
^ permalink raw reply related
* [PATCH 1/2] staging: vc04_services: remove duplicate mutex_lock_interruptible
From: Arnd Bergmann @ 2016-11-16 15:39 UTC (permalink / raw)
To: linux-arm-kernel
The driver tries to redefine mutex_lock_interruptible as an open-coded
mutex_lock_killable, but that definition clashes with the normal
mutex_lock_interruptible definition when CONFIG_DEBUG_LOCK_ALLOC
is set:
staging/vc04_services/interface/vchiq_arm/vchiq_killable.h:67:0: error: "mutex_lock_interruptible" redefined [-Werror]
#define mutex_lock_interruptible mutex_lock_interruptible_killable
include/linux/mutex.h:161:0: note: this is the location of the previous definition
This simply removes the private implementation and uses the
normal mutex_lock_killable directly.
We could do the same for the down_interruptible_killable here, but
it's better to just remove the semaphores entirely from the driver,
which also takes care of that.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
.../vc04_services/interface/vchiq_arm/vchiq_arm.c | 2 +-
.../interface/vchiq_arm/vchiq_connected.c | 4 ++--
.../vc04_services/interface/vchiq_arm/vchiq_core.c | 20 ++++++++++----------
.../interface/vchiq_arm/vchiq_kern_lib.c | 4 ++--
.../interface/vchiq_arm/vchiq_killable.h | 14 --------------
5 files changed, 15 insertions(+), 29 deletions(-)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index d0435a05ea35..0d987898b4f8 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -554,7 +554,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = -EINVAL;
break;
}
- rc = mutex_lock_interruptible(&instance->state->mutex);
+ rc = mutex_lock_killable(&instance->state->mutex);
if (rc != 0) {
vchiq_log_error(vchiq_arm_log_level,
"vchiq: connect: could not lock mutex for "
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
index 5efc62ffb2f5..7ea29665bd0c 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
@@ -72,7 +72,7 @@ void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback)
{
connected_init();
- if (mutex_lock_interruptible(&g_connected_mutex) != 0)
+ if (mutex_lock_killable(&g_connected_mutex) != 0)
return;
if (g_connected)
@@ -107,7 +107,7 @@ void vchiq_call_connected_callbacks(void)
connected_init();
- if (mutex_lock_interruptible(&g_connected_mutex) != 0)
+ if (mutex_lock_killable(&g_connected_mutex) != 0)
return;
for (i = 0; i < g_num_deferred_callbacks; i++)
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
index 7440db2ce40b..028e90bc1cdc 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -794,7 +794,7 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
WARN_ON(!(stride <= VCHIQ_SLOT_SIZE));
if (!(flags & QMFLAGS_NO_MUTEX_LOCK) &&
- (mutex_lock_interruptible(&state->slot_mutex) != 0))
+ (mutex_lock_killable(&state->slot_mutex) != 0))
return VCHIQ_RETRY;
if (type == VCHIQ_MSG_DATA) {
@@ -863,7 +863,7 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
return VCHIQ_RETRY;
if (service->closing)
return VCHIQ_ERROR;
- if (mutex_lock_interruptible(&state->slot_mutex) != 0)
+ if (mutex_lock_killable(&state->slot_mutex) != 0)
return VCHIQ_RETRY;
if (service->srvstate != VCHIQ_SRVSTATE_OPEN) {
/* The service has been closed */
@@ -1033,7 +1033,7 @@ queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
local = state->local;
if ((VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME) &&
- (mutex_lock_interruptible(&state->sync_mutex) != 0))
+ (mutex_lock_killable(&state->sync_mutex) != 0))
return VCHIQ_RETRY;
remote_event_wait(state, &local->sync_release);
@@ -1365,7 +1365,7 @@ resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue)
WARN_ON(!((int)(queue->local_insert - queue->process) > 0));
WARN_ON(!((int)(queue->remote_insert - queue->process) > 0));
- rc = mutex_lock_interruptible(&state->bulk_transfer_mutex);
+ rc = mutex_lock_killable(&state->bulk_transfer_mutex);
if (rc != 0)
break;
@@ -1839,7 +1839,7 @@ parse_rx_slots(VCHIQ_STATE_T *state)
int resolved = 0;
DEBUG_TRACE(PARSE_LINE);
- if (mutex_lock_interruptible(
+ if (mutex_lock_killable(
&service->bulk_mutex) != 0) {
DEBUG_TRACE(PARSE_LINE);
goto bail_not_ready;
@@ -1903,7 +1903,7 @@ parse_rx_slots(VCHIQ_STATE_T *state)
&service->bulk_rx : &service->bulk_tx;
DEBUG_TRACE(PARSE_LINE);
- if (mutex_lock_interruptible(
+ if (mutex_lock_killable(
&service->bulk_mutex) != 0) {
DEBUG_TRACE(PARSE_LINE);
goto bail_not_ready;
@@ -2780,7 +2780,7 @@ do_abort_bulks(VCHIQ_SERVICE_T *service)
VCHIQ_STATUS_T status;
/* Abort any outstanding bulk transfers */
- if (mutex_lock_interruptible(&service->bulk_mutex) != 0)
+ if (mutex_lock_killable(&service->bulk_mutex) != 0)
return 0;
abort_outstanding_bulks(service, &service->bulk_tx);
abort_outstanding_bulks(service, &service->bulk_rx);
@@ -3300,7 +3300,7 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
queue = (dir == VCHIQ_BULK_TRANSMIT) ?
&service->bulk_tx : &service->bulk_rx;
- if (mutex_lock_interruptible(&service->bulk_mutex) != 0) {
+ if (mutex_lock_killable(&service->bulk_mutex) != 0) {
status = VCHIQ_RETRY;
goto error_exit;
}
@@ -3314,7 +3314,7 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
status = VCHIQ_RETRY;
goto error_exit;
}
- if (mutex_lock_interruptible(&service->bulk_mutex)
+ if (mutex_lock_killable(&service->bulk_mutex)
!= 0) {
status = VCHIQ_RETRY;
goto error_exit;
@@ -3344,7 +3344,7 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
/* The slot mutex must be held when the service is being closed, so
claim it here to ensure that isn't happening */
- if (mutex_lock_interruptible(&state->slot_mutex) != 0) {
+ if (mutex_lock_killable(&state->slot_mutex) != 0) {
status = VCHIQ_RETRY;
goto cancel_bulk_error_exit;
}
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
index 14bd2857e462..e93922a87263 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
@@ -134,7 +134,7 @@ VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
vchiq_log_trace(vchiq_core_log_level,
"%s(%p) called", __func__, instance);
- if (mutex_lock_interruptible(&state->mutex) != 0)
+ if (mutex_lock_killable(&state->mutex) != 0)
return VCHIQ_RETRY;
/* Remove all services */
@@ -191,7 +191,7 @@ VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
vchiq_log_trace(vchiq_core_log_level,
"%s(%p) called", __func__, instance);
- if (mutex_lock_interruptible(&state->mutex) != 0) {
+ if (mutex_lock_killable(&state->mutex) != 0) {
vchiq_log_trace(vchiq_core_log_level,
"%s: call to mutex_lock failed", __func__);
status = VCHIQ_RETRY;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h
index 335446e05476..778063ba312a 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h
@@ -52,18 +52,4 @@ static inline int __must_check down_interruptible_killable(struct semaphore *sem
}
#define down_interruptible down_interruptible_killable
-
-static inline int __must_check mutex_lock_interruptible_killable(struct mutex *lock)
-{
- /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */
- int ret;
- sigset_t blocked, oldset;
- siginitsetinv(&blocked, SHUTDOWN_SIGS);
- sigprocmask(SIG_SETMASK, &blocked, &oldset);
- ret = mutex_lock_interruptible(lock);
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- return ret;
-}
-#define mutex_lock_interruptible mutex_lock_interruptible_killable
-
#endif
--
2.9.0
^ permalink raw reply related
* [PATCH net 1/3] net: phy: realtek: add eee advertisement disable options
From: Jerome Brunet @ 2016-11-16 15:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116150628.GI23231@lunn.ch>
On Wed, 2016-11-16 at 16:06 +0100, Andrew Lunn wrote:
> On Wed, Nov 16, 2016 at 03:51:30PM +0100, Jerome Brunet wrote:
> >
> > On Wed, 2016-11-16 at 14:23 +0100, Andrew Lunn wrote:
> > >
> > > >
> > > >
> > > > There two kind of PHYs supporting eee, the one advertising eee
> > > > by
> > > > default (like realtek) and the one not advertising it (like
> > > > micrel).
> >
> > This is just the default register value.
> >
> > >
> > >
> > > I don't know too much about EEE. So maybe a dumb question. Does
> > > the
> > > MAC need to be involved? Or is it just the PHY?
> > >
> > > If the MAC needs to be involved, the PHY should not be
> > > advertising
> > > EEE
> > > unless the MAC asks for it by calling phy_init_eee(). If this is
> > > true,
> > > maybe we need to change the realtek driver, and others in that
> > > class.
> >
> > As far I understand, the advertised capabilities are exchanged
> > during
> > the auto-negotiation.
> >
> > At this stage, if the advertisement is disabled (regarless of the
> > actual support) on either side of the link, there will be no low
> > power
> > idle state on the Tx nor the Rx path.
> >
> > If the advertisement is enabled on both side but we don't call
> > phy_init_eee, I suppose Tx won't enter LPI, but Rx could.
>
> What i was trying to find out is, if the MAC needs to support EEE as
> well as the PHY, what happens when the MAC does not support EEE, but
> the PHYs do negotiate EEE? Does it break?
Interesting question. In a regular case, I suppose it should be fine.
As you would have LPI only on the Rx path this should be transparent to
the MAC. That's my understanding. Maybe people knowing EEE better than
me could confirm (or not) ? Peppe? Alexandre?
I just checked with the OdroidC2, I disabled eee support by forcing
"dma_cap.eee = 0" in?stmmac_get_hw_features. As expected, no tx_LPI
interrupts but plenty of rx_LPI interrupts.
What was not expected is test failing like before.
So in our case, having LPI on the Rx path is fine for receiving data,
but not for sending.
>
> ????Andrew
^ permalink raw reply
* [PATCH] ARM: ux500: fix prcmu_is_cpu_in_wfi() calculation
From: Daniel Lezcano @ 2016-11-16 15:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152047.3336967-1-arnd@arndb.de>
On Wed, Nov 16, 2016 at 04:20:37PM +0100, Arnd Bergmann wrote:
> This function clearly never worked and always returns true,
> as pointed out by gcc-7:
>
> arch/arm/mach-ux500/pm.c: In function 'prcmu_is_cpu_in_wfi':
> arch/arm/mach-ux500/pm.c:137:212: error: ?: using integer constants in boolean context, the expression will always evaluate to 'true' [-Werror=int-in-bool-context]
>
> With the added braces, the condition actually makes sense.
>
> Fixes: 34fe6f107eab ("mfd : Check if the other db8500 core is in WFI")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> arch/arm/mach-ux500/pm.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c
> index 8538910db202..a970e7fcba9e 100644
> --- a/arch/arm/mach-ux500/pm.c
> +++ b/arch/arm/mach-ux500/pm.c
> @@ -134,8 +134,8 @@ bool prcmu_pending_irq(void)
> */
> bool prcmu_is_cpu_in_wfi(int cpu)
> {
> - return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
> - PRCM_ARM_WFI_STANDBY_WFI0;
> + return readl(PRCM_ARM_WFI_STANDBY) &
> + (cpu ? PRCM_ARM_WFI_STANDBY_WFI1 : PRCM_ARM_WFI_STANDBY_WFI0);
> }
>
> /*
Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Very strange this board did not hang with this broken function.
It is used in a critical function for cpuidle. Is it possible to make a quick
test with this cpuidle test program [1] ?
Thanks!
-- Daniel
[1] https://git.linaro.org/power/pm-qa.git/tree/cpuidle/cpuidle_killer.c
--
<http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* [PATCH v8 16/16] drivers: acpi: iort: introduce iort_iommu_configure
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
DT based systems have a generic kernel API to configure IOMMUs
for devices (ie of_iommu_configure()).
On ARM based ACPI systems, the of_iommu_configure() equivalent can
be implemented atop ACPI IORT kernel API, with the corresponding
functions to map device identifiers to IOMMUs and retrieve the
corresponding IOMMU operations necessary for DMA operations set-up.
By relying on the iommu_fwspec generic kernel infrastructure,
implement the IORT based IOMMU configuration for ARM ACPI systems
and hook it up in the ACPI kernel layer that implements DMA
configuration for a device.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> [ACPI core]
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/arm64/iort.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/scan.c | 7 +++-
include/linux/acpi_iort.h | 6 +++
3 files changed, 110 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 7d30605..5fa585d 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -28,6 +28,8 @@
#define IORT_TYPE_MASK(type) (1 << (type))
#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP)
+#define IORT_IOMMU_TYPE ((1 << ACPI_IORT_NODE_SMMU) | \
+ (1 << ACPI_IORT_NODE_SMMU_V3))
struct iort_its_msi_chip {
struct list_head list;
@@ -501,6 +503,102 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
+{
+ u32 *rid = data;
+
+ *rid = alias;
+ return 0;
+}
+
+static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
+ struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops)
+{
+ int ret = iommu_fwspec_init(dev, fwnode, ops);
+
+ if (!ret)
+ ret = iommu_fwspec_add_ids(dev, &streamid, 1);
+
+ return ret;
+}
+
+static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
+ struct acpi_iort_node *node,
+ u32 streamid)
+{
+ const struct iommu_ops *ops = NULL;
+ int ret = -ENODEV;
+ struct fwnode_handle *iort_fwnode;
+
+ if (node) {
+ iort_fwnode = iort_get_fwnode(node);
+ if (!iort_fwnode)
+ return NULL;
+
+ ops = iommu_get_instance(iort_fwnode);
+ if (!ops)
+ return NULL;
+
+ ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
+ }
+
+ return ret ? NULL : ops;
+}
+
+/**
+ * iort_iommu_configure - Set-up IOMMU configuration for a device.
+ *
+ * @dev: device to configure
+ *
+ * Returns: iommu_ops pointer on configuration success
+ * NULL on configuration failure
+ */
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{
+ struct acpi_iort_node *node, *parent;
+ const struct iommu_ops *ops = NULL;
+ u32 streamid = 0;
+
+ if (dev_is_pci(dev)) {
+ struct pci_bus *bus = to_pci_dev(dev)->bus;
+ u32 rid;
+
+ pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
+ &rid);
+
+ node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+ iort_match_node_callback, &bus->dev);
+ if (!node)
+ return NULL;
+
+ parent = iort_node_map_rid(node, rid, &streamid,
+ IORT_IOMMU_TYPE);
+
+ ops = iort_iommu_xlate(dev, parent, streamid);
+
+ } else {
+ int i = 0;
+
+ node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+ iort_match_node_callback, dev);
+ if (!node)
+ return NULL;
+
+ parent = iort_node_get_id(node, &streamid,
+ IORT_IOMMU_TYPE, i++);
+
+ while (parent) {
+ ops = iort_iommu_xlate(dev, parent, streamid);
+
+ parent = iort_node_get_id(node, &streamid,
+ IORT_IOMMU_TYPE, i++);
+ }
+ }
+
+ return ops;
+}
+
static void __init acpi_iort_register_irq(int hwirq, const char *name,
int trigger,
struct resource *res)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 694e0b6..e5f7004 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/signal.h>
#include <linux/kthread.h>
#include <linux/dmi.h>
@@ -1377,6 +1378,8 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
*/
void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
{
+ const struct iommu_ops *iommu;
+
/*
* Set default coherent_dma_mask to 32 bit. Drivers are expected to
* setup the correct supported mask.
@@ -1391,11 +1394,13 @@ void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
if (!dev->dma_mask)
dev->dma_mask = &dev->coherent_dma_mask;
+ iommu = iort_iommu_configure(dev);
+
/*
* Assume dma valid range starts at 0 and covers the whole
* coherent_dma_mask.
*/
- arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL,
+ arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu,
attr == DEV_DMA_COHERENT);
}
EXPORT_SYMBOL_GPL(acpi_dma_configure);
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 79ba1bb..dcb2b60 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -34,6 +34,8 @@ void acpi_iort_init(void);
bool iort_node_match(u8 type);
u32 iort_msi_map_rid(struct device *dev, u32 req_id);
struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
+/* IOMMU interface */
+const struct iommu_ops *iort_iommu_configure(struct device *dev);
#else
static inline void acpi_iort_init(void) { }
static inline bool iort_node_match(u8 type) { return false; }
@@ -42,6 +44,10 @@ static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
static inline struct irq_domain *iort_get_device_domain(struct device *dev,
u32 req_id)
{ return NULL; }
+/* IOMMU interface */
+static inline
+const struct iommu_ops *iort_iommu_configure(struct device *dev)
+{ return NULL; }
#endif
#define IORT_ACPI_DECLARE(name, table_id, fn) \
--
2.10.0
^ permalink raw reply related
* [PATCH v8 15/16] drivers: acpi: iort: add single mapping function
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
The current IORT id mapping API requires components to provide
an input requester ID (a Bus-Device-Function (BDF) identifier for
PCI devices) to translate an input identifier to an output
identifier through an IORT range mapping.
Named components do not have an identifiable source ID therefore
their respective input/output mapping can only be defined in
IORT tables through single mappings, that provide a translation
that does not require any input identifier.
Current IORT interface for requester id mappings (iort_node_map_rid())
is not suitable for components that do not provide a requester id,
so it cannot be used for IORT named components.
Add an interface to the IORT API to enable retrieval of id
by allowing an indexed walk of the single mappings array for
a given component, therefore completing the IORT mapping API.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/arm64/iort.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 62057c6..7d30605 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -318,6 +318,45 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
return 0;
}
+static
+struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
+ u32 *id_out, u8 type_mask,
+ int index)
+{
+ struct acpi_iort_node *parent;
+ struct acpi_iort_id_mapping *map;
+
+ if (!node->mapping_offset || !node->mapping_count ||
+ index >= node->mapping_count)
+ return NULL;
+
+ map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+ node->mapping_offset);
+
+ /* Firmware bug! */
+ if (!map->output_reference) {
+ pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+ node, node->type);
+ return NULL;
+ }
+
+ parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+ map->output_reference);
+
+ if (!(IORT_TYPE_MASK(parent->type) & type_mask))
+ return NULL;
+
+ if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
+ if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+ node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+ *id_out = map[index].output_base;
+ return parent;
+ }
+ }
+
+ return NULL;
+}
+
static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
u32 rid_in, u32 *rid_out,
u8 type_mask)
--
2.10.0
^ permalink raw reply related
* [PATCH v8 14/16] drivers: acpi: iort: replace rid map type with type mask
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
IORT tables provide data that allow the kernel to carry out
device ID mappings between endpoints and system components
(eg interrupt controllers, IOMMUs). When the mapping for a
given device ID is carried out, the translation mechanism
is done on a per-subsystem basis rather than a component
subtype (ie the IOMMU kernel layer will look for mappings
from a device to all IORT node types corresponding to IOMMU
components), therefore the corresponding mapping API should
work on a range (ie mask) of IORT node types corresponding
to a common set of components (eg IOMMUs) rather than a
specific node type.
Upgrade the IORT iort_node_map_rid() API to work with a
type mask instead of a single node type so that it can
be used for mappings that span multiple components types
(ie IOMMUs).
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/arm64/iort.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 4708806..62057c6 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -26,6 +26,9 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#define IORT_TYPE_MASK(type) (1 << (type))
+#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP)
+
struct iort_its_msi_chip {
struct list_head list;
struct fwnode_handle *fw_node;
@@ -317,7 +320,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
u32 rid_in, u32 *rid_out,
- u8 type)
+ u8 type_mask)
{
u32 rid = rid_in;
@@ -326,7 +329,7 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
struct acpi_iort_id_mapping *map;
int i;
- if (node->type == type) {
+ if (IORT_TYPE_MASK(node->type) & type_mask) {
if (rid_out)
*rid_out = rid;
return node;
@@ -399,7 +402,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
if (!node)
return req_id;
- iort_node_map_rid(node, req_id, &dev_id, ACPI_IORT_NODE_ITS_GROUP);
+ iort_node_map_rid(node, req_id, &dev_id, IORT_MSI_TYPE);
return dev_id;
}
@@ -421,7 +424,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
if (!node)
return -ENXIO;
- node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP);
+ node = iort_node_map_rid(node, req_id, NULL, IORT_MSI_TYPE);
if (!node)
return -ENXIO;
--
2.10.0
^ permalink raw reply related
* [PATCH v8 13/16] drivers: iommu: arm-smmu: add IORT configuration
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
In ACPI bases systems, in order to be able to create platform
devices and initialize them for ARM SMMU components, the IORT
kernel implementation requires a set of static functions to be
used by the IORT kernel layer to configure platform devices for
ARM SMMU components.
Add static configuration functions to the IORT kernel layer for
the ARM SMMU components, so that the ARM SMMU driver can
initialize its respective platform device by relying on the IORT
kernel infrastructure and by adding a corresponding ACPI device
early probe section entry.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
---
drivers/acpi/arm64/iort.c | 81 +++++++++++++++++++++++++++++++++++++++++++++
drivers/iommu/arm-smmu.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/acpi_iort.h | 3 ++
3 files changed, 166 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index fd52e4c..4708806 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -548,6 +548,78 @@ static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)
return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE;
}
+static int __init arm_smmu_count_resources(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+ int num_irqs;
+ u64 *glb_irq;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
+ if (!IORT_IRQ_MASK(glb_irq[1])) /* 0 means not implemented */
+ num_irqs = 1;
+ else
+ num_irqs = 2;
+
+ num_irqs += smmu->context_interrupt_count;
+
+ return num_irqs + 1;
+}
+
+static void __init arm_smmu_init_resources(struct resource *res,
+ struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+ int i, hw_irq, trigger, num_res = 0;
+ u64 *ctx_irq, *glb_irq;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ res[num_res].start = smmu->base_address;
+ res[num_res].end = smmu->base_address + smmu->span - 1;
+ res[num_res].flags = IORESOURCE_MEM;
+ num_res++;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
+ /* Global IRQs */
+ hw_irq = IORT_IRQ_MASK(glb_irq[0]);
+ trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[0]);
+
+ acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
+ &res[num_res++]);
+
+ /* Global IRQs */
+ hw_irq = IORT_IRQ_MASK(glb_irq[1]);
+ if (hw_irq) {
+ trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[1]);
+ acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
+ &res[num_res++]);
+ }
+
+ /* Context IRQs */
+ ctx_irq = ACPI_ADD_PTR(u64, node, smmu->context_interrupt_offset);
+ for (i = 0; i < smmu->context_interrupt_count; i++) {
+ hw_irq = IORT_IRQ_MASK(ctx_irq[i]);
+ trigger = IORT_IRQ_TRIGGER_MASK(ctx_irq[i]);
+
+ acpi_iort_register_irq(hw_irq, "arm-smmu-context", trigger,
+ &res[num_res++]);
+ }
+}
+
+static bool __init arm_smmu_is_coherent(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu *smmu;
+
+ /* Retrieve SMMU specific data */
+ smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ return smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK;
+}
+
struct iort_iommu_config {
const char *name;
int (*iommu_init)(struct acpi_iort_node *node);
@@ -564,12 +636,21 @@ static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
.iommu_init_resources = arm_smmu_v3_init_resources
};
+static const struct iort_iommu_config iort_arm_smmu_cfg __initconst = {
+ .name = "arm-smmu",
+ .iommu_is_coherent = arm_smmu_is_coherent,
+ .iommu_count_resources = arm_smmu_count_resources,
+ .iommu_init_resources = arm_smmu_init_resources
+};
+
static __init
const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
{
switch (node->type) {
case ACPI_IORT_NODE_SMMU_V3:
return &iort_arm_smmu_v3_cfg;
+ case ACPI_IORT_NODE_SMMU:
+ return &iort_arm_smmu_cfg;
default:
return NULL;
}
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 573b2b6..21d1892 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -28,6 +28,8 @@
#define pr_fmt(fmt) "arm-smmu: " fmt
+#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/atomic.h>
#include <linux/delay.h>
#include <linux/dma-iommu.h>
@@ -1904,6 +1906,70 @@ static const struct of_device_id arm_smmu_of_match[] = {
};
MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+#ifdef CONFIG_ACPI
+static int acpi_smmu_get_data(u32 model, u32 *version, u32 *impl)
+{
+ int ret = 0;
+
+ switch (model) {
+ case ACPI_IORT_SMMU_V1:
+ case ACPI_IORT_SMMU_CORELINK_MMU400:
+ *version = ARM_SMMU_V1;
+ *impl = GENERIC_SMMU;
+ break;
+ case ACPI_IORT_SMMU_V2:
+ *version = ARM_SMMU_V2;
+ *impl = GENERIC_SMMU;
+ break;
+ case ACPI_IORT_SMMU_CORELINK_MMU500:
+ *version = ARM_SMMU_V2;
+ *impl = ARM_MMU500;
+ break;
+ default:
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ struct device *dev = smmu->dev;
+ struct acpi_iort_node *node =
+ *(struct acpi_iort_node **)dev_get_platdata(dev);
+ struct acpi_iort_smmu *iort_smmu;
+ u64 *glb_irq;
+ int ret;
+
+ /* Retrieve SMMU1/2 specific data */
+ iort_smmu = (struct acpi_iort_smmu *)node->node_data;
+
+ ret = acpi_smmu_get_data(iort_smmu->model, &smmu->version,
+ &smmu->model);
+ if (ret < 0)
+ return ret;
+
+ glb_irq = ACPI_ADD_PTR(u64, node, iort_smmu->global_interrupt_offset);
+
+ if (!IORT_IRQ_MASK(glb_irq[1])) /* 0 means not implemented */
+ smmu->num_global_irqs = 1;
+ else
+ smmu->num_global_irqs = 2;
+
+ if (iort_smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK)
+ smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+
+ return 0;
+}
+#else
+static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
+{
+ return -ENODEV;
+}
+#endif
+
static int arm_smmu_device_dt_probe(struct platform_device *pdev,
struct arm_smmu_device *smmu)
{
@@ -1955,7 +2021,11 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
}
smmu->dev = dev;
- err = arm_smmu_device_dt_probe(pdev, smmu);
+ if (dev->of_node)
+ err = arm_smmu_device_dt_probe(pdev, smmu);
+ else
+ err = arm_smmu_device_acpi_probe(pdev, smmu);
+
if (err)
return err;
@@ -2103,6 +2173,17 @@ IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", arm_smmu_of_init);
IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", arm_smmu_of_init);
IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init);
+#ifdef CONFIG_ACPI
+static int __init arm_smmu_acpi_init(struct acpi_table_header *table)
+{
+ if (iort_node_match(ACPI_IORT_NODE_SMMU))
+ return arm_smmu_init();
+
+ return 0;
+}
+IORT_ACPI_DECLARE(arm_smmu, ACPI_SIG_IORT, arm_smmu_acpi_init);
+#endif
+
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations");
MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
MODULE_LICENSE("GPL v2");
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 17bb078..79ba1bb 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -23,6 +23,9 @@
#include <linux/fwnode.h>
#include <linux/irqdomain.h>
+#define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL)
+#define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL)
+
int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
void iort_deregister_domain_token(int trans_id);
struct fwnode_handle *iort_find_domain_token(int trans_id);
--
2.10.0
^ permalink raw reply related
* [PATCH v8 12/16] drivers: iommu: arm-smmu: split probe functions into DT/generic portions
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
Current ARM SMMU probe functions intermingle HW and DT probing
in the initialization functions to detect and programme the ARM SMMU
driver features. In order to allow probing the ARM SMMU with other
firmwares than DT, this patch splits the ARM SMMU init functions into
DT and HW specific portions so that other FW interfaces (ie ACPI) can
reuse the HW probing functions and skip the DT portion accordingly.
This patch implements no functional change, only code reshuffling.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
---
drivers/iommu/arm-smmu.c | 62 +++++++++++++++++++++++++++++-------------------
1 file changed, 37 insertions(+), 25 deletions(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 339a8d3..573b2b6 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1668,7 +1668,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
unsigned long size;
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
u32 id;
- bool cttw_dt, cttw_reg;
+ bool cttw_reg, cttw_fw = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK;
int i;
dev_notice(smmu->dev, "probing hardware configuration...\n");
@@ -1713,20 +1713,17 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
/*
* In order for DMA API calls to work properly, we must defer to what
- * the DT says about coherency, regardless of what the hardware claims.
+ * the FW says about coherency, regardless of what the hardware claims.
* Fortunately, this also opens up a workaround for systems where the
* ID register value has ended up configured incorrectly.
*/
- cttw_dt = of_dma_is_coherent(smmu->dev->of_node);
cttw_reg = !!(id & ID0_CTTW);
- if (cttw_dt)
- smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
- if (cttw_dt || cttw_reg)
+ if (cttw_fw || cttw_reg)
dev_notice(smmu->dev, "\t%scoherent table walk\n",
- cttw_dt ? "" : "non-");
- if (cttw_dt != cttw_reg)
+ cttw_fw ? "" : "non-");
+ if (cttw_fw != cttw_reg)
dev_notice(smmu->dev,
- "\t(IDR0.CTTW overridden by dma-coherent property)\n");
+ "\t(IDR0.CTTW overridden by FW configuration)\n");
/* Max. number of entries we have for stream matching/indexing */
size = 1 << ((id >> ID0_NUMSIDB_SHIFT) & ID0_NUMSIDB_MASK);
@@ -1907,15 +1904,25 @@ static const struct of_device_id arm_smmu_of_match[] = {
};
MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
-static int arm_smmu_device_dt_probe(struct platform_device *pdev)
+static int arm_smmu_device_dt_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu)
{
const struct arm_smmu_match_data *data;
- struct resource *res;
- struct arm_smmu_device *smmu;
struct device *dev = &pdev->dev;
- int num_irqs, i, err;
bool legacy_binding;
+ if (of_property_read_u32(dev->of_node, "#global-interrupts",
+ &smmu->num_global_irqs)) {
+ dev_err(dev, "missing #global-interrupts property\n");
+ return -ENODEV;
+ }
+
+ data = of_device_get_match_data(dev);
+ smmu->version = data->version;
+ smmu->model = data->model;
+
+ parse_driver_options(smmu);
+
legacy_binding = of_find_property(dev->of_node, "mmu-masters", NULL);
if (legacy_binding && !using_generic_binding) {
if (!using_legacy_binding)
@@ -1928,6 +1935,19 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (of_dma_is_coherent(dev->of_node))
+ smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+
+ return 0;
+}
+
+static int arm_smmu_device_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct arm_smmu_device *smmu;
+ struct device *dev = &pdev->dev;
+ int num_irqs, i, err;
+
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
if (!smmu) {
dev_err(dev, "failed to allocate arm_smmu_device\n");
@@ -1935,9 +1955,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
}
smmu->dev = dev;
- data = of_device_get_match_data(dev);
- smmu->version = data->version;
- smmu->model = data->model;
+ err = arm_smmu_device_dt_probe(pdev, smmu);
+ if (err)
+ return err;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
smmu->base = devm_ioremap_resource(dev, res);
@@ -1945,12 +1965,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
return PTR_ERR(smmu->base);
smmu->size = resource_size(res);
- if (of_property_read_u32(dev->of_node, "#global-interrupts",
- &smmu->num_global_irqs)) {
- dev_err(dev, "missing #global-interrupts property\n");
- return -ENODEV;
- }
-
num_irqs = 0;
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) {
num_irqs++;
@@ -1985,8 +1999,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
if (err)
return err;
- parse_driver_options(smmu);
-
if (smmu->version == ARM_SMMU_V2 &&
smmu->num_context_banks != smmu->num_context_irqs) {
dev_err(dev,
@@ -2048,7 +2060,7 @@ static struct platform_driver arm_smmu_driver = {
.name = "arm-smmu",
.of_match_table = of_match_ptr(arm_smmu_of_match),
},
- .probe = arm_smmu_device_dt_probe,
+ .probe = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
};
--
2.10.0
^ permalink raw reply related
* [PATCH v8 11/16] drivers: iommu: arm-smmu-v3: add IORT configuration
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
In ACPI bases systems, in order to be able to create platform
devices and initialize them for ARM SMMU v3 components, the IORT
kernel implementation requires a set of static functions to be
used by the IORT kernel layer to configure platform devices for
ARM SMMU v3 components.
Add static configuration functions to the IORT kernel layer for
the ARM SMMU v3 components, so that the ARM SMMU v3 driver can
initialize its respective platform device by relying on the IORT
kernel infrastructure and by adding a corresponding ACPI device
early probe section entry.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
---
drivers/acpi/arm64/iort.c | 103 +++++++++++++++++++++++++++++++++++++++++++-
drivers/iommu/arm-smmu-v3.c | 49 ++++++++++++++++++++-
2 files changed, 150 insertions(+), 2 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index ddf83b5..fd52e4c 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -459,6 +459,95 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+static void __init acpi_iort_register_irq(int hwirq, const char *name,
+ int trigger,
+ struct resource *res)
+{
+ int irq = acpi_register_gsi(NULL, hwirq, trigger,
+ ACPI_ACTIVE_HIGH);
+
+ if (irq <= 0) {
+ pr_err("could not register gsi hwirq %d name [%s]\n", hwirq,
+ name);
+ return;
+ }
+
+ res->start = irq;
+ res->end = irq;
+ res->flags = IORESOURCE_IRQ;
+ res->name = name;
+}
+
+static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu_v3 *smmu;
+ /* Always present mem resource */
+ int num_res = 1;
+
+ /* Retrieve SMMUv3 specific data */
+ smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+ if (smmu->event_gsiv)
+ num_res++;
+
+ if (smmu->pri_gsiv)
+ num_res++;
+
+ if (smmu->gerr_gsiv)
+ num_res++;
+
+ if (smmu->sync_gsiv)
+ num_res++;
+
+ return num_res;
+}
+
+static void __init arm_smmu_v3_init_resources(struct resource *res,
+ struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu_v3 *smmu;
+ int num_res = 0;
+
+ /* Retrieve SMMUv3 specific data */
+ smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+ res[num_res].start = smmu->base_address;
+ res[num_res].end = smmu->base_address + SZ_128K - 1;
+ res[num_res].flags = IORESOURCE_MEM;
+
+ num_res++;
+
+ if (smmu->event_gsiv)
+ acpi_iort_register_irq(smmu->event_gsiv, "eventq",
+ ACPI_EDGE_SENSITIVE,
+ &res[num_res++]);
+
+ if (smmu->pri_gsiv)
+ acpi_iort_register_irq(smmu->pri_gsiv, "priq",
+ ACPI_EDGE_SENSITIVE,
+ &res[num_res++]);
+
+ if (smmu->gerr_gsiv)
+ acpi_iort_register_irq(smmu->gerr_gsiv, "gerror",
+ ACPI_EDGE_SENSITIVE,
+ &res[num_res++]);
+
+ if (smmu->sync_gsiv)
+ acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync",
+ ACPI_EDGE_SENSITIVE,
+ &res[num_res++]);
+}
+
+static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu_v3 *smmu;
+
+ /* Retrieve SMMUv3 specific data */
+ smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+ return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE;
+}
+
struct iort_iommu_config {
const char *name;
int (*iommu_init)(struct acpi_iort_node *node);
@@ -468,10 +557,22 @@ struct iort_iommu_config {
struct acpi_iort_node *node);
};
+static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
+ .name = "arm-smmu-v3",
+ .iommu_is_coherent = arm_smmu_v3_is_coherent,
+ .iommu_count_resources = arm_smmu_v3_count_resources,
+ .iommu_init_resources = arm_smmu_v3_init_resources
+};
+
static __init
const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
{
- return NULL;
+ switch (node->type) {
+ case ACPI_IORT_NODE_SMMU_V3:
+ return &iort_arm_smmu_v3_cfg;
+ default:
+ return NULL;
+ }
}
/**
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index ed563307..9315bf3 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -20,6 +20,8 @@
* This driver is powered by bad coffee and bombay mix.
*/
+#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/delay.h>
#include <linux/dma-iommu.h>
#include <linux/err.h>
@@ -2559,6 +2561,36 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
return 0;
}
+#ifdef CONFIG_ACPI
+static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu,
+ bool *bypass)
+{
+ struct acpi_iort_smmu_v3 *iort_smmu;
+ struct device *dev = smmu->dev;
+ struct acpi_iort_node *node;
+
+ node = *(struct acpi_iort_node **)dev_get_platdata(dev);
+
+ /* Retrieve SMMUv3 specific data */
+ iort_smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+
+ if (iort_smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE)
+ smmu->features |= ARM_SMMU_FEAT_COHERENCY;
+
+ *bypass = false;
+
+ return 0;
+}
+#else
+static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu,
+ bool *bypass)
+{
+ return -ENODEV;
+}
+#endif
+
static int arm_smmu_device_dt_probe(struct platform_device *pdev,
struct arm_smmu_device *smmu,
bool *bypass)
@@ -2626,7 +2658,11 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
if (irq > 0)
smmu->gerr_irq = irq;
- ret = arm_smmu_device_dt_probe(pdev, smmu, &bypass);
+ if (dev->of_node)
+ ret = arm_smmu_device_dt_probe(pdev, smmu, &bypass);
+ else
+ ret = arm_smmu_device_acpi_probe(pdev, smmu, &bypass);
+
if (ret)
return ret;
@@ -2731,6 +2767,17 @@ static int __init arm_smmu_of_init(struct device_node *np)
}
IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", arm_smmu_of_init);
+#ifdef CONFIG_ACPI
+static int __init acpi_smmu_v3_init(struct acpi_table_header *table)
+{
+ if (iort_node_match(ACPI_IORT_NODE_SMMU_V3))
+ return arm_smmu_init();
+
+ return 0;
+}
+IORT_ACPI_DECLARE(arm_smmu_v3, ACPI_SIG_IORT, acpi_smmu_v3_init);
+#endif
+
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations");
MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
MODULE_LICENSE("GPL v2");
--
2.10.0
^ permalink raw reply related
* [PATCH v8 10/16] drivers: iommu: arm-smmu-v3: split probe functions into DT/generic portions
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
Current ARM SMMUv3 probe functions intermingle HW and DT probing in the
initialization functions to detect and programme the ARM SMMU v3 driver
features. In order to allow probing the ARM SMMUv3 with other firmwares
than DT, this patch splits the ARM SMMUv3 init functions into DT and HW
specific portions so that other FW interfaces (ie ACPI) can reuse the HW
probing functions and skip the DT portion accordingly.
This patch implements no functional change, only code reshuffling.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
---
drivers/iommu/arm-smmu-v3.c | 46 +++++++++++++++++++++++++++++----------------
1 file changed, 30 insertions(+), 16 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index e6e1c87..ed563307 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -2381,10 +2381,10 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
return 0;
}
-static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
+static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
{
u32 reg;
- bool coherent;
+ bool coherent = smmu->features & ARM_SMMU_FEAT_COHERENCY;
/* IDR0 */
reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0);
@@ -2436,13 +2436,9 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
smmu->features |= ARM_SMMU_FEAT_HYP;
/*
- * The dma-coherent property is used in preference to the ID
+ * The coherency feature as set by FW is used in preference to the ID
* register, but warn on mismatch.
*/
- coherent = of_dma_is_coherent(smmu->dev->of_node);
- if (coherent)
- smmu->features |= ARM_SMMU_FEAT_COHERENCY;
-
if (!!(reg & IDR0_COHACC) != coherent)
dev_warn(smmu->dev, "IDR0.COHACC overridden by dma-coherent property (%s)\n",
coherent ? "true" : "false");
@@ -2563,21 +2559,37 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
return 0;
}
-static int arm_smmu_device_dt_probe(struct platform_device *pdev)
+static int arm_smmu_device_dt_probe(struct platform_device *pdev,
+ struct arm_smmu_device *smmu,
+ bool *bypass)
{
- int irq, ret;
- struct resource *res;
- struct arm_smmu_device *smmu;
struct device *dev = &pdev->dev;
- bool bypass = true;
u32 cells;
+ *bypass = true;
+
if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells))
dev_err(dev, "missing #iommu-cells property\n");
else if (cells != 1)
dev_err(dev, "invalid #iommu-cells value (%d)\n", cells);
else
- bypass = false;
+ *bypass = false;
+
+ parse_driver_options(smmu);
+
+ if (of_dma_is_coherent(dev->of_node))
+ smmu->features |= ARM_SMMU_FEAT_COHERENCY;
+
+ return 0;
+}
+
+static int arm_smmu_device_probe(struct platform_device *pdev)
+{
+ int irq, ret;
+ struct resource *res;
+ struct arm_smmu_device *smmu;
+ struct device *dev = &pdev->dev;
+ bool bypass;
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
if (!smmu) {
@@ -2614,10 +2626,12 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
if (irq > 0)
smmu->gerr_irq = irq;
- parse_driver_options(smmu);
+ ret = arm_smmu_device_dt_probe(pdev, smmu, &bypass);
+ if (ret)
+ return ret;
/* Probe the h/w */
- ret = arm_smmu_device_probe(smmu);
+ ret = arm_smmu_device_hw_probe(smmu);
if (ret)
return ret;
@@ -2679,7 +2693,7 @@ static struct platform_driver arm_smmu_driver = {
.name = "arm-smmu-v3",
.of_match_table = of_match_ptr(arm_smmu_of_match),
},
- .probe = arm_smmu_device_dt_probe,
+ .probe = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
};
--
2.10.0
^ permalink raw reply related
* [PATCH v8 09/16] drivers: acpi: iort: add support for ARM SMMU platform devices creation
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
In ARM ACPI systems, IOMMU components are specified through static
IORT table entries. In order to create platform devices for the
corresponding ARM SMMU components, IORT kernel code should be made
able to parse IORT table entries and create platform devices
dynamically.
This patch adds the generic IORT infrastructure required to create
platform devices for ARM SMMUs.
ARM SMMU versions have different resources requirement therefore this
patch also introduces an IORT specific structure (ie iort_iommu_config)
that contains hooks (to be defined when the corresponding ARM SMMU
driver support is added to the kernel) to be used to define the
platform devices names, init the IOMMUs, count their resources and
finally initialize them.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/arm64/iort.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 151 insertions(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 4bb6acb..ddf83b5 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -19,9 +19,11 @@
#define pr_fmt(fmt) "ACPI: IORT: " fmt
#include <linux/acpi_iort.h>
+#include <linux/iommu.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
struct iort_its_msi_chip {
@@ -457,6 +459,153 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+struct iort_iommu_config {
+ const char *name;
+ int (*iommu_init)(struct acpi_iort_node *node);
+ bool (*iommu_is_coherent)(struct acpi_iort_node *node);
+ int (*iommu_count_resources)(struct acpi_iort_node *node);
+ void (*iommu_init_resources)(struct resource *res,
+ struct acpi_iort_node *node);
+};
+
+static __init
+const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
+{
+ return NULL;
+}
+
+/**
+ * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
+ * @node: Pointer to SMMU ACPI IORT node
+ *
+ * Returns: 0 on success, <0 failure
+ */
+static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
+{
+ struct fwnode_handle *fwnode;
+ struct platform_device *pdev;
+ struct resource *r;
+ enum dev_dma_attr attr;
+ int ret, count;
+ const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
+
+ if (!ops)
+ return -ENODEV;
+
+ pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
+ if (!pdev)
+ return PTR_ERR(pdev);
+
+ count = ops->iommu_count_resources(node);
+
+ r = kcalloc(count, sizeof(*r), GFP_KERNEL);
+ if (!r) {
+ ret = -ENOMEM;
+ goto dev_put;
+ }
+
+ ops->iommu_init_resources(r, node);
+
+ ret = platform_device_add_resources(pdev, r, count);
+ /*
+ * Resources are duplicated in platform_device_add_resources,
+ * free their allocated memory
+ */
+ kfree(r);
+
+ if (ret)
+ goto dev_put;
+
+ /*
+ * Add a copy of IORT node pointer to platform_data to
+ * be used to retrieve IORT data information.
+ */
+ ret = platform_device_add_data(pdev, &node, sizeof(node));
+ if (ret)
+ goto dev_put;
+
+ /*
+ * We expect the dma masks to be equivalent for
+ * all SMMUs set-ups
+ */
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+ fwnode = iort_get_fwnode(node);
+
+ if (!fwnode) {
+ ret = -ENODEV;
+ goto dev_put;
+ }
+
+ pdev->dev.fwnode = fwnode;
+
+ attr = ops->iommu_is_coherent(node) ?
+ DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
+
+ /* Configure DMA for the page table walker */
+ acpi_dma_configure(&pdev->dev, attr);
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto dma_deconfigure;
+
+ return 0;
+
+dma_deconfigure:
+ acpi_dma_deconfigure(&pdev->dev);
+dev_put:
+ platform_device_put(pdev);
+
+ return ret;
+}
+
+static void __init iort_init_platform_devices(void)
+{
+ struct acpi_iort_node *iort_node, *iort_end;
+ struct acpi_table_iort *iort;
+ struct fwnode_handle *fwnode;
+ int i, ret;
+
+ /*
+ * iort_table and iort both point to the start of IORT table, but
+ * have different struct types
+ */
+ iort = (struct acpi_table_iort *)iort_table;
+
+ /* Get the first IORT node */
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+ iort->node_offset);
+ iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+ iort_table->length);
+
+ for (i = 0; i < iort->node_count; i++) {
+ if (iort_node >= iort_end) {
+ pr_err("iort node pointer overflows, bad table\n");
+ return;
+ }
+
+ if ((iort_node->type == ACPI_IORT_NODE_SMMU) ||
+ (iort_node->type == ACPI_IORT_NODE_SMMU_V3)) {
+
+ fwnode = acpi_alloc_fwnode_static();
+ if (!fwnode)
+ return;
+
+ iort_set_fwnode(iort_node, fwnode);
+
+ ret = iort_add_smmu_platform_device(iort_node);
+ if (ret) {
+ iort_delete_fwnode(iort_node);
+ acpi_free_fwnode_static(fwnode);
+ return;
+ }
+ }
+
+ iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+ iort_node->length);
+ }
+}
+
void __init acpi_iort_init(void)
{
acpi_status status;
@@ -472,5 +621,7 @@ void __init acpi_iort_init(void)
return;
}
+ iort_init_platform_devices();
+
acpi_probe_device_table(iort);
}
--
2.10.0
^ permalink raw reply related
* [PATCH v8 08/16] drivers: acpi: iort: add node match function
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
Device drivers (eg ARM SMMU) need to know if a specific component
is part of the IORT table, so that kernel data structures are not
initialized at initcalls time if the respective component is not
part of the IORT table.
To this end, this patch adds a trivial function that allows detecting
if a given IORT node type is present or not in the ACPI table, providing
an ACPI IORT equivalent for of_find_matching_node().
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/arm64/iort.c | 15 +++++++++++++++
include/linux/acpi_iort.h | 2 ++
2 files changed, 17 insertions(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 1ac2720..4bb6acb 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -227,6 +227,21 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
return NULL;
}
+static acpi_status
+iort_match_type_callback(struct acpi_iort_node *node, void *context)
+{
+ return AE_OK;
+}
+
+bool iort_node_match(u8 type)
+{
+ struct acpi_iort_node *node;
+
+ node = iort_scan_node(type, iort_match_type_callback, NULL);
+
+ return node != NULL;
+}
+
static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
void *context)
{
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index d16fdda..17bb078 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -28,10 +28,12 @@ void iort_deregister_domain_token(int trans_id);
struct fwnode_handle *iort_find_domain_token(int trans_id);
#ifdef CONFIG_ACPI_IORT
void acpi_iort_init(void);
+bool iort_node_match(u8 type);
u32 iort_msi_map_rid(struct device *dev, u32 req_id);
struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
#else
static inline void acpi_iort_init(void) { }
+static inline bool iort_node_match(u8 type) { return false; }
static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
{ return req_id; }
static inline struct irq_domain *iort_get_device_domain(struct device *dev,
--
2.10.0
^ permalink raw reply related
* [PATCH v8 07/16] drivers: acpi: implement acpi_dma_configure
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
On DT based systems, the of_dma_configure() API implements DMA
configuration for a given device. On ACPI systems an API equivalent to
of_dma_configure() is missing which implies that it is currently not
possible to set-up DMA operations for devices through the ACPI generic
kernel layer.
This patch fills the gap by introducing acpi_dma_configure/deconfigure()
calls that for now are just wrappers around arch_setup_dma_ops() and
arch_teardown_dma_ops() and also updates ACPI and PCI core code to use
the newly introduced acpi_dma_configure/acpi_dma_deconfigure functions.
Since acpi_dma_configure() is used to configure DMA operations, the
function initializes the dma/coherent_dma masks to sane default values
if the current masks are uninitialized (also to keep the default values
consistent with DT systems) to make sure the device has a complete
default DMA set-up.
The DMA range size passed to arch_setup_dma_ops() is sized according
to the device coherent_dma_mask (starting at address 0x0), mirroring the
DT probing path behaviour when a dma-ranges property is not provided
for the device being probed; this changes the current arch_setup_dma_ops()
call parameters in the ACPI probing case, but since arch_setup_dma_ops()
is a NOP on all architectures but ARM/ARM64 this patch does not change
the current kernel behaviour on them.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com> [pci]
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/glue.c | 4 ++--
drivers/acpi/scan.c | 40 ++++++++++++++++++++++++++++++++++++++++
drivers/pci/probe.c | 3 +--
include/acpi/acpi_bus.h | 2 ++
include/linux/acpi.h | 5 +++++
5 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 5ea5dc2..f8d6564 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -227,8 +227,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
attr = acpi_get_dma_attr(acpi_dev);
if (attr != DEV_DMA_NOT_SUPPORTED)
- arch_setup_dma_ops(dev, 0, 0, NULL,
- attr == DEV_DMA_COHERENT);
+ acpi_dma_configure(dev, attr);
acpi_physnode_link_name(physical_node_name, node_id);
retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
@@ -251,6 +250,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
return 0;
err:
+ acpi_dma_deconfigure(dev);
ACPI_COMPANION_SET(dev, NULL);
put_device(dev);
put_device(&acpi_dev->dev);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 035ac64..694e0b6 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1370,6 +1370,46 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
return DEV_DMA_NON_COHERENT;
}
+/**
+ * acpi_dma_configure - Set-up DMA configuration for the device.
+ * @dev: The pointer to the device
+ * @attr: device dma attributes
+ */
+void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
+{
+ /*
+ * Set default coherent_dma_mask to 32 bit. Drivers are expected to
+ * setup the correct supported mask.
+ */
+ if (!dev->coherent_dma_mask)
+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ /*
+ * Set it to coherent_dma_mask by default if the architecture
+ * code has not set it.
+ */
+ if (!dev->dma_mask)
+ dev->dma_mask = &dev->coherent_dma_mask;
+
+ /*
+ * Assume dma valid range starts at 0 and covers the whole
+ * coherent_dma_mask.
+ */
+ arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL,
+ attr == DEV_DMA_COHERENT);
+}
+EXPORT_SYMBOL_GPL(acpi_dma_configure);
+
+/**
+ * acpi_dma_deconfigure - Tear-down DMA configuration for the device.
+ * @dev: The pointer to the device
+ */
+void acpi_dma_deconfigure(struct device *dev)
+{
+ arch_teardown_dma_ops(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_dma_deconfigure);
+
static void acpi_init_coherency(struct acpi_device *adev)
{
unsigned long long cca = 0;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ab00267..c29e07a 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1738,8 +1738,7 @@ static void pci_dma_configure(struct pci_dev *dev)
if (attr == DEV_DMA_NOT_SUPPORTED)
dev_warn(&dev->dev, "DMA not supported.\n");
else
- arch_setup_dma_ops(&dev->dev, 0, 0, NULL,
- attr == DEV_DMA_COHERENT);
+ acpi_dma_configure(&dev->dev, attr);
}
pci_put_host_bridge_device(bridge);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index c1a524d..4242c31 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -573,6 +573,8 @@ struct acpi_pci_root {
bool acpi_dma_supported(struct acpi_device *adev);
enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
+void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
+void acpi_dma_deconfigure(struct device *dev);
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
u64 address, bool check_children);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 6efb13c..df961f4 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -764,6 +764,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
return DEV_DMA_NOT_SUPPORTED;
}
+static inline void acpi_dma_configure(struct device *dev,
+ enum dev_dma_attr attr) { }
+
+static inline void acpi_dma_deconfigure(struct device *dev) { }
+
#define ACPI_PTR(_ptr) (NULL)
static inline void acpi_device_set_enumerated(struct acpi_device *adev)
--
2.10.0
^ permalink raw reply related
* [PATCH v8 06/16] drivers: iommu: arm-smmu-v3: convert struct device of_node to fwnode usage
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
Current ARM SMMU v3 driver rely on the struct device.of_node pointer for
device look-up and iommu_ops retrieval.
In preparation for ACPI probing enablement, convert the driver to use
the struct device.fwnode member for device and iommu_ops look-up so that
the driver infrastructure can be used also on systems that do not
associate an of_node pointer to a struct device (eg ACPI), making the
device look-up and iommu_ops retrieval firmware agnostic.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
---
drivers/iommu/arm-smmu-v3.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index e6f9b2d..e6e1c87 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1723,13 +1723,14 @@ static struct platform_driver arm_smmu_driver;
static int arm_smmu_match_node(struct device *dev, void *data)
{
- return dev->of_node == data;
+ return dev->fwnode == data;
}
-static struct arm_smmu_device *arm_smmu_get_by_node(struct device_node *np)
+static
+struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
{
struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL,
- np, arm_smmu_match_node);
+ fwnode, arm_smmu_match_node);
put_device(dev);
return dev ? dev_get_drvdata(dev) : NULL;
}
@@ -1765,7 +1766,7 @@ static int arm_smmu_add_device(struct device *dev)
master = fwspec->iommu_priv;
smmu = master->smmu;
} else {
- smmu = arm_smmu_get_by_node(to_of_node(fwspec->iommu_fwnode));
+ smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
if (!smmu)
return -ENODEV;
master = kzalloc(sizeof(*master), GFP_KERNEL);
@@ -2634,7 +2635,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
return ret;
/* And we're up. Go go go! */
- of_iommu_set_ops(dev->of_node, &arm_smmu_ops);
+ iommu_register_instance(dev->fwnode, &arm_smmu_ops);
+
#ifdef CONFIG_PCI
if (pci_bus_type.iommu_ops != &arm_smmu_ops) {
pci_request_acs();
--
2.10.0
^ permalink raw reply related
* [PATCH v8 05/16] drivers: iommu: arm-smmu: convert struct device of_node to fwnode usage
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
Current ARM SMMU driver rely on the struct device.of_node pointer for
device look-up and iommu_ops retrieval.
In preparation for ACPI probing enablement, convert the driver to use
the struct device.fwnode member for device and iommu_ops look-up so that
the driver infrastructure can be used also on systems that do not
associate an of_node pointer to a struct device (eg ACPI), making the
device look-up and iommu_ops retrieval firmware agnostic.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
---
drivers/iommu/arm-smmu.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 8f72814..339a8d3 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1379,13 +1379,14 @@ static bool arm_smmu_capable(enum iommu_cap cap)
static int arm_smmu_match_node(struct device *dev, void *data)
{
- return dev->of_node == data;
+ return dev->fwnode == data;
}
-static struct arm_smmu_device *arm_smmu_get_by_node(struct device_node *np)
+static
+struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
{
struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL,
- np, arm_smmu_match_node);
+ fwnode, arm_smmu_match_node);
put_device(dev);
return dev ? dev_get_drvdata(dev) : NULL;
}
@@ -1403,7 +1404,7 @@ static int arm_smmu_add_device(struct device *dev)
if (ret)
goto out_free;
} else if (fwspec && fwspec->ops == &arm_smmu_ops) {
- smmu = arm_smmu_get_by_node(to_of_node(fwspec->iommu_fwnode));
+ smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
} else {
return -ENODEV;
}
@@ -2007,7 +2008,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
}
}
- of_iommu_set_ops(dev->of_node, &arm_smmu_ops);
+ iommu_register_instance(dev->fwnode, &arm_smmu_ops);
platform_set_drvdata(pdev, smmu);
arm_smmu_device_reset(smmu);
--
2.10.0
^ permalink raw reply related
* [PATCH v8 04/16] drivers: iommu: make of_iommu_set/get_ops() DT agnostic
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
The of_iommu_{set/get}_ops() API is used to associate a device
tree node with a specific set of IOMMU operations. The same
kernel interface is required on systems booting with ACPI, where
devices are not associated with a device tree node, therefore
the interface requires generalization.
The struct device fwnode member represents the fwnode token associated
with the device and the struct it points at is firmware specific;
regardless, it is initialized on both ACPI and DT systems and makes an
ideal candidate to use it to associate a set of IOMMU operations to a
given device, through its struct device.fwnode member pointer, paving
the way for representing per-device iommu_ops (ie an iommu instance
associated with a device).
Convert the DT specific of_iommu_{set/get}_ops() interface to
use struct device.fwnode as a look-up token, making the interface
usable on ACPI systems and rename the data structures and the
registration API so that they are made to represent their usage
more clearly.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <joro@8bytes.org>
---
drivers/iommu/iommu.c | 40 ++++++++++++++++++++++++++++++++++++++++
drivers/iommu/of_iommu.c | 39 ---------------------------------------
include/linux/iommu.h | 14 ++++++++++++++
include/linux/of_iommu.h | 12 ++++++++++--
4 files changed, 64 insertions(+), 41 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 9a2f196..8d3e847 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1615,6 +1615,46 @@ int iommu_request_dm_for_dev(struct device *dev)
return ret;
}
+struct iommu_instance {
+ struct list_head list;
+ struct fwnode_handle *fwnode;
+ const struct iommu_ops *ops;
+};
+static LIST_HEAD(iommu_instance_list);
+static DEFINE_SPINLOCK(iommu_instance_lock);
+
+void iommu_register_instance(struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops)
+{
+ struct iommu_instance *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+
+ if (WARN_ON(!iommu))
+ return;
+
+ of_node_get(to_of_node(fwnode));
+ INIT_LIST_HEAD(&iommu->list);
+ iommu->fwnode = fwnode;
+ iommu->ops = ops;
+ spin_lock(&iommu_instance_lock);
+ list_add_tail(&iommu->list, &iommu_instance_list);
+ spin_unlock(&iommu_instance_lock);
+}
+
+const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode)
+{
+ struct iommu_instance *instance;
+ const struct iommu_ops *ops = NULL;
+
+ spin_lock(&iommu_instance_lock);
+ list_for_each_entry(instance, &iommu_instance_list, list)
+ if (instance->fwnode == fwnode) {
+ ops = instance->ops;
+ break;
+ }
+ spin_unlock(&iommu_instance_lock);
+ return ops;
+}
+
int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
const struct iommu_ops *ops)
{
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 5b82862..0f57ddc 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -96,45 +96,6 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
}
EXPORT_SYMBOL_GPL(of_get_dma_window);
-struct of_iommu_node {
- struct list_head list;
- struct device_node *np;
- const struct iommu_ops *ops;
-};
-static LIST_HEAD(of_iommu_list);
-static DEFINE_SPINLOCK(of_iommu_lock);
-
-void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops)
-{
- struct of_iommu_node *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
-
- if (WARN_ON(!iommu))
- return;
-
- of_node_get(np);
- INIT_LIST_HEAD(&iommu->list);
- iommu->np = np;
- iommu->ops = ops;
- spin_lock(&of_iommu_lock);
- list_add_tail(&iommu->list, &of_iommu_list);
- spin_unlock(&of_iommu_lock);
-}
-
-const struct iommu_ops *of_iommu_get_ops(struct device_node *np)
-{
- struct of_iommu_node *node;
- const struct iommu_ops *ops = NULL;
-
- spin_lock(&of_iommu_lock);
- list_for_each_entry(node, &of_iommu_list, list)
- if (node->np == np) {
- ops = node->ops;
- break;
- }
- spin_unlock(&of_iommu_lock);
- return ops;
-}
-
static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
{
struct of_phandle_args *iommu_spec = data;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 436dc21..f2960e4 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -351,6 +351,9 @@ int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
const struct iommu_ops *ops);
void iommu_fwspec_free(struct device *dev);
int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
+void iommu_register_instance(struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops);
+const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode);
#else /* CONFIG_IOMMU_API */
@@ -580,6 +583,17 @@ static inline int iommu_fwspec_add_ids(struct device *dev, u32 *ids,
return -ENODEV;
}
+static inline void iommu_register_instance(struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops)
+{
+}
+
+static inline
+const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
#endif /* CONFIG_IOMMU_API */
#endif /* __LINUX_IOMMU_H */
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
index e80b9c7..6a7fc50 100644
--- a/include/linux/of_iommu.h
+++ b/include/linux/of_iommu.h
@@ -31,8 +31,16 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev,
#endif /* CONFIG_OF_IOMMU */
-void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops);
-const struct iommu_ops *of_iommu_get_ops(struct device_node *np);
+static inline void of_iommu_set_ops(struct device_node *np,
+ const struct iommu_ops *ops)
+{
+ iommu_register_instance(&np->fwnode, ops);
+}
+
+static inline const struct iommu_ops *of_iommu_get_ops(struct device_node *np)
+{
+ return iommu_get_instance(&np->fwnode);
+}
extern struct of_device_id __iommu_of_table;
--
2.10.0
^ permalink raw reply related
* [PATCH v8 03/16] drivers: acpi: iort: add support for IOMMU fwnode registration
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
The ACPI IORT table provide entries for IOMMU (aka SMMU in ARM world)
components that allow creating the kernel data structures required to
probe and initialize the IOMMU devices.
This patch provides support in the IORT kernel code to register IOMMU
components and their respective fwnode.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
drivers/acpi/arm64/iort.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 2c46ebc..1ac2720 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -20,7 +20,9 @@
#include <linux/acpi_iort.h>
#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/pci.h>
+#include <linux/slab.h>
struct iort_its_msi_chip {
struct list_head list;
@@ -28,6 +30,90 @@ struct iort_its_msi_chip {
u32 translation_id;
};
+struct iort_fwnode {
+ struct list_head list;
+ struct acpi_iort_node *iort_node;
+ struct fwnode_handle *fwnode;
+};
+static LIST_HEAD(iort_fwnode_list);
+static DEFINE_SPINLOCK(iort_fwnode_lock);
+
+/**
+ * iort_set_fwnode() - Create iort_fwnode and use it to register
+ * iommu data in the iort_fwnode_list
+ *
+ * @node: IORT table node associated with the IOMMU
+ * @fwnode: fwnode associated with the IORT node
+ *
+ * Returns: 0 on success
+ * <0 on failure
+ */
+static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
+ struct fwnode_handle *fwnode)
+{
+ struct iort_fwnode *np;
+
+ np = kzalloc(sizeof(struct iort_fwnode), GFP_ATOMIC);
+
+ if (WARN_ON(!np))
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&np->list);
+ np->iort_node = iort_node;
+ np->fwnode = fwnode;
+
+ spin_lock(&iort_fwnode_lock);
+ list_add_tail(&np->list, &iort_fwnode_list);
+ spin_unlock(&iort_fwnode_lock);
+
+ return 0;
+}
+
+/**
+ * iort_get_fwnode() - Retrieve fwnode associated with an IORT node
+ *
+ * @node: IORT table node to be looked-up
+ *
+ * Returns: fwnode_handle pointer on success, NULL on failure
+ */
+static inline
+struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node)
+{
+ struct iort_fwnode *curr;
+ struct fwnode_handle *fwnode = NULL;
+
+ spin_lock(&iort_fwnode_lock);
+ list_for_each_entry(curr, &iort_fwnode_list, list) {
+ if (curr->iort_node == node) {
+ fwnode = curr->fwnode;
+ break;
+ }
+ }
+ spin_unlock(&iort_fwnode_lock);
+
+ return fwnode;
+}
+
+/**
+ * iort_delete_fwnode() - Delete fwnode associated with an IORT node
+ *
+ * @node: IORT table node associated with fwnode to delete
+ */
+static inline void iort_delete_fwnode(struct acpi_iort_node *node)
+{
+ struct iort_fwnode *curr, *tmp;
+
+ spin_lock(&iort_fwnode_lock);
+ list_for_each_entry_safe(curr, tmp, &iort_fwnode_list, list) {
+ if (curr->iort_node == node) {
+ list_del(&curr->list);
+ kfree(curr);
+ break;
+ }
+ }
+ spin_unlock(&iort_fwnode_lock);
+}
+
typedef acpi_status (*iort_find_node_callback)
(struct acpi_iort_node *node, void *context);
--
2.10.0
^ permalink raw reply related
* [PATCH v8 02/16] drivers: acpi: iort: introduce linker section for IORT entries probing
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
Since commit e647b532275b ("ACPI: Add early device probing
infrastructure") the kernel has gained the infrastructure that allows
adding linker script section entries to execute ACPI driver callbacks
(ie probe routines) for all subsystems that register a table entry
in the respective kernel section (eg clocksource, irqchip).
Since ARM IOMMU devices data is described through IORT tables when
booting with ACPI, the ARM IOMMU drivers must be made able to hook ACPI
callback routines that are called to probe IORT entries and initialize
the respective IOMMU devices.
To avoid adding driver specific hooks into IORT table initialization
code (breaking therefore code modularity - ie ACPI IORT code must be made
aware of ARM SMMU drivers ACPI init callbacks), this patch adds code
that allows ARM SMMU drivers to take advantage of the ACPI early probing
infrastructure, so that they can add linker script section entries
containing drivers callback to be executed on IORT tables detection.
Since IORT nodes are differentiated by a type, the callback routines
can easily parse the IORT table entries, check the IORT nodes and
carry out some actions whenever the IORT node type associated with
the driver specific callback is matched.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
drivers/acpi/arm64/iort.c | 13 ++++++++++---
include/asm-generic/vmlinux.lds.h | 1 +
include/linux/acpi_iort.h | 3 +++
3 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 6b81746..2c46ebc 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -361,8 +361,15 @@ void __init acpi_iort_init(void)
acpi_status status;
status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
- const char *msg = acpi_format_exception(status);
- pr_err("Failed to get table, %s\n", msg);
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND) {
+ const char *msg = acpi_format_exception(status);
+
+ pr_err("Failed to get table, %s\n", msg);
+ }
+
+ return;
}
+
+ acpi_probe_device_table(iort);
}
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 3074796..f9c9f3c 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -563,6 +563,7 @@
IRQCHIP_OF_MATCH_TABLE() \
ACPI_PROBE_TABLE(irqchip) \
ACPI_PROBE_TABLE(clksrc) \
+ ACPI_PROBE_TABLE(iort) \
EARLYCON_TABLE()
#define INIT_TEXT \
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 0e32dac..d16fdda 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -39,4 +39,7 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev,
{ return NULL; }
#endif
+#define IORT_ACPI_DECLARE(name, table_id, fn) \
+ ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
+
#endif /* __ACPI_IORT_H__ */
--
2.10.0
^ permalink raw reply related
* [PATCH v8 01/16] drivers: acpi: add FWNODE_ACPI_STATIC fwnode type
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116152936.22955-1-lorenzo.pieralisi@arm.com>
On systems booting with a device tree, every struct device is associated
with a struct device_node, that provides its DT firmware representation.
The device node can be used in generic kernel contexts (eg IRQ
translation, IOMMU streamid mapping), to retrieve the properties
associated with the device and carry out kernel operations accordingly.
Owing to the 1:1 relationship between the device and its device_node,
the device_node can also be used as a look-up token for the device (eg
looking up a device through its device_node), to retrieve the device in
kernel paths where the device_node is available.
On systems booting with ACPI, the same abstraction provided by
the device_node is required to provide look-up functionality.
The struct acpi_device, that represents firmware objects in the
ACPI namespace already includes a struct fwnode_handle of
type FWNODE_ACPI as their member; the same abstraction is missing
though for devices that are instantiated out of static ACPI tables
entries (eg ARM SMMU devices).
Add a new fwnode_handle type to associate devices created out
of static ACPI table entries to the respective firmware components
and create a simple ACPI core layer interface to dynamically allocate
and free the corresponding firmware nodes so that kernel subsystems
can use it to instantiate the nodes and associate them with the
respective devices.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: Tomasz Nowicki <tn@semihalf.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Tested-by: Tomasz Nowicki <tn@semihalf.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
---
include/linux/acpi.h | 21 +++++++++++++++++++++
include/linux/fwnode.h | 3 ++-
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 689a8b9..6efb13c 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -56,6 +56,27 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev)
acpi_fwnode_handle(adev) : NULL)
#define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev))
+static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
+{
+ struct fwnode_handle *fwnode;
+
+ fwnode = kzalloc(sizeof(struct fwnode_handle), GFP_KERNEL);
+ if (!fwnode)
+ return NULL;
+
+ fwnode->type = FWNODE_ACPI_STATIC;
+
+ return fwnode;
+}
+
+static inline void acpi_free_fwnode_static(struct fwnode_handle *fwnode)
+{
+ if (WARN_ON(!fwnode || fwnode->type != FWNODE_ACPI_STATIC))
+ return;
+
+ kfree(fwnode);
+}
+
/**
* ACPI_DEVICE_CLASS - macro used to describe an ACPI device with
* the PCI-defined class-code information
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 8516717..8bd28ce 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -17,8 +17,9 @@ enum fwnode_type {
FWNODE_OF,
FWNODE_ACPI,
FWNODE_ACPI_DATA,
+ FWNODE_ACPI_STATIC,
FWNODE_PDATA,
- FWNODE_IRQCHIP,
+ FWNODE_IRQCHIP
};
struct fwnode_handle {
--
2.10.0
^ permalink raw reply related
* [PATCH v8 00/16] ACPI IORT ARM SMMU support
From: Lorenzo Pieralisi @ 2016-11-16 15:29 UTC (permalink / raw)
To: linux-arm-kernel
This patch series is v8 of a previous posting:
https://lkml.org/lkml/2016/11/9/422
v7 -> v8
- Renamed fwnode iommu_ops registration API according to review
- Minor change in ARM SMMU driver DT/ACPI split
- Added review tags
v6 -> v7
- Rebased against v4.9-rc4
- Fixed IORT probing on ACPI systems with missing IORT table
- Fixed SMMUv1/v2 global interrupt detection
- Updated iommu_ops firmware look-up
v5 -> v6
- Rebased against v4.9-rc1
- Changed FWNODE_IOMMU to FWNODE_ACPI_STATIC
- Moved platform devices creation into IORT code
- Updated fwnode handling
- Added default dma masks initialization
v4 -> v5
- Added SMMUv1/v2 support
- Rebased against v4.8-rc5 and dependencies series
- Consolidated IORT platform devices creation
v3 -> v4
- Added single mapping API (for IORT named components)
- Fixed arm_smmu_iort_xlate() return value
- Reworked fwnode registration and platform device creation
ordering to fix probe ordering dependencies
- Added code to keep device_node ref count with new iommu
fwspec API
- Added patch to make iommu_fwspec arch agnostic
- Dropped RFC status
- Rebased against v4.8-rc2
v2 -> v3
- Rebased on top of dependencies series [1][2][3](v4.7-rc3)
- Added back reliance on ACPI early probing infrastructure
- Patch[1-3] merged through other dependent series
- Added back IOMMU fwnode generalization
- Move SMMU v3 static functions configuration to IORT code
- Implemented generic IOMMU fwspec API
- Added code to implement fwnode platform device look-up
v1 -> v2:
- Rebased on top of dependencies series [1][2][3](v4.7-rc1)
- Removed IOMMU fwnode generalization
- Implemented ARM SMMU v3 ACPI probing instead of ARM SMMU v2
owing to patch series dependencies [1]
- Moved platform device creation logic to IORT code to
generalize its usage for ARM SMMU v1-v2-v3 components
- Removed reliance on ACPI early device probing
- Created IORT specific iommu_xlate() translation hook leaving
OF code unchanged according to v1 reviews
The ACPI IORT table provides information that allows instantiating
ARM SMMU devices and carrying out id mappings between components on
ARM based systems (devices, IOMMUs, interrupt controllers).
http://infocenter.arm.com/help/topic/com.arm.doc.den0049b/DEN0049B_IO_Remapping_Table.pdf
Building on basic IORT support, this patchset enables ARM SMMUs support
on ACPI systems.
Most of the code is aimed at building the required generic ACPI
infrastructure to create and enable IOMMU components and to bring
the IOMMU infrastructure for ACPI on par with DT, which is going to
make future ARM SMMU components easier to integrate.
PATCH (1) adds a FWNODE_ACPI_STATIC type to the struct fwnode_handle type.
It is required to attach a fwnode identifier to platform
devices allocated/detected through static ACPI table entries
(ie IORT tables entries).
IOMMU devices have to have an identifier to look them up
eg IOMMU core layer carrying out id translation. This can be
done through a fwnode_handle (ie IOMMU platform devices created
out of IORT tables are not ACPI devices hence they can't be
allocated as such, otherwise they would have a fwnode_handle of
type FWNODE_ACPI).
PATCH (2) makes use of the ACPI early probing API to add a linker script
section for probing devices via IORT ACPI kernel code.
PATCH (3) provides IORT support for registering IOMMU IORT node through
their fwnode handle.
PATCH (4) make of_iommu_{set/get}_ops() functions DT agnostic and
rename the registration API.
PATCH (5) convert ARM SMMU driver to use fwnode instead of of_node as
look-up and iommu_ops retrieval token.
PATCH (6) convert ARM SMMU v3 driver to use fwnode instead of of_node as
look-up and iommu_ops retrieval token.
PATCH (7) implements the of_dma_configure() API in ACPI world -
acpi_dma_configure() - and patches PCI and ACPI core code to
start making use of it.
PATCH (8) provides an IORT function to detect existence of specific type
of IORT components.
PATCH (9) creates the kernel infrastructure required to create ARM SMMU
platform devices for IORT nodes.
PATCH (10) refactors the ARM SMMU v3 driver so that the init functions are
split in a way that groups together code that probes through DT
and code that carries out HW registers FW agnostic probing, in
preparation for adding the ACPI probing path.
PATCH (11) adds ARM SMMU v3 IORT IOMMU operations to create and probe
ARM SMMU v3 components.
PATCH (12) refactors the ARM SMMU v1/v2 driver so that the init functions
are split in a way that groups together code that probes
through DT and code that carries out HW registers FW agnostic
probing, in preparation for adding the ACPI probing path.
PATCH (13) adds ARM SMMU v1/v2 IORT IOMMU operations to create and
probe ARM SMMU v1/v2 components.
PATCH (14) Extend the IORT iort_node_map_rid() to work on a type mask
instead of a single type so that the translation API can
be used on a range of components.
PATCH (15) Add IORT API to carry out id mappings for components that do
do not have an input identifier/RIDs (ie named components).
PATCH (16) provides IORT infrastructure to carry out IOMMU configuration
for devices and hook it up to the previously introduced ACPI
DMA configure API.
This patchset is provided for review/testing purposes here:
git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux.git acpi/iort-smmu-v8
Tested on Juno and FVP models for ARM SMMU v1 and v3 probing path.
Lorenzo Pieralisi (16):
drivers: acpi: add FWNODE_ACPI_STATIC fwnode type
drivers: acpi: iort: introduce linker section for IORT entries probing
drivers: acpi: iort: add support for IOMMU fwnode registration
drivers: iommu: make of_iommu_set/get_ops() DT agnostic
drivers: iommu: arm-smmu: convert struct device of_node to fwnode
usage
drivers: iommu: arm-smmu-v3: convert struct device of_node to fwnode
usage
drivers: acpi: implement acpi_dma_configure
drivers: acpi: iort: add node match function
drivers: acpi: iort: add support for ARM SMMU platform devices
creation
drivers: iommu: arm-smmu-v3: split probe functions into DT/generic
portions
drivers: iommu: arm-smmu-v3: add IORT configuration
drivers: iommu: arm-smmu: split probe functions into DT/generic
portions
drivers: iommu: arm-smmu: add IORT configuration
drivers: acpi: iort: replace rid map type with type mask
drivers: acpi: iort: add single mapping function
drivers: acpi: iort: introduce iort_iommu_configure
drivers/acpi/arm64/iort.c | 595 +++++++++++++++++++++++++++++++++++++-
drivers/acpi/glue.c | 4 +-
drivers/acpi/scan.c | 45 +++
drivers/iommu/arm-smmu-v3.c | 105 +++++--
drivers/iommu/arm-smmu.c | 154 ++++++++--
drivers/iommu/iommu.c | 40 +++
drivers/iommu/of_iommu.c | 39 ---
drivers/pci/probe.c | 3 +-
include/acpi/acpi_bus.h | 2 +
include/asm-generic/vmlinux.lds.h | 1 +
include/linux/acpi.h | 26 ++
include/linux/acpi_iort.h | 14 +
include/linux/fwnode.h | 3 +-
include/linux/iommu.h | 14 +
include/linux/of_iommu.h | 12 +-
15 files changed, 953 insertions(+), 104 deletions(-)
--
2.10.0
^ permalink raw reply
* [PATCH] iommu: mtk: add common-clk dependency
From: Arnd Bergmann @ 2016-11-16 15:28 UTC (permalink / raw)
To: linux-arm-kernel
After the MT2701 clock driver was added, we get a harmless warning for
the iommu driver that selects it, when compile-testing without
COMMON_CLK.
warning: (MTK_IOMMU_V1) selects COMMON_CLK_MT2701_IMGSYS which has unmet direct dependencies (COMMON_CLK)
Adding a dependency on COMMON_CLK avoids the warning.
Fixes: e9862118272a ("clk: mediatek: Add MT2701 clock support")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/iommu/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 8ee54d71c7eb..bb537d06d319 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -346,7 +346,7 @@ config MTK_IOMMU
config MTK_IOMMU_V1
bool "MTK IOMMU Version 1 (M4U gen1) Support"
- depends on ARM
+ depends on ARM && COMMON_CLK
depends on ARCH_MEDIATEK || COMPILE_TEST
select ARM_DMA_USE_IOMMU
select IOMMU_API
--
2.9.0
^ permalink raw reply related
* [PATCH/RESEND] recordmcount: arm: Implement make_nop
From: Ard Biesheuvel @ 2016-11-16 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116090838.6c540230@gandalf.local.home>
On 16 November 2016 at 14:08, Steven Rostedt <rostedt@goodmis.org> wrote:
> On Wed, 16 Nov 2016 11:48:38 +0000
> Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>
>> >
>> > Does that allay your concerns?
>> >
>>
>> Yes, it does. Thanks
>
> Does this mean I can pull this patch into my queue then?
>
Fine by me
Thanks,
Ard.
^ 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