diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-10-01 19:55:10 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-10-01 19:55:10 +0100 |
commit | b5ce42f5d138d7546f9faa2decbd6ee8702243a3 (patch) | |
tree | fb24528a9ff8c227609198d3b3a7164770e0c5a8 /hw | |
parent | 625581c2602b5b43e115b779a9a782478e6f92e7 (diff) | |
parent | 55adb3c45620c31f29978f209e2a44a08d34e2da (diff) |
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.c | 2 | ||||
-rw-r--r-- | hw/ide/core.c | 124 | ||||
-rw-r--r-- | hw/ide/ioport.c | 2 | ||||
-rw-r--r-- | hw/ide/macio.c | 2 | ||||
-rw-r--r-- | hw/ide/mmio.c | 8 | ||||
-rw-r--r-- | hw/ide/pci.c | 12 | ||||
-rw-r--r-- | hw/ide/trace-events | 2 |
7 files changed, 90 insertions, 62 deletions
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index ee1d47ff75..680304a24c 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 f76f7e5234..0e32abd779 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 ab1f4e5d9c..b613ff3bba 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 62a599a075..b270a10163 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 4bf6e3a8b7..36e2f4790a 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 b50091b615..84ba733548 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 2e4162629f..6e357685f9 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" |