tsunami_pchip.cc revision 909
19665Sandreas.hansson@arm.com/*
29520SN/A * Copyright (c) 2004 The Regents of The University of Michigan
39520SN/A * All rights reserved.
49520SN/A *
59520SN/A * Redistribution and use in source and binary forms, with or without
69520SN/A * modification, are permitted provided that the following conditions are
79520SN/A * met: redistributions of source code must retain the above copyright
89520SN/A * notice, this list of conditions and the following disclaimer;
99520SN/A * redistributions in binary form must reproduce the above copyright
109520SN/A * notice, this list of conditions and the following disclaimer in the
119520SN/A * documentation and/or other materials provided with the distribution;
129520SN/A * neither the name of the copyright holders nor the names of its
139520SN/A * contributors may be used to endorse or promote products derived from
149520SN/A * this software without specific prior written permission.
159520SN/A *
169520SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
179520SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
189520SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
199520SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
209520SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
219520SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
229520SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239520SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249520SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259520SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
269520SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279520SN/A */
289520SN/A
299520SN/A/* @file
309520SN/A * Tsunami PChip (pci)
319520SN/A */
329520SN/A
339520SN/A#include <deque>
349520SN/A#include <string>
359520SN/A#include <vector>
369520SN/A
379665Sandreas.hansson@arm.com#include "base/trace.hh"
389520SN/A#include "dev/tsunami_pchip.hh"
399520SN/A#include "dev/tsunamireg.h"
409520SN/A#include "dev/tsunami.hh"
419520SN/A#include "mem/bus/bus.hh"
429520SN/A#include "mem/bus/pio_interface.hh"
439520SN/A#include "mem/bus/pio_interface_impl.hh"
449665Sandreas.hansson@arm.com#include "mem/functional_mem/memory_control.hh"
459665Sandreas.hansson@arm.com#include "mem/functional_mem/physical_memory.hh"
469665Sandreas.hansson@arm.com#include "sim/builder.hh"
479520SN/A#include "sim/system.hh"
489665Sandreas.hansson@arm.com
499665Sandreas.hansson@arm.comusing namespace std;
509520SN/A
519520SN/ATsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a,
529520SN/A                           MemoryController *mmu, HierParams *hier,
539520SN/A                           Bus *bus)
549665Sandreas.hansson@arm.com    : PioDevice(name), addr(a), tsunami(t)
559665Sandreas.hansson@arm.com{
569520SN/A    mmu->add_child(this, Range<Addr>(addr, addr + size));
579520SN/A
589520SN/A    for (int i = 0; i < 4; i++) {
599520SN/A        wsba[i] = 0;
6010789Sandreas.hansson@arm.com        wsm[i] = 0;
619520SN/A        tba[i] = 0;
629520SN/A    }
6310789Sandreas.hansson@arm.com
649665Sandreas.hansson@arm.com    if (bus) {
659520SN/A        pioInterface = newPioInterface(name, hier, bus, this,
669665Sandreas.hansson@arm.com                                      &TsunamiPChip::cacheAccess);
679520SN/A        pioInterface->addAddrRange(addr, addr + size - 1);
689520SN/A    }
699665Sandreas.hansson@arm.com
7010789Sandreas.hansson@arm.com
719520SN/A    // initialize pchip control register
729665Sandreas.hansson@arm.com    pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36);
739520SN/A
749665Sandreas.hansson@arm.com    //Set back pointer in tsunami
759520SN/A    tsunami->pchip = this;
769520SN/A}
779520SN/A
789520SN/AFault
799520SN/ATsunamiPChip::read(MemReqPtr &req, uint8_t *data)
809520SN/A{
819520SN/A    DPRINTF(Tsunami, "read  va=%#x size=%d\n",
829520SN/A            req->vaddr, req->size);
839520SN/A
849665Sandreas.hansson@arm.com    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
859665Sandreas.hansson@arm.com
8610789Sandreas.hansson@arm.com    switch (req->size) {
879520SN/A
889665Sandreas.hansson@arm.com      case sizeof(uint64_t):
899665Sandreas.hansson@arm.com          switch(daddr) {
909665Sandreas.hansson@arm.com              case TSDEV_PC_WSBA0:
919520SN/A                    *(uint64_t*)data = wsba[0];
9210675Sandreas.hansson@arm.com                    return No_Fault;
9310442Snilay@cs.wisc.edu              case TSDEV_PC_WSBA1:
9410442Snilay@cs.wisc.edu                    *(uint64_t*)data = wsba[1];
9510442Snilay@cs.wisc.edu                    return No_Fault;
9610442Snilay@cs.wisc.edu              case TSDEV_PC_WSBA2:
9710442Snilay@cs.wisc.edu                    *(uint64_t*)data = wsba[2];
9810442Snilay@cs.wisc.edu                    return No_Fault;
9910442Snilay@cs.wisc.edu              case TSDEV_PC_WSBA3:
10010675Sandreas.hansson@arm.com                    *(uint64_t*)data = wsba[3];
10110442Snilay@cs.wisc.edu                    return No_Fault;
10210677Sandreas.hansson@arm.com              case TSDEV_PC_WSM0:
10310677Sandreas.hansson@arm.com                    *(uint64_t*)data = wsm[0];
10410677Sandreas.hansson@arm.com                    return No_Fault;
10510677Sandreas.hansson@arm.com              case TSDEV_PC_WSM1:
10610677Sandreas.hansson@arm.com                    *(uint64_t*)data = wsm[1];
10710677Sandreas.hansson@arm.com                    return No_Fault;
10810677Sandreas.hansson@arm.com              case TSDEV_PC_WSM2:
10910442Snilay@cs.wisc.edu                    *(uint64_t*)data = wsm[2];
11010442Snilay@cs.wisc.edu                    return No_Fault;
11110442Snilay@cs.wisc.edu              case TSDEV_PC_WSM3:
11210442Snilay@cs.wisc.edu                    *(uint64_t*)data = wsm[3];
11310442Snilay@cs.wisc.edu                    return No_Fault;
11410442Snilay@cs.wisc.edu              case TSDEV_PC_TBA0:
11510442Snilay@cs.wisc.edu                    *(uint64_t*)data = tba[0];
11610442Snilay@cs.wisc.edu                    return No_Fault;
11710442Snilay@cs.wisc.edu              case TSDEV_PC_TBA1:
11810442Snilay@cs.wisc.edu                    *(uint64_t*)data = tba[1];
11910442Snilay@cs.wisc.edu                    return No_Fault;
12010442Snilay@cs.wisc.edu              case TSDEV_PC_TBA2:
12110442Snilay@cs.wisc.edu                    *(uint64_t*)data = tba[2];
12210442Snilay@cs.wisc.edu                    return No_Fault;
12310442Snilay@cs.wisc.edu              case TSDEV_PC_TBA3:
12410442Snilay@cs.wisc.edu                    *(uint64_t*)data = tba[3];
12510442Snilay@cs.wisc.edu                    return No_Fault;
12610442Snilay@cs.wisc.edu              case TSDEV_PC_PCTL:
12710442Snilay@cs.wisc.edu                    *(uint64_t*)data = pctl;
12810442Snilay@cs.wisc.edu                    return No_Fault;
12910442Snilay@cs.wisc.edu              case TSDEV_PC_PLAT:
13010675Sandreas.hansson@arm.com                    panic("PC_PLAT not implemented\n");
13110442Snilay@cs.wisc.edu              case TSDEV_PC_RES:
13210442Snilay@cs.wisc.edu                    panic("PC_RES not implemented\n");
13310442Snilay@cs.wisc.edu              case TSDEV_PC_PERROR:
13410442Snilay@cs.wisc.edu                    *(uint64_t*)data = 0x00;
13510442Snilay@cs.wisc.edu                    return No_Fault;
13610675Sandreas.hansson@arm.com              case TSDEV_PC_PERRMASK:
13710677Sandreas.hansson@arm.com                    *(uint64_t*)data = 0x00;
13810677Sandreas.hansson@arm.com                    return No_Fault;
13910442Snilay@cs.wisc.edu              case TSDEV_PC_PERRSET:
14010442Snilay@cs.wisc.edu                    panic("PC_PERRSET not implemented\n");
14110442Snilay@cs.wisc.edu              case TSDEV_PC_TLBIV:
14210442Snilay@cs.wisc.edu                    panic("PC_TLBIV not implemented\n");
1439836Sandreas.hansson@arm.com              case TSDEV_PC_TLBIA:
1449836Sandreas.hansson@arm.com                    *(uint64_t*)data = 0x00; // shouldn't be readable, but linux
1459836Sandreas.hansson@arm.com                    return No_Fault;
1469836Sandreas.hansson@arm.com              case TSDEV_PC_PMONCTL:
1479836Sandreas.hansson@arm.com                    panic("PC_PMONCTL not implemented\n");
1489836Sandreas.hansson@arm.com              case TSDEV_PC_PMONCNT:
1499836Sandreas.hansson@arm.com                    panic("PC_PMONCTN not implemented\n");
1509836Sandreas.hansson@arm.com              default:
1519836Sandreas.hansson@arm.com                  panic("Default in PChip Read reached reading 0x%x\n", daddr);
1529836Sandreas.hansson@arm.com
1539836Sandreas.hansson@arm.com           } // uint64_t
15410780SCurtis.Dunham@arm.com
15510780SCurtis.Dunham@arm.com      break;
15610780SCurtis.Dunham@arm.com      case sizeof(uint32_t):
15710780SCurtis.Dunham@arm.com      case sizeof(uint16_t):
15810780SCurtis.Dunham@arm.com      case sizeof(uint8_t):
15910780SCurtis.Dunham@arm.com      default:
16010780SCurtis.Dunham@arm.com        panic("invalid access size(?) for tsunami register!\n\n");
16110780SCurtis.Dunham@arm.com    }
1629836Sandreas.hansson@arm.com    DPRINTFN("Tsunami PChip ERROR: read  daddr=%#x size=%d\n", daddr, req->size);
1639836Sandreas.hansson@arm.com
1649836Sandreas.hansson@arm.com    return No_Fault;
1659836Sandreas.hansson@arm.com}
1669836Sandreas.hansson@arm.com
1679836Sandreas.hansson@arm.comFault
16810442Snilay@cs.wisc.eduTsunamiPChip::write(MemReqPtr &req, const uint8_t *data)
1699836Sandreas.hansson@arm.com{
1709836Sandreas.hansson@arm.com    DPRINTF(Tsunami, "write - va=%#x size=%d \n",
1719836Sandreas.hansson@arm.com            req->vaddr, req->size);
17210675Sandreas.hansson@arm.com
17310675Sandreas.hansson@arm.com    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
17410675Sandreas.hansson@arm.com
17510675Sandreas.hansson@arm.com    switch (req->size) {
17610675Sandreas.hansson@arm.com
17710675Sandreas.hansson@arm.com      case sizeof(uint64_t):
1789836Sandreas.hansson@arm.com          switch(daddr) {
1799836Sandreas.hansson@arm.com              case TSDEV_PC_WSBA0:
1809836Sandreas.hansson@arm.com                    wsba[0] = *(uint64_t*)data;
1819836Sandreas.hansson@arm.com                    return No_Fault;
1829836Sandreas.hansson@arm.com              case TSDEV_PC_WSBA1:
18310620Sandreas.hansson@arm.com                    wsba[1] = *(uint64_t*)data;
18410675Sandreas.hansson@arm.com                    return No_Fault;
18510620Sandreas.hansson@arm.com              case TSDEV_PC_WSBA2:
18610620Sandreas.hansson@arm.com                    wsba[2] = *(uint64_t*)data;
18710620Sandreas.hansson@arm.com                    return No_Fault;
18810620Sandreas.hansson@arm.com              case TSDEV_PC_WSBA3:
18910620Sandreas.hansson@arm.com                    wsba[3] = *(uint64_t*)data;
19010620Sandreas.hansson@arm.com                    return No_Fault;
19110620Sandreas.hansson@arm.com              case TSDEV_PC_WSM0:
1929836Sandreas.hansson@arm.com                    wsm[0] = *(uint64_t*)data;
1939836Sandreas.hansson@arm.com                    return No_Fault;
1949836Sandreas.hansson@arm.com              case TSDEV_PC_WSM1:
1959836Sandreas.hansson@arm.com                    wsm[1] = *(uint64_t*)data;
19610041Snilay@cs.wisc.edu                    return No_Fault;
1979836Sandreas.hansson@arm.com              case TSDEV_PC_WSM2:
198                    wsm[2] = *(uint64_t*)data;
199                    return No_Fault;
200              case TSDEV_PC_WSM3:
201                    wsm[3] = *(uint64_t*)data;
202                    return No_Fault;
203              case TSDEV_PC_TBA0:
204                    tba[0] = *(uint64_t*)data;
205                    return No_Fault;
206              case TSDEV_PC_TBA1:
207                    tba[1] = *(uint64_t*)data;
208                    return No_Fault;
209              case TSDEV_PC_TBA2:
210                    tba[2] = *(uint64_t*)data;
211                    return No_Fault;
212              case TSDEV_PC_TBA3:
213                    tba[3] = *(uint64_t*)data;
214                    return No_Fault;
215              case TSDEV_PC_PCTL:
216                    pctl = *(uint64_t*)data;
217                    return No_Fault;
218              case TSDEV_PC_PLAT:
219                    panic("PC_PLAT not implemented\n");
220              case TSDEV_PC_RES:
221                    panic("PC_RES not implemented\n");
222              case TSDEV_PC_PERROR:
223                    return No_Fault;
224              case TSDEV_PC_PERRMASK:
225                    panic("PC_PERRMASK not implemented\n");
226              case TSDEV_PC_PERRSET:
227                    panic("PC_PERRSET not implemented\n");
228              case TSDEV_PC_TLBIV:
229                    panic("PC_TLBIV not implemented\n");
230              case TSDEV_PC_TLBIA:
231                    return No_Fault; // value ignored, supposted to invalidate SG TLB
232              case TSDEV_PC_PMONCTL:
233                    panic("PC_PMONCTL not implemented\n");
234              case TSDEV_PC_PMONCNT:
235                    panic("PC_PMONCTN not implemented\n");
236              default:
237                  panic("Default in PChip Read reached reading 0x%x\n", daddr);
238
239           } // uint64_t
240
241      break;
242      case sizeof(uint32_t):
243      case sizeof(uint16_t):
244      case sizeof(uint8_t):
245      default:
246        panic("invalid access size(?) for tsunami register!\n\n");
247    }
248
249    DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size);
250
251    return No_Fault;
252}
253
254#define DMA_ADDR_MASK ULL(0x3ffffffff)
255
256Addr
257TsunamiPChip::translatePciToDma(Addr busAddr)
258{
259    // compare the address to the window base registers
260    uint64_t tbaMask = 0;
261    uint64_t baMask = 0;
262
263    uint64_t windowMask = 0;
264    uint64_t windowBase = 0;
265
266    uint64_t pteEntry = 0;
267
268    Addr pteAddr;
269    Addr dmaAddr;
270
271#if 0
272    DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr);
273    for (int i = 0; i < 4; i++) {
274        DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n",
275                i, wsba[i], wsm[i]);
276
277        windowBase = wsba[i];
278        windowMask = ~wsm[i] & (ULL(0xfff) << 20);
279
280        if ((busAddr & windowMask) == (windowBase & windowMask)) {
281            DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n",
282                    i, windowBase, windowMask, (busAddr & windowMask),
283                    (windowBase & windowMask));
284        }
285    }
286#endif
287
288    for (int i = 0; i < 4; i++) {
289
290        windowBase = wsba[i];
291        windowMask = ~wsm[i] & (ULL(0xfff) << 20);
292
293        if ((busAddr & windowMask) == (windowBase & windowMask)) {
294
295            if (wsba[i] & 0x1) {   // see if enabled
296                if (wsba[i] & 0x2) { // see if SG bit is set
297                    /** @todo
298                        This currently is faked by just doing a direct
299                        read from memory, however, to be realistic, this
300                        needs to actually do a bus transaction.  The process
301                        is explained in the tsunami documentation on page
302                        10-12 and basically munges the address to look up a
303                        PTE from a table in memory and then uses that mapping
304                        to create an address for the SG page
305                    */
306
307                    tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff));
308                    baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13);
309                    pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10);
310
311                    memcpy((void *)&pteEntry,
312                           tsunami->system->
313                           physmem->dma_addr(pteAddr, sizeof(uint64_t)),
314                           sizeof(uint64_t));
315
316                    dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff));
317
318                } else {
319                    baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff);
320                    tbaMask = ~baMask;
321                    dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask);
322                }
323
324                return (dmaAddr & DMA_ADDR_MASK);
325            }
326        }
327    }
328
329    // if no match was found, then return the original address
330    return busAddr;
331}
332
333void
334TsunamiPChip::serialize(std::ostream &os)
335{
336    SERIALIZE_SCALAR(pctl);
337    SERIALIZE_ARRAY(wsba, 4);
338    SERIALIZE_ARRAY(wsm, 4);
339    SERIALIZE_ARRAY(tba, 4);
340}
341
342void
343TsunamiPChip::unserialize(Checkpoint *cp, const std::string &section)
344{
345    UNSERIALIZE_SCALAR(pctl);
346    UNSERIALIZE_ARRAY(wsba, 4);
347    UNSERIALIZE_ARRAY(wsm, 4);
348    UNSERIALIZE_ARRAY(tba, 4);
349}
350
351Tick
352TsunamiPChip::cacheAccess(MemReqPtr &req)
353{
354    return curTick + 1000;
355}
356
357BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
358
359    SimObjectParam<Tsunami *> tsunami;
360    SimObjectParam<MemoryController *> mmu;
361    Param<Addr> addr;
362    SimObjectParam<Bus*> io_bus;
363    SimObjectParam<HierParams *> hier;
364
365END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
366
367BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
368
369    INIT_PARAM(tsunami, "Tsunami"),
370    INIT_PARAM(mmu, "Memory Controller"),
371    INIT_PARAM(addr, "Device Address"),
372    INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
373    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
374
375END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
376
377CREATE_SIM_OBJECT(TsunamiPChip)
378{
379    return new TsunamiPChip(getInstanceName(), tsunami, addr, mmu, hier, io_bus);
380}
381
382REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip)
383