* [PATCH 2/2] iommu/core: split mapping to page sizes as
From: Ohad Ben-Cohen @ 2011-10-10 21:50 UTC (permalink / raw)
To: linux-arm-kernel
supported by the hardware
When mapping a memory region, split it to page sizes as supported
by the iommu hardware. Always prefer bigger pages, when possible,
in order to reduce the TLB pressure.
The logic to do that is now added to the IOMMU core, so neither the iommu
drivers themselves nor users of the IOMMU API have to duplicate it.
This allows a more lenient granularity of mappings; traditionally the
IOMMU API took 'order' (of a page) as a mapping size, and directly let
the low level iommu drivers handle the mapping, but now that the IOMMU
core can split arbitrary memory regions into pages, we can remove this
limitation, so users don't have to split those regions by themselves.
Currently the supported page sizes are advertised once and they then
remain static. That works well for OMAP and MSM but it would probably
not fly well with intel's hardware, where the page size capabilities
seem to have the potential to be different between several DMA
remapping devices.
register_iommu() currently sets a default pgsize behavior, so we can convert
the IOMMU drivers in subsequent patches. After all the drivers
are converted, the temporary default settings will be removed.
Mainline users of the IOMMU API (kvm and omap-iovmm) are adopted
to deal with bytes instead of page order.
Many thanks to Joerg Roedel <Joerg.Roedel@amd.com> for significant review!
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: David Brown <davidb@codeaurora.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Joerg Roedel <Joerg.Roedel@amd.com>
Cc: Stepan Moskovchenko <stepanm@codeaurora.org>
Cc: KyongHo Cho <pullip.cho@samsung.com>
Cc: Hiroshi DOYU <hdoyu@nvidia.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: kvm at vger.kernel.org
---
drivers/iommu/iommu.c | 112 +++++++++++++++++++++++++++++++++++++++----
drivers/iommu/omap-iovmm.c | 17 ++----
include/linux/iommu.h | 24 ++++++++-
virt/kvm/iommu.c | 8 ++--
4 files changed, 132 insertions(+), 29 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 5d042e8..9355632 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -16,6 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/bug.h>
@@ -47,6 +49,19 @@ int bus_set_iommu(struct bus_type *bus, struct
iommu_ops *ops)
if (bus->iommu_ops != NULL)
return -EBUSY;
+ /*
+ * Set the default pgsize values, which retain the existing
+ * IOMMU API behavior: drivers will be called to map
+ * regions that are sized/aligned to order of 4KiB pages.
+ *
+ * This will be removed once all drivers are migrated.
+ */
+ if (!ops->pgsize_bitmap)
+ ops->pgsize_bitmap = ~0xFFFUL;
+
+ /* find out the minimum page size only once */
+ ops->min_pagesz = 1 << __ffs(ops->pgsize_bitmap);
+
bus->iommu_ops = ops;
/* Do IOMMU specific setup for this bus-type */
@@ -157,35 +172,110 @@ int iommu_domain_has_cap(struct iommu_domain *domain,
EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
int iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, int gfp_order, int prot)
+ phys_addr_t paddr, size_t size, int prot)
{
- size_t size;
+ unsigned long orig_iova = iova;
+ size_t orig_size = size;
+ int ret = 0;
if (unlikely(domain->ops->map == NULL))
return -ENODEV;
- size = PAGE_SIZE << gfp_order;
+ /*
+ * both the virtual address and the physical one, as well as
+ * the size of the mapping, must be aligned (at least) to the
+ * size of the smallest page supported by the hardware
+ */
+ if (!IS_ALIGNED(iova | paddr | size, domain->ops->min_pagesz)) {
+ pr_err("unaligned: iova 0x%lx pa 0x%lx size 0x%x min_pagesz "
+ "0x%x\n", iova, (unsigned long)paddr,
+ size, domain->ops->min_pagesz);
+ return -EINVAL;
+ }
+
+ pr_debug("map: iova 0x%lx pa 0x%lx size 0x%x\n", iova,
+ (unsigned long)paddr, size);
+
+ while (size) {
+ unsigned long pgsize, addr_merge = iova | paddr;
+ unsigned int pgsize_idx;
+
+ /* Max page size that still fits into 'size' */
+ pgsize_idx = __fls(size);
+
+ /* need to consider alignment requirements ? */
+ if (likely(addr_merge)) {
+ /* Max page size allowed by both iova and paddr */
+ unsigned int align_pgsize_idx = __ffs(addr_merge);
+
+ pgsize_idx = min(pgsize_idx, align_pgsize_idx);
+ }
+
+ /* build a mask of acceptable page sizes */
+ pgsize = (1UL << (pgsize_idx + 1)) - 1;
- BUG_ON(!IS_ALIGNED(iova | paddr, size));
+ /* throw away page sizes not supported by the hardware */
+ pgsize &= domain->ops->pgsize_bitmap;
- return domain->ops->map(domain, iova, paddr, size, prot);
+ /* make sure we're still sane */
+ BUG_ON(!pgsize);
+
+ /* pick the biggest page */
+ pgsize_idx = __fls(pgsize);
+ pgsize = 1UL << pgsize_idx;
+
+ pr_debug("mapping: iova 0x%lx pa 0x%lx pgsize %lu\n", iova,
+ (unsigned long)paddr, pgsize);
+
+ ret = domain->ops->map(domain, iova, paddr, pgsize, prot);
+ if (ret)
+ break;
+
+ iova += pgsize;
+ paddr += pgsize;
+ size -= pgsize;
+ }
+
+ /* unroll mapping in case something went wrong */
+ if (ret)
+ iommu_unmap(domain, orig_iova, orig_size - size);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(iommu_map);
-int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
+size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size)
{
- size_t size, unmapped;
+ size_t unmapped, left = size;
if (unlikely(domain->ops->unmap == NULL))
return -ENODEV;
- size = PAGE_SIZE << gfp_order;
+ /*
+ * The virtual address, as well as the size of the mapping, must be
+ * aligned (at least) to the size of the smallest page supported
+ * by the hardware
+ */
+ if (!IS_ALIGNED(iova | size, domain->ops->min_pagesz)) {
+ pr_err("unaligned: iova 0x%lx size 0x%x min_pagesz 0x%x\n",
+ iova, size, domain->ops->min_pagesz);
+ return -EINVAL;
+ }
+
+ pr_debug("unmap this: iova 0x%lx size 0x%x\n", iova, size);
+
+ while (left) {
+ unmapped = domain->ops->unmap(domain, iova, left);
+ if (!unmapped)
+ break;
- BUG_ON(!IS_ALIGNED(iova, size));
+ pr_debug("unmapped: iova 0x%lx size %u\n", iova, unmapped);
- unmapped = domain->ops->unmap(domain, iova, size);
+ iova += unmapped;
+ left -= unmapped;
+ }
- return get_order(unmapped);
+ return size - left;
}
EXPORT_SYMBOL_GPL(iommu_unmap);
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c
index e8fdb88..0b7b14c 100644
--- a/drivers/iommu/omap-iovmm.c
+++ b/drivers/iommu/omap-iovmm.c
@@ -409,7 +409,6 @@ static int map_iovm_area(struct iommu_domain
*domain, struct iovm_struct *new,
unsigned int i, j;
struct scatterlist *sg;
u32 da = new->da_start;
- int order;
if (!domain || !sgt)
return -EINVAL;
@@ -428,12 +427,10 @@ static int map_iovm_area(struct iommu_domain
*domain, struct iovm_struct *new,
if (bytes_to_iopgsz(bytes) < 0)
goto err_out;
- order = get_order(bytes);
-
pr_debug("%s: [%d] %08x %08x(%x)\n", __func__,
i, da, pa, bytes);
- err = iommu_map(domain, da, pa, order, flags);
+ err = iommu_map(domain, da, pa, bytes, flags);
if (err)
goto err_out;
@@ -448,10 +445,9 @@ err_out:
size_t bytes;
bytes = sg->length + sg->offset;
- order = get_order(bytes);
/* ignore failures.. we're already handling one */
- iommu_unmap(domain, da, order);
+ iommu_unmap(domain, da, bytes);
da += bytes;
}
@@ -466,7 +462,8 @@ static void unmap_iovm_area(struct iommu_domain
*domain, struct omap_iommu *obj,
size_t total = area->da_end - area->da_start;
const struct sg_table *sgt = area->sgt;
struct scatterlist *sg;
- int i, err;
+ int i;
+ size_t unmapped;
BUG_ON(!sgtable_ok(sgt));
BUG_ON((!total) || !IS_ALIGNED(total, PAGE_SIZE));
@@ -474,13 +471,11 @@ static void unmap_iovm_area(struct iommu_domain
*domain, struct omap_iommu *obj,
start = area->da_start;
for_each_sg(sgt->sgl, sg, sgt->nents, i) {
size_t bytes;
- int order;
bytes = sg->length + sg->offset;
- order = get_order(bytes);
- err = iommu_unmap(domain, start, order);
- if (err < 0)
+ unmapped = iommu_unmap(domain, start, bytes);
+ if (unmapped < bytes)
break;
dev_dbg(obj->dev, "%s: unmap %08x(%x) %08x\n",
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 6b6ed21..76d7ce4 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -48,6 +48,22 @@ struct iommu_domain {
#ifdef CONFIG_IOMMU_API
+/**
+ * struct iommu_ops - iommu ops and capabilities
+ * @domain_init: init iommu domain
+ * @domain_destroy: destroy iommu domain
+ * @attach_dev: attach device to an iommu domain
+ * @detach_dev: detach device from an iommu domain
+ * @map: map a physically contiguous memory region to an iommu domain
+ * @unmap: unmap a physically contiguous memory region from an iommu domain
+ * @iova_to_phys: translate iova to physical address
+ * @domain_has_cap: domain capabilities query
+ * @commit: commit iommu domain
+ * @pgsize_bitmap: bitmap of supported page sizes
+ * @min_pagesz: smallest page size supported. note: this member is private
+ * to the IOMMU core, and maintained only for efficiency sake;
+ * drivers don't need to set it.
+ */
struct iommu_ops {
int (*domain_init)(struct iommu_domain *domain);
void (*domain_destroy)(struct iommu_domain *domain);
@@ -62,6 +78,8 @@ struct iommu_ops {
int (*domain_has_cap)(struct iommu_domain *domain,
unsigned long cap);
void (*commit)(struct iommu_domain *domain);
+ unsigned long pgsize_bitmap;
+ unsigned int min_pagesz;
};
extern int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops);
@@ -73,9 +91,9 @@ extern int iommu_attach_device(struct iommu_domain *domain,
extern void iommu_detach_device(struct iommu_domain *domain,
struct device *dev);
extern int iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, int gfp_order, int prot);
-extern int iommu_unmap(struct iommu_domain *domain, unsigned long iova,
- int gfp_order);
+ phys_addr_t paddr, size_t size, int prot);
+extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova,
+ size_t size);
extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
unsigned long iova);
extern int iommu_domain_has_cap(struct iommu_domain *domain,
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
index ca409be..35ed096 100644
--- a/virt/kvm/iommu.c
+++ b/virt/kvm/iommu.c
@@ -111,7 +111,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct
kvm_memory_slot *slot)
/* Map into IO address space */
r = iommu_map(domain, gfn_to_gpa(gfn), pfn_to_hpa(pfn),
- get_order(page_size), flags);
+ page_size, flags);
if (r) {
printk(KERN_ERR "kvm_iommu_map_address:"
"iommu failed to map pfn=%llx\n", pfn);
@@ -292,15 +292,15 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
while (gfn < end_gfn) {
unsigned long unmap_pages;
- int order;
+ size_t size;
/* Get physical address */
phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn));
pfn = phys >> PAGE_SHIFT;
/* Unmap address from IO address space */
- order = iommu_unmap(domain, gfn_to_gpa(gfn), 0);
- unmap_pages = 1ULL << order;
+ size = iommu_unmap(domain, gfn_to_gpa(gfn), PAGE_SIZE);
+ unmap_pages = 1ULL << get_order(size);
/* Unpin all pages we just unmapped to not leak any memory */
kvm_unpin_pages(kvm, pfn, unmap_pages);
--
1.7.4.1
^ permalink raw reply related
* [PATCH] iommu/core: split mapping to page sizes as supported
From: Ohad Ben-Cohen @ 2011-10-10 21:50 UTC (permalink / raw)
To: linux-arm-kernel
by the hardware
When mapping a memory region, split it to page sizes as supported
by the iommu hardware. Always prefer bigger pages, when possible,
in order to reduce the TLB pressure.
The logic to do that is now added to the IOMMU core, so neither the iommu
drivers themselves nor users of the IOMMU API have to duplicate it.
This allows a more lenient granularity of mappings; traditionally the
IOMMU API took 'order' (of a page) as a mapping size, and directly let
the low level iommu drivers handle the mapping, but now that the IOMMU
core can split arbitrary memory regions into pages, we can remove this
limitation, so users don't have to split those regions by themselves.
Currently the supported page sizes are advertised once and they then
remain static. That works well for OMAP and MSM but it would probably
not fly well with intel's hardware, where the page size capabilities
seem to have the potential to be different between several DMA
remapping devices.
register_iommu() currently sets a default pgsize behavior, so we can convert
the IOMMU drivers in subsequent patches. After all the drivers
are converted, the temporary default settings will be removed.
Mainline users of the IOMMU API (kvm and omap-iovmm) are adopted
to deal with bytes instead of page order.
Many thanks to Joerg Roedel <Joerg.Roedel@amd.com> for significant review!
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: David Brown <davidb@codeaurora.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Joerg Roedel <Joerg.Roedel@amd.com>
Cc: Stepan Moskovchenko <stepanm@codeaurora.org>
Cc: KyongHo Cho <pullip.cho@samsung.com>
Cc: Hiroshi DOYU <hdoyu@nvidia.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: kvm at vger.kernel.org
---
drivers/iommu/iommu.c | 124 +++++++++++++++++++++++++++++++++++++++-----
drivers/iommu/omap-iovmm.c | 17 ++----
include/linux/iommu.h | 24 +++++++-
virt/kvm/iommu.c | 8 ++--
4 files changed, 141 insertions(+), 32 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 5d042e8..26309fc 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -16,6 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/bug.h>
@@ -47,6 +49,19 @@ int bus_set_iommu(struct bus_type *bus, struct
iommu_ops *ops)
if (bus->iommu_ops != NULL)
return -EBUSY;
+ /*
+ * Set the default pgsize values, which retain the existing
+ * IOMMU API behavior: drivers will be called to map
+ * regions that are sized/aligned to order of 4KiB pages.
+ *
+ * This will be removed once all drivers are migrated.
+ */
+ if (!ops->pgsize_bitmap)
+ ops->pgsize_bitmap = ~0xFFFUL;
+
+ /* find out the minimum page size only once */
+ ops->min_pagesz = 1 << __ffs(ops->pgsize_bitmap);
+
bus->iommu_ops = ops;
/* Do IOMMU specific setup for this bus-type */
@@ -157,35 +172,116 @@ int iommu_domain_has_cap(struct iommu_domain *domain,
EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
int iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, int gfp_order, int prot)
+ phys_addr_t paddr, size_t size, int prot)
{
- size_t size;
+ unsigned long orig_iova = iova;
+ size_t orig_size = size;
+ int ret = 0;
if (unlikely(domain->ops->map == NULL))
return -ENODEV;
- size = PAGE_SIZE << gfp_order;
+ /*
+ * both the virtual address and the physical one, as well as
+ * the size of the mapping, must be aligned (at least) to the
+ * size of the smallest page supported by the hardware
+ */
+ if (!IS_ALIGNED(iova | paddr | size, domain->ops->min_pagesz)) {
+ pr_err("unaligned: iova 0x%lx pa 0x%lx size 0x%x min_pagesz "
+ "0x%x\n", iova, (unsigned long)paddr,
+ size, domain->ops->min_pagesz);
+ return -EINVAL;
+ }
+
+ pr_debug("map: iova 0x%lx pa 0x%lx size 0x%x\n", iova,
+ (unsigned long)paddr, size);
+
+ while (size) {
+ unsigned long pgsize, addr_merge = iova | paddr;
+ unsigned int pgsize_idx;
+
+ /* Max page size that still fits into 'size' */
+ pgsize_idx = __fls(size);
+
+ /* need to consider alignment requirements ? */
+ if (likely(addr_merge)) {
+ /* Max page size allowed by both iova and paddr */
+ unsigned int align_pgsize_idx = __ffs(addr_merge);
+
+ pgsize_idx = min(pgsize_idx, align_pgsize_idx);
+ }
+
+ /* build a mask of acceptable page sizes */
+ pgsize = (1UL << (pgsize_idx + 1)) - 1;
+
+ /* throw away page sizes not supported by the hardware */
+ pgsize &= domain->ops->pgsize_bitmap;
- BUG_ON(!IS_ALIGNED(iova | paddr, size));
+ /* make sure we're still sane */
+ BUG_ON(!pgsize);
- return domain->ops->map(domain, iova, paddr, size, prot);
+ /* pick the biggest page */
+ pgsize_idx = __fls(pgsize);
+ pgsize = 1UL << pgsize_idx;
+
+ pr_debug("mapping: iova 0x%lx pa 0x%lx pgsize %lu\n", iova,
+ (unsigned long)paddr, pgsize);
+
+ ret = domain->ops->map(domain, iova, paddr, pgsize, prot);
+ if (ret)
+ break;
+
+ iova += pgsize;
+ paddr += pgsize;
+ size -= pgsize;
+ }
+
+ /* unroll mapping in case something went wrong */
+ if (ret)
+ iommu_unmap(domain, orig_iova, orig_size - size);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(iommu_map);
-int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
+size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size)
{
- size_t size, unmapped;
+ size_t unmapped_page, unmapped = 0;
if (unlikely(domain->ops->unmap == NULL))
return -ENODEV;
- size = PAGE_SIZE << gfp_order;
-
- BUG_ON(!IS_ALIGNED(iova, size));
-
- unmapped = domain->ops->unmap(domain, iova, size);
-
- return get_order(unmapped);
+ /*
+ * The virtual address, as well as the size of the mapping, must be
+ * aligned (at least) to the size of the smallest page supported
+ * by the hardware
+ */
+ if (!IS_ALIGNED(iova | size, domain->ops->min_pagesz)) {
+ pr_err("unaligned: iova 0x%lx size 0x%x min_pagesz 0x%x\n",
+ iova, size, domain->ops->min_pagesz);
+ return -EINVAL;
+ }
+
+ pr_debug("unmap this: iova 0x%lx size 0x%x\n", iova, size);
+
+ /*
+ * Keep iterating until we either unmap 'size' bytes (or more)
+ * or we hit an area that isn't mapped.
+ */
+ while (unmapped < size) {
+ size_t left = size - unmapped;
+
+ unmapped_page = domain->ops->unmap(domain, iova, left);
+ if (!unmapped_page)
+ break;
+
+ pr_debug("unmapped: iova 0x%lx size %u\n", iova, unmapped_page);
+
+ iova += unmapped_page;
+ unmapped += unmapped_page;
+ }
+
+ return unmapped;
}
EXPORT_SYMBOL_GPL(iommu_unmap);
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c
index e8fdb88..0b7b14c 100644
--- a/drivers/iommu/omap-iovmm.c
+++ b/drivers/iommu/omap-iovmm.c
@@ -409,7 +409,6 @@ static int map_iovm_area(struct iommu_domain
*domain, struct iovm_struct *new,
unsigned int i, j;
struct scatterlist *sg;
u32 da = new->da_start;
- int order;
if (!domain || !sgt)
return -EINVAL;
@@ -428,12 +427,10 @@ static int map_iovm_area(struct iommu_domain
*domain, struct iovm_struct *new,
if (bytes_to_iopgsz(bytes) < 0)
goto err_out;
- order = get_order(bytes);
-
pr_debug("%s: [%d] %08x %08x(%x)\n", __func__,
i, da, pa, bytes);
- err = iommu_map(domain, da, pa, order, flags);
+ err = iommu_map(domain, da, pa, bytes, flags);
if (err)
goto err_out;
@@ -448,10 +445,9 @@ err_out:
size_t bytes;
bytes = sg->length + sg->offset;
- order = get_order(bytes);
/* ignore failures.. we're already handling one */
- iommu_unmap(domain, da, order);
+ iommu_unmap(domain, da, bytes);
da += bytes;
}
@@ -466,7 +462,8 @@ static void unmap_iovm_area(struct iommu_domain
*domain, struct omap_iommu *obj,
size_t total = area->da_end - area->da_start;
const struct sg_table *sgt = area->sgt;
struct scatterlist *sg;
- int i, err;
+ int i;
+ size_t unmapped;
BUG_ON(!sgtable_ok(sgt));
BUG_ON((!total) || !IS_ALIGNED(total, PAGE_SIZE));
@@ -474,13 +471,11 @@ static void unmap_iovm_area(struct iommu_domain
*domain, struct omap_iommu *obj,
start = area->da_start;
for_each_sg(sgt->sgl, sg, sgt->nents, i) {
size_t bytes;
- int order;
bytes = sg->length + sg->offset;
- order = get_order(bytes);
- err = iommu_unmap(domain, start, order);
- if (err < 0)
+ unmapped = iommu_unmap(domain, start, bytes);
+ if (unmapped < bytes)
break;
dev_dbg(obj->dev, "%s: unmap %08x(%x) %08x\n",
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 6b6ed21..76d7ce4 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -48,6 +48,22 @@ struct iommu_domain {
#ifdef CONFIG_IOMMU_API
+/**
+ * struct iommu_ops - iommu ops and capabilities
+ * @domain_init: init iommu domain
+ * @domain_destroy: destroy iommu domain
+ * @attach_dev: attach device to an iommu domain
+ * @detach_dev: detach device from an iommu domain
+ * @map: map a physically contiguous memory region to an iommu domain
+ * @unmap: unmap a physically contiguous memory region from an iommu domain
+ * @iova_to_phys: translate iova to physical address
+ * @domain_has_cap: domain capabilities query
+ * @commit: commit iommu domain
+ * @pgsize_bitmap: bitmap of supported page sizes
+ * @min_pagesz: smallest page size supported. note: this member is private
+ * to the IOMMU core, and maintained only for efficiency sake;
+ * drivers don't need to set it.
+ */
struct iommu_ops {
int (*domain_init)(struct iommu_domain *domain);
void (*domain_destroy)(struct iommu_domain *domain);
@@ -62,6 +78,8 @@ struct iommu_ops {
int (*domain_has_cap)(struct iommu_domain *domain,
unsigned long cap);
void (*commit)(struct iommu_domain *domain);
+ unsigned long pgsize_bitmap;
+ unsigned int min_pagesz;
};
extern int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops);
@@ -73,9 +91,9 @@ extern int iommu_attach_device(struct iommu_domain *domain,
extern void iommu_detach_device(struct iommu_domain *domain,
struct device *dev);
extern int iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, int gfp_order, int prot);
-extern int iommu_unmap(struct iommu_domain *domain, unsigned long iova,
- int gfp_order);
+ phys_addr_t paddr, size_t size, int prot);
+extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova,
+ size_t size);
extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
unsigned long iova);
extern int iommu_domain_has_cap(struct iommu_domain *domain,
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
index ca409be..35ed096 100644
--- a/virt/kvm/iommu.c
+++ b/virt/kvm/iommu.c
@@ -111,7 +111,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct
kvm_memory_slot *slot)
/* Map into IO address space */
r = iommu_map(domain, gfn_to_gpa(gfn), pfn_to_hpa(pfn),
- get_order(page_size), flags);
+ page_size, flags);
if (r) {
printk(KERN_ERR "kvm_iommu_map_address:"
"iommu failed to map pfn=%llx\n", pfn);
@@ -292,15 +292,15 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
while (gfn < end_gfn) {
unsigned long unmap_pages;
- int order;
+ size_t size;
/* Get physical address */
phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn));
pfn = phys >> PAGE_SHIFT;
/* Unmap address from IO address space */
- order = iommu_unmap(domain, gfn_to_gpa(gfn), 0);
- unmap_pages = 1ULL << order;
+ size = iommu_unmap(domain, gfn_to_gpa(gfn), PAGE_SIZE);
+ unmap_pages = 1ULL << get_order(size);
/* Unpin all pages we just unmapped to not leak any memory */
kvm_unpin_pages(kvm, pfn, unmap_pages);
--
1.7.4.1
^ permalink raw reply related
* [PATCH] iommu/core: fix build issue
From: Ohad Ben-Cohen @ 2011-10-10 21:55 UTC (permalink / raw)
To: linux-arm-kernel
Fix this:
drivers/iommu/iommu.c: In function 'iommu_commit':
drivers/iommu/iommu.c:291: error: 'iommu_ops' undeclared (first use in
this function)
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
---
drivers/iommu/iommu.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 909b0d2..a5131f1 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -288,7 +288,7 @@ EXPORT_SYMBOL_GPL(iommu_unmap);
void iommu_commit(struct iommu_domain *domain)
{
- if (iommu_ops->commit)
- iommu_ops->commit(domain);
+ if (domain->ops->commit)
+ domain->ops->commit(domain);
}
EXPORT_SYMBOL_GPL(iommu_commit);
--
1.7.4.1
^ permalink raw reply related
* [Linaro-mm-sig] [PATCH 1/2] ARM: initial proof-of-concept IOMMU mapper for DMA-mapping
From: Krishna Reddy @ 2011-10-10 21:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <001f01cc786d$d55222c0$7ff66840$%szyprowski@samsung.com>
Marek,
Here is a patch that has fixes to get SDHC driver work as a DMA IOMMU client. Here is the overview of changes.
1. Converted the mutex to spinlock to handle atomic context calls and used spinlock in necessary places.
2. Implemented arm_iommu_map_page and arm_iommu_unmap_page, which are used by MMC host stack.
3. Fixed the bugs identified during testing with SDHC driver.
From: Krishna Reddy <vdumpa@nvidia.com>
Date: Fri, 7 Oct 2011 17:25:59 -0700
Subject: [PATCH] ARM: dma-mapping: Implement arm_iommu_map_page/unmap_page and fix issues.
Change-Id: I47a1a0065538fa0a161dd6d551b38079bd8f84fd
---
arch/arm/include/asm/dma-iommu.h | 3 +-
arch/arm/mm/dma-mapping.c | 182 +++++++++++++++++++++-----------------
2 files changed, 102 insertions(+), 83 deletions(-)
diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
index 0b2677e..ad1a4d9 100644
--- a/arch/arm/include/asm/dma-iommu.h
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -7,6 +7,7 @@
#include <linux/scatterlist.h>
#include <linux/dma-debug.h>
#include <linux/kmemcheck.h>
+#include <linux/spinlock_types.h>
#include <asm/memory.h>
@@ -19,7 +20,7 @@ struct dma_iommu_mapping {
unsigned int order;
dma_addr_t base;
- struct mutex lock;
+ spinlock_t lock;
};
int arm_iommu_attach_device(struct device *dev, dma_addr_t base,
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 020bde1..0befd88 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -739,32 +739,42 @@ fs_initcall(dma_debug_do_init);
/* IOMMU */
-static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping, size_t size)
+static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
+ size_t size)
{
- unsigned int order = get_order(size);
unsigned int align = 0;
unsigned int count, start;
+ unsigned long flags;
- if (order > mapping->order)
- align = (1 << (order - mapping->order)) - 1;
+ count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
- count = ((size >> PAGE_SHIFT) + (1 << mapping->order) - 1) >> mapping->order;
-
- start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0, count, align);
- if (start > mapping->bits)
+ spin_lock_irqsave(&mapping->lock, flags);
+ start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits,
+ 0, count, align);
+ if (start > mapping->bits) {
+ spin_unlock_irqrestore(&mapping->lock, flags);
return ~0;
+ }
bitmap_set(mapping->bitmap, start, count);
+ spin_unlock_irqrestore(&mapping->lock, flags);
return mapping->base + (start << (mapping->order + PAGE_SHIFT));
}
-static inline void __free_iova(struct dma_iommu_mapping *mapping, dma_addr_t addr, size_t size)
+static inline void __free_iova(struct dma_iommu_mapping *mapping,
+ dma_addr_t addr, size_t size)
{
- unsigned int start = (addr - mapping->base) >> (mapping->order + PAGE_SHIFT);
- unsigned int count = ((size >> PAGE_SHIFT) + (1 << mapping->order) - 1) >> mapping->order;
+ unsigned int start = (addr - mapping->base) >>
+ (mapping->order + PAGE_SHIFT);
+ unsigned int count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+ unsigned long flags;
+ spin_lock_irqsave(&mapping->lock, flags);
bitmap_clear(mapping->bitmap, start, count);
+ spin_unlock_irqrestore(&mapping->lock, flags);
}
static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
@@ -867,7 +877,7 @@ __iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot)
static dma_addr_t __iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
{
struct dma_iommu_mapping *mapping = dev->archdata.mapping;
- unsigned int count = size >> PAGE_SHIFT;
+ unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
dma_addr_t dma_addr, iova;
int i, ret = ~0;
@@ -892,13 +902,12 @@ fail:
static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t size)
{
struct dma_iommu_mapping *mapping = dev->archdata.mapping;
- unsigned int count = size >> PAGE_SHIFT;
+ unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
int i;
- for (i=0; i<count; i++) {
- iommu_unmap(mapping->domain, iova, 0);
- iova += PAGE_SIZE;
- }
+ iova = iova & PAGE_MASK;
+ for (i=0; i<count; i++)
+ iommu_unmap(mapping->domain, iova + i * PAGE_SIZE, 0);
__free_iova(mapping, iova, size);
return 0;
}
@@ -906,7 +915,6 @@ static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t si
static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
{
- struct dma_iommu_mapping *mapping = dev->archdata.mapping;
pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
struct page **pages;
void *addr = NULL;
@@ -914,11 +922,9 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
*handle = ~0;
size = PAGE_ALIGN(size);
- mutex_lock(&mapping->lock);
-
pages = __iommu_alloc_buffer(dev, size, gfp);
if (!pages)
- goto err_unlock;
+ goto exit;
*handle = __iommu_create_mapping(dev, pages, size);
if (*handle == ~0)
@@ -928,15 +934,13 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
if (!addr)
goto err_mapping;
- mutex_unlock(&mapping->lock);
return addr;
err_mapping:
__iommu_remove_mapping(dev, *handle, size);
err_buffer:
__iommu_free_buffer(dev, pages, size);
-err_unlock:
- mutex_unlock(&mapping->lock);
+exit:
return NULL;
}
@@ -944,11 +948,9 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
struct dma_attrs *attrs)
{
- unsigned long user_size;
struct arm_vmregion *c;
vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
- user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
if (c) {
@@ -981,11 +983,9 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t handle, struct dma_attrs *attrs)
{
- struct dma_iommu_mapping *mapping = dev->archdata.mapping;
struct arm_vmregion *c;
size = PAGE_ALIGN(size);
- mutex_lock(&mapping->lock);
c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
if (c) {
struct page **pages = c->priv;
@@ -993,7 +993,6 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
__iommu_remove_mapping(dev, handle, size);
__iommu_free_buffer(dev, pages, size);
}
- mutex_unlock(&mapping->lock);
}
static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
@@ -1001,80 +1000,93 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
enum dma_data_direction dir)
{
struct dma_iommu_mapping *mapping = dev->archdata.mapping;
- dma_addr_t dma_addr, iova;
+ dma_addr_t iova;
int ret = 0;
+ unsigned long i;
+ phys_addr_t phys = page_to_phys(sg_page(sg));
+ size = PAGE_ALIGN(size);
*handle = ~0;
- mutex_lock(&mapping->lock);
- iova = dma_addr = __alloc_iova(mapping, size);
- if (dma_addr == 0)
- goto fail;
-
- while (size) {
- unsigned int phys = page_to_phys(sg_page(sg));
- unsigned int len = sg->offset + sg->length;
+ iova = __alloc_iova(mapping, size);
+ if (iova == 0)
+ return -ENOMEM;
- if (!arch_is_coherent())
- __dma_page_cpu_to_dev(sg_page(sg), sg->offset, sg->length, dir);
-
- while (len) {
- ret = iommu_map(mapping->domain, iova, phys, 0, 0);
- if (ret < 0)
- goto fail;
- iova += PAGE_SIZE;
- len -= PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- sg = sg_next(sg);
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(sg_page(sg), sg->offset,
+ sg->length, dir);
+ for (i = 0; i < (size >> PAGE_SHIFT); i++) {
+ ret = iommu_map(mapping->domain, iova + i * PAGE_SIZE,
+ phys + i * PAGE_SIZE, 0, 0);
+ if (ret < 0)
+ goto fail;
}
-
- *handle = dma_addr;
- mutex_unlock(&mapping->lock);
+ *handle = iova;
return 0;
fail:
+ while (i--)
+ iommu_unmap(mapping->domain, iova + i * PAGE_SIZE, 0);
+
__iommu_remove_mapping(dev, iova, size);
- mutex_unlock(&mapping->lock);
return ret;
}
+static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ dma_addr_t dma_addr;
+
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+
+ BUG_ON((offset+size) > PAGE_SIZE);
+ dma_addr = __iommu_create_mapping(dev, &page, PAGE_SIZE);
+ return dma_addr + offset;
+}
+
+static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ phys_addr_t phys;
+
+ phys = iommu_iova_to_phys(mapping->domain, handle);
+ __iommu_remove_mapping(dev, handle, size);
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(pfn_to_page(__phys_to_pfn(phys)),
+ phys & ~PAGE_MASK, size, dir);
+}
+
int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir, struct dma_attrs *attrs)
{
- struct scatterlist *s = sg, *dma = sg, *start = sg;
- int i, count = 1;
- unsigned int offset = s->offset;
- unsigned int size = s->offset + s->length;
+ struct scatterlist *s;
+ unsigned int size;
+ int i, count = 0;
- for (i = 1; i < nents; i++) {
+ for_each_sg(sg, s, nents, i) {
s->dma_address = ~0;
s->dma_length = 0;
+ size = s->offset + s->length;
- s = sg_next(s);
-
- if (s->offset || (size & (PAGE_SIZE - 1))) {
- if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir) < 0)
- goto bad_mapping;
-
- dma->dma_address += offset;
- dma->dma_length = size;
+ if (__map_sg_chunk(dev, s, size, &s->dma_address, dir) < 0)
+ goto bad_mapping;
- size = offset = s->offset;
- start = s;
- dma = sg_next(dma);
- count += 1;
- }
- size += sg->length;
+ s->dma_address += s->offset;
+ s->dma_length = s->length;
+ count++;
}
- __map_sg_chunk(dev, start, size, &dma->dma_address, dir);
- d->dma_address += offset;
return count;
bad_mapping:
- for_each_sg(sg, s, count-1, i)
- __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s));
+ for_each_sg(sg, s, count, i) {
+ __iommu_remove_mapping(dev, sg_dma_address(s),
+ PAGE_ALIGN(sg_dma_len(s)));
+ }
return 0;
}
@@ -1086,9 +1098,11 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
for_each_sg(sg, s, nents, i) {
if (sg_dma_len(s))
- __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s));
+ __iommu_remove_mapping(dev, sg_dma_address(s),
+ sg_dma_len(s));
if (!arch_is_coherent())
- __dma_page_dev_to_cpu(sg_page(sg), sg->offset, sg->length, dir);
+ __dma_page_dev_to_cpu(sg_page(s), s->offset,
+ s->length, dir);
}
}
@@ -1108,7 +1122,8 @@ void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
for_each_sg(sg, s, nents, i)
if (!arch_is_coherent())
- __dma_page_dev_to_cpu(sg_page(sg), sg->offset, sg->length, dir);
+ __dma_page_dev_to_cpu(sg_page(s), s->offset,
+ s->length, dir);
}
/**
@@ -1126,13 +1141,16 @@ void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
for_each_sg(sg, s, nents, i)
if (!arch_is_coherent())
- __dma_page_cpu_to_dev(sg_page(sg), sg->offset, sg->length, dir);
+ __dma_page_cpu_to_dev(sg_page(s), s->offset,
+ s->length, dir);
}
struct dma_map_ops iommu_ops = {
.alloc = arm_iommu_alloc_attrs,
.free = arm_iommu_free_attrs,
.mmap = arm_iommu_mmap_attrs,
+ .map_page = arm_iommu_map_page,
+ .unmap_page = arm_iommu_unmap_page,
.map_sg = arm_iommu_map_sg,
.unmap_sg = arm_iommu_unmap_sg,
.sync_sg_for_cpu = arm_iommu_sync_sg_for_cpu,
@@ -1157,7 +1175,7 @@ int arm_iommu_attach_device(struct device *dev, dma_addr_t base, size_t size, in
mapping->base = base;
mapping->bits = bitmap_size;
mapping->order = order;
- mutex_init(&mapping->lock);
+ spin_lock_init(&mapping->lock);
mapping->domain = iommu_domain_alloc();
if (!mapping->domain)
--
1.7.0.4
--
nvpublic
^ permalink raw reply related
* [PATCH v3 1/6] iommu/core: split mapping to page sizes as supported by the hardware
From: Ohad Ben-Cohen @ 2011-10-10 22:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAK=WgbYR_qx53Z7s3R=q29KYo8ebYCH9H9=2OrrWXWMv6=-iOQ@mail.gmail.com>
> On Mon, Oct 10, 2011 at 5:36 PM, Roedel, Joerg <Joerg.Roedel@amd.com> wrote:
>> The master branch is best to base your patches on for generic work.
It looks like the master branch is missing something like this:
^ permalink raw reply
* [PATCHv9 03/18] TEMP: OMAP3xxx: hwmod data: add PRM hwmod
From: Cousson, Benoit @ 2011-10-10 22:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1110101416530.5205@utopia.booyaka.com>
On 10/10/2011 10:42 PM, Paul Walmsley wrote:
> Hi Beno?t
>
> On Mon, 10 Oct 2011, Cousson, Benoit wrote:
>
>> On 10/10/2011 9:24 PM, Paul Walmsley wrote:
>>> On Fri, 23 Sep 2011, Tero Kristo wrote:
>>>
>>>> This patch is temporary until Paul can provide a final version.
>>>>
>>>> Signed-off-by: Tero Kristo<t-kristo@ti.com>
>>>
>>> Here's an updated version of this one. The one change is that the hwmod's
>>> name is now "prm3xxx" to reflect that the register layout of this IP block
>>> is quite different from its OMAP2 predecessors and OMAP4 successors.
>>> This should avoid some of the special-purpose driver probing code.
>>
>> This is not really aligned with the naming convention we've been using so far.
>> In both cases, the hwmod should just be named "prm". If a version information
>> is needed, then it should be added in the revision class field.
>>
>> It will make the device creation even simpler and not dependent of the SoC
>> version.
>
> The problem in this case is that we should be using a completely different
> device driver for the PRM that's in the OMAP3 chips, from the driver used
> for OMAP2 or OMAP4 PRM blocks, due to the completely different register
> layout. As far as I know, we haven't yet used the hwmod IP version to
> probe a different device driver when the version number changes. There's
> no support for that in the current Linux platform* code, so we'd need
> special-purpose code for that.
>
> In an ideal world, we'd have an omap_bus, etc., which would include an
> additional interface version number as part of its driver matching
> criteria. Device drivers would then specify which interface version
> numbers they supported. The device data would specify that interface
> version number should be matched.
>
> But as it is right now in the current platform_device/platform_driver
> based system, we have only the name to match. We could implement
> something where we concatenate the existing IP version number onto the
> hwmod name, and modify the device drivers to use that name. But that
> seems like a lot of potential churn in light of a future DT and/or
> omap_bus migration.
>
> So I'm proposing to use the IP version number field that's in the hwmod
> data to indicate evolutionary revisions of an IP block -- rather than
> revolutionary revisions that would require a new driver. Then, since we
> use the hwmod name for driver matching, we'd use a different name for
> radically different IPs.
>
> If it's the "3xxx" that you're objecting to in the name, we could call it
> "prm2" or "prmxyz" - the '3xxx' just seemed like the most logical
> approach. The name of the hwmod class in the patch is still "prm", of
> course.
Yes, but that's different, the number is supposed to represent the
instance number in the IP naming convention. So prm2 != prmv2.
> Thoughts?
In fact the device name does not have to match the hwmod name. So we can
just create an "omap2_prm" omap_device for OMAP2, "omap3_prm"
omap_device for OMAP3...
That will allow the relevant PRM driver to be bound to the proper device.
> N.B., it's true that by waiting, this problem will presumably go away,
> with DT, in which the driver matching data would go into the
> "compatible" string in the DT.
Yes, this will become indeed straightforward with DT.
We will just have something like:
prm {
compatible = "prm-omap2";
ti,hwmods = "prm";
}
> But I guess it would be good to figure out a clean approach in the
> meantime.
I guess the different device names should make that work in the meantime.
Regards,
Benoit
^ permalink raw reply
* [PATCH v6 02/16] OMAP2+: hwmod: Add API to check IO PAD wakeup status
From: Kevin Hilman @ 2011-10-10 22:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAAL8m4xkC1Ftnr=RpAK5m2PVvPx3yzitO5gNJfOKiD0_YkGkdA@mail.gmail.com>
Govindraj <govindraj.ti@gmail.com> writes:
> On Mon, Oct 3, 2011 at 10:53 AM, Rajendra Nayak <rnayak@ti.com> wrote:
>> On Monday 03 October 2011 10:30 AM, Govindraj wrote:
>>
>>> On Sat, Oct 1, 2011 at 8:03 PM, Rajendra Nayak<rnayak@ti.com> ?wrote:
>>>>
>>>> On Friday 30 September 2011 04:31 PM, Govindraj.R wrote:
>>>>>
>>>>> Add API to determine IO-PAD wakeup event status for a given
>>>>> hwmod dynamic_mux pad.
>>>>>
>>>>> Wake up event set will be cleared on pad mux_read.
>>>>
>>>> Are these api's even getting used in this series?
>>>
>>> Used in Tero's irq_chaining patches.
>>
>> So shouldn't this patch be part of his series instead?
>
> Yes it is. Part of his v9-series.
>
Then please drop from this series and state the introductory patch
(PATCH 0/n) that this series has a dependency on Tero's series.
Kevin
^ permalink raw reply
* [PATCH v6 05/16] OMAP2+: UART: Cleanup part of clock gating mechanism for uart
From: Kevin Hilman @ 2011-10-10 22:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317380495-584-5-git-send-email-govindraj.raja@ti.com>
"Govindraj.R" <govindraj.raja@ti.com> writes:
> Currently we use a shared irq handler to identify uart activity and then
> trigger a timer.
OK.
> Based the timeout value set from sysfs the timer used to expire.
Please re-phrase as I'm not sure what is being said here.
> If no uart-activity was detected timer-expiry func sets can_sleep
> flag. Based on this we will disable the uart clocks in idle path.
>
> Since the clock gating mechanism is outside the uart driver, we currently
> use this mechanism. In preparation to runtime implementation for omap-serial
> driver we can cleanup this mechanism and use runtime API's to gate uart clocks.
>
> Also remove timer related info from local uart_state struct and remove
> the code used to set timeout value from sysfs. Remove un-used function
> omap_uart_check_wakeup.
>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
The patch itself fine, and is a well-neede cleanup, but changelog
(especially the first part) does not read well.
Kevin
^ permalink raw reply
* [PATCHv9 03/18] TEMP: OMAP3xxx: hwmod data: add PRM hwmod
From: Paul Walmsley @ 2011-10-10 22:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E936F0E.9050203@ti.com>
On Tue, 11 Oct 2011, Cousson, Benoit wrote:
> On 10/10/2011 10:42 PM, Paul Walmsley wrote:
>
> > If it's the "3xxx" that you're objecting to in the name, we could call it
> > "prm2" or "prmxyz" - the '3xxx' just seemed like the most logical
> > approach. The name of the hwmod class in the patch is still "prm", of
> > course.
>
> Yes, but that's different, the number is supposed to represent the instance
> number in the IP naming convention. So prm2 != prmv2.
Heh, that works as long as there's no "prmv" IP block ;-)
> > Thoughts?
>
> In fact the device name does not have to match the hwmod name. So we can just
> create an "omap2_prm" omap_device for OMAP2, "omap3_prm" omap_device for
> OMAP3...
> That will allow the relevant PRM driver to be bound to the proper device.
We can, we'd just need to add this extra mapping layer, so it doesn't
become a nasty special-case hack for each IP block that this applies to.
Sounds like something for 3.3 (if ever...)
- Paul
^ permalink raw reply
* [PATCH v3 1/6] iommu/core: split mapping to page sizes as supported by the hardware
From: Ohad Ben-Cohen @ 2011-10-10 22:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111010153609.GB2138@amd.com>
Hi Joerg,
On Mon, Oct 10, 2011 at 5:36 PM, Roedel, Joerg <Joerg.Roedel@amd.com> wrote:
> The master branch is best to base your patches on for generic work.
Done. I've revised the patches and attached the main one
below; please tell me if it looks ok, and then I'll resubmit the
entire patch set.
Thanks,
Ohad.
commit bf1d730b5f4f7631becfcd4be52693d85bfea36b
Author: Ohad Ben-Cohen <ohad@wizery.com>
Date: Mon Oct 10 23:50:55 2011 +0200
iommu/core: split mapping to page sizes as supported by the hardware
When mapping a memory region, split it to page sizes as supported
by the iommu hardware. Always prefer bigger pages, when possible,
in order to reduce the TLB pressure.
The logic to do that is now added to the IOMMU core, so neither the iommu
drivers themselves nor users of the IOMMU API have to duplicate it.
This allows a more lenient granularity of mappings; traditionally the
IOMMU API took 'order' (of a page) as a mapping size, and directly let
the low level iommu drivers handle the mapping, but now that the IOMMU
core can split arbitrary memory regions into pages, we can remove this
limitation, so users don't have to split those regions by themselves.
Currently the supported page sizes are advertised once and they then
remain static. That works well for OMAP and MSM but it would probably
not fly well with intel's hardware, where the page size capabilities
seem to have the potential to be different between several DMA
remapping devices.
register_iommu() currently sets a default pgsize behavior, so we can convert
the IOMMU drivers in subsequent patches, and after all the drivers
are converted, register_iommu will be changed (and the temporary
default settings will be removed).
Mainline users of the IOMMU API (kvm and omap-iovmm) are adopted
to send the mapping size in bytes instead of in page order.
Many thanks to Joerg Roedel <Joerg.Roedel@amd.com> for significant review!
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: David Brown <davidb@codeaurora.org>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Joerg Roedel <Joerg.Roedel@amd.com>
Cc: Stepan Moskovchenko <stepanm@codeaurora.org>
Cc: KyongHo Cho <pullip.cho@samsung.com>
Cc: Hiroshi DOYU <hdoyu@nvidia.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: kvm at vger.kernel.org
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 73778b7..909b0d2 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -16,6 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/bug.h>
@@ -47,6 +49,19 @@ int bus_set_iommu(struct bus_type *bus, struct
iommu_ops *ops)
if (bus->iommu_ops != NULL)
return -EBUSY;
+ /*
+ * Set the default pgsize values, which retain the existing
+ * IOMMU API behavior: drivers will be called to map
+ * regions that are sized/aligned to order of 4KiB pages.
+ *
+ * This will be removed once all drivers are migrated.
+ */
+ if (!ops->pgsize_bitmap)
+ ops->pgsize_bitmap = ~0xFFFUL;
+
+ /* find out the minimum page size only once */
+ ops->min_pagesz = 1 << __ffs(ops->pgsize_bitmap);
+
bus->iommu_ops = ops;
/* Do IOMMU specific setup for this bus-type */
@@ -157,33 +172,117 @@ int iommu_domain_has_cap(struct iommu_domain *domain,
EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
int iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, int gfp_order, int prot)
+ phys_addr_t paddr, int size, int prot)
{
- size_t size;
+ unsigned long orig_iova = iova;
+ int ret = 0, orig_size = size;
if (unlikely(domain->ops->map == NULL))
return -ENODEV;
- size = PAGE_SIZE << gfp_order;
+ /*
+ * both the virtual address and the physical one, as well as
+ * the size of the mapping, must be aligned (at least) to the
+ * size of the smallest page supported by the hardware
+ */
+ if (!IS_ALIGNED(iova | paddr | size, domain->ops->min_pagesz)) {
+ pr_err("unaligned: iova 0x%lx pa 0x%lx size 0x%x min_pagesz "
+ "0x%x\n", iova, (unsigned long)paddr,
+ size, domain->ops->min_pagesz);
+ return -EINVAL;
+ }
+
+ pr_debug("map: iova 0x%lx pa 0x%lx size 0x%x\n", iova,
+ (unsigned long)paddr, size);
+
+ while (size) {
+ unsigned long pgsize, addr_merge = iova | paddr;
+ unsigned int pgsize_idx;
+
+ /* Max page size that still fits into 'size' */
+ pgsize_idx = __fls(size);
+
+ /* need to consider alignment requirements ? */
+ if (likely(addr_merge)) {
+ /* Max page size allowed by both iova and paddr */
+ unsigned int align_pgsize_idx = __ffs(addr_merge);
+
+ pgsize_idx = min(pgsize_idx, align_pgsize_idx);
+ }
+
+ /* build a mask of acceptable page sizes */
+ pgsize = (1UL << (pgsize_idx + 1)) - 1;
+
+ /* throw away page sizes not supported by the hardware */
+ pgsize &= domain->ops->pgsize_bitmap;
+
+ /* make sure we're still sane */
+ BUG_ON(!pgsize);
- BUG_ON(!IS_ALIGNED(iova | paddr, size));
+ /* pick the biggest page */
+ pgsize_idx = __fls(pgsize);
+ pgsize = 1UL << pgsize_idx;
- return domain->ops->map(domain, iova, paddr, gfp_order, prot);
+ /* convert index to page order */
+ pgsize_idx -= PAGE_SHIFT;
+
+ pr_debug("mapping: iova 0x%lx pa 0x%lx order %u\n", iova,
+ (unsigned long)paddr, pgsize_idx);
+
+ ret = domain->ops->map(domain, iova, paddr, pgsize_idx, prot);
+ if (ret)
+ break;
+
+ iova += pgsize;
+ paddr += pgsize;
+ size -= pgsize;
+ }
+
+ /* unroll mapping in case something went wrong */
+ if (ret)
+ iommu_unmap(domain, orig_iova, orig_size);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(iommu_map);
-int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
+int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int size)
{
- size_t size;
+ int order, unmapped_size, unmapped_order, total_unmapped = 0;
if (unlikely(domain->ops->unmap == NULL))
return -ENODEV;
- size = PAGE_SIZE << gfp_order;
+ /*
+ * The virtual address, as well as the size of the mapping, must be
+ * aligned (at least) to the size of the smallest page supported
+ * by the hardware
+ */
+ if (!IS_ALIGNED(iova | size, domain->ops->min_pagesz)) {
+ pr_err("unaligned: iova 0x%lx size 0x%x min_pagesz 0x%x\n",
+ iova, size, domain->ops->min_pagesz);
+ return -EINVAL;
+ }
+
+ pr_debug("unmap this: iova 0x%lx size 0x%x\n", iova, size);
+
+ while (size > total_unmapped) {
+ order = get_order(size - total_unmapped);
+
+ unmapped_order = domain->ops->unmap(domain, iova, order);
+ if (unmapped_order < 0)
+ break;
+
+ pr_debug("unmapped: iova 0x%lx order %d\n", iova,
+ unmapped_order);
+
+ unmapped_size = 0x1000UL << unmapped_order;
- BUG_ON(!IS_ALIGNED(iova, size));
+ iova += unmapped_size;
+ total_unmapped += unmapped_size;
+ }
- return domain->ops->unmap(domain, iova, gfp_order);
+ return total_unmapped;
}
EXPORT_SYMBOL_GPL(iommu_unmap);
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c
index e8fdb88..4a8f761 100644
--- a/drivers/iommu/omap-iovmm.c
+++ b/drivers/iommu/omap-iovmm.c
@@ -409,7 +409,6 @@ static int map_iovm_area(struct iommu_domain
*domain, struct iovm_struct *new,
unsigned int i, j;
struct scatterlist *sg;
u32 da = new->da_start;
- int order;
if (!domain || !sgt)
return -EINVAL;
@@ -428,12 +427,10 @@ static int map_iovm_area(struct iommu_domain
*domain, struct iovm_struct *new,
if (bytes_to_iopgsz(bytes) < 0)
goto err_out;
- order = get_order(bytes);
-
pr_debug("%s: [%d] %08x %08x(%x)\n", __func__,
i, da, pa, bytes);
- err = iommu_map(domain, da, pa, order, flags);
+ err = iommu_map(domain, da, pa, bytes, flags);
if (err)
goto err_out;
@@ -448,10 +445,9 @@ err_out:
size_t bytes;
bytes = sg->length + sg->offset;
- order = get_order(bytes);
/* ignore failures.. we're already handling one */
- iommu_unmap(domain, da, order);
+ iommu_unmap(domain, da, bytes);
da += bytes;
}
@@ -474,13 +470,11 @@ static void unmap_iovm_area(struct iommu_domain
*domain, struct omap_iommu *obj,
start = area->da_start;
for_each_sg(sgt->sgl, sg, sgt->nents, i) {
size_t bytes;
- int order;
bytes = sg->length + sg->offset;
- order = get_order(bytes);
- err = iommu_unmap(domain, start, order);
- if (err < 0)
+ err = iommu_unmap(domain, start, bytes);
+ if (err < bytes)
break;
dev_dbg(obj->dev, "%s: unmap %08x(%x) %08x\n",
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 710291f..a10a86c 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -48,6 +48,22 @@ struct iommu_domain {
#ifdef CONFIG_IOMMU_API
+/**
+ * struct iommu_ops - iommu ops and capabilities
+ * @domain_init: init iommu domain
+ * @domain_destroy: destroy iommu domain
+ * @attach_dev: attach device to an iommu domain
+ * @detach_dev: detach device from an iommu domain
+ * @map: map a physically contiguous memory region to an iommu domain
+ * @unmap: unmap a physically contiguous memory region from an iommu domain
+ * @iova_to_phys: translate iova to physical address
+ * @domain_has_cap: domain capabilities query
+ * @commit: commit iommu domain
+ * @pgsize_bitmap: bitmap of supported page sizes
+ * @min_pagesz: smallest page size supported. note: this member is private
+ * to the IOMMU core, and maintained only for efficiency sake;
+ * drivers don't need to set it.
+ */
struct iommu_ops {
int (*domain_init)(struct iommu_domain *domain);
void (*domain_destroy)(struct iommu_domain *domain);
@@ -62,6 +78,8 @@ struct iommu_ops {
int (*domain_has_cap)(struct iommu_domain *domain,
unsigned long cap);
void (*commit)(struct iommu_domain *domain);
+ unsigned long pgsize_bitmap;
+ unsigned int min_pagesz;
};
extern int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops);
@@ -73,9 +91,9 @@ extern int iommu_attach_device(struct iommu_domain *domain,
extern void iommu_detach_device(struct iommu_domain *domain,
struct device *dev);
extern int iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, int gfp_order, int prot);
+ phys_addr_t paddr, int size, int prot);
extern int iommu_unmap(struct iommu_domain *domain, unsigned long iova,
- int gfp_order);
+ int size);
extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
unsigned long iova);
extern int iommu_domain_has_cap(struct iommu_domain *domain,
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
index ca409be..26b3199 100644
--- a/virt/kvm/iommu.c
+++ b/virt/kvm/iommu.c
@@ -111,7 +111,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct
kvm_memory_slot *slot)
/* Map into IO address space */
r = iommu_map(domain, gfn_to_gpa(gfn), pfn_to_hpa(pfn),
- get_order(page_size), flags);
+ page_size, flags);
if (r) {
printk(KERN_ERR "kvm_iommu_map_address:"
"iommu failed to map pfn=%llx\n", pfn);
@@ -292,15 +292,15 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
while (gfn < end_gfn) {
unsigned long unmap_pages;
- int order;
+ int size;
/* Get physical address */
phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn));
pfn = phys >> PAGE_SHIFT;
/* Unmap address from IO address space */
- order = iommu_unmap(domain, gfn_to_gpa(gfn), 0);
- unmap_pages = 1ULL << order;
+ size = iommu_unmap(domain, gfn_to_gpa(gfn), PAGE_SIZE);
+ unmap_pages = 1ULL << get_order(size);
/* Unpin all pages we just unmapped to not leak any memory */
kvm_unpin_pages(kvm, pfn, unmap_pages);
^ permalink raw reply related
* [PATCHv16 0/9] Contiguous Memory Allocator
From: Andrew Morton @ 2011-10-10 22:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201110071827.06366.arnd@arndb.de>
On Fri, 7 Oct 2011 18:27:06 +0200
Arnd Bergmann <arnd@arndb.de> wrote:
> On Thursday 06 October 2011, Marek Szyprowski wrote:
> > Once again I decided to post an updated version of the Contiguous Memory
> > Allocator patches.
> >
> > This version provides mainly a bugfix for a very rare issue that might
> > have changed migration type of the CMA page blocks resulting in dropping
> > CMA features from the affected page block and causing memory allocation
> > to fail. Also the issue reported by Dave Hansen has been fixed.
> >
> > This version also introduces basic support for x86 architecture, what
> > allows wide testing on KVM/QEMU emulators and all common x86 boxes. I
> > hope this will result in wider testing, comments and easier merging to
> > mainline.
>
> Hi Marek,
>
> I think we need to finally get this into linux-next now, to get some
> broader testing. Having the x86 patch definitely helps here becauses
> it potentially exposes the code to many more testers.
>
> IMHO it would be good to merge the entire series into 3.2, since
> the ARM portion fixes an important bug (double mapping of memory
> ranges with conflicting attributes) that we've lived with for far
> too long, but it really depends on how everyone sees the risk
> for regressions here. If something breaks in unfixable ways before
> the 3.2 release, we can always revert the patches and have another
> try later.
>
> It's also not clear how we should merge it. Ideally the first bunch
> would go through linux-mm, and the architecture specific patches
> through the respective architecture trees, but there is an obvious
> inderdependency between these sets.
>
> Russell, Andrew, are you both comfortable with putting the entire
> set into linux-mm to solve this? Do you see this as 3.2 or rather
> as 3.3 material?
>
Russell's going to hate me, but...
I do know that he had substantial objections to at least earlier
versions of this, and he is a guy who knows of what he speaks.
So I would want to get a nod from rmk on this work before proceeding.
If that nod isn't available then let's please identify the issues and
see what we can do about them.
^ permalink raw reply
* [PATCHv9 03/18] TEMP: OMAP3xxx: hwmod data: add PRM hwmod
From: Paul Walmsley @ 2011-10-10 23:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E936F0E.9050203@ti.com>
On Tue, 11 Oct 2011, Cousson, Benoit wrote:
> In fact the device name does not have to match the hwmod name. So we can just
> create an "omap2_prm" omap_device for OMAP2, "omap3_prm" omap_device for
> OMAP3...
> That will allow the relevant PRM driver to be bound to the proper device.
Incidentally, given that we would be using the hwmod name and the version
number to determine the appropriate omap_device name, what IP version
numbers should we assign to these PRM IP blocks for different SoCs?
- Paul
^ permalink raw reply
* [PATCH v6 06/16] OMAP2+: UART: Remove certain feilds from omap_uart_state struct
From: Kevin Hilman @ 2011-10-10 23:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317380495-584-6-git-send-email-govindraj.raja@ti.com>
"Govindraj.R" <govindraj.raja@ti.com> writes:
> Removing some of the uart info that is maintained in omap_uart_state struct
> used for UART PM in serial.c.
>
> Remove omap_uart_state struct dependency from omap_serial_init,
> omap_serial_init_port, omap_serial_early_init and omap_uart_idle_init
> functions. And populate the same info in omap_uart_port_info struct
> used as pdata struct.
IMO, this change doesn't belong in this patch and leads to clutter. The
rest of the series slowly removes/replaces all the fields from this
struct, so the right place to remove it's usage all together is at the
end of the series when (if) all the fields are no longer needed (or have
been moved.)
Stated differently, IMO, this patch should leave the uart->num and
uart->oh and the list_head (uart->node) alone (probably uart->pdev too)
and just cleanup the fields that are no longer used. Removing num, oh,
node here causes churn because you're force to change things here that
are then removed in later patches.
> Added omap_uart_hwmod_lookup function to look up oh by name used in
> serial_port_init and omap_serial_early_init functions.
Because of the above change, you now are doing a hwmod lookup 2 times
for every UART. Leaving the uart_list and uart->num in place will avoid
the need for that change.
> A list of omap_uart_state was maintained one for each uart, the same
> is removed. Number of uarts available is maintained in num_uarts
> field, re-use the same in omap_serial_init func to register each uart.
>
> Remove omap_info which used details from omap_uart_state and use a
> pdata pointer to pass platform specific info to driver.
There is no omap_info. Did you mean omap_up_info?
> The mapbase (start_address), membase(io_remap cookie) maintained as
> part of uart_state struct and pdata struct are removed as this is
> handled within driver.
This part makes sense.
> Errata field is also moved to pdata.
Why in this patch instead of the subsequent "Move errata handling from
serial.c to omap-serial" patch?
> These changes are done to cleanup serial.c file and prepare for
> runtime changes.
There are a lot of changes in this patch with very little description as
to why, and many appear to be unrelated. They should probably be
separate patches, or have a better description as to how all the changes
are related so they belong in the same patch.
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
> ---
> arch/arm/mach-omap2/serial.c | 132 +++++++++---------------
> arch/arm/plat-omap/include/plat/omap-serial.h | 4 +-
> drivers/tty/serial/omap-serial.c | 12 ++-
> 3 files changed, 61 insertions(+), 87 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
> index c98b9b4..8c43d1c 100644
> --- a/arch/arm/mach-omap2/serial.c
> +++ b/arch/arm/mach-omap2/serial.c
> @@ -68,14 +68,6 @@ struct omap_uart_state {
> int clocked;
>
> int regshift;
> - void __iomem *membase;
> - resource_size_t mapbase;
> -
> - struct list_head node;
> - struct omap_hwmod *oh;
> - struct platform_device *pdev;
> -
> - u32 errata;
> #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
> int context_valid;
>
> @@ -90,7 +82,6 @@ struct omap_uart_state {
> #endif
> };
>
> -static LIST_HEAD(uart_list);
> static u8 num_uarts;
>
> static int uart_idle_hwmod(struct omap_device *od)
> @@ -143,7 +134,19 @@ static inline void serial_write_reg(struct omap_uart_state *uart, int offset,
> __raw_writeb(value, uart->membase + offset);
> }
>
> -#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
> +struct omap_hwmod *omap_uart_hwmod_lookup(int num)
> +{
> + struct omap_hwmod *oh;
> + char oh_name[MAX_UART_HWMOD_NAME_LEN];
> +
> + snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN, "uart%d", num + 1);
> + oh = omap_hwmod_lookup(oh_name);
> + WARN(IS_ERR(oh), "Could not lookup hmwod info for %s\n",
> + oh_name);
> + return oh;
> +}
> +
> +#if defined(CONFIG_PM)
The CONFIG_ARCH_OMAP3 part of this #if was dropped with this change with
no mention as to why. (I understand why it was done, but it's not
releveant to $SUBJECT patch so should be a separate patch.)
> /*
> * Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6)
> @@ -357,22 +360,17 @@ int omap_uart_can_sleep(void)
> return can_sleep;
> }
>
> -static void omap_uart_idle_init(struct omap_uart_state *uart)
> +static void omap_uart_idle_init(struct omap_uart_port_info *uart,
> + unsigned short num)
> {
> - int ret;
> -
> - uart->can_sleep = 0;
> - omap_uart_smart_idle_enable(uart, 0);
> -
> if (cpu_is_omap34xx() && !cpu_is_ti816x()) {
> - u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
> + u32 mod = (num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
> u32 wk_mask = 0;
> u32 padconf = 0;
>
> - /* XXX These PRM accesses do not belong here */
why?
> uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
> uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
> - switch (uart->num) {
> + switch (num) {
> case 0:
> wk_mask = OMAP3430_ST_UART1_MASK;
> padconf = 0x182;
> @@ -391,12 +389,11 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
> break;
> }
> uart->wk_mask = wk_mask;
> - uart->padconf = padconf;
The assignment is removed here, making all the rest of the padconf stuff
that remains useless.
However, a subsequent patch removes the mux stuff entirely, so I suggest
you just drop this change from here.
> } else if (cpu_is_omap24xx()) {
> u32 wk_mask = 0;
> u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
>
> - switch (uart->num) {
> + switch (num) {
> case 0:
> wk_mask = OMAP24XX_ST_UART1_MASK;
> break;
> @@ -421,7 +418,6 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
> uart->wk_en = NULL;
> uart->wk_st = NULL;
> uart->wk_mask = 0;
> - uart->padconf = 0;
> }
> }
>
> @@ -436,26 +432,13 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart)
>
> static int __init omap_serial_early_init(void)
> {
> - int i = 0;
> -
> do {
> - char oh_name[MAX_UART_HWMOD_NAME_LEN];
> struct omap_hwmod *oh;
> - struct omap_uart_state *uart;
>
> - snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN,
> - "uart%d", i + 1);
> - oh = omap_hwmod_lookup(oh_name);
> + oh = omap_uart_hwmod_lookup(num_uarts);
> if (!oh)
> break;
>
> - uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);
> - if (WARN_ON(!uart))
> - return -ENODEV;
> -
> - uart->oh = oh;
> - uart->num = i++;
> - list_add_tail(&uart->node, &uart_list);
> num_uarts++;
>
> /*
> @@ -468,7 +451,7 @@ static int __init omap_serial_early_init(void)
> * to determine SoC specific init before omap_device
> * is ready. Therefore, don't allow idle here
> */
> - uart->oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
> + oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
> } while (1);
>
> return 0;
> @@ -488,57 +471,47 @@ core_initcall(omap_serial_early_init);
> */
> void __init omap_serial_init_port(struct omap_board_data *bdata)
> {
> - struct omap_uart_state *uart;
> struct omap_hwmod *oh;
> struct platform_device *pdev;
> - void *pdata = NULL;
> + char *name = DRIVER_NAME;
> + struct omap_uart_port_info *pdata;
> u32 pdata_size = 0;
> - char *name;
> - struct omap_uart_port_info omap_up;
>
> if (WARN_ON(!bdata))
> return;
> if (WARN_ON(bdata->id < 0))
> return;
> - if (WARN_ON(bdata->id >= num_uarts))
> + if (WARN_ON(bdata->id >= OMAP_MAX_HSUART_PORTS))
why? because of early_init, num_uarts is already the max number
of UARTs available (based on hwmod probe.)
> return;
>
> - list_for_each_entry(uart, &uart_list, node)
> - if (bdata->id == uart->num)
> - break;
> -
> - oh = uart->oh;
> - uart->dma_enabled = 0;
> - name = DRIVER_NAME;
> + oh = omap_uart_hwmod_lookup(bdata->id);
> + if (!oh)
> + return;
>
> - omap_up.dma_enabled = uart->dma_enabled;
> - omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
> - omap_up.mapbase = oh->slaves[0]->addr->pa_start;
> - omap_up.membase = omap_hwmod_get_mpu_rt_va(oh);
> - omap_up.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
> + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
> + if (!pdata) {
> + pr_err("Memory allocation for UART pdata failed\n");
> + return;
> + }
>
> - pdata = &omap_up;
> pdata_size = sizeof(struct omap_uart_port_info);
> + omap_uart_idle_init(pdata, bdata->id);
Why was this moved here?
ISTR that the order of this call relative to the hwmod/omap_device
enable/disable calls below was important, especially in the DEBUG_LL
case.
> - if (WARN_ON(!oh))
> - return;
> + pdata->uartclk = OMAP24XX_BASE_BAUD * 16;
> + pdata->flags = UPF_BOOT_AUTOCONF;
> +
> + /* Enable the MDR1 errata for OMAP3 */
> + if (cpu_is_omap34xx() && !cpu_is_ti816x())
> + pdata->errata |= UART_ERRATA_i202_MDR1_ACCESS;
>
> - pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size,
> - omap_uart_latency,
> - ARRAY_SIZE(omap_uart_latency), false);
> + pdev = omap_device_build(name, bdata->id, oh, pdata,
> + pdata_size, omap_uart_latency,
> + ARRAY_SIZE(omap_uart_latency), false);
Note the unecesary whitespace changes in this change.
> WARN(IS_ERR(pdev), "Could not build omap_device for %s: %s.\n",
> name, oh->name);
>
> - omap_device_disable_idle_on_suspend(pdev);
This should also be a separate patch at the end of the series, and is
not related to the changes described in the changelog.
> oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt);
>
> - uart->regshift = 2;
> - uart->mapbase = oh->slaves[0]->addr->pa_start;
> - uart->membase = omap_hwmod_get_mpu_rt_va(oh);
> - uart->pdev = pdev;
> -
> - oh->dev_attr = uart;
> -
> console_lock(); /* in case the earlycon is on the UART */
>
> /*
> @@ -546,23 +519,18 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
> * on init. Now that omap_device is ready, ensure full idle
> * before doing omap_device_enable().
> */
> - omap_hwmod_idle(uart->oh);
> + omap_hwmod_idle(oh);
>
> - omap_device_enable(uart->pdev);
> - omap_uart_idle_init(uart);
> - omap_hwmod_enable_wakeup(uart->oh);
> - omap_device_idle(uart->pdev);
> + omap_device_enable(pdev);
> + omap_hwmod_enable_wakeup(oh);
>
> - omap_uart_block_sleep(uart);
> console_unlock();
>
> - if ((cpu_is_omap34xx() && uart->padconf) ||
> - (uart->wk_en && uart->wk_mask))
> + if ((cpu_is_omap34xx() && bdata->pads) ||
> + (pdata->wk_en && pdata->wk_mask))
This change seems to belong as part of the mux patch.
> device_init_wakeup(&pdev->dev, true);
>
> - /* Enable the MDR1 errata for OMAP3 */
> - if (cpu_is_omap34xx() && !cpu_is_ti816x())
> - uart->errata |= UART_ERRATA_i202_MDR1_ACCESS;
> + kfree(pdata);
> }
>
> /**
> @@ -574,11 +542,11 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
> */
> void __init omap_serial_init(void)
> {
> - struct omap_uart_state *uart;
> struct omap_board_data bdata;
> + u8 i;
>
> - list_for_each_entry(uart, &uart_list, node) {
> - bdata.id = uart->num;
> + for (i = 0; i < num_uarts; i++) {
> + bdata.id = i;
> bdata.flags = 0;
> bdata.pads = NULL;
> bdata.pads_cnt = 0;
> diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
> index 307cd6f..0f061b4 100644
> --- a/arch/arm/plat-omap/include/plat/omap-serial.h
> +++ b/arch/arm/plat-omap/include/plat/omap-serial.h
> @@ -59,9 +59,9 @@
> struct omap_uart_port_info {
> bool dma_enabled; /* To specify DMA Mode */
> unsigned int uartclk; /* UART clock rate */
> - void __iomem *membase; /* ioremap cookie or NULL */
> - resource_size_t mapbase; /* resource base */
> upf_t flags; /* UPF_* flags */
> +
> + u32 errata;
> };
>
> struct uart_omap_dma {
> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
> index 5e713d3..6c2ea54 100644
> --- a/drivers/tty/serial/omap-serial.c
> +++ b/drivers/tty/serial/omap-serial.c
> @@ -1275,10 +1275,16 @@ static int serial_omap_probe(struct platform_device *pdev)
> up->port.ops = &serial_omap_pops;
> up->port.line = pdev->id;
>
> - up->port.membase = omap_up_info->membase;
> - up->port.mapbase = omap_up_info->mapbase;
> + up->port.mapbase = mem->start;
> + up->port.membase = ioremap(mem->start, resource_size(mem));
> +
> + if (!up->port.membase) {
> + dev_err(&pdev->dev, "can't ioremap UART\n");
> + ret = -ENOMEM;
> + goto err;
> + }
> +
> up->port.flags = omap_up_info->flags;
> - up->port.irqflags = omap_up_info->irqflags;
> up->port.uartclk = omap_up_info->uartclk;
> up->uart_dma.uart_base = mem->start;
Kevin
^ permalink raw reply
* [PATCH v6 09/16] OMAP2+: UART: Add runtime pm support for omap-serial driver
From: Kevin Hilman @ 2011-10-10 23:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317380495-584-9-git-send-email-govindraj.raja@ti.com>
"Govindraj.R" <govindraj.raja@ti.com> writes:
> Adapts omap-serial driver to use pm_runtime API's.
[...]
> @@ -1065,19 +1123,18 @@ static struct uart_driver serial_omap_reg = {
> .cons = OMAP_CONSOLE,
> };
>
> -static int
> -serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
> +static int serial_omap_suspend(struct device *dev)
> {
> - struct uart_omap_port *up = platform_get_drvdata(pdev);
> + struct uart_omap_port *up = dev_get_drvdata(dev);
>
> if (up)
> uart_suspend_port(&serial_omap_reg, &up->port);
> return 0;
> }
>
> -static int serial_omap_resume(struct platform_device *dev)
> +static int serial_omap_resume(struct device *dev)
> {
> - struct uart_omap_port *up = platform_get_drvdata(dev);
> + struct uart_omap_port *up = dev_get_drvdata(dev);
>
> if (up)
> uart_resume_port(&serial_omap_reg, &up->port);
These functions need to be wrapped in #ifdef CONFIG_SUSPEND, otherwise,
when building with !CONFIG_SUSPEND you'll get :
/work/kernel/omap/pm/drivers/tty/serial/omap-serial.c:1134:12: warning: 'serial_omap_suspend' defined but not used
/work/kernel/omap/pm/drivers/tty/serial/omap-serial.c:1150:12: warning: 'serial_omap_resume' defined but not used
[...]
> +static int serial_omap_runtime_suspend(struct device *dev)
> +{
> + struct uart_omap_port *up = dev_get_drvdata(dev);
> + struct omap_uart_port_info *pdata = dev->platform_data;
> +
> + if (!up)
> + return -EINVAL;
> +
> + if (!pdata->enable_wakeup || !pdata->get_context_loss_count)
> + return 0;
> +
> + if (pdata->get_context_loss_count)
> + up->context_loss_cnt = pdata->get_context_loss_count(dev);
> +
> + if (device_may_wakeup(dev)) {
> + if (!up->wakeups_enabled) {
> + pdata->enable_wakeup(up->pdev, true);
> + up->wakeups_enabled = true;
> + }
> + } else {
> + if (up->wakeups_enabled) {
> + pdata->enable_wakeup(up->pdev, false);
> + up->wakeups_enabled = false;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int serial_omap_runtime_resume(struct device *dev)
> +{
> + struct uart_omap_port *up = dev_get_drvdata(dev);
> + struct omap_uart_port_info *pdata = dev->platform_data;
> +
> + if (up) {
> + if (pdata->get_context_loss_count) {
> + u32 loss_cnt = pdata->get_context_loss_count(dev);
> +
> + if (up->context_loss_cnt != loss_cnt)
> + serial_omap_restore_context(up);
> + }
> + }
> +
> return 0;
> }
Similarily, thse need to be wrapped with #ifdef CONFIG_PM_RUNTIME,
otherwise, when !CONFIG_PM_RUNTIME:
/work/kernel/omap/pm/drivers/tty/serial/omap-serial.c:1498:12: warning: 'serial_omap_runtime_suspend' defined but not used
/work/kernel/omap/pm/drivers/tty/serial/omap-serial.c:1531:12: warning: 'serial_omap_runtime_resume' defined but not used
> +static const struct dev_pm_ops serial_omap_dev_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(serial_omap_suspend, serial_omap_resume)
> + SET_RUNTIME_PM_OPS(serial_omap_runtime_suspend,
> + serial_omap_runtime_resume, NULL)
> +};
> +
Note that you don't need #else parts to the above #ifdefs since
the SET_*_OPS() macros used here take care of that.
Kevin
^ permalink raw reply
* [PATCH v6 09/16] OMAP2+: UART: Add runtime pm support for omap-serial driver
From: Kevin Hilman @ 2011-10-10 23:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317380495-584-9-git-send-email-govindraj.raja@ti.com>
"Govindraj.R" <govindraj.raja@ti.com> writes:
> Adapts omap-serial driver to use pm_runtime API's.
>
> Use runtime runtime API's to handle uart clocks and obtain
> device_usage statics. Set runtime API's usage to irq_safe so that
> we can use get_sync from irq context. Auto-suspend for port specific
> activities and put for reg access. Use device_may_wakeup to check
> whether uart has wakeup capabilities and then enable uart runtime
> usage for the uart.
OK. Current patch should do only this part. The rest should be
separate patches with their own descriptive changelogs.
> Removing save_context/restore_context functions from serial.c
> Adding context restore to .runtime_suspend and using reg values from port
> structure to restore the uart port context based on context_loss_count.
> Maintain internal state machine using wakeups_enabled field for avoiding
> repeated enable/disable of uart port wakeup mechanism.
This part should be a separate patch that follows.
> Remove omap_uart_disable_wakeup and modify omap_uart_enable_wakeup
> to accept pdev and bool value to enable/disable the uart wakeup mechanism
> after uart clock's are cut.
>
> omap_hwmod_enable_wakeup is used to set
> pad wakeup for the uarts. PM_WKEN reg values are left to default.
> Removed omap_uart_enable/disable_clocks in serial.c now clock handling
> done with runtime API's.
As stated in previous reviews, this wakeup enable/disable needs more
description as the functionality is changing compared to current code.
Current version modifies wakeup enable/disable at both power-domain
level (PM_WKEN) and at the IO ring.
Updated version modifies wakeups at module-level (SYSCONFIG) and at IO
ring using omap_hwmod_enable_wakeup()
IMO, the updated version makes more sense, but needs a description as to
why that change in functionality will have equivalent results compared
to the existing one.
> By default uart autosuspend delay is set to -1 to avoid character loss
> if uart's are autoidled and woken up on rx pin.
OK, good.
> After boot up UART's can be autoidled by setting autosuspendi delay from sysfs.
>
> echo 3000 > /sys/devices/platform/omap/omap_uart.X/power/autosuspend_delay_ms
> X=0,1,2,3 for UART1/2/3/4. Number of uarts available may vary across omap_soc.
>
> Acked-by: Alan Cox <alan@linux.intel.com>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
Kevin
^ permalink raw reply
* [PATCH v6 08/16] OMAP2+: UART: Store certain reg values to port structure
From: Kevin Hilman @ 2011-10-10 23:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317380495-584-8-git-send-email-govindraj.raja@ti.com>
"Govindraj.R" <govindraj.raja@ti.com> writes:
> In preparation to runtime conversion add missing uart regs to
> port structure which can be used in context restore.
> Also ensuring all uart reg info's are part of port structure.
>
> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
IMO, this should come later in the series to avoid adding bunch of code
that gets moved in a subsequent patch.
First, convert to runtime PM (current patch 9/16)
Then, add a patch to move context save/restore into driver.
Then, add this patch.
Kevin
^ permalink raw reply
* Please update linux-next url for tegra
From: Stephen Rothwell @ 2011-10-11 0:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOesGMjT+vyC8Jsjshrcz2f2xC=VEw+dTQh-rqLpjJMH5OJnag@mail.gmail.com>
Hi Olof,
On Mon, 10 Oct 2011 11:09:19 -0700 Olof Johansson <olof@lixom.net> wrote:
>
> I'm taking over running the main tegra repo for a while, so please
> change the old android.git.kernel.org-hosted branch to instead pull:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/olof/tegra.git for-next
OK, I will switch to this from today.
> And please pull it after the arm-soc tree.
No worries.
--
Cheers,
Stephen Rothwell sfr at canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20111011/29cdf877/attachment.sig>
^ permalink raw reply
* [PATCH 3/3] ARM: SAMSUNG: Add lookup of sdhci-s3c clocks using generic names
From: Rajeshwari Birje @ 2011-10-11 3:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201110050930.32216.heiko@sntech.de>
Hi Heiko,
Thank you for your comments,
Will work on the same and post the modified patches.
Regards,
Rajeshwari Shinde.
On Wed, Oct 5, 2011 at 1:00 PM, Heiko St?bner <heiko@sntech.de> wrote:
> Am Mittwoch, 5. Oktober 2011, 07:31:09 schrieb Rajeshwari Shinde:
>> Add support for lookup of sdhci-s3c controller clocks using generic names
>> for s3c2416, s3c64xx, s5pc100, s5pv210 and exynos4 SoC's.
>>
>> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
>> ---
>
> [...]
>
>> diff --git a/arch/arm/mach-s3c2416/clock.c b/arch/arm/mach-s3c2416/clock.c
>> index 72b7c62..cebaf3f 100644
>> --- a/arch/arm/mach-s3c2416/clock.c
>> +++ b/arch/arm/mach-s3c2416/clock.c
>
> [...]
>
>> @@ -143,8 +142,14 @@ static struct clksrc_clk *clksrcs[] __initdata = {
>> ? ? ? &hsspi_mux,
>> ? ? ? &hsmmc_div[0],
>> ? ? ? &hsmmc_div[1],
>> - ? ? &hsmmc_mux[0],
>> - ? ? &hsmmc_mux[1],
>> + ? ? &hsmmc_mux0,
>> + ? ? &hsmmc_mux1,
>> +};
>> +
>> +static struct clk_lookup s3c2416_clk_lookup[] = {
>> + ? ? CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk),
> This is missing the s3c-sdhci.1 mmc_busclk.0 as 4th entry which is defined in
> s3c2443-clock.c. The pclk for hsmmc1 is common to S3C2416/2450 and S3C2443 and
> is therefore defined in plat-s3c24xx [S3C2443 only has a hsmmc1 to be exact].
>
> Also it would be nice to include the hsmmc-clock in mach-s3c2443/clock.c too.
> The sdhci support there seems to be incomplete but it would be nice to have
> the clocks similar to everything else if anyone wants to start on this arch.
>
>> + ? ? CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk),
>> + ? ? CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk),
>> ?};
>>
>> ?void __init s3c2416_init_clocks(int xtal)
>> @@ -164,6 +169,7 @@ void __init s3c2416_init_clocks(int xtal)
>> ? ? ? ? ? ? ? s3c_register_clksrc(clksrcs[ptr], 1);
>>
>> ? ? ? s3c24xx_register_clock(&hsmmc0_clk);
>> + ? ? clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup));
>>
>> ? ? ? s3c_pwmclk_init();
>>
>
> Heiko
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH v2 5/5] regulator: map consumer regulator based on device tree
From: Rajendra Nayak @ 2011-10-11 5:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111010173506.GH3607@opensource.wolfsonmicro.com>
>
>> @@ -1178,6 +1225,10 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
>> goto found;
>> }
>> }
>> + if (!dev)
>> + list_for_each_entry(rdev,®ulator_list, list)
>> + if (strcmp(rdev_get_name(rdev), id))
>> + goto found;
>>
>
> This looks really strange, we didn't remove any old lookup code and the
> DT lookup jumps to found by iself so why are we adding code here?
The old lookup code looks up using the regulator_map_list, and the dt
lookup depends on a dev pointer to extract the of_node.
This above code was needed for cases when a regulator_get() would be
called on dt builds without specifying a device pointer, like the
cpufreq implementations you mentioned.
This is what I tried putting in the comments above the lookup code.
/*
* Lookup happens in 3 ways
* 1. If a dev and dev->of_node exist, look for a
* regulator mapping in dt node.
* 2. Check if a match can be found in regulator_map_list
* if regulator info is still passed in non-dt way
* 3. if !dev, then just look for a matching regulator name.
* Useful for dt builds using regulator_get() without specifying
* a device.
*/
I know its quite complicated but thats because we need to support both
the legacy and the dt based lookups.
>
>> + if (supply) {
>> + struct regulator_dev *r;
>> + struct device_node *node;
>> +
>> + /* first do a dt based lookup */
>> + if (dev) {
>> + node = of_get_regulator(dev, supply);
>> + if (node)
>> + list_for_each_entry(r,®ulator_list, list)
>> + if (node == r->dev.parent->of_node)
>> + goto found;
>> }
>>
>> - if (!found) {
>> - dev_err(dev, "Failed to find supply %s\n",
>> - init_data->supply_regulator);
>> - ret = -ENODEV;
>> - goto scrub;
>> - }
>> + /* next try doing it non-dt way */
>> + list_for_each_entry(r,®ulator_list, list)
>> + if (strcmp(rdev_get_name(r), supply) == 0)
>> + goto found;
>>
>> + dev_err(dev, "Failed to find supply %s\n", supply);
>> + ret = -ENODEV;
>> + goto scrub;
>> +
>> +found:
>
> This is all getting *really* complicated and illegible. I'm not sure
> what the best way to structure is but erroring out early looks useful.
^ permalink raw reply
* [PATCH v2 3/5] regulator: helper routine to extract regulator_init_data
From: Rajendra Nayak @ 2011-10-11 5:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111010172222.GG3607@opensource.wolfsonmicro.com>
On Monday 10 October 2011 10:52 PM, Mark Brown wrote:
> On Mon, Oct 10, 2011 at 09:49:36PM +0530, Rajendra Nayak wrote:
>
>> +- regulator-change-voltage: boolean, Output voltage can be changed by software
>> +- regulator-change-current: boolean, Output current can be chnaged by software
>> +- regulator-change-mode: boolean, Operating mode can be changed by software
>> +- regulator-change-status: boolean, Enable/Disable control for regulator exists
>> +- regulator-change-drms: boolean, Dynamic regulator mode switching is enabled
>> +- regulator-mode-fast: boolean, allow/set fast mode for the regulator
>> +- regulator-mode-normal: boolean, allow/set normal mode for the regulator
>> +- regulator-mode-idle: boolean, allow/set idle mode for the regulator
>> +- regulator-mode-standby: boolean, allow/set standby mode for the regulator
>> +- regulator-input-uV: Input voltage for regulator when supplied by another regulator
>> +- regulator-always-on: boolean, regulator should never be disabled
>
> Thinking about this I'm not sure that these should go in the device
> tree, they're as much talking about what Linux is able to cope with as
> they are talking about what the hardware is able to do. Sometimes
> they'll be fixed by the design but they are sometimes also restricted by
> what the software is currently capable of. DRMS is a prime example
> here, it depends on how good we are at telling the API about how much
> current we're using.
So is there another way of passing these, if not through device tree?
There are other linux specific things that need to be passed to the
framework as well, like the state of the regulator in the various
linux specific suspend states, like standby/mem/disk.
So if these can't be passed through device tree, should they still
be passed in some way through platform_data? Or is it best to identify
the bindings as being linux specific and not generic by appending a
"linux," to the bindings.
Grant, need some help and advice.
^ permalink raw reply
* [PATCH v6 02/16] OMAP2+: hwmod: Add API to check IO PAD wakeup status
From: Govindraj @ 2011-10-11 6:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <878vosh4ds.fsf@ti.com>
On Tue, Oct 11, 2011 at 3:54 AM, Kevin Hilman <khilman@ti.com> wrote:
> Govindraj <govindraj.ti@gmail.com> writes:
>
>> On Mon, Oct 3, 2011 at 10:53 AM, Rajendra Nayak <rnayak@ti.com> wrote:
>>> On Monday 03 October 2011 10:30 AM, Govindraj wrote:
>>>
>>>> On Sat, Oct 1, 2011 at 8:03 PM, Rajendra Nayak<rnayak@ti.com> ?wrote:
>>>>>
>>>>> On Friday 30 September 2011 04:31 PM, Govindraj.R wrote:
>>>>>>
>>>>>> Add API to determine IO-PAD wakeup event status for a given
>>>>>> hwmod dynamic_mux pad.
>>>>>>
>>>>>> Wake up event set will be cleared on pad mux_read.
>>>>>
>>>>> Are these api's even getting used in this series?
>>>>
>>>> Used in Tero's irq_chaining patches.
>>>
>>> So shouldn't this patch be part of his series instead?
>>
>> Yes it is. Part of his v9-series.
>>
>
> Then please drop from this series and state the introductory patch
> (PATCH 0/n) that this series has a dependency on Tero's series.
>
Okay.
--
Thanks,
Govindraj.R
^ permalink raw reply
* [PATCH v6 05/16] OMAP2+: UART: Cleanup part of clock gating mechanism for uart
From: Govindraj @ 2011-10-11 6:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87ty7gfpik.fsf@ti.com>
On Tue, Oct 11, 2011 at 4:00 AM, Kevin Hilman <khilman@ti.com> wrote:
> "Govindraj.R" <govindraj.raja@ti.com> writes:
>
>> Currently we use a shared irq handler to identify uart activity and then
>> trigger a timer.
>
> OK.
>
>> Based the timeout value set from sysfs the timer used to expire.
>
> Please re-phrase as I'm not sure what is being said here.
>
>> If no uart-activity was detected timer-expiry func sets can_sleep
>> flag. Based on this we will disable the uart clocks in idle path.
>>
>> Since the clock gating mechanism is outside the uart driver, we currently
>> use this mechanism. In preparation to runtime implementation for omap-serial
>> driver we can cleanup this mechanism and use runtime API's to gate uart clocks.
>>
>> Also remove timer related info from local uart_state struct and remove
>> the code used to set timeout value from sysfs. Remove un-used function
>> omap_uart_check_wakeup.
>>
>> Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
>
> The patch itself fine, and is a well-neede cleanup, but changelog
> (especially the first part) does not read well.
>
Okay, Will Correct.
--
Thanks.
Govindraj.R
^ permalink raw reply
* [PATCHv16 0/9] Contiguous Memory Allocator
From: Marek Szyprowski @ 2011-10-11 6:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111010155642.38df59af.akpm@linux-foundation.org>
Hello,
On Tuesday, October 11, 2011 12:57 AM Andrew Morton wrote:
> On Fri, 7 Oct 2011 18:27:06 +0200 Arnd Bergmann <arnd@arndb.de> wrote:
>
> > On Thursday 06 October 2011, Marek Szyprowski wrote:
> > > Once again I decided to post an updated version of the Contiguous Memory
> > > Allocator patches.
> > >
> > > This version provides mainly a bugfix for a very rare issue that might
> > > have changed migration type of the CMA page blocks resulting in dropping
> > > CMA features from the affected page block and causing memory allocation
> > > to fail. Also the issue reported by Dave Hansen has been fixed.
> > >
> > > This version also introduces basic support for x86 architecture, what
> > > allows wide testing on KVM/QEMU emulators and all common x86 boxes. I
> > > hope this will result in wider testing, comments and easier merging to
> > > mainline.
> >
> > Hi Marek,
> >
> > I think we need to finally get this into linux-next now, to get some
> > broader testing. Having the x86 patch definitely helps here becauses
> > it potentially exposes the code to many more testers.
> >
> > IMHO it would be good to merge the entire series into 3.2, since
> > the ARM portion fixes an important bug (double mapping of memory
> > ranges with conflicting attributes) that we've lived with for far
> > too long, but it really depends on how everyone sees the risk
> > for regressions here. If something breaks in unfixable ways before
> > the 3.2 release, we can always revert the patches and have another
> > try later.
> >
> > It's also not clear how we should merge it. Ideally the first bunch
> > would go through linux-mm, and the architecture specific patches
> > through the respective architecture trees, but there is an obvious
> > inderdependency between these sets.
> >
> > Russell, Andrew, are you both comfortable with putting the entire
> > set into linux-mm to solve this? Do you see this as 3.2 or rather
> > as 3.3 material?
> >
>
> Russell's going to hate me, but...
>
> I do know that he had substantial objections to at least earlier
> versions of this, and he is a guy who knows of what he speaks.
I've did my best to fix these issues. I'm still waiting for comments...
Best regards
--
Marek Szyprowski
Samsung Poland R&D Center
^ permalink raw reply
* [PATCH] rtc: rtc-s3c: Add device tree support
From: Thomas Abraham @ 2011-10-11 7:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1315064959-16930-1-git-send-email-thomas.abraham@linaro.org>
On 3 September 2011 21:19, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> Add device tree based discovery support for Samsung's rtc controller.
>
> Cc: Ben Dooks <ben-linux@fluff.org>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
> ?Documentation/devicetree/bindings/rtc/s3c-rtc.txt | ? 20 ++++++++++++++++++++
> ?drivers/rtc/rtc-s3c.c ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? 21 ++++++++++++++++++++-
> ?2 files changed, 40 insertions(+), 1 deletions(-)
> ?create mode 100644 Documentation/devicetree/bindings/rtc/s3c-rtc.txt
Ping. Any comments for this patch? If this looks fine, can this be
considered for 3.2 merge via the Samsung kernel tree.
Thanks,
Thomas.
>
> diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.txt b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt
> new file mode 100644
> index 0000000..90ec45f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt
> @@ -0,0 +1,20 @@
> +* Samsung's S3C Real Time Clock controller
> +
> +Required properties:
> +- compatible: should be one of the following.
> + ? ?* "samsung,s3c2410-rtc" - for controllers compatible with s3c2410 rtc.
> + ? ?* "samsung,s3c6410-rtc" - for controllers compatible with s3c6410 rtc.
> +- reg: physical base address of the controller and length of memory mapped
> + ?region.
> +- interrupts: Two interrupt numbers to the cpu should be specified. First
> + ?interrupt number is the rtc alarm interupt and second interrupt number
> + ?is the rtc tick interrupt. The number of cells representing a interrupt
> + ?depends on the parent interrupt controller.
> +
> +Example:
> +
> + ? ? ? rtc at 10070000 {
> + ? ? ? ? ? ? ? compatible = "samsung,s3c6410-rtc";
> + ? ? ? ? ? ? ? reg = <0x10070000 0x100>;
> + ? ? ? ? ? ? ? interrupts = <44 0 45 0>;
> + ? ? ? };
> diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
> index 4e7c04e..29f928c 100644
> --- a/drivers/rtc/rtc-s3c.c
> +++ b/drivers/rtc/rtc-s3c.c
> @@ -25,6 +25,7 @@
> ?#include <linux/clk.h>
> ?#include <linux/log2.h>
> ?#include <linux/slab.h>
> +#include <linux/of.h>
>
> ?#include <mach/hardware.h>
> ?#include <asm/uaccess.h>
> @@ -481,7 +482,13 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
> ? ? ? ? ? ? ? ?goto err_nortc;
> ? ? ? ?}
>
> - ? ? ? s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
> +#ifdef CONFIG_OF
> + ? ? ? if (pdev->dev.of_node)
> + ? ? ? ? ? ? ? s3c_rtc_cpu_type = of_device_is_compatible(pdev->dev.of_node,
> + ? ? ? ? ? ? ? ? ? ? ? "samsung,s3c6410-rtc") ? TYPE_S3C64XX : TYPE_S3C2410;
> + ? ? ? else
> +#endif
> + ? ? ? ? ? ? ? s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
>
> ? ? ? ?/* Check RTC Time */
>
> @@ -603,6 +610,17 @@ static int s3c_rtc_resume(struct platform_device *pdev)
> ?#define s3c_rtc_resume ?NULL
> ?#endif
>
> +#ifdef CONFIG_OF
> +static const struct of_device_id s3c_rtc_dt_match[] = {
> + ? ? ? { .compatible = "samsung,s3c2410-rtc" },
> + ? ? ? { .compatible = "samsung,s3c6410-rtc" },
> + ? ? ? {},
> +};
> +MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
> +#else
> +#define s3c_rtc_dt_match NULL
> +#endif
> +
> ?static struct platform_device_id s3c_rtc_driver_ids[] = {
> ? ? ? ?{
> ? ? ? ? ? ? ? ?.name ? ? ? ? ? = "s3c2410-rtc",
> @@ -625,6 +643,7 @@ static struct platform_driver s3c_rtc_driver = {
> ? ? ? ?.driver ? ? ? ? = {
> ? ? ? ? ? ? ? ?.name ? = "s3c-rtc",
> ? ? ? ? ? ? ? ?.owner ?= THIS_MODULE,
> + ? ? ? ? ? ? ? .of_match_table = s3c_rtc_dt_match,
> ? ? ? ?},
> ?};
>
> --
> 1.6.6.rc2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH v2 5/5] regulator: map consumer regulator based on device tree
From: Nayak, Rajendra @ 2011-10-11 7:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111010173506.GH3607@opensource.wolfsonmicro.com>
>
>> + ? ? if (supply) {
>> + ? ? ? ? ? ? struct regulator_dev *r;
>> + ? ? ? ? ? ? struct device_node *node;
>> +
>> + ? ? ? ? ? ? /* first do a dt based lookup */
>> + ? ? ? ? ? ? if (dev) {
>> + ? ? ? ? ? ? ? ? ? ? node = of_get_regulator(dev, supply);
>> + ? ? ? ? ? ? ? ? ? ? if (node)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? list_for_each_entry(r, ®ulator_list, list)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (node == r->dev.parent->of_node)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? goto found;
>> ? ? ? ? ? ? ? }
>>
>> - ? ? ? ? ? ? if (!found) {
>> - ? ? ? ? ? ? ? ? ? ? dev_err(dev, "Failed to find supply %s\n",
>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? init_data->supply_regulator);
>> - ? ? ? ? ? ? ? ? ? ? ret = -ENODEV;
>> - ? ? ? ? ? ? ? ? ? ? goto scrub;
>> - ? ? ? ? ? ? }
>> + ? ? ? ? ? ? /* next try doing it non-dt way */
>> + ? ? ? ? ? ? list_for_each_entry(r, ®ulator_list, list)
>> + ? ? ? ? ? ? ? ? ? ? if (strcmp(rdev_get_name(r), supply) == 0)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? goto found;
>>
>> + ? ? ? ? ? ? dev_err(dev, "Failed to find supply %s\n", supply);
>> + ? ? ? ? ? ? ret = -ENODEV;
>> + ? ? ? ? ? ? goto scrub;
>> +
>> +found:
>
> This is all getting *really* complicated and illegible. ?I'm not sure
> what the best way to structure is but erroring out early looks useful.
>
How about this updated patch?
^ 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