Skip to content

Commit

Permalink
msm: iommu: Support cache-coherent memory access
Browse files Browse the repository at this point in the history
Add support for allowing IOMMU memory transactions to be
cache coherent, eliminating the need for software cache
management in certain situations. This can lead to
improvements in performance and power usage, assuming the
multimedia core's access pattern exhibits spatial locality
and that its working set fits into the cache.

Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
  • Loading branch information
Stepan Moskovchenko authored and Daniel Walker committed Dec 1, 2010
1 parent 08bd683 commit 100832c
Showing 1 changed file with 82 additions and 11 deletions.
93 changes: 82 additions & 11 deletions arch/arm/mach-msm/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@
#include <mach/iommu_hw-8xxx.h>
#include <mach/iommu.h>

#define MRC(reg, processor, op1, crn, crm, op2) \
__asm__ __volatile__ ( \
" mrc " #processor "," #op1 ", %0," #crn "," #crm "," #op2 "\n" \
: "=r" (reg))

#define RCP15_PRRR(reg) MRC(reg, p15, 0, c10, c2, 0)
#define RCP15_NMRR(reg) MRC(reg, p15, 0, c10, c2, 1)

static int msm_iommu_tex_class[4];

DEFINE_SPINLOCK(msm_iommu_lock);

struct msm_priv {
Expand Down Expand Up @@ -98,6 +108,7 @@ static void __reset_context(void __iomem *base, int ctx)

static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable)
{
unsigned int prrr, nmrr;
__reset_context(base, ctx);

/* Set up HTW mode */
Expand Down Expand Up @@ -130,11 +141,11 @@ static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable)
/* Turn on TEX Remap */
SET_TRE(base, ctx, 1);

/* Do not configure PRRR / NMRR on the IOMMU for now. We will assume
* TEX class 0 for everything until attributes are properly worked out
*/
SET_PRRR(base, ctx, 0);
SET_NMRR(base, ctx, 0);
/* Set TEX remap attributes */
RCP15_PRRR(prrr);
RCP15_NMRR(nmrr);
SET_PRRR(base, ctx, prrr);
SET_NMRR(base, ctx, nmrr);

/* Turn on BFB prefetch */
SET_BFBDFE(base, ctx, 1);
Expand Down Expand Up @@ -304,12 +315,21 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
unsigned long *sl_table;
unsigned long *sl_pte;
unsigned long sl_offset;
unsigned int pgprot;
size_t len = 0x1000UL << order;
int ret = 0;
int ret = 0, tex, sh;

spin_lock_irqsave(&msm_iommu_lock, flags);
priv = domain->priv;

sh = (prot & MSM_IOMMU_ATTR_SH) ? 1 : 0;
tex = msm_iommu_tex_class[prot & MSM_IOMMU_CP_MASK];

if (tex < 0 || tex > NUM_TEX_CLASS - 1) {
ret = -EINVAL;
goto fail;
}

priv = domain->priv;
if (!priv) {
ret = -EINVAL;
goto fail;
Expand All @@ -330,6 +350,18 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
goto fail;
}

if (len == SZ_16M || len == SZ_1M) {
pgprot = sh ? FL_SHARED : 0;
pgprot |= tex & 0x01 ? FL_BUFFERABLE : 0;
pgprot |= tex & 0x02 ? FL_CACHEABLE : 0;
pgprot |= tex & 0x04 ? FL_TEX0 : 0;
} else {
pgprot = sh ? SL_SHARED : 0;
pgprot |= tex & 0x01 ? SL_BUFFERABLE : 0;
pgprot |= tex & 0x02 ? SL_CACHEABLE : 0;
pgprot |= tex & 0x04 ? SL_TEX0 : 0;
}

fl_offset = FL_OFFSET(va); /* Upper 12 bits */
fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */

Expand All @@ -338,12 +370,12 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
for (i = 0; i < 16; i++)
*(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION |
FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT |
FL_SHARED;
FL_SHARED | pgprot;
}

if (len == SZ_1M)
*fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE |
FL_TYPE_SECT | FL_SHARED;
FL_TYPE_SECT | FL_SHARED | pgprot;

/* Need a 2nd level table */
if ((len == SZ_4K || len == SZ_64K) && (*fl_pte) == 0) {
Expand All @@ -368,14 +400,14 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,

if (len == SZ_4K)
*sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 |
SL_SHARED | SL_TYPE_SMALL;
SL_SHARED | SL_TYPE_SMALL | pgprot;

if (len == SZ_64K) {
int i;

for (i = 0; i < 16; i++)
*(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 |
SL_AP1 | SL_SHARED | SL_TYPE_LARGE;
SL_AP1 | SL_SHARED | SL_TYPE_LARGE | pgprot;
}

__flush_iotlb(domain);
Expand Down Expand Up @@ -593,8 +625,47 @@ static struct iommu_ops msm_iommu_ops = {
.domain_has_cap = msm_iommu_domain_has_cap
};

static int __init get_tex_class(int icp, int ocp, int mt, int nos)
{
int i = 0;
unsigned int prrr = 0;
unsigned int nmrr = 0;
int c_icp, c_ocp, c_mt, c_nos;

RCP15_PRRR(prrr);
RCP15_NMRR(nmrr);

for (i = 0; i < NUM_TEX_CLASS; i++) {
c_nos = PRRR_NOS(prrr, i);
c_mt = PRRR_MT(prrr, i);
c_icp = NMRR_ICP(nmrr, i);
c_ocp = NMRR_OCP(nmrr, i);

if (icp == c_icp && ocp == c_ocp && c_mt == mt && c_nos == nos)
return i;
}

return -ENODEV;
}

static void __init setup_iommu_tex_classes(void)
{
msm_iommu_tex_class[MSM_IOMMU_ATTR_NONCACHED] =
get_tex_class(CP_NONCACHED, CP_NONCACHED, MT_NORMAL, 1);

msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_WA] =
get_tex_class(CP_WB_WA, CP_WB_WA, MT_NORMAL, 1);

msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_NWA] =
get_tex_class(CP_WB_NWA, CP_WB_NWA, MT_NORMAL, 1);

msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WT] =
get_tex_class(CP_WT, CP_WT, MT_NORMAL, 1);
}

static int __init msm_iommu_init(void)
{
setup_iommu_tex_classes();
register_iommu(&msm_iommu_ops);
return 0;
}
Expand Down

0 comments on commit 100832c

Please sign in to comment.