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