mem: Tie in the snoop filter in the coherent bus
This commit is contained in:
parent
7d488cc66f
commit
afa2428eca
|
@ -75,6 +75,7 @@ class CoherentBus(BaseBus):
|
|||
cxx_header = "mem/coherent_bus.hh"
|
||||
|
||||
system = Param.System(Parent.any, "System that the bus belongs to.")
|
||||
snoop_filter = Param.SnoopFilter(NULL, "Selected snoop filter for the bus.")
|
||||
|
||||
class SnoopFilter(SimObject):
|
||||
type = 'SnoopFilter'
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
#include "sim/system.hh"
|
||||
|
||||
CoherentBus::CoherentBus(const CoherentBusParams *p)
|
||||
: BaseBus(p), system(p->system)
|
||||
: BaseBus(p), system(p->system), snoopFilter(p->snoop_filter)
|
||||
{
|
||||
// create the ports based on the size of the master and slave
|
||||
// vector ports, and the presence of the default port, the ports
|
||||
|
@ -95,6 +95,9 @@ CoherentBus::CoherentBus(const CoherentBusParams *p)
|
|||
snoopRespPorts.push_back(new SnoopRespPort(*bp, *this));
|
||||
}
|
||||
|
||||
if (snoopFilter)
|
||||
snoopFilter->setSlavePorts(slavePorts);
|
||||
|
||||
clearPortCache();
|
||||
}
|
||||
|
||||
|
@ -171,7 +174,18 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
|
|||
if (!pkt->req->isUncacheable() && !system->bypassCaches()) {
|
||||
// the packet is a memory-mapped request and should be
|
||||
// broadcasted to our snoopers but the source
|
||||
forwardTiming(pkt, slave_port_id);
|
||||
if (snoopFilter) {
|
||||
// check with the snoop filter where to forward this packet
|
||||
auto sf_res = snoopFilter->lookupRequest(pkt, *src_port);
|
||||
packetFinishTime += sf_res.second * clockPeriod();
|
||||
DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x"\
|
||||
" SF size: %i lat: %i\n", src_port->name(),
|
||||
pkt->cmdString(), pkt->getAddr(), sf_res.first.size(),
|
||||
sf_res.second);
|
||||
forwardTiming(pkt, slave_port_id, sf_res.first);
|
||||
} else {
|
||||
forwardTiming(pkt, slave_port_id);
|
||||
}
|
||||
}
|
||||
|
||||
// remember if we add an outstanding req so we can undo it if
|
||||
|
@ -190,9 +204,27 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
|
|||
outstandingReq.insert(pkt->req);
|
||||
}
|
||||
|
||||
// Note: Cannot create a copy of the full packet, here.
|
||||
MemCmd orig_cmd(pkt->cmd);
|
||||
|
||||
// since it is a normal request, attempt to send the packet
|
||||
bool success = masterPorts[master_port_id]->sendTimingReq(pkt);
|
||||
|
||||
if (snoopFilter && !pkt->req->isUncacheable()
|
||||
&& !system->bypassCaches()) {
|
||||
// The packet may already be overwritten by the sendTimingReq function.
|
||||
// The snoop filter needs to see the original request *and* the return
|
||||
// status of the send operation, so we need to recreate the original
|
||||
// request. Atomic mode does not have the issue, as there the send
|
||||
// operation and the response happen instantaneously and don't need two
|
||||
// phase tracking.
|
||||
MemCmd tmp_cmd(pkt->cmd);
|
||||
pkt->cmd = orig_cmd;
|
||||
// Let the snoop filter know about the success of the send operation
|
||||
snoopFilter->updateRequest(pkt, *src_port, !success);
|
||||
pkt->cmd = tmp_cmd;
|
||||
}
|
||||
|
||||
// if this is an express snoop, we are done at this point
|
||||
if (is_express_snoop) {
|
||||
assert(success);
|
||||
|
@ -267,6 +299,11 @@ CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
|
|||
// have seen passing through the bus
|
||||
assert(outstandingReq.find(pkt->req) != outstandingReq.end());
|
||||
|
||||
if (snoopFilter && !pkt->req->isUncacheable() && !system->bypassCaches()) {
|
||||
// let the snoop filter inspect the response and update its state
|
||||
snoopFilter->updateResponse(pkt, *slavePorts[slave_port_id]);
|
||||
}
|
||||
|
||||
// remove it as outstanding
|
||||
outstandingReq.erase(pkt->req);
|
||||
|
||||
|
@ -306,8 +343,20 @@ CoherentBus::recvTimingSnoopReq(PacketPtr pkt, PortID master_port_id)
|
|||
// set the source port for routing of the response
|
||||
pkt->setSrc(master_port_id);
|
||||
|
||||
// forward to all snoopers
|
||||
forwardTiming(pkt, InvalidPortID);
|
||||
if (snoopFilter) {
|
||||
// let the Snoop Filter work its magic and guide probing
|
||||
auto sf_res = snoopFilter->lookupSnoop(pkt);
|
||||
// No timing here: packetFinishTime += sf_res.second * clockPeriod();
|
||||
DPRINTF(CoherentBus, "recvTimingSnoopReq: src %s %s 0x%x"\
|
||||
" SF size: %i lat: %i\n", masterPorts[master_port_id]->name(),
|
||||
pkt->cmdString(), pkt->getAddr(), sf_res.first.size(),
|
||||
sf_res.second);
|
||||
|
||||
// forward to all snoopers
|
||||
forwardTiming(pkt, InvalidPortID, sf_res.first);
|
||||
} else {
|
||||
forwardTiming(pkt, InvalidPortID);
|
||||
}
|
||||
|
||||
// a snoop request came from a connected slave device (one of
|
||||
// our master ports), and if it is not coming from the slave
|
||||
|
@ -372,6 +421,13 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
|
|||
// this is a snoop response to a snoop request we forwarded,
|
||||
// e.g. coming from the L1 and going to the L2, and it should
|
||||
// be forwarded as a snoop response
|
||||
|
||||
if (snoopFilter) {
|
||||
// update the probe filter so that it can properly track the line
|
||||
snoopFilter->updateSnoopForward(pkt, *slavePorts[slave_port_id],
|
||||
*masterPorts[dest_port_id]);
|
||||
}
|
||||
|
||||
bool success M5_VAR_USED =
|
||||
masterPorts[dest_port_id]->sendTimingSnoopResp(pkt);
|
||||
pktCount[slave_port_id][dest_port_id]++;
|
||||
|
@ -393,6 +449,16 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
|
|||
// original request came from
|
||||
assert(slave_port_id != dest_port_id);
|
||||
|
||||
if (snoopFilter) {
|
||||
// update the probe filter so that it can properly track the line
|
||||
snoopFilter->updateSnoopResponse(pkt, *slavePorts[slave_port_id],
|
||||
*slavePorts[dest_port_id]);
|
||||
}
|
||||
|
||||
DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x"\
|
||||
" FWD RESP\n", src_port->name(), pkt->cmdString(),
|
||||
pkt->getAddr());
|
||||
|
||||
// as a normal response, it should go back to a master through
|
||||
// one of our slave ports, at this point we are ignoring the
|
||||
// fact that the response layer could be busy and do not touch
|
||||
|
@ -420,7 +486,8 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
|
|||
|
||||
|
||||
void
|
||||
CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
|
||||
CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id,
|
||||
const std::vector<SlavePort*>& dests)
|
||||
{
|
||||
DPRINTF(CoherentBus, "%s for %s address %x size %d\n", __func__,
|
||||
pkt->cmdString(), pkt->getAddr(), pkt->getSize());
|
||||
|
@ -430,7 +497,7 @@ CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
|
|||
|
||||
unsigned fanout = 0;
|
||||
|
||||
for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
|
||||
for (SlavePortConstIter s = dests.begin(); s != dests.end(); ++s) {
|
||||
SlavePort *p = *s;
|
||||
// we could have gotten this request from a snooping master
|
||||
// (corresponding to our own slave port that is also in
|
||||
|
@ -473,10 +540,23 @@ CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id)
|
|||
// uncacheable requests need never be snooped
|
||||
if (!pkt->req->isUncacheable() && !system->bypassCaches()) {
|
||||
// forward to all snoopers but the source
|
||||
std::pair<MemCmd, Tick> snoop_result =
|
||||
forwardAtomic(pkt, slave_port_id);
|
||||
std::pair<MemCmd, Tick> snoop_result;
|
||||
if (snoopFilter) {
|
||||
// check with the snoop filter where to forward this packet
|
||||
auto sf_res =
|
||||
snoopFilter->lookupRequest(pkt, *slavePorts[slave_port_id]);
|
||||
snoop_response_latency += sf_res.second * clockPeriod();
|
||||
DPRINTF(CoherentBus, "%s: src %s %s 0x%x"\
|
||||
" SF size: %i lat: %i\n", __func__,
|
||||
slavePorts[slave_port_id]->name(), pkt->cmdString(),
|
||||
pkt->getAddr(), sf_res.first.size(), sf_res.second);
|
||||
snoop_result = forwardAtomic(pkt, slave_port_id, InvalidPortID,
|
||||
sf_res.first);
|
||||
} else {
|
||||
snoop_result = forwardAtomic(pkt, slave_port_id);
|
||||
}
|
||||
snoop_response_cmd = snoop_result.first;
|
||||
snoop_response_latency = snoop_result.second;
|
||||
snoop_response_latency += snoop_result.second;
|
||||
}
|
||||
|
||||
// even if we had a snoop response, we must continue and also
|
||||
|
@ -486,6 +566,12 @@ CoherentBus::recvAtomic(PacketPtr pkt, PortID slave_port_id)
|
|||
// forward the request to the appropriate destination
|
||||
Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
|
||||
|
||||
// Lower levels have replied, tell the snoop filter
|
||||
if (snoopFilter && !pkt->req->isUncacheable() && !system->bypassCaches() &&
|
||||
pkt->isResponse()) {
|
||||
snoopFilter->updateResponse(pkt, *slavePorts[slave_port_id]);
|
||||
}
|
||||
|
||||
// if we got a response from a snooper, restore it here
|
||||
if (snoop_response_cmd != MemCmd::InvalidCmd) {
|
||||
// no one else should have responded
|
||||
|
@ -515,10 +601,21 @@ CoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id)
|
|||
snoopsThroughBus++;
|
||||
|
||||
// forward to all snoopers
|
||||
std::pair<MemCmd, Tick> snoop_result =
|
||||
forwardAtomic(pkt, InvalidPortID);
|
||||
std::pair<MemCmd, Tick> snoop_result;
|
||||
Tick snoop_response_latency = 0;
|
||||
if (snoopFilter) {
|
||||
auto sf_res = snoopFilter->lookupSnoop(pkt);
|
||||
snoop_response_latency += sf_res.second * clockPeriod();
|
||||
DPRINTF(CoherentBus, "%s: src %s %s 0x%x SF size: %i lat: %i\n",
|
||||
__func__, masterPorts[master_port_id]->name(), pkt->cmdString(),
|
||||
pkt->getAddr(), sf_res.first.size(), sf_res.second);
|
||||
snoop_result = forwardAtomic(pkt, InvalidPortID, master_port_id,
|
||||
sf_res.first);
|
||||
} else {
|
||||
snoop_result = forwardAtomic(pkt, InvalidPortID);
|
||||
}
|
||||
MemCmd snoop_response_cmd = snoop_result.first;
|
||||
Tick snoop_response_latency = snoop_result.second;
|
||||
snoop_response_latency += snoop_result.second;
|
||||
|
||||
if (snoop_response_cmd != MemCmd::InvalidCmd)
|
||||
pkt->cmd = snoop_response_cmd;
|
||||
|
@ -535,7 +632,9 @@ CoherentBus::recvAtomicSnoop(PacketPtr pkt, PortID master_port_id)
|
|||
}
|
||||
|
||||
std::pair<MemCmd, Tick>
|
||||
CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
|
||||
CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id,
|
||||
PortID source_master_port_id,
|
||||
const std::vector<SlavePort*>& dests)
|
||||
{
|
||||
// the packet may be changed on snoops, record the original
|
||||
// command to enable us to restore it between snoops so that
|
||||
|
@ -549,33 +648,51 @@ CoherentBus::forwardAtomic(PacketPtr pkt, PortID exclude_slave_port_id)
|
|||
|
||||
unsigned fanout = 0;
|
||||
|
||||
for (SlavePortIter s = snoopPorts.begin(); s != snoopPorts.end(); ++s) {
|
||||
for (SlavePortConstIter s = dests.begin(); s != dests.end(); ++s) {
|
||||
SlavePort *p = *s;
|
||||
// we could have gotten this request from a snooping master
|
||||
// (corresponding to our own slave port that is also in
|
||||
// snoopPorts) and should not send it back to where it came
|
||||
// from
|
||||
if (exclude_slave_port_id == InvalidPortID ||
|
||||
p->getId() != exclude_slave_port_id) {
|
||||
Tick latency = p->sendAtomicSnoop(pkt);
|
||||
fanout++;
|
||||
if (exclude_slave_port_id != InvalidPortID &&
|
||||
p->getId() == exclude_slave_port_id)
|
||||
continue;
|
||||
|
||||
// in contrast to a functional access, we have to keep on
|
||||
// going as all snoopers must be updated even if we get a
|
||||
// response
|
||||
if (pkt->isResponse()) {
|
||||
// response from snoop agent
|
||||
assert(pkt->cmd != orig_cmd);
|
||||
assert(pkt->memInhibitAsserted());
|
||||
// should only happen once
|
||||
assert(snoop_response_cmd == MemCmd::InvalidCmd);
|
||||
// save response state
|
||||
snoop_response_cmd = pkt->cmd;
|
||||
snoop_response_latency = latency;
|
||||
// restore original packet state for remaining snoopers
|
||||
pkt->cmd = orig_cmd;
|
||||
Tick latency = p->sendAtomicSnoop(pkt);
|
||||
fanout++;
|
||||
|
||||
// in contrast to a functional access, we have to keep on
|
||||
// going as all snoopers must be updated even if we get a
|
||||
// response
|
||||
if (!pkt->isResponse())
|
||||
continue;
|
||||
|
||||
// response from snoop agent
|
||||
assert(pkt->cmd != orig_cmd);
|
||||
assert(pkt->memInhibitAsserted());
|
||||
// should only happen once
|
||||
assert(snoop_response_cmd == MemCmd::InvalidCmd);
|
||||
// save response state
|
||||
snoop_response_cmd = pkt->cmd;
|
||||
snoop_response_latency = latency;
|
||||
|
||||
if (snoopFilter) {
|
||||
// Handle responses by the snoopers and differentiate between
|
||||
// responses to requests from above and snoops from below
|
||||
if (source_master_port_id != InvalidPortID) {
|
||||
// Getting a response for a snoop from below
|
||||
assert(exclude_slave_port_id == InvalidPortID);
|
||||
snoopFilter->updateSnoopForward(pkt, *p,
|
||||
*masterPorts[source_master_port_id]);
|
||||
} else {
|
||||
// Getting a response for a request from above
|
||||
assert(source_master_port_id == InvalidPortID);
|
||||
snoopFilter->updateSnoopResponse(pkt, *p,
|
||||
*slavePorts[exclude_slave_port_id]);
|
||||
}
|
||||
}
|
||||
// restore original packet state for remaining snoopers
|
||||
pkt->cmd = orig_cmd;
|
||||
}
|
||||
|
||||
// Stats for fanout
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
|
||||
#include "base/hashmap.hh"
|
||||
#include "mem/bus.hh"
|
||||
#include "mem/snoop_filter.hh"
|
||||
#include "params/CoherentBus.hh"
|
||||
|
||||
/**
|
||||
|
@ -270,6 +271,10 @@ class CoherentBus : public BaseBus
|
|||
*/
|
||||
System *system;
|
||||
|
||||
/** A snoop filter that tracks cache line residency and can restrict the
|
||||
* broadcast needed for probes. NULL denotes an absent filter. */
|
||||
SnoopFilter *snoopFilter;
|
||||
|
||||
/** Function called by the port when the bus is recieving a Timing
|
||||
request packet.*/
|
||||
bool recvTimingReq(PacketPtr pkt, PortID slave_port_id);
|
||||
|
@ -298,7 +303,21 @@ class CoherentBus : public BaseBus
|
|||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward a timing packet to a selected list of snoopers, potentially
|
||||
* excluding one of the connected coherent masters to avoid sending a packet
|
||||
* back to where it came from.
|
||||
*
|
||||
* @param pkt Packet to forward
|
||||
* @param exclude_slave_port_id Id of slave port to exclude
|
||||
* @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 bus is recieving a Atomic
|
||||
transaction.*/
|
||||
|
@ -319,7 +338,27 @@ class CoherentBus : public BaseBus
|
|||
* @return a pair containing the snoop response and snoop latency
|
||||
*/
|
||||
std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
|
||||
PortID exclude_slave_port_id);
|
||||
PortID exclude_slave_port_id)
|
||||
{
|
||||
return forwardAtomic(pkt, exclude_slave_port_id, InvalidPortID, snoopPorts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward an atomic packet to a selected list of snoopers, potentially
|
||||
* excluding one of the connected coherent masters to avoid sending a packet
|
||||
* back to where it came from.
|
||||
*
|
||||
* @param pkt Packet to forward
|
||||
* @param exclude_slave_port_id Id of slave port to exclude
|
||||
* @param source_master_port_id Id of the master port for snoops from below
|
||||
* @param dests Vector of destination ports for the forwarded pkt
|
||||
*
|
||||
* @return a pair containing the snoop response and snoop latency
|
||||
*/
|
||||
std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
|
||||
PortID exclude_slave_port_id,
|
||||
PortID source_master_port_id,
|
||||
const std::vector<SlavePort*>& dests);
|
||||
|
||||
/** Function called by the port when the bus is recieving a Functional
|
||||
transaction.*/
|
||||
|
|
Loading…
Reference in a new issue