当前位置: 首页 > news >正文

有数据库的网站深圳宝安天气预报

有数据库的网站,深圳宝安天气预报,wordpress 文件夹权限,立创商城概念 scatterlist scatterlist用来描述一块内存#xff0c;sg_table一般用于将物理不同大小的物理内存链接起来#xff0c;一次性送给DMA控制器搬运 struct scatterlist {unsigned long page_link; //指示该内存块所在的页面unsigned int offset; //指示该内存块在页面中的…概念 scatterlist scatterlist用来描述一块内存sg_table一般用于将物理不同大小的物理内存链接起来一次性送给DMA控制器搬运 struct scatterlist {unsigned long page_link; //指示该内存块所在的页面unsigned int offset; //指示该内存块在页面中的偏移起始位置unsigned int length; //该内存块的长度dma_addr_t dma_address; //该内存块实际的物理起始地址 #ifdef CONFIG_NEED_SG_DMA_LENGTHunsigned int dma_length; //相应的长度信息 #endif }; page_link (1).对于chain sg 来说记录下一个 SG 数组的首地址并且用bit[0] 和 bit[1] 来表示是chain sg 还是 end sg (2).对于 end sg 来说只有bit[1] 为1其他无意义 (3).对于普通 sg 来说记录的是关联的内存页块的地址 sg_table 既然链接起物理内存那么就需要多个sg内核给了个sg_table和一系列api便于操作sg struct sg_table {struct scatterlist *sgl; /* the list */unsigned int nents; //实际的内存块映射数量unsigned int orig_nents; ///内存块映射的数量 }; sg_alloc_table一次可以分配page size / sizeof(scatterlist)个scatterlist结构体如果超过这个数就需要再通过sg_alloc_table分配scatterlist并且通过sg_chain()来连接上一个sg_table和新的sg_table sg_alloc_table sg_kmalloc用以批量分配 sg 的内存;G_MAX_SINGLE_ALLOC系统规定了每次sg_kmalloc的最大个数为4096/32 128个 int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) {int ret;ret __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,NULL, 0, gfp_mask, sg_kmalloc);if (unlikely(ret))__sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);return ret; } EXPORT_SYMBOL(sg_alloc_table); 当申请的时候按照 SG_MAX_SINGLE_ALLOC那么是一次性申请 4K 内存系统直接调用 __get_free_page() 从buddy 中分配当没有达到 4K 内存则通过kmalloc_array()申请 static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask) {if (nents SG_MAX_SINGLE_ALLOC) {/** Kmemleak doesnt track page allocations as they are not* commonly used (in a raw form) for kernel data structures.* As we chain together a list of pages and then a normal* kmalloc (tracked by kmemleak), in order to for that last* allocation not to become decoupled (and thus a* false-positive) we need to inform kmemleak of all the* intermediate allocations.*/void *ptr (void *) __get_free_page(gfp_mask);kmemleak_alloc(ptr, PAGE_SIZE, 1, gfp_mask);return ptr;} elsereturn kmalloc_array(nents, sizeof(struct scatterlist),gfp_mask); } 根据nents决定需不需要再次调用sg_kmalloc分配struct scatterlist数组并返回首个scatterlist的地址为什么叫数组因为是在一个页面里面分配的是连续的 int __sg_alloc_table(struct sg_table *table, unsigned int nents,unsigned int max_ents, struct scatterlist *first_chunk,unsigned int nents_first_chunk, gfp_t gfp_mask,sg_alloc_fn *alloc_fn) {struct scatterlist *sg, *prv;unsigned int left;unsigned curr_max_ents nents_first_chunk ?: max_ents;unsigned prv_max_ents;//准备初始化 sg_table先memsetmemset(table, 0, sizeof(*table));//sg 条目数量不能为0if (nents 0)return -EINVAL; #ifdef CONFIG_ARCH_NO_SG_CHAINif (WARN_ON_ONCE(nents max_ents))return -EINVAL; #endif//初始化还没有申请的sg数目left nents;prv NULL;do {unsigned int sg_size, alloc_size left;//确定此次需要申请的sg 个数//申请的sg超过最大值将分多次分配if (alloc_size curr_max_ents) {alloc_size curr_max_ents;sg_size alloc_size - 1; //申请的sg数组中最后一个作为一个chain不作为有效sg} elsesg_size alloc_size;//还剩余多少sg没有申请left - sg_size;if (first_chunk) {sg first_chunk;first_chunk NULL;} else {sg alloc_fn(alloc_size, gfp_mask); //调用sg分配的回调函数}if (unlikely(!sg)) {/** Adjust entry count to reflect that the last* entry of the previous table wont be used for* linkage. Without this, sg_kfree() may get* confused.*/if (prv)table-nents table-orig_nents;return -ENOMEM;}/** 初始化此次申请的sg 数组这些sg 在物理上是连续的所以可以直接memset* 另外还会调用sg_mark_end() 初始化最后一个sg为 end sg*/sg_init_table(sg, alloc_size);//更新sg_table-nents初始化时 nents和orig_nents相同table-nents table-orig_nents sg_size;/** 当再次进入循环时说明需要的nents是大于max_nents的那么上一次申请肯定是按照最大值* 申请.* 第一次申请时会将sg数组放入sg_table的sgl* 当再进入循环时需要连接新建的sg数组所以要将prv的最后一个sg设为CHAIN*/if (prv)sg_chain(prv, prv_max_ents, sg);elsetable-sgl sg;//如果没剩余sg需要分配了将推出循环此时将最新分配的sg数组的最后一个sg设为ENDif (!left)sg_mark_end(sg[sg_size - 1]);prv sg;prv_max_ents curr_max_ents; //能进入下一个循环的话上一个sg数组肯定按最大值申请的curr_max_ents max_ents;} while (left);return 0; } EXPORT_SYMBOL(__sg_alloc_table); 用以配置铰链 sgoffset 和 length 为0通过该函数将当前的sg数组与下一个sg数组通过chain sg捆绑在一起。 static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,struct scatterlist *sgl) {/** offset and length are unused for chain entry. Clear them.*/prv[prv_nents - 1].offset 0;prv[prv_nents - 1].length 0;/** Set lowest bit to indicate a link pointer, and make sure to clear* the termination bit if it happens to be set.*/prv[prv_nents - 1].page_link ((unsigned long) sgl | SG_CHAIN) ~SG_END; } sg跟buffer 常用api sg_set_page函数用sg_assign_page以将当前sg与某个内存页进行关联并设置大小和偏移 static inline void sg_set_page(struct scatterlist *sg, struct page *page,unsigned int len, unsigned int offset) {sg_assign_page(sg, page);sg-offset offset;sg-length len; } sg_set_buf传入buf,然后用sg_set_page将sg与这个buf的page关联 static inline void sg_set_buf(struct scatterlist *sg, const void *buf,unsigned int buflen) { #ifdef CONFIG_DEBUG_SGBUG_ON(!virt_addr_valid(buf)); #endifsg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); } 只初始化一个sg void sg_init_table(struct scatterlist *sgl, unsigned int nents) {memset(sgl, 0, sizeof(*sgl) * nents);sg_init_marker(sgl, nents); } EXPORT_SYMBOL(sg_init_table); void sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen) {sg_init_table(sg, 1);sg_set_buf(sg, buf, buflen); } EXPORT_SYMBOL(sg_init_one); 示例  int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) {struct mmc_request mrq {NULL};struct mmc_command cmd {0};struct mmc_data data {0};struct scatterlist sg, *sg_ptr;struct sg_table sgtable;unsigned int nents, left_size, i;unsigned int seg_size card-host-max_seg_size;......data.blksz blksz;/* Code in host drivers/fwk assumes that blocks always is 1 */data.blocks blocks ? blocks : 1;data.flags write ? MMC_DATA_WRITE : MMC_DATA_READ;left_size data.blksz * data.blocks;nents (left_size - 1) / seg_size 1;if (nents 1) {if (sg_alloc_table(sgtable, nents, GFP_KERNEL))return -ENOMEM;data.sg sgtable.sgl;data.sg_len nents;for_each_sg(data.sg, sg_ptr, data.sg_len, i) {sg_set_page(sg_ptr, virt_to_page(buf (i * seg_size)),min(seg_size, left_size),offset_in_page(buf (i * seg_size)));left_size left_size - seg_size;}} else {data.sg sg;data.sg_len 1;sg_init_one(sg, buf, left_size);}...... } sg跟DMA 常用api 判断当前sg是否为chain #define sg_is_chain(sg) ((sg)-page_link SG_CHAIN) 判断当前sg是否为last #define sg_is_last(sg) ((sg)-page_link SG_END)chain sg用来获取下一个指向的sg数组 #define sg_chain_ptr(sg) \ ((struct scatterlist *) ((sg)-page_link ~(SG_CHAIN | SG_END)))获取下一个sg,可能在下一个sg_table里 struct scatterlist *sg_next(struct scatterlist *sg) {if (sg_is_last(sg))return NULL;sg;if (unlikely(sg_is_chain(sg)))sg sg_chain_ptr(sg);return sg; } EXPORT_SYMBOL(sg_next); 遍历sg #define for_each_sg(sglist, sg, nr, __i) \for (__i 0, sg (sglist); __i (nr); __i, sg sg_next(sg)) 获取sg关联的页块地址 static inline struct page *sg_page(struct scatterlist *sg) { #ifdef CONFIG_DEBUG_SGBUG_ON(sg_is_chain(sg)); #endifreturn (struct page *)((sg)-page_link ~(SG_CHAIN | SG_END)); } 示例 这是个支持sg的dma控制器mmp_pdma_desc_hw用来dma描述符描述一个buf的信息通过sg_dma_address将sg的总线物理地址作为dma描述符的传输地址(源地址/目的地址)用来发送数据到设备或者从设备接收数据 mmp_pdma_prep_slave_sg将下一个描述符的地址给到上一个描述符的--下一个描述符地址的成员以实现DMA控制器自动遍历描述符来传输sg的多个数据块。 struct mmp_pdma_desc_hw {u32 ddadr; /* Points to the next descriptor flags */u32 dsadr; /* DSADR value for the current transfer */u32 dtadr; /* DTADR value for the current transfer */u32 dcmd; /* DCMD value for the current transfer */ } __aligned(32);mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,unsigned int sg_len, enum dma_transfer_direction dir,unsigned long flags, void *context) {struct mmp_pdma_chan *chan to_mmp_pdma_chan(dchan);struct mmp_pdma_desc_sw *first NULL, *prev NULL, *new NULL;size_t len, avail;struct scatterlist *sg;dma_addr_t addr;int i;if ((sgl NULL) || (sg_len 0))return NULL;chan-byte_align true;mmp_pdma_config_write(dchan, chan-slave_config, dir);for_each_sg(sgl, sg, sg_len, i) {addr sg_dma_address(sg);avail sg_dma_len(sg);do {len min_t(size_t, avail, PDMA_MAX_DESC_BYTES);if (addr 0x7)chan-byte_align true;/* allocate and populate the descriptor */new mmp_pdma_alloc_descriptor(chan);if (!new) {dev_err(chan-dev, no memory for desc\n);goto fail;}new-desc.dcmd chan-dcmd | (DCMD_LENGTH len);if (dir DMA_MEM_TO_DEV) {new-desc.dsadr addr;new-desc.dtadr chan-dev_addr;} else {new-desc.dsadr chan-dev_addr;new-desc.dtadr addr;}if (!first)first new;elseprev-desc.ddadr new-async_tx.phys; //将下一个描述符的地址给到上一个描述符的--下一个描述符地址的成员以实现控制器自动遍历描述符来传输sg的多个数据块new-async_tx.cookie 0;async_tx_ack(new-async_tx);prev new;/* Insert the link descriptor to the LD ring */list_add_tail(new-node, first-tx_list);/* update metadata */addr len;avail - len;} while (avail);}first-async_tx.cookie -EBUSY;first-async_tx.flags flags;/* last desc and fire IRQ */new-desc.ddadr DDADR_STOP;new-desc.dcmd | DCMD_ENDIRQEN;chan-dir dir;chan-cyclic_first NULL;return first-async_tx;fail:if (first)mmp_pdma_free_desc_list(chan, first-tx_list);return NULL; }
http://www.zqtcl.cn/news/910219/

相关文章:

  • 郴州做网站 郴网互联网站制作公司起名
  • 织梦做的的网站首页显示空白查企业营业执照的网站
  • 葫芦岛公司做网站外贸西班牙语网站建设
  • 广西住房和城乡建设厅培训中心网站首页wordpress建导航
  • 企业建立网站需要提供什么建立网站需要多长钱
  • 科技企业网站源码下载网页设计公司哪家效果好
  • 成都龙泉工程建设有限公司网站网络科技有限公司网站建设策划书
  • 温州网站建设对比赣州招聘网最新招聘
  • 网站建设什么时候好商丘创小资网络有限公司
  • 做网站不切片可以吗wordpress导入表单
  • 广告公司的网站建设价格wordpress简洁淘宝客免费主题
  • 内蒙古建设安全监督站的网站做网站排名多少钱
  • 自学网站平面设计友链大全
  • go语言做的网站哪个公司搭建网站
  • 网站地图抓取正邦设计创始人
  • 济南建网站公司佛山做营销型网站建设
  • 网站总体策划的内容有哪些做网站排名seo
  • 网站备案上传照片几寸上海网站排名提升
  • 重庆cms建站系统丰都网站建设联系电话
  • 网络教学平台昆明理工大学优化大师的功能有哪些
  • 个人主题网站做的步骤一流的网站建设
  • 公司网站建设规划国外搜索关键词的网站
  • 石家庄网站快速优化排名国内做性视频网站有哪些
  • 易居做网站网页设计的发展
  • 开一个网站建设公司好产品销售型的网站
  • 苍梧县网站建设南京网站建设 雷仁网络
  • 四川网站制作成都wordpress 移动支付
  • 山西网站开发二次开发做自媒体可以参考的外国网站
  • 合肥 网站设计大学生创新创业大赛项目计划书
  • 北京网站主题制作做婚恋网站怎么样