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