add a backoff algorithm when nacks are received by devices

add seperate response buffers and request queue sizes in bus bridge
add delay to respond to a nack in the bus bridge

src/dev/i8254xGBe.cc:
src/dev/ide_ctrl.cc:
src/dev/ns_gige.cc:
src/dev/pcidev.hh:
src/dev/sinic.cc:
    add backoff delay parameters
src/dev/io_device.cc:
src/dev/io_device.hh:
    add a backoff algorithm when nacks are received.
src/mem/bridge.cc:
src/mem/bridge.hh:
    add seperate response buffers and request queue sizes
    add a new parameters to specify how long before a nack in ready to go after a packet that needs to be nacked is received
src/mem/cache/cache_impl.hh:
    assert on the
src/mem/tport.cc:
    add a friendly assert to make sure the packet was inserted into the list

--HG--
extra : convert_revision : 3595ad932015a4ce2bb72772da7850ad91bd09b1
This commit is contained in:
Ali Saidi
2007-05-09 18:20:24 -04:00
parent 37b45e3c8c
commit 3c608bf765
11 changed files with 250 additions and 61 deletions

View File

@@ -43,22 +43,22 @@
Bridge::BridgePort::BridgePort(const std::string &_name,
Bridge *_bridge, BridgePort *_otherPort,
int _delay, int _queueLimit,
bool fix_partial_write)
int _delay, int _nack_delay, int _req_limit,
int _resp_limit, bool fix_partial_write)
: Port(_name), bridge(_bridge), otherPort(_otherPort),
delay(_delay), fixPartialWrite(fix_partial_write),
outstandingResponses(0), queuedRequests(0),
queueLimit(_queueLimit), sendEvent(this)
delay(_delay), nackDelay(_nack_delay), fixPartialWrite(fix_partial_write),
outstandingResponses(0), queuedRequests(0), inRetry(false),
reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this)
{
}
Bridge::Bridge(const std::string &n, int qsa, int qsb,
Tick _delay, int write_ack, bool fix_partial_write_a,
bool fix_partial_write_b)
: MemObject(n),
portA(n + "-portA", this, &portB, _delay, qsa, fix_partial_write_a),
portB(n + "-portB", this, &portA, _delay, qsa, fix_partial_write_b),
ackWrites(write_ack)
Bridge::Bridge(Params *p)
: MemObject(p->name),
portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay,
p->req_size_a, p->resp_size_a, p->fix_partial_write_a),
portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay,
p->req_size_b, p->resp_size_b, p->fix_partial_write_b),
ackWrites(p->write_ack), _params(p)
{
if (ackWrites)
panic("No support for acknowledging writes\n");
@@ -94,11 +94,17 @@ Bridge::init()
}
bool
Bridge::BridgePort::queueFull()
Bridge::BridgePort::respQueueFull()
{
// use >= here because sendQueue could get larger because of
// nacks getting inserted
return queuedRequests + outstandingResponses >= queueLimit;
assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit);
return outstandingResponses >= respQueueLimit;
}
bool
Bridge::BridgePort::reqQueueFull()
{
assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit);
return queuedRequests >= reqQueueLimit;
}
/** Function called by the port when the bus is receiving a Timing
@@ -113,14 +119,14 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt)
DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
pkt->getSrc(), pkt->getDest(), pkt->getAddr());
if (pkt->isRequest() && otherPort->queueFull()) {
if (pkt->isRequest() && otherPort->reqQueueFull()) {
DPRINTF(BusBridge, "Remote queue full, nacking\n");
nackRequest(pkt);
return true;
}
if (pkt->needsResponse() && pkt->result != Packet::Nacked)
if (queueFull()) {
if (respQueueFull()) {
DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
sendQueue.size(), queuedRequests, outstandingResponses);
@@ -144,12 +150,41 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt)
pkt->setDest(pkt->getSrc());
//put it on the list to send
Tick readyTime = curTick + delay;
Tick readyTime = curTick + nackDelay;
PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true);
// nothing on the list, add it and we're done
if (sendQueue.empty()) {
assert(!sendEvent.scheduled());
sendEvent.schedule(readyTime);
sendQueue.push_back(buf);
return;
}
sendQueue.push_back(buf);
assert(sendEvent.scheduled() || inRetry);
// does it go at the end?
if (readyTime >= sendQueue.back()->ready) {
sendQueue.push_back(buf);
return;
}
// ok, somewhere in the middle, fun
std::list<PacketBuffer*>::iterator i = sendQueue.begin();
std::list<PacketBuffer*>::iterator end = sendQueue.end();
std::list<PacketBuffer*>::iterator begin = sendQueue.begin();
bool done = false;
while (i != end && !done) {
if (readyTime < (*i)->ready) {
if (i == begin)
sendEvent.reschedule(readyTime);
sendQueue.insert(i,buf);
done = true;
}
i++;
}
assert(done);
}
@@ -199,7 +234,6 @@ Bridge::BridgePort::trySend()
{
assert(!sendQueue.empty());
bool was_full = queueFull();
int pbs = peerBlockSize();
PacketBuffer *buf = sendQueue.front();
@@ -245,15 +279,10 @@ Bridge::BridgePort::trySend()
DPRINTF(BusBridge, "Scheduling next send\n");
sendEvent.schedule(std::max(buf->ready, curTick + 1));
}
// Let things start sending again
if (was_full && !queueFull()) {
DPRINTF(BusBridge, "Queue was full, sending retry\n");
otherPort->sendRetry();
}
} else {
DPRINTF(BusBridge, " unsuccessful\n");
buf->undoPartialWriteFix();
inRetry = true;
}
DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
sendQueue.size(), queuedRequests, outstandingResponses);
@@ -263,7 +292,12 @@ Bridge::BridgePort::trySend()
void
Bridge::BridgePort::recvRetry()
{
trySend();
inRetry = false;
Tick nextReady = sendQueue.front()->ready;
if (nextReady <= curTick)
trySend();
else
sendEvent.schedule(nextReady);
}
/** Function called by the port when the bus is receiving a Atomic
@@ -309,9 +343,12 @@ Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp,
BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge)
Param<int> queue_size_a;
Param<int> queue_size_b;
Param<int> req_size_a;
Param<int> req_size_b;
Param<int> resp_size_a;
Param<int> resp_size_b;
Param<Tick> delay;
Param<Tick> nack_delay;
Param<bool> write_ack;
Param<bool> fix_partial_write_a;
Param<bool> fix_partial_write_b;
@@ -320,9 +357,12 @@ END_DECLARE_SIM_OBJECT_PARAMS(Bridge)
BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge)
INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"),
INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"),
INIT_PARAM(req_size_a, "The size of the queue for requests coming into side a"),
INIT_PARAM(req_size_b, "The size of the queue for requests coming into side b"),
INIT_PARAM(resp_size_a, "The size of the queue for responses coming into side a"),
INIT_PARAM(resp_size_b, "The size of the queue for responses coming into side b"),
INIT_PARAM(delay, "The miminum delay to cross this bridge"),
INIT_PARAM(nack_delay, "The minimum delay to nack a packet"),
INIT_PARAM(write_ack, "Acknowledge any writes that are received."),
INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"),
INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received")
@@ -331,8 +371,18 @@ END_INIT_SIM_OBJECT_PARAMS(Bridge)
CREATE_SIM_OBJECT(Bridge)
{
return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay,
write_ack, fix_partial_write_a, fix_partial_write_b);
Bridge::Params *p = new Bridge::Params;
p->name = getInstanceName();
p->req_size_a = req_size_a;
p->req_size_b = req_size_b;
p->resp_size_a = resp_size_a;
p->resp_size_b = resp_size_b;
p->delay = delay;
p->nack_delay = nack_delay;
p->write_ack = write_ack;
p->fix_partial_write_a = fix_partial_write_a;
p->fix_partial_write_b = fix_partial_write_b;
return new Bridge(p);
}
REGISTER_SIM_OBJECT("Bridge", Bridge)

View File

@@ -66,6 +66,9 @@ class Bridge : public MemObject
/** Minimum delay though this bridge. */
Tick delay;
/** Min delay to respond to a nack. */
Tick nackDelay;
bool fixPartialWrite;
class PacketBuffer : public Packet::SenderState {
@@ -149,13 +152,20 @@ class Bridge : public MemObject
int outstandingResponses;
int queuedRequests;
/** If we're waiting for a retry to happen.*/
bool inRetry;
/** Max queue size for outbound packets */
int queueLimit;
int reqQueueLimit;
/** Max queue size for reserved responses. */
int respQueueLimit;
/**
* Is this side blocked from accepting outbound packets?
*/
bool queueFull();
bool respQueueFull();
bool reqQueueFull();
void queueForSendTiming(PacketPtr pkt);
@@ -186,11 +196,10 @@ class Bridge : public MemObject
SendEvent sendEvent;
public:
/** Constructor for the BusPort.*/
BridgePort(const std::string &_name,
Bridge *_bridge, BridgePort *_otherPort,
int _delay, int _queueLimit, bool fix_partial_write);
BridgePort(const std::string &_name, Bridge *_bridge,
BridgePort *_otherPort, int _delay, int _nack_delay,
int _req_limit, int _resp_limit, bool fix_partial_write);
protected:
@@ -226,14 +235,32 @@ class Bridge : public MemObject
bool ackWrites;
public:
struct Params
{
std::string name;
int req_size_a;
int req_size_b;
int resp_size_a;
int resp_size_b;
Tick delay;
Tick nack_delay;
bool write_ack;
bool fix_partial_write_a;
bool fix_partial_write_b;
};
protected:
Params *_params;
public:
const Params *params() const { return _params; }
/** A function used to return the port associated with this bus object. */
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual void init();
Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack,
bool fix_partial_write_a, bool fix_partial_write_b);
Bridge(Params *p);
};
#endif //__MEM_BUS_HH__

View File

@@ -1192,6 +1192,8 @@ template<class TagStore, class Coherence>
bool
Cache<TagStore,Coherence>::CpuSidePort::recvTiming(PacketPtr pkt)
{
assert(pkt->result != Packet::Nacked);
if (!pkt->req->isUncacheable()
&& pkt->isInvalidate()
&& !pkt->isRead() && !pkt->isWrite()) {
@@ -1249,6 +1251,12 @@ template<class TagStore, class Coherence>
bool
Cache<TagStore,Coherence>::MemSidePort::recvTiming(PacketPtr pkt)
{
// this needs to be fixed so that the cache updates the mshr and sends the
// packet back out on the link, but it probably won't happen so until this
// gets fixed, just panic when it does
if (pkt->result == Packet::Nacked)
panic("Need to implement cache resending nacked packets!\n");
if (pkt->isRequest() && blocked)
{
DPRINTF(Cache,"Scheduling a retry while blocked\n");

View File

@@ -128,6 +128,7 @@ SimpleTimingPort::sendTiming(PacketPtr pkt, Tick time)
}
i++;
}
assert(done);
}
void