111244Sandreas.sandberg@arm.com/*
211244Sandreas.sandberg@arm.com * Copyright (c) 2015 ARM Limited
311244Sandreas.sandberg@arm.com * All rights reserved
411244Sandreas.sandberg@arm.com *
511244Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall
611244Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual
711244Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating
811244Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software
911244Sandreas.sandberg@arm.com * licensed hereunder.  You may use the software subject to the license
1011244Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated
1111244Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software,
1211244Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form.
1311244Sandreas.sandberg@arm.com *
1411244Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without
1511244Sandreas.sandberg@arm.com * modification, are permitted provided that the following conditions are
1611244Sandreas.sandberg@arm.com * met: redistributions of source code must retain the above copyright
1711244Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer;
1811244Sandreas.sandberg@arm.com * redistributions in binary form must reproduce the above copyright
1911244Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer in the
2011244Sandreas.sandberg@arm.com * documentation and/or other materials provided with the distribution;
2111244Sandreas.sandberg@arm.com * neither the name of the copyright holders nor the names of its
2211244Sandreas.sandberg@arm.com * contributors may be used to endorse or promote products derived from
2311244Sandreas.sandberg@arm.com * this software without specific prior written permission.
2411244Sandreas.sandberg@arm.com *
2511244Sandreas.sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2611244Sandreas.sandberg@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2711244Sandreas.sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2811244Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2911244Sandreas.sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3011244Sandreas.sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3111244Sandreas.sandberg@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3211244Sandreas.sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3311244Sandreas.sandberg@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3411244Sandreas.sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3511244Sandreas.sandberg@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3611244Sandreas.sandberg@arm.com *
3711244Sandreas.sandberg@arm.com * Authors: Andreas Sandberg
3811244Sandreas.sandberg@arm.com */
3911244Sandreas.sandberg@arm.com
4011244Sandreas.sandberg@arm.com#include "dev/pci/host.hh"
4111244Sandreas.sandberg@arm.com
4211244Sandreas.sandberg@arm.com#include <utility>
4311244Sandreas.sandberg@arm.com
4411244Sandreas.sandberg@arm.com#include "debug/PciHost.hh"
4511260Sandreas.sandberg@arm.com#include "dev/pci/device.hh"
4611244Sandreas.sandberg@arm.com#include "dev/platform.hh"
4711244Sandreas.sandberg@arm.com#include "params/GenericPciHost.hh"
4811244Sandreas.sandberg@arm.com#include "params/PciHost.hh"
4911244Sandreas.sandberg@arm.com
5011244Sandreas.sandberg@arm.comPciHost::PciHost(const PciHostParams *p)
5111244Sandreas.sandberg@arm.com    : PioDevice(p)
5211244Sandreas.sandberg@arm.com{
5311244Sandreas.sandberg@arm.com}
5411244Sandreas.sandberg@arm.com
5511244Sandreas.sandberg@arm.comPciHost::~PciHost()
5611244Sandreas.sandberg@arm.com{
5711244Sandreas.sandberg@arm.com}
5811244Sandreas.sandberg@arm.com
5911244Sandreas.sandberg@arm.comPciHost::DeviceInterface
6011244Sandreas.sandberg@arm.comPciHost::registerDevice(PciDevice *device, PciBusAddr bus_addr, PciIntPin pin)
6111244Sandreas.sandberg@arm.com{
6211244Sandreas.sandberg@arm.com    auto map_entry = devices.emplace(bus_addr, device);
6311244Sandreas.sandberg@arm.com
6411244Sandreas.sandberg@arm.com    DPRINTF(PciHost, "%02x:%02x.%i: Registering device\n",
6511244Sandreas.sandberg@arm.com            bus_addr.bus, bus_addr.dev, bus_addr.func);
6611244Sandreas.sandberg@arm.com
6711244Sandreas.sandberg@arm.com    fatal_if(!map_entry.second,
6811244Sandreas.sandberg@arm.com             "%02x:%02x.%i: PCI bus ID collision\n",
6911244Sandreas.sandberg@arm.com             bus_addr.bus, bus_addr.dev, bus_addr.func);
7011244Sandreas.sandberg@arm.com
7111244Sandreas.sandberg@arm.com    return DeviceInterface(*this, bus_addr, pin);
7211244Sandreas.sandberg@arm.com}
7311244Sandreas.sandberg@arm.com
7411244Sandreas.sandberg@arm.comPciDevice *
7511244Sandreas.sandberg@arm.comPciHost::getDevice(const PciBusAddr &addr)
7611244Sandreas.sandberg@arm.com{
7711244Sandreas.sandberg@arm.com    auto device = devices.find(addr);
7811244Sandreas.sandberg@arm.com    return device != devices.end() ? device->second : nullptr;
7911244Sandreas.sandberg@arm.com}
8011244Sandreas.sandberg@arm.com
8111244Sandreas.sandberg@arm.comconst PciDevice *
8211244Sandreas.sandberg@arm.comPciHost::getDevice(const PciBusAddr &addr) const
8311244Sandreas.sandberg@arm.com{
8411244Sandreas.sandberg@arm.com    auto device = devices.find(addr);
8511244Sandreas.sandberg@arm.com    return device != devices.end() ? device->second : nullptr;
8611244Sandreas.sandberg@arm.com}
8711244Sandreas.sandberg@arm.com
8811244Sandreas.sandberg@arm.comPciHost::DeviceInterface::DeviceInterface(
8911244Sandreas.sandberg@arm.com    PciHost &_host,
9011244Sandreas.sandberg@arm.com    PciBusAddr &bus_addr, PciIntPin interrupt_pin)
9111244Sandreas.sandberg@arm.com    : host(_host),
9211244Sandreas.sandberg@arm.com      busAddr(bus_addr), interruptPin(interrupt_pin)
9311244Sandreas.sandberg@arm.com{
9411244Sandreas.sandberg@arm.com}
9511244Sandreas.sandberg@arm.com
9611244Sandreas.sandberg@arm.comconst std::string
9711244Sandreas.sandberg@arm.comPciHost::DeviceInterface::name() const
9811244Sandreas.sandberg@arm.com{
9911244Sandreas.sandberg@arm.com    return csprintf("%s.interface[%02x:%02x.%i]",
10011244Sandreas.sandberg@arm.com                    host.name(), busAddr.bus, busAddr.dev, busAddr.func);
10111244Sandreas.sandberg@arm.com}
10211244Sandreas.sandberg@arm.com
10311244Sandreas.sandberg@arm.comvoid
10411244Sandreas.sandberg@arm.comPciHost::DeviceInterface::postInt()
10511244Sandreas.sandberg@arm.com{
10611244Sandreas.sandberg@arm.com    DPRINTF(PciHost, "postInt\n");
10711244Sandreas.sandberg@arm.com
10811244Sandreas.sandberg@arm.com    host.postInt(busAddr, interruptPin);
10911244Sandreas.sandberg@arm.com}
11011244Sandreas.sandberg@arm.com
11111244Sandreas.sandberg@arm.comvoid
11211244Sandreas.sandberg@arm.comPciHost::DeviceInterface::clearInt()
11311244Sandreas.sandberg@arm.com{
11411244Sandreas.sandberg@arm.com    DPRINTF(PciHost, "clearInt\n");
11511244Sandreas.sandberg@arm.com
11611244Sandreas.sandberg@arm.com    host.clearInt(busAddr, interruptPin);
11711244Sandreas.sandberg@arm.com}
11811244Sandreas.sandberg@arm.com
11911244Sandreas.sandberg@arm.com
12011244Sandreas.sandberg@arm.comGenericPciHost::GenericPciHost(const GenericPciHostParams *p)
12111244Sandreas.sandberg@arm.com    : PciHost(p),
12211244Sandreas.sandberg@arm.com      platform(*p->platform),
12311244Sandreas.sandberg@arm.com      confBase(p->conf_base), confSize(p->conf_size),
12411244Sandreas.sandberg@arm.com      confDeviceBits(p->conf_device_bits),
12511244Sandreas.sandberg@arm.com      pciPioBase(p->pci_pio_base), pciMemBase(p->pci_mem_base),
12611244Sandreas.sandberg@arm.com      pciDmaBase(p->pci_dma_base)
12711244Sandreas.sandberg@arm.com{
12811244Sandreas.sandberg@arm.com}
12911244Sandreas.sandberg@arm.com
13011244Sandreas.sandberg@arm.comGenericPciHost::~GenericPciHost()
13111244Sandreas.sandberg@arm.com{
13211244Sandreas.sandberg@arm.com}
13311244Sandreas.sandberg@arm.com
13411244Sandreas.sandberg@arm.com
13511244Sandreas.sandberg@arm.comTick
13611244Sandreas.sandberg@arm.comGenericPciHost::read(PacketPtr pkt)
13711244Sandreas.sandberg@arm.com{
13811244Sandreas.sandberg@arm.com    const auto dev_addr(decodeAddress(pkt->getAddr() - confBase));
13911244Sandreas.sandberg@arm.com    const Addr size(pkt->getSize());
14011244Sandreas.sandberg@arm.com
14111244Sandreas.sandberg@arm.com    DPRINTF(PciHost, "%02x:%02x.%i: read: offset=0x%x, size=0x%x\n",
14211244Sandreas.sandberg@arm.com            dev_addr.first.bus, dev_addr.first.dev, dev_addr.first.func,
14311244Sandreas.sandberg@arm.com            dev_addr.second,
14411244Sandreas.sandberg@arm.com            size);
14511244Sandreas.sandberg@arm.com
14611244Sandreas.sandberg@arm.com    PciDevice *const pci_dev(getDevice(dev_addr.first));
14711244Sandreas.sandberg@arm.com    if (pci_dev) {
14811244Sandreas.sandberg@arm.com        // @todo Remove this after testing
14911244Sandreas.sandberg@arm.com        pkt->headerDelay = pkt->payloadDelay = 0;
15011244Sandreas.sandberg@arm.com        return pci_dev->readConfig(pkt);
15111244Sandreas.sandberg@arm.com    } else {
15211244Sandreas.sandberg@arm.com        uint8_t *pkt_data(pkt->getPtr<uint8_t>());
15311244Sandreas.sandberg@arm.com        std::fill(pkt_data, pkt_data + size, 0xFF);
15411244Sandreas.sandberg@arm.com        pkt->makeAtomicResponse();
15511244Sandreas.sandberg@arm.com        return 0;
15611244Sandreas.sandberg@arm.com    }
15711244Sandreas.sandberg@arm.com}
15811244Sandreas.sandberg@arm.com
15911244Sandreas.sandberg@arm.comTick
16011244Sandreas.sandberg@arm.comGenericPciHost::write(PacketPtr pkt)
16111244Sandreas.sandberg@arm.com{
16211244Sandreas.sandberg@arm.com    const auto dev_addr(decodeAddress(pkt->getAddr() - confBase));
16311244Sandreas.sandberg@arm.com
16411244Sandreas.sandberg@arm.com    DPRINTF(PciHost, "%02x:%02x.%i: write: offset=0x%x, size=0x%x\n",
16511244Sandreas.sandberg@arm.com            dev_addr.first.bus, dev_addr.first.dev, dev_addr.first.func,
16611244Sandreas.sandberg@arm.com            dev_addr.second,
16711244Sandreas.sandberg@arm.com            pkt->getSize());
16811244Sandreas.sandberg@arm.com
16911244Sandreas.sandberg@arm.com    PciDevice *const pci_dev(getDevice(dev_addr.first));
17011244Sandreas.sandberg@arm.com    panic_if(!pci_dev,
17111244Sandreas.sandberg@arm.com             "%02x:%02x.%i: Write to config space on non-existent PCI device\n",
17211244Sandreas.sandberg@arm.com             dev_addr.first.bus, dev_addr.first.dev, dev_addr.first.func);
17311244Sandreas.sandberg@arm.com
17411244Sandreas.sandberg@arm.com    // @todo Remove this after testing
17511244Sandreas.sandberg@arm.com    pkt->headerDelay = pkt->payloadDelay = 0;
17611244Sandreas.sandberg@arm.com
17711244Sandreas.sandberg@arm.com    return pci_dev->writeConfig(pkt);
17811244Sandreas.sandberg@arm.com}
17911244Sandreas.sandberg@arm.com
18011244Sandreas.sandberg@arm.comAddrRangeList
18111244Sandreas.sandberg@arm.comGenericPciHost::getAddrRanges() const
18211244Sandreas.sandberg@arm.com{
18311244Sandreas.sandberg@arm.com    return AddrRangeList({ RangeSize(confBase, confSize) });
18411244Sandreas.sandberg@arm.com}
18511244Sandreas.sandberg@arm.com
18611244Sandreas.sandberg@arm.comstd::pair<PciBusAddr, Addr>
18711244Sandreas.sandberg@arm.comGenericPciHost::decodeAddress(Addr addr)
18811244Sandreas.sandberg@arm.com{
18911244Sandreas.sandberg@arm.com    const Addr offset(addr & mask(confDeviceBits));
19011244Sandreas.sandberg@arm.com    const Addr bus_addr(addr >> confDeviceBits);
19111244Sandreas.sandberg@arm.com
19211244Sandreas.sandberg@arm.com    return std::make_pair(
19311244Sandreas.sandberg@arm.com        PciBusAddr(bits(bus_addr, 15, 8),
19411244Sandreas.sandberg@arm.com                   bits(bus_addr,  7, 3),
19511244Sandreas.sandberg@arm.com                   bits(bus_addr,  2, 0)),
19611244Sandreas.sandberg@arm.com        offset);
19711244Sandreas.sandberg@arm.com}
19811244Sandreas.sandberg@arm.com
19911244Sandreas.sandberg@arm.com
20011244Sandreas.sandberg@arm.comvoid
20111244Sandreas.sandberg@arm.comGenericPciHost::postInt(const PciBusAddr &addr, PciIntPin pin)
20211244Sandreas.sandberg@arm.com{
20311244Sandreas.sandberg@arm.com    platform.postPciInt(mapPciInterrupt(addr, pin));
20411244Sandreas.sandberg@arm.com}
20511244Sandreas.sandberg@arm.com
20611244Sandreas.sandberg@arm.comvoid
20711244Sandreas.sandberg@arm.comGenericPciHost::clearInt(const PciBusAddr &addr, PciIntPin pin)
20811244Sandreas.sandberg@arm.com{
20911244Sandreas.sandberg@arm.com    platform.clearPciInt(mapPciInterrupt(addr, pin));
21011244Sandreas.sandberg@arm.com}
21111244Sandreas.sandberg@arm.com
21211244Sandreas.sandberg@arm.com
21311244Sandreas.sandberg@arm.comuint32_t
21411244Sandreas.sandberg@arm.comGenericPciHost::mapPciInterrupt(const PciBusAddr &addr, PciIntPin pin) const
21511244Sandreas.sandberg@arm.com{
21611244Sandreas.sandberg@arm.com    const PciDevice *dev(getDevice(addr));
21711244Sandreas.sandberg@arm.com    assert(dev);
21811244Sandreas.sandberg@arm.com
21911244Sandreas.sandberg@arm.com    return dev->interruptLine();
22011244Sandreas.sandberg@arm.com}
22111244Sandreas.sandberg@arm.com
22211244Sandreas.sandberg@arm.com
22311244Sandreas.sandberg@arm.comGenericPciHost *
22411244Sandreas.sandberg@arm.comGenericPciHostParams::create()
22511244Sandreas.sandberg@arm.com{
22611244Sandreas.sandberg@arm.com    return new GenericPciHost(this);
22711244Sandreas.sandberg@arm.com}
228