Lines Matching full:ch

592 static inline void pl330_fault(PL330Chan *ch, uint32_t flags)  in pl330_fault()  argument
594 trace_pl330_fault(ch, flags); in pl330_fault()
595 ch->fault_type |= flags; in pl330_fault()
596 if (ch->state == pl330_chan_fault) { in pl330_fault()
599 ch->state = pl330_chan_fault; in pl330_fault()
600 ch->parent->num_faulting++; in pl330_fault()
601 if (ch->parent->num_faulting == 1) { in pl330_fault()
603 qemu_irq_raise(ch->parent->irq_abort); in pl330_fault()
611 * CH - channel executing the instruction
617 static void pl330_dmaadxh(PL330Chan *ch, uint8_t *args, bool ra, bool neg) in pl330_dmaadxh() argument
624 if (ch->is_manager) { in pl330_dmaadxh()
625 pl330_fault(ch, PL330_FAULT_UNDEF_INSTR); in pl330_dmaadxh()
629 ch->dst += im; in pl330_dmaadxh()
631 ch->src += im; in pl330_dmaadxh()
635 static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmaaddh() argument
637 pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), false); in pl330_dmaaddh()
640 static void pl330_dmaadnh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmaadnh() argument
642 pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), true); in pl330_dmaadnh()
645 static void pl330_dmaend(PL330Chan *ch, uint8_t opcode, in pl330_dmaend() argument
648 PL330State *s = ch->parent; in pl330_dmaend()
650 if (ch->state == pl330_chan_executing && !ch->is_manager) { in pl330_dmaend()
652 if (pl330_fifo_has_tag(&s->fifo, ch->tag) || in pl330_dmaend()
653 pl330_queue_find_insn(&s->read_queue, ch->tag, false) != NULL || in pl330_dmaend()
654 pl330_queue_find_insn(&s->write_queue, ch->tag, false) != NULL) { in pl330_dmaend()
656 ch->stall = 1; in pl330_dmaend()
661 pl330_fifo_tagged_remove(&s->fifo, ch->tag); in pl330_dmaend()
662 pl330_queue_remove_tagged(&s->read_queue, ch->tag); in pl330_dmaend()
663 pl330_queue_remove_tagged(&s->write_queue, ch->tag); in pl330_dmaend()
664 ch->state = pl330_chan_stopped; in pl330_dmaend()
667 static void pl330_dmaflushp(PL330Chan *ch, uint8_t opcode, in pl330_dmaflushp() argument
673 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmaflushp()
677 if (periph_id >= ch->parent->num_periph_req) { in pl330_dmaflushp()
678 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmaflushp()
681 if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { in pl330_dmaflushp()
682 pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); in pl330_dmaflushp()
688 static void pl330_dmago(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmago() argument
697 if (!ch->is_manager) { in pl330_dmago()
698 pl330_fault(ch, PL330_FAULT_UNDEF_INSTR); in pl330_dmago()
704 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmago()
707 if (chan_id >= ch->parent->num_chnls) { in pl330_dmago()
708 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmago()
713 if (ch->parent->chan[chan_id].state != pl330_chan_stopped) { in pl330_dmago()
714 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmago()
717 if (ch->ns && !ns) { in pl330_dmago()
718 pl330_fault(ch, PL330_FAULT_DMAGO_ERR); in pl330_dmago()
721 s = &ch->parent->chan[chan_id]; in pl330_dmago()
727 static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmald() argument
734 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmald()
737 if ((bs == 1 && ch->request_flag == PL330_BURST) || in pl330_dmald()
738 (bs == 3 && ch->request_flag == PL330_SINGLE)) { in pl330_dmald()
742 if (bs == 1 && ch->request_flag == PL330_SINGLE) { in pl330_dmald()
745 num = ((ch->control >> 4) & 0xf) + 1; in pl330_dmald()
747 size = (uint32_t)1 << ((ch->control >> 1) & 0x7); in pl330_dmald()
748 inc = !!(ch->control & 1); in pl330_dmald()
749 ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src, in pl330_dmald()
750 size, num, inc, 0, ch->tag); in pl330_dmald()
751 if (!ch->stall) { in pl330_dmald()
752 trace_pl330_dmald(ch->tag, ch->src, size, num, inc ? 'Y' : 'N'); in pl330_dmald()
753 ch->src += inc ? size * num - (ch->src & (size - 1)) : 0; in pl330_dmald()
757 static void pl330_dmaldp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmaldp() argument
762 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmaldp()
766 if (periph_id >= ch->parent->num_periph_req) { in pl330_dmaldp()
767 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmaldp()
770 if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { in pl330_dmaldp()
771 pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); in pl330_dmaldp()
774 pl330_dmald(ch, opcode, args, len); in pl330_dmaldp()
777 static void pl330_dmalp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmalp() argument
781 ch->lc[lc] = args[0]; in pl330_dmalp()
784 static void pl330_dmakill(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmakill() argument
786 if (ch->state == pl330_chan_fault || in pl330_dmakill()
787 ch->state == pl330_chan_fault_completing) { in pl330_dmakill()
789 ch->fault_type = 0; in pl330_dmakill()
790 ch->parent->num_faulting--; in pl330_dmakill()
791 if (ch->parent->num_faulting == 0) { in pl330_dmakill()
793 qemu_irq_lower(ch->parent->irq_abort); in pl330_dmakill()
796 ch->state = pl330_chan_killing; in pl330_dmakill()
797 pl330_fifo_tagged_remove(&ch->parent->fifo, ch->tag); in pl330_dmakill()
798 pl330_queue_remove_tagged(&ch->parent->read_queue, ch->tag); in pl330_dmakill()
799 pl330_queue_remove_tagged(&ch->parent->write_queue, ch->tag); in pl330_dmakill()
800 ch->state = pl330_chan_stopped; in pl330_dmakill()
803 static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode, in pl330_dmalpend() argument
810 trace_pl330_dmalpend(nf, bs, lc, ch->lc[lc], ch->request_flag); in pl330_dmalpend()
813 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmalpend()
816 if ((bs == 1 && ch->request_flag == PL330_BURST) || in pl330_dmalpend()
817 (bs == 3 && ch->request_flag == PL330_SINGLE)) { in pl330_dmalpend()
821 if (!nf || ch->lc[lc]) { in pl330_dmalpend()
823 ch->lc[lc]--; in pl330_dmalpend()
826 ch->pc -= args[0]; in pl330_dmalpend()
827 ch->pc -= len + 1; in pl330_dmalpend()
828 /* "ch->pc -= args[0] + len + 1" is incorrect when args[0] == 256 */ in pl330_dmalpend()
835 static void pl330_dmamov(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmamov() argument
841 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmamov()
848 ch->src = im; in pl330_dmamov()
851 ch->control = im; in pl330_dmamov()
854 ch->dst = im; in pl330_dmamov()
857 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmamov()
862 static void pl330_dmanop(PL330Chan *ch, uint8_t opcode, in pl330_dmanop() argument
868 static void pl330_dmarmb(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmarmb() argument
870 if (pl330_queue_find_insn(&ch->parent->read_queue, ch->tag, false)) { in pl330_dmarmb()
871 ch->state = pl330_chan_at_barrier; in pl330_dmarmb()
872 ch->stall = 1; in pl330_dmarmb()
875 ch->state = pl330_chan_executing; in pl330_dmarmb()
879 static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmasev() argument
884 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmasev()
888 if (ev_id >= ch->parent->num_events) { in pl330_dmasev()
889 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmasev()
892 if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) { in pl330_dmasev()
893 pl330_fault(ch, PL330_FAULT_EVENT_ERR); in pl330_dmasev()
896 if (ch->parent->inten & (1 << ev_id)) { in pl330_dmasev()
897 ch->parent->int_status |= (1 << ev_id); in pl330_dmasev()
899 qemu_irq_raise(ch->parent->irq[ev_id]); in pl330_dmasev()
902 ch->parent->ev_status |= (1 << ev_id); in pl330_dmasev()
905 static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) in pl330_dmast() argument
912 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmast()
915 if ((bs == 1 && ch->request_flag == PL330_BURST) || in pl330_dmast()
916 (bs == 3 && ch->request_flag == PL330_SINGLE)) { in pl330_dmast()
920 num = ((ch->control >> 18) & 0xf) + 1; in pl330_dmast()
921 size = (uint32_t)1 << ((ch->control >> 15) & 0x7); in pl330_dmast()
922 inc = !!((ch->control >> 14) & 1); in pl330_dmast()
923 ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst, in pl330_dmast()
924 size, num, inc, 0, ch->tag); in pl330_dmast()
925 if (!ch->stall) { in pl330_dmast()
926 trace_pl330_dmast(ch->tag, ch->dst, size, num, inc ? 'Y' : 'N'); in pl330_dmast()
927 ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0; in pl330_dmast()
931 static void pl330_dmastp(PL330Chan *ch, uint8_t opcode, in pl330_dmastp() argument
937 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmastp()
941 if (periph_id >= ch->parent->num_periph_req) { in pl330_dmastp()
942 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmastp()
945 if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { in pl330_dmastp()
946 pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); in pl330_dmastp()
949 pl330_dmast(ch, opcode, args, len); in pl330_dmastp()
952 static void pl330_dmastz(PL330Chan *ch, uint8_t opcode, in pl330_dmastz() argument
958 num = ((ch->control >> 18) & 0xf) + 1; in pl330_dmastz()
959 size = (uint32_t)1 << ((ch->control >> 15) & 0x7); in pl330_dmastz()
960 inc = !!((ch->control >> 14) & 1); in pl330_dmastz()
961 ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst, in pl330_dmastz()
962 size, num, inc, 1, ch->tag); in pl330_dmastz()
964 ch->dst += size * num; in pl330_dmastz()
968 static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode, in pl330_dmawfe() argument
975 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmawfe()
979 if (ev_id >= ch->parent->num_events) { in pl330_dmawfe()
980 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmawfe()
983 if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) { in pl330_dmawfe()
984 pl330_fault(ch, PL330_FAULT_EVENT_ERR); in pl330_dmawfe()
987 ch->wakeup = ev_id; in pl330_dmawfe()
988 ch->state = pl330_chan_waiting_event; in pl330_dmawfe()
989 if (~ch->parent->inten & ch->parent->ev_status & 1 << ev_id) { in pl330_dmawfe()
990 ch->state = pl330_chan_executing; in pl330_dmawfe()
994 for (i = 0; i < ch->parent->num_chnls; ++i) { in pl330_dmawfe()
995 PL330Chan *peer = &ch->parent->chan[i]; in pl330_dmawfe()
1001 ch->parent->ev_status &= ~(1 << ev_id); in pl330_dmawfe()
1004 ch->stall = 1; in pl330_dmawfe()
1008 static void pl330_dmawfp(PL330Chan *ch, uint8_t opcode, in pl330_dmawfp() argument
1015 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmawfp()
1019 if (periph_id >= ch->parent->num_periph_req) { in pl330_dmawfp()
1020 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmawfp()
1023 if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { in pl330_dmawfp()
1024 pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); in pl330_dmawfp()
1029 ch->request_flag = PL330_SINGLE; in pl330_dmawfp()
1030 ch->wfp_sbp = 0; in pl330_dmawfp()
1033 ch->request_flag = PL330_BURST; in pl330_dmawfp()
1034 ch->wfp_sbp = 2; in pl330_dmawfp()
1037 ch->request_flag = PL330_BURST; in pl330_dmawfp()
1038 ch->wfp_sbp = 1; in pl330_dmawfp()
1041 pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); in pl330_dmawfp()
1045 if (ch->parent->periph_busy[periph_id]) { in pl330_dmawfp()
1046 ch->state = pl330_chan_waiting_periph; in pl330_dmawfp()
1047 ch->stall = 1; in pl330_dmawfp()
1048 } else if (ch->state == pl330_chan_waiting_periph) { in pl330_dmawfp()
1049 ch->state = pl330_chan_executing; in pl330_dmawfp()
1053 static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode, in pl330_dmawmb() argument
1056 if (pl330_queue_find_insn(&ch->parent->write_queue, ch->tag, false)) { in pl330_dmawmb()
1057 ch->state = pl330_chan_at_barrier; in pl330_dmawmb()
1058 ch->stall = 1; in pl330_dmawmb()
1061 ch->state = pl330_chan_executing; in pl330_dmawmb()
1101 static inline const PL330InsnDesc *pl330_fetch_insn(PL330Chan *ch) in pl330_fetch_insn() argument
1106 dma_memory_read(ch->parent->mem_as, ch->pc, &opcode, 1, in pl330_fetch_insn()
1116 static inline void pl330_exec_insn(PL330Chan *ch, const PL330InsnDesc *insn) in pl330_exec_insn() argument
1121 dma_memory_read(ch->parent->mem_as, ch->pc, buf, insn->size, in pl330_exec_insn()
1123 insn->exec(ch, buf[0], &buf[1], insn->size - 1); in pl330_exec_insn()
1126 static inline void pl330_update_pc(PL330Chan *ch, in pl330_update_pc() argument
1129 ch->pc += insn->size; in pl330_update_pc()
1132 /* Try to execute current instruction in channel CH. Number of executed
1134 static int pl330_chan_exec(PL330Chan *ch) in pl330_chan_exec() argument
1138 if (ch->state != pl330_chan_executing && in pl330_chan_exec()
1139 ch->state != pl330_chan_waiting_periph && in pl330_chan_exec()
1140 ch->state != pl330_chan_at_barrier && in pl330_chan_exec()
1141 ch->state != pl330_chan_waiting_event) { in pl330_chan_exec()
1144 ch->stall = 0; in pl330_chan_exec()
1145 insn = pl330_fetch_insn(ch); in pl330_chan_exec()
1148 pl330_fault(ch, PL330_FAULT_UNDEF_INSTR); in pl330_chan_exec()
1151 pl330_exec_insn(ch, insn); in pl330_chan_exec()
1152 if (!ch->stall) { in pl330_chan_exec()
1153 pl330_update_pc(ch, insn); in pl330_chan_exec()
1154 ch->watchdog_timer = 0; in pl330_chan_exec()
1157 } else if (ch->state == pl330_chan_executing) { in pl330_chan_exec()
1158 ch->watchdog_timer++; in pl330_chan_exec()
1159 if (ch->watchdog_timer >= PL330_WATCHDOG_LIMIT) { in pl330_chan_exec()
1160 pl330_fault(ch, PL330_FAULT_LOCKUP_ERR); in pl330_chan_exec()
1299 PL330Chan *ch; in pl330_debug_exec() local
1312 ch = &s->chan[chan_id]; in pl330_debug_exec()
1314 ch = &s->manager; in pl330_debug_exec()
1323 pl330_fault(ch, PL330_FAULT_UNDEF_INSTR | PL330_FAULT_DBG_INSTR); in pl330_debug_exec()
1326 ch->stall = 0; in pl330_debug_exec()
1327 insn->exec(ch, opcode, args, insn->size - 1); in pl330_debug_exec()
1328 if (ch->fault_type) { in pl330_debug_exec()
1329 ch->fault_type |= PL330_FAULT_DBG_INSTR; in pl330_debug_exec()
1331 if (ch->stall) { in pl330_debug_exec()
1516 static void pl330_chan_reset(PL330Chan *ch) in pl330_chan_reset() argument
1518 ch->src = 0; in pl330_chan_reset()
1519 ch->dst = 0; in pl330_chan_reset()
1520 ch->pc = 0; in pl330_chan_reset()
1521 ch->state = pl330_chan_stopped; in pl330_chan_reset()
1522 ch->watchdog_timer = 0; in pl330_chan_reset()
1523 ch->stall = 0; in pl330_chan_reset()
1524 ch->control = 0; in pl330_chan_reset()
1525 ch->status = 0; in pl330_chan_reset()
1526 ch->fault_type = 0; in pl330_chan_reset()