virtio: support modern devices
fixes #17239 #17238 Change-Id: Ia5b6347110a60fab18852079b30dca6301010474 Reviewed-on: https://review.haiku-os.org/c/haiku/+/6995 Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
This commit is contained in:
parent
518e9cb9f2
commit
6d42b430d1
@ -26,13 +26,14 @@
|
||||
#define VIRTIO_DEVICE_ID_VSOCK 19
|
||||
#define VIRTIO_DEVICE_ID_CRYPTO 20
|
||||
|
||||
#define VIRTIO_FEATURE_TRANSPORT_MASK ((1 << 28) - 1)
|
||||
#define VIRTIO_FEATURE_TRANSPORT_MASK ((1ULL << 28) - 1)
|
||||
|
||||
#define VIRTIO_FEATURE_NOTIFY_ON_EMPTY (1 << 24)
|
||||
#define VIRTIO_FEATURE_ANY_LAYOUT (1 << 27)
|
||||
#define VIRTIO_FEATURE_RING_INDIRECT_DESC (1 << 28)
|
||||
#define VIRTIO_FEATURE_RING_EVENT_IDX (1 << 29)
|
||||
#define VIRTIO_FEATURE_BAD_FEATURE (1 << 30)
|
||||
#define VIRTIO_FEATURE_VERSION_1 (1ULL << 32)
|
||||
|
||||
#define VIRTIO_VIRTQUEUES_MAX_COUNT 8
|
||||
|
||||
@ -40,6 +41,8 @@
|
||||
#define VIRTIO_CONFIG_STATUS_ACK 0x01
|
||||
#define VIRTIO_CONFIG_STATUS_DRIVER 0x02
|
||||
#define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
|
||||
#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08
|
||||
#define VIRTIO_CONFIG_STATUS_DEVICE_NEEDS_RESET 0x40
|
||||
#define VIRTIO_CONFIG_STATUS_FAILED 0x80
|
||||
|
||||
// attributes:
|
||||
@ -50,6 +53,8 @@
|
||||
#define VIRTIO_DEVICE_TYPE_ITEM "virtio/type"
|
||||
// alignment (uint16)
|
||||
#define VIRTIO_VRING_ALIGNMENT_ITEM "virtio/vring_alignment"
|
||||
// version (uint8)
|
||||
#define VIRTIO_VERSION_ITEM "virtio/version"
|
||||
|
||||
// sim cookie, issued by virtio bus manager
|
||||
typedef void* virtio_sim;
|
||||
@ -78,8 +83,8 @@ typedef struct {
|
||||
driver_module_info info;
|
||||
|
||||
void (*set_sim)(void* cookie, virtio_sim sim);
|
||||
status_t (*read_host_features)(void* cookie, uint32* features);
|
||||
status_t (*write_guest_features)(void* cookie, uint32 features);
|
||||
status_t (*read_host_features)(void* cookie, uint64* features);
|
||||
status_t (*write_guest_features)(void* cookie, uint64 features);
|
||||
uint8 (*get_status)(void* cookie);
|
||||
void (*set_status)(void* cookie, uint8 status);
|
||||
status_t (*read_device_config)(void* cookie, uint8 offset, void* buffer,
|
||||
@ -88,7 +93,8 @@ typedef struct {
|
||||
const void* buffer, size_t bufferSize);
|
||||
|
||||
uint16 (*get_queue_ring_size)(void* cookie, uint16 queue);
|
||||
status_t (*setup_queue)(void* cookie, uint16 queue, phys_addr_t phy);
|
||||
status_t (*setup_queue)(void* cookie, uint16 queue, phys_addr_t phy, phys_addr_t phyAvail,
|
||||
phys_addr_t phyUsed);
|
||||
status_t (*setup_interrupt)(void* cookie, uint16 queueCount);
|
||||
status_t (*free_interrupt)(void* cookie);
|
||||
void (*notify_queue)(void* cookie, uint16 queue);
|
||||
@ -99,10 +105,10 @@ typedef struct {
|
||||
typedef struct {
|
||||
driver_module_info info;
|
||||
|
||||
status_t (*negotiate_features)(virtio_device cookie, uint32 supported,
|
||||
uint32* negotiated, const char* (*get_feature_name)(uint32));
|
||||
status_t (*negotiate_features)(virtio_device cookie, uint64 supported,
|
||||
uint64* negotiated, const char* (*get_feature_name)(uint64));
|
||||
|
||||
status_t (*clear_feature)(virtio_device cookie, uint32 feature);
|
||||
status_t (*clear_feature)(virtio_device cookie, uint64 feature);
|
||||
|
||||
status_t (*read_device_config)(virtio_device cookie, uint8 offset,
|
||||
void* buffer, size_t bufferSize);
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
const char*
|
||||
get_feature_name(uint32 feature)
|
||||
get_feature_name(uint64 feature)
|
||||
{
|
||||
switch (feature) {
|
||||
case VIRTIO_BALLOON_F_MUST_TELL_HOST:
|
||||
|
@ -61,7 +61,7 @@ private:
|
||||
virtio_device* fVirtioDevice;
|
||||
|
||||
status_t fStatus;
|
||||
uint32 fFeatures;
|
||||
uint64 fFeatures;
|
||||
::virtio_queue fVirtioQueues[2];
|
||||
|
||||
physical_entry fEntry;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
|
||||
const char *
|
||||
virtio_get_feature_name(uint32 feature)
|
||||
virtio_get_feature_name(uint64 feature)
|
||||
{
|
||||
switch (feature) {
|
||||
case VIRTIO_FEATURE_NOTIFY_ON_EMPTY:
|
||||
@ -62,6 +62,7 @@ VirtioDevice::VirtioDevice(device_node *node)
|
||||
fQueues(NULL),
|
||||
fFeatures(0),
|
||||
fAlignment(0),
|
||||
fVirtio1(false),
|
||||
fConfigHandler(NULL),
|
||||
fDriverCookie(NULL)
|
||||
{
|
||||
@ -80,6 +81,9 @@ VirtioDevice::VirtioDevice(device_node *node)
|
||||
ERROR("alignment missing\n");
|
||||
return;
|
||||
}
|
||||
uint8 version = 0;
|
||||
if (gDeviceManager->get_attr_uint8(fNode, VIRTIO_VERSION_ITEM, &version, true) == B_OK)
|
||||
fVirtio1 = version == 1;
|
||||
|
||||
fController->set_sim(fCookie, this);
|
||||
|
||||
@ -104,8 +108,8 @@ VirtioDevice::InitCheck()
|
||||
|
||||
|
||||
status_t
|
||||
VirtioDevice::NegotiateFeatures(uint32 supported, uint32* negotiated,
|
||||
const char* (*get_feature_name)(uint32))
|
||||
VirtioDevice::NegotiateFeatures(uint64 supported, uint64* negotiated,
|
||||
const char* (*get_feature_name)(uint64))
|
||||
{
|
||||
fFeatures = 0;
|
||||
status_t status = fController->read_host_features(fCookie, &fFeatures);
|
||||
@ -114,22 +118,43 @@ VirtioDevice::NegotiateFeatures(uint32 supported, uint32* negotiated,
|
||||
|
||||
_DumpFeatures("read features", fFeatures, get_feature_name);
|
||||
|
||||
if (fVirtio1) {
|
||||
supported |= VIRTIO_FEATURE_VERSION_1;
|
||||
supported &= ~VIRTIO_FEATURE_NOTIFY_ON_EMPTY;
|
||||
}
|
||||
|
||||
fFeatures &= supported;
|
||||
|
||||
// filter our own features
|
||||
fFeatures &= (VIRTIO_FEATURE_TRANSPORT_MASK
|
||||
| VIRTIO_FEATURE_RING_INDIRECT_DESC | VIRTIO_FEATURE_RING_EVENT_IDX);
|
||||
|
||||
*negotiated = fFeatures;
|
||||
| VIRTIO_FEATURE_RING_INDIRECT_DESC | VIRTIO_FEATURE_RING_EVENT_IDX
|
||||
| VIRTIO_FEATURE_VERSION_1);
|
||||
|
||||
_DumpFeatures("negotiated features", fFeatures, get_feature_name);
|
||||
|
||||
return fController->write_guest_features(fCookie, fFeatures);
|
||||
status = fController->write_guest_features(fCookie, fFeatures);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (fVirtio1) {
|
||||
fController->set_status(fCookie, VIRTIO_CONFIG_STATUS_FEATURES_OK);
|
||||
if ((fController->get_status(fCookie) & VIRTIO_CONFIG_STATUS_FEATURES_OK) == 0) {
|
||||
fController->set_status(fCookie, VIRTIO_CONFIG_STATUS_FAILED);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
if ((fFeatures & VIRTIO_FEATURE_VERSION_1) == 0) {
|
||||
fController->set_status(fCookie, VIRTIO_CONFIG_STATUS_FAILED);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
}
|
||||
*negotiated = fFeatures;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VirtioDevice::ClearFeature(uint32 feature)
|
||||
VirtioDevice::ClearFeature(uint64 feature)
|
||||
{
|
||||
fFeatures &= ~feature;
|
||||
return fController->write_guest_features(fCookie, fFeatures);
|
||||
@ -224,9 +249,10 @@ VirtioDevice::FreeInterrupts()
|
||||
|
||||
|
||||
status_t
|
||||
VirtioDevice::SetupQueue(uint16 queueNumber, phys_addr_t physAddr)
|
||||
VirtioDevice::SetupQueue(uint16 queueNumber, phys_addr_t physAddr, phys_addr_t phyAvail,
|
||||
phys_addr_t phyUsed)
|
||||
{
|
||||
return fController->setup_queue(fCookie, queueNumber, physAddr);
|
||||
return fController->setup_queue(fCookie, queueNumber, physAddr, phyAvail, phyUsed);
|
||||
}
|
||||
|
||||
|
||||
@ -278,12 +304,12 @@ VirtioDevice::_DestroyQueues(size_t count)
|
||||
|
||||
|
||||
void
|
||||
VirtioDevice::_DumpFeatures(const char* title, uint32 features,
|
||||
const char* (*get_feature_name)(uint32))
|
||||
VirtioDevice::_DumpFeatures(const char* title, uint64 features,
|
||||
const char* (*get_feature_name)(uint64))
|
||||
{
|
||||
char features_string[512] = "";
|
||||
for (uint32 i = 0; i < 32; i++) {
|
||||
uint32 feature = features & (1 << i);
|
||||
for (uint32 i = 0; i < 64; i++) {
|
||||
uint64 feature = features & (1ULL << i);
|
||||
if (feature == 0)
|
||||
continue;
|
||||
const char* name = virtio_get_feature_name(feature);
|
||||
|
@ -54,8 +54,8 @@ virtio_device_removed(void *_device)
|
||||
|
||||
|
||||
status_t
|
||||
virtio_negotiate_features(void* _device, uint32 supported,
|
||||
uint32* negotiated, const char* (*get_feature_name)(uint32))
|
||||
virtio_negotiate_features(void* _device, uint64 supported,
|
||||
uint64* negotiated, const char* (*get_feature_name)(uint64))
|
||||
{
|
||||
CALLED();
|
||||
VirtioDevice *device = (VirtioDevice *)_device;
|
||||
@ -65,7 +65,7 @@ virtio_negotiate_features(void* _device, uint32 supported,
|
||||
|
||||
|
||||
status_t
|
||||
virtio_clear_feature(void* _device, uint32 feature)
|
||||
virtio_clear_feature(void* _device, uint64 feature)
|
||||
{
|
||||
CALLED();
|
||||
VirtioDevice *device = (VirtioDevice *)_device;
|
||||
|
@ -45,10 +45,10 @@ public:
|
||||
status_t InitCheck();
|
||||
uint32 ID() const { return fID; }
|
||||
|
||||
status_t NegotiateFeatures(uint32 supported,
|
||||
uint32* negotiated,
|
||||
const char* (*get_feature_name)(uint32));
|
||||
status_t ClearFeature(uint32 feature);
|
||||
status_t NegotiateFeatures(uint64 supported,
|
||||
uint64* negotiated,
|
||||
const char* (*get_feature_name)(uint64));
|
||||
status_t ClearFeature(uint64 feature);
|
||||
|
||||
status_t ReadDeviceConfig(uint8 offset, void* buffer,
|
||||
size_t bufferSize);
|
||||
@ -63,12 +63,13 @@ public:
|
||||
status_t FreeInterrupts();
|
||||
|
||||
uint16 Alignment() const { return fAlignment; }
|
||||
uint32 Features() const { return fFeatures; }
|
||||
uint64 Features() const { return fFeatures; }
|
||||
|
||||
void* DriverCookie() { return fDriverCookie; }
|
||||
|
||||
status_t SetupQueue(uint16 queueNumber,
|
||||
phys_addr_t physAddr);
|
||||
phys_addr_t physAddr, phys_addr_t phyAvail,
|
||||
phys_addr_t phyUsed);
|
||||
void NotifyQueue(uint16 queueNumber);
|
||||
|
||||
status_t QueueInterrupt(uint16 queueNumber);
|
||||
@ -76,8 +77,8 @@ public:
|
||||
|
||||
private:
|
||||
void _DumpFeatures(const char* title,
|
||||
uint32 features,
|
||||
const char* (*get_feature_name)(uint32));
|
||||
uint64 features,
|
||||
const char* (*get_feature_name)(uint64));
|
||||
void _DestroyQueues(size_t count);
|
||||
|
||||
|
||||
@ -89,8 +90,9 @@ private:
|
||||
status_t fStatus;
|
||||
VirtioQueue** fQueues;
|
||||
size_t fQueueCount;
|
||||
uint32 fFeatures;
|
||||
uint64 fFeatures;
|
||||
uint16 fAlignment;
|
||||
bool fVirtio1;
|
||||
|
||||
virtio_intr_func fConfigHandler;
|
||||
void* fDriverCookie;
|
||||
|
@ -182,7 +182,9 @@ VirtioQueue::VirtioQueue(VirtioDevice* device, uint16 queueNumber,
|
||||
|
||||
DisableInterrupt();
|
||||
|
||||
device->SetupQueue(fQueueNumber, physAddr);
|
||||
device->SetupQueue(fQueueNumber, physAddr,
|
||||
physAddr + ((addr_t)fRing.avail - (addr_t)fRing.desc),
|
||||
physAddr + ((addr_t)fRing.used - (addr_t)fRing.desc));
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
|
||||
const char *
|
||||
get_feature_name(uint32 feature)
|
||||
get_feature_name(uint64 feature)
|
||||
{
|
||||
switch (feature) {
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ private:
|
||||
virtio_device* fVirtioDevice;
|
||||
|
||||
status_t fStatus;
|
||||
uint32 fFeatures;
|
||||
uint64 fFeatures;
|
||||
::virtio_queue fVirtioQueue;
|
||||
|
||||
spinlock fInterruptLock;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
|
||||
const char *
|
||||
get_feature_name(uint32 feature)
|
||||
get_feature_name(uint64 feature)
|
||||
{
|
||||
switch (feature) {
|
||||
case VIRTIO_SCSI_F_INOUT:
|
||||
|
@ -81,7 +81,7 @@ private:
|
||||
|
||||
status_t fStatus;
|
||||
struct virtio_scsi_config fConfig;
|
||||
uint32 fFeatures;
|
||||
uint64 fFeatures;
|
||||
::virtio_queue fControlVirtioQueue;
|
||||
::virtio_queue fEventVirtioQueue;
|
||||
::virtio_queue fRequestVirtioQueue;
|
||||
|
@ -33,7 +33,7 @@ device_manager_info* gDeviceManager;
|
||||
|
||||
|
||||
static const char *
|
||||
virtio_get_feature_name(uint32 feature)
|
||||
virtio_get_feature_name(uint64 feature)
|
||||
{
|
||||
switch (feature) {
|
||||
case VIRTIO_FEATURE_NOTIFY_ON_EMPTY:
|
||||
@ -52,12 +52,12 @@ virtio_get_feature_name(uint32 feature)
|
||||
|
||||
|
||||
static void
|
||||
virtio_dump_features(const char* title, uint32 features,
|
||||
const char* (*get_feature_name)(uint32))
|
||||
virtio_dump_features(const char* title, uint64 features,
|
||||
const char* (*get_feature_name)(uint64))
|
||||
{
|
||||
char features_string[512] = "";
|
||||
for (uint32 i = 0; i < 32; i++) {
|
||||
uint32 feature = features & (1 << i);
|
||||
for (uint64 i = 0; i < 32; i++) {
|
||||
uint64 feature = features & (1 << i);
|
||||
if (feature == 0)
|
||||
continue;
|
||||
const char* name = virtio_get_feature_name(feature);
|
||||
@ -365,8 +365,8 @@ virtio_device_register_child_devices(void* cookie)
|
||||
|
||||
|
||||
static status_t
|
||||
virtio_device_negotiate_features(virtio_device cookie, uint32 supported,
|
||||
uint32* negotiated, const char* (*get_feature_name)(uint32))
|
||||
virtio_device_negotiate_features(virtio_device cookie, uint64 supported,
|
||||
uint64* negotiated, const char* (*get_feature_name)(uint64))
|
||||
{
|
||||
TRACE("virtio_device_negotiate_features(%p)\n", cookie);
|
||||
VirtioDevice* dev = (VirtioDevice*)cookie;
|
||||
@ -374,7 +374,7 @@ virtio_device_negotiate_features(virtio_device cookie, uint32 supported,
|
||||
dev->fRegs->status |= kVirtioConfigSAcknowledge;
|
||||
dev->fRegs->status |= kVirtioConfigSDriver;
|
||||
|
||||
uint32 features = dev->fRegs->deviceFeatures;
|
||||
uint64 features = dev->fRegs->deviceFeatures;
|
||||
virtio_dump_features("read features", features, get_feature_name);
|
||||
features &= supported;
|
||||
|
||||
@ -395,7 +395,7 @@ virtio_device_negotiate_features(virtio_device cookie, uint32 supported,
|
||||
|
||||
|
||||
static status_t
|
||||
virtio_device_clear_feature(virtio_device cookie, uint32 feature)
|
||||
virtio_device_clear_feature(virtio_device cookie, uint64 feature)
|
||||
{
|
||||
panic("not implemented");
|
||||
return B_ERROR;
|
||||
|
@ -2,7 +2,8 @@ SubDir HAIKU_TOP src add-ons kernel busses virtio virtio_pci ;
|
||||
|
||||
SubDirC++Flags -fno-rtti ;
|
||||
|
||||
UsePrivateHeaders kernel virtio ;
|
||||
UsePrivateHeaders virtio ;
|
||||
UsePrivateKernelHeaders ;
|
||||
|
||||
KernelAddon virtio_pci :
|
||||
virtio_pci.cpp
|
||||
|
@ -9,6 +9,9 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <bus/PCI.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include <kernel.h>
|
||||
#include <virtio.h>
|
||||
|
||||
#include "virtio_pci.h"
|
||||
@ -45,11 +48,18 @@ typedef struct {
|
||||
typedef struct {
|
||||
pci_device_module_info* pci;
|
||||
pci_device* device;
|
||||
bool virtio1;
|
||||
addr_t base_addr;
|
||||
area_id registersArea[4];
|
||||
addr_t commonCfgAddr;
|
||||
addr_t isrAddr;
|
||||
addr_t notifyAddr;
|
||||
uint32 notifyOffsetMultiplier;
|
||||
uint8 irq;
|
||||
virtio_irq_type irq_type;
|
||||
virtio_sim sim;
|
||||
uint16 queue_count;
|
||||
addr_t* notifyOffsets;
|
||||
|
||||
device_node* node;
|
||||
pci_info info;
|
||||
@ -62,12 +72,53 @@ device_manager_info* gDeviceManager;
|
||||
virtio_for_controller_interface* gVirtio;
|
||||
|
||||
|
||||
int32
|
||||
static status_t
|
||||
virtio_pci_find_capability(virtio_pci_sim_info* bus, uint8 cfgType,
|
||||
void* buffer, size_t size)
|
||||
{
|
||||
uint8 capabilityOffset;
|
||||
if (bus->pci->find_pci_capability(bus->device, PCI_cap_id_vendspec, &capabilityOffset) != B_OK)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
if (size < sizeof(virtio_pci_cap))
|
||||
return B_RESULT_NOT_REPRESENTABLE;
|
||||
union regs {
|
||||
uint32 reg[8];
|
||||
struct virtio_pci_cap capability;
|
||||
} * v = (union regs*)buffer;
|
||||
|
||||
while (capabilityOffset != 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v->reg[i] = bus->pci->read_pci_config(bus->device, capabilityOffset + i * 4, 4);
|
||||
}
|
||||
if (v->capability.cfg_type == cfgType)
|
||||
break;
|
||||
capabilityOffset = v->capability.cap_next;
|
||||
}
|
||||
if (capabilityOffset == 0)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
if (v->capability.length > sizeof(virtio_pci_cap)) {
|
||||
size_t length = min_c(ROUNDUP(v->capability.length, sizeof(uint32)), size);
|
||||
for (size_t i = 4; i < length / sizeof(uint32); i++)
|
||||
v->reg[i] = bus->pci->read_pci_config(bus->device, capabilityOffset + i * 4, 4);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
virtio_pci_interrupt(void *data)
|
||||
{
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)data;
|
||||
uint8 isr = bus->pci->read_io_8(bus->device,
|
||||
bus->base_addr + VIRTIO_PCI_ISR);
|
||||
uint8 isr;
|
||||
if (bus->virtio1) {
|
||||
uint8* isrAddr = (uint8*)bus->isrAddr;
|
||||
isr = *isrAddr;
|
||||
} else {
|
||||
isr = bus->pci->read_io_8(bus->device,
|
||||
bus->base_addr + VIRTIO_PCI_ISR);
|
||||
}
|
||||
if (isr == 0)
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
|
||||
@ -81,7 +132,7 @@ virtio_pci_interrupt(void *data)
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
static int32
|
||||
virtio_pci_config_interrupt(void *data)
|
||||
{
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)data;
|
||||
@ -91,7 +142,7 @@ virtio_pci_config_interrupt(void *data)
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
static int32
|
||||
virtio_pci_queue_interrupt(void *data)
|
||||
{
|
||||
virtio_pci_queue_cookie* cookie = (virtio_pci_queue_cookie*)data;
|
||||
@ -101,33 +152,47 @@ virtio_pci_queue_interrupt(void *data)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
static status_t
|
||||
virtio_pci_setup_msix_interrupts(virtio_pci_sim_info* bus)
|
||||
{
|
||||
CALLED();
|
||||
uint8 irq = 0; // first irq slot
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_MSI_CONFIG_VECTOR, irq);
|
||||
if (bus->pci->read_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_MSI_CONFIG_VECTOR) == VIRTIO_MSI_NO_VECTOR) {
|
||||
ERROR("msix config vector incorrect\n");
|
||||
return B_BAD_VALUE;
|
||||
if (bus->virtio1) {
|
||||
volatile uint16 *msixVector = (uint16*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, config_msix_vector));
|
||||
*msixVector = irq;
|
||||
} else {
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_MSI_CONFIG_VECTOR, irq);
|
||||
if (bus->pci->read_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_MSI_CONFIG_VECTOR) == VIRTIO_MSI_NO_VECTOR) {
|
||||
ERROR("msix config vector incorrect\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
}
|
||||
if (bus->irq_type == VIRTIO_IRQ_MSI_X)
|
||||
irq++;
|
||||
|
||||
for (uint16 queue = 0; queue < bus->queue_count; queue++) {
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_PCI_QUEUE_SEL, queue);
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_MSI_QUEUE_VECTOR, irq);
|
||||
if (bus->virtio1) {
|
||||
volatile uint16* queueSelect = (uint16*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, queue_select));
|
||||
*queueSelect = queue;
|
||||
volatile uint16* msixVector = (uint16*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, queue_msix_vector));
|
||||
*msixVector = irq;
|
||||
} else {
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_PCI_QUEUE_SEL, queue);
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_MSI_QUEUE_VECTOR, irq);
|
||||
|
||||
if (bus->pci->read_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_MSI_QUEUE_VECTOR) == VIRTIO_MSI_NO_VECTOR) {
|
||||
ERROR("msix queue vector incorrect\n");
|
||||
return B_BAD_VALUE;
|
||||
if (bus->pci->read_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_MSI_QUEUE_VECTOR) == VIRTIO_MSI_NO_VECTOR) {
|
||||
ERROR("msix queue vector incorrect\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (bus->irq_type == VIRTIO_IRQ_MSI_X)
|
||||
irq++;
|
||||
}
|
||||
@ -146,7 +211,7 @@ set_sim(void* cookie, virtio_sim sim)
|
||||
|
||||
|
||||
static status_t
|
||||
read_host_features(void* cookie, uint32 *features)
|
||||
read_host_features(void* cookie, uint64 *features)
|
||||
{
|
||||
CALLED();
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
|
||||
@ -154,65 +219,116 @@ read_host_features(void* cookie, uint32 *features)
|
||||
TRACE("read_host_features() %p node %p pci %p device %p\n", bus,
|
||||
bus->node, bus->pci, bus->device);
|
||||
|
||||
*features = bus->pci->read_io_32(bus->device,
|
||||
bus->base_addr + VIRTIO_PCI_HOST_FEATURES);
|
||||
if (bus->virtio1) {
|
||||
volatile uint32 *select = (uint32*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, device_feature_select));
|
||||
volatile uint32 *feature = (uint32*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, device_feature));
|
||||
*select = 0;
|
||||
*features = *feature;
|
||||
*select = 1;
|
||||
*features |= ((uint64)*feature << 32) ;
|
||||
TRACE("read_host_features() %" B_PRIx64 "\n", *features);
|
||||
} else {
|
||||
*features = bus->pci->read_io_32(bus->device,
|
||||
bus->base_addr + VIRTIO_PCI_HOST_FEATURES);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
write_guest_features(void* cookie, uint32 features)
|
||||
write_guest_features(void* cookie, uint64 features)
|
||||
{
|
||||
CALLED();
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
|
||||
bus->pci->write_io_32(bus->device, bus->base_addr
|
||||
+ VIRTIO_PCI_GUEST_FEATURES, features);
|
||||
if (bus->virtio1) {
|
||||
volatile uint32 *select = (uint32*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, device_feature_select));
|
||||
volatile uint32 *feature = (uint32*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, device_feature));
|
||||
*select = 0;
|
||||
*feature = features & 0xffffffff;
|
||||
*select = 1;
|
||||
*feature = (features >> 32) ;
|
||||
} else {
|
||||
bus->pci->write_io_32(bus->device, bus->base_addr
|
||||
+ VIRTIO_PCI_GUEST_FEATURES, features);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
uint8
|
||||
static uint8
|
||||
get_status(void* cookie)
|
||||
{
|
||||
CALLED();
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
|
||||
return bus->pci->read_io_8(bus->device, bus->base_addr
|
||||
+ VIRTIO_PCI_STATUS);
|
||||
if (bus->virtio1) {
|
||||
uint8 *addr = (uint8*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, device_status));
|
||||
return *addr;
|
||||
} else {
|
||||
return bus->pci->read_io_8(bus->device, bus->base_addr + VIRTIO_PCI_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
set_status(void* cookie, uint8 status)
|
||||
{
|
||||
CALLED();
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
|
||||
bus->pci->write_io_8(bus->device, bus->base_addr + VIRTIO_PCI_STATUS,
|
||||
status);
|
||||
if (bus->virtio1) {
|
||||
uint8 *addr = (uint8*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, device_status));
|
||||
uint8 old = 0;
|
||||
if (status != 0)
|
||||
old = *addr;
|
||||
*addr = status | old;
|
||||
} else {
|
||||
uint8 old = 0;
|
||||
if (status != 0)
|
||||
old = bus->pci->read_io_8(bus->device, bus->base_addr + VIRTIO_PCI_STATUS);
|
||||
bus->pci->write_io_8(bus->device, bus->base_addr + VIRTIO_PCI_STATUS, status | old);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
static status_t
|
||||
read_device_config(void* cookie, uint8 _offset, void* _buffer,
|
||||
size_t bufferSize)
|
||||
{
|
||||
CALLED();
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
|
||||
|
||||
addr_t offset = bus->base_addr + VIRTIO_PCI_CONFIG(bus) + _offset;
|
||||
addr_t offset = bus->base_addr + _offset;
|
||||
if (!bus->virtio1)
|
||||
offset += VIRTIO_PCI_CONFIG(bus);
|
||||
uint8* buffer = (uint8*)_buffer;
|
||||
while (bufferSize > 0) {
|
||||
uint8 size = 4;
|
||||
if (bufferSize == 1) {
|
||||
size = 1;
|
||||
*buffer = bus->pci->read_io_8(bus->device,
|
||||
offset);
|
||||
if (bus->virtio1) {
|
||||
*buffer = *(uint8*)offset;
|
||||
} else {
|
||||
*buffer = bus->pci->read_io_8(bus->device, offset);
|
||||
}
|
||||
} else if (bufferSize <= 3) {
|
||||
size = 2;
|
||||
*(uint16*)buffer = bus->pci->read_io_16(bus->device,
|
||||
offset);
|
||||
if (bus->virtio1) {
|
||||
*(uint16*)buffer = *(uint16*)offset;
|
||||
} else {
|
||||
*(uint16*)buffer = bus->pci->read_io_16(bus->device, offset);
|
||||
}
|
||||
} else {
|
||||
*(uint32*)buffer = bus->pci->read_io_32(bus->device,
|
||||
offset);
|
||||
if (bus->virtio1) {
|
||||
*(uint32*)buffer = *(uint32*)offset;
|
||||
} else {
|
||||
*(uint32*)buffer = bus->pci->read_io_32(bus->device,
|
||||
offset);
|
||||
}
|
||||
}
|
||||
buffer += size;
|
||||
bufferSize -= size;
|
||||
@ -223,28 +339,39 @@ read_device_config(void* cookie, uint8 _offset, void* _buffer,
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
static status_t
|
||||
write_device_config(void* cookie, uint8 _offset, const void* _buffer,
|
||||
size_t bufferSize)
|
||||
{
|
||||
CALLED();
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
|
||||
|
||||
addr_t offset = bus->base_addr + VIRTIO_PCI_CONFIG(bus) + _offset;
|
||||
addr_t offset = bus->base_addr + _offset;
|
||||
if (!bus->virtio1)
|
||||
offset += VIRTIO_PCI_CONFIG(bus);
|
||||
const uint8* buffer = (const uint8*)_buffer;
|
||||
while (bufferSize > 0) {
|
||||
uint8 size = 4;
|
||||
if (bufferSize == 1) {
|
||||
size = 1;
|
||||
bus->pci->write_io_8(bus->device,
|
||||
offset, *buffer);
|
||||
if (bus->virtio1) {
|
||||
*(uint8*)offset = *buffer;
|
||||
} else {
|
||||
bus->pci->write_io_8(bus->device, offset, *buffer);
|
||||
}
|
||||
} else if (bufferSize <= 3) {
|
||||
size = 2;
|
||||
bus->pci->write_io_16(bus->device,
|
||||
offset, *(const uint16*)buffer);
|
||||
if (bus->virtio1) {
|
||||
*(uint16*)offset = *(uint16*)buffer;
|
||||
} else {
|
||||
bus->pci->write_io_16(bus->device, offset, *(const uint16*)buffer);
|
||||
}
|
||||
} else {
|
||||
bus->pci->write_io_32(bus->device,
|
||||
offset, *(const uint32*)buffer);
|
||||
if (bus->virtio1) {
|
||||
*(uint32*)offset = *(uint32*)buffer;
|
||||
} else {
|
||||
bus->pci->write_io_32(bus->device, offset, *(const uint32*)buffer);
|
||||
}
|
||||
}
|
||||
buffer += size;
|
||||
bufferSize -= size;
|
||||
@ -254,32 +381,67 @@ write_device_config(void* cookie, uint8 _offset, const void* _buffer,
|
||||
}
|
||||
|
||||
|
||||
uint16
|
||||
static uint16
|
||||
get_queue_ring_size(void* cookie, uint16 queue)
|
||||
{
|
||||
CALLED();
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_SEL,
|
||||
queue);
|
||||
return bus->pci->read_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_PCI_QUEUE_NUM);
|
||||
if (bus->virtio1) {
|
||||
volatile uint16* queueSelect = (uint16*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, queue_select));
|
||||
*queueSelect = queue;
|
||||
volatile uint16* ringSize = (volatile uint16*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, queue_size));
|
||||
return *ringSize;
|
||||
} else {
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_SEL,
|
||||
queue);
|
||||
return bus->pci->read_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_PCI_QUEUE_NUM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
setup_queue(void* cookie, uint16 queue, phys_addr_t phy)
|
||||
static status_t
|
||||
setup_queue(void* cookie, uint16 queue, phys_addr_t phy, phys_addr_t phyAvail,
|
||||
phys_addr_t phyUsed)
|
||||
{
|
||||
CALLED();
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_SEL,
|
||||
queue);
|
||||
bus->pci->write_io_32(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_PFN,
|
||||
(uint32)phy >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
|
||||
if (queue >= bus->queue_count)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (bus->virtio1) {
|
||||
volatile uint16* queueSelect = (uint16*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, queue_select));
|
||||
*queueSelect = queue;
|
||||
|
||||
volatile uint64* queueDesc = (volatile uint64*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, queue_desc));
|
||||
*queueDesc = phy;
|
||||
volatile uint64* queueAvail = (volatile uint64*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, queue_avail));
|
||||
*queueAvail = phyAvail;
|
||||
volatile uint64* queueUsed = (volatile uint64*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, queue_used));
|
||||
*queueUsed = phyUsed;
|
||||
volatile uint16* queueEnable = (volatile uint16*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, queue_enable));
|
||||
*queueEnable = 1;
|
||||
|
||||
volatile uint16* queueNotifyOffset = (volatile uint16*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, queue_notify_off));
|
||||
bus->notifyOffsets[queue] = *queueNotifyOffset * bus->notifyOffsetMultiplier;
|
||||
} else {
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_SEL, queue);
|
||||
bus->pci->write_io_32(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_PFN,
|
||||
(uint32)phy >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
static status_t
|
||||
setup_interrupt(void* cookie, uint16 queueCount)
|
||||
{
|
||||
CALLED();
|
||||
@ -308,7 +470,7 @@ setup_interrupt(void* cookie, uint16 queueCount)
|
||||
}
|
||||
} else {
|
||||
uint8 vector;
|
||||
if (bus->pci->configure_msix(bus->device, queueCount + 1, &vector) == B_OK
|
||||
if (bus->pci->configure_msix(bus->device, 1, &vector) == B_OK
|
||||
&& bus->pci->enable_msix(bus->device) == B_OK) {
|
||||
TRACE_ALWAYS("using MSI-X vector shared %u\n", 1);
|
||||
bus->irq = vector;
|
||||
@ -375,7 +537,7 @@ setup_interrupt(void* cookie, uint16 queueCount)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
static status_t
|
||||
free_interrupt(void* cookie)
|
||||
{
|
||||
CALLED();
|
||||
@ -402,13 +564,20 @@ free_interrupt(void* cookie)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
notify_queue(void* cookie, uint16 queue)
|
||||
{
|
||||
CALLED();
|
||||
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_PCI_QUEUE_NOTIFY, queue);
|
||||
if (queue >= bus->queue_count)
|
||||
return;
|
||||
if (bus->virtio1) {
|
||||
volatile uint16* notifyAddr = (volatile uint16*)(bus->notifyAddr + bus->notifyOffsets[queue]);
|
||||
*notifyAddr = queue;
|
||||
} else {
|
||||
bus->pci->write_io_16(bus->device, bus->base_addr
|
||||
+ VIRTIO_PCI_QUEUE_NOTIFY, queue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -446,14 +615,89 @@ init_bus(device_node* node, void** bus_cookie)
|
||||
pci_info *pciInfo = &bus->info;
|
||||
pci->get_pci_info(device, pciInfo);
|
||||
|
||||
// legacy interrupt
|
||||
bus->base_addr = pciInfo->u.h0.base_registers[0];
|
||||
bus->virtio1 = pciInfo->revision == 1;
|
||||
|
||||
if (bus->virtio1) {
|
||||
struct virtio_pci_cap common, isr, deviceCap;
|
||||
struct virtio_pci_notify_cap notify;
|
||||
bool deviceCfgFound = false;
|
||||
if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_COMMON_CFG, &common,
|
||||
sizeof(common)) != B_OK) {
|
||||
return B_DEVICE_NOT_FOUND;
|
||||
}
|
||||
if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_ISR_CFG, &isr,
|
||||
sizeof(isr)) != B_OK) {
|
||||
return B_DEVICE_NOT_FOUND;
|
||||
}
|
||||
if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_DEVICE_CFG, &deviceCap,
|
||||
sizeof(deviceCap)) != B_OK) {
|
||||
memset(&deviceCap, 0, sizeof(deviceCap));
|
||||
} else {
|
||||
deviceCfgFound = true;
|
||||
}
|
||||
if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_NOTIFY_CFG, ¬ify,
|
||||
sizeof(notify)) != B_OK) {
|
||||
return B_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
size_t bars[6] = {0};
|
||||
if (common.length > 0)
|
||||
bars[common.bar] = common.offset + common.length;
|
||||
if (isr.length > 0)
|
||||
bars[isr.bar] = max_c(bars[isr.bar], isr.offset + isr.length);
|
||||
if (notify.cap.length > 0) {
|
||||
bars[notify.cap.bar] = max_c(bars[notify.cap.bar], notify.cap.offset
|
||||
+ notify.cap.length);
|
||||
}
|
||||
if (deviceCfgFound && deviceCap.length > 0)
|
||||
bars[deviceCap.bar] = max_c(bars[deviceCap.bar], deviceCap.offset + deviceCap.length);
|
||||
|
||||
int index = 0;
|
||||
addr_t registers[6] = {0};
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (bars[i] == 0)
|
||||
continue;
|
||||
phys_addr_t barAddr = pciInfo->u.h0.base_registers[i];
|
||||
size_t barSize = pciInfo->u.h0.base_register_sizes[i];
|
||||
if ((pciInfo->u.h0.base_register_flags[i] & PCI_address_type) == PCI_address_type_64) {
|
||||
barAddr |= (uint64)pciInfo->u.h0.base_registers[i + 1] << 32;
|
||||
barSize |= (uint64)pciInfo->u.h0.base_register_sizes[i + 1] << 32;
|
||||
}
|
||||
|
||||
bus->registersArea[i] = map_physical_memory("Virtio PCI memory mapped registers",
|
||||
barAddr, barSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
|
||||
(void **)®isters[i]);
|
||||
index++;
|
||||
}
|
||||
|
||||
bus->commonCfgAddr = registers[common.bar] + common.offset;
|
||||
bus->isrAddr = registers[isr.bar] + isr.offset;
|
||||
bus->notifyAddr = registers[notify.cap.bar] + notify.cap.offset;
|
||||
bus->notifyOffsetMultiplier = notify.notify_off_multiplier;
|
||||
if (deviceCfgFound)
|
||||
bus->base_addr = registers[deviceCap.bar] + deviceCap.offset;
|
||||
|
||||
// enable bus master and memory
|
||||
uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
|
||||
pcicmd &= ~(PCI_command_int_disable | PCI_command_io);
|
||||
pci->write_pci_config(device, PCI_command, 2,
|
||||
pcicmd | PCI_command_master | PCI_command_memory);
|
||||
|
||||
volatile uint16 *queueCount = (uint16*)(bus->commonCfgAddr
|
||||
+ offsetof(struct virtio_pci_common_cfg, num_queues));
|
||||
bus->notifyOffsets = new addr_t[*queueCount];
|
||||
|
||||
} else {
|
||||
// legacy interrupt
|
||||
bus->base_addr = pciInfo->u.h0.base_registers[0];
|
||||
|
||||
// enable bus master and io
|
||||
uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
|
||||
pcicmd &= ~(PCI_command_memory | PCI_command_int_disable);
|
||||
pcicmd |= PCI_command_master | PCI_command_io;
|
||||
pci->write_pci_config(device, PCI_command, 2, pcicmd);
|
||||
}
|
||||
|
||||
// enable bus master and io
|
||||
uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
|
||||
pcicmd &= ~(PCI_command_memory | PCI_command_int_disable);
|
||||
pcicmd |= PCI_command_master | PCI_command_io;
|
||||
pci->write_pci_config(device, PCI_command, 2, pcicmd);
|
||||
|
||||
set_status(bus, VIRTIO_CONFIG_STATUS_RESET);
|
||||
set_status(bus, VIRTIO_CONFIG_STATUS_ACK);
|
||||
@ -488,6 +732,16 @@ uninit_bus(void* bus_cookie)
|
||||
} else
|
||||
remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus);
|
||||
|
||||
if (bus->virtio1) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (bus->registersArea[i] >= 0)
|
||||
delete_area(bus->registersArea[i]);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] bus->notifyOffsets;
|
||||
delete[] bus->cookies;
|
||||
delete bus;
|
||||
}
|
||||
@ -514,11 +768,16 @@ register_child_devices(void* cookie)
|
||||
gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
|
||||
(void**)&device);
|
||||
|
||||
uint16 pciSubDeviceId = pci->read_pci_config(device, PCI_subsystem_id,
|
||||
2);
|
||||
uint16 pciSubDeviceId = pci->read_pci_config(device, PCI_subsystem_id, 2);
|
||||
uint8 pciRevision = pci->read_pci_config(device, PCI_revision, 1);
|
||||
uint16 pciDeviceId = pci->read_pci_config(device, PCI_device_id, 2);
|
||||
|
||||
uint16 virtioDeviceId = pciSubDeviceId;
|
||||
if (pciDeviceId >= VIRTIO_PCI_DEVICEID_MODERN_MIN)
|
||||
virtioDeviceId = pciDeviceId - VIRTIO_PCI_DEVICEID_MODERN_MIN;
|
||||
|
||||
char prettyName[25];
|
||||
sprintf(prettyName, "Virtio Device %" B_PRIu16, pciSubDeviceId);
|
||||
sprintf(prettyName, "Virtio Device %" B_PRIu16, virtioDeviceId);
|
||||
|
||||
device_attr attrs[] = {
|
||||
// properties of this controller for virtio bus manager
|
||||
@ -529,9 +788,11 @@ register_child_devices(void* cookie)
|
||||
|
||||
// private data to identify the device
|
||||
{ VIRTIO_DEVICE_TYPE_ITEM, B_UINT16_TYPE,
|
||||
{ .ui16 = pciSubDeviceId }},
|
||||
{ .ui16 = virtioDeviceId }},
|
||||
{ VIRTIO_VRING_ALIGNMENT_ITEM, B_UINT16_TYPE,
|
||||
{ .ui16 = VIRTIO_PCI_VRING_ALIGN }},
|
||||
{ VIRTIO_VERSION_ITEM, B_UINT8_TYPE,
|
||||
{ .ui8 = pciRevision }},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -583,7 +844,7 @@ supports_device(device_node* parent)
|
||||
|
||||
if (vendorID == VIRTIO_PCI_VENDORID) {
|
||||
if (deviceID < VIRTIO_PCI_DEVICEID_MIN
|
||||
|| deviceID > VIRTIO_PCI_DEVICEID_MAX) {
|
||||
|| deviceID > VIRTIO_PCI_DEVICEID_MODERN_MAX) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
@ -591,9 +852,16 @@ supports_device(device_node* parent)
|
||||
pci_device* device;
|
||||
gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
|
||||
(void**)&device);
|
||||
uint8 pciSubDeviceId = pci->read_pci_config(device, PCI_revision,
|
||||
uint8 pciRevision = pci->read_pci_config(device, PCI_revision,
|
||||
1);
|
||||
if (pciSubDeviceId != VIRTIO_PCI_ABI_VERSION)
|
||||
if (deviceID >= VIRTIO_PCI_DEVICEID_MIN
|
||||
&& deviceID <= VIRTIO_PCI_DEVICEID_LEGACY_MAX
|
||||
&& pciRevision != 0) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (deviceID >= VIRTIO_PCI_DEVICEID_MODERN_MIN
|
||||
&& deviceID <= VIRTIO_PCI_DEVICEID_MODERN_MAX
|
||||
&& pciRevision != 1)
|
||||
return 0.0f;
|
||||
|
||||
TRACE("Virtio device found! vendor 0x%04x, device 0x%04x\n", vendorID,
|
||||
|
@ -39,10 +39,9 @@
|
||||
/* VirtIO PCI vendor/device ID. */
|
||||
#define VIRTIO_PCI_VENDORID 0x1AF4
|
||||
#define VIRTIO_PCI_DEVICEID_MIN 0x1000
|
||||
#define VIRTIO_PCI_DEVICEID_MAX 0x103F
|
||||
|
||||
/* VirtIO ABI version, this must match exactly. */
|
||||
#define VIRTIO_PCI_ABI_VERSION 0
|
||||
#define VIRTIO_PCI_DEVICEID_LEGACY_MAX 0x103F
|
||||
#define VIRTIO_PCI_DEVICEID_MODERN_MIN 0x1040
|
||||
#define VIRTIO_PCI_DEVICEID_MODERN_MAX 0x107F
|
||||
|
||||
/*
|
||||
* VirtIO Header, located in BAR 0.
|
||||
@ -84,4 +83,63 @@
|
||||
/* The alignment to use between consumer and producer parts of vring. */
|
||||
#define VIRTIO_PCI_VRING_ALIGN 4096
|
||||
|
||||
|
||||
/*
|
||||
* Virtio 1.0 specific
|
||||
*/
|
||||
|
||||
struct virtio_pci_cap {
|
||||
uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */
|
||||
uint8_t cap_next; /* Generic PCI field: next ptr. */
|
||||
uint8_t cap_len; /* Generic PCI field: capability length */
|
||||
uint8_t cfg_type; /* Identifies the structure. */
|
||||
uint8_t bar; /* Where to find it. */
|
||||
uint8_t padding[3]; /* Pad to full dword. */
|
||||
uint32_t offset; /* Offset within bar. */
|
||||
uint32_t length; /* Length of the structure, in bytes. */
|
||||
} _PACKED;
|
||||
|
||||
/* Common configuration */
|
||||
#define VIRTIO_PCI_CAP_COMMON_CFG 1
|
||||
/* Notifications */
|
||||
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
|
||||
/* ISR Status */
|
||||
#define VIRTIO_PCI_CAP_ISR_CFG 3
|
||||
/* Device specific configuration */
|
||||
#define VIRTIO_PCI_CAP_DEVICE_CFG 4
|
||||
/* PCI configuration access */
|
||||
#define VIRTIO_PCI_CAP_PCI_CFG 5
|
||||
|
||||
struct virtio_pci_notify_cap {
|
||||
struct virtio_pci_cap cap;
|
||||
uint32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */
|
||||
} _PACKED;
|
||||
|
||||
struct virtio_pci_cfg_cap {
|
||||
struct virtio_pci_cap cap;
|
||||
uint8_t pci_cfg_data[4]; /* Data for BAR access. */
|
||||
} _PACKED;
|
||||
|
||||
struct virtio_pci_common_cfg {
|
||||
/* About the whole device. */
|
||||
uint32_t device_feature_select; /* read-write */
|
||||
uint32_t device_feature; /* read-only for driver */
|
||||
uint32_t driver_feature_select; /* read-write */
|
||||
uint32_t driver_feature; /* read-write */
|
||||
uint16_t config_msix_vector; /* read-write */
|
||||
uint16_t num_queues; /* read-only for driver */
|
||||
uint8_t device_status; /* read-write */
|
||||
uint8_t config_generation; /* read-only for driver */
|
||||
|
||||
/* About a specific virtqueue. */
|
||||
uint16_t queue_select; /* read-write */
|
||||
uint16_t queue_size; /* read-write, power of 2, or 0. */
|
||||
uint16_t queue_msix_vector; /* read-write */
|
||||
uint16_t queue_enable; /* read-write */
|
||||
uint16_t queue_notify_off; /* read-only for driver */
|
||||
uint64_t queue_desc; /* read-write */
|
||||
uint64_t queue_avail; /* read-write */
|
||||
uint64_t queue_used; /* read-write */
|
||||
} _PACKED;
|
||||
|
||||
#endif /* _VIRTIO_PCI_H */
|
||||
|
@ -55,7 +55,7 @@ typedef struct {
|
||||
|
||||
struct virtio_blk_config config;
|
||||
|
||||
uint32 features;
|
||||
uint64 features;
|
||||
uint64 capacity;
|
||||
uint32 block_size;
|
||||
uint32 physical_block_size;
|
||||
@ -98,7 +98,7 @@ bool virtio_block_set_capacity(virtio_block_driver_info* info);
|
||||
|
||||
|
||||
const char *
|
||||
get_feature_name(uint32 feature)
|
||||
get_feature_name(uint64 feature)
|
||||
{
|
||||
switch (feature) {
|
||||
case VIRTIO_BLK_F_BARRIER:
|
||||
|
@ -51,7 +51,7 @@ struct VirtioInputDevice {
|
||||
virtio_device_interface* virtio;
|
||||
::virtio_queue virtio_queue;
|
||||
|
||||
uint32 features;
|
||||
uint64 features;
|
||||
|
||||
uint32 packetCnt;
|
||||
int32 freePackets;
|
||||
|
@ -57,7 +57,7 @@ typedef struct {
|
||||
::virtio_device virtio_device;
|
||||
virtio_device_interface* virtio;
|
||||
|
||||
uint32 features;
|
||||
uint64 features;
|
||||
|
||||
uint32 pairsCount;
|
||||
|
||||
@ -123,7 +123,7 @@ static void virtio_net_txDone(void* driverCookie, void* cookie);
|
||||
|
||||
|
||||
const char*
|
||||
get_feature_name(uint32 feature)
|
||||
get_feature_name(uint64 feature)
|
||||
{
|
||||
switch (feature) {
|
||||
case VIRTIO_NET_F_CSUM:
|
||||
@ -195,6 +195,7 @@ virtio_net_drain_queues(virtio_net_driver_info* info)
|
||||
static status_t
|
||||
virtio_net_rx_enqueue_buf(virtio_net_driver_info* info, BufInfo* buf)
|
||||
{
|
||||
CALLED();
|
||||
physical_entry entries[2];
|
||||
entries[0] = buf->hdrEntry;
|
||||
entries[1] = buf->entry;
|
||||
|
@ -54,8 +54,10 @@
|
||||
#define VIRTIO_NET_F_GUEST_ANNOUNCE 0x200000 /* Announce device on network */
|
||||
#define VIRTIO_NET_F_MQ 0x400000 /* Device supports RFS */
|
||||
#define VIRTIO_NET_F_CTRL_MAC_ADDR 0x800000 /* Set MAC address */
|
||||
#define VIRTIO_NET_F_SPEED_DUPLEX (1ULL << 63) /* Device set linkspeed and duplex */
|
||||
|
||||
#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
|
||||
#define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */
|
||||
|
||||
struct virtio_net_config {
|
||||
/* The config defining mac address (if VIRTIO_NET_F_MAC) */
|
||||
@ -68,6 +70,8 @@ struct virtio_net_config {
|
||||
*/
|
||||
uint16_t max_virtqueue_pairs;
|
||||
uint16_t mtu;
|
||||
uint32_t speed;
|
||||
uint8_t duplex;
|
||||
} _PACKED;
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user