diff --git a/src/hdd/hdd_ide_at.c b/src/hdd/hdd_ide_at.c index fbc256540..bac99852e 100644 --- a/src/hdd/hdd_ide_at.c +++ b/src/hdd/hdd_ide_at.c @@ -172,16 +172,9 @@ void ide_irq_raise(IDE *ide) if (!(ide->fdisk&2)) { - if (PCI && (ide->board < 2)) + if (PCI && (ide->board < 2) && ide_bus_master_set_irq) { - if (pci_irq_is_level(ide_irq[ide->board])) - { - picintlevel(1 << ide_irq[ide->board]); - } - else - { - picint(1 << ide_irq[ide->board]); - } + pci_ide_set_irq(ide->board, ide_irq[ide->board]); } else { @@ -211,7 +204,14 @@ void ide_irq_lower(IDE *ide) ide_log("Lowering IRQ %i (board %i)\n", ide_irq[ide->board], ide->board); - picintc(1 << ide_irq[ide->board]); + if (PCI && (ide->board < 2) && ide_bus_master_set_irq) + { + pci_ide_clear_irq(ide->board, ide_irq[ide->board]); + } + else + { + picintc(1 << ide_irq[ide->board]); + } ide->irqstat=0; } @@ -233,11 +233,25 @@ void ide_irq_update(IDE *ide) if (ide->irqstat && !pending && !(ide->fdisk & 2)) { - picint(1 << ide_irq[ide->board]); + if (PCI && (ide->board < 2) && ide_bus_master_set_irq) + { + pci_ide_set_irq(ide->board, ide_irq[ide->board]); + } + else + { + picint(1 << ide_irq[ide->board]); + } } else if (pending) { - picintc(1 << ide_irq[ide->board]); + if (PCI && (ide->board < 2) && ide_bus_master_set_irq) + { + pci_ide_clear_irq(ide->board, ide_irq[ide->board]); + } + else + { + picintc(1 << ide_irq[ide->board]); + } } } /** diff --git a/src/pci.c b/src/pci.c index adc23285a..a51ecd835 100644 --- a/src/pci.c +++ b/src/pci.c @@ -12,7 +12,7 @@ static int pci_irq_routing[32]; /* static int pci_irq_active[32]; */ static int pci_irqs[4]; static int pci_card_valid[32]; -static int pci_irq_hold[16]; +static uint64_t pci_irq_hold[16]; static int pci_index, pci_func, pci_card, pci_bus, pci_enable, pci_key; int pci_burst_time, pci_nonburst_time; @@ -187,15 +187,46 @@ void pci_issue_irq(int irq) } } +void pci_ide_set_irq(int ide_board, int irq) +{ + if (pci_irq_is_level(irq) && (pci_irq_hold[irq] & (1LL << (0x20LL + ide_board)))) + { + /* IRQ already held, do nothing. */ + return; + } + + if (!pci_irq_is_level(irq) || !pci_irq_hold[irq]) + { + /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ + pci_issue_irq(irq); + } + + /* If the IRQ is level-triggered, mark that this card is holding it. */ + if (pci_irq_is_level(irq)) + { + pci_irq_hold[irq] |= (1LL << (0x20LL + ide_board)); + } +} + void pci_set_irq(int card, int pci_int) { int irq = ((pci_int - PCI_INTA) + (pci_irq_routing[card] - PCI_INTA)) & 3; if (pci_irq_routing[card] && (pci_irqs[irq] != PCI_IRQ_DISABLED)) { - pci_issue_irq(pci_irqs[irq]); + if (pci_irq_is_level(pci_irqs[irq]) && (pci_irq_hold[pci_irqs[irq]] & (1 << card))) + { + /* IRQ already held, do nothing. */ + return; + } - /* If the IRQ is set to edge, there is no need to hold it. */ + if (!pci_irq_is_level(pci_irqs[irq]) || !pci_irq_hold[pci_irqs[irq]]) + { + /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ + pci_issue_irq(pci_irqs[irq]); + } + + /* If the IRQ is level-triggered, mark that this card is holding it. */ if (pci_irq_is_level(pci_irqs[irq])) { pci_irq_hold[pci_irqs[irq]] |= (1 << card); @@ -203,6 +234,22 @@ void pci_set_irq(int card, int pci_int) } } +void pci_ide_clear_irq(int ide_board, int irq) +{ + if (pci_irq_is_level(irq)) + { + pci_irq_hold[irq] &= ~(1LL << (0x20LL + ide_board)); + if (!pci_irq_hold[irq]) + { + picintc(1 << irq); + } + } + else + { + picintc(1 << irq); + } +} + void pci_clear_irq(int card, int pci_int) { int irq = ((pci_int - PCI_INTA) + (pci_irq_routing[card] - PCI_INTA)) & 3; diff --git a/src/pci.h b/src/pci.h index 7f1e69857..ece5f0b66 100644 --- a/src/pci.h +++ b/src/pci.h @@ -6,7 +6,9 @@ void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), int pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); void pci_set_irq_routing(int card, int irq); void pci_set_card_routing(int card, int pci_int); +void pci_ide_set_irq(int ide_board, int irq); void pci_set_irq(int card, int pci_int); +void pci_ide_clear_irq(int ide_board, int irq); void pci_clear_irq(int card, int pci_int); int pci_irq_is_level(int irq);