blob: 56687b85b000214fb8d7c8f3753cd163ce6029df [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 "common.h"
#include "root.h"
#include "upstream_node.h"
#include <cassert>
#include <cinttypes>
#include <cstring>
#include <err.h>
#include <fbl/algorithm.h>
#include <fbl/auto_call.h>
#include <lib/zx/resource.h>
#include <lib/zx/vmo.h>
#include <memory>
#include <zircon/rights.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_t PciRootAllocator::AllocateWindow(zx_paddr_t in_base, size_t size,
std::unique_ptr<PciAllocation>* out_alloc) {
zx_paddr_t out_base;
zx::resource res;
zx_status_t status = pciroot_.GetAddressSpace(size, in_base, type_, low_, &out_base, &res);
if (status != ZX_OK) {
pci_errorf("failed to allocate [%#8lx, %#8lx, %s] from root: %d\n", in_base, size,
(type_ == PCI_ADDRESS_SPACE_MMIO) ? "mmio" : "io", status);
return status;
}
auto cleanup = fbl::MakeAutoCall([&]() { pciroot_.FreeAddressSpace(out_base, size, type_); });
*out_alloc = std::make_unique<PciRootAllocation>(pciroot_, type_, std::move(res), out_base, size);
cleanup.cancel();
return ZX_OK;
}
zx_status_t PciRootAllocator::GrantAddressSpace(std::unique_ptr<PciAllocation> alloc) {
// PciRootAllocations will free any space they hold when they are destroyed,
// and nothing grants anything to PciRootAllocator.
alloc.release();
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t PciRegionAllocator::AllocateWindow(zx_paddr_t base, size_t size,
std::unique_ptr<PciAllocation>* out_alloc) {
if (!backing_alloc_) {
return ZX_ERR_NO_MEMORY;
}
RegionAllocator::Region::UPtr region_uptr;
zx_status_t status;
// 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,
.size = size,
};
status = allocator_.GetRegion(request, region_uptr);
} else {
status = allocator_.GetRegion(size, region_uptr);
}
if (status != ZX_OK) {
return status;
}
zx::resource out_resource;
// TODO(ZX-3146): When the resource subset CL lands, make this a smaller resource.
status = backing_alloc_->resource().duplicate(ZX_DEFAULT_RESOURCE_RIGHTS, &out_resource);
if (status != ZX_OK) {
return status;
}
pci_tracef("bridge: assigned [ %#lx-%#lx ] to downstream\n", region_uptr->base,
region_uptr->base + size);
*out_alloc =
std::make_unique<PciRegionAllocation>(std::move(out_resource), std::move(region_uptr));
return ZX_OK;
}
zx_status_t PciRegionAllocator::GrantAddressSpace(std::unique_ptr<PciAllocation> alloc) {
ZX_DEBUG_ASSERT(!backing_alloc_);
backing_alloc_ = std::move(alloc);
auto base = backing_alloc_->base();
auto size = backing_alloc_->size();
return allocator_.AddRegion({.base = base, .size = size});
}
} // namespace pci