aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-10-01 19:55:10 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-10-01 19:55:10 +0100
commitb5ce42f5d138d7546f9faa2decbd6ee8702243a3 (patch)
treefb24528a9ff8c227609198d3b3a7164770e0c5a8 /hw
parent625581c2602b5b43e115b779a9a782478e6f92e7 (diff)
parent55adb3c45620c31f29978f209e2a44a08d34e2da (diff)
downloadqemu-b5ce42f5d138d7546f9faa2decbd6ee8702243a3.zip
qemu-b5ce42f5d138d7546f9faa2decbd6ee8702243a3.tar.gz
qemu-b5ce42f5d138d7546f9faa2decbd6ee8702243a3.tar.bz2
Merge remote-tracking branch 'remotes/jsnow-gitlab/tags/ide-pull-request' into staging
Pull request # gpg: Signature made Thu 01 Oct 2020 18:41:05 BST # gpg: using RSA key F9B7ABDBBCACDF95BE76CBD07DEF8106AAFC390E # gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" [full] # Primary key fingerprint: FAEB 9711 A12C F475 812F 18F2 88A9 064D 1835 61EB # Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76 CBD0 7DEF 8106 AAFC 390E * remotes/jsnow-gitlab/tags/ide-pull-request: ide: cancel pending callbacks on SRST ide: clear interrupt on command write ide: remove magic constants from the device register ide: reorder set/get sector functions ide: model HOB correctly ide: don't tamper with the device register ide: rename cmd_write to ctrl_write hw/ide/ahci: Do not dma_memory_unmap(NULL) MAINTAINERS: Update my git address Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/ide/ahci.c2
-rw-r--r--hw/ide/core.c124
-rw-r--r--hw/ide/ioport.c2
-rw-r--r--hw/ide/macio.c2
-rw-r--r--hw/ide/mmio.c8
-rw-r--r--hw/ide/pci.c12
-rw-r--r--hw/ide/trace-events2
7 files changed, 90 insertions, 62 deletions
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index ee1d47f..680304a 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -250,7 +250,7 @@ static void map_page(AddressSpace *as, uint8_t **ptr, uint64_t addr,
}
*ptr = dma_memory_map(as, addr, &len, DMA_DIRECTION_FROM_DEVICE);
- if (len < wanted) {
+ if (len < wanted && *ptr) {
dma_memory_unmap(as, *ptr, len, DMA_DIRECTION_FROM_DEVICE, len);
*ptr = NULL;
}
diff --git a/hw/ide/core.c b/hw/ide/core.c
index f76f7e5..0e32abd 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -367,7 +367,7 @@ fill_buffer:
static void ide_set_signature(IDEState *s)
{
- s->select &= 0xf0; /* clear head */
+ s->select &= ~(ATA_DEV_HS); /* clear head */
/* put signature */
s->nsector = 1;
s->sector = 1;
@@ -586,48 +586,54 @@ void ide_transfer_stop(IDEState *s)
int64_t ide_get_sector(IDEState *s)
{
int64_t sector_num;
- if (s->select & 0x40) {
- /* lba */
- if (!s->lba48) {
- sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) |
- (s->lcyl << 8) | s->sector;
- } else {
+ if (s->select & (ATA_DEV_LBA)) {
+ if (s->lba48) {
sector_num = ((int64_t)s->hob_hcyl << 40) |
((int64_t) s->hob_lcyl << 32) |
((int64_t) s->hob_sector << 24) |
((int64_t) s->hcyl << 16) |
((int64_t) s->lcyl << 8) | s->sector;
+ } else {
+ /* LBA28 */
+ sector_num = ((s->select & (ATA_DEV_LBA_MSB)) << 24) |
+ (s->hcyl << 16) | (s->lcyl << 8) | s->sector;
}
} else {
+ /* CHS */
sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
- (s->select & 0x0f) * s->sectors + (s->sector - 1);
+ (s->select & (ATA_DEV_HS)) * s->sectors + (s->sector - 1);
}
+
return sector_num;
}
void ide_set_sector(IDEState *s, int64_t sector_num)
{
unsigned int cyl, r;
- if (s->select & 0x40) {
- if (!s->lba48) {
- s->select = (s->select & 0xf0) | (sector_num >> 24);
- s->hcyl = (sector_num >> 16);
- s->lcyl = (sector_num >> 8);
- s->sector = (sector_num);
- } else {
+ if (s->select & (ATA_DEV_LBA)) {
+ if (s->lba48) {
s->sector = sector_num;
s->lcyl = sector_num >> 8;
s->hcyl = sector_num >> 16;
s->hob_sector = sector_num >> 24;
s->hob_lcyl = sector_num >> 32;
s->hob_hcyl = sector_num >> 40;
+ } else {
+ /* LBA28 */
+ s->select = (s->select & ~(ATA_DEV_LBA_MSB)) |
+ ((sector_num >> 24) & (ATA_DEV_LBA_MSB));
+ s->hcyl = (sector_num >> 16);
+ s->lcyl = (sector_num >> 8);
+ s->sector = (sector_num);
}
} else {
+ /* CHS */
cyl = sector_num / (s->heads * s->sectors);
r = sector_num % (s->heads * s->sectors);
s->hcyl = cyl >> 8;
s->lcyl = cyl;
- s->select = (s->select & 0xf0) | ((r / s->sectors) & 0x0f);
+ s->select = (s->select & ~(ATA_DEV_HS)) |
+ ((r / s->sectors) & (ATA_DEV_HS));
s->sector = (r % s->sectors) + 1;
}
}
@@ -1215,8 +1221,7 @@ static void ide_cmd_lba48_transform(IDEState *s, int lba48)
static void ide_clear_hob(IDEBus *bus)
{
/* any write clears HOB high bit of device control register */
- bus->ifs[0].select &= ~(1 << 7);
- bus->ifs[1].select &= ~(1 << 7);
+ bus->cmd &= ~(IDE_CTRL_HOB);
}
/* IOport [W]rite [R]egisters */
@@ -1256,12 +1261,14 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
return;
}
+ /* NOTE: Device0 and Device1 both receive incoming register writes.
+ * (They're on the same bus! They have to!) */
+
switch (reg_num) {
case 0:
break;
case ATA_IOPORT_WR_FEATURES:
ide_clear_hob(bus);
- /* NOTE: data is written to the two drives */
bus->ifs[0].hob_feature = bus->ifs[0].feature;
bus->ifs[1].hob_feature = bus->ifs[1].feature;
bus->ifs[0].feature = val;
@@ -1296,15 +1303,16 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
bus->ifs[1].hcyl = val;
break;
case ATA_IOPORT_WR_DEVICE_HEAD:
- /* FIXME: HOB readback uses bit 7 */
- bus->ifs[0].select = (val & ~0x10) | 0xa0;
- bus->ifs[1].select = (val | 0x10) | 0xa0;
+ ide_clear_hob(bus);
+ bus->ifs[0].select = val | (ATA_DEV_ALWAYS_ON);
+ bus->ifs[1].select = val | (ATA_DEV_ALWAYS_ON);
/* select drive */
- bus->unit = (val >> 4) & 1;
+ bus->unit = (val & (ATA_DEV_SELECT)) ? 1 : 0;
break;
default:
case ATA_IOPORT_WR_COMMAND:
- /* command */
+ ide_clear_hob(bus);
+ qemu_irq_lower(bus->irq);
ide_exec_cmd(bus, val);
break;
}
@@ -1338,7 +1346,7 @@ static void ide_reset(IDEState *s)
s->hob_lcyl = 0;
s->hob_hcyl = 0;
- s->select = 0xa0;
+ s->select = (ATA_DEV_ALWAYS_ON);
s->status = READY_STAT | SEEK_STAT;
s->lba48 = 0;
@@ -2142,9 +2150,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr)
int ret, hob;
reg_num = addr & 7;
- /* FIXME: HOB readback uses bit 7, but it's always set right now */
- //hob = s->select & (1 << 7);
- hob = 0;
+ hob = bus->cmd & (IDE_CTRL_HOB);
switch (reg_num) {
case ATA_IOPORT_RR_DATA:
ret = 0xff;
@@ -2235,34 +2241,56 @@ uint32_t ide_status_read(void *opaque, uint32_t addr)
return ret;
}
-void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val)
+static void ide_perform_srst(IDEState *s)
+{
+ s->status |= BUSY_STAT;
+
+ /* Halt PIO (Via register state); PIO BH remains scheduled. */
+ ide_transfer_halt(s);
+
+ /* Cancel DMA -- may drain block device and invoke callbacks */
+ ide_cancel_dma_sync(s);
+
+ /* Cancel PIO callback, reset registers/signature, etc */
+ ide_reset(s);
+
+ if (s->drive_kind == IDE_CD) {
+ /* ATAPI drives do not set READY or SEEK */
+ s->status = 0x00;
+ }
+}
+
+static void ide_bus_perform_srst(void *opaque)
{
IDEBus *bus = opaque;
IDEState *s;
int i;
- trace_ide_cmd_write(addr, val, bus);
+ for (i = 0; i < 2; i++) {
+ s = &bus->ifs[i];
+ ide_perform_srst(s);
+ }
+}
- /* common for both drives */
- if (!(bus->cmd & IDE_CMD_RESET) &&
- (val & IDE_CMD_RESET)) {
- /* reset low to high */
- for(i = 0;i < 2; i++) {
- s = &bus->ifs[i];
- s->status = BUSY_STAT | SEEK_STAT;
- s->error = 0x01;
- }
- } else if ((bus->cmd & IDE_CMD_RESET) &&
- !(val & IDE_CMD_RESET)) {
- /* high to low */
- for(i = 0;i < 2; i++) {
+void ide_ctrl_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ IDEBus *bus = opaque;
+ IDEState *s;
+ int i;
+
+ trace_ide_ctrl_write(addr, val, bus);
+
+ /* Device0 and Device1 each have their own control register,
+ * but QEMU models it as just one register in the controller. */
+ if ((bus->cmd & IDE_CTRL_RESET) &&
+ !(val & IDE_CTRL_RESET)) {
+ /* SRST triggers on falling edge */
+ for (i = 0; i < 2; i++) {
s = &bus->ifs[i];
- if (s->drive_kind == IDE_CD)
- s->status = 0x00; /* NOTE: READY is _not_ set */
- else
- s->status = READY_STAT | SEEK_STAT;
- ide_set_signature(s);
+ s->status |= BUSY_STAT;
}
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ ide_bus_perform_srst, bus);
}
bus->cmd = val;
diff --git a/hw/ide/ioport.c b/hw/ide/ioport.c
index ab1f4e5..b613ff3 100644
--- a/hw/ide/ioport.c
+++ b/hw/ide/ioport.c
@@ -46,7 +46,7 @@ static const MemoryRegionPortio ide_portio_list[] = {
};
static const MemoryRegionPortio ide_portio2_list[] = {
- { 0, 1, 1, .read = ide_status_read, .write = ide_cmd_write },
+ { 0, 1, 1, .read = ide_status_read, .write = ide_ctrl_write },
PORTIO_END_OF_LIST(),
};
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 62a599a..b270a10 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -329,7 +329,7 @@ static void pmac_ide_write(void *opaque, hwaddr addr, uint64_t val,
case 0x8:
case 0x16:
if (size == 1) {
- ide_cmd_write(&d->bus, 0, val);
+ ide_ctrl_write(&d->bus, 0, val);
}
break;
case 0x20:
diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c
index 4bf6e3a..36e2f47 100644
--- a/hw/ide/mmio.c
+++ b/hw/ide/mmio.c
@@ -98,16 +98,16 @@ static uint64_t mmio_ide_status_read(void *opaque, hwaddr addr,
return ide_status_read(&s->bus, 0);
}
-static void mmio_ide_cmd_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
+static void mmio_ide_ctrl_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
{
MMIOState *s = opaque;
- ide_cmd_write(&s->bus, 0, val);
+ ide_ctrl_write(&s->bus, 0, val);
}
static const MemoryRegionOps mmio_ide_cs_ops = {
.read = mmio_ide_status_read,
- .write = mmio_ide_cmd_write,
+ .write = mmio_ide_ctrl_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index b50091b..84ba733 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -38,7 +38,7 @@
(IDE_RETRY_DMA | IDE_RETRY_PIO | \
IDE_RETRY_READ | IDE_RETRY_FLUSH)
-static uint64_t pci_ide_cmd_read(void *opaque, hwaddr addr, unsigned size)
+static uint64_t pci_ide_status_read(void *opaque, hwaddr addr, unsigned size)
{
IDEBus *bus = opaque;
@@ -48,20 +48,20 @@ static uint64_t pci_ide_cmd_read(void *opaque, hwaddr addr, unsigned size)
return ide_status_read(bus, addr + 2);
}
-static void pci_ide_cmd_write(void *opaque, hwaddr addr,
- uint64_t data, unsigned size)
+static void pci_ide_ctrl_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
{
IDEBus *bus = opaque;
if (addr != 2 || size != 1) {
return;
}
- ide_cmd_write(bus, addr + 2, data);
+ ide_ctrl_write(bus, addr + 2, data);
}
const MemoryRegionOps pci_ide_cmd_le_ops = {
- .read = pci_ide_cmd_read,
- .write = pci_ide_cmd_write,
+ .read = pci_ide_status_read,
+ .write = pci_ide_ctrl_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
diff --git a/hw/ide/trace-events b/hw/ide/trace-events
index 2e41626..6e35768 100644
--- a/hw/ide/trace-events
+++ b/hw/ide/trace-events
@@ -5,7 +5,7 @@
ide_ioport_read(uint32_t addr, const char *reg, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (%s); val 0x%02"PRIx32"; bus %p IDEState %p"
ide_ioport_write(uint32_t addr, const char *reg, uint32_t val, void *bus, void *s) "IDE PIO wr @ 0x%"PRIx32" (%s); val 0x%02"PRIx32"; bus %p IDEState %p"
ide_status_read(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (Alt Status); val 0x%02"PRIx32"; bus %p; IDEState %p"
-ide_cmd_write(uint32_t addr, uint32_t val, void *bus) "IDE PIO wr @ 0x%"PRIx32" (Device Control); val 0x%02"PRIx32"; bus %p"
+ide_ctrl_write(uint32_t addr, uint32_t val, void *bus) "IDE PIO wr @ 0x%"PRIx32" (Device Control); val 0x%02"PRIx32"; bus %p"
# Warning: verbose
ide_data_readw(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (Data: Word); val 0x%04"PRIx32"; bus %p; IDEState %p"
ide_data_writew(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO wr @ 0x%"PRIx32" (Data: Word); val 0x%04"PRIx32"; bus %p; IDEState %p"