Commit f8709a9e authored by Tomasz Nowicki's avatar Tomasz Nowicki Committed by Greg Kroah-Hartman

PCI: thunder-pem: Add legacy firmware support for Cavium ThunderX host controller

commit 9abb27c7 upstream.

During early days of PCI quirks support, ThunderX firmware did not provide
PNP0c02 node with PCI configuration space and PEM-specific register ranges.
This means that for legacy FW we are not reserving these resources and
cannot gather PEM-specific resources for further PEM initialization.

To support already deployed legacy FW, calculate PEM-specific ranges and
provide resources reservation as fallback scenario into PEM driver when we
could not gather PEM reg base from ACPI tables.
Tested-by: default avatarRobert Richter <rrichter@cavium.com>
Signed-off-by: default avatarTomasz Nowicki <tn@semihalf.com>
Signed-off-by: default avatarVadim Lomovtsev <Vadim.Lomovtsev@caviumnetworks.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Acked-by: default avatarRobert Richter <rrichter@cavium.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 44eed6f0
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* Copyright (C) 2015 - 2016 Cavium, Inc. * Copyright (C) 2015 - 2016 Cavium, Inc.
*/ */
#include <linux/bitfield.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -319,6 +320,50 @@ static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg, ...@@ -319,6 +320,50 @@ static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg,
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
#define PEM_RES_BASE 0x87e0c0000000UL
#define PEM_NODE_MASK GENMASK(45, 44)
#define PEM_INDX_MASK GENMASK(26, 24)
#define PEM_MIN_DOM_IN_NODE 4
#define PEM_MAX_DOM_IN_NODE 10
static void thunder_pem_reserve_range(struct device *dev, int seg,
struct resource *r)
{
resource_size_t start = r->start, end = r->end;
struct resource *res;
const char *regionid;
regionid = kasprintf(GFP_KERNEL, "PEM RC:%d", seg);
if (!regionid)
return;
res = request_mem_region(start, end - start + 1, regionid);
if (res)
res->flags &= ~IORESOURCE_BUSY;
else
kfree(regionid);
dev_info(dev, "%pR %s reserved\n", r,
res ? "has been" : "could not be");
}
static void thunder_pem_legacy_fw(struct acpi_pci_root *root,
struct resource *res_pem)
{
int node = acpi_get_node(root->device->handle);
int index;
if (node == NUMA_NO_NODE)
node = 0;
index = root->segment - PEM_MIN_DOM_IN_NODE;
index -= node * PEM_MAX_DOM_IN_NODE;
res_pem->start = PEM_RES_BASE | FIELD_PREP(PEM_NODE_MASK, node) |
FIELD_PREP(PEM_INDX_MASK, index);
res_pem->end = res_pem->start + SZ_16M - 1;
res_pem->flags = IORESOURCE_MEM;
}
static int thunder_pem_acpi_init(struct pci_config_window *cfg) static int thunder_pem_acpi_init(struct pci_config_window *cfg)
{ {
struct device *dev = cfg->parent; struct device *dev = cfg->parent;
...@@ -332,9 +377,16 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg) ...@@ -332,9 +377,16 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg)
return -ENOMEM; return -ENOMEM;
ret = acpi_get_rc_resources(dev, "CAVA02B", root->segment, res_pem); ret = acpi_get_rc_resources(dev, "CAVA02B", root->segment, res_pem);
/*
* If we fail to gather resources it means that we run with old
* FW where we need to calculate PEM-specific resources manually.
*/
if (ret) { if (ret) {
dev_err(dev, "can't get rc base address\n"); thunder_pem_legacy_fw(root, res_pem);
return ret; /* Reserve PEM-specific resources and PCI configuration space */
thunder_pem_reserve_range(dev, root->segment, res_pem);
thunder_pem_reserve_range(dev, root->segment, &cfg->res);
} }
return thunder_pem_init(dev, cfg, res_pem); return thunder_pem_init(dev, cfg, res_pem);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment