tsunami_pchip.cc revision 909
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
49using namespace std;
50
51TsunamiPChip::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
78Fault
79TsunamiPChip::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
167Fault
168TsunamiPChip::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
256Addr
257TsunamiPChip::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
333void
334TsunamiPChip::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
342void
343TsunamiPChip::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
351Tick
352TsunamiPChip::cacheAccess(MemReqPtr &req)
353{
354    return curTick + 1000;
355}
356
357BEGIN_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
365END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
366
367BEGIN_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
375END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
376
377CREATE_SIM_OBJECT(TsunamiPChip)
378{
379    return new TsunamiPChip(getInstanceName(), tsunami, addr, mmu, hier, io_bus);
380}
381
382REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip)
383