device.cc revision 8711
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 55using namespace std; 56 57 58PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid, 59 int funcid, Platform *p) 60 : SimpleTimingPort(dev->name() + "-pciconf", dev), device(dev), 61 platform(p), busId(busid), deviceId(devid), functionId(funcid) 62{ 63 configAddr = platform->calcPciConfigAddr(busId, deviceId, functionId); 64} 65 66 67Tick 68PciDev::PciConfigPort::recvAtomic(PacketPtr pkt) 69{ 70 assert(pkt->getAddr() >= configAddr && 71 pkt->getAddr() < configAddr + PCI_CONFIG_SIZE); 72 return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt); 73} 74 75AddrRangeList 76PciDev::PciConfigPort::getAddrRanges() 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 85PciDev::PciDev(const Params *p) 86 : DmaDevice(p), plat(p->platform), pioDelay(p->pio_latency), 87 configDelay(p->config_latency), configPort(NULL) 88{ 89 config.vendor = htole(p->VendorID); 90 config.device = htole(p->DeviceID); 91 config.command = htole(p->Command); 92 config.status = htole(p->Status); 93 config.revision = htole(p->Revision); 94 config.progIF = htole(p->ProgIF); 95 config.subClassCode = htole(p->SubClassCode); 96 config.classCode = htole(p->ClassCode); 97 config.cacheLineSize = htole(p->CacheLineSize); 98 config.latencyTimer = htole(p->LatencyTimer); 99 config.headerType = htole(p->HeaderType); 100 config.bist = htole(p->BIST); 101 102 config.baseAddr[0] = htole(p->BAR0); 103 config.baseAddr[1] = htole(p->BAR1); 104 config.baseAddr[2] = htole(p->BAR2); 105 config.baseAddr[3] = htole(p->BAR3); 106 config.baseAddr[4] = htole(p->BAR4); 107 config.baseAddr[5] = htole(p->BAR5); 108 config.cardbusCIS = htole(p->CardbusCIS); 109 config.subsystemVendorID = htole(p->SubsystemVendorID); 110 config.subsystemID = htole(p->SubsystemID); 111 config.expansionROM = htole(p->ExpansionROM); 112 config.reserved0 = 0; 113 config.reserved1 = 0; 114 config.interruptLine = htole(p->InterruptLine); 115 config.interruptPin = htole(p->InterruptPin); 116 config.minimumGrant = htole(p->MinimumGrant); 117 config.maximumLatency = htole(p->MaximumLatency); 118 119 BARSize[0] = p->BAR0Size; 120 BARSize[1] = p->BAR1Size; 121 BARSize[2] = p->BAR2Size; 122 BARSize[3] = p->BAR3Size; 123 BARSize[4] = p->BAR4Size; 124 BARSize[5] = p->BAR5Size; 125 126 legacyIO[0] = p->BAR0LegacyIO; 127 legacyIO[1] = p->BAR1LegacyIO; 128 legacyIO[2] = p->BAR2LegacyIO; 129 legacyIO[3] = p->BAR3LegacyIO; 130 legacyIO[4] = p->BAR4LegacyIO; 131 legacyIO[5] = p->BAR5LegacyIO; 132 133 for (int i = 0; i < 6; ++i) { 134 if (legacyIO[i]) { 135 BARAddrs[i] = platform->calcPciIOAddr(letoh(config.baseAddr[i])); 136 config.baseAddr[i] = 0; 137 } else { 138 BARAddrs[i] = 0; 139 uint32_t barsize = BARSize[i]; 140 if (barsize != 0 && !isPowerOf2(barsize)) { 141 fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]); 142 } 143 } 144 } 145 146 plat->registerPciDevice(p->pci_bus, p->pci_dev, p->pci_func, 147 letoh(config.interruptLine)); 148} 149 150void 151PciDev::init() 152{ 153 if (!configPort) 154 panic("pci config port not connected to anything!"); 155 configPort->sendRangeChange(); 156 PioDevice::init(); 157} 158 159unsigned int 160PciDev::drain(Event *de) 161{ 162 unsigned int count; 163 count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de); 164 if (count) 165 changeState(Draining); 166 else 167 changeState(Drained); 168 return count; 169} 170 171Tick 172PciDev::readConfig(PacketPtr pkt) 173{ 174 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 175 if (offset >= PCI_DEVICE_SPECIFIC) 176 panic("Device specific PCI config space not implemented!\n"); 177 178 pkt->allocate(); 179 180 switch (pkt->getSize()) { 181 case sizeof(uint8_t): 182 pkt->set<uint8_t>(config.data[offset]); 183 DPRINTF(PCIDEV, 184 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 185 params()->pci_dev, params()->pci_func, offset, 186 (uint32_t)pkt->get<uint8_t>()); 187 break; 188 case sizeof(uint16_t): 189 pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 190 DPRINTF(PCIDEV, 191 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 192 params()->pci_dev, params()->pci_func, offset, 193 (uint32_t)pkt->get<uint16_t>()); 194 break; 195 case sizeof(uint32_t): 196 pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 197 DPRINTF(PCIDEV, 198 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 199 params()->pci_dev, params()->pci_func, offset, 200 (uint32_t)pkt->get<uint32_t>()); 201 break; 202 default: 203 panic("invalid access size(?) for PCI configspace!\n"); 204 } 205 pkt->makeAtomicResponse(); 206 return configDelay; 207 208} 209 210AddrRangeList 211PciDev::getAddrRanges() 212{ 213 AddrRangeList ranges; 214 int x = 0; 215 for (x = 0; x < 6; x++) 216 if (BARAddrs[x] != 0) 217 ranges.push_back(RangeSize(BARAddrs[x],BARSize[x])); 218 return ranges; 219} 220 221Tick 222PciDev::writeConfig(PacketPtr pkt) 223{ 224 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 225 if (offset >= PCI_DEVICE_SPECIFIC) 226 panic("Device specific PCI config space not implemented!\n"); 227 228 switch (pkt->getSize()) { 229 case sizeof(uint8_t): 230 switch (offset) { 231 case PCI0_INTERRUPT_LINE: 232 config.interruptLine = pkt->get<uint8_t>(); 233 break; 234 case PCI_CACHE_LINE_SIZE: 235 config.cacheLineSize = pkt->get<uint8_t>(); 236 break; 237 case PCI_LATENCY_TIMER: 238 config.latencyTimer = pkt->get<uint8_t>(); 239 break; 240 /* Do nothing for these read-only registers */ 241 case PCI0_INTERRUPT_PIN: 242 case PCI0_MINIMUM_GRANT: 243 case PCI0_MAXIMUM_LATENCY: 244 case PCI_CLASS_CODE: 245 case PCI_REVISION_ID: 246 break; 247 default: 248 panic("writing to a read only register"); 249 } 250 DPRINTF(PCIDEV, 251 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 252 params()->pci_dev, params()->pci_func, offset, 253 (uint32_t)pkt->get<uint8_t>()); 254 break; 255 case sizeof(uint16_t): 256 switch (offset) { 257 case PCI_COMMAND: 258 config.command = pkt->get<uint8_t>(); 259 break; 260 case PCI_STATUS: 261 config.status = pkt->get<uint8_t>(); 262 break; 263 case PCI_CACHE_LINE_SIZE: 264 config.cacheLineSize = pkt->get<uint8_t>(); 265 break; 266 default: 267 panic("writing to a read only register"); 268 } 269 DPRINTF(PCIDEV, 270 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 271 params()->pci_dev, params()->pci_func, offset, 272 (uint32_t)pkt->get<uint16_t>()); 273 break; 274 case sizeof(uint32_t): 275 switch (offset) { 276 case PCI0_BASE_ADDR0: 277 case PCI0_BASE_ADDR1: 278 case PCI0_BASE_ADDR2: 279 case PCI0_BASE_ADDR3: 280 case PCI0_BASE_ADDR4: 281 case PCI0_BASE_ADDR5: 282 { 283 int barnum = BAR_NUMBER(offset); 284 285 if (!legacyIO[barnum]) { 286 // convert BAR values to host endianness 287 uint32_t he_old_bar = letoh(config.baseAddr[barnum]); 288 uint32_t he_new_bar = letoh(pkt->get<uint32_t>()); 289 290 uint32_t bar_mask = 291 BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; 292 293 // Writing 0xffffffff to a BAR tells the card to set the 294 // value of the bar to a bitmask indicating the size of 295 // memory it needs 296 if (he_new_bar == 0xffffffff) { 297 he_new_bar = ~(BARSize[barnum] - 1); 298 } else { 299 // does it mean something special to write 0 to a BAR? 300 he_new_bar &= ~bar_mask; 301 if (he_new_bar) { 302 BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ? 303 platform->calcPciIOAddr(he_new_bar) : 304 platform->calcPciMemAddr(he_new_bar); 305 pioPort->sendRangeChange(); 306 } 307 } 308 config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | 309 (he_old_bar & bar_mask)); 310 } 311 } 312 break; 313 314 case PCI0_ROM_BASE_ADDR: 315 if (letoh(pkt->get<uint32_t>()) == 0xfffffffe) 316 config.expansionROM = htole((uint32_t)0xffffffff); 317 else 318 config.expansionROM = pkt->get<uint32_t>(); 319 break; 320 321 case PCI_COMMAND: 322 // This could also clear some of the error bits in the Status 323 // register. However they should never get set, so lets ignore 324 // it for now 325 config.command = pkt->get<uint32_t>(); 326 break; 327 328 default: 329 DPRINTF(PCIDEV, "Writing to a read only register"); 330 } 331 DPRINTF(PCIDEV, 332 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 333 params()->pci_dev, params()->pci_func, offset, 334 (uint32_t)pkt->get<uint32_t>()); 335 break; 336 default: 337 panic("invalid access size(?) for PCI configspace!\n"); 338 } 339 pkt->makeAtomicResponse(); 340 return configDelay; 341} 342 343void 344PciDev::serialize(ostream &os) 345{ 346 SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 347 SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 348 SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); 349} 350 351void 352PciDev::unserialize(Checkpoint *cp, const std::string §ion) 353{ 354 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 355 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 356 UNSERIALIZE_ARRAY(config.data, 357 sizeof(config.data) / sizeof(config.data[0])); 358 pioPort->sendRangeChange(); 359 360} 361 362