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