int msm_iommu_pagetable_map(struct msm_iommu_pt *pt, unsigned long va,
                            phys_addr_t pa, size_t len, int prot)
{
    u64 *fl_pte;
    u32 fl_offset;
    u32 sl_offset;
    u64 *sl_table;
    u64 *sl_pte;
    u64 upper_attr;
    u64 lower_attr;
    s32 ret;
    u32 redirect = pt->redirect;

    ret = common_error_check(len, pt->fl_table);
    if (ret)
        goto fail;

    if (!pt->fl_table) {
        pr_err("Null page table\n");
        ret = -EINVAL;
        goto fail;
    }

    __get_attr(prot, &upper_attr, &lower_attr);

    fl_offset = FL_OFFSET(va);
    fl_pte = pt->fl_table + fl_offset;

    ret = handle_1st_lvl(fl_pte, pa, upper_attr, lower_attr, len, redirect);
    if (ret)
        goto fail;

    sl_table = FOLLOW_TO_NEXT_TABLE(fl_pte);
    sl_offset = SL_OFFSET(va);
    sl_pte = sl_table + sl_offset;

    if (len == SZ_32M)
        ret = sl_32m_map(sl_pte, pa, upper_attr, lower_attr, redirect);
    else if (len == SZ_2M)
        ret = sl_2m_map(sl_pte, pa, upper_attr, lower_attr, redirect);
    else if (len == SZ_64K || len == SZ_4K)
        ret = handle_3rd_lvl(sl_pte, va, pa, upper_attr, lower_attr,
                             len, redirect);

fail:
    return ret;
}
Beispiel #2
0
struct con_pair * __get_pair( char ** cp )
{
char *keyword, *value;
struct con_pair * con_p;

    __get_attr( cp, &keyword, &value );
    if ( keyword )
    {
        con_p = malloc( sizeof( *con_p ));
        con_p -> keyword = keyword;
        con_p -> attribute = value;
        return con_p;
    }
    else
    {
        return NULL;
    }
}
s32 msm_iommu_pagetable_map_range(struct msm_iommu_pt *pt, u32 va,
                                  struct scatterlist *sg, u32 len, s32 prot)
{
    phys_addr_t pa;
    u32 offset = 0;
    u64 *fl_pte;
    u64 *sl_pte;
    u32 fl_offset;
    u32 sl_offset;
    u64 *sl_table = NULL;
    u32 chunk_size, chunk_offset = 0;
    s32 ret = 0;
    u64 up_at;
    u64 lo_at;
    u32 redirect = pt->redirect;
    unsigned int start_va = va;

    BUG_ON(len & (SZ_4K - 1));

    if (!pt->fl_table) {
        pr_err("Null page table\n");
        ret = -EINVAL;
        goto fail;
    }

    __get_attr(prot, &up_at, &lo_at);

    pa = get_phys_addr(sg);

    while (offset < len) {
        u32 chunk_left = sg->length - chunk_offset;

        fl_offset = FL_OFFSET(va);
        fl_pte = pt->fl_table + fl_offset;

        chunk_size = SZ_4K;
        if (is_fully_aligned(va, pa, chunk_left, SZ_1G))
            chunk_size = SZ_1G;
        else if (is_fully_aligned(va, pa, chunk_left, SZ_32M))
            chunk_size = SZ_32M;
        else if (is_fully_aligned(va, pa, chunk_left, SZ_2M))
            chunk_size = SZ_2M;
        else if (is_fully_aligned(va, pa, chunk_left, SZ_64K))
            chunk_size = SZ_64K;

        trace_iommu_map_range(va, pa, sg->length, chunk_size);

        ret = handle_1st_lvl(fl_pte, pa, up_at, lo_at,
                             chunk_size, redirect);
        if (ret)
            goto fail;

        sl_table = FOLLOW_TO_NEXT_TABLE(fl_pte);
        sl_offset = SL_OFFSET(va);
        sl_pte = sl_table + sl_offset;

        if (chunk_size == SZ_32M)
            ret = sl_32m_map(sl_pte, pa, up_at, lo_at, redirect);
        else if (chunk_size == SZ_2M)
            ret = sl_2m_map(sl_pte, pa, up_at, lo_at, redirect);
        else if (chunk_size == SZ_64K || chunk_size == SZ_4K)
            ret = handle_3rd_lvl(sl_pte, va, pa, up_at, lo_at,
                                 chunk_size, redirect);
        if (ret)
            goto fail;

        offset += chunk_size;
        chunk_offset += chunk_size;
        va += chunk_size;
        pa += chunk_size;

        if (chunk_offset >= sg->length && offset < len) {
            chunk_offset = 0;
            sg = sg_next(sg);
            pa = get_phys_addr(sg);
        }
    }
fail:
    if (ret && offset > 0)
        __msm_iommu_pagetable_unmap_range(pt, start_va, offset, 1);
    return ret;
}