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