Only issue responses if we aren;t already blocked
[gem5.git] / src / dev / ide_ctrl.cc
index eb03d5db8afc3556c320b854529cf54f34c0fbd4..8007fda5ec6de49a4c0a40b5fb546547b29e8810 100644 (file)
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andrew Schultz
+ *          Ali Saidi
+ *          Miguel Serrano
  */
 
 #include <cstddef>
@@ -223,177 +227,143 @@ IdeController::setDmaComplete(IdeDisk *disk)
 // Read and write handling
 ////
 
-void
-IdeController::readConfig(int offset, uint8_t *data)
+Tick
+IdeController::readConfig(Packet *pkt)
 {
-    if (offset < PCI_DEVICE_SPECIFIC) {
-        PciDev::readConfig(offset, data);
-    } else if (offset >= IDE_CTRL_CONF_START &&
-               (offset + 1) <= IDE_CTRL_CONF_END) {
+    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);
 
+    pkt->allocate();
+
+    switch (pkt->getSize()) {
+      case sizeof(uint8_t):
         switch (offset) {
           case IDE_CTRL_CONF_DEV_TIMING:
-            *data = config_regs.sidetim;
+            pkt->set<uint8_t>(config_regs.sidetim);
             break;
           case IDE_CTRL_CONF_UDMA_CNTRL:
-            *data = config_regs.udmactl;
+            pkt->set<uint8_t>(config_regs.udmactl);
             break;
           case IDE_CTRL_CONF_PRIM_TIMING+1:
-            *data = htole(config_regs.idetim0) >> 8;
+            pkt->set<uint8_t>(htole(config_regs.idetim0) >> 8);
             break;
           case IDE_CTRL_CONF_SEC_TIMING+1:
-            *data = htole(config_regs.idetim1) >> 8;
+            pkt->set<uint8_t>(htole(config_regs.idetim1) >> 8);
             break;
           case IDE_CTRL_CONF_IDE_CONFIG:
-            *data = htole(config_regs.ideconfig) & 0xFF;
+            pkt->set<uint8_t>(htole(config_regs.ideconfig) & 0xFF);
             break;
           case IDE_CTRL_CONF_IDE_CONFIG+1:
-            *data = htole(config_regs.ideconfig) >> 8;
+            pkt->set<uint8_t>(htole(config_regs.ideconfig) >> 8);
             break;
           default:
             panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
                     offset);
         }
-
-    } else {
-        panic("Read of unimplemented PCI config. register: %x\n", offset);
-    }
-    DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n",
-                offset, (uint32_t)*data);
-}
-
-void
-IdeController::readConfig(int offset, uint16_t *data)
-{
-    if (offset < PCI_DEVICE_SPECIFIC) {
-        PciDev::readConfig(offset, data);
-    } else if (offset >= IDE_CTRL_CONF_START &&
-               (offset + 2) <= IDE_CTRL_CONF_END) {
-
+        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
+                (uint32_t)pkt->get<uint8_t>());
+        break;
+      case sizeof(uint16_t):
         switch (offset) {
           case IDE_CTRL_CONF_PRIM_TIMING:
-            *data = config_regs.idetim0;
+            pkt->set<uint16_t>(config_regs.idetim0);
             break;
           case IDE_CTRL_CONF_SEC_TIMING:
-            *data = config_regs.idetim1;
+            pkt->set<uint16_t>(config_regs.idetim1);
             break;
           case IDE_CTRL_CONF_UDMA_TIMING:
-            *data = config_regs.udmatim;
+            pkt->set<uint16_t>(config_regs.udmatim);
             break;
           case IDE_CTRL_CONF_IDE_CONFIG:
-            *data = config_regs.ideconfig;
+            pkt->set<uint16_t>(config_regs.ideconfig);
             break;
           default:
             panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
                     offset);
         }
-
-    } else {
-        panic("Read of unimplemented PCI config. register: %x\n", offset);
+        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
+                (uint32_t)pkt->get<uint16_t>());
+        break;
+      case sizeof(uint32_t):
+        panic("No 32bit reads implemented for this device.");
+        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
+                (uint32_t)pkt->get<uint32_t>());
+        break;
+      default:
+        panic("invalid access size(?) for PCI configspace!\n");
     }
-    DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, *data);
-}
+    pkt->result = Packet::Success;
+    return configDelay;
 
-void
-IdeController::readConfig(int offset, uint32_t *data)
-{
-    if (offset < PCI_DEVICE_SPECIFIC) {
-        PciDev::readConfig(offset, data);
-    } else {
-        panic("Read of unimplemented PCI config. register: %x\n", offset);
-    }
-    DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, *data);
 }
-void
-IdeController::writeConfig(int offset, const uint8_t data)
-{
-    if (offset < PCI_DEVICE_SPECIFIC) {
-        PciDev::writeConfig(offset, data);
-    } else if (offset >= IDE_CTRL_CONF_START &&
-               (offset + 1) <= IDE_CTRL_CONF_END) {
 
-        switch (offset) {
-          case IDE_CTRL_CONF_DEV_TIMING:
-            config_regs.sidetim = data;
-            break;
-          case IDE_CTRL_CONF_UDMA_CNTRL:
-            config_regs.udmactl = data;
-            break;
-          case IDE_CTRL_CONF_IDE_CONFIG:
-            config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | (data);
-            break;
-          case IDE_CTRL_CONF_IDE_CONFIG+1:
-            config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) | data << 8;
-            break;
-          default:
-            panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
-                    offset);
-        }
 
