下面介绍pl330驱动关键函数:
1 在驱动probe函数中,注册pl330中断服务函数
2927 ret = request_irq(irq, pl330_irq_handler, 0,
2928 dev_name(&adev->dev), pi);
2884 }
1690 /* Returns 1 if state was updated, 0 otherwise */
1691 static int pl330_update(const struct pl330_info *pi)
1692 {
1693 struct pl330_req *rqdone, *tmp;
1694 struct pl330_dmac *pl330;
1695 unsigned long flags;
1696 void __iomem *regs;
1697 u32 val;
1698 int id, ev, ret = 0;
1699
1700 if (!pi || !pi->pl330_data)
1701 return 0;
1702
1703 regs = pi->base;
1704 pl330 = pi->pl330_data;
1705
1706 spin_lock_irqsave(&pl330->lock, flags);
1707
1708 val = readl(regs + FSM) & 0x1; //读取管理通道的fsm寄存器,判断是否需要复位管理通道
1709 if (val)
1710 pl330->dmac_tbd.reset_mngr = true;
1711 else
1712 pl330->dmac_tbd.reset_mngr = false;
1713
1714 val = readl(regs + FSC) & ((1 << pi->pcfg.num_chan) - 1); //读取普通通道的fsc寄存器,判断哪些通道需要复位
1715 pl330->dmac_tbd.reset_chan |= val;
1716 if (val) {
1717 int i = 0;
1718 while (i < pi->pcfg.num_chan) { //循环复位相应的通道
1719 if (val & (1 << i)) {
1720 dev_info(pi->dev,
1721 "Reset Channel-%d\t CS-%x FTC-%x\n",
1722 i, readl(regs + CS(i)),
1723 readl(regs + FTC(i)));
1724 _stop(&pl330->channels[i]); //停止相应通道线程
1725 }
1726 i++;
1727 }
1728 }
1729
1730 /* Check which event happened i.e, thread notified */
1731 val = readl(regs + ES); //读取es寄存器,检查发生的事件
1732 if (pi->pcfg.num_events < 32
1733 && val & ~((1 << pi->pcfg.num_events) - 1)) {
1734 pl330->dmac_tbd.reset_dmac = true;
1735 dev_err(pi->dev, "%s:%d Unexpected!\n", __func__, __LINE__);
1736 ret = 1;
1737 goto updt_exit;
1738 }
1739
1740 for (ev = 0; ev < pi->pcfg.num_events; ev++) { //循环处理已经发生的事件
1741 if (val & (1 << ev)) { /* Event occurred */
1742 struct pl330_thread *thrd;
1743 u32 inten = readl(regs + INTEN); //读取中断使能寄存器
1744 int active;
1745
1746 /* Clear the event */
1747 if (inten & (1 << ev)) //如果相应事件的中断已经发生,清除相应中断
1748 writel(1 << ev, regs + INTCLR); //清除中断
1749
1750 ret = 1;
1751
1752 id = pl330->events[ev]; //获取事件对应的通道id
1753
1754 thrd = &pl330->channels[id]; //获取dmac处理线程
1755
1756 active = thrd->req_running; //获取当前正在处理的请求
1757 if (active == -1) /* Aborted */
1758 continue;
1759
1760 /* Detach the req */
1761 rqdone = thrd->req[active].r; //获取已经处理的请求
1762 thrd->req[active].r = NULL; //将该请求指针置空
1763
1764 mark_free(thrd, active); //将该dmac处理线程的请求标记为free
1765
1766 /* Get going again ASAP */
1767 _start(thrd); //继续该dmac处理线程
1768
1769 /* For now, just make a list of callbacks to be done */
1770 list_add_tail(&rqdone->rqd, &pl330->req_done); //将该请求加入到已经处理完成链表
1771 }
1772 }
1773
1774 /* Now that we are in no hurry, do the callbacks */
1775 list_for_each_entry_safe(rqdone, tmp, &pl330->req_done, rqd) { //处理pl330 dmac中的已经完成处理链表的每个成员
1776 list_del(&rqdone->rqd); //从链表删除该节点
1777
1778 spin_unlock_irqrestore(&pl330->lock, flags);
1779 _callback(rqdone, PL330_ERR_NONE); //调用请求中的回调处理该完成请求。
1780 spin_lock_irqsave(&pl330->lock, flags);
1781 }
1782
1783 updt_exit:
1784 spin_unlock_irqrestore(&pl330->lock, flags);
1785
1786 if (pl330->dmac_tbd.reset_dmac
1787 || pl330->dmac_tbd.reset_mngr
1788 || pl330->dmac_tbd.reset_chan) {
1789 ret = 1;
1790 tasklet_schedule(&pl330->tasks);
1791 }
1792
1793 return ret;
1794 }
该函数主要功能为处理dmac管理通道和普通通道的复位,以及处理请求完成事件处理,同时通过回调函数处理完成的请求。
1139 static void _stop(struct pl330_thread *thrd)
1140 {
1141 void __iomem *regs = thrd->dmac->pinfo->base;
1142 u8 insn[6] = {0, 0, 0, 0, 0, 0};
1143
1144 if (_state(thrd) == PL330_STATE_FAULT_COMPLETING) //判断dmac线程状态
1145 UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING); //等待其状态改变
1146
1147 /* Return if nothing needs to be done */
1148 if (_state(thrd) == PL330_STATE_COMPLETING
1149 || _state(thrd) == PL330_STATE_KILLING
1150 || _state(thrd) == PL330_STATE_STOPPED)
1151 return;
1152
1153 _emit_KILL(0, insn); //设置kill指令到insn
1154
1155 /* Stop generating interrupts for SEV */
1156 writel(readl(regs + INTEN) & ~(1 << thrd->ev), regs + INTEN); //清除事件的中断
1157
1158 _execute_DBGINSN(thrd, insn, is_manager(thrd)); //使相应的处理线程执行kill指令
1159 }
该函数停止相应的dmac线程
1079 }
该函数将一个请求标记为free
1161 /* Start doing req 'idx' of thread 'thrd' */
1162 static bool _trigger(struct pl330_thread *thrd)
1163 {
1164 void __iomem *regs = thrd->dmac->pinfo->base;
1165 struct _pl330_req *req;
1166 struct pl330_req *r;
1167 struct _arg_GO go;
1168 unsigned ns;
1169 u8 insn[6] = {0, 0, 0, 0, 0, 0};
1170 int idx;
1171
1172 /* Return if already ACTIVE */
1173 if (_state(thrd) != PL330_STATE_STOPPED)
1174 return true;
1175
1176 idx = 1 - thrd->lstenq; //获取需要被执行的请求索引
1177 if (!IS_FREE(&thrd->req[idx])) //检查该请求是否free
1178 req = &thrd->req[idx]; //获取需要被执行的请求
1179 else {
1180 idx = thrd->lstenq;
1181 if (!IS_FREE(&thrd->req[idx]))
1182 req = &thrd->req[idx];
1183 else
1184 req = NULL;
1185 }
1186
1187 /* Return if no request */
1188 if (!req || !req->r)
1189 return true;
1190
1191 r = req->r;
1192
1193 if (r->cfg)
1194 ns = r->cfg->nonsecure ? 1 : 0; //查看该请求配置的模式
1195 else if (readl(regs + CS(thrd->id)) & CS_CNS)
1196 ns = 1;
1197 else
1198 ns = 0;
1199
1200 /* See 'Abort Sources' point-4 at Page 2-25 */
1201 if (_manager_ns(thrd) && !ns)
1202 dev_info(thrd->dmac->pinfo->dev, "%s:%d Recipe for ABORT!\n",
1203 __func__, __LINE__);
1204
1205 go.chan = thrd->id;
1206 go.addr = req->mc_bus;
1207 go.ns = ns;
1208 _emit_GO(0, insn, &go); //设置go指令
1209
1210 /* Set to generate interrupts for SEV */
1211 writel(readl(regs + INTEN) | (1 << thrd->ev), regs + INTEN); //设置相应的事件产生中断
1212
1213 /* Only manager can execute GO */
1214 _execute_DBGINSN(thrd, insn, true); //相应线程执行指令
1215
1216 thrd->req_running = idx; //设置线程正在执行的请求索引
1217
1218 return true;
1219 }
该函数使相应线程重新开始处理下一个请求
616 static inline void _callback(struct pl330_req *r, enum pl330_op_err err)
617 {
618 if (r && r->xfer_cb)
619 r->xfer_cb(r->token, err);
620 }
调用请求回调处理函数处理完成请求
2 添加pl330 dmac实例
2932 ret = pl330_add(pi);
2079 static int pl330_add(struct pl330_info *pi)
2080 {
2081 struct pl330_dmac *pl330;
2082 void __iomem *regs;
2083 int i, ret;
2084
2085 pr_info("%s:enter!\n", __func__);
2086
2087 if (!pi || !pi->dev)
2088 return -EINVAL;
2089
2090 /* If already added */
2091 if (pi->pl330_data)
2092 return -EINVAL;
2093
2094 /*
2095 * If the SoC can perform reset on the DMAC, then do it
2096 * before reading its configuration.
2097 */
2098 if (pi->dmac_reset)
2099 pi->dmac_reset(pi); //执行平台指定的dmac复位程序
2100
2101 regs = pi->base;
2102
2103 /* Check if we can handle this DMAC */
2104 if ((get_id(pi, PERIPH_ID) & 0xfffff) != PERIPH_ID_VAL //通过读取dmac寄存器检查是否可以操作该dmac
2105 || get_id(pi, PCELL_ID) != PCELL_ID_VAL) {
2106 dev_err(pi->dev, "PERIPH_ID 0x%x, PCELL_ID 0x%x !\n",
2107 get_id(pi, PERIPH_ID), get_id(pi, PCELL_ID));
2108 return -EINVAL;
2109 }
2110
2111 pr_info("%s:read_dmac_config()\n", __func__);
2112 /* Read the configuration of the DMAC */
2113 read_dmac_config(pi); //读取dmac配置,填充struct pl330_info的struct pl330_config成员
2114
2115
2116 if (pi->pcfg.num_events == 0) {
2117 dev_err(pi->dev, "%s:%d Can't work without events!\n",
2118 __func__, __LINE__);
2119 return -EINVAL;
2120 }
2121
2122 pl330 = kzalloc(sizeof(*pl330), GFP_KERNEL); //分配pl330 dmac实例内存空间
2123 if (!pl330) {
2124 dev_err(pi->dev, "%s:%d Can't allocate memory!\n",
2125 __func__, __LINE__);
2126 return -ENOMEM;
2127 }
2128
2129 /* Assign the info structure and private data */
2130 pl330->pinfo = pi; //设置pl330 dmac
2131 pi->pl330_data = pl330; //将pl330 dmac实例连接到上层pl330 dmac抽象
2132
2133 spin_lock_init(&pl330->lock);
2134
2135 INIT_LIST_HEAD(&pl330->req_done);*/
2136
2137 /* Use default MC buffer size if not provided */
2138 if (!pi->mcbufsz)
2139 pi->mcbufsz = MCODE_BUFF_PER_REQ * 2; //设置pl330 info
2140
2141 /* Mark all events as free */
2142 for (i = 0; i < pi->pcfg.num_events; i++)
2143 pl330->events[i] = -1; //free全部的pl330 dmac 事件
2144
2145 pr_info("%s:dmac_alloc_resources()\n", __func__);
2146 /* Allocate resources needed by the DMAC */
2147 ret = dmac_alloc_resources(pl330); //分配pl330 dmac需要的资源
2148 if (ret) {
2149 dev_err(pi->dev, "Unable to create channels for DMAC\n");
2150 kfree(pl330);
2151 return ret;
2152 }
2153
2154 tasklet_init(&pl330->tasks, pl330_dotask, (unsigned long) pl330); //初始化pl330 dmac的struct tasklet_struct软中断处理,该操作主要处理一些dmac出现的错误
2155
2156 pl330->state = INIT;
2157
2158 return 0;
2159 }
1950 static void read_dmac_config(struct pl330_info *pi)
1951 {
1952 void __iomem *regs = pi->base;
1953 u32 val;
1954
1955 val = readl(regs + CRD) >> CRD_DATA_WIDTH_SHIFT; //读取配置寄存器
1956 val &= CRD_DATA_WIDTH_MASK;
1957 pi->pcfg.data_bus_width = 8 * (1 << val);
1958
1959 val = readl(regs + CRD) >> CRD_DATA_BUFF_SHIFT;
1960 val &= CRD_DATA_BUFF_MASK;
1961 pi->pcfg.data_buf_dep = val + 1;
1962
1963 val = readl(regs + CR0) >> CR0_NUM_CHANS_SHIFT;
1964 val &= CR0_NUM_CHANS_MASK;
1965 val += 1;
1966 pi->pcfg.num_chan = val;
1967
1968 val = readl(regs + CR0);
1969 if (val & CR0_PERIPH_REQ_SET) {
1970 val = (val >> CR0_NUM_PERIPH_SHIFT) & CR0_NUM_PERIPH_MASK;
1971 val += 1;
1972 pi->pcfg.num_peri = val;
1973 pi->pcfg.peri_ns = readl(regs + CR4);
1974 } else {
1975 pi->pcfg.num_peri = 0;
1976 }
1977
1978 val = readl(regs + CR0);
1979 if (val & CR0_BOOT_MAN_NS)
1980 pi->pcfg.mode |= DMAC_MODE_NS;
1981 else
1982 pi->pcfg.mode &= ~DMAC_MODE_NS;
1983
1984 val = readl(regs + CR0) >> CR0_NUM_EVENTS_SHIFT;
1985 val &= CR0_NUM_EVENTS_MASK;
1986 val += 1;
1987 pi->pcfg.num_events = val;
1988
1989 pi->pcfg.irq_ns = readl(regs + CR3);
1990
1991 pi->pcfg.periph_id = get_id(pi, PERIPH_ID);
1992 pi->pcfg.pcell_id = get_id(pi, PCELL_ID);
1993 }
此函数通过读取配置寄存器初始化pl330 info的struct pl330_config结构
2047 static int dmac_alloc_resources(struct pl330_dmac *pl330)
2048 {
2049 struct pl330_info *pi = pl330->pinfo;
2050 int chans = pi->pcfg.num_chan; //获取pl330 dmac通道数量
2051 int ret;
2052
2053 /*
2054 * Alloc MicroCode buffer for 'chans' Channel threads.
2055 * A channel's buffer offset is (Channel_Id * MCODE_BUFF_PERCHAN)
2056 */
2057 pl330->mcode_cpu = dma_alloc_coherent(pi->dev,
2058 chans * pi->mcbufsz,
2059 &pl330->mcode_bus, GFP_KERNEL); //分配pl330 dmac 指令缓存总大小的dma地址和虚拟地址
2060 if (!pl330->mcode_cpu) {
2061 dev_err(pi->dev, "%s:%d Can't allocate memory!\n",
2062 __func__, __LINE__);
2063 return -ENOMEM;
2064 }
2065
2066 ret = dmac_alloc_threads(pl330); //给pl330 dmac各线程分配资源
2067 if (ret) {
2068 dev_err(pi->dev, "%s:%d Can't to create channels for DMAC!\n",
2069 __func__, __LINE__);
2070 dma_free_coherent(pi->dev,
2071 chans * pi->mcbufsz,
2072 pl330->mcode_cpu, pl330->mcode_bus);
2073 return ret;
2074 }
2075
2076 return 0;
2077 }
此函数给pl330 dmac分配资源
2015 static int dmac_alloc_threads(struct pl330_dmac *pl330)
2016 {
2017 struct pl330_info *pi = pl330->pinfo;
2018 int chans = pi->pcfg.num_chan; //获取pl330 dmac通道数量
2019 struct pl330_thread *thrd;
2020 int i;
2021
2022 /* Allocate 1 Manager and 'chans' Channel threads */
2023 pl330->channels = kzalloc((1 + chans) * sizeof(*thrd),
2024 GFP_KERNEL); //分配一个管理线程和n个通道线程
2025 if (!pl330->channels)
2026 return -ENOMEM;
2027
2028 /* Init Channel threads */
2029 for (i = 0; i < chans; i++) { //初始化每一个通道线程
2030 thrd = &pl330->channels[i];
2031 thrd->id = i; //线程分配id
2032 thrd->dmac = pl330; //线程和pl330 dmac关联
2033 _reset_thread(thrd); //复位线程
2034 thrd->free = true; //设置线程free
2035 }
2036
2037 /* MANAGER is indexed at the end */
2038 thrd = &pl330->channels[chans]; //初始化管理线程
2039 thrd->id = chans;
2040 thrd->dmac = pl330;
2041 thrd->free = false; //管理线程默认占用
2042 pl330->manager = thrd; //设在pl330 dmac和管理线程关联
2043
2044 return 0;
2045 }
此函数分配pl330 dmac线程空间,并初始化各线程
1995 static inline void _reset_thread(struct pl330_thread *thrd)
1996 {
1997 struct pl330_dmac *pl330 = thrd->dmac;
1998 struct pl330_info *pi = pl330->pinfo;
1999
2000 thrd->req[0].mc_cpu = pl330->mcode_cpu
2001 + (thrd->id * pi->mcbufsz); //设置线程指令缓存虚拟地址
2002 thrd->req[0].mc_bus = pl330->mcode_bus //设置线程指令物理地址
2003 + (thrd->id * pi->mcbufsz);
2004 thrd->req[0].r = NULL; //dmac请求置空
2005 mark_free(thrd, 0); //标记线程free
2006
2007 thrd->req[1].mc_cpu = thrd->req[0].mc_cpu
2008 + pi->mcbufsz / 2;
2009 thrd->req[1].mc_bus = thrd->req[0].mc_bus
2010 + pi->mcbufsz / 2;
2011 thrd->req[1].r = NULL;
2012 mark_free(thrd, 1);
2013 }
此函数主要设置线程请求为复位状态
1071 static void mark_free(struct pl330_thread *thrd, int idx)
1072 {
1073 struct _pl330_req *req = &thrd->req[idx]; //获取线程一个请求
1074
1075 _emit_END(0, req->mc_cpu); //设置请求指令为end
1076 req->mc_len = 0; //设置指令长度0
1077
1078 thrd->req_running = -1; //设置线程正在运行请求为-1
1079 }
此函数通过设置请求指令为end来标记其为free
1628 static void pl330_dotask(unsigned long data)
1629 {
1630 struct pl330_dmac *pl330 = (struct pl330_dmac *) data;
1631 struct pl330_info *pi = pl330->pinfo;
1632 unsigned long flags;
1633 int i;
1634
1635 spin_lock_irqsave(&pl330->lock, flags);
1636
1637 /* The DMAC itself gone nuts */
1638 if (pl330->dmac_tbd.reset_dmac) { //判断pl330 dmac是否需要复位
1639 pl330->state = DYING; //标记dmac状态为dying
1640 /* Reset the manager too */
1641 pl330->dmac_tbd.reset_mngr = true; //标记复位dmac管理线程
1642 /* Clear the reset flag */
1643 pl330->dmac_tbd.reset_dmac = false;
1644 }
1645
1646 if (pl330->dmac_tbd.reset_mngr) { //判读是否需要复位dmac管理线程
1647 _stop(pl330->manager); //停止管理线程
1648 /* Reset all channels */
1649 pl330->dmac_tbd.reset_chan = (1 << pi->pcfg.num_chan) - 1; //标记复位所有通道
1650 /* Clear the reset flag */
1651 pl330->dmac_tbd.reset_mngr = false;
1652 }
1653
1654 for (i = 0; i < pi->pcfg.num_chan; i++) { //循环复位所有通道线程
1655
1656 if (pl330->dmac_tbd.reset_chan & (1 << i)) {
1657 struct pl330_thread *thrd = &pl330->channels[i];
1658 void __iomem *regs = pi->base;
1659 enum pl330_op_err err;
1660
1661 _stop(thrd); //停止相应线程
1662
1663 if (readl(regs + FSC) & (1 << thrd->id)) //读取通道状态寄存器,设置err
1664 err = PL330_ERR_FAIL;
1665 else
1666 err = PL330_ERR_ABORT;
1667
1668 spin_unlock_irqrestore(&pl330->lock, flags);
1669
1670 _callback(thrd->req[1 - thrd->lstenq].r, err); //调用请求中的回调处理请求
1671 _callback(thrd->req[thrd->lstenq].r, err);
1672
1673 spin_lock_irqsave(&pl330->lock, flags);
1674
1675 thrd->req[0].r = NULL; //设置请求为复位状态
1676 thrd->req[1].r = NULL;
1677 mark_free(thrd, 0); //标记线程请求为free
1678 mark_free(thrd, 1);
1679
1680 /* Clear the reset flag */
1681 pl330->dmac_tbd.reset_chan &= ~(1 << i);
1682 }
1683 }
1684
1685 spin_unlock_irqrestore(&pl330->lock, flags);
1686
1687 return;
1688 }
3 创建描述符池
if (!add_desc(pdmac, GFP_KERNEL, NR_DEFAULT_DESC))
2942 dev_warn(&adev->dev, "unable to allocate desc\n");
2566 /* Returns the number of descriptors added to the DMAC pool */
2567 static int add_desc(struct dma_pl330_dmac *pdmac, gfp_t flg, int count)
2568 {
2569 struct dma_pl330_desc *desc;
2570 unsigned long flags;
2571 int i;
2572
2573 if (!pdmac)
2574 return 0;
2575
2576 desc = kmalloc(count * sizeof(*desc), flg); //分配所需添加的描述符空间
2577 if (!desc)
2578 return 0;
2579
2580 spin_lock_irqsave(&pdmac->pool_lock, flags);
2581
2582 for (i = 0; i < count; i++) { //循环初始化各个描述符并将其添加到描述符池链表中
2583 _init_desc(&desc[i]);
2584 list_add_tail(&desc[i].node, &pdmac->desc_pool);
2585 }
2586
2587 spin_unlock_irqrestore(&pdmac->pool_lock, flags);
2588
2589 return count;
2590 }
此函数分配描述符空间,并初始化描述符,然后将其添加到pl330 dmac 描述符池链表
2549 static inline void _init_desc(struct dma_pl330_desc *desc)
2550 {
2551 desc->pchan = NULL; //将描述符所属通道置空
2552 desc->req.x = &desc->px; //设置请求的传输为描述符传输
2553 desc->req.token = desc; //设置请求令牌为描述符
2554 desc->rqcfg.swap = SWAP_NO; //设置请求配置swap
2555 desc->rqcfg.privileged = 0; //设置请求配置权限
2556 desc->rqcfg.insnaccess = 0;
2557 desc->rqcfg.scctl = SCCTRL0;
2558 desc->rqcfg.dcctl = DCCTRL0;
2559 desc->req.cfg = &desc->rqcfg; //设置请求的请求配置
2560 desc->req.xfer_cb = dma_pl330_rqcb; //设置请求的回调处理
2561 desc->txd.tx_submit = pl330_tx_submit; //设置dma引擎层描述符的发送函数
2562
2563 INIT_LIST_HEAD(&desc->node); //初始化链表节点,用来加入到pl330 dmac描述符池链表
2564 }
此函数初始化pl330 dmac描述符成员
2348 static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
2349 {
2350 struct dma_pl330_desc *desc = token;
2351 struct dma_pl330_chan *pch = desc->pchan;
2352 unsigned long flags;
2353
2354 /* If desc aborted */
2355 if (!pch)
2356 return;
2357
2358 spin_lock_irqsave(&pch->lock, flags);
2359
2360 desc->status = DONE; //设置传输描述符为已经操作完成
2361
2362 spin_unlock_irqrestore(&pch->lock, flags);
2363
2364 tasklet_schedule(&pch->task); //调用通道处理任务
2365 }
此函数为处理万传输描述后的回调函数,主要是标记处理完成,然后调用通道处理函数。
2524 static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
2525 {
2526 struct dma_pl330_desc *desc, *last = to_desc(tx); //获取pl330 dmac层的传输描述符
2527 struct dma_pl330_chan *pch = to_pchan(tx->chan); //获取pl330 dmac的传输层通道
2528 dma_cookie_t cookie;
2529 unsigned long flags;
2530
2531 spin_lock_irqsave(&pch->lock, flags);
2532
2533 /* Assign cookies to all nodes */
2534 while (!list_empty(&last->node)) { //判断链表是否为空
2535 desc = list_entry(last->node.next, struct dma_pl330_desc, node); //获取下一个pl330 dmac层传输描述符
2536
2537 dma_cookie_assign(&desc->txd); //分配dma引擎层传输描述符cookie
2538
2539 list_move_tail(&desc->node, &pch->work_list); //将此节点移到pl330 dmac层通道工作链表尾
2540 }
2541
2542 cookie = dma_cookie_assign(&last->txd); //给最后一个dma引擎层传输描述符分配cookie
2543 list_add_tail(&last->node, &pch->work_list); //将其添加到通道工作链表尾
2544 spin_unlock_irqrestore(&pch->lock, flags);
2545
2546 return cookie;
2547 }
此函数将传输描述符及其队列dma引擎层传输描述符添加cookie,并将其添加到pl330 dmac通道工作队列以备处理
4 dma引擎层dma device的关键操作函数
4.1
2413 static int pl330_alloc_chan_resources(struct dma_chan *chan)
2414 {
2415 struct dma_pl330_chan *pch = to_pchan(chan); //获取pl330 dmac层通道
2416 struct dma_pl330_dmac *pdmac = pch->dmac;
2417 unsigned long flags;
2418
2419 spin_lock_irqsave(&pch->lock, flags);
2420
2421 dma_cookie_init(chan); //初始化dma通道cookie
2422 pch->cyclic = false; //通道默认不支持循环操作
2423
2424 pch->pl330_chid = pl330_request_channel(&pdmac->pif); //给pl330 dmac通道分配一个处理线程
2425 if (!pch->pl330_chid) {
2426 spin_unlock_irqrestore(&pch->lock, flags);
2427 return -ENOMEM;
2428 }
2429
2430 tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch); //初始化通道处理任务
2431
2432 spin_unlock_irqrestore(&pch->lock, flags);
2433
2434 return 1;
2435 }
1871 static void *pl330_request_channel(const struct pl330_info *pi)
1872 {
1873 struct pl330_thread *thrd = NULL;
1874 struct pl330_dmac *pl330;
1875 unsigned long flags;
1876 int chans, i;
1877
1878 if (!pi || !pi->pl330_data)
1879 return NULL;
1880
1881 pl330 = pi->pl330_data;
1882
1883 if (pl330->state == DYING)
1884 return NULL;
1885
1886 chans = pi->pcfg.num_chan;
1887
1888 spin_lock_irqsave(&pl330->lock, flags);
1889
1890 for (i = 0; i < chans; i++) { //循环找一个free的dmac 线程
1891 thrd = &pl330->channels[i];
1892 if ((thrd->free) && (!_manager_ns(thrd) || //如果线程free 不是管理线程
1893 _chan_ns(pi, i))) {
1894 thrd->ev = _alloc_event(thrd); //线程分配事件
1895 if (thrd->ev >= 0) { //初始化线程
1896 thrd->free = false;
1897 thrd->lstenq = 1;
1898 thrd->req[0].r = NULL;
1899 mark_free(thrd, 0);
1900 thrd->req[1].r = NULL;
1901 mark_free(thrd, 1);
1902 break;
1903 }
1904 }
1905 thrd = NULL;
1906 }
1907
1908 spin_unlock_irqrestore(&pl330->lock, flags);
1909
1910 return thrd;
1911 }
此函数给一个pl330 damc通道分配一个dmac处理线程,并初始化该线程
1848 static inline int _alloc_event(struct pl330_thread *thrd)
1849 {
1850 struct pl330_dmac *pl330 = thrd->dmac;
1851 struct pl330_info *pi = pl330->pinfo;
1852 int ev;
1853
1854 for (ev = 0; ev < pi->pcfg.num_events; ev++) //从pl330 dmac自由事件中分配一个给线程
1855 if (pl330->events[ev] == -1) {
1856 pl330->events[ev] = thrd->id; //事件和线程绑定
1857 return ev;
1858 }
1859
1860 return -1;
1861 }
此函数从pl330 dmac自由事件中分配一个给线程
2317 static void pl330_tasklet(unsigned long data)
2318 {
2319 struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
2320 struct dma_pl330_desc *desc, *_dt;
2321 unsigned long flags;
2322 LIST_HEAD(list);
2323
2324 spin_lock_irqsave(&pch->lock, flags);
2325
2326 /* Pick up ripe tomatoes */
2327 list_for_each_entry_safe(desc, _dt, &pch->work_list, node) //遍历通道工作队列
2328 if (desc->status == DONE) { //如果此描述被处理完成
2329 if (!pch->cyclic) //通道不是循环操作
2330 dma_cookie_complete(&desc->txd); //标记dma引擎层传输描述完成cookie
2331 list_move_tail(&desc->node, &list); /从工作队列删除节点
2332 }
2333
2334 /* Try to submit a req imm. next to the last completed cookie */
2335 fill_queue(pch); //填充线程处理请求,准备处理的下个描述符请求
2336
2337 /* Make sure the PL330 Channel thread is active */
2338 pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START); //设置dmac线程继续工作
2339
2340 spin_unlock_irqrestore(&pch->lock, flags);
2341
2342 if (pch->cyclic)
2343 handle_cyclic_desc_list(&list);
2344 else
2345 free_desc_list(&list);
2346 }
此函数在传输描述处理完成后调用
2289 static inline void fill_queue(struct dma_pl330_chan *pch)
2290 {
2291 struct dma_pl330_desc *desc;
2292 int ret;
2293
2294 list_for_each_entry(desc, &pch->work_list, node) { //遍历通道工作队列
2295
2296 /* If already submitted */
2297 if (desc->status == BUSY) //跳过正在处理的节点
2298 continue;
2299
2300 ret = pl330_submit_req(pch->pl330_chid,
2301 &desc->req); //将描述请求添加到线程
2302 if (!ret) {
2303 desc->status = BUSY;
2304 } else if (ret == -EAGAIN) {
2305 /* QFull or DMAC Dying */
2306 break;
2307 } else {
2308 /* Unacceptable request */
2309 desc->status = DONE;
2310 dev_err(pch->dmac->pif.dev, "%s:%d Bad Desc(%d)\n",
2311 __func__, __LINE__, desc->txd.cookie);
2312 tasklet_schedule(&pch->task);
2313 }
2314 }
2315 }
此函数给通道处理线程提交一个描述请求,以备处理
1533 static int pl330_submit_req(void *ch_id, struct pl330_req *r)
1534 {
1535 struct pl330_thread *thrd = ch_id;
1536 struct pl330_dmac *pl330;
1537 struct pl330_info *pi;
1538 struct _xfer_spec xs;
1539 unsigned long flags;
1540 void __iomem *regs;
1541 unsigned idx;
1542 u32 ccr;
1543 int ret = 0;
1544
1545 /* No Req or Unacquired Channel or DMAC */
1546 if (!r || !thrd || thrd->free)
1547 return -EINVAL;
1548
1549 pl330 = thrd->dmac;
1550 pi = pl330->pinfo;
1551 regs = pi->base;
1552
1553 if (pl330->state == DYING
1554 || pl330->dmac_tbd.reset_chan & (1 << thrd->id)) {
1555 dev_info(thrd->dmac->pinfo->dev, "%s:%d\n",
1556 __func__, __LINE__);
1557 return -EAGAIN;
1558 }
1559
1560 /* If request for non-existing peripheral */
1561 if (r->rqtype != MEMTOMEM && r->peri >= pi->pcfg.num_peri) {
1562 dev_info(thrd->dmac->pinfo->dev,
1563 "%s:%d Invalid peripheral(%u)!\n",
1564 __func__, __LINE__, r->peri);
1565 return -EINVAL;
1566 }
1567
1568 spin_lock_irqsave(&pl330->lock, flags);
1569
1570 if (_queue_full(thrd)) { //判断线程处理队列是否已满
1571 ret = -EAGAIN;
1572 goto xfer_exit;
1573 }
1574
1575
1576 /* Use last settings, if not provided */
1577 if (r->cfg) {
1578 /* Prefer Secure Channel */
1579 if (!_manager_ns(thrd)) //判断线程是否是安全模式
1580 r->cfg->nonsecure = 0;
1581 else
1582 r->cfg->nonsecure = 1;
1583
1584 ccr = _prepare_ccr(r->cfg); //以及请求配置设置通道控制寄存器
1585 } else {
1586 ccr = readl(regs + CC(thrd->id));
1587 }
1588
1589 /* If this req doesn't have valid xfer settings */
1590 if (!_is_valid(ccr)) { //判断此请求配置是否有效
1591 ret = -EINVAL;
1592 dev_info(thrd->dmac->pinfo->dev, "%s:%d Invalid CCR(%x)!\n",
1593 __func__, __LINE__, ccr);
1594 goto xfer_exit;
1595 }
1596
1597 idx = IS_FREE(&thrd->req[0]) ? 0 : 1; //在处理线程找到一个free的请求节点
1598
1599 xs.ccr = ccr; //设置请求空间
1600 xs.r = r;
1601
1602 /* First dry run to check if req is acceptable */
1603 ret = _setup_req(1, thrd, idx, &xs); //先不真正处理请求,此操作主要为了检查可执行性
1604 if (ret < 0)
1605 goto xfer_exit;
1606
1607 if (ret > pi->mcbufsz / 2) {
1608 dev_info(thrd->dmac->pinfo->dev,
1609 "%s:%d Trying increasing mcbufsz\n",
1610 __func__, __LINE__);
1611 ret = -ENOMEM;
1612 goto xfer_exit;
1613 }
1614
1615 /* Hook the request */
1616 thrd->lstenq = idx; //设置线程即将执行请求队列节点
1617 thrd->req[idx].mc_len = _setup_req(0, thrd, idx, &xs); //设置线程的请求的指令集
1618 thrd->req[idx].r = r;
1619
1620 ret = 0;
1621
1622 xfer_exit:
1623 spin_unlock_irqrestore(&pl330->lock, flags);
1624
1625 return ret;
1626 }
此函数用来给线程请求队列提交即将处理的请求,并设置线程请求空间
1481 static inline u32 _prepare_ccr(const struct pl330_reqcfg *rqc)
1482 {
1483 u32 ccr = 0;
1484
1485 if (rqc->src_inc)
1486 ccr |= CC_SRCINC;
1487
1488 if (rqc->dst_inc)
1489 ccr |= CC_DSTINC;
1490
1491 /* We set same protection levels for Src and DST for now */
1492 if (rqc->privileged)
1493 ccr |= CC_SRCPRI | CC_DSTPRI;
1494 if (rqc->nonsecure)
1495 ccr |= CC_SRCNS | CC_DSTNS;
1496 if (rqc->insnaccess)
1497 ccr |= CC_SRCIA | CC_DSTIA;
1498
1499 ccr |= (((rqc->brst_len - 1) & 0xf) << CC_SRCBRSTLEN_SHFT);
1500 ccr |= (((rqc->brst_len - 1) & 0xf) << CC_DSTBRSTLEN_SHFT);
1501
1502 ccr |= (rqc->brst_size << CC_SRCBRSTSIZE_SHFT);
1503 ccr |= (rqc->brst_size << CC_DSTBRSTSIZE_SHFT);
1504
1505 ccr |= (rqc->scctl << CC_SRCCCTRL_SHFT);
1506 ccr |= (rqc->dcctl << CC_DSTCCTRL_SHFT);
1507
1508 ccr |= (rqc->swap << CC_SWAP_SHFT);
1509
1510 return ccr;
1511 }
此函数依据请求配置来设置通道控制寄存器值
1448 static int _setup_req(unsigned dry_run, struct pl330_thread *thrd,
1449 unsigned index, struct _xfer_spec *pxs)
1450 {
1451 struct _pl330_req *req = &thrd->req[index]; //获取请求队列节点
1452 struct pl330_xfer *x;
1453 u8 *buf = req->mc_cpu;
1454 int off = 0;
1455
1456 PL330_DBGMC_START(req->mc_bus); //设置pl300处理指令缓存区物理地址
1457
1458 /* DMAMOV CCR, ccr */
1459 off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr); //设置请求指令缓存区mov指令
1460
1461 x = pxs->r->x; //从请求获取传输
1462 do {
1463 /* Error if xfer length is not aligned at burst size */
1464 if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr)))
1465 return -EINVAL;
1466
1467 pxs->x = x;
1468 off += _setup_xfer(dry_run, &buf[off], pxs); //设置请求指令缓存区传输指令
1469
1470 x = x->next;
1471 } while (x); //循环设置请求指令缓存区传输指令
1472
1473 /* DMASEV peripheral/event */
1474 off += _emit_SEV(dry_run, &buf[off], thrd->ev); //设置请求指令缓存区设置事件
1475 /* DMAEND */
1476 off += _emit_END(dry_run, &buf[off]); //设置请求指令缓存区end命令
1477
1478 return off;
1479 }
此函数是实际设置请求指令缓存核心函数,封装了设置dmac 汇编指令程序,方便用户调用
1427 static inline int _setup_xfer(unsigned dry_run, u8 buf[],
1428 const struct _xfer_spec *pxs)
1429 {
1430 struct pl330_xfer *x = pxs->x;
1431 int off = 0;
1432
1433 /* DMAMOV SAR, x->src_addr */
1434 off += _emit_MOV(dry_run, &buf[off], SAR, x->src_addr); //设置指令缓存区mov 源地址
1435 /* DMAMOV DAR, x->dst_addr */
1436 off += _emit_MOV(dry_run, &buf[off], DAR, x->dst_addr); //设置指令缓存区mov 目的地址
1437
1438 /* Setup Loop(s) */
1439 off += _setup_loops(dry_run, &buf[off], pxs);
1440
1441 return off;
1442 }
2762 static struct dma_async_tx_descriptor *
2763 pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
2764 dma_addr_t src, size_t len, unsigned long flags)
2765 {
2766 struct dma_pl330_desc *desc;
2767 struct dma_pl330_chan *pch = to_pchan(chan); //获取pl330 dmac层通道
2768 struct pl330_info *pi;
2769 int burst;
2770
2771 if (unlikely(!pch || !len))
2772 return NULL;
2773
2774 pi = &pch->dmac->pif;
2775
2776 desc = __pl330_prep_dma_memcpy(pch, dst, src, len); //调用pl330 dmac层准备内存拷贝描述符
2777 if (!desc)
2778 return NULL;
2779
2780 desc->rqcfg.src_inc = 1; //设置描述请求配置
2781 desc->rqcfg.dst_inc = 1;
2782 desc->req.rqtype = MEMTOMEM;
2783
2784 /* Select max possible burst size */
2785 burst = pi->pcfg.data_bus_width / 8; //设置突发长度
2786
2787 while (burst > 1) {
2788 if (!(len % burst))
2789 break;
2790 burst /= 2;
2791 }
2792
2793 desc->rqcfg.brst_size = 0;
2794 while (burst != (1 << desc->rqcfg.brst_size))
2795 desc->rqcfg.brst_size++;
2796
2797 desc->rqcfg.brst_len = get_burst_len(desc, len);
2798
2799 desc->txd.flags = flags;
2800
2801 return &desc->txd;
2802 }
此函数为准备dma引擎层内存拷贝传输描述符
2663 static struct dma_pl330_desc *
2664 __pl330_prep_dma_memcpy(struct dma_pl330_chan *pch, dma_addr_t dst,
2665 dma_addr_t src, size_t len)
2666 {
2667 struct dma_pl330_desc *desc = pl330_get_desc(pch); //从pl330 dmac 描述池获得一个描述
2668
2669 if (!desc) {
2670 dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
2671 __func__, __LINE__);
2672 return NULL;
2673 }
2674
2675 /*
2676 * Ideally we should lookout for reqs bigger than
2677 * those that can be programmed with 256 bytes of
2678 * MC buffer, but considering a req size is seldom
2679 * going to be word-unaligned and more than 200MB,
2680 * we take it easy.
2681 * Also, should the limit is reached we'd rather
2682 * have the platform increase MC buffer size than
2683 * complicating this API driver.
2684 */
2685 fill_px(&desc->px, dst, src, len); //填充描述符中的传输内容
2686
2687 return desc;
2688 }
2654 static inline void fill_px(struct pl330_xfer *px,
2655 dma_addr_t dst, dma_addr_t src, size_t len)
2656 {
2657 px->next = NULL;
2658 px->bytes = len;
2659 px->dst_addr = dst;
2660 px->src_addr = src;
2661 }
2514 static void pl330_issue_pending(struct dma_chan *chan)
2515 {
2516 pl330_tasklet((unsigned long) to_pchan(chan)); //处理通道中完成的描述符,填充下一个待处理的描述符
2517 }
此函数开始执行通道传输
2317 static void pl330_tasklet(unsigned long data)
2318 {
2319 struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data; //获取pl330 dmac层通道
2320 struct dma_pl330_desc *desc, *_dt;
2321 unsigned long flags;
2322 LIST_HEAD(list);
2323
2324 spin_lock_irqsave(&pch->lock, flags);
2325
2326 /* Pick up ripe tomatoes */
2327 list_for_each_entry_safe(desc, _dt, &pch->work_list, node) //遍历同搭配工作队列,查找已经完成的描述符,标记其为完成,并将其从链表删除
2328 if (desc->status == DONE) {
2329 if (!pch->cyclic)
2330 dma_cookie_complete(&desc->txd);
2331 list_move_tail(&desc->node, &list);
2332 }
2333
2334 /* Try to submit a req imm. next to the last completed cookie */
2335 fill_queue(pch); //填充下一个带出来描述符
2336
2337 /* Make sure the PL330 Channel thread is active */
2338 pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START); //开始通道
2339
2340 spin_unlock_irqrestore(&pch->lock, flags);
2341
2342 if (pch->cyclic)
2343 handle_cyclic_desc_list(&list);
2344 else
2345 free_desc_list(&list);
2346 }
理通道中完成的描述符,填充下一个待处理的描述符
2437 static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
2438 {
2439 struct dma_pl330_chan *pch = to_pchan(chan); //获取pl330 dmac层通道
2440 struct dma_pl330_desc *desc, *_dt;
2441 unsigned long flags;
2442 struct dma_pl330_dmac *pdmac = pch->dmac;
2443 struct dma_slave_config *slave_config;
2444 LIST_HEAD(list);
2445
2446 switch (cmd) {
2447 case DMA_TERMINATE_ALL: //关闭通道
2448 spin_lock_irqsave(&pch->lock, flags);
2449
2450 /* FLUSH the PL330 Channel thread */
2451 pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH); //清空线程操作
2452
2453 /* Mark all desc done */
2454 list_for_each_entry_safe(desc, _dt, &pch->work_list , node) { //遍历链表标记所有描述符为完成 ,并将其移到pl330 dmac 描述池链表
2455 desc->status = DONE;
2456 list_move_tail(&desc->node, &list);
2457 }
2458
2459 list_splice_tail_init(&list, &pdmac->desc_pool);
2460 spin_unlock_irqrestore(&pch->lock, flags);
2461 break;
2462 case DMA_SLAVE_CONFIG:
2463 slave_config = (struct dma_slave_config *)arg;
2464
2465 if (slave_config->direction == DMA_MEM_TO_DEV) {
2466 if (slave_config->dst_addr)
2467 pch->fifo_addr = slave_config->dst_addr;
2468 if (slave_config->dst_addr_width)
2469 pch->burst_sz = __ffs(slave_config->dst_addr_width);
2470 if (slave_config->dst_maxburst)
2471 pch->burst_len = slave_config->dst_maxburst;
2472 } else if (slave_config->direction == DMA_DEV_TO_MEM) {
2473 if (slave_config->src_addr)
2474 pch->fifo_addr = slave_config->src_addr;
2475 if (slave_config->src_addr_width)
2476 pch->burst_sz = __ffs(slave_config->src_addr_width);
2477 if (slave_config->src_maxburst)
2478 pch->burst_len = slave_config->src_maxburst;
2479 }
2480 break;
2481 default:
2482 dev_err(pch->dmac->pif.dev, "Not supported command.\n");
2483 return -ENXIO;
2484 }
2485
2486 return 0;
2487 }
此函数控制dma通道