blob: 580438183414a6414d9918d2b7b76a3fda7a7532 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include "backend.h"
#include <ddktl/mmio.h>
#include <optional>
#include <zircon/thread_annotations.h>
namespace virtio {
class PciBackend : public Backend {
public:
PciBackend(pci_protocol_t pci, zx_pcie_device_info_t info);
zx_status_t Bind() override;
virtual zx_status_t Init() = 0;
const char* tag() { return tag_; }
zx_status_t InterruptValid() override;
zx_status_t WaitForInterrupt() override;
protected:
pci_protocol_t pci_ = {nullptr, nullptr};
zx_pcie_device_info_t info_;
fbl::Mutex lock_;
char tag_[16]; // pci[XX:XX.X] + \0, aligned to 8
DISALLOW_COPY_ASSIGN_AND_MOVE(PciBackend);
};
class PciLegacyBackend : public PciBackend {
public:
PciLegacyBackend(pci_protocol_t pci, zx_pcie_device_info_t info)
: PciBackend(pci, info) {}
virtual ~PciLegacyBackend();
zx_status_t Init() override;
void DriverStatusOk() override;
void DriverStatusAck() override;
void DeviceReset() override;
uint32_t IsrStatus() override;
bool ReadFeature(uint32_t feature) override;
void SetFeature(uint32_t feature) override;
zx_status_t ConfirmFeatures() override;
// These handle reading and writing a device's device config to allow derived
// virtio devices to work with fields only they know about. For most virtio
// devices they will have their device config copied over via
// CopyDeviceConfig when device config interrupts are asserted and will not
// need to call these directly.
void ReadDeviceConfig(uint16_t offset, uint8_t* value) override;
void ReadDeviceConfig(uint16_t offset, uint16_t* value) override;
void ReadDeviceConfig(uint16_t offset, uint32_t* value) override;
void ReadDeviceConfig(uint16_t offset, uint64_t* value) override;
void WriteDeviceConfig(uint16_t offset, uint8_t value) override;
void WriteDeviceConfig(uint16_t offset, uint16_t value) override;
void WriteDeviceConfig(uint16_t offset, uint32_t value) override;
void WriteDeviceConfig(uint16_t offset, uint64_t value) override;
// Handle the virtio queues for the device. Due to configuration layouts changing
// depending on backend this has to be handled by the backend itself.
uint16_t GetRingSize(uint16_t index) override;
void SetRing(uint16_t index, uint16_t count, zx_paddr_t pa_desc, zx_paddr_t pa_avail,
zx_paddr_t pa_used) override;
void RingKick(uint16_t ring_index) override;
private:
void IoReadLocked(uint16_t port, uint8_t* val);
void IoReadLocked(uint16_t port, uint16_t* val);
void IoReadLocked(uint16_t port, uint32_t* val);
void IoWriteLocked(uint16_t port, uint8_t val);
void IoWriteLocked(uint16_t port, uint16_t val);
void IoWriteLocked(uint16_t port, uint32_t val);
void SetStatusBits(uint8_t bits);
uint16_t bar0_base_ TA_GUARDED(lock_);
uint16_t device_cfg_offset_ TA_GUARDED(lock_);
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(PciLegacyBackend);
};
class PciModernBackend : public PciBackend {
public:
PciModernBackend(pci_protocol_t pci, zx_pcie_device_info_t info)
: PciBackend(pci, info) {}
// The dtor handles cleanup of allocated bars because we cannot tear down
// the mappings safely while the virtio device is being used by a driver.
virtual ~PciModernBackend(){};
zx_status_t Init() override;
void DriverStatusOk() override;
void DriverStatusAck() override;
void DeviceReset() override;
uint32_t IsrStatus() override;
bool ReadFeature(uint32_t feature) override;
void SetFeature(uint32_t feature) override;
zx_status_t ConfirmFeatures() override;
// These handle writing to/from a device's device config to allow derived
// virtio devices to work with fields only they know about.
void ReadDeviceConfig(uint16_t offset, uint8_t* value) override;
void ReadDeviceConfig(uint16_t offset, uint16_t* value) override;
void ReadDeviceConfig(uint16_t offset, uint32_t* value) override;
void ReadDeviceConfig(uint16_t offset, uint64_t* value) override;
void WriteDeviceConfig(uint16_t offset, uint8_t value) override;
void WriteDeviceConfig(uint16_t offset, uint16_t value) override;
void WriteDeviceConfig(uint16_t offset, uint32_t value) override;
void WriteDeviceConfig(uint16_t offset, uint64_t value) override;
// Callbacks called during PciBackend's parsing of capabilities in Bind()
void CommonCfgCallbackLocked(const virtio_pci_cap_t& cap) TA_REQ(lock_);
void NotifyCfgCallbackLocked(const virtio_pci_cap_t& cap) TA_REQ(lock_);
void IsrCfgCallbackLocked(const virtio_pci_cap_t& cap) TA_REQ(lock_);
void DeviceCfgCallbackLocked(const virtio_pci_cap_t& cap) TA_REQ(lock_);
void PciCfgCallbackLocked(const virtio_pci_cap_t& cap) TA_REQ(lock_);
// Handle the virtio queues for the device. Due to configuration layouts changing
// depending on backend this has to be handled by the backend itself.
uint16_t GetRingSize(uint16_t index) override;
void SetRing(uint16_t index, uint16_t count, zx_paddr_t pa_desc, zx_paddr_t pa_avail,
zx_paddr_t pa_used) override;
void RingKick(uint16_t ring_index) override;
char* tag() { return tag_; }
private:
zx_status_t MapBar(uint8_t bar);
std::optional<ddk::MmioBuffer> bar_[6];
uintptr_t notify_base_ = 0;
volatile uint32_t* isr_status_ = nullptr;
uintptr_t device_cfg_ TA_GUARDED(lock_) = 0;
volatile virtio_pci_common_cfg_t* common_cfg_ TA_GUARDED(lock_) = nullptr;
uint32_t notify_off_mul_;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(PciModernBackend);
};
} // namespace virtio