-    } else {
-        panic("Read of unimplemented PCI config. register: %x\n", offset);
-    }
-    DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
-                offset, (uint32_t)data);
-}
-
-void
-IdeController::writeConfig(int offset, const uint16_t data)
+Tick
+IdeController::writeConfig(Packet *pkt)
 {
+    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
     if (offset < PCI_DEVICE_SPECIFIC) {
-        PciDev::writeConfig(offset, data);
-    } else if (offset >= IDE_CTRL_CONF_START &&
-               (offset + 2) <= IDE_CTRL_CONF_END) {
+        PciDev::writeConfig(pkt);
+    } else {
+        assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
 
-        switch (offset) {
-          case IDE_CTRL_CONF_PRIM_TIMING:
-            config_regs.idetim0 = data;
-            break;
-          case IDE_CTRL_CONF_SEC_TIMING:
-            config_regs.idetim1 = data;
+        switch (pkt->getSize()) {
+          case sizeof(uint8_t):
+            switch (offset) {
+              case IDE_CTRL_CONF_DEV_TIMING:
+                config_regs.sidetim = pkt->get<uint8_t>();
+                break;
+              case IDE_CTRL_CONF_UDMA_CNTRL:
+                config_regs.udmactl = pkt->get<uint8_t>();
+                break;
+              case IDE_CTRL_CONF_IDE_CONFIG:
+                config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) |
+                    (pkt->get<uint8_t>());
+                break;
+              case IDE_CTRL_CONF_IDE_CONFIG+1:
+                config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) |
+                    pkt->get<uint8_t>() << 8;
+                break;
+              default:
+                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<uint8_t>());
             break;
-          case IDE_CTRL_CONF_UDMA_TIMING:
-            config_regs.udmatim = data;
+          case sizeof(uint16_t):
+            switch (offset) {
+              case IDE_CTRL_CONF_PRIM_TIMING:
+                config_regs.idetim0 = pkt->get<uint16_t>();
+                break;
+              case IDE_CTRL_CONF_SEC_TIMING:
+                config_regs.idetim1 = pkt->get<uint16_t>();
+                break;
+              case IDE_CTRL_CONF_UDMA_TIMING:
+                config_regs.udmatim = pkt->get<uint16_t>();
+                break;
+              case IDE_CTRL_CONF_IDE_CONFIG:
+                config_regs.ideconfig = pkt->get<uint16_t>();
+                break;
+              default:
+                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<uint16_t>());
             break;
-          case IDE_CTRL_CONF_IDE_CONFIG:
-            config_regs.ideconfig = data;
+          case sizeof(uint32_t):
+            panic("Write of unimplemented PCI config. register: %x\n", offset);
             break;
           default:
-            panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
-                    offset);
+            panic("invalid access size(?) for PCI configspace!\n");
         }
-
-    } else {
-        panic("Write of unimplemented PCI config. register: %x\n", offset);
-    }
-    DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", offset, data);
-
-    /* Trap command register writes and enable IO/BM as appropriate. */
-    if (offset == 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;
-    }
-
-}
-
-void
-IdeController::writeConfig(int offset, const uint32_t data)
-{
-    if (offset < PCI_DEVICE_SPECIFIC) {
-        PciDev::writeConfig(offset, data);
-    } else {
-        panic("Read of unimplemented PCI config. register: %x\n", offset);
     }
 
-    DPRINTF(IdeCtrl, "PCI write offset: %#x size: 4 data: %#x\n", offset, data);
-
+    /* Trap command register writes and enable IO/BM as appropriate as well as
+     * BARs. */
     switch(offset) {
       case PCI0_BASE_ADDR0:
         if (BARAddrs[0] != 0)
@@ -419,9 +389,24 @@ IdeController::writeConfig(int offset, const uint32_t data)
         if (BARAddrs[4] != 0)
             bmi_addr = 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;
+        break;
     }
+    pkt->result = Packet::Success;
+    return configDelay;
 }
 
+
 Tick
 IdeController::read(Packet *pkt)
 {
@@ -430,7 +415,6 @@ IdeController::read(Packet *pkt)
     IdeRegType reg_type;
     int disk;
 
-    pkt->time += pioDelay;
     pkt->allocate();
     if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
          panic("Bad IDE read size: %d\n", pkt->getSize());
@@ -518,8 +502,6 @@ IdeController::write(Packet *pkt)
     int disk;
     uint8_t oldVal, newVal;
 
-    pkt->time += pioDelay;
-
     parseAddr(pkt->getAddr(), offset, channel, reg_type);
 
     if (!io_enabled) {
@@ -760,7 +742,6 @@ IdeController::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_SCALAR(bm_enabled);
     UNSERIALIZE_ARRAY(cmd_in_progress,
                       sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
-    pioPort->sendStatusChange(Port::RangeChange);
 }
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -769,12 +750,12 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
 
     SimObjectParam<System *> system;
     SimObjectParam<Platform *> platform;
-    SimObjectParam<PciConfigAll *> configspace;
     SimObjectParam<PciConfigData *> configdata;
     Param<uint32_t> pci_bus;
     Param<uint32_t> pci_dev;
     Param<uint32_t> pci_func;
     Param<Tick> pio_latency;
+    Param<Tick> config_latency;
     SimObjectVectorParam<IdeDisk *> disks;
 
 END_DECLARE_SIM_OBJECT_PARAMS(IdeController)
@@ -783,12 +764,12 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
 
     INIT_PARAM(system, "System pointer"),
     INIT_PARAM(platform, "Platform pointer"),
-    INIT_PARAM(configspace, "PCI Configspace"),
     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)
@@ -799,12 +780,12 @@ CREATE_SIM_OBJECT(IdeController)
     params->name = getInstanceName();
     params->platform = platform;
     params->system = system;
-    params->configSpace = configspace;
     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);
 }