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