国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

smmu學(xué)習(xí)筆記之streamtable

2019-11-06 09:45:50
字體:
供稿:網(wǎng)友
streamtable有兩種組織方式,根據(jù)ARM_SMMU_FEAT_2_LVL_STRTAB來判斷而這個(gè)flag是在arm_smmu_device_hw_PRobe 中通過讀取ARM_SMMU_IDR0 這個(gè)寄存器來判斷的static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu){    u32 reg;    bool coherent = smmu->features & ARM_SMMU_FEAT_COHERENCY;    /* IDR0 */    reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0);    /* 2-level structures */    if ((reg & IDR0_ST_LVL_MASK << IDR0_ST_LVL_SHIFT) == IDR0_ST_LVL_2LVL)        smmu->features |= ARM_SMMU_FEAT_2_LVL_STRTAB;}所以在arm_smmu_init_strtab 中就根據(jù)這個(gè)flag 將streamtable分成兩種組織方式static int arm_smmu_init_strtab(struct arm_smmu_device *smmu){    u64 reg;    int ret;    if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)        ret = arm_smmu_init_strtab_2lvl(smmu);    else        ret = arm_smmu_init_strtab_linear(smmu);    if (ret)        return ret;    /* Set the strtab base address */    reg  = smmu->strtab_cfg.strtab_dma &           STRTAB_BASE_ADDR_MASK << STRTAB_BASE_ADDR_SHIFT;    reg |= STRTAB_BASE_RA;    smmu->strtab_cfg.strtab_base = reg;    /* Allocate the first VMID for stage-2 bypass STEs */    set_bit(0, smmu->vmid_map);    return 0;}不管采用哪種streamtable,都會(huì)對smmu->strtab_cfg.strtab_dma賦值,最后將smmu->strtab_cfg.strtab_dma 保存到smmu->strtab_cfg.strtab_base 中。我們先來看arm_smmu_init_strtab_2lvlstatic int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu){    void *strtab;    u64 reg;    u32 size, l1size;//讓cfg 指針指向smmu->strtab_cfg    struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;    /*     * If we can resolve everything with a single L2 table, then we     * just need a single L1 descriptor. Otherwise, calculate the L1     * size, capped to the SIDSIZE.     */    if (smmu->sid_bits < STRTAB_SPLIT) {        size = 0;    } else {        size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWordS) + 3);        size = min(size, smmu->sid_bits - STRTAB_SPLIT);    }#計(jì)算l1 entry 的size    cfg->num_l1_ents = 1 << size;    size += STRTAB_SPLIT;    if (size < smmu->sid_bits)        dev_warn(smmu->dev,             "2-level strtab only covers %u/%u bits of SID/n",             size, smmu->sid_bits);    l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);#為strtab 申請memory    strtab = dmam_alloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,                     GFP_KERNEL | __GFP_ZERO);    if (!strtab) {        dev_err(smmu->dev,            "failed to allocate l1 stream table (%u bytes)/n",            size);        return -ENOMEM;    }    cfg->strtab = strtab;    /* Configure strtab_base_cfg for 2 levels */    reg  = STRTAB_BASE_CFG_FMT_2LVL;    reg |= (size & STRTAB_BASE_CFG_LOG2SIZE_MASK)        << STRTAB_BASE_CFG_LOG2SIZE_SHIFT;    reg |= (STRTAB_SPLIT & STRTAB_BASE_CFG_SPLIT_MASK)        << STRTAB_BASE_CFG_SPLIT_SHIFT;#這里就給cfg->strtab_base_cfg 賦值    cfg->strtab_base_cfg = reg;    return arm_smmu_init_l1_strtab(smmu);}總結(jié)一下arm_smmu_init_strtab_2lvl 主要是對arm_smmu_strtab_cfg來進(jìn)行初始化static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu){    unsigned int i;    struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;    size_t size = sizeof(*cfg->l1_desc) * cfg->num_l1_ents;    void *strtab = smmu->strtab_cfg.strtab;    cfg->l1_desc = devm_kzalloc(smmu->dev, size, GFP_KERNEL);    if (!cfg->l1_desc) {        dev_err(smmu->dev, "failed to allocate l1 stream table desc/n");        return -ENOMEM;    }    for (i = 0; i < cfg->num_l1_ents; ++i) {    #這里將cfg->l1_desc[i] 里面SPAN和L2PTR的值寫到strtab 里面。        arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);        strtab += STRTAB_L1_DESC_DWORDS << 3;    }    return 0;}總結(jié)一下arm_smmu_init_l1_strtab 主要是對strtab_cfg.strtab 賦值,我比較疑惑的是這里的cfg->l1_desc 也是剛申請的,理論上cfg->l1_desc 里面是空的才對,不知道為什么要把這里的值寫到strtab中.這個(gè)疑惑在arm_smmu_add_device 中可以得到解答    /* Check the SIDs are in range of the SMMU and our stream table */    for (i = 0; i < fwspec->num_ids; i++) {        u32 sid = fwspec->ids[i];        if (!arm_smmu_sid_in_range(smmu, sid))            return -ERANGE;        /* Ensure l2 strtab is initialised */        if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {            ret = arm_smmu_init_l2_strtab(smmu, sid);            if (ret)                return ret;        }    }從上面在這段code中可以看到如果置了ARM_SMMU_FEAT_2_LVL_STRTAB 這個(gè)flag,會(huì)調(diào)用arm_smmu_init_l2_strtabstatic int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid){    size_t size;    void *strtab;    struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;    struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];    if (desc->l2ptr)        return 0;    size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);    strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];    desc->span = STRTAB_SPLIT + 1;    desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,                      GFP_KERNEL | __GFP_ZERO);    if (!desc->l2ptr) {        dev_err(smmu->dev,            "failed to allocate l2 stream table for SID %u/n",            sid);        return -ENOMEM;    }    arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);    arm_smmu_write_strtab_l1_desc(strtab, desc);    return 0;}在arm_smmu_init_l2_strtab 中可以看到會(huì)對desc->l2ptr和desc->span 賦值,然后在調(diào)用arm_smmu_write_strtab_l1_desc 來寫streamtable。這感覺在arm_smmu_init_l1_strtab中調(diào)用arm_smmu_write_strtab_l1_desc 沒有啥意思.
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 庐江县| 阆中市| 托克逊县| 辽阳市| 沂源县| 寻乌县| 三亚市| 天津市| 河南省| 毕节市| 柯坪县| 新疆| 绥芬河市| 益阳市| 三亚市| 肇庆市| 津市市| 英山县| 金平| 益阳市| 措勤县| 日土县| 松阳县| 于田县| 赣榆县| 普陀区| 叶城县| 兴宁市| 武川县| 肇东市| 阳山县| 中西区| 涟水县| 巴林左旗| 淮滨县| 宣城市| 轮台县| 龙海市| 金昌市| 江源县| 黄冈市|