博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iommu 的dma_strict
阅读量:4216 次
发布时间:2019-05-26

本文共 3772 字,大约阅读时间需要 12 分钟。

在iommu.c 中有定义一个变量,让iommu默认就设置的是dma_strictstatic bool iommu_dma_strict __read_mostly = true;那什么是dma_strict的呢?struct iommu_group *iommu_group_get_for_dev(struct device *dev){	if (!group->default_domain) {		struct iommu_domain *dom;		dom = __iommu_domain_alloc(dev->bus, iommu_def_domain_type);		if (!dom && iommu_def_domain_type != IOMMU_DOMAIN_DMA) {			dev_warn(dev,				 "failed to allocate default IOMMU domain of type %u; falling back to IOMMU_DOMAIN_DMA",				 iommu_def_domain_type);			dom = __iommu_domain_alloc(dev->bus, IOMMU_DOMAIN_DMA);		}		group->default_domain = dom;		if (!group->domain)			group->domain = dom;#可以看到这个变量是在这里被利用的		if (dom && !iommu_dma_strict) {			int attr = 1;			iommu_domain_set_attr(dom,					      DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE,					      &attr);		}	}}iommu_domain_set_attr的实现如下:int iommu_domain_set_attr(struct iommu_domain *domain,			  enum iommu_attr attr, void *data){	int ret = 0;	switch (attr) {	default:		if (domain->ops->domain_set_attr == NULL)			return -EINVAL;#这里的domain_set_attr的实现在具体的驱动中		ret = domain->ops->domain_set_attr(domain, attr, data);	}	return ret;}driver/iommu/arm_iommu-v3.cstatic int arm_smmu_domain_set_attr(struct iommu_domain *domain,				    enum iommu_attr attr, void *data){	int ret = 0;	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);	mutex_lock(&smmu_domain->init_mutex);	switch (domain->type) {	case IOMMU_DOMAIN_DMA:		switch(attr) {#从上面一路调下来,这里看到这里的data其实等于1.		case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:			smmu_domain->non_strict = *(int *)data;			break;		default:			ret = -ENODEV;		}		break;	default:		ret = -EINVAL;	}}driver/iommu/arm_iommu-v3.cstatic int arm_smmu_domain_finalise(struct iommu_domain *domain){	#从这里可以看到又将non_strict转成IO_PGTABLE_QUIRK_NON_STRICT,及以后要判断这个flag	if (smmu_domain->non_strict)		pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT;}static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,			      unsigned long iova, size_t size, int lvl,			      arm_v7s_iopte *ptep){	/* If the size matches this level, we're in the right place */	if (num_entries) {		size_t blk_size = ARM_V7S_BLOCK_SIZE(lvl);		__arm_v7s_set_pte(ptep, 0, num_entries, &iop->cfg);		for (i = 0; i < num_entries; i++) {			if (ARM_V7S_PTE_IS_TABLE(pte[i], lvl)) {				/* Also flush any partial walks */				io_pgtable_tlb_add_flush(iop, iova, blk_size,					ARM_V7S_BLOCK_SIZE(lvl + 1), false);				io_pgtable_tlb_sync(iop);				ptep = iopte_deref(pte[i], lvl);				__arm_v7s_free_table(ptep, lvl + 1, data);#从这里看到所谓的no-strict就是不刷新iommu的tlb			} else if (iop->cfg.quirks & IO_PGTABLE_QUIRK_NON_STRICT) {				/*				 * Order the PTE update against queueing the IOVA, to				 * guarantee that a flush callback from a different CPU				 * has observed it before the TLBIALL can be issued.				 */				smp_wmb();			} else {				io_pgtable_tlb_add_flush(iop, iova, blk_size,							 blk_size, true);			}			iova += blk_size;		}		return size;}那具体是在什么时候刷新tlb呢?原来是在下面的的函数中建立了一个timer来定时刷新tlbint init_iova_flush_queue(struct iova_domain *iovad,			  iova_flush_cb flush_cb, iova_entry_dtor entry_dtor){	timer_setup(&iovad->fq_timer, fq_flush_timeout, 0);	atomic_set(&iovad->fq_timer_on, 0);	return 0;}fq_flush_timeout->iova_domain_flushstatic void iova_domain_flush(struct iova_domain *iovad){	atomic64_inc(&iovad->fq_flush_start_cnt);#这里调用flush_cb来flush tlb	iovad->flush_cb(iovad);	atomic64_inc(&iovad->fq_flush_finish_cnt);}int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,		u64 size, struct device *dev){	if (!cookie->fq_domain && !iommu_domain_get_attr(domain,			DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE, &attr) && attr) {		cookie->fq_domain = domain;		init_iova_flush_queue(iovad, iommu_dma_flush_iotlb_all, NULL);	}}从上面的函数可以看到flush_cb是iommu_dma_flush_iotlb_all所以iommu的non-strict 模式就是不刷新tlb,而是通过起一个timer来刷tlb,来提高性能

 

转载地址:http://vvnmi.baihongyu.com/

你可能感兴趣的文章
表格存储最佳实践:一种用于存储时间序列数据的表结构设计
查看>>
OpenTSDB介绍
查看>>
OpenTSDB原理系列:元数据模型
查看>>
解密OpenTSDB的表存储优化
查看>>
OpeTSDB的Configuration配置
查看>>
FQDN
查看>>
时序数据库
查看>>
jmxtrans+influxdb+granafa监控hbase
查看>>
使用jmxtrans监控Spark JVM信息到grafana显示
查看>>
HBase - ROOT 和 META 表结构 (region定位原理)
查看>>
HBase API 和 基本操作
查看>>
Hbase的存储模型
查看>>
InfluxDB influxdbc.conf配置文件详解
查看>>
通过BulkLoad的方式快速导入海量数据
查看>>
Mysql根据内容查找在哪个表(Go版本)
查看>>
玩转Anaconda
查看>>
kali linux中文版安装
查看>>
安卓逆向之环境搭建
查看>>
修改包名实现app分身
查看>>
NDK静态注册之调用C层并返回字符串
查看>>