msm: mpq8064: pcie: Correct the PCIE device address space allocation
PCIE device resources are being allocated from the system memory
address space, instead of the PCIE device address space. This causes
conflict in system memory address space. Specify the PCI framework
to allocate device resources from a separate PCIE device address space
instead of the default system memory address space. Correctly allocate
the PCIE AXI resources from the system memory resource. The PCIE hardware
address translation block translates the PCIE AXI region to PCIE device
address region. Pass the PCIE AXI region as platfrom data instead of the
device platform resource to the PCIE controller driver. That way only the
required PCIE AXI resources are allocated from the system memory resource.
Change-Id: Id01bcbeb95f6894d00dfb786267c6c2fb30657e8
Signed-off-by: Niranjana Vishwanathapura <nvishwan@codeaurora.org>
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
index 5818bef..f105356 100644
--- a/arch/arm/mach-msm/pcie.c
+++ b/arch/arm/mach-msm/pcie.c
@@ -27,6 +27,7 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
#include <linux/types.h>
#include <asm/mach/pci.h>
#include <mach/gpiomux.h>
@@ -72,6 +73,9 @@
#define RD 0
#define WR 1
+/* PCIE AXI address space */
+#define PCIE_AXI_CONF_SIZE SZ_1M
+
/* debug mask sys interface */
static int msm_pcie_debug_mask;
module_param_named(debug_mask, msm_pcie_debug_mask,
@@ -79,12 +83,15 @@
/* resources from device file */
enum msm_pcie_res {
+ /* platform defined resources */
MSM_PCIE_RES_PARF,
MSM_PCIE_RES_ELBI,
MSM_PCIE_RES_PCIE20,
- MSM_PCIE_RES_AXI_BAR,
- MSM_PCIE_RES_AXI_CONF,
- MSM_PCIE_MAX_RES
+ MSM_PCIE_MAX_PLATFORM_RES,
+
+ /* other resources */
+ MSM_PCIE_RES_AXI_CONF = MSM_PCIE_MAX_PLATFORM_RES,
+ MSM_PCIE_MAX_RES,
};
/* msm pcie device data */
@@ -107,11 +114,10 @@
/* resources */
static struct msm_pcie_res_info_t msm_pcie_res_info[MSM_PCIE_MAX_RES] = {
- {"parf", 0, 0, 0},
- {"elbi", 0, 0, 0},
- {"pcie20", 0, 0, 0},
- {"axi_bar", 0, 0, 0},
- {"axi_conf", 0, 0, 0},
+ {"pcie_parf", 0, 0},
+ {"pcie_elbi", 0, 0},
+ {"pcie20", 0, 0},
+ {"pcie_axi_conf", 0, 0},
};
int msm_pcie_get_debug_mask(void)
@@ -350,8 +356,7 @@
static void __init msm_pcie_config_controller(void)
{
struct msm_pcie_dev_t *dev = &msm_pcie_dev;
- struct msm_pcie_res_info_t *axi_bar = &dev->res[MSM_PCIE_RES_AXI_BAR];
- struct msm_pcie_res_info_t *axi_conf = &dev->res[MSM_PCIE_RES_AXI_CONF];
+ struct resource *axi_conf = dev->res[MSM_PCIE_RES_AXI_CONF].resource;
/*
* program and enable address translation region 0 (device config
@@ -384,9 +389,9 @@
writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
- writel_relaxed(axi_bar->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
+ writel_relaxed(dev->axi_bar_start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
- writel_relaxed(axi_bar->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
+ writel_relaxed(dev->axi_bar_end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
writel_relaxed(MSM_PCIE_DEV_BAR_ADDR,
dev->pcie20 + PCIE20_PLR_IATU_LTAR);
writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
@@ -404,8 +409,15 @@
for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
info = &dev->res[i];
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, info->name);
+ if (i < MSM_PCIE_MAX_PLATFORM_RES) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ info->name);
+ } else {
+ res = dev->res[i].resource;
+ if (request_resource(&iomem_resource, res))
+ res = NULL;
+ }
+
if (!res) {
pr_err("can't get %s resource\n", info->name);
rc = -ENOMEM;
@@ -419,14 +431,15 @@
break;
}
- info->start = res->start;
- info->end = res->end;
+ info->resource = res;
}
if (rc) {
while (i--) {
iounmap(dev->res[i].base);
dev->res[i].base = NULL;
+ if (i >= MSM_PCIE_MAX_PLATFORM_RES)
+ release_resource(dev->res[i].resource);
}
} else {
dev->parf = dev->res[MSM_PCIE_RES_PARF].base;
@@ -445,6 +458,8 @@
for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
iounmap(msm_pcie_dev.res[i].base);
msm_pcie_dev.res[i].base = NULL;
+ if (i >= MSM_PCIE_MAX_PLATFORM_RES)
+ release_resource(msm_pcie_dev.res[i].resource);
}
msm_pcie_dev.parf = NULL;
@@ -463,6 +478,13 @@
if (nr != 0)
return 0;
+ /*
+ * specify linux PCI framework to allocate device memory (BARs)
+ * from msm_pcie_dev.dev_mem_res resource.
+ */
+ sys->mem_offset = 0;
+ pci_add_resource(&sys->resources, &msm_pcie_dev.dev_mem_res);
+
/* assert PCIe reset link to keep EP in reset */
gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
dev->gpio[MSM_PCIE_GPIO_RST_N].on);
@@ -556,7 +578,8 @@
PCIE_DBG("bus %d\n", nr);
if (nr == 0)
- bus = pci_scan_bus(sys->busnr, &msm_pcie_ops, sys);
+ bus = pci_scan_root_bus(NULL, sys->busnr, &msm_pcie_ops, sys,
+ &sys->resources);
return bus;
}
@@ -578,6 +601,7 @@
static int __init msm_pcie_probe(struct platform_device *pdev)
{
const struct msm_pcie_platform *pdata;
+ struct resource *res;
int rc;
PCIE_DBG("\n");
@@ -589,6 +613,31 @@
msm_pcie_dev.clk = msm_pcie_clk_info;
msm_pcie_dev.res = msm_pcie_res_info;
+ /* device memory resource */
+ res = &msm_pcie_dev.dev_mem_res;
+ res->name = "pcie_dev_mem";
+ res->start = MSM_PCIE_DEV_BAR_ADDR;
+ res->end = res->start + pdata->axi_size - 1;
+ res->flags = IORESOURCE_MEM;
+
+ /* axi address space = axi bar space + axi config space */
+ msm_pcie_dev.axi_bar_start = pdata->axi_addr;
+ msm_pcie_dev.axi_bar_end = pdata->axi_addr + pdata->axi_size -
+ PCIE_AXI_CONF_SIZE - 1;
+
+ /* axi config space resource */
+ res = kzalloc(sizeof(*res), GFP_KERNEL);
+ if (!res) {
+ pr_err("can't allocate memory\n");
+ return -ENOMEM;
+ }
+
+ msm_pcie_dev.res[MSM_PCIE_RES_AXI_CONF].resource = res;
+ res->name = msm_pcie_dev.res[MSM_PCIE_RES_AXI_CONF].name;
+ res->start = msm_pcie_dev.axi_bar_end + 1;
+ res->end = res->start + PCIE_AXI_CONF_SIZE - 1;
+ res->flags = IORESOURCE_MEM;
+
rc = msm_pcie_get_resources(msm_pcie_dev.pdev);
if (rc)
return rc;
@@ -632,7 +681,6 @@
static int __init msm_pcie_init(void)
{
PCIE_DBG("\n");
- pcibios_min_io = 0x10000000;
pcibios_min_mem = 0x10000000;
return platform_driver_probe(&msm_pcie_driver, msm_pcie_probe);
}
@@ -649,22 +697,30 @@
msm_pcie_fixup_early);
/*
- * actual physical (BAR) address of the device resources starts from 0x10xxxxxx;
- * the system axi address for the device resources starts from 0x08xxxxxx;
- * correct the device resource structure here; address translation unit handles
- * the required translations
+ * actual physical (BAR) address of the device resources starts from
+ * MSM_PCIE_DEV_BAR_ADDR; the system axi address for the device resources starts
+ * from msm_pcie_dev.axi_bar_start; correct the device resource structure here;
+ * address translation unit handles the required translations
*/
static void __devinit msm_pcie_fixup_final(struct pci_dev *dev)
{
int i;
+ struct resource *res;
PCIE_DBG("vendor 0x%x 0x%x\n", dev->vendor, dev->device);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- if (dev->resource[i].start & 0xFF000000) {
- dev->resource[i].start &= 0x00FFFFFF;
- dev->resource[i].start |= 0x08000000;
- dev->resource[i].end &= 0x00FFFFFF;
- dev->resource[i].end |= 0x08000000;
+ res = &dev->resource[i];
+ if (res->start & MSM_PCIE_DEV_BAR_ADDR) {
+ res->start -= MSM_PCIE_DEV_BAR_ADDR;
+ res->start += msm_pcie_dev.axi_bar_start;
+ res->end -= MSM_PCIE_DEV_BAR_ADDR;
+ res->end += msm_pcie_dev.axi_bar_start;
+
+ /* If Root Port, request for the changed resource */
+ if ((dev->vendor == PCIE_VENDOR_ID_RCP) &&
+ (dev->device == PCIE_DEVICE_ID_RCP)) {
+ insert_resource(&iomem_resource, res);
+ }
}
}
}