1 // Copyright 2016 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 #pragma once
5 
6 #include <zircon/types.h>
7 
8 #include "backends/backend.h"
9 #include <ddk/device.h>
10 #include <ddk/driver.h>
11 #include <ddk/protocol/pci.h>
12 #include <fbl/mutex.h>
13 #include <fbl/unique_ptr.h>
14 #include <threads.h>
15 #include <virtio/virtio.h>
16 #include <lib/zx/bti.h>
17 #include <lib/zx/handle.h>
18 
19 // Virtio devices are represented by a derived class specific to their type (eg
20 // gpu) with a virtio::Device base. The device class handles general work around
21 // IRQ handling and contains a backend that is instantiated at creation time
22 // that implements a virtio backend. This allows a single device driver to work
23 // on both Virtio legacy or transistional without needing to special case the
24 // device interaction.
25 namespace virtio {
26 
27 class Device {
28 public:
29     Device(zx_device_t* bus_device, zx::bti bti, fbl::unique_ptr<Backend> backend);
30     virtual ~Device();
31 
32     virtual zx_status_t Init() = 0;
33     virtual void Release();
34     virtual void Unbind();
35 
36     void StartIrqThread();
37     // interrupt cases that devices may override
38     virtual void IrqRingUpdate() = 0;
39     virtual void IrqConfigChange() = 0;
40 
41     // Get the Ring size for the particular device / backend.
42     // This has to be proxied to a backend method because we can't
43     // simply do config reads to determine the information.
GetRingSize(uint16_t index)44     uint16_t GetRingSize(uint16_t index) { return backend_->GetRingSize(index); }
45     // Set up ring descriptors with the backend.
SetRing(uint16_t index,uint16_t count,zx_paddr_t pa_desc,zx_paddr_t pa_avail,zx_paddr_t pa_used)46     void SetRing(uint16_t index, uint16_t count, zx_paddr_t pa_desc, zx_paddr_t pa_avail,
47                  zx_paddr_t pa_used) {
48         backend_->SetRing(index, count, pa_desc, pa_avail, pa_used);
49     }
50 
51     // Another method that has to be proxied to the backend due to differences
52     // in how Legacy vs Modern systems are laid out.
RingKick(uint16_t ring_index)53     void RingKick(uint16_t ring_index) { backend_->RingKick(ring_index); }
54 
55     // It is expected that each derived device will implement tag().
device()56     zx_device_t* device() { return device_; }
57     virtual const char* tag() const = 0; // Implemented by derived devices
58 
59     // Accessor for bti so that Rings can map IO buffers
bti()60     const zx::bti& bti() { return bti_; }
61 protected:
62     // Methods for checking / acknowledging features
DeviceFeatureSupported(uint32_t feature)63     bool DeviceFeatureSupported(uint32_t feature) { return backend_->ReadFeature(feature); }
DriverFeatureAck(uint32_t feature)64     void DriverFeatureAck(uint32_t feature) { backend_->SetFeature(feature); }
DeviceStatusFeaturesOk()65     bool DeviceStatusFeaturesOk() { return backend_->ConfirmFeatures(); }
66 
67     // Devie lifecycle methods
DeviceReset()68     void DeviceReset() { backend_->DeviceReset(); }
DriverStatusAck()69     void DriverStatusAck() { backend_->DriverStatusAck(); }
DriverStatusOk()70     void DriverStatusOk() { backend_->DriverStatusOk(); }
IsrStatus()71     uint32_t IsrStatus() { return backend_->IsrStatus(); }
72 
73     // Device config management
74     zx_status_t CopyDeviceConfig(void* _buf, size_t len) const;
75     template <typename T>
ReadDeviceConfig(uint16_t offset,T * val)76     T ReadDeviceConfig(uint16_t offset, T* val) { return backend_->DeviceConfigRead(offset, val); }
77     template <typename T>
WriteDeviceConfig(uint16_t offset,T val)78     void WriteDeviceConfig(uint16_t offset, T val) { backend_->DeviceConfigWrite(offset, val); }
79 
bus_device()80     zx_device_t* bus_device() const { return bus_device_; }
81     static int IrqThreadEntry(void* arg);
82     void IrqWorker();
83 
84     // BTI for managing DMA
85     zx::bti bti_;
86     // backend responsible for hardware io. Will be released when device goes out of scope
87     fbl::unique_ptr<Backend> backend_;
88     // irq thread object
89     thrd_t irq_thread_ = {};
90     zx::handle irq_handle_ = {};
91     // Bus device is the parent device on the bus, device is this driver's device node.
92     zx_device_t* bus_device_ = nullptr;
93     zx_device_t* device_ = nullptr;
94 
95     // DDK device
96     // TODO: It might make sense for the base device class to be the one
97     // to handle device_add() calls rather than delegating it to the derived
98     // instances of devices.
99     zx_protocol_device_t device_ops_ = {};
100 
101     // This lock exists for devices to synchronize themselves, it should not be used by the base
102     // device class.
103     fbl::Mutex lock_;
104 };
105 
106 } // namespace virtio
107