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#ifndef __DEV_PCI_HOST_HH__
41#define __DEV_PCI_HOST_HH__
42
43#include "dev/io_device.hh"
44#include "dev/pci/types.hh"
45
46struct PciHostParams;
47struct GenericPciHostParams;
48
49class PciDevice;
50class Platform;
51
52/**
53 * The PCI host describes the interface between PCI devices and a
54 * simulated system.
55 *
56 * The PCI host controller has three main responsibilities:
57 * <ol>
58 *     <li>Expose a configuration memory space that allows devices to
59 *         be discovered and configured.
60 *     <li>Map and deliver interrupts to the CPU.
61 *     <li>Map memory addresses from the PCI bus's various memory
62 *         spaces (Legacy IO, non-prefetchable memory, and
63 *         prefetchable memory) to physical memory.
64 * </ol>
65 *
66 * PCI devices need to register themselves with a PCI host using the
67 * PciHost::registerDevice() call. This call returns a
68 * PciHost::DeviceInterface that provides for common functionality
69 * such as interrupt delivery and memory mapping.
70 *
71 * The PciHost class itself provides very little functionality. Simple
72 * PciHost functionality is implemented by the GenericPciHost class.
73 */
74class PciHost : public PioDevice
75{
76  public:
77    PciHost(const PciHostParams *p);
78    virtual ~PciHost();
79
80  public:
81    /**
82     * @{
83     * @name Device interface
84     */
85
86    /**
87     * Callback interface from PCI devices to the host.
88     *
89     * Devices get an instance of this object when they register
90     * themselves with the host using the PciHost::registerDevice()
91     * call.
92     */
93    class DeviceInterface
94    {
95        friend class ::PciHost;
96
97      protected:
98        /**
99         * Instantiate a device interface
100         *
101         * @param host PCI host that this device belongs to.
102         * @param bus_addr The device's position on the PCI bus
103         * @param pin Interrupt pin
104         */
105        DeviceInterface(PciHost &host, PciBusAddr &bus_addr, PciIntPin pin);
106
107      public:
108        DeviceInterface() = delete;
109        void operator=(const DeviceInterface &) = delete;
110
111        const std::string name() const;
112
113        /**
114         * Post a PCI interrupt to the CPU.
115         */
116        void postInt();
117
118        /**
119         * Clear a posted PCI interrupt
120         */
121        void clearInt();
122
123        /**
124         * Calculate the physical address of an IO location on the PCI
125         * bus.
126         *
127         * @param addr Address in the PCI IO address space
128         * @return Address in the system's physical address space.
129         */
130        Addr pioAddr(Addr addr) const { return host.pioAddr(busAddr, addr); }
131
132        /**
133         * Calculate the physical address of a non-prefetchable memory
134         * location in the PCI address space.
135         *
136         * @param addr Address in the PCI memory address space
137         * @return Address in the system's physical address space.
138         */
139        Addr memAddr(Addr addr) const { return host.memAddr(busAddr, addr); }
140
141        /**
142         * Calculate the physical address of a prefetchable memory
143         * location in the PCI address space.
144         *
145         * @param addr Address in the PCI DMA memory address space
146         * @return Address in the system's physical address space.
147         */
148        Addr dmaAddr(Addr addr) const { return host.dmaAddr(busAddr, addr); }
149
150      protected:
151        PciHost &host;
152
153        const PciBusAddr busAddr;
154        const PciIntPin interruptPin;
155    };
156
157    /**
158     * Register a PCI device with the host.
159     *
160     * @param device Device to register
161     * @param bus_addr The device's position on the PCI bus
162     * @param pin Interrupt pin
163     * @return A device-specific DeviceInterface instance.
164     */
165    virtual DeviceInterface registerDevice(PciDevice *device,
166                                           PciBusAddr bus_addr, PciIntPin pin);
167
168    /** @} */
169
170  protected:
171    /**
172     * @{
173     * @name PciHost controller interface
174     */
175
176    /**
177     * Post an interrupt to the CPU.
178     *
179     * @param bus_addr The device's position on the PCI bus
180     * @param pin PCI interrupt pin
181     */
182    virtual void postInt(const PciBusAddr &bus_addr, PciIntPin pin) = 0;
183
184    /**
185     * Post an interrupt to the CPU.
186     *
187     * @param bus_addr The device's position on the PCI bus
188     * @param pin PCI interrupt pin
189     */
190    virtual void clearInt(const PciBusAddr &bus_addr, PciIntPin pin) = 0;
191
192    /**
193     * Calculate the physical address of an IO location on the PCI
194     * bus.
195     *
196     * @param bus_addr The device's position on the PCI bus
197     * @param pci_addr Address in the PCI IO address space
198     * @return Address in the system's physical address space.
199     */
200    virtual Addr pioAddr(const PciBusAddr &bus_addr, Addr pci_addr) const = 0;
201
202    /**
203     * Calculate the physical address of a non-prefetchable memory
204     * location in the PCI address space.
205     *
206     * @param bus_addr The device's position on the PCI bus
207     * @param pci_addr Address in the PCI memory address space
208     * @return Address in the system's physical address space.
209     */
210    virtual Addr memAddr(const PciBusAddr &bus_addr, Addr pci_addr) const = 0;
211
212
213    /**
214     * Calculate the physical address of a prefetchable memory
215     * location in the PCI address space.
216     *
217     * @param bus_addr The device's position on the PCI bus
218     * @param pci_addr Address in the PCI DMA memory address space
219     * @return Address in the system's physical address space.
220     */
221    virtual Addr dmaAddr(const PciBusAddr &bus_addr, Addr pci_addr) const = 0;
222
223    /** @} */
224
225  protected:
226    /**
227     * Retrieve a PCI device from its bus address.
228     *
229     * @return Pointer to a PciDevice instance or nullptr if the
230     *         device doesn't exist.
231     */
232    PciDevice *getDevice(const PciBusAddr &addr);
233
234    /**
235     * Retrieve a PCI device from its bus address.
236     *
237     * @return Pointer to a constant PciDevice instance or nullptr if
238     *         the device doesn't exist.
239     */
240    const PciDevice *getDevice(const PciBusAddr &addr) const;
241
242  private:
243    /** Currently registered PCI devices */
244    std::map<PciBusAddr, PciDevice *> devices;
245};
246
247/**
248 * Configurable generic PCI host interface
249 *
250 * The GenericPciHost provides a configurable generic PCI host
251 * implementation.
252 *
253 * The generic controller binds to one range of physical addresses to
254 * implement the PCI subsystem's configuraiton space. The base
255 * address, size and mapping between memory addresses and PCI devices
256 * are all configurable as simulation parameters. The basic
257 * implementation supports both the Configuration Access Mechanism
258 * (CAM) and Enhanced Configuration Access Mechanism (ECAM)
259 * configuration space layout. The layouts can be configured by
260 * changing the number of bits allocated to each device in the
261 * configuration space. ECAM uses 12 bits per device, while CAM uses 8
262 * bits per device.
263 *
264 * Interrupts are delivered via the Platform::postInt() and
265 * Platform::clearInt() calls. Interrupt numbers are mapped statically
266 * using the interrupt line (PciDevice::interruptLine()) returned from
267 * the device. Implementations may override mapPciInterrupt() to
268 * dynamically map a PciBusAddr and PciIntPin to a platform-specific
269 * interrupt.
270 *
271 * All PCI memory spaces (IO, prefetchable, and non-prefetchable)
272 * support a simple base+offset mapping that can be configured using
273 * simulation parameters. The base defaults to 0 for all of them.
274 */
275class GenericPciHost : public PciHost
276{
277  public:
278    GenericPciHost(const GenericPciHostParams *p);
279    virtual ~GenericPciHost();
280
281  public: // PioDevice
282    Tick read(PacketPtr pkt) override;
283    Tick write(PacketPtr pkt) override;
284
285    AddrRangeList getAddrRanges() const override;
286
287  protected: // PciHost
288    Addr pioAddr(const PciBusAddr &bus_addr, Addr pci_addr) const override {
289        return pciPioBase + pci_addr;
290    }
291
292    Addr memAddr(const PciBusAddr &bus_addr, Addr pci_addr) const override {
293        return pciMemBase + pci_addr;
294    }
295
296    Addr dmaAddr(const PciBusAddr &bus_addr, Addr pci_addr) const override {
297        return pciDmaBase + pci_addr;
298    }
299
300  protected: // Configuration address space handling
301    /**
302     * Decode a configuration space address.
303     *
304     *
305     * @param addr Offset into the configuration space
306     * @return Tuple containing the PCI bus address and an offset into
307     *         the device's configuration space.
308     */
309    virtual std::pair<PciBusAddr, Addr> decodeAddress(Addr address);
310
311  protected: // Interrupt handling
312    void postInt(const PciBusAddr &addr, PciIntPin pin) override;
313    void clearInt(const PciBusAddr &addr, PciIntPin pin) override;
314
315    virtual uint32_t mapPciInterrupt(const PciBusAddr &bus_addr,
316                                     PciIntPin pin) const;
317
318  protected:
319    Platform &platform;
320
321    const Addr confBase;
322    const Addr confSize;
323    const uint8_t confDeviceBits;
324
325    const Addr pciPioBase;
326    const Addr pciMemBase;
327    const Addr pciDmaBase;
328};
329
330#endif // __DEV_PCI_HOST_HH__
331