msm: pcie: add SMMU support to calculate SID for PCIe EP
SMMU requires PCIe to provide a SID for each of its endpoint so that the endpoint can successful transaction on the bus. This change adds the support for PCIe bus driver to calculate a SID for its endpoint and give it to the SMMU driver. Change-Id: I52099bbfed0a38c75b0277b0f58f45f6e6559695 Signed-off-by: Tony Truong <truong@codeaurora.org>
This commit is contained in:
parent
58763943bc
commit
c27c02ee65
3 changed files with 163 additions and 1 deletions
|
@ -81,6 +81,7 @@ Optional Properties:
|
||||||
complex. This should be used in separate nodes from the main root
|
complex. This should be used in separate nodes from the main root
|
||||||
complex nodes, and is the only property needed in that case.
|
complex nodes, and is the only property needed in that case.
|
||||||
- qcom,common-phy: There is a common phy for all the Root Complexes.
|
- qcom,common-phy: There is a common phy for all the Root Complexes.
|
||||||
|
- qcom,smmu-exist: PCIe uses a SMMU.
|
||||||
- qcom,ep-latency: The time (unit: ms) to wait for the PCIe endpoint to become
|
- qcom,ep-latency: The time (unit: ms) to wait for the PCIe endpoint to become
|
||||||
stable after power on, before de-assert the PERST to the endpoint.
|
stable after power on, before de-assert the PERST to the endpoint.
|
||||||
- qcom,tlp-rd-size: The max TLP read size (Calculation: 128 times 2 to the
|
- qcom,tlp-rd-size: The max TLP read size (Calculation: 128 times 2 to the
|
||||||
|
@ -220,6 +221,7 @@ Example:
|
||||||
qcom,ext-ref-clk;
|
qcom,ext-ref-clk;
|
||||||
qcom,tlp-rd-size = <0x5>;
|
qcom,tlp-rd-size = <0x5>;
|
||||||
qcom,common-phy;
|
qcom,common-phy;
|
||||||
|
qcom,smmu-exist;
|
||||||
qcom,ep-latency = <100>;
|
qcom,ep-latency = <100>;
|
||||||
|
|
||||||
iommus = <&anoc0_smmu>;
|
iommus = <&anoc0_smmu>;
|
||||||
|
|
|
@ -160,6 +160,10 @@
|
||||||
#define PCIE20_PARF_MHI_CLOCK_RESET_CTRL 0x174
|
#define PCIE20_PARF_MHI_CLOCK_RESET_CTRL 0x174
|
||||||
#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x1A8
|
#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x1A8
|
||||||
#define PCIE20_PARF_LTSSM 0x1B0
|
#define PCIE20_PARF_LTSSM 0x1B0
|
||||||
|
#define PCIE20_PARF_SID_OFFSET 0x234
|
||||||
|
#define PCIE20_PARF_BDF_TRANSLATE_CFG 0x24C
|
||||||
|
#define PCIE20_PARF_BDF_TRANSLATE_N 0x250
|
||||||
|
|
||||||
|
|
||||||
#define PCIE20_ELBI_VERSION 0x00
|
#define PCIE20_ELBI_VERSION 0x00
|
||||||
#define PCIE20_ELBI_SYS_CTRL 0x04
|
#define PCIE20_ELBI_SYS_CTRL 0x04
|
||||||
|
@ -237,6 +241,7 @@
|
||||||
#define MSM_PCIE_MAX_PIPE_CLK 1
|
#define MSM_PCIE_MAX_PIPE_CLK 1
|
||||||
#define MAX_RC_NUM 3
|
#define MAX_RC_NUM 3
|
||||||
#define MAX_DEVICE_NUM 20
|
#define MAX_DEVICE_NUM 20
|
||||||
|
#define MAX_SHORT_BDF_NUM 16
|
||||||
#define PCIE_TLP_RD_SIZE 0x5
|
#define PCIE_TLP_RD_SIZE 0x5
|
||||||
#define PCIE_MSI_NR_IRQS 256
|
#define PCIE_MSI_NR_IRQS 256
|
||||||
#define MSM_PCIE_MAX_MSI 32
|
#define MSM_PCIE_MAX_MSI 32
|
||||||
|
@ -415,6 +420,8 @@ struct msm_pcie_irq_info_t {
|
||||||
struct msm_pcie_device_info {
|
struct msm_pcie_device_info {
|
||||||
u32 bdf;
|
u32 bdf;
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
|
short short_bdf;
|
||||||
|
u32 sid;
|
||||||
int domain;
|
int domain;
|
||||||
void __iomem *conf_base;
|
void __iomem *conf_base;
|
||||||
unsigned long phy_address;
|
unsigned long phy_address;
|
||||||
|
@ -482,11 +489,13 @@ struct msm_pcie_dev_t {
|
||||||
bool common_clk_en;
|
bool common_clk_en;
|
||||||
bool clk_power_manage_en;
|
bool clk_power_manage_en;
|
||||||
bool aux_clk_sync;
|
bool aux_clk_sync;
|
||||||
|
bool smmu_exist;
|
||||||
uint32_t n_fts;
|
uint32_t n_fts;
|
||||||
bool ext_ref_clk;
|
bool ext_ref_clk;
|
||||||
bool common_phy;
|
bool common_phy;
|
||||||
uint32_t ep_latency;
|
uint32_t ep_latency;
|
||||||
uint32_t current_bdf;
|
uint32_t current_bdf;
|
||||||
|
short current_short_bdf;
|
||||||
uint32_t tlp_rd_size;
|
uint32_t tlp_rd_size;
|
||||||
bool ep_wakeirq;
|
bool ep_wakeirq;
|
||||||
|
|
||||||
|
@ -1440,6 +1449,10 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev)
|
||||||
dev->msi_gicm_base);
|
dev->msi_gicm_base);
|
||||||
pr_alert("bus_client: %d\n",
|
pr_alert("bus_client: %d\n",
|
||||||
dev->bus_client);
|
dev->bus_client);
|
||||||
|
pr_alert("current short bdf: %d\n",
|
||||||
|
dev->current_short_bdf);
|
||||||
|
pr_alert("smmu does %s exist\n",
|
||||||
|
dev->smmu_exist ? "" : "not");
|
||||||
pr_alert("n_fts: %d\n",
|
pr_alert("n_fts: %d\n",
|
||||||
dev->n_fts);
|
dev->n_fts);
|
||||||
pr_alert("common_phy: %d\n",
|
pr_alert("common_phy: %d\n",
|
||||||
|
@ -2929,6 +2942,8 @@ static void msm_pcie_iatu_config_all_ep(struct msm_pcie_dev_t *dev)
|
||||||
|
|
||||||
static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev)
|
static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
PCIE_DBG(dev, "RC%d\n", dev->rc_idx);
|
PCIE_DBG(dev, "RC%d\n", dev->rc_idx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2970,6 +2985,27 @@ static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev)
|
||||||
|
|
||||||
PCIE_DBG(dev, "RC's PCIE20_CAP_DEVCTRLSTATUS:0x%x\n",
|
PCIE_DBG(dev, "RC's PCIE20_CAP_DEVCTRLSTATUS:0x%x\n",
|
||||||
readl_relaxed(dev->dm_core + PCIE20_CAP_DEVCTRLSTATUS));
|
readl_relaxed(dev->dm_core + PCIE20_CAP_DEVCTRLSTATUS));
|
||||||
|
|
||||||
|
/* configure SMMU registers */
|
||||||
|
if (dev->smmu_exist) {
|
||||||
|
msm_pcie_write_reg(dev->parf,
|
||||||
|
PCIE20_PARF_BDF_TRANSLATE_CFG, 0);
|
||||||
|
msm_pcie_write_reg(dev->parf,
|
||||||
|
PCIE20_PARF_SID_OFFSET, 0);
|
||||||
|
|
||||||
|
if (dev->enumerated) {
|
||||||
|
for (i = 0; i < MAX_DEVICE_NUM; i++) {
|
||||||
|
if (dev->pcidev_table[i].dev &&
|
||||||
|
dev->pcidev_table[i].short_bdf) {
|
||||||
|
msm_pcie_write_reg(dev->parf,
|
||||||
|
PCIE20_PARF_BDF_TRANSLATE_N +
|
||||||
|
dev->pcidev_table[i].short_bdf
|
||||||
|
* 4,
|
||||||
|
dev->pcidev_table[i].bdf >> 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msm_pcie_config_link_state(struct msm_pcie_dev_t *dev)
|
static void msm_pcie_config_link_state(struct msm_pcie_dev_t *dev)
|
||||||
|
@ -3889,6 +3925,105 @@ static int msm_pcie_config_device_table(struct device *dev, void *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int msm_pcie_configure_sid(struct device *dev, u32 *sid, int *domain)
|
||||||
|
{
|
||||||
|
struct pci_dev *pcidev;
|
||||||
|
struct msm_pcie_dev_t *pcie_dev;
|
||||||
|
struct pci_bus *bus;
|
||||||
|
int i;
|
||||||
|
u32 bdf;
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
|
pr_err("%s: PCIe: endpoint device passed in is NULL\n",
|
||||||
|
__func__);
|
||||||
|
return MSM_PCIE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcidev = to_pci_dev(dev);
|
||||||
|
if (!pcidev) {
|
||||||
|
pr_err("%s: PCIe: PCI device of endpoint is NULL\n",
|
||||||
|
__func__);
|
||||||
|
return MSM_PCIE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
bus = pcidev->bus;
|
||||||
|
if (!bus) {
|
||||||
|
pr_err("%s: PCIe: Bus of PCI device is NULL\n",
|
||||||
|
__func__);
|
||||||
|
return MSM_PCIE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!pci_is_root_bus(bus))
|
||||||
|
bus = bus->parent;
|
||||||
|
|
||||||
|
pcie_dev = (struct msm_pcie_dev_t *)(bus->sysdata);
|
||||||
|
if (!pcie_dev) {
|
||||||
|
pr_err("%s: PCIe: Could not get PCIe structure\n",
|
||||||
|
__func__);
|
||||||
|
return MSM_PCIE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pcie_dev->smmu_exist) {
|
||||||
|
PCIE_DBG(pcie_dev,
|
||||||
|
"PCIe: RC:%d: smmu does not exist\n",
|
||||||
|
pcie_dev->rc_idx);
|
||||||
|
return MSM_PCIE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
PCIE_DBG(pcie_dev, "PCIe: RC%d: device address is: %p\n",
|
||||||
|
pcie_dev->rc_idx, dev);
|
||||||
|
PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device address is: %p\n",
|
||||||
|
pcie_dev->rc_idx, pcidev);
|
||||||
|
|
||||||
|
*domain = pcie_dev->rc_idx;
|
||||||
|
|
||||||
|
if (pcie_dev->current_short_bdf < (MAX_SHORT_BDF_NUM - 1)) {
|
||||||
|
pcie_dev->current_short_bdf++;
|
||||||
|
} else {
|
||||||
|
PCIE_ERR(pcie_dev,
|
||||||
|
"PCIe: RC%d: No more short BDF left\n",
|
||||||
|
pcie_dev->rc_idx);
|
||||||
|
return MSM_PCIE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdf = BDF_OFFSET(pcidev->bus->number, pcidev->devfn);
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_DEVICE_NUM; i++) {
|
||||||
|
if (pcie_dev->pcidev_table[i].bdf == bdf) {
|
||||||
|
*sid = (pcie_dev->rc_idx << 4) |
|
||||||
|
pcie_dev->current_short_bdf;
|
||||||
|
|
||||||
|
msm_pcie_write_reg(pcie_dev->parf,
|
||||||
|
PCIE20_PARF_BDF_TRANSLATE_N +
|
||||||
|
pcie_dev->current_short_bdf * 4,
|
||||||
|
bdf >> 16);
|
||||||
|
|
||||||
|
pcie_dev->pcidev_table[i].sid = *sid;
|
||||||
|
pcie_dev->pcidev_table[i].short_bdf =
|
||||||
|
pcie_dev->current_short_bdf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == MAX_DEVICE_NUM) {
|
||||||
|
pcie_dev->current_short_bdf--;
|
||||||
|
PCIE_ERR(pcie_dev,
|
||||||
|
"PCIe: RC%d could not find BDF:%d\n",
|
||||||
|
pcie_dev->rc_idx, bdf);
|
||||||
|
return MSM_PCIE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
PCIE_DBG(pcie_dev,
|
||||||
|
"PCIe: RC%d: Device: %02x:%02x.%01x received SID %d\n",
|
||||||
|
pcie_dev->rc_idx,
|
||||||
|
bdf >> 24,
|
||||||
|
bdf >> 19 & 0x1f,
|
||||||
|
bdf >> 16 & 0x07,
|
||||||
|
*sid);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(msm_pcie_configure_sid);
|
||||||
|
|
||||||
int msm_pcie_enumerate(u32 rc_idx)
|
int msm_pcie_enumerate(u32 rc_idx)
|
||||||
{
|
{
|
||||||
|
@ -4817,6 +4952,13 @@ static int msm_pcie_probe(struct platform_device *pdev)
|
||||||
"AUX clock is %s synchronous to Core clock.\n",
|
"AUX clock is %s synchronous to Core clock.\n",
|
||||||
msm_pcie_dev[rc_idx].aux_clk_sync ? "" : "not");
|
msm_pcie_dev[rc_idx].aux_clk_sync ? "" : "not");
|
||||||
|
|
||||||
|
msm_pcie_dev[rc_idx].smmu_exist =
|
||||||
|
of_property_read_bool((&pdev->dev)->of_node,
|
||||||
|
"qcom,smmu-exist");
|
||||||
|
PCIE_DBG(&msm_pcie_dev[rc_idx],
|
||||||
|
"SMMU does %s exist.\n",
|
||||||
|
msm_pcie_dev[rc_idx].smmu_exist ? "" : "not");
|
||||||
|
|
||||||
msm_pcie_dev[rc_idx].ep_wakeirq =
|
msm_pcie_dev[rc_idx].ep_wakeirq =
|
||||||
of_property_read_bool((&pdev->dev)->of_node,
|
of_property_read_bool((&pdev->dev)->of_node,
|
||||||
"qcom,ep-wakeirq");
|
"qcom,ep-wakeirq");
|
||||||
|
@ -4933,6 +5075,7 @@ static int msm_pcie_probe(struct platform_device *pdev)
|
||||||
msm_pcie_dev[rc_idx].suspending = false;
|
msm_pcie_dev[rc_idx].suspending = false;
|
||||||
msm_pcie_dev[rc_idx].wake_counter = 0;
|
msm_pcie_dev[rc_idx].wake_counter = 0;
|
||||||
msm_pcie_dev[rc_idx].power_on = false;
|
msm_pcie_dev[rc_idx].power_on = false;
|
||||||
|
msm_pcie_dev[rc_idx].current_short_bdf = 0;
|
||||||
msm_pcie_dev[rc_idx].use_msi = false;
|
msm_pcie_dev[rc_idx].use_msi = false;
|
||||||
msm_pcie_dev[rc_idx].use_pinctrl = false;
|
msm_pcie_dev[rc_idx].use_pinctrl = false;
|
||||||
msm_pcie_dev[rc_idx].bridge_found = false;
|
msm_pcie_dev[rc_idx].bridge_found = false;
|
||||||
|
@ -4959,6 +5102,8 @@ static int msm_pcie_probe(struct platform_device *pdev)
|
||||||
for (i = 0; i < MAX_DEVICE_NUM; i++) {
|
for (i = 0; i < MAX_DEVICE_NUM; i++) {
|
||||||
msm_pcie_dev[rc_idx].pcidev_table[i].bdf = 0;
|
msm_pcie_dev[rc_idx].pcidev_table[i].bdf = 0;
|
||||||
msm_pcie_dev[rc_idx].pcidev_table[i].dev = NULL;
|
msm_pcie_dev[rc_idx].pcidev_table[i].dev = NULL;
|
||||||
|
msm_pcie_dev[rc_idx].pcidev_table[i].short_bdf = 0;
|
||||||
|
msm_pcie_dev[rc_idx].pcidev_table[i].sid = 0;
|
||||||
msm_pcie_dev[rc_idx].pcidev_table[i].domain = rc_idx;
|
msm_pcie_dev[rc_idx].pcidev_table[i].domain = rc_idx;
|
||||||
msm_pcie_dev[rc_idx].pcidev_table[i].conf_base = 0;
|
msm_pcie_dev[rc_idx].pcidev_table[i].conf_base = 0;
|
||||||
msm_pcie_dev[rc_idx].pcidev_table[i].phy_address = 0;
|
msm_pcie_dev[rc_idx].pcidev_table[i].phy_address = 0;
|
||||||
|
@ -5158,6 +5303,8 @@ int __init pcie_init(void)
|
||||||
for (i = 0; i < MAX_RC_NUM * MAX_DEVICE_NUM; i++) {
|
for (i = 0; i < MAX_RC_NUM * MAX_DEVICE_NUM; i++) {
|
||||||
msm_pcie_dev_tbl[i].bdf = 0;
|
msm_pcie_dev_tbl[i].bdf = 0;
|
||||||
msm_pcie_dev_tbl[i].dev = NULL;
|
msm_pcie_dev_tbl[i].dev = NULL;
|
||||||
|
msm_pcie_dev_tbl[i].short_bdf = 0;
|
||||||
|
msm_pcie_dev_tbl[i].sid = 0;
|
||||||
msm_pcie_dev_tbl[i].domain = -1;
|
msm_pcie_dev_tbl[i].domain = -1;
|
||||||
msm_pcie_dev_tbl[i].conf_base = 0;
|
msm_pcie_dev_tbl[i].conf_base = 0;
|
||||||
msm_pcie_dev_tbl[i].phy_address = 0;
|
msm_pcie_dev_tbl[i].phy_address = 0;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2 and
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
@ -155,4 +155,17 @@ int msm_pcie_shadow_control(struct pci_dev *dev, bool enable);
|
||||||
*/
|
*/
|
||||||
int msm_pcie_debug_info(struct pci_dev *dev, u32 option, u32 base,
|
int msm_pcie_debug_info(struct pci_dev *dev, u32 option, u32 base,
|
||||||
u32 offset, u32 mask, u32 value);
|
u32 offset, u32 mask, u32 value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* msm_pcie_configure_sid - calculates the SID for a PCIe endpoint.
|
||||||
|
* @dev: device structure
|
||||||
|
* @sid: the calculated SID
|
||||||
|
* @domain: the domain number of the Root Complex
|
||||||
|
*
|
||||||
|
* This function calculates the SID for a PCIe endpoint device.
|
||||||
|
*
|
||||||
|
* Return: 0 on success, negative value on error
|
||||||
|
*/
|
||||||
|
int msm_pcie_configure_sid(struct device *dev, u32 *sid,
|
||||||
|
int *domain);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue