/*
- * Copyright (c) 2011-2014 ARM Limited
+ * Copyright (c) 2011-2015, 2017 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
#ifndef __MEM_COHERENT_XBAR_HH__
#define __MEM_COHERENT_XBAR_HH__
+#include <unordered_map>
+#include <unordered_set>
+
#include "mem/snoop_filter.hh"
#include "mem/xbar.hh"
#include "params/CoherentXBar.hh"
* Declare the layers of this crossbar, one vector for requests,
* one for responses, and one for snoop responses
*/
- typedef Layer<SlavePort,MasterPort> ReqLayer;
- typedef Layer<MasterPort,SlavePort> RespLayer;
- typedef Layer<SlavePort,MasterPort> SnoopLayer;
std::vector<ReqLayer*> reqLayers;
std::vector<RespLayer*> respLayers;
- std::vector<SnoopLayer*> snoopLayers;
+ std::vector<SnoopRespLayer*> snoopLayers;
/**
* Declaration of the coherent crossbar slave port type, one will
* be instantiated for each of the master ports connecting to the
* crossbar.
*/
- class CoherentXBarSlavePort : public SlavePort
+ class CoherentXBarSlavePort : public QueuedSlavePort
{
private:
/** A reference to the crossbar to which this port belongs. */
CoherentXBar &xbar;
+ /** A normal packet queue used to store responses. */
+ RespPacketQueue queue;
+
public:
CoherentXBarSlavePort(const std::string &_name,
CoherentXBar &_xbar, PortID _id)
- : SlavePort(_name, &_xbar, _id), xbar(_xbar)
+ : QueuedSlavePort(_name, &_xbar, queue, _id), xbar(_xbar),
+ queue(_xbar, *this)
{ }
protected:
- /**
- * When receiving a timing request, pass it to the crossbar.
- */
- virtual bool recvTimingReq(PacketPtr pkt)
- { return xbar.recvTimingReq(pkt, id); }
+ bool
+ recvTimingReq(PacketPtr pkt) override
+ {
+ return xbar.recvTimingReq(pkt, id);
+ }
- /**
- * When receiving a timing snoop response, pass it to the crossbar.
- */
- virtual bool recvTimingSnoopResp(PacketPtr pkt)
- { return xbar.recvTimingSnoopResp(pkt, id); }
+ bool
+ recvTimingSnoopResp(PacketPtr pkt) override
+ {
+ return xbar.recvTimingSnoopResp(pkt, id);
+ }
- /**
- * When receiving an atomic request, pass it to the crossbar.
- */
- virtual Tick recvAtomic(PacketPtr pkt)
- { return xbar.recvAtomic(pkt, id); }
+ Tick
+ recvAtomic(PacketPtr pkt) override
+ {
+ return xbar.recvAtomicBackdoor(pkt, id);
+ }
- /**
- * When receiving a functional request, pass it to the crossbar.
- */
- virtual void recvFunctional(PacketPtr pkt)
- { xbar.recvFunctional(pkt, id); }
+ Tick
+ recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor) override
+ {
+ return xbar.recvAtomicBackdoor(pkt, id, &backdoor);
+ }
- /**
- * When receiving a retry, pass it to the crossbar.
- */
- virtual void recvRetry()
- { panic("Crossbar slave ports should never retry.\n"); }
+ void
+ recvFunctional(PacketPtr pkt) override
+ {
+ xbar.recvFunctional(pkt, id);
+ }
- /**
- * Return the union of all adress ranges seen by this crossbar.
- */
- virtual AddrRangeList getAddrRanges() const
- { return xbar.getAddrRanges(); }
+ AddrRangeList
+ getAddrRanges() const override
+ {
+ return xbar.getAddrRanges();
+ }
};
*
* @return a boolean that is true if this port is snooping
*/
- virtual bool isSnooping() const
- { return true; }
+ bool isSnooping() const override { return true; }
- /**
- * When receiving a timing response, pass it to the crossbar.
- */
- virtual bool recvTimingResp(PacketPtr pkt)
- { return xbar.recvTimingResp(pkt, id); }
-
- /**
- * When receiving a timing snoop request, pass it to the crossbar.
- */
- virtual void recvTimingSnoopReq(PacketPtr pkt)
- { return xbar.recvTimingSnoopReq(pkt, id); }
+ bool
+ recvTimingResp(PacketPtr pkt) override
+ {
+ return xbar.recvTimingResp(pkt, id);
+ }
- /**
- * When receiving an atomic snoop request, pass it to the crossbar.
- */
- virtual Tick recvAtomicSnoop(PacketPtr pkt)
- { return xbar.recvAtomicSnoop(pkt, id); }
+ void
+ recvTimingSnoopReq(PacketPtr pkt) override
+ {
+ return xbar.recvTimingSnoopReq(pkt, id);
+ }
- /**
- * When receiving a functional snoop request, pass it to the crossbar.
- */
- virtual void recvFunctionalSnoop(PacketPtr pkt)
- { xbar.recvFunctionalSnoop(pkt, id); }
+ Tick
+ recvAtomicSnoop(PacketPtr pkt) override
+ {
+ return xbar.recvAtomicSnoop(pkt, id);
+ }
- /** When reciving a range change from the peer port (at id),
- pass it to the crossbar. */
- virtual void recvRangeChange()
- { xbar.recvRangeChange(id); }
+ void
+ recvFunctionalSnoop(PacketPtr pkt) override
+ {
+ xbar.recvFunctionalSnoop(pkt, id);
+ }
- /** When reciving a retry from the peer port (at id),
- pass it to the crossbar. */
- virtual void recvRetry()
- { xbar.recvRetry(id); }
+ void recvRangeChange() override { xbar.recvRangeChange(id); }
+ void recvReqRetry() override { xbar.recvReqRetry(id); }
};
private:
/** The port which we mirror internally. */
- SlavePort& slavePort;
+ QueuedSlavePort& slavePort;
public:
/**
* Create a snoop response port that mirrors a given slave port.
*/
- SnoopRespPort(SlavePort& slave_port, CoherentXBar& _xbar) :
+ SnoopRespPort(QueuedSlavePort& slave_port, CoherentXBar& _xbar) :
MasterPort(slave_port.name() + ".snoopRespPort", &_xbar),
slavePort(slave_port) { }
* Override the sending of retries and pass them on through
* the mirrored slave port.
*/
- void sendRetry() {
- slavePort.sendRetry();
+ void
+ sendRetryResp() override
+ {
+ // forward it as a snoop response retry
+ slavePort.sendRetrySnoopResp();
}
- /**
- * Provided as necessary.
- */
- void recvRetry() { panic("SnoopRespPort should never see retry\n"); }
+ void
+ recvReqRetry() override
+ {
+ panic("SnoopRespPort should never see retry");
+ }
- /**
- * Provided as necessary.
- */
- bool recvTimingResp(PacketPtr pkt)
+ bool
+ recvTimingResp(PacketPtr pkt) override
{
- panic("SnoopRespPort should never see timing response\n");
- return false;
+ panic("SnoopRespPort should never see timing response");
}
};
std::vector<SnoopRespPort*> snoopRespPorts;
- std::vector<SlavePort*> snoopPorts;
+ std::vector<QueuedSlavePort*> snoopPorts;
/**
* Store the outstanding requests that we are expecting snoop
* responses from so we can determine which snoop responses we
* generated and which ones were merely forwarded.
*/
- m5::hash_set<RequestPtr> outstandingSnoop;
+ std::unordered_set<RequestPtr> outstandingSnoop;
+
+ /**
+ * Store the outstanding cache maintenance that we are expecting
+ * snoop responses from so we can determine when we received all
+ * snoop responses and if any of the agents satisfied the request.
+ */
+ std::unordered_map<PacketId, PacketPtr> outstandingCMO;
/**
* Keep a pointer to the system to be allow to querying memory system
* broadcast needed for probes. NULL denotes an absent filter. */
SnoopFilter *snoopFilter;
- /** Function called by the port when the crossbar is recieving a Timing
- request packet.*/
- bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
+ const Cycles snoopResponseLatency;
+ const bool pointOfCoherency;
+ const bool pointOfUnification;
- /** Function called by the port when the crossbar is recieving a Timing
- response packet.*/
- bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
+ /**
+ * Upstream caches need this packet until true is returned, so
+ * hold it for deletion until a subsequent call
+ */
+ std::unique_ptr<Packet> pendingDelete;
- /** Function called by the port when the crossbar is recieving a timing
- snoop request.*/
+ bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
+ bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
void recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id);
-
- /** Function called by the port when the crossbar is recieving a timing
- snoop response.*/
bool recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id);
-
- /** Timing function called by port when it is once again able to process
- * requests. */
- void recvRetry(PortID master_port_id);
+ void recvReqRetry(PortID master_port_id);
/**
* Forward a timing packet to our snoopers, potentially excluding
* @param pkt Packet to forward
* @param exclude_slave_port_id Id of slave port to exclude
*/
- void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id) {
+ void
+ forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
+ {
forwardTiming(pkt, exclude_slave_port_id, snoopPorts);
}
* @param dests Vector of destination ports for the forwarded pkt
*/
void forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id,
- const std::vector<SlavePort*>& dests);
-
- /** Function called by the port when the crossbar is recieving a Atomic
- transaction.*/
- Tick recvAtomic(PacketPtr pkt, PortID slave_port_id);
+ const std::vector<QueuedSlavePort*>& dests);
- /** Function called by the port when the crossbar is recieving an
- atomic snoop transaction.*/
+ Tick recvAtomicBackdoor(PacketPtr pkt, PortID slave_port_id,
+ MemBackdoorPtr *backdoor=nullptr);
Tick recvAtomicSnoop(PacketPtr pkt, PortID master_port_id);
/**
*
* @return a pair containing the snoop response and snoop latency
*/
- std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
- PortID exclude_slave_port_id)
+ std::pair<MemCmd, Tick>
+ forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
{
- return forwardAtomic(pkt, exclude_slave_port_id, InvalidPortID, snoopPorts);
+ return forwardAtomic(pkt, exclude_slave_port_id, InvalidPortID,
+ snoopPorts);
}
/**
std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
PortID exclude_slave_port_id,
PortID source_master_port_id,
- const std::vector<SlavePort*>& dests);
+ const std::vector<QueuedSlavePort*>&
+ dests);
/** Function called by the port when the crossbar is recieving a Functional
transaction.*/
*/
void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id);
+ /**
+ * Determine if the crossbar should sink the packet, as opposed to
+ * forwarding it, or responding.
+ */
+ bool sinkPacket(const PacketPtr pkt) const;
+
+ /**
+ * Determine if the crossbar should forward the packet, as opposed to
+ * responding to it.
+ */
+ bool forwardPacket(const PacketPtr pkt);
+
+ /**
+ * Determine if the packet's destination is the memory below
+ *
+ * The memory below is the destination for a cache mainteance
+ * operation to the Point of Coherence/Unification if this is the
+ * Point of Coherence/Unification.
+ *
+ * @param pkt The processed packet
+ *
+ * @return Whether the memory below is the destination for the packet
+ */
+ bool
+ isDestination(const PacketPtr pkt) const
+ {
+ return (pkt->req->isToPOC() && pointOfCoherency) ||
+ (pkt->req->isToPOU() && pointOfUnification);
+ }
+
Stats::Scalar snoops;
+ Stats::Scalar snoopTraffic;
Stats::Distribution snoopFanout;
public:
virtual ~CoherentXBar();
- unsigned int drain(DrainManager *dm);
-
virtual void regStats();
};