device.cc revision 1155
1/* 2 * Copyright (c) 2004 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 29/* @file 30 * A single PCI device configuration space entry. 31 */ 32 33#include <list> 34#include <sstream> 35#include <string> 36#include <vector> 37 38#include "base/inifile.hh" 39#include "base/misc.hh" 40#include "base/str.hh" // for to_number 41#include "base/trace.hh" 42#include "dev/pciareg.h" 43#include "dev/pcidev.hh" 44#include "dev/pciconfigall.hh" 45#include "mem/functional_mem/memory_control.hh" 46#include "sim/builder.hh" 47#include "sim/param.hh" 48#include "sim/universe.hh" 49#include "dev/tsunamireg.h" 50 51using namespace std; 52 53PciDev::PciDev(Params *p) 54 : DmaDevice(p->name), _params(p), plat(p->plat), configData(p->configData) 55{ 56 // copy the config data from the PciConfigData object 57 if (configData) { 58 memcpy(config.data, configData->config.data, sizeof(config.data)); 59 memcpy(BARSize, configData->BARSize, sizeof(BARSize)); 60 memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs)); 61 } else 62 panic("NULL pointer to configuration data"); 63 64 // Setup pointer in config space to point to this entry 65 if (p->configSpace->deviceExists(p->deviceNum, p->functionNum)) 66 panic("Two PCI devices occuping same dev: %#x func: %#x", 67 p->deviceNum, p->functionNum); 68 else 69 p->configSpace->registerDevice(p->deviceNum, p->functionNum, this); 70} 71 72void 73PciDev::ReadConfig(int offset, int size, uint8_t *data) 74{ 75 if (offset >= PCI_DEVICE_SPECIFIC) 76 panic("Device specific PCI config space not implemented!\n"); 77 78 switch(size) { 79 case sizeof(uint32_t): 80 memcpy((uint8_t*)data, config.data + offset, sizeof(uint32_t)); 81 *(uint32_t*)data = htoa(*(uint32_t*)data); 82 DPRINTF(PCIDEV, 83 "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n", 84 params()->deviceNum, params()->functionNum, offset, size, 85 *(uint32_t*)(config.data + offset)); 86 break; 87 88 case sizeof(uint16_t): 89 memcpy((uint8_t*)data, config.data + offset, sizeof(uint16_t)); 90 *(uint16_t*)data = htoa(*(uint16_t*)data); 91 DPRINTF(PCIDEV, 92 "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n", 93 params()->deviceNum, params()->functionNum, offset, size, 94 *(uint16_t*)(config.data + offset)); 95 break; 96 97 case sizeof(uint8_t): 98 memcpy((uint8_t*)data, config.data + offset, sizeof(uint8_t)); 99 DPRINTF(PCIDEV, 100 "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n", 101 params()->deviceNum, params()->functionNum, offset, size, 102 (uint16_t)(*(uint8_t*)(config.data + offset))); 103 break; 104 105 default: 106 panic("Invalid Read Size"); 107 } 108} 109 110void 111PciDev::WriteConfig(int offset, int size, uint32_t data) 112{ 113 if (offset >= PCI_DEVICE_SPECIFIC) 114 panic("Device specific PCI config space not implemented!\n"); 115 116 uint32_t barnum; 117 118 union { 119 uint8_t byte_value; 120 uint16_t half_value; 121 uint32_t word_value; 122 }; 123 word_value = data; 124 125 DPRINTF(PCIDEV, 126 "write device: %#x function: %#x reg: %#x size: %d data: %#x\n", 127 params()->deviceNum, params()->functionNum, offset, size, 128 word_value); 129 130 barnum = (offset - PCI0_BASE_ADDR0) >> 2; 131 132 switch (size) { 133 case sizeof(uint8_t): // 1-byte access 134 switch (offset) { 135 case PCI0_INTERRUPT_LINE: 136 case PCI_CACHE_LINE_SIZE: 137 case PCI_LATENCY_TIMER: 138 *(uint8_t *)&config.data[offset] = htoa(byte_value); 139 break; 140 141 default: 142 panic("writing to a read only register"); 143 } 144 break; 145 146 case sizeof(uint16_t): // 2-byte access 147 switch (offset) { 148 case PCI_COMMAND: 149 case PCI_STATUS: 150 case PCI_CACHE_LINE_SIZE: 151 *(uint16_t *)&config.data[offset] = htoa(half_value); 152 break; 153 154 default: 155 panic("writing to a read only register"); 156 } 157 break; 158 159 case sizeof(uint16_t)+1: // 3-byte access 160 panic("invalid access size"); 161 162 case sizeof(uint32_t): // 4-byte access 163 switch (offset) { 164 case PCI0_BASE_ADDR0: 165 case PCI0_BASE_ADDR1: 166 case PCI0_BASE_ADDR2: 167 case PCI0_BASE_ADDR3: 168 case PCI0_BASE_ADDR4: 169 case PCI0_BASE_ADDR5: 170 // Writing 0xffffffff to a BAR tells the card to set the 171 // value of the bar 172 // to size of memory it needs 173 if (word_value == 0xffffffff) { 174 // This is I/O Space, bottom two bits are read only 175 if (htoa(config.data[offset]) & 0x1) { 176 *(uint32_t *)&config.data[offset] = htoa( 177 ~(BARSize[barnum] - 1) | 178 (htoa(config.data[offset]) & 0x3)); 179 } else { 180 // This is memory space, bottom four bits are read only 181 *(uint32_t *)&config.data[offset] = htoa( 182 ~(BARSize[barnum] - 1) | 183 (htoa(config.data[offset]) & 0xF)); 184 } 185 } else { 186 MemoryController *mmu = params()->mmu; 187 188 // This is I/O Space, bottom two bits are read only 189 if(htoa(config.data[offset]) & 0x1) { 190 *(uint32_t *)&config.data[offset] = 191 htoa((word_value & ~0x3) | 192 (htoa(config.data[offset]) & 0x3)); 193 194 if (word_value & ~0x1) { 195 Addr base_addr = (word_value & ~0x1) + TSUNAMI_PCI0_IO; 196 Addr base_size = BARSize[barnum]; 197 198 // It's never been set 199 if (BARAddrs[barnum] == 0) 200 mmu->add_child((FunctionalMemory *)this, 201 RangeSize(base_addr, base_size)); 202 else 203 mmu->update_child((FunctionalMemory *)this, 204 RangeSize(BARAddrs[barnum], 205 base_size), 206 RangeSize(base_addr, base_size)); 207 208 BARAddrs[barnum] = base_addr; 209 } 210 211 } else { 212 // This is memory space, bottom four bits are read only 213 *(uint32_t *)&config.data[offset] = 214 htoa((word_value & ~0xF) | 215 (htoa(config.data[offset]) & 0xF)); 216 217 if (word_value & ~0x3) { 218 Addr base_addr = (word_value & ~0x3) + 219 TSUNAMI_PCI0_MEMORY; 220 221 Addr base_size = BARSize[barnum]; 222 223 // It's never been set 224 if (BARAddrs[barnum] == 0) 225 mmu->add_child((FunctionalMemory *)this, 226 RangeSize(base_addr, base_size)); 227 else 228 mmu->update_child((FunctionalMemory *)this, 229 RangeSize(BARAddrs[barnum], 230 base_size), 231 RangeSize(base_addr, base_size)); 232 233 BARAddrs[barnum] = base_addr; 234 } 235 } 236 } 237 break; 238 239 case PCI0_ROM_BASE_ADDR: 240 if (word_value == 0xfffffffe) 241 *(uint32_t *)&config.data[offset] = 0xffffffff; 242 else 243 *(uint32_t *)&config.data[offset] = htoa(word_value); 244 break; 245 246 case PCI_COMMAND: 247 // This could also clear some of the error bits in the Status 248 // register. However they should never get set, so lets ignore 249 // it for now 250 *(uint16_t *)&config.data[offset] = htoa(half_value); 251 break; 252 253 default: 254 DPRINTF(PCIDEV, "Writing to a read only register"); 255 } 256 break; 257 } 258} 259 260void 261PciDev::serialize(ostream &os) 262{ 263 SERIALIZE_ARRAY(BARSize, 6); 264 SERIALIZE_ARRAY(BARAddrs, 6); 265 SERIALIZE_ARRAY(config.data, 64); 266} 267 268void 269PciDev::unserialize(Checkpoint *cp, const std::string §ion) 270{ 271 UNSERIALIZE_ARRAY(BARSize, 6); 272 UNSERIALIZE_ARRAY(BARAddrs, 6); 273 UNSERIALIZE_ARRAY(config.data, 64); 274 275 // Add the MMU mappings for the BARs 276 for (int i=0; i < 6; i++) { 277 if (BARAddrs[i] != 0) 278 params()->mmu->add_child(this, RangeSize(BARAddrs[i], BARSize[i])); 279 } 280} 281 282#ifndef DOXYGEN_SHOULD_SKIP_THIS 283 284BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) 285 286 Param<uint16_t> VendorID; 287 Param<uint16_t> DeviceID; 288 Param<uint16_t> Command; 289 Param<uint16_t> Status; 290 Param<uint8_t> Revision; 291 Param<uint8_t> ProgIF; 292 Param<uint8_t> SubClassCode; 293 Param<uint8_t> ClassCode; 294 Param<uint8_t> CacheLineSize; 295 Param<uint8_t> LatencyTimer; 296 Param<uint8_t> HeaderType; 297 Param<uint8_t> BIST; 298 Param<uint32_t> BAR0; 299 Param<uint32_t> BAR1; 300 Param<uint32_t> BAR2; 301 Param<uint32_t> BAR3; 302 Param<uint32_t> BAR4; 303 Param<uint32_t> BAR5; 304 Param<uint32_t> CardbusCIS; 305 Param<uint16_t> SubsystemVendorID; 306 Param<uint16_t> SubsystemID; 307 Param<uint32_t> ExpansionROM; 308 Param<uint8_t> InterruptLine; 309 Param<uint8_t> InterruptPin; 310 Param<uint8_t> MinimumGrant; 311 Param<uint8_t> MaximumLatency; 312 Param<uint32_t> BAR0Size; 313 Param<uint32_t> BAR1Size; 314 Param<uint32_t> BAR2Size; 315 Param<uint32_t> BAR3Size; 316 Param<uint32_t> BAR4Size; 317 Param<uint32_t> BAR5Size; 318 319END_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) 320 321BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData) 322 323 INIT_PARAM(VendorID, "Vendor ID"), 324 INIT_PARAM(DeviceID, "Device ID"), 325 INIT_PARAM_DFLT(Command, "Command Register", 0x00), 326 INIT_PARAM_DFLT(Status, "Status Register", 0x00), 327 INIT_PARAM_DFLT(Revision, "Device Revision", 0x00), 328 INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00), 329 INIT_PARAM(SubClassCode, "Sub-Class Code"), 330 INIT_PARAM(ClassCode, "Class Code"), 331 INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00), 332 INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00), 333 INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00), 334 INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00), 335 INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00), 336 INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00), 337 INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00), 338 INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00), 339 INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00), 340 INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00), 341 INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00), 342 INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00), 343 INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00), 344 INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00), 345 INIT_PARAM(InterruptLine, "Interrupt Line Register"), 346 INIT_PARAM(InterruptPin, "Interrupt Pin Register"), 347 INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00), 348 INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00), 349 INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00), 350 INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00), 351 INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00), 352 INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00), 353 INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00), 354 INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00) 355 356END_INIT_SIM_OBJECT_PARAMS(PciConfigData) 357 358CREATE_SIM_OBJECT(PciConfigData) 359{ 360 PciConfigData *data = new PciConfigData(getInstanceName()); 361 362 data->config.hdr.vendor = htoa(VendorID); 363 data->config.hdr.device = htoa(DeviceID); 364 data->config.hdr.command = htoa(Command); 365 data->config.hdr.status = htoa(Status); 366 data->config.hdr.revision = htoa(Revision); 367 data->config.hdr.progIF = htoa(ProgIF); 368 data->config.hdr.subClassCode = htoa(SubClassCode); 369 data->config.hdr.classCode = htoa(ClassCode); 370 data->config.hdr.cacheLineSize = htoa(CacheLineSize); 371 data->config.hdr.latencyTimer = htoa(LatencyTimer); 372 data->config.hdr.headerType = htoa(HeaderType); 373 data->config.hdr.bist = htoa(BIST); 374 375 data->config.hdr.pci0.baseAddr0 = htoa(BAR0); 376 data->config.hdr.pci0.baseAddr1 = htoa(BAR1); 377 data->config.hdr.pci0.baseAddr2 = htoa(BAR2); 378 data->config.hdr.pci0.baseAddr3 = htoa(BAR3); 379 data->config.hdr.pci0.baseAddr4 = htoa(BAR4); 380 data->config.hdr.pci0.baseAddr5 = htoa(BAR5); 381 data->config.hdr.pci0.cardbusCIS = htoa(CardbusCIS); 382 data->config.hdr.pci0.subsystemVendorID = htoa(SubsystemVendorID); 383 data->config.hdr.pci0.subsystemID = htoa(SubsystemVendorID); 384 data->config.hdr.pci0.expansionROM = htoa(ExpansionROM); 385 data->config.hdr.pci0.interruptLine = htoa(InterruptLine); 386 data->config.hdr.pci0.interruptPin = htoa(InterruptPin); 387 data->config.hdr.pci0.minimumGrant = htoa(MinimumGrant); 388 data->config.hdr.pci0.maximumLatency = htoa(MaximumLatency); 389 390 data->BARSize[0] = BAR0Size; 391 data->BARSize[1] = BAR1Size; 392 data->BARSize[2] = BAR2Size; 393 data->BARSize[3] = BAR3Size; 394 data->BARSize[4] = BAR4Size; 395 data->BARSize[5] = BAR5Size; 396 397 return data; 398} 399 400REGISTER_SIM_OBJECT("PciConfigData", PciConfigData) 401 402#endif // DOXYGEN_SHOULD_SKIP_THIS 403