soc/intel/xeon_sp: Move common chip.c code
Move common CPX and SKX chip.c code to chip_common.c. Change-Id: I158882ab15659858c2b13b4a3e02a26ef8d4ed3c Signed-off-by: Marc Jones <marcjones@sysproconsulting.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/46478 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Jay Talbott <JayTalbott@sysproconsulting.com> Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
parent
9a0d4f8620
commit
1f500845b4
|
@ -7,7 +7,7 @@ subdirs-$(CONFIG_SOC_INTEL_COOPERLAKE_SP) += cpx
|
|||
|
||||
bootblock-y += bootblock.c spi.c lpc.c gpio.c pch.c
|
||||
romstage-y += romstage.c reset.c util.c spi.c gpio.c pmutil.c
|
||||
ramstage-y += uncore.c reset.c util.c lpc.c spi.c gpio.c nb_acpi.c ramstage.c
|
||||
ramstage-y += uncore.c reset.c util.c lpc.c spi.c gpio.c nb_acpi.c ramstage.c chip_common.c
|
||||
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_PMC) += pmc.c
|
||||
postcar-y += spi.c
|
||||
|
||||
|
|
|
@ -0,0 +1,527 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <assert.h>
|
||||
#include <console/console.h>
|
||||
#include <post.h>
|
||||
#include <device/pci.h>
|
||||
#include <soc/chip_common.h>
|
||||
#include <soc/soc_util.h>
|
||||
#include <soc/util.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct pci_resource {
|
||||
struct device *dev;
|
||||
struct resource *res;
|
||||
struct pci_resource *next;
|
||||
};
|
||||
|
||||
struct stack_dev_resource {
|
||||
uint8_t align;
|
||||
struct pci_resource *children;
|
||||
struct stack_dev_resource *next;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
RES_TYPE_IO = 0,
|
||||
RES_TYPE_NONPREF_MEM,
|
||||
RES_TYPE_PREF_MEM,
|
||||
MAX_RES_TYPES
|
||||
} RES_TYPE;
|
||||
|
||||
static RES_TYPE get_res_type(uint64_t flags)
|
||||
{
|
||||
if (flags & IORESOURCE_IO)
|
||||
return RES_TYPE_IO;
|
||||
if (flags & IORESOURCE_MEM) {
|
||||
if (flags & IORESOURCE_PREFETCH) {
|
||||
printk(BIOS_DEBUG, "%s:%d flags: 0x%llx\n", __func__, __LINE__, flags);
|
||||
return RES_TYPE_PREF_MEM;
|
||||
}
|
||||
/* both 64-bit and 32-bit use below 4GB address space */
|
||||
return RES_TYPE_NONPREF_MEM;
|
||||
}
|
||||
printk(BIOS_ERR, "Invalid resource type 0x%llx\n", flags);
|
||||
die("");
|
||||
}
|
||||
|
||||
static bool need_assignment(uint64_t flags)
|
||||
{
|
||||
if (flags & (IORESOURCE_STORED | IORESOURCE_RESERVE | IORESOURCE_FIXED |
|
||||
IORESOURCE_ASSIGNED))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t get_resource_base(STACK_RES *stack, RES_TYPE res_type)
|
||||
{
|
||||
if (res_type == RES_TYPE_IO) {
|
||||
assert(stack->PciResourceIoBase <= stack->PciResourceIoLimit);
|
||||
return stack->PciResourceIoBase;
|
||||
}
|
||||
if (res_type == RES_TYPE_NONPREF_MEM) {
|
||||
assert(stack->PciResourceMem32Base <= stack->PciResourceMem32Limit);
|
||||
return stack->PciResourceMem32Base;
|
||||
}
|
||||
assert(stack->PciResourceMem64Base <= stack->PciResourceMem64Limit);
|
||||
return stack->PciResourceMem64Base;
|
||||
}
|
||||
|
||||
static void set_resource_base(STACK_RES *stack, RES_TYPE res_type, uint64_t base)
|
||||
{
|
||||
if (res_type == RES_TYPE_IO) {
|
||||
assert(base <= (stack->PciResourceIoLimit + 1));
|
||||
stack->PciResourceIoBase = base;
|
||||
} else if (res_type == RES_TYPE_NONPREF_MEM) {
|
||||
assert(base <= (stack->PciResourceMem32Limit + 1));
|
||||
stack->PciResourceMem32Base = base;
|
||||
} else {
|
||||
assert(base <= (stack->PciResourceMem64Limit + 1));
|
||||
stack->PciResourceMem64Base = base;
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_stack_resources(struct iiostack_resource *stack_list,
|
||||
struct device *dev, struct resource *bridge);
|
||||
|
||||
void xeonsp_pci_domain_scan_bus(struct device *dev)
|
||||
{
|
||||
DEV_FUNC_ENTER(dev);
|
||||
struct bus *link = dev->link_list;
|
||||
|
||||
printk(BIOS_SPEW, "%s:%s scanning buses under device %s\n",
|
||||
__FILE__, __func__, dev_path(dev));
|
||||
while (link != NULL) {
|
||||
if (link->secondary == 0) { // scan only PSTACK buses
|
||||
struct device *d;
|
||||
for (d = link->children; d; d = d->sibling)
|
||||
pci_probe_dev(d, link, d->path.pci.devfn);
|
||||
scan_bridges(link);
|
||||
} else {
|
||||
pci_scan_bus(link, PCI_DEVFN(0, 0), 0xff);
|
||||
}
|
||||
link = link->next;
|
||||
}
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
static void xeonsp_pci_dev_iterator(struct bus *bus,
|
||||
void (*dev_iterator)(struct device *, void *),
|
||||
void (*res_iterator)(struct device *, struct resource *, void *),
|
||||
void *data)
|
||||
{
|
||||
struct device *curdev;
|
||||
struct resource *res;
|
||||
|
||||
/* Walk through all devices and find which resources they need. */
|
||||
for (curdev = bus->children; curdev; curdev = curdev->sibling) {
|
||||
struct bus *link;
|
||||
|
||||
if (!curdev->enabled)
|
||||
continue;
|
||||
|
||||
if (!curdev->ops || !curdev->ops->read_resources) {
|
||||
if (curdev->path.type != DEVICE_PATH_APIC)
|
||||
printk(BIOS_ERR, "%s missing read_resources\n",
|
||||
dev_path(curdev));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dev_iterator)
|
||||
dev_iterator(curdev, data);
|
||||
|
||||
if (res_iterator) {
|
||||
for (res = curdev->resource_list; res; res = res->next)
|
||||
res_iterator(curdev, res, data);
|
||||
}
|
||||
|
||||
/* Read in the resources behind the current device's links. */
|
||||
for (link = curdev->link_list; link; link = link->next)
|
||||
xeonsp_pci_dev_iterator(link, dev_iterator, res_iterator, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void xeonsp_pci_dev_read_resources(struct device *dev, void *data)
|
||||
{
|
||||
post_log_path(dev);
|
||||
dev->ops->read_resources(dev);
|
||||
}
|
||||
|
||||
static void xeonsp_pci_dev_dummy_func(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static void xeonsp_reset_pci_op(struct device *dev, void *data)
|
||||
{
|
||||
if (dev->ops)
|
||||
dev->ops->read_resources = xeonsp_pci_dev_dummy_func;
|
||||
}
|
||||
|
||||
static STACK_RES *find_stack_for_bus(struct iiostack_resource *info, uint8_t bus)
|
||||
{
|
||||
for (int i = 0; i < info->no_of_stacks; ++i) {
|
||||
if (bus >= info->res[i].BusBase && bus <= info->res[i].BusLimit)
|
||||
return &info->res[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void add_res_to_stack(struct stack_dev_resource **root,
|
||||
struct device *dev, struct resource *res)
|
||||
{
|
||||
struct stack_dev_resource *cur = *root;
|
||||
while (cur) {
|
||||
if (cur->align == res->align || cur->next == NULL) /* equal or last record */
|
||||
break;
|
||||
else if (cur->align > res->align) {
|
||||
if (cur->next->align < res->align) /* need to insert new record here */
|
||||
break;
|
||||
cur = cur->next;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct stack_dev_resource *nr;
|
||||
if (!cur || cur->align != res->align) { /* need to add new record */
|
||||
nr = malloc(sizeof(struct stack_dev_resource));
|
||||
if (nr == 0)
|
||||
die("assign_resource_to_stack(): out of memory.\n");
|
||||
memset(nr, 0, sizeof(struct stack_dev_resource));
|
||||
nr->align = res->align;
|
||||
if (!cur) {
|
||||
*root = nr; /* head node */
|
||||
} else if (cur->align > nr->align) {
|
||||
if (cur->next == NULL) {
|
||||
cur->next = nr;
|
||||
} else {
|
||||
nr->next = cur->next;
|
||||
cur->next = nr;
|
||||
}
|
||||
} else { /* insert in the beginning */
|
||||
nr->next = cur;
|
||||
*root = nr;
|
||||
}
|
||||
} else {
|
||||
nr = cur;
|
||||
}
|
||||
|
||||
assert(nr != NULL && nr->align == res->align);
|
||||
|
||||
struct pci_resource *npr = malloc(sizeof(struct pci_resource));
|
||||
if (npr == NULL)
|
||||
die("%s: out of memory.\n", __func__);
|
||||
npr->res = res;
|
||||
npr->dev = dev;
|
||||
npr->next = NULL;
|
||||
|
||||
if (nr->children == NULL) {
|
||||
nr->children = npr;
|
||||
} else {
|
||||
struct pci_resource *pr = nr->children;
|
||||
while (pr->next != NULL)
|
||||
pr = pr->next;
|
||||
pr->next = npr;
|
||||
}
|
||||
}
|
||||
|
||||
static void reserve_dev_resources(STACK_RES *stack, RES_TYPE res_type,
|
||||
struct stack_dev_resource *res_root, struct resource *bridge)
|
||||
{
|
||||
uint8_t align;
|
||||
uint64_t orig_base, base;
|
||||
|
||||
orig_base = get_resource_base(stack, res_type);
|
||||
|
||||
align = 0;
|
||||
base = orig_base;
|
||||
int first = 1;
|
||||
while (res_root) { /* loop through all devices grouped by alignment requirements */
|
||||
struct pci_resource *pr = res_root->children;
|
||||
while (pr) {
|
||||
if (first) {
|
||||
if (bridge) { /* takes highest alignment */
|
||||
if (bridge->align < pr->res->align)
|
||||
bridge->align = pr->res->align;
|
||||
orig_base = ALIGN_UP(orig_base, 1 << bridge->align);
|
||||
} else {
|
||||
orig_base = ALIGN_UP(orig_base, 1 << pr->res->align);
|
||||
}
|
||||
base = orig_base;
|
||||
|
||||
if (bridge)
|
||||
bridge->base = base;
|
||||
pr->res->base = base;
|
||||
first = 0;
|
||||
} else {
|
||||
pr->res->base = ALIGN_UP(base, 1 << pr->res->align);
|
||||
}
|
||||
pr->res->limit = pr->res->base + pr->res->size - 1;
|
||||
base = pr->res->limit + 1;
|
||||
pr->res->flags |= (IORESOURCE_ASSIGNED);
|
||||
pr = pr->next;
|
||||
}
|
||||
res_root = res_root->next;
|
||||
}
|
||||
|
||||
if (bridge) {
|
||||
/* this bridge doesn't have any resources, will set it to default window */
|
||||
if (first) {
|
||||
orig_base = ALIGN_UP(orig_base, 1 << bridge->align);
|
||||
bridge->base = orig_base;
|
||||
base = orig_base + (1ULL << bridge->gran);
|
||||
}
|
||||
|
||||
bridge->size = ALIGN_UP(base, 1 << bridge->align) - bridge->base;
|
||||
|
||||
bridge->limit = bridge->base + bridge->size - 1;
|
||||
bridge->flags |= (IORESOURCE_ASSIGNED);
|
||||
base = bridge->limit + 1;
|
||||
}
|
||||
|
||||
set_resource_base(stack, res_type, base);
|
||||
}
|
||||
|
||||
static void reclaim_resource_mem(struct stack_dev_resource *res_root)
|
||||
{
|
||||
while (res_root) { /* loop through all devices grouped by alignment requirements */
|
||||
/* free pci_resource */
|
||||
struct pci_resource *pr = res_root->children;
|
||||
while (pr) {
|
||||
struct pci_resource *dpr = pr;
|
||||
pr = pr->next;
|
||||
free(dpr);
|
||||
}
|
||||
|
||||
/* free stack_dev_resource */
|
||||
struct stack_dev_resource *ddr = res_root;
|
||||
res_root = res_root->next;
|
||||
free(ddr);
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_bridge_resources(struct iiostack_resource *stack_list,
|
||||
struct device *dev, struct resource *bridge)
|
||||
{
|
||||
struct resource *res;
|
||||
if (!dev->enabled)
|
||||
return;
|
||||
|
||||
for (res = dev->resource_list; res; res = res->next) {
|
||||
if (!(res->flags & IORESOURCE_BRIDGE) ||
|
||||
(bridge && (get_res_type(bridge->flags) != get_res_type(res->flags))))
|
||||
continue;
|
||||
|
||||
assign_stack_resources(stack_list, dev, res);
|
||||
|
||||
if (!bridge)
|
||||
continue;
|
||||
|
||||
/* for 1st time update, overlading IORESOURCE_ASSIGNED */
|
||||
if (!(bridge->flags & IORESOURCE_ASSIGNED)) {
|
||||
bridge->base = res->base;
|
||||
bridge->limit = res->limit;
|
||||
bridge->flags |= (IORESOURCE_ASSIGNED);
|
||||
} else {
|
||||
/* update bridge range from child bridge range */
|
||||
if (res->base < bridge->base)
|
||||
bridge->base = res->base;
|
||||
if (res->limit > bridge->limit)
|
||||
bridge->limit = res->limit;
|
||||
}
|
||||
bridge->size = (bridge->limit - bridge->base + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_stack_resources(struct iiostack_resource *stack_list,
|
||||
struct device *dev, struct resource *bridge)
|
||||
{
|
||||
struct bus *bus;
|
||||
|
||||
/* Read in the resources behind the current device's links. */
|
||||
for (bus = dev->link_list; bus; bus = bus->next) {
|
||||
struct device *curdev;
|
||||
STACK_RES *stack;
|
||||
|
||||
/* get IIO stack for this bus */
|
||||
stack = find_stack_for_bus(stack_list, bus->secondary);
|
||||
assert(stack != NULL);
|
||||
|
||||
/* Assign resources to bridge */
|
||||
for (curdev = bus->children; curdev; curdev = curdev->sibling)
|
||||
assign_bridge_resources(stack_list, curdev, bridge);
|
||||
|
||||
/* Pick non-bridged resources for resource allocation for each resource type */
|
||||
RES_TYPE res_types[MAX_RES_TYPES] = {
|
||||
RES_TYPE_IO,
|
||||
RES_TYPE_NONPREF_MEM,
|
||||
RES_TYPE_PREF_MEM
|
||||
};
|
||||
|
||||
uint8_t no_res_types = MAX_RES_TYPES;
|
||||
|
||||
/* if it is a bridge, only process matching bridge resource type */
|
||||
if (bridge) {
|
||||
res_types[0] = get_res_type(bridge->flags);
|
||||
no_res_types = 1;
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "%s:%d no_res_types: %d\n", __func__, __LINE__,
|
||||
no_res_types);
|
||||
|
||||
/* Process each resource type */
|
||||
for (int rt = 0; rt < no_res_types; ++rt) {
|
||||
struct stack_dev_resource *res_root = NULL;
|
||||
printk(BIOS_DEBUG, "%s:%d rt: %d\n", __func__, __LINE__, rt);
|
||||
for (curdev = bus->children; curdev; curdev = curdev->sibling) {
|
||||
struct resource *res;
|
||||
printk(BIOS_DEBUG, "%s:%d dev: %s\n",
|
||||
__func__, __LINE__, dev_path(curdev));
|
||||
if (!curdev->enabled)
|
||||
continue;
|
||||
|
||||
for (res = curdev->resource_list; res; res = res->next) {
|
||||
printk(BIOS_DEBUG, "%s:%d dev: %s, flags: 0x%lx\n",
|
||||
__func__, __LINE__,
|
||||
dev_path(curdev), res->flags);
|
||||
if (res->size == 0 ||
|
||||
get_res_type(res->flags) != res_types[rt] ||
|
||||
(res->flags & IORESOURCE_BRIDGE) ||
|
||||
!need_assignment(res->flags))
|
||||
continue;
|
||||
else
|
||||
add_res_to_stack(&res_root, curdev, res);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate resources and update bridge range */
|
||||
if (res_root || (bridge && !(bridge->flags & IORESOURCE_ASSIGNED))) {
|
||||
reserve_dev_resources(stack, res_types[rt], res_root, bridge);
|
||||
reclaim_resource_mem(res_root);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xeonsp_pci_domain_read_resources(struct device *dev)
|
||||
{
|
||||
struct bus *link;
|
||||
|
||||
DEV_FUNC_ENTER(dev);
|
||||
|
||||
pci_domain_read_resources(dev);
|
||||
|
||||
/*
|
||||
* Walk through all devices in this domain and read resources.
|
||||
* Since there is no callback when read resource operation is
|
||||
* complete for all devices, domain read resource function initiates
|
||||
* read resources for all devices and swaps read resource operation
|
||||
* with dummy function to avoid warning.
|
||||
*/
|
||||
for (link = dev->link_list; link; link = link->next)
|
||||
xeonsp_pci_dev_iterator(link, xeonsp_pci_dev_read_resources, NULL, NULL);
|
||||
|
||||
for (link = dev->link_list; link; link = link->next)
|
||||
xeonsp_pci_dev_iterator(link, xeonsp_reset_pci_op, NULL, NULL);
|
||||
|
||||
struct iiostack_resource stack_info = {0};
|
||||
uint8_t pci64bit_alloc_flag = get_iiostack_info(&stack_info);
|
||||
if (!pci64bit_alloc_flag) {
|
||||
/*
|
||||
* Split 32 bit address space between prefetchable and
|
||||
* non-prefetchable windows
|
||||
*/
|
||||
for (int s = 0; s < stack_info.no_of_stacks; ++s) {
|
||||
STACK_RES *res = &stack_info.res[s];
|
||||
uint64_t length = (res->PciResourceMem32Limit -
|
||||
res->PciResourceMem32Base + 1)/2;
|
||||
res->PciResourceMem64Limit = res->PciResourceMem32Limit;
|
||||
res->PciResourceMem32Limit = (res->PciResourceMem32Base + length - 1);
|
||||
res->PciResourceMem64Base = res->PciResourceMem32Limit + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* assign resources */
|
||||
assign_stack_resources(&stack_info, dev, NULL);
|
||||
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
static void reset_resource_to_unassigned(struct device *dev, struct resource *res, void *data)
|
||||
{
|
||||
if ((res->flags & (IORESOURCE_IO | IORESOURCE_MEM)) &&
|
||||
!(res->flags & (IORESOURCE_FIXED | IORESOURCE_RESERVE))) {
|
||||
res->flags &= ~IORESOURCE_ASSIGNED;
|
||||
}
|
||||
}
|
||||
|
||||
void xeonsp_pci_domain_set_resources(struct device *dev)
|
||||
{
|
||||
DEV_FUNC_ENTER(dev);
|
||||
|
||||
print_resource_tree(dev, BIOS_SPEW, "Before xeonsp pci domain set resource");
|
||||
|
||||
/* reset bus 0 dev resource assignment - need to change them to FSP IIOStack window */
|
||||
xeonsp_pci_dev_iterator(dev->link_list, NULL, reset_resource_to_unassigned, NULL);
|
||||
|
||||
/* update dev resources based on IIOStack IO/Mem32/Mem64 windows */
|
||||
xeonsp_pci_domain_read_resources(dev);
|
||||
|
||||
struct bus *link = dev->link_list;
|
||||
while (link != NULL) {
|
||||
assign_resources(link);
|
||||
link = link->next;
|
||||
}
|
||||
|
||||
print_resource_tree(dev, BIOS_SPEW, "After xeonsp pci domain set resource");
|
||||
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
/* Attach IIO stack bus numbers with dummy device to PCI DOMAIN 0000 device */
|
||||
void attach_iio_stacks(struct device *dev)
|
||||
{
|
||||
struct bus *iiostack_bus;
|
||||
struct device dummy;
|
||||
struct iiostack_resource stack_info = {0};
|
||||
|
||||
DEV_FUNC_ENTER(dev);
|
||||
|
||||
get_iiostack_info(&stack_info);
|
||||
for (int s = 0; s < stack_info.no_of_stacks; ++s) {
|
||||
/* only non zero bus no. needs to be enumerated */
|
||||
if (stack_info.res[s].BusBase == 0)
|
||||
continue;
|
||||
|
||||
iiostack_bus = malloc(sizeof(struct bus));
|
||||
if (iiostack_bus == NULL)
|
||||
die("%s: out of memory.\n", __func__);
|
||||
memset(iiostack_bus, 0, sizeof(*iiostack_bus));
|
||||
memcpy(iiostack_bus, dev->bus, sizeof(*iiostack_bus));
|
||||
iiostack_bus->secondary = stack_info.res[s].BusBase;
|
||||
iiostack_bus->subordinate = stack_info.res[s].BusBase;
|
||||
iiostack_bus->dev = NULL;
|
||||
iiostack_bus->children = NULL;
|
||||
iiostack_bus->next = NULL;
|
||||
iiostack_bus->link_num = 1;
|
||||
|
||||
dummy.bus = iiostack_bus;
|
||||
dummy.path.type = DEVICE_PATH_PCI;
|
||||
dummy.path.pci.devfn = 0;
|
||||
uint32_t id = pci_read_config32(&dummy, PCI_VENDOR_ID);
|
||||
if (id == 0xffffffff)
|
||||
printk(BIOS_WARNING, "IIO Stack device %s not visible\n",
|
||||
dev_path(&dummy));
|
||||
|
||||
if (dev->link_list == NULL) {
|
||||
dev->link_list = iiostack_bus;
|
||||
} else {
|
||||
struct bus *nlink = dev->link_list;
|
||||
while (nlink->next != NULL)
|
||||
nlink = nlink->next;
|
||||
nlink->next = iiostack_bus;
|
||||
}
|
||||
}
|
||||
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
|
@ -1,498 +1,21 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <arch/ioapic.h>
|
||||
#include <assert.h>
|
||||
#include <console/console.h>
|
||||
#include <console/debug.h>
|
||||
#include <cpu/x86/lapic.h>
|
||||
#include <device/pci.h>
|
||||
#include <fsp/api.h>
|
||||
#include <intelblocks/lpc_lib.h>
|
||||
#include <intelblocks/p2sb.h>
|
||||
#include <post.h>
|
||||
#include <soc/acpi.h>
|
||||
#include <soc/chip_common.h>
|
||||
#include <soc/cpu.h>
|
||||
#include <soc/ramstage.h>
|
||||
#include <soc/pm.h>
|
||||
#include <soc/soc_util.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* C620 IOAPIC has 120 redirection entries */
|
||||
#define C620_IOAPIC_REDIR_ENTRIES 120
|
||||
|
||||
struct pci_resource {
|
||||
struct device *dev;
|
||||
struct resource *res;
|
||||
struct pci_resource *next;
|
||||
};
|
||||
|
||||
struct stack_dev_resource {
|
||||
uint8_t align;
|
||||
struct pci_resource *children;
|
||||
struct stack_dev_resource *next;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
RES_TYPE_IO = 0,
|
||||
RES_TYPE_NONPREF_MEM,
|
||||
RES_TYPE_PREF_MEM,
|
||||
MAX_RES_TYPES
|
||||
} ResType;
|
||||
|
||||
static ResType get_res_type(uint64_t flags)
|
||||
{
|
||||
if (flags & IORESOURCE_IO)
|
||||
return RES_TYPE_IO;
|
||||
if (flags & IORESOURCE_MEM) {
|
||||
if (flags & IORESOURCE_PREFETCH) {
|
||||
printk(BIOS_DEBUG, "%s:%d flags: 0x%llx\n", __func__, __LINE__, flags);
|
||||
return RES_TYPE_PREF_MEM;
|
||||
}
|
||||
/* both 64-bit and 32-bit use below 4GB address space */
|
||||
return RES_TYPE_NONPREF_MEM;
|
||||
}
|
||||
printk(BIOS_ERR, "Invalid resource type 0x%llx\n", flags);
|
||||
die("Invalida resource type");
|
||||
}
|
||||
|
||||
static bool need_assignment(uint64_t flags)
|
||||
{
|
||||
if (flags & (IORESOURCE_STORED | IORESOURCE_RESERVE | IORESOURCE_FIXED |
|
||||
IORESOURCE_ASSIGNED))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t get_resource_base(STACK_RES *stack, ResType res_type)
|
||||
{
|
||||
if (res_type == RES_TYPE_IO) {
|
||||
assert(stack->PciResourceIoBase <= stack->PciResourceIoLimit);
|
||||
return stack->PciResourceIoBase;
|
||||
}
|
||||
if (res_type == RES_TYPE_NONPREF_MEM) {
|
||||
assert(stack->PciResourceMem32Base <= stack->PciResourceMem32Limit);
|
||||
return stack->PciResourceMem32Base;
|
||||
}
|
||||
assert(stack->PciResourceMem64Base <= stack->PciResourceMem64Limit);
|
||||
return stack->PciResourceMem64Base;
|
||||
}
|
||||
|
||||
static void set_resource_base(STACK_RES *stack, ResType res_type, uint64_t base)
|
||||
{
|
||||
if (res_type == RES_TYPE_IO) {
|
||||
assert(base <= (stack->PciResourceIoLimit + 1));
|
||||
stack->PciResourceIoBase = base;
|
||||
} else if (res_type == RES_TYPE_NONPREF_MEM) {
|
||||
assert(base <= (stack->PciResourceMem32Limit + 1));
|
||||
stack->PciResourceMem32Base = base;
|
||||
} else {
|
||||
assert(base <= (stack->PciResourceMem64Limit + 1));
|
||||
stack->PciResourceMem64Base = base;
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_stack_resources(struct iiostack_resource *stack_list,
|
||||
struct device *dev, struct resource *bridge);
|
||||
|
||||
static void xeonsp_cpx_pci_domain_scan_bus(struct device *dev)
|
||||
{
|
||||
DEV_FUNC_ENTER(dev);
|
||||
struct bus *link = dev->link_list;
|
||||
|
||||
printk(BIOS_SPEW, "%s:%s scanning buses under device %s\n",
|
||||
__FILE__, __func__, dev_path(dev));
|
||||
while (link != NULL) {
|
||||
if (link->secondary == 0) { // scan only PSTACK buses
|
||||
struct device *d;
|
||||
for (d = link->children; d; d = d->sibling)
|
||||
pci_probe_dev(d, link, d->path.pci.devfn);
|
||||
scan_bridges(link);
|
||||
} else {
|
||||
pci_scan_bus(link, PCI_DEVFN(0, 0), 0xff);
|
||||
}
|
||||
link = link->next;
|
||||
}
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
static void xeonsp_pci_dev_iterator(struct bus *bus,
|
||||
void (*dev_iterator)(struct device *, void *),
|
||||
void (*res_iterator)(struct device *, struct resource *, void *),
|
||||
void *data)
|
||||
{
|
||||
struct device *curdev;
|
||||
struct resource *res;
|
||||
|
||||
/* Walk through all devices and find which resources they need. */
|
||||
for (curdev = bus->children; curdev; curdev = curdev->sibling) {
|
||||
struct bus *link;
|
||||
|
||||
if (!curdev->enabled)
|
||||
continue;
|
||||
|
||||
if (!curdev->ops || !curdev->ops->read_resources) {
|
||||
if (curdev->path.type != DEVICE_PATH_APIC)
|
||||
printk(BIOS_ERR, "%s missing read_resources\n",
|
||||
dev_path(curdev));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dev_iterator)
|
||||
dev_iterator(curdev, data);
|
||||
|
||||
if (res_iterator) {
|
||||
for (res = curdev->resource_list; res; res = res->next)
|
||||
res_iterator(curdev, res, data);
|
||||
}
|
||||
|
||||
/* Read in the resources behind the current device's links. */
|
||||
for (link = curdev->link_list; link; link = link->next)
|
||||
xeonsp_pci_dev_iterator(link, dev_iterator, res_iterator, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void xeonsp_pci_dev_read_resources(struct device *dev, void *data)
|
||||
{
|
||||
post_log_path(dev);
|
||||
dev->ops->read_resources(dev);
|
||||
}
|
||||
|
||||
static void xeonsp_pci_dev_dummy_func(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static void xeonsp_reset_pci_op(struct device *dev, void *data)
|
||||
{
|
||||
if (dev->ops)
|
||||
dev->ops->read_resources = xeonsp_pci_dev_dummy_func;
|
||||
}
|
||||
|
||||
static STACK_RES *find_stack_for_bus(struct iiostack_resource *info, uint8_t bus)
|
||||
{
|
||||
for (int i = 0; i < info->no_of_stacks; ++i) {
|
||||
if (bus >= info->res[i].BusBase && bus <= info->res[i].BusLimit)
|
||||
return &info->res[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void add_res_to_stack(struct stack_dev_resource **root,
|
||||
struct device *dev, struct resource *res)
|
||||
{
|
||||
struct stack_dev_resource *cur = *root;
|
||||
while (cur) {
|
||||
if (cur->align == res->align || cur->next == NULL) /* equal or last record */
|
||||
break;
|
||||
else if (cur->align > res->align) {
|
||||
if (cur->next->align < res->align) /* need to insert new record here */
|
||||
break;
|
||||
cur = cur->next;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct stack_dev_resource *nr;
|
||||
if (!cur || cur->align != res->align) { /* need to add new record */
|
||||
nr = malloc(sizeof(struct stack_dev_resource));
|
||||
if (nr == 0)
|
||||
die("assign_resource_to_stack(): out of memory.\n");
|
||||
memset(nr, 0, sizeof(struct stack_dev_resource));
|
||||
nr->align = res->align;
|
||||
if (!cur) {
|
||||
*root = nr; /* head node */
|
||||
} else if (cur->align > nr->align) {
|
||||
if (cur->next == NULL) {
|
||||
cur->next = nr;
|
||||
} else {
|
||||
nr->next = cur->next;
|
||||
cur->next = nr;
|
||||
}
|
||||
} else { /* insert in the beginning */
|
||||
nr->next = cur;
|
||||
*root = nr;
|
||||
}
|
||||
} else {
|
||||
nr = cur;
|
||||
}
|
||||
|
||||
assert(nr != NULL && nr->align == res->align);
|
||||
|
||||
struct pci_resource *npr = malloc(sizeof(struct pci_resource));
|
||||
if (npr == NULL)
|
||||
die("%s: out of memory.\n", __func__);
|
||||
npr->res = res;
|
||||
npr->dev = dev;
|
||||
npr->next = NULL;
|
||||
|
||||
if (nr->children == NULL) {
|
||||
nr->children = npr;
|
||||
} else {
|
||||
struct pci_resource *pr = nr->children;
|
||||
while (pr->next != NULL)
|
||||
pr = pr->next;
|
||||
pr->next = npr;
|
||||
}
|
||||
}
|
||||
|
||||
static void reserve_dev_resources(STACK_RES *stack, ResType res_type,
|
||||
struct stack_dev_resource *res_root, struct resource *bridge)
|
||||
{
|
||||
uint8_t align;
|
||||
uint64_t orig_base, base;
|
||||
|
||||
orig_base = get_resource_base(stack, res_type);
|
||||
|
||||
align = 0;
|
||||
base = orig_base;
|
||||
int first = 1;
|
||||
while (res_root) { /* loop through all devices grouped by alignment requirements */
|
||||
struct pci_resource *pr = res_root->children;
|
||||
while (pr) {
|
||||
if (first) {
|
||||
if (bridge) { /* takes highest alignment */
|
||||
if (bridge->align < pr->res->align)
|
||||
bridge->align = pr->res->align;
|
||||
orig_base = ALIGN_UP(orig_base, 1 << bridge->align);
|
||||
} else {
|
||||
orig_base = ALIGN_UP(orig_base, 1 << pr->res->align);
|
||||
}
|
||||
base = orig_base;
|
||||
|
||||
if (bridge)
|
||||
bridge->base = base;
|
||||
pr->res->base = base;
|
||||
first = 0;
|
||||
} else {
|
||||
pr->res->base = ALIGN_UP(base, 1 << pr->res->align);
|
||||
}
|
||||
pr->res->limit = pr->res->base + pr->res->size - 1;
|
||||
base = pr->res->limit + 1;
|
||||
pr->res->flags |= (IORESOURCE_ASSIGNED);
|
||||
pr = pr->next;
|
||||
}
|
||||
res_root = res_root->next;
|
||||
}
|
||||
|
||||
if (bridge) {
|
||||
/* this bridge doesn't have any resources, will set it to default window */
|
||||
if (first) {
|
||||
orig_base = ALIGN_UP(orig_base, 1 << bridge->align);
|
||||
bridge->base = orig_base;
|
||||
base = orig_base + (1ULL << bridge->gran);
|
||||
}
|
||||
|
||||
bridge->size = ALIGN_UP(base, 1 << bridge->align) - bridge->base;
|
||||
|
||||
bridge->limit = bridge->base + bridge->size - 1;
|
||||
bridge->flags |= (IORESOURCE_ASSIGNED);
|
||||
base = bridge->limit + 1;
|
||||
}
|
||||
|
||||
set_resource_base(stack, res_type, base);
|
||||
}
|
||||
|
||||
static void reclaim_resource_mem(struct stack_dev_resource *res_root)
|
||||
{
|
||||
while (res_root) { /* loop through all devices grouped by alignment requirements */
|
||||
/* free pci_resource */
|
||||
struct pci_resource *pr = res_root->children;
|
||||
while (pr) {
|
||||
struct pci_resource *dpr = pr;
|
||||
pr = pr->next;
|
||||
free(dpr);
|
||||
}
|
||||
|
||||
/* free stack_dev_resource */
|
||||
struct stack_dev_resource *ddr = res_root;
|
||||
res_root = res_root->next;
|
||||
free(ddr);
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_bridge_resources(struct iiostack_resource *stack_list,
|
||||
struct device *dev, struct resource *bridge)
|
||||
{
|
||||
struct resource *res;
|
||||
if (!dev->enabled)
|
||||
return;
|
||||
|
||||
for (res = dev->resource_list; res; res = res->next) {
|
||||
if (!(res->flags & IORESOURCE_BRIDGE) ||
|
||||
(bridge && (get_res_type(bridge->flags) != get_res_type(res->flags))))
|
||||
continue;
|
||||
|
||||
assign_stack_resources(stack_list, dev, res);
|
||||
|
||||
if (!bridge)
|
||||
continue;
|
||||
|
||||
/* for 1st time update, overlading IORESOURCE_ASSIGNED */
|
||||
if (!(bridge->flags & IORESOURCE_ASSIGNED)) {
|
||||
bridge->base = res->base;
|
||||
bridge->limit = res->limit;
|
||||
bridge->flags |= (IORESOURCE_ASSIGNED);
|
||||
} else {
|
||||
/* update bridge range from child bridge range */
|
||||
if (res->base < bridge->base)
|
||||
bridge->base = res->base;
|
||||
if (res->limit > bridge->limit)
|
||||
bridge->limit = res->limit;
|
||||
}
|
||||
bridge->size = (bridge->limit - bridge->base + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_stack_resources(struct iiostack_resource *stack_list,
|
||||
struct device *dev, struct resource *bridge)
|
||||
{
|
||||
struct bus *bus;
|
||||
|
||||
/* Read in the resources behind the current device's links. */
|
||||
for (bus = dev->link_list; bus; bus = bus->next) {
|
||||
struct device *curdev;
|
||||
STACK_RES *stack;
|
||||
|
||||
/* get IIO stack for this bus */
|
||||
stack = find_stack_for_bus(stack_list, bus->secondary);
|
||||
assert(stack != NULL);
|
||||
|
||||
/* Assign resources to bridge */
|
||||
for (curdev = bus->children; curdev; curdev = curdev->sibling)
|
||||
assign_bridge_resources(stack_list, curdev, bridge);
|
||||
|
||||
/* Pick non-bridged resources for resource allocation for each resource type */
|
||||
ResType res_types[MAX_RES_TYPES] = {
|
||||
RES_TYPE_IO,
|
||||
RES_TYPE_NONPREF_MEM,
|
||||
RES_TYPE_PREF_MEM
|
||||
};
|
||||
|
||||
uint8_t no_res_types = MAX_RES_TYPES;
|
||||
|
||||
/* if it is a bridge, only process matching brigge resource type */
|
||||
if (bridge) {
|
||||
res_types[0] = get_res_type(bridge->flags);
|
||||
no_res_types = 1;
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "%s:%d no_res_types: %d\n", __func__, __LINE__,
|
||||
no_res_types);
|
||||
|
||||
/* Process each resource type */
|
||||
for (int rt = 0; rt < no_res_types; ++rt) {
|
||||
struct stack_dev_resource *res_root = NULL;
|
||||
printk(BIOS_DEBUG, "%s:%d rt: %d\n", __func__, __LINE__, rt);
|
||||
for (curdev = bus->children; curdev; curdev = curdev->sibling) {
|
||||
struct resource *res;
|
||||
printk(BIOS_DEBUG, "%s:%d dev: %s\n",
|
||||
__func__, __LINE__, dev_path(curdev));
|
||||
if (!curdev->enabled)
|
||||
continue;
|
||||
|
||||
for (res = curdev->resource_list; res; res = res->next) {
|
||||
printk(BIOS_DEBUG, "%s:%d dev: %s, flags: 0x%lx\n",
|
||||
__func__, __LINE__,
|
||||
dev_path(curdev), res->flags);
|
||||
if (res->size == 0 ||
|
||||
get_res_type(res->flags) != res_types[rt] ||
|
||||
(res->flags & IORESOURCE_BRIDGE) ||
|
||||
!need_assignment(res->flags))
|
||||
continue;
|
||||
else
|
||||
add_res_to_stack(&res_root, curdev, res);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate resources and update bridge range */
|
||||
if (res_root || (bridge && !(bridge->flags & IORESOURCE_ASSIGNED))) {
|
||||
reserve_dev_resources(stack, res_types[rt], res_root, bridge);
|
||||
reclaim_resource_mem(res_root);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xeonsp_pci_domain_read_resources(struct device *dev)
|
||||
{
|
||||
struct bus *link;
|
||||
|
||||
DEV_FUNC_ENTER(dev);
|
||||
|
||||
pci_domain_read_resources(dev);
|
||||
|
||||
/*
|
||||
* Walk through all devices in this domain and read resources.
|
||||
* Since there is no callback when read resource operation is
|
||||
* complete for all devices, domain read resource function initiates
|
||||
* read resources for all devices and swaps read resource operation
|
||||
* with dummy function to avoid warning.
|
||||
*/
|
||||
for (link = dev->link_list; link; link = link->next)
|
||||
xeonsp_pci_dev_iterator(link, xeonsp_pci_dev_read_resources, NULL, NULL);
|
||||
|
||||
for (link = dev->link_list; link; link = link->next)
|
||||
xeonsp_pci_dev_iterator(link, xeonsp_reset_pci_op, NULL, NULL);
|
||||
|
||||
struct iiostack_resource stack_info = {0};
|
||||
uint8_t pci64bit_alloc_flag = get_iiostack_info(&stack_info);
|
||||
if (!pci64bit_alloc_flag) {
|
||||
/*
|
||||
* Split 32 bit address space between prefetchable and
|
||||
* non-prefetchable windows
|
||||
*/
|
||||
for (int s = 0; s < stack_info.no_of_stacks; ++s) {
|
||||
STACK_RES *res = &stack_info.res[s];
|
||||
uint64_t length = (res->PciResourceMem32Limit -
|
||||
res->PciResourceMem32Base + 1)/2;
|
||||
res->PciResourceMem64Limit = res->PciResourceMem32Limit;
|
||||
res->PciResourceMem32Limit = (res->PciResourceMem32Base + length - 1);
|
||||
res->PciResourceMem64Base = res->PciResourceMem32Limit + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* assign resources */
|
||||
assign_stack_resources(&stack_info, dev, NULL);
|
||||
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
static void reset_resource_to_unassigned(struct device *dev, struct resource *res, void *data)
|
||||
{
|
||||
if ((res->flags & (IORESOURCE_IO | IORESOURCE_MEM)) &&
|
||||
!(res->flags & (IORESOURCE_FIXED | IORESOURCE_RESERVE))) {
|
||||
res->flags &= ~IORESOURCE_ASSIGNED;
|
||||
}
|
||||
}
|
||||
|
||||
static void xeonsp_cpx_pci_domain_set_resources(struct device *dev)
|
||||
{
|
||||
DEV_FUNC_ENTER(dev);
|
||||
|
||||
print_resource_tree(dev, BIOS_SPEW, "Before xeonsp pci domain set resource");
|
||||
|
||||
/* reset bus 0 dev resource assignment - need to change them to FSP IIOStack window */
|
||||
xeonsp_pci_dev_iterator(dev->link_list, NULL, reset_resource_to_unassigned, NULL);
|
||||
|
||||
/* update dev resources based on IIOStack IO/Mem32/Mem64 windows */
|
||||
xeonsp_pci_domain_read_resources(dev);
|
||||
|
||||
struct bus *link = dev->link_list;
|
||||
while (link != NULL) {
|
||||
assign_resources(link);
|
||||
link = link->next;
|
||||
}
|
||||
|
||||
print_resource_tree(dev, BIOS_SPEW, "After xeonsp pci domain set resource");
|
||||
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
/* UPD parameters to be initialized before SiliconInit */
|
||||
void platform_fsp_silicon_init_params_cb(FSPS_UPD *silupd)
|
||||
{
|
||||
|
||||
mainboard_silicon_init_params(silupd);
|
||||
}
|
||||
|
||||
|
@ -507,8 +30,8 @@ static const char *soc_acpi_name(const struct device *dev)
|
|||
|
||||
static struct device_operations pci_domain_ops = {
|
||||
.read_resources = &pci_domain_read_resources,
|
||||
.set_resources = &xeonsp_cpx_pci_domain_set_resources,
|
||||
.scan_bus = &xeonsp_cpx_pci_domain_scan_bus,
|
||||
.set_resources = &xeonsp_pci_domain_set_resources,
|
||||
.scan_bus = &xeonsp_pci_domain_scan_bus,
|
||||
#if CONFIG(HAVE_ACPI_TABLES)
|
||||
.write_acpi_tables = &northbridge_write_acpi_tables,
|
||||
.acpi_name = soc_acpi_name
|
||||
|
@ -522,45 +45,6 @@ static struct device_operations cpu_bus_ops = {
|
|||
.acpi_fill_ssdt = generate_cpu_entries,
|
||||
};
|
||||
|
||||
/* Attach IIO stack bus numbers with dummy device to PCI DOMAIN 0000 device */
|
||||
static void attach_iio_stacks(struct device *dev)
|
||||
{
|
||||
struct bus *iiostack_bus;
|
||||
struct iiostack_resource stack_info = {0};
|
||||
|
||||
DEV_FUNC_ENTER(dev);
|
||||
|
||||
get_iiostack_info(&stack_info);
|
||||
for (int s = 0; s < stack_info.no_of_stacks; ++s) {
|
||||
/* only non zero bus no. needs to be enumerated */
|
||||
if (stack_info.res[s].BusBase == 0)
|
||||
continue;
|
||||
|
||||
iiostack_bus = malloc(sizeof(struct bus));
|
||||
if (iiostack_bus == NULL)
|
||||
die("%s: out of memory.\n", __func__);
|
||||
memset(iiostack_bus, 0, sizeof(*iiostack_bus));
|
||||
memcpy(iiostack_bus, dev->bus, sizeof(*iiostack_bus));
|
||||
iiostack_bus->secondary = stack_info.res[s].BusBase;
|
||||
iiostack_bus->subordinate = stack_info.res[s].BusBase;
|
||||
iiostack_bus->dev = NULL;
|
||||
iiostack_bus->children = NULL;
|
||||
iiostack_bus->next = NULL;
|
||||
iiostack_bus->link_num = 1;
|
||||
|
||||
if (dev->link_list == NULL) {
|
||||
dev->link_list = iiostack_bus;
|
||||
} else {
|
||||
struct bus *nlink = dev->link_list;
|
||||
while (nlink->next != NULL)
|
||||
nlink = nlink->next;
|
||||
nlink->next = iiostack_bus;
|
||||
}
|
||||
}
|
||||
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
struct pci_operations soc_pci_ops = {
|
||||
.set_subsystem = pci_dev_set_subsystem,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef _CHIP_COMMON_H_
|
||||
#define _CHIP_COMMON_H_
|
||||
|
||||
void xeonsp_pci_domain_set_resources(struct device *dev);
|
||||
void xeonsp_pci_domain_scan_bus(struct device *dev);
|
||||
void attach_iio_stacks(struct device *dev);
|
||||
|
||||
#endif /* _CHIP_COMMON_H_ */
|
|
@ -1,485 +1,14 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <cbfs.h>
|
||||
#include <assert.h>
|
||||
#include <console/console.h>
|
||||
#include <console/debug.h>
|
||||
#include <post.h>
|
||||
#include <device/pci.h>
|
||||
#include <soc/acpi.h>
|
||||
#include <soc/chip_common.h>
|
||||
#include <soc/ramstage.h>
|
||||
#include <soc/soc_util.h>
|
||||
#include <soc/util.h>
|
||||
|
||||
struct pci_resource {
|
||||
struct device *dev;
|
||||
struct resource *res;
|
||||
struct pci_resource *next;
|
||||
};
|
||||
|
||||
struct stack_dev_resource {
|
||||
uint8_t align;
|
||||
struct pci_resource *children;
|
||||
struct stack_dev_resource *next;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
RES_TYPE_IO = 0,
|
||||
RES_TYPE_NONPREF_MEM,
|
||||
RES_TYPE_PREF_MEM,
|
||||
MAX_RES_TYPES
|
||||
} RES_TYPE;
|
||||
|
||||
static RES_TYPE get_res_type(uint64_t flags)
|
||||
{
|
||||
if (flags & IORESOURCE_IO)
|
||||
return RES_TYPE_IO;
|
||||
if (flags & IORESOURCE_MEM) {
|
||||
if (flags & IORESOURCE_PREFETCH) {
|
||||
printk(BIOS_DEBUG, "%s:%d flags: 0x%llx\n", __func__, __LINE__, flags);
|
||||
return RES_TYPE_PREF_MEM;
|
||||
}
|
||||
/* both 64-bit and 32-bit use below 4GB address space */
|
||||
return RES_TYPE_NONPREF_MEM;
|
||||
}
|
||||
printk(BIOS_ERR, "Invalid resource type 0x%llx\n", flags);
|
||||
die("");
|
||||
}
|
||||
|
||||
static bool need_assignment(uint64_t flags)
|
||||
{
|
||||
if (flags & (IORESOURCE_STORED | IORESOURCE_RESERVE | IORESOURCE_FIXED |
|
||||
IORESOURCE_ASSIGNED))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t get_resource_base(STACK_RES *stack, RES_TYPE res_type)
|
||||
{
|
||||
if (res_type == RES_TYPE_IO) {
|
||||
assert(stack->PciResourceIoBase <= stack->PciResourceIoLimit);
|
||||
return stack->PciResourceIoBase;
|
||||
}
|
||||
if (res_type == RES_TYPE_NONPREF_MEM) {
|
||||
assert(stack->PciResourceMem32Base <= stack->PciResourceMem32Limit);
|
||||
return stack->PciResourceMem32Base;
|
||||
}
|
||||
assert(stack->PciResourceMem64Base <= stack->PciResourceMem64Limit);
|
||||
return stack->PciResourceMem64Base;
|
||||
}
|
||||
|
||||
static void set_resource_base(STACK_RES *stack, RES_TYPE res_type, uint64_t base)
|
||||
{
|
||||
if (res_type == RES_TYPE_IO) {
|
||||
assert(base <= (stack->PciResourceIoLimit + 1));
|
||||
stack->PciResourceIoBase = base;
|
||||
} else if (res_type == RES_TYPE_NONPREF_MEM) {
|
||||
assert(base <= (stack->PciResourceMem32Limit + 1));
|
||||
stack->PciResourceMem32Base = base;
|
||||
} else {
|
||||
assert(base <= (stack->PciResourceMem64Limit + 1));
|
||||
stack->PciResourceMem64Base = base;
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_stack_resources(struct iiostack_resource *stack_list,
|
||||
struct device *dev, struct resource *bridge);
|
||||
|
||||
static void xeonsp_pci_domain_scan_bus(struct device *dev)
|
||||
{
|
||||
DEV_FUNC_ENTER(dev);
|
||||
struct bus *link = dev->link_list;
|
||||
|
||||
printk(BIOS_SPEW, "%s:%s scanning buses under device %s\n",
|
||||
__FILE__, __func__, dev_path(dev));
|
||||
while (link != NULL) {
|
||||
if (link->secondary == 0) { // scan only PSTACK buses
|
||||
struct device *d;
|
||||
for (d = link->children; d; d = d->sibling)
|
||||
pci_probe_dev(d, link, d->path.pci.devfn);
|
||||
scan_bridges(link);
|
||||
} else {
|
||||
pci_scan_bus(link, PCI_DEVFN(0, 0), 0xff);
|
||||
}
|
||||
link = link->next;
|
||||
}
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
static void xeonsp_pci_dev_iterator(struct bus *bus,
|
||||
void (*dev_iterator)(struct device *, void *),
|
||||
void (*res_iterator)(struct device *, struct resource *, void *),
|
||||
void *data)
|
||||
{
|
||||
struct device *curdev;
|
||||
struct resource *res;
|
||||
|
||||
/* Walk through all devices and find which resources they need. */
|
||||
for (curdev = bus->children; curdev; curdev = curdev->sibling) {
|
||||
struct bus *link;
|
||||
|
||||
if (!curdev->enabled)
|
||||
continue;
|
||||
|
||||
if (!curdev->ops || !curdev->ops->read_resources) {
|
||||
if (curdev->path.type != DEVICE_PATH_APIC)
|
||||
printk(BIOS_ERR, "%s missing read_resources\n",
|
||||
dev_path(curdev));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dev_iterator)
|
||||
dev_iterator(curdev, data);
|
||||
|
||||
if (res_iterator) {
|
||||
for (res = curdev->resource_list; res; res = res->next)
|
||||
res_iterator(curdev, res, data);
|
||||
}
|
||||
|
||||
/* Read in the resources behind the current device's links. */
|
||||
for (link = curdev->link_list; link; link = link->next)
|
||||
xeonsp_pci_dev_iterator(link, dev_iterator, res_iterator, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void xeonsp_pci_dev_read_resources(struct device *dev, void *data)
|
||||
{
|
||||
post_log_path(dev);
|
||||
dev->ops->read_resources(dev);
|
||||
}
|
||||
|
||||
static void xeonsp_pci_dev_dummy_func(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static void xeonsp_reset_pci_op(struct device *dev, void *data)
|
||||
{
|
||||
if (dev->ops)
|
||||
dev->ops->read_resources = xeonsp_pci_dev_dummy_func;
|
||||
}
|
||||
|
||||
static STACK_RES *find_stack_for_bus(struct iiostack_resource *info, uint8_t bus)
|
||||
{
|
||||
for (int i = 0; i < info->no_of_stacks; ++i) {
|
||||
if (bus >= info->res[i].BusBase && bus <= info->res[i].BusLimit)
|
||||
return &info->res[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void add_res_to_stack(struct stack_dev_resource **root,
|
||||
struct device *dev, struct resource *res)
|
||||
{
|
||||
struct stack_dev_resource *cur = *root;
|
||||
while (cur) {
|
||||
if (cur->align == res->align || cur->next == NULL) /* equal or last record */
|
||||
break;
|
||||
else if (cur->align > res->align) {
|
||||
if (cur->next->align < res->align) /* need to insert new record here */
|
||||
break;
|
||||
cur = cur->next;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct stack_dev_resource *nr;
|
||||
if (!cur || cur->align != res->align) { /* need to add new record */
|
||||
nr = malloc(sizeof(struct stack_dev_resource));
|
||||
if (nr == 0)
|
||||
die("assign_resource_to_stack(): out of memory.\n");
|
||||
memset(nr, 0, sizeof(struct stack_dev_resource));
|
||||
nr->align = res->align;
|
||||
if (!cur) {
|
||||
*root = nr; /* head node */
|
||||
} else if (cur->align > nr->align) {
|
||||
if (cur->next == NULL) {
|
||||
cur->next = nr;
|
||||
} else {
|
||||
nr->next = cur->next;
|
||||
cur->next = nr;
|
||||
}
|
||||
} else { /* insert in the beginning */
|
||||
nr->next = cur;
|
||||
*root = nr;
|
||||
}
|
||||
} else {
|
||||
nr = cur;
|
||||
}
|
||||
|
||||
assert(nr != NULL && nr->align == res->align);
|
||||
|
||||
struct pci_resource *npr = malloc(sizeof(struct pci_resource));
|
||||
if (npr == NULL)
|
||||
die("%s: out of memory.\n", __func__);
|
||||
npr->res = res;
|
||||
npr->dev = dev;
|
||||
npr->next = NULL;
|
||||
|
||||
if (nr->children == NULL) {
|
||||
nr->children = npr;
|
||||
} else {
|
||||
struct pci_resource *pr = nr->children;
|
||||
while (pr->next != NULL)
|
||||
pr = pr->next;
|
||||
pr->next = npr;
|
||||
}
|
||||
}
|
||||
|
||||
static void reserve_dev_resources(STACK_RES *stack, RES_TYPE res_type,
|
||||
struct stack_dev_resource *res_root, struct resource *bridge)
|
||||
{
|
||||
uint8_t align;
|
||||
uint64_t orig_base, base;
|
||||
|
||||
orig_base = get_resource_base(stack, res_type);
|
||||
|
||||
align = 0;
|
||||
base = orig_base;
|
||||
int first = 1;
|
||||
while (res_root) { /* loop through all devices grouped by alignment requirements */
|
||||
struct pci_resource *pr = res_root->children;
|
||||
while (pr) {
|
||||
if (first) {
|
||||
if (bridge) { /* takes highest alignment */
|
||||
if (bridge->align < pr->res->align)
|
||||
bridge->align = pr->res->align;
|
||||
orig_base = ALIGN_UP(orig_base, 1 << bridge->align);
|
||||
} else {
|
||||
orig_base = ALIGN_UP(orig_base, 1 << pr->res->align);
|
||||
}
|
||||
base = orig_base;
|
||||
|
||||
if (bridge)
|
||||
bridge->base = base;
|
||||
pr->res->base = base;
|
||||
first = 0;
|
||||
} else {
|
||||
pr->res->base = ALIGN_UP(base, 1 << pr->res->align);
|
||||
}
|
||||
pr->res->limit = pr->res->base + pr->res->size - 1;
|
||||
base = pr->res->limit + 1;
|
||||
pr->res->flags |= (IORESOURCE_ASSIGNED);
|
||||
pr = pr->next;
|
||||
}
|
||||
res_root = res_root->next;
|
||||
}
|
||||
|
||||
if (bridge) {
|
||||
/* this bridge doesn't have any resources, will set it to default window */
|
||||
if (first) {
|
||||
orig_base = ALIGN_UP(orig_base, 1 << bridge->align);
|
||||
bridge->base = orig_base;
|
||||
base = orig_base + (1ULL << bridge->gran);
|
||||
}
|
||||
|
||||
bridge->size = ALIGN_UP(base, 1 << bridge->align) - bridge->base;
|
||||
|
||||
bridge->limit = bridge->base + bridge->size - 1;
|
||||
bridge->flags |= (IORESOURCE_ASSIGNED);
|
||||
base = bridge->limit + 1;
|
||||
}
|
||||
|
||||
set_resource_base(stack, res_type, base);
|
||||
}
|
||||
|
||||
static void reclaim_resource_mem(struct stack_dev_resource *res_root)
|
||||
{
|
||||
while (res_root) { /* loop through all devices grouped by alignment requirements */
|
||||
/* free pci_resource */
|
||||
struct pci_resource *pr = res_root->children;
|
||||
while (pr) {
|
||||
struct pci_resource *dpr = pr;
|
||||
pr = pr->next;
|
||||
free(dpr);
|
||||
}
|
||||
|
||||
/* free stack_dev_resource */
|
||||
struct stack_dev_resource *ddr = res_root;
|
||||
res_root = res_root->next;
|
||||
free(ddr);
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_bridge_resources(struct iiostack_resource *stack_list,
|
||||
struct device *dev, struct resource *bridge)
|
||||
{
|
||||
struct resource *res;
|
||||
if (!dev->enabled)
|
||||
return;
|
||||
|
||||
for (res = dev->resource_list; res; res = res->next) {
|
||||
if (!(res->flags & IORESOURCE_BRIDGE) ||
|
||||
(bridge && (get_res_type(bridge->flags) != get_res_type(res->flags))))
|
||||
continue;
|
||||
|
||||
assign_stack_resources(stack_list, dev, res);
|
||||
|
||||
if (!bridge)
|
||||
continue;
|
||||
|
||||
/* for 1st time update, overlading IORESOURCE_ASSIGNED */
|
||||
if (!(bridge->flags & IORESOURCE_ASSIGNED)) {
|
||||
bridge->base = res->base;
|
||||
bridge->limit = res->limit;
|
||||
bridge->flags |= (IORESOURCE_ASSIGNED);
|
||||
} else {
|
||||
/* update bridge range from child bridge range */
|
||||
if (res->base < bridge->base)
|
||||
bridge->base = res->base;
|
||||
if (res->limit > bridge->limit)
|
||||
bridge->limit = res->limit;
|
||||
}
|
||||
bridge->size = (bridge->limit - bridge->base + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void assign_stack_resources(struct iiostack_resource *stack_list,
|
||||
struct device *dev, struct resource *bridge)
|
||||
{
|
||||
struct bus *bus;
|
||||
|
||||
/* Read in the resources behind the current device's links. */
|
||||
for (bus = dev->link_list; bus; bus = bus->next) {
|
||||
struct device *curdev;
|
||||
STACK_RES *stack;
|
||||
|
||||
/* get IIO stack for this bus */
|
||||
stack = find_stack_for_bus(stack_list, bus->secondary);
|
||||
assert(stack != NULL);
|
||||
|
||||
/* Assign resources to bridge */
|
||||
for (curdev = bus->children; curdev; curdev = curdev->sibling)
|
||||
assign_bridge_resources(stack_list, curdev, bridge);
|
||||
|
||||
/* Pick non-bridged resources for resource allocation for each resource type */
|
||||
RES_TYPE res_types[MAX_RES_TYPES] = {
|
||||
RES_TYPE_IO,
|
||||
RES_TYPE_NONPREF_MEM,
|
||||
RES_TYPE_PREF_MEM
|
||||
};
|
||||
|
||||
uint8_t no_res_types = MAX_RES_TYPES;
|
||||
|
||||
/* if it is a bridge, only process matching bridge resource type */
|
||||
if (bridge) {
|
||||
res_types[0] = get_res_type(bridge->flags);
|
||||
no_res_types = 1;
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "%s:%d no_res_types: %d\n", __func__, __LINE__,
|
||||
no_res_types);
|
||||
|
||||
/* Process each resource type */
|
||||
for (int rt = 0; rt < no_res_types; ++rt) {
|
||||
struct stack_dev_resource *res_root = NULL;
|
||||
printk(BIOS_DEBUG, "%s:%d rt: %d\n", __func__, __LINE__, rt);
|
||||
for (curdev = bus->children; curdev; curdev = curdev->sibling) {
|
||||
struct resource *res;
|
||||
printk(BIOS_DEBUG, "%s:%d dev: %s\n",
|
||||
__func__, __LINE__, dev_path(curdev));
|
||||
if (!curdev->enabled)
|
||||
continue;
|
||||
|
||||
for (res = curdev->resource_list; res; res = res->next) {
|
||||
printk(BIOS_DEBUG, "%s:%d dev: %s, flags: 0x%lx\n",
|
||||
__func__, __LINE__,
|
||||
dev_path(curdev), res->flags);
|
||||
if (res->size == 0 ||
|
||||
get_res_type(res->flags) != res_types[rt] ||
|
||||
(res->flags & IORESOURCE_BRIDGE) ||
|
||||
!need_assignment(res->flags))
|
||||
continue;
|
||||
else
|
||||
add_res_to_stack(&res_root, curdev, res);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate resources and update bridge range */
|
||||
if (res_root || (bridge && !(bridge->flags & IORESOURCE_ASSIGNED))) {
|
||||
reserve_dev_resources(stack, res_types[rt], res_root, bridge);
|
||||
reclaim_resource_mem(res_root);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xeonsp_pci_domain_read_resources(struct device *dev)
|
||||
{
|
||||
struct bus *link;
|
||||
|
||||
DEV_FUNC_ENTER(dev);
|
||||
|
||||
pci_domain_read_resources(dev);
|
||||
|
||||
/*
|
||||
* Walk through all devices in this domain and read resources.
|
||||
* Since there is no callback when read resource operation is
|
||||
* complete for all devices, domain read resource function initiates
|
||||
* read resources for all devices and swaps read resource operation
|
||||
* with dummy function to avoid warning.
|
||||
*/
|
||||
for (link = dev->link_list; link; link = link->next)
|
||||
xeonsp_pci_dev_iterator(link, xeonsp_pci_dev_read_resources, NULL, NULL);
|
||||
|
||||
for (link = dev->link_list; link; link = link->next)
|
||||
xeonsp_pci_dev_iterator(link, xeonsp_reset_pci_op, NULL, NULL);
|
||||
|
||||
struct iiostack_resource stack_info = {0};
|
||||
uint8_t pci64bit_alloc_flag = get_iiostack_info(&stack_info);
|
||||
if (!pci64bit_alloc_flag) {
|
||||
/*
|
||||
* Split 32 bit address space between prefetchable and
|
||||
* non-prefetchable windows
|
||||
*/
|
||||
for (int s = 0; s < stack_info.no_of_stacks; ++s) {
|
||||
STACK_RES *res = &stack_info.res[s];
|
||||
uint64_t length = (res->PciResourceMem32Limit -
|
||||
res->PciResourceMem32Base + 1)/2;
|
||||
res->PciResourceMem64Limit = res->PciResourceMem32Limit;
|
||||
res->PciResourceMem32Limit = (res->PciResourceMem32Base + length - 1);
|
||||
res->PciResourceMem64Base = res->PciResourceMem32Limit + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* assign resources */
|
||||
assign_stack_resources(&stack_info, dev, NULL);
|
||||
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
static void reset_resource_to_unassigned(struct device *dev, struct resource *res, void *data)
|
||||
{
|
||||
if ((res->flags & (IORESOURCE_IO | IORESOURCE_MEM)) &&
|
||||
!(res->flags & (IORESOURCE_FIXED | IORESOURCE_RESERVE))) {
|
||||
res->flags &= ~IORESOURCE_ASSIGNED;
|
||||
}
|
||||
}
|
||||
|
||||
static void xeonsp_pci_domain_set_resources(struct device *dev)
|
||||
{
|
||||
DEV_FUNC_ENTER(dev);
|
||||
|
||||
print_resource_tree(dev, BIOS_SPEW, "Before xeonsp pci domain set resource");
|
||||
|
||||
/* reset bus 0 dev resource assignment - need to change them to FSP IIOStack window */
|
||||
xeonsp_pci_dev_iterator(dev->link_list, NULL, reset_resource_to_unassigned, NULL);
|
||||
|
||||
/* update dev resources based on IIOStack IO/Mem32/Mem64 windows */
|
||||
xeonsp_pci_domain_read_resources(dev);
|
||||
|
||||
struct bus *link = dev->link_list;
|
||||
while (link != NULL) {
|
||||
assign_resources(link);
|
||||
link = link->next;
|
||||
}
|
||||
|
||||
print_resource_tree(dev, BIOS_SPEW, "After xeonsp pci domain set resource");
|
||||
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
static struct device_operations pci_domain_ops = {
|
||||
.read_resources = &pci_domain_read_resources,
|
||||
.set_resources = &xeonsp_pci_domain_set_resources,
|
||||
|
@ -499,54 +28,6 @@ static struct device_operations cpu_bus_ops = {
|
|||
#endif
|
||||
};
|
||||
|
||||
/* Attach IIO stack bus numbers with dummy device to PCI DOMAIN 0000 device */
|
||||
static void attach_iio_stacks(struct device *dev)
|
||||
{
|
||||
struct bus *iiostack_bus;
|
||||
struct device dummy;
|
||||
struct iiostack_resource stack_info = {0};
|
||||
|
||||
DEV_FUNC_ENTER(dev);
|
||||
|
||||
get_iiostack_info(&stack_info);
|
||||
for (int s = 0; s < stack_info.no_of_stacks; ++s) {
|
||||
/* only non zero bus no. needs to be enumerated */
|
||||
if (stack_info.res[s].BusBase == 0)
|
||||
continue;
|
||||
|
||||
iiostack_bus = malloc(sizeof(struct bus));
|
||||
if (iiostack_bus == NULL)
|
||||
die("%s: out of memory.\n", __func__);
|
||||
memset(iiostack_bus, 0, sizeof(*iiostack_bus));
|
||||
memcpy(iiostack_bus, dev->bus, sizeof(*iiostack_bus));
|
||||
iiostack_bus->secondary = stack_info.res[s].BusBase;
|
||||
iiostack_bus->subordinate = stack_info.res[s].BusBase;
|
||||
iiostack_bus->dev = NULL;
|
||||
iiostack_bus->children = NULL;
|
||||
iiostack_bus->next = NULL;
|
||||
iiostack_bus->link_num = 1;
|
||||
|
||||
dummy.bus = iiostack_bus;
|
||||
dummy.path.type = DEVICE_PATH_PCI;
|
||||
dummy.path.pci.devfn = 0;
|
||||
uint32_t id = pci_read_config32(&dummy, PCI_VENDOR_ID);
|
||||
if (id == 0xffffffff)
|
||||
printk(BIOS_WARNING, "IIO Stack device %s not visible\n",
|
||||
dev_path(&dummy));
|
||||
|
||||
if (dev->link_list == NULL) {
|
||||
dev->link_list = iiostack_bus;
|
||||
} else {
|
||||
struct bus *nlink = dev->link_list;
|
||||
while (nlink->next != NULL)
|
||||
nlink = nlink->next;
|
||||
nlink->next = iiostack_bus;
|
||||
}
|
||||
}
|
||||
|
||||
DEV_FUNC_EXIT(dev);
|
||||
}
|
||||
|
||||
static void soc_enable_dev(struct device *dev)
|
||||
{
|
||||
/* Set the operations if it is a special bus type */
|
||||
|
@ -571,10 +52,6 @@ static void soc_final(void *data)
|
|||
set_bios_init_completion();
|
||||
}
|
||||
|
||||
static void soc_silicon_init_params(FSPS_UPD *silupd)
|
||||
{
|
||||
}
|
||||
|
||||
void platform_fsp_silicon_init_params_cb(FSPS_UPD *silupd)
|
||||
{
|
||||
const struct microcode *microcode_file;
|
||||
|
@ -591,7 +68,6 @@ void platform_fsp_silicon_init_params_cb(FSPS_UPD *silupd)
|
|||
(uint32_t)microcode_len;
|
||||
}
|
||||
|
||||
soc_silicon_init_params(silupd);
|
||||
mainboard_silicon_init_params(silupd);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue