b1346bb1af60acd6f09decd635b01f16a0d6723c
[gem5.git] / dev / tsunami_pchip.cc
1 /*
2 * Copyright (c) 2004 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/bus/bus.hh"
42 #include "mem/bus/pio_interface.hh"
43 #include "mem/bus/pio_interface_impl.hh"
44 #include "mem/functional_mem/memory_control.hh"
45 #include "mem/functional_mem/physical_memory.hh"
46 #include "sim/builder.hh"
47 #include "sim/system.hh"
48
49 using namespace std;
50
51 TsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a,
52 MemoryController *mmu, HierParams *hier,
53 Bus *bus)
54 : PioDevice(name), addr(a), tsunami(t)
55 {
56 mmu->add_child(this, Range<Addr>(addr, addr + size));
57
58 for (int i = 0; i < 4; i++) {
59 wsba[i] = 0;
60 wsm[i] = 0;
61 tba[i] = 0;
62 }
63
64 if (bus) {
65 pioInterface = newPioInterface(name, hier, bus, this,
66 &TsunamiPChip::cacheAccess);
67 pioInterface->addAddrRange(addr, addr + size - 1);
68 }
69
70
71 // initialize pchip control register
72 pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36);
73
74 //Set back pointer in tsunami
75 tsunami->pchip = this;
76 }
77
78 Fault
79 TsunamiPChip::read(MemReqPtr &req, uint8_t *data)
80 {
81 DPRINTF(Tsunami, "read va=%#x size=%d\n",
82 req->vaddr, req->size);
83
84 Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
85
86 switch (req->size) {
87
88 case sizeof(uint64_t):
89 switch(daddr) {
90 case TSDEV_PC_WSBA0:
91 *(uint64_t*)data = wsba[0];
92 return No_Fault;
93 case TSDEV_PC_WSBA1:
94 *(uint64_t*)data = wsba[1];
95 return No_Fault;
96 case TSDEV_PC_WSBA2:
97 *(uint64_t*)data = wsba[2];
98 return No_Fault;
99 case TSDEV_PC_WSBA3:
100 *(uint64_t*)data = wsba[3];
101 return No_Fault;
102 case TSDEV_PC_WSM0:
103 *(uint64_t*)data = wsm[0];
104 return No_Fault;
105 case TSDEV_PC_WSM1:
106 *(uint64_t*)data = wsm[1];
107 return No_Fault;
108 case TSDEV_PC_WSM2:
109 *(uint64_t*)data = wsm[2];
110 return No_Fault;
111 case TSDEV_PC_WSM3:
112 *(uint64_t*)data = wsm[3];
113 return No_Fault;
114 case TSDEV_PC_TBA0:
115 *(uint64_t*)data = tba[0];
116 return No_Fault;
117 case TSDEV_PC_TBA1:
118 *(uint64_t*)data = tba[1];
119 return No_Fault;
120 case TSDEV_PC_TBA2:
121 *(uint64_t*)data = tba[2];
122 return No_Fault;
123 case TSDEV_PC_TBA3:
124 *(uint64_t*)data = tba[3];
125 return No_Fault;
126 case TSDEV_PC_PCTL:
127 *(uint64_t*)data = pctl;
128 return No_Fault;
129 case TSDEV_PC_PLAT:
130 panic("PC_PLAT not implemented\n");
131 case TSDEV_PC_RES:
132 panic("PC_RES not implemented\n");
133 case TSDEV_PC_PERROR:
134 *(uint64_t*)data = 0x00;
135 return No_Fault;
136 case TSDEV_PC_PERRMASK:
137 *(uint64_t*)data = 0x00;
138 return No_Fault;
139 case TSDEV_PC_PERRSET:
140 panic("PC_PERRSET not implemented\n");
141 case TSDEV_PC_TLBIV:
142 panic("PC_TLBIV not implemented\n");
143 case TSDEV_PC_TLBIA:
144 *(uint64_t*)data = 0x00; // shouldn't be readable, but linux
145 return No_Fault;
146 case TSDEV_PC_PMONCTL:
147 panic("PC_PMONCTL not implemented\n");
148 case TSDEV_PC_PMONCNT:
149 panic("PC_PMONCTN not implemented\n");
150 default:
151 panic("Default in PChip Read reached reading 0x%x\n", daddr);
152
153 } // uint64_t
154
155 break;
156 case sizeof(uint32_t):
157 case sizeof(uint16_t):
158 case sizeof(uint8_t):
159 default:
160 panic("invalid access size(?) for tsunami register!\n\n");
161 }
162 DPRINTFN("Tsunami PChip ERROR: read daddr=%#x size=%d\n", daddr, req->size);
163
164 return No_Fault;
165 }
166
167 Fault
168 TsunamiPChip::write(MemReqPtr &req, const uint8_t *data)
169 {
170 DPRINTF(Tsunami, "write - va=%#x size=%d \n",
171 req->vaddr, req->size);
172
173 Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
174
175 switch (req->size) {
176
177 case sizeof(uint64_t):
178 switch(daddr) {
179 case TSDEV_PC_WSBA0:
180 wsba[0] = *(uint64_t*)data;
181 return No_Fault;
182 case TSDEV_PC_WSBA1:
183 wsba[1] = *(uint64_t*)data;
184 return No_Fault;
185 case TSDEV_PC_WSBA2:
186 wsba[2] = *(uint64_t*)data;
187 return No_Fault;
188 case TSDEV_PC_WSBA3:
189 wsba[3] = *(uint64_t*)data;
190 return No_Fault;
191 case TSDEV_PC_WSM0:
192 wsm[0] = *(uint64_t*)data;
193 return No_Fault;
194 case TSDEV_PC_WSM1:
195 wsm[1] = *(uint64_t*)data;
196 return No_Fault;
197 case TSDEV_PC_WSM2:
198 wsm[2] = *(uint64_t*)data;
199 return No_Fault;
200 case TSDEV_PC_WSM3:
201 wsm[3] = *(uint64_t*)data;
202 return No_Fault;
203 case TSDEV_PC_TBA0:
204 tba[0] = *(uint64_t*)data;
205 return No_Fault;
206 case TSDEV_PC_TBA1:
207 tba[1] = *(uint64_t*)data;
208 return No_Fault;
209 case TSDEV_PC_TBA2:
210 tba[2] = *(uint64_t*)data;
211 return No_Fault;
212 case TSDEV_PC_TBA3:
213 tba[3] = *(uint64_t*)data;
214 return No_Fault;
215 case TSDEV_PC_PCTL:
216 pctl = *(uint64_t*)data;
217 return No_Fault;
218 case TSDEV_PC_PLAT:
219 panic("PC_PLAT not implemented\n");
220 case TSDEV_PC_RES:
221 panic("PC_RES not implemented\n");
222 case TSDEV_PC_PERROR:
223 return No_Fault;
224 case TSDEV_PC_PERRMASK:
225 panic("PC_PERRMASK not implemented\n");
226 case TSDEV_PC_PERRSET:
227 panic("PC_PERRSET not implemented\n");
228 case TSDEV_PC_TLBIV:
229 panic("PC_TLBIV not implemented\n");
230 case TSDEV_PC_TLBIA:
231 return No_Fault; // value ignored, supposted to invalidate SG TLB
232 case TSDEV_PC_PMONCTL:
233 panic("PC_PMONCTL not implemented\n");
234 case TSDEV_PC_PMONCNT:
235 panic("PC_PMONCTN not implemented\n");
236 default:
237 panic("Default in PChip Read reached reading 0x%x\n", daddr);
238
239 } // uint64_t
240
241 break;
242 case sizeof(uint32_t):
243 case sizeof(uint16_t):
244 case sizeof(uint8_t):
245 default:
246 panic("invalid access size(?) for tsunami register!\n\n");
247 }
248
249 DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size);
250
251 return No_Fault;
252 }
253
254 #define DMA_ADDR_MASK ULL(0x3ffffffff)
255
256 Addr
257 TsunamiPChip::translatePciToDma(Addr busAddr)
258 {
259 // compare the address to the window base registers
260 uint64_t tbaMask = 0;
261 uint64_t baMask = 0;
262
263 uint64_t windowMask = 0;
264 uint64_t windowBase = 0;
265
266 uint64_t pteEntry = 0;
267
268 Addr pteAddr;
269 Addr dmaAddr;
270
271 #if 0
272 DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr);
273 for (int i = 0; i < 4; i++) {
274 DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n",
275 i, wsba[i], wsm[i]);
276
277 windowBase = wsba[i];
278 windowMask = ~wsm[i] & (ULL(0xfff) << 20);
279
280 if ((busAddr & windowMask) == (windowBase & windowMask)) {
281 DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n",
282 i, windowBase, windowMask, (busAddr & windowMask),
283 (windowBase & windowMask));
284 }
285 }
286 #endif
287
288 for (int i = 0; i < 4; i++) {
289
290 windowBase = wsba[i];
291 windowMask = ~wsm[i] & (ULL(0xfff) << 20);
292
293 if ((busAddr & windowMask) == (windowBase & windowMask)) {
294
295 if (wsba[i] & 0x1) { // see if enabled
296 if (wsba[i] & 0x2) { // see if SG bit is set
297 /** @todo
298 This currently is faked by just doing a direct
299 read from memory, however, to be realistic, this
300 needs to actually do a bus transaction. The process
301 is explained in the tsunami documentation on page
302 10-12 and basically munges the address to look up a
303 PTE from a table in memory and then uses that mapping
304 to create an address for the SG page
305 */
306
307 tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff));
308 baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13);
309 pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10);
310
311 memcpy((void *)&pteEntry,
312 tsunami->system->
313 physmem->dma_addr(pteAddr, sizeof(uint64_t)),
314 sizeof(uint64_t));
315
316 dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff));
317
318 } else {
319 baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff);
320 tbaMask = ~baMask;
321 dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask);
322 }
323
324 return (dmaAddr & DMA_ADDR_MASK);
325 }
326 }
327 }
328
329 // if no match was found, then return the original address
330 return busAddr;
331 }
332
333 void
334 TsunamiPChip::serialize(std::ostream &os)
335 {
336 SERIALIZE_SCALAR(pctl);
337 SERIALIZE_ARRAY(wsba, 4);
338 SERIALIZE_ARRAY(wsm, 4);
339 SERIALIZE_ARRAY(tba, 4);
340 }
341
342 void
343 TsunamiPChip::unserialize(Checkpoint *cp, const std::string &section)
344 {
345 UNSERIALIZE_SCALAR(pctl);
346 UNSERIALIZE_ARRAY(wsba, 4);
347 UNSERIALIZE_ARRAY(wsm, 4);
348 UNSERIALIZE_ARRAY(tba, 4);
349 }
350
351 Tick
352 TsunamiPChip::cacheAccess(MemReqPtr &req)
353 {
354 return curTick + 1000;
355 }
356
357 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
358
359 SimObjectParam<Tsunami *> tsunami;
360 SimObjectParam<MemoryController *> mmu;
361 Param<Addr> addr;
362 SimObjectParam<Bus*> io_bus;
363 SimObjectParam<HierParams *> hier;
364
365 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
366
367 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
368
369 INIT_PARAM(tsunami, "Tsunami"),
370 INIT_PARAM(mmu, "Memory Controller"),
371 INIT_PARAM(addr, "Device Address"),
372 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
373 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
374
375 END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
376
377 CREATE_SIM_OBJECT(TsunamiPChip)
378 {
379 return new TsunamiPChip(getInstanceName(), tsunami, addr, mmu, hier, io_bus);
380 }
381
382 REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip)