blob: eae6b239ff53297e1671c6b121c39693ca0d710d [file] [log] [blame]
// Copyright 2017 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 <hw/pci.h>
#include <hypervisor/bits.h>
#include <hypervisor/pci.h>
#include <unittest/unittest.h>
/* Test we can read multiple fields in 1 32-bit word. */
static bool read_config_register(void) {
BEGIN_TEST;
pci_bus_t bus;
pci_bus_init(&bus, nullptr);
pci_device_t* device = &bus.root_complex;
// Access Vendor/Device ID as a single 32bit read.
uint32_t value = 0;
EXPECT_EQ(pci_device_read(device, PCI_CONFIG_VENDOR_ID, 4, &value), ZX_OK,
"Failed to read PCI_CONFIG_VENDOR_ID");
EXPECT_EQ(value, PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_Q35 << 16),
"Unexpected value of PCI_CONFIG_VENDOR_ID");
END_TEST;
}
/* Verify we can read portions of a 32 bit word, one byte at a time. */
static bool read_config_register_bytewise(void) {
BEGIN_TEST;
pci_bus_t bus;
pci_bus_init(&bus, nullptr);
pci_device_t* device = &bus.root_complex;
uint32_t expected_device_vendor = PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_Q35 << 16);
for (int i = 0; i < 4; ++i) {
uint16_t reg = static_cast<uint16_t>(PCI_CONFIG_VENDOR_ID + i);
uint32_t value = 0;
EXPECT_EQ(pci_device_read(device, reg, 1, &value), ZX_OK,
"Failed to read PCI_CONFIG_VENDOR_ID");
EXPECT_EQ(value, bits_shift(expected_device_vendor, i * 8 + 7, i * 8),
"Unexpected value of PCI_CONFIG_VENDOR_ID");
}
END_TEST;
}
/* PCI devices BAR sizes must be a power of 2 and must not support setting any
* bits in the BAR that are not size aligned. Software often relies on this to
* read the bar size by writing all 1's to the register and reading back the
* value.
*
* This tests that we properly mask the lowest bits so software can compute the
* BAR size.
*/
static bool read_bar_size(void) {
BEGIN_TEST;
pci_bus_t bus;
pci_bus_init(&bus, nullptr);
pci_device_t* device = &bus.root_complex;
// Set all bits in the BAR register. The device will ignore writes to the
// LSBs which we can read out to determine the size.
EXPECT_EQ(pci_device_write(device, PCI_CONFIG_BASE_ADDRESSES, 4, UINT32_MAX), ZX_OK,
"Failed to write BAR0 to PCI config space");
// Read out BAR and compute size.
uint32_t value = 0;
EXPECT_EQ(pci_device_read(device, PCI_CONFIG_BASE_ADDRESSES, 4, &value), ZX_OK,
"Failed to read BAR0 from PCI config space");
EXPECT_EQ(value & PCI_BAR_IO_TYPE_MASK, PCI_BAR_IO_TYPE_PIO,
"Expected PIO bit to be set in BAR");
EXPECT_EQ(~(value & ~PCI_BAR_IO_TYPE_MASK) + 1, pci_bar_size(&device->bar[0]),
"Incorrect bar size read from pci device");
END_TEST;
}
/* Verify stats & cap registers correctly show present capabilities and that
* capability data is readable.
*/
static bool read_cap_basic(void) {
BEGIN_TEST;
pci_bus_t bus;
pci_bus_init(&bus, NULL);
pci_device_t* device = &bus.root_complex;
// Create and install a simple capability. First two bytes are ignored.
uint8_t cap_data[] = {0, 0, 0xf, 0xa};
pci_cap_t cap = {
.id = 0x9,
.data = cap_data,
.len = sizeof(cap_data),
};
device->capabilities = &cap;
device->num_capabilities = 1;
// PCI Local Bus Spec 3.0 Table 6-2: Status Register Bits
//
// This optional read-only bit indicates whether or not this device
// implements the pointer for a New Capabilities linked list at offset 34h.
// A value of zero indicates that no New Capabilities linked list is
// available. A value of one indicates that the value read at offset 34h is
// a pointer in Configuration Space to a linked list of new capabilities.
// Refer to Section 6.7 for details on New Capabilities.
uint32_t status = 0;
EXPECT_EQ(pci_device_read(device, PCI_CONFIG_STATUS, 2, &status), ZX_OK,
"Failed to read status register from PCI config space.\n");
EXPECT_TRUE(status & PCI_STATUS_NEW_CAPS,
"CAP bit not set in status register with a cap list present.\n");
// Read the cap pointer from config space. Here just verify it points to
// some location beyond the pre-defined header.
uint32_t cap_ptr = 0;
EXPECT_EQ(pci_device_read(device, PCI_CONFIG_CAPABILITIES, 1, &cap_ptr), ZX_OK,
"Failed to read CAP pointer from PCI config space.\n");
EXPECT_LT(0x40u, cap_ptr, "CAP pointer does not lie beyond the reserved region.\n");
// Read the capability. This will be the Cap ID, next pointer (0), followed
// by data bytes (starting at index 2).
uint32_t cap_value = 0;
EXPECT_EQ(pci_device_read(device, static_cast<uint16_t>(cap_ptr), 4, &cap_value), ZX_OK,
"Failed to read CAP value from PCI config space.\n");
EXPECT_EQ(0x0a0f0009u, cap_value,
"Incorrect CAP value read from PCI config space.\n");
END_TEST;
}
/* Build a list of capabilities with no data (only the required ID/next
* fields). Verify the next pointers are correctly wired up to traverse
* the linked list.
*/
static bool read_cap_chained(void) {
BEGIN_TEST;
pci_bus_t bus;
pci_bus_init(&bus, NULL);
pci_device_t* device = &bus.root_complex;
// Build list of caps.
pci_cap_t caps[5];
size_t num_caps = sizeof(caps)/sizeof(caps[0]);
for (uint8_t i = 0; i < num_caps; ++i) {
caps[i].id = i;
caps[i].len = 2;
}
device->capabilities = caps;
device->num_capabilities = num_caps;
uint32_t cap_ptr = 0;
uint32_t cap_header;
EXPECT_EQ(pci_device_read(device, PCI_CONFIG_CAPABILITIES, 1, &cap_ptr), ZX_OK,
"Failed to read CAP pointer from PCI config space.\n");
for (uint8_t i = 0; i < num_caps; ++i) {
// Read the current capability.
EXPECT_EQ(pci_device_read(device, static_cast<uint16_t>(cap_ptr), 4, &cap_header), ZX_OK,
"Failed to read CAP from PCI config space.\n");
// ID is the first byte.
EXPECT_EQ(i, cap_header & UINT8_MAX, "Incorrect CAP ID read.\n");
// Next pointer is the second byte.
cap_ptr = cap_header >> 8;
}
EXPECT_EQ(0u, cap_ptr, "Failed to read CAP pointer from PCI config space.\n");
END_TEST;
}
BEGIN_TEST_CASE(pci)
RUN_TEST(read_config_register)
RUN_TEST(read_config_register_bytewise)
RUN_TEST(read_bar_size)
RUN_TEST(read_cap_basic)
RUN_TEST(read_cap_chained)
END_TEST_CASE(pci)