ide_ctrl.cc revision 10775
12SN/A/*
213610Sgiacomo.gabrielli@arm.com * Copyright (c) 2013 ARM Limited
39920Syasuko.eckert@amd.com * All rights reserved
48733Sgeoffrey.blake@arm.com *
58733Sgeoffrey.blake@arm.com * The license below extends only to copyright in the software and shall
68733Sgeoffrey.blake@arm.com * not be construed as granting a license to any other intellectual
78733Sgeoffrey.blake@arm.com * property including but not limited to intellectual property relating
88733Sgeoffrey.blake@arm.com * to a hardware implementation of the functionality of the software
98733Sgeoffrey.blake@arm.com * licensed hereunder.  You may use the software subject to the license
108733Sgeoffrey.blake@arm.com * terms below provided that you ensure that this notice is replicated
118733Sgeoffrey.blake@arm.com * unmodified and in its entirety in all distributions of the software,
128733Sgeoffrey.blake@arm.com * modified or unmodified, in source code or in binary form.
138733Sgeoffrey.blake@arm.com *
148733Sgeoffrey.blake@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
152188SN/A * All rights reserved.
162SN/A *
172SN/A * Redistribution and use in source and binary forms, with or without
182SN/A * modification, are permitted provided that the following conditions are
192SN/A * met: redistributions of source code must retain the above copyright
202SN/A * notice, this list of conditions and the following disclaimer;
212SN/A * redistributions in binary form must reproduce the above copyright
222SN/A * notice, this list of conditions and the following disclaimer in the
232SN/A * documentation and/or other materials provided with the distribution;
242SN/A * neither the name of the copyright holders nor the names of its
252SN/A * contributors may be used to endorse or promote products derived from
262SN/A * this software without specific prior written permission.
272SN/A *
282SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392SN/A *
402665SN/A * Authors: Andrew Schultz
412665SN/A *          Ali Saidi
422665SN/A *          Miguel Serrano
432SN/A */
442SN/A
452683Sktlim@umich.edu#include <string>
462683Sktlim@umich.edu
472SN/A#include "cpu/intr_control.hh"
489020Sgblack@eecs.umich.edu#include "debug/IdeCtrl.hh"
4912406Sgabeblack@google.com#include "dev/ide_ctrl.hh"
506313Sgblack@eecs.umich.edu#include "dev/ide_disk.hh"
512190SN/A#include "mem/packet.hh"
526329Sgblack@eecs.umich.edu#include "mem/packet_access.hh"
536316Sgblack@eecs.umich.edu#include "params/IdeController.hh"
546216Snate@binkert.org#include "sim/byteswap.hh"
556658Snate@binkert.org
562680SN/A// clang complains about std::set being overloaded with Packet::set if
572683Sktlim@umich.edu// we open up the entire namespace std
589920Syasuko.eckert@amd.comusing std::string;
598232Snate@binkert.org
608232Snate@binkert.org// Bus master IDE registers
6113610Sgiacomo.gabrielli@arm.comenum BMIRegOffset {
6212109SRekai.GonzalezAlberquilla@arm.com    BMICommand = 0x0,
638777Sgblack@eecs.umich.edu    BMIStatus = 0x2,
642395SN/A    BMIDescTablePtr = 0x4
652190SN/A};
662188SN/A
678777Sgblack@eecs.umich.edu// PCI config space registers
68217SN/Aenum ConfRegOffset {
698777Sgblack@eecs.umich.edu    PrimaryTiming = 0x40,
702SN/A    SecondaryTiming = 0x42,
712SN/A    DeviceTiming = 0x44,
728887Sgeoffrey.blake@arm.com    UDMAControl = 0x48,
731070SN/A    UDMATiming = 0x4A,
741917SN/A    IDEConfig = 0x54
751917SN/A};
762521SN/A
7713905Sgabeblack@google.comstatic const uint16_t timeRegWithDecodeEn = 0x8000;
7813905Sgabeblack@google.com
798902Sandreas.hansson@arm.comIdeController::Channel::Channel(
802330SN/A        string newName, Addr _cmdSize, Addr _ctrlSize) :
812683Sktlim@umich.edu    _name(newName),
822683Sktlim@umich.edu    cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize),
832683Sktlim@umich.edu    master(NULL), slave(NULL), selected(NULL)
8413865Sgabeblack@google.com{
852683Sktlim@umich.edu    memset(&bmiRegs, 0, sizeof(bmiRegs));
862683Sktlim@umich.edu    bmiRegs.status.dmaCap0 = 1;
872683Sktlim@umich.edu    bmiRegs.status.dmaCap1 = 1;
882683Sktlim@umich.edu}
892683Sktlim@umich.edu
902683Sktlim@umich.eduIdeController::Channel::~Channel()
912683Sktlim@umich.edu{
922683Sktlim@umich.edu}
932683Sktlim@umich.edu
942SN/AIdeController::IdeController(Params *p)
9513865Sgabeblack@google.com    : PciDevice(p), primary(name() + ".primary", BARSize[0], BARSize[1]),
962SN/A    secondary(name() + ".secondary", BARSize[2], BARSize[3]),
972107SN/A    bmiAddr(0), bmiSize(BARSize[4]),
982107SN/A    primaryTiming(htole(timeRegWithDecodeEn)),
9912109SRekai.GonzalezAlberquilla@arm.com    secondaryTiming(htole(timeRegWithDecodeEn)),
10012109SRekai.GonzalezAlberquilla@arm.com    deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
10113610Sgiacomo.gabrielli@arm.com    ioEnabled(false), bmEnabled(false),
1022SN/A    ioShift(p->io_shift), ctrlOffset(p->ctrl_offset)
1032680SN/A{
1042SN/A    if (params()->disks.size() > 3)
1052190SN/A        panic("IDE controllers support a maximum of 4 devices attached!\n");
10613557Sgabeblack@google.com
10713557Sgabeblack@google.com    // Assign the disks to channels
10812109SRekai.GonzalezAlberquilla@arm.com    int numDisks = params()->disks.size();
10913610Sgiacomo.gabrielli@arm.com    if (numDisks > 0)
1109920Syasuko.eckert@amd.com        primary.master = params()->disks[0];
11113622Sgabeblack@google.com    if (numDisks > 1)
1129920Syasuko.eckert@amd.com        primary.slave = params()->disks[1];
1139384SAndreas.Sandberg@arm.com    if (numDisks > 2)
1142SN/A        secondary.master = params()->disks[2];
1157720Sgblack@eecs.umich.edu    if (numDisks > 3)
1166324Sgblack@eecs.umich.edu        secondary.slave = params()->disks[3];
1177597Sminkyu.jeong@arm.com
1187597Sminkyu.jeong@arm.com    for (int i = 0; i < params()->disks.size(); i++) {
1197597Sminkyu.jeong@arm.com        params()->disks[i]->setController(this);
12013953Sgiacomo.gabrielli@arm.com    }
12113953Sgiacomo.gabrielli@arm.com    primary.select(false);
12213953Sgiacomo.gabrielli@arm.com    secondary.select(false);
1232190SN/A
1248357Sksewell@umich.edu    if ((BARAddrs[0] & ~BAR_IO_MASK) && (!legacyIO[0] || ioShift)) {
1258357Sksewell@umich.edu        primary.cmdAddr = BARAddrs[0];  primary.cmdSize = BARSize[0];
12613865Sgabeblack@google.com        primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARSize[1];
1278357Sksewell@umich.edu    }
1288357Sksewell@umich.edu    if ((BARAddrs[2] & ~BAR_IO_MASK) && (!legacyIO[2] || ioShift)) {
1292378SN/A        secondary.cmdAddr = BARAddrs[2];  secondary.cmdSize = BARSize[2];
1302400SN/A        secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARSize[3];
13112406Sgabeblack@google.com    }
13212406Sgabeblack@google.com
1332SN/A    ioEnabled = (config.command & htole(PCI_CMD_IOSE));
1349020Sgblack@eecs.umich.edu    bmEnabled = (config.command & htole(PCI_CMD_BME));
1358541Sgblack@eecs.umich.edu}
1362683Sktlim@umich.edu
1378793Sgblack@eecs.umich.edubool
1382683Sktlim@umich.eduIdeController::isDiskSelected(IdeDisk *diskPtr)
13912406Sgabeblack@google.com{
1402683Sktlim@umich.edu    return (primary.selected == diskPtr || secondary.selected == diskPtr);
1418793Sgblack@eecs.umich.edu}
1428820Sgblack@eecs.umich.edu
14312406Sgabeblack@google.comvoid
1449384SAndreas.Sandberg@arm.comIdeController::intrPost()
1452862Sktlim@umich.edu{
14613865Sgabeblack@google.com    primary.bmiRegs.status.intStatus = 1;
1472SN/A    PciDevice::intrPost();
14813865Sgabeblack@google.com}
149180SN/A
15013865Sgabeblack@google.comvoid
1512SN/AIdeController::setDmaComplete(IdeDisk *disk)
1522862Sktlim@umich.edu{
1532862Sktlim@umich.edu    Channel *channel;
15411168Sandreas.hansson@arm.com    if (disk == primary.master || disk == primary.slave) {
15511168Sandreas.hansson@arm.com        channel = &primary;
1569461Snilay@cs.wisc.edu    } else if (disk == secondary.master || disk == secondary.slave) {
157217SN/A        channel = &secondary;
1582683Sktlim@umich.edu    } else {
1592683Sktlim@umich.edu        panic("Unable to find disk based on pointer %#x\n", disk);
1605891Sgblack@eecs.umich.edu    }
1612683Sktlim@umich.edu
1622190SN/A    channel->bmiRegs.command.startStop = 0;
1632683Sktlim@umich.edu    channel->bmiRegs.status.active = 0;
1642683Sktlim@umich.edu    channel->bmiRegs.status.intStatus = 1;
1652683Sktlim@umich.edu}
1662683Sktlim@umich.edu
16713865Sgabeblack@google.comTick
1682190SN/AIdeController::readConfig(PacketPtr pkt)
1695358Sgblack@eecs.umich.edu{
1705358Sgblack@eecs.umich.edu    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1715358Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC) {
1725358Sgblack@eecs.umich.edu        return PciDevice::readConfig(pkt);
1735358Sgblack@eecs.umich.edu    }
1745358Sgblack@eecs.umich.edu
1755358Sgblack@eecs.umich.edu    switch (pkt->getSize()) {
1765358Sgblack@eecs.umich.edu      case sizeof(uint8_t):
1775358Sgblack@eecs.umich.edu        switch (offset) {
1785358Sgblack@eecs.umich.edu          case DeviceTiming:
1795358Sgblack@eecs.umich.edu            pkt->set<uint8_t>(deviceTiming);
1805358Sgblack@eecs.umich.edu            break;
1815358Sgblack@eecs.umich.edu          case UDMAControl:
1825358Sgblack@eecs.umich.edu            pkt->set<uint8_t>(udmaControl);
1835358Sgblack@eecs.umich.edu            break;
1845358Sgblack@eecs.umich.edu          case PrimaryTiming + 1:
18513865Sgabeblack@google.com            pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8));
1862521SN/A            break;
1872683Sktlim@umich.edu          case SecondaryTiming + 1:
1882683Sktlim@umich.edu            pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8));
1892683Sktlim@umich.edu            break;
1902683Sktlim@umich.edu          case IDEConfig:
19113865Sgabeblack@google.com            pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0));
1922683Sktlim@umich.edu            break;
19313865Sgabeblack@google.com          case IDEConfig + 1:
19413865Sgabeblack@google.com            pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8));
19513865Sgabeblack@google.com            break;
19613865Sgabeblack@google.com          default:
19713865Sgabeblack@google.com            panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
19813865Sgabeblack@google.com                    offset);
1992683Sktlim@umich.edu        }
20013865Sgabeblack@google.com        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
2012683Sktlim@umich.edu                (uint32_t)pkt->get<uint8_t>());
20213865Sgabeblack@google.com        break;
2038733Sgeoffrey.blake@arm.com      case sizeof(uint16_t):
20413865Sgabeblack@google.com        switch (offset) {
20513693Sgiacomo.gabrielli@arm.com          case UDMAControl:
20613865Sgabeblack@google.com            pkt->set<uint16_t>(udmaControl);
2078541Sgblack@eecs.umich.edu            break;
20813865Sgabeblack@google.com          case PrimaryTiming:
2094997Sgblack@eecs.umich.edu            pkt->set<uint16_t>(primaryTiming);
21013865Sgabeblack@google.com            break;
2112683Sktlim@umich.edu          case SecondaryTiming:
21213905Sgabeblack@google.com            pkt->set<uint16_t>(secondaryTiming);
21313875SAndrea.Mondelli@ucf.edu            break;
21413865Sgabeblack@google.com          case UDMATiming:
21513865Sgabeblack@google.com            pkt->set<uint16_t>(udmaTiming);
21613865Sgabeblack@google.com            break;
21713865Sgabeblack@google.com          case IDEConfig:
21813875SAndrea.Mondelli@ucf.edu            pkt->set<uint16_t>(ideConfig);
21914022Sgabeblack@google.com            break;
22013865Sgabeblack@google.com          default:
22113875SAndrea.Mondelli@ucf.edu            panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
22213875SAndrea.Mondelli@ucf.edu                    offset);
22313875SAndrea.Mondelli@ucf.edu        }
22413875SAndrea.Mondelli@ucf.edu        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
22513875SAndrea.Mondelli@ucf.edu                (uint32_t)pkt->get<uint16_t>());
22614022Sgabeblack@google.com        break;
22713875SAndrea.Mondelli@ucf.edu      case sizeof(uint32_t):
22813865Sgabeblack@google.com        switch (offset) {
22913865Sgabeblack@google.com          case PrimaryTiming:
23013865Sgabeblack@google.com            pkt->set<uint32_t>(primaryTiming);
23113865Sgabeblack@google.com            break;
23213875SAndrea.Mondelli@ucf.edu          case IDEConfig:
23313865Sgabeblack@google.com            pkt->set<uint32_t>(ideConfig);
23413865Sgabeblack@google.com            break;
23513865Sgabeblack@google.com          default:
23613865Sgabeblack@google.com            panic("No 32bit reads implemented for this device.");
23713865Sgabeblack@google.com        }
2382683Sktlim@umich.edu        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
23910407Smitch.hayenga@arm.com                (uint32_t)pkt->get<uint32_t>());
24013865Sgabeblack@google.com        break;
2412683Sktlim@umich.edu      default:
2422683Sktlim@umich.edu        panic("invalid access size(?) for PCI configspace!\n");
24313865Sgabeblack@google.com    }
2442683Sktlim@umich.edu    pkt->makeAtomicResponse();
2452683Sktlim@umich.edu    return configDelay;
24613865Sgabeblack@google.com}
2472683Sktlim@umich.edu
24813865Sgabeblack@google.com
24913865Sgabeblack@google.comTick
25013865Sgabeblack@google.comIdeController::writeConfig(PacketPtr pkt)
25113865Sgabeblack@google.com{
25213865Sgabeblack@google.com    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
2532190SN/A    if (offset < PCI_DEVICE_SPECIFIC) {
25413865Sgabeblack@google.com        PciDevice::writeConfig(pkt);
25513865Sgabeblack@google.com    } else {
25613865Sgabeblack@google.com        switch (pkt->getSize()) {
25713865Sgabeblack@google.com          case sizeof(uint8_t):
25813865Sgabeblack@google.com            switch (offset) {
25913865Sgabeblack@google.com              case DeviceTiming:
26013865Sgabeblack@google.com                deviceTiming = pkt->get<uint8_t>();
26113865Sgabeblack@google.com                break;
26213865Sgabeblack@google.com              case UDMAControl:
26313865Sgabeblack@google.com                udmaControl = pkt->get<uint8_t>();
26413865Sgabeblack@google.com                break;
26513865Sgabeblack@google.com              case IDEConfig:
26613865Sgabeblack@google.com                replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>());
26713865Sgabeblack@google.com                break;
26813865Sgabeblack@google.com              case IDEConfig + 1:
26913865Sgabeblack@google.com                replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>());
27013865Sgabeblack@google.com                break;
2716315Sgblack@eecs.umich.edu              default:
2727720Sgblack@eecs.umich.edu                panic("Invalid PCI configuration write "
2736316Sgblack@eecs.umich.edu                        "for size 1 offset: %#x!\n", offset);
27413501Sgabeblack@google.com            }
27512109SRekai.GonzalezAlberquilla@arm.com            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
27612109SRekai.GonzalezAlberquilla@arm.com                    offset, (uint32_t)pkt->get<uint8_t>());
27712109SRekai.GonzalezAlberquilla@arm.com            break;
27813610Sgiacomo.gabrielli@arm.com          case sizeof(uint16_t):
27913610Sgiacomo.gabrielli@arm.com            switch (offset) {
28013610Sgiacomo.gabrielli@arm.com              case UDMAControl:
2819920Syasuko.eckert@amd.com                udmaControl = pkt->get<uint16_t>();
2829920Syasuko.eckert@amd.com                break;
2839920Syasuko.eckert@amd.com              case PrimaryTiming:
2849384SAndreas.Sandberg@arm.com                primaryTiming = pkt->get<uint16_t>();
2856315Sgblack@eecs.umich.edu                break;
2862190SN/A              case SecondaryTiming:
2872SN/A                secondaryTiming = pkt->get<uint16_t>();
2882SN/A                break;
2892SN/A              case UDMATiming:
29013557Sgabeblack@google.com                udmaTiming = pkt->get<uint16_t>();
29113865Sgabeblack@google.com                break;
2922SN/A              case IDEConfig:
2939384SAndreas.Sandberg@arm.com                ideConfig = pkt->get<uint16_t>();
2946323Sgblack@eecs.umich.edu                break;
2959426SAndreas.Sandberg@ARM.com              default:
2967601Sminkyu.jeong@arm.com                panic("Invalid PCI configuration write "
2977601Sminkyu.jeong@arm.com                        "for size 2 offset: %#x!\n",
2986418Sgblack@eecs.umich.edu                        offset);
2992SN/A            }
3002SN/A            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
30113557Sgabeblack@google.com                    offset, (uint32_t)pkt->get<uint16_t>());
30213865Sgabeblack@google.com            break;
3032455SN/A          case sizeof(uint32_t):
3049384SAndreas.Sandberg@arm.com            switch (offset) {
3056323Sgblack@eecs.umich.edu              case PrimaryTiming:
30613611Sgabeblack@google.com                primaryTiming = pkt->get<uint32_t>();
30713501Sgabeblack@google.com                break;
30813501Sgabeblack@google.com              case IDEConfig:
3097341Sgblack@eecs.umich.edu                ideConfig = pkt->get<uint32_t>();
3102SN/A                break;
3112SN/A              default:
31212109SRekai.GonzalezAlberquilla@arm.com                panic("Write of unimplemented PCI config. register: %x\n", offset);
31313865Sgabeblack@google.com            }
31412109SRekai.GonzalezAlberquilla@arm.com            break;
31512109SRekai.GonzalezAlberquilla@arm.com          default:
31612109SRekai.GonzalezAlberquilla@arm.com            panic("invalid access size(?) for PCI configspace!\n");
31712109SRekai.GonzalezAlberquilla@arm.com        }
31812109SRekai.GonzalezAlberquilla@arm.com        pkt->makeAtomicResponse();
31913610Sgiacomo.gabrielli@arm.com    }
32012109SRekai.GonzalezAlberquilla@arm.com
32112109SRekai.GonzalezAlberquilla@arm.com    /* Trap command register writes and enable IO/BM as appropriate as well as
32212109SRekai.GonzalezAlberquilla@arm.com     * BARs. */
32312109SRekai.GonzalezAlberquilla@arm.com    switch(offset) {
32413865Sgabeblack@google.com      case PCI0_BASE_ADDR0:
32512109SRekai.GonzalezAlberquilla@arm.com        if (BARAddrs[0] != 0)
32612109SRekai.GonzalezAlberquilla@arm.com            primary.cmdAddr = BARAddrs[0];
32712109SRekai.GonzalezAlberquilla@arm.com        break;
32812109SRekai.GonzalezAlberquilla@arm.com
32912109SRekai.GonzalezAlberquilla@arm.com      case PCI0_BASE_ADDR1:
33013610Sgiacomo.gabrielli@arm.com        if (BARAddrs[1] != 0)
33112109SRekai.GonzalezAlberquilla@arm.com            primary.ctrlAddr = BARAddrs[1];
33212109SRekai.GonzalezAlberquilla@arm.com        break;
33312109SRekai.GonzalezAlberquilla@arm.com
33412109SRekai.GonzalezAlberquilla@arm.com      case PCI0_BASE_ADDR2:
33512109SRekai.GonzalezAlberquilla@arm.com        if (BARAddrs[2] != 0)
33612109SRekai.GonzalezAlberquilla@arm.com            secondary.cmdAddr = BARAddrs[2];
33712109SRekai.GonzalezAlberquilla@arm.com        break;
33812109SRekai.GonzalezAlberquilla@arm.com
33912109SRekai.GonzalezAlberquilla@arm.com      case PCI0_BASE_ADDR3:
34012109SRekai.GonzalezAlberquilla@arm.com        if (BARAddrs[3] != 0)
34112109SRekai.GonzalezAlberquilla@arm.com            secondary.ctrlAddr = BARAddrs[3];
34212109SRekai.GonzalezAlberquilla@arm.com        break;
34312109SRekai.GonzalezAlberquilla@arm.com
34412109SRekai.GonzalezAlberquilla@arm.com      case PCI0_BASE_ADDR4:
34512109SRekai.GonzalezAlberquilla@arm.com        if (BARAddrs[4] != 0)
34612109SRekai.GonzalezAlberquilla@arm.com            bmiAddr = BARAddrs[4];
34712109SRekai.GonzalezAlberquilla@arm.com        break;
34812109SRekai.GonzalezAlberquilla@arm.com
34912109SRekai.GonzalezAlberquilla@arm.com      case PCI_COMMAND:
35012109SRekai.GonzalezAlberquilla@arm.com        DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command);
35113865Sgabeblack@google.com        ioEnabled = (config.command & htole(PCI_CMD_IOSE));
35213865Sgabeblack@google.com        bmEnabled = (config.command & htole(PCI_CMD_BME));
35313865Sgabeblack@google.com        break;
35413865Sgabeblack@google.com    }
35512109SRekai.GonzalezAlberquilla@arm.com    return configDelay;
35612109SRekai.GonzalezAlberquilla@arm.com}
35712109SRekai.GonzalezAlberquilla@arm.com
35813865Sgabeblack@google.comvoid
35913865Sgabeblack@google.comIdeController::Channel::accessCommand(Addr offset,
36013865Sgabeblack@google.com        int size, uint8_t *data, bool read)
36113865Sgabeblack@google.com{
36212109SRekai.GonzalezAlberquilla@arm.com    const Addr SelectOffset = 6;
36312109SRekai.GonzalezAlberquilla@arm.com    const uint8_t SelectDevBit = 0x10;
36412109SRekai.GonzalezAlberquilla@arm.com
36513865Sgabeblack@google.com    if (!read && offset == SelectOffset)
36613865Sgabeblack@google.com        select(*data & SelectDevBit);
36713865Sgabeblack@google.com
36813865Sgabeblack@google.com    if (selected == NULL) {
36912109SRekai.GonzalezAlberquilla@arm.com        assert(size == sizeof(uint8_t));
37012109SRekai.GonzalezAlberquilla@arm.com        *data = 0;
37112109SRekai.GonzalezAlberquilla@arm.com    } else if (read) {
37213865Sgabeblack@google.com        selected->readCommand(offset, size, data);
37313865Sgabeblack@google.com    } else {
37413865Sgabeblack@google.com        selected->writeCommand(offset, size, data);
37513865Sgabeblack@google.com    }
37612109SRekai.GonzalezAlberquilla@arm.com}
37712109SRekai.GonzalezAlberquilla@arm.com
37812109SRekai.GonzalezAlberquilla@arm.comvoid
37913865Sgabeblack@google.comIdeController::Channel::accessControl(Addr offset,
38013865Sgabeblack@google.com        int size, uint8_t *data, bool read)
38112109SRekai.GonzalezAlberquilla@arm.com{
38212109SRekai.GonzalezAlberquilla@arm.com    if (selected == NULL) {
38312109SRekai.GonzalezAlberquilla@arm.com        assert(size == sizeof(uint8_t));
38412109SRekai.GonzalezAlberquilla@arm.com        *data = 0;
38512109SRekai.GonzalezAlberquilla@arm.com    } else if (read) {
38612109SRekai.GonzalezAlberquilla@arm.com        selected->readControl(offset, size, data);
38712109SRekai.GonzalezAlberquilla@arm.com    } else {
38813865Sgabeblack@google.com        selected->writeControl(offset, size, data);
38913865Sgabeblack@google.com    }
39013865Sgabeblack@google.com}
39113865Sgabeblack@google.com
39213865Sgabeblack@google.comvoid
39313865Sgabeblack@google.comIdeController::Channel::accessBMI(Addr offset,
39413865Sgabeblack@google.com        int size, uint8_t *data, bool read)
39513865Sgabeblack@google.com{
39613865Sgabeblack@google.com    assert(offset + size <= sizeof(BMIRegs));
39713865Sgabeblack@google.com    if (read) {
39813865Sgabeblack@google.com        memcpy(data, (uint8_t *)&bmiRegs + offset, size);
39913865Sgabeblack@google.com    } else {
40013865Sgabeblack@google.com        switch (offset) {
40113865Sgabeblack@google.com          case BMICommand:
40213865Sgabeblack@google.com            {
40313865Sgabeblack@google.com                if (size != sizeof(uint8_t))
40413865Sgabeblack@google.com                    panic("Invalid BMIC write size: %x\n", size);
40513865Sgabeblack@google.com
40613865Sgabeblack@google.com                BMICommandReg oldVal = bmiRegs.command;
40713865Sgabeblack@google.com                BMICommandReg newVal = *data;
40813865Sgabeblack@google.com
40913865Sgabeblack@google.com                // if a DMA transfer is in progress, R/W control cannot change
41013865Sgabeblack@google.com                if (oldVal.startStop && oldVal.rw != newVal.rw)
41112109SRekai.GonzalezAlberquilla@arm.com                    oldVal.rw = newVal.rw;
41212109SRekai.GonzalezAlberquilla@arm.com
41313865Sgabeblack@google.com                if (oldVal.startStop != newVal.startStop) {
41413865Sgabeblack@google.com                    if (selected == NULL)
41512109SRekai.GonzalezAlberquilla@arm.com                        panic("DMA start for disk which does not exist\n");
41612109SRekai.GonzalezAlberquilla@arm.com
41712109SRekai.GonzalezAlberquilla@arm.com                    if (oldVal.startStop) {
41812109SRekai.GonzalezAlberquilla@arm.com                        DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
41912109SRekai.GonzalezAlberquilla@arm.com                        bmiRegs.status.active = 0;
42012109SRekai.GonzalezAlberquilla@arm.com
42112109SRekai.GonzalezAlberquilla@arm.com                        selected->abortDma();
42212109SRekai.GonzalezAlberquilla@arm.com                    } else {
42312109SRekai.GonzalezAlberquilla@arm.com                        DPRINTF(IdeCtrl, "Starting DMA transfer\n");
42413865Sgabeblack@google.com                        bmiRegs.status.active = 1;
42513865Sgabeblack@google.com
42613610Sgiacomo.gabrielli@arm.com                        selected->startDma(letoh(bmiRegs.bmidtp));
42713610Sgiacomo.gabrielli@arm.com                    }
42813610Sgiacomo.gabrielli@arm.com                }
42913610Sgiacomo.gabrielli@arm.com
43013610Sgiacomo.gabrielli@arm.com                bmiRegs.command = newVal;
43113610Sgiacomo.gabrielli@arm.com            }
43213610Sgiacomo.gabrielli@arm.com            break;
43313610Sgiacomo.gabrielli@arm.com          case BMIStatus:
43413610Sgiacomo.gabrielli@arm.com            {
43513865Sgabeblack@google.com                if (size != sizeof(uint8_t))
43613865Sgabeblack@google.com                    panic("Invalid BMIS write size: %x\n", size);
43713610Sgiacomo.gabrielli@arm.com
43813610Sgiacomo.gabrielli@arm.com                BMIStatusReg oldVal = bmiRegs.status;
43913610Sgiacomo.gabrielli@arm.com                BMIStatusReg newVal = *data;
44013610Sgiacomo.gabrielli@arm.com
44113610Sgiacomo.gabrielli@arm.com                // the BMIDEA bit is read only
44213610Sgiacomo.gabrielli@arm.com                newVal.active = oldVal.active;
44313610Sgiacomo.gabrielli@arm.com
44413610Sgiacomo.gabrielli@arm.com                // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
44513610Sgiacomo.gabrielli@arm.com                if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) {
44612109SRekai.GonzalezAlberquilla@arm.com                    newVal.intStatus = 0; // clear the interrupt?
44713622Sgabeblack@google.com                } else {
44813865Sgabeblack@google.com                    // Assigning two bitunion fields to each other does not
4499920Syasuko.eckert@amd.com                    // work as intended, so we need to use this temporary variable
4509920Syasuko.eckert@amd.com                    // to get around the bug.
4519920Syasuko.eckert@amd.com                    uint8_t tmp = oldVal.intStatus;
45210338SCurtis.Dunham@arm.com                    newVal.intStatus = tmp;
4539920Syasuko.eckert@amd.com                }
4549920Syasuko.eckert@amd.com                if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) {
4559920Syasuko.eckert@amd.com                    newVal.dmaError = 0;
4569920Syasuko.eckert@amd.com                } else {
4579920Syasuko.eckert@amd.com                    uint8_t tmp = oldVal.dmaError;
4589920Syasuko.eckert@amd.com                    newVal.dmaError = tmp;
4599920Syasuko.eckert@amd.com                }
4609920Syasuko.eckert@amd.com
4619920Syasuko.eckert@amd.com                bmiRegs.status = newVal;
4629920Syasuko.eckert@amd.com            }
4639920Syasuko.eckert@amd.com            break;
46413557Sgabeblack@google.com          case BMIDescTablePtr:
46513865Sgabeblack@google.com            if (size != sizeof(uint32_t))
4662SN/A                panic("Invalid BMIDTP write size: %x\n", size);
4679384SAndreas.Sandberg@arm.com            bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
4686323Sgblack@eecs.umich.edu            break;
4697601Sminkyu.jeong@arm.com          default:
4707601Sminkyu.jeong@arm.com            if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
4719426SAndreas.Sandberg@ARM.com                    size != sizeof(uint32_t))
4722SN/A                panic("IDE controller write of invalid write size: %x\n", size);
4732SN/A            memcpy((uint8_t *)&bmiRegs + offset, data, size);
47413557Sgabeblack@google.com        }
47513865Sgabeblack@google.com    }
4762455SN/A}
4779384SAndreas.Sandberg@arm.com
4786323Sgblack@eecs.umich.eduvoid
4798733Sgeoffrey.blake@arm.comIdeController::dispatchAccess(PacketPtr pkt, bool read)
4808733Sgeoffrey.blake@arm.com{
4818733Sgeoffrey.blake@arm.com    if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
48213611Sgabeblack@google.com         panic("Bad IDE read size: %d\n", pkt->getSize());
48313501Sgabeblack@google.com
48413501Sgabeblack@google.com    if (!ioEnabled) {
4852SN/A        pkt->makeAtomicResponse();
4862SN/A        DPRINTF(IdeCtrl, "io not enabled\n");
48713557Sgabeblack@google.com        return;
48813865Sgabeblack@google.com    }
48912109SRekai.GonzalezAlberquilla@arm.com
49012109SRekai.GonzalezAlberquilla@arm.com    Addr addr = pkt->getAddr();
49112109SRekai.GonzalezAlberquilla@arm.com    int size = pkt->getSize();
49212109SRekai.GonzalezAlberquilla@arm.com    uint8_t *dataPtr = pkt->getPtr<uint8_t>();
49312109SRekai.GonzalezAlberquilla@arm.com
49412109SRekai.GonzalezAlberquilla@arm.com    if (addr >= primary.cmdAddr &&
49512109SRekai.GonzalezAlberquilla@arm.com            addr < (primary.cmdAddr + primary.cmdSize)) {
49612109SRekai.GonzalezAlberquilla@arm.com        addr -= primary.cmdAddr;
49713557Sgabeblack@google.com        // linux may have shifted the address by ioShift,
49813865Sgabeblack@google.com        // here we shift it back, similarly for ctrlOffset.
49912109SRekai.GonzalezAlberquilla@arm.com        addr >>= ioShift;
50012109SRekai.GonzalezAlberquilla@arm.com        primary.accessCommand(addr, size, dataPtr, read);
50112109SRekai.GonzalezAlberquilla@arm.com    } else if (addr >= primary.ctrlAddr &&
50212109SRekai.GonzalezAlberquilla@arm.com               addr < (primary.ctrlAddr + primary.ctrlSize)) {
50312109SRekai.GonzalezAlberquilla@arm.com        addr -= primary.ctrlAddr;
50412109SRekai.GonzalezAlberquilla@arm.com        addr += ctrlOffset;
50512109SRekai.GonzalezAlberquilla@arm.com        primary.accessControl(addr, size, dataPtr, read);
50612109SRekai.GonzalezAlberquilla@arm.com    } else if (addr >= secondary.cmdAddr &&
50713557Sgabeblack@google.com               addr < (secondary.cmdAddr + secondary.cmdSize)) {
50813865Sgabeblack@google.com        addr -= secondary.cmdAddr;
50913610Sgiacomo.gabrielli@arm.com        secondary.accessCommand(addr, size, dataPtr, read);
51013610Sgiacomo.gabrielli@arm.com    } else if (addr >= secondary.ctrlAddr &&
51113610Sgiacomo.gabrielli@arm.com               addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
51213610Sgiacomo.gabrielli@arm.com        addr -= secondary.ctrlAddr;
51313610Sgiacomo.gabrielli@arm.com        secondary.accessControl(addr, size, dataPtr, read);
51413610Sgiacomo.gabrielli@arm.com    } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
51513610Sgiacomo.gabrielli@arm.com        if (!read && !bmEnabled)
51613610Sgiacomo.gabrielli@arm.com            return;
51713610Sgiacomo.gabrielli@arm.com        addr -= bmiAddr;
51813865Sgabeblack@google.com        if (addr < sizeof(Channel::BMIRegs)) {
5199920Syasuko.eckert@amd.com            primary.accessBMI(addr, size, dataPtr, read);
5209920Syasuko.eckert@amd.com        } else {
5219920Syasuko.eckert@amd.com            addr -= sizeof(Channel::BMIRegs);
5229920Syasuko.eckert@amd.com            secondary.accessBMI(addr, size, dataPtr, read);
5239920Syasuko.eckert@amd.com        }
5249920Syasuko.eckert@amd.com    } else {
5259920Syasuko.eckert@amd.com        panic("IDE controller access to invalid address: %#x\n", addr);
5269920Syasuko.eckert@amd.com    }
5279920Syasuko.eckert@amd.com
5289920Syasuko.eckert@amd.com#ifndef NDEBUG
5299920Syasuko.eckert@amd.com    uint32_t data;
5309920Syasuko.eckert@amd.com    if (pkt->getSize() == 1)
53113865Sgabeblack@google.com        data = pkt->get<uint8_t>();
53213865Sgabeblack@google.com    else if (pkt->getSize() == 2)
5332SN/A        data = pkt->get<uint16_t>();
5347720Sgblack@eecs.umich.edu    else
53513865Sgabeblack@google.com        data = pkt->get<uint32_t>();
5362190SN/A    DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
5377720Sgblack@eecs.umich.edu            read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
5382190SN/A#endif
5392190SN/A
54013865Sgabeblack@google.com    pkt->makeAtomicResponse();
54113865Sgabeblack@google.com}
54213865Sgabeblack@google.com
54313865Sgabeblack@google.comTick
54413865Sgabeblack@google.comIdeController::read(PacketPtr pkt)
5457597Sminkyu.jeong@arm.com{
54613557Sgabeblack@google.com    dispatchAccess(pkt, true);
54713865Sgabeblack@google.com    return pioDelay;
5484172Ssaidi@eecs.umich.edu}
5499384SAndreas.Sandberg@arm.com
5504172Ssaidi@eecs.umich.eduTick
5514172Ssaidi@eecs.umich.eduIdeController::write(PacketPtr pkt)
55213557Sgabeblack@google.com{
55313865Sgabeblack@google.com    dispatchAccess(pkt, false);
5542SN/A    return pioDelay;
55513865Sgabeblack@google.com}
5562SN/A
5572SN/Avoid
5586221Snate@binkert.orgIdeController::serialize(std::ostream &os)
55913865Sgabeblack@google.com{
5602SN/A    // Serialize the PciDevice base class
5619384SAndreas.Sandberg@arm.com    PciDevice::serialize(os);
5622SN/A
5632SN/A    // Serialize channels
5646221Snate@binkert.org    primary.serialize("primary", os);
56513865Sgabeblack@google.com    secondary.serialize("secondary", os);
5662SN/A
56713865Sgabeblack@google.com    // Serialize config registers
5686313Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(primaryTiming);
5696313Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(secondaryTiming);
57012106SRekai.GonzalezAlberquilla@arm.com    SERIALIZE_SCALAR(deviceTiming);
57113865Sgabeblack@google.com    SERIALIZE_SCALAR(udmaControl);
5726313Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(udmaTiming);
57312106SRekai.GonzalezAlberquilla@arm.com    SERIALIZE_SCALAR(ideConfig);
57410033SAli.Saidi@ARM.com
57510033SAli.Saidi@ARM.com    // Serialize internal state
57613865Sgabeblack@google.com    SERIALIZE_SCALAR(ioEnabled);
5772190SN/A    SERIALIZE_SCALAR(bmEnabled);
57813953Sgiacomo.gabrielli@arm.com    SERIALIZE_SCALAR(bmiAddr);
57913953Sgiacomo.gabrielli@arm.com    SERIALIZE_SCALAR(bmiSize);
58013953Sgiacomo.gabrielli@arm.com}
58113953Sgiacomo.gabrielli@arm.com
58213953Sgiacomo.gabrielli@arm.comvoid
58313953Sgiacomo.gabrielli@arm.comIdeController::Channel::serialize(const std::string &base, std::ostream &os)
58413953Sgiacomo.gabrielli@arm.com{
58513953Sgiacomo.gabrielli@arm.com    paramOut(os, base + ".cmdAddr", cmdAddr);
58613953Sgiacomo.gabrielli@arm.com    paramOut(os, base + ".cmdSize", cmdSize);
58713953Sgiacomo.gabrielli@arm.com    paramOut(os, base + ".ctrlAddr", ctrlAddr);
58813953Sgiacomo.gabrielli@arm.com    paramOut(os, base + ".ctrlSize", ctrlSize);
58913953Sgiacomo.gabrielli@arm.com    uint8_t command = bmiRegs.command;
59013557Sgabeblack@google.com    paramOut(os, base + ".bmiRegs.command", command);
59113865Sgabeblack@google.com    paramOut(os, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
5922SN/A    uint8_t status = bmiRegs.status;
59313865Sgabeblack@google.com    paramOut(os, base + ".bmiRegs.status", status);
5942SN/A    paramOut(os, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
5959426SAndreas.Sandberg@ARM.com    paramOut(os, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
59613865Sgabeblack@google.com    paramOut(os, base + ".selectBit", selectBit);
59713865Sgabeblack@google.com}
59813865Sgabeblack@google.com
59913865Sgabeblack@google.comvoid
60013865Sgabeblack@google.comIdeController::unserialize(Checkpoint *cp, const std::string &section)
6019426SAndreas.Sandberg@ARM.com{
60213865Sgabeblack@google.com    // Unserialize the PciDevice base class
60313865Sgabeblack@google.com    PciDevice::unserialize(cp, section);
60413865Sgabeblack@google.com
60513865Sgabeblack@google.com    // Unserialize channels
60613865Sgabeblack@google.com    primary.unserialize("primary", cp, section);
60713865Sgabeblack@google.com    secondary.unserialize("secondary", cp, section);
60813865Sgabeblack@google.com
60913865Sgabeblack@google.com    // Unserialize config registers
61013865Sgabeblack@google.com    UNSERIALIZE_SCALAR(primaryTiming);
61113865Sgabeblack@google.com    UNSERIALIZE_SCALAR(secondaryTiming);
61213865Sgabeblack@google.com    UNSERIALIZE_SCALAR(deviceTiming);
61313865Sgabeblack@google.com    UNSERIALIZE_SCALAR(udmaControl);
61413865Sgabeblack@google.com    UNSERIALIZE_SCALAR(udmaTiming);
61513865Sgabeblack@google.com    UNSERIALIZE_SCALAR(ideConfig);
61613865Sgabeblack@google.com
61713865Sgabeblack@google.com    // Unserialize internal state
61813865Sgabeblack@google.com    UNSERIALIZE_SCALAR(ioEnabled);
61913865Sgabeblack@google.com    UNSERIALIZE_SCALAR(bmEnabled);
62013865Sgabeblack@google.com    UNSERIALIZE_SCALAR(bmiAddr);
62113865Sgabeblack@google.com    UNSERIALIZE_SCALAR(bmiSize);
62213865Sgabeblack@google.com}
62313865Sgabeblack@google.com
62413865Sgabeblack@google.comvoid
6259426SAndreas.Sandberg@ARM.comIdeController::Channel::unserialize(const std::string &base, Checkpoint *cp,
62613557Sgabeblack@google.com    const std::string &section)
62713865Sgabeblack@google.com{
62812109SRekai.GonzalezAlberquilla@arm.com    paramIn(cp, section, base + ".cmdAddr", cmdAddr);
62912109SRekai.GonzalezAlberquilla@arm.com    paramIn(cp, section, base + ".cmdSize", cmdSize);
63012109SRekai.GonzalezAlberquilla@arm.com    paramIn(cp, section, base + ".ctrlAddr", ctrlAddr);
63112109SRekai.GonzalezAlberquilla@arm.com    paramIn(cp, section, base + ".ctrlSize", ctrlSize);
63213557Sgabeblack@google.com    uint8_t command;
63313865Sgabeblack@google.com    paramIn(cp, section, base +".bmiRegs.command", command);
63412109SRekai.GonzalezAlberquilla@arm.com    bmiRegs.command = command;
63512109SRekai.GonzalezAlberquilla@arm.com    paramIn(cp, section, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
63612109SRekai.GonzalezAlberquilla@arm.com    uint8_t status;
63712109SRekai.GonzalezAlberquilla@arm.com    paramIn(cp, section, base + ".bmiRegs.status", status);
63813557Sgabeblack@google.com    bmiRegs.status = status;
63913865Sgabeblack@google.com    paramIn(cp, section, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
64012109SRekai.GonzalezAlberquilla@arm.com    paramIn(cp, section, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
64112109SRekai.GonzalezAlberquilla@arm.com    paramIn(cp, section, base + ".selectBit", selectBit);
64212109SRekai.GonzalezAlberquilla@arm.com    select(selectBit);
64312109SRekai.GonzalezAlberquilla@arm.com}
64412109SRekai.GonzalezAlberquilla@arm.com
64513557Sgabeblack@google.comIdeController *
64613865Sgabeblack@google.comIdeControllerParams::create()
64712109SRekai.GonzalezAlberquilla@arm.com{
64812109SRekai.GonzalezAlberquilla@arm.com    return new IdeController(this);
64912109SRekai.GonzalezAlberquilla@arm.com}
65012109SRekai.GonzalezAlberquilla@arm.com