blob: 6ea26199eeedeb3f27343b97fd4d1af24a33929b [file] [log] [blame]
// Copyright 2019 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.
#include <err.h>
#include <lib/zx/resource.h>
#include <lib/zx/status.h>
#include <lib/zx/vmo.h>
#include <zircon/rights.h>
#include <zircon/status.h>
#include <cassert>
#include <cinttypes>
#include <cstring>
#include <memory>
#include <fbl/algorithm.h>
#include "src/devices/bus/drivers/pci/common.h"
#include "src/devices/bus/drivers/pci/root.h"
#include "src/devices/bus/drivers/pci/upstream_node.h"
namespace pci {
zx_status_t PciAllocation::CreateVmObject(zx::vmo* out_vmo) const {
return zx::vmo::create_physical(resource(), base(), size(), out_vmo);
}
zx::status<std::unique_ptr<PciAllocation>> PciRootAllocator::Allocate(
std::optional<zx_paddr_t> base, size_t size) {
zx_paddr_t in_base = (base) ? *base : 0;
zx_paddr_t out_base = {};
zx::resource res = {};
zx::eventpair ep = {};
zx_status_t status = pciroot_.GetAddressSpace(in_base, size, type_, low_, &out_base, &res, &ep);
if (status != ZX_OK) {
bool mmio = type_ == PCI_ADDRESS_SPACE_MEMORY;
// This error may not be fatal, the Device probe/allocation methods will know for sure.
zxlogf(DEBUG, "failed to allocate %s %s [%#8lx, %#8lx) from root: %s", (mmio) ? "mmio" : "io",
(mmio) ? ((low_) ? "<4GB" : ">4GB") : "", in_base, in_base + size,
zx_status_get_string(status));
return zx::error(status);
}
auto allocation = std::unique_ptr<PciAllocation>(
new PciRootAllocation(pciroot_, type_, std::move(res), std::move(ep), out_base, size));
return zx::ok(std::move(allocation));
}
zx::status<std::unique_ptr<PciAllocation>> PciRegionAllocator::Allocate(
std::optional<zx_paddr_t> base, size_t size) {
if (!parent_alloc_) {
return zx::error(ZX_ERR_NO_MEMORY);
}
RegionAllocator::Region::UPtr region_uptr;
zx_status_t status = ZX_OK;
// Only use base if it is non-zero. RegionAllocator's interface is overloaded so we have
// to call it differently.
if (base) {
ralloc_region_t request = {
.base = (base) ? *base : 0,
.size = size,
};
status = allocator_.GetRegion(request, region_uptr);
} else {
status = allocator_.GetRegion(size, ZX_PAGE_SIZE, region_uptr);
}
if (status != ZX_OK) {
return zx::error(status);
}
zx::resource out_resource = {};
// TODO(fxbug.dev/32978): When the resource subset CL lands, make this a smaller resource.
status = parent_alloc_->resource().duplicate(ZX_DEFAULT_RESOURCE_RIGHTS, &out_resource);
if (status != ZX_OK) {
return zx::error(status);
}
zxlogf(TRACE, "bridge: assigned [%#lx, %#lx) downstream", region_uptr->base,
region_uptr->base + size);
auto allocation = std::unique_ptr<PciAllocation>(
new PciRegionAllocation(std::move(out_resource), std::move(region_uptr)));
return zx::ok(std::move(allocation));
}
zx_status_t PciRegionAllocator::SetParentAllocation(std::unique_ptr<PciAllocation> alloc) {
ZX_DEBUG_ASSERT(!parent_alloc_);
parent_alloc_ = std::move(alloc);
auto base = parent_alloc_->base();
auto size = parent_alloc_->size();
return allocator_.AddRegion({.base = base, .size = size});
}
} // namespace pci