pci.cc revision 11793
1955SN/A/*
2955SN/A * Copyright (c) 2014 ARM Limited
31762SN/A * All rights reserved
4955SN/A *
5955SN/A * The license below extends only to copyright in the software and shall
6955SN/A * not be construed as granting a license to any other intellectual
7955SN/A * property including but not limited to intellectual property relating
8955SN/A * to a hardware implementation of the functionality of the software
9955SN/A * licensed hereunder.  You may use the software subject to the license
10955SN/A * terms below provided that you ensure that this notice is replicated
11955SN/A * unmodified and in its entirety in all distributions of the software,
12955SN/A * modified or unmodified, in source code or in binary form.
13955SN/A *
14955SN/A * Redistribution and use in source and binary forms, with or without
15955SN/A * modification, are permitted provided that the following conditions are
16955SN/A * met: redistributions of source code must retain the above copyright
17955SN/A * notice, this list of conditions and the following disclaimer;
18955SN/A * redistributions in binary form must reproduce the above copyright
19955SN/A * notice, this list of conditions and the following disclaimer in the
20955SN/A * documentation and/or other materials provided with the distribution;
21955SN/A * neither the name of the copyright holders nor the names of its
22955SN/A * contributors may be used to endorse or promote products derived from
23955SN/A * this software without specific prior written permission.
24955SN/A *
25955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282665Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
294762Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
315522Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
324762Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
335522Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
355522Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36955SN/A *
375522Snate@binkert.org * Authors: Andreas Sandberg
384202Sbinkertn@umich.edu */
395742Snate@binkert.org
40955SN/A#include "dev/virtio/pci.hh"
414381Sbinkertn@umich.edu
424381Sbinkertn@umich.edu#include "debug/VIOPci.hh"
43955SN/A#include "mem/packet_access.hh"
44955SN/A#include "params/PciVirtIO.hh"
45955SN/A
464202Sbinkertn@umich.eduPciVirtIO::PciVirtIO(const Params *params)
47955SN/A    : PciDevice(params), queueNotify(0), interruptDeliveryPending(false),
484382Sbinkertn@umich.edu      vio(*params->vio), callbackKick(this)
494382Sbinkertn@umich.edu{
504382Sbinkertn@umich.edu    // Override the subsystem ID with the device ID from VirtIO
515863Snate@binkert.org    config.subsystemID = htole(vio.deviceId);
525517Snate@binkert.org    BARSize[0] = BAR0_SIZE_BASE + vio.configSize;
534762Snate@binkert.org
544762Snate@binkert.org    vio.registerKickCallback(&callbackKick);
554762Snate@binkert.org}
564762Snate@binkert.org
574762Snate@binkert.orgPciVirtIO::~PciVirtIO()
584762Snate@binkert.org{
594762Snate@binkert.org}
604762Snate@binkert.org
614762Snate@binkert.orgTick
624762Snate@binkert.orgPciVirtIO::read(PacketPtr pkt)
635522Snate@binkert.org{
645604Snate@binkert.org    const unsigned M5_VAR_USED size(pkt->getSize());
655604Snate@binkert.org    int bar;
665604Snate@binkert.org    Addr offset;
674762Snate@binkert.org    if (!getBAR(pkt->getAddr(), bar, offset))
684762Snate@binkert.org        panic("Invalid PCI memory access to unmapped memory.\n");
694762Snate@binkert.org    assert(bar == 0);
705522Snate@binkert.org
715522Snate@binkert.org    DPRINTF(VIOPci, "Reading offset 0x%x [len: %i]\n", offset, size);
725522Snate@binkert.org
735522Snate@binkert.org    // Forward device configuration writes to the device VirtIO model
745604Snate@binkert.org    if (offset >= OFF_VIO_DEVICE) {
755604Snate@binkert.org        vio.readConfig(pkt, offset - OFF_VIO_DEVICE);
764762Snate@binkert.org        return 0;
774762Snate@binkert.org    }
784762Snate@binkert.org
794762Snate@binkert.org    pkt->makeResponse();
805522Snate@binkert.org
814762Snate@binkert.org    switch(offset) {
824762Snate@binkert.org      case OFF_DEVICE_FEATURES:
835604Snate@binkert.org        DPRINTF(VIOPci, "   DEVICE_FEATURES request\n");
845604Snate@binkert.org        assert(size == sizeof(uint32_t));
855604Snate@binkert.org        pkt->set<uint32_t>(vio.deviceFeatures);
865604Snate@binkert.org        break;
875604Snate@binkert.org
885604Snate@binkert.org      case OFF_GUEST_FEATURES:
894762Snate@binkert.org        DPRINTF(VIOPci, "   GUEST_FEATURES request\n");
904762Snate@binkert.org        assert(size == sizeof(uint32_t));
914762Snate@binkert.org        pkt->set<uint32_t>(vio.getGuestFeatures());
924762Snate@binkert.org        break;
935604Snate@binkert.org
944762Snate@binkert.org      case OFF_QUEUE_ADDRESS:
955522Snate@binkert.org        DPRINTF(VIOPci, "   QUEUE_ADDRESS request\n");
965522Snate@binkert.org        assert(size == sizeof(uint32_t));
975522Snate@binkert.org        pkt->set<uint32_t>(vio.getQueueAddress());
984762Snate@binkert.org        break;
994382Sbinkertn@umich.edu
1004762Snate@binkert.org      case OFF_QUEUE_SIZE:
1014382Sbinkertn@umich.edu        DPRINTF(VIOPci, "   QUEUE_SIZE request\n");
1025522Snate@binkert.org        assert(size == sizeof(uint16_t));
1034381Sbinkertn@umich.edu        pkt->set<uint16_t>(vio.getQueueSize());
1045522Snate@binkert.org        break;
1054762Snate@binkert.org
1064762Snate@binkert.org      case OFF_QUEUE_SELECT:
1074762Snate@binkert.org        DPRINTF(VIOPci, "   QUEUE_SELECT\n");
1085522Snate@binkert.org        assert(size == sizeof(uint16_t));
1095522Snate@binkert.org        pkt->set<uint16_t>(vio.getQueueSelect());
1105522Snate@binkert.org        break;
1115522Snate@binkert.org
1125522Snate@binkert.org      case OFF_QUEUE_NOTIFY:
1135522Snate@binkert.org        DPRINTF(VIOPci, "   QUEUE_NOTIFY request\n");
1145522Snate@binkert.org        assert(size == sizeof(uint16_t));
1155522Snate@binkert.org        pkt->set<uint16_t>(queueNotify);
1165522Snate@binkert.org        break;
1174762Snate@binkert.org
1184762Snate@binkert.org      case OFF_DEVICE_STATUS:
1194762Snate@binkert.org        DPRINTF(VIOPci, "   DEVICE_STATUS request\n");
1204762Snate@binkert.org        assert(size == sizeof(uint8_t));
1214762Snate@binkert.org        pkt->set<uint8_t>(vio.getDeviceStatus());
1224762Snate@binkert.org        break;
1234762Snate@binkert.org
1244762Snate@binkert.org      case OFF_ISR_STATUS: {
1254762Snate@binkert.org          DPRINTF(VIOPci, "   ISR_STATUS\n");
1264762Snate@binkert.org          assert(size == sizeof(uint8_t));
1274762Snate@binkert.org          const uint8_t isr_status(interruptDeliveryPending ? 1 : 0);
1284762Snate@binkert.org          if (interruptDeliveryPending) {
1294762Snate@binkert.org              interruptDeliveryPending = false;
1304762Snate@binkert.org              intrClear();
1314762Snate@binkert.org          }
1324762Snate@binkert.org          pkt->set<uint8_t>(isr_status);
1334762Snate@binkert.org      } break;
1344762Snate@binkert.org
1354762Snate@binkert.org      default:
1364762Snate@binkert.org        panic("Unhandled read offset (0x%x)\n", offset);
1374762Snate@binkert.org    }
1384762Snate@binkert.org
1394762Snate@binkert.org    return 0;
1404762Snate@binkert.org}
1414762Snate@binkert.org
1424762Snate@binkert.orgTick
1434762Snate@binkert.orgPciVirtIO::write(PacketPtr pkt)
1444762Snate@binkert.org{
1454762Snate@binkert.org    const unsigned M5_VAR_USED size(pkt->getSize());
1464762Snate@binkert.org    int bar;
1474762Snate@binkert.org    Addr offset;
1484762Snate@binkert.org    if (!getBAR(pkt->getAddr(), bar, offset))
1494762Snate@binkert.org        panic("Invalid PCI memory access to unmapped memory.\n");
1504762Snate@binkert.org    assert(bar == 0);
1514762Snate@binkert.org
152955SN/A    DPRINTF(VIOPci, "Writing offset 0x%x [len: %i]\n", offset, size);
1535584Snate@binkert.org
1545584Snate@binkert.org    // Forward device configuration writes to the device VirtIO model
1555584Snate@binkert.org    if (offset >= OFF_VIO_DEVICE) {
1565584Snate@binkert.org        vio.writeConfig(pkt, offset - OFF_VIO_DEVICE);
1575584Snate@binkert.org        return 0;
1585584Snate@binkert.org    }
1595584Snate@binkert.org
1605584Snate@binkert.org    pkt->makeResponse();
1615584Snate@binkert.org
1625584Snate@binkert.org    switch(offset) {
1635584Snate@binkert.org      case OFF_DEVICE_FEATURES:
1645584Snate@binkert.org        warn("Guest tried to write device features.");
1655584Snate@binkert.org        break;
1664382Sbinkertn@umich.edu
1674202Sbinkertn@umich.edu      case OFF_GUEST_FEATURES:
1685522Snate@binkert.org        DPRINTF(VIOPci, "   WRITE GUEST_FEATURES request\n");
1694382Sbinkertn@umich.edu        assert(size == sizeof(uint32_t));
1704382Sbinkertn@umich.edu        vio.setGuestFeatures(pkt->get<uint32_t>());
1714382Sbinkertn@umich.edu        break;
1725584Snate@binkert.org
1734382Sbinkertn@umich.edu      case OFF_QUEUE_ADDRESS:
1744382Sbinkertn@umich.edu        DPRINTF(VIOPci, "   WRITE QUEUE_ADDRESS\n");
1754382Sbinkertn@umich.edu        assert(size == sizeof(uint32_t));
1765192Ssaidi@eecs.umich.edu        vio.setQueueAddress(pkt->get<uint32_t>());
1775192Ssaidi@eecs.umich.edu        break;
1785799Snate@binkert.org
1795799Snate@binkert.org      case OFF_QUEUE_SIZE:
1805799Snate@binkert.org        panic("Guest tried to write queue size.");
1815192Ssaidi@eecs.umich.edu        break;
1825799Snate@binkert.org
1835192Ssaidi@eecs.umich.edu      case OFF_QUEUE_SELECT:
1845799Snate@binkert.org        DPRINTF(VIOPci, "   WRITE QUEUE_SELECT\n");
1855799Snate@binkert.org        assert(size == sizeof(uint16_t));
1865192Ssaidi@eecs.umich.edu        vio.setQueueSelect(pkt->get<uint16_t>());
1875192Ssaidi@eecs.umich.edu        break;
1885192Ssaidi@eecs.umich.edu
1895192Ssaidi@eecs.umich.edu      case OFF_QUEUE_NOTIFY:
1905799Snate@binkert.org        DPRINTF(VIOPci, "   WRITE QUEUE_NOTIFY\n");
1915192Ssaidi@eecs.umich.edu        assert(size == sizeof(uint16_t));
1925799Snate@binkert.org        queueNotify = pkt->get<uint16_t>();
1935192Ssaidi@eecs.umich.edu        vio.onNotify(queueNotify);
1945192Ssaidi@eecs.umich.edu        break;
1955192Ssaidi@eecs.umich.edu
1965799Snate@binkert.org      case OFF_DEVICE_STATUS: {
1975192Ssaidi@eecs.umich.edu          assert(size == sizeof(uint8_t));
1985192Ssaidi@eecs.umich.edu          uint8_t status(pkt->get<uint8_t>());
1995192Ssaidi@eecs.umich.edu          DPRINTF(VIOPci, "VirtIO set status: 0x%x\n", status);
2005192Ssaidi@eecs.umich.edu          vio.setDeviceStatus(status);
2015192Ssaidi@eecs.umich.edu      } break;
2025192Ssaidi@eecs.umich.edu
2034382Sbinkertn@umich.edu      case OFF_ISR_STATUS:
2044382Sbinkertn@umich.edu        warn("Guest tried to write ISR status.");
2054382Sbinkertn@umich.edu        break;
2062667Sstever@eecs.umich.edu
2072667Sstever@eecs.umich.edu      default:
2082667Sstever@eecs.umich.edu        panic("Unhandled read offset (0x%x)\n", offset);
2092667Sstever@eecs.umich.edu    }
2102667Sstever@eecs.umich.edu
2112667Sstever@eecs.umich.edu    return 0;
2125742Snate@binkert.org}
2135742Snate@binkert.org
2145742Snate@binkert.orgvoid
2152037SN/APciVirtIO::kick()
2162037SN/A{
2172037SN/A    DPRINTF(VIOPci, "kick(): Sending interrupt...\n");
2185793Snate@binkert.org    interruptDeliveryPending = true;
2195793Snate@binkert.org    intrPost();
2205793Snate@binkert.org}
2215793Snate@binkert.org
2225793Snate@binkert.orgPciVirtIO *
2234382Sbinkertn@umich.eduPciVirtIOParams::create()
2244762Snate@binkert.org{
2255344Sstever@gmail.com    return new PciVirtIO(this);
2264382Sbinkertn@umich.edu}
2275341Sstever@gmail.com