ide_ctrl.cc revision 5772
16019Shines@cs.fsu.edu/*
212509Schuan.zhu@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
37189Sgblack@eecs.umich.edu * All rights reserved.
47189Sgblack@eecs.umich.edu *
57189Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67189Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77189Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87189Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97189Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107189Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117189Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127189Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137189Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
146019Shines@cs.fsu.edu * this software without specific prior written permission.
156019Shines@cs.fsu.edu *
166019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276019Shines@cs.fsu.edu *
286019Shines@cs.fsu.edu * Authors: Andrew Schultz
296019Shines@cs.fsu.edu *          Ali Saidi
306019Shines@cs.fsu.edu *          Miguel Serrano
316019Shines@cs.fsu.edu */
326019Shines@cs.fsu.edu
336019Shines@cs.fsu.edu#include <string>
346019Shines@cs.fsu.edu
356019Shines@cs.fsu.edu#include "base/trace.hh"
366019Shines@cs.fsu.edu#include "cpu/intr_control.hh"
376019Shines@cs.fsu.edu#include "dev/ide_ctrl.hh"
386019Shines@cs.fsu.edu#include "dev/ide_disk.hh"
396019Shines@cs.fsu.edu#include "mem/packet.hh"
406019Shines@cs.fsu.edu#include "mem/packet_access.hh"
416735Sgblack@eecs.umich.edu#include "params/IdeController.hh"
426735Sgblack@eecs.umich.edu#include "sim/byteswap.hh"
4310037SARM gem5 Developers
4410037SARM gem5 Developersusing namespace std;
456019Shines@cs.fsu.edu
466019Shines@cs.fsu.edu// Bus master IDE registers
476019Shines@cs.fsu.eduenum BMIRegOffset {
486019Shines@cs.fsu.edu    BMICommand = 0x0,
496019Shines@cs.fsu.edu    BMIStatus = 0x2,
507362Sgblack@eecs.umich.edu    BMIDescTablePtr = 0x4
5110037SARM gem5 Developers};
526735Sgblack@eecs.umich.edu
5312334Sgabeblack@google.com// PCI config space registers
546019Shines@cs.fsu.eduenum ConfRegOffset {
558782Sgblack@eecs.umich.edu    PrimaryTiming = 0x40,
566019Shines@cs.fsu.edu    SecondaryTiming = 0x42,
576019Shines@cs.fsu.edu    DeviceTiming = 0x44,
586019Shines@cs.fsu.edu    UDMAControl = 0x48,
596019Shines@cs.fsu.edu    UDMATiming = 0x4A,
606019Shines@cs.fsu.edu    IDEConfig = 0x54
6111294Sandreas.hansson@arm.com};
626019Shines@cs.fsu.edu
637362Sgblack@eecs.umich.edustatic const uint16_t timeRegWithDecodeEn = 0x8000;
646019Shines@cs.fsu.edu
656019Shines@cs.fsu.eduIdeController::Channel::Channel(
6610037SARM gem5 Developers        string newName, Addr _cmdSize, Addr _ctrlSize) :
6710037SARM gem5 Developers    _name(newName),
6810037SARM gem5 Developers    cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize),
6910037SARM gem5 Developers    master(NULL), slave(NULL), selected(NULL)
7010037SARM gem5 Developers{
7110037SARM gem5 Developers    memset(&bmiRegs, 0, sizeof(bmiRegs));
7210037SARM gem5 Developers    bmiRegs.status.dmaCap0 = 1;
7310037SARM gem5 Developers    bmiRegs.status.dmaCap1 = 1;
7410037SARM gem5 Developers}
7510037SARM gem5 Developers
7612402Sgiacomo.travaglini@arm.comIdeController::Channel::~Channel()
7712402Sgiacomo.travaglini@arm.com{
786735Sgblack@eecs.umich.edu    delete master;
7910037SARM gem5 Developers    delete slave;
806735Sgblack@eecs.umich.edu}
816019Shines@cs.fsu.edu
8210037SARM gem5 DevelopersIdeController::IdeController(Params *p)
8310037SARM gem5 Developers    : PciDev(p), primary(name() + ".primary", BARSize[0], BARSize[1]),
8410037SARM gem5 Developers    secondary(name() + ".secondary", BARSize[2], BARSize[3]),
8510037SARM gem5 Developers    bmiAddr(0), bmiSize(BARSize[4]),
8610037SARM gem5 Developers    primaryTiming(htole(timeRegWithDecodeEn)),
877362Sgblack@eecs.umich.edu    secondaryTiming(htole(timeRegWithDecodeEn)),
8810037SARM gem5 Developers    deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
8910037SARM gem5 Developers    ioEnabled(false), bmEnabled(false)
9010037SARM gem5 Developers{
9110037SARM gem5 Developers    if (params()->disks.size() > 3)
9210037SARM gem5 Developers        panic("IDE controllers support a maximum of 4 devices attached!\n");
9310037SARM gem5 Developers
9410037SARM gem5 Developers    // Assign the disks to channels
9510037SARM gem5 Developers    int numDisks = params()->disks.size();
9610037SARM gem5 Developers    if (numDisks > 0)
9710037SARM gem5 Developers        primary.master = params()->disks[0];
9810037SARM gem5 Developers    if (numDisks > 1)
9910037SARM gem5 Developers        primary.slave = params()->disks[1];
10010037SARM gem5 Developers    if (numDisks > 2)
10110037SARM gem5 Developers        secondary.master = params()->disks[2];
10210037SARM gem5 Developers    if (numDisks > 3)
1037611SGene.Wu@arm.com        secondary.slave = params()->disks[3];
10410037SARM gem5 Developers
10510037SARM gem5 Developers    for (int i = 0; i < params()->disks.size(); i++) {
10610037SARM gem5 Developers        params()->disks[i]->setController(this);
10710037SARM gem5 Developers    }
10810037SARM gem5 Developers    primary.select(false);
10910037SARM gem5 Developers    secondary.select(false);
11010037SARM gem5 Developers}
11110037SARM gem5 Developers
11210037SARM gem5 Developersbool
11310037SARM gem5 DevelopersIdeController::isDiskSelected(IdeDisk *diskPtr)
11410037SARM gem5 Developers{
11510037SARM gem5 Developers    return (primary.selected == diskPtr || secondary.selected == diskPtr);
11610037SARM gem5 Developers}
11710037SARM gem5 Developers
11810037SARM gem5 Developersvoid
11910037SARM gem5 DevelopersIdeController::intrPost()
12010037SARM gem5 Developers{
12110037SARM gem5 Developers    primary.bmiRegs.status.intStatus = 1;
12210037SARM gem5 Developers    PciDev::intrPost();
12310037SARM gem5 Developers}
12410037SARM gem5 Developers
12510037SARM gem5 Developersvoid
12610037SARM gem5 DevelopersIdeController::setDmaComplete(IdeDisk *disk)
12710037SARM gem5 Developers{
12810037SARM gem5 Developers    Channel *channel;
12910037SARM gem5 Developers    if (disk == primary.master || disk == primary.slave) {
13010037SARM gem5 Developers        channel = &primary;
13110037SARM gem5 Developers    } else if (disk == secondary.master || disk == secondary.slave) {
13210037SARM gem5 Developers        channel = &secondary;
13310037SARM gem5 Developers    } else {
13410037SARM gem5 Developers        panic("Unable to find disk based on pointer %#x\n", disk);
13510037SARM gem5 Developers    }
13610037SARM gem5 Developers
13710037SARM gem5 Developers    channel->bmiRegs.command.startStop = 0;
13810037SARM gem5 Developers    channel->bmiRegs.status.active = 0;
13910037SARM gem5 Developers    channel->bmiRegs.status.intStatus = 1;
14010037SARM gem5 Developers}
1417362Sgblack@eecs.umich.edu
1427362Sgblack@eecs.umich.eduTick
1436735Sgblack@eecs.umich.eduIdeController::readConfig(PacketPtr pkt)
1446735Sgblack@eecs.umich.edu{
1456735Sgblack@eecs.umich.edu    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
14610037SARM gem5 Developers    if (offset < PCI_DEVICE_SPECIFIC) {
1476735Sgblack@eecs.umich.edu        return PciDev::readConfig(pkt);
14810037SARM gem5 Developers    }
14910037SARM gem5 Developers
15010037SARM gem5 Developers    pkt->allocate();
15110037SARM gem5 Developers
15210037SARM gem5 Developers    switch (pkt->getSize()) {
15310037SARM gem5 Developers      case sizeof(uint8_t):
15410037SARM gem5 Developers        switch (offset) {
1556735Sgblack@eecs.umich.edu          case DeviceTiming:
15610037SARM gem5 Developers            pkt->set<uint8_t>(deviceTiming);
1576735Sgblack@eecs.umich.edu            break;
1586735Sgblack@eecs.umich.edu          case UDMAControl:
15910037SARM gem5 Developers            pkt->set<uint8_t>(udmaControl);
16010037SARM gem5 Developers            break;
16110037SARM gem5 Developers          case PrimaryTiming + 1:
16210037SARM gem5 Developers            pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8));
16310037SARM gem5 Developers            break;
16410037SARM gem5 Developers          case SecondaryTiming + 1:
16510037SARM gem5 Developers            pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8));
1666735Sgblack@eecs.umich.edu            break;
1676735Sgblack@eecs.umich.edu          case IDEConfig:
16810037SARM gem5 Developers            pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0));
16910037SARM gem5 Developers            break;
17010037SARM gem5 Developers          case IDEConfig + 1:
17110037SARM gem5 Developers            pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8));
17210037SARM gem5 Developers            break;
1736735Sgblack@eecs.umich.edu          default:
1746735Sgblack@eecs.umich.edu            panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
1756735Sgblack@eecs.umich.edu                    offset);
17610037SARM gem5 Developers        }
17710537Sandreas.hansson@arm.com        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
17812402Sgiacomo.travaglini@arm.com                (uint32_t)pkt->get<uint8_t>());
17910037SARM gem5 Developers        break;
18010037SARM gem5 Developers      case sizeof(uint16_t):
18110037SARM gem5 Developers        switch (offset) {
18210037SARM gem5 Developers          case PrimaryTiming:
18310037SARM gem5 Developers            pkt->set<uint16_t>(primaryTiming);
18410037SARM gem5 Developers            break;
18510037SARM gem5 Developers          case SecondaryTiming:
18610037SARM gem5 Developers            pkt->set<uint16_t>(secondaryTiming);
18710417Sandreas.hansson@arm.com            break;
18812176Sandreas.sandberg@arm.com          case UDMATiming:
18910417Sandreas.hansson@arm.com            pkt->set<uint16_t>(udmaTiming);
19010417Sandreas.hansson@arm.com            break;
19110037SARM gem5 Developers          case IDEConfig:
1926735Sgblack@eecs.umich.edu            pkt->set<uint16_t>(ideConfig);
19310037SARM gem5 Developers            break;
19412511Schuan.zhu@arm.com          default:
1956735Sgblack@eecs.umich.edu            panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
19610037SARM gem5 Developers                    offset);
19710037SARM gem5 Developers        }
19810037SARM gem5 Developers        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
19910037SARM gem5 Developers                (uint32_t)pkt->get<uint16_t>());
20010037SARM gem5 Developers        break;
20110037SARM gem5 Developers      case sizeof(uint32_t):
20210037SARM gem5 Developers        panic("No 32bit reads implemented for this device.");
20310037SARM gem5 Developers        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
20410037SARM gem5 Developers                (uint32_t)pkt->get<uint32_t>());
20510037SARM gem5 Developers        break;
20610037SARM gem5 Developers      default:
20710037SARM gem5 Developers        panic("invalid access size(?) for PCI configspace!\n");
20810037SARM gem5 Developers    }
2096019Shines@cs.fsu.edu    pkt->makeAtomicResponse();
2106019Shines@cs.fsu.edu    return configDelay;
2116735Sgblack@eecs.umich.edu}
2127362Sgblack@eecs.umich.edu
2136019Shines@cs.fsu.edu
2146735Sgblack@eecs.umich.eduTick
2156735Sgblack@eecs.umich.eduIdeController::writeConfig(PacketPtr pkt)
2166735Sgblack@eecs.umich.edu{
2176019Shines@cs.fsu.edu    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
21810037SARM gem5 Developers    if (offset < PCI_DEVICE_SPECIFIC) {
21910037SARM gem5 Developers        PciDev::writeConfig(pkt);
22012176Sandreas.sandberg@arm.com    } else {
22112176Sandreas.sandberg@arm.com        switch (pkt->getSize()) {
22212176Sandreas.sandberg@arm.com          case sizeof(uint8_t):
22310037SARM gem5 Developers            switch (offset) {
22412511Schuan.zhu@arm.com              case DeviceTiming:
22510037SARM gem5 Developers                deviceTiming = pkt->get<uint8_t>();
22612176Sandreas.sandberg@arm.com                break;
22712176Sandreas.sandberg@arm.com              case UDMAControl:
22812176Sandreas.sandberg@arm.com                udmaControl = pkt->get<uint8_t>();
22912176Sandreas.sandberg@arm.com                break;
23012176Sandreas.sandberg@arm.com              case IDEConfig:
23112176Sandreas.sandberg@arm.com                replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>());
23212176Sandreas.sandberg@arm.com                break;
23312176Sandreas.sandberg@arm.com              case IDEConfig + 1:
23412176Sandreas.sandberg@arm.com                replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>());
23512176Sandreas.sandberg@arm.com                break;
23612176Sandreas.sandberg@arm.com              default:
23712176Sandreas.sandberg@arm.com                panic("Invalid PCI configuration write "
23812176Sandreas.sandberg@arm.com                        "for size 1 offset: %#x!\n", offset);
23912176Sandreas.sandberg@arm.com            }
24012176Sandreas.sandberg@arm.com            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
24112176Sandreas.sandberg@arm.com                    offset, (uint32_t)pkt->get<uint8_t>());
24212176Sandreas.sandberg@arm.com            break;
24312176Sandreas.sandberg@arm.com          case sizeof(uint16_t):
2446019Shines@cs.fsu.edu            switch (offset) {
2456019Shines@cs.fsu.edu              case PrimaryTiming:
2467400SAli.Saidi@ARM.com                primaryTiming = pkt->get<uint16_t>();
2477400SAli.Saidi@ARM.com                break;
2487400SAli.Saidi@ARM.com              case SecondaryTiming:
24910417Sandreas.hansson@arm.com                secondaryTiming = pkt->get<uint16_t>();
25012176Sandreas.sandberg@arm.com                break;
2517400SAli.Saidi@ARM.com              case UDMATiming:
2527189Sgblack@eecs.umich.edu                udmaTiming = pkt->get<uint16_t>();
2537362Sgblack@eecs.umich.edu                break;
2547189Sgblack@eecs.umich.edu              case IDEConfig:
2557189Sgblack@eecs.umich.edu                ideConfig = pkt->get<uint16_t>();
2567189Sgblack@eecs.umich.edu                break;
2577640Sgblack@eecs.umich.edu              default:
25810037SARM gem5 Developers                panic("Invalid PCI configuration write "
25910205SAli.Saidi@ARM.com                        "for size 2 offset: %#x!\n",
2607189Sgblack@eecs.umich.edu                        offset);
2617189Sgblack@eecs.umich.edu            }
2627189Sgblack@eecs.umich.edu            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
2637189Sgblack@eecs.umich.edu                    offset, (uint32_t)pkt->get<uint16_t>());
2647640Sgblack@eecs.umich.edu            break;
2657640Sgblack@eecs.umich.edu          case sizeof(uint32_t):
26610037SARM gem5 Developers            panic("Write of unimplemented PCI config. register: %x\n", offset);
26710205SAli.Saidi@ARM.com            break;
26810205SAli.Saidi@ARM.com          default:
26910037SARM gem5 Developers            panic("invalid access size(?) for PCI configspace!\n");
27010205SAli.Saidi@ARM.com        }
27110205SAli.Saidi@ARM.com        pkt->makeAtomicResponse();
27210037SARM gem5 Developers    }
27310205SAli.Saidi@ARM.com
27410205SAli.Saidi@ARM.com    /* Trap command register writes and enable IO/BM as appropriate as well as
2758782Sgblack@eecs.umich.edu     * BARs. */
2767189Sgblack@eecs.umich.edu    switch(offset) {
27710417Sandreas.hansson@arm.com      case PCI0_BASE_ADDR0:
27812176Sandreas.sandberg@arm.com        if (BARAddrs[0] != 0)
27912176Sandreas.sandberg@arm.com            primary.cmdAddr = BARAddrs[0];
28012176Sandreas.sandberg@arm.com        break;
28112176Sandreas.sandberg@arm.com
2827189Sgblack@eecs.umich.edu      case PCI0_BASE_ADDR1:
2837189Sgblack@eecs.umich.edu        if (BARAddrs[1] != 0)
2847362Sgblack@eecs.umich.edu            primary.ctrlAddr = BARAddrs[1];
2857197Sgblack@eecs.umich.edu        break;
2867197Sgblack@eecs.umich.edu
28710037SARM gem5 Developers      case PCI0_BASE_ADDR2:
2887197Sgblack@eecs.umich.edu        if (BARAddrs[2] != 0)
28910037SARM gem5 Developers            secondary.cmdAddr = BARAddrs[2];
29010037SARM gem5 Developers        break;
29110037SARM gem5 Developers
29210037SARM gem5 Developers      case PCI0_BASE_ADDR3:
2938782Sgblack@eecs.umich.edu        if (BARAddrs[3] != 0)
2947197Sgblack@eecs.umich.edu            secondary.ctrlAddr = BARAddrs[3];
29510417Sandreas.hansson@arm.com        break;
29612176Sandreas.sandberg@arm.com
29712176Sandreas.sandberg@arm.com      case PCI0_BASE_ADDR4:
29812176Sandreas.sandberg@arm.com        if (BARAddrs[4] != 0)
29912176Sandreas.sandberg@arm.com            bmiAddr = BARAddrs[4];
30010037SARM gem5 Developers        break;
30110037SARM gem5 Developers
30210037SARM gem5 Developers      case PCI_COMMAND:
30310037SARM gem5 Developers        ioEnabled = (config.command & htole(PCI_CMD_IOSE));
30410037SARM gem5 Developers        bmEnabled = (config.command & htole(PCI_CMD_BME));
30510037SARM gem5 Developers        break;
30610037SARM gem5 Developers    }
30710037SARM gem5 Developers    return configDelay;
30810037SARM gem5 Developers}
30910417Sandreas.hansson@arm.com
31012176Sandreas.sandberg@arm.comvoid
31112176Sandreas.sandberg@arm.comIdeController::Channel::accessCommand(Addr offset,
31212176Sandreas.sandberg@arm.com        int size, uint8_t *data, bool read)
31310037SARM gem5 Developers{
31410037SARM gem5 Developers    const Addr SelectOffset = 6;
31510037SARM gem5 Developers    const uint8_t SelectDevBit = 0x10;
31610037SARM gem5 Developers
31710037SARM gem5 Developers    if (!read && offset == SelectOffset)
31810037SARM gem5 Developers        select(*data & SelectDevBit);
31910037SARM gem5 Developers
32010037SARM gem5 Developers    if (selected == NULL) {
32110037SARM gem5 Developers        assert(size == sizeof(uint8_t));
32210037SARM gem5 Developers        *data = 0;
32310037SARM gem5 Developers    } else if (read) {
32410037SARM gem5 Developers        selected->readCommand(offset, size, data);
32510037SARM gem5 Developers    } else {
32610037SARM gem5 Developers        selected->writeCommand(offset, size, data);
32710037SARM gem5 Developers    }
32812509Schuan.zhu@arm.com}
32912509Schuan.zhu@arm.com
33012176Sandreas.sandberg@arm.comvoid
33110037SARM gem5 DevelopersIdeController::Channel::accessControl(Addr offset,
33210037SARM gem5 Developers        int size, uint8_t *data, bool read)
33310037SARM gem5 Developers{
33410037SARM gem5 Developers    if (selected == NULL) {
33510037SARM gem5 Developers        assert(size == sizeof(uint8_t));
33610037SARM gem5 Developers        *data = 0;
33710037SARM gem5 Developers    } else if (read) {
33810037SARM gem5 Developers        selected->readControl(offset, size, data);
33910037SARM gem5 Developers    } else {
34010037SARM gem5 Developers        selected->writeControl(offset, size, data);
34110037SARM gem5 Developers    }
34210037SARM gem5 Developers}
34310037SARM gem5 Developers
34410037SARM gem5 Developersvoid
34510037SARM gem5 DevelopersIdeController::Channel::accessBMI(Addr offset,
34612176Sandreas.sandberg@arm.com        int size, uint8_t *data, bool read)
34710037SARM gem5 Developers{
34810037SARM gem5 Developers    assert(offset + size <= sizeof(BMIRegs));
34910037SARM gem5 Developers    if (read) {
35010037SARM gem5 Developers        memcpy(data, (uint8_t *)&bmiRegs + offset, size);
35110037SARM gem5 Developers    } else {
35210037SARM gem5 Developers        switch (offset) {
35311576SDylan.Johnson@ARM.com          case BMICommand:
35412176Sandreas.sandberg@arm.com            {
35510037SARM gem5 Developers                if (size != sizeof(uint8_t))
35610037SARM gem5 Developers                    panic("Invalid BMIC write size: %x\n", size);
35710037SARM gem5 Developers
35810037SARM gem5 Developers                BMICommandReg oldVal = bmiRegs.command;
35910037SARM gem5 Developers                BMICommandReg newVal = *data;
36010037SARM gem5 Developers
36110037SARM gem5 Developers                // if a DMA transfer is in progress, R/W control cannot change
36210037SARM gem5 Developers                if (oldVal.startStop && oldVal.rw != newVal.rw)
36310037SARM gem5 Developers                    oldVal.rw = newVal.rw;
36410037SARM gem5 Developers
36510037SARM gem5 Developers                if (oldVal.startStop != newVal.startStop) {
36610037SARM gem5 Developers                    if (selected == NULL)
36710037SARM gem5 Developers                        panic("DMA start for disk which does not exist\n");
36810037SARM gem5 Developers
36910037SARM gem5 Developers                    if (oldVal.startStop) {
37012176Sandreas.sandberg@arm.com                        DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
3717197Sgblack@eecs.umich.edu                        bmiRegs.status.active = 0;
3727362Sgblack@eecs.umich.edu
3737362Sgblack@eecs.umich.edu                        selected->abortDma();
3747362Sgblack@eecs.umich.edu                    } else {
3757362Sgblack@eecs.umich.edu                        DPRINTF(IdeCtrl, "Starting DMA transfer\n");
3767362Sgblack@eecs.umich.edu                        bmiRegs.status.active = 1;
37710037SARM gem5 Developers
37810037SARM gem5 Developers                        selected->startDma(letoh(bmiRegs.bmidtp));
37910037SARM gem5 Developers                    }
38010037SARM gem5 Developers                }
38110037SARM gem5 Developers
38210037SARM gem5 Developers                bmiRegs.command = newVal;
3837362Sgblack@eecs.umich.edu            }
38410037SARM gem5 Developers            break;
38510037SARM gem5 Developers          case BMIStatus:
38610037SARM gem5 Developers            {
38710037SARM gem5 Developers                if (size != sizeof(uint8_t))
38810037SARM gem5 Developers                    panic("Invalid BMIS write size: %x\n", size);
38910037SARM gem5 Developers
3907362Sgblack@eecs.umich.edu                BMIStatusReg oldVal = bmiRegs.status;
39110037SARM gem5 Developers                BMIStatusReg newVal = *data;
39210037SARM gem5 Developers
39310037SARM gem5 Developers                // the BMIDEA bit is read only
39410037SARM gem5 Developers                newVal.active = oldVal.active;
39510037SARM gem5 Developers
39610037SARM gem5 Developers                // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
3977362Sgblack@eecs.umich.edu                if (oldVal.intStatus && newVal.intStatus)
3987362Sgblack@eecs.umich.edu                    newVal.intStatus = 0; // clear the interrupt?
39910537Sandreas.hansson@arm.com                else
40010537Sandreas.hansson@arm.com                    newVal.intStatus = oldVal.intStatus;
40110537Sandreas.hansson@arm.com                if (oldVal.dmaError && newVal.dmaError)
40210537Sandreas.hansson@arm.com                    newVal.dmaError = 0;
40310537Sandreas.hansson@arm.com                else
40410037SARM gem5 Developers                    newVal.dmaError = oldVal.dmaError;
4057362Sgblack@eecs.umich.edu
4067362Sgblack@eecs.umich.edu                bmiRegs.status = newVal;
40710417Sandreas.hansson@arm.com            }
40812176Sandreas.sandberg@arm.com            break;
40910037SARM gem5 Developers          case BMIDescTablePtr:
41012176Sandreas.sandberg@arm.com            if (size != sizeof(uint32_t))
41112176Sandreas.sandberg@arm.com                panic("Invalid BMIDTP write size: %x\n", size);
41212176Sandreas.sandberg@arm.com            bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
41312176Sandreas.sandberg@arm.com            break;
41412176Sandreas.sandberg@arm.com          default:
41510037SARM gem5 Developers            if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
4167362Sgblack@eecs.umich.edu                    size != sizeof(uint32_t))
4177362Sgblack@eecs.umich.edu                panic("IDE controller write of invalid write size: %x\n", size);
4187362Sgblack@eecs.umich.edu            memcpy((uint8_t *)&bmiRegs + offset, data, size);
4197362Sgblack@eecs.umich.edu        }
4207362Sgblack@eecs.umich.edu    }
42110037SARM gem5 Developers}
42210037SARM gem5 Developers
42310037SARM gem5 Developersvoid
4247362Sgblack@eecs.umich.eduIdeController::dispatchAccess(PacketPtr pkt, bool read)
42510037SARM gem5 Developers{
42610037SARM gem5 Developers    pkt->allocate();
42710037SARM gem5 Developers    if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
42810037SARM gem5 Developers         panic("Bad IDE read size: %d\n", pkt->getSize());
4297362Sgblack@eecs.umich.edu
43010037SARM gem5 Developers    if (!ioEnabled) {
43112176Sandreas.sandberg@arm.com        pkt->makeAtomicResponse();
43210037SARM gem5 Developers        DPRINTF(IdeCtrl, "io not enabled\n");
43312176Sandreas.sandberg@arm.com        return;
43412176Sandreas.sandberg@arm.com    }
4357362Sgblack@eecs.umich.edu
4367362Sgblack@eecs.umich.edu    Addr addr = pkt->getAddr();
4377362Sgblack@eecs.umich.edu    int size = pkt->getSize();
4387362Sgblack@eecs.umich.edu    uint8_t *dataPtr = pkt->getPtr<uint8_t>();
4397362Sgblack@eecs.umich.edu
44010037SARM gem5 Developers    if (addr >= primary.cmdAddr &&
44110037SARM gem5 Developers            addr < (primary.cmdAddr + primary.cmdSize)) {
44210037SARM gem5 Developers        addr -= primary.cmdAddr;
44310037SARM gem5 Developers        primary.accessCommand(addr, size, dataPtr, read);
44410037SARM gem5 Developers    } else if (addr >= primary.ctrlAddr &&
44510037SARM gem5 Developers               addr < (primary.ctrlAddr + primary.ctrlSize)) {
44610037SARM gem5 Developers        addr -= primary.ctrlAddr;
4477362Sgblack@eecs.umich.edu        primary.accessControl(addr, size, dataPtr, read);
44810037SARM gem5 Developers    } else if (addr >= secondary.cmdAddr &&
44910037SARM gem5 Developers               addr < (secondary.cmdAddr + secondary.cmdSize)) {
45010037SARM gem5 Developers        addr -= secondary.cmdAddr;
45110037SARM gem5 Developers        secondary.accessCommand(addr, size, dataPtr, read);
45210037SARM gem5 Developers    } else if (addr >= secondary.ctrlAddr &&
45310037SARM gem5 Developers               addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
45410037SARM gem5 Developers        addr -= secondary.ctrlAddr;
45510037SARM gem5 Developers        secondary.accessControl(addr, size, dataPtr, read);
45610037SARM gem5 Developers    } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
4577362Sgblack@eecs.umich.edu        if (!read && !bmEnabled)
45810037SARM gem5 Developers            return;
45912176Sandreas.sandberg@arm.com        addr -= bmiAddr;
46010037SARM gem5 Developers        if (addr < sizeof(Channel::BMIRegs)) {
46112176Sandreas.sandberg@arm.com            primary.accessBMI(addr, size, dataPtr, read);
46212176Sandreas.sandberg@arm.com        } else {
46312176Sandreas.sandberg@arm.com            addr -= sizeof(Channel::BMIRegs);
46412176Sandreas.sandberg@arm.com            secondary.accessBMI(addr, size, dataPtr, read);
4657362Sgblack@eecs.umich.edu        }
4667362Sgblack@eecs.umich.edu    } else {
46710037SARM gem5 Developers        panic("IDE controller access to invalid address: %#x\n", addr);
46810037SARM gem5 Developers    }
46910037SARM gem5 Developers
47010037SARM gem5 Developers    uint32_t data;
47110037SARM gem5 Developers    if (pkt->getSize() == 1)
47210037SARM gem5 Developers        data = pkt->get<uint8_t>();
47310037SARM gem5 Developers    else if (pkt->getSize() == 2)
47410037SARM gem5 Developers        data = pkt->get<uint16_t>();
47510037SARM gem5 Developers    else
47610037SARM gem5 Developers        data = pkt->get<uint32_t>();
47710037SARM gem5 Developers    DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
47810037SARM gem5 Developers            read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
47912176Sandreas.sandberg@arm.com
48010037SARM gem5 Developers    pkt->makeAtomicResponse();
48110037SARM gem5 Developers}
48210037SARM gem5 Developers
48310037SARM gem5 DevelopersTick
48410037SARM gem5 DevelopersIdeController::read(PacketPtr pkt)
48512176Sandreas.sandberg@arm.com{
48612176Sandreas.sandberg@arm.com    dispatchAccess(pkt, true);
48712176Sandreas.sandberg@arm.com    return pioDelay;
48810037SARM gem5 Developers}
48910037SARM gem5 Developers
49010037SARM gem5 DevelopersTick
49110037SARM gem5 DevelopersIdeController::write(PacketPtr pkt)
49210037SARM gem5 Developers{
49310037SARM gem5 Developers    dispatchAccess(pkt, false);
49410037SARM gem5 Developers    return pioDelay;
49510037SARM gem5 Developers}
49610037SARM gem5 Developers
49710037SARM gem5 Developersvoid
49810037SARM gem5 DevelopersIdeController::serialize(std::ostream &os)
49912176Sandreas.sandberg@arm.com{
50012176Sandreas.sandberg@arm.com    // Serialize the PciDev base class
50112176Sandreas.sandberg@arm.com    PciDev::serialize(os);
50212176Sandreas.sandberg@arm.com
50310037SARM gem5 Developers    // Serialize channels
50410037SARM gem5 Developers    primary.serialize(os);
50510037SARM gem5 Developers    secondary.serialize(os);
50610037SARM gem5 Developers
50710037SARM gem5 Developers    // Serialize config registers
50810037SARM gem5 Developers    SERIALIZE_SCALAR(primaryTiming);
50910037SARM gem5 Developers    SERIALIZE_SCALAR(secondaryTiming);
51010037SARM gem5 Developers    SERIALIZE_SCALAR(deviceTiming);
51110037SARM gem5 Developers    SERIALIZE_SCALAR(udmaControl);
51210037SARM gem5 Developers    SERIALIZE_SCALAR(udmaTiming);
51310037SARM gem5 Developers    SERIALIZE_SCALAR(ideConfig);
51410037SARM gem5 Developers
51510037SARM gem5 Developers    // Serialize internal state
51610037SARM gem5 Developers    SERIALIZE_SCALAR(ioEnabled);
51710037SARM gem5 Developers    SERIALIZE_SCALAR(bmEnabled);
51810037SARM gem5 Developers}
51910037SARM gem5 Developers
52010417Sandreas.hansson@arm.comvoid
52112176Sandreas.sandberg@arm.comIdeController::Channel::serialize(std::ostream &os)
52210037SARM gem5 Developers{
52310037SARM gem5 Developers    SERIALIZE_SCALAR(cmdAddr);
52410037SARM gem5 Developers    SERIALIZE_SCALAR(cmdSize);
52510037SARM gem5 Developers    SERIALIZE_SCALAR(ctrlAddr);
52610037SARM gem5 Developers    SERIALIZE_SCALAR(ctrlSize);
52710037SARM gem5 Developers    SERIALIZE_SCALAR((uint8_t)bmiRegs.command);
52810037SARM gem5 Developers    SERIALIZE_SCALAR(bmiRegs.reserved0);
52910037SARM gem5 Developers    SERIALIZE_SCALAR((uint8_t)bmiRegs.status);
53010037SARM gem5 Developers    SERIALIZE_SCALAR(bmiRegs.reserved1);
53110037SARM gem5 Developers    SERIALIZE_SCALAR(bmiRegs.bmidtp);
53210037SARM gem5 Developers    SERIALIZE_SCALAR(selectBit);
53310037SARM gem5 Developers}
53410037SARM gem5 Developers
53510037SARM gem5 Developersvoid
53610417Sandreas.hansson@arm.comIdeController::unserialize(Checkpoint *cp, const std::string &section)
53712176Sandreas.sandberg@arm.com{
53812176Sandreas.sandberg@arm.com    // Unserialize the PciDev base class
53912176Sandreas.sandberg@arm.com    PciDev::unserialize(cp, section);
54010037SARM gem5 Developers
5416019Shines@cs.fsu.edu    // Unserialize channels
54212299Sandreas.sandberg@arm.com    primary.unserialize(cp, section);
54312299Sandreas.sandberg@arm.com    secondary.unserialize(cp, section);
54412299Sandreas.sandberg@arm.com
54512299Sandreas.sandberg@arm.com    // Unserialize config registers
54612299Sandreas.sandberg@arm.com    UNSERIALIZE_SCALAR(primaryTiming);
54712299Sandreas.sandberg@arm.com    UNSERIALIZE_SCALAR(secondaryTiming);
54812299Sandreas.sandberg@arm.com    UNSERIALIZE_SCALAR(deviceTiming);
54912299Sandreas.sandberg@arm.com    UNSERIALIZE_SCALAR(udmaControl);
55012299Sandreas.sandberg@arm.com    UNSERIALIZE_SCALAR(udmaTiming);
5517652Sminkyu.jeong@arm.com    UNSERIALIZE_SCALAR(ideConfig);
5528518Sgeoffrey.blake@arm.com
5538518Sgeoffrey.blake@arm.com    // Unserialize internal state
5548518Sgeoffrey.blake@arm.com    UNSERIALIZE_SCALAR(ioEnabled);
5558518Sgeoffrey.blake@arm.com    UNSERIALIZE_SCALAR(bmEnabled);
55610417Sandreas.hansson@arm.com}
55712176Sandreas.sandberg@arm.com
5588518Sgeoffrey.blake@arm.comvoid
5598518Sgeoffrey.blake@arm.comIdeController::Channel::unserialize(
56010037SARM gem5 Developers        Checkpoint *cp, const std::string &section)
56110037SARM gem5 Developers{
56210037SARM gem5 Developers    uint8_t temp;
56310037SARM gem5 Developers    UNSERIALIZE_SCALAR(cmdAddr);
56410037SARM gem5 Developers    UNSERIALIZE_SCALAR(cmdSize);
56510037SARM gem5 Developers    UNSERIALIZE_SCALAR(ctrlAddr);
56610037SARM gem5 Developers    UNSERIALIZE_SCALAR(ctrlSize);
56711929SMatteo.Andreozzi@arm.com    UNSERIALIZE_SCALAR(temp);
56812032Sandreas.sandberg@arm.com    bmiRegs.command = temp;
56912032Sandreas.sandberg@arm.com    UNSERIALIZE_SCALAR(bmiRegs.reserved0);
57011929SMatteo.Andreozzi@arm.com    UNSERIALIZE_SCALAR(temp);
57111929SMatteo.Andreozzi@arm.com    bmiRegs.status = temp;
57211929SMatteo.Andreozzi@arm.com    UNSERIALIZE_SCALAR(bmiRegs.reserved1);
57311929SMatteo.Andreozzi@arm.com    UNSERIALIZE_SCALAR(bmiRegs.bmidtp);
57411929SMatteo.Andreozzi@arm.com    UNSERIALIZE_SCALAR(selectBit);
57511929SMatteo.Andreozzi@arm.com    select(selectBit);
57611929SMatteo.Andreozzi@arm.com}
57711929SMatteo.Andreozzi@arm.com
57811929SMatteo.Andreozzi@arm.comIdeController *
57911929SMatteo.Andreozzi@arm.comIdeControllerParams::create()
58011929SMatteo.Andreozzi@arm.com{
58111929SMatteo.Andreozzi@arm.com    return new IdeController(this);
58211929SMatteo.Andreozzi@arm.com}
58311929SMatteo.Andreozzi@arm.com