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