tsunami_pchip.cc revision 4762
114039Sstacze01@arm.com/*
214039Sstacze01@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
314039Sstacze01@arm.com * All rights reserved.
414039Sstacze01@arm.com *
514039Sstacze01@arm.com * Redistribution and use in source and binary forms, with or without
614039Sstacze01@arm.com * modification, are permitted provided that the following conditions are
714039Sstacze01@arm.com * met: redistributions of source code must retain the above copyright
814039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer;
914039Sstacze01@arm.com * redistributions in binary form must reproduce the above copyright
1014039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer in the
1114039Sstacze01@arm.com * documentation and/or other materials provided with the distribution;
1214039Sstacze01@arm.com * neither the name of the copyright holders nor the names of its
1314039Sstacze01@arm.com * contributors may be used to endorse or promote products derived from
1414039Sstacze01@arm.com * this software without specific prior written permission.
1514039Sstacze01@arm.com *
1614039Sstacze01@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1714039Sstacze01@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1814039Sstacze01@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1914039Sstacze01@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2014039Sstacze01@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2114039Sstacze01@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2214039Sstacze01@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2314039Sstacze01@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2414039Sstacze01@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2514039Sstacze01@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2614039Sstacze01@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2714039Sstacze01@arm.com *
2814039Sstacze01@arm.com * Authors: Ali Saidi
2914039Sstacze01@arm.com *          Andrew Schultz
3014039Sstacze01@arm.com */
3114039Sstacze01@arm.com
3214039Sstacze01@arm.com/** @file
3314039Sstacze01@arm.com * Tsunami PChip (pci)
3414039Sstacze01@arm.com */
3514039Sstacze01@arm.com
3614039Sstacze01@arm.com#include <deque>
3714039Sstacze01@arm.com#include <string>
3814039Sstacze01@arm.com#include <vector>
3914039Sstacze01@arm.com
4014039Sstacze01@arm.com#include "base/trace.hh"
4114039Sstacze01@arm.com#include "dev/alpha/tsunami_pchip.hh"
4214039Sstacze01@arm.com#include "dev/alpha/tsunamireg.h"
4314039Sstacze01@arm.com#include "dev/alpha/tsunami.hh"
4414039Sstacze01@arm.com#include "mem/packet.hh"
4514039Sstacze01@arm.com#include "mem/packet_access.hh"
4614039Sstacze01@arm.com#include "sim/system.hh"
4714039Sstacze01@arm.com
4814039Sstacze01@arm.comusing namespace std;
4914039Sstacze01@arm.com//Should this be AlphaISA?
5014039Sstacze01@arm.comusing namespace TheISA;
5114252Sgabeblack@google.com
5214039Sstacze01@arm.comTsunamiPChip::TsunamiPChip(const Params *p)
5314039Sstacze01@arm.com: BasicPioDevice(p)
5414039Sstacze01@arm.com{
5514039Sstacze01@arm.com    pioSize = 0x1000;
5614039Sstacze01@arm.com
5714252Sgabeblack@google.com    for (int i = 0; i < 4; i++) {
5814039Sstacze01@arm.com        wsba[i] = 0;
5914064Sadrian.herrera@arm.com        wsm[i] = 0;
6014064Sadrian.herrera@arm.com        tba[i] = 0;
6114064Sadrian.herrera@arm.com    }
6214039Sstacze01@arm.com
6314039Sstacze01@arm.com    // initialize pchip control register
6414039Sstacze01@arm.com    pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36);
6514039Sstacze01@arm.com
6614039Sstacze01@arm.com    //Set back pointer in tsunami
6714039Sstacze01@arm.com    p->tsunami->pchip = this;
6814039Sstacze01@arm.com}
6914039Sstacze01@arm.com
7014039Sstacze01@arm.comTick
7114039Sstacze01@arm.comTsunamiPChip::read(PacketPtr pkt)
7214039Sstacze01@arm.com{
7314039Sstacze01@arm.com    assert(pkt->result == Packet::Unknown);
7414039Sstacze01@arm.com    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
7514039Sstacze01@arm.com
7614039Sstacze01@arm.com    pkt->allocate();
7714039Sstacze01@arm.com    Addr daddr = (pkt->getAddr() - pioAddr) >> 6;;
7814039Sstacze01@arm.com    assert(pkt->getSize() == sizeof(uint64_t));
7914039Sstacze01@arm.com
8014039Sstacze01@arm.com
8114039Sstacze01@arm.com    DPRINTF(Tsunami, "read  va=%#x size=%d\n", pkt->getAddr(), pkt->getSize());
8214039Sstacze01@arm.com
8314039Sstacze01@arm.com    switch(daddr) {
8414039Sstacze01@arm.com      case TSDEV_PC_WSBA0:
8514039Sstacze01@arm.com            pkt->set(wsba[0]);
8614223Sgiacomo.travaglini@arm.com            break;
8714039Sstacze01@arm.com      case TSDEV_PC_WSBA1:
8814039Sstacze01@arm.com            pkt->set(wsba[1]);
8914039Sstacze01@arm.com            break;
9014039Sstacze01@arm.com      case TSDEV_PC_WSBA2:
9114039Sstacze01@arm.com            pkt->set(wsba[2]);
9214039Sstacze01@arm.com            break;
9314039Sstacze01@arm.com      case TSDEV_PC_WSBA3:
9414039Sstacze01@arm.com            pkt->set(wsba[3]);
9514039Sstacze01@arm.com            break;
9614039Sstacze01@arm.com      case TSDEV_PC_WSM0:
9714039Sstacze01@arm.com            pkt->set(wsm[0]);
9814039Sstacze01@arm.com            break;
9914039Sstacze01@arm.com      case TSDEV_PC_WSM1:
10014039Sstacze01@arm.com            pkt->set(wsm[1]);
10114039Sstacze01@arm.com            break;
10214039Sstacze01@arm.com      case TSDEV_PC_WSM2:
10314039Sstacze01@arm.com            pkt->set(wsm[2]);
10414039Sstacze01@arm.com            break;
10514039Sstacze01@arm.com      case TSDEV_PC_WSM3:
10614039Sstacze01@arm.com            pkt->set(wsm[3]);
10714039Sstacze01@arm.com            break;
10814039Sstacze01@arm.com      case TSDEV_PC_TBA0:
10914039Sstacze01@arm.com            pkt->set(tba[0]);
11014039Sstacze01@arm.com            break;
11114039Sstacze01@arm.com      case TSDEV_PC_TBA1:
11214039Sstacze01@arm.com            pkt->set(tba[1]);
11314039Sstacze01@arm.com            break;
11414039Sstacze01@arm.com      case TSDEV_PC_TBA2:
11514039Sstacze01@arm.com            pkt->set(tba[2]);
11614039Sstacze01@arm.com            break;
11714039Sstacze01@arm.com      case TSDEV_PC_TBA3:
11814039Sstacze01@arm.com            pkt->set(tba[3]);
11914039Sstacze01@arm.com            break;
12014092Smatteo.andreozzi@arm.com      case TSDEV_PC_PCTL:
12114039Sstacze01@arm.com            pkt->set(pctl);
12214039Sstacze01@arm.com            break;
12314039Sstacze01@arm.com      case TSDEV_PC_PLAT:
12414039Sstacze01@arm.com            panic("PC_PLAT not implemented\n");
12514039Sstacze01@arm.com      case TSDEV_PC_RES:
12614039Sstacze01@arm.com            panic("PC_RES not implemented\n");
12714039Sstacze01@arm.com      case TSDEV_PC_PERROR:
12814039Sstacze01@arm.com            pkt->set((uint64_t)0x00);
12914039Sstacze01@arm.com            break;
13014039Sstacze01@arm.com      case TSDEV_PC_PERRMASK:
13114064Sadrian.herrera@arm.com            pkt->set((uint64_t)0x00);
13214064Sadrian.herrera@arm.com            break;
13314064Sadrian.herrera@arm.com      case TSDEV_PC_PERRSET:
13414064Sadrian.herrera@arm.com            panic("PC_PERRSET not implemented\n");
13514064Sadrian.herrera@arm.com      case TSDEV_PC_TLBIV:
13614064Sadrian.herrera@arm.com            panic("PC_TLBIV not implemented\n");
13714064Sadrian.herrera@arm.com      case TSDEV_PC_TLBIA:
13814064Sadrian.herrera@arm.com            pkt->set((uint64_t)0x00); // shouldn't be readable, but linux
13914039Sstacze01@arm.com            break;
14014039Sstacze01@arm.com      case TSDEV_PC_PMONCTL:
14114039Sstacze01@arm.com            panic("PC_PMONCTL not implemented\n");
14214039Sstacze01@arm.com      case TSDEV_PC_PMONCNT:
14314039Sstacze01@arm.com            panic("PC_PMONCTN not implemented\n");
144      default:
145          panic("Default in PChip Read reached reading 0x%x\n", daddr);
146    }
147    pkt->result = Packet::Success;
148    return pioDelay;
149
150}
151
152Tick
153TsunamiPChip::write(PacketPtr pkt)
154{
155    assert(pkt->result == Packet::Unknown);
156    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
157    Addr daddr = (pkt->getAddr() - pioAddr) >> 6;
158
159    assert(pkt->getSize() == sizeof(uint64_t));
160
161    DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->getAddr(), pkt->getSize());
162
163    switch(daddr) {
164        case TSDEV_PC_WSBA0:
165              wsba[0] = pkt->get<uint64_t>();
166              break;
167        case TSDEV_PC_WSBA1:
168              wsba[1] = pkt->get<uint64_t>();
169              break;
170        case TSDEV_PC_WSBA2:
171              wsba[2] = pkt->get<uint64_t>();
172              break;
173        case TSDEV_PC_WSBA3:
174              wsba[3] = pkt->get<uint64_t>();
175              break;
176        case TSDEV_PC_WSM0:
177              wsm[0] = pkt->get<uint64_t>();
178              break;
179        case TSDEV_PC_WSM1:
180              wsm[1] = pkt->get<uint64_t>();
181              break;
182        case TSDEV_PC_WSM2:
183              wsm[2] = pkt->get<uint64_t>();
184              break;
185        case TSDEV_PC_WSM3:
186              wsm[3] = pkt->get<uint64_t>();
187              break;
188        case TSDEV_PC_TBA0:
189              tba[0] = pkt->get<uint64_t>();
190              break;
191        case TSDEV_PC_TBA1:
192              tba[1] = pkt->get<uint64_t>();
193              break;
194        case TSDEV_PC_TBA2:
195              tba[2] = pkt->get<uint64_t>();
196              break;
197        case TSDEV_PC_TBA3:
198              tba[3] = pkt->get<uint64_t>();
199              break;
200        case TSDEV_PC_PCTL:
201              pctl = pkt->get<uint64_t>();
202              break;
203        case TSDEV_PC_PLAT:
204              panic("PC_PLAT not implemented\n");
205        case TSDEV_PC_RES:
206              panic("PC_RES not implemented\n");
207        case TSDEV_PC_PERROR:
208              break;
209        case TSDEV_PC_PERRMASK:
210              panic("PC_PERRMASK not implemented\n");
211        case TSDEV_PC_PERRSET:
212              panic("PC_PERRSET not implemented\n");
213        case TSDEV_PC_TLBIV:
214              panic("PC_TLBIV not implemented\n");
215        case TSDEV_PC_TLBIA:
216              break; // value ignored, supposted to invalidate SG TLB
217        case TSDEV_PC_PMONCTL:
218              panic("PC_PMONCTL not implemented\n");
219        case TSDEV_PC_PMONCNT:
220              panic("PC_PMONCTN not implemented\n");
221        default:
222            panic("Default in PChip write reached reading 0x%x\n", daddr);
223
224    } // uint64_t
225
226    pkt->result = Packet::Success;
227    return pioDelay;
228}
229
230#define DMA_ADDR_MASK ULL(0x3ffffffff)
231
232Addr
233TsunamiPChip::translatePciToDma(Addr busAddr)
234{
235    // compare the address to the window base registers
236    uint64_t tbaMask = 0;
237    uint64_t baMask = 0;
238
239    uint64_t windowMask = 0;
240    uint64_t windowBase = 0;
241
242    uint64_t pteEntry = 0;
243
244    Addr pteAddr;
245    Addr dmaAddr;
246
247#if 0
248    DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr);
249    for (int i = 0; i < 4; i++) {
250        DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n",
251                i, wsba[i], wsm[i]);
252
253        windowBase = wsba[i];
254        windowMask = ~wsm[i] & (ULL(0xfff) << 20);
255
256        if ((busAddr & windowMask) == (windowBase & windowMask)) {
257            DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n",
258                    i, windowBase, windowMask, (busAddr & windowMask),
259                    (windowBase & windowMask));
260        }
261    }
262#endif
263
264    for (int i = 0; i < 4; i++) {
265
266        windowBase = wsba[i];
267        windowMask = ~wsm[i] & (ULL(0xfff) << 20);
268
269        if ((busAddr & windowMask) == (windowBase & windowMask)) {
270
271            if (wsba[i] & 0x1) {   // see if enabled
272                if (wsba[i] & 0x2) { // see if SG bit is set
273                    /** @todo
274                        This currently is faked by just doing a direct
275                        read from memory, however, to be realistic, this
276                        needs to actually do a bus transaction.  The process
277                        is explained in the tsunami documentation on page
278                        10-12 and basically munges the address to look up a
279                        PTE from a table in memory and then uses that mapping
280                        to create an address for the SG page
281                    */
282
283                    tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff));
284                    baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13);
285                    pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10);
286
287                    pioPort->readBlob(pteAddr, (uint8_t*)&pteEntry, sizeof(uint64_t));
288
289                    dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff));
290
291                } else {
292                    baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff);
293                    tbaMask = ~baMask;
294                    dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask);
295                }
296
297                return (dmaAddr & DMA_ADDR_MASK);
298            }
299        }
300    }
301
302    // if no match was found, then return the original address
303    return busAddr;
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
315
316
317void
318TsunamiPChip::serialize(std::ostream &os)
319{
320    SERIALIZE_SCALAR(pctl);
321    SERIALIZE_ARRAY(wsba, 4);
322    SERIALIZE_ARRAY(wsm, 4);
323    SERIALIZE_ARRAY(tba, 4);
324}
325
326void
327TsunamiPChip::unserialize(Checkpoint *cp, const std::string &section)
328{
329    UNSERIALIZE_SCALAR(pctl);
330    UNSERIALIZE_ARRAY(wsba, 4);
331    UNSERIALIZE_ARRAY(wsm, 4);
332    UNSERIALIZE_ARRAY(tba, 4);
333}
334
335
336TsunamiPChip *
337TsunamiPChipParams::create()
338{
339    return new TsunamiPChip(this);
340}
341