解读函数 alloc channel source

/* ioat2_alloc_chan_resources - allocate/initialize ioat2 descriptor ring
 * @chan: channel to be initialized
 */
int ioat2_alloc_chan_resources(struct dma_chan *c)
{
 struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
 struct ioat_chan_common *chan = &ioat->base;
 struct ioat_ring_ent **ring;
 int order;

// ring 是一个双指针, ring 是一个地址, 存放的是 申请的内存链表地址,应该是查看ring是否为空, 若为空, 说明没有给该通道申请内存空间。若不为空, 说明已经为该通道申请的内存空间, 返回该通道分配的descriptor order数目, 然后让该通道处理这些数据。

 /* have we already been set up? */
 if (ioat->ring)
  return 1 << ioat->alloc_order;

 

//若还没有为该通道分配资源,则向控制寄存器里下发RUN的指令, 该指令时在手册 93页,bit 0, bit3组成,

//#define IOAT_CHANCTRL_RUN   (IOAT_CHANCTRL_INT_REARM |/
       IOAT_CHANCTRL_ANY_ERR_ABORT_EN)

//这样的话, 通道遇到Error的时候就有能力终止操作。

 /* Setup register to interrupt and write completion status on error */
 writew(IOAT_CHANCTRL_RUN, chan->reg_base + IOAT_CHANCTRL_OFFSET);

 

//此处是申请一段内存空间作为完成状态通知区域,并把该区域写通知给通道寄存器, 以便通道做了什么事,可以写进来。

/* allocate a completion writeback area */
 /* doing 2 32bit writes to mmio since 1 64b write doesn't work */
 chan->completion = pci_pool_alloc(chan->device->completion_pool,
       GFP_KERNEL, &chan->completion_dma);
 if (!chan->completion)
  return -ENOMEM;

 memset(chan->completion, 0, sizeof(*chan->completion));
 writel(((u64) chan->completion_dma) & 0x00000000FFFFFFFF,
        chan->reg_base + IOAT_CHANCMP_OFFSET_LOW);
 writel(((u64) chan->completion_dma) >> 32,
        chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);

 

//获得通道可以得到的order数。

 order = ioat_get_alloc_order();

//函数ioat2_alloc_ring 这个函数, 根据oder数目, 为通道“c” 申请ring buffer,即 为2的order次方个Descriptor申请分配内存空

//间。
 ring = ioat2_alloc_ring(c, order, GFP_KERNEL);
//如果没有申请到, 返回内存不够用的信息。 

if (!ring)
  return -ENOMEM;

 spin_lock_bh(&chan->cleanup_lock);
 spin_lock_bh(&ioat->prep_lock);

//把申请的内存空间的地址告诉通道
 ioat->ring = ring;
 ioat->head = 0;
 ioat->issued = 0;
 ioat->tail = 0;
 ioat->alloc_order = order;
 spin_unlock_bh(&ioat->prep_lock);
 spin_unlock_bh(&chan->cleanup_lock);

 tasklet_enable(&chan->cleanup_task);
//告诉你说, 这个通道已经配置好, 可以工作了。

 ioat2_start_null_desc(ioat);

//返回这个通道可以处理的Descriptor个数。

 return 1 << ioat->alloc_order;
}

 

 

 

第二个函数:

static struct ioat_ring_ent **ioat2_alloc_ring(struct dma_chan *c, int order, gfp_t flags)
{
 struct ioat_ring_ent **ring;
 int descs = 1 << order;/*tt- descs is 2,order quarter. */
 int i;

 if (order > ioat_get_max_alloc_order())
  return NULL;

 

//算出desc个数,每个Desc是*ring结构, 长度为 sizeof(*ring), 为这些Desc申请内存空间。

 /* allocate the array to hold the software ring */
 ring = kcalloc(descs, sizeof(*ring), flags); /* tt-alloc descs*sizeof(*ring) memory*/
 if (!ring)
  return NULL;

 

//用for循环得到每个ring 的首 地址, 即entry.
 for (i = 0; i < descs; i++) {
  ring[i] = ioat2_alloc_ring_ent(c, flags);
  if (!ring[i]) {
   while (i--)
    ioat2_free_ring_ent(ring[i], c);
   kfree(ring);
   return NULL;
  }
  set_desc_id(ring[i], i);
 }

 

//把这些desc连成一个循环链表

 /* link descs */
 for (i = 0; i < descs-1; i++) {
  struct ioat_ring_ent *next = ring[i+1];
  struct ioat_dma_descriptor *hw = ring[i]->hw;

  hw->next = next->txd.phys;
 }
 ring[i]->hw->next = ring[0]->txd.phys;

 return ring;
}

 

第三个函数:

//

//这里面 ent的意思应该是 DMA通道所能知道的可以处理这些desc的信息。

static struct ioat_ring_ent *ioat2_alloc_ring_ent(struct dma_chan *chan, gfp_t flags)
{
 struct ioat_dma_descriptor *hw;
 struct ioat_ring_ent *desc;
 struct ioatdma_device *dma;
 dma_addr_t phys;

 dma = to_ioatdma_device(chan->device);
//给DMA通道申请一个内存

 hw = pci_pool_alloc(dma->dma_pool, flags, &phys);
 if (!hw)
  return NULL;

//设置该内存空间的值全为0。
 memset(hw, 0, sizeof(*hw));

 desc = kmem_cache_alloc(ioat2_cache, flags);
 if (!desc) {
  pci_pool_free(dma->dma_pool, hw, phys);
  return NULL;
 }

 

//感觉这里还是在给desc配置信息。

//首先清空该desc空间,然后初始化该desc,然后再配置。
 memset(desc, 0, sizeof(*desc));

//如下一个函数所说

//该函数告诉tx, 要处理这些数据的通道时哪一个, 那么就是之前传进来的参数  struct dma_chan *chan.

//配置好了ring, desc, tx,那么之前申请到的这个通道就可以处理这些事情了。

 dma_async_tx_descriptor_init(&desc->txd, chan);
 desc->txd.tx_submit = ioat2_tx_submit_unlock;
 desc->hw = hw;
 desc->txd.phys = phys;
 return desc;
}

 

void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
 struct dma_chan *chan)
{
 tx->chan = chan;
 spin_lock_init(&tx->lock);
}

 

 

static void ioat2_free_ring_ent(struct ioat_ring_ent *desc, struct dma_chan *chan)
{
 struct ioatdma_device *dma;

 dma = to_ioatdma_device(chan->device);
 pci_pool_free(dma->dma_pool, desc->hw, desc->txd.phys);
 kmem_cache_free(ioat2_cache, desc);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值