下面介绍pl330驱动关键函数:
1 在驱动probe函数中,注册pl330中断服务函数
2927 ret = request_irq(irq, pl330_irq_handler, 0,
2928 dev_name(&adev->dev), pi);
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-&