Significant rework of Packet class interface:
[gem5.git] / src / dev / tsunami_pchip.cc
1 /*
2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /** @file
30 * Tsunami PChip (pci)
31 */
32
33 #include <deque>
34 #include <string>
35 #include <vector>
36
37 #include "base/trace.hh"
38 #include "dev/tsunami_pchip.hh"
39 #include "dev/tsunamireg.h"
40 #include "dev/tsunami.hh"
41 #include "mem/packet.hh"
42 #include "sim/builder.hh"
43 #include "sim/system.hh"
44
45 using namespace std;
46 //Should this be AlphaISA?
47 using namespace TheISA;
48
49 TsunamiPChip::TsunamiPChip(Params *p)
50 : BasicPioDevice(p)
51 {
52 pioSize = 0xfff;
53
54 for (int i = 0; i < 4; i++) {
55 wsba[i] = 0;
56 wsm[i] = 0;
57 tba[i] = 0;
58 }
59
60 // initialize pchip control register
61 pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36);
62
63 //Set back pointer in tsunami
64 p->tsunami->pchip = this;
65 }
66
67 Tick
68 TsunamiPChip::read(Packet *pkt)
69 {
70 assert(pkt->result == Packet::Unknown);
71 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
72
73
74 pkt->time += pioDelay;
75 pkt->allocate();
76 Addr daddr = (pkt->getAddr() - pioAddr) >> 6;;
77 assert(pkt->getSize() == sizeof(uint64_t));
78
79
80 DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->getAddr(), pkt->getSize());
81
82 switch(daddr) {
83 case TSDEV_PC_WSBA0:
84 pkt->set(wsba[0]);
85 break;
86 case TSDEV_PC_WSBA1:
87 pkt->set(wsba[1]);
88 break;
89 case TSDEV_PC_WSBA2:
90 pkt->set(wsba[2]);
91 break;
92 case TSDEV_PC_WSBA3:
93 pkt->set(wsba[3]);
94 break;
95 case TSDEV_PC_WSM0:
96 pkt->set(wsm[0]);
97 break;
98 case TSDEV_PC_WSM1:
99 pkt->set(wsm[1]);
100 break;
101 case TSDEV_PC_WSM2:
102 pkt->set(wsm[2]);
103 break;
104 case TSDEV_PC_WSM3:
105 pkt->set(wsm[3]);
106 break;
107 case TSDEV_PC_TBA0:
108 pkt->set(tba[0]);
109 break;
110 case TSDEV_PC_TBA1:
111 pkt->set(tba[1]);
112 break;
113 case TSDEV_PC_TBA2:
114 pkt->set(tba[2]);
115 break;
116 case TSDEV_PC_TBA3:
117 pkt->set(tba[3]);
118 break;
119 case TSDEV_PC_PCTL:
120 pkt->set(pctl);
121 break;
122 case TSDEV_PC_PLAT:
123 panic("PC_PLAT not implemented\n");
124 case TSDEV_PC_RES:
125 panic("PC_RES not implemented\n");
126 case TSDEV_PC_PERROR:
127 pkt->set((uint64_t)0x00);
128 break;
129 case TSDEV_PC_PERRMASK:
130 pkt->set((uint64_t)0x00);
131 break;
132 case TSDEV_PC_PERRSET:
133 panic("PC_PERRSET not implemented\n");
134 case TSDEV_PC_TLBIV:
135 panic("PC_TLBIV not implemented\n");
136 case TSDEV_PC_TLBIA:
137 pkt->set((uint64_t)0x00); // shouldn't be readable, but linux
138 break;
139 case TSDEV_PC_PMONCTL:
140 panic("PC_PMONCTL not implemented\n");
141 case TSDEV_PC_PMONCNT:
142 panic("PC_PMONCTN not implemented\n");
143 default:
144 panic("Default in PChip Read reached reading 0x%x\n", daddr);
145 }
146 pkt->result = Packet::Success;
147 return pioDelay;
148
149 }
150
151 Tick
152 TsunamiPChip::write(Packet *pkt)
153 {
154 pkt->time += pioDelay;
155
156 assert(pkt->result == Packet::Unknown);
157 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
158 Addr daddr = (pkt->getAddr() - pioAddr) >> 6;
159
160 assert(pkt->getSize() == sizeof(uint64_t));
161
162 DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->getAddr(), pkt->getSize());
163
164 switch(daddr) {
165 case TSDEV_PC_WSBA0:
166 wsba[0] = pkt->get<uint64_t>();
167 break;
168 case TSDEV_PC_WSBA1:
169 wsba[1] = pkt->get<uint64_t>();
170 break;
171 case TSDEV_PC_WSBA2:
172 wsba[2] = pkt->get<uint64_t>();
173 break;
174 case TSDEV_PC_WSBA3:
175 wsba[3] = pkt->get<uint64_t>();
176 break;
177 case TSDEV_PC_WSM0:
178 wsm[0] = pkt->get<uint64_t>();
179 break;
180 case TSDEV_PC_WSM1:
181 wsm[1] = pkt->get<uint64_t>();
182 break;
183 case TSDEV_PC_WSM2:
184 wsm[2] = pkt->get<uint64_t>();
185 break;
186 case TSDEV_PC_WSM3:
187 wsm[3] = pkt->get<uint64_t>();
188 break;
189 case TSDEV_PC_TBA0:
190 tba[0] = pkt->get<uint64_t>();
191 break;
192 case TSDEV_PC_TBA1:
193 tba[1] = pkt->get<uint64_t>();
194 break;
195 case TSDEV_PC_TBA2:
196 tba[2] = pkt->get<uint64_t>();
197 break;
198 case TSDEV_PC_TBA3:
199 tba[3] = pkt->get<uint64_t>();
200 break;
201 case TSDEV_PC_PCTL:
202 pctl = pkt->get<uint64_t>();
203 break;
204 case TSDEV_PC_PLAT:
205 panic("PC_PLAT not implemented\n");
206 case TSDEV_PC_RES:
207 panic("PC_RES not implemented\n");
208 case TSDEV_PC_PERROR:
209 break;
210 case TSDEV_PC_PERRMASK:
211 panic("PC_PERRMASK not implemented\n");
212 case TSDEV_PC_PERRSET:
213 panic("PC_PERRSET not implemented\n");
214 case TSDEV_PC_TLBIV:
215 panic("PC_TLBIV not implemented\n");
216 case TSDEV_PC_TLBIA:
217 break; // value ignored, supposted to invalidate SG TLB
218 case TSDEV_PC_PMONCTL:
219 panic("PC_PMONCTL not implemented\n");
220 case TSDEV_PC_PMONCNT:
221 panic("PC_PMONCTN not implemented\n");
222 default:
223 panic("Default in PChip write reached reading 0x%x\n", daddr);
224
225 } // uint64_t
226
227 pkt->result = Packet::Success;
228 return pioDelay;
229 }
230
231 #define DMA_ADDR_MASK ULL(0x3ffffffff)
232
233 Addr
234 TsunamiPChip::translatePciToDma(Addr busAddr)
235 {
236 // compare the address to the window base registers
237 uint64_t tbaMask = 0;
238 uint64_t baMask = 0;
239
240 uint64_t windowMask = 0;
241 uint64_t windowBase = 0;
242
243 uint64_t pteEntry = 0;
244
245 Addr pteAddr;
246 Addr dmaAddr;
247
248 #if 0
249 DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr);
250 for (int i = 0; i < 4; i++) {
251 DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n",
252 i, wsba[i], wsm[i]);
253
254 windowBase = wsba[i];
255 windowMask = ~wsm[i] & (ULL(0xfff) << 20);
256
257 if ((busAddr & windowMask) == (windowBase & windowMask)) {
258 DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n",
259 i, windowBase, windowMask, (busAddr & windowMask),
260 (windowBase & windowMask));
261 }
262 }
263 #endif
264
265 for (int i = 0; i < 4; i++) {
266
267 windowBase = wsba[i];
268 windowMask = ~wsm[i] & (ULL(0xfff) << 20);
269
270 if ((busAddr & windowMask) == (windowBase & windowMask)) {
271
272 if (wsba[i] & 0x1) { // see if enabled
273 if (wsba[i] & 0x2) { // see if SG bit is set
274 /** @todo
275 This currently is faked by just doing a direct
276 read from memory, however, to be realistic, this
277 needs to actually do a bus transaction. The process
278 is explained in the tsunami documentation on page
279 10-12 and basically munges the address to look up a
280 PTE from a table in memory and then uses that mapping
281 to create an address for the SG page
282 */
283
284 tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff));
285 baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13);
286 pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10);
287
288 pioPort->readBlob(pteAddr, (uint8_t*)&pteEntry, sizeof(uint64_t));
289
290 dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff));
291
292 } else {
293 baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff);
294 tbaMask = ~baMask;
295 dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask);
296 }
297
298 return (dmaAddr & DMA_ADDR_MASK);
299 }
300 }
301 }
302
303 // if no match was found, then return the original address
304 return busAddr;
305 }
306
307 void
308 TsunamiPChip::serialize(std::ostream &os)
309 {
310 SERIALIZE_SCALAR(pctl);
311 SERIALIZE_ARRAY(wsba, 4);
312 SERIALIZE_ARRAY(wsm, 4);
313 SERIALIZE_ARRAY(tba, 4);
314 }
315
316 void
317 TsunamiPChip::unserialize(Checkpoint *cp, const std::string &section)
318 {
319 UNSERIALIZE_SCALAR(pctl);
320 UNSERIALIZE_ARRAY(wsba, 4);
321 UNSERIALIZE_ARRAY(wsm, 4);
322 UNSERIALIZE_ARRAY(tba, 4);
323 }
324
325
326 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
327
328 Param<Addr> pio_addr;
329 Param<Tick> pio_latency;
330 SimObjectParam<Platform *> platform;
331 SimObjectParam<System *> system;
332 SimObjectParam<Tsunami *> tsunami;
333
334 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
335
336 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
337
338 INIT_PARAM(pio_addr, "Device Address"),
339 INIT_PARAM(pio_latency, "Programmed IO latency"),
340 INIT_PARAM(platform, "platform"),
341 INIT_PARAM(system, "system object"),
342 INIT_PARAM(tsunami, "Tsunami")
343
344 END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
345
346 CREATE_SIM_OBJECT(TsunamiPChip)
347 {
348 TsunamiPChip::Params *p = new TsunamiPChip::Params;
349 p->name = getInstanceName();
350 p->pio_addr = pio_addr;
351 p->pio_delay = pio_latency;
352 p->platform = platform;
353 p->system = system;
354 p->tsunami = tsunami;
355 return new TsunamiPChip(p);
356 }
357
358 REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip)