device.hh revision 2846
1955SN/A/*
2955SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
31762SN/A * All rights reserved.
4955SN/A *
5955SN/A * Redistribution and use in source and binary forms, with or without
6955SN/A * modification, are permitted provided that the following conditions are
7955SN/A * met: redistributions of source code must retain the above copyright
8955SN/A * notice, this list of conditions and the following disclaimer;
9955SN/A * redistributions in binary form must reproduce the above copyright
10955SN/A * notice, this list of conditions and the following disclaimer in the
11955SN/A * documentation and/or other materials provided with the distribution;
12955SN/A * neither the name of the copyright holders nor the names of its
13955SN/A * contributors may be used to endorse or promote products derived from
14955SN/A * this software without specific prior written permission.
15955SN/A *
16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27955SN/A *
282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi
294762Snate@binkert.org *          Andrew Schultz
30955SN/A *          Nathan Binkert
315522Snate@binkert.org */
326143Snate@binkert.org
334762Snate@binkert.org/* @file
345522Snate@binkert.org * Interface for devices using PCI configuration
35955SN/A */
365522Snate@binkert.org
3711974Sgabeblack@google.com#ifndef __DEV_PCIDEV_HH__
38955SN/A#define __DEV_PCIDEV_HH__
395522Snate@binkert.org
404202Sbinkertn@umich.edu#include "dev/io_device.hh"
415742Snate@binkert.org#include "dev/pcireg.h"
42955SN/A#include "dev/platform.hh"
434381Sbinkertn@umich.edu
444381Sbinkertn@umich.edu#define BAR_IO_MASK 0x3
458334Snate@binkert.org#define BAR_MEM_MASK 0xF
46955SN/A#define BAR_IO_SPACE_BIT 0x1
47955SN/A#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT)
484202Sbinkertn@umich.edu#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2);
49955SN/A
504382Sbinkertn@umich.edu
514382Sbinkertn@umich.edu/**
524382Sbinkertn@umich.edu * This class encapulates the first 64 bytes of a singles PCI
536654Snate@binkert.org * devices config space that in configured by the configuration file.
545517Snate@binkert.org */
558614Sgblack@eecs.umich.educlass PciConfigData : public SimObject
567674Snate@binkert.org{
576143Snate@binkert.org  public:
586143Snate@binkert.org    /**
596143Snate@binkert.org     * Constructor to initialize the devices config space to 0.
608233Snate@binkert.org     */
618233Snate@binkert.org    PciConfigData(const std::string &name)
628233Snate@binkert.org        : SimObject(name)
638233Snate@binkert.org    {
648233Snate@binkert.org        memset(config.data, 0, sizeof(config.data));
658334Snate@binkert.org        memset(BARAddrs, 0, sizeof(BARAddrs));
668334Snate@binkert.org        memset(BARSize, 0, sizeof(BARSize));
6710453SAndrew.Bardsley@arm.com    }
6810453SAndrew.Bardsley@arm.com
698233Snate@binkert.org    /** The first 64 bytes */
708233Snate@binkert.org    PCIConfig config;
718233Snate@binkert.org
728233Snate@binkert.org    /** The size of the BARs */
738233Snate@binkert.org    uint32_t BARSize[6];
748233Snate@binkert.org
7511983Sgabeblack@google.com    /** The addresses of the BARs */
7611983Sgabeblack@google.com    Addr BARAddrs[6];
7711983Sgabeblack@google.com};
7811983Sgabeblack@google.com
7911983Sgabeblack@google.com
8011983Sgabeblack@google.com/**
8111983Sgabeblack@google.com * PCI device, base implemnation is only config space.
8211983Sgabeblack@google.com */
8311983Sgabeblack@google.comclass PciDev : public DmaDevice
8411983Sgabeblack@google.com{
8511983Sgabeblack@google.com    class PciConfigPort : public PioPort
866143Snate@binkert.org    {
878233Snate@binkert.org      protected:
888233Snate@binkert.org        PciDev *device;
898233Snate@binkert.org
906143Snate@binkert.org        virtual bool recvTiming(Packet *pkt);
916143Snate@binkert.org
926143Snate@binkert.org        virtual Tick recvAtomic(Packet *pkt);
9311308Santhony.gutierrez@amd.com
948233Snate@binkert.org        virtual void recvFunctional(Packet *pkt) ;
958233Snate@binkert.org
968233Snate@binkert.org        virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
9711983Sgabeblack@google.com
9811983Sgabeblack@google.com        int busId;
994762Snate@binkert.org        int deviceId;
1006143Snate@binkert.org        int functionId;
1018233Snate@binkert.org
1028233Snate@binkert.org        Addr configAddr;
1038233Snate@binkert.org
1048233Snate@binkert.org      public:
1058233Snate@binkert.org        PciConfigPort(PciDev *dev, int busid, int devid, int funcid,
1066143Snate@binkert.org                Platform *p);
1078233Snate@binkert.org
1088233Snate@binkert.org      friend class PioPort::SendEvent;
1098233Snate@binkert.org    };
1108233Snate@binkert.org
1116143Snate@binkert.org  public:
1126143Snate@binkert.org    struct Params : public PioDevice::Params
1136143Snate@binkert.org    {
1146143Snate@binkert.org        /**
1156143Snate@binkert.org         * A pointer to the object that contains the first 64 bytes of
1166143Snate@binkert.org         * config space
1176143Snate@binkert.org         */
1186143Snate@binkert.org        PciConfigData *configData;
1196143Snate@binkert.org
1207065Snate@binkert.org        /** The bus number we are on */
1216143Snate@binkert.org        uint32_t busNum;
1228233Snate@binkert.org
1238233Snate@binkert.org        /** The device number we have */
1248233Snate@binkert.org        uint32_t deviceNum;
1258233Snate@binkert.org
1268233Snate@binkert.org        /** The function number */
1278233Snate@binkert.org        uint32_t functionNum;
1288233Snate@binkert.org
1298233Snate@binkert.org        /** The latency for pio accesses. */
1308233Snate@binkert.org        Tick pio_delay;
1318233Snate@binkert.org
1328233Snate@binkert.org        /** The latency for a config access. */
1338233Snate@binkert.org        Tick config_delay;
1348233Snate@binkert.org    };
1358233Snate@binkert.org
1368233Snate@binkert.org  public:
1378233Snate@binkert.org    const Params *params() const { return (const Params *)_params; }
1388233Snate@binkert.org
1398233Snate@binkert.org  protected:
1408233Snate@binkert.org    /** The current config space. Unlike the PciConfigData this is
1418233Snate@binkert.org     * updated during simulation while continues to reflect what was
1428233Snate@binkert.org     * in the config file.
1438233Snate@binkert.org     */
1448233Snate@binkert.org    PCIConfig config;
1458233Snate@binkert.org
1468233Snate@binkert.org    /** The size of the BARs */
1478233Snate@binkert.org    uint32_t BARSize[6];
1488233Snate@binkert.org
1498233Snate@binkert.org    /** The current address mapping of the BARs */
1508233Snate@binkert.org    Addr BARAddrs[6];
1518233Snate@binkert.org
1528233Snate@binkert.org    bool
1536143Snate@binkert.org    isBAR(Addr addr, int bar) const
1546143Snate@binkert.org    {
1556143Snate@binkert.org        assert(bar >= 0 && bar < 6);
1566143Snate@binkert.org        return BARAddrs[bar] <= addr && addr < BARAddrs[bar] + BARSize[bar];
1576143Snate@binkert.org    }
1586143Snate@binkert.org
1599982Satgutier@umich.edu    int
16010196SCurtis.Dunham@arm.com    getBAR(Addr addr)
16110196SCurtis.Dunham@arm.com    {
16210196SCurtis.Dunham@arm.com        for (int i = 0; i <= 5; ++i)
16310196SCurtis.Dunham@arm.com            if (isBAR(addr, i))
16410196SCurtis.Dunham@arm.com                return i;
16510196SCurtis.Dunham@arm.com
16610196SCurtis.Dunham@arm.com        return -1;
16710196SCurtis.Dunham@arm.com    }
1686143Snate@binkert.org
16911983Sgabeblack@google.com    bool
17011983Sgabeblack@google.com    getBAR(Addr paddr, Addr &daddr, int &bar)
17111983Sgabeblack@google.com    {
17211983Sgabeblack@google.com        int b = getBAR(paddr);
17311983Sgabeblack@google.com        if (b < 0)
17411983Sgabeblack@google.com            return false;
17511983Sgabeblack@google.com
17611983Sgabeblack@google.com        daddr = paddr - BARAddrs[b];
17711983Sgabeblack@google.com        bar = b;
1786143Snate@binkert.org        return true;
17911988Sandreas.sandberg@arm.com    }
1808233Snate@binkert.org
1818233Snate@binkert.org  protected:
1826143Snate@binkert.org    Platform *plat;
1838945Ssteve.reinhardt@amd.com    PciConfigData *configData;
1846143Snate@binkert.org    Tick pioDelay;
18511983Sgabeblack@google.com    Tick configDelay;
18611983Sgabeblack@google.com    PciConfigPort *configPort;
1876143Snate@binkert.org
1886143Snate@binkert.org    /**
1895522Snate@binkert.org     * Write to the PCI config space data that is stored locally. This may be
1906143Snate@binkert.org     * overridden by the device but at some point it will eventually call this
1916143Snate@binkert.org     * for normal operations that it does not need to override.
1926143Snate@binkert.org     * @param pkt packet containing the write the offset into config space
1939982Satgutier@umich.edu     */
1948233Snate@binkert.org    virtual Tick writeConfig(Packet *pkt);
1958233Snate@binkert.org
1968233Snate@binkert.org
1976143Snate@binkert.org    /**
1986143Snate@binkert.org     * Read from the PCI config space data that is stored locally. This may be
1996143Snate@binkert.org     * overridden by the device but at some point it will eventually call this
2006143Snate@binkert.org     * for normal operations that it does not need to override.
2015522Snate@binkert.org     * @param pkt packet containing the write the offset into config space
2025522Snate@binkert.org     */
2035522Snate@binkert.org    virtual Tick readConfig(Packet *pkt);
2045522Snate@binkert.org
2055604Snate@binkert.org  public:
2065604Snate@binkert.org    Addr pciToDma(Addr pciAddr) const
2076143Snate@binkert.org    { return plat->pciToDma(pciAddr); }
2086143Snate@binkert.org
2094762Snate@binkert.org    void
2104762Snate@binkert.org    intrPost()
2116143Snate@binkert.org    { plat->postPciInt(letoh(configData->config.interruptLine)); }
2126727Ssteve.reinhardt@amd.com
2136727Ssteve.reinhardt@amd.com    void
2146727Ssteve.reinhardt@amd.com    intrClear()
2154762Snate@binkert.org    { plat->clearPciInt(letoh(configData->config.interruptLine)); }
2166143Snate@binkert.org
2176143Snate@binkert.org    uint8_t
2186143Snate@binkert.org    interruptLine()
2196143Snate@binkert.org    { return letoh(configData->config.interruptLine); }
2206727Ssteve.reinhardt@amd.com
2216143Snate@binkert.org    /** return the address ranges that this device responds to.
2227674Snate@binkert.org     * @params range_list range list to populate with ranges
2237674Snate@binkert.org     */
2245604Snate@binkert.org    void addressRanges(AddrRangeList &range_list);
2256143Snate@binkert.org
2266143Snate@binkert.org    /** Do a PCI Configspace memory access. */
2276143Snate@binkert.org    Tick recvConfig(Packet *pkt)
2284762Snate@binkert.org    { return pkt->isRead() ? readConfig(pkt) : writeConfig(pkt); }
2296143Snate@binkert.org
2304762Snate@binkert.org    /**
2314762Snate@binkert.org     * Constructor for PCI Dev. This function copies data from the
2324762Snate@binkert.org     * config file object PCIConfigData and registers the device with
2336143Snate@binkert.org     * a PciConfigAll object.
2346143Snate@binkert.org     */
2354762Snate@binkert.org    PciDev(Params *params);
2368233Snate@binkert.org
2378233Snate@binkert.org    virtual void init();
2388233Snate@binkert.org
2398233Snate@binkert.org    /**
2406143Snate@binkert.org     * Serialize this object to the given output stream.
2416143Snate@binkert.org     * @param os The stream to serialize to.
2424762Snate@binkert.org     */
2436143Snate@binkert.org    virtual void serialize(std::ostream &os);
2444762Snate@binkert.org
2459396Sandreas.hansson@arm.com    /**
2469396Sandreas.hansson@arm.com     * Reconstruct the state of this object from a checkpoint.
2479396Sandreas.hansson@arm.com     * @param cp The checkpoint use.
2489396Sandreas.hansson@arm.com     * @param section The section name of this object
2499396Sandreas.hansson@arm.com     */
2509396Sandreas.hansson@arm.com    virtual void unserialize(Checkpoint *cp, const std::string &section);
2519396Sandreas.hansson@arm.com
2529396Sandreas.hansson@arm.com    virtual Port *getPort(const std::string &if_name, int idx = -1)
2539396Sandreas.hansson@arm.com    {
2549396Sandreas.hansson@arm.com        if (if_name == "config") {
2559396Sandreas.hansson@arm.com            if (configPort != NULL)
2569396Sandreas.hansson@arm.com                panic("pciconfig port already connected to.");
2579396Sandreas.hansson@arm.com            configPort = new PciConfigPort(this, params()->busNum,
2589930Sandreas.hansson@arm.com                    params()->deviceNum, params()->functionNum,
2599930Sandreas.hansson@arm.com                    params()->platform);
2609396Sandreas.hansson@arm.com            return configPort;
2618235Snate@binkert.org        }
2628235Snate@binkert.org        return DmaDevice::getPort(if_name, idx);
2636143Snate@binkert.org    }
2648235Snate@binkert.org
2659003SAli.Saidi@ARM.com};
2668235Snate@binkert.org#endif // __DEV_PCIDEV_HH__
2678235Snate@binkert.org