summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVidya Sagar <vidyas@nvidia.com>2018-09-11 05:23:34 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2018-09-12 10:17:54 -0400
commit2df159b5cfcea2fa4af6be6848c0e2ca0f917761 (patch)
treef215871f425096e9212405475fa464f1fad96a97
parent03e4b12b8a900dba405858cfb5e6256b3a99568a (diff)
PCI: tegra: add hot-plug/unplug support
Adds hot-plug/unplug APIs to support dynamic creation and destruction of PCIe hierarchy of a respective host controller Bug 2312016 Bug 200427921 Change-Id: Id8ecef5ab6b2c55543a3c43de2561f47a80fe282 Signed-off-by: Vidya Sagar <vidyas@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1819382 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r--drivers/pci/dwc/pcie-tegra.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/drivers/pci/dwc/pcie-tegra.c b/drivers/pci/dwc/pcie-tegra.c
index 90d9b7100..49b353171 100644
--- a/drivers/pci/dwc/pcie-tegra.c
+++ b/drivers/pci/dwc/pcie-tegra.c
@@ -566,6 +566,9 @@ static unsigned int pcie_gen_freq[] = {
566 566
567static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie); 567static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie);
568static int tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie); 568static int tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie);
569static int tegra_pcie_dw_runtime_suspend(struct device *dev);
570static int tegra_pcie_dw_runtime_resume(struct device *dev);
571static int tegra_pcie_dw_link_up(struct dw_pcie *pci);
569 572
570static inline void dma_common_wr16(void __iomem *p, u32 val, u32 offset) 573static inline void dma_common_wr16(void __iomem *p, u32 val, u32 offset)
571{ 574{
@@ -1773,6 +1776,80 @@ static int verify_voltage_margin(struct seq_file *s, void *data)
1773 return 0; 1776 return 0;
1774} 1777}
1775 1778
1779static int __attach_controller(struct tegra_pcie_dw *pcie)
1780{
1781 int ret;
1782
1783 if (!pcie->link_state && !pcie->power_down_en) {
1784 ret = pm_runtime_put_sync(pcie->dev);
1785 if (ret)
1786 return ret;
1787 }
1788
1789 ret = pm_runtime_get_sync(pcie->dev);
1790 if (ret)
1791 return ret;
1792 pcie->link_state = tegra_pcie_dw_link_up(&pcie->pci);
1793
1794 return 0;
1795}
1796
1797static int __detach_controller(struct tegra_pcie_dw *pcie)
1798{
1799 if (!pcie->link_state && pcie->power_down_en)
1800 return 0;
1801
1802 return pm_runtime_put_sync(pcie->dev);
1803}
1804
1805/* Enables root port controller and attempts PCIe link up with the device
1806 * connected downstream. If link is up, registers host controller with
1807 * PCIe sub-system.
1808 * @cookie : opaque pointer returned by tegra_pcie_detach_controller() API
1809 */
1810int tegra_pcie_attach_controller(void *cookie)
1811{
1812 struct tegra_pcie_dw *pcie = (struct tegra_pcie_dw *)cookie;
1813
1814 return __attach_controller(pcie);
1815}
1816EXPORT_SYMBOL(tegra_pcie_attach_controller);
1817
1818/* Removes PCIe hierarchy of the respective host controller and brings PCIe
1819 * link down in a safe way
1820 * @pdev: pointer to end point's pci_dev structure
1821 * returns a cookie which needs to be passed to
1822 * tegra_pcie_attach_controller() API
1823 */
1824void *tegra_pcie_detach_controller(struct pci_dev *pdev)
1825{
1826 struct pcie_port *pp = pdev->sysdata;
1827 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
1828 struct tegra_pcie_dw *pcie = dw_pcie_to_tegra_pcie(pci);
1829 int ret;
1830
1831 ret = __detach_controller(pcie);
1832 if (ret)
1833 return ERR_PTR(ret);
1834
1835 return (void *)pcie;
1836}
1837EXPORT_SYMBOL(tegra_pcie_detach_controller);
1838
1839static int hot_plug(struct seq_file *s, void *data)
1840{
1841 struct tegra_pcie_dw *pcie = (struct tegra_pcie_dw *)(s->private);
1842
1843 return __attach_controller(pcie);
1844}
1845
1846static int hot_unplug(struct seq_file *s, void *data)
1847{
1848 struct tegra_pcie_dw *pcie = (struct tegra_pcie_dw *)(s->private);
1849
1850 return __detach_controller(pcie);
1851}
1852
1776#define DEFINE_ENTRY(__name) \ 1853#define DEFINE_ENTRY(__name) \
1777static int __name ## _open(struct inode *inode, struct file *file) \ 1854static int __name ## _open(struct inode *inode, struct file *file) \
1778{ \ 1855{ \
@@ -1798,6 +1875,8 @@ DEFINE_ENTRY(apply_sbr);
1798DEFINE_ENTRY(aspm_state_cnt); 1875DEFINE_ENTRY(aspm_state_cnt);
1799DEFINE_ENTRY(verify_timing_margin); 1876DEFINE_ENTRY(verify_timing_margin);
1800DEFINE_ENTRY(verify_voltage_margin); 1877DEFINE_ENTRY(verify_voltage_margin);
1878DEFINE_ENTRY(hot_plug);
1879DEFINE_ENTRY(hot_unplug);
1801 1880
1802#ifdef CONFIG_PCIE_TEGRA_DW_DMA_TEST 1881#ifdef CONFIG_PCIE_TEGRA_DW_DMA_TEST
1803static void init_dma_test_debugfs(struct tegra_pcie_dw *pcie) 1882static void init_dma_test_debugfs(struct tegra_pcie_dw *pcie)
@@ -1925,6 +2004,16 @@ static int init_debugfs(struct tegra_pcie_dw *pcie)
1925 if (!d) 2004 if (!d)
1926 dev_err(pcie->dev, "debugfs for verify_voltage_margin failed\n"); 2005 dev_err(pcie->dev, "debugfs for verify_voltage_margin failed\n");
1927 2006
2007 d = debugfs_create_file("hot_plug", 0444, pcie->debugfs,
2008 (void *)pcie, &hot_plug_fops);
2009 if (!d)
2010 dev_err(pcie->dev, "debugfs for hot_plug failed\n");
2011
2012 d = debugfs_create_file("hot_unplug", 0444, pcie->debugfs,
2013 (void *)pcie, &hot_unplug_fops);
2014 if (!d)
2015 dev_err(pcie->dev, "debugfs for hot_unplug failed\n");
2016
1928 init_dma_test_debugfs(pcie); 2017 init_dma_test_debugfs(pcie);
1929 2018
1930 return 0; 2019 return 0;