device.cc revision 9807
1/* 2 * Copyright (c) 2004-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Ali Saidi 29 * Andrew Schultz 30 * Miguel Serrano 31 */ 32 33/* @file 34 * A single PCI device configuration space entry. 35 */ 36 37#include <list> 38#include <string> 39#include <vector> 40 41#include "base/inifile.hh" 42#include "base/intmath.hh" 43#include "base/misc.hh" 44#include "base/str.hh" 45#include "base/trace.hh" 46#include "debug/PCIDEV.hh" 47#include "dev/alpha/tsunamireg.h" 48#include "dev/pciconfigall.hh" 49#include "dev/pcidev.hh" 50#include "mem/packet.hh" 51#include "mem/packet_access.hh" 52#include "sim/byteswap.hh" 53#include "sim/core.hh" 54 55 56PciDevice::PciConfigPort::PciConfigPort(PciDevice *dev, int busid, int devid, 57 int funcid, Platform *p) 58 : SimpleTimingPort(dev->name() + "-pciconf", dev), device(dev), 59 platform(p), busId(busid), deviceId(devid), functionId(funcid) 60{ 61 configAddr = platform->calcPciConfigAddr(busId, deviceId, functionId); 62} 63 64 65Tick 66PciDevice::PciConfigPort::recvAtomic(PacketPtr pkt) 67{ 68 assert(pkt->getAddr() >= configAddr && 69 pkt->getAddr() < configAddr + PCI_CONFIG_SIZE); 70 // @todo someone should pay for this 71 pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; 72 return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt); 73} 74 75AddrRangeList 76PciDevice::PciConfigPort::getAddrRanges() const 77{ 78 AddrRangeList ranges; 79 if (configAddr != ULL(-1)) 80 ranges.push_back(RangeSize(configAddr, PCI_CONFIG_SIZE+1)); 81 return ranges; 82} 83 84 85PciDevice::PciDevice(const Params *p) 86 : DmaDevice(p), platform(p->platform), pioDelay(p->pio_latency), 87 configDelay(p->config_latency), 88 configPort(this, params()->pci_bus, params()->pci_dev, 89 params()->pci_func, params()->platform) 90{ 91 config.vendor = htole(p->VendorID); 92 config.device = htole(p->DeviceID); 93 config.command = htole(p->Command); 94 config.status = htole(p->Status); 95 config.revision = htole(p->Revision); 96 config.progIF = htole(p->ProgIF); 97 config.subClassCode = htole(p->SubClassCode); 98 config.classCode = htole(p->ClassCode); 99 config.cacheLineSize = htole(p->CacheLineSize); 100 config.latencyTimer = htole(p->LatencyTimer); 101 config.headerType = htole(p->HeaderType); 102 config.bist = htole(p->BIST); 103 104 config.baseAddr[0] = htole(p->BAR0); 105 config.baseAddr[1] = htole(p->BAR1); 106 config.baseAddr[2] = htole(p->BAR2); 107 config.baseAddr[3] = htole(p->BAR3); 108 config.baseAddr[4] = htole(p->BAR4); 109 config.baseAddr[5] = htole(p->BAR5); 110 config.cardbusCIS = htole(p->CardbusCIS); 111 config.subsystemVendorID = htole(p->SubsystemVendorID); 112 config.subsystemID = htole(p->SubsystemID); 113 config.expansionROM = htole(p->ExpansionROM); 114 config.reserved0 = 0; 115 config.reserved1 = 0; 116 config.interruptLine = htole(p->InterruptLine); 117 config.interruptPin = htole(p->InterruptPin); 118 config.minimumGrant = htole(p->MinimumGrant); 119 config.maximumLatency = htole(p->MaximumLatency); 120 121 BARSize[0] = p->BAR0Size; 122 BARSize[1] = p->BAR1Size; 123 BARSize[2] = p->BAR2Size; 124 BARSize[3] = p->BAR3Size; 125 BARSize[4] = p->BAR4Size; 126 BARSize[5] = p->BAR5Size; 127 128 legacyIO[0] = p->BAR0LegacyIO; 129 legacyIO[1] = p->BAR1LegacyIO; 130 legacyIO[2] = p->BAR2LegacyIO; 131 legacyIO[3] = p->BAR3LegacyIO; 132 legacyIO[4] = p->BAR4LegacyIO; 133 legacyIO[5] = p->BAR5LegacyIO; 134 135 for (int i = 0; i < 6; ++i) { 136 if (legacyIO[i]) { 137 BARAddrs[i] = platform->calcPciIOAddr(letoh(config.baseAddr[i])); 138 config.baseAddr[i] = 0; 139 } else { 140 BARAddrs[i] = 0; 141 uint32_t barsize = BARSize[i]; 142 if (barsize != 0 && !isPowerOf2(barsize)) { 143 fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]); 144 } 145 } 146 } 147 148 platform->registerPciDevice(p->pci_bus, p->pci_dev, p->pci_func, 149 letoh(config.interruptLine)); 150} 151 152void 153PciDevice::init() 154{ 155 if (!configPort.isConnected()) 156 panic("PCI config port on %s not connected to anything!\n", name()); 157 configPort.sendRangeChange(); 158 DmaDevice::init(); 159} 160 161unsigned int 162PciDevice::drain(DrainManager *dm) 163{ 164 unsigned int count; 165 count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm); 166 if (count) 167 setDrainState(Drainable::Draining); 168 else 169 setDrainState(Drainable::Drained); 170 return count; 171} 172 173Tick 174PciDevice::readConfig(PacketPtr pkt) 175{ 176 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 177 if (offset >= PCI_DEVICE_SPECIFIC) 178 panic("Device specific PCI config space not implemented!\n"); 179 180 pkt->allocate(); 181 182 switch (pkt->getSize()) { 183 case sizeof(uint8_t): 184 pkt->set<uint8_t>(config.data[offset]); 185 DPRINTF(PCIDEV, 186 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 187 params()->pci_dev, params()->pci_func, offset, 188 (uint32_t)pkt->get<uint8_t>()); 189 break; 190 case sizeof(uint16_t): 191 pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 192 DPRINTF(PCIDEV, 193 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 194 params()->pci_dev, params()->pci_func, offset, 195 (uint32_t)pkt->get<uint16_t>()); 196 break; 197 case sizeof(uint32_t): 198 pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 199 DPRINTF(PCIDEV, 200 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 201 params()->pci_dev, params()->pci_func, offset, 202 (uint32_t)pkt->get<uint32_t>()); 203 break; 204 default: 205 panic("invalid access size(?) for PCI configspace!\n"); 206 } 207 pkt->makeAtomicResponse(); 208 return configDelay; 209 210} 211 212AddrRangeList 213PciDevice::getAddrRanges() const 214{ 215 AddrRangeList ranges; 216 int x = 0; 217 for (x = 0; x < 6; x++) 218 if (BARAddrs[x] != 0) 219 ranges.push_back(RangeSize(BARAddrs[x],BARSize[x])); 220 return ranges; 221} 222 223Tick 224PciDevice::writeConfig(PacketPtr pkt) 225{ 226 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 227 if (offset >= PCI_DEVICE_SPECIFIC) 228 panic("Device specific PCI config space not implemented!\n"); 229 230 switch (pkt->getSize()) { 231 case sizeof(uint8_t): 232 switch (offset) { 233 case PCI0_INTERRUPT_LINE: 234 config.interruptLine = pkt->get<uint8_t>(); 235 break; 236 case PCI_CACHE_LINE_SIZE: 237 config.cacheLineSize = pkt->get<uint8_t>(); 238 break; 239 case PCI_LATENCY_TIMER: 240 config.latencyTimer = pkt->get<uint8_t>(); 241 break; 242 /* Do nothing for these read-only registers */ 243 case PCI0_INTERRUPT_PIN: 244 case PCI0_MINIMUM_GRANT: 245 case PCI0_MAXIMUM_LATENCY: 246 case PCI_CLASS_CODE: 247 case PCI_REVISION_ID: 248 break; 249 default: 250 panic("writing to a read only register"); 251 } 252 DPRINTF(PCIDEV, 253 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 254 params()->pci_dev, params()->pci_func, offset, 255 (uint32_t)pkt->get<uint8_t>()); 256 break; 257 case sizeof(uint16_t): 258 switch (offset) { 259 case PCI_COMMAND: 260 config.command = pkt->get<uint8_t>(); 261 break; 262 case PCI_STATUS: 263 config.status = pkt->get<uint8_t>(); 264 break; 265 case PCI_CACHE_LINE_SIZE: 266 config.cacheLineSize = pkt->get<uint8_t>(); 267 break; 268 default: 269 panic("writing to a read only register"); 270 } 271 DPRINTF(PCIDEV, 272 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 273 params()->pci_dev, params()->pci_func, offset, 274 (uint32_t)pkt->get<uint16_t>()); 275 break; 276 case sizeof(uint32_t): 277 switch (offset) { 278 case PCI0_BASE_ADDR0: 279 case PCI0_BASE_ADDR1: 280 case PCI0_BASE_ADDR2: 281 case PCI0_BASE_ADDR3: 282 case PCI0_BASE_ADDR4: 283 case PCI0_BASE_ADDR5: 284 { 285 int barnum = BAR_NUMBER(offset); 286 287 if (!legacyIO[barnum]) { 288 // convert BAR values to host endianness 289 uint32_t he_old_bar = letoh(config.baseAddr[barnum]); 290 uint32_t he_new_bar = letoh(pkt->get<uint32_t>()); 291 292 uint32_t bar_mask = 293 BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; 294 295 // Writing 0xffffffff to a BAR tells the card to set the 296 // value of the bar to a bitmask indicating the size of 297 // memory it needs 298 if (he_new_bar == 0xffffffff) { 299 he_new_bar = ~(BARSize[barnum] - 1); 300 } else { 301 // does it mean something special to write 0 to a BAR? 302 he_new_bar &= ~bar_mask; 303 if (he_new_bar) { 304 BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ? 305 platform->calcPciIOAddr(he_new_bar) : 306 platform->calcPciMemAddr(he_new_bar); 307 pioPort.sendRangeChange(); 308 } 309 } 310 config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | 311 (he_old_bar & bar_mask)); 312 } 313 } 314 break; 315 316 case PCI0_ROM_BASE_ADDR: 317 if (letoh(pkt->get<uint32_t>()) == 0xfffffffe) 318 config.expansionROM = htole((uint32_t)0xffffffff); 319 else 320 config.expansionROM = pkt->get<uint32_t>(); 321 break; 322 323 case PCI_COMMAND: 324 // This could also clear some of the error bits in the Status 325 // register. However they should never get set, so lets ignore 326 // it for now 327 config.command = pkt->get<uint32_t>(); 328 break; 329 330 default: 331 DPRINTF(PCIDEV, "Writing to a read only register"); 332 } 333 DPRINTF(PCIDEV, 334 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 335 params()->pci_dev, params()->pci_func, offset, 336 (uint32_t)pkt->get<uint32_t>()); 337 break; 338 default: 339 panic("invalid access size(?) for PCI configspace!\n"); 340 } 341 pkt->makeAtomicResponse(); 342 return configDelay; 343} 344 345void 346PciDevice::serialize(std::ostream &os) 347{ 348 SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 349 SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 350 SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); 351} 352 353void 354PciDevice::unserialize(Checkpoint *cp, const std::string §ion) 355{ 356 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 357 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 358 UNSERIALIZE_ARRAY(config.data, 359 sizeof(config.data) / sizeof(config.data[0])); 360 pioPort.sendRangeChange(); 361 362} 363 364