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