Comparar commits
2 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 5c64a1c8d4 | |||
| 360ed32e18 |
@@ -330,6 +330,42 @@ mx_status_t sys_pci_get_nth_device(mx_handle_t hrsrc,
|
||||
return MX_OK;
|
||||
}
|
||||
|
||||
mx_status_t sys_pci_config_read(mx_handle_t handle, uint16_t offset, size_t width,
|
||||
user_ptr<uint32_t> out_val) {
|
||||
mxtl::RefPtr<PciDeviceDispatcher> pci_device;
|
||||
mxtl::RefPtr<Dispatcher> dispatcher;
|
||||
|
||||
if (handle == MX_HANDLE_INVALID) {
|
||||
return MX_ERR_BAD_HANDLE;
|
||||
}
|
||||
|
||||
if (out_val.get() == nullptr) {
|
||||
return MX_ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// Get the PciDeviceDispatcher from the handle passed in via the pci protocol
|
||||
auto up = ProcessDispatcher::GetCurrent();
|
||||
mx_status_t status = up->GetDispatcherWithRights(handle, MX_RIGHT_READ | MX_RIGHT_WRITE,
|
||||
&pci_device);
|
||||
if (status != MX_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Based on the width passed in we can use the type safety of the PciConfig layer
|
||||
// to ensure we're getting correctly sized data back and return errors in the PIO
|
||||
// cases.
|
||||
auto config = pci_device->device()->config();
|
||||
switch(width) {
|
||||
case 8u: return out_val.copy_to_user(static_cast<uint32_t>(config->Read(PciReg8(offset))));
|
||||
case 16u: return out_val.copy_to_user(static_cast<uint32_t>(config->Read(PciReg16(offset))));
|
||||
case 32u: return out_val.copy_to_user(config->Read(PciReg32(offset)));
|
||||
default: return MX_ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// If we reached this point then the width was invalid.
|
||||
return MX_ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
/* This is a transitional method to bootstrap legacy PIO access before
|
||||
* PCI moves to userspace.
|
||||
*/
|
||||
@@ -713,6 +749,16 @@ mx_status_t sys_pci_add_subtract_io_range(mx_handle_t handle, bool mmio, uint64_
|
||||
return MX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
mx_status_t sys_pci_config_read(mx_handle_t handle, uint16_t offset, size_t width,
|
||||
user_ptr<uint32_t> out_val) {
|
||||
return MX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
mx_status_t sys_pci_cfg_pio_rw(mx_handle_t handle, uint8_t bus, uint8_t dev, uint8_t func,
|
||||
uint8_t offset, user_ptr<uint32_t> val, size_t width, bool write) {
|
||||
return MX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
mx_status_t sys_pci_get_nth_device(mx_handle_t, uint32_t, user_ptr<mx_pcie_device_info_t>,
|
||||
user_ptr<mx_handle_t>) {
|
||||
return MX_ERR_NOT_SUPPORTED;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <magenta/assert.h>
|
||||
#include <magenta/process.h>
|
||||
|
||||
#include "kpci-private.h"
|
||||
@@ -51,10 +52,53 @@ static mx_status_t do_resource_bookkeeping(mx_pci_resource_t* res) {
|
||||
return status;
|
||||
}
|
||||
|
||||
static mx_status_t pci_get_resource(void* ctx, uint32_t res_id, mx_pci_resource_t* out_res) {
|
||||
|
||||
// These reads are proxied directly over to the device's PciConfig object so the validity of the
|
||||
// widths and offsets will be validated on that end and then trickle back to this level of the
|
||||
// protocol.
|
||||
//
|
||||
// In the case of config and capability reads/writes, failure is a catastrophic occurrence
|
||||
// along the lines of hardware failure or a device being removed from the bus. Due to this,
|
||||
// those statuses will be asserted upon rather than forcing callers to add additional checks
|
||||
// every time they wish to do a config read / write.
|
||||
static uint32_t kpci_config_read(void* ctx, uint8_t offset, size_t width) {
|
||||
MX_DEBUG_ASSERT(ctx);
|
||||
kpci_device_t* device = ctx;
|
||||
uint32_t val;
|
||||
|
||||
mx_status_t status = mx_pci_config_read(device->handle, offset, width, &val);
|
||||
MX_DEBUG_ASSERT_MSG(status == MX_OK, "pci_config_read: %d\n", status);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint8_t kpci_get_next_capability(void* ctx, uint8_t offset, uint8_t type) {
|
||||
uint8_t cap_offset = (uint8_t)kpci_config_read(ctx, offset + 1, 8);
|
||||
uint8_t limit = 64;
|
||||
|
||||
// Walk the capability list looking for the type requested, starting at the offset
|
||||
// passed in. limit acts as a barrier in case of an invalid capability pointer list
|
||||
// that causes us to iterate forever otherwise.
|
||||
while (cap_offset != 0 && limit--) {
|
||||
uint8_t type_id = (uint8_t)kpci_config_read(ctx, cap_offset, 8);
|
||||
printf("kpci_get_next_capability loop offset %u, type %u\n", cap_offset, type_id);
|
||||
if (type_id == type) {
|
||||
printf("kpci_get_next_capability: returning %u\n", cap_offset);
|
||||
return cap_offset;
|
||||
}
|
||||
|
||||
// We didn't find the right type, move on
|
||||
cap_offset = (uint8_t)kpci_config_read(ctx, cap_offset + 1, 8);
|
||||
}
|
||||
|
||||
// No more entries are in the list
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mx_status_t kpci_get_resource(void* ctx, uint32_t res_id, mx_pci_resource_t* out_res) {
|
||||
mx_status_t status = MX_OK;
|
||||
|
||||
if (!out_res || res_id >= PCI_RESOURCE_COUNT) {
|
||||
printf("????\n");
|
||||
return MX_ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
@@ -98,7 +142,7 @@ static mx_status_t kpci_map_resource(void* ctx,
|
||||
}
|
||||
|
||||
mx_pci_resource_t resource;
|
||||
mx_status_t status = pci_get_resource(ctx, res_id, &resource);
|
||||
mx_status_t status = kpci_get_resource(ctx, res_id, &resource);
|
||||
if (status != MX_OK) {
|
||||
return status;
|
||||
}
|
||||
@@ -188,9 +232,12 @@ static pci_protocol_ops_t _pci_protocol = {
|
||||
.enable_bus_master = kpci_enable_bus_master,
|
||||
.enable_pio = kpci_enable_pio,
|
||||
.reset_device = kpci_reset_device,
|
||||
.get_resource = kpci_get_resource,
|
||||
.map_resource = kpci_map_resource,
|
||||
.map_interrupt = kpci_map_interrupt,
|
||||
.query_irq_mode_caps = kpci_query_irq_mode_caps,
|
||||
.set_irq_mode = kpci_set_irq_mode,
|
||||
.get_device_info = kpci_get_device_info,
|
||||
.config_read = kpci_config_read,
|
||||
.get_next_capability = kpci_get_next_capability,
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -17,7 +18,7 @@
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
#define LOCAL_TRACE 1
|
||||
|
||||
namespace virtio {
|
||||
|
||||
@@ -31,15 +32,31 @@ Device::~Device() {
|
||||
LTRACE_ENTRY;
|
||||
}
|
||||
|
||||
static void ReadVirtioCap(pci_protocol_t* pci, uint8_t offset, virtio_pci_cap& cap) {
|
||||
cap.cap_vndr = pci_config_read8(pci, static_cast<uint8_t>(offset + offsetof(virtio_pci_cap, cap_vndr)));
|
||||
cap.cap_next = pci_config_read8(pci, static_cast<uint8_t>(offset + offsetof(virtio_pci_cap, cap_next)));
|
||||
cap.cap_len = pci_config_read8(pci, static_cast<uint8_t>(offset + offsetof(virtio_pci_cap, cap_len)));
|
||||
cap.cfg_type = pci_config_read8(pci, static_cast<uint8_t>(offset + offsetof(virtio_pci_cap, cfg_type)));
|
||||
cap.bar = pci_config_read8(pci, static_cast<uint8_t>(offset + offsetof(virtio_pci_cap, bar)));
|
||||
cap.padding[0] = pci_config_read8(pci, static_cast<uint8_t>(offset + offsetof(virtio_pci_cap, padding)));
|
||||
cap.padding[1] = pci_config_read8(pci, static_cast<uint8_t>(offset + offsetof(virtio_pci_cap, padding) + 1));
|
||||
cap.padding[2] = pci_config_read8(pci, static_cast<uint8_t>(offset + offsetof(virtio_pci_cap, padding) + 2));
|
||||
cap.offset = pci_config_read32(pci, static_cast<uint8_t>(offset + offsetof(virtio_pci_cap, offset)));
|
||||
cap.length = pci_config_read32(pci, static_cast<uint8_t>(offset + offsetof(virtio_pci_cap, length)));
|
||||
}
|
||||
|
||||
mx_status_t Device::MapBar(uint8_t i) {
|
||||
LTRACEF("bar %u\n", i);
|
||||
if (bar_[i].mmio_handle != MX_HANDLE_INVALID)
|
||||
return MX_OK;
|
||||
|
||||
uint64_t sz;
|
||||
mx_handle_t tmp_handle;
|
||||
|
||||
TRACE;
|
||||
mx_status_t r = pci_map_resource(&pci_, PCI_RESOURCE_BAR_0 + i, MX_CACHE_POLICY_UNCACHED_DEVICE,
|
||||
(void**)&bar_[i].mmio_base, &sz, &tmp_handle);
|
||||
TRACE;
|
||||
if (r != MX_OK) {
|
||||
VIRTIO_ERROR("cannot map io %d\n", bar_[i].mmio_handle.get());
|
||||
return r;
|
||||
@@ -50,8 +67,7 @@ mx_status_t Device::MapBar(uint8_t i) {
|
||||
return MX_OK;
|
||||
}
|
||||
|
||||
mx_status_t Device::Bind(pci_protocol_t* pci,
|
||||
mx_handle_t pci_config_handle, const pci_config_t* pci_config) {
|
||||
mx_status_t Device::Bind(pci_protocol_t* pci, mx_pcie_device_info_t info) {
|
||||
LTRACE_ENTRY;
|
||||
|
||||
mxtl::AutoLock lock(&lock_);
|
||||
@@ -59,8 +75,7 @@ mx_status_t Device::Bind(pci_protocol_t* pci,
|
||||
|
||||
// save off handles to things
|
||||
memcpy(&pci_, pci, sizeof(pci_protocol_t));
|
||||
pci_config_handle_.reset(pci_config_handle);
|
||||
pci_config_ = pci_config;
|
||||
info_ = info;
|
||||
|
||||
// enable bus mastering
|
||||
mx_status_t r;
|
||||
@@ -89,101 +104,63 @@ mx_status_t Device::Bind(pci_protocol_t* pci,
|
||||
LTRACEF("irq handle %u\n", irq_handle_.get());
|
||||
|
||||
// try to parse capabilities
|
||||
if (pci_config_->status & PCI_STATUS_NEW_CAPS) {
|
||||
LTRACEF("pci config capabilities_ptr 0x%x\n", pci_config_->capabilities_ptr);
|
||||
for (uint8_t off = pci_get_first_capability(&pci_, kPciCapIdVendor);
|
||||
off != 0;
|
||||
off = pci_get_next_capability(&pci_, off, kPciCapIdVendor)) {
|
||||
virtio_pci_cap cap;
|
||||
|
||||
size_t off = pci_config_->capabilities_ptr;
|
||||
for (int i = 0; i < 64; i++) { // only loop so many times in case things out of whack
|
||||
virtio_pci_cap *cap;
|
||||
|
||||
if (off > PAGE_SIZE) {
|
||||
VIRTIO_ERROR("capability pointer is out of whack %zu\n", off);
|
||||
return MX_ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
cap = (virtio_pci_cap *)(((uintptr_t)pci_config_) + off);
|
||||
LTRACEF("cap %p: type %#hhx next %#hhx len %#hhx cfg_type %#hhx bar %#hhx offset %#x length %#x\n",
|
||||
cap, cap->cfg_type, cap->cap_next, cap->cap_len, cap->cfg_type, cap->bar, cap->offset, cap->length);
|
||||
|
||||
if (cap->cap_vndr == 0x9) { // vendor specific capability
|
||||
switch (cap->cfg_type) {
|
||||
case VIRTIO_PCI_CAP_COMMON_CFG: {
|
||||
MapBar(cap->bar);
|
||||
mmio_regs_.common_config = (volatile virtio_pci_common_cfg*)((uintptr_t)bar_[cap->bar].mmio_base + cap->offset);
|
||||
LTRACEF("common_config %p\n", mmio_regs_.common_config);
|
||||
break;
|
||||
}
|
||||
case VIRTIO_PCI_CAP_NOTIFY_CFG: {
|
||||
MapBar(cap->bar);
|
||||
mmio_regs_.notify_base = (volatile uint16_t*)((uintptr_t)bar_[cap->bar].mmio_base + cap->offset);
|
||||
LTRACEF("notify_base %p\n", mmio_regs_.notify_base);
|
||||
mmio_regs_.notify_mul = ((virtio_pci_notify_cap *) cap)->notify_off_multiplier;
|
||||
LTRACEF("notify_mul %x\n", mmio_regs_.notify_mul);
|
||||
break;
|
||||
}
|
||||
case VIRTIO_PCI_CAP_ISR_CFG: {
|
||||
MapBar(cap->bar);
|
||||
mmio_regs_.isr_status = (volatile uint32_t*)((uintptr_t)bar_[cap->bar].mmio_base + cap->offset);
|
||||
LTRACEF("isr_status %p\n", mmio_regs_.isr_status);
|
||||
break;
|
||||
}
|
||||
case VIRTIO_PCI_CAP_DEVICE_CFG: {
|
||||
MapBar(cap->bar);
|
||||
mmio_regs_.device_config = (volatile void*)((uintptr_t)bar_[cap->bar].mmio_base + cap->offset);
|
||||
LTRACEF("device_config %p\n", mmio_regs_.device_config);
|
||||
break;
|
||||
}
|
||||
case VIRTIO_PCI_CAP_PCI_CFG: {
|
||||
// will be pointing at bar0, which we'll map below anyway
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
off = cap->cap_next;
|
||||
if (cap->cap_next == 0)
|
||||
ReadVirtioCap(&pci_, off, cap);
|
||||
LTRACEF("cap type %#hhx next %#hhx len %#hhx cfg_type %#hhx bar %#hhx "
|
||||
"offset %#x length %#x\n", cap.cap_vndr, cap.cap_next, cap.cap_len, cap.cfg_type, cap.bar, cap.offset, cap.length);
|
||||
switch (cap.cfg_type) {
|
||||
case VIRTIO_PCI_CAP_COMMON_CFG: {
|
||||
MapBar(cap.bar);
|
||||
mmio_regs_.common_config = (volatile virtio_pci_common_cfg*)((uintptr_t)bar_[cap.bar].mmio_base + cap.offset);
|
||||
LTRACEF("common_config %p\n", mmio_regs_.common_config);
|
||||
break;
|
||||
}
|
||||
case VIRTIO_PCI_CAP_NOTIFY_CFG: {
|
||||
MapBar(cap.bar);
|
||||
mmio_regs_.notify_base = (volatile uint16_t*)((uintptr_t)bar_[cap.bar].mmio_base + cap.offset);
|
||||
uint8_t notify_mul_off = static_cast<uint8_t>(off + offsetof(virtio_pci_notify_cap, notify_off_multiplier));
|
||||
mmio_regs_.notify_mul = pci_config_read32(&pci_, notify_mul_off);
|
||||
LTRACEF("notify_base %p\n", mmio_regs_.notify_base);
|
||||
LTRACEF("notify_mul %x\n", mmio_regs_.notify_mul);
|
||||
break;
|
||||
}
|
||||
case VIRTIO_PCI_CAP_ISR_CFG: {
|
||||
MapBar(cap.bar);
|
||||
mmio_regs_.isr_status = (volatile uint32_t*)((uintptr_t)bar_[cap.bar].mmio_base + cap.offset);
|
||||
LTRACEF("isr_status %p\n", mmio_regs_.isr_status);
|
||||
break;
|
||||
}
|
||||
case VIRTIO_PCI_CAP_DEVICE_CFG: {
|
||||
MapBar(cap.bar);
|
||||
mmio_regs_.device_config = (volatile void*)((uintptr_t)bar_[cap.bar].mmio_base + cap.offset);
|
||||
LTRACEF("device_config %p\n", mmio_regs_.device_config);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we've found mmio pointers to everything from the capability structure, then skip mapping bar0, since we don't
|
||||
// need legacy pio access from BAR0
|
||||
if (!(mmio_regs_.common_config && mmio_regs_.notify_base && mmio_regs_.isr_status && mmio_regs_.device_config)) {
|
||||
// transitional devices have a single PIO window at BAR0
|
||||
if (pci_config_->base_addresses[0] & 0x1) {
|
||||
// look at BAR0, which should be a PIO memory window
|
||||
bar0_pio_base_ = pci_config->base_addresses[0];
|
||||
LTRACEF("BAR0 address %#x\n", bar0_pio_base_);
|
||||
if ((bar0_pio_base_ & 0x1) == 0) {
|
||||
VIRTIO_ERROR("bar 0 does not appear to be PIO (address %#x, aborting\n", bar0_pio_base_);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bar0_pio_base_ &= ~1;
|
||||
if (bar0_pio_base_ > 0xffff) {
|
||||
bar0_pio_base_ = 0;
|
||||
|
||||
r = MapBar(0);
|
||||
if (r != MX_OK) {
|
||||
VIRTIO_ERROR("cannot mmap io %d\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
LTRACEF("bar_[0].mmio_base %p\n", bar_[0].mmio_base);
|
||||
} else {
|
||||
// this is probably PIO
|
||||
r = mx_mmap_device_io(get_root_resource(), bar0_pio_base_, bar0_size_);
|
||||
if (r != MX_OK) {
|
||||
VIRTIO_ERROR("failed to access PIO range %#x, length %#xw\n", bar0_pio_base_, bar0_size_);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
// enable pio access
|
||||
if ((r = pci_enable_pio(&pci_, true)) < 0) {
|
||||
VIRTIO_ERROR("cannot enable PIO %d\n", r);
|
||||
// if we've found mmio pointers to everything from the capability structure,
|
||||
// then skip mapping bar0, since we don't need legacy pio access from BAR0
|
||||
if (!(mmio_regs_.common_config && mmio_regs_.notify_base &&
|
||||
mmio_regs_.isr_status && mmio_regs_.device_config)) {
|
||||
mx_pci_resource_t bar0;
|
||||
r = MapBar(0);
|
||||
if (r == MX_OK) {
|
||||
LTRACEF("bar_[0].mmio_base %p\n", bar_[0].mmio_base);
|
||||
} else if (r == MX_ERR_NOT_FOUND) {
|
||||
r = pci_get_resource(&pci_, PCI_RESOURCE_BAR_0, &bar0);
|
||||
if (r != MX_OK || bar0.type != PCI_RESOURCE_TYPE_PIO) {
|
||||
VIRTIO_ERROR("failed to get PIO BAR0: %d\n", r);
|
||||
return -1;
|
||||
}
|
||||
bar0_pio_base_ = static_cast<uint32_t>(bar0.pio_addr);
|
||||
LTRACEF("Using PIO bar0, base: %d\n", bar0_pio_base_);
|
||||
} else {
|
||||
LTRACEF("Failed to do the bar0 thing\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
mx_device_t* bus_device() { return bus_device_; }
|
||||
mx_device_t* device() { return device_; }
|
||||
|
||||
virtual mx_status_t Bind(pci_protocol_t*, mx_handle_t pci_config_handle, const pci_config_t*);
|
||||
virtual mx_status_t Bind(pci_protocol_t*, mx_pcie_device_info_t info);
|
||||
virtual mx_status_t Init() = 0;
|
||||
virtual void Unbind();
|
||||
virtual void Release();
|
||||
@@ -60,9 +60,8 @@ protected:
|
||||
|
||||
// handles to pci bits
|
||||
pci_protocol_t pci_ = { nullptr, nullptr };
|
||||
mx::handle pci_config_handle_ = {};
|
||||
const pci_config_t* pci_config_ = nullptr;
|
||||
mx::handle irq_handle_ = {};
|
||||
mx_pcie_device_info_t info_;
|
||||
|
||||
// bar0 memory map or PIO
|
||||
uint32_t bar0_pio_base_ = 0;
|
||||
|
||||
@@ -10,18 +10,15 @@
|
||||
#include <ddk/device.h>
|
||||
#include <ddk/driver.h>
|
||||
#include <ddk/protocol/pci.h>
|
||||
|
||||
#include <mxtl/alloc_checker.h>
|
||||
#include <mxtl/unique_ptr.h>
|
||||
|
||||
#include <magenta/compiler.h>
|
||||
#include <magenta/types.h>
|
||||
|
||||
#include "block.h"
|
||||
#include "device.h"
|
||||
#include "trace.h"
|
||||
#include "ethernet.h"
|
||||
#include "gpu.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
@@ -38,22 +35,18 @@ extern "C" mx_status_t virtio_bind(void* ctx, mx_device_t* device, void** cookie
|
||||
return -1;
|
||||
}
|
||||
|
||||
const pci_config_t* config;
|
||||
size_t config_size;
|
||||
mx_handle_t config_handle = MX_HANDLE_INVALID;
|
||||
status = pci_map_resource(&pci, PCI_RESOURCE_CONFIG, MX_CACHE_POLICY_UNCACHED_DEVICE,
|
||||
(void**)&config, &config_size, &config_handle);
|
||||
mx_pcie_device_info_t info;
|
||||
status = pci_get_device_info(&pci, &info);
|
||||
if (status != MX_OK) {
|
||||
TRACEF("failed to grab config handle\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
LTRACEF("pci %p\n", &pci);
|
||||
LTRACEF("0x%x:0x%x\n", config->vendor_id, config->device_id);
|
||||
LTRACEF("0x%x:0x%x\n", info.vendor_id, info.device_id);
|
||||
|
||||
// TODO: Make symbols for these constants and reuse in the BIND protocol.
|
||||
// XXX TODO: Make symbols for these constants and reuse in the BIND protocol.
|
||||
mxtl::unique_ptr<virtio::Device> vd = nullptr;
|
||||
switch (config->device_id) {
|
||||
switch (info.device_id) {
|
||||
case 0x1000:
|
||||
LTRACEF("found net device\n");
|
||||
vd.reset(new virtio::EthernetDevice(device));
|
||||
@@ -73,7 +66,7 @@ extern "C" mx_status_t virtio_bind(void* ctx, mx_device_t* device, void** cookie
|
||||
}
|
||||
|
||||
LTRACEF("calling Bind on driver\n");
|
||||
status = vd->Bind(&pci, config_handle, config);
|
||||
status = vd->Bind(&pci, info);
|
||||
if (status != MX_OK)
|
||||
return status;
|
||||
|
||||
|
||||
@@ -566,6 +566,10 @@ syscall pci_reset_device
|
||||
(handle: mx_handle_t)
|
||||
returns (mx_status_t);
|
||||
|
||||
syscall pci_config_read
|
||||
(handle: mx_handle_t, offset: uint16_t, width: size_t, out_val: uint32_t[1] OUT)
|
||||
returns (mx_status_t);
|
||||
|
||||
syscall pci_cfg_pio_rw
|
||||
(handle: mx_handle_t, bus: uint8_t, dev: uint8_t, func: uint8_t, offset: uint8_t,
|
||||
val: uint32_t[1] OUT, width: size_t, write: bool)
|
||||
|
||||
@@ -28,7 +28,41 @@ enum pci_resource_ids {
|
||||
PCI_RESOURCE_COUNT,
|
||||
};
|
||||
|
||||
enum pci_header_fields {
|
||||
kPciCfgVendorId = 0x00,
|
||||
kPciCfgDeviceId = 0x02,
|
||||
kPciCfgRevisionId = 0x08,
|
||||
kPciCfgClassCode = 0x09,
|
||||
kPciCfgSubsystemVendorId = 0x2C,
|
||||
kPciCfgSubsystemId = 0x2E,
|
||||
kPciCfgCapabilitiesPtr = 0x34,
|
||||
};
|
||||
|
||||
enum pci_cap_types {
|
||||
kPciCapIdNull = 0x00,
|
||||
kPciCapIdPciPwrMgmt = 0x01,
|
||||
kPciCapIdAgp = 0x02,
|
||||
kPciCapIdVpd = 0x03,
|
||||
kPciCapIdMsi = 0x05,
|
||||
kPciCapIdPcix = 0x07,
|
||||
kPciCapIdHypertransport = 0x08,
|
||||
kPciCapIdVendor = 0x09,
|
||||
kPciCapIdDebugPort = 0x0A,
|
||||
kPciCapIdCompactPciCrc = 0x0B,
|
||||
kPciCapIdPciHotplug = 0x0C,
|
||||
kPciCapIdPciBridgeSubsystemVid = 0x0D,
|
||||
kPciCapIdAgp8x = 0x0E,
|
||||
kPciCapIdSecureDevice = 0x0F,
|
||||
kPciCapIdPciExpress = 0x10,
|
||||
kPciCapIdMsix = 0x11,
|
||||
kPciCapIdSataDataNdxCfg = 0x12,
|
||||
kPciCapIdAdvancedFeatures = 0x13,
|
||||
PciCapIdEnhancedAllocation = 0x14,
|
||||
};
|
||||
|
||||
|
||||
typedef struct pci_protocol_ops {
|
||||
mx_status_t (*get_resource)(void* ctx, uint32_t res_id, mx_pci_resource_t* out_res);
|
||||
mx_status_t (*map_resource)(void* ctx, uint32_t res_id, uint32_t cache_policy,
|
||||
void** vaddr, size_t* size, mx_handle_t* out_handle);
|
||||
mx_status_t (*enable_bus_master)(void* ctx, bool enable);
|
||||
@@ -40,6 +74,8 @@ typedef struct pci_protocol_ops {
|
||||
mx_status_t (*set_irq_mode)(void* ctx, mx_pci_irq_mode_t mode,
|
||||
uint32_t requested_irq_count);
|
||||
mx_status_t (*get_device_info)(void* ctx, mx_pcie_device_info_t* out_info);
|
||||
uint32_t (*config_read)(void* ctx, uint8_t offset, size_t width);
|
||||
uint8_t (*get_next_capability)(void* ctx, uint8_t type, uint8_t offset);
|
||||
} pci_protocol_ops_t;
|
||||
|
||||
typedef struct pci_protocol {
|
||||
@@ -47,6 +83,11 @@ typedef struct pci_protocol {
|
||||
void* ctx;
|
||||
} pci_protocol_t;
|
||||
|
||||
static inline mx_status_t pci_get_resource(pci_protocol_t* pci, uint32_t res_id,
|
||||
mx_pci_resource_t* out_info) {
|
||||
return pci->ops->get_resource(pci->ctx, res_id, out_info);
|
||||
}
|
||||
|
||||
static inline mx_status_t pci_map_resource(pci_protocol_t* pci, uint32_t res_id,
|
||||
uint32_t cache_policy, void** vaddr, size_t* size,
|
||||
mx_handle_t* out_handle) {
|
||||
@@ -85,4 +126,27 @@ static inline mx_status_t pci_get_device_info(pci_protocol_t* pci,
|
||||
return pci->ops->get_device_info(pci->ctx, out_info);
|
||||
}
|
||||
|
||||
static inline uint8_t pci_config_read8(pci_protocol_t* pci, uint8_t offset) {
|
||||
return (uint8_t)(pci->ops->config_read(pci->ctx, offset, 8u) & 0XFF);
|
||||
}
|
||||
|
||||
static inline uint16_t pci_config_read16(pci_protocol_t* pci, uint8_t offset) {
|
||||
return (uint16_t)(pci->ops->config_read(pci->ctx, offset, 16u) & 0xFFFF);
|
||||
}
|
||||
|
||||
static inline uint32_t pci_config_read32(pci_protocol_t* pci, uint8_t offset) {
|
||||
return pci->ops->config_read(pci->ctx, offset, 32u);
|
||||
}
|
||||
|
||||
static uint8_t pci_get_next_capability(pci_protocol_t* pci, uint8_t type, uint8_t offset) {
|
||||
return pci->ops->get_next_capability(pci->ctx, type, offset);
|
||||
}
|
||||
|
||||
static uint8_t pci_get_first_capability(pci_protocol_t* pci, uint8_t type) {
|
||||
// the next_capability method will always look at the second byte next
|
||||
// pointer to fetch the next capability. By offsetting the CapPtr field
|
||||
// by -1 we can pretend we're working with a normal capability entry
|
||||
return pci_get_next_capability(pci, kPciCfgCapabilitiesPtr - 1u, type);
|
||||
}
|
||||
|
||||
__END_CDECLS;
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário