提交 b2003c7a 编写于 作者: F Finn Thain 提交者: Geert Uytterhoeven

m68k: mac: Avoid stuck ISM IOP interrupt on Quadra 900/950

On a Quadra 900/950, the ISM IOP IRQ output pin is connected to an
edge-triggered input on VIA2. It is theoretically possible that this
signal could fail to produce the expected VIA2 interrupt.

The two IOP interrupt flags can be asserted in any order but the logic
in iop_ism_irq() does not allow for that. In particular, INT0 can be
asserted right after INT0 is checked and before INT1 is cleared.

Such an interrupt would produce no new edge and VIA2 would detect no
further interrupts from the IOP. Avoid this by looping over the INT0/1
handlers so an edge can be produced.
Signed-off-by: NFinn Thain <fthain@telegraphics.com.au>
Tested-by: NStan Johnson <userm57@yahoo.com>
Cc: Joshua Thompson <funaho@jurai.org>
Link: https://lore.kernel.org/r/bfbb71db52c5e162d3afa25a28fc5d535ca87138.1589949122.git.fthain@telegraphics.com.auSigned-off-by: NGeert Uytterhoeven <geert@linux-m68k.org>
上级 bf6c68ea
...@@ -565,36 +565,42 @@ irqreturn_t iop_ism_irq(int irq, void *dev_id) ...@@ -565,36 +565,42 @@ irqreturn_t iop_ism_irq(int irq, void *dev_id)
uint iop_num = (uint) dev_id; uint iop_num = (uint) dev_id;
volatile struct mac_iop *iop = iop_base[iop_num]; volatile struct mac_iop *iop = iop_base[iop_num];
int i,state; int i,state;
u8 events = iop->status_ctrl & (IOP_INT0 | IOP_INT1);
iop_pr_debug("status %02X\n", iop->status_ctrl); iop_pr_debug("status %02X\n", iop->status_ctrl);
/* INT0 indicates a state change on an outgoing message channel */ do {
/* INT0 indicates state change on an outgoing message channel */
if (iop->status_ctrl & IOP_INT0) { if (events & IOP_INT0) {
iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC; iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC;
iop_pr_debug("new status %02X, send states", iop->status_ctrl); iop_pr_debug("new status %02X, send states",
for (i = 0 ; i < NUM_IOP_CHAN ; i++) { iop->status_ctrl);
for (i = 0; i < NUM_IOP_CHAN; i++) {
state = iop_readb(iop, IOP_ADDR_SEND_STATE + i); state = iop_readb(iop, IOP_ADDR_SEND_STATE + i);
iop_pr_cont(" %02X", state); iop_pr_cont(" %02X", state);
if (state == IOP_MSG_COMPLETE) { if (state == IOP_MSG_COMPLETE)
iop_handle_send(iop_num, i); iop_handle_send(iop_num, i);
} }
}
iop_pr_cont("\n"); iop_pr_cont("\n");
} }
if (iop->status_ctrl & IOP_INT1) { /* INT1 for incoming msgs */ /* INT1 for incoming messages */
if (events & IOP_INT1) {
iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC; iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC;
iop_pr_debug("new status %02X, recv states", iop->status_ctrl); iop_pr_debug("new status %02X, recv states",
for (i = 0 ; i < NUM_IOP_CHAN ; i++) { iop->status_ctrl);
for (i = 0; i < NUM_IOP_CHAN; i++) {
state = iop_readb(iop, IOP_ADDR_RECV_STATE + i); state = iop_readb(iop, IOP_ADDR_RECV_STATE + i);
iop_pr_cont(" %02X", state); iop_pr_cont(" %02X", state);
if (state == IOP_MSG_NEW) { if (state == IOP_MSG_NEW)
iop_handle_recv(iop_num, i); iop_handle_recv(iop_num, i);
} }
}
iop_pr_cont("\n"); iop_pr_cont("\n");
} }
events = iop->status_ctrl & (IOP_INT0 | IOP_INT1);
} while (events);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册