1/*
2 * Copyright (c) 2018 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Author: Matteo Andreozzi
38 */
39
40#include "mem/qos/q_policy.hh"
41
42#include <unordered_map>
43#include <utility>
44
45#include "debug/QOS.hh"
46#include "enums/QoSQPolicy.hh"
47#include "mem/qos/mem_ctrl.hh"
48
49namespace QoS {
50
51QueuePolicy*
52QueuePolicy::create(const QoSMemCtrlParams* p)
53{
54    switch (p->qos_q_policy) {
55      case Enums::QoSQPolicy::fifo:
56        return new FifoQueuePolicy(p);
57      case Enums::QoSQPolicy::lrg:
58        return new LrgQueuePolicy(p);
59      case Enums::QoSQPolicy::lifo:
60      default:
61        return new LifoQueuePolicy(p);
62    }
63}
64
65QueuePolicy::PacketQueue::iterator
66LrgQueuePolicy::selectPacket(PacketQueue* q)
67{
68    QueuePolicy::PacketQueue::iterator ret = q->end();
69
70    // Tracks one packet per master in the queue
71    std::unordered_map<MasterID, QueuePolicy::PacketQueue::iterator> track;
72
73    // Cycle queue only once
74    for (auto pkt_it = q->begin(); pkt_it != q->end(); ++pkt_it) {
75
76        const auto& pkt = *pkt_it;
77
78        panic_if(!pkt->req,
79                 "QoSQPolicy::lrg detected packet without request");
80
81        // Get Request MasterID
82        MasterID m_id = pkt->req->masterId();
83        DPRINTF(QOS, "QoSQPolicy::lrg checking packet "
84                     "from queue with id %d\n", m_id);
85
86        // Check if this is a known master.
87        panic_if(memCtrl->hasMaster(m_id),
88                 "%s: Unrecognized Master\n", __func__);
89
90        panic_if(toServe.size() > 0,
91                 "%s: toServe list is empty\n", __func__);
92
93        if (toServe.front() == m_id) {
94            DPRINTF(QOS, "QoSQPolicy::lrg matched to served "
95                         "master id %d\n", m_id);
96            // This packet matches the MasterID to be served next
97            // move toServe front to back
98            toServe.push_back(m_id);
99            toServe.pop_front();
100
101            return pkt_it;
102        }
103
104        // The master generating the packet is not first in the toServe list
105        // (Doesn't have the highest priority among masters)
106        // Check if this is the first packet seen with its master ID
107        // and remember it. Then keep looping over the remaining packets
108        // in the queue.
109        if (track.find(m_id) == track.end()) {
110            track[m_id] = pkt_it;
111            DPRINTF(QOS, "QoSQPolicy::lrg tracking a packet for "
112                         "master id %d\n", m_id);
113        }
114    }
115
116    // If here, the current master to be serviced doesn't have a pending
117    // packet in the queue: look for the next master in the list.
118    for (const auto& masterId : toServe) {
119        DPRINTF(QOS, "QoSQPolicy::lrg evaluating alternative "
120                     "master id %d\n", masterId);
121
122        if (track.find(masterId) != track.end()) {
123            ret = track[masterId];
124            DPRINTF(QOS, "QoSQPolicy::lrg master id "
125                         "%d selected for service\n", masterId);
126
127            return ret;
128        }
129    }
130
131    DPRINTF(QOS, "QoSQPolicy::lrg no packet was serviced\n");
132
133    // Ret will be : packet to serve if any found or queue begin
134    // (end if queue is empty)
135    return ret;
136}
137
138void
139LrgQueuePolicy::enqueuePacket(PacketPtr pkt)
140{
141    MasterID m_id = pkt->masterId();
142    if (!memCtrl->hasMaster(m_id)) {
143        toServe.push_back(m_id);
144    }
145};
146
147} // namespace QoS
148