dma_device.cc (9165:f9e3dac185ba) dma_device.cc (9166:1d983855df2c)
1/*
2 * Copyright (c) 2012 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

--- 25 unchanged lines hidden (view full) ---

34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ali Saidi
41 * Nathan Binkert
1/*
2 * Copyright (c) 2012 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

--- 25 unchanged lines hidden (view full) ---

34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ali Saidi
41 * Nathan Binkert
42 * Andreas Hansson
42 */
43
44#include "base/chunk_generator.hh"
45#include "debug/DMA.hh"
46#include "debug/Drain.hh"
47#include "dev/dma_device.hh"
48#include "sim/system.hh"
49
50DmaPort::DmaPort(MemObject *dev, System *s)
51 : MasterPort(dev->name() + ".dma", dev), device(dev), sys(s),
52 masterId(s->getMasterId(dev->name())),
53 pendingCount(0), drainEvent(NULL),
54 inRetry(false)
55{ }
56
43 */
44
45#include "base/chunk_generator.hh"
46#include "debug/DMA.hh"
47#include "debug/Drain.hh"
48#include "dev/dma_device.hh"
49#include "sim/system.hh"
50
51DmaPort::DmaPort(MemObject *dev, System *s)
52 : MasterPort(dev->name() + ".dma", dev), device(dev), sys(s),
53 masterId(s->getMasterId(dev->name())),
54 pendingCount(0), drainEvent(NULL),
55 inRetry(false)
56{ }
57
57bool
58DmaPort::recvTimingResp(PacketPtr pkt)
58void
59DmaPort::handleResp(PacketPtr pkt, Tick delay)
59{
60{
60 if (pkt->senderState) {
61 DmaReqState *state;
61 // should always see a response with a sender state
62 assert(pkt->isResponse());
62
63
63 DPRINTF(DMA, "Received response %s addr %#x size %#x\n",
64 pkt->cmdString(), pkt->getAddr(), pkt->req->getSize());
65 state = dynamic_cast<DmaReqState*>(pkt->senderState);
66 pendingCount--;
64 // get the DMA sender state
65 DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
66 assert(state);
67
67
68 assert(pendingCount >= 0);
69 assert(state);
68 DPRINTF(DMA, "Received response %s for addr: %#x size: %d nb: %d," \
69 " tot: %d sched %d\n",
70 pkt->cmdString(), pkt->getAddr(), pkt->req->getSize(),
71 state->numBytes, state->totBytes,
72 state->completionEvent ?
73 state->completionEvent->scheduled() : 0);
70
74
71 // We shouldn't ever get a block in ownership state
72 assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
75 assert(pendingCount != 0);
76 pendingCount--;
73
77
74 state->numBytes += pkt->req->getSize();
75 assert(state->totBytes >= state->numBytes);
76 if (state->totBytes == state->numBytes) {
77 if (state->completionEvent) {
78 if (state->delay)
79 device->schedule(state->completionEvent,
80 curTick() + state->delay);
81 else
82 state->completionEvent->process();
83 }
84 delete state;
85 }
86 delete pkt->req;
87 delete pkt;
78 // update the number of bytes received based on the request rather
79 // than the packet as the latter could be rounded up to line sizes
80 state->numBytes += pkt->req->getSize();
81 assert(state->totBytes >= state->numBytes);
88
82
89 if (pendingCount == 0 && transmitList.empty() && drainEvent) {
90 drainEvent->process();
91 drainEvent = NULL;
83 // if we have reached the total number of bytes for this DMA
84 // request, then signal the completion and delete the sate
85 if (state->totBytes == state->numBytes) {
86 if (state->completionEvent) {
87 delay += state->delay;
88 if (delay)
89 device->schedule(state->completionEvent, curTick() + delay);
90 else
91 state->completionEvent->process();
92 }
92 }
93 } else {
94 panic("Got packet without sender state... huh?\n");
93 delete state;
95 }
96
94 }
95
96 // delete the request that we created and also the packet
97 delete pkt->req;
98 delete pkt;
99
100 // we might be drained at this point, if so signal the drain event
101 if (pendingCount == 0 && drainEvent) {
102 drainEvent->process();
103 drainEvent = NULL;
104 }
105}
106
107bool
108DmaPort::recvTimingResp(PacketPtr pkt)
109{
110 // We shouldn't ever get a block in ownership state
111 assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
112
113 handleResp(pkt);
114
97 return true;
98}
99
100DmaDevice::DmaDevice(const Params *p)
101 : PioDevice(p), dmaPort(this, sys)
102{ }
103
104void
105DmaDevice::init()
106{
107 if (!dmaPort.isConnected())
108 panic("DMA port of %s not connected to anything!", name());
109 PioDevice::init();
110}
111
112unsigned int
113DmaDevice::drain(Event *de)
114{
115 return true;
116}
117
118DmaDevice::DmaDevice(const Params *p)
119 : PioDevice(p), dmaPort(this, sys)
120{ }
121
122void
123DmaDevice::init()
124{
125 if (!dmaPort.isConnected())
126 panic("DMA port of %s not connected to anything!", name());
127 PioDevice::init();
128}
129
130unsigned int
131DmaDevice::drain(Event *de)
132{
115 unsigned int count;
116 count = pioPort.drain(de) + dmaPort.drain(de);
133 unsigned int count = pioPort.drain(de) + dmaPort.drain(de);
117 if (count)
118 changeState(Draining);
119 else
120 changeState(Drained);
121 return count;
122}
123
124unsigned int
125DmaPort::drain(Event *de)
126{
134 if (count)
135 changeState(Draining);
136 else
137 changeState(Drained);
138 return count;
139}
140
141unsigned int
142DmaPort::drain(Event *de)
143{
127 if (transmitList.empty() && pendingCount == 0)
144 if (pendingCount == 0)
128 return 0;
129 drainEvent = de;
130 DPRINTF(Drain, "DmaPort not drained\n");
131 return 1;
132}
133
134void
135DmaPort::recvRetry()

--- 18 unchanged lines hidden (view full) ---

154 DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n",
155 transmitList.size(), inRetry);
156}
157
158void
159DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
160 uint8_t *data, Tick delay, Request::Flags flag)
161{
145 return 0;
146 drainEvent = de;
147 DPRINTF(Drain, "DmaPort not drained\n");
148 return 1;
149}
150
151void
152DmaPort::recvRetry()

--- 18 unchanged lines hidden (view full) ---

171 DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n",
172 transmitList.size(), inRetry);
173}
174
175void
176DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
177 uint8_t *data, Tick delay, Request::Flags flag)
178{
179 // one DMA request sender state for every action, that is then
180 // split into many requests and packets based on the block size,
181 // i.e. cache line size
162 DmaReqState *reqState = new DmaReqState(event, size, delay);
163
182 DmaReqState *reqState = new DmaReqState(event, size, delay);
183
164
165 DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
184 DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
166 event ? event->scheduled() : -1 );
185 event ? event->scheduled() : -1);
167 for (ChunkGenerator gen(addr, size, peerBlockSize());
168 !gen.done(); gen.next()) {
186 for (ChunkGenerator gen(addr, size, peerBlockSize());
187 !gen.done(); gen.next()) {
169 Request *req = new Request(gen.addr(), gen.size(), flag, masterId);
170 PacketPtr pkt = new Packet(req, cmd);
188 Request *req = new Request(gen.addr(), gen.size(), flag, masterId);
189 PacketPtr pkt = new Packet(req, cmd);
171
190
172 // Increment the data pointer on a write
173 if (data)
174 pkt->dataStatic(data + gen.complete());
191 // Increment the data pointer on a write
192 if (data)
193 pkt->dataStatic(data + gen.complete());
175
194
176 pkt->senderState = reqState;
195 pkt->senderState = reqState;
177
196
178 assert(pendingCount >= 0);
179 pendingCount++;
180 DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
181 gen.size());
182 queueDma(pkt);
197 DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
198 gen.size());
199 queueDma(pkt);
183 }
200 }
184
185}
186
187void
201}
202
203void
188DmaPort::queueDma(PacketPtr pkt, bool front)
204DmaPort::queueDma(PacketPtr pkt)
189{
205{
206 transmitList.push_back(pkt);
190
207
191 if (front)
192 transmitList.push_front(pkt);
193 else
194 transmitList.push_back(pkt);
208 // remember that we have another packet pending, this will only be
209 // decremented once a response comes back
210 pendingCount++;
211
195 sendDma();
196}
197
198void
199DmaPort::sendDma()
200{
212 sendDma();
213}
214
215void
216DmaPort::sendDma()
217{
201 // some kind of selction between access methods
218 // some kind of selcetion between access methods
202 // more work is going to have to be done to make
203 // switching actually work
204 assert(transmitList.size());
205 PacketPtr pkt = transmitList.front();
206
207 Enums::MemoryMode state = sys->getMemoryMode();
208 if (state == Enums::timing) {
209 if (inRetry) {

--- 13 unchanged lines hidden (view full) ---

223 } else {
224 inRetry = true;
225 DPRINTF(DMA, "-- Failed: queued\n");
226 }
227 } while (result && transmitList.size());
228 } else if (state == Enums::atomic) {
229 transmitList.pop_front();
230
219 // more work is going to have to be done to make
220 // switching actually work
221 assert(transmitList.size());
222 PacketPtr pkt = transmitList.front();
223
224 Enums::MemoryMode state = sys->getMemoryMode();
225 if (state == Enums::timing) {
226 if (inRetry) {

--- 13 unchanged lines hidden (view full) ---

240 } else {
241 inRetry = true;
242 DPRINTF(DMA, "-- Failed: queued\n");
243 }
244 } while (result && transmitList.size());
245 } else if (state == Enums::atomic) {
246 transmitList.pop_front();
247
231 Tick lat;
232 DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n",
248 DPRINTF(DMA, "Sending DMA for addr: %#x size: %d\n",
233 pkt->req->getPaddr(), pkt->req->getSize());
249 pkt->req->getPaddr(), pkt->req->getSize());
234 lat = sendAtomic(pkt);
235 assert(pkt->senderState);
236 DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
237 assert(state);
238 state->numBytes += pkt->req->getSize();
250 Tick lat = sendAtomic(pkt);
239
251
240 DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n",
241 pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes,
242 state->totBytes,
243 state->completionEvent ? state->completionEvent->scheduled() : 0 );
244
245 if (state->totBytes == state->numBytes) {
246 if (state->completionEvent) {
247 assert(!state->completionEvent->scheduled());
248 device->schedule(state->completionEvent,
249 curTick() + lat + state->delay);
250 }
251 delete state;
252 delete pkt->req;
253 }
254 pendingCount--;
255 assert(pendingCount >= 0);
256 delete pkt;
257
258 if (pendingCount == 0 && transmitList.empty() && drainEvent) {
259 DPRINTF(Drain, "DmaPort done draining, processing drain event\n");
260 drainEvent->process();
261 drainEvent = NULL;
262 }
263
264 } else
265 panic("Unknown memory command state.");
252 handleResp(pkt, lat);
253 } else
254 panic("Unknown memory mode.");
266}
267
255}
256
268DmaDevice::~DmaDevice()
269{
270}
271
272MasterPort &
273DmaDevice::getMasterPort(const std::string &if_name, int idx)
274{
275 if (if_name == "dma") {
276 return dmaPort;
277 }
278 return PioDevice::getMasterPort(if_name, idx);
279}
257MasterPort &
258DmaDevice::getMasterPort(const std::string &if_name, int idx)
259{
260 if (if_name == "dma") {
261 return dmaPort;
262 }
263 return PioDevice::getMasterPort(if_name, idx);
264}