pl330 dmac驱动分析2----关键函数

饿哦
摘要由CSDN通过智能技术生成

下面介绍pl330驱动关键函数:

1 在驱动probe函数中,注册pl330中断服务函数


2927         ret = request_irq(irq, pl330_irq_handler, 0,

  2928                         dev_name(&adev->dev), pi);



  2878 static irqreturn_t pl330_irq_handler(int irq, void *data)
  2879 {
  2880         if (pl330_update(data))
  2881                 return IRQ_HANDLED;
  2882         else
  2883                 return IRQ_NONE;

  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线程



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;
  1077
  1078         thrd->req_running = -1;

  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-&

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值