1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of tag() source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <assert.h> 6#include <ddk/debug.h> 7#include <ddk/protocol/pci.h> 8#include <fbl/auto_lock.h> 9#include <fbl/mutex.h> 10#include <virtio/virtio.h> 11#include <lib/zx/handle.h> 12 13#include "pci.h" 14 15namespace virtio { 16 17PciBackend::PciBackend(pci_protocol_t pci, zx_pcie_device_info_t info) 18 : pci_(pci), info_(info) { 19 snprintf(tag_, sizeof(tag_), "pci[%02x:%02x.%1x]", info_.bus_id, info_.dev_id, info_.func_id); 20} 21 22zx_status_t PciBackend::Bind() { 23 zx_handle_t tmp_handle; 24 25 // enable bus mastering 26 zx_status_t st; 27 if ((st = pci_enable_bus_master(&pci_, true)) != ZX_OK) { 28 zxlogf(ERROR, "%s: cannot enable bus master %d\n", tag(), st); 29 return st; 30 } 31 32 // try to set up our IRQ mode 33 uint32_t avail_irqs = 0; 34 zx_pci_irq_mode_t mode = ZX_PCIE_IRQ_MODE_MSI; 35 if ((st = pci_query_irq_mode(&pci_, mode, &avail_irqs)) != ZX_OK || 36 avail_irqs == 0) { 37 mode = ZX_PCIE_IRQ_MODE_LEGACY; 38 if ((st = pci_query_irq_mode(&pci_, mode, &avail_irqs)) != ZX_OK || 39 avail_irqs == 0) { 40 zxlogf(ERROR, "%s: no available IRQs found\n", tag()); 41 return st; 42 } 43 } 44 45 if ((st = pci_set_irq_mode(&pci_, mode, 1)) != ZX_OK) { 46 zxlogf(ERROR, "%s: failed to set irq mode %u\n", tag(), mode); 47 return st; 48 } 49 50 if ((st = pci_map_interrupt(&pci_, 0, &tmp_handle)) != ZX_OK) { 51 zxlogf(ERROR, "%s: failed to map irq %d\n", tag(), st); 52 return st; 53 } 54 irq_handle_.reset(tmp_handle); 55 zxlogf(SPEW, "%s: irq handle %u\n", tag(), irq_handle_.get()); 56 return Init(); 57} 58 59zx_status_t PciBackend::InterruptValid() { 60 if (!irq_handle_.get()) { 61 return ZX_ERR_BAD_HANDLE; 62 } 63 return ZX_OK; 64} 65 66zx_status_t PciBackend::WaitForInterrupt() { 67 return zx_interrupt_wait(irq_handle_.get(), nullptr); 68} 69 70} // namespace virtio 71