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 §ion) 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 §ion) 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