Skip to content

Commit b2003c7

Browse files
Finn Thaingeertu
authored andcommitted
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: Finn Thain <[email protected]> Tested-by: Stan Johnson <[email protected]> Cc: Joshua Thompson <[email protected]> Link: https://lore.kernel.org/r/bfbb71db52c5e162d3afa25a28fc5d535ca87138.1589949122.git.fthain@telegraphics.com.au Signed-off-by: Geert Uytterhoeven <[email protected]>
1 parent bf6c68e commit b2003c7

File tree

1 file changed

+28
-22
lines changed

1 file changed

+28
-22
lines changed

arch/m68k/mac/iop.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -565,36 +565,42 @@ irqreturn_t iop_ism_irq(int irq, void *dev_id)
565565
uint iop_num = (uint) dev_id;
566566
volatile struct mac_iop *iop = iop_base[iop_num];
567567
int i,state;
568+
u8 events = iop->status_ctrl & (IOP_INT0 | IOP_INT1);
568569

569570
iop_pr_debug("status %02X\n", iop->status_ctrl);
570571

571-
/* INT0 indicates a state change on an outgoing message channel */
572-
573-
if (iop->status_ctrl & IOP_INT0) {
574-
iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC;
575-
iop_pr_debug("new status %02X, send states", iop->status_ctrl);
576-
for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
577-
state = iop_readb(iop, IOP_ADDR_SEND_STATE + i);
578-
iop_pr_cont(" %02X", state);
579-
if (state == IOP_MSG_COMPLETE) {
580-
iop_handle_send(iop_num, i);
572+
do {
573+
/* INT0 indicates state change on an outgoing message channel */
574+
if (events & IOP_INT0) {
575+
iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC;
576+
iop_pr_debug("new status %02X, send states",
577+
iop->status_ctrl);
578+
for (i = 0; i < NUM_IOP_CHAN; i++) {
579+
state = iop_readb(iop, IOP_ADDR_SEND_STATE + i);
580+
iop_pr_cont(" %02X", state);
581+
if (state == IOP_MSG_COMPLETE)
582+
iop_handle_send(iop_num, i);
581583
}
584+
iop_pr_cont("\n");
582585
}
583-
iop_pr_cont("\n");
584-
}
585586

586-
if (iop->status_ctrl & IOP_INT1) { /* INT1 for incoming msgs */
587-
iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC;
588-
iop_pr_debug("new status %02X, recv states", iop->status_ctrl);
589-
for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
590-
state = iop_readb(iop, IOP_ADDR_RECV_STATE + i);
591-
iop_pr_cont(" %02X", state);
592-
if (state == IOP_MSG_NEW) {
593-
iop_handle_recv(iop_num, i);
587+
/* INT1 for incoming messages */
588+
if (events & IOP_INT1) {
589+
iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC;
590+
iop_pr_debug("new status %02X, recv states",
591+
iop->status_ctrl);
592+
for (i = 0; i < NUM_IOP_CHAN; i++) {
593+
state = iop_readb(iop, IOP_ADDR_RECV_STATE + i);
594+
iop_pr_cont(" %02X", state);
595+
if (state == IOP_MSG_NEW)
596+
iop_handle_recv(iop_num, i);
594597
}
598+
iop_pr_cont("\n");
595599
}
596-
iop_pr_cont("\n");
597-
}
600+
601+
events = iop->status_ctrl & (IOP_INT0 | IOP_INT1);
602+
} while (events);
603+
598604
return IRQ_HANDLED;
599605
}
600606

0 commit comments

Comments
 (0)