1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#pragma once
6
7#include "backend.h"
8#include <zircon/thread_annotations.h>
9
10namespace virtio {
11
12class PciBackend : public Backend {
13public:
14    PciBackend(pci_protocol_t pci, zx_pcie_device_info_t info);
15    zx_status_t Bind() override;
16    virtual zx_status_t Init() = 0;
17    const char* tag() { return tag_; }
18
19    zx_status_t InterruptValid() override;
20    zx_status_t WaitForInterrupt() override;
21
22protected:
23    pci_protocol_t pci_ = {nullptr, nullptr};
24    zx_pcie_device_info_t info_;
25    fbl::Mutex lock_;
26    char tag_[16]; // pci[XX:XX.X] + \0, aligned to 8
27
28    DISALLOW_COPY_ASSIGN_AND_MOVE(PciBackend);
29};
30
31class PciLegacyBackend : public PciBackend {
32public:
33    PciLegacyBackend(pci_protocol_t pci, zx_pcie_device_info_t info)
34        : PciBackend(pci, info) {}
35    virtual ~PciLegacyBackend();
36    zx_status_t Init() override;
37
38    void DriverStatusOk() override;
39    void DriverStatusAck() override;
40    void DeviceReset() override;
41    uint32_t IsrStatus() override;
42    bool ReadFeature(uint32_t feature) override;
43    void SetFeature(uint32_t feature) override;
44    zx_status_t ConfirmFeatures() override;
45
46    // These handle reading and writing a device's device config to allow derived
47    // virtio devices to work with fields only they know about. For most virtio
48    // devices they will have their device config copied over via
49    // CopyDeviceConfig when device config interrupts are asserted and will not
50    // need to call these directly.
51    void DeviceConfigRead(uint16_t offset, uint8_t* value) override;
52    void DeviceConfigRead(uint16_t offset, uint16_t* value) override;
53    void DeviceConfigRead(uint16_t offset, uint32_t* value) override;
54    void DeviceConfigRead(uint16_t offset, uint64_t* value) override;
55    void DeviceConfigWrite(uint16_t offset, uint8_t value) override;
56    void DeviceConfigWrite(uint16_t offset, uint16_t value) override;
57    void DeviceConfigWrite(uint16_t offset, uint32_t value) override;
58    void DeviceConfigWrite(uint16_t offset, uint64_t value) override;
59
60    // Handle the virtio queues for the device. Due to configuration layouts changing
61    // depending on backend this has to be handled by the backend itself.
62    uint16_t GetRingSize(uint16_t index) override;
63    void SetRing(uint16_t index, uint16_t count, zx_paddr_t pa_desc, zx_paddr_t pa_avail,
64                 zx_paddr_t pa_used) override;
65    void RingKick(uint16_t ring_index) override;
66
67private:
68    void IoReadLocked(uint16_t port, uint8_t* val);
69    void IoReadLocked(uint16_t port, uint16_t* val);
70    void IoReadLocked(uint16_t port, uint32_t* val);
71    void IoWriteLocked(uint16_t port, uint8_t val);
72    void IoWriteLocked(uint16_t port, uint16_t val);
73    void IoWriteLocked(uint16_t port, uint32_t val);
74    void SetStatusBits(uint8_t bits);
75    uint16_t bar0_base_ TA_GUARDED(lock_);
76    uint16_t device_cfg_offset_ TA_GUARDED(lock_);
77
78    DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(PciLegacyBackend);
79};
80
81class PciModernBackend : public PciBackend {
82public:
83    PciModernBackend(pci_protocol_t pci, zx_pcie_device_info_t info)
84        : PciBackend(pci, info) {}
85    // The dtor handles cleanup of allocated bars because we cannot tear down
86    // the mappings safely while the virtio device is being used by a driver.
87    virtual ~PciModernBackend(){};
88    zx_status_t Init() override;
89
90    void DriverStatusOk() override;
91    void DriverStatusAck() override;
92    void DeviceReset() override;
93    uint32_t IsrStatus() override;
94    bool ReadFeature(uint32_t feature) override;
95    void SetFeature(uint32_t feature) override;
96    zx_status_t ConfirmFeatures() override;
97
98    // These handle writing to/from a device's device config to allow derived
99    // virtio devices to work with fields only they know about.
100    void DeviceConfigRead(uint16_t offset, uint8_t* value) override;
101    void DeviceConfigRead(uint16_t offset, uint16_t* value) override;
102    void DeviceConfigRead(uint16_t offset, uint32_t* value) override;
103    void DeviceConfigRead(uint16_t offset, uint64_t* value) override;
104    void DeviceConfigWrite(uint16_t offset, uint8_t value) override;
105    void DeviceConfigWrite(uint16_t offset, uint16_t value) override;
106    void DeviceConfigWrite(uint16_t offset, uint32_t value) override;
107    void DeviceConfigWrite(uint16_t offset, uint64_t value) override;
108
109    // Callbacks called during PciBackend's parsing of capabilities in Bind()
110    void CommonCfgCallbackLocked(const virtio_pci_cap_t& cap) TA_REQ(lock_);
111    void NotifyCfgCallbackLocked(const virtio_pci_cap_t& cap) TA_REQ(lock_);
112    void IsrCfgCallbackLocked(const virtio_pci_cap_t& cap) TA_REQ(lock_);
113    void DeviceCfgCallbackLocked(const virtio_pci_cap_t& cap) TA_REQ(lock_);
114    void PciCfgCallbackLocked(const virtio_pci_cap_t& cap) TA_REQ(lock_);
115
116    // Handle the virtio queues for the device. Due to configuration layouts changing
117    // depending on backend this has to be handled by the backend itself.
118    uint16_t GetRingSize(uint16_t index) override;
119    void SetRing(uint16_t index, uint16_t count, zx_paddr_t pa_desc, zx_paddr_t pa_avail,
120                 zx_paddr_t pa_used) override;
121    void RingKick(uint16_t ring_index) override;
122    char* tag() { return tag_; }
123
124private:
125    zx_status_t MapBar(uint8_t bar);
126
127    struct bar {
128        uintptr_t mmio_base;
129        zx::handle mmio_handle;
130    } bar_[6] = {{0, {}}};
131
132    uintptr_t notify_base_ = 0;
133    volatile uint32_t* isr_status_ = nullptr;
134    uintptr_t device_cfg_ TA_GUARDED(lock_) = 0;
135    volatile virtio_pci_common_cfg_t* common_cfg_ TA_GUARDED(lock_) = nullptr;
136    uint32_t notify_off_mul_;
137
138    DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(PciModernBackend);
139};
140
141} // namespace virtio
142