1848SN/A/*
29956SN/A * Copyright (c) 2013 ARM Limited
39956SN/A * All rights reserved
49956SN/A *
59956SN/A * The license below extends only to copyright in the software and shall
69956SN/A * not be construed as granting a license to any other intellectual
79956SN/A * property including but not limited to intellectual property relating
89956SN/A * to a hardware implementation of the functionality of the software
99956SN/A * licensed hereunder.  You may use the software subject to the license
109956SN/A * terms below provided that you ensure that this notice is replicated
119956SN/A * unmodified and in its entirety in all distributions of the software,
129956SN/A * modified or unmodified, in source code or in binary form.
139956SN/A *
141762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
15848SN/A * All rights reserved.
16848SN/A *
17848SN/A * Redistribution and use in source and binary forms, with or without
18848SN/A * modification, are permitted provided that the following conditions are
19848SN/A * met: redistributions of source code must retain the above copyright
20848SN/A * notice, this list of conditions and the following disclaimer;
21848SN/A * redistributions in binary form must reproduce the above copyright
22848SN/A * notice, this list of conditions and the following disclaimer in the
23848SN/A * documentation and/or other materials provided with the distribution;
24848SN/A * neither the name of the copyright holders nor the names of its
25848SN/A * contributors may be used to endorse or promote products derived from
26848SN/A * this software without specific prior written permission.
27848SN/A *
28848SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29848SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30848SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31848SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32848SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33848SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34848SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35848SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36848SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37848SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38848SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392665SN/A *
402665SN/A * Authors: Andrew Schultz
412665SN/A *          Ali Saidi
422665SN/A *          Miguel Serrano
43848SN/A */
44848SN/A
4511264Sandreas.sandberg@arm.com#include "dev/storage/ide_ctrl.hh"
4611264Sandreas.sandberg@arm.com
47848SN/A#include <string>
48848SN/A
49848SN/A#include "cpu/intr_control.hh"
508232SN/A#include "debug/IdeCtrl.hh"
5111264Sandreas.sandberg@arm.com#include "dev/storage/ide_disk.hh"
522565SN/A#include "mem/packet.hh"
533348SN/A#include "mem/packet_access.hh"
544762SN/A#include "params/IdeController.hh"
552565SN/A#include "sim/byteswap.hh"
56848SN/A
578737SN/A// clang complains about std::set being overloaded with Packet::set if
588737SN/A// we open up the entire namespace std
598737SN/Ausing std::string;
60848SN/A
615772SN/A// Bus master IDE registers
625772SN/Aenum BMIRegOffset {
635772SN/A    BMICommand = 0x0,
645772SN/A    BMIStatus = 0x2,
655772SN/A    BMIDescTablePtr = 0x4
665772SN/A};
675772SN/A
685772SN/A// PCI config space registers
695772SN/Aenum ConfRegOffset {
705772SN/A    PrimaryTiming = 0x40,
715772SN/A    SecondaryTiming = 0x42,
725772SN/A    DeviceTiming = 0x44,
735772SN/A    UDMAControl = 0x48,
745772SN/A    UDMATiming = 0x4A,
755772SN/A    IDEConfig = 0x54
765772SN/A};
775772SN/A
785772SN/Astatic const uint16_t timeRegWithDecodeEn = 0x8000;
795772SN/A
805772SN/AIdeController::Channel::Channel(
815772SN/A        string newName, Addr _cmdSize, Addr _ctrlSize) :
825772SN/A    _name(newName),
835772SN/A    cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize),
845772SN/A    master(NULL), slave(NULL), selected(NULL)
855772SN/A{
8612895Sjason@lowepower.com    bmiRegs.reset();
875772SN/A    bmiRegs.status.dmaCap0 = 1;
885772SN/A    bmiRegs.status.dmaCap1 = 1;
895772SN/A}
905772SN/A
915772SN/AIdeController::Channel::~Channel()
925772SN/A{
935772SN/A}
94848SN/A
951149SN/AIdeController::IdeController(Params *p)
969807SN/A    : PciDevice(p), primary(name() + ".primary", BARSize[0], BARSize[1]),
975772SN/A    secondary(name() + ".secondary", BARSize[2], BARSize[3]),
985772SN/A    bmiAddr(0), bmiSize(BARSize[4]),
995772SN/A    primaryTiming(htole(timeRegWithDecodeEn)),
1005772SN/A    secondaryTiming(htole(timeRegWithDecodeEn)),
1015772SN/A    deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
1027750SN/A    ioEnabled(false), bmEnabled(false),
1037750SN/A    ioShift(p->io_shift), ctrlOffset(p->ctrl_offset)
104848SN/A{
105848SN/A
1065772SN/A    // Assign the disks to channels
1071149SN/A    for (int i = 0; i < params()->disks.size(); i++) {
10812201Sgabeblack@google.com        if (!params()->disks[i])
10912201Sgabeblack@google.com            continue;
11012201Sgabeblack@google.com        switch (i) {
11112201Sgabeblack@google.com          case 0:
11212201Sgabeblack@google.com            primary.master = params()->disks[0];
11312201Sgabeblack@google.com            break;
11412201Sgabeblack@google.com          case 1:
11512201Sgabeblack@google.com            primary.slave = params()->disks[1];
11612201Sgabeblack@google.com            break;
11712201Sgabeblack@google.com          case 2:
11812201Sgabeblack@google.com            secondary.master = params()->disks[2];
11912201Sgabeblack@google.com            break;
12012201Sgabeblack@google.com          case 3:
12112201Sgabeblack@google.com            secondary.slave = params()->disks[3];
12212201Sgabeblack@google.com            break;
12312201Sgabeblack@google.com          default:
12412201Sgabeblack@google.com            panic("IDE controllers support a maximum "
12512201Sgabeblack@google.com                  "of 4 devices attached!\n");
12612201Sgabeblack@google.com        }
1275772SN/A        params()->disks[i]->setController(this);
128848SN/A    }
12912201Sgabeblack@google.com
1305772SN/A    primary.select(false);
1315772SN/A    secondary.select(false);
1326431SN/A
1338198SN/A    if ((BARAddrs[0] & ~BAR_IO_MASK) && (!legacyIO[0] || ioShift)) {
1347750SN/A        primary.cmdAddr = BARAddrs[0];  primary.cmdSize = BARSize[0];
1359956SN/A        primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARSize[1];
1367750SN/A    }
1378198SN/A    if ((BARAddrs[2] & ~BAR_IO_MASK) && (!legacyIO[2] || ioShift)) {
1387750SN/A        secondary.cmdAddr = BARAddrs[2];  secondary.cmdSize = BARSize[2];
1399956SN/A        secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARSize[3];
1407750SN/A    }
1417750SN/A
1426431SN/A    ioEnabled = (config.command & htole(PCI_CMD_IOSE));
1436431SN/A    bmEnabled = (config.command & htole(PCI_CMD_BME));
144864SN/A}
145864SN/A
146929SN/Abool
147929SN/AIdeController::isDiskSelected(IdeDisk *diskPtr)
148929SN/A{
1495772SN/A    return (primary.selected == diskPtr || secondary.selected == diskPtr);
150929SN/A}
151929SN/A
1525772SN/Avoid
1535772SN/AIdeController::intrPost()
1545772SN/A{
1555772SN/A    primary.bmiRegs.status.intStatus = 1;
1569807SN/A    PciDevice::intrPost();
1575772SN/A}
158849SN/A
159849SN/Avoid
160849SN/AIdeController::setDmaComplete(IdeDisk *disk)
161849SN/A{
1625772SN/A    Channel *channel;
1635772SN/A    if (disk == primary.master || disk == primary.slave) {
1645772SN/A        channel = &primary;
1655772SN/A    } else if (disk == secondary.master || disk == secondary.slave) {
1665772SN/A        channel = &secondary;
1675772SN/A    } else {
1685772SN/A        panic("Unable to find disk based on pointer %#x\n", disk);
1695772SN/A    }
170849SN/A
1715772SN/A    channel->bmiRegs.command.startStop = 0;
1725772SN/A    channel->bmiRegs.status.active = 0;
1735772SN/A    channel->bmiRegs.status.intStatus = 1;
174849SN/A}
175849SN/A
1762846SN/ATick
1773349SN/AIdeController::readConfig(PacketPtr pkt)
178848SN/A{
1792846SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1804875SN/A    if (offset < PCI_DEVICE_SPECIFIC) {
1819807SN/A        return PciDevice::readConfig(pkt);
1824875SN/A    }
1834875SN/A
1842846SN/A    switch (pkt->getSize()) {
1852846SN/A      case sizeof(uint8_t):
1862565SN/A        switch (offset) {
1875772SN/A          case DeviceTiming:
18813342Sgabeblack@google.com            pkt->setLE<uint8_t>(deviceTiming);
1891817SN/A            break;
1905772SN/A          case UDMAControl:
19113342Sgabeblack@google.com            pkt->setLE<uint8_t>(udmaControl);
1921817SN/A            break;
1935772SN/A          case PrimaryTiming + 1:
19413342Sgabeblack@google.com            pkt->setLE<uint8_t>(bits(htole(primaryTiming), 15, 8));
1952565SN/A            break;
1965772SN/A          case SecondaryTiming + 1:
19713342Sgabeblack@google.com            pkt->setLE<uint8_t>(bits(htole(secondaryTiming), 15, 8));
1982565SN/A            break;
1995772SN/A          case IDEConfig:
20013342Sgabeblack@google.com            pkt->setLE<uint8_t>(bits(htole(ideConfig), 7, 0));
2012565SN/A            break;
2025772SN/A          case IDEConfig + 1:
20313342Sgabeblack@google.com            pkt->setLE<uint8_t>(bits(htole(ideConfig), 15, 8));
2041817SN/A            break;
2051817SN/A          default:
2062565SN/A            panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
2072565SN/A                    offset);
208848SN/A        }
2092846SN/A        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
21013342Sgabeblack@google.com                (uint32_t)pkt->getLE<uint8_t>());
2112846SN/A        break;
2122846SN/A      case sizeof(uint16_t):
2132565SN/A        switch (offset) {
21410775SN/A          case UDMAControl:
21513342Sgabeblack@google.com            pkt->setLE<uint16_t>(udmaControl);
21610775SN/A            break;
2175772SN/A          case PrimaryTiming:
21813342Sgabeblack@google.com            pkt->setLE<uint16_t>(primaryTiming);
2191877SN/A            break;
2205772SN/A          case SecondaryTiming:
22113342Sgabeblack@google.com            pkt->setLE<uint16_t>(secondaryTiming);
2221877SN/A            break;
2235772SN/A          case UDMATiming:
22413342Sgabeblack@google.com            pkt->setLE<uint16_t>(udmaTiming);
2252565SN/A            break;
2265772SN/A          case IDEConfig:
22713342Sgabeblack@google.com            pkt->setLE<uint16_t>(ideConfig);
2281817SN/A            break;
2291817SN/A          default:
2302565SN/A            panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
2312565SN/A                    offset);
2321817SN/A        }
2332846SN/A        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
23413342Sgabeblack@google.com                (uint32_t)pkt->getLE<uint16_t>());
2352846SN/A        break;
2362846SN/A      case sizeof(uint32_t):
23710775SN/A        switch (offset) {
23810775SN/A          case PrimaryTiming:
23913342Sgabeblack@google.com            pkt->setLE<uint32_t>(primaryTiming);
24010775SN/A            break;
24110775SN/A          case IDEConfig:
24213342Sgabeblack@google.com            pkt->setLE<uint32_t>(ideConfig);
24310775SN/A            break;
24410775SN/A          default:
2458522SN/A            panic("No 32bit reads implemented for this device.");
24610775SN/A        }
2472846SN/A        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
24813342Sgabeblack@google.com                (uint32_t)pkt->getLE<uint32_t>());
2492846SN/A        break;
2502846SN/A      default:
2512846SN/A        panic("invalid access size(?) for PCI configspace!\n");
2522565SN/A    }
2534870SN/A    pkt->makeAtomicResponse();
2542846SN/A    return configDelay;
2552565SN/A}
2562565SN/A
2572846SN/A
2582846SN/ATick
2593349SN/AIdeController::writeConfig(PacketPtr pkt)
2602565SN/A{
2612846SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
2622565SN/A    if (offset < PCI_DEVICE_SPECIFIC) {
2639807SN/A        PciDevice::writeConfig(pkt);
2642565SN/A    } else {
2652846SN/A        switch (pkt->getSize()) {
2662846SN/A          case sizeof(uint8_t):
2672846SN/A            switch (offset) {
2685772SN/A              case DeviceTiming:
26913342Sgabeblack@google.com                deviceTiming = pkt->getLE<uint8_t>();
2702846SN/A                break;
2715772SN/A              case UDMAControl:
27213342Sgabeblack@google.com                udmaControl = pkt->getLE<uint8_t>();
2732846SN/A                break;
2745772SN/A              case IDEConfig:
27513342Sgabeblack@google.com                replaceBits(ideConfig, 7, 0, pkt->getLE<uint8_t>());
2762846SN/A                break;
2775772SN/A              case IDEConfig + 1:
27813342Sgabeblack@google.com                replaceBits(ideConfig, 15, 8, pkt->getLE<uint8_t>());
2792846SN/A                break;
2802846SN/A              default:
2815772SN/A                panic("Invalid PCI configuration write "
2825772SN/A                        "for size 1 offset: %#x!\n", offset);
2832846SN/A            }
2842846SN/A            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
28513342Sgabeblack@google.com                    offset, (uint32_t)pkt->getLE<uint8_t>());
2862846SN/A            break;
2872846SN/A          case sizeof(uint16_t):
2882846SN/A            switch (offset) {
28910775SN/A              case UDMAControl:
29013342Sgabeblack@google.com                udmaControl = pkt->getLE<uint16_t>();
29110775SN/A                break;
2925772SN/A              case PrimaryTiming:
29313342Sgabeblack@google.com                primaryTiming = pkt->getLE<uint16_t>();
2942846SN/A                break;
2955772SN/A              case SecondaryTiming:
29613342Sgabeblack@google.com                secondaryTiming = pkt->getLE<uint16_t>();
2972846SN/A                break;
2985772SN/A              case UDMATiming:
29913342Sgabeblack@google.com                udmaTiming = pkt->getLE<uint16_t>();
3002846SN/A                break;
3015772SN/A              case IDEConfig:
30213342Sgabeblack@google.com                ideConfig = pkt->getLE<uint16_t>();
3032846SN/A                break;
3042846SN/A              default:
3055772SN/A                panic("Invalid PCI configuration write "
3065772SN/A                        "for size 2 offset: %#x!\n",
3072846SN/A                        offset);
3082846SN/A            }
3092846SN/A            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
31013342Sgabeblack@google.com                    offset, (uint32_t)pkt->getLE<uint16_t>());
3112846SN/A            break;
3122846SN/A          case sizeof(uint32_t):
31310775SN/A            switch (offset) {
31410775SN/A              case PrimaryTiming:
31513342Sgabeblack@google.com                primaryTiming = pkt->getLE<uint32_t>();
31610775SN/A                break;
31710775SN/A              case IDEConfig:
31813342Sgabeblack@google.com                ideConfig = pkt->getLE<uint32_t>();
31910775SN/A                break;
32010775SN/A              default:
3218522SN/A                panic("Write of unimplemented PCI config. register: %x\n", offset);
32210775SN/A            }
3232846SN/A            break;
3242846SN/A          default:
3252846SN/A            panic("invalid access size(?) for PCI configspace!\n");
3262846SN/A        }
3274875SN/A        pkt->makeAtomicResponse();
3282565SN/A    }
3292565SN/A
3302846SN/A    /* Trap command register writes and enable IO/BM as appropriate as well as
3312846SN/A     * BARs. */
3322565SN/A    switch(offset) {
333897SN/A      case PCI0_BASE_ADDR0:
3342565SN/A        if (BARAddrs[0] != 0)
3355772SN/A            primary.cmdAddr = BARAddrs[0];
336897SN/A        break;
337848SN/A
338897SN/A      case PCI0_BASE_ADDR1:
3392565SN/A        if (BARAddrs[1] != 0)
3405772SN/A            primary.ctrlAddr = BARAddrs[1];
341897SN/A        break;
342848SN/A
343897SN/A      case PCI0_BASE_ADDR2:
3442565SN/A        if (BARAddrs[2] != 0)
3455772SN/A            secondary.cmdAddr = BARAddrs[2];
346897SN/A        break;
347848SN/A
348897SN/A      case PCI0_BASE_ADDR3:
3492565SN/A        if (BARAddrs[3] != 0)
3505772SN/A            secondary.ctrlAddr = BARAddrs[3];
351897SN/A        break;
352848SN/A
353897SN/A      case PCI0_BASE_ADDR4:
3542565SN/A        if (BARAddrs[4] != 0)
3555772SN/A            bmiAddr = BARAddrs[4];
356897SN/A        break;
3572846SN/A
3582846SN/A      case PCI_COMMAND:
3598522SN/A        DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command);
3605772SN/A        ioEnabled = (config.command & htole(PCI_CMD_IOSE));
3615772SN/A        bmEnabled = (config.command & htole(PCI_CMD_BME));
3622846SN/A        break;
363848SN/A    }
3642846SN/A    return configDelay;
365848SN/A}
366848SN/A
3675772SN/Avoid
3685772SN/AIdeController::Channel::accessCommand(Addr offset,
3695772SN/A        int size, uint8_t *data, bool read)
3705772SN/A{
3715772SN/A    const Addr SelectOffset = 6;
3725772SN/A    const uint8_t SelectDevBit = 0x10;
3735772SN/A
3745772SN/A    if (!read && offset == SelectOffset)
3755772SN/A        select(*data & SelectDevBit);
3765772SN/A
3775772SN/A    if (selected == NULL) {
3785772SN/A        assert(size == sizeof(uint8_t));
3795772SN/A        *data = 0;
3805772SN/A    } else if (read) {
3815772SN/A        selected->readCommand(offset, size, data);
3825772SN/A    } else {
3835772SN/A        selected->writeCommand(offset, size, data);
3845772SN/A    }
3855772SN/A}
3865772SN/A
3875772SN/Avoid
3885772SN/AIdeController::Channel::accessControl(Addr offset,
3895772SN/A        int size, uint8_t *data, bool read)
3905772SN/A{
3915772SN/A    if (selected == NULL) {
3925772SN/A        assert(size == sizeof(uint8_t));
3935772SN/A        *data = 0;
3945772SN/A    } else if (read) {
3955772SN/A        selected->readControl(offset, size, data);
3965772SN/A    } else {
3975772SN/A        selected->writeControl(offset, size, data);
3985772SN/A    }
3995772SN/A}
4005772SN/A
4015772SN/Avoid
4025772SN/AIdeController::Channel::accessBMI(Addr offset,
4035772SN/A        int size, uint8_t *data, bool read)
4045772SN/A{
4055772SN/A    assert(offset + size <= sizeof(BMIRegs));
4065772SN/A    if (read) {
4075772SN/A        memcpy(data, (uint8_t *)&bmiRegs + offset, size);
4085772SN/A    } else {
4095772SN/A        switch (offset) {
4105772SN/A          case BMICommand:
4115772SN/A            {
4125772SN/A                if (size != sizeof(uint8_t))
4135772SN/A                    panic("Invalid BMIC write size: %x\n", size);
4145772SN/A
4155772SN/A                BMICommandReg oldVal = bmiRegs.command;
4165772SN/A                BMICommandReg newVal = *data;
4175772SN/A
4185772SN/A                // if a DMA transfer is in progress, R/W control cannot change
4195772SN/A                if (oldVal.startStop && oldVal.rw != newVal.rw)
4205772SN/A                    oldVal.rw = newVal.rw;
4215772SN/A
4225772SN/A                if (oldVal.startStop != newVal.startStop) {
4235772SN/A                    if (selected == NULL)
4245772SN/A                        panic("DMA start for disk which does not exist\n");
4255772SN/A
4265772SN/A                    if (oldVal.startStop) {
4275772SN/A                        DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
4285772SN/A                        bmiRegs.status.active = 0;
4295772SN/A
4305772SN/A                        selected->abortDma();
4315772SN/A                    } else {
4325772SN/A                        DPRINTF(IdeCtrl, "Starting DMA transfer\n");
4335772SN/A                        bmiRegs.status.active = 1;
4345772SN/A
4355772SN/A                        selected->startDma(letoh(bmiRegs.bmidtp));
4365772SN/A                    }
4375772SN/A                }
4385772SN/A
4395772SN/A                bmiRegs.command = newVal;
4405772SN/A            }
4415772SN/A            break;
4425772SN/A          case BMIStatus:
4435772SN/A            {
4445772SN/A                if (size != sizeof(uint8_t))
4455772SN/A                    panic("Invalid BMIS write size: %x\n", size);
4465772SN/A
4475772SN/A                BMIStatusReg oldVal = bmiRegs.status;
4485772SN/A                BMIStatusReg newVal = *data;
4495772SN/A
4505772SN/A                // the BMIDEA bit is read only
4515772SN/A                newVal.active = oldVal.active;
4525772SN/A
4535772SN/A                // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
4549956SN/A                if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) {
4555772SN/A                    newVal.intStatus = 0; // clear the interrupt?
4569956SN/A                } else {
4579956SN/A                    // Assigning two bitunion fields to each other does not
4589956SN/A                    // work as intended, so we need to use this temporary variable
4599956SN/A                    // to get around the bug.
4609956SN/A                    uint8_t tmp = oldVal.intStatus;
4619956SN/A                    newVal.intStatus = tmp;
4629956SN/A                }
4639956SN/A                if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) {
4645772SN/A                    newVal.dmaError = 0;
4659956SN/A                } else {
4669956SN/A                    uint8_t tmp = oldVal.dmaError;
4679956SN/A                    newVal.dmaError = tmp;
4689956SN/A                }
4695772SN/A
4705772SN/A                bmiRegs.status = newVal;
4715772SN/A            }
4725772SN/A            break;
4735772SN/A          case BMIDescTablePtr:
4745772SN/A            if (size != sizeof(uint32_t))
4755772SN/A                panic("Invalid BMIDTP write size: %x\n", size);
4765772SN/A            bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
4775772SN/A            break;
4785772SN/A          default:
4795772SN/A            if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
4805772SN/A                    size != sizeof(uint32_t))
4815772SN/A                panic("IDE controller write of invalid write size: %x\n", size);
4825772SN/A            memcpy((uint8_t *)&bmiRegs + offset, data, size);
4835772SN/A        }
4845772SN/A    }
4855772SN/A}
4865772SN/A
4875772SN/Avoid
4885772SN/AIdeController::dispatchAccess(PacketPtr pkt, bool read)
4895772SN/A{
4905772SN/A    if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
4915772SN/A         panic("Bad IDE read size: %d\n", pkt->getSize());
4925772SN/A
4935772SN/A    if (!ioEnabled) {
4945772SN/A        pkt->makeAtomicResponse();
4955772SN/A        DPRINTF(IdeCtrl, "io not enabled\n");
4965772SN/A        return;
4975772SN/A    }
4985772SN/A
4995772SN/A    Addr addr = pkt->getAddr();
5005772SN/A    int size = pkt->getSize();
5015772SN/A    uint8_t *dataPtr = pkt->getPtr<uint8_t>();
5025772SN/A
5035772SN/A    if (addr >= primary.cmdAddr &&
5045772SN/A            addr < (primary.cmdAddr + primary.cmdSize)) {
5055772SN/A        addr -= primary.cmdAddr;
5067750SN/A        // linux may have shifted the address by ioShift,
5077750SN/A        // here we shift it back, similarly for ctrlOffset.
5087750SN/A        addr >>= ioShift;
5095772SN/A        primary.accessCommand(addr, size, dataPtr, read);
5105772SN/A    } else if (addr >= primary.ctrlAddr &&
5115772SN/A               addr < (primary.ctrlAddr + primary.ctrlSize)) {
5125772SN/A        addr -= primary.ctrlAddr;
5137750SN/A        addr += ctrlOffset;
5145772SN/A        primary.accessControl(addr, size, dataPtr, read);
5155772SN/A    } else if (addr >= secondary.cmdAddr &&
5165772SN/A               addr < (secondary.cmdAddr + secondary.cmdSize)) {
5175772SN/A        addr -= secondary.cmdAddr;
5185772SN/A        secondary.accessCommand(addr, size, dataPtr, read);
5195772SN/A    } else if (addr >= secondary.ctrlAddr &&
5205772SN/A               addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
5215772SN/A        addr -= secondary.ctrlAddr;
5225772SN/A        secondary.accessControl(addr, size, dataPtr, read);
5235772SN/A    } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
5245772SN/A        if (!read && !bmEnabled)
5255772SN/A            return;
5265772SN/A        addr -= bmiAddr;
5275772SN/A        if (addr < sizeof(Channel::BMIRegs)) {
5285772SN/A            primary.accessBMI(addr, size, dataPtr, read);
5295772SN/A        } else {
5305772SN/A            addr -= sizeof(Channel::BMIRegs);
5315772SN/A            secondary.accessBMI(addr, size, dataPtr, read);
5325772SN/A        }
5335772SN/A    } else {
5345772SN/A        panic("IDE controller access to invalid address: %#x\n", addr);
5355772SN/A    }
5365772SN/A
5378641SN/A#ifndef NDEBUG
5385772SN/A    uint32_t data;
5395772SN/A    if (pkt->getSize() == 1)
54013342Sgabeblack@google.com        data = pkt->getLE<uint8_t>();
5415772SN/A    else if (pkt->getSize() == 2)
54213342Sgabeblack@google.com        data = pkt->getLE<uint16_t>();
5435772SN/A    else
54413342Sgabeblack@google.com        data = pkt->getLE<uint32_t>();
5455772SN/A    DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
5465772SN/A            read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
5478641SN/A#endif
5485772SN/A
5495772SN/A    pkt->makeAtomicResponse();
5505772SN/A}
5512846SN/A
5522565SN/ATick
5533349SN/AIdeController::read(PacketPtr pkt)
554848SN/A{
5555772SN/A    dispatchAccess(pkt, true);
5562565SN/A    return pioDelay;
557848SN/A}
558848SN/A
5592565SN/ATick
5603349SN/AIdeController::write(PacketPtr pkt)
561848SN/A{
5625772SN/A    dispatchAccess(pkt, false);
5632565SN/A    return pioDelay;
564848SN/A}
565848SN/A
566848SN/Avoid
56710905SN/AIdeController::serialize(CheckpointOut &cp) const
568848SN/A{
5699807SN/A    // Serialize the PciDevice base class
57010905SN/A    PciDevice::serialize(cp);
571897SN/A
5725772SN/A    // Serialize channels
57310905SN/A    primary.serialize("primary", cp);
57410905SN/A    secondary.serialize("secondary", cp);
575864SN/A
5765772SN/A    // Serialize config registers
5775772SN/A    SERIALIZE_SCALAR(primaryTiming);
5785772SN/A    SERIALIZE_SCALAR(secondaryTiming);
5795772SN/A    SERIALIZE_SCALAR(deviceTiming);
5805772SN/A    SERIALIZE_SCALAR(udmaControl);
5815772SN/A    SERIALIZE_SCALAR(udmaTiming);
5825772SN/A    SERIALIZE_SCALAR(ideConfig);
583864SN/A
584864SN/A    // Serialize internal state
5855772SN/A    SERIALIZE_SCALAR(ioEnabled);
5865772SN/A    SERIALIZE_SCALAR(bmEnabled);
5875776SN/A    SERIALIZE_SCALAR(bmiAddr);
5885776SN/A    SERIALIZE_SCALAR(bmiSize);
5895772SN/A}
5905772SN/A
5915772SN/Avoid
59210905SN/AIdeController::Channel::serialize(const std::string &base,
59310905SN/A                                  CheckpointOut &cp) const
5945772SN/A{
59510905SN/A    paramOut(cp, base + ".cmdAddr", cmdAddr);
59610905SN/A    paramOut(cp, base + ".cmdSize", cmdSize);
59710905SN/A    paramOut(cp, base + ".ctrlAddr", ctrlAddr);
59810905SN/A    paramOut(cp, base + ".ctrlSize", ctrlSize);
5995775SN/A    uint8_t command = bmiRegs.command;
60010905SN/A    paramOut(cp, base + ".bmiRegs.command", command);
60110905SN/A    paramOut(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
6025775SN/A    uint8_t status = bmiRegs.status;
60310905SN/A    paramOut(cp, base + ".bmiRegs.status", status);
60410905SN/A    paramOut(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
60510905SN/A    paramOut(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
60610905SN/A    paramOut(cp, base + ".selectBit", selectBit);
607848SN/A}
608848SN/A
609848SN/Avoid
61010905SN/AIdeController::unserialize(CheckpointIn &cp)
611848SN/A{
6129807SN/A    // Unserialize the PciDevice base class
61310905SN/A    PciDevice::unserialize(cp);
614897SN/A
6155772SN/A    // Unserialize channels
61610905SN/A    primary.unserialize("primary", cp);
61710905SN/A    secondary.unserialize("secondary", cp);
618864SN/A
6195772SN/A    // Unserialize config registers
6205772SN/A    UNSERIALIZE_SCALAR(primaryTiming);
6215772SN/A    UNSERIALIZE_SCALAR(secondaryTiming);
6225772SN/A    UNSERIALIZE_SCALAR(deviceTiming);
6235772SN/A    UNSERIALIZE_SCALAR(udmaControl);
6245772SN/A    UNSERIALIZE_SCALAR(udmaTiming);
6255772SN/A    UNSERIALIZE_SCALAR(ideConfig);
626864SN/A
627864SN/A    // Unserialize internal state
6285772SN/A    UNSERIALIZE_SCALAR(ioEnabled);
6295772SN/A    UNSERIALIZE_SCALAR(bmEnabled);
6305776SN/A    UNSERIALIZE_SCALAR(bmiAddr);
6315776SN/A    UNSERIALIZE_SCALAR(bmiSize);
6325772SN/A}
6335772SN/A
6345772SN/Avoid
63510905SN/AIdeController::Channel::unserialize(const std::string &base, CheckpointIn &cp)
6365772SN/A{
63710905SN/A    paramIn(cp, base + ".cmdAddr", cmdAddr);
63810905SN/A    paramIn(cp, base + ".cmdSize", cmdSize);
63910905SN/A    paramIn(cp, base + ".ctrlAddr", ctrlAddr);
64010905SN/A    paramIn(cp, base + ".ctrlSize", ctrlSize);
6415775SN/A    uint8_t command;
64210905SN/A    paramIn(cp, base +".bmiRegs.command", command);
6435775SN/A    bmiRegs.command = command;
64410905SN/A    paramIn(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
6455775SN/A    uint8_t status;
64610905SN/A    paramIn(cp, base + ".bmiRegs.status", status);
6475775SN/A    bmiRegs.status = status;
64810905SN/A    paramIn(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
64910905SN/A    paramIn(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
65010905SN/A    paramIn(cp, base + ".selectBit", selectBit);
6515772SN/A    select(selectBit);
652848SN/A}
653848SN/A
6544762SN/AIdeController *
6554762SN/AIdeControllerParams::create()
656848SN/A{
6574762SN/A    return new IdeController(this);
658848SN/A}
659