📄 iop.c
字号:
* into the buffer, setting the channel state to MSG_COMPLETE and * notifying the IOP. */void iop_complete_message(struct iop_msg *msg){ int iop_num = msg->iop_num; int chan = msg->channel; int i,offset;#ifdef DEBUG_IOP printk("iop_complete(%p): iop %d chan %d\n", msg, msg->iop_num, msg->channel);#endif offset = IOP_ADDR_RECV_MSG + (msg->channel * IOP_MSG_LEN); for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { iop_writeb(iop_base[iop_num], offset, msg->reply[i]); } iop_writeb(iop_base[iop_num], IOP_ADDR_RECV_STATE + chan, IOP_MSG_COMPLETE); iop_interrupt(iop_base[msg->iop_num]); iop_free_msg(msg);}/* * Actually put a message into a send channel buffer */static void iop_do_send(struct iop_msg *msg){ volatile struct mac_iop *iop = iop_base[msg->iop_num]; int i,offset; offset = IOP_ADDR_SEND_MSG + (msg->channel * IOP_MSG_LEN); for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { iop_writeb(iop, offset, msg->message[i]); } iop_writeb(iop, IOP_ADDR_SEND_STATE + msg->channel, IOP_MSG_NEW); iop_interrupt(iop);}/* * Handle sending a message on a channel that * has gone into the IOP_MSG_COMPLETE state. */static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs){ volatile struct mac_iop *iop = iop_base[iop_num]; struct iop_msg *msg,*msg2; int i,offset;#ifdef DEBUG_IOP printk("iop_handle_send: iop %d channel %d\n", iop_num, chan);#endif iop_writeb(iop, IOP_ADDR_SEND_STATE + chan, IOP_MSG_IDLE); if (!(msg = iop_send_queue[iop_num][chan])) return; msg->status = IOP_MSGSTATUS_COMPLETE; offset = IOP_ADDR_SEND_MSG + (chan * IOP_MSG_LEN); for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { msg->reply[i] = iop_readb(iop, offset); } if (msg->handler) (*msg->handler)(msg, regs); msg2 = msg; msg = msg->next; iop_free_msg(msg2); iop_send_queue[iop_num][chan] = msg; if (msg) iop_do_send(msg);}/* * Handle reception of a message on a channel that has * gone into the IOP_MSG_NEW state. */static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs){ volatile struct mac_iop *iop = iop_base[iop_num]; int i,offset; struct iop_msg *msg;#ifdef DEBUG_IOP printk("iop_handle_recv: iop %d channel %d\n", iop_num, chan);#endif msg = iop_alloc_msg(); msg->iop_num = iop_num; msg->channel = chan; msg->status = IOP_MSGSTATUS_UNSOL; msg->handler = iop_listeners[iop_num][chan].handler; offset = IOP_ADDR_RECV_MSG + (chan * IOP_MSG_LEN); for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { msg->message[i] = iop_readb(iop, offset); } iop_writeb(iop, IOP_ADDR_RECV_STATE + chan, IOP_MSG_RCVD); /* If there is a listener, call it now. Otherwise complete */ /* the message ourselves to avoid possible stalls. */ if (msg->handler) { (*msg->handler)(msg, regs); } else {#ifdef DEBUG_IOP printk("iop_handle_recv: unclaimed message on iop %d channel %d\n", iop_num, chan); printk("iop_handle_recv:"); for (i = 0 ; i < IOP_MSG_LEN ; i++) { printk(" %02X", (uint) msg->message[i]); } printk("\n");#endif iop_complete_message(msg); }}/* * Send a message * * The message is placed at the end of the send queue. Afterwards if the * channel is idle we force an immediate send of the next message in the * queue. */int iop_send_message(uint iop_num, uint chan, void *privdata, uint msg_len, __u8 *msg_data, void (*handler)(struct iop_msg *, struct pt_regs *)){ struct iop_msg *msg, *q; if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL; if (chan >= NUM_IOP_CHAN) return -EINVAL; if (msg_len > IOP_MSG_LEN) return -EINVAL; msg = iop_alloc_msg(); if (!msg) return -ENOMEM; msg->next = NULL; msg->status = IOP_MSGSTATUS_WAITING; msg->iop_num = iop_num; msg->channel = chan; msg->caller_priv = privdata; memcpy(msg->message, msg_data, msg_len); msg->handler = handler; if (!(q = iop_send_queue[iop_num][chan])) { iop_send_queue[iop_num][chan] = msg; } else { while (q->next) q = q->next; q->next = msg; } if (iop_readb(iop_base[iop_num], IOP_ADDR_SEND_STATE + chan) == IOP_MSG_IDLE) { iop_do_send(msg); } return 0;}/* * Upload code to the shared RAM of an IOP. */void iop_upload_code(uint iop_num, __u8 *code_start, uint code_len, __u16 shared_ram_start){ if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return; iop_loadaddr(iop_base[iop_num], shared_ram_start); while (code_len--) { iop_base[iop_num]->ram_data = *code_start++; }}/* * Download code from the shared RAM of an IOP. */void iop_download_code(uint iop_num, __u8 *code_start, uint code_len, __u16 shared_ram_start){ if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return; iop_loadaddr(iop_base[iop_num], shared_ram_start); while (code_len--) { *code_start++ = iop_base[iop_num]->ram_data; }}/* * Compare the code in the shared RAM of an IOP with a copy in system memory * and return 0 on match or the first nonmatching system memory address on * failure. */__u8 *iop_compare_code(uint iop_num, __u8 *code_start, uint code_len, __u16 shared_ram_start){ if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return code_start; iop_loadaddr(iop_base[iop_num], shared_ram_start); while (code_len--) { if (*code_start != iop_base[iop_num]->ram_data) { return code_start; } code_start++; } return (__u8 *) 0;}/* * Handle an ISM IOP interrupt */void iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs){ uint iop_num = (uint) dev_id; volatile struct mac_iop *iop = iop_base[iop_num]; int i,state;#ifdef DEBUG_IOP printk("iop_ism_irq: status = %02X\n", (uint) iop->status_ctrl);#endif /* INT0 indicates a state change on an outgoing message channel */ if (iop->status_ctrl & IOP_INT0) { iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC;#ifdef DEBUG_IOP printk("iop_ism_irq: new status = %02X, send states", (uint) iop->status_ctrl);#endif for (i = 0 ; i < NUM_IOP_CHAN ; i++) { state = iop_readb(iop, IOP_ADDR_SEND_STATE + i);#ifdef DEBUG_IOP printk(" %02X", state);#endif if (state == IOP_MSG_COMPLETE) { iop_handle_send(iop_num, i, regs); } }#ifdef DEBUG_IOP printk("\n");#endif } if (iop->status_ctrl & IOP_INT1) { /* INT1 for incoming msgs */ iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC;#ifdef DEBUG_IOP printk("iop_ism_irq: new status = %02X, recv states", (uint) iop->status_ctrl);#endif for (i = 0 ; i < NUM_IOP_CHAN ; i++) { state = iop_readb(iop, IOP_ADDR_RECV_STATE + i);#ifdef DEBUG_IOP printk(" %02X", state);#endif if (state == IOP_MSG_NEW) { iop_handle_recv(iop_num, i, regs); } }#ifdef DEBUG_IOP printk("\n");#endif }}#ifdef CONFIG_PROC_FSchar *iop_chan_state(int state){ switch(state) { case IOP_MSG_IDLE : return "idle "; case IOP_MSG_NEW : return "new "; case IOP_MSG_RCVD : return "received "; case IOP_MSG_COMPLETE : return "completed "; default : return "unknown "; }}int iop_dump_one_iop(char *buf, int iop_num, char *iop_name){ int i,len = 0; volatile struct mac_iop *iop = iop_base[iop_num]; len += sprintf(buf+len, "%s IOP channel states:\n\n", iop_name); len += sprintf(buf+len, "## send_state recv_state device\n"); len += sprintf(buf+len, "------------------------------------------------\n"); for (i = 0 ; i < NUM_IOP_CHAN ; i++) { len += sprintf(buf+len, "%2d %10s %10s %s\n", i, iop_chan_state(iop_readb(iop, IOP_ADDR_SEND_STATE+i)), iop_chan_state(iop_readb(iop, IOP_ADDR_RECV_STATE+i)), iop_listeners[iop_num][i].handler? iop_listeners[iop_num][i].devname : ""); } len += sprintf(buf+len, "\n"); return len;} static int iop_get_proc_info(char *buf, char **start, off_t pos, int count){ int len, cnt; cnt = 0; len = sprintf(buf, "IOPs detected:\n\n"); if (iop_scc_present) { len += sprintf(buf+len, "SCC IOP (%p): status %02X\n", iop_base[IOP_NUM_SCC], (uint) iop_base[IOP_NUM_SCC]->status_ctrl); } if (iop_ism_present) { len += sprintf(buf+len, "ISM IOP (%p): status %02X\n\n", iop_base[IOP_NUM_ISM], (uint) iop_base[IOP_NUM_ISM]->status_ctrl); } if (iop_scc_present) { len += iop_dump_one_iop(buf+len, IOP_NUM_SCC, "SCC"); } if (iop_ism_present) { len += iop_dump_one_iop(buf+len, IOP_NUM_ISM, "ISM"); } if (len >= pos) { if (!*start) { *start = buf + pos; cnt = len - pos; } else { cnt += len; } } return (count > cnt) ? cnt : count;}#endif /* CONFIG_PROC_FS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -