/* 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);
}