X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fdev%2Fide_ctrl.cc;h=291ce1389910a66ad80d60c2a292e60b43167214;hb=23755eb43428845737aa514314f1bd0ace5d5372;hp=921ba1cd04d79e959f4cde9aeb1b24275d6a12d7;hpb=376cff64bd3ac5bafd8fa566674964fd4836790c;p=gem5.git diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc index 921ba1cd0..291ce1389 100644 --- a/src/dev/ide_ctrl.cc +++ b/src/dev/ide_ctrl.cc @@ -30,234 +30,157 @@ * Miguel Serrano */ -#include -#include #include -#include #include "base/trace.hh" #include "cpu/intr_control.hh" +#include "debug/IdeCtrl.hh" #include "dev/ide_ctrl.hh" #include "dev/ide_disk.hh" -#include "dev/pciconfigall.hh" -#include "dev/pcireg.h" -#include "dev/platform.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" -#include "sim/builder.hh" -#include "sim/sim_object.hh" +#include "params/IdeController.hh" #include "sim/byteswap.hh" using namespace std; -//// -// Initialization and destruction -//// - -IdeController::IdeController(Params *p) - : PciDev(p) +// Bus master IDE registers +enum BMIRegOffset { + BMICommand = 0x0, + BMIStatus = 0x2, + BMIDescTablePtr = 0x4 +}; + +// PCI config space registers +enum ConfRegOffset { + PrimaryTiming = 0x40, + SecondaryTiming = 0x42, + DeviceTiming = 0x44, + UDMAControl = 0x48, + UDMATiming = 0x4A, + IDEConfig = 0x54 +}; + +static const uint16_t timeRegWithDecodeEn = 0x8000; + +IdeController::Channel::Channel( + string newName, Addr _cmdSize, Addr _ctrlSize) : + _name(newName), + cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize), + master(NULL), slave(NULL), selected(NULL) { - // initialize the PIO interface addresses - pri_cmd_addr = 0; - pri_cmd_size = BARSize[0]; - - pri_ctrl_addr = 0; - pri_ctrl_size = BARSize[1]; - - sec_cmd_addr = 0; - sec_cmd_size = BARSize[2]; - - sec_ctrl_addr = 0; - sec_ctrl_size = BARSize[3]; - - // initialize the bus master interface (BMI) address to be configured - // via PCI - bmi_addr = 0; - bmi_size = BARSize[4]; - - // zero out all of the registers - memset(bmi_regs.data, 0, sizeof(bmi_regs)); - memset(config_regs.data, 0, sizeof(config_regs.data)); - - // setup initial values - // enable both channels - config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN); - config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN); - bmi_regs.bmis0 = DMA1CAP | DMA0CAP; - bmi_regs.bmis1 = DMA1CAP | DMA0CAP; - - // reset all internal variables - io_enabled = false; - bm_enabled = false; - memset(cmd_in_progress, 0, sizeof(cmd_in_progress)); - - // setup the disks attached to controller - memset(disks, 0, sizeof(disks)); - dev[0] = 0; - dev[1] = 0; - - if (params()->disks.size() > 3) - panic("IDE controllers support a maximum of 4 devices attached!\n"); - - for (int i = 0; i < params()->disks.size(); i++) { - disks[i] = params()->disks[i]; - disks[i]->setController(this); - } + memset(&bmiRegs, 0, sizeof(bmiRegs)); + bmiRegs.status.dmaCap0 = 1; + bmiRegs.status.dmaCap1 = 1; } -IdeController::~IdeController() +IdeController::Channel::~Channel() { - for (int i = 0; i < 4; i++) - if (disks[i]) - delete disks[i]; } -//// -// Utility functions -/// - -void -IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, - IdeRegType ®_type) +IdeController::IdeController(Params *p) + : PciDev(p), primary(name() + ".primary", BARSize[0], BARSize[1]), + secondary(name() + ".secondary", BARSize[2], BARSize[3]), + bmiAddr(0), bmiSize(BARSize[4]), + primaryTiming(htole(timeRegWithDecodeEn)), + secondaryTiming(htole(timeRegWithDecodeEn)), + deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0), + ioEnabled(false), bmEnabled(false), + ioShift(p->io_shift), ctrlOffset(p->ctrl_offset) { - offset = addr; - - if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) { - offset -= pri_cmd_addr; - reg_type = COMMAND_BLOCK; - channel = PRIMARY; - } else if (addr >= pri_ctrl_addr && - addr < (pri_ctrl_addr + pri_ctrl_size)) { - offset -= pri_ctrl_addr; - reg_type = CONTROL_BLOCK; - channel = PRIMARY; - } else if (addr >= sec_cmd_addr && - addr < (sec_cmd_addr + sec_cmd_size)) { - offset -= sec_cmd_addr; - reg_type = COMMAND_BLOCK; - channel = SECONDARY; - } else if (addr >= sec_ctrl_addr && - addr < (sec_ctrl_addr + sec_ctrl_size)) { - offset -= sec_ctrl_addr; - reg_type = CONTROL_BLOCK; - channel = SECONDARY; - } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) { - offset -= bmi_addr; - reg_type = BMI_BLOCK; - channel = (offset < BMIC1) ? PRIMARY : SECONDARY; - } else { - panic("IDE controller access to invalid address: %#x\n", addr); - } -} + if (params()->disks.size() > 3) + panic("IDE controllers support a maximum of 4 devices attached!\n"); -int -IdeController::getDisk(IdeChannel channel) -{ - int disk = 0; - uint8_t *devBit = &dev[0]; + // Assign the disks to channels + int numDisks = params()->disks.size(); + if (numDisks > 0) + primary.master = params()->disks[0]; + if (numDisks > 1) + primary.slave = params()->disks[1]; + if (numDisks > 2) + secondary.master = params()->disks[2]; + if (numDisks > 3) + secondary.slave = params()->disks[3]; - if (channel == SECONDARY) { - disk += 2; - devBit = &dev[1]; + for (int i = 0; i < params()->disks.size(); i++) { + params()->disks[i]->setController(this); } + primary.select(false); + secondary.select(false); - disk += *devBit; - - assert(*devBit == 0 || *devBit == 1); - - return disk; -} - -int -IdeController::getDisk(IdeDisk *diskPtr) -{ - for (int i = 0; i < 4; i++) { - if ((long)diskPtr == (long)disks[i]) - return i; + 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]; + } + 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]; } - return -1; + + ioEnabled = (config.command & htole(PCI_CMD_IOSE)); + bmEnabled = (config.command & htole(PCI_CMD_BME)); } bool IdeController::isDiskSelected(IdeDisk *diskPtr) { - for (int i = 0; i < 4; i++) { - if ((long)diskPtr == (long)disks[i]) { - // is disk is on primary or secondary channel - int channel = i/2; - // is disk the master or slave - int devID = i%2; - - return (dev[channel] == devID); - } - } - panic("Unable to find disk by pointer!!\n"); + return (primary.selected == diskPtr || secondary.selected == diskPtr); } -//// -// Command completion -//// +void +IdeController::intrPost() +{ + primary.bmiRegs.status.intStatus = 1; + PciDev::intrPost(); +} void IdeController::setDmaComplete(IdeDisk *disk) { - int diskNum = getDisk(disk); - - if (diskNum < 0) - panic("Unable to find disk based on pointer %#x\n", disk); - - if (diskNum < 2) { - // clear the start/stop bit in the command register - bmi_regs.bmic0 &= ~SSBM; - // clear the bus master active bit in the status register - bmi_regs.bmis0 &= ~BMIDEA; - // set the interrupt bit - bmi_regs.bmis0 |= IDEINTS; + Channel *channel; + if (disk == primary.master || disk == primary.slave) { + channel = &primary; + } else if (disk == secondary.master || disk == secondary.slave) { + channel = &secondary; } else { - // clear the start/stop bit in the command register - bmi_regs.bmic1 &= ~SSBM; - // clear the bus master active bit in the status register - bmi_regs.bmis1 &= ~BMIDEA; - // set the interrupt bit - bmi_regs.bmis1 |= IDEINTS; + panic("Unable to find disk based on pointer %#x\n", disk); } -} - -//// -// Read and write handling -//// + channel->bmiRegs.command.startStop = 0; + channel->bmiRegs.status.active = 0; + channel->bmiRegs.status.intStatus = 1; +} Tick IdeController::readConfig(PacketPtr pkt) { int offset = pkt->getAddr() & PCI_CONFIG_SIZE; - if (offset < PCI_DEVICE_SPECIFIC) - return PciDev::readConfig(pkt); - assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END); + if (offset < PCI_DEVICE_SPECIFIC) { + return PciDev::readConfig(pkt); + } pkt->allocate(); switch (pkt->getSize()) { case sizeof(uint8_t): switch (offset) { - case IDE_CTRL_CONF_DEV_TIMING: - pkt->set(config_regs.sidetim); + case DeviceTiming: + pkt->set(deviceTiming); break; - case IDE_CTRL_CONF_UDMA_CNTRL: - pkt->set(config_regs.udmactl); + case UDMAControl: + pkt->set(udmaControl); break; - case IDE_CTRL_CONF_PRIM_TIMING+1: - pkt->set(htole(config_regs.idetim0) >> 8); + case PrimaryTiming + 1: + pkt->set(bits(htole(primaryTiming), 15, 8)); break; - case IDE_CTRL_CONF_SEC_TIMING+1: - pkt->set(htole(config_regs.idetim1) >> 8); + case SecondaryTiming + 1: + pkt->set(bits(htole(secondaryTiming), 15, 8)); break; - case IDE_CTRL_CONF_IDE_CONFIG: - pkt->set(htole(config_regs.ideconfig) & 0xFF); + case IDEConfig: + pkt->set(bits(htole(ideConfig), 7, 0)); break; - case IDE_CTRL_CONF_IDE_CONFIG+1: - pkt->set(htole(config_regs.ideconfig) >> 8); + case IDEConfig + 1: + pkt->set(bits(htole(ideConfig), 15, 8)); break; default: panic("Invalid PCI configuration read for size 1 at offset: %#x!\n", @@ -268,17 +191,17 @@ IdeController::readConfig(PacketPtr pkt) break; case sizeof(uint16_t): switch (offset) { - case IDE_CTRL_CONF_PRIM_TIMING: - pkt->set(config_regs.idetim0); + case PrimaryTiming: + pkt->set(primaryTiming); break; - case IDE_CTRL_CONF_SEC_TIMING: - pkt->set(config_regs.idetim1); + case SecondaryTiming: + pkt->set(secondaryTiming); break; - case IDE_CTRL_CONF_UDMA_TIMING: - pkt->set(config_regs.udmatim); + case UDMATiming: + pkt->set(udmaTiming); break; - case IDE_CTRL_CONF_IDE_CONFIG: - pkt->set(config_regs.ideconfig); + case IDEConfig: + pkt->set(ideConfig); break; default: panic("Invalid PCI configuration read for size 2 offset: %#x!\n", @@ -288,16 +211,18 @@ IdeController::readConfig(PacketPtr pkt) (uint32_t)pkt->get()); break; case sizeof(uint32_t): - panic("No 32bit reads implemented for this device."); + if (offset == IDEConfig) + pkt->set(ideConfig); + else + panic("No 32bit reads implemented for this device."); DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, (uint32_t)pkt->get()); break; default: panic("invalid access size(?) for PCI configspace!\n"); } - pkt->result = Packet::Success; + pkt->makeAtomicResponse(); return configDelay; - } @@ -308,59 +233,60 @@ IdeController::writeConfig(PacketPtr pkt) if (offset < PCI_DEVICE_SPECIFIC) { PciDev::writeConfig(pkt); } else { - assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END); - switch (pkt->getSize()) { case sizeof(uint8_t): switch (offset) { - case IDE_CTRL_CONF_DEV_TIMING: - config_regs.sidetim = pkt->get(); + case DeviceTiming: + deviceTiming = pkt->get(); break; - case IDE_CTRL_CONF_UDMA_CNTRL: - config_regs.udmactl = pkt->get(); + case UDMAControl: + udmaControl = pkt->get(); break; - case IDE_CTRL_CONF_IDE_CONFIG: - config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | - (pkt->get()); + case IDEConfig: + replaceBits(ideConfig, 7, 0, pkt->get()); break; - case IDE_CTRL_CONF_IDE_CONFIG+1: - config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) | - pkt->get() << 8; + case IDEConfig + 1: + replaceBits(ideConfig, 15, 8, pkt->get()); break; default: - panic("Invalid PCI configuration write for size 1 offset: %#x!\n", - offset); + panic("Invalid PCI configuration write " + "for size 1 offset: %#x!\n", offset); } DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n", offset, (uint32_t)pkt->get()); break; case sizeof(uint16_t): switch (offset) { - case IDE_CTRL_CONF_PRIM_TIMING: - config_regs.idetim0 = pkt->get(); + case PrimaryTiming: + primaryTiming = pkt->get(); break; - case IDE_CTRL_CONF_SEC_TIMING: - config_regs.idetim1 = pkt->get(); + case SecondaryTiming: + secondaryTiming = pkt->get(); break; - case IDE_CTRL_CONF_UDMA_TIMING: - config_regs.udmatim = pkt->get(); + case UDMATiming: + udmaTiming = pkt->get(); break; - case IDE_CTRL_CONF_IDE_CONFIG: - config_regs.ideconfig = pkt->get(); + case IDEConfig: + ideConfig = pkt->get(); break; default: - panic("Invalid PCI configuration write for size 2 offset: %#x!\n", + panic("Invalid PCI configuration write " + "for size 2 offset: %#x!\n", offset); } DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", offset, (uint32_t)pkt->get()); break; case sizeof(uint32_t): - panic("Write of unimplemented PCI config. register: %x\n", offset); + if (offset == IDEConfig) + ideConfig = pkt->get(); + else + panic("Write of unimplemented PCI config. register: %x\n", offset); break; default: panic("invalid access size(?) for PCI configspace!\n"); } + pkt->makeAtomicResponse(); } /* Trap command register writes and enable IO/BM as appropriate as well as @@ -368,318 +294,228 @@ IdeController::writeConfig(PacketPtr pkt) switch(offset) { case PCI0_BASE_ADDR0: if (BARAddrs[0] != 0) - pri_cmd_addr = BARAddrs[0]; + primary.cmdAddr = BARAddrs[0]; break; case PCI0_BASE_ADDR1: if (BARAddrs[1] != 0) - pri_ctrl_addr = BARAddrs[1]; + primary.ctrlAddr = BARAddrs[1]; break; case PCI0_BASE_ADDR2: if (BARAddrs[2] != 0) - sec_cmd_addr = BARAddrs[2]; + secondary.cmdAddr = BARAddrs[2]; break; case PCI0_BASE_ADDR3: if (BARAddrs[3] != 0) - sec_ctrl_addr = BARAddrs[3]; + secondary.ctrlAddr = BARAddrs[3]; break; case PCI0_BASE_ADDR4: if (BARAddrs[4] != 0) - bmi_addr = BARAddrs[4]; + bmiAddr = BARAddrs[4]; break; case PCI_COMMAND: - if (letoh(config.command) & PCI_CMD_IOSE) - io_enabled = true; - else - io_enabled = false; - - if (letoh(config.command) & PCI_CMD_BME) - bm_enabled = true; - else - bm_enabled = false; + DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command); + ioEnabled = (config.command & htole(PCI_CMD_IOSE)); + bmEnabled = (config.command & htole(PCI_CMD_BME)); break; } - pkt->result = Packet::Success; return configDelay; } - -Tick -IdeController::read(PacketPtr pkt) +void +IdeController::Channel::accessCommand(Addr offset, + int size, uint8_t *data, bool read) { - Addr offset; - IdeChannel channel; - IdeRegType reg_type; - int disk; + const Addr SelectOffset = 6; + const uint8_t SelectDevBit = 0x10; - pkt->allocate(); - if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4) - panic("Bad IDE read size: %d\n", pkt->getSize()); - - parseAddr(pkt->getAddr(), offset, channel, reg_type); - - if (!io_enabled) { - pkt->result = Packet::Success; - return pioDelay; - } + if (!read && offset == SelectOffset) + select(*data & SelectDevBit); - switch (reg_type) { - case BMI_BLOCK: - switch (pkt->getSize()) { - case sizeof(uint8_t): - pkt->set(bmi_regs.data[offset]); - break; - case sizeof(uint16_t): - pkt->set(*(uint16_t*)&bmi_regs.data[offset]); - break; - case sizeof(uint32_t): - pkt->set(*(uint32_t*)&bmi_regs.data[offset]); - break; - default: - panic("IDE read of BMI reg invalid size: %#x\n", pkt->getSize()); - } - break; - - case COMMAND_BLOCK: - case CONTROL_BLOCK: - disk = getDisk(channel); - - if (disks[disk] == NULL) { - pkt->set(0); - break; - } - - switch (offset) { - case DATA_OFFSET: - switch (pkt->getSize()) { - case sizeof(uint16_t): - disks[disk]->read(offset, reg_type, pkt->getPtr()); - break; - - case sizeof(uint32_t): - disks[disk]->read(offset, reg_type, pkt->getPtr()); - disks[disk]->read(offset, reg_type, - pkt->getPtr() + sizeof(uint16_t)); - break; - - default: - panic("IDE read of data reg invalid size: %#x\n", pkt->getSize()); - } - break; - default: - if (pkt->getSize() == sizeof(uint8_t)) { - disks[disk]->read(offset, reg_type, pkt->getPtr()); - } else - panic("IDE read of command reg of invalid size: %#x\n", pkt->getSize()); - } - break; - default: - panic("IDE controller read of unknown register block type!\n"); + if (selected == NULL) { + assert(size == sizeof(uint8_t)); + *data = 0; + } else if (read) { + selected->readCommand(offset, size, data); + } else { + selected->writeCommand(offset, size, data); } - if (pkt->getSize() == 1) - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), (uint32_t)pkt->get()); - else if (pkt->getSize() == 2) - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), pkt->get()); - else - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), pkt->get()); - - pkt->result = Packet::Success; - return pioDelay; } -Tick -IdeController::write(PacketPtr pkt) +void +IdeController::Channel::accessControl(Addr offset, + int size, uint8_t *data, bool read) { - Addr offset; - IdeChannel channel; - IdeRegType reg_type; - int disk; - uint8_t oldVal, newVal; - - parseAddr(pkt->getAddr(), offset, channel, reg_type); - - if (!io_enabled) { - pkt->result = Packet::Success; - DPRINTF(IdeCtrl, "io not enabled\n"); - return pioDelay; + if (selected == NULL) { + assert(size == sizeof(uint8_t)); + *data = 0; + } else if (read) { + selected->readControl(offset, size, data); + } else { + selected->writeControl(offset, size, data); } +} - switch (reg_type) { - case BMI_BLOCK: - if (!bm_enabled) { - pkt->result = Packet::Success; - return pioDelay; - } - +void +IdeController::Channel::accessBMI(Addr offset, + int size, uint8_t *data, bool read) +{ + assert(offset + size <= sizeof(BMIRegs)); + if (read) { + memcpy(data, (uint8_t *)&bmiRegs + offset, size); + } else { switch (offset) { - // Bus master IDE command register - case BMIC1: - case BMIC0: - if (pkt->getSize() != sizeof(uint8_t)) - panic("Invalid BMIC write size: %x\n", pkt->getSize()); - - // select the current disk based on DEV bit - disk = getDisk(channel); - - oldVal = bmi_regs.chan[channel].bmic; - newVal = pkt->get(); - - // if a DMA transfer is in progress, R/W control cannot change - if (oldVal & SSBM) { - if ((oldVal & RWCON) ^ (newVal & RWCON)) { - (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON; - } - } - - // see if the start/stop bit is being changed - if ((oldVal & SSBM) ^ (newVal & SSBM)) { - if (oldVal & SSBM) { - // stopping DMA transfer - DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); + case BMICommand: + { + if (size != sizeof(uint8_t)) + panic("Invalid BMIC write size: %x\n", size); - // clear the BMIDEA bit - bmi_regs.chan[channel].bmis = - bmi_regs.chan[channel].bmis & ~BMIDEA; + BMICommandReg oldVal = bmiRegs.command; + BMICommandReg newVal = *data; - if (disks[disk] == NULL) - panic("DMA stop for disk %d which does not exist\n", - disk); + // if a DMA transfer is in progress, R/W control cannot change + if (oldVal.startStop && oldVal.rw != newVal.rw) + oldVal.rw = newVal.rw; - // inform the disk of the DMA transfer abort - disks[disk]->abortDma(); - } else { - // starting DMA transfer - DPRINTF(IdeCtrl, "Starting DMA transfer\n"); + if (oldVal.startStop != newVal.startStop) { + if (selected == NULL) + panic("DMA start for disk which does not exist\n"); - // set the BMIDEA bit - bmi_regs.chan[channel].bmis = - bmi_regs.chan[channel].bmis | BMIDEA; + if (oldVal.startStop) { + DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); + bmiRegs.status.active = 0; - if (disks[disk] == NULL) - panic("DMA start for disk %d which does not exist\n", - disk); + selected->abortDma(); + } else { + DPRINTF(IdeCtrl, "Starting DMA transfer\n"); + bmiRegs.status.active = 1; - // inform the disk of the DMA transfer start - disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp)); + selected->startDma(letoh(bmiRegs.bmidtp)); + } } - } - - // update the register value - bmi_regs.chan[channel].bmic = newVal; - break; - - // Bus master IDE status register - case BMIS0: - case BMIS1: - if (pkt->getSize() != sizeof(uint8_t)) - panic("Invalid BMIS write size: %x\n", pkt->getSize()); - oldVal = bmi_regs.chan[channel].bmis; - newVal = pkt->get(); - - // the BMIDEA bit is RO - newVal |= (oldVal & BMIDEA); - - // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each - if ((oldVal & IDEINTS) && (newVal & IDEINTS)) - newVal &= ~IDEINTS; // clear the interrupt? - else - (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS; - - if ((oldVal & IDEDMAE) && (newVal & IDEDMAE)) - newVal &= ~IDEDMAE; - else - (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE; - - bmi_regs.chan[channel].bmis = newVal; + bmiRegs.command = newVal; + } break; - - // Bus master IDE descriptor table pointer register - case BMIDTP0: - case BMIDTP1: + case BMIStatus: { - if (pkt->getSize() != sizeof(uint32_t)) - panic("Invalid BMIDTP write size: %x\n", pkt->getSize()); - - bmi_regs.chan[channel].bmidtp = htole(pkt->get() & ~0x3); + if (size != sizeof(uint8_t)) + panic("Invalid BMIS write size: %x\n", size); + + BMIStatusReg oldVal = bmiRegs.status; + BMIStatusReg newVal = *data; + + // the BMIDEA bit is read only + newVal.active = oldVal.active; + + // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each + if (oldVal.intStatus && newVal.intStatus) + newVal.intStatus = 0; // clear the interrupt? + else + newVal.intStatus = oldVal.intStatus; + if (oldVal.dmaError && newVal.dmaError) + newVal.dmaError = 0; + else + newVal.dmaError = oldVal.dmaError; + + bmiRegs.status = newVal; } break; - + case BMIDescTablePtr: + if (size != sizeof(uint32_t)) + panic("Invalid BMIDTP write size: %x\n", size); + bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3); + break; default: - if (pkt->getSize() != sizeof(uint8_t) && - pkt->getSize() != sizeof(uint16_t) && - pkt->getSize() != sizeof(uint32_t)) - panic("IDE controller write of invalid write size: %x\n", - pkt->getSize()); - - // do a default copy of data into the registers - memcpy(&bmi_regs.data[offset], pkt->getPtr(), pkt->getSize()); - } - break; - case COMMAND_BLOCK: - if (offset == IDE_SELECT_OFFSET) { - uint8_t *devBit = &dev[channel]; - *devBit = (letoh(pkt->get()) & IDE_SELECT_DEV_BIT) ? 1 : 0; + if (size != sizeof(uint8_t) && size != sizeof(uint16_t) && + size != sizeof(uint32_t)) + panic("IDE controller write of invalid write size: %x\n", size); + memcpy((uint8_t *)&bmiRegs + offset, data, size); } - // fall-through ok! - case CONTROL_BLOCK: - disk = getDisk(channel); + } +} - if (disks[disk] == NULL) - break; +void +IdeController::dispatchAccess(PacketPtr pkt, bool read) +{ + pkt->allocate(); + if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4) + panic("Bad IDE read size: %d\n", pkt->getSize()); - switch (offset) { - case DATA_OFFSET: - switch (pkt->getSize()) { - case sizeof(uint16_t): - disks[disk]->write(offset, reg_type, pkt->getPtr()); - break; + if (!ioEnabled) { + pkt->makeAtomicResponse(); + DPRINTF(IdeCtrl, "io not enabled\n"); + return; + } - case sizeof(uint32_t): - disks[disk]->write(offset, reg_type, pkt->getPtr()); - disks[disk]->write(offset, reg_type, pkt->getPtr() + - sizeof(uint16_t)); - break; - default: - panic("IDE write of data reg invalid size: %#x\n", pkt->getSize()); - } - break; - default: - if (pkt->getSize() == sizeof(uint8_t)) { - disks[disk]->write(offset, reg_type, pkt->getPtr()); - } else - panic("IDE write of command reg of invalid size: %#x\n", pkt->getSize()); + Addr addr = pkt->getAddr(); + int size = pkt->getSize(); + uint8_t *dataPtr = pkt->getPtr(); + + if (addr >= primary.cmdAddr && + addr < (primary.cmdAddr + primary.cmdSize)) { + addr -= primary.cmdAddr; + // linux may have shifted the address by ioShift, + // here we shift it back, similarly for ctrlOffset. + addr >>= ioShift; + primary.accessCommand(addr, size, dataPtr, read); + } else if (addr >= primary.ctrlAddr && + addr < (primary.ctrlAddr + primary.ctrlSize)) { + addr -= primary.ctrlAddr; + addr += ctrlOffset; + primary.accessControl(addr, size, dataPtr, read); + } else if (addr >= secondary.cmdAddr && + addr < (secondary.cmdAddr + secondary.cmdSize)) { + addr -= secondary.cmdAddr; + secondary.accessCommand(addr, size, dataPtr, read); + } else if (addr >= secondary.ctrlAddr && + addr < (secondary.ctrlAddr + secondary.ctrlSize)) { + addr -= secondary.ctrlAddr; + secondary.accessControl(addr, size, dataPtr, read); + } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) { + if (!read && !bmEnabled) + return; + addr -= bmiAddr; + if (addr < sizeof(Channel::BMIRegs)) { + primary.accessBMI(addr, size, dataPtr, read); + } else { + addr -= sizeof(Channel::BMIRegs); + secondary.accessBMI(addr, size, dataPtr, read); } - break; - default: - panic("IDE controller write of unknown register block type!\n"); + } else { + panic("IDE controller access to invalid address: %#x\n", addr); } + uint32_t data; if (pkt->getSize() == 1) - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), (uint32_t)pkt->get()); + data = pkt->get(); else if (pkt->getSize() == 2) - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), pkt->get()); + data = pkt->get(); else - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, pkt->getSize(), pkt->get()); + data = pkt->get(); + DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n", + read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data); + pkt->makeAtomicResponse(); +} - pkt->result = Packet::Success; +Tick +IdeController::read(PacketPtr pkt) +{ + dispatchAccess(pkt, true); return pioDelay; } -//// -// Serialization -//// +Tick +IdeController::write(PacketPtr pkt) +{ + dispatchAccess(pkt, false); + return pioDelay; +} void IdeController::serialize(std::ostream &os) @@ -687,30 +523,40 @@ IdeController::serialize(std::ostream &os) // Serialize the PciDev base class PciDev::serialize(os); - // Serialize register addresses and sizes - SERIALIZE_SCALAR(pri_cmd_addr); - SERIALIZE_SCALAR(pri_cmd_size); - SERIALIZE_SCALAR(pri_ctrl_addr); - SERIALIZE_SCALAR(pri_ctrl_size); - SERIALIZE_SCALAR(sec_cmd_addr); - SERIALIZE_SCALAR(sec_cmd_size); - SERIALIZE_SCALAR(sec_ctrl_addr); - SERIALIZE_SCALAR(sec_ctrl_size); - SERIALIZE_SCALAR(bmi_addr); - SERIALIZE_SCALAR(bmi_size); - - // Serialize registers - SERIALIZE_ARRAY(bmi_regs.data, - sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); - SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); - SERIALIZE_ARRAY(config_regs.data, - sizeof(config_regs.data) / sizeof(config_regs.data[0])); + // Serialize channels + primary.serialize("primary", os); + secondary.serialize("secondary", os); + + // Serialize config registers + SERIALIZE_SCALAR(primaryTiming); + SERIALIZE_SCALAR(secondaryTiming); + SERIALIZE_SCALAR(deviceTiming); + SERIALIZE_SCALAR(udmaControl); + SERIALIZE_SCALAR(udmaTiming); + SERIALIZE_SCALAR(ideConfig); // Serialize internal state - SERIALIZE_SCALAR(io_enabled); - SERIALIZE_SCALAR(bm_enabled); - SERIALIZE_ARRAY(cmd_in_progress, - sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); + SERIALIZE_SCALAR(ioEnabled); + SERIALIZE_SCALAR(bmEnabled); + SERIALIZE_SCALAR(bmiAddr); + SERIALIZE_SCALAR(bmiSize); +} + +void +IdeController::Channel::serialize(const std::string &base, std::ostream &os) +{ + paramOut(os, base + ".cmdAddr", cmdAddr); + paramOut(os, base + ".cmdSize", cmdSize); + paramOut(os, base + ".ctrlAddr", ctrlAddr); + paramOut(os, base + ".ctrlSize", ctrlSize); + uint8_t command = bmiRegs.command; + paramOut(os, base + ".bmiRegs.command", command); + paramOut(os, base + ".bmiRegs.reserved0", bmiRegs.reserved0); + uint8_t status = bmiRegs.status; + paramOut(os, base + ".bmiRegs.status", status); + paramOut(os, base + ".bmiRegs.reserved1", bmiRegs.reserved1); + paramOut(os, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp); + paramOut(os, base + ".selectBit", selectBit); } void @@ -719,84 +565,48 @@ IdeController::unserialize(Checkpoint *cp, const std::string §ion) // Unserialize the PciDev base class PciDev::unserialize(cp, section); - // Unserialize register addresses and sizes - UNSERIALIZE_SCALAR(pri_cmd_addr); - UNSERIALIZE_SCALAR(pri_cmd_size); - UNSERIALIZE_SCALAR(pri_ctrl_addr); - UNSERIALIZE_SCALAR(pri_ctrl_size); - UNSERIALIZE_SCALAR(sec_cmd_addr); - UNSERIALIZE_SCALAR(sec_cmd_size); - UNSERIALIZE_SCALAR(sec_ctrl_addr); - UNSERIALIZE_SCALAR(sec_ctrl_size); - UNSERIALIZE_SCALAR(bmi_addr); - UNSERIALIZE_SCALAR(bmi_size); - - // Unserialize registers - UNSERIALIZE_ARRAY(bmi_regs.data, - sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); - UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); - UNSERIALIZE_ARRAY(config_regs.data, - sizeof(config_regs.data) / sizeof(config_regs.data[0])); + // Unserialize channels + primary.unserialize("primary", cp, section); + secondary.unserialize("secondary", cp, section); + + // Unserialize config registers + UNSERIALIZE_SCALAR(primaryTiming); + UNSERIALIZE_SCALAR(secondaryTiming); + UNSERIALIZE_SCALAR(deviceTiming); + UNSERIALIZE_SCALAR(udmaControl); + UNSERIALIZE_SCALAR(udmaTiming); + UNSERIALIZE_SCALAR(ideConfig); // Unserialize internal state - UNSERIALIZE_SCALAR(io_enabled); - UNSERIALIZE_SCALAR(bm_enabled); - UNSERIALIZE_ARRAY(cmd_in_progress, - sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); + UNSERIALIZE_SCALAR(ioEnabled); + UNSERIALIZE_SCALAR(bmEnabled); + UNSERIALIZE_SCALAR(bmiAddr); + UNSERIALIZE_SCALAR(bmiSize); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController) - - SimObjectParam system; - SimObjectParam platform; - Param min_backoff_delay; - Param max_backoff_delay; - SimObjectParam configdata; - Param pci_bus; - Param pci_dev; - Param pci_func; - Param pio_latency; - Param config_latency; - SimObjectVectorParam disks; - -END_DECLARE_SIM_OBJECT_PARAMS(IdeController) - -BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController) - - INIT_PARAM(system, "System pointer"), - INIT_PARAM(platform, "Platform pointer"), - INIT_PARAM(min_backoff_delay, "Minimum delay after receving a nack packed"), - INIT_PARAM(max_backoff_delay, "Maximum delay after receving a nack packed"), - INIT_PARAM(configdata, "PCI Config data"), - INIT_PARAM(pci_bus, "PCI bus ID"), - INIT_PARAM(pci_dev, "PCI device number"), - INIT_PARAM(pci_func, "PCI function code"), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM(config_latency, "Number of cycles for a config read or write"), - INIT_PARAM(disks, "IDE disks attached to this controller") - -END_INIT_SIM_OBJECT_PARAMS(IdeController) - -CREATE_SIM_OBJECT(IdeController) +void +IdeController::Channel::unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion) { - IdeController::Params *params = new IdeController::Params; - params->name = getInstanceName(); - params->platform = platform; - params->system = system; - params->min_backoff_delay = min_backoff_delay; - params->max_backoff_delay = max_backoff_delay; - params->configData = configdata; - params->busNum = pci_bus; - params->deviceNum = pci_dev; - params->functionNum = pci_func; - params->pio_delay = pio_latency; - params->config_delay = config_latency; - params->disks = disks; - return new IdeController(params); + paramIn(cp, section, base + ".cmdAddr", cmdAddr); + paramIn(cp, section, base + ".cmdSize", cmdSize); + paramIn(cp, section, base + ".ctrlAddr", ctrlAddr); + paramIn(cp, section, base + ".ctrlSize", ctrlSize); + uint8_t command; + paramIn(cp, section, base +".bmiRegs.command", command); + bmiRegs.command = command; + paramIn(cp, section, base + ".bmiRegs.reserved0", bmiRegs.reserved0); + uint8_t status; + paramIn(cp, section, base + ".bmiRegs.status", status); + bmiRegs.status = status; + paramIn(cp, section, base + ".bmiRegs.reserved1", bmiRegs.reserved1); + paramIn(cp, section, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp); + paramIn(cp, section, base + ".selectBit", selectBit); + select(selectBit); } -REGISTER_SIM_OBJECT("IdeController", IdeController) - -#endif //DOXYGEN_SHOULD_SKIP_THIS +IdeController * +IdeControllerParams::create() +{ + return new IdeController(this); +}