diff options
Diffstat (limited to 'drivers/pci/host/pci-tegra.c')
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index abd65784618d..0fb0fdb223d5 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c | |||
@@ -25,6 +25,7 @@ | |||
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/clk.h> | 27 | #include <linux/clk.h> |
28 | #include <linux/debugfs.h> | ||
28 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
29 | #include <linux/export.h> | 30 | #include <linux/export.h> |
30 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
@@ -276,6 +277,7 @@ struct tegra_pcie { | |||
276 | unsigned int num_supplies; | 277 | unsigned int num_supplies; |
277 | 278 | ||
278 | const struct tegra_pcie_soc_data *soc_data; | 279 | const struct tegra_pcie_soc_data *soc_data; |
280 | struct dentry *debugfs; | ||
279 | }; | 281 | }; |
280 | 282 | ||
281 | struct tegra_pcie_port { | 283 | struct tegra_pcie_port { |
@@ -1739,6 +1741,115 @@ static const struct of_device_id tegra_pcie_of_match[] = { | |||
1739 | }; | 1741 | }; |
1740 | MODULE_DEVICE_TABLE(of, tegra_pcie_of_match); | 1742 | MODULE_DEVICE_TABLE(of, tegra_pcie_of_match); |
1741 | 1743 | ||
1744 | static void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos) | ||
1745 | { | ||
1746 | struct tegra_pcie *pcie = s->private; | ||
1747 | |||
1748 | if (list_empty(&pcie->ports)) | ||
1749 | return NULL; | ||
1750 | |||
1751 | seq_printf(s, "Index Status\n"); | ||
1752 | |||
1753 | return seq_list_start(&pcie->ports, *pos); | ||
1754 | } | ||
1755 | |||
1756 | static void *tegra_pcie_ports_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
1757 | { | ||
1758 | struct tegra_pcie *pcie = s->private; | ||
1759 | |||
1760 | return seq_list_next(v, &pcie->ports, pos); | ||
1761 | } | ||
1762 | |||
1763 | static void tegra_pcie_ports_seq_stop(struct seq_file *s, void *v) | ||
1764 | { | ||
1765 | } | ||
1766 | |||
1767 | static int tegra_pcie_ports_seq_show(struct seq_file *s, void *v) | ||
1768 | { | ||
1769 | bool up = false, active = false; | ||
1770 | struct tegra_pcie_port *port; | ||
1771 | unsigned int value; | ||
1772 | |||
1773 | port = list_entry(v, struct tegra_pcie_port, list); | ||
1774 | |||
1775 | value = readl(port->base + RP_VEND_XP); | ||
1776 | |||
1777 | if (value & RP_VEND_XP_DL_UP) | ||
1778 | up = true; | ||
1779 | |||
1780 | value = readl(port->base + RP_LINK_CONTROL_STATUS); | ||
1781 | |||
1782 | if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE) | ||
1783 | active = true; | ||
1784 | |||
1785 | seq_printf(s, "%2u ", port->index); | ||
1786 | |||
1787 | if (up) | ||
1788 | seq_printf(s, "up"); | ||
1789 | |||
1790 | if (active) { | ||
1791 | if (up) | ||
1792 | seq_printf(s, ", "); | ||
1793 | |||
1794 | seq_printf(s, "active"); | ||
1795 | } | ||
1796 | |||
1797 | seq_printf(s, "\n"); | ||
1798 | return 0; | ||
1799 | } | ||
1800 | |||
1801 | static const struct seq_operations tegra_pcie_ports_seq_ops = { | ||
1802 | .start = tegra_pcie_ports_seq_start, | ||
1803 | .next = tegra_pcie_ports_seq_next, | ||
1804 | .stop = tegra_pcie_ports_seq_stop, | ||
1805 | .show = tegra_pcie_ports_seq_show, | ||
1806 | }; | ||
1807 | |||
1808 | static int tegra_pcie_ports_open(struct inode *inode, struct file *file) | ||
1809 | { | ||
1810 | struct tegra_pcie *pcie = inode->i_private; | ||
1811 | struct seq_file *s; | ||
1812 | int err; | ||
1813 | |||
1814 | err = seq_open(file, &tegra_pcie_ports_seq_ops); | ||
1815 | if (err) | ||
1816 | return err; | ||
1817 | |||
1818 | s = file->private_data; | ||
1819 | s->private = pcie; | ||
1820 | |||
1821 | return 0; | ||
1822 | } | ||
1823 | |||
1824 | static const struct file_operations tegra_pcie_ports_ops = { | ||
1825 | .owner = THIS_MODULE, | ||
1826 | .open = tegra_pcie_ports_open, | ||
1827 | .read = seq_read, | ||
1828 | .llseek = seq_lseek, | ||
1829 | .release = seq_release, | ||
1830 | }; | ||
1831 | |||
1832 | static int tegra_pcie_debugfs_init(struct tegra_pcie *pcie) | ||
1833 | { | ||
1834 | struct dentry *file; | ||
1835 | |||
1836 | pcie->debugfs = debugfs_create_dir("pcie", NULL); | ||
1837 | if (!pcie->debugfs) | ||
1838 | return -ENOMEM; | ||
1839 | |||
1840 | file = debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, | ||
1841 | pcie, &tegra_pcie_ports_ops); | ||
1842 | if (!file) | ||
1843 | goto remove; | ||
1844 | |||
1845 | return 0; | ||
1846 | |||
1847 | remove: | ||
1848 | debugfs_remove_recursive(pcie->debugfs); | ||
1849 | pcie->debugfs = NULL; | ||
1850 | return -ENOMEM; | ||
1851 | } | ||
1852 | |||
1742 | static int tegra_pcie_probe(struct platform_device *pdev) | 1853 | static int tegra_pcie_probe(struct platform_device *pdev) |
1743 | { | 1854 | { |
1744 | const struct of_device_id *match; | 1855 | const struct of_device_id *match; |
@@ -1793,6 +1904,13 @@ static int tegra_pcie_probe(struct platform_device *pdev) | |||
1793 | goto disable_msi; | 1904 | goto disable_msi; |
1794 | } | 1905 | } |
1795 | 1906 | ||
1907 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
1908 | err = tegra_pcie_debugfs_init(pcie); | ||
1909 | if (err < 0) | ||
1910 | dev_err(&pdev->dev, "failed to setup debugfs: %d\n", | ||
1911 | err); | ||
1912 | } | ||
1913 | |||
1796 | platform_set_drvdata(pdev, pcie); | 1914 | platform_set_drvdata(pdev, pcie); |
1797 | return 0; | 1915 | return 0; |
1798 | 1916 | ||