diff options
Diffstat (limited to 'src/dev')
-rw-r--r-- | src/dev/ide_ctrl.cc | 35 | ||||
-rw-r--r-- | src/dev/ide_disk.cc | 69 | ||||
-rw-r--r-- | src/dev/ide_disk.hh | 17 |
3 files changed, 108 insertions, 13 deletions
diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc index df02bf5f5..bbc0e379d 100644 --- a/src/dev/ide_ctrl.cc +++ b/src/dev/ide_ctrl.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2005 The Regents of The University of Michigan * All rights reserved. * @@ -111,11 +123,11 @@ IdeController::IdeController(Params *p) if ((BARAddrs[0] & ~BAR_IO_MASK) && (!legacyIO[0] || ioShift)) { primary.cmdAddr = BARAddrs[0]; primary.cmdSize = BARSize[0]; - primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARAddrs[1]; + primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARSize[1]; } if ((BARAddrs[2] & ~BAR_IO_MASK) && (!legacyIO[2] || ioShift)) { secondary.cmdAddr = BARAddrs[2]; secondary.cmdSize = BARSize[2]; - secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARAddrs[3]; + secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARSize[3]; } ioEnabled = (config.command & htole(PCI_CMD_IOSE)); @@ -414,14 +426,21 @@ IdeController::Channel::accessBMI(Addr offset, newVal.active = oldVal.active; // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each - if (oldVal.intStatus && newVal.intStatus) + if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) { newVal.intStatus = 0; // clear the interrupt? - else - newVal.intStatus = oldVal.intStatus; - if (oldVal.dmaError && newVal.dmaError) + } else { + // Assigning two bitunion fields to each other does not + // work as intended, so we need to use this temporary variable + // to get around the bug. + uint8_t tmp = oldVal.intStatus; + newVal.intStatus = tmp; + } + if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) { newVal.dmaError = 0; - else - newVal.dmaError = oldVal.dmaError; + } else { + uint8_t tmp = oldVal.dmaError; + newVal.dmaError = tmp; + } bmiRegs.status = newVal; } diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc index bc7210d42..b910c8a6a 100644 --- a/src/dev/ide_disk.cc +++ b/src/dev/ide_disk.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2005 The Regents of The University of Michigan * All rights reserved. * @@ -143,6 +155,7 @@ IdeDisk::reset(int id) drqBytesLeft = 0; dmaRead = false; intrPending = false; + dmaAborted = false; // set the device state to idle dmaState = Dma_Idle; @@ -319,6 +332,12 @@ IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data) void IdeDisk::doDmaTransfer() { + if (dmaAborted) { + DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n"); + updateState(ACT_CMD_ERROR); + return; + } + if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", dmaState, devState); @@ -334,6 +353,11 @@ IdeDisk::doDmaTransfer() void IdeDisk::dmaPrdReadDone() { + if (dmaAborted) { + DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n"); + updateState(ACT_CMD_ERROR); + return; + } DPRINTF(IdeDisk, "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", @@ -396,6 +420,14 @@ IdeDisk::regStats() void IdeDisk::doDmaRead() { + if (dmaAborted) { + DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n"); + if (dmaReadCG) + delete dmaReadCG; + dmaReadCG = NULL; + updateState(ACT_CMD_ERROR); + return; + } if (!dmaReadCG) { // clear out the data buffer @@ -427,10 +459,8 @@ IdeDisk::doDmaRead() void IdeDisk::dmaReadDone() { - uint32_t bytesWritten = 0; - // write the data to the disk image for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); bytesWritten += SectorSize) { @@ -475,7 +505,14 @@ IdeDisk::doDmaDataWrite() void IdeDisk::doDmaWrite() { - DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n"); + if (dmaAborted) { + DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n"); + if (dmaWriteCG) + delete dmaWriteCG; + dmaWriteCG = NULL; + updateState(ACT_CMD_ERROR); + return; + } if (!dmaWriteCG) { // clear out the data buffer dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), @@ -980,7 +1017,10 @@ IdeDisk::updateState(DevAction_t action) break; case Transfer_Data_Dma: - if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { + if (action == ACT_CMD_ERROR) { + dmaAborted = true; + devState = Device_Dma_Abort; + } else if (action == ACT_DMA_DONE) { // clear the BSY bit setComplete(); // set the seek bit @@ -997,6 +1037,25 @@ IdeDisk::updateState(DevAction_t action) } break; + case Device_Dma_Abort: + if (action == ACT_CMD_ERROR) { + setComplete(); + status |= STATUS_SEEK_BIT; + ctrl->setDmaComplete(this); + dmaAborted = false; + dmaState = Dma_Idle; + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } else { + DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n"); + } + break; + default: panic("Unknown IDE device state: %#x\n", devState); } @@ -1074,6 +1133,7 @@ IdeDisk::serialize(ostream &os) SERIALIZE_SCALAR(curSector); SERIALIZE_SCALAR(dmaRead); SERIALIZE_SCALAR(intrPending); + SERIALIZE_SCALAR(dmaAborted); SERIALIZE_ENUM(devState); SERIALIZE_ENUM(dmaState); SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); @@ -1126,6 +1186,7 @@ IdeDisk::unserialize(Checkpoint *cp, const string §ion) UNSERIALIZE_SCALAR(curSector); UNSERIALIZE_SCALAR(dmaRead); UNSERIALIZE_SCALAR(intrPending); + UNSERIALIZE_SCALAR(dmaAborted); UNSERIALIZE_ENUM(devState); UNSERIALIZE_ENUM(dmaState); UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); diff --git a/src/dev/ide_disk.hh b/src/dev/ide_disk.hh index b29d13870..6ccca985e 100644 --- a/src/dev/ide_disk.hh +++ b/src/dev/ide_disk.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2013 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2005 The Regents of The University of Michigan * All rights reserved. * @@ -177,7 +189,8 @@ typedef enum DevState { // DMA protocol Prepare_Data_Dma, - Transfer_Data_Dma + Transfer_Data_Dma, + Device_Dma_Abort } DevState_t; typedef enum DmaState { @@ -236,6 +249,8 @@ class IdeDisk : public SimObject int devID; /** Interrupt pending */ bool intrPending; + /** DMA Aborted */ + bool dmaAborted; Stats::Scalar dmaReadFullPages; Stats::Scalar dmaReadBytes; |