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