device.cc revision 5777
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->calcConfigAddr(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 for (int i = 0; i < 6; ++i) { 125 uint32_t barsize = BARSize[i]; 126 if (barsize != 0 && !isPowerOf2(barsize)) { 127 fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]); 128 } 129 } 130 131 memset(BARAddrs, 0, sizeof(BARAddrs)); 132 133 plat->registerPciDevice(0, p->pci_dev, p->pci_func, 134 letoh(config.interruptLine)); 135} 136 137void 138PciDev::init() 139{ 140 if (!configPort) 141 panic("pci config port not connected to anything!"); 142 configPort->sendStatusChange(Port::RangeChange); 143 PioDevice::init(); 144} 145 146unsigned int 147PciDev::drain(Event *de) 148{ 149 unsigned int count; 150 count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de); 151 if (count) 152 changeState(Draining); 153 else 154 changeState(Drained); 155 return count; 156} 157 158Tick 159PciDev::readConfig(PacketPtr pkt) 160{ 161 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 162 if (offset >= PCI_DEVICE_SPECIFIC) 163 panic("Device specific PCI config space not implemented!\n"); 164 165 pkt->allocate(); 166 167 switch (pkt->getSize()) { 168 case sizeof(uint8_t): 169 pkt->set<uint8_t>(config.data[offset]); 170 DPRINTF(PCIDEV, 171 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 172 params()->pci_dev, params()->pci_func, offset, 173 (uint32_t)pkt->get<uint8_t>()); 174 break; 175 case sizeof(uint16_t): 176 pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]); 177 DPRINTF(PCIDEV, 178 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 179 params()->pci_dev, params()->pci_func, offset, 180 (uint32_t)pkt->get<uint16_t>()); 181 break; 182 case sizeof(uint32_t): 183 pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]); 184 DPRINTF(PCIDEV, 185 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 186 params()->pci_dev, params()->pci_func, offset, 187 (uint32_t)pkt->get<uint32_t>()); 188 break; 189 default: 190 panic("invalid access size(?) for PCI configspace!\n"); 191 } 192 pkt->makeAtomicResponse(); 193 return configDelay; 194 195} 196 197void 198PciDev::addressRanges(AddrRangeList &range_list) 199{ 200 int x = 0; 201 range_list.clear(); 202 for (x = 0; x < 6; x++) 203 if (BARAddrs[x] != 0) 204 range_list.push_back(RangeSize(BARAddrs[x],BARSize[x])); 205} 206 207Tick 208PciDev::writeConfig(PacketPtr pkt) 209{ 210 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 211 if (offset >= PCI_DEVICE_SPECIFIC) 212 panic("Device specific PCI config space not implemented!\n"); 213 214 switch (pkt->getSize()) { 215 case sizeof(uint8_t): 216 switch (offset) { 217 case PCI0_INTERRUPT_LINE: 218 config.interruptLine = pkt->get<uint8_t>(); 219 break; 220 case PCI_CACHE_LINE_SIZE: 221 config.cacheLineSize = pkt->get<uint8_t>(); 222 break; 223 case PCI_LATENCY_TIMER: 224 config.latencyTimer = pkt->get<uint8_t>(); 225 break; 226 /* Do nothing for these read-only registers */ 227 case PCI0_INTERRUPT_PIN: 228 case PCI0_MINIMUM_GRANT: 229 case PCI0_MAXIMUM_LATENCY: 230 case PCI_CLASS_CODE: 231 case PCI_REVISION_ID: 232 break; 233 default: 234 panic("writing to a read only register"); 235 } 236 DPRINTF(PCIDEV, 237 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n", 238 params()->pci_dev, params()->pci_func, offset, 239 (uint32_t)pkt->get<uint8_t>()); 240 break; 241 case sizeof(uint16_t): 242 switch (offset) { 243 case PCI_COMMAND: 244 config.command = pkt->get<uint8_t>(); 245 break; 246 case PCI_STATUS: 247 config.status = pkt->get<uint8_t>(); 248 break; 249 case PCI_CACHE_LINE_SIZE: 250 config.cacheLineSize = pkt->get<uint8_t>(); 251 break; 252 default: 253 panic("writing to a read only register"); 254 } 255 DPRINTF(PCIDEV, 256 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n", 257 params()->pci_dev, params()->pci_func, offset, 258 (uint32_t)pkt->get<uint16_t>()); 259 break; 260 case sizeof(uint32_t): 261 switch (offset) { 262 case PCI0_BASE_ADDR0: 263 case PCI0_BASE_ADDR1: 264 case PCI0_BASE_ADDR2: 265 case PCI0_BASE_ADDR3: 266 case PCI0_BASE_ADDR4: 267 case PCI0_BASE_ADDR5: 268 { 269 int barnum = BAR_NUMBER(offset); 270 271 // convert BAR values to host endianness 272 uint32_t he_old_bar = letoh(config.baseAddr[barnum]); 273 uint32_t he_new_bar = letoh(pkt->get<uint32_t>()); 274 275 uint32_t bar_mask = 276 BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK; 277 278 // Writing 0xffffffff to a BAR tells the card to set the 279 // value of the bar to a bitmask indicating the size of 280 // memory it needs 281 if (he_new_bar == 0xffffffff) { 282 he_new_bar = ~(BARSize[barnum] - 1); 283 } else { 284 // does it mean something special to write 0 to a BAR? 285 he_new_bar &= ~bar_mask; 286 if (he_new_bar) { 287 Addr space_base = BAR_IO_SPACE(he_old_bar) ? 288 TSUNAMI_PCI0_IO : TSUNAMI_PCI0_MEMORY; 289 BARAddrs[barnum] = he_new_bar + space_base; 290 pioPort->sendStatusChange(Port::RangeChange); 291 } 292 } 293 config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) | 294 (he_old_bar & bar_mask)); 295 } 296 break; 297 298 case PCI0_ROM_BASE_ADDR: 299 if (letoh(pkt->get<uint32_t>()) == 0xfffffffe) 300 config.expansionROM = htole((uint32_t)0xffffffff); 301 else 302 config.expansionROM = pkt->get<uint32_t>(); 303 break; 304 305 case PCI_COMMAND: 306 // This could also clear some of the error bits in the Status 307 // register. However they should never get set, so lets ignore 308 // it for now 309 config.command = pkt->get<uint32_t>(); 310 break; 311 312 default: 313 DPRINTF(PCIDEV, "Writing to a read only register"); 314 } 315 DPRINTF(PCIDEV, 316 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n", 317 params()->pci_dev, params()->pci_func, offset, 318 (uint32_t)pkt->get<uint32_t>()); 319 break; 320 default: 321 panic("invalid access size(?) for PCI configspace!\n"); 322 } 323 pkt->makeAtomicResponse(); 324 return configDelay; 325} 326 327void 328PciDev::serialize(ostream &os) 329{ 330 SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 331 SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 332 SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); 333} 334 335void 336PciDev::unserialize(Checkpoint *cp, const std::string §ion) 337{ 338 UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); 339 UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); 340 UNSERIALIZE_ARRAY(config.data, 341 sizeof(config.data) / sizeof(config.data[0])); 342 pioPort->sendStatusChange(Port::RangeChange); 343 344} 345 346