* [PATCH 3/8] PM / Domains: Allow domain power states to be read from DT
From: Ulf Hansson @ 2016-10-06 9:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475699519-109623-4-git-send-email-lina.iyer@linaro.org>
On 5 October 2016 at 22:31, Lina Iyer <lina.iyer@linaro.org> wrote:
> This patch allows domains to define idle states in the DT. SoC's can
> define domain idle states in DT using the "domain-idle-states" property
> of the domain provider. Calling of_pm_genpd_init() will read the idle
> states and initialize the genpd for the domain.
>
> In addition to the entry and exit latency for idle state, also add
> residency_ns, param and of_node property to each state. A domain idling
> in a state is only power effecient if it stays idle for a certain period
> in that state. The residency provides this minimum time for the idle
> state to provide power benefits. The param is a state specific u32 value
> that the platform may use for that idle state.
>
> This patch is based on the original patch by Marc Titinger.
>
> Signed-off-by: Marc Titinger <mtitinger+renesas@baylibre.com>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
> drivers/base/power/domain.c | 103 ++++++++++++++++++++++++++++++++++++++++++++
> include/linux/pm_domain.h | 8 ++++
> 2 files changed, 111 insertions(+)
>
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index 740afa9..368a5b8 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -1895,6 +1895,109 @@ out:
> return ret ? -EPROBE_DEFER : 0;
> }
> EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
> +
> +static const struct of_device_id idle_state_match[] = {
> + { .compatible = "arm,idle-state", },
> + { }
> +};
> +
> +static int read_genpd_state(struct genpd_power_state *genpd_state,
/s/read_genpd_state/genpd_parse_state
> + struct device_node *state_node)
> +{
> + int err = 0;
No need to assign err to 0.
> + u32 latency;
> + u32 residency;
> + u32 entry_latency, exit_latency;
> + const struct of_device_id *match_id;
> +
> + match_id = of_match_node(idle_state_match, state_node);
> + if (!match_id)
> + return -EINVAL;
> +
> + err = of_property_read_u32(state_node, "entry-latency-us",
> + &entry_latency);
> + if (err) {
> + pr_debug(" * %s missing entry-latency-us property\n",
> + state_node->full_name);
> + return -EINVAL;
> + }
> +
> + err = of_property_read_u32(state_node, "exit-latency-us",
> + &exit_latency);
> + if (err) {
> + pr_debug(" * %s missing exit-latency-us property\n",
> + state_node->full_name);
> + return -EINVAL;
> + }
> +
> + err = of_property_read_u32(state_node, "min-residency-us", &residency);
> + if (!err)
> + genpd_state->residency_ns = 1000 * residency;
> +
> + latency = entry_latency + exit_latency;
Hmm, this is probably not what you want.
The genpd governor, via __default_power_down_ok(), already adds the
->power_on_latency_ns and the ->power_off_latency_ns, when it
validates which idle state you are allowed to enter.
> + genpd_state->power_on_latency_ns = 1000 * latency;
> + genpd_state->power_off_latency_ns = 1000 * entry_latency;
> +
> + return 0;
> +}
> +
> +/**
> + * of_genpd_parse_idle_states: Return array of idle states for the genpd.
> + *
> + * @dn: The genpd device node
> + * @states: The pointer to which the state array will be saved.
> + * @n: The count of elements in the array returned from this function.
> + *
> + * Returns the device states parsed from the OF node. The memory for the states
> + * is allocated by this function and is the responsibility of the caller to
> + * free the memory after use.
> + */
> +int of_genpd_parse_idle_states(struct device_node *dn,
> + struct genpd_power_state **states, int *n)
> +{
> + struct genpd_power_state *st;
> + struct device_node *np;
> + int i, ret = 0;
> + int count;
> +
> + for (count = 0; ; count++)
> + if (!of_parse_phandle(dn, "domain-idle-states", count))
> + break;
I think it's better to use of_count_phandle_with_args() to find out
the number of phandles.
> +
> + st = kcalloc(count, sizeof(*st), GFP_KERNEL);
> + if (!st)
> + return -ENOMEM;
> +
> + for (i = 0; i < count; i++) {
> + np = of_parse_phandle(dn, "domain-idle-states", i);
Isn't this a case of when it would be convenient to use the
of_phandle_iterator*() APIs?
> + if (!np) {
> + ret = -EFAULT;
> + break;
> + }
> +
> + ret = read_genpd_state(&st[i], np);
> + if (ret) {
> + pr_err
> + ("Parsing idle state node %s failed with err %d\n",
> + np->full_name, ret);
> + of_node_put(np);
> + break;
> + }
> + of_node_put(np);
> + }
> +
> + if (ret) {
> + kfree(st);
> + return ret;
> + }
> +
> + *n = count;
> + *states = st;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(of_genpd_parse_idle_states);
> +
> #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
>
>
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index c113713..4c9152d 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -204,6 +204,8 @@ extern int of_genpd_add_device(struct of_phandle_args *args,
> extern int of_genpd_add_subdomain(struct of_phandle_args *parent,
> struct of_phandle_args *new_subdomain);
> extern struct generic_pm_domain *of_genpd_remove_last(struct device_node *np);
> +extern int of_genpd_parse_idle_states(struct device_node *dn,
> + struct genpd_power_state **states, int *n);
>
> int genpd_dev_pm_attach(struct device *dev);
> #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
> @@ -233,6 +235,12 @@ static inline int of_genpd_add_subdomain(struct of_phandle_args *parent,
> return -ENODEV;
> }
>
> +static inline int of_genpd_parse_idle_states(struct device_node *dn,
> + struct genpd_power_state **states, int *n)
> +{
> + return -ENODEV;
> +}
> +
> static inline int genpd_dev_pm_attach(struct device *dev)
> {
> return -ENODEV;
> --
> 2.7.4
>
Kind regards
Uffe
^ permalink raw reply
* [PATCH 5/7] arm64/kvm: hyp: tlb: use __tlbi() helper
From: Punit Agrawal @ 2016-10-06 9:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <07921948-8692-67c1-8ae9-a68f0cc387c8@suse.com>
Matthias Brugger <mbrugger@suse.com> writes:
> On 13/09/16 12:16, Punit Agrawal wrote:
>> From: Mark Rutland <mark.rutland@arm.com>
>>
>> Now that we have a __tlbi() helper, make use of this in the arm64 KVM hyp
>> code to get rid of asm() boilerplate. At the same time, we simplify
>> __tlb_flush_vm_context by using __flush_icache_all(), as this has the
>> appropriate instruction cache maintenance and barrier.
>>
>> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
>> Cc: Marc Zyngier <marc.zyngier@arm.com>
>> [ rename tlbi -> __tlbi, convert additional sites, update commit log ]
>> Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
>> Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
>> ---
>
> Reviewed-by: Matthias Brugger <mbrugger@suse.com>
Thanks for reviewing the patch. I'll re-spin a new version with the tag
after the merge window.
Punit
[...]
^ permalink raw reply
* [PATCH v9 17/19] drm/virtio: kconfig: Fix recursive dependency issue.
From: Peter Griffin @ 2016-10-06 9:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <8760pqncee.fsf@intel.com>
Hi Jani,
Sorry for the delay, I've been travelling last week.
On Tue, 20 Sep 2016, Jani Nikula wrote:
> On Tue, 20 Sep 2016, Peter Griffin <peter.griffin@linaro.org> wrote:
> > Hi Emil,
> >
> > On Tue, 20 Sep 2016, Emil Velikov wrote:
> >
> >> On 5 September 2016 at 14:16, Peter Griffin <peter.griffin@linaro.org> wrote:
> >> > ST_SLIM_REMOTEPROC must select REMOTEPROC, which exposes the following
> >> > recursive dependency.
> >
> >
> >> >
> >> From a humble skim through remoteproc, drm and a few other subsystems
> >> I think the above is wrong. All the drivers (outside of remoteproc),
> >> that I've seen, depend on the core component, they don't select it.
> >
> > I will let Bjorn comment on the remoteproc subsystem Kconfig design, and
> > why it is like it is.
> >
> > For this particular SLIM_RPROC I have added it to Kconfig in keeping with all
> > the other drivers in the remoteproc subsystem which has exposed this recursive
> > dependency issue.
> >
> > For this particular kconfig symbol a quick grep reveals more drivers in
> > the kernel using 'select', than 'depend on'
> >
> > git grep "select VIRTIO" | wc -l
> > 14
> >
> > git grep "depends on VIRTIO" | wc -l
> > 10
> >
> >
> >> Furthermore most places explicitly hide the drivers from the menu if
> >> the core component isn't enabled.
> >
> > Remoteproc subsystem takes a different approach, the core code is only enabled
> > if a driver which relies on it is enabled. This IMHO makes sense, as
> > remoteproc is not widely used (only a few particular ARM SoC's).
> >
> > It is true that for subsystems which rely on the core component being
> > explicitly enabled, they often tend to hide drivers which depend on it
> > from the menu unless it is. This also makes sense.
> >
> >>
> >> Is there something that requires such a different/unusual behaviour in
> >> remoteproc ?
> >>
> >
> > I'm not sure it is that unusual...looking at config USB, it selects USB_COMMON in
> > mfd subsystem, client drivers select MFD_CORE.
> >
> > I've added Arnd to this thread, as I've seen lots of Kconfig patches from him
> > recently, maybe he has some thoughts on whether this is the correct fix or not?
>
>
> Documentation/kbuild/kconfig-language.txt:
>
> Note:
> select should be used with care. select will force
> a symbol to a value without visiting the dependencies.
> By abusing select you are able to select a symbol FOO even
> if FOO depends on BAR that is not set.
> In general use select only for non-visible symbols
> (no prompts anywhere) and for symbols with no dependencies.
> That will limit the usefulness but on the other hand avoid
> the illegal configurations all over.
Thanks for the documentation link. I believe this proves this patch is an
appropriate fix as VIRTIO is a non-visible symbol, and has no dependencies.
In fact the help text for VIRTIO even states this option should be selected
by any driver which implements virtio.
>
> People tend to abuse select because it's "convenient". If you depend,
> but some of your dependencies aren't met, you're in for some digging
> through Kconfig to find the missing deps. Just to make the option you
> want visible in menuconfig. If you instead select something with
> dependencies, it'll be right most of the time, and it's "convenient",
> until it breaks. (And hey, it usually breaks for someone else with some
> other config, so it's still convenient for you.)
I'm sure they do but in this case it is actually the use of 'depends on'
which has caused the breakage and inconvenience for somebody else and sadly this
inconvienice is still on-going due to this patch not being applied or getting an
acked-by from the appropriate maintainers.
>
> Perhaps kconfig should complain about selecting visible symbols and
> symbols with dependencies.
That sounds like it would be a useful addition.
Is it possible to get this patch applied or an acked-by to avoid further delay
to the fdma series?
regards,
Peter.
^ permalink raw reply
* [PATCH -next] serial: stm32: fix build failure
From: Alexandre TORGUE @ 2016-10-06 9:33 UTC (permalink / raw)
To: linux-arm-kernel
While building m32r config the build failed with:
ERROR: stm32-usart.c:(.text+0xdc988): undefined reference to `bad_dma_ops'
To satisfy the dependency CONFIG_SERIAL_STM32 should depend on HAS_DMA.
Signed-off-by: Alexandre TORGUE <alexandre.torgue@st.com>
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index c783140..8a261c0 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1624,6 +1624,7 @@ config SERIAL_SPRD_CONSOLE
config SERIAL_STM32
tristate "STMicroelectronics STM32 serial port support"
+ depends on HAS_DMA
select SERIAL_CORE
depends on ARM || COMPILE_TEST
help
--
1.9.1
^ permalink raw reply related
* arm64: kernel BUG at mm/page_alloc.c:1844!
From: Robert Richter @ 2016-10-06 9:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161005141313.GF22012@rric.localdomain>
On 05.10.16 16:13:13, Robert Richter wrote:
> I tried various changes to fix that, but without success so far:
>
> a) I modified reserve_regions() to use memblock_reserve() instead of
> memblock_mark_nomap(). This marked efi regions as reserved instead of
> unmap. pfn_valid() now worked as before the nomap change. I could boot
> the system but noticed the following malloc assertion which looks like
> there is some mem corruption:
>
> emacs: malloc.c:2395: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
>
> Other than that the system looked ok so far.
>
> I checked pfn used by the process with kmem:mm_page_alloc_zone_locked,
> it looked correct with all pfn allocated from free memory, mem ranges
> reported by efi as reserved were not used.
I have updated the packages in my system and the problem went
away. Also I have run memtest for memory ranges close to efi
boundaries without any issues. So I assume this problem was userland
specific and unrelated to the original bug.
>
> b) I found a quote that for sparsemem the entire memmap (all pages have a
> struct *page) for single section (include/linux/mmzone.h):
>
> "In SPARSEMEM, it is assumed that a valid section has a memmap for
> the entire section."
>
> So I implemented a arm64 private __early_pfn_valid() function that
> uses memblock_is_memory() to setup all pages of a zone. I got the same
> result as for a).
>
> c) I modified (almost) all arch arm64 users of pfn_valid() to use
> memblock_mark_nomap() instead of pfn_valid() and changed pfn_valid()
> to use memblock_is_memory(). Same problem as a).
I am going to prepare a patch that implements c).
-Robert
>
> d) Enabling HOLES_IN_ZONE config option does not looks correct for
> sparsemem, trying it anyway causes VM_BUG_ON_PAGE() in in line 1849
> since (uninitialized) struct *page is accessed. This did not work
> either.
^ permalink raw reply
* [PATCH] arm64, numa: Add cpu_to_node() implementation.
From: Robert Richter @ 2016-10-06 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <57EA1100.2080900@linaro.org>
On 27.09.16 14:26:08, Hanjun Guo wrote:
> On 09/20/2016 09:21 PM, Robert Richter wrote:
> >On 20.09.16 19:32:34, Hanjun Guo wrote:
> >>On 09/20/2016 06:43 PM, Robert Richter wrote:
> >
> >>>Unfortunately either your nor my code does fix the BUG_ON() I see with
> >>>the numa kernel:
> >>>
> >>> kernel BUG at mm/page_alloc.c:1848!
> >>>
> >>>See below for the core dump. It looks like this happens due to moving
> >>>a mem block where first and last page are mapped to different numa
> >>>nodes, thus, triggering the BUG_ON().
> >>
> >>Didn't triggered it on our NUMA hardware, could you provide your
> >>config then we can have a try?
> >
> >Config attached. Other configs with an initrd fail too.
>
> hmm, we can't reproduce it on our hardware, do we need
> to run some specific stress test on it?
No, it depends on the efi memory zones marked reserved. See my other
thread on this where I have attached mem ranges from the log. I have a
fix available already.
Thanks,
-Robert
^ permalink raw reply
* [PATCH v2] arm64: dts: marvell: Add definition for the Globalscale Marvell ESPRESSOBin Board
From: Romain Perier @ 2016-10-06 9:14 UTC (permalink / raw)
To: linux-arm-kernel
This is a high performance 64 bit dual core low power consuming
networking computing platform based on the ARMv8 architecture.
It contains an Armada 3720 running up to 1.2Ghz.
This commit adds a basic definition for this board.
Signed-off-by: Romain Perier <romain.perier@free-electrons.com>
---
Changes in v2:
- Improved commit message
- Added informations about connectors
arch/arm64/boot/dts/marvell/Makefile | 1 +
.../boot/dts/marvell/armada-3720-espressobin.dts | 82 ++++++++++++++++++++++
2 files changed, 83 insertions(+)
create mode 100644 arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
diff --git a/arch/arm64/boot/dts/marvell/Makefile b/arch/arm64/boot/dts/marvell/Makefile
index 308468d..392eeb6 100644
--- a/arch/arm64/boot/dts/marvell/Makefile
+++ b/arch/arm64/boot/dts/marvell/Makefile
@@ -4,6 +4,7 @@ dtb-$(CONFIG_ARCH_BERLIN) += berlin4ct-stb.dtb
# Mvebu SoC Family
dtb-$(CONFIG_ARCH_MVEBU) += armada-3720-db.dtb
+dtb-$(CONFIG_ARCH_MVEBU) += armada-3720-espressobin.dtb
dtb-$(CONFIG_ARCH_MVEBU) += armada-7040-db.dtb
always := $(dtb-y)
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
new file mode 100644
index 0000000..ae005f1
--- /dev/null
+++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dts
@@ -0,0 +1,82 @@
+/*
+ * Device Tree file for Globalscale Marvell ESPRESSOBin Board
+ * Copyright (C) 2016 Marvell
+ *
+ * Romain Perier <romain.perier@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "armada-372x.dtsi"
+
+/ {
+ model = "Globalscale Marvell ESPRESSOBin Board";
+ compatible = "globalscale,espressobin", "marvell,armada3720", "marvell,armada3710";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
+ };
+};
+
+/* J9 */
+&pcie0 {
+ status = "okay";
+};
+
+/* J6 */
+&sata {
+ status = "okay";
+};
+
+/* J5 */
+&uart0 {
+ status = "okay";
+};
+
+/* J7 */
+&usb3 {
+ status = "okay";
+};
--
2.9.3
^ permalink raw reply related
* [PATCH v13 15/15] vfio/type1: Return the MSI geometry through VFIO_IOMMU_GET_INFO capability chains
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
This patch allows the user-space to retrieve the MSI geometry. The
implementation is based on capability chains, now also added to
VFIO_IOMMU_GET_INFO.
The returned info comprise:
- whether the MSI IOVA are constrained to a reserved range (x86 case) and
in the positive, the start/end of the aperture,
- or whether the IOVA aperture need to be set by the userspace. In that
case, the size and alignment of the IOVA window to be provided are
returned.
In case the userspace must provide the IOVA aperture, we currently report
a size/alignment based on all the doorbells registered by the host kernel.
This may exceed the actual needs.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v11 -> v11:
- msi_doorbell_pages was renamed msi_doorbell_calc_pages
v9 -> v10:
- move cap_offset after iova_pgsizes
- replace __u64 alignment by __u32 order
- introduce __u32 flags in vfio_iommu_type1_info_cap_msi_geometry and
fix alignment
- call msi-doorbell API to compute the size/alignment
v8 -> v9:
- use iommu_msi_supported flag instead of programmable
- replace IOMMU_INFO_REQUIRE_MSI_MAP flag by a more sophisticated
capability chain, reporting the MSI geometry
v7 -> v8:
- use iommu_domain_msi_geometry
v6 -> v7:
- remove the computation of the number of IOVA pages to be provisionned.
This number depends on the domain/group/device topology which can
dynamically change. Let's rely instead rely on an arbitrary max depending
on the system
v4 -> v5:
- move msi_info and ret declaration within the conditional code
v3 -> v4:
- replace former vfio_domains_require_msi_mapping by
more complex computation of MSI mapping requirements, especially the
number of pages to be provided by the user-space.
- reword patch title
RFC v1 -> v1:
- derived from
[RFC PATCH 3/6] vfio: Extend iommu-info to return MSIs automap state
- renamed allow_msi_reconfig into require_msi_mapping
- fixed VFIO_IOMMU_GET_INFO
---
drivers/vfio/vfio_iommu_type1.c | 78 ++++++++++++++++++++++++++++++++++++++++-
include/uapi/linux/vfio.h | 32 ++++++++++++++++-
2 files changed, 108 insertions(+), 2 deletions(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index dc3ee5d..ce5e7eb 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -38,6 +38,8 @@
#include <linux/workqueue.h>
#include <linux/dma-iommu.h>
#include <linux/msi-doorbell.h>
+#include <linux/irqdomain.h>
+#include <linux/msi.h>
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
@@ -1101,6 +1103,55 @@ static int vfio_domains_have_iommu_cache(struct vfio_iommu *iommu)
return ret;
}
+static int compute_msi_geometry_caps(struct vfio_iommu *iommu,
+ struct vfio_info_cap *caps)
+{
+ struct vfio_iommu_type1_info_cap_msi_geometry *vfio_msi_geometry;
+ unsigned long order = __ffs(vfio_pgsize_bitmap(iommu));
+ struct iommu_domain_msi_geometry msi_geometry;
+ struct vfio_info_cap_header *header;
+ struct vfio_domain *d;
+ bool reserved;
+ size_t size;
+
+ mutex_lock(&iommu->lock);
+ /* All domains have same require_msi_map property, pick first */
+ d = list_first_entry(&iommu->domain_list, struct vfio_domain, next);
+ iommu_domain_get_attr(d->domain, DOMAIN_ATTR_MSI_GEOMETRY,
+ &msi_geometry);
+ reserved = !msi_geometry.iommu_msi_supported;
+
+ mutex_unlock(&iommu->lock);
+
+ size = sizeof(*vfio_msi_geometry);
+ header = vfio_info_cap_add(caps, size,
+ VFIO_IOMMU_TYPE1_INFO_CAP_MSI_GEOMETRY, 1);
+
+ if (IS_ERR(header))
+ return PTR_ERR(header);
+
+ vfio_msi_geometry = container_of(header,
+ struct vfio_iommu_type1_info_cap_msi_geometry,
+ header);
+
+ vfio_msi_geometry->flags = reserved;
+ if (reserved) {
+ vfio_msi_geometry->aperture_start = msi_geometry.aperture_start;
+ vfio_msi_geometry->aperture_end = msi_geometry.aperture_end;
+ return 0;
+ }
+
+ vfio_msi_geometry->order = order;
+ /*
+ * we compute a system-wide requirement based on all the registered
+ * doorbells
+ */
+ vfio_msi_geometry->size =
+ msi_doorbell_calc_pages(order) * ((uint64_t) 1 << order);
+
+ return 0;
+}
+
static long vfio_iommu_type1_ioctl(void *iommu_data,
unsigned int cmd, unsigned long arg)
{
@@ -1122,8 +1173,10 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
}
} else if (cmd == VFIO_IOMMU_GET_INFO) {
struct vfio_iommu_type1_info info;
+ struct vfio_info_cap caps = { .buf = NULL, .size = 0 };
+ int ret;
- minsz = offsetofend(struct vfio_iommu_type1_info, iova_pgsizes);
+ minsz = offsetofend(struct vfio_iommu_type1_info, cap_offset);
if (copy_from_user(&info, (void __user *)arg, minsz))
return -EFAULT;
@@ -1135,6 +1188,29 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
info.iova_pgsizes = vfio_pgsize_bitmap(iommu);
+ ret = compute_msi_geometry_caps(iommu, &caps);
+ if (ret)
+ return ret;
+
+ if (caps.size) {
+ info.flags |= VFIO_IOMMU_INFO_CAPS;
+ if (info.argsz < sizeof(info) + caps.size) {
+ info.argsz = sizeof(info) + caps.size;
+ info.cap_offset = 0;
+ } else {
+ vfio_info_cap_shift(&caps, sizeof(info));
+ if (copy_to_user((void __user *)arg +
+ sizeof(info), caps.buf,
+ caps.size)) {
+ kfree(caps.buf);
+ return -EFAULT;
+ }
+ info.cap_offset = sizeof(info);
+ }
+
+ kfree(caps.buf);
+ }
+
return copy_to_user((void __user *)arg, &info, minsz) ?
-EFAULT : 0;
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 4a9dbc2..8dae013 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -488,7 +488,35 @@ struct vfio_iommu_type1_info {
__u32 argsz;
__u32 flags;
#define VFIO_IOMMU_INFO_PGSIZES (1 << 0) /* supported page sizes info */
- __u64 iova_pgsizes; /* Bitmap of supported page sizes */
+#define VFIO_IOMMU_INFO_CAPS (1 << 1) /* Info supports caps */
+ __u64 iova_pgsizes; /* Bitmap of supported page sizes */
+ __u32 __resv;
+ __u32 cap_offset; /* Offset within info struct of first cap */
+};
+
+#define VFIO_IOMMU_TYPE1_INFO_CAP_MSI_GEOMETRY 1
+
+/*
+ * The MSI geometry capability allows to report the MSI IOVA geometry:
+ * - either the MSI IOVAs are constrained within a reserved IOVA aperture
+ * whose boundaries are given by [@aperture_start, @aperture_end].
+ * this is typically the case on x86 host. The userspace is not allowed
+ * to map userspace memory@IOVAs intersecting this range using
+ * VFIO_IOMMU_MAP_DMA.
+ * - or the MSI IOVAs are not requested to belong to any reserved range;
+ * in that case the userspace must provide an IOVA window characterized by
+ * @size and @alignment using VFIO_IOMMU_MAP_DMA with RESERVED_MSI_IOVA flag.
+ */
+struct vfio_iommu_type1_info_cap_msi_geometry {
+ struct vfio_info_cap_header header;
+ __u32 flags;
+#define VFIO_IOMMU_MSI_GEOMETRY_RESERVED (1 << 0) /* reserved geometry */
+ /* not reserved */
+ __u32 order; /* iommu page order used for aperture alignment*/
+ __u64 size; /* IOVA aperture size (bytes) the userspace must provide */
+ /* reserved */
+ __u64 aperture_start;
+ __u64 aperture_end;
};
#define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12)
@@ -503,6 +531,8 @@ struct vfio_iommu_type1_info {
* IOVA region that will be used on some platforms to map the host MSI frames.
* In that specific case, vaddr is ignored. Once registered, an MSI reserved
* IOVA region stays until the container is closed.
+ * The requirement for provisioning such reserved IOVA range can be checked by
+ * checking the VFIO_IOMMU_TYPE1_INFO_CAP_MSI_GEOMETRY capability.
*/
struct vfio_iommu_type1_dma_map {
__u32 argsz;
--
1.9.1
^ permalink raw reply related
* [PATCH v13 14/15] iommu/arm-smmu: Do not advertise IOMMU_CAP_INTR_REMAP
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
Do not advertise IOMMU_CAP_INTR_REMAP for arm-smmu(-v3). Indeed the
irq_remapping capability is abstracted on irqchip side for ARM as
opposed to Intel IOMMU featuring IRQ remapping HW.
So to check IRQ remapping capability, the msi domain needs to be
checked instead.
This commit affects platform and PCIe device assignment use cases
on any platform featuring an unsafe MSI controller (currently the
ARM GICv2m). For those platforms the VFIO module must be loaded with
allow_unsafe_interrupts set to 1.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v9 -> v10:
- reword the commit message (allow_unsafe_interrupts)
---
drivers/iommu/arm-smmu-v3.c | 3 ++-
drivers/iommu/arm-smmu.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index f82eec3..c0a34be 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1371,7 +1371,8 @@ static bool arm_smmu_capable(enum iommu_cap cap)
case IOMMU_CAP_CACHE_COHERENCY:
return true;
case IOMMU_CAP_INTR_REMAP:
- return true; /* MSIs are just memory writes */
+ /* interrupt translation handled at MSI controller level */
+ return false;
case IOMMU_CAP_NOEXEC:
return true;
default:
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 97ff1b4..0c0cd9e 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1361,7 +1361,8 @@ static bool arm_smmu_capable(enum iommu_cap cap)
*/
return true;
case IOMMU_CAP_INTR_REMAP:
- return true; /* MSIs are just memory writes */
+ /* interrupt translation handled at MSI controller level */
+ return false;
case IOMMU_CAP_NOEXEC:
return true;
default:
--
1.9.1
^ permalink raw reply related
* [PATCH v13 13/15] vfio/type1: Check doorbell safety
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
On x86 IRQ remapping is abstracted by the IOMMU. On ARM this is abstracted
by the msi controller.
Since we currently have no way to detect whether the MSI controller is
upstream or downstream to the IOMMU we rely on the MSI doorbell information
registered by the interrupt controllers. In case at least one doorbell
does not implement proper isolation, we state the assignment is unsafe
with regard to interrupts. This is a coase assessment but should allow to
wait for a better system description.
At this point ARM sMMU still advertises IOMMU_CAP_INTR_REMAP. This is
removed in next patch.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v9 -> v10:
- coarse safety assessment based on MSI doorbell info
v3 -> v4:
- rename vfio_msi_parent_irq_remapping_capable into vfio_safe_irq_domain
and irq_remapping into safe_irq_domains
v2 -> v3:
- protect vfio_msi_parent_irq_remapping_capable with
CONFIG_GENERIC_MSI_IRQ_DOMAIN
---
drivers/vfio/vfio_iommu_type1.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index c2f8bd9..dc3ee5d 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -37,6 +37,7 @@
#include <linux/vfio.h>
#include <linux/workqueue.h>
#include <linux/dma-iommu.h>
+#include <linux/msi-doorbell.h>
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
@@ -921,8 +922,13 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
INIT_LIST_HEAD(&domain->group_list);
list_add(&group->next, &domain->group_list);
+ /*
+ * to advertise safe interrupts either the IOMMU or the MSI controllers
+ * must support IRQ remapping (aka. interrupt translation)
+ */
if (!allow_unsafe_interrupts &&
- !iommu_capable(bus, IOMMU_CAP_INTR_REMAP)) {
+ (!iommu_capable(bus, IOMMU_CAP_INTR_REMAP) &&
+ !msi_doorbell_safe())) {
pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n",
__func__);
ret = -EPERM;
--
1.9.1
^ permalink raw reply related
* [PATCH v13 12/15] vfio: Allow reserved msi iova registration
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
The user is allowed to register a reserved MSI IOVA range by using the
DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
This region is stored in the vfio_dma rb tree. At that point the iova
range is not mapped to any target address yet. The host kernel will use
those iova when needed, typically when MSIs are allocated.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Bharat Bhushan <Bharat.Bhushan@freescale.com>
---
v12 -> v13:
- use iommu_get_dma_msi_region_cookie
v9 -> v10
- use VFIO_IOVA_RESERVED_MSI enum value
v7 -> v8:
- use iommu_msi_set_aperture function. There is no notion of
unregistration anymore since the reserved msi slot remains
until the container gets closed.
v6 -> v7:
- use iommu_free_reserved_iova_domain
- convey prot attributes downto dma-reserved-iommu iova domain creation
- reserved bindings teardown now performed on iommu domain destruction
- rename VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA into
VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA
- change title
- pass the protection attribute to dma-reserved-iommu API
v3 -> v4:
- use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
- protect vfio_register_reserved_iova_range implementation with
CONFIG_IOMMU_DMA_RESERVED
- handle unregistration by user-space and on vfio_iommu_type1 release
v1 -> v2:
- set returned value according to alloc_reserved_iova_domain result
- free the iova domains in case any error occurs
RFC v1 -> v1:
- takes into account Alex comments, based on
[RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
- use the existing dma map/unmap ioctl interface with a flag to register
a reserved IOVA range. A single reserved iova region is allowed.
---
drivers/vfio/vfio_iommu_type1.c | 77 ++++++++++++++++++++++++++++++++++++++++-
include/uapi/linux/vfio.h | 10 +++++-
2 files changed, 85 insertions(+), 2 deletions(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 5bc5fc9..c2f8bd9 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -442,6 +442,20 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma)
vfio_lock_acct(-unlocked);
}
+static int vfio_set_msi_aperture(struct vfio_iommu *iommu,
+ dma_addr_t iova, size_t size)
+{
+ struct vfio_domain *d;
+ int ret = 0;
+
+ list_for_each_entry(d, &iommu->domain_list, next) {
+ ret = iommu_get_dma_msi_region_cookie(d->domain, iova, size);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
{
vfio_unmap_unpin(iommu, dma);
@@ -691,6 +705,63 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
return ret;
}
+static int vfio_register_msi_range(struct vfio_iommu *iommu,
+ struct vfio_iommu_type1_dma_map *map)
+{
+ dma_addr_t iova = map->iova;
+ size_t size = map->size;
+ int ret = 0;
+ struct vfio_dma *dma;
+ unsigned long order;
+ uint64_t mask;
+
+ /* Verify that none of our __u64 fields overflow */
+ if (map->size != size || map->iova != iova)
+ return -EINVAL;
+
+ order = __ffs(vfio_pgsize_bitmap(iommu));
+ mask = ((uint64_t)1 << order) - 1;
+
+ WARN_ON(mask & PAGE_MASK);
+
+ if (!size || (size | iova) & mask)
+ return -EINVAL;
+
+ /* Don't allow IOVA address wrap */
+ if (iova + size - 1 < iova)
+ return -EINVAL;
+
+ mutex_lock(&iommu->lock);
+
+ if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
+ ret = -EEXIST;
+ goto unlock;
+ }
+
+ dma = kzalloc(sizeof(*dma), GFP_KERNEL);
+ if (!dma) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ dma->iova = iova;
+ dma->size = size;
+ dma->type = VFIO_IOVA_RESERVED_MSI;
+
+ ret = vfio_set_msi_aperture(iommu, iova, size);
+ if (ret)
+ goto free_unlock;
+
+ vfio_link_dma(iommu, dma);
+ goto unlock;
+
+free_unlock:
+ kfree(dma);
+unlock:
+ mutex_unlock(&iommu->lock);
+ return ret;
+}
+
static int vfio_bus_type(struct device *dev, void *data)
{
struct bus_type **bus = data;
@@ -1064,7 +1135,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
} else if (cmd == VFIO_IOMMU_MAP_DMA) {
struct vfio_iommu_type1_dma_map map;
uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
- VFIO_DMA_MAP_FLAG_WRITE;
+ VFIO_DMA_MAP_FLAG_WRITE |
+ VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA;
minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
@@ -1074,6 +1146,9 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
if (map.argsz < minsz || map.flags & ~mask)
return -EINVAL;
+ if (map.flags & VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA)
+ return vfio_register_msi_range(iommu, &map);
+
return vfio_dma_do_map(iommu, &map);
} else if (cmd == VFIO_IOMMU_UNMAP_DMA) {
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 255a211..4a9dbc2 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -498,12 +498,19 @@ struct vfio_iommu_type1_info {
*
* Map process virtual addresses to IO virtual addresses using the
* provided struct vfio_dma_map. Caller sets argsz. READ &/ WRITE required.
+ *
+ * In case RESERVED_MSI_IOVA flag is set, the API only aims@registering an
+ * IOVA region that will be used on some platforms to map the host MSI frames.
+ * In that specific case, vaddr is ignored. Once registered, an MSI reserved
+ * IOVA region stays until the container is closed.
*/
struct vfio_iommu_type1_dma_map {
__u32 argsz;
__u32 flags;
#define VFIO_DMA_MAP_FLAG_READ (1 << 0) /* readable from device */
#define VFIO_DMA_MAP_FLAG_WRITE (1 << 1) /* writable from device */
+/* reserved iova for MSI vectors*/
+#define VFIO_DMA_MAP_FLAG_RESERVED_MSI_IOVA (1 << 2)
__u64 vaddr; /* Process virtual address */
__u64 iova; /* IO virtual address */
__u64 size; /* Size of mapping (bytes) */
@@ -519,7 +526,8 @@ struct vfio_iommu_type1_dma_map {
* Caller sets argsz. The actual unmapped size is returned in the size
* field. No guarantee is made to the user that arbitrary unmaps of iova
* or size different from those used in the original mapping call will
- * succeed.
+ * succeed. Once registered, an MSI region cannot be unmapped and stays
+ * until the container is closed.
*/
struct vfio_iommu_type1_dma_unmap {
__u32 argsz;
--
1.9.1
^ permalink raw reply related
* [PATCH v13 11/15] vfio/type1: Handle unmap/unpin and replay for VFIO_IOVA_RESERVED slots
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
Before allowing the end-user to create VFIO_IOVA_RESERVED dma slots,
let's implement the expected behavior for removal and replay.
As opposed to user dma slots, reserved IOVAs are not systematically bound
to PAs and PAs are not pinned. VFIO just initializes the IOVA "aperture".
IOVAs are allocated outside of the VFIO framework, by the MSI layer which
is responsible to free and unmap them. The MSI mapping resources are freeed
by the IOMMU driver on domain destruction.
On the creation of a new domain, the "replay" of a reserved slot simply
needs to set the MSI aperture on the new domain.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v12 -> v13:
- use dma-iommu iommu_get_dma_msi_region_cookie
v9 -> v10:
- replay of a reserved slot sets the MSI aperture on the new domain
- use VFIO_IOVA_RESERVED_MSI enum value instead of VFIO_IOVA_RESERVED
v7 -> v8:
- do no destroy anything anymore, just bypass unmap/unpin and iommu_map
on replay
---
drivers/vfio/Kconfig | 1 +
drivers/vfio/vfio_iommu_type1.c | 10 +++++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index da6e2ce..673ec79 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -1,6 +1,7 @@
config VFIO_IOMMU_TYPE1
tristate
depends on VFIO
+ select IOMMU_DMA
default n
config VFIO_IOMMU_SPAPR_TCE
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 65a4038..5bc5fc9 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -36,6 +36,7 @@
#include <linux/uaccess.h>
#include <linux/vfio.h>
#include <linux/workqueue.h>
+#include <linux/dma-iommu.h>
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
@@ -387,7 +388,7 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma)
struct vfio_domain *domain, *d;
long unlocked = 0;
- if (!dma->size)
+ if (!dma->size || dma->type != VFIO_IOVA_USER)
return;
/*
* We use the IOMMU to track the physical addresses, otherwise we'd
@@ -724,6 +725,13 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
dma = rb_entry(n, struct vfio_dma, node);
iova = dma->iova;
+ if (dma->type == VFIO_IOVA_RESERVED_MSI) {
+ ret = iommu_get_dma_msi_region_cookie(domain->domain,
+ dma->iova, dma->size);
+ WARN_ON(ret);
+ continue;
+ }
+
while (iova < dma->iova + dma->size) {
phys_addr_t phys = iommu_iova_to_phys(d->domain, iova);
size_t size;
--
1.9.1
^ permalink raw reply related
* [PATCH v13 10/15] vfio/type1: Implement recursive vfio_find_dma_from_node
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
This patch handles the case where a node is encountered, matching
@start and @size arguments but not matching the @type argument.
In that case, we need to skip that node and pursue the search in the
node's leaves. In case @start is inferior to the node's base, we
resume the search on the left leaf. If the recursive search on the left
leaves did not produce any match, we search the right leaves recursively.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v10: creation
---
drivers/vfio/vfio_iommu_type1.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index cb7267a..65a4038 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -125,7 +125,17 @@ static struct vfio_dma *vfio_find_dma_from_node(struct rb_node *top,
if (type == VFIO_IOVA_ANY || dma->type == type)
return dma;
- return NULL;
+ /* restart 2 searches skipping the current node */
+ if (start < dma->iova) {
+ dma = vfio_find_dma_from_node(node->rb_left, start,
+ size, type);
+ if (dma)
+ return dma;
+ }
+ if (start + size > dma->iova + dma->size)
+ dma = vfio_find_dma_from_node(node->rb_right, start,
+ size, type);
+ return dma;
}
/**
--
1.9.1
^ permalink raw reply related
* [PATCH v13 09/15] vfio/type1: vfio_find_dma accepting a type argument
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
In our RB-tree we get prepared to insert slots of different types
(USER and RESERVED). It becomes useful to be able to search for dma
slots of a specific type or any type.
This patch introduces vfio_find_dma_from_node which starts the
search from a given node and stops on the first node that matches
the @start and @size parameters. If this node also matches the
@type parameter, the node is returned else NULL is returned.
At the moment we only have USER SLOTS so the type will always match.
In a separate patch, this function will be enhanced to pursue the
search recursively in case a node with a different type is
encountered.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
drivers/vfio/vfio_iommu_type1.c | 53 +++++++++++++++++++++++++++++++++--------
1 file changed, 43 insertions(+), 10 deletions(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index a9f8b93..cb7267a 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -94,25 +94,56 @@ struct vfio_group {
* into DMA'ble space using the IOMMU
*/
-static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
- dma_addr_t start, size_t size)
+/**
+ * vfio_find_dma_from_node: looks for a dma slot intersecting a window
+ * from a given rb tree node
+ * @top: top rb tree node where the search starts (including this node)
+ * @start: window start
+ * @size: window size
+ * @type: window type
+ */
+static struct vfio_dma *vfio_find_dma_from_node(struct rb_node *top,
+ dma_addr_t start, size_t size,
+ enum vfio_iova_type type)
{
- struct rb_node *node = iommu->dma_list.rb_node;
+ struct rb_node *node = top;
+ struct vfio_dma *dma;
while (node) {
- struct vfio_dma *dma = rb_entry(node, struct vfio_dma, node);
-
+ dma = rb_entry(node, struct vfio_dma, node);
if (start + size <= dma->iova)
node = node->rb_left;
else if (start >= dma->iova + dma->size)
node = node->rb_right;
else
- return dma;
+ break;
}
+ if (!node)
+ return NULL;
+
+ /* a dma slot intersects our window, check the type also matches */
+ if (type == VFIO_IOVA_ANY || dma->type == type)
+ return dma;
return NULL;
}
+/**
+ * vfio_find_dma: find a dma slot intersecting a given window
+ * @iommu: vfio iommu handle
+ * @start: window base iova
+ * @size: window size
+ * @type: window type
+ */
+static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
+ dma_addr_t start, size_t size,
+ enum vfio_iova_type type)
+{
+ struct rb_node *top_node = iommu->dma_list.rb_node;
+
+ return vfio_find_dma_from_node(top_node, start, size, type);
+}
+
static void vfio_link_dma(struct vfio_iommu *iommu, struct vfio_dma *new)
{
struct rb_node **link = &iommu->dma_list.rb_node, *parent = NULL;
@@ -484,19 +515,21 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
* mappings within the range.
*/
if (iommu->v2) {
- dma = vfio_find_dma(iommu, unmap->iova, 0);
+ dma = vfio_find_dma(iommu, unmap->iova, 0, VFIO_IOVA_USER);
if (dma && dma->iova != unmap->iova) {
ret = -EINVAL;
goto unlock;
}
- dma = vfio_find_dma(iommu, unmap->iova + unmap->size - 1, 0);
+ dma = vfio_find_dma(iommu, unmap->iova + unmap->size - 1, 0,
+ VFIO_IOVA_USER);
if (dma && dma->iova + dma->size != unmap->iova + unmap->size) {
ret = -EINVAL;
goto unlock;
}
}
- while ((dma = vfio_find_dma(iommu, unmap->iova, unmap->size))) {
+ while ((dma = vfio_find_dma(iommu, unmap->iova, unmap->size,
+ VFIO_IOVA_USER))) {
if (!iommu->v2 && unmap->iova > dma->iova)
break;
unmapped += dma->size;
@@ -600,7 +633,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
mutex_lock(&iommu->lock);
- if (vfio_find_dma(iommu, iova, size)) {
+ if (vfio_find_dma(iommu, iova, size, VFIO_IOVA_ANY)) {
mutex_unlock(&iommu->lock);
return -EEXIST;
}
--
1.9.1
^ permalink raw reply related
* [PATCH v13 08/15] vfio: Introduce a vfio_dma type field
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
We introduce a vfio_dma type since we will need to discriminate
different types of dma slots:
- VFIO_IOVA_USER: IOVA region used to map user vaddr
- VFIO_IOVA_RESERVED_MSI: IOVA region reserved to map MSI doorbells
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v9 -> v10:
- renamed VFIO_IOVA_RESERVED into VFIO_IOVA_RESERVED_MSI
- explicitly set type to VFIO_IOVA_USER on dma_map
v6 -> v7:
- add VFIO_IOVA_ANY
- do not introduce yet any VFIO_IOVA_RESERVED handling
---
drivers/vfio/vfio_iommu_type1.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 2ba1942..a9f8b93 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -53,6 +53,12 @@ module_param_named(disable_hugepages,
MODULE_PARM_DESC(disable_hugepages,
"Disable VFIO IOMMU support for IOMMU hugepages.");
+enum vfio_iova_type {
+ VFIO_IOVA_USER = 0, /* standard IOVA used to map user vaddr */
+ VFIO_IOVA_RESERVED_MSI, /* reserved to map MSI doorbells */
+ VFIO_IOVA_ANY, /* matches any IOVA type */
+};
+
struct vfio_iommu {
struct list_head domain_list;
struct mutex lock;
@@ -75,6 +81,7 @@ struct vfio_dma {
unsigned long vaddr; /* Process virtual addr */
size_t size; /* Map size (bytes) */
int prot; /* IOMMU_READ/WRITE */
+ enum vfio_iova_type type; /* type of IOVA */
};
struct vfio_group {
@@ -607,6 +614,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
dma->iova = iova;
dma->vaddr = vaddr;
dma->prot = prot;
+ dma->type = VFIO_IOVA_USER;
/* Insert zero-sized and grow as we map chunks of it */
vfio_link_dma(iommu, dma);
--
1.9.1
^ permalink raw reply related
* [PATCH v13 07/15] irqchip/gicv3-its: Register the MSI doorbell
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
This patch registers the ITS global doorbell. Registered information
are needed to set up the KVM passthrough use case.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v12 -> v13:
- use new doorbell registration prototype
v11 -> v12:
- use new irq_get_msi_doorbell_info name
- simplify error handling
v10 -> v11:
- adapt to new doorbell registration API and implement msi_doorbell_info
---
drivers/irqchip/irq-gic-v3-its.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 98ff669..3fc715e 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -30,6 +30,7 @@
#include <linux/of_platform.h>
#include <linux/percpu.h>
#include <linux/slab.h>
+#include <linux/msi-doorbell.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic-v3.h>
@@ -86,6 +87,7 @@ struct its_node {
u32 ite_size;
u32 device_ids;
int numa_node;
+ struct msi_doorbell_info *doorbell_info;
};
#define ITS_ITT_ALIGN SZ_256
@@ -1717,6 +1719,7 @@ static int __init its_probe(struct device_node *node,
if (of_property_read_bool(node, "msi-controller")) {
struct msi_domain_info *info;
+ phys_addr_t translater;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
@@ -1724,10 +1727,21 @@ static int __init its_probe(struct device_node *node,
goto out_free_tables;
}
+ translater = its->phys_base + GITS_TRANSLATER;
+ err = msi_doorbell_register_global(translater, sizeof(u32),
+ true, &its->doorbell_info);
+
+ if (err) {
+ kfree(info);
+ goto out_free_tables;
+ }
+
+
inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
if (!inner_domain) {
err = -ENOMEM;
kfree(info);
+ msi_doorbell_unregister_global(its->doorbell_info);
goto out_free_tables;
}
--
1.9.1
^ permalink raw reply related
* [PATCH v13 06/15] irqchip/gic-v2m: Register the MSI doorbell
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
Register the GIC V2M global doorbell. The registered information
are used to set up the KVM passthrough use case.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v12 -> v13:
- use new msi doorbell registration prototype
- remove iommu protection attributes
- add unregistration in teardown
v11 -> v12:
- use irq_get_msi_doorbell_info new name
- simplify error handling
v10 -> v11:
- use the new registration API and re-implement the msi_doorbell_info
ops
v9 -> v10:
- introduce the registration concept in place of msi_doorbell_info
callback
v8 -> v9:
- use global_doorbell instead of percpu_doorbells
v7 -> v8:
- gicv2m_msi_doorbell_info does not return a pointer to const
- remove spurious !v2m check
- add IOMMU_MMIO flag
v7: creation
---
drivers/irqchip/irq-gic-v2m.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index 863e073..343f19f 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/irqchip/arm-gic.h>
+#include <linux/msi-doorbell.h>
/*
* MSI_TYPER:
@@ -70,6 +71,7 @@ struct v2m_data {
u32 spi_offset; /* offset to be subtracted from SPI number */
unsigned long *bm; /* MSI vector bitmap */
u32 flags; /* v2m flags for specific implementation */
+ struct msi_doorbell_info *doorbell_info; /* MSI doorbell */
};
static void gicv2m_mask_msi_irq(struct irq_data *d)
@@ -254,6 +256,7 @@ static void gicv2m_teardown(void)
struct v2m_data *v2m, *tmp;
list_for_each_entry_safe(v2m, tmp, &v2m_nodes, entry) {
+ msi_doorbell_unregister_global(v2m->doorbell_info);
list_del(&v2m->entry);
kfree(v2m->bm);
iounmap(v2m->base);
@@ -370,12 +373,18 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
goto err_iounmap;
}
+ ret = msi_doorbell_register_global(v2m->res.start, sizeof(u32),
+ false, &v2m->doorbell_info);
+ if (ret)
+ goto err_free_bm;
+
list_add_tail(&v2m->entry, &v2m_nodes);
pr_info("range%pR, SPI[%d:%d]\n", res,
v2m->spi_start, (v2m->spi_start + v2m->nr_spis - 1));
return 0;
-
+err_free_bm:
+ kfree(v2m->bm);
err_iounmap:
iounmap(v2m->base);
err_free_v2m:
--
1.9.1
^ permalink raw reply related
* [PATCH v13 05/15] genirq/msi: msi_doorbell_calc_pages
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
msi_doorbell_calc_pages() sum up the number of iommu pages of a given order
requested to map all the registered doorbells. This function will allow
to dimension the intermediate physical address (IPA) aperture requested
to map the MSI doorbells.
Note this requirement cannot be computed at MSI doorbell registration time
since the IOMMU page order is not known.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v11 -> v12:
- fix style issues: remove useless line break, remove pointless braces,
fix kernel-doc comments
- reword commit message
- rename msi_doorbell_pages into msi_doorbell_calc_pages
- rename static compute* functions
v10: creation
---
include/linux/msi-doorbell.h | 15 +++++++++++
kernel/irq/msi-doorbell.c | 64 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 79 insertions(+)
diff --git a/include/linux/msi-doorbell.h b/include/linux/msi-doorbell.h
index c18a382..f1106cb 100644
--- a/include/linux/msi-doorbell.h
+++ b/include/linux/msi-doorbell.h
@@ -54,6 +54,15 @@ void msi_doorbell_unregister_global(struct msi_doorbell_info *db);
*/
bool msi_doorbell_safe(void);
+/**
+ * msi_doorbell_calc_pages - compute the number of pages
+ * requested to map all the registered doorbells
+ * @order: iommu page order
+ *
+ * Return: the number of requested pages
+ */
+int msi_doorbell_calc_pages(unsigned int order);
+
#else
static inline int
@@ -72,6 +81,12 @@ static inline bool msi_doorbell_safe(void)
{
return true;
}
+
+static inline int msi_doorbell_calc_pages(unsigned int order)
+{
+ return 0;
+}
+
#endif /* CONFIG_MSI_DOORBELL */
#endif
diff --git a/kernel/irq/msi-doorbell.c b/kernel/irq/msi-doorbell.c
index 60a262a..d1cc525 100644
--- a/kernel/irq/msi-doorbell.c
+++ b/kernel/irq/msi-doorbell.c
@@ -96,3 +96,67 @@ bool msi_doorbell_safe(void)
return !nb_unsafe_doorbells;
}
EXPORT_SYMBOL_GPL(msi_doorbell_safe);
+
+/**
+ * calc_region_reqs - compute the number of pages requested to map a region
+ *
+ * @addr: physical base address of the region
+ * @size: size of the region
+ * @order: the page order
+ *
+ * Return: the number of requested pages to map this region
+ */
+static int calc_region_reqs(phys_addr_t addr, size_t size, unsigned int order)
+{
+ phys_addr_t offset, granule;
+ unsigned int nb_pages;
+
+ granule = (uint64_t)(1 << order);
+ offset = addr & (granule - 1);
+ size = ALIGN(size + offset, granule);
+ nb_pages = size >> order;
+
+ return nb_pages;
+}
+
+/**
+ * calc_dbinfo_reqs - compute the number of pages requested to map a given
+ * MSI doorbell
+ *
+ * @dbi: doorbell info descriptor
+ * @order: page order
+ *
+ * Return: the number of requested pages to map this doorbell
+ */
+static int calc_dbinfo_reqs(struct msi_doorbell_info *dbi, unsigned int order)
+{
+ int ret = 0;
+
+ if (!dbi->doorbell_is_percpu) {
+ ret = calc_region_reqs(dbi->global_doorbell, dbi->size, order);
+ } else {
+ phys_addr_t __percpu *pbase;
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ pbase = per_cpu_ptr(dbi->percpu_doorbells, cpu);
+ ret += calc_region_reqs(*pbase, dbi->size, order);
+ }
+ }
+ return ret;
+}
+
+int msi_doorbell_calc_pages(unsigned int order)
+{
+ struct msi_doorbell *db;
+ int ret = 0;
+
+ mutex_lock(&msi_doorbell_mutex);
+ list_for_each_entry(db, &msi_doorbell_list, next)
+ ret += calc_dbinfo_reqs(&db->info, order);
+
+ mutex_unlock(&msi_doorbell_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(msi_doorbell_calc_pages);
--
1.9.1
^ permalink raw reply related
* [PATCH v13 04/15] genirq/msi: Introduce the MSI doorbell API
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
We introduce a new msi-doorbell API that allows msi controllers
to allocate and register their doorbells. This is useful when
those doorbells are likely to be iommu mapped (typically on ARM).
The VFIO layer will need to gather information about those doorbells:
whether they are safe (ie. they implement irq remapping) and how
many IOMMU pages are requested to map all of them.
This patch first introduces the dedicated msi_doorbell_info struct
and the registration/unregistration functions.
A doorbell region is characterized by its physical address base, size,
and whether it its safe (ie. it implements IRQ remapping). A doorbell
can be per-cpu of global. We currently only care about global doorbells.
A function returns whether all doorbells are safe.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v12 -> v13:
- directly select MSI_DOORBELL in ARM_SMMU and ARM_SMMU_V3 configs
- remove prot attribute
- move msi_doorbell_info struct definition in msi-doorbell.c
- change the commit title
- change proto of the registration function
- msi_doorbell_safe now in this patch
v11 -> v12:
- rename irqchip_doorbell into msi_doorbell, irqchip_doorbell_list
into msi_doorbell_list and irqchip_doorbell_mutex into
msi_doorbell_mutex
- fix style issues: align msi_doorbell struct members, kernel-doc comments
- use kzalloc
- use container_of in msi_doorbell_unregister_global
- compute nb_unsafe_doorbells on registration/unregistration
- registration simply returns NULL if allocation failed
v10 -> v11:
- remove void *chip_data argument from register/unregister function
- remove lookup funtions since we restored the struct irq_chip
msi_doorbell_info ops to realize this function
- reword commit message and title
Conflicts:
kernel/irq/Makefile
Conflicts:
drivers/iommu/Kconfig
---
drivers/iommu/Kconfig | 2 +
include/linux/msi-doorbell.h | 77 ++++++++++++++++++++++++++++++++++
kernel/irq/Kconfig | 4 ++
kernel/irq/Makefile | 1 +
kernel/irq/msi-doorbell.c | 98 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 182 insertions(+)
create mode 100644 include/linux/msi-doorbell.h
create mode 100644 kernel/irq/msi-doorbell.c
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 8ee54d7..0cc7fac 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -297,6 +297,7 @@ config SPAPR_TCE_IOMMU
config ARM_SMMU
bool "ARM Ltd. System MMU (SMMU) Support"
depends on (ARM64 || ARM) && MMU
+ select MSI_DOORBELL
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select ARM_DMA_USE_IOMMU if ARM
@@ -310,6 +311,7 @@ config ARM_SMMU
config ARM_SMMU_V3
bool "ARM Ltd. System MMU Version 3 (SMMUv3) Support"
depends on ARM64
+ select MSI_DOORBELL
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select GENERIC_MSI_IRQ_DOMAIN
diff --git a/include/linux/msi-doorbell.h b/include/linux/msi-doorbell.h
new file mode 100644
index 0000000..c18a382
--- /dev/null
+++ b/include/linux/msi-doorbell.h
@@ -0,0 +1,77 @@
+/*
+ * API to register/query MSI doorbells likely to be IOMMU mapped
+ *
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LINUX_MSI_DOORBELL_H
+#define _LINUX_MSI_DOORBELL_H
+
+struct msi_doorbell_info;
+
+#ifdef CONFIG_MSI_DOORBELL
+
+/**
+ * msi_doorbell_register - allocate and register a global doorbell
+ * @base: physical base address of the global doorbell
+ * @size: size of the global doorbell
+ * @prot: protection/memory attributes
+ * @safe: true is irq_remapping implemented for this doorbell
+ * @dbinfo: returned doorbell info
+ *
+ * Return: 0 on success, -ENOMEM on allocation failure
+ */
+int msi_doorbell_register_global(phys_addr_t base, size_t size,
+ bool safe,
+ struct msi_doorbell_info **dbinfo);
+
+/**
+ * msi_doorbell_unregister_global - unregister a global doorbell
+ * @db: doorbell info to unregister
+ *
+ * remove the doorbell descriptor from the list of registered doorbells
+ * and deallocates it
+ */
+void msi_doorbell_unregister_global(struct msi_doorbell_info *db);
+
+/**
+ * msi_doorbell_safe - return whether all registered doorbells are safe
+ *
+ * Safe doorbells are those which implement irq remapping
+ * Return: true if all doorbells are safe, false otherwise
+ */
+bool msi_doorbell_safe(void);
+
+#else
+
+static inline int
+msi_doorbell_register_global(phys_addr_t base, size_t size,
+ int prot, bool safe,
+ struct msi_doorbell_info **dbinfo)
+{
+ *dbinfo = NULL;
+ return 0;
+}
+
+static inline void
+msi_doorbell_unregister_global(struct msi_doorbell_info *db) {}
+
+static inline bool msi_doorbell_safe(void)
+{
+ return true;
+}
+#endif /* CONFIG_MSI_DOORBELL */
+
+#endif
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index 3bbfd6a..d4faaaa 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -72,6 +72,10 @@ config GENERIC_IRQ_IPI
config GENERIC_MSI_IRQ
bool
+# MSI doorbell support (for doorbell IOMMU mapping)
+config MSI_DOORBELL
+ bool
+
# Generic MSI hierarchical interrupt domain support
config GENERIC_MSI_IRQ_DOMAIN
bool
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
index 1d3ee31..5b04dd1 100644
--- a/kernel/irq/Makefile
+++ b/kernel/irq/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_PM_SLEEP) += pm.o
obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o
obj-$(CONFIG_SMP) += affinity.o
+obj-$(CONFIG_MSI_DOORBELL) += msi-doorbell.o
diff --git a/kernel/irq/msi-doorbell.c b/kernel/irq/msi-doorbell.c
new file mode 100644
index 0000000..60a262a
--- /dev/null
+++ b/kernel/irq/msi-doorbell.c
@@ -0,0 +1,98 @@
+/*
+ * API to register/query MSI doorbells likely to be IOMMU mapped
+ *
+ * Copyright (C) 2016 Red Hat, Inc.
+ * Author: Eric Auger <eric.auger@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/msi-doorbell.h>
+
+/**
+ * struct msi_doorbell_info - MSI doorbell region descriptor
+ * @percpu_doorbells: per cpu doorbell base address
+ * @global_doorbell: base address of the doorbell
+ * @doorbell_is_percpu: is the doorbell per cpu or global?
+ * @safe: true if irq remapping is implemented
+ * @size: size of the doorbell
+ */
+struct msi_doorbell_info {
+ union {
+ phys_addr_t __percpu *percpu_doorbells;
+ phys_addr_t global_doorbell;
+ };
+ bool doorbell_is_percpu;
+ bool safe;
+ size_t size;
+};
+
+struct msi_doorbell {
+ struct msi_doorbell_info info;
+ struct list_head next;
+};
+
+/* list of registered MSI doorbells */
+static LIST_HEAD(msi_doorbell_list);
+
+/* counts the number of unsafe registered doorbells */
+static uint nb_unsafe_doorbells;
+
+/* protects the list and nb__unsafe_doorbells */
+static DEFINE_MUTEX(msi_doorbell_mutex);
+
+int msi_doorbell_register_global(phys_addr_t base, size_t size, bool safe,
+ struct msi_doorbell_info **dbinfo)
+{
+ struct msi_doorbell *db;
+
+ db = kzalloc(sizeof(*db), GFP_KERNEL);
+ if (!db)
+ return -ENOMEM;
+
+ db->info.global_doorbell = base;
+ db->info.size = size;
+ db->info.safe = safe;
+
+ mutex_lock(&msi_doorbell_mutex);
+ list_add(&db->next, &msi_doorbell_list);
+ if (!db->info.safe)
+ nb_unsafe_doorbells++;
+ mutex_unlock(&msi_doorbell_mutex);
+ *dbinfo = &db->info;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(msi_doorbell_register_global);
+
+void msi_doorbell_unregister_global(struct msi_doorbell_info *dbinfo)
+{
+ struct msi_doorbell *db;
+
+ db = container_of(dbinfo, struct msi_doorbell, info);
+
+ mutex_lock(&msi_doorbell_mutex);
+ list_del(&db->next);
+ if (!db->info.safe)
+ nb_unsafe_doorbells--;
+ mutex_unlock(&msi_doorbell_mutex);
+ kfree(db);
+}
+EXPORT_SYMBOL_GPL(msi_doorbell_unregister_global);
+
+bool msi_doorbell_safe(void)
+{
+ return !nb_unsafe_doorbells;
+}
+EXPORT_SYMBOL_GPL(msi_doorbell_safe);
--
1.9.1
^ permalink raw reply related
* [PATCH v13 03/15] iommu/dma: Allow MSI-only cookies
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
From: Robin Murphy <robin.murphy@arm.com>
IOMMU domain users such as VFIO face a similar problem to DMA API ops
with regard to mapping MSI messages in systems where the MSI write is
subject to IOMMU translation. With the relevant infrastructure now in
place for managed DMA domains, it's actually really simple for other
users to piggyback off that and reap the benefits without giving up
their own IOVA management, and without having to reinvent their own
wheel in the MSI layer.
Allow such users to opt into automatic MSI remapping by dedicating a
region of their IOVA space to a managed cookie.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v1 -> v2:
- compared to Robin's version
- add NULL last param to iommu_dma_init_domain
- set the msi_geometry aperture
- I removed
if (base < U64_MAX - size)
reserve_iova(iovad, iova_pfn(iovad, base + size), ULONG_MAX);
don't get why we would reserve something out of the scope of the iova domain?
what do I miss?
---
drivers/iommu/dma-iommu.c | 40 ++++++++++++++++++++++++++++++++++++++++
include/linux/dma-iommu.h | 9 +++++++++
2 files changed, 49 insertions(+)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index c5ab866..11da1a0 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -716,3 +716,43 @@ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
msg->address_lo += lower_32_bits(msi_page->iova);
}
}
+
+/**
+ * iommu_get_dma_msi_region_cookie - Configure a domain for MSI remapping only
+ * @domain: IOMMU domain to prepare
+ * @base: Base address of IOVA region to use as the MSI remapping aperture
+ * @size: Size of the desired MSI aperture
+ *
+ * Users who manage their own IOVA allocation and do not want DMA API support,
+ * but would still like to take advantage of automatic MSI remapping, can use
+ * this to initialise their own domain appropriately.
+ */
+int iommu_get_dma_msi_region_cookie(struct iommu_domain *domain,
+ dma_addr_t base, u64 size)
+{
+ struct iommu_dma_cookie *cookie;
+ struct iova_domain *iovad;
+ int ret;
+
+ if (domain->type == IOMMU_DOMAIN_DMA)
+ return -EINVAL;
+
+ ret = iommu_get_dma_cookie(domain);
+ if (ret)
+ return ret;
+
+ ret = iommu_dma_init_domain(domain, base, size, NULL);
+ if (ret) {
+ iommu_put_dma_cookie(domain);
+ return ret;
+ }
+
+ domain->msi_geometry.aperture_start = base;
+ domain->msi_geometry.aperture_end = base + size - 1;
+
+ cookie = domain->iova_cookie;
+ iovad = &cookie->iovad;
+
+ return 0;
+}
+EXPORT_SYMBOL(iommu_get_dma_msi_region_cookie);
diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h
index 32c5890..1c55413 100644
--- a/include/linux/dma-iommu.h
+++ b/include/linux/dma-iommu.h
@@ -67,6 +67,9 @@ int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
/* The DMA API isn't _quite_ the whole story, though... */
void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg);
+int iommu_get_dma_msi_region_cookie(struct iommu_domain *domain,
+ dma_addr_t base, u64 size);
+
#else
struct iommu_domain;
@@ -90,6 +93,12 @@ static inline void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
{
}
+static inline int iommu_get_dma_msi_region_cookie(struct iommu_domain *domain,
+ dma_addr_t base, u64 size)
+{
+ return -ENODEV;
+}
+
#endif /* CONFIG_IOMMU_DMA */
#endif /* __KERNEL__ */
#endif /* __DMA_IOMMU_H */
--
1.9.1
^ permalink raw reply related
* [PATCH v13 02/15] iommu/arm-smmu: Initialize the msi geometry
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
On ARM, MSI write transactions also are translated by the smmu.
Let's report that specificity by setting the iommu_msi_supported
field to true. A valid aperture window will need to be provided.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
v12 -> v13:
- reword the commit message
v8 -> v9:
- reword the title and patch description
v7 -> v8:
- use DOMAIN_ATTR_MSI_GEOMETRY
v4 -> v5:
- don't handle fsl_pamu_domain anymore
- handle arm-smmu-v3
---
drivers/iommu/arm-smmu-v3.c | 2 ++
drivers/iommu/arm-smmu.c | 3 +++
2 files changed, 5 insertions(+)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 15c01c3..f82eec3 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1382,6 +1382,7 @@ static bool arm_smmu_capable(enum iommu_cap cap)
static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
{
struct arm_smmu_domain *smmu_domain;
+ struct iommu_domain_msi_geometry msi_geometry = {0, 0, true};
if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
return NULL;
@@ -1400,6 +1401,7 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
kfree(smmu_domain);
return NULL;
}
+ smmu_domain->domain.msi_geometry = msi_geometry;
mutex_init(&smmu_domain->init_mutex);
spin_lock_init(&smmu_domain->pgtbl_lock);
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index ac4aab9..97ff1b4 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1002,6 +1002,7 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
{
struct arm_smmu_domain *smmu_domain;
+ struct iommu_domain_msi_geometry msi_geometry = {0, 0, true};
if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
return NULL;
@@ -1020,6 +1021,8 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
return NULL;
}
+ smmu_domain->domain.msi_geometry = msi_geometry;
+
mutex_init(&smmu_domain->init_mutex);
spin_lock_init(&smmu_domain->pgtbl_lock);
--
1.9.1
^ permalink raw reply related
* [PATCH v13 01/15] iommu: Introduce DOMAIN_ATTR_MSI_GEOMETRY
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475743531-4780-1-git-send-email-eric.auger@redhat.com>
Introduce a new DOMAIN_ATTR_MSI_GEOMETRY domain attribute. It enables
to query the aperture of the IOVA window dedicated to MSIs and
test whether the MSIs must be IOMMU mapped.
x86 IOMMUs will typically expose an MSI aperture matching the 1MB
region [FEE0_0000h - FEF0_000h] corresponding to the the APIC
configuration space and no support for MSI IOMMU mapping.
On ARM, the requirement to map MSIs will be reported by setting
iommu_msi_supported to true.
A helper function is added to allow testing if the aperture is valid.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Suggested-by: Alex Williamson <alex.williamson@redhat.com>
---
v12 -> v13:
- reword the commit message
v8 -> v9:
- rename programmable into iommu_msi_supported
- add iommu_domain_msi_aperture_valid
v8: creation
- deprecates DOMAIN_ATTR_MSI_MAPPING flag
---
drivers/iommu/iommu.c | 5 +++++
include/linux/iommu.h | 14 ++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 9a2f196..617cb2b 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1485,6 +1485,7 @@ int iommu_domain_get_attr(struct iommu_domain *domain,
enum iommu_attr attr, void *data)
{
struct iommu_domain_geometry *geometry;
+ struct iommu_domain_msi_geometry *msi_geometry;
bool *paging;
int ret = 0;
u32 *count;
@@ -1495,6 +1496,10 @@ int iommu_domain_get_attr(struct iommu_domain *domain,
*geometry = domain->geometry;
break;
+ case DOMAIN_ATTR_MSI_GEOMETRY:
+ msi_geometry = data;
+ *msi_geometry = domain->msi_geometry;
+ break;
case DOMAIN_ATTR_PAGING:
paging = data;
*paging = (domain->pgsize_bitmap != 0UL);
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 436dc21..9f90735 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -52,6 +52,12 @@ struct iommu_domain_geometry {
bool force_aperture; /* DMA only allowed in mappable range? */
};
+struct iommu_domain_msi_geometry {
+ dma_addr_t aperture_start; /* First address used for MSI IOVA */
+ dma_addr_t aperture_end; /* Last address used for MSI IOVA */
+ bool iommu_msi_supported; /* Is MSI mapping supported? */
+};
+
/* Domain feature flags */
#define __IOMMU_DOMAIN_PAGING (1U << 0) /* Support for iommu_map/unmap */
#define __IOMMU_DOMAIN_DMA_API (1U << 1) /* Domain for use in DMA-API
@@ -83,6 +89,7 @@ struct iommu_domain {
iommu_fault_handler_t handler;
void *handler_token;
struct iommu_domain_geometry geometry;
+ struct iommu_domain_msi_geometry msi_geometry;
void *iova_cookie;
};
@@ -108,6 +115,7 @@ enum iommu_cap {
enum iommu_attr {
DOMAIN_ATTR_GEOMETRY,
+ DOMAIN_ATTR_MSI_GEOMETRY,
DOMAIN_ATTR_PAGING,
DOMAIN_ATTR_WINDOWS,
DOMAIN_ATTR_FSL_PAMU_STASH,
@@ -352,6 +360,12 @@ int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
void iommu_fwspec_free(struct device *dev);
int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
+static inline bool iommu_domain_msi_aperture_valid(struct iommu_domain *domain)
+{
+ return (domain->msi_geometry.aperture_end >
+ domain->msi_geometry.aperture_start);
+}
+
#else /* CONFIG_IOMMU_API */
struct iommu_ops {};
--
1.9.1
^ permalink raw reply related
* [PATCH v13 00/15] KVM PCIe/MSI passthrough on ARM/ARM64
From: Eric Auger @ 2016-10-06 8:45 UTC (permalink / raw)
To: linux-arm-kernel
Following Robin's series [1], addressing MSI IOMMU mapping for devices
attached to a DMA ops domain, quite a lot of changes (and simplifications)
were induced with respect to the v12 iteration:
- msi-iommu API role now is handled at dma-iommu level
- MSI doorbell registration API still is used for security assessment
and doorbell overall iommu page size computation.
- MSI layer part II is not needed anymore since mapping directly is
done in the irqchip compose callback.
The VFIO user API and VFIO layer changes have not changed though. All the
patches now are in the same series.
Tested on AMD Overdrive (single GICv2m frame) with I350 VF assignment.
dependency:
the series depends on Robin's generic-v7 branch:
[1] [PATCH v7 00/22] Generic DT bindings for PCI IOMMUs and ARM SMMU
http://www.spinics.net/lists/arm-kernel/msg531110.html
Best Regards
Eric
Git: complete series available at
https://github.com/eauger/linux/tree/generic-v7-pcie-passthru-v13
the above branch includes a temporary patch to work around a ThunderX pci
bus reset crash (which I think unrelated to this series):
"vfio: pci: HACK! workaround thunderx pci_try_reset_bus crash"
Do not take this one for other platforms.
Eric Auger (14):
iommu: Introduce DOMAIN_ATTR_MSI_GEOMETRY
iommu/arm-smmu: Initialize the msi geometry
genirq/msi: Introduce the MSI doorbell API
genirq/msi: msi_doorbell_calc_pages
irqchip/gic-v2m: Register the MSI doorbell
irqchip/gicv3-its: Register the MSI doorbell
vfio: Introduce a vfio_dma type field
vfio/type1: vfio_find_dma accepting a type argument
vfio/type1: Implement recursive vfio_find_dma_from_node
vfio/type1: Handle unmap/unpin and replay for VFIO_IOVA_RESERVED slots
vfio: Allow reserved msi iova registration
vfio/type1: Check doorbell safety
iommu/arm-smmu: Do not advertise IOMMU_CAP_INTR_REMAP
vfio/type1: Return the MSI geometry through VFIO_IOMMU_GET_INFO
capability chains
Robin Murphy (1):
iommu/dma: Allow MSI-only cookies
drivers/iommu/Kconfig | 2 +
drivers/iommu/arm-smmu-v3.c | 5 +-
drivers/iommu/arm-smmu.c | 6 +-
drivers/iommu/dma-iommu.c | 40 +++++++
drivers/iommu/iommu.c | 5 +
drivers/irqchip/irq-gic-v2m.c | 11 +-
drivers/irqchip/irq-gic-v3-its.c | 14 +++
drivers/vfio/Kconfig | 1 +
drivers/vfio/vfio_iommu_type1.c | 244 ++++++++++++++++++++++++++++++++++++---
include/linux/dma-iommu.h | 9 ++
include/linux/iommu.h | 14 +++
include/linux/msi-doorbell.h | 92 +++++++++++++++
include/uapi/linux/vfio.h | 42 ++++++-
kernel/irq/Kconfig | 4 +
kernel/irq/Makefile | 1 +
kernel/irq/msi-doorbell.c | 162 ++++++++++++++++++++++++++
16 files changed, 633 insertions(+), 19 deletions(-)
create mode 100644 include/linux/msi-doorbell.h
create mode 100644 kernel/irq/msi-doorbell.c
--
1.9.1
^ permalink raw reply
* [PATCH 2/8] PM / Domain: Add residency property to genpd states
From: Ulf Hansson @ 2016-10-06 8:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475699519-109623-3-git-send-email-lina.iyer@linaro.org>
On 5 October 2016 at 22:31, Lina Iyer <lina.iyer@linaro.org> wrote:
> Residency of a domain's idle state indicates that the minimum idle time
> for the domain's idle state to be beneficial for power. Add the
> parameter to the state node. Future patches, will use the residency
> value in the genpd governor to determine if it is worth while to enter
> an idle state.
>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Kind regards
Uffe
> ---
> include/linux/pm_domain.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index bd1ffb9..c113713 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -38,6 +38,7 @@ struct gpd_dev_ops {
> struct genpd_power_state {
> s64 power_off_latency_ns;
> s64 power_on_latency_ns;
> + s64 residency_ns;
> };
>
> struct generic_pm_domain {
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH 1/8] PM / Domains: Make genpd state allocation dynamic
From: Ulf Hansson @ 2016-10-06 8:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475699519-109623-2-git-send-email-lina.iyer@linaro.org>
On 5 October 2016 at 22:31, Lina Iyer <lina.iyer@linaro.org> wrote:
> Allow PM Domain states to be defined dynamically by the drivers. This
> removes the limitation on the maximum number of states possible for a
> domain.
>
> Cc: Axel Haslam <ahaslam+renesas@baylibre.com>
> Suggested-by: Ulf Hansson <ulf.hansson@linaro.org>
> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
> ---
> arch/arm/mach-imx/gpc.c | 17 ++++++++++-------
> drivers/base/power/domain.c | 10 ----------
> include/linux/pm_domain.h | 4 +---
> 3 files changed, 11 insertions(+), 20 deletions(-)
>
> diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
> index 0df062d..b92dad5 100644
> --- a/arch/arm/mach-imx/gpc.c
> +++ b/arch/arm/mach-imx/gpc.c
> @@ -380,13 +380,6 @@ static struct pu_domain imx6q_pu_domain = {
> .name = "PU",
> .power_off = imx6q_pm_pu_power_off,
> .power_on = imx6q_pm_pu_power_on,
> - .states = {
> - [0] = {
> - .power_off_latency_ns = 25000,
> - .power_on_latency_ns = 2000000,
> - },
> - },
> - .state_count = 1,
> },
> };
>
> @@ -430,6 +423,16 @@ static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
> if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
> return 0;
>
> + imx6q_pu_domain.base.states = devm_kzalloc(dev,
> + sizeof(*imx6q_pu_domain.base.states),
> + GFP_KERNEL);
> + if (!imx6q_pu_domain.base.states)
> + return -ENOMEM;
> +
> + imx6q_pu_domain.base.states[0].power_off_latency_ns = 25000;
> + imx6q_pu_domain.base.states[0].power_on_latency_ns = 2000000;
> + mx6q_pu_domain.base.state_count = 1,
> +
> pm_genpd_init(&imx6q_pu_domain.base, NULL, false);
> return of_genpd_add_provider_onecell(dev->of_node,
> &imx_gpc_onecell_data);
> diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
> index e023066..740afa9 100644
> --- a/drivers/base/power/domain.c
> +++ b/drivers/base/power/domain.c
> @@ -1325,16 +1325,6 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
> genpd->dev_ops.start = pm_clk_resume;
> }
>
> - if (genpd->state_idx >= GENPD_MAX_NUM_STATES) {
> - pr_warn("Initial state index out of bounds.\n");
> - genpd->state_idx = GENPD_MAX_NUM_STATES - 1;
> - }
> -
> - if (genpd->state_count > GENPD_MAX_NUM_STATES) {
> - pr_warn("Limiting states to %d\n", GENPD_MAX_NUM_STATES);
> - genpd->state_count = GENPD_MAX_NUM_STATES;
> - }
> -
> /* Use only one "off" state if there were no states declared */
> if (genpd->state_count == 0)
> genpd->state_count = 1;
> diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
> index a09fe5c..bd1ffb9 100644
> --- a/include/linux/pm_domain.h
> +++ b/include/linux/pm_domain.h
> @@ -19,8 +19,6 @@
> /* Defines used for the flags field in the struct generic_pm_domain */
> #define GENPD_FLAG_PM_CLK (1U << 0) /* PM domain uses PM clk */
>
> -#define GENPD_MAX_NUM_STATES 8 /* Number of possible low power states */
> -
> enum gpd_status {
> GPD_STATE_ACTIVE = 0, /* PM domain is active */
> GPD_STATE_POWER_OFF, /* PM domain is off */
> @@ -70,7 +68,7 @@ struct generic_pm_domain {
> void (*detach_dev)(struct generic_pm_domain *domain,
> struct device *dev);
> unsigned int flags; /* Bit field of configs for genpd */
> - struct genpd_power_state states[GENPD_MAX_NUM_STATES];
> + struct genpd_power_state *states;
> unsigned int state_count; /* number of states */
> unsigned int state_idx; /* state that genpd will go to when off */
>
> --
> 2.7.4
>
In general I like the improvement, but..
This change implies that ->states may very well be NULL. This isn't
validated by genpd's internal logic when power off/on the domain
(genpd_power_on|off(), __default_power_down_ok()). You need to fix
this, somehow.
Perhaps the easiest solutions is, when pm_genpd_init() finds that
->state is NULL, that we allocate a struct genpd_power_state with
array size of 1 and assign it to ->states. Although, doing this also
means you need to track that genpd was responsible for the the
allocation, so it must also free the data from within genpd_remove().
Unless you have other ideas!?
Kind regards
Uffe
^ 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