diff options
author | Tomasz Nowicki <tn@semihalf.com> | 2017-03-23 18:10:16 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-03-23 18:11:26 -0400 |
commit | 9abb27c7594a62bbf6385e20b7f5a90b4eceae2f (patch) | |
tree | 27c3048b54fa2f885bd1eef704c7ccbd6513ddd4 | |
parent | 81caa91b72fd6a0b8dfc5eb10942c34f7efd2bc5 (diff) |
PCI: thunder-pem: Add legacy firmware support for Cavium ThunderX host controller
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: Robert Richter <rrichter@cavium.com>
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev@caviumnetworks.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Robert Richter <rrichter@cavium.com>
CC: stable@vger.kernel.org # v4.10+
-rw-r--r-- | drivers/pci/host/pci-thunder-pem.c | 56 |
1 files changed, 54 insertions, 2 deletions
diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c index 5b88faeebaaa..b89c373555c5 100644 --- a/drivers/pci/host/pci-thunder-pem.c +++ b/drivers/pci/host/pci-thunder-pem.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * Copyright (C) 2015 - 2016 Cavium, Inc. | 14 | * Copyright (C) 2015 - 2016 Cavium, Inc. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/bitfield.h> | ||
17 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
19 | #include <linux/of_address.h> | 20 | #include <linux/of_address.h> |
@@ -334,6 +335,50 @@ static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg, | |||
334 | 335 | ||
335 | #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) | 336 | #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) |
336 | 337 | ||
338 | #define PEM_RES_BASE 0x87e0c0000000UL | ||
339 | #define PEM_NODE_MASK GENMASK(45, 44) | ||
340 | #define PEM_INDX_MASK GENMASK(26, 24) | ||
341 | #define PEM_MIN_DOM_IN_NODE 4 | ||
342 | #define PEM_MAX_DOM_IN_NODE 10 | ||
343 | |||
344 | static void thunder_pem_reserve_range(struct device *dev, int seg, | ||
345 | struct resource *r) | ||
346 | { | ||
347 | resource_size_t start = r->start, end = r->end; | ||
348 | struct resource *res; | ||
349 | const char *regionid; | ||
350 | |||
351 | regionid = kasprintf(GFP_KERNEL, "PEM RC:%d", seg); | ||
352 | if (!regionid) | ||
353 | return; | ||
354 | |||
355 | res = request_mem_region(start, end - start + 1, regionid); | ||
356 | if (res) | ||
357 | res->flags &= ~IORESOURCE_BUSY; | ||
358 | else | ||
359 | kfree(regionid); | ||
360 | |||
361 | dev_info(dev, "%pR %s reserved\n", r, | ||
362 | res ? "has been" : "could not be"); | ||
363 | } | ||
364 | |||
365 | static void thunder_pem_legacy_fw(struct acpi_pci_root *root, | ||
366 | struct resource *res_pem) | ||
367 | { | ||
368 | int node = acpi_get_node(root->device->handle); | ||
369 | int index; | ||
370 | |||
371 | if (node == NUMA_NO_NODE) | ||
372 | node = 0; | ||
373 | |||
374 | index = root->segment - PEM_MIN_DOM_IN_NODE; | ||
375 | index -= node * PEM_MAX_DOM_IN_NODE; | ||
376 | res_pem->start = PEM_RES_BASE | FIELD_PREP(PEM_NODE_MASK, node) | | ||
377 | FIELD_PREP(PEM_INDX_MASK, index); | ||
378 | res_pem->end = res_pem->start + SZ_16M - 1; | ||
379 | res_pem->flags = IORESOURCE_MEM; | ||
380 | } | ||
381 | |||
337 | static int thunder_pem_acpi_init(struct pci_config_window *cfg) | 382 | static int thunder_pem_acpi_init(struct pci_config_window *cfg) |
338 | { | 383 | { |
339 | struct device *dev = cfg->parent; | 384 | struct device *dev = cfg->parent; |
@@ -347,9 +392,16 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg) | |||
347 | return -ENOMEM; | 392 | return -ENOMEM; |
348 | 393 | ||
349 | ret = acpi_get_rc_resources(dev, "CAVA02B", root->segment, res_pem); | 394 | ret = acpi_get_rc_resources(dev, "CAVA02B", root->segment, res_pem); |
395 | |||
396 | /* | ||
397 | * If we fail to gather resources it means that we run with old | ||
398 | * FW where we need to calculate PEM-specific resources manually. | ||
399 | */ | ||
350 | if (ret) { | 400 | if (ret) { |
351 | dev_err(dev, "can't get rc base address\n"); | 401 | thunder_pem_legacy_fw(root, res_pem); |
352 | return ret; | 402 | /* Reserve PEM-specific resources and PCI configuration space */ |
403 | thunder_pem_reserve_range(dev, root->segment, res_pem); | ||
404 | thunder_pem_reserve_range(dev, root->segment, &cfg->res); | ||
353 | } | 405 | } |
354 | 406 | ||
355 | return thunder_pem_init(dev, cfg, res_pem); | 407 | return thunder_pem_init(dev, cfg, res_pem); |