1/* 2 * Copyright (c) 2015 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Andreas Sandberg 38 */ 39 40#include "dev/pci/host.hh" 41 42#include <utility> 43 44#include "debug/PciHost.hh" 45#include "dev/pci/device.hh" 46#include "dev/platform.hh" 47#include "params/GenericPciHost.hh" 48#include "params/PciHost.hh" 49 50PciHost::PciHost(const PciHostParams *p) 51 : PioDevice(p) 52{ 53} 54 55PciHost::~PciHost() 56{ 57} 58 59PciHost::DeviceInterface 60PciHost::registerDevice(PciDevice *device, PciBusAddr bus_addr, PciIntPin pin) 61{ 62 auto map_entry = devices.emplace(bus_addr, device); 63 64 DPRINTF(PciHost, "%02x:%02x.%i: Registering device\n", 65 bus_addr.bus, bus_addr.dev, bus_addr.func); 66 67 fatal_if(!map_entry.second, 68 "%02x:%02x.%i: PCI bus ID collision\n", 69 bus_addr.bus, bus_addr.dev, bus_addr.func); 70 71 return DeviceInterface(*this, bus_addr, pin); 72} 73 74PciDevice * 75PciHost::getDevice(const PciBusAddr &addr) 76{ 77 auto device = devices.find(addr); 78 return device != devices.end() ? device->second : nullptr; 79} 80 81const PciDevice * 82PciHost::getDevice(const PciBusAddr &addr) const 83{ 84 auto device = devices.find(addr); 85 return device != devices.end() ? device->second : nullptr; 86} 87 88PciHost::DeviceInterface::DeviceInterface( 89 PciHost &_host, 90 PciBusAddr &bus_addr, PciIntPin interrupt_pin) 91 : host(_host), 92 busAddr(bus_addr), interruptPin(interrupt_pin) 93{ 94} 95 96const std::string 97PciHost::DeviceInterface::name() const 98{ 99 return csprintf("%s.interface[%02x:%02x.%i]", 100 host.name(), busAddr.bus, busAddr.dev, busAddr.func); 101} 102 103void 104PciHost::DeviceInterface::postInt() 105{ 106 DPRINTF(PciHost, "postInt\n"); 107 108 host.postInt(busAddr, interruptPin); 109} 110 111void 112PciHost::DeviceInterface::clearInt() 113{ 114 DPRINTF(PciHost, "clearInt\n"); 115 116 host.clearInt(busAddr, interruptPin); 117} 118 119 120GenericPciHost::GenericPciHost(const GenericPciHostParams *p) 121 : PciHost(p), 122 platform(*p->platform), 123 confBase(p->conf_base), confSize(p->conf_size), 124 confDeviceBits(p->conf_device_bits), 125 pciPioBase(p->pci_pio_base), pciMemBase(p->pci_mem_base), 126 pciDmaBase(p->pci_dma_base) 127{ 128} 129 130GenericPciHost::~GenericPciHost() 131{ 132} 133 134 135Tick 136GenericPciHost::read(PacketPtr pkt) 137{ 138 const auto dev_addr(decodeAddress(pkt->getAddr() - confBase)); 139 const Addr size(pkt->getSize()); 140 141 DPRINTF(PciHost, "%02x:%02x.%i: read: offset=0x%x, size=0x%x\n", 142 dev_addr.first.bus, dev_addr.first.dev, dev_addr.first.func, 143 dev_addr.second, 144 size); 145 146 PciDevice *const pci_dev(getDevice(dev_addr.first)); 147 if (pci_dev) { 148 // @todo Remove this after testing 149 pkt->headerDelay = pkt->payloadDelay = 0; 150 return pci_dev->readConfig(pkt); 151 } else { 152 uint8_t *pkt_data(pkt->getPtr<uint8_t>()); 153 std::fill(pkt_data, pkt_data + size, 0xFF); 154 pkt->makeAtomicResponse(); 155 return 0; 156 } 157} 158 159Tick 160GenericPciHost::write(PacketPtr pkt) 161{ 162 const auto dev_addr(decodeAddress(pkt->getAddr() - confBase)); 163 164 DPRINTF(PciHost, "%02x:%02x.%i: write: offset=0x%x, size=0x%x\n", 165 dev_addr.first.bus, dev_addr.first.dev, dev_addr.first.func, 166 dev_addr.second, 167 pkt->getSize()); 168 169 PciDevice *const pci_dev(getDevice(dev_addr.first)); 170 panic_if(!pci_dev, 171 "%02x:%02x.%i: Write to config space on non-existent PCI device\n", 172 dev_addr.first.bus, dev_addr.first.dev, dev_addr.first.func); 173 174 // @todo Remove this after testing 175 pkt->headerDelay = pkt->payloadDelay = 0; 176 177 return pci_dev->writeConfig(pkt); 178} 179 180AddrRangeList 181GenericPciHost::getAddrRanges() const 182{ 183 return AddrRangeList({ RangeSize(confBase, confSize) }); 184} 185 186std::pair<PciBusAddr, Addr> 187GenericPciHost::decodeAddress(Addr addr) 188{ 189 const Addr offset(addr & mask(confDeviceBits)); 190 const Addr bus_addr(addr >> confDeviceBits); 191 192 return std::make_pair( 193 PciBusAddr(bits(bus_addr, 15, 8), 194 bits(bus_addr, 7, 3), 195 bits(bus_addr, 2, 0)), 196 offset); 197} 198 199 200void 201GenericPciHost::postInt(const PciBusAddr &addr, PciIntPin pin) 202{ 203 platform.postPciInt(mapPciInterrupt(addr, pin)); 204} 205 206void 207GenericPciHost::clearInt(const PciBusAddr &addr, PciIntPin pin) 208{ 209 platform.clearPciInt(mapPciInterrupt(addr, pin)); 210} 211 212 213uint32_t 214GenericPciHost::mapPciInterrupt(const PciBusAddr &addr, PciIntPin pin) const 215{ 216 const PciDevice *dev(getDevice(addr)); 217 assert(dev); 218 219 return dev->interruptLine(); 220} 221 222 223GenericPciHost * 224GenericPciHostParams::create() 225{ 226 return new GenericPciHost(this); 227} 228