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