summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2014-08-08 17:23:33 +0100
committerStefan Hajnoczi <stefanha@redhat.com>2014-08-15 18:03:13 +0100
commit5bbc0a703d8241a866f51856336aeb2a2d54b79f (patch)
tree4c9e2e309f7d6d9174b5a15dc9095538b888764f
parent58f16a7b47e0e8418b1222b6adc08d2b7079a4c0 (diff)
downloadqemu-5bbc0a703d8241a866f51856336aeb2a2d54b79f.tar.gz
cmd646: synchronise DMA interrupt status with UDMA interrupt status
Make sure that the standard DMA interrupt status bits reflect any changes made to the UDMA interrupt status bits. The CMD646U2 datasheet claims that these bits are equivalent, and they must be synchronised for guests that manipulate both registers. Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
-rw-r--r--hw/ide/cmd646.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index d8395ef248..c3c6c53d91 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -33,9 +33,13 @@
#include <hw/ide/pci.h>
/* CMD646 specific */
+#define CFR 0x50
+#define CFR_INTR_CH0 0x04
#define CNTRL 0x51
#define CNTRL_EN_CH0 0x04
#define CNTRL_EN_CH1 0x08
+#define ARTTIM23 0x57
+#define ARTTIM23_INTR_CH1 0x10
#define MRDMODE 0x71
#define MRDMODE_INTR_CH0 0x04
#define MRDMODE_INTR_CH1 0x08
@@ -126,6 +130,22 @@ static void setup_cmd646_bar(PCIIDEState *d, int bus_num)
"cmd646-data", 8);
}
+static void cmd646_update_dma_interrupts(PCIDevice *pd)
+{
+ /* Sync DMA interrupt status from UDMA interrupt status */
+ if (pd->config[MRDMODE] & MRDMODE_INTR_CH0) {
+ pd->config[CFR] |= CFR_INTR_CH0;
+ } else {
+ pd->config[CFR] &= ~CFR_INTR_CH0;
+ }
+
+ if (pd->config[MRDMODE] & MRDMODE_INTR_CH1) {
+ pd->config[ARTTIM23] |= ARTTIM23_INTR_CH1;
+ } else {
+ pd->config[ARTTIM23] &= ~ARTTIM23_INTR_CH1;
+ }
+}
+
static uint64_t bmdma_read(void *opaque, hwaddr addr,
unsigned size)
{
@@ -184,6 +204,7 @@ static void bmdma_write(void *opaque, hwaddr addr,
case 1:
pci_dev->config[MRDMODE] =
(pci_dev->config[MRDMODE] & ~0x30) | (val & 0x30);
+ cmd646_update_dma_interrupts(pci_dev);
cmd646_update_irq(bm->pci_dev);
break;
case 2:
@@ -249,6 +270,7 @@ static void cmd646_set_irq(void *opaque, int channel, int level)
} else {
pd->config[MRDMODE] &= ~irq_mask;
}
+ cmd646_update_dma_interrupts(pd);
cmd646_update_irq(d);
}