tsunami_pchip.cc revision 9808:13ffc0066b76
11689SN/A/*
21689SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
39915Ssteve.reinhardt@amd.com * All rights reserved.
41689SN/A *
51689SN/A * Redistribution and use in source and binary forms, with or without
61689SN/A * modification, are permitted provided that the following conditions are
71689SN/A * met: redistributions of source code must retain the above copyright
81689SN/A * notice, this list of conditions and the following disclaimer;
91689SN/A * redistributions in binary form must reproduce the above copyright
101689SN/A * notice, this list of conditions and the following disclaimer in the
111689SN/A * documentation and/or other materials provided with the distribution;
121689SN/A * neither the name of the copyright holders nor the names of its
131689SN/A * contributors may be used to endorse or promote products derived from
141689SN/A * this software without specific prior written permission.
151689SN/A *
161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271689SN/A *
282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi
292665Ssaidi@eecs.umich.edu *          Andrew Schultz
302665Ssaidi@eecs.umich.edu */
311689SN/A
321689SN/A/** @file
332292SN/A * Tsunami PChip (pci)
342292SN/A */
351060SN/A
366658Snate@binkert.org#include <deque>
376658Snate@binkert.org#include <string>
382165SN/A#include <vector>
398793Sgblack@eecs.umich.edu
402669Sktlim@umich.edu#include "base/trace.hh"
411681SN/A#include "config/the_isa.hh"
426658Snate@binkert.org#include "debug/Tsunami.hh"
431717SN/A#include "dev/alpha/tsunami.hh"
448232Snate@binkert.org#include "dev/alpha/tsunami_pchip.hh"
451060SN/A#include "dev/alpha/tsunamireg.h"
469919Ssteve.reinhardt@amd.com#include "mem/packet.hh"
479919Ssteve.reinhardt@amd.com#include "mem/packet_access.hh"
482292SN/A#include "sim/system.hh"
492292SN/A
502292SN/Ausing namespace std;
511060SN/A//Should this be AlphaISA?
521060SN/Ausing namespace TheISA;
539915Ssteve.reinhardt@amd.com
549915Ssteve.reinhardt@amd.comTsunamiPChip::TsunamiPChip(const Params *p)
552107SN/A    : BasicPioDevice(p, 0x1000)
562107SN/A{
572669Sktlim@umich.edu    for (int i = 0; i < 4; i++) {
582159SN/A        wsba[i] = 0;
592669Sktlim@umich.edu        wsm[i] = 0;
602669Sktlim@umich.edu        tba[i] = 0;
612669Sktlim@umich.edu    }
622669Sktlim@umich.edu
631060SN/A    // initialize pchip control register
649915Ssteve.reinhardt@amd.com    pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36);
659919Ssteve.reinhardt@amd.com
661060SN/A    //Set back pointer in tsunami
679915Ssteve.reinhardt@amd.com    p->tsunami->pchip = this;
689919Ssteve.reinhardt@amd.com}
699915Ssteve.reinhardt@amd.com
709915Ssteve.reinhardt@amd.comTick
719915Ssteve.reinhardt@amd.comTsunamiPChip::read(PacketPtr pkt)
729915Ssteve.reinhardt@amd.com{
739915Ssteve.reinhardt@amd.com    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
749915Ssteve.reinhardt@amd.com
759915Ssteve.reinhardt@amd.com    pkt->allocate();
769915Ssteve.reinhardt@amd.com    Addr daddr = (pkt->getAddr() - pioAddr) >> 6;;
779919Ssteve.reinhardt@amd.com    assert(pkt->getSize() == sizeof(uint64_t));
789919Ssteve.reinhardt@amd.com
799919Ssteve.reinhardt@amd.com
809919Ssteve.reinhardt@amd.com    DPRINTF(Tsunami, "read  va=%#x size=%d\n", pkt->getAddr(), pkt->getSize());
819919Ssteve.reinhardt@amd.com
829919Ssteve.reinhardt@amd.com    switch(daddr) {
839915Ssteve.reinhardt@amd.com      case TSDEV_PC_WSBA0:
849915Ssteve.reinhardt@amd.com            pkt->set(wsba[0]);
859915Ssteve.reinhardt@amd.com            break;
869915Ssteve.reinhardt@amd.com      case TSDEV_PC_WSBA1:
879915Ssteve.reinhardt@amd.com            pkt->set(wsba[1]);
889915Ssteve.reinhardt@amd.com            break;
891060SN/A      case TSDEV_PC_WSBA2:
902292SN/A            pkt->set(wsba[2]);
912292SN/A            break;
922292SN/A      case TSDEV_PC_WSBA3:
932292SN/A            pkt->set(wsba[3]);
949915Ssteve.reinhardt@amd.com            break;
951060SN/A      case TSDEV_PC_WSM0:
961060SN/A            pkt->set(wsm[0]);
979086Sandreas.hansson@arm.com            break;
989086Sandreas.hansson@arm.com      case TSDEV_PC_WSM1:
999086Sandreas.hansson@arm.com            pkt->set(wsm[1]);
1009919Ssteve.reinhardt@amd.com            break;
1019919Ssteve.reinhardt@amd.com      case TSDEV_PC_WSM2:
1029919Ssteve.reinhardt@amd.com            pkt->set(wsm[2]);
1039919Ssteve.reinhardt@amd.com            break;
1049086Sandreas.hansson@arm.com      case TSDEV_PC_WSM3:
1059915Ssteve.reinhardt@amd.com            pkt->set(wsm[3]);
1069915Ssteve.reinhardt@amd.com            break;
1079915Ssteve.reinhardt@amd.com      case TSDEV_PC_TBA0:
1089915Ssteve.reinhardt@amd.com            pkt->set(tba[0]);
1099915Ssteve.reinhardt@amd.com            break;
1109915Ssteve.reinhardt@amd.com      case TSDEV_PC_TBA1:
1119915Ssteve.reinhardt@amd.com            pkt->set(tba[1]);
1129915Ssteve.reinhardt@amd.com            break;
1139915Ssteve.reinhardt@amd.com      case TSDEV_PC_TBA2:
1149915Ssteve.reinhardt@amd.com            pkt->set(tba[2]);
1159915Ssteve.reinhardt@amd.com            break;
1169915Ssteve.reinhardt@amd.com      case TSDEV_PC_TBA3:
1179915Ssteve.reinhardt@amd.com            pkt->set(tba[3]);
1189915Ssteve.reinhardt@amd.com            break;
1199915Ssteve.reinhardt@amd.com      case TSDEV_PC_PCTL:
1209915Ssteve.reinhardt@amd.com            pkt->set(pctl);
1219915Ssteve.reinhardt@amd.com            break;
1229915Ssteve.reinhardt@amd.com      case TSDEV_PC_PLAT:
1239915Ssteve.reinhardt@amd.com            panic("PC_PLAT not implemented\n");
1249915Ssteve.reinhardt@amd.com      case TSDEV_PC_RES:
1259915Ssteve.reinhardt@amd.com            panic("PC_RES not implemented\n");
1269915Ssteve.reinhardt@amd.com      case TSDEV_PC_PERROR:
1279915Ssteve.reinhardt@amd.com            pkt->set((uint64_t)0x00);
1289915Ssteve.reinhardt@amd.com            break;
1299915Ssteve.reinhardt@amd.com      case TSDEV_PC_PERRMASK:
1309915Ssteve.reinhardt@amd.com            pkt->set((uint64_t)0x00);
1319915Ssteve.reinhardt@amd.com            break;
1321060SN/A      case TSDEV_PC_PERRSET:
1332292SN/A            panic("PC_PERRSET not implemented\n");
1349915Ssteve.reinhardt@amd.com      case TSDEV_PC_TLBIV:
1351060SN/A            panic("PC_TLBIV not implemented\n");
1369915Ssteve.reinhardt@amd.com      case TSDEV_PC_TLBIA:
1371061SN/A            pkt->set((uint64_t)0x00); // shouldn't be readable, but linux
1381060SN/A            break;
1392690Sktlim@umich.edu      case TSDEV_PC_PMONCTL:
1401060SN/A            panic("PC_PMONCTL not implemented\n");
1411060SN/A      case TSDEV_PC_PMONCNT:
1421060SN/A            panic("PC_PMONCTN not implemented\n");
1432292SN/A      default:
1449915Ssteve.reinhardt@amd.com          panic("Default in PChip Read reached reading 0x%x\n", daddr);
1451060SN/A    }
1469915Ssteve.reinhardt@amd.com    pkt->makeAtomicResponse();
1479915Ssteve.reinhardt@amd.com    return pioDelay;
1481060SN/A
1499915Ssteve.reinhardt@amd.com}
1501060SN/A
1512455SN/ATick
1529915Ssteve.reinhardt@amd.comTsunamiPChip::write(PacketPtr pkt)
1532455SN/A{
1549915Ssteve.reinhardt@amd.com    assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
1551060SN/A    Addr daddr = (pkt->getAddr() - pioAddr) >> 6;
1561060SN/A
1579915Ssteve.reinhardt@amd.com    assert(pkt->getSize() == sizeof(uint64_t));
1582455SN/A
1599915Ssteve.reinhardt@amd.com    DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->getAddr(), pkt->getSize());
1609915Ssteve.reinhardt@amd.com
1612455SN/A    switch(daddr) {
1629915Ssteve.reinhardt@amd.com        case TSDEV_PC_WSBA0:
1632455SN/A              wsba[0] = pkt->get<uint64_t>();
1649915Ssteve.reinhardt@amd.com              break;
1652455SN/A        case TSDEV_PC_WSBA1:
1662455SN/A              wsba[1] = pkt->get<uint64_t>();
1672690Sktlim@umich.edu              break;
1682455SN/A        case TSDEV_PC_WSBA2:
1692455SN/A              wsba[2] = pkt->get<uint64_t>();
1701060SN/A              break;
1711060SN/A        case TSDEV_PC_WSBA3:
1722292SN/A              wsba[3] = pkt->get<uint64_t>();
1731060SN/A              break;
1741060SN/A        case TSDEV_PC_WSM0:
1759915Ssteve.reinhardt@amd.com              wsm[0] = pkt->get<uint64_t>();
1761061SN/A              break;
1772690Sktlim@umich.edu        case TSDEV_PC_WSM1:
1781060SN/A              wsm[1] = pkt->get<uint64_t>();
1791060SN/A              break;
1802292SN/A        case TSDEV_PC_WSM2:
1812292SN/A              wsm[2] = pkt->get<uint64_t>();
1821060SN/A              break;
1831060SN/A        case TSDEV_PC_WSM3:
1842292SN/A              wsm[3] = pkt->get<uint64_t>();
1852455SN/A              break;
1861060SN/A        case TSDEV_PC_TBA0:
1879915Ssteve.reinhardt@amd.com              tba[0] = pkt->get<uint64_t>();
1889915Ssteve.reinhardt@amd.com              break;
1891060SN/A        case TSDEV_PC_TBA1:
1909915Ssteve.reinhardt@amd.com              tba[1] = pkt->get<uint64_t>();
1911061SN/A              break;
1922690Sktlim@umich.edu        case TSDEV_PC_TBA2:
1932690Sktlim@umich.edu              tba[2] = pkt->get<uint64_t>();
1941060SN/A              break;
1954642Sgblack@eecs.umich.edu        case TSDEV_PC_TBA3:
1969915Ssteve.reinhardt@amd.com              tba[3] = pkt->get<uint64_t>();
1974642Sgblack@eecs.umich.edu              break;
1989915Ssteve.reinhardt@amd.com        case TSDEV_PC_PCTL:
1991060SN/A              pctl = pkt->get<uint64_t>();
2001060SN/A              break;
2012455SN/A        case TSDEV_PC_PLAT:
2022455SN/A              panic("PC_PLAT not implemented\n");
2039915Ssteve.reinhardt@amd.com        case TSDEV_PC_RES:
2049915Ssteve.reinhardt@amd.com              panic("PC_RES not implemented\n");
2052455SN/A        case TSDEV_PC_PERROR:
2069915Ssteve.reinhardt@amd.com              break;
2072455SN/A        case TSDEV_PC_PERRMASK:
2082690Sktlim@umich.edu              panic("PC_PERRMASK not implemented\n");
2092455SN/A        case TSDEV_PC_PERRSET:
2102455SN/A              panic("PC_PERRSET not implemented\n");
2119915Ssteve.reinhardt@amd.com        case TSDEV_PC_TLBIV:
2121060SN/A              panic("PC_TLBIV not implemented\n");
2131060SN/A        case TSDEV_PC_TLBIA:
2141060SN/A              break; // value ignored, supposted to invalidate SG TLB
2151060SN/A        case TSDEV_PC_PMONCTL:
2169915Ssteve.reinhardt@amd.com              panic("PC_PMONCTL not implemented\n");
2179915Ssteve.reinhardt@amd.com        case TSDEV_PC_PMONCNT:
218              panic("PC_PMONCTN not implemented\n");
219        default:
220            panic("Default in PChip write reached reading 0x%x\n", daddr);
221
222    } // uint64_t
223
224    pkt->makeAtomicResponse();
225    return pioDelay;
226}
227
228#define DMA_ADDR_MASK ULL(0x3ffffffff)
229
230Addr
231TsunamiPChip::translatePciToDma(Addr busAddr)
232{
233    // compare the address to the window base registers
234    uint64_t tbaMask = 0;
235    uint64_t baMask = 0;
236
237    uint64_t windowMask = 0;
238    uint64_t windowBase = 0;
239
240    uint64_t pteEntry = 0;
241
242    Addr pteAddr;
243    Addr dmaAddr;
244
245#if 0
246    DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr);
247    for (int i = 0; i < 4; i++) {
248        DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n",
249                i, wsba[i], wsm[i]);
250
251        windowBase = wsba[i];
252        windowMask = ~wsm[i] & (ULL(0xfff) << 20);
253
254        if ((busAddr & windowMask) == (windowBase & windowMask)) {
255            DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n",
256                    i, windowBase, windowMask, (busAddr & windowMask),
257                    (windowBase & windowMask));
258        }
259    }
260#endif
261
262    for (int i = 0; i < 4; i++) {
263
264        windowBase = wsba[i];
265        windowMask = ~wsm[i] & (ULL(0xfff) << 20);
266
267        if ((busAddr & windowMask) == (windowBase & windowMask)) {
268
269            if (wsba[i] & 0x1) {   // see if enabled
270                if (wsba[i] & 0x2) { // see if SG bit is set
271                    /** @todo
272                        This currently is faked by just doing a direct
273                        read from memory, however, to be realistic, this
274                        needs to actually do a bus transaction.  The process
275                        is explained in the tsunami documentation on page
276                        10-12 and basically munges the address to look up a
277                        PTE from a table in memory and then uses that mapping
278                        to create an address for the SG page
279                    */
280
281                    tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff));
282                    baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13);
283                    pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10);
284
285                    sys->physProxy.readBlob(pteAddr, (uint8_t*)&pteEntry,
286                                            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