* Re: [PATCH 4/4 v6] iommu/fsl: Freescale PAMU driver and IOMMU API implementation.
From: Tabi Timur-B04825 @ 2012-12-01 22:58 UTC (permalink / raw)
To: Sethi Varun-B16395
Cc: Wood Scott-B07421, joerg.roedel@amd.com, Tabi Timur-B04825,
linux-kernel@vger.kernel.org, iommu@lists.linux-foundation.org,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1354360921-20850-1-git-send-email-Varun.Sethi@freescale.com>
Varun Sethi wrote:
> Following is a brief description of the PAMU hardware:
> PAMU determines what action to take and whether to authorize the action o=
n
> the basis of the memory address, a Logical IO Device Number (LIODN), and
> PAACT table (logically) indexed by LIODN and address. Hardware devices wh=
ich
> need to access memory must provide an LIODN in addition to the memory add=
ress.
>
> Peripheral Access Authorization and Control Tables (PAACTs) are the prima=
ry
> data structures used by PAMU. A PAACT is a table of peripheral access
> authorization and control entries (PAACE).Each PAACE defines the range of
> I/O bus address space that is accessible by the LIOD and the associated a=
ccess
> capabilities.
>
> There are two types of PAACTs: primary PAACT (PPAACT) and secondary PAACT
> (SPAACT).A given physical I/O device may be able to act as one or more
> independent logical I/O devices (LIODs). Each such logical I/O device is
> assigned an identifier called logical I/O device number (LIODN). A LIODN =
is
> allocated a contiguous portion of the I/O bus address space called the DS=
A window
> for performing DSA operations. The DSA window may optionally be divided i=
nto
> multiple sub-windows, each of which may be used to map to a region in sys=
tem
> storage space. The first sub-window is referred to as the primary sub-win=
dow
> and the remaining are called secondary sub-windows.
>
> This patch provides the PAMU driver (fsl_pamu.c) and the corresponding IO=
MMU
> API implementation (fsl_pamu_domain.c). The PAMU hardware driver (fsl_pam=
u.c)
> has been derived from the work done by Ashish Kalra and Timur Tabi
> (timur@freescale.com).
>
> Signed-off-by: Timur Tabi<timur@freescale.com>
> Signed-off-by: Varun Sethi<Varun.Sethi@freescale.com>
> ---
Acked-by: Timur Tabi <timur@freescale.com>
--=20
Timur Tabi
Linux kernel developer at Freescale=
^ permalink raw reply
* RE: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes required by fsl PAMU driver.
From: Sethi Varun-B16395 @ 2012-12-02 8:12 UTC (permalink / raw)
To: joerg.roedel@amd.com
Cc: Wood Scott-B07421, iommu@lists.linux-foundation.org,
Tabi Timur-B04825, linuxppc-dev@lists.ozlabs.org,
linux-kernel@vger.kernel.org
In-Reply-To: <1353419697-31269-4-git-send-email-Varun.Sethi@freescale.com>
Ping!!
> -----Original Message-----
> From: Sethi Varun-B16395
> Sent: Monday, November 26, 2012 10:55 AM
> To: joerg.roedel@amd.com
> Cc: Sethi Varun-B16395; iommu@lists.linux-foundation.org; linuxppc-
> dev@lists.ozlabs.org; linux-kernel@vger.kernel.org; Wood Scott-B07421;
> Tabi Timur-B04825
> Subject: RE: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes
> required by fsl PAMU driver.
>=20
> Hi Joerg,
> Any comments? Can we apply this patch?
>=20
> Regards
> Varun
>=20
> > -----Original Message-----
> > From: Sethi Varun-B16395
> > Sent: Tuesday, November 20, 2012 7:25 PM
> > To: joerg.roedel@amd.com; iommu@lists.linux-foundation.org; linuxppc-
> > dev@lists.ozlabs.org; linux-kernel@vger.kernel.org; Wood Scott-B07421;
> > Tabi Timur-B04825
> > Cc: Sethi Varun-B16395
> > Subject: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes
> > required by fsl PAMU driver.
> >
> > Added the following domain attributes required by FSL PAMU driver:
> > 1. Subwindows field added to the iommu domain geometry attribute.
> > 2. Added new iommu stash attribute, which allows setting of the
> > LIODN specific stash id parameter through IOMMU API.
> > 3. Added an attribute for enabling/disabling DMA to a particular
> > memory window.
> >
> > Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com>
> > ---
> > changes in v5:
> > - Updated description of the subwindows field.
> > changes in v4:
> > - Updated comment explaining subwindows(as mentioned by Scott).
> > change in v3:
> > -renamed the stash attribute targets
> > include/linux/iommu.h | 43
> +++++++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 43 insertions(+), 0 deletions(-)
> >
> > diff --git a/include/linux/iommu.h b/include/linux/iommu.h index
> > f3b99e1..7ca1cda 100644
> > --- a/include/linux/iommu.h
> > +++ b/include/linux/iommu.h
> > @@ -44,6 +44,41 @@ struct iommu_domain_geometry {
> > dma_addr_t aperture_start; /* First address that can be mapped */
> > dma_addr_t aperture_end; /* Last address that can be mapped
> > */
> > bool force_aperture; /* DMA only allowed in mappable range?
> > */
> > +
> > + /*
> > + * A geometry mapping can be created in one of the following ways
> > + * for an IOMMU:
> > + * 1. A single contiguous window
> > + * 2. Through arbritary paging throughout the aperture.
> > + * 3. Using multiple subwindows
> > + *
> > + * In absence of arbritary paging, subwindows allow for supporting
> > + * physically discontiguous mappings.
> > + *
> > + * This attribute indicates number of DMA subwindows supported by
> > + * the geometry. If there is a single window that maps the entire
> > + * geometry, attribute must be set to "1". A value of "0" implies
> > + * that this mechanism is not used at all(normal paging is used).
> > + * Value other than* "0" or "1" indicates the actual number of
> > + * subwindows.
> > + */
> > + u32 subwindows;
> > +};
> > +
> > +/* cache stash targets */
> > +#define IOMMU_ATTR_CACHE_L1 1
> > +#define IOMMU_ATTR_CACHE_L2 2
> > +#define IOMMU_ATTR_CACHE_L3 3
> > +
> > +/* This attribute corresponds to IOMMUs capable of generating
> > + * a stash transaction. A stash transaction is typically a
> > + * hardware initiated prefetch of data from memory to cache.
> > + * This attribute allows configuring stashig specific parameters
> > + * in the IOMMU hardware.
> > + */
> > +struct iommu_stash_attribute {
> > + u32 cpu; /* cpu number */
> > + u32 cache; /* cache to stash to: L1,L2,L3 */
> > };
> >
> > struct iommu_domain {
> > @@ -60,6 +95,14 @@ struct iommu_domain { enum iommu_attr {
> > DOMAIN_ATTR_MAX,
> > DOMAIN_ATTR_GEOMETRY,
> > + /* Set the IOMMU hardware stashing
> > + * parameters.
> > + */
> > + DOMAIN_ATTR_STASH,
> > + /* Explicity enable/disable DMA for a
> > + * particular memory window.
> > + */
> > + DOMAIN_ATTR_ENABLE,
> > };
> >
> > #ifdef CONFIG_IOMMU_API
> > --
> > 1.7.4.1
^ permalink raw reply
* [PATCH] powerpc/windfarm: use for_each_node_by_type() macro
From: Wei Yongjun @ 2012-12-02 13:00 UTC (permalink / raw)
To: benh; +Cc: yongjun_wei, linuxppc-dev, linux-kernel
From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
Use for_each_node_by_type() macro instead of open coding it.
Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
---
drivers/macintosh/windfarm_rm31.c | 2 +-
drivers/macintosh/windfarm_pm72.c | 2 +-
drivers/macintosh/windfarm_pm112.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c
index 3eca6d4..4190b27 100644
--- a/drivers/macintosh/windfarm_rm31.c
+++ b/drivers/macintosh/windfarm_rm31.c
@@ -696,7 +696,7 @@ static int __init wf_rm31_init(void)
/* Count the number of CPU cores */
nr_chips = 0;
- for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+ for_each_node_by_type(cpu, "cpu")
++nr_chips;
if (nr_chips > NR_CHIPS)
nr_chips = NR_CHIPS;
diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c
index 84ac913..73f5e24 100644
--- a/drivers/macintosh/windfarm_pm72.c
+++ b/drivers/macintosh/windfarm_pm72.c
@@ -804,7 +804,7 @@ static int __init wf_pm72_init(void)
/* Count the number of CPU cores */
nr_chips = 0;
- for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+ for_each_node_by_type(cpu, "cpu")
++nr_chips;
if (nr_chips > NR_CHIPS)
nr_chips = NR_CHIPS;
diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c
index e0ee807..b479b82 100644
--- a/drivers/macintosh/windfarm_pm112.c
+++ b/drivers/macintosh/windfarm_pm112.c
@@ -681,7 +681,7 @@ static int __init wf_pm112_init(void)
/* Count the number of CPU cores */
nr_cores = 0;
- for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+ for_each_node_by_type(cpu, "cpu")
++nr_cores;
printk(KERN_INFO "windfarm: initializing for dual-core desktop G5\n");
^ permalink raw reply related
* Re: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes required by fsl PAMU driver.
From: Joerg Roedel @ 2012-12-02 14:03 UTC (permalink / raw)
To: Varun Sethi
Cc: joerg.roedel, linux-kernel, iommu, scottwood, linuxppc-dev, timur
In-Reply-To: <1353419697-31269-4-git-send-email-Varun.Sethi@freescale.com>
Hmm, we need to work out a good abstraction for this.
On Tue, Nov 20, 2012 at 07:24:56PM +0530, Varun Sethi wrote:
> Added the following domain attributes required by FSL PAMU driver:
> 1. Subwindows field added to the iommu domain geometry attribute.
Are the Subwindows mapped with full size or do you map only parts of the
subwindows?
> + * This attribute indicates number of DMA subwindows supported by
> + * the geometry. If there is a single window that maps the entire
> + * geometry, attribute must be set to "1". A value of "0" implies
> + * that this mechanism is not used at all(normal paging is used).
> + * Value other than* "0" or "1" indicates the actual number of
> + * subwindows.
> + */
This semantic is ugly, how about a feature detection mechanism?
> +struct iommu_stash_attribute {
> + u32 cpu; /* cpu number */
> + u32 cache; /* cache to stash to: L1,L2,L3 */
> };
>
> struct iommu_domain {
> @@ -60,6 +95,14 @@ struct iommu_domain {
> enum iommu_attr {
> DOMAIN_ATTR_MAX,
> DOMAIN_ATTR_GEOMETRY,
> + /* Set the IOMMU hardware stashing
> + * parameters.
> + */
> + DOMAIN_ATTR_STASH,
> + /* Explicity enable/disable DMA for a
> + * particular memory window.
> + */
> + DOMAIN_ATTR_ENABLE,
> };
When you add implementation specific attributes please add some
indication to the names that it is only for PAMU. DOMAIN_ATTR_STASH
sounds too generic.
Joerg
^ permalink raw reply
* Re: [PATCH 0/9] dma_debug: add debug_dma_mapping_error support to architectures that support DMA_DEBUG_API
From: Joerg Roedel @ 2012-12-02 14:06 UTC (permalink / raw)
To: Marek Szyprowski
Cc: linux-mips, linux-ia64, a-jacquiot, catalin.marinas, Ming Lei,
shuahkhan, sparclinux, linux-c6x-dev, linux-sh, msalter,
shuah.khan, fenghua.yu, microblaze-uclinux, linux-arm-kernel,
monstr, tony.luck, LKML, ralf, lethal, linuxppc-dev, davem
In-Reply-To: <50B34B0F.3080204@samsung.com>
Hi Marek,
On Mon, Nov 26, 2012 at 11:57:19AM +0100, Marek Szyprowski wrote:
> I've took all the patches to the next-dma-debug branch in my tree, I sorry
> that You have to wait so long for it. My branch is based on Joerg's
> dma-debug branch and I've included it for testing in linux-next branch.
The patches are now two times in next. One version from my tree and one
from yours. Please remove the version from your tree, the patches should
go upstream via my dma-debug branch.
Joerg
^ permalink raw reply
* Re: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes required by fsl PAMU driver.
From: Tabi Timur-B04825 @ 2012-12-02 15:11 UTC (permalink / raw)
To: Joerg Roedel
Cc: Wood Scott-B07421, joerg.roedel@amd.com, Tabi Timur-B04825,
linux-kernel@vger.kernel.org, iommu@lists.linux-foundation.org,
Sethi Varun-B16395, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20121202140323.GO30633@8bytes.org>
Joerg Roedel wrote:
> When you add implementation specific attributes please add some
> indication to the names that it is only for PAMU. DOMAIN_ATTR_STASH
> sounds too generic.
We were thinking that maybe this attribute could be useful to other IOMMUs=
=20
in the future. Stashing is not a concept that would only work on=20
Freescale processors.
But we'll change it if you insist.
--=20
Timur Tabi
Linux kernel developer at Freescale=
^ permalink raw reply
* Re: 3.7-rc7: BUG: MAX_STACK_TRACE_ENTRIES too low!
From: Li Zhong @ 2012-12-03 2:09 UTC (permalink / raw)
To: Christian Kujau; +Cc: paulus, linuxppc-dev, LKML
In-Reply-To: <alpine.DEB.2.01.1212011229400.7378@trent.utfs.org>
On Sat, 2012-12-01 at 12:32 -0800, Christian Kujau wrote:
> On Wed, 28 Nov 2012 at 16:41, Li Zhong wrote:
> > On Tue, 2012-11-27 at 19:22 -0800, Christian Kujau wrote:
> > > On Tue, 27 Nov 2012 at 19:06, Christian Kujau wrote:
> > > > the same thing[0] happened again in 3.7-rc7, after ~20h uptime:
> > >
> > > I found the following on patchwork, but this seems to deal with powerpc64
> > > only, while this PowerBook G4 of mine is powerpc32:
> > >
> > > http://patchwork.ozlabs.org/patch/193414/
> > >
> > > It looks related, but then again, I fail to parse assember...
> >
> > Hi Christian,
> >
> > Would you please help to try the following fix? I don't have a powerpc32
> > machine for test...
>
> After 3 days of uptime with your patch applied (and "normal" usage, just
> as before) no such BUG message occured. So, from my point of view, feel
> free to add:
>
> Tested-by: Christian Kujau <lists@nerdbynature.de>
Thank you, Christian.
I'll try to submit a patch for it.
Thanks, Zhong
>
> Thanks!
> Christian.
>
> > ==============================================
> > diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
> > index 9499385..cadebfd 100644
> > --- a/arch/powerpc/kernel/entry_32.S
> > +++ b/arch/powerpc/kernel/entry_32.S
> > @@ -439,6 +439,8 @@ ret_from_fork:
> > ret_from_kernel_thread:
> > REST_NVGPRS(r1)
> > bl schedule_tail
> > + li r3,0
> > + stw r3,0(r1)
> > mtlr r14
> > mr r3,r15
> > PPC440EP_ERR42
> > ==============================================
> >
> > >
> > > Christian.
> > >
> > > > [40007.339487] [sched_delayed] sched: RT throttling activated
> > > > [69731.388717] BUG: MAX_STACK_TRACE_ENTRIES too low!
> > > > [69731.390371] turning off the locking correctness validator.
> > > > [69731.391942] Call Trace:
> > > > [69731.393525] [c9a61c10] [c0009064] show_stack+0x70/0x1bc (unreliable)
> > > > [69731.395152] [c9a61c50] [c0077460] save_trace+0xfc/0x114
> > > > [69731.396735] [c9a61c60] [c007be20] __lock_acquire+0x1568/0x19b8
> > > > [69731.398296] [c9a61d00] [c007c2c0] lock_acquire+0x50/0x70
> > > > [69731.399857] [c9a61d20] [c0550e28] _raw_spin_lock_irq+0x5c/0x78
> > > > [69731.401419] [c9a61d40] [c054fb58] __schedule+0xd8/0x534
> > > > [69731.402972] [c9a61da0] [c0550094] _cond_resched+0x50/0x68
> > > > [69731.404527] [c9a61db0] [c0479908] dst_gc_task+0xbc/0x258
> > > > [69731.406070] [c9a61e40] [c004eeb8] process_one_work+0x1f4/0x49c
> > > > [69731.407585] [c9a61e80] [c004f644] worker_thread+0x14c/0x400
> > > > [69731.409075] [c9a61eb0] [c0057634] kthread+0xbc/0xc0
> > > > [69731.410521] [c9a61f40] [c0011ad4] ret_from_kernel_thread+0x5c/0x64
> > > > [...repeated 54 times...]
> > > >
> > > > Anyone knows what this is about?
> > > >
> > > > Thanks,
> > > > Christian.
> > > >
> > > > [0] http://lkml.indiana.edu/hypermail/linux/kernel/1211.0/03025.html
>
^ permalink raw reply
* Re: [Patch v4 08/12] memory-hotplug: remove memmap of sparse-vmemmap
From: Jianguo Wu @ 2012-12-03 2:23 UTC (permalink / raw)
To: Wen Congyang
Cc: linux-s390, linux-ia64, Len Brown, linux-acpi, linux-sh, x86,
linux-kernel, cmetcalf, linux-mm, Yasuaki Ishimatsu, paulus,
Minchan Kim, KOSAKI Motohiro, David Rientjes, sparclinux,
Christoph Lameter, linuxppc-dev, Andrew Morton, Jiang Liu
In-Reply-To: <50B80FB1.6040906@cn.fujitsu.com>
Hi Congyang,
This is the new version.
Thanks,
Jianguo Wu.
Signed-off-by: Jianguo Wu <wujianguo@huawei.com>
Signed-off-by: Jiang Liu <jiang.liu@huawei.com>
---
include/linux/mm.h | 1 +
mm/sparse-vmemmap.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++
mm/sparse.c | 3 +-
3 files changed, 234 insertions(+), 1 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 5657670..1f26af5 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1642,6 +1642,7 @@ int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
void vmemmap_populate_print_last(void);
void register_page_bootmem_memmap(unsigned long section_nr, struct page *map,
unsigned long size);
+void vmemmap_free(struct page *memmap, unsigned long nr_pages);
enum mf_flags {
MF_COUNT_INCREASED = 1 << 0,
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index 1b7e22a..748732d 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -29,6 +29,10 @@
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
+#ifdef CONFIG_MEMORY_HOTREMOVE
+#include <asm/tlbflush.h>
+#endif
+
/*
* Allocate a block of memory to be used to back the virtual memory map
* or to back the page tables that are used to create the mapping.
@@ -224,3 +228,230 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
vmemmap_buf_end = NULL;
}
}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+
+#define PAGE_INUSE 0xFD
+
+static void vmemmap_free_pages(struct page *page, int order)
+{
+ struct zone *zone;
+ unsigned long magic;
+
+ magic = (unsigned long) page->lru.next;
+ if (magic == SECTION_INFO || magic == MIX_SECTION_INFO) {
+ put_page_bootmem(page);
+
+ zone = page_zone(page);
+ zone_span_writelock(zone);
+ zone->present_pages++;
+ zone_span_writeunlock(zone);
+ totalram_pages++;
+ } else
+ free_pages((unsigned long)page_address(page), order);
+}
+
+static void free_pte_table(pmd_t *pmd)
+{
+ pte_t *pte, *pte_start;
+ int i;
+
+ pte_start = (pte_t *)pmd_page_vaddr(*pmd);
+ for (i = 0; i < PTRS_PER_PTE; i++) {
+ pte = pte_start + i;
+ if (pte_val(*pte))
+ return;
+ }
+
+ /* free a pte talbe */
+ vmemmap_free_pages(pmd_page(*pmd), 0);
+ spin_lock(&init_mm.page_table_lock);
+ pmd_clear(pmd);
+ spin_unlock(&init_mm.page_table_lock);
+}
+
+static void free_pmd_table(pud_t *pud)
+{
+ pmd_t *pmd, *pmd_start;
+ int i;
+
+ pmd_start = (pmd_t *)pud_page_vaddr(*pud);
+ for (i = 0; i < PTRS_PER_PMD; i++) {
+ pmd = pmd_start + i;
+ if (pmd_val(*pmd))
+ return;
+ }
+
+ /* free a pmd talbe */
+ vmemmap_free_pages(pud_page(*pud), 0);
+ spin_lock(&init_mm.page_table_lock);
+ pud_clear(pud);
+ spin_unlock(&init_mm.page_table_lock);
+}
+
+static void free_pud_table(pgd_t *pgd)
+{
+ pud_t *pud, *pud_start;
+ int i;
+
+ pud_start = (pud_t *)pgd_page_vaddr(*pgd);
+ for (i = 0; i < PTRS_PER_PUD; i++) {
+ pud = pud_start + i;
+ if (pud_val(*pud))
+ return;
+ }
+
+ /* free a pud table */
+ vmemmap_free_pages(pgd_page(*pgd), 0);
+ spin_lock(&init_mm.page_table_lock);
+ pgd_clear(pgd);
+ spin_unlock(&init_mm.page_table_lock);
+}
+
+static int split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase)
+{
+ struct page *page = pmd_page(*(pmd_t *)kpte);
+ int i = 0;
+ unsigned long magic;
+ unsigned long section_nr;
+
+ __split_large_page(kpte, address, pbase);
+ __flush_tlb_all();
+
+ magic = (unsigned long) page->lru.next;
+ if (magic == SECTION_INFO) {
+ section_nr = pfn_to_section_nr(page_to_pfn(page));
+ while (i < PTRS_PER_PMD) {
+ page++;
+ i++;
+ get_page_bootmem(section_nr, page, SECTION_INFO);
+ }
+ }
+
+ return 0;
+}
+
+static void vmemmap_pte_remove(pmd_t *pmd, unsigned long addr, unsigned long end)
+{
+ pte_t *pte;
+ unsigned long next;
+ void *page_addr;
+
+ pte = pte_offset_kernel(pmd, addr);
+ for (; addr < end; pte++, addr += PAGE_SIZE) {
+ next = (addr + PAGE_SIZE) & PAGE_MASK;
+ if (next > end)
+ next = end;
+
+ if (pte_none(*pte))
+ continue;
+ if (IS_ALIGNED(addr, PAGE_SIZE) &&
+ IS_ALIGNED(next, PAGE_SIZE)) {
+ vmemmap_free_pages(pte_page(*pte), 0);
+ spin_lock(&init_mm.page_table_lock);
+ pte_clear(&init_mm, addr, pte);
+ spin_unlock(&init_mm.page_table_lock);
+ } else {
+ /*
+ * Removed page structs are filled with 0xFD.
+ */
+ memset((void *)addr, PAGE_INUSE, next - addr);
+ page_addr = page_address(pte_page(*pte));
+
+ if (!memchr_inv(page_addr, PAGE_INUSE, PAGE_SIZE)) {
+ spin_lock(&init_mm.page_table_lock);
+ pte_clear(&init_mm, addr, pte);
+ spin_unlock(&init_mm.page_table_lock);
+ }
+ }
+ }
+
+ free_pte_table(pmd);
+ __flush_tlb_all();
+}
+
+static void vmemmap_pmd_remove(pud_t *pud, unsigned long addr, unsigned long end)
+{
+ unsigned long next;
+ pmd_t *pmd;
+
+ pmd = pmd_offset(pud, addr);
+ for (; addr < end; addr = next, pmd++) {
+ next = pmd_addr_end(addr, end);
+ if (pmd_none(*pmd))
+ continue;
+
+ if (cpu_has_pse) {
+ unsigned long pte_base;
+
+ if (IS_ALIGNED(addr, PMD_SIZE) &&
+ IS_ALIGNED(next, PMD_SIZE)) {
+ vmemmap_free_pages(pmd_page(*pmd),
+ get_order(PMD_SIZE));
+ spin_lock(&init_mm.page_table_lock);
+ pmd_clear(pmd);
+ spin_unlock(&init_mm.page_table_lock);
+ continue;
+ }
+
+ /*
+ * We use 2M page, but we need to remove part of them,
+ * so split 2M page to 4K page.
+ */
+ pte_base = get_zeroed_page(GFP_ATOMIC | __GFP_NOTRACK);
+ if (!pte_base) {
+ WARN_ON(1);
+ continue;
+ }
+
+ split_large_page((pte_t *)pmd, addr, (pte_t *)pte_base);
+ __flush_tlb_all();
+
+ spin_lock(&init_mm.page_table_lock);
+ pmd_populate_kernel(&init_mm, pmd, (pte_t *)pte_base);
+ spin_unlock(&init_mm.page_table_lock);
+ }
+
+ vmemmap_pte_remove(pmd, addr, next);
+ }
+
+ free_pmd_table(pud);
+ __flush_tlb_all();
+}
+
+static void vmemmap_pud_remove(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+ unsigned long next;
+ pud_t *pud;
+
+ pud = pud_offset(pgd, addr);
+ for (; addr < end; addr = next, pud++) {
+ next = pud_addr_end(addr, end);
+ if (pud_none(*pud))
+ continue;
+
+ vmemmap_pmd_remove(pud, addr, next);
+ }
+
+ free_pud_table(pgd);
+ __flush_tlb_all();
+}
+
+void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+{
+ unsigned long addr = (unsigned long)memmap;
+ unsigned long end = (unsigned long)(memmap + nr_pages);
+ unsigned long next;
+
+ for (; addr < end; addr = next) {
+ pgd_t *pgd = pgd_offset_k(addr);
+
+ next = pgd_addr_end(addr, end);
+ if (!pgd_present(*pgd))
+ continue;
+
+ vmemmap_pud_remove(pgd, addr, next);
+ sync_global_pgds(addr, next - 1);
+ }
+}
+#endif
diff --git a/mm/sparse.c b/mm/sparse.c
index fac95f2..4060229 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -615,10 +615,11 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
}
static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
{
- return; /* XXX: Not implemented yet */
+ vmemmap_free(memmap, nr_pages);
}
static void free_map_bootmem(struct page *page, unsigned long nr_pages)
{
+ vmemmap_free(page, nr_pages);
}
#else
static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
--
1.7.6.1
On 2012/11/30 9:45, Wen Congyang wrote:
> At 11/28/2012 05:40 PM, Jianguo Wu Wrote:
>> Hi Congyang,
>>
>> I think vmemmap's pgtable pages should be freed after all entries are cleared, I have a patch to do this.
>> The code logic is the same as [Patch v4 09/12] memory-hotplug: remove page table of x86_64 architecture.
>>
>> How do you think about this?
>>
>> Signed-off-by: Jianguo Wu <wujianguo@huawei.com>
>> Signed-off-by: Jiang Liu <jiang.liu@huawei.com>
>> ---
>> include/linux/mm.h | 1 +
>> mm/sparse-vmemmap.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++
>> mm/sparse.c | 5 +-
>> 3 files changed, 218 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/mm.h b/include/linux/mm.h
>> index 5657670..1f26af5 100644
>> --- a/include/linux/mm.h
>> +++ b/include/linux/mm.h
>> @@ -1642,6 +1642,7 @@ int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
>> void vmemmap_populate_print_last(void);
>> void register_page_bootmem_memmap(unsigned long section_nr, struct page *map,
>> unsigned long size);
>> +void vmemmap_free(struct page *memmap, unsigned long nr_pages);
>>
>> enum mf_flags {
>> MF_COUNT_INCREASED = 1 << 0,
>> diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
>> index 1b7e22a..242cb28 100644
>> --- a/mm/sparse-vmemmap.c
>> +++ b/mm/sparse-vmemmap.c
>> @@ -29,6 +29,10 @@
>> #include <asm/pgalloc.h>
>> #include <asm/pgtable.h>
>>
>> +#ifdef CONFIG_MEMORY_HOTREMOVE
>> +#include <asm/tlbflush.h>
>> +#endif
>> +
>> /*
>> * Allocate a block of memory to be used to back the virtual memory map
>> * or to back the page tables that are used to create the mapping.
>> @@ -224,3 +228,213 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
>> vmemmap_buf_end = NULL;
>> }
>> }
>> +
>> +#ifdef CONFIG_MEMORY_HOTREMOVE
>> +static void vmemmap_free_pages(struct page *page, int order)
>> +{
>> + struct zone *zone;
>> + unsigned long magic;
>> +
>> + magic = (unsigned long) page->lru.next;
>> + if (magic == SECTION_INFO || magic == MIX_SECTION_INFO) {
>> + put_page_bootmem(page);
>> +
>> + zone = page_zone(page);
>> + zone_span_writelock(zone);
>> + zone->present_pages++;
>> + zone_span_writeunlock(zone);
>> + totalram_pages++;
>> + } else {
>> + if (is_vmalloc_addr(page_address(page)))
>> + vfree(page_address(page));
>
> Hmm, vmemmap doesn't use vmalloc() to allocate memory.
>
>> + else
>> + free_pages((unsigned long)page_address(page), order);
>> + }
>> +}
>> +
>> +static void free_pte_table(pmd_t *pmd)
>> +{
>> + pte_t *pte, *pte_start;
>> + int i;
>> +
>> + pte_start = (pte_t *)pmd_page_vaddr(*pmd);
>> + for (i = 0; i < PTRS_PER_PTE; i++) {
>> + pte = pte_start + i;
>> + if (pte_val(*pte))
>> + return;
>> + }
>> +
>> + /* free a pte talbe */
>> + vmemmap_free_pages(pmd_page(*pmd), 0);
>> + spin_lock(&init_mm.page_table_lock);
>> + pmd_clear(pmd);
>> + spin_unlock(&init_mm.page_table_lock);
>> +}
>> +
>> +static void free_pmd_table(pud_t *pud)
>> +{
>> + pmd_t *pmd, *pmd_start;
>> + int i;
>> +
>> + pmd_start = (pmd_t *)pud_page_vaddr(*pud);
>> + for (i = 0; i < PTRS_PER_PMD; i++) {
>> + pmd = pmd_start + i;
>> + if (pmd_val(*pmd))
>> + return;
>> + }
>> +
>> + /* free a pmd talbe */
>> + vmemmap_free_pages(pud_page(*pud), 0);
>> + spin_lock(&init_mm.page_table_lock);
>> + pud_clear(pud);
>> + spin_unlock(&init_mm.page_table_lock);
>> +}
>> +
>> +static void free_pud_table(pgd_t *pgd)
>> +{
>> + pud_t *pud, *pud_start;
>> + int i;
>> +
>> + pud_start = (pud_t *)pgd_page_vaddr(*pgd);
>> + for (i = 0; i < PTRS_PER_PUD; i++) {
>> + pud = pud_start + i;
>> + if (pud_val(*pud))
>> + return;
>> + }
>> +
>> + /* free a pud table */
>> + vmemmap_free_pages(pgd_page(*pgd), 0);
>> + spin_lock(&init_mm.page_table_lock);
>> + pgd_clear(pgd);
>> + spin_unlock(&init_mm.page_table_lock);
>> +}
>> +
>> +static int split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase)
>> +{
>> + struct page *page = pmd_page(*(pmd_t *)kpte);
>> + int i = 0;
>> + unsigned long magic;
>> + unsigned long section_nr;
>> +
>> + __split_large_page(kpte, address, pbase);
>> + __flush_tlb_all();
>> +
>> + magic = (unsigned long) page->lru.next;
>> + if (magic == SECTION_INFO) {
>> + section_nr = pfn_to_section_nr(page_to_pfn(page));
>> + while (i < PTRS_PER_PMD) {
>> + page++;
>> + i++;
>> + get_page_bootmem(section_nr, page, SECTION_INFO);
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void vmemmap_pte_remove(pmd_t *pmd, unsigned long addr, unsigned long end)
>> +{
>> + pte_t *pte;
>> + unsigned long next;
>> +
>> + pte = pte_offset_kernel(pmd, addr);
>> + for (; addr < end; pte++, addr += PAGE_SIZE) {
>> + next = (addr + PAGE_SIZE) & PAGE_MASK;
>> + if (next > end)
>> + next = end;
>> +
>> + if (pte_none(*pte))
>> + continue;
>> + if (IS_ALIGNED(addr, PAGE_SIZE) &&
>> + IS_ALIGNED(end, PAGE_SIZE)) {
>> + vmemmap_free_pages(pte_page(*pte), 0);
>> + spin_lock(&init_mm.page_table_lock);
>> + pte_clear(&init_mm, addr, pte);
>> + spin_unlock(&init_mm.page_table_lock);
>
> If addr or end is not alianed with PAGE_SIZE, you may leak some
> memory.
>
>> + }
>> + }
>> +
>> + free_pte_table(pmd);
>> + __flush_tlb_all();
>> +}
>> +
>> +static void vmemmap_pmd_remove(pud_t *pud, unsigned long addr, unsigned long end)
>> +{
>> + unsigned long next;
>> + pmd_t *pmd;
>> +
>> + pmd = pmd_offset(pud, addr);
>> + for (; addr < end; addr = next, pmd++) {
>> + next = pmd_addr_end(addr, end);
>> + if (pmd_none(*pmd))
>> + continue;
>> +
>> + if (cpu_has_pse) {
>> + unsigned long pte_base;
>> +
>> + if (IS_ALIGNED(addr, PMD_SIZE) &&
>> + IS_ALIGNED(next, PMD_SIZE)) {
>> + vmemmap_free_pages(pmd_page(*pmd),
>> + get_order(PMD_SIZE));
>> + spin_lock(&init_mm.page_table_lock);
>> + pmd_clear(pmd);
>> + spin_unlock(&init_mm.page_table_lock);
>> + continue;
>> + }
>> +
>> + /*
>> + * We use 2M page, but we need to remove part of them,
>> + * so split 2M page to 4K page.
>> + */
>> + pte_base = get_zeroed_page(GFP_ATOMIC | __GFP_NOTRACK);
>
> get_zeored_page() may fail. You should handle this error.
>
>> + split_large_page((pte_t *)pmd, addr, (pte_t *)pte_base);
>> + __flush_tlb_all();
>> +
>> + spin_lock(&init_mm.page_table_lock);
>> + pmd_populate_kernel(&init_mm, pmd, (pte_t *)pte_base);
>> + spin_unlock(&init_mm.page_table_lock);
>> + }
>> +
>> + vmemmap_pte_remove(pmd, addr, next);
>> + }
>> +
>> + free_pmd_table(pud);
>> + __flush_tlb_all();
>> +}
>> +
>> +static void vmemmap_pud_remove(pgd_t *pgd, unsigned long addr, unsigned long end)
>> +{
>> + unsigned long next;
>> + pud_t *pud;
>> +
>> + pud = pud_offset(pgd, addr);
>> + for (; addr < end; addr = next, pud++) {
>> + next = pud_addr_end(addr, end);
>> + if (pud_none(*pud))
>> + continue;
>> +
>> + vmemmap_pmd_remove(pud, addr, next);
>> + }
>> +
>> + free_pud_table(pgd);
>> + __flush_tlb_all();
>> +}
>> +
>> +void vmemmap_free(struct page *memmap, unsigned long nr_pages)
>> +{
>> + unsigned long addr = (unsigned long)memmap;
>> + unsigned long end = (unsigned long)(memmap + nr_pages);
>> + unsigned long next;
>> +
>> + for (; addr < end; addr = next) {
>> + pgd_t *pgd = pgd_offset_k(addr);
>> +
>> + next = pgd_addr_end(addr, end);
>> + if (!pgd_present(*pgd))
>> + continue;
>> +
>> + vmemmap_pud_remove(pgd, addr, next);
>> + sync_global_pgds(addr, next);
>
> The parameter for sync_global_pgds() is [start, end], not
> [start, end)
>
>> + }
>> +}
>> +#endif
>> diff --git a/mm/sparse.c b/mm/sparse.c
>> index fac95f2..3a16d68 100644
>> --- a/mm/sparse.c
>> +++ b/mm/sparse.c
>> @@ -613,12 +613,13 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
>> /* This will make the necessary allocations eventually. */
>> return sparse_mem_map_populate(pnum, nid);
>> }
>> -static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
>> +static void __kfree_section_memmap(struct page *page, unsigned long nr_pages)
> Why do you change this line?
>
>> {
>> - return; /* XXX: Not implemented yet */
>> + vmemmap_free(page, nr_pages);
>> }
>> static void free_map_bootmem(struct page *page, unsigned long nr_pages)
>> {
>> + vmemmap_free(page, nr_pages);
>> }
>> #else
>> static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
>
>
> .
>
^ permalink raw reply related
* [PATCH 0/2] vfio on power: yet another try
From: Alexey Kardashevskiy @ 2012-12-03 2:52 UTC (permalink / raw)
To: Alex Williamson
Cc: kvm, Alexey Kardashevskiy, linux-kernel, Paul Mackerras,
linuxppc-dev, David Gibson
In-Reply-To: <1353661396-14374-1-git-send-email-aik@ozlabs.ru>
The set includes 2 patches.
The first one adds necessary support for VFIO IOMMU support,
the second one adds a SPAPR TCE IOMMU driver to VFIO.
At the moment we have decided to get rid of DMA64 window
properties because we need more API than just 2 properties
(such as dynamic window allocation) but have not decided
about its actual design yet.
Alexey Kardashevskiy (2):
vfio powerpc: enabled on powernv platform
vfio powerpc: implemented IOMMU driver for VFIO
arch/powerpc/include/asm/iommu.h | 9 +
arch/powerpc/kernel/iommu.c | 186 ++++++++++++++++++
arch/powerpc/platforms/powernv/pci.c | 135 +++++++++++++
drivers/iommu/Kconfig | 8 +
drivers/vfio/Kconfig | 6 +
drivers/vfio/Makefile | 1 +
drivers/vfio/vfio_iommu_spapr_tce.c | 350 ++++++++++++++++++++++++++++++++++
include/linux/vfio.h | 26 +++
8 files changed, 721 insertions(+)
create mode 100644 drivers/vfio/vfio_iommu_spapr_tce.c
--
1.7.10.4
^ permalink raw reply
* [PATCH 1/2] vfio powerpc: enabled on powernv platform
From: Alexey Kardashevskiy @ 2012-12-03 2:52 UTC (permalink / raw)
To: Alex Williamson
Cc: kvm, Alexey Kardashevskiy, linux-kernel, Paul Mackerras,
linuxppc-dev, David Gibson
In-Reply-To: <1354503178-2602-1-git-send-email-aik@ozlabs.ru>
This patch initializes IOMMU groups based on the IOMMU
configuration discovered during the PCI scan on POWERNV
(POWER non virtualized) platform. The IOMMU groups are
to be used later by VFIO driver (PCI pass through).
It also implements an API for mapping/unmapping pages for
guest PCI drivers and providing DMA window properties.
This API is going to be used later by QEMU-VFIO to handle
h_put_tce hypercalls from the KVM guest.
Although this driver has been tested only on the POWERNV
platform, it should work on any platform which supports
TCE tables.
To enable VFIO on POWER, enable SPAPR_TCE_IOMMU config
option and configure VFIO as required.
Cc: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
---
arch/powerpc/include/asm/iommu.h | 9 ++
arch/powerpc/kernel/iommu.c | 186 ++++++++++++++++++++++++++++++++++
arch/powerpc/platforms/powernv/pci.c | 135 ++++++++++++++++++++++++
drivers/iommu/Kconfig | 8 ++
4 files changed, 338 insertions(+)
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index cbfe678..5c7087a 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -76,6 +76,9 @@ struct iommu_table {
struct iommu_pool large_pool;
struct iommu_pool pools[IOMMU_NR_POOLS];
unsigned long *it_map; /* A simple allocation bitmap for now */
+#ifdef CONFIG_IOMMU_API
+ struct iommu_group *it_group;
+#endif
};
struct scatterlist;
@@ -147,5 +150,11 @@ static inline void iommu_restore(void)
}
#endif
+extern long iommu_clear_tces(struct iommu_table *tbl, unsigned long entry,
+ unsigned long pages);
+extern long iommu_put_tces(struct iommu_table *tbl, unsigned long entry,
+ uint64_t tce, enum dma_data_direction direction,
+ unsigned long pages);
+
#endif /* __KERNEL__ */
#endif /* _ASM_IOMMU_H */
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index ff5a6ce..2738aa4 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -44,6 +44,7 @@
#include <asm/kdump.h>
#include <asm/fadump.h>
#include <asm/vio.h>
+#include <asm/tce.h>
#define DBG(...)
@@ -856,3 +857,188 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
free_pages((unsigned long)vaddr, get_order(size));
}
}
+
+#ifdef CONFIG_IOMMU_API
+/*
+ * SPAPR TCE API
+ */
+
+/*
+ * Returns the number of used IOMMU pages (4K) within
+ * the same system page (4K or 64K).
+ * bitmap_weight is not used as it does not support bigendian maps.
+ */
+static int syspage_weight(unsigned long *map, unsigned long entry)
+{
+ int ret = 0, nbits = PAGE_SIZE/IOMMU_PAGE_SIZE;
+
+ /* Aligns TCE entry number to system page boundary */
+ entry &= PAGE_MASK >> IOMMU_PAGE_SHIFT;
+
+ /* Count used 4K pages */
+ while (nbits--)
+ ret += (test_bit(entry++, map) == 0) ? 0 : 1;
+
+ return ret;
+}
+
+static void tce_flush(struct iommu_table *tbl)
+{
+ /* Flush/invalidate TLB caches if necessary */
+ if (ppc_md.tce_flush)
+ ppc_md.tce_flush(tbl);
+
+ /* Make sure updates are seen by hardware */
+ mb();
+}
+
+/*
+ * iommu_clear_tces clears tces and returned the number of system pages
+ * which it called put_page() on
+ */
+static long clear_tces_nolock(struct iommu_table *tbl, unsigned long entry,
+ unsigned long pages)
+{
+ int i, retpages = 0;
+ unsigned long oldtce, oldweight;
+ struct page *page;
+
+ for (i = 0; i < pages; ++i) {
+ oldtce = ppc_md.tce_get(tbl, entry + i);
+ ppc_md.tce_free(tbl, entry + i, 1);
+
+ oldweight = syspage_weight(tbl->it_map, entry);
+ __clear_bit(entry - tbl->it_offset, tbl->it_map);
+
+ if (!(oldtce & (TCE_PCI_WRITE | TCE_PCI_READ)))
+ continue;
+
+ page = pfn_to_page(oldtce >> PAGE_SHIFT);
+
+ WARN_ON(!page);
+ if (!page)
+ continue;
+
+ if (oldtce & TCE_PCI_WRITE)
+ SetPageDirty(page);
+
+ put_page(page);
+
+ /* That was the last IOMMU page within the system page */
+ if ((oldweight == 1) && !syspage_weight(tbl->it_map, entry))
+ ++retpages;
+ }
+
+ return retpages;
+}
+
+/*
+ * iommu_clear_tces clears tces and returned the number
+ / of released system pages
+ */
+long iommu_clear_tces(struct iommu_table *tbl, unsigned long entry,
+ unsigned long pages)
+{
+ int ret;
+ struct iommu_pool *pool = get_pool(tbl, entry);
+
+ spin_lock(&(pool->lock));
+ ret = clear_tces_nolock(tbl, entry, pages);
+ tce_flush(tbl);
+ spin_unlock(&(pool->lock));
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_clear_tces);
+
+static int put_tce(struct iommu_table *tbl, unsigned long entry,
+ uint64_t tce, enum dma_data_direction direction)
+{
+ int ret;
+ struct page *page = NULL;
+ unsigned long kva, offset, oldweight;
+
+ /* Map new TCE */
+ offset = (tce & IOMMU_PAGE_MASK) - (tce & PAGE_MASK);
+ ret = get_user_pages_fast(tce & PAGE_MASK, 1,
+ direction != DMA_TO_DEVICE, &page);
+ if (ret < 1) {
+ printk(KERN_ERR "tce_vfio: get_user_pages_fast failed tce=%llx ioba=%lx ret=%d\n",
+ tce, entry << IOMMU_PAGE_SHIFT, ret);
+ if (!ret || (ret > 1))
+ ret = -EFAULT;
+ return ret;
+ }
+
+ kva = (unsigned long) page_address(page);
+ kva += offset;
+
+ /* tce_build receives a virtual address */
+ entry += tbl->it_offset; /* Offset into real TCE table */
+ ret = ppc_md.tce_build(tbl, entry, 1, kva, direction, NULL);
+
+ /* tce_build() only returns non-zero for transient errors */
+ if (unlikely(ret)) {
+ printk(KERN_ERR "tce_vfio: tce_put failed on tce=%llx ioba=%lx kva=%lx ret=%d\n",
+ tce, entry << IOMMU_PAGE_SHIFT, kva, ret);
+ put_page(page);
+ return -EIO;
+ }
+
+ /* Calculate if new system page has been locked */
+ oldweight = syspage_weight(tbl->it_map, entry);
+ __set_bit(entry - tbl->it_offset, tbl->it_map);
+
+ return (oldweight == 0) ? 1 : 0;
+}
+
+/*
+ * iommu_put_tces builds tces and returned the number of actually
+ * locked system pages
+ */
+long iommu_put_tces(struct iommu_table *tbl, unsigned long entry,
+ uint64_t tce, enum dma_data_direction direction,
+ unsigned long pages)
+{
+ int i, ret = 0, retpages = 0;
+ struct iommu_pool *pool = get_pool(tbl, entry);
+
+ BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE);
+ BUG_ON(direction == DMA_NONE);
+
+ spin_lock(&(pool->lock));
+
+ /* Check if any is in use */
+ for (i = 0; i < pages; ++i) {
+ unsigned long oldtce = ppc_md.tce_get(tbl, entry + i);
+ if ((oldtce & (TCE_PCI_WRITE | TCE_PCI_READ)) ||
+ test_bit(entry + i, tbl->it_map)) {
+ WARN_ON(test_bit(entry + i, tbl->it_map));
+ spin_unlock(&(pool->lock));
+ return -EBUSY;
+ }
+ }
+
+ /* Put tces to the table */
+ for (i = 0; (i < pages) && (ret >= 0); ++i, tce += IOMMU_PAGE_SIZE) {
+ ret = put_tce(tbl, entry + i, tce, direction);
+ if (ret == 1)
+ ++retpages;
+ }
+
+ /*
+ * If failed, release locked pages, otherwise return the number
+ * of locked system pages
+ */
+ if (ret < 0)
+ clear_tces_nolock(tbl, entry, i);
+ else
+ ret = retpages;
+
+ tce_flush(tbl);
+ spin_unlock(&(pool->lock));
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_put_tces);
+#endif /* CONFIG_IOMMU_API */
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 05205cf..21250ef 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -20,6 +20,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/msi.h>
+#include <linux/iommu.h>
#include <asm/sections.h>
#include <asm/io.h>
@@ -613,3 +614,137 @@ void __init pnv_pci_init(void)
ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs;
#endif
}
+
+#ifdef CONFIG_IOMMU_API
+/*
+ * IOMMU groups support required by VFIO
+ */
+static int add_device(struct device *dev)
+{
+ struct iommu_table *tbl;
+ int ret = 0;
+
+ if (WARN_ON(dev->iommu_group)) {
+ printk(KERN_WARNING "tce_vfio: device %s is already in iommu group %d, skipping\n",
+ dev_name(dev),
+ iommu_group_id(dev->iommu_group));
+ return -EBUSY;
+ }
+
+ tbl = get_iommu_table_base(dev);
+ if (!tbl) {
+ pr_debug("tce_vfio: skipping device %s with no tbl\n",
+ dev_name(dev));
+ return 0;
+ }
+
+ pr_debug("tce_vfio: adding %s to iommu group %d\n",
+ dev_name(dev), iommu_group_id(tbl->it_group));
+
+ ret = iommu_group_add_device(tbl->it_group, dev);
+ if (ret < 0)
+ printk(KERN_ERR "tce_vfio: %s has not been added, ret=%d\n",
+ dev_name(dev), ret);
+
+ return ret;
+}
+
+static void del_device(struct device *dev)
+{
+ iommu_group_remove_device(dev);
+}
+
+static int iommu_bus_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ return add_device(dev);
+ case BUS_NOTIFY_DEL_DEVICE:
+ del_device(dev);
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static struct notifier_block tce_iommu_bus_nb = {
+ .notifier_call = iommu_bus_notifier,
+};
+
+static void group_release(void *iommu_data)
+{
+ struct iommu_table *tbl = iommu_data;
+ tbl->it_group = NULL;
+}
+
+static int __init tce_iommu_init(void)
+{
+ struct pci_dev *pdev = NULL;
+ struct iommu_table *tbl;
+ struct iommu_group *grp;
+
+ /* Allocate and initialize IOMMU groups */
+ for_each_pci_dev(pdev) {
+ tbl = get_iommu_table_base(&pdev->dev);
+ if (!tbl)
+ continue;
+
+ /* Skip already initialized */
+ if (tbl->it_group)
+ continue;
+
+ grp = iommu_group_alloc();
+ if (IS_ERR(grp)) {
+ printk(KERN_INFO "tce_vfio: cannot create "
+ "new IOMMU group, ret=%ld\n",
+ PTR_ERR(grp));
+ return PTR_ERR(grp);
+ }
+ tbl->it_group = grp;
+ iommu_group_set_iommudata(grp, tbl, group_release);
+ }
+
+ bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
+
+ /* Add PCI devices to VFIO groups */
+ for_each_pci_dev(pdev)
+ add_device(&pdev->dev);
+
+ return 0;
+}
+
+static void __exit tce_iommu_cleanup(void)
+{
+ struct pci_dev *pdev = NULL;
+ struct iommu_table *tbl;
+ struct iommu_group *grp = NULL;
+
+ bus_unregister_notifier(&pci_bus_type, &tce_iommu_bus_nb);
+
+ /* Delete PCI devices from VFIO groups */
+ for_each_pci_dev(pdev)
+ del_device(&pdev->dev);
+
+ /* Release VFIO groups */
+ for_each_pci_dev(pdev) {
+ tbl = get_iommu_table_base(&pdev->dev);
+ if (!tbl)
+ continue;
+ grp = tbl->it_group;
+
+ /* Skip (already) uninitialized */
+ if (!grp)
+ continue;
+
+ /* Do actual release, group_release() is expected to work */
+ iommu_group_put(grp);
+ BUG_ON(tbl->it_group);
+ }
+}
+
+module_init(tce_iommu_init);
+module_exit(tce_iommu_cleanup);
+#endif /* CONFIG_IOMMU_API */
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 9f69b56..29d11dc 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -187,4 +187,12 @@ config EXYNOS_IOMMU_DEBUG
Say N unless you need kernel log message for IOMMU debugging
+config SPAPR_TCE_IOMMU
+ bool "sPAPR TCE IOMMU Support"
+ depends on PPC_POWERNV
+ select IOMMU_API
+ help
+ Enables bits of IOMMU API required by VFIO. The iommu_ops is
+ still not implemented.
+
endif # IOMMU_SUPPORT
--
1.7.10.4
^ permalink raw reply related
* [PATCH 2/2] vfio powerpc: implemented IOMMU driver for VFIO
From: Alexey Kardashevskiy @ 2012-12-03 2:52 UTC (permalink / raw)
To: Alex Williamson
Cc: kvm, Alexey Kardashevskiy, linux-kernel, Paul Mackerras,
linuxppc-dev, David Gibson
In-Reply-To: <1354503178-2602-1-git-send-email-aik@ozlabs.ru>
VFIO implements platform independent stuff such as
a PCI driver, BAR access (via read/write on a file descriptor
or direct mapping when possible) and IRQ signaling.
The platform dependent part includes IOMMU initialization
and handling. This patch implements an IOMMU driver for VFIO
which does mapping/unmapping pages for the guest IO and
provides information about DMA window (required by a POWERPC
guest).
The counterpart in QEMU is required to support this functionality.
Cc: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
---
drivers/vfio/Kconfig | 6 +
drivers/vfio/Makefile | 1 +
drivers/vfio/vfio_iommu_spapr_tce.c | 350 +++++++++++++++++++++++++++++++++++
include/linux/vfio.h | 26 +++
4 files changed, 383 insertions(+)
create mode 100644 drivers/vfio/vfio_iommu_spapr_tce.c
diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index 7cd5dec..b464687 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -3,10 +3,16 @@ config VFIO_IOMMU_TYPE1
depends on VFIO
default n
+config VFIO_IOMMU_SPAPR_TCE
+ tristate
+ depends on VFIO && SPAPR_TCE_IOMMU
+ default n
+
menuconfig VFIO
tristate "VFIO Non-Privileged userspace driver framework"
depends on IOMMU_API
select VFIO_IOMMU_TYPE1 if X86
+ select VFIO_IOMMU_SPAPR_TCE if PPC_POWERNV
help
VFIO provides a framework for secure userspace device drivers.
See Documentation/vfio.txt for more details.
diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
index 2398d4a..72bfabc 100644
--- a/drivers/vfio/Makefile
+++ b/drivers/vfio/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_VFIO) += vfio.o
obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
+obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
obj-$(CONFIG_VFIO_PCI) += pci/
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
new file mode 100644
index 0000000..806ad9f
--- /dev/null
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -0,0 +1,350 @@
+/*
+ * VFIO: IOMMU DMA mapping support for TCE on POWER
+ *
+ * Copyright (C) 2012 IBM Corp. All rights reserved.
+ * Author: Alexey Kardashevskiy <aik@ozlabs.ru>
+ *
+ * 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.
+ *
+ * Derived from original vfio_iommu_type1.c:
+ * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+ * Author: Alex Williamson <alex.williamson@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/err.h>
+#include <linux/vfio.h>
+#include <asm/iommu.h>
+
+#define DRIVER_VERSION "0.1"
+#define DRIVER_AUTHOR "aik@ozlabs.ru"
+#define DRIVER_DESC "VFIO IOMMU SPAPR TCE"
+
+static void tce_iommu_detach_group(void *iommu_data,
+ struct iommu_group *iommu_group);
+
+/*
+ * VFIO IOMMU fd for SPAPR_TCE IOMMU implementation
+ */
+
+/*
+ * This code handles mapping and unmapping of user data buffers
+ * into DMA'ble space using the IOMMU
+ */
+
+#define NPAGE_TO_SIZE(npage) ((size_t)(npage) << PAGE_SHIFT)
+
+struct vwork {
+ struct mm_struct *mm;
+ long npage;
+ struct work_struct work;
+};
+
+/* delayed decrement/increment for locked_vm */
+static void lock_acct_bg(struct work_struct *work)
+{
+ struct vwork *vwork = container_of(work, struct vwork, work);
+ struct mm_struct *mm;
+
+ mm = vwork->mm;
+ down_write(&mm->mmap_sem);
+ mm->locked_vm += vwork->npage;
+ up_write(&mm->mmap_sem);
+ mmput(mm);
+ kfree(vwork);
+}
+
+static void lock_acct(long npage)
+{
+ struct vwork *vwork;
+ struct mm_struct *mm;
+
+ if (!current->mm)
+ return; /* process exited */
+
+ if (down_write_trylock(¤t->mm->mmap_sem)) {
+ current->mm->locked_vm += npage;
+ up_write(¤t->mm->mmap_sem);
+ return;
+ }
+
+ /*
+ * Couldn't get mmap_sem lock, so must setup to update
+ * mm->locked_vm later. If locked_vm were atomic, we
+ * wouldn't need this silliness
+ */
+ vwork = kmalloc(sizeof(struct vwork), GFP_KERNEL);
+ if (!vwork)
+ return;
+ mm = get_task_mm(current);
+ if (!mm) {
+ kfree(vwork);
+ return;
+ }
+ INIT_WORK(&vwork->work, lock_acct_bg);
+ vwork->mm = mm;
+ vwork->npage = npage;
+ schedule_work(&vwork->work);
+}
+
+/*
+ * The container descriptor supports only a single group per container.
+ * Required by the API as the container is not supplied with the IOMMU group
+ * at the moment of initialization.
+ */
+struct tce_container {
+ struct mutex lock;
+ struct iommu_table *tbl;
+};
+
+static void *tce_iommu_open(unsigned long arg)
+{
+ struct tce_container *container;
+
+ if (arg != VFIO_SPAPR_TCE_IOMMU) {
+ pr_err("tce_vfio: Wrong IOMMU type\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ container = kzalloc(sizeof(*container), GFP_KERNEL);
+ if (!container)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&container->lock);
+
+ return container;
+}
+
+static void tce_iommu_release(void *iommu_data)
+{
+ struct tce_container *container = iommu_data;
+
+ WARN_ON(container->tbl && !container->tbl->it_group);
+ if (container->tbl && container->tbl->it_group)
+ tce_iommu_detach_group(iommu_data, container->tbl->it_group);
+
+ mutex_destroy(&container->lock);
+
+ kfree(container);
+}
+
+static long tce_iommu_ioctl(void *iommu_data,
+ unsigned int cmd, unsigned long arg)
+{
+ struct tce_container *container = iommu_data;
+ unsigned long minsz;
+ long ret;
+
+ switch (cmd) {
+ case VFIO_CHECK_EXTENSION: {
+ return (arg == VFIO_SPAPR_TCE_IOMMU) ? 1 : 0;
+ }
+ case VFIO_IOMMU_SPAPR_TCE_GET_INFO: {
+ struct vfio_iommu_spapr_tce_info info;
+ struct iommu_table *tbl = container->tbl;
+
+ if (WARN_ON(!tbl))
+ return -ENXIO;
+
+ minsz = offsetofend(struct vfio_iommu_spapr_tce_info,
+ dma32_window_size);
+
+ if (copy_from_user(&info, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (info.argsz < minsz)
+ return -EINVAL;
+
+ info.dma32_window_start = tbl->it_offset << IOMMU_PAGE_SHIFT;
+ info.dma32_window_size = tbl->it_size << IOMMU_PAGE_SHIFT;
+ info.flags = 0;
+
+ if (copy_to_user((void __user *)arg, &info, minsz))
+ return -EFAULT;
+
+ return 0;
+ }
+ case VFIO_IOMMU_MAP_DMA: {
+ vfio_iommu_spapr_tce_dma_map param;
+ struct iommu_table *tbl = container->tbl;
+ enum dma_data_direction direction;
+ unsigned long locked, lock_limit;
+
+ if (WARN_ON(!tbl))
+ return -ENXIO;
+
+ minsz = offsetofend(vfio_iommu_spapr_tce_dma_map, size);
+
+ if (copy_from_user(¶m, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (param.argsz < minsz)
+ return -EINVAL;
+
+ if ((param.flags & VFIO_DMA_MAP_FLAG_READ) &&
+ (param.flags & VFIO_DMA_MAP_FLAG_WRITE))
+ direction = DMA_BIDIRECTIONAL;
+ else if (param.flags & VFIO_DMA_MAP_FLAG_READ)
+ direction = DMA_TO_DEVICE;
+ else if (param.flags & VFIO_DMA_MAP_FLAG_WRITE)
+ direction = DMA_FROM_DEVICE;
+ else
+ return -EINVAL;
+
+ if ((param.size & ~IOMMU_PAGE_MASK) ||
+ (param.iova & ~IOMMU_PAGE_MASK) ||
+ (param.vaddr & ~IOMMU_PAGE_MASK))
+ return -EINVAL;
+
+ if ((param.iova + param.size) >
+ (tbl->it_size << IOMMU_PAGE_SHIFT))
+ return -EINVAL;
+
+ if (param.iova < (tbl->it_offset << IOMMU_PAGE_SHIFT))
+ return -EINVAL;
+
+ /* Account for locked pages */
+ locked = current->mm->locked_vm +
+ (param.size >> PAGE_SHIFT);
+ lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+ if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
+ pr_warn("RLIMIT_MEMLOCK (%ld) exceeded\n",
+ rlimit(RLIMIT_MEMLOCK));
+ return -ENOMEM;
+ }
+
+ ret = iommu_put_tces(tbl, param.iova >> IOMMU_PAGE_SHIFT,
+ param.vaddr, direction,
+ param.size >> IOMMU_PAGE_SHIFT);
+
+ if (ret > 0)
+ lock_acct(ret);
+
+ return ret;
+ }
+ case VFIO_IOMMU_UNMAP_DMA: {
+ vfio_iommu_spapr_tce_dma_unmap param;
+ struct iommu_table *tbl = container->tbl;
+
+ if (WARN_ON(!tbl))
+ return -ENXIO;
+
+ minsz = offsetofend(vfio_iommu_spapr_tce_dma_unmap, size);
+
+ if (copy_from_user(¶m, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (param.argsz < minsz)
+ return -EINVAL;
+
+ if ((param.size & ~IOMMU_PAGE_MASK) ||
+ (param.iova & ~IOMMU_PAGE_MASK))
+ return -EINVAL;
+
+ if ((param.iova + param.size) >
+ (tbl->it_size << IOMMU_PAGE_SHIFT))
+ return -EINVAL;
+
+ if (param.iova < (tbl->it_offset << IOMMU_PAGE_SHIFT))
+ return -EINVAL;
+
+ ret = iommu_clear_tces(tbl, param.iova >> IOMMU_PAGE_SHIFT,
+ param.size >> IOMMU_PAGE_SHIFT);
+
+ if (ret > 0)
+ lock_acct(-ret);
+
+ return ret;
+ }
+ default:
+ pr_warn("tce_vfio: unexpected cmd %x\n", cmd);
+ }
+
+ return -ENOTTY;
+}
+
+static int tce_iommu_attach_group(void *iommu_data,
+ struct iommu_group *iommu_group)
+{
+ struct tce_container *container = iommu_data;
+ struct iommu_table *tbl = iommu_group_get_iommudata(iommu_group);
+
+ BUG_ON(!tbl);
+ mutex_lock(&container->lock);
+ pr_debug("tce_vfio: Attaching group #%u to iommu %p\n",
+ iommu_group_id(iommu_group), iommu_group);
+ if (container->tbl) {
+ pr_warn("tce_vfio: Only one group per IOMMU container is allowed, existing id=%d, attaching id=%d\n",
+ iommu_group_id(container->tbl->it_group),
+ iommu_group_id(iommu_group));
+ mutex_unlock(&container->lock);
+ return -EBUSY;
+ }
+
+ container->tbl = tbl;
+ iommu_clear_tces(tbl, tbl->it_offset, tbl->it_size);
+ mutex_unlock(&container->lock);
+
+ return 0;
+}
+
+static void tce_iommu_detach_group(void *iommu_data,
+ struct iommu_group *iommu_group)
+{
+ struct tce_container *container = iommu_data;
+ struct iommu_table *tbl = iommu_group_get_iommudata(iommu_group);
+
+ BUG_ON(!tbl);
+ mutex_lock(&container->lock);
+ if (tbl != container->tbl) {
+ pr_warn("tce_vfio: detaching group #%u, expected group is #%u\n",
+ iommu_group_id(iommu_group),
+ iommu_group_id(tbl->it_group));
+ } else {
+
+ pr_debug("tce_vfio: detaching group #%u from iommu %p\n",
+ iommu_group_id(iommu_group), iommu_group);
+
+ iommu_clear_tces(tbl, tbl->it_offset, tbl->it_size);
+ container->tbl = NULL;
+ /* Restore reserve for page 0 */
+ if (tbl->it_offset == 0)
+ set_bit(0, tbl->it_map);
+
+ }
+ mutex_unlock(&container->lock);
+}
+
+const struct vfio_iommu_driver_ops tce_iommu_driver_ops = {
+ .name = "iommu-vfio-powerpc",
+ .owner = THIS_MODULE,
+ .open = tce_iommu_open,
+ .release = tce_iommu_release,
+ .ioctl = tce_iommu_ioctl,
+ .attach_group = tce_iommu_attach_group,
+ .detach_group = tce_iommu_detach_group,
+};
+
+static int __init tce_iommu_init(void)
+{
+ return vfio_register_iommu_driver(&tce_iommu_driver_ops);
+}
+
+static void __exit tce_iommu_cleanup(void)
+{
+ vfio_unregister_iommu_driver(&tce_iommu_driver_ops);
+}
+
+module_init(tce_iommu_init);
+module_exit(tce_iommu_cleanup);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 0a4f180..a12295c 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -99,6 +99,7 @@ extern void vfio_unregister_iommu_driver(
/* Extensions */
#define VFIO_TYPE1_IOMMU 1
+#define VFIO_SPAPR_TCE_IOMMU 2
/*
* The IOCTL interface is designed for extensibility by embedding the
@@ -442,4 +443,29 @@ struct vfio_iommu_type1_dma_unmap {
#define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)
+/* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */
+
+/*
+ * The SPAPR TCE info struct provides the information about the PCI bus
+ * address ranges available for DMA, these values are programmed into
+ * the hardware so the guest has to know that information.
+ *
+ * The IOMMU page size is always 4K.
+ */
+
+struct vfio_iommu_spapr_tce_info {
+ __u32 argsz;
+ __u32 flags; /* reserved for future use */
+ __u32 dma32_window_start; /* 32 bit window start (bytes) */
+ __u32 dma32_window_size; /* 32 bit window size (bytes) */
+};
+
+#define VFIO_IOMMU_SPAPR_TCE_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12)
+
+/* Reuse type1 map/unmap structs as they are the same at the moment */
+typedef struct vfio_iommu_type1_dma_map vfio_iommu_spapr_tce_dma_map;
+typedef struct vfio_iommu_type1_dma_unmap vfio_iommu_spapr_tce_dma_unmap;
+
+/* ***************************************************************** */
+
#endif /* VFIO_H */
--
1.7.10.4
^ permalink raw reply related
* [PATCH powerpc] Fix MAX_STACK_TRACE_ENTRIES too low warning for ppc32
From: Li Zhong @ 2012-12-03 6:19 UTC (permalink / raw)
To: PowerPC email list; +Cc: Christian Kujau, Paul Mackerras
This patch fixes MAX_STACK_TRACE_ENTRIES too low warning for ppc32,
which is similar to commit 12660b17.
Reported-by: Christian Kujau <lists@nerdbynature.de>
Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
Tested-by: Christian Kujau <lists@nerdbynature.de>
---
arch/powerpc/kernel/entry_32.S | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index d22e73e..e514de5 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -439,6 +439,8 @@ ret_from_fork:
ret_from_kernel_thread:
REST_NVGPRS(r1)
bl schedule_tail
+ li r3,0
+ stw r3,0(r1)
mtlr r14
mr r3,r15
PPC440EP_ERR42
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH powerpc] Fix MAX_STACK_TRACE_ENTRIES too low warning for ppc32
From: Denis Kirjanov @ 2012-12-03 8:03 UTC (permalink / raw)
To: Li Zhong; +Cc: Christian Kujau, Paul Mackerras, PowerPC email list
In-Reply-To: <1354515562.3243.27.camel@ThinkPad-T5421.cn.ibm.com>
Could you please provide a more verbose patch description
Thanks.
On 12/3/12, Li Zhong <zhong@linux.vnet.ibm.com> wrote:
> This patch fixes MAX_STACK_TRACE_ENTRIES too low warning for ppc32,
> which is similar to commit 12660b17.
>
> Reported-by: Christian Kujau <lists@nerdbynature.de>
> Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
> Tested-by: Christian Kujau <lists@nerdbynature.de>
> ---
> arch/powerpc/kernel/entry_32.S | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/arch/powerpc/kernel/entry_32.S
> b/arch/powerpc/kernel/entry_32.S
> index d22e73e..e514de5 100644
> --- a/arch/powerpc/kernel/entry_32.S
> +++ b/arch/powerpc/kernel/entry_32.S
> @@ -439,6 +439,8 @@ ret_from_fork:
> ret_from_kernel_thread:
> REST_NVGPRS(r1)
> bl schedule_tail
> + li r3,0
> + stw r3,0(r1)
> mtlr r14
> mr r3,r15
> PPC440EP_ERR42
> --
> 1.7.9.5
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
--
Regards,
Denis
^ permalink raw reply
* Re: [PATCH 0/9] dma_debug: add debug_dma_mapping_error support to architectures that support DMA_DEBUG_API
From: Marek Szyprowski @ 2012-12-03 8:51 UTC (permalink / raw)
To: Joerg Roedel
Cc: linux-mips, linux-ia64, a-jacquiot, catalin.marinas, Ming Lei,
shuahkhan, sparclinux, linux-c6x-dev, linux-sh, msalter,
shuah.khan, fenghua.yu, microblaze-uclinux, linux-arm-kernel,
monstr, tony.luck, LKML, ralf, lethal, linuxppc-dev, davem
In-Reply-To: <20121202140644.GP30633@8bytes.org>
On 12/2/2012 3:06 PM, Joerg Roedel wrote:
> Hi Marek,
>
> On Mon, Nov 26, 2012 at 11:57:19AM +0100, Marek Szyprowski wrote:
>
> > I've took all the patches to the next-dma-debug branch in my tree, I sorry
> > that You have to wait so long for it. My branch is based on Joerg's
> > dma-debug branch and I've included it for testing in linux-next branch.
>
> The patches are now two times in next. One version from my tree and one
> from yours. Please remove the version from your tree, the patches should
> go upstream via my dma-debug branch.
Ok, I've removed them from my dma-mapping-next tree. Please add/cherry-pick
the missing patch for ARM architecture, which I've accidentally already
pushed to mainline some time ago and then reverted. See commit
871ae57adc5ed092 (and 697575896670ba).
Best regards
--
Marek Szyprowski
Samsung Poland R&D Center
^ permalink raw reply
* [PATCH -next] powerpc/85xx: use for_each_compatible_node() macro
From: Wei Yongjun @ 2012-12-03 13:36 UTC (permalink / raw)
To: galak, benh, paulus, grant.likely, rob.herring
Cc: yongjun_wei, linuxppc-dev, devicetree-discuss, linux-kernel
From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
Use for_each_compatible_node() macro instead of open coding it.
Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
---
arch/powerpc/platforms/85xx/mpc85xx_mds.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index bd12588..a7b3621 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -206,9 +206,7 @@ static void __init mpc85xx_mds_reset_ucc_phys(void)
setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
- for (np = NULL; (np = of_find_compatible_node(np,
- "network",
- "ucc_geth")) != NULL;) {
+ for_each_compatible_node(np, "network", "ucc_geth") {
const unsigned int *prop;
int ucc_num;
^ permalink raw reply related
* [PATCH v2 1/4] kprobes/powerpc: Do not disable External interrupts during single step
From: Suzuki K. Poulose @ 2012-12-03 15:07 UTC (permalink / raw)
To: bigeasy, oleg, ananth, srikar
Cc: peterz, linux-kernel, linuxppc-dev, anton, mingo
In-Reply-To: <20121203150438.7727.74924.stgit@suzukikp>
From: Suzuki K. Poulose <suzuki@in.ibm.com>
External/Decrement exceptions have lower priority than the Debug Exception.
So, we don't have to disable the External interrupts before a single step.
However, on BookE, Critical Input Exception(CE) has higher priority than a
Debug Exception. Hence we mask them.
Signed-off-by: Suzuki K. Poulose <suzuki@in.ibm.com>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Ananth N Mavinakaynahalli <ananth@in.ibm.com>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: linuxppc-dev@ozlabs.org
---
arch/powerpc/kernel/kprobes.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index e88c643..4901b34 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -104,13 +104,13 @@ void __kprobes arch_remove_kprobe(struct kprobe *p)
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
- /* We turn off async exceptions to ensure that the single step will
- * be for the instruction we have the kprobe on, if we dont its
- * possible we'd get the single step reported for an exception handler
- * like Decrementer or External Interrupt */
- regs->msr &= ~MSR_EE;
regs->msr |= MSR_SINGLESTEP;
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ /*
+ * We turn off Critical Input Exception(CE) to ensure that the single
+ * step will be for the instruction we have the probe on; if we don't,
+ * it is possible we'd get the single step reported for CE.
+ */
regs->msr &= ~MSR_CE;
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
#ifdef CONFIG_PPC_47x
^ permalink raw reply related
* [PATCH v2 2/4] powerpc: Move the single step enable code to a generic path
From: Suzuki K. Poulose @ 2012-12-03 15:08 UTC (permalink / raw)
To: bigeasy, oleg, ananth, srikar
Cc: peterz, linux-kernel, linuxppc-dev, anton, mingo
In-Reply-To: <20121203150438.7727.74924.stgit@suzukikp>
From: Suzuki K. Poulose <suzuki@in.ibm.com>
This patch moves the single step enable code used by kprobe to a generic
routine header so that, it can be re-used by other code, in this case,
uprobes. No functional changes.
Signed-off-by: Suzuki K. Poulose <suzuki@in.ibm.com>
Cc: Ananth N Mavinakaynahalli <ananth@in.ibm.com>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: linuxppc-dev@ozlabs.org
---
arch/powerpc/include/asm/probes.h | 25 +++++++++++++++++++++++++
arch/powerpc/kernel/kprobes.c | 21 +--------------------
2 files changed, 26 insertions(+), 20 deletions(-)
diff --git a/arch/powerpc/include/asm/probes.h b/arch/powerpc/include/asm/probes.h
index 5f1e15b..f94a44f 100644
--- a/arch/powerpc/include/asm/probes.h
+++ b/arch/powerpc/include/asm/probes.h
@@ -38,5 +38,30 @@ typedef u32 ppc_opcode_t;
#define is_trap(instr) (IS_TW(instr) || IS_TWI(instr))
#endif /* CONFIG_PPC64 */
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+#define MSR_SINGLESTEP (MSR_DE)
+#else
+#define MSR_SINGLESTEP (MSR_SE)
+#endif
+
+/* Enable single stepping for the current task */
+static inline void enable_single_step(struct pt_regs *regs)
+{
+ regs->msr |= MSR_SINGLESTEP;
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ /*
+ * We turn off Critical Input Exception(CE) to ensure that the single
+ * step will be for the instruction we have the probe on; if we don't,
+ * it is possible we'd get the single step reported for CE.
+ */
+ regs->msr &= ~MSR_CE;
+ mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
+#ifdef CONFIG_PPC_47x
+ isync();
+#endif
+#endif
+}
+
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PROBES_H */
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index 4901b34..92f1be7 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -36,12 +36,6 @@
#include <asm/sstep.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_PPC_ADV_DEBUG_REGS
-#define MSR_SINGLESTEP (MSR_DE)
-#else
-#define MSR_SINGLESTEP (MSR_SE)
-#endif
-
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -104,20 +98,7 @@ void __kprobes arch_remove_kprobe(struct kprobe *p)
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
- regs->msr |= MSR_SINGLESTEP;
-#ifdef CONFIG_PPC_ADV_DEBUG_REGS
- /*
- * We turn off Critical Input Exception(CE) to ensure that the single
- * step will be for the instruction we have the probe on; if we don't,
- * it is possible we'd get the single step reported for CE.
- */
- regs->msr &= ~MSR_CE;
- mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
-#ifdef CONFIG_PPC_47x
- isync();
-#endif
-#endif
-
+ enable_single_step(regs);
/*
* On powerpc we should single step on the original
* instruction even if the probed insn is a trap
^ permalink raw reply related
* Re: [PATCH] KVM: PPC: Make EPCR a valid field for booke64 and bookehv
From: Scott Wood @ 2012-12-03 16:47 UTC (permalink / raw)
To: Alexander Graf
Cc: Mihai Caraman, linuxppc-dev, kvm@vger.kernel.org list, kvm-ppc
In-Reply-To: <1354370305-12344-1-git-send-email-agraf@suse.de>
On 12/01/2012 07:58:25 AM, Alexander Graf wrote:
> In BookE, EPCR is defined and valid when either the HV or the 64bit
> category are implemented. Reflect this in the field definition.
>=20
> Today the only KVM target on 64bit is HV enabled, so there is no
> change in actual source code, but this keeps the code closer to the
> spec and doesn't build up artificial road blocks for a PR KVM
> on 64bit.
[snip]
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
> arch/powerpc/include/asm/kvm_host.h | 9 +++++++--
> 1 files changed, 7 insertions(+), 2 deletions(-)
>=20
> diff --git a/arch/powerpc/include/asm/kvm_host.h =20
> b/arch/powerpc/include/asm/kvm_host.h
> index 62fbd38..3480526 100644
> --- a/arch/powerpc/include/asm/kvm_host.h
> +++ b/arch/powerpc/include/asm/kvm_host.h
> @@ -405,14 +405,19 @@ struct kvm_vcpu_arch {
> #ifdef CONFIG_KVM_BOOKE_HV
> u32 host_mas4;
> u32 host_mas6;
> - u32 shadow_epcr;
> - u32 epcr;
> u32 shadow_msrp;
> u32 eplc;
> u32 epsc;
> u32 oldpir;
> #endif
>=20
> +#if defined(CONFIG_BOOKE)
> +#if defined(CONFIG_KVM_BOOKE_HV) || defined(CONFIG_64BIT)
> + u32 shadow_epcr;
> + u32 epcr;
> +#endif
> +#endif
On a PR-mode implementation, why would we be have a shadow_epcr? It =20
would always be set based on the host kernel, just like when running =20
any other userspace process.
-Scott=
^ permalink raw reply
* RE: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes required by fsl PAMU driver.
From: Sethi Varun-B16395 @ 2012-12-03 16:57 UTC (permalink / raw)
To: Joerg Roedel
Cc: Wood Scott-B07421, iommu@lists.linux-foundation.org,
Tabi Timur-B04825, linuxppc-dev@lists.ozlabs.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20121202140323.GO30633@8bytes.org>
> -----Original Message-----
> From: iommu-bounces@lists.linux-foundation.org [mailto:iommu-
> bounces@lists.linux-foundation.org] On Behalf Of Joerg Roedel
> Sent: Sunday, December 02, 2012 7:33 PM
> To: Sethi Varun-B16395
> Cc: linux-kernel@vger.kernel.org; iommu@lists.linux-foundation.org; Wood
> Scott-B07421; linuxppc-dev@lists.ozlabs.org; Tabi Timur-B04825
> Subject: Re: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes
> required by fsl PAMU driver.
>=20
> Hmm, we need to work out a good abstraction for this.
>=20
> On Tue, Nov 20, 2012 at 07:24:56PM +0530, Varun Sethi wrote:
> > Added the following domain attributes required by FSL PAMU driver:
> > 1. Subwindows field added to the iommu domain geometry attribute.
>=20
> Are the Subwindows mapped with full size or do you map only parts of the
> subwindows?
>=20
[Sethi Varun-B16395] It's possible to map a part of the subwindow i.e. size=
of the mapping can be less than the sub window size.
> > + * This attribute indicates number of DMA subwindows supported by
> > + * the geometry. If there is a single window that maps the entire
> > + * geometry, attribute must be set to "1". A value of "0" implies
> > + * that this mechanism is not used at all(normal paging is used).
> > + * Value other than* "0" or "1" indicates the actual number of
> > + * subwindows.
> > + */
>=20
> This semantic is ugly, how about a feature detection mechanism?
>=20
[Sethi Varun-B16395] A feature mechanism to query the type of IOMMU?
-Varun
^ permalink raw reply
* Re: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes required by fsl PAMU driver.
From: Scott Wood @ 2012-12-03 17:03 UTC (permalink / raw)
To: Sethi Varun-B16395
Cc: Wood Scott-B07421, Joerg Roedel, Tabi Timur-B04825,
linux-kernel@vger.kernel.org, iommu@lists.linux-foundation.org,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <C5ECD7A89D1DC44195F34B25E172658D2B2A51@039-SN2MPN1-013.039d.mgd.msft.net>
On 12/03/2012 10:57:29 AM, Sethi Varun-B16395 wrote:
>=20
>=20
> > -----Original Message-----
> > From: iommu-bounces@lists.linux-foundation.org [mailto:iommu-
> > bounces@lists.linux-foundation.org] On Behalf Of Joerg Roedel
> > Sent: Sunday, December 02, 2012 7:33 PM
> > To: Sethi Varun-B16395
> > Cc: linux-kernel@vger.kernel.org; iommu@lists.linux-foundation.org; =20
> Wood
> > Scott-B07421; linuxppc-dev@lists.ozlabs.org; Tabi Timur-B04825
> > Subject: Re: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes
> > required by fsl PAMU driver.
> >
> > Hmm, we need to work out a good abstraction for this.
> >
> > On Tue, Nov 20, 2012 at 07:24:56PM +0530, Varun Sethi wrote:
> > > Added the following domain attributes required by FSL PAMU driver:
> > > 1. Subwindows field added to the iommu domain geometry attribute.
> >
> > Are the Subwindows mapped with full size or do you map only parts =20
> of the
> > subwindows?
> >
> [Sethi Varun-B16395] It's possible to map a part of the subwindow =20
> i.e. size of the mapping can be less than the sub window size.
>=20
> > > + * This attribute indicates number of DMA subwindows supported =20
> by
> > > + * the geometry. If there is a single window that maps the =20
> entire
> > > + * geometry, attribute must be set to "1". A value of "0" =20
> implies
> > > + * that this mechanism is not used at all(normal paging is =20
> used).
> > > + * Value other than* "0" or "1" indicates the actual number of
> > > + * subwindows.
> > > + */
> >
> > This semantic is ugly, how about a feature detection mechanism?
> >
> [Sethi Varun-B16395] A feature mechanism to query the type of IOMMU?
A feature mechanism to determine whether this subwindow mechanism is =20
available, and what the limits are.
-Scott=
^ permalink raw reply
* Re: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes required by fsl PAMU driver.
From: Joerg Roedel @ 2012-12-03 17:27 UTC (permalink / raw)
To: Sethi Varun-B16395
Cc: Wood Scott-B07421, iommu@lists.linux-foundation.org,
Tabi Timur-B04825, linuxppc-dev@lists.ozlabs.org,
linux-kernel@vger.kernel.org
In-Reply-To: <C5ECD7A89D1DC44195F34B25E172658D2B2A51@039-SN2MPN1-013.039d.mgd.msft.net>
On Mon, Dec 03, 2012 at 04:57:29PM +0000, Sethi Varun-B16395 wrote:
>
>
> > -----Original Message-----
> > From: iommu-bounces@lists.linux-foundation.org [mailto:iommu-
> > bounces@lists.linux-foundation.org] On Behalf Of Joerg Roedel
> > Sent: Sunday, December 02, 2012 7:33 PM
> > To: Sethi Varun-B16395
> > Cc: linux-kernel@vger.kernel.org; iommu@lists.linux-foundation.org; Wood
> > Scott-B07421; linuxppc-dev@lists.ozlabs.org; Tabi Timur-B04825
> > Subject: Re: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes
> > required by fsl PAMU driver.
> >
> > Hmm, we need to work out a good abstraction for this.
> >
> > On Tue, Nov 20, 2012 at 07:24:56PM +0530, Varun Sethi wrote:
> > > Added the following domain attributes required by FSL PAMU driver:
> > > 1. Subwindows field added to the iommu domain geometry attribute.
> >
> > Are the Subwindows mapped with full size or do you map only parts of the
> > subwindows?
> >
> [Sethi Varun-B16395] It's possible to map a part of the subwindow i.e.
> size of the mapping can be less than the sub window size.
Yes, I know that this is possible. But do you plan to support that or is
it sufficient when the whole subwindow is mapped?
Joerg
^ permalink raw reply
* Re: [PATCH 1/2] vfio powerpc: enabled on powernv platform
From: Alex Williamson @ 2012-12-03 17:35 UTC (permalink / raw)
To: Alexey Kardashevskiy
Cc: kvm, linux-kernel, Paul Mackerras, linuxppc-dev, David Gibson
In-Reply-To: <1354503178-2602-2-git-send-email-aik@ozlabs.ru>
On Mon, 2012-12-03 at 13:52 +1100, Alexey Kardashevskiy wrote:
> This patch initializes IOMMU groups based on the IOMMU
> configuration discovered during the PCI scan on POWERNV
> (POWER non virtualized) platform. The IOMMU groups are
> to be used later by VFIO driver (PCI pass through).
>
> It also implements an API for mapping/unmapping pages for
> guest PCI drivers and providing DMA window properties.
> This API is going to be used later by QEMU-VFIO to handle
> h_put_tce hypercalls from the KVM guest.
>
> Although this driver has been tested only on the POWERNV
> platform, it should work on any platform which supports
> TCE tables.
>
> To enable VFIO on POWER, enable SPAPR_TCE_IOMMU config
> option and configure VFIO as required.
>
> Cc: David Gibson <david@gibson.dropbear.id.au>
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/include/asm/iommu.h | 9 ++
> arch/powerpc/kernel/iommu.c | 186 ++++++++++++++++++++++++++++++++++
> arch/powerpc/platforms/powernv/pci.c | 135 ++++++++++++++++++++++++
> drivers/iommu/Kconfig | 8 ++
> 4 files changed, 338 insertions(+)
>
> diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
> index cbfe678..5c7087a 100644
> --- a/arch/powerpc/include/asm/iommu.h
> +++ b/arch/powerpc/include/asm/iommu.h
> @@ -76,6 +76,9 @@ struct iommu_table {
> struct iommu_pool large_pool;
> struct iommu_pool pools[IOMMU_NR_POOLS];
> unsigned long *it_map; /* A simple allocation bitmap for now */
> +#ifdef CONFIG_IOMMU_API
> + struct iommu_group *it_group;
> +#endif
> };
>
> struct scatterlist;
> @@ -147,5 +150,11 @@ static inline void iommu_restore(void)
> }
> #endif
>
> +extern long iommu_clear_tces(struct iommu_table *tbl, unsigned long entry,
> + unsigned long pages);
> +extern long iommu_put_tces(struct iommu_table *tbl, unsigned long entry,
> + uint64_t tce, enum dma_data_direction direction,
> + unsigned long pages);
> +
> #endif /* __KERNEL__ */
> #endif /* _ASM_IOMMU_H */
> diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
> index ff5a6ce..2738aa4 100644
> --- a/arch/powerpc/kernel/iommu.c
> +++ b/arch/powerpc/kernel/iommu.c
> @@ -44,6 +44,7 @@
> #include <asm/kdump.h>
> #include <asm/fadump.h>
> #include <asm/vio.h>
> +#include <asm/tce.h>
>
> #define DBG(...)
>
> @@ -856,3 +857,188 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
> free_pages((unsigned long)vaddr, get_order(size));
> }
> }
> +
> +#ifdef CONFIG_IOMMU_API
> +/*
> + * SPAPR TCE API
> + */
> +
> +/*
> + * Returns the number of used IOMMU pages (4K) within
> + * the same system page (4K or 64K).
> + * bitmap_weight is not used as it does not support bigendian maps.
> + */
> +static int syspage_weight(unsigned long *map, unsigned long entry)
> +{
> + int ret = 0, nbits = PAGE_SIZE/IOMMU_PAGE_SIZE;
> +
> + /* Aligns TCE entry number to system page boundary */
> + entry &= PAGE_MASK >> IOMMU_PAGE_SHIFT;
> +
> + /* Count used 4K pages */
> + while (nbits--)
> + ret += (test_bit(entry++, map) == 0) ? 0 : 1;
> +
> + return ret;
> +}
> +
> +static void tce_flush(struct iommu_table *tbl)
> +{
> + /* Flush/invalidate TLB caches if necessary */
> + if (ppc_md.tce_flush)
> + ppc_md.tce_flush(tbl);
> +
> + /* Make sure updates are seen by hardware */
> + mb();
> +}
> +
> +/*
> + * iommu_clear_tces clears tces and returned the number of system pages
> + * which it called put_page() on
> + */
> +static long clear_tces_nolock(struct iommu_table *tbl, unsigned long entry,
> + unsigned long pages)
> +{
> + int i, retpages = 0;
> + unsigned long oldtce, oldweight;
> + struct page *page;
> +
> + for (i = 0; i < pages; ++i) {
> + oldtce = ppc_md.tce_get(tbl, entry + i);
> + ppc_md.tce_free(tbl, entry + i, 1);
> +
> + oldweight = syspage_weight(tbl->it_map, entry);
> + __clear_bit(entry - tbl->it_offset, tbl->it_map);
> +
> + if (!(oldtce & (TCE_PCI_WRITE | TCE_PCI_READ)))
> + continue;
Could this happen earlier, above syspage_weight() and __clear_bit()?
> +
> + page = pfn_to_page(oldtce >> PAGE_SHIFT);
> +
> + WARN_ON(!page);
> + if (!page)
> + continue;
> +
> + if (oldtce & TCE_PCI_WRITE)
> + SetPageDirty(page);
> +
> + put_page(page);
> +
> + /* That was the last IOMMU page within the system page */
> + if ((oldweight == 1) && !syspage_weight(tbl->it_map, entry))
> + ++retpages;
If you used __test_and_clear_bit() above I think you could avoid this
2nd call to syspage_weight. A minor optimization though.
> + }
> +
> + return retpages;
> +}
> +
> +/*
> + * iommu_clear_tces clears tces and returned the number
> + / of released system pages
> + */
Something bad happened to your comments here.
> +long iommu_clear_tces(struct iommu_table *tbl, unsigned long entry,
> + unsigned long pages)
> +{
> + int ret;
> + struct iommu_pool *pool = get_pool(tbl, entry);
> +
> + spin_lock(&(pool->lock));
> + ret = clear_tces_nolock(tbl, entry, pages);
> + tce_flush(tbl);
> + spin_unlock(&(pool->lock));
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(iommu_clear_tces);
> +
> +static int put_tce(struct iommu_table *tbl, unsigned long entry,
> + uint64_t tce, enum dma_data_direction direction)
> +{
> + int ret;
> + struct page *page = NULL;
> + unsigned long kva, offset, oldweight;
> +
> + /* Map new TCE */
> + offset = (tce & IOMMU_PAGE_MASK) - (tce & PAGE_MASK);
Maybe the compiler will figure this out, but isn't this the same as tce
& (IOMMU_PAGE_MASK & PAGE_MASK)?
> + ret = get_user_pages_fast(tce & PAGE_MASK, 1,
> + direction != DMA_TO_DEVICE, &page);
> + if (ret < 1) {
Probably (ret != 1) here or else we never get to your >1 case below.
> + printk(KERN_ERR "tce_vfio: get_user_pages_fast failed tce=%llx ioba=%lx ret=%d\n",
> + tce, entry << IOMMU_PAGE_SHIFT, ret);
Use pr_err
> + if (!ret || (ret > 1))
Then (ret >= 0) here. Or return (ret >= 0) ? -EFAULT : ret
> + ret = -EFAULT;
> + return ret;
> + }
You're missing the code from x86 that handles mapping mmap'd ranges.
This is intended to allow peer-to-peer DMA between devices. Is that
intentional?
> +
> + kva = (unsigned long) page_address(page);
> + kva += offset;
> +
> + /* tce_build receives a virtual address */
> + entry += tbl->it_offset; /* Offset into real TCE table */
Here's what makes me call the entry "relative" rather than zero-based.
The iova is relative to the start of dma32_window_start, ie. if the
window starts at bus address 512MB and I want to create a translation at
bus address 512MB, I pass in an iova of 0, right? The above adds the
window offset. So you've removed dma64 window, but we really need to
define iova better.
> + ret = ppc_md.tce_build(tbl, entry, 1, kva, direction, NULL);
> +
> + /* tce_build() only returns non-zero for transient errors */
> + if (unlikely(ret)) {
> + printk(KERN_ERR "tce_vfio: tce_put failed on tce=%llx ioba=%lx kva=%lx ret=%d\n",
> + tce, entry << IOMMU_PAGE_SHIFT, kva, ret);
Use pr_err
> + put_page(page);
> + return -EIO;
> + }
> +
> + /* Calculate if new system page has been locked */
> + oldweight = syspage_weight(tbl->it_map, entry);
> + __set_bit(entry - tbl->it_offset, tbl->it_map);
> +
> + return (oldweight == 0) ? 1 : 0;
> +}
> +
> +/*
> + * iommu_put_tces builds tces and returned the number of actually
> + * locked system pages
> + */
> +long iommu_put_tces(struct iommu_table *tbl, unsigned long entry,
> + uint64_t tce, enum dma_data_direction direction,
> + unsigned long pages)
> +{
> + int i, ret = 0, retpages = 0;
> + struct iommu_pool *pool = get_pool(tbl, entry);
> +
> + BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE);
> + BUG_ON(direction == DMA_NONE);
This doesn't seem BUG worthy, -EINVAL? We can't assume tce_iommu_ioctl
will always be the only caller of this function.
> +
> + spin_lock(&(pool->lock));
> +
> + /* Check if any is in use */
> + for (i = 0; i < pages; ++i) {
> + unsigned long oldtce = ppc_md.tce_get(tbl, entry + i);
> + if ((oldtce & (TCE_PCI_WRITE | TCE_PCI_READ)) ||
> + test_bit(entry + i, tbl->it_map)) {
> + WARN_ON(test_bit(entry + i, tbl->it_map));
The WARN_ON seems to confirm that these are redundant tests, does that
imply we don't trust it_map? It would be a lot faster if we could rely
on it_map exclusively here.
> + spin_unlock(&(pool->lock));
> + return -EBUSY;
> + }
> + }
> +
> + /* Put tces to the table */
> + for (i = 0; (i < pages) && (ret >= 0); ++i, tce += IOMMU_PAGE_SIZE) {
> + ret = put_tce(tbl, entry + i, tce, direction);
> + if (ret == 1)
> + ++retpages;
> + }
> +
> + /*
> + * If failed, release locked pages, otherwise return the number
> + * of locked system pages
> + */
> + if (ret < 0)
> + clear_tces_nolock(tbl, entry, i);
> + else
> + ret = retpages;
> +
> + tce_flush(tbl);
> + spin_unlock(&(pool->lock));
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(iommu_put_tces);
> +#endif /* CONFIG_IOMMU_API */
> diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
> index 05205cf..21250ef 100644
> --- a/arch/powerpc/platforms/powernv/pci.c
> +++ b/arch/powerpc/platforms/powernv/pci.c
> @@ -20,6 +20,7 @@
> #include <linux/irq.h>
> #include <linux/io.h>
> #include <linux/msi.h>
> +#include <linux/iommu.h>
>
> #include <asm/sections.h>
> #include <asm/io.h>
> @@ -613,3 +614,137 @@ void __init pnv_pci_init(void)
> ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs;
> #endif
> }
> +
> +#ifdef CONFIG_IOMMU_API
> +/*
> + * IOMMU groups support required by VFIO
> + */
> +static int add_device(struct device *dev)
> +{
> + struct iommu_table *tbl;
> + int ret = 0;
> +
> + if (WARN_ON(dev->iommu_group)) {
> + printk(KERN_WARNING "tce_vfio: device %s is already in iommu group %d, skipping\n",
> + dev_name(dev),
> + iommu_group_id(dev->iommu_group));
Use pr_warn
> + return -EBUSY;
> + }
> +
> + tbl = get_iommu_table_base(dev);
> + if (!tbl) {
> + pr_debug("tce_vfio: skipping device %s with no tbl\n",
> + dev_name(dev));
> + return 0;
> + }
> +
> + pr_debug("tce_vfio: adding %s to iommu group %d\n",
> + dev_name(dev), iommu_group_id(tbl->it_group));
> +
> + ret = iommu_group_add_device(tbl->it_group, dev);
> + if (ret < 0)
> + printk(KERN_ERR "tce_vfio: %s has not been added, ret=%d\n",
> + dev_name(dev), ret);
Use pr_err
> +
> + return ret;
> +}
> +
> +static void del_device(struct device *dev)
> +{
> + iommu_group_remove_device(dev);
> +}
> +
> +static int iommu_bus_notifier(struct notifier_block *nb,
> + unsigned long action, void *data)
> +{
> + struct device *dev = data;
> +
> + switch (action) {
> + case BUS_NOTIFY_ADD_DEVICE:
> + return add_device(dev);
> + case BUS_NOTIFY_DEL_DEVICE:
> + del_device(dev);
> + return 0;
> + default:
> + return 0;
> + }
> +}
> +
> +static struct notifier_block tce_iommu_bus_nb = {
> + .notifier_call = iommu_bus_notifier,
> +};
> +
> +static void group_release(void *iommu_data)
> +{
> + struct iommu_table *tbl = iommu_data;
> + tbl->it_group = NULL;
> +}
> +
> +static int __init tce_iommu_init(void)
> +{
> + struct pci_dev *pdev = NULL;
> + struct iommu_table *tbl;
> + struct iommu_group *grp;
> +
> + /* Allocate and initialize IOMMU groups */
> + for_each_pci_dev(pdev) {
> + tbl = get_iommu_table_base(&pdev->dev);
> + if (!tbl)
> + continue;
> +
> + /* Skip already initialized */
> + if (tbl->it_group)
> + continue;
> +
> + grp = iommu_group_alloc();
> + if (IS_ERR(grp)) {
> + printk(KERN_INFO "tce_vfio: cannot create "
> + "new IOMMU group, ret=%ld\n",
> + PTR_ERR(grp));
Use pr_info
> + return PTR_ERR(grp);
> + }
> + tbl->it_group = grp;
> + iommu_group_set_iommudata(grp, tbl, group_release);
> + }
> +
> + bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
> +
> + /* Add PCI devices to VFIO groups */
> + for_each_pci_dev(pdev)
> + add_device(&pdev->dev);
> +
> + return 0;
> +}
> +
> +static void __exit tce_iommu_cleanup(void)
> +{
> + struct pci_dev *pdev = NULL;
> + struct iommu_table *tbl;
> + struct iommu_group *grp = NULL;
> +
> + bus_unregister_notifier(&pci_bus_type, &tce_iommu_bus_nb);
> +
> + /* Delete PCI devices from VFIO groups */
> + for_each_pci_dev(pdev)
> + del_device(&pdev->dev);
> +
> + /* Release VFIO groups */
> + for_each_pci_dev(pdev) {
> + tbl = get_iommu_table_base(&pdev->dev);
> + if (!tbl)
> + continue;
> + grp = tbl->it_group;
> +
> + /* Skip (already) uninitialized */
> + if (!grp)
> + continue;
> +
> + /* Do actual release, group_release() is expected to work */
> + iommu_group_put(grp);
> + BUG_ON(tbl->it_group);
> + }
> +}
> +
> +module_init(tce_iommu_init);
> +module_exit(tce_iommu_cleanup);
> +#endif /* CONFIG_IOMMU_API */
> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> index 9f69b56..29d11dc 100644
> --- a/drivers/iommu/Kconfig
> +++ b/drivers/iommu/Kconfig
> @@ -187,4 +187,12 @@ config EXYNOS_IOMMU_DEBUG
>
> Say N unless you need kernel log message for IOMMU debugging
>
> +config SPAPR_TCE_IOMMU
> + bool "sPAPR TCE IOMMU Support"
> + depends on PPC_POWERNV
> + select IOMMU_API
> + help
> + Enables bits of IOMMU API required by VFIO. The iommu_ops is
> + still not implemented.
> +
> endif # IOMMU_SUPPORT
Thanks,
Alex
^ permalink raw reply
* Re: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes required by fsl PAMU driver.
From: Scott Wood @ 2012-12-03 17:36 UTC (permalink / raw)
To: Joerg Roedel
Cc: Wood Scott-B07421, Tabi Timur-B04825,
linux-kernel@vger.kernel.org, iommu@lists.linux-foundation.org,
Sethi Varun-B16395, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20121203172712.GA18368@8bytes.org>
On 12/03/2012 11:27:12 AM, Joerg Roedel wrote:
> On Mon, Dec 03, 2012 at 04:57:29PM +0000, Sethi Varun-B16395 wrote:
> >
> >
> > > -----Original Message-----
> > > From: iommu-bounces@lists.linux-foundation.org [mailto:iommu-
> > > bounces@lists.linux-foundation.org] On Behalf Of Joerg Roedel
> > > Sent: Sunday, December 02, 2012 7:33 PM
> > > To: Sethi Varun-B16395
> > > Cc: linux-kernel@vger.kernel.org; =20
> iommu@lists.linux-foundation.org; Wood
> > > Scott-B07421; linuxppc-dev@lists.ozlabs.org; Tabi Timur-B04825
> > > Subject: Re: [PATCH 3/4 v5] iommu/fsl: Add iommu domain attributes
> > > required by fsl PAMU driver.
> > >
> > > Hmm, we need to work out a good abstraction for this.
> > >
> > > On Tue, Nov 20, 2012 at 07:24:56PM +0530, Varun Sethi wrote:
> > > > Added the following domain attributes required by FSL PAMU =20
> driver:
> > > > 1. Subwindows field added to the iommu domain geometry =20
> attribute.
> > >
> > > Are the Subwindows mapped with full size or do you map only parts =20
> of the
> > > subwindows?
> > >
> > [Sethi Varun-B16395] It's possible to map a part of the subwindow =20
> i.e.
> > size of the mapping can be less than the sub window size.
>=20
> Yes, I know that this is possible. But do you plan to support that or =20
> is
> it sufficient when the whole subwindow is mapped?
We do plan to support that.
-Scott=
^ permalink raw reply
* Re: [PATCH] KVM: PPC: Make EPCR a valid field for booke64 and bookehv
From: Alexander Graf @ 2012-12-03 17:38 UTC (permalink / raw)
To: Scott Wood; +Cc: Mihai Caraman, linuxppc-dev, kvm@vger.kernel.org list, kvm-ppc
In-Reply-To: <1354553228.2960.4@snotra>
On 03.12.2012, at 17:47, Scott Wood wrote:
> On 12/01/2012 07:58:25 AM, Alexander Graf wrote:
>> In BookE, EPCR is defined and valid when either the HV or the 64bit
>> category are implemented. Reflect this in the field definition.
>> Today the only KVM target on 64bit is HV enabled, so there is no
>> change in actual source code, but this keeps the code closer to the
>> spec and doesn't build up artificial road blocks for a PR KVM
>> on 64bit.
> [snip]
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> ---
>> arch/powerpc/include/asm/kvm_host.h | 9 +++++++--
>> 1 files changed, 7 insertions(+), 2 deletions(-)
>> diff --git a/arch/powerpc/include/asm/kvm_host.h =
b/arch/powerpc/include/asm/kvm_host.h
>> index 62fbd38..3480526 100644
>> --- a/arch/powerpc/include/asm/kvm_host.h
>> +++ b/arch/powerpc/include/asm/kvm_host.h
>> @@ -405,14 +405,19 @@ struct kvm_vcpu_arch {
>> #ifdef CONFIG_KVM_BOOKE_HV
>> u32 host_mas4;
>> u32 host_mas6;
>> - u32 shadow_epcr;
>> - u32 epcr;
>> u32 shadow_msrp;
>> u32 eplc;
>> u32 epsc;
>> u32 oldpir;
>> #endif
>> +#if defined(CONFIG_BOOKE)
>> +#if defined(CONFIG_KVM_BOOKE_HV) || defined(CONFIG_64BIT)
>> + u32 shadow_epcr;
>> + u32 epcr;
>> +#endif
>> +#endif
>=20
> On a PR-mode implementation, why would we be have a shadow_epcr? It =
would always be set based on the host kernel, just like when running any =
other userspace process.
Right - we could simply set MSR_CM. I'll move shadow_epcr back into the =
HV only bit above.
Alex
^ permalink raw reply
* Re: [PATCH 2/2] vfio powerpc: implemented IOMMU driver for VFIO
From: Alex Williamson @ 2012-12-03 17:53 UTC (permalink / raw)
To: Alexey Kardashevskiy
Cc: kvm, linux-kernel, Paul Mackerras, linuxppc-dev, David Gibson
In-Reply-To: <1354503178-2602-3-git-send-email-aik@ozlabs.ru>
On Mon, 2012-12-03 at 13:52 +1100, Alexey Kardashevskiy wrote:
> VFIO implements platform independent stuff such as
> a PCI driver, BAR access (via read/write on a file descriptor
> or direct mapping when possible) and IRQ signaling.
>
> The platform dependent part includes IOMMU initialization
> and handling. This patch implements an IOMMU driver for VFIO
> which does mapping/unmapping pages for the guest IO and
> provides information about DMA window (required by a POWERPC
> guest).
>
> The counterpart in QEMU is required to support this functionality.
>
> Cc: David Gibson <david@gibson.dropbear.id.au>
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> drivers/vfio/Kconfig | 6 +
> drivers/vfio/Makefile | 1 +
> drivers/vfio/vfio_iommu_spapr_tce.c | 350 +++++++++++++++++++++++++++++++++++
> include/linux/vfio.h | 26 +++
> 4 files changed, 383 insertions(+)
> create mode 100644 drivers/vfio/vfio_iommu_spapr_tce.c
>
> diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
> index 7cd5dec..b464687 100644
> --- a/drivers/vfio/Kconfig
> +++ b/drivers/vfio/Kconfig
> @@ -3,10 +3,16 @@ config VFIO_IOMMU_TYPE1
> depends on VFIO
> default n
>
> +config VFIO_IOMMU_SPAPR_TCE
> + tristate
> + depends on VFIO && SPAPR_TCE_IOMMU
> + default n
> +
> menuconfig VFIO
> tristate "VFIO Non-Privileged userspace driver framework"
> depends on IOMMU_API
> select VFIO_IOMMU_TYPE1 if X86
> + select VFIO_IOMMU_SPAPR_TCE if PPC_POWERNV
> help
> VFIO provides a framework for secure userspace device drivers.
> See Documentation/vfio.txt for more details.
> diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
> index 2398d4a..72bfabc 100644
> --- a/drivers/vfio/Makefile
> +++ b/drivers/vfio/Makefile
> @@ -1,3 +1,4 @@
> obj-$(CONFIG_VFIO) += vfio.o
> obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
> +obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
> obj-$(CONFIG_VFIO_PCI) += pci/
> diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
> new file mode 100644
> index 0000000..806ad9f
> --- /dev/null
> +++ b/drivers/vfio/vfio_iommu_spapr_tce.c
> @@ -0,0 +1,350 @@
> +/*
> + * VFIO: IOMMU DMA mapping support for TCE on POWER
> + *
> + * Copyright (C) 2012 IBM Corp. All rights reserved.
> + * Author: Alexey Kardashevskiy <aik@ozlabs.ru>
> + *
> + * 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.
> + *
> + * Derived from original vfio_iommu_type1.c:
> + * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
> + * Author: Alex Williamson <alex.williamson@redhat.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +#include <linux/err.h>
> +#include <linux/vfio.h>
> +#include <asm/iommu.h>
> +
> +#define DRIVER_VERSION "0.1"
> +#define DRIVER_AUTHOR "aik@ozlabs.ru"
> +#define DRIVER_DESC "VFIO IOMMU SPAPR TCE"
> +
> +static void tce_iommu_detach_group(void *iommu_data,
> + struct iommu_group *iommu_group);
> +
> +/*
> + * VFIO IOMMU fd for SPAPR_TCE IOMMU implementation
> + */
> +
> +/*
> + * This code handles mapping and unmapping of user data buffers
> + * into DMA'ble space using the IOMMU
> + */
> +
> +#define NPAGE_TO_SIZE(npage) ((size_t)(npage) << PAGE_SHIFT)
> +
> +struct vwork {
> + struct mm_struct *mm;
> + long npage;
> + struct work_struct work;
> +};
> +
> +/* delayed decrement/increment for locked_vm */
> +static void lock_acct_bg(struct work_struct *work)
> +{
> + struct vwork *vwork = container_of(work, struct vwork, work);
> + struct mm_struct *mm;
> +
> + mm = vwork->mm;
> + down_write(&mm->mmap_sem);
> + mm->locked_vm += vwork->npage;
> + up_write(&mm->mmap_sem);
> + mmput(mm);
> + kfree(vwork);
> +}
> +
> +static void lock_acct(long npage)
> +{
> + struct vwork *vwork;
> + struct mm_struct *mm;
> +
> + if (!current->mm)
> + return; /* process exited */
> +
> + if (down_write_trylock(¤t->mm->mmap_sem)) {
> + current->mm->locked_vm += npage;
> + up_write(¤t->mm->mmap_sem);
> + return;
> + }
> +
> + /*
> + * Couldn't get mmap_sem lock, so must setup to update
> + * mm->locked_vm later. If locked_vm were atomic, we
> + * wouldn't need this silliness
> + */
> + vwork = kmalloc(sizeof(struct vwork), GFP_KERNEL);
> + if (!vwork)
> + return;
> + mm = get_task_mm(current);
> + if (!mm) {
> + kfree(vwork);
> + return;
> + }
> + INIT_WORK(&vwork->work, lock_acct_bg);
> + vwork->mm = mm;
> + vwork->npage = npage;
> + schedule_work(&vwork->work);
> +}
> +
> +/*
> + * The container descriptor supports only a single group per container.
> + * Required by the API as the container is not supplied with the IOMMU group
> + * at the moment of initialization.
> + */
> +struct tce_container {
> + struct mutex lock;
> + struct iommu_table *tbl;
> +};
> +
> +static void *tce_iommu_open(unsigned long arg)
> +{
> + struct tce_container *container;
> +
> + if (arg != VFIO_SPAPR_TCE_IOMMU) {
> + pr_err("tce_vfio: Wrong IOMMU type\n");
> + return ERR_PTR(-EINVAL);
> + }
> +
> + container = kzalloc(sizeof(*container), GFP_KERNEL);
> + if (!container)
> + return ERR_PTR(-ENOMEM);
> +
> + mutex_init(&container->lock);
> +
> + return container;
> +}
> +
> +static void tce_iommu_release(void *iommu_data)
> +{
> + struct tce_container *container = iommu_data;
> +
> + WARN_ON(container->tbl && !container->tbl->it_group);
> + if (container->tbl && container->tbl->it_group)
> + tce_iommu_detach_group(iommu_data, container->tbl->it_group);
> +
> + mutex_destroy(&container->lock);
> +
> + kfree(container);
> +}
> +
> +static long tce_iommu_ioctl(void *iommu_data,
> + unsigned int cmd, unsigned long arg)
> +{
> + struct tce_container *container = iommu_data;
> + unsigned long minsz;
> + long ret;
> +
> + switch (cmd) {
> + case VFIO_CHECK_EXTENSION: {
> + return (arg == VFIO_SPAPR_TCE_IOMMU) ? 1 : 0;
> + }
nit, {}s are unnecessary for this case
> + case VFIO_IOMMU_SPAPR_TCE_GET_INFO: {
> + struct vfio_iommu_spapr_tce_info info;
> + struct iommu_table *tbl = container->tbl;
> +
> + if (WARN_ON(!tbl))
> + return -ENXIO;
> +
> + minsz = offsetofend(struct vfio_iommu_spapr_tce_info,
> + dma32_window_size);
> +
> + if (copy_from_user(&info, (void __user *)arg, minsz))
> + return -EFAULT;
> +
> + if (info.argsz < minsz)
> + return -EINVAL;
> +
> + info.dma32_window_start = tbl->it_offset << IOMMU_PAGE_SHIFT;
> + info.dma32_window_size = tbl->it_size << IOMMU_PAGE_SHIFT;
> + info.flags = 0;
> +
> + if (copy_to_user((void __user *)arg, &info, minsz))
> + return -EFAULT;
> +
> + return 0;
> + }
> + case VFIO_IOMMU_MAP_DMA: {
> + vfio_iommu_spapr_tce_dma_map param;
> + struct iommu_table *tbl = container->tbl;
> + enum dma_data_direction direction;
> + unsigned long locked, lock_limit;
> +
> + if (WARN_ON(!tbl))
> + return -ENXIO;
> +
> + minsz = offsetofend(vfio_iommu_spapr_tce_dma_map, size);
> +
> + if (copy_from_user(¶m, (void __user *)arg, minsz))
> + return -EFAULT;
> +
> + if (param.argsz < minsz)
> + return -EINVAL;
> +
> + if ((param.flags & VFIO_DMA_MAP_FLAG_READ) &&
> + (param.flags & VFIO_DMA_MAP_FLAG_WRITE))
> + direction = DMA_BIDIRECTIONAL;
> + else if (param.flags & VFIO_DMA_MAP_FLAG_READ)
> + direction = DMA_TO_DEVICE;
> + else if (param.flags & VFIO_DMA_MAP_FLAG_WRITE)
> + direction = DMA_FROM_DEVICE;
> + else
> + return -EINVAL;
> +
> + if ((param.size & ~IOMMU_PAGE_MASK) ||
> + (param.iova & ~IOMMU_PAGE_MASK) ||
> + (param.vaddr & ~IOMMU_PAGE_MASK))
> + return -EINVAL;
> +
> + if ((param.iova + param.size) >
> + (tbl->it_size << IOMMU_PAGE_SHIFT))
> + return -EINVAL;
> +
> + if (param.iova < (tbl->it_offset << IOMMU_PAGE_SHIFT))
> + return -EINVAL;
This is confusing me, in 1/2 we had:
entry += tbl->it_offset; /* Offset into real TCE table */
Which implies to me that entry is relative to it_offset. So I'm not
sure how iova can be less than it_offset (it's u64, so it can't be
negative). If iova is not relative then the iova + size > it_size
doesn't make any sense. Looks like you have a few extra ()s in these
too. Same for unmap case below.
> +
> + /* Account for locked pages */
> + locked = current->mm->locked_vm +
> + (param.size >> PAGE_SHIFT);
> + lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
> + if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
> + pr_warn("RLIMIT_MEMLOCK (%ld) exceeded\n",
> + rlimit(RLIMIT_MEMLOCK));
> + return -ENOMEM;
> + }
> +
> + ret = iommu_put_tces(tbl, param.iova >> IOMMU_PAGE_SHIFT,
> + param.vaddr, direction,
> + param.size >> IOMMU_PAGE_SHIFT);
> +
> + if (ret > 0)
> + lock_acct(ret);
> +
> + return ret;
> + }
> + case VFIO_IOMMU_UNMAP_DMA: {
> + vfio_iommu_spapr_tce_dma_unmap param;
> + struct iommu_table *tbl = container->tbl;
> +
> + if (WARN_ON(!tbl))
> + return -ENXIO;
> +
> + minsz = offsetofend(vfio_iommu_spapr_tce_dma_unmap, size);
> +
> + if (copy_from_user(¶m, (void __user *)arg, minsz))
> + return -EFAULT;
> +
> + if (param.argsz < minsz)
> + return -EINVAL;
> +
> + if ((param.size & ~IOMMU_PAGE_MASK) ||
> + (param.iova & ~IOMMU_PAGE_MASK))
> + return -EINVAL;
> +
> + if ((param.iova + param.size) >
> + (tbl->it_size << IOMMU_PAGE_SHIFT))
> + return -EINVAL;
> +
> + if (param.iova < (tbl->it_offset << IOMMU_PAGE_SHIFT))
> + return -EINVAL;
> +
> + ret = iommu_clear_tces(tbl, param.iova >> IOMMU_PAGE_SHIFT,
> + param.size >> IOMMU_PAGE_SHIFT);
> +
> + if (ret > 0)
> + lock_acct(-ret);
> +
> + return ret;
> + }
> + default:
> + pr_warn("tce_vfio: unexpected cmd %x\n", cmd);
> + }
> +
> + return -ENOTTY;
> +}
> +
> +static int tce_iommu_attach_group(void *iommu_data,
> + struct iommu_group *iommu_group)
> +{
> + struct tce_container *container = iommu_data;
> + struct iommu_table *tbl = iommu_group_get_iommudata(iommu_group);
> +
> + BUG_ON(!tbl);
> + mutex_lock(&container->lock);
> + pr_debug("tce_vfio: Attaching group #%u to iommu %p\n",
> + iommu_group_id(iommu_group), iommu_group);
> + if (container->tbl) {
> + pr_warn("tce_vfio: Only one group per IOMMU container is allowed, existing id=%d, attaching id=%d\n",
> + iommu_group_id(container->tbl->it_group),
> + iommu_group_id(iommu_group));
> + mutex_unlock(&container->lock);
> + return -EBUSY;
> + }
> +
> + container->tbl = tbl;
> + iommu_clear_tces(tbl, tbl->it_offset, tbl->it_size);
> + mutex_unlock(&container->lock);
> +
> + return 0;
> +}
> +
> +static void tce_iommu_detach_group(void *iommu_data,
> + struct iommu_group *iommu_group)
> +{
> + struct tce_container *container = iommu_data;
> + struct iommu_table *tbl = iommu_group_get_iommudata(iommu_group);
> +
> + BUG_ON(!tbl);
> + mutex_lock(&container->lock);
> + if (tbl != container->tbl) {
> + pr_warn("tce_vfio: detaching group #%u, expected group is #%u\n",
> + iommu_group_id(iommu_group),
> + iommu_group_id(tbl->it_group));
> + } else {
> +
> + pr_debug("tce_vfio: detaching group #%u from iommu %p\n",
> + iommu_group_id(iommu_group), iommu_group);
> +
> + iommu_clear_tces(tbl, tbl->it_offset, tbl->it_size);
> + container->tbl = NULL;
> + /* Restore reserve for page 0 */
> + if (tbl->it_offset == 0)
> + set_bit(0, tbl->it_map);
> +
> + }
> + mutex_unlock(&container->lock);
> +}
> +
> +const struct vfio_iommu_driver_ops tce_iommu_driver_ops = {
> + .name = "iommu-vfio-powerpc",
> + .owner = THIS_MODULE,
> + .open = tce_iommu_open,
> + .release = tce_iommu_release,
> + .ioctl = tce_iommu_ioctl,
> + .attach_group = tce_iommu_attach_group,
> + .detach_group = tce_iommu_detach_group,
> +};
> +
> +static int __init tce_iommu_init(void)
> +{
> + return vfio_register_iommu_driver(&tce_iommu_driver_ops);
> +}
> +
> +static void __exit tce_iommu_cleanup(void)
> +{
> + vfio_unregister_iommu_driver(&tce_iommu_driver_ops);
> +}
> +
> +module_init(tce_iommu_init);
> +module_exit(tce_iommu_cleanup);
> +
> +MODULE_VERSION(DRIVER_VERSION);
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +
> diff --git a/include/linux/vfio.h b/include/linux/vfio.h
> index 0a4f180..a12295c 100644
> --- a/include/linux/vfio.h
> +++ b/include/linux/vfio.h
> @@ -99,6 +99,7 @@ extern void vfio_unregister_iommu_driver(
> /* Extensions */
>
> #define VFIO_TYPE1_IOMMU 1
> +#define VFIO_SPAPR_TCE_IOMMU 2
>
> /*
> * The IOCTL interface is designed for extensibility by embedding the
> @@ -442,4 +443,29 @@ struct vfio_iommu_type1_dma_unmap {
>
> #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)
>
> +/* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */
> +
> +/*
> + * The SPAPR TCE info struct provides the information about the PCI bus
> + * address ranges available for DMA, these values are programmed into
> + * the hardware so the guest has to know that information.
> + *
> + * The IOMMU page size is always 4K.
> + */
> +
> +struct vfio_iommu_spapr_tce_info {
> + __u32 argsz;
> + __u32 flags; /* reserved for future use */
> + __u32 dma32_window_start; /* 32 bit window start (bytes) */
> + __u32 dma32_window_size; /* 32 bit window size (bytes) */
> +};
> +
> +#define VFIO_IOMMU_SPAPR_TCE_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12)
> +
> +/* Reuse type1 map/unmap structs as they are the same at the moment */
> +typedef struct vfio_iommu_type1_dma_map vfio_iommu_spapr_tce_dma_map;
> +typedef struct vfio_iommu_type1_dma_unmap vfio_iommu_spapr_tce_dma_unmap;
One or both of us are still confused whether iova passed via these
structures are absolute or relative, so let's add some documentation for
that. Thanks,
Alex
> +
> +/* ***************************************************************** */
> +
> #endif /* VFIO_H */
^ 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