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