blob: 66d72f55850c80303a9d34799093d059dda6178e [file] [log] [blame]
// Copyright 2016 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 "zircon_platform_pci_device.h"
#include "magma_util/dlog.h"
#include "magma_util/macros.h"
#include "platform_mmio.h"
#include "zircon_platform_bus_mapper.h"
#include "zircon_platform_interrupt.h"
#include "zircon_platform_mmio.h"
#include <ddk/device.h>
#include <ddk/driver.h>
namespace magma {
std::unique_ptr<PlatformMmio>
ZirconPlatformPciDevice::CpuMapPciMmio(unsigned int pci_bar, PlatformMmio::CachePolicy cache_policy)
{
DLOG("CpuMapPciMmio bar %d", pci_bar);
zx_pci_bar_t bar;
zx_status_t status = pci_get_bar(&pci(), pci_bar, &bar);
if (status != ZX_OK)
return DRETP(nullptr, "map_resource failed");
DASSERT(bar.type == ZX_PCI_BAR_TYPE_MMIO);
mmio_buffer_t mmio_buffer;
mmio_buffer_init(&mmio_buffer, 0, bar.size, bar.handle, cache_policy);
std::unique_ptr<ZirconPlatformMmio> mmio(new ZirconPlatformMmio(mmio_buffer));
DLOG("map_mmio bar %d cache_policy %d returned: 0x%x", pci_bar, static_cast<int>(cache_policy),
mmio_buffer.vmo);
return mmio;
}
bool ZirconPlatformPciDevice::ReadPciConfig16(uint64_t addr, uint16_t* value)
{
if (!value)
return DRETF(false, "bad value");
zx_status_t status = pci_config_read16(&pci(), addr, value);
if (status != ZX_OK)
return DRETF(false, "failed to read config: %d\n", status);
return true;
}
std::unique_ptr<PlatformHandle> ZirconPlatformPciDevice::GetBusTransactionInitiator()
{
zx_handle_t bti_handle;
zx_status_t status = pci_get_bti(&pci(), 0, &bti_handle);
if (status != ZX_OK)
return DRETP(nullptr, "failed to get bus transaction initiator");
return std::make_unique<ZirconPlatformHandle>(zx::handle(bti_handle));
}
std::unique_ptr<PlatformInterrupt> ZirconPlatformPciDevice::RegisterInterrupt()
{
uint32_t max_irqs;
zx_status_t status = pci_query_irq_mode(&pci(), ZX_PCIE_IRQ_MODE_LEGACY, &max_irqs);
if (status != ZX_OK)
return DRETP(nullptr, "query_irq_mode_caps failed (%d)", status);
if (max_irqs == 0)
return DRETP(nullptr, "max_irqs is zero");
// Mode must be Disabled before we can request Legacy
status = pci_set_irq_mode(&pci(), ZX_PCIE_IRQ_MODE_DISABLED, 0);
if (status != ZX_OK)
return DRETP(nullptr, "set_irq_mode(DISABLED) failed (%d)", status);
status = pci_set_irq_mode(&pci(), ZX_PCIE_IRQ_MODE_LEGACY, 1);
if (status != ZX_OK)
return DRETP(nullptr, "set_irq_mode(LEGACY) failed (%d)", status);
zx_handle_t interrupt_handle;
status = pci_map_interrupt(&pci(), 0, &interrupt_handle);
if (status < 0)
return DRETP(nullptr, "map_interrupt failed (%d)", status);
return std::make_unique<ZirconPlatformInterrupt>(zx::handle(interrupt_handle));
}
ZirconPlatformPciDevice::~ZirconPlatformPciDevice() {}
std::unique_ptr<PlatformPciDevice> PlatformPciDevice::Create(void* device_handle)
{
if (!device_handle)
return DRETP(nullptr, "device_handle is null, cannot create PlatformPciDevice");
pci_protocol_t pci;
zx_device_t* zx_device = reinterpret_cast<zx_device_t*>(device_handle);
zx_status_t status = device_get_protocol(zx_device, ZX_PROTOCOL_PCI, &pci);
if (status != ZX_OK)
return DRETP(nullptr, "pci protocol is null, cannot create PlatformPciDevice");
return std::unique_ptr<PlatformPciDevice>(new ZirconPlatformPciDevice(zx_device, pci));
}
} // namespace magma