* [PATCH v3 1/6] iommu/core: split mapping to page sizes as supported by the hardware
From: Ohad Ben-Cohen @ 2011-09-16 17:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316195506-9777-1-git-send-email-ohad@wizery.com>
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 seemingly MSM too) but
it would probably not fly with intel's hardware, where the page size
capabilities seem to have the potential to be different between
several DMA remapping devices. This limitation can be dealt with
later, if desired. For now, the existing IOMMU API behavior is retained
(see: "iommu/intel: announce supported page sizes").
As requested, register_iommu() isn't changed yet, 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
register_iommu_pgsize() 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.
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: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: kvm at vger.kernel.org
---
drivers/iommu/iommu.c | 158 +++++++++++++++++++++++++++++++++++++++++---
drivers/iommu/omap-iovmm.c | 12 +---
include/linux/iommu.h | 6 +-
virt/kvm/iommu.c | 4 +-
4 files changed, 157 insertions(+), 23 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index c68ff29..7c01c8c 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/kernel.h>
#include <linux/bug.h>
#include <linux/types.h>
@@ -23,15 +25,73 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/iommu.h>
+#include <linux/bitmap.h>
static struct iommu_ops *iommu_ops;
+/* bitmap of supported page sizes */
+static unsigned long *iommu_pgsize_bitmap;
+
+/* number of bits used to represent the supported pages */
+static unsigned int iommu_nr_page_bits;
+
+/* size of the smallest supported page (in bytes) */
+static unsigned int iommu_min_pagesz;
+
+/* bit number of the smallest supported page */
+static unsigned int iommu_min_page_idx;
+
+/**
+ * register_iommu() - register an IOMMU hardware
+ * @ops: iommu handlers
+ * @pgsize_bitmap: bitmap of page sizes supported by the hardware
+ * @nr_page_bits: size of @pgsize_bitmap (in bits)
+ *
+ * Note: this is a temporary function, which will be removed once
+ * all IOMMU drivers are converted. The only reason it exists is to
+ * allow splitting the pgsizes changes to several patches in order to ease
+ * the review.
+ */
+void register_iommu_pgsize(struct iommu_ops *ops, unsigned long *pgsize_bitmap,
+ unsigned int nr_page_bits)
+{
+ if (iommu_ops || iommu_pgsize_bitmap || !nr_page_bits)
+ BUG();
+
+ iommu_ops = ops;
+ iommu_pgsize_bitmap = pgsize_bitmap;
+ iommu_nr_page_bits = nr_page_bits;
+
+ /* find the minimum page size and its index only once */
+ iommu_min_page_idx = find_first_bit(pgsize_bitmap, nr_page_bits);
+ iommu_min_pagesz = 1 << iommu_min_page_idx;
+}
+
+/*
+ * default pagesize bitmap, will be removed once all IOMMU drivers
+ * are converted
+ */
+static unsigned long default_iommu_pgsizes = ~0xFFFUL;
+
void register_iommu(struct iommu_ops *ops)
{
if (iommu_ops)
BUG();
iommu_ops = ops;
+
+ /*
+ * set 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
+ */
+ iommu_pgsize_bitmap = &default_iommu_pgsizes;
+ iommu_nr_page_bits = BITS_PER_LONG;
+
+ /* find the minimum page size and its index only once */
+ iommu_min_page_idx = find_first_bit(iommu_pgsize_bitmap,
+ iommu_nr_page_bits);
+ iommu_min_pagesz = 1 << iommu_min_page_idx;
}
bool iommu_found(void)
@@ -109,26 +169,104 @@ 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;
+ int ret = 0;
+
+ /*
+ * 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, iommu_min_pagesz)) {
+ pr_err("unaligned: iova 0x%lx pa 0x%lx size 0x%lx min_pagesz "
+ "0x%x\n", iova, (unsigned long)paddr,
+ (unsigned long)size, iommu_min_pagesz);
+ return -EINVAL;
+ }
+
+ pr_debug("map: iova 0x%lx pa 0x%lx size 0x%lx\n", iova,
+ (unsigned long)paddr, (unsigned long)size);
+
+ while (size) {
+ unsigned long pgsize = iommu_min_pagesz;
+ unsigned long idx = iommu_min_page_idx;
+ unsigned long addr_merge = iova | paddr;
+ int order;
+
+ /* find the max page size with which iova, paddr are aligned */
+ for (;;) {
+ unsigned long try_pgsize;
+
+ idx = find_next_bit(iommu_pgsize_bitmap,
+ iommu_nr_page_bits, idx + 1);
+
+ /* no more pages to check ? */
+ if (idx >= iommu_nr_page_bits)
+ break;
+
+ try_pgsize = 1 << idx;
- size = 0x1000UL << gfp_order;
+ /* page too big ? addresses not aligned ? */
+ if (size < try_pgsize ||
+ !IS_ALIGNED(addr_merge, try_pgsize))
+ break;
- BUG_ON(!IS_ALIGNED(iova | paddr, size));
+ pgsize = try_pgsize;
+ }
- return iommu_ops->map(domain, iova, paddr, gfp_order, prot);
+ order = get_order(pgsize);
+
+ pr_debug("mapping: iova 0x%lx pa 0x%lx order %d\n", iova,
+ (unsigned long)paddr, order);
+
+ ret = iommu_ops->map(domain, iova, paddr, order, prot);
+ if (ret)
+ break;
+
+ size -= pgsize;
+ iova += pgsize;
+ paddr += pgsize;
+ }
+
+ 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, size_t size)
{
- size_t size;
+ int order, unmapped_size, unmapped_order, total_unmapped = 0;
+
+ /*
+ * 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, iommu_min_pagesz)) {
+ pr_err("unaligned: iova 0x%lx size 0x%lx min_pagesz 0x%x\n",
+ iova, (unsigned long)size, iommu_min_pagesz);
+ return -EINVAL;
+ }
+
+ pr_debug("unmap this: iova 0x%lx size 0x%lx\n", iova,
+ (unsigned long)size);
+
+ while (size > total_unmapped) {
+ order = get_order(size - total_unmapped);
+
+ unmapped_order = iommu_ops->unmap(domain, iova, order);
+ if (unmapped_order < 0)
+ return unmapped_order;
+
+ pr_debug("unmapped: iova 0x%lx order %d\n", iova,
+ unmapped_order);
- size = 0x1000UL << gfp_order;
+ unmapped_size = 0x1000UL << unmapped_order;
- BUG_ON(!IS_ALIGNED(iova, size));
+ iova += unmapped_size;
+ total_unmapped += unmapped_size;
+ }
- return iommu_ops->unmap(domain, iova, gfp_order);
+ return get_order(total_unmapped);
}
EXPORT_SYMBOL_GPL(iommu_unmap);
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c
index e8fdb88..f4dea5a 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,12 +470,10 @@ 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);
+ err = iommu_unmap(domain, start, bytes);
if (err < 0)
break;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index d084e87..1806956 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -61,6 +61,8 @@ struct iommu_ops {
#ifdef CONFIG_IOMMU_API
extern void register_iommu(struct iommu_ops *ops);
+extern void register_iommu_pgsize(struct iommu_ops *ops,
+ unsigned long *pgsize_bitmap, unsigned int nr_page_bits);
extern bool iommu_found(void);
extern struct iommu_domain *iommu_domain_alloc(void);
extern void iommu_domain_free(struct iommu_domain *domain);
@@ -69,9 +71,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, size_t size, int prot);
extern int iommu_unmap(struct iommu_domain *domain, unsigned long iova,
- int gfp_order);
+ 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 78c80f6..ea142d3 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);
@@ -293,7 +293,7 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
pfn = phys >> PAGE_SHIFT;
/* Unmap address from IO address space */
- order = iommu_unmap(domain, gfn_to_gpa(gfn), 0);
+ order = iommu_unmap(domain, gfn_to_gpa(gfn), PAGE_SIZE);
unmap_pages = 1ULL << order;
/* Unpin all pages we just unmapped to not leak any memory */
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 2/6] iommu/omap: announce supported page sizes
From: Ohad Ben-Cohen @ 2011-09-16 17:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316195506-9777-1-git-send-email-ohad@wizery.com>
Let the IOMMU core know we support 4KiB, 64KiB, 1MiB and 16MiB page sizes.
This way the IOMMU core can split any arbitrary-sized physically
contiguous regions (that it needs to map) as needed.
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
---
drivers/iommu/omap-iommu.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 7e0188f..403dd6a 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1202,6 +1202,9 @@ static int omap_iommu_domain_has_cap(struct iommu_domain *domain,
return 0;
}
+/* bitmap of the page sizes supported by the OMAP IOMMU hardware */
+static unsigned long omap_iommu_pgsizes = SZ_4K | SZ_64K | SZ_1M | SZ_16M;
+
static struct iommu_ops omap_iommu_ops = {
.domain_init = omap_iommu_domain_init,
.domain_destroy = omap_iommu_domain_destroy,
@@ -1225,7 +1228,8 @@ static int __init omap_iommu_init(void)
return -ENOMEM;
iopte_cachep = p;
- register_iommu(&omap_iommu_ops);
+ /* we're only using the first 25 bits of the pgsizes bitmap */
+ register_iommu_pgsize(&omap_iommu_ops, &omap_iommu_pgsizes, 25);
return platform_driver_register(&omap_iommu_driver);
}
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 3/6] iommu/msm: announce supported page sizes
From: Ohad Ben-Cohen @ 2011-09-16 17:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316195506-9777-1-git-send-email-ohad@wizery.com>
Let the IOMMU core know we support 4KiB, 64KiB, 1MiB and 16MiB page sizes.
This way the IOMMU core can split any arbitrary-sized physically
contiguous regions (that it needs to map) as needed.
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: David Brown <davidb@codeaurora.org>
Cc: Stepan Moskovchenko <stepanm@codeaurora.org>
---
drivers/iommu/msm_iommu.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index d1733f6..a4ed116 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -676,6 +676,9 @@ fail:
return 0;
}
+/* bitmap of the page sizes currently supported */
+static unsigned long msm_iommu_pgsizes = SZ_4K | SZ_64K | SZ_1M | SZ_16M;
+
static struct iommu_ops msm_iommu_ops = {
.domain_init = msm_iommu_domain_init,
.domain_destroy = msm_iommu_domain_destroy,
@@ -728,7 +731,10 @@ static void __init setup_iommu_tex_classes(void)
static int __init msm_iommu_init(void)
{
setup_iommu_tex_classes();
- register_iommu(&msm_iommu_ops);
+
+ /* we're only using the first 25 bits of the pgsizes bitmap */
+ register_iommu_pgsize(&msm_iommu_ops, &msm_iommu_pgsizes, 25);
+
return 0;
}
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 4/6] iommu/amd: announce supported page sizes
From: Ohad Ben-Cohen @ 2011-09-16 17:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316195506-9777-1-git-send-email-ohad@wizery.com>
Let the IOMMU core know we support arbitrary page sizes (as long as
they're an order of 4KiB).
This way the IOMMU core will retain the existing behavior we're used to;
it will let us map regions that:
- their size is an order of 4KiB
- they are naturally aligned
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Joerg Roedel <Joerg.Roedel@amd.com>
---
drivers/iommu/amd_iommu.c | 21 ++++++++++++++++++++-
1 files changed, 20 insertions(+), 1 deletions(-)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index a14f8dc..80191d2 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2488,12 +2488,31 @@ static unsigned device_dma_ops_init(void)
}
/*
+ * This bitmap is used to advertise the page sizes our hardware support
+ * to the IOMMU core, which will then use this information to split
+ * physically contiguous memory regions it is mapping into page sizes
+ * that we support.
+ *
+ * Traditionally the IOMMU core just handed us the mappings directly,
+ * after making sure the size is an order of a 4KiB page and that the
+ * mapping has natural alignment.
+ *
+ * To retain this behavior, we currently advertise that we support
+ * all page sizes that are an order of 4KiB.
+ *
+ * If at some point we'd like to utilize the IOMMU core's new behavior,
+ * we could change this to advertise the real page sizes we support.
+ */
+static unsigned long amd_iommu_pgsizes = ~0xFFFUL;
+
+/*
* The function which clues the AMD IOMMU driver into dma_ops.
*/
void __init amd_iommu_init_api(void)
{
- register_iommu(&amd_iommu_ops);
+ register_iommu_pgsize(&amd_iommu_ops, &amd_iommu_pgsizes,
+ BITS_PER_LONG);
}
int __init amd_iommu_init_dma_ops(void)
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 5/6] iommu/intel: announce supported page sizes
From: Ohad Ben-Cohen @ 2011-09-16 17:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316195506-9777-1-git-send-email-ohad@wizery.com>
Let the IOMMU core know we support arbitrary page sizes (as long as
they're an order of 4KiB).
This way the IOMMU core will retain the existing behavior we're used to;
it will let us map regions that:
- their size is an order of 4KiB
- they are naturally aligned
Note: Intel IOMMU hardware doesn't support arbitrary page sizes,
but the driver does (it splits arbitrary-sized mappings into
the pages supported by the hardware).
To make everything simpler for now, though, this patch effectively tells
the IOMMU core to keep giving this driver the same memory regions it did
before, so nothing is changed as far as it's concerned.
At this point, the page sizes announced remain static within the IOMMU
core. To correctly utilize the pgsize-splitting of the IOMMU core by
this driver, it seems that some core changes should still be done,
because Intel's IOMMU page size capabilities seem to have the potential
to be different between different DMA remapping devices.
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: David Woodhouse <dwmw2@infradead.org>
---
drivers/iommu/intel-iommu.c | 21 ++++++++++++++++++++-
1 files changed, 20 insertions(+), 1 deletions(-)
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c621c98..46c21a2 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3426,6 +3426,24 @@ static struct notifier_block device_nb = {
.notifier_call = device_notifier,
};
+/*
+ * This bitmap is used to advertise the page sizes our hardware support
+ * to the IOMMU core, which will then use this information to split
+ * physically contiguous memory regions it is mapping into page sizes
+ * that we support.
+ *
+ * Traditionally the IOMMU core just handed us the mappings directly,
+ * after making sure the size is an order of a 4KiB page and that the
+ * mapping has natural alignment.
+ *
+ * To retain this behavior, we currently advertise that we support
+ * all page sizes that are an order of 4KiB.
+ *
+ * If at some point we'd like to utilize the IOMMU core's new behavior,
+ * we could change this to advertise the real page sizes we support.
+ */
+static unsigned long intel_iommu_pgsizes = ~0xFFFUL;
+
int __init intel_iommu_init(void)
{
int ret = 0;
@@ -3486,7 +3504,8 @@ int __init intel_iommu_init(void)
init_iommu_pm_ops();
- register_iommu(&intel_iommu_ops);
+ register_iommu_pgsize(&intel_iommu_ops, &intel_iommu_pgsizes,
+ BITS_PER_LONG);
bus_register_notifier(&pci_bus_type, &device_nb);
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 6/6] iommu/core: remove the temporary register_iommu_pgsize API
From: Ohad Ben-Cohen @ 2011-09-16 17:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316195506-9777-1-git-send-email-ohad@wizery.com>
Now that all IOMMU drivers are converted to the new
register_iommu_pgsize() API, the old code can be removed, and
we can s/register_iommu_pgsize/register_iommu/.
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Joerg Roedel <Joerg.Roedel@amd.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: David Brown <davidb@codeaurora.org>
Cc: Stepan Moskovchenko <stepanm@codeaurora.org>
---
drivers/iommu/amd_iommu.c | 3 +--
drivers/iommu/intel-iommu.c | 3 +--
drivers/iommu/iommu.c | 34 +---------------------------------
drivers/iommu/msm_iommu.c | 2 +-
drivers/iommu/omap-iommu.c | 2 +-
include/linux/iommu.h | 5 ++---
6 files changed, 7 insertions(+), 42 deletions(-)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 80191d2..cf29645 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2511,8 +2511,7 @@ static unsigned long amd_iommu_pgsizes = ~0xFFFUL;
void __init amd_iommu_init_api(void)
{
- register_iommu_pgsize(&amd_iommu_ops, &amd_iommu_pgsizes,
- BITS_PER_LONG);
+ register_iommu(&amd_iommu_ops, &amd_iommu_pgsizes, BITS_PER_LONG);
}
int __init amd_iommu_init_dma_ops(void)
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 46c21a2..c013b85 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3504,8 +3504,7 @@ int __init intel_iommu_init(void)
init_iommu_pm_ops();
- register_iommu_pgsize(&intel_iommu_ops, &intel_iommu_pgsizes,
- BITS_PER_LONG);
+ register_iommu(&intel_iommu_ops, &intel_iommu_pgsizes, BITS_PER_LONG);
bus_register_notifier(&pci_bus_type, &device_nb);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 7c01c8c..8bbd1aa 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -46,13 +46,8 @@ static unsigned int iommu_min_page_idx;
* @ops: iommu handlers
* @pgsize_bitmap: bitmap of page sizes supported by the hardware
* @nr_page_bits: size of @pgsize_bitmap (in bits)
- *
- * Note: this is a temporary function, which will be removed once
- * all IOMMU drivers are converted. The only reason it exists is to
- * allow splitting the pgsizes changes to several patches in order to ease
- * the review.
*/
-void register_iommu_pgsize(struct iommu_ops *ops, unsigned long *pgsize_bitmap,
+void register_iommu(struct iommu_ops *ops, unsigned long *pgsize_bitmap,
unsigned int nr_page_bits)
{
if (iommu_ops || iommu_pgsize_bitmap || !nr_page_bits)
@@ -67,33 +62,6 @@ void register_iommu_pgsize(struct iommu_ops *ops, unsigned long *pgsize_bitmap,
iommu_min_pagesz = 1 << iommu_min_page_idx;
}
-/*
- * default pagesize bitmap, will be removed once all IOMMU drivers
- * are converted
- */
-static unsigned long default_iommu_pgsizes = ~0xFFFUL;
-
-void register_iommu(struct iommu_ops *ops)
-{
- if (iommu_ops)
- BUG();
-
- iommu_ops = ops;
-
- /*
- * set 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
- */
- iommu_pgsize_bitmap = &default_iommu_pgsizes;
- iommu_nr_page_bits = BITS_PER_LONG;
-
- /* find the minimum page size and its index only once */
- iommu_min_page_idx = find_first_bit(iommu_pgsize_bitmap,
- iommu_nr_page_bits);
- iommu_min_pagesz = 1 << iommu_min_page_idx;
-}
-
bool iommu_found(void)
{
return iommu_ops != NULL;
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index a4ed116..e59ced9 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -733,7 +733,7 @@ static int __init msm_iommu_init(void)
setup_iommu_tex_classes();
/* we're only using the first 25 bits of the pgsizes bitmap */
- register_iommu_pgsize(&msm_iommu_ops, &msm_iommu_pgsizes, 25);
+ register_iommu(&msm_iommu_ops, &msm_iommu_pgsizes, 25);
return 0;
}
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 403dd6a..3d8ad87 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1229,7 +1229,7 @@ static int __init omap_iommu_init(void)
iopte_cachep = p;
/* we're only using the first 25 bits of the pgsizes bitmap */
- register_iommu_pgsize(&omap_iommu_ops, &omap_iommu_pgsizes, 25);
+ register_iommu(&omap_iommu_ops, &omap_iommu_pgsizes, 25);
return platform_driver_register(&omap_iommu_driver);
}
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 1806956..297893f 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -60,9 +60,8 @@ struct iommu_ops {
#ifdef CONFIG_IOMMU_API
-extern void register_iommu(struct iommu_ops *ops);
-extern void register_iommu_pgsize(struct iommu_ops *ops,
- unsigned long *pgsize_bitmap, unsigned int nr_page_bits);
+extern void register_iommu(struct iommu_ops *ops, unsigned long *pgsize_bitmap,
+ unsigned int nr_page_bits);
extern bool iommu_found(void);
extern struct iommu_domain *iommu_domain_alloc(void);
extern void iommu_domain_free(struct iommu_domain *domain);
--
1.7.4.1
^ permalink raw reply related
* [PATCH 8/8] OMAP4: Fix the emif and dmm virtual mapping
From: Kevin Hilman @ 2011-09-16 17:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1315459327-3285-9-git-send-email-santosh.shilimkar@ti.com>
Santosh Shilimkar <santosh.shilimkar@ti.com> writes:
> Fix the address overlap with Emulation domain (EMU).
>
> The previous mapping was entering into EMU mapping
> and was not as per comments. Fix the mapping accordingly.
>
> [girishsg at ti.com: Helped fixing comments.]
> Signed-off-by: Girish S G <girishsg@ti.com>
> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> ---
> arch/arm/plat-omap/include/plat/io.h | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/plat-omap/include/plat/io.h b/arch/arm/plat-omap/include/plat/io.h
> index d72ec85..a2f7d31 100644
> --- a/arch/arm/plat-omap/include/plat/io.h
> +++ b/arch/arm/plat-omap/include/plat/io.h
> @@ -228,12 +228,12 @@
>
> #define OMAP44XX_EMIF2_PHYS OMAP44XX_EMIF2_BASE
> /* 0x4d000000 --> 0xfd200000 */
> -#define OMAP44XX_EMIF2_VIRT (OMAP44XX_EMIF2_PHYS + OMAP4_L3_PER_IO_OFFSET)
> +#define OMAP44XX_EMIF2_VIRT (OMAP44XX_EMIF1_VIRT + SZ_1M)
IMO, this would be much clearer (and future proof) if you used
'+ OMAP44XX_EMIF1_SIZE' instead of SZ_1M.
> #define OMAP44XX_EMIF2_SIZE SZ_1M
>
> #define OMAP44XX_DMM_PHYS OMAP44XX_DMM_BASE
> /* 0x4e000000 --> 0xfd300000 */
> -#define OMAP44XX_DMM_VIRT (OMAP44XX_DMM_PHYS + OMAP4_L3_PER_IO_OFFSET)
> +#define OMAP44XX_DMM_VIRT (OMAP44XX_EMIF2_VIRT + SZ_1M)
and '+ OMAP44XX_EMIF2_SIZE' here.
> #define OMAP44XX_DMM_SIZE SZ_1M
> /*
> * ----------------------------------------------------------------------------
Kevin
^ permalink raw reply
* [PATCH 01/19] ARM: sort the meminfo array earlier
From: Nicolas Pitre @ 2011-09-16 18:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E73858A.9050106@codeaurora.org>
On Fri, 16 Sep 2011, Stephen Boyd wrote:
> On 9/16/2011 12:07 AM, Nicolas Pitre wrote:
> > @@ -875,6 +876,12 @@ static struct machine_desc * __init setup_machine_tags(unsigned int nr)
> > return mdesc;
> > }
> >
> > +static int __init meminfo_cmp(const void *_a, const void *_b)
> > +{
> > + const struct membank *a = _a, *b = _b;
> > + long cmp = bank_pfn_start(a) - bank_pfn_start(b);
> > + return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
>
> This looks like:
>
> return clamp(bank_pfn_start(a) - bank_pfn_start(b), -1, 1);
Won't work. The pfn is of an unsigned type, hence the subtraction
result will also be unsigned. The code above looks a bit odd, but there
is an implicit cast to a signed result with the result stored into a
long.
What would have been even clearer, and possibly more efficient as well,
is something like this:
if (bank_pfn_start(a) < bank_pfn_start(b))
return -1;
if (bank_pfn_start(a) > bank_pfn_start(b))
return 1;
return 0;
But the goal here was to simply move the code, changing it would warrant
a separate patch.
> > diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
> > index 91bca355cd..7080f10cc2 100644
> > --- a/arch/arm/mm/init.c
> > +++ b/arch/arm/mm/init.c
> > @@ -318,19 +317,10 @@ static void arm_memory_present(void)
> > }
> > #endif
> >
> > -static int __init meminfo_cmp(const void *_a, const void *_b)
> > -{
> > - const struct membank *a = _a, *b = _b;
> > - long cmp = bank_pfn_start(a) - bank_pfn_start(b);
> > - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
> > -}
> > -
> > void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
> > {
> > int i;
> >
> > - sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
> > -
>
> Why not call sanity_check_meminfo() here?
That could be done as well. However the populating of the meminfo array
is done in kernel/setup.c, so it made sense to move the sort there as
this could be improved upon eventually to make the memory bank parser a
bit more robust against problems such as overlapping memory ranges which
was the subject of a somewhat entertaining thread recently. But I don't
have a strong opinion about this.
Nicolas
^ permalink raw reply
* [PATCH v2] dmaengine: add CSR SiRFprimaII DMAC driver
From: Jassi Brar @ 2011-09-16 18:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316166960-20964-1-git-send-email-Baohua.Song@csr.com>
On Fri, Sep 16, 2011 at 3:26 PM, Barry Song <Baohua.Song@csr.com> wrote:
> +static int sirfsoc_dma_slave_config(struct sirfsoc_dma_chan *schan,
> + ? ? ? struct dma_slave_config *config)
> +{
> + ? ? ? u32 addr, direction;
> + ? ? ? unsigned long flags;
> +
> + ? ? ? switch (config->direction) {
> + ? ? ? case DMA_FROM_DEVICE:
> + ? ? ? ? ? ? ? direction = 0;
> + ? ? ? ? ? ? ? addr = config->dst_addr;
> + ? ? ? ? ? ? ? break;
> +
> + ? ? ? case DMA_TO_DEVICE:
> + ? ? ? ? ? ? ? direction = 1;
> + ? ? ? ? ? ? ? addr = config->src_addr;
> + ? ? ? ? ? ? ? break;
> +
> + ? ? ? default:
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? }
> +
> + ? ? ? if ((config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
> + ? ? ? ? ? ? ? (config->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES))
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? spin_lock_irqsave(&schan->lock, flags);
> + ? ? ? schan->addr = addr;
> + ? ? ? schan->direction = direction;
> + ? ? ? schan->mode = (config->src_maxburst == 4 ? 1 : 0);
> + ? ? ? spin_unlock_irqrestore(&schan->lock, flags);
> +
> + ? ? ? return 0;
> +}
You don't need to pass as much info via dma_slave_config as you do here.
dmaxfer_template.src_inc && !dmaxfer_template.dst_inc => DMA_TO_DEVICE
!dmaxfer_template.src_inc && dmaxfer_template.dst_inc => DMA_FROM_DEVICE
Pass addresses using dmaxfer_template.src_start and dmaxfer_template.dst_start
instead of dma_slave_config.dst_addr and dma_slave_config.src_addr
So, currently you need dma_slave_config only to pass src_addr_width,
dst_addr_width and src_maxburst to the dmac driver.
> +
> +static struct dma_async_tx_descriptor *sirfsoc_dma_prep_slave_sg(
> + ? ? ? struct dma_chan *chan, struct scatterlist *sgl,
> + ? ? ? unsigned int sg_len, enum dma_data_direction direction,
> + ? ? ? unsigned long flags)
> +{
> + ? ? ? return NULL;
> +}
> +
In v3 I'll remove the BUG_ON check that requires every SLAVE channel
provides device_prep_slave_sg, so you should be able to simply discard
this stub.
^ permalink raw reply
* [PATCH 01/19] ARM: sort the meminfo array earlier
From: Stephen Boyd @ 2011-09-16 19:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.00.1109161345560.20358@xanadu.home>
On 09/16/11 11:09, Nicolas Pitre wrote:
> On Fri, 16 Sep 2011, Stephen Boyd wrote:
>
>
>> This looks like:
>>
>> return clamp(bank_pfn_start(a) - bank_pfn_start(b), -1, 1);
> Won't work. The pfn is of an unsigned type, hence the subtraction
> result will also be unsigned. The code above looks a bit odd, but there
> is an implicit cast to a signed result with the result stored into a
> long.
>
> What would have been even clearer, and possibly more efficient as well,
> is something like this:
>
> if (bank_pfn_start(a) < bank_pfn_start(b))
> return -1;
> if (bank_pfn_start(a) > bank_pfn_start(b))
> return 1;
> return 0;
Ok so
return clamp_t(long, bank_pfn_start(a) - bank_pfn_start(b), -1, 1);
?
>
> But the goal here was to simply move the code, changing it would warrant
> a separate patch.
Fair enough.
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply
* [PATCH 01/19] ARM: sort the meminfo array earlier
From: Nicolas Pitre @ 2011-09-16 20:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E73A1AC.20709@codeaurora.org>
On Fri, 16 Sep 2011, Stephen Boyd wrote:
> On 09/16/11 11:09, Nicolas Pitre wrote:
> > On Fri, 16 Sep 2011, Stephen Boyd wrote:
> >
> >
> >> This looks like:
> >>
> >> return clamp(bank_pfn_start(a) - bank_pfn_start(b), -1, 1);
> > Won't work. The pfn is of an unsigned type, hence the subtraction
> > result will also be unsigned. The code above looks a bit odd, but there
> > is an implicit cast to a signed result with the result stored into a
> > long.
> >
> > What would have been even clearer, and possibly more efficient as well,
> > is something like this:
> >
> > if (bank_pfn_start(a) < bank_pfn_start(b))
> > return -1;
> > if (bank_pfn_start(a) > bank_pfn_start(b))
> > return 1;
> > return 0;
>
> Ok so
>
> return clamp_t(long, bank_pfn_start(a) - bank_pfn_start(b), -1, 1);
>
>
> ?
Well...
Given that the pfn range typically fits into an int, having a simple:
return bank_pfn_start(a) - bank_pfn_start(b);
should be all that is needed here, since the expected return value is
either <0, 0, or >0. But that assumes that physical memory will always
be representable with less than 44 bits, and that's a bad assumption to
make these days. Even your usage of clamp_t() is broken the same way,
just like the current code in fact.
So probably using bank_phys_start() instead of bank_pfn_start() would
already be slightly more efficient, given that reducing the range with a
pfn is not going to help when PHYSADDR_t is a 64-bit type. Then having
direct comparisons like I proposed would be the best that can be
achieved in C.
Nicolas
^ permalink raw reply
* [PATCH v2] pata-generic/of: Make probing via device tree non-powerpc-specific
From: Rob Herring @ 2011-09-16 21:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316190120-17010-1-git-send-email-dave.martin@linaro.org>
Dave,
On 09/16/2011 11:22 AM, Dave Martin wrote:
> This patch enables device-tree-based probing of the pata-generic
> platform driver across all architectures:
>
> * make the pata_of_generic module depend on OF instead of PPC_OF;
> * supply some missing inclues;
> * replace endianness-sensitive raw access to device tree data
> with of_property_read_u32() calls.
>
> Signed-off-by: Dave Martin <dave.martin@linaro.org>
> ---
> v2: correct sense of the check of_property_read_u32(dn, "pio-mode",
> &pio_mode). Somehow I posted an old version of this patch, depite
> having already fixed this...
>
> Tested on ARM Versatile Express, with my soon-to-be-posted device
> tree support patches.
>
> I'm not in a position to build/test this for powerpc easily --
> if anyone is able to do that, it would be appreciated.
>
Building just requires getting Codesourcery PPC toolchain...
You also have to be aware that you are enabling this for all OF-enabled
arches which could break with an allyesconfig. So really you need sparc,
x86, mips, and microblaze, but a subset is probably sufficient.
> Grant, does this require similar cleanup to the isp1760 USB hcd driver?
>
Yes. It really should be merged with pata_platform.c. If you're willing
to combine them, I'll do ppc and sparc builds as I already have those on
my system.
Rob
> drivers/ata/Kconfig | 2 +-
> drivers/ata/pata_of_platform.c | 16 +++++++---------
> 2 files changed, 8 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
> index 5987e0b..c6ef9d0 100644
> --- a/drivers/ata/Kconfig
> +++ b/drivers/ata/Kconfig
> @@ -820,7 +820,7 @@ config PATA_PLATFORM
>
> config PATA_OF_PLATFORM
> tristate "OpenFirmware platform device PATA support"
> - depends on PATA_PLATFORM && PPC_OF
> + depends on PATA_PLATFORM && OF
> help
> This option enables support for generic directly connected ATA
> devices commonly found on embedded systems with OpenFirmware
> diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c
> index f305400..e6e9aa9 100644
> --- a/drivers/ata/pata_of_platform.c
> +++ b/drivers/ata/pata_of_platform.c
> @@ -11,6 +11,9 @@
>
> #include <linux/kernel.h>
> #include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> #include <linux/of_platform.h>
> #include <linux/ata_platform.h>
>
> @@ -21,10 +24,9 @@ static int __devinit pata_of_platform_probe(struct platform_device *ofdev)
> struct resource io_res;
> struct resource ctl_res;
> struct resource irq_res;
> - unsigned int reg_shift = 0;
> - int pio_mode = 0;
> + u32 reg_shift = 0;
> + u32 pio_mode = 0;
> int pio_mask;
> - const u32 *prop;
>
> ret = of_address_to_resource(dn, 0, &io_res);
> if (ret) {
> @@ -55,13 +57,9 @@ static int __devinit pata_of_platform_probe(struct platform_device *ofdev)
> else
> irq_res.flags = 0;
>
> - prop = of_get_property(dn, "reg-shift", NULL);
> - if (prop)
> - reg_shift = *prop;
> + of_property_read_u32(dn, "reg-shift", ®_shift);
>
> - prop = of_get_property(dn, "pio-mode", NULL);
> - if (prop) {
> - pio_mode = *prop;
> + if (!of_property_read_u32(dn, "pio-mode", &pio_mode)) {
> if (pio_mode > 6) {
> dev_err(&ofdev->dev, "invalid pio-mode\n");
> return -EINVAL;
^ permalink raw reply
* [PATCH v2 1/3] ARM: imx: Add imx cpuidle driver
From: Russell King - ARM Linux @ 2011-09-16 21:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316194070-21889-2-git-send-email-rob.lee@linaro.org>
On Fri, Sep 16, 2011 at 12:27:48PM -0500, Robert Lee wrote:
> Introduce a new cpuidle driver which provides the common cpuidle
> functionality necessary for any imx soc cpuidle implementation.
I think its probably about time we said no to this duplication of CPU
idle infrastructure. There seems to be a common pattern appearing
through all SoCs - they're all doing this:
> +static int imx_enter_idle(struct cpuidle_device *dev,
> + struct cpuidle_state *state)
> +{
> + struct timeval before, after;
> + int idle_time;
> +
> + local_irq_disable();
> + local_fiq_disable();
> +
> + do_gettimeofday(&before);
> +
> + mach_cpuidle(dev, state);
> +
> + do_gettimeofday(&after);
> +
> + local_fiq_enable();
> + local_irq_enable();
> +
> + idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
> + (after.tv_usec - before.tv_usec);
> +
> + return idle_time;
> +}
in some form, where 'do_gettimeofday' might be ktime_get() or
getnstimeofday(). If we can standardize on which of the many time
functions can be used (which would be a definite plus) we should move
this out to common code.
Maybe also the initialization code could be standardized and improved
too - for instance, what if you boot with maxcpus=1 on a platform
supporting 2 CPUs, and you bring CPU1 online from userspace? When
these CPU idle initialization functions are called, only one CPU will
be online, and as they use 'for_each_cpu(cpu_id, cpu_online_mask)'
CPU1 will be missing the cpu idle init.
^ permalink raw reply
* [PATCH] pata-generic/of: Make probing via device tree non-powerpc-specific
From: Russell King - ARM Linux @ 2011-09-16 21:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316183890-13677-1-git-send-email-dave.martin@linaro.org>
On Fri, Sep 16, 2011 at 03:38:10PM +0100, Dave Martin wrote:
> This patch enables device-tree-based probing of the pata-generic
> platform driver across all architectures:
>
> * make the pata_of_generic module depend on OF instead of PPC_OF;
> * supply some missing inclues;
> * replace endianness-sensitive raw access to device tree data
> with of_property_read_u32() calls.
>
> Signed-off-by: Dave Martin <dave.martin@linaro.org>
> ---
>
> Tested on ARM Versatile Express, with my soon-to-be-posted device
> tree support patches.
This may not be the correct way to support the CF slot on Versatile
Express - it depends whether the CF slot on VE supports just CF
memory cards or whether it can take any CF card.
If the latter, then what may be inserted could be a CF network card,
and that means it's probably wrong to tell the kernel that what's
there is a PATA interface.
^ permalink raw reply
* [GIT PULL] Samsung Fixes for v3.1-rc7
From: Kukjin Kim @ 2011-09-17 1:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110916134300.GB16280@suse.de>
Greg KH wrote:
>
> On Fri, Sep 16, 2011 at 08:50:51PM +0900, Kukjin Kim wrote:
> > Arnd Bergmann wrote:
> > >
> > > On Thursday 15 September 2011, Kukjin Kim wrote:
> > > > This is Samsung fixes for v3.1
> > > >
> > > > Please pull from:
> > > > git://github.com/kgene/linux-samsung.git samsung-fixes-2
> > > > As you know, git.kernel.org/master.kernel.org has been down so I use
> > > > temporary git repo. at github now.
> > > >
> > > > These things are needed for v3.1 and if any problems, please let me
> > know.
> > > >
> > > > As a note, others for v3.2 will be sent in the next week...
> > >
> > > Thanks, pulled.
> > >
> > > Is it correct that you want none of these patches to be backported
> > > into the stable or longterm releases? Some of these look like they
> > > should be marked 'Cc: stable at kernel.org'.
> > >
> > (Cc'ed Greg K-H)
> >
> > Yes, you're right. Some patches are needed to sent to stable at kernel.org.
> > But unfortunately, when they have been submitted, there was no 'Cc:
> > stable at kernel.org'...
>
> What do you mean? Do you mean you just forgot to add them, or you
> created them so long ago before there was a stable at kernel.org?
>
I mean I didn't add them before sending 'pull request' during -rc :(
> > In this case, I'm not sure which following method is proper...
> > - to send 'pull request' to Greg / stable at kernel.org like bug fix during
-rc
> > - to submit each patches with adding 'Cc: stable at kernel.org' again
> > - or ?
>
> Are these in Linus's tree already? If so, send me the git commit ids
> and I will add them to the stable kernels.
>
In this case, not yet. But there are some bug fixing patches which have been
accepted in mainline not in stable.
> If not, wait until they are, and then send me the git commit ids, and I
> will then add them.
>
OK, let you know what git commit is needed to apply into stable.
> Before they get to Linus, there's nothing I can do with them, and I
> don't accept pull requests as that makes no sense when it comes to the
> stable kernel patch flow.
>
OK, I didn't know about the stable kernel patch flow exactly.
> Does this help?
>
Sure, thank you so much.
Have a nice weekend :)
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply
* [GIT PULL] Samsung Fixes for v3.1-rc7
From: Kukjin Kim @ 2011-09-17 1:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1642876.jgt6epCtEP@wuerfel>
Arnd Bergmann wrote:
>
> On Friday 16 September 2011 15:43:00 Greg KH wrote:
> > > In this case, I'm not sure which following method is proper...
> > > - to send 'pull request' to Greg / stable at kernel.org like bug fix
during -rc
> > > - to submit each patches with adding 'Cc: stable at kernel.org' again
> > > - or ?
>
> The patches are currently queued in the stable branch of the arm-soc
> tree, I haven't forwarded them to Linus yet. I can easily change
> the changelog before I actually send them on (if you tell me which ones
> they are, or I can pull an updated set of patches to replace them.
>
Arnd, I think, would be better to me if you could not change the
changelog(commit id) because some my topic branch which is for v3.2 has it.
> > Are these in Linus's tree already? If so, send me the git commit ids
> > and I will add them to the stable kernels.
> >
> > If not, wait until they are, and then send me the git commit ids, and I
> > will then add them.
>
> This is fine with me as well, but I'm trying to get more people to
> send me patches that are annotated already. I forgot to ask during
> the last set of bug fixes I forwarded and should probably go through
> the ones that are already merged and ask the authors about backporting.
>
I need to sort out commit ids which are needed to apply in stable among
Samsung stuff already in mainline.
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
^ permalink raw reply
* [PATCH] ARM: OMAP: Add support for dmtimer v2 ip (Re: [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver)
From: Tony Lindgren @ 2011-09-17 1:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAC83ZvKXEb7MTujP4JqhrPeysYxQcLF+BV-J9tpYoRwWGVZ8_Q@mail.gmail.com>
* DebBarma, Tarun Kanti <tarun.kanti@ti.com> [110916 01:56]:
> [...]
> >>> 1. Modify the inline access functions to take the PEND and others
> >>> ? ?if needed registers as a parameter
> >>>
> >>> 2. Modify mach-omap2/timer.c to initialize the PEND and others
> >>> ? ?in the SoC specific timer_init function
> Just to make my understanding complete, need some clarifications:
> As we would end up modifying almost all inline functions, what naming
> convention should we follow for the parameters?
Well here's what I came up with to deal with the different timer
registers. We can't use the context registers as those are for
the value naturally..
But we can map the interrupt registers separately and then have
the rest start from func_base that is different based on the timer
version. Rebasing the rest of the dmtimer hwmod patches on this
should be fairly easy, mostly just need to pass timer instead of
timer->io_base and use __raw_read/write for the interrupt registers.
Also, I ended up checking the timer revision with if (!(tidr >> 16))
as it seems that those bits are zero for v1 timers? If that works,
then we don't need patch 02/12 for the revision number.
Afzal, care to check if that works for AM335X/TI816X/TI814X?
It tried it briefly with omap4 gptimer3 as the clockevent and
CONFIG_LOCAL_TIMER disabled.
The patch is against the current cleanup branch in linux-omap
tree.
Regards,
Tony
From: Tony Lindgren <tony@atomide.com>
Date: Fri, 16 Sep 2011 15:44:20 -0700
Subject: [PATCH] ARM: OMAP: Add support for dmtimer v2 ip
The registers are slightly different between v1 and v2 ip that
is available in omap4 and later for some timers.
Add support for v2 ip by mapping the interrupt related registers
separately and adding func_base for the functional registers.
Also disable dmtimer driver features on omap4 for now as
those need the hwmod conversion series to deal with enabling
the timers properly in omap_dm_timer_init.
Signed-off-by: Tony Lindgren <tony@atomide.com>
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index cf1de7d..21d34fb 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -78,7 +78,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = &clockevent_gpt;
- __omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
+ __omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW);
evt->event_handler(evt);
return IRQ_HANDLED;
@@ -93,7 +93,7 @@ static struct irqaction omap2_gp_timer_irq = {
static int omap2_gp_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
- __omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST,
+ __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
0xffffffff - cycles, 1);
return 0;
@@ -104,16 +104,16 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
{
u32 period;
- __omap_dm_timer_stop(clkev.io_base, 1, clkev.rate);
+ __omap_dm_timer_stop(&clkev, 1, clkev.rate);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
period = clkev.rate / HZ;
period -= 1;
/* Looks like we need to first set the load value separately */
- __omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG,
+ __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG,
0xffffffff - period, 1);
- __omap_dm_timer_load_start(clkev.io_base,
+ __omap_dm_timer_load_start(&clkev,
OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
0xffffffff - period, 1);
break;
@@ -172,6 +172,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
}
omap_hwmod_enable(oh);
+ __omap_dm_timer_init_regs(timer);
sys_timer_reserved |= (1 << (gptimer_id - 1));
@@ -189,7 +190,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
clk_put(src);
}
}
- __omap_dm_timer_reset(timer->io_base, 1, 1);
+ __omap_dm_timer_reset(timer, 1, 1);
timer->posted = 1;
timer->rate = clk_get_rate(timer->fclk);
@@ -210,7 +211,7 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
omap2_gp_timer_irq.dev_id = (void *)&clkev;
setup_irq(clkev.irq, &omap2_gp_timer_irq);
- __omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
+ __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC,
clockevent_gpt.shift);
@@ -251,7 +252,7 @@ static struct omap_dm_timer clksrc;
static DEFINE_CLOCK_DATA(cd);
static cycle_t clocksource_read_cycles(struct clocksource *cs)
{
- return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1);
+ return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1);
}
static struct clocksource clocksource_gpt = {
@@ -266,7 +267,7 @@ static void notrace dmtimer_update_sched_clock(void)
{
u32 cyc;
- cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
+ cyc = __omap_dm_timer_read_counter(&clksrc, 1);
update_sched_clock(&cd, cyc, (u32)~0);
}
@@ -276,7 +277,7 @@ unsigned long long notrace sched_clock(void)
u32 cyc = 0;
if (clksrc.reserved)
- cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
+ cyc = __omap_dm_timer_read_counter(&clksrc, 1);
return cyc_to_sched_clock(&cd, cyc, (u32)~0);
}
@@ -293,7 +294,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
gptimer_id, clksrc.rate);
- __omap_dm_timer_load_start(clksrc.io_base,
+ __omap_dm_timer_load_start(&clksrc,
OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 75a847d..e23b7cf 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -170,7 +170,8 @@ static spinlock_t dm_timer_lock;
*/
static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
{
- return __omap_dm_timer_read(timer->io_base, reg, timer->posted);
+ WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
+ return __omap_dm_timer_read(timer, reg, timer->posted);
}
/*
@@ -182,15 +183,19 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
u32 value)
{
- __omap_dm_timer_write(timer->io_base, reg, value, timer->posted);
+ WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
+ __omap_dm_timer_write(timer, reg, value, timer->posted);
}
static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
{
int c;
+ if (!timer->sys_stat)
+ return;
+
c = 0;
- while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) {
+ while (!(__raw_readl(timer->sys_stat) & 1)) {
c++;
if (c > 100000) {
printk(KERN_ERR "Timer failed to reset\n");
@@ -219,7 +224,7 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
if (cpu_class_is_omap2())
wakeup = 1;
- __omap_dm_timer_reset(timer->io_base, autoidle, wakeup);
+ __omap_dm_timer_reset(timer, autoidle, wakeup);
timer->posted = 1;
}
@@ -401,7 +406,7 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
rate = clk_get_rate(timer->fclk);
#endif
- __omap_dm_timer_stop(timer->io_base, timer->posted, rate);
+ __omap_dm_timer_stop(timer, timer->posted, rate);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
@@ -466,7 +471,7 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
}
l |= OMAP_TIMER_CTRL_ST;
- __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted);
+ __omap_dm_timer_load_start(timer, l, load, timer->posted);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
@@ -519,7 +524,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
unsigned int value)
{
- __omap_dm_timer_int_enable(timer->io_base, value);
+ __omap_dm_timer_int_enable(timer, value);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
@@ -527,7 +532,7 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
{
unsigned int l;
- l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+ l = __raw_readl(timer->irq_stat);
return l;
}
@@ -535,13 +540,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
{
- __omap_dm_timer_write_status(timer->io_base, value);
+ __omap_dm_timer_write_status(timer, value);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
{
- return __omap_dm_timer_read_counter(timer->io_base, timer->posted);
+ return __omap_dm_timer_read_counter(timer, timer->posted);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
@@ -601,6 +606,9 @@ static int __init omap_dm_timer_init(void)
dm_timer_count = omap4_dm_timer_count;
dm_source_names = omap4_dm_source_names;
dm_source_clocks = omap4_dm_source_clocks;
+
+ pr_err("dmtimers disabled for omap4 until hwmod conversion\n");
+ return -ENODEV;
}
if (cpu_class_is_omap2())
@@ -630,8 +638,12 @@ static int __init omap_dm_timer_init(void)
if (sys_timer_reserved & (1 << i)) {
timer->reserved = 1;
timer->posted = 1;
+ continue;
}
#endif
+ omap_dm_timer_enable(timer);
+ __omap_dm_timer_init_regs(timer);
+ omap_dm_timer_disable(timer);
}
return 0;
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index eb5d16c..a11d0c0 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -98,12 +98,30 @@ int omap_dm_timers_active(void);
* used by dmtimer.c and sys_timer related code.
*/
-/* register offsets */
-#define _OMAP_TIMER_ID_OFFSET 0x00
-#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10
-#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14
-#define _OMAP_TIMER_STAT_OFFSET 0x18
-#define _OMAP_TIMER_INT_EN_OFFSET 0x1c
+/*
+ * The interrupt registers are different between v1 and v2 ip.
+ * These registers are offsets from timer->iobase.
+ */
+#define OMAP_TIMER_ID_OFFSET 0x00
+#define OMAP_TIMER_OCP_CFG_OFFSET 0x10
+
+#define OMAP_TIMER_V1_SYS_STAT_OFFSET 0x14
+#define OMAP_TIMER_V1_STAT_OFFSET 0x18
+#define OMAP_TIMER_V1_INT_EN_OFFSET 0x1c
+
+#define OMAP_TIMER_V2_IRQSTATUS_RAW 0x24
+#define OMAP_TIMER_V2_IRQSTATUS 0x28
+#define OMAP_TIMER_V2_IRQENABLE_SET 0x2c
+#define OMAP_TIMER_V2_IRQENABLE_CLR 0x30
+
+/*
+ * The functional registers have a different base on v1 and v2 ip.
+ * These registers are offsets from timer->func_base. The func_base
+ * is samae as io_base for v1 and io_base + 0x14 for v2 ip.
+ *
+ */
+#define OMAP_TIMER_V2_FUNC_OFFSET 0x14
+
#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20
#define _OMAP_TIMER_CTRL_OFFSET 0x24
#define OMAP_TIMER_CTRL_GPOCFG (1 << 14)
@@ -147,21 +165,6 @@ int omap_dm_timers_active(void);
/* register offsets with the write pending bit encoded */
#define WPSHIFT 16
-#define OMAP_TIMER_ID_REG (_OMAP_TIMER_ID_OFFSET \
- | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \
- | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \
- | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \
- | (WP_NONE << WPSHIFT))
-
-#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \
- | (WP_NONE << WPSHIFT))
-
#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \
| (WP_NONE << WPSHIFT))
@@ -213,7 +216,14 @@ struct omap_dm_timer {
#ifdef CONFIG_ARCH_OMAP2PLUS
struct clk *iclk, *fclk;
#endif
- void __iomem *io_base;
+ void __iomem *io_base;
+ void __iomem *sys_stat; /* TISTAT timer status */
+ void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */
+ void __iomem *irq_ena; /* irq enable */
+ void __iomem *irq_dis; /* irq disable, only on v2 ip */
+ void __iomem *pend; /* write pending */
+ void __iomem *func_base; /* function register base */
+
unsigned long rate;
unsigned reserved:1;
unsigned enabled:1;
@@ -223,35 +233,57 @@ struct omap_dm_timer {
extern u32 sys_timer_reserved;
void omap_dm_timer_prepare(struct omap_dm_timer *timer);
-static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg,
+static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
int posted)
{
if (posted)
- while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
- & (reg >> WPSHIFT))
+ while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
cpu_relax();
- return __raw_readl(base + (reg & 0xff));
+ return __raw_readl(timer->func_base + (reg & 0xff));
}
-static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val,
- int posted)
+static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
+ u32 reg, u32 val, int posted)
{
if (posted)
- while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
- & (reg >> WPSHIFT))
+ while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
cpu_relax();
- __raw_writel(val, base + (reg & 0xff));
+ __raw_writel(val, timer->func_base + (reg & 0xff));
+}
+
+static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
+{
+ u32 tidr;
+
+ /* Assume v1 ip if bits [31:16] are zero */
+ tidr = __raw_readl(timer->io_base);
+ if (!(tidr >> 16)) {
+ timer->sys_stat = timer->io_base + OMAP_TIMER_V1_SYS_STAT_OFFSET;
+ timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
+ timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
+ timer->irq_dis = 0;
+ timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
+ timer->func_base = timer->io_base;
+ } else {
+ timer->sys_stat = 0;
+ timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
+ timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
+ timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
+ timer->pend = timer->io_base +
+ _OMAP_TIMER_WRITE_PEND_OFFSET + OMAP_TIMER_V2_FUNC_OFFSET;
+ timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
+ }
}
/* Assumes the source clock has been set by caller */
-static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle,
- int wakeup)
+static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
+ int autoidle, int wakeup)
{
u32 l;
- l = __omap_dm_timer_read(base, OMAP_TIMER_OCP_CFG_REG, 0);
+ l = __raw_readl(timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
l |= 0x02 << 3; /* Set to smart-idle mode */
l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */
@@ -261,10 +293,10 @@ static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle,
if (wakeup)
l |= 1 << 2;
- __omap_dm_timer_write(base, OMAP_TIMER_OCP_CFG_REG, l, 0);
+ __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
/* Match hardware reset default of posted mode */
- __omap_dm_timer_write(base, OMAP_TIMER_IF_CTRL_REG,
+ __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
OMAP_TIMER_CTRL_POSTED, 0);
}
@@ -286,18 +318,18 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
return ret;
}
-static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
- unsigned long rate)
+static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
+ int posted, unsigned long rate)
{
u32 l;
- l = __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted);
+ l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
if (l & OMAP_TIMER_CTRL_ST) {
l &= ~0x1;
- __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, l, posted);
+ __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
#ifdef CONFIG_ARCH_OMAP2PLUS
/* Readback to make sure write has completed */
- __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted);
+ __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
/*
* Wait for functional clock period x 3.5 to make sure that
* timer is stopped
@@ -307,34 +339,34 @@ static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
}
/* Ack possibly pending interrupt */
- __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG,
- OMAP_TIMER_INT_OVERFLOW, 0);
+ __raw_writel(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
}
-static inline void __omap_dm_timer_load_start(void __iomem *base, u32 ctrl,
- unsigned int load, int posted)
+static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
+ u32 ctrl, unsigned int load,
+ int posted)
{
- __omap_dm_timer_write(base, OMAP_TIMER_COUNTER_REG, load, posted);
- __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, ctrl, posted);
+ __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
+ __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted);
}
-static inline void __omap_dm_timer_int_enable(void __iomem *base,
+static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
unsigned int value)
{
- __omap_dm_timer_write(base, OMAP_TIMER_INT_EN_REG, value, 0);
- __omap_dm_timer_write(base, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
+ __raw_writel(value, timer->irq_ena);
+ __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
}
-static inline unsigned int __omap_dm_timer_read_counter(void __iomem *base,
- int posted)
+static inline unsigned int
+__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
{
- return __omap_dm_timer_read(base, OMAP_TIMER_COUNTER_REG, posted);
+ return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
}
-static inline void __omap_dm_timer_write_status(void __iomem *base,
+static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
unsigned int value)
{
- __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, value, 0);
+ __raw_writel(value, timer->irq_stat);
}
#endif /* __ASM_ARCH_DMTIMER_H */
^ permalink raw reply related
* [GIT PULL] omap cleanup part1 for v3.2 merge window
From: Tony Lindgren @ 2011-09-17 1:46 UTC (permalink / raw)
To: linux-arm-kernel
Hi Arnd,
Please pull the first part of omap cleanup from:
git://github.com/tmlind/linux.git cleanup
This series cleans up early_init functions and removes
CHIP_IS macro usage. This makes it easier to have SoC
specific init functions so adding support for new omap
variants does not require patching all over the place.
Regards,
Tony
The following changes since commit b6fd41e29dea9c6753b1843a77e50433e6123bcb:
Linus Torvalds (1):
Linux 3.1-rc6
are available in the git repository at:
git://github.com/tmlind/linux.git cleanup
Paul Walmsley (12):
OMAP3: id: remove identification codes that only correspond to marketing names
OMAP3: id: remove useless strcpy()s
OMAP3: id: use explicit omap_revision codes for 3505/3517 ES levels
OMAP3: id: add fallthrough warning; fix some CodingStyle issues
OMAP3: id: remove duplicate code for testing SoC ES level
OMAP2+: id: remove OMAP_REVBITS_* macros
OMAP: clockdomain: split clkdm_init()
OMAP: clockdomain code/data: remove omap_chip bitmask from struct clockdomain
OMAP: powerdomain: split pwrdm_init() into two functions
OMAP: powerdomain: remove omap_chip bitmasks
OMAP2+: hwmod: remove OMAP_CHIP*
OMAP: id: remove OMAP_CHIP declarations, code
Tony Lindgren (4):
omap2+: Use Kconfig symbol in Makefile instead of obj-y
ARM: OMAP: Move omap2_init_common_devices out of init_early
ARM: OMAP: Introduce SoC specific early_init
Merge branch 'omap_chip_remove_cleanup_3.2' of git://git.pwsan.com/linux-2.6 into cleanup
arch/arm/mach-omap2/Makefile | 81 +--
arch/arm/mach-omap2/board-2430sdp.c | 9 +-
arch/arm/mach-omap2/board-3430sdp.c | 9 +-
arch/arm/mach-omap2/board-3630sdp.c | 11 +-
arch/arm/mach-omap2/board-4430sdp.c | 9 +-
arch/arm/mach-omap2/board-am3517crane.c | 9 +-
arch/arm/mach-omap2/board-am3517evm.c | 8 +-
arch/arm/mach-omap2/board-apollon.c | 9 +-
arch/arm/mach-omap2/board-cm-t35.c | 13 +-
arch/arm/mach-omap2/board-cm-t3517.c | 9 +-
arch/arm/mach-omap2/board-devkit8000.c | 12 +-
arch/arm/mach-omap2/board-generic.c | 2 +-
arch/arm/mach-omap2/board-h4.c | 9 +-
arch/arm/mach-omap2/board-igep0020.c | 13 +-
arch/arm/mach-omap2/board-ldp.c | 9 +-
arch/arm/mach-omap2/board-n8x0.c | 13 +-
arch/arm/mach-omap2/board-omap3beagle.c | 4 +-
arch/arm/mach-omap2/board-omap3evm.c | 9 +-
arch/arm/mach-omap2/board-omap3logic.c | 11 +-
arch/arm/mach-omap2/board-omap3pandora.c | 11 +-
arch/arm/mach-omap2/board-omap3stalker.c | 9 +-
arch/arm/mach-omap2/board-omap3touchbook.c | 11 +-
arch/arm/mach-omap2/board-omap4panda.c | 9 +-
arch/arm/mach-omap2/board-overo.c | 11 +-
arch/arm/mach-omap2/board-rm680.c | 17 +-
arch/arm/mach-omap2/board-rx51.c | 17 +-
arch/arm/mach-omap2/board-ti8168evm.c | 9 +-
arch/arm/mach-omap2/board-zoom.c | 23 +-
arch/arm/mach-omap2/clock3xxx_data.c | 11 +-
arch/arm/mach-omap2/clockdomain.c | 147 +++--
arch/arm/mach-omap2/clockdomain.h | 22 +-
arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | 4 -
arch/arm/mach-omap2/clockdomain44xx.c | 2 -
arch/arm/mach-omap2/clockdomains2420_data.c | 154 +++++
arch/arm/mach-omap2/clockdomains2430_data.c | 181 +++++
arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c | 803 +---------------------
arch/arm/mach-omap2/clockdomains3xxx_data.c | 398 +++++++++++
arch/arm/mach-omap2/clockdomains44xx_data.c | 409 +++---------
arch/arm/mach-omap2/id.c | 191 ++----
arch/arm/mach-omap2/io.c | 52 ++-
arch/arm/mach-omap2/omap_hwmod.c | 3 -
arch/arm/mach-omap2/omap_hwmod_2420_data.c | 37 -
arch/arm/mach-omap2/omap_hwmod_2430_data.c | 45 --
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 169 +++---
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 82 ---
arch/arm/mach-omap2/powerdomain-common.c | 7 +-
arch/arm/mach-omap2/powerdomain.c | 87 ++-
arch/arm/mach-omap2/powerdomain.h | 9 +-
arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c | 19 +-
arch/arm/mach-omap2/powerdomains2xxx_data.c | 44 +-
arch/arm/mach-omap2/powerdomains3xxx_data.c | 81 ++-
arch/arm/mach-omap2/powerdomains44xx_data.c | 20 +-
arch/arm/plat-omap/include/plat/clock.h | 2 -
arch/arm/plat-omap/include/plat/common.h | 9 +
arch/arm/plat-omap/include/plat/cpu.h | 108 +---
arch/arm/plat-omap/include/plat/io.h | 2 +-
arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 -
57 files changed, 1430 insertions(+), 2036 deletions(-)
create mode 100644 arch/arm/mach-omap2/clockdomains2420_data.c
create mode 100644 arch/arm/mach-omap2/clockdomains2430_data.c
create mode 100644 arch/arm/mach-omap2/clockdomains3xxx_data.c
^ permalink raw reply
* [GIT PULL] omap voltage cleanup for v3.2 merge window
From: Tony Lindgren @ 2011-09-17 1:54 UTC (permalink / raw)
To: linux-arm-kernel
Hi Arnd,
Please pull omap voltage cleanup series:
git://github.com/tmlind/linux.git voltage
This has a dependency to the cleanup part 1 series. As
this contains some voltage fixes too, it's a separate
series. You can either pull it into cleanup or keep it
separate.
Regards,
Tony
The following changes since commit ceb1c532ba6220900e61ec7073a9234661efa450:
Tony Lindgren (1):
Merge branch 'omap_chip_remove_cleanup_3.2' of git://git.pwsan.com/linux-2.6 into cleanup
are available in the git repository at:
git://github.com/tmlind/linux.git voltage
Benoit Cousson (1):
OMAP4: powerdomain data: add voltage domains
Kevin Hilman (48):
OMAP2+: hwmod: remove unused voltagedomain pointer
OMAP2+: voltage: move PRCM mod offets into VC/VP structures
OMAP2+: voltage: move prm_irqst_reg from VP into voltage domain
OMAP2+: voltage: start towards a new voltagedomain layer
OMAP3: voltage: rename "mpu" voltagedomain to "mpu_iva"
OMAP3: voltagedomain data: add wakeup domain
OMAP3+: voltage: add scalable flag to voltagedomain
OMAP2+: powerdomain: add voltagedomain to struct powerdomain
OMAP2: add voltage domains and connect to powerdomains
OMAP3: powerdomain data: add voltage domains
OMAP2+: powerdomain: add voltage domain lookup during register
OMAP2+: voltage: keep track of powerdomains in each voltagedomain
OMAP2+: voltage: split voltage controller (VC) code into dedicated layer
OMAP2+: voltage: move VC into struct voltagedomain, misc. renames
OMAP2+: voltage: enable VC bypass scale method when VC is initialized
OMAP2+: voltage: split out voltage processor (VP) code into new layer
OMAP2+: VC: support PMICs with separate voltage and command registers
OMAP2+: add PRM VP functions for checking/clearing VP TX done status
OMAP3+ VP: replace transaction done check/clear with VP ops
OMAP2+: PRM: add register access functions for VC/VP
OMAP3+: voltage: convert to PRM register access functions
OMAP3+: VC: cleanup i2c slave address configuration
OMAP3+: VC: cleanup PMIC register address configuration
OMAP3+: VC bypass: use fields from VC struct instead of PMIC info
OMAP3+: VC: cleanup voltage setup time configuration
OMAP3+: VC: move on/onlp/ret/off command configuration into common init
OMAP3+: VC: abstract out channel configuration
OMAP3+: voltage domain: move PMIC struct from vdd_info into struct voltagedomain
OMAP3+: VC: make I2C config programmable with PMIC-specific settings
OMAP3+: PM: VC: handle mutant channel config for OMAP4 MPU channel
OMAP3+: VC: use last nominal voltage setting to get current_vsel
OMAP3+: VP: cleanup: move VP instance into voltdm, misc. renames
OMAP3+: voltage: remove unneeded debugfs interface
OMAP3+: VP: struct omap_vp_common: replace shift with __ffs(mask)
OMAP3+: VP: move SoC-specific sys clock rate retreival late init
OMAP3+: VP: move timing calculation/config into VP init
OMAP3+: VP: create VP helper function for updating error gain
OMAP3+: VP: remove omap_vp_runtime_data
OMAP3+: VP: move voltage scale function pointer into struct voltagedomain
OMAP3+: VP: update_errorgain(): return error if VP
OMAP3+: VP: remove unused omap_vp_get_curr_volt()
OMAP3+: VP: combine setting init voltage into common function
OMAP3+: voltage: rename scale and reset functions using voltdm_ prefix
OMAP3+: voltage: move/rename curr_volt from vdd_info into struct voltagedomain
OMAP3+: voltdm: final removal of omap_vdd_info
OMAP3+: voltage: rename omap_voltage_get_nom_volt -> voltdm_get_voltage
OMAP3+: voltage: update nominal voltage in voltdm_scale() not VC post-scale
OMAP2+: VC: more registers are per-channel starting with OMAP5
Nishanth Menon (3):
OMAP4: PM: TWL6030: fix uv to voltage for >0x39
OMAP4: PM: TWL6030: address 0V conversions
OMAP4: PM: TWL6030: add cmd register
Patrick Titiano (2):
OMAP4: PM: TWL6030: fix voltage conversion formula
OMAP4: PM: TWL6030: fix ON/RET/OFF voltages
Tero Kristo (1):
omap: voltage: add a stub header file for external/regulator use
Todd Poynor (1):
OMAP: VP: Explicitly mask VPVOLTAGE field
Tony Lindgren (1):
Merge branch 'for_3.2/voltage-cleanup' of git://gitorious.org/khilman/linux-omap-pm into voltage
arch/arm/mach-omap2/Makefile | 5 +-
arch/arm/mach-omap2/io.c | 5 +
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 4 +-
arch/arm/mach-omap2/omap_twl.c | 107 ++-
arch/arm/mach-omap2/pm.c | 6 +-
arch/arm/mach-omap2/powerdomain.c | 23 +
arch/arm/mach-omap2/powerdomain.h | 10 +
arch/arm/mach-omap2/powerdomain2xxx_3xxx.c | 2 +-
arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c | 2 +
arch/arm/mach-omap2/powerdomains2xxx_data.c | 4 +
arch/arm/mach-omap2/powerdomains3xxx_data.c | 16 +
arch/arm/mach-omap2/powerdomains44xx_data.c | 16 +
arch/arm/mach-omap2/prm2xxx_3xxx.c | 56 ++
arch/arm/mach-omap2/prm2xxx_3xxx.h | 12 +
arch/arm/mach-omap2/prm44xx.c | 71 ++
arch/arm/mach-omap2/prm44xx.h | 12 +
arch/arm/mach-omap2/smartreflex-class3.c | 4 +-
arch/arm/mach-omap2/smartreflex.c | 29 +-
arch/arm/mach-omap2/sr_device.c | 2 +-
arch/arm/mach-omap2/vc.c | 367 ++++++++
arch/arm/mach-omap2/vc.h | 88 ++-
arch/arm/mach-omap2/vc3xxx_data.c | 31 +-
arch/arm/mach-omap2/vc44xx_data.c | 44 +-
arch/arm/mach-omap2/voltage.c | 1088 ++++------------------
arch/arm/mach-omap2/voltage.h | 138 ++--
arch/arm/mach-omap2/voltagedomains2xxx_data.c | 32 +
arch/arm/mach-omap2/voltagedomains3xxx_data.c | 83 +-
arch/arm/mach-omap2/voltagedomains44xx_data.c | 99 ++-
arch/arm/mach-omap2/vp.c | 278 ++++++
arch/arm/mach-omap2/vp.h | 133 ++--
arch/arm/mach-omap2/vp3xxx_data.c | 35 +-
arch/arm/mach-omap2/vp44xx_data.c | 47 +-
arch/arm/plat-omap/include/plat/omap_hwmod.h | 1 -
arch/arm/plat-omap/include/plat/voltage.h | 20 +
34 files changed, 1599 insertions(+), 1271 deletions(-)
create mode 100644 arch/arm/mach-omap2/vc.c
create mode 100644 arch/arm/mach-omap2/voltagedomains2xxx_data.c
create mode 100644 arch/arm/mach-omap2/vp.c
create mode 100644 arch/arm/plat-omap/include/plat/voltage.h
^ permalink raw reply
* READ THIS: the next mach-types update
From: Jean-Christophe PLAGNIOL-VILLARD @ 2011-09-17 2:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110916073159.GC22533@n2100.arm.linux.org.uk>
On 08:31 Fri 16 Sep , Russell King - ARM Linux wrote:
> On Thu, Sep 15, 2011 at 04:50:22PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > On 11:25 Thu 15 Sep , Russell King - ARM Linux wrote:
> > > I'm going to be merging a mach-types update (the cut-down and the
> > > policy-conforming version) for the next merge window. This will mean
> > > that things WILL BREAK, and I will not notice that things have broken.
> > >
> > > In order to fix this, entries need to be fixed to conform to the
> > > requirements - where the machine_is_xxx() name is the same as the
> > > MACH_TYPE_xxx name and the CONFIG_MACH_xxx name too.
> > >
> > > Moreover, entries older than 12 months which have not been merged will
> > > be removed. It is not possible to automatically check for machine_is_xxx()
> > > usages as these could conflict with other architectures, and I'm
> > > certainly NOT checking for them by hand (I estimate that'd take a
> > > significant amount of manual effort to do.) What that means is that it
> > > is _important_ to get the core platform support in _first_ before any
> > > drivers which may make use of this.
> > >
> > > The following will be deleted from the file this time around are:
> > > -ts_x09 MACH_TS209 TS209 1565
> > > -at572d940hfek MACH_AT572D940HFEB AT572D940HFEB 1783
> > can be dropped the at572d940hfek as the at572d940hf is drop from mainline
> >
> > Russell an you confirm you will re-add the usb-a9g20 and the folowing one
> >
> > usb_a9g20 MACH_USB_A9G20 USB_A9G20 1841
> > qil_a9g20 MACH_QIL_A9G20 QIL_A9G20 1844
> > tny_a9260 MACH_TNY_A9260 TNY_A9260 2058
> > tny_a9g20 MACH_TNY_A9G20 TNY_A9G20 2059
> > tny_a9263 MACH_TNY_A9263 TNY_A9263 2140
>
> Here's the two relevent question:
> 1. have they been submitted or edited within the last 12 months? No.
> 2. are they merged into mainline? No.
>
> So will they be in the update? No.
agreed but I've receive the hardware just recently so I add them one by one
the usb_a9g20 is the first and already in Arnd tree
so If you can re-add the otherone it will be nice
they will come soon
Best Regards,
J.
^ permalink raw reply
* [PATCH 3/3] ARM: vfp: fix a hole in VFP thread migration
From: Colin Cross @ 2011-09-17 2:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <E1QfaTD-0006QO-SR@rmk-PC.arm.linux.org.uk>
On Sat, Jul 9, 2011 at 9:33 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> Fix a hole in the VFP thread migration. ?Lets define two threads.
I was using the 4 patches in this series on a heavily modified
OMAP4460 SMP kernel based on v3.0, and getting reports from userspace
developers that they were seeing reproducible FP register corruption
resulting in an infinite loop in userspace. Bisecting this series
showed this patch was the culprit, and reverting this patch and the
following patch fixed the problem. Since I'm not running a mainline
kernel, this is mostly just an FYI in case someone else sees a similar
problem.
^ permalink raw reply
* [PATCH] ARM: BUG() dies silently
From: Rabin Vincent @ 2011-09-17 6:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1301602523-9906-1-git-send-email-omar.ramirez@ti.com>
On Fri, Apr 1, 2011 at 01:45, Omar Ramirez Luna <omar.ramirez@ti.com> wrote:
> There are some cases where the code generated for BUG() results
> into an infinite while loop without causing a null dereference,
> this ends on a kernel being stuck on a loop and the user without
> a clue of what happened.
>
> E.g.: lib/scatterlist.c : __sg_alloc_table
>
> ? ? ? ?BUG_ON(nents > max_ents);
> ?438: ? 9a000000 ? ? ? ?bls ? ? 440 <__sg_alloc_table+0x20>
> ?43c: ? eafffffe ? ? ? ?b ? ? ? 43c <__sg_alloc_table+0x1c>
>
> Adding volatile makes the compiler to avoid optimizations on this
> code, which makes the panic to occur:
>
> ? ? ? ?BUG_ON(nents > max_ents);
> ?438: ? 9a000002 ? ? ? ?bls ? ? 448 <__sg_alloc_table+0x28>
> ?43c: ? e3a03000 ? ? ? ?mov ? ? r3, #0
> ?440: ? e5833000 ? ? ? ?str ? ? r3, [r3]
> ?444: ? eafffffc ? ? ? ?b ? ? ? 43c <__sg_alloc_table+0x1c>
>
> Seen with gnu/linux cs arm-2010q1-202 and arm2010.09-50.
>
> Signed-off-by: Omar Ramirez Luna <omar.ramirez@ti.com>
If the "Use generic BUG() handler" patch is only scheduled for the next
merge window and not for 3.1, can this patch be merged instead for 3.1
and -stable? This problem is easily seen with GCC 4.6.
^ permalink raw reply
* [PATCH 3/7] ASoC: edb93xx: convert to use snd_soc_register_card()
From: Mika Westerberg @ 2011-09-17 6:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316191555.17769.2.camel@r60e>
On Fri, Sep 16, 2011 at 06:45:55PM +0200, Alexander Sverdlin wrote:
>
> Have you tried the driver on reference boards?
No - I don't have any of those.
> For me it doesn't work any more. Boot messages are ok, as before, but
> alsa open produces such messages:
> Jan 1 00:32:19 IPCUn user.err kernel: asoc: can't open platform
> ep93xx-pcm-audio
Do you have the first patch ("ASoC: ep93xx-pcm: add MODULE_ALIAS") in this
series applied? Have you tried whether it still works if you compile
everything in?
^ permalink raw reply
* [PATCH v2 6/6] arm/imx6q: add suspend/resume support
From: Shawn Guo @ 2011-09-17 8:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110916144539.GA18765@e102568-lin.cambridge.arm.com>
On Fri, Sep 16, 2011 at 03:45:39PM +0100, Lorenzo Pieralisi wrote:
> Hi Shawn,
>
> On Fri, Sep 16, 2011 at 07:09:00AM +0100, Shawn Guo wrote:
> > Hi Lorenzo,
> >
> > On Thu, Sep 15, 2011 at 05:28:29PM +0100, Lorenzo Pieralisi wrote:
> > > On Thu, Sep 15, 2011 at 03:45:26PM +0100, Shawn Guo wrote:
> > > > It adds suspend/resume support for imx6q.
> > > >
> > > > Signed-off-by: Anson Huang <b20788@freescale.com>
> > > > Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> > > > ---
>
> [...]
>
> > > > +ENTRY(v7_cpu_resume)
> > > > + bl v7_invalidate_l1
> > > > +
> > > > + /*
> > > > + * Restore L2 AUX_CTRL register saved by suspend procedure
> > > > + * and enable L2
> > > > + */
> > > > + adr r4, 1f
> > > > + ldmia r4, {r5, r6, r7}
> > > > + sub r4, r4, r5
> > > > + add r6, r6, r4
> > > > + add r7, r7, r4
> > > > + ldr r0, [r6]
> > > > + ldr r7, [r7]
> > > > + ldr r1, [r7]
> > > > + str r1, [r0, #L2X0_AUX_CTRL]
> > > > + ldr r1, =0x1
> > > > + str r1, [r0, #L2X0_CTRL]
> > > > +
> > > > + b cpu_resume
> > > > +
> > > > + .align
> > > > +1: .long .
> > > > + .long pl310_pbase
> > > > + .long pl310_aux_ctrl_paddr
> > >
> > > Would not something like:
> > >
> > > adr r4, pl310_pbase
> > > ldmia r4, {r6, r7}
> > > [...]
> > >
> > > pl310_pbase:
> > > .long 0
> > > pl310_aux_ctrl:
> > > .long 0
> > >
> > > be better and faster ? Why play with virtual addresses ?
> > > Of course you should initialize the values, but then you can access them
> > > through a PC relative load when running physical.
> >
> > Thanks for the comment. I agree with you that it's better, though my
> > first thought on the existing approach is I can access the global
> > variables defined in C file directly from assembly code.
> >
>
> You can even access assembly variables from C code, declare them
>
> .globl pl310_base
>
> and
>
> extern unsigned int pl310_base;
>
> in your C code and you are all set. But I would avoid global variables,
> comments below.
>
Ah, thanks. As you can see, I'm still at entry level of assembly :)
> > > Your code should be in the .data section for it to be writable (adr does not
> > > work across sections), have a look at Russell's code in sleep.S it is
> > > very well commented and similar to what you need.
> >
> > Thanks for pointing me the example.
> >
>
> You are welcome, my pleasure.
>
> > >
> > > > +ENDPROC(v7_cpu_resume)
> > > > diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c
> > > > new file mode 100644
> > > > index 0000000..124bcd5
> > > > --- /dev/null
> > > > +++ b/arch/arm/mach-imx/pm-imx6q.c
> > > > @@ -0,0 +1,88 @@
> > > > +/*
> > > > + * Copyright 2011 Freescale Semiconductor, Inc.
> > > > + * Copyright 2011 Linaro Ltd.
> > > > + *
> > > > + * The code contained herein is licensed under the GNU General Public
> > > > + * License. You may obtain a copy of the GNU General Public License
> > > > + * Version 2 or later at the following locations:
> > > > + *
> > > > + * http://www.opensource.org/licenses/gpl-license.html
> > > > + * http://www.gnu.org/copyleft/gpl.html
> > > > + */
> > > > +
> > > > +#include <linux/init.h>
> > > > +#include <linux/io.h>
> > > > +#include <linux/of.h>
> > > > +#include <linux/suspend.h>
> > > > +#include <asm/proc-fns.h>
> > > > +#include <asm/suspend.h>
> > > > +#include <asm/hardware/cache-l2x0.h>
> > > > +#include <mach/common.h>
> > > > +#include <mach/hardware.h>
> > > > +
> > > > +static void __iomem *pl310_vbase;
> > > > +void __iomem *pl310_pbase;
> > > > +
> > > > +static volatile unsigned long pl310_aux_ctrl;
> > > > +volatile unsigned long pl310_aux_ctrl_paddr;
> > >
> > > I think that by defining those variables in assembly you would make
> > > your life much simpler.
> >
> > Yes. But I need a function call to learn the address of those variables
> > from assembly now.
> >
>
> No, you do not, see above.
>
> > > I think you know your L2 is already initialized here to make sure you
> > > save the right aux value. Hence you should clean the variables above from
> > > L2 to make sure they are available at reset from DRAM (L2 is retained
> > > and you do not clean it on suspend, correct ?)
> >
> > Yes, agreed. It's right thing to do for being safe. Actually, I did it
> > when I saved the variables during suspend. If I do not do, it simply
> > does not work. But later, when I moved the saving to init function
> > since it needs to be done for only once, I found it works even without
> > the cache clean. Then I dropped it. To be safe, now I'm adding it
> > back with following your comment.
> >
> > >
> > > I do not think that code to save/restore L2 config belongs here though.
> > > More below.
> > >
> > > > +
> > > > +static int imx6q_suspend_finish(unsigned long val)
> > > > +{
> > > > + cpu_do_idle();
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static int imx6q_pm_enter(suspend_state_t state)
> > > > +{
> > > > + switch (state) {
> > > > + case PM_SUSPEND_MEM:
> > > > + imx6q_set_lpm(STOP_POWER_OFF);
> > > > + imx_gpc_pre_suspend();
> > > > + imx_set_cpu_jump(0, v7_cpu_resume);
> > > > + /* Zzz ... */
> > > > + cpu_suspend(0, imx6q_suspend_finish);
> > > > + imx_smp_prepare();
> > > > + imx_gpc_post_resume();
> > > > + break;
> > > > + default:
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static const struct platform_suspend_ops imx6q_pm_ops = {
> > > > + .enter = imx6q_pm_enter,
> > > > + .valid = suspend_valid_only_mem,
> > > > +};
> > > > +
> > > > +void __init imx6q_pm_init(void)
> > > > +{
> > > > + struct device_node *np;
> > > > + u32 reg[2];
> > > > +
> > > > + np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
> > > > + of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
> > > > + pl310_vbase = ioremap(reg[0], reg[1]);
> > >
> > > Mmmm...is this vma ever released ? L2 is already mapped in the L2
> > > driver from DT or through static mappings.
> >
> > I think we can do another mapping even it's been done in the L2 driver,
> > no?
> >
>
> I still think that it is not really clean. But more importantly you should
> release the mapping when you are done with it (iounmap).
>
Yes, I should iounmap it.
> > > Overall, I think that code to restore PL310 belongs in cache-l2x0.c, not here.
> > > We can easily write an assembly stub that reinitialize L2 before
> > > resume if that's something we should and can do (security ?).
> > >
> > I would be definitely happy to see that, but before rmk agrees on that,
> > I have to find a way around in the platform code.
>
> I am working on that; your point is fair, but security notwithstanding
> there is nothing that can prevent us from having an assembly hook to
> resume L2 in a platform independent manner. More to come.
>
Great. I will definitely migrate imx6q to that once it gets merged.
> >
> > Here is the updated patch. If it looks better to you, I will
> > incorporate it in the v3 of the series.
> >
> > 8<---
> > diff --git a/arch/arm/mach-imx/head-v7.S b/arch/arm/mach-imx/head-v7.S
> > index ede908b..5a486a9 100644
> > --- a/arch/arm/mach-imx/head-v7.S
> > +++ b/arch/arm/mach-imx/head-v7.S
> > @@ -69,3 +69,35 @@ ENTRY(v7_secondary_startup)
> > b secondary_startup
> > ENDPROC(v7_secondary_startup)
> > #endif
> > +
> > +ENTRY(pl310_get_save_ptr)
> > + ldr r0, =pl310_pbase
> > + mov pc, lr
> > +ENDPROC(pl310_get_save_ptr)
> > +
>
> You do not need a function to do that. Just declare the label as
>
> .globl
>
> and from C you can access those values. See above.
>
> It would be nicer to avoid global variables altogether though.
> You can write an assembly function taking the values to be saved and
> returning the pointer to flush from L1 and L2.
>
Thanks for the suggestion. But I feel good about the current
implementation.
> > +ENTRY(v7_cpu_resume)
> > + bl v7_invalidate_l1
> > + bl pl310_resume
> > + b cpu_resume
> > +ENDPROC(v7_cpu_resume)
> > +
> > +/*
> > + * The following code is located into the .data section. This is to
> > + * allow pl310_pbase and pl310_aux_ctrl to be accessed with a relative
> > + * load as we are running on physical address here.
> > + */
> > + .data
> > + .align
> > +ENTRY(pl310_resume)
> > + adr r2, pl310_pbase
> > + ldmia r2, {r0, r1}
> > + str r1, [r0, #L2X0_AUX_CTRL] @ restore aux_ctrl
> > + mov r1, #0x1
> > + str r1, [r0, #L2X0_CTRL] @ re-enable L2
> > + mov pc, lr
> > +ENDPROC(pl310_resume)
> > +
> > +pl310_pbase:
> > + .long 0
> > +pl310_aux_ctrl:
> > + .long 0
>
> You might want to inline it and avoid the jump.
>
One reason that I implemented pl310_resume as a function call is that
I was trying to minimize the code that we have to put in .data section.
Now I do not think it's a point that really matters. So following your
suggestion, here it is. Please let me know it is not what you meant to
see.
/*
* The following code is located into the .data section. This is to
* allow pl310_pbase and pl310_aux_ctrl to be accessed with a relative
* load as we are running on physical address here.
*/
.data
.align
.macro pl310_resume
adr r2, pl310_pbase
ldmia r2, {r0, r1}
str r1, [r0, #L2X0_AUX_CTRL] @ restore aux_ctrl
mov r1, #0x1
str r1, [r0, #L2X0_CTRL] @ re-enable L2
.endm
ENTRY(v7_cpu_resume)
bl v7_invalidate_l1
pl310_resume
b cpu_resume
ENDPROC(v7_cpu_resume)
.globl
pl310_pbase:
.long 0
pl310_aux_ctrl:
.long 0
--
Regards,
Shawn
^ permalink raw reply
* [PATCH v2 2/2] ARM: smp_scu: remove __init annotation from scu_enable()
From: Shawn Guo @ 2011-09-17 8:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1315288107-14689-3-git-send-email-shawn.guo@linaro.org>
On Tue, Sep 06, 2011 at 01:48:27PM +0800, Shawn Guo wrote:
> When Cortex-A9 MPCore resumes from Dormant or Shutdown modes,
> SCU needs to be re-enabled. This patch removes __init annotation
> from function scu_enable(), so that platform resume procedure can
> call it to re-enable SCU.
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
Hi Russell,
Do you have any comment on this patch? Can I put it into patch tracker?
Regards,
Shawn
> arch/arm/kernel/smp_scu.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
> index 79ed5e7..5b6d536 100644
> --- a/arch/arm/kernel/smp_scu.c
> +++ b/arch/arm/kernel/smp_scu.c
> @@ -33,7 +33,7 @@ unsigned int __init scu_get_core_count(void __iomem *scu_base)
> /*
> * Enable the SCU
> */
> -void __init scu_enable(void __iomem *scu_base)
> +void scu_enable(void __iomem *scu_base)
> {
> u32 scu_ctrl;
>
> --
> 1.7.4.1
^ 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