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 nodes, and is the only property needed in that case.
|
||||
- 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
|
||||
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
|
||||
|
@ -220,6 +221,7 @@ Example:
|
|||
qcom,ext-ref-clk;
|
||||
qcom,tlp-rd-size = <0x5>;
|
||||
qcom,common-phy;
|
||||
qcom,smmu-exist;
|
||||
qcom,ep-latency = <100>;
|
||||
|
||||
iommus = <&anoc0_smmu>;
|
||||
|
|
|
@ -160,6 +160,10 @@
|
|||
#define PCIE20_PARF_MHI_CLOCK_RESET_CTRL 0x174
|
||||
#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x1A8
|
||||
#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_SYS_CTRL 0x04
|
||||
|
@ -237,6 +241,7 @@
|
|||
#define MSM_PCIE_MAX_PIPE_CLK 1
|
||||
#define MAX_RC_NUM 3
|
||||
#define MAX_DEVICE_NUM 20
|
||||
#define MAX_SHORT_BDF_NUM 16
|
||||
#define PCIE_TLP_RD_SIZE 0x5
|
||||
#define PCIE_MSI_NR_IRQS 256
|
||||
#define MSM_PCIE_MAX_MSI 32
|
||||
|
@ -415,6 +420,8 @@ struct msm_pcie_irq_info_t {
|
|||
struct msm_pcie_device_info {
|
||||
u32 bdf;
|
||||
struct pci_dev *dev;
|
||||
short short_bdf;
|
||||
u32 sid;
|
||||
int domain;
|
||||
void __iomem *conf_base;
|
||||
unsigned long phy_address;
|
||||
|
@ -482,11 +489,13 @@ struct msm_pcie_dev_t {
|
|||
bool common_clk_en;
|
||||
bool clk_power_manage_en;
|
||||
bool aux_clk_sync;
|
||||
bool smmu_exist;
|
||||
uint32_t n_fts;
|
||||
bool ext_ref_clk;
|
||||
bool common_phy;
|
||||
uint32_t ep_latency;
|
||||
uint32_t current_bdf;
|
||||
short current_short_bdf;
|
||||
uint32_t tlp_rd_size;
|
||||
bool ep_wakeirq;
|
||||
|
||||
|
@ -1440,6 +1449,10 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev)
|
|||
dev->msi_gicm_base);
|
||||
pr_alert("bus_client: %d\n",
|
||||
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",
|
||||
dev->n_fts);
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
|
||||
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",
|
||||
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)
|
||||
|
@ -3889,6 +3925,105 @@ static int msm_pcie_config_device_table(struct device *dev, void *pdev)
|
|||
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)
|
||||
{
|
||||
|
@ -4817,6 +4952,13 @@ static int msm_pcie_probe(struct platform_device *pdev)
|
|||
"AUX clock is %s synchronous to Core clock.\n",
|
||||
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 =
|
||||
of_property_read_bool((&pdev->dev)->of_node,
|
||||
"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].wake_counter = 0;
|
||||
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_pinctrl = 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++) {
|
||||
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].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].conf_base = 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++) {
|
||||
msm_pcie_dev_tbl[i].bdf = 0;
|
||||
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].conf_base = 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
|
||||
* 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,
|
||||
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
|
||||
|
|
Loading…
Add table
Reference in a new issue