hmc_controller.cc revision 11184:07b0dacf27d6
1#include "base/random.hh"
2#include "debug/HMCController.hh"
3#include "mem/hmc_controller.hh"
4
5HMCController::HMCController(const HMCControllerParams* p) :
6    NoncoherentXBar(p),
7    n_master_ports(p->port_master_connection_count),
8    rr_counter(0)
9{
10    assert(p->port_slave_connection_count == 1);
11}
12
13HMCController*
14HMCControllerParams::create()
15{
16    return new HMCController(this);
17}
18
19// Since this module is a load distributor, all its master ports have the same
20//  range so we should keep only one of the ranges and ignore the others
21void HMCController::recvRangeChange(PortID master_port_id)
22{
23    if (master_port_id == 0)
24    {
25       gotAllAddrRanges = true;
26       BaseXBar::recvRangeChange(master_port_id);
27    }
28    else
29        gotAddrRanges[master_port_id] = true;
30}
31
32int HMCController::rotate_counter()
33{
34    int current_value = rr_counter;
35    rr_counter++;
36    if (rr_counter == n_master_ports)
37        rr_counter = 0;
38    return current_value;
39}
40
41bool HMCController::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
42{
43    // determine the source port based on the id
44    SlavePort *src_port = slavePorts[slave_port_id];
45
46    // we should never see express snoops on a non-coherent component
47    assert(!pkt->isExpressSnoop());
48
49    // For now, this is a simple round robin counter, for distribution the
50    //  load among the serial links
51    PortID master_port_id = rotate_counter();
52
53    // test if the layer should be considered occupied for the current
54    // port
55    if (!reqLayers[master_port_id]->tryTiming(src_port)) {
56        DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x BUSY\n",
57                src_port->name(), pkt->cmdString(), pkt->getAddr());
58        return false;
59    }
60
61    DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x\n",
62            src_port->name(), pkt->cmdString(), pkt->getAddr());
63
64    // store size and command as they might be modified when
65    // forwarding the packet
66    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
67    unsigned int pkt_cmd = pkt->cmdToIndex();
68
69    // store the old header delay so we can restore it if needed
70    Tick old_header_delay = pkt->headerDelay;
71
72    // a request sees the frontend and forward latency
73    Tick xbar_delay = (frontendLatency + forwardLatency) * clockPeriod();
74
75    // set the packet header and payload delay
76    calcPacketTiming(pkt, xbar_delay);
77
78    // determine how long to be layer is busy
79    Tick packetFinishTime = clockEdge(Cycles(1)) + pkt->payloadDelay;
80
81    // before forwarding the packet (and possibly altering it),
82    // remember if we are expecting a response
83    const bool expect_response = pkt->needsResponse() &&
84        !pkt->memInhibitAsserted();
85
86    // since it is a normal request, attempt to send the packet
87    bool success = masterPorts[master_port_id]->sendTimingReq(pkt);
88
89    if (!success)  {
90        // inhibited packets should never be forced to retry
91        assert(!pkt->memInhibitAsserted());
92
93        DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x RETRY\n",
94                src_port->name(), pkt->cmdString(), pkt->getAddr());
95
96        // restore the header delay as it is additive
97        pkt->headerDelay = old_header_delay;
98
99        // occupy until the header is sent
100        reqLayers[master_port_id]->failedTiming(src_port,
101                                                clockEdge(Cycles(1)));
102
103        return false;
104    }
105
106    // remember where to route the response to
107    if (expect_response) {
108        assert(routeTo.find(pkt->req) == routeTo.end());
109        routeTo[pkt->req] = slave_port_id;
110    }
111
112    reqLayers[master_port_id]->succeededTiming(packetFinishTime);
113
114    // stats updates
115    pktCount[slave_port_id][master_port_id]++;
116    pktSize[slave_port_id][master_port_id] += pkt_size;
117    transDist[pkt_cmd]++;
118
119    return true;
120}
121