mirror of https://gitee.com/openkylin/qemu.git
acpi: Extract crs build form acpi_build.c
Extract crs build form acpi_build.c, the function could also be used to build the crs for pxbs for arm. The resources are composed by two parts: 1. The bar space of pci-bridge/pcie-root-ports 2. The resources needed by devices behind PXBs. The base and limit of memory/io are obtained from the config via two APIs: pci_bridge_get_base and pci_bridge_get_limit Signed-off-by: Yubo Miao <miaoyubo@huawei.com> Signed-off-by: Jiahui Cen <cenjiahui@huawei.com> Message-Id: <20201119014841.7298-5-cenjiahui@huawei.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
09fad16744
commit
37d5c0a8ff
|
@ -27,6 +27,9 @@
|
||||||
#include "sysemu/numa.h"
|
#include "sysemu/numa.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "hw/acpi/tpm.h"
|
#include "hw/acpi/tpm.h"
|
||||||
|
#include "hw/pci/pci_host.h"
|
||||||
|
#include "hw/pci/pci_bus.h"
|
||||||
|
#include "hw/pci/pci_bridge.h"
|
||||||
|
|
||||||
static GArray *build_alloc_array(void)
|
static GArray *build_alloc_array(void)
|
||||||
{
|
{
|
||||||
|
@ -55,6 +58,128 @@ static void build_append_array(GArray *array, GArray *val)
|
||||||
|
|
||||||
#define ACPI_NAMESEG_LEN 4
|
#define ACPI_NAMESEG_LEN 4
|
||||||
|
|
||||||
|
void crs_range_insert(GPtrArray *ranges, uint64_t base, uint64_t limit)
|
||||||
|
{
|
||||||
|
CrsRangeEntry *entry;
|
||||||
|
|
||||||
|
entry = g_malloc(sizeof(*entry));
|
||||||
|
entry->base = base;
|
||||||
|
entry->limit = limit;
|
||||||
|
|
||||||
|
g_ptr_array_add(ranges, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void crs_range_free(gpointer data)
|
||||||
|
{
|
||||||
|
CrsRangeEntry *entry = (CrsRangeEntry *)data;
|
||||||
|
g_free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crs_range_set_init(CrsRangeSet *range_set)
|
||||||
|
{
|
||||||
|
range_set->io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||||
|
range_set->mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||||
|
range_set->mem_64bit_ranges =
|
||||||
|
g_ptr_array_new_with_free_func(crs_range_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
void crs_range_set_free(CrsRangeSet *range_set)
|
||||||
|
{
|
||||||
|
g_ptr_array_free(range_set->io_ranges, true);
|
||||||
|
g_ptr_array_free(range_set->mem_ranges, true);
|
||||||
|
g_ptr_array_free(range_set->mem_64bit_ranges, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint crs_range_compare(gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
CrsRangeEntry *entry_a = *(CrsRangeEntry **)a;
|
||||||
|
CrsRangeEntry *entry_b = *(CrsRangeEntry **)b;
|
||||||
|
|
||||||
|
if (entry_a->base < entry_b->base) {
|
||||||
|
return -1;
|
||||||
|
} else if (entry_a->base > entry_b->base) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* crs_replace_with_free_ranges - given the 'used' ranges within [start - end]
|
||||||
|
* interval, computes the 'free' ranges from the same interval.
|
||||||
|
* Example: If the input array is { [a1 - a2],[b1 - b2] }, the function
|
||||||
|
* will return { [base - a1], [a2 - b1], [b2 - limit] }.
|
||||||
|
*/
|
||||||
|
void crs_replace_with_free_ranges(GPtrArray *ranges,
|
||||||
|
uint64_t start, uint64_t end)
|
||||||
|
{
|
||||||
|
GPtrArray *free_ranges = g_ptr_array_new();
|
||||||
|
uint64_t free_base = start;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g_ptr_array_sort(ranges, crs_range_compare);
|
||||||
|
for (i = 0; i < ranges->len; i++) {
|
||||||
|
CrsRangeEntry *used = g_ptr_array_index(ranges, i);
|
||||||
|
|
||||||
|
if (free_base < used->base) {
|
||||||
|
crs_range_insert(free_ranges, free_base, used->base - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_base = used->limit + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (free_base < end) {
|
||||||
|
crs_range_insert(free_ranges, free_base, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_set_size(ranges, 0);
|
||||||
|
for (i = 0; i < free_ranges->len; i++) {
|
||||||
|
g_ptr_array_add(ranges, g_ptr_array_index(free_ranges, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_free(free_ranges, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* crs_range_merge - merges adjacent ranges in the given array.
|
||||||
|
* Array elements are deleted and replaced with the merged ranges.
|
||||||
|
*/
|
||||||
|
static void crs_range_merge(GPtrArray *range)
|
||||||
|
{
|
||||||
|
GPtrArray *tmp = g_ptr_array_new_with_free_func(crs_range_free);
|
||||||
|
CrsRangeEntry *entry;
|
||||||
|
uint64_t range_base, range_limit;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!range->len) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_sort(range, crs_range_compare);
|
||||||
|
|
||||||
|
entry = g_ptr_array_index(range, 0);
|
||||||
|
range_base = entry->base;
|
||||||
|
range_limit = entry->limit;
|
||||||
|
for (i = 1; i < range->len; i++) {
|
||||||
|
entry = g_ptr_array_index(range, i);
|
||||||
|
if (entry->base - 1 == range_limit) {
|
||||||
|
range_limit = entry->limit;
|
||||||
|
} else {
|
||||||
|
crs_range_insert(tmp, range_base, range_limit);
|
||||||
|
range_base = entry->base;
|
||||||
|
range_limit = entry->limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crs_range_insert(tmp, range_base, range_limit);
|
||||||
|
|
||||||
|
g_ptr_array_set_size(range, 0);
|
||||||
|
for (i = 0; i < tmp->len; i++) {
|
||||||
|
entry = g_ptr_array_index(tmp, i);
|
||||||
|
crs_range_insert(range, entry->base, entry->limit);
|
||||||
|
}
|
||||||
|
g_ptr_array_free(tmp, true);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
build_append_nameseg(GArray *array, const char *seg)
|
build_append_nameseg(GArray *array, const char *seg)
|
||||||
{
|
{
|
||||||
|
@ -1951,6 +2076,166 @@ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
|
||||||
tpm2_ptr, "TPM2", table_data->len - tpm2_start, 4, NULL, NULL);
|
tpm2_ptr, "TPM2", table_data->len - tpm2_start, 4, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set)
|
||||||
|
{
|
||||||
|
Aml *crs = aml_resource_template();
|
||||||
|
CrsRangeSet temp_range_set;
|
||||||
|
CrsRangeEntry *entry;
|
||||||
|
uint8_t max_bus = pci_bus_num(host->bus);
|
||||||
|
uint8_t type;
|
||||||
|
int devfn;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
crs_range_set_init(&temp_range_set);
|
||||||
|
for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
|
||||||
|
uint64_t range_base, range_limit;
|
||||||
|
PCIDevice *dev = host->bus->devices[devfn];
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < PCI_NUM_REGIONS; i++) {
|
||||||
|
PCIIORegion *r = &dev->io_regions[i];
|
||||||
|
|
||||||
|
range_base = r->addr;
|
||||||
|
range_limit = r->addr + r->size - 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work-around for old bioses
|
||||||
|
* that do not support multiple root buses
|
||||||
|
*/
|
||||||
|
if (!range_base || range_base > range_limit) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
|
||||||
|
crs_range_insert(temp_range_set.io_ranges,
|
||||||
|
range_base, range_limit);
|
||||||
|
} else { /* "memory" */
|
||||||
|
uint64_t length = range_limit - range_base + 1;
|
||||||
|
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
||||||
|
crs_range_insert(temp_range_set.mem_ranges, range_base,
|
||||||
|
range_limit);
|
||||||
|
} else {
|
||||||
|
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
||||||
|
range_base, range_limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
|
||||||
|
if (type == PCI_HEADER_TYPE_BRIDGE) {
|
||||||
|
uint8_t subordinate = dev->config[PCI_SUBORDINATE_BUS];
|
||||||
|
if (subordinate > max_bus) {
|
||||||
|
max_bus = subordinate;
|
||||||
|
}
|
||||||
|
|
||||||
|
range_base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
|
||||||
|
range_limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work-around for old bioses
|
||||||
|
* that do not support multiple root buses
|
||||||
|
*/
|
||||||
|
if (range_base && range_base <= range_limit) {
|
||||||
|
crs_range_insert(temp_range_set.io_ranges,
|
||||||
|
range_base, range_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
range_base =
|
||||||
|
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
||||||
|
range_limit =
|
||||||
|
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work-around for old bioses
|
||||||
|
* that do not support multiple root buses
|
||||||
|
*/
|
||||||
|
if (range_base && range_base <= range_limit) {
|
||||||
|
uint64_t length = range_limit - range_base + 1;
|
||||||
|
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
||||||
|
crs_range_insert(temp_range_set.mem_ranges,
|
||||||
|
range_base, range_limit);
|
||||||
|
} else {
|
||||||
|
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
||||||
|
range_base, range_limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
range_base =
|
||||||
|
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||||
|
range_limit =
|
||||||
|
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Work-around for old bioses
|
||||||
|
* that do not support multiple root buses
|
||||||
|
*/
|
||||||
|
if (range_base && range_base <= range_limit) {
|
||||||
|
uint64_t length = range_limit - range_base + 1;
|
||||||
|
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
||||||
|
crs_range_insert(temp_range_set.mem_ranges,
|
||||||
|
range_base, range_limit);
|
||||||
|
} else {
|
||||||
|
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
||||||
|
range_base, range_limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crs_range_merge(temp_range_set.io_ranges);
|
||||||
|
for (i = 0; i < temp_range_set.io_ranges->len; i++) {
|
||||||
|
entry = g_ptr_array_index(temp_range_set.io_ranges, i);
|
||||||
|
aml_append(crs,
|
||||||
|
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
|
||||||
|
AML_POS_DECODE, AML_ENTIRE_RANGE,
|
||||||
|
0, entry->base, entry->limit, 0,
|
||||||
|
entry->limit - entry->base + 1));
|
||||||
|
crs_range_insert(range_set->io_ranges, entry->base, entry->limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
crs_range_merge(temp_range_set.mem_ranges);
|
||||||
|
for (i = 0; i < temp_range_set.mem_ranges->len; i++) {
|
||||||
|
entry = g_ptr_array_index(temp_range_set.mem_ranges, i);
|
||||||
|
assert(entry->limit <= UINT32_MAX &&
|
||||||
|
(entry->limit - entry->base + 1) <= UINT32_MAX);
|
||||||
|
aml_append(crs,
|
||||||
|
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||||
|
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
||||||
|
AML_READ_WRITE,
|
||||||
|
0, entry->base, entry->limit, 0,
|
||||||
|
entry->limit - entry->base + 1));
|
||||||
|
crs_range_insert(range_set->mem_ranges, entry->base, entry->limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
crs_range_merge(temp_range_set.mem_64bit_ranges);
|
||||||
|
for (i = 0; i < temp_range_set.mem_64bit_ranges->len; i++) {
|
||||||
|
entry = g_ptr_array_index(temp_range_set.mem_64bit_ranges, i);
|
||||||
|
aml_append(crs,
|
||||||
|
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||||
|
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
||||||
|
AML_READ_WRITE,
|
||||||
|
0, entry->base, entry->limit, 0,
|
||||||
|
entry->limit - entry->base + 1));
|
||||||
|
crs_range_insert(range_set->mem_64bit_ranges,
|
||||||
|
entry->base, entry->limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
crs_range_set_free(&temp_range_set);
|
||||||
|
|
||||||
|
aml_append(crs,
|
||||||
|
aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
|
||||||
|
0,
|
||||||
|
pci_bus_num(host->bus),
|
||||||
|
max_bus,
|
||||||
|
0,
|
||||||
|
max_bus - pci_bus_num(host->bus) + 1));
|
||||||
|
|
||||||
|
return crs;
|
||||||
|
}
|
||||||
|
|
||||||
/* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */
|
/* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors */
|
||||||
static Aml *aml_serial_bus_device(uint8_t serial_bus_type, uint8_t flags,
|
static Aml *aml_serial_bus_device(uint8_t serial_bus_type, uint8_t flags,
|
||||||
uint16_t type_flags,
|
uint16_t type_flags,
|
||||||
|
|
|
@ -613,299 +613,6 @@ static Aml *build_prt(bool is_pci0_prt)
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct CrsRangeEntry {
|
|
||||||
uint64_t base;
|
|
||||||
uint64_t limit;
|
|
||||||
} CrsRangeEntry;
|
|
||||||
|
|
||||||
static void crs_range_insert(GPtrArray *ranges, uint64_t base, uint64_t limit)
|
|
||||||
{
|
|
||||||
CrsRangeEntry *entry;
|
|
||||||
|
|
||||||
entry = g_malloc(sizeof(*entry));
|
|
||||||
entry->base = base;
|
|
||||||
entry->limit = limit;
|
|
||||||
|
|
||||||
g_ptr_array_add(ranges, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void crs_range_free(gpointer data)
|
|
||||||
{
|
|
||||||
CrsRangeEntry *entry = (CrsRangeEntry *)data;
|
|
||||||
g_free(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct CrsRangeSet {
|
|
||||||
GPtrArray *io_ranges;
|
|
||||||
GPtrArray *mem_ranges;
|
|
||||||
GPtrArray *mem_64bit_ranges;
|
|
||||||
} CrsRangeSet;
|
|
||||||
|
|
||||||
static void crs_range_set_init(CrsRangeSet *range_set)
|
|
||||||
{
|
|
||||||
range_set->io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
|
||||||
range_set->mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
|
||||||
range_set->mem_64bit_ranges =
|
|
||||||
g_ptr_array_new_with_free_func(crs_range_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void crs_range_set_free(CrsRangeSet *range_set)
|
|
||||||
{
|
|
||||||
g_ptr_array_free(range_set->io_ranges, true);
|
|
||||||
g_ptr_array_free(range_set->mem_ranges, true);
|
|
||||||
g_ptr_array_free(range_set->mem_64bit_ranges, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint crs_range_compare(gconstpointer a, gconstpointer b)
|
|
||||||
{
|
|
||||||
CrsRangeEntry *entry_a = *(CrsRangeEntry **)a;
|
|
||||||
CrsRangeEntry *entry_b = *(CrsRangeEntry **)b;
|
|
||||||
|
|
||||||
if (entry_a->base < entry_b->base) {
|
|
||||||
return -1;
|
|
||||||
} else if (entry_a->base > entry_b->base) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* crs_replace_with_free_ranges - given the 'used' ranges within [start - end]
|
|
||||||
* interval, computes the 'free' ranges from the same interval.
|
|
||||||
* Example: If the input array is { [a1 - a2],[b1 - b2] }, the function
|
|
||||||
* will return { [base - a1], [a2 - b1], [b2 - limit] }.
|
|
||||||
*/
|
|
||||||
static void crs_replace_with_free_ranges(GPtrArray *ranges,
|
|
||||||
uint64_t start, uint64_t end)
|
|
||||||
{
|
|
||||||
GPtrArray *free_ranges = g_ptr_array_new();
|
|
||||||
uint64_t free_base = start;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
g_ptr_array_sort(ranges, crs_range_compare);
|
|
||||||
for (i = 0; i < ranges->len; i++) {
|
|
||||||
CrsRangeEntry *used = g_ptr_array_index(ranges, i);
|
|
||||||
|
|
||||||
if (free_base < used->base) {
|
|
||||||
crs_range_insert(free_ranges, free_base, used->base - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
free_base = used->limit + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (free_base < end) {
|
|
||||||
crs_range_insert(free_ranges, free_base, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_ptr_array_set_size(ranges, 0);
|
|
||||||
for (i = 0; i < free_ranges->len; i++) {
|
|
||||||
g_ptr_array_add(ranges, g_ptr_array_index(free_ranges, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_ptr_array_free(free_ranges, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* crs_range_merge - merges adjacent ranges in the given array.
|
|
||||||
* Array elements are deleted and replaced with the merged ranges.
|
|
||||||
*/
|
|
||||||
static void crs_range_merge(GPtrArray *range)
|
|
||||||
{
|
|
||||||
GPtrArray *tmp = g_ptr_array_new_with_free_func(crs_range_free);
|
|
||||||
CrsRangeEntry *entry;
|
|
||||||
uint64_t range_base, range_limit;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!range->len) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_ptr_array_sort(range, crs_range_compare);
|
|
||||||
|
|
||||||
entry = g_ptr_array_index(range, 0);
|
|
||||||
range_base = entry->base;
|
|
||||||
range_limit = entry->limit;
|
|
||||||
for (i = 1; i < range->len; i++) {
|
|
||||||
entry = g_ptr_array_index(range, i);
|
|
||||||
if (entry->base - 1 == range_limit) {
|
|
||||||
range_limit = entry->limit;
|
|
||||||
} else {
|
|
||||||
crs_range_insert(tmp, range_base, range_limit);
|
|
||||||
range_base = entry->base;
|
|
||||||
range_limit = entry->limit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
crs_range_insert(tmp, range_base, range_limit);
|
|
||||||
|
|
||||||
g_ptr_array_set_size(range, 0);
|
|
||||||
for (i = 0; i < tmp->len; i++) {
|
|
||||||
entry = g_ptr_array_index(tmp, i);
|
|
||||||
crs_range_insert(range, entry->base, entry->limit);
|
|
||||||
}
|
|
||||||
g_ptr_array_free(tmp, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set)
|
|
||||||
{
|
|
||||||
Aml *crs = aml_resource_template();
|
|
||||||
CrsRangeSet temp_range_set;
|
|
||||||
CrsRangeEntry *entry;
|
|
||||||
uint8_t max_bus = pci_bus_num(host->bus);
|
|
||||||
uint8_t type;
|
|
||||||
int devfn;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
crs_range_set_init(&temp_range_set);
|
|
||||||
for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
|
|
||||||
uint64_t range_base, range_limit;
|
|
||||||
PCIDevice *dev = host->bus->devices[devfn];
|
|
||||||
|
|
||||||
if (!dev) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < PCI_NUM_REGIONS; i++) {
|
|
||||||
PCIIORegion *r = &dev->io_regions[i];
|
|
||||||
|
|
||||||
range_base = r->addr;
|
|
||||||
range_limit = r->addr + r->size - 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Work-around for old bioses
|
|
||||||
* that do not support multiple root buses
|
|
||||||
*/
|
|
||||||
if (!range_base || range_base > range_limit) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
|
|
||||||
crs_range_insert(temp_range_set.io_ranges,
|
|
||||||
range_base, range_limit);
|
|
||||||
} else { /* "memory" */
|
|
||||||
uint64_t length = range_limit - range_base + 1;
|
|
||||||
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
|
||||||
crs_range_insert(temp_range_set.mem_ranges, range_base,
|
|
||||||
range_limit);
|
|
||||||
} else {
|
|
||||||
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
|
||||||
range_base, range_limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
|
|
||||||
if (type == PCI_HEADER_TYPE_BRIDGE) {
|
|
||||||
uint8_t subordinate = dev->config[PCI_SUBORDINATE_BUS];
|
|
||||||
if (subordinate > max_bus) {
|
|
||||||
max_bus = subordinate;
|
|
||||||
}
|
|
||||||
|
|
||||||
range_base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
|
|
||||||
range_limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Work-around for old bioses
|
|
||||||
* that do not support multiple root buses
|
|
||||||
*/
|
|
||||||
if (range_base && range_base <= range_limit) {
|
|
||||||
crs_range_insert(temp_range_set.io_ranges,
|
|
||||||
range_base, range_limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
range_base =
|
|
||||||
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
|
||||||
range_limit =
|
|
||||||
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Work-around for old bioses
|
|
||||||
* that do not support multiple root buses
|
|
||||||
*/
|
|
||||||
if (range_base && range_base <= range_limit) {
|
|
||||||
uint64_t length = range_limit - range_base + 1;
|
|
||||||
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
|
||||||
crs_range_insert(temp_range_set.mem_ranges,
|
|
||||||
range_base, range_limit);
|
|
||||||
} else {
|
|
||||||
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
|
||||||
range_base, range_limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
range_base =
|
|
||||||
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
|
|
||||||
range_limit =
|
|
||||||
pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Work-around for old bioses
|
|
||||||
* that do not support multiple root buses
|
|
||||||
*/
|
|
||||||
if (range_base && range_base <= range_limit) {
|
|
||||||
uint64_t length = range_limit - range_base + 1;
|
|
||||||
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
|
||||||
crs_range_insert(temp_range_set.mem_ranges,
|
|
||||||
range_base, range_limit);
|
|
||||||
} else {
|
|
||||||
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
|
||||||
range_base, range_limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crs_range_merge(temp_range_set.io_ranges);
|
|
||||||
for (i = 0; i < temp_range_set.io_ranges->len; i++) {
|
|
||||||
entry = g_ptr_array_index(temp_range_set.io_ranges, i);
|
|
||||||
aml_append(crs,
|
|
||||||
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
|
|
||||||
AML_POS_DECODE, AML_ENTIRE_RANGE,
|
|
||||||
0, entry->base, entry->limit, 0,
|
|
||||||
entry->limit - entry->base + 1));
|
|
||||||
crs_range_insert(range_set->io_ranges, entry->base, entry->limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
crs_range_merge(temp_range_set.mem_ranges);
|
|
||||||
for (i = 0; i < temp_range_set.mem_ranges->len; i++) {
|
|
||||||
entry = g_ptr_array_index(temp_range_set.mem_ranges, i);
|
|
||||||
assert(entry->limit <= UINT32_MAX &&
|
|
||||||
(entry->limit - entry->base + 1) <= UINT32_MAX);
|
|
||||||
aml_append(crs,
|
|
||||||
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
|
||||||
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
|
||||||
AML_READ_WRITE,
|
|
||||||
0, entry->base, entry->limit, 0,
|
|
||||||
entry->limit - entry->base + 1));
|
|
||||||
crs_range_insert(range_set->mem_ranges, entry->base, entry->limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
crs_range_merge(temp_range_set.mem_64bit_ranges);
|
|
||||||
for (i = 0; i < temp_range_set.mem_64bit_ranges->len; i++) {
|
|
||||||
entry = g_ptr_array_index(temp_range_set.mem_64bit_ranges, i);
|
|
||||||
aml_append(crs,
|
|
||||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
|
||||||
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
|
||||||
AML_READ_WRITE,
|
|
||||||
0, entry->base, entry->limit, 0,
|
|
||||||
entry->limit - entry->base + 1));
|
|
||||||
crs_range_insert(range_set->mem_64bit_ranges,
|
|
||||||
entry->base, entry->limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
crs_range_set_free(&temp_range_set);
|
|
||||||
|
|
||||||
aml_append(crs,
|
|
||||||
aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
|
|
||||||
0,
|
|
||||||
pci_bus_num(host->bus),
|
|
||||||
max_bus,
|
|
||||||
0,
|
|
||||||
max_bus - pci_bus_num(host->bus) + 1));
|
|
||||||
|
|
||||||
return crs;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void build_hpet_aml(Aml *table)
|
static void build_hpet_aml(Aml *table)
|
||||||
{
|
{
|
||||||
Aml *crs;
|
Aml *crs;
|
||||||
|
|
|
@ -224,6 +224,20 @@ struct AcpiBuildTables {
|
||||||
BIOSLinker *linker;
|
BIOSLinker *linker;
|
||||||
} AcpiBuildTables;
|
} AcpiBuildTables;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct CrsRangeEntry {
|
||||||
|
uint64_t base;
|
||||||
|
uint64_t limit;
|
||||||
|
} CrsRangeEntry;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct CrsRangeSet {
|
||||||
|
GPtrArray *io_ranges;
|
||||||
|
GPtrArray *mem_ranges;
|
||||||
|
GPtrArray *mem_64bit_ranges;
|
||||||
|
} CrsRangeSet;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors
|
* ACPI 5.0: 6.4.3.8.2 Serial Bus Connection Descriptors
|
||||||
* Serial Bus Type
|
* Serial Bus Type
|
||||||
|
@ -432,6 +446,14 @@ build_append_gas_from_struct(GArray *table, const struct AcpiGenericAddress *s)
|
||||||
s->access_width, s->address);
|
s->access_width, s->address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void crs_range_insert(GPtrArray *ranges, uint64_t base, uint64_t limit);
|
||||||
|
void crs_replace_with_free_ranges(GPtrArray *ranges,
|
||||||
|
uint64_t start, uint64_t end);
|
||||||
|
void crs_range_set_init(CrsRangeSet *range_set);
|
||||||
|
void crs_range_set_free(CrsRangeSet *range_set);
|
||||||
|
|
||||||
|
Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set);
|
||||||
|
|
||||||
void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
|
void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
|
||||||
uint64_t len, int node, MemoryAffinityFlags flags);
|
uint64_t len, int node, MemoryAffinityFlags flags);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue