blob: 676cf17eeebecdef678704be1093705e7308cbc0 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include "common.h"
#include "root.h"
#include "upstream_node.h"
#include <assert.h>
#include <err.h>
#include <fbl/algorithm.h>
#include <fbl/auto_call.h>
#include <inttypes.h>
#include <lib/zx/resource.h>
#include <lib/zx/vmo.h>
#include <string.h>
#include <zircon/rights.h>
namespace pci {
zx_status_t PciAllocation::CreateVmObject(fbl::unique_ptr<zx::vmo>* out_vmo) const {
zx::vmo temp;
zx_status_t status = zx::vmo::create_physical(resource_, base(), size(), &temp);
if (status != ZX_OK) {
return status;
}
*out_vmo = std::make_unique<zx::vmo>(std::move(temp));
return status;
}
zx_status_t PciRootAllocator::GetRegion(zx_paddr_t in_base,
size_t size,
fbl::unique_ptr<PciAllocation>* 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_); });
fbl::AllocChecker ac;
*alloc = fbl::unique_ptr<PciRootAllocation>(new (&ac) PciRootAllocation(pciroot_, type_,
std::move(res),
out_base, size));
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
cleanup.cancel();
return ZX_OK;
}
zx_status_t PciRootAllocator::AddAddressSpace(fbl::unique_ptr<PciAllocation> alloc) {
// PciRootAllocations will free any space they hold when they are destroyed,
// and nothing seeds a PciRootAllocator.
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t PciRegionAllocator::GetRegion(zx_paddr_t base,
size_t size,
fbl::unique_ptr<PciAllocation>* alloc) {
RegionAllocator::Region::UPtr region_uptr;
zx_status_t status;
// Only use base if it is non-zero
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;
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);
fbl::AllocChecker ac;
*alloc =
fbl::unique_ptr<PciRegionAllocation>(new (&ac) PciRegionAllocation(std::move(out_resource),
std::move(region_uptr)));
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
return ZX_OK;
}
zx_status_t PciRegionAllocator::AddAddressSpace(fbl::unique_ptr<PciAllocation> 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