diff options
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r-- | drivers/pci/pci-sysfs.c | 204 |
1 files changed, 197 insertions, 7 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 31e99613a12e..2f3780b50723 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -154,6 +154,129 @@ static ssize_t resource_show(struct device *dev, struct device_attribute *attr, | |||
154 | } | 154 | } |
155 | static DEVICE_ATTR_RO(resource); | 155 | static DEVICE_ATTR_RO(resource); |
156 | 156 | ||
157 | static ssize_t max_link_speed_show(struct device *dev, | ||
158 | struct device_attribute *attr, char *buf) | ||
159 | { | ||
160 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
161 | u32 linkcap; | ||
162 | int err; | ||
163 | const char *speed; | ||
164 | |||
165 | err = pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &linkcap); | ||
166 | if (err) | ||
167 | return -EINVAL; | ||
168 | |||
169 | switch (linkcap & PCI_EXP_LNKCAP_SLS) { | ||
170 | case PCI_EXP_LNKCAP_SLS_8_0GB: | ||
171 | speed = "8 GT/s"; | ||
172 | break; | ||
173 | case PCI_EXP_LNKCAP_SLS_5_0GB: | ||
174 | speed = "5 GT/s"; | ||
175 | break; | ||
176 | case PCI_EXP_LNKCAP_SLS_2_5GB: | ||
177 | speed = "2.5 GT/s"; | ||
178 | break; | ||
179 | default: | ||
180 | speed = "Unknown speed"; | ||
181 | } | ||
182 | |||
183 | return sprintf(buf, "%s\n", speed); | ||
184 | } | ||
185 | static DEVICE_ATTR_RO(max_link_speed); | ||
186 | |||
187 | static ssize_t max_link_width_show(struct device *dev, | ||
188 | struct device_attribute *attr, char *buf) | ||
189 | { | ||
190 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
191 | u32 linkcap; | ||
192 | int err; | ||
193 | |||
194 | err = pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &linkcap); | ||
195 | if (err) | ||
196 | return -EINVAL; | ||
197 | |||
198 | return sprintf(buf, "%u\n", (linkcap & PCI_EXP_LNKCAP_MLW) >> 4); | ||
199 | } | ||
200 | static DEVICE_ATTR_RO(max_link_width); | ||
201 | |||
202 | static ssize_t current_link_speed_show(struct device *dev, | ||
203 | struct device_attribute *attr, char *buf) | ||
204 | { | ||
205 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
206 | u16 linkstat; | ||
207 | int err; | ||
208 | const char *speed; | ||
209 | |||
210 | err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat); | ||
211 | if (err) | ||
212 | return -EINVAL; | ||
213 | |||
214 | switch (linkstat & PCI_EXP_LNKSTA_CLS) { | ||
215 | case PCI_EXP_LNKSTA_CLS_8_0GB: | ||
216 | speed = "8 GT/s"; | ||
217 | break; | ||
218 | case PCI_EXP_LNKSTA_CLS_5_0GB: | ||
219 | speed = "5 GT/s"; | ||
220 | break; | ||
221 | case PCI_EXP_LNKSTA_CLS_2_5GB: | ||
222 | speed = "2.5 GT/s"; | ||
223 | break; | ||
224 | default: | ||
225 | speed = "Unknown speed"; | ||
226 | } | ||
227 | |||
228 | return sprintf(buf, "%s\n", speed); | ||
229 | } | ||
230 | static DEVICE_ATTR_RO(current_link_speed); | ||
231 | |||
232 | static ssize_t current_link_width_show(struct device *dev, | ||
233 | struct device_attribute *attr, char *buf) | ||
234 | { | ||
235 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
236 | u16 linkstat; | ||
237 | int err; | ||
238 | |||
239 | err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat); | ||
240 | if (err) | ||
241 | return -EINVAL; | ||
242 | |||
243 | return sprintf(buf, "%u\n", | ||
244 | (linkstat & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT); | ||
245 | } | ||
246 | static DEVICE_ATTR_RO(current_link_width); | ||
247 | |||
248 | static ssize_t secondary_bus_number_show(struct device *dev, | ||
249 | struct device_attribute *attr, | ||
250 | char *buf) | ||
251 | { | ||
252 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
253 | u8 sec_bus; | ||
254 | int err; | ||
255 | |||
256 | err = pci_read_config_byte(pci_dev, PCI_SECONDARY_BUS, &sec_bus); | ||
257 | if (err) | ||
258 | return -EINVAL; | ||
259 | |||
260 | return sprintf(buf, "%u\n", sec_bus); | ||
261 | } | ||
262 | static DEVICE_ATTR_RO(secondary_bus_number); | ||
263 | |||
264 | static ssize_t subordinate_bus_number_show(struct device *dev, | ||
265 | struct device_attribute *attr, | ||
266 | char *buf) | ||
267 | { | ||
268 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
269 | u8 sub_bus; | ||
270 | int err; | ||
271 | |||
272 | err = pci_read_config_byte(pci_dev, PCI_SUBORDINATE_BUS, &sub_bus); | ||
273 | if (err) | ||
274 | return -EINVAL; | ||
275 | |||
276 | return sprintf(buf, "%u\n", sub_bus); | ||
277 | } | ||
278 | static DEVICE_ATTR_RO(subordinate_bus_number); | ||
279 | |||
157 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | 280 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, |
158 | char *buf) | 281 | char *buf) |
159 | { | 282 | { |
@@ -472,7 +595,6 @@ static ssize_t sriov_numvfs_store(struct device *dev, | |||
472 | const char *buf, size_t count) | 595 | const char *buf, size_t count) |
473 | { | 596 | { |
474 | struct pci_dev *pdev = to_pci_dev(dev); | 597 | struct pci_dev *pdev = to_pci_dev(dev); |
475 | struct pci_sriov *iov = pdev->sriov; | ||
476 | int ret; | 598 | int ret; |
477 | u16 num_vfs; | 599 | u16 num_vfs; |
478 | 600 | ||
@@ -483,7 +605,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, | |||
483 | if (num_vfs > pci_sriov_get_totalvfs(pdev)) | 605 | if (num_vfs > pci_sriov_get_totalvfs(pdev)) |
484 | return -ERANGE; | 606 | return -ERANGE; |
485 | 607 | ||
486 | mutex_lock(&iov->dev->sriov->lock); | 608 | device_lock(&pdev->dev); |
487 | 609 | ||
488 | if (num_vfs == pdev->sriov->num_VFs) | 610 | if (num_vfs == pdev->sriov->num_VFs) |
489 | goto exit; | 611 | goto exit; |
@@ -518,7 +640,7 @@ static ssize_t sriov_numvfs_store(struct device *dev, | |||
518 | num_vfs, ret); | 640 | num_vfs, ret); |
519 | 641 | ||
520 | exit: | 642 | exit: |
521 | mutex_unlock(&iov->dev->sriov->lock); | 643 | device_unlock(&pdev->dev); |
522 | 644 | ||
523 | if (ret < 0) | 645 | if (ret < 0) |
524 | return ret; | 646 | return ret; |
@@ -629,12 +751,17 @@ static struct attribute *pci_dev_attrs[] = { | |||
629 | NULL, | 751 | NULL, |
630 | }; | 752 | }; |
631 | 753 | ||
632 | static const struct attribute_group pci_dev_group = { | 754 | static struct attribute *pci_bridge_attrs[] = { |
633 | .attrs = pci_dev_attrs, | 755 | &dev_attr_subordinate_bus_number.attr, |
756 | &dev_attr_secondary_bus_number.attr, | ||
757 | NULL, | ||
634 | }; | 758 | }; |
635 | 759 | ||
636 | const struct attribute_group *pci_dev_groups[] = { | 760 | static struct attribute *pcie_dev_attrs[] = { |
637 | &pci_dev_group, | 761 | &dev_attr_current_link_speed.attr, |
762 | &dev_attr_current_link_width.attr, | ||
763 | &dev_attr_max_link_width.attr, | ||
764 | &dev_attr_max_link_speed.attr, | ||
638 | NULL, | 765 | NULL, |
639 | }; | 766 | }; |
640 | 767 | ||
@@ -1557,6 +1684,57 @@ static umode_t pci_dev_hp_attrs_are_visible(struct kobject *kobj, | |||
1557 | return a->mode; | 1684 | return a->mode; |
1558 | } | 1685 | } |
1559 | 1686 | ||
1687 | static umode_t pci_bridge_attrs_are_visible(struct kobject *kobj, | ||
1688 | struct attribute *a, int n) | ||
1689 | { | ||
1690 | struct device *dev = kobj_to_dev(kobj); | ||
1691 | struct pci_dev *pdev = to_pci_dev(dev); | ||
1692 | |||
1693 | if (pci_is_bridge(pdev)) | ||
1694 | return a->mode; | ||
1695 | |||
1696 | return 0; | ||
1697 | } | ||
1698 | |||
1699 | static umode_t pcie_dev_attrs_are_visible(struct kobject *kobj, | ||
1700 | struct attribute *a, int n) | ||
1701 | { | ||
1702 | struct device *dev = kobj_to_dev(kobj); | ||
1703 | struct pci_dev *pdev = to_pci_dev(dev); | ||
1704 | |||
1705 | if (pci_is_pcie(pdev)) | ||
1706 | return a->mode; | ||
1707 | |||
1708 | return 0; | ||
1709 | } | ||
1710 | |||
1711 | static const struct attribute_group pci_dev_group = { | ||
1712 | .attrs = pci_dev_attrs, | ||
1713 | }; | ||
1714 | |||
1715 | const struct attribute_group *pci_dev_groups[] = { | ||
1716 | &pci_dev_group, | ||
1717 | NULL, | ||
1718 | }; | ||
1719 | |||
1720 | static const struct attribute_group pci_bridge_group = { | ||
1721 | .attrs = pci_bridge_attrs, | ||
1722 | }; | ||
1723 | |||
1724 | const struct attribute_group *pci_bridge_groups[] = { | ||
1725 | &pci_bridge_group, | ||
1726 | NULL, | ||
1727 | }; | ||
1728 | |||
1729 | static const struct attribute_group pcie_dev_group = { | ||
1730 | .attrs = pcie_dev_attrs, | ||
1731 | }; | ||
1732 | |||
1733 | const struct attribute_group *pcie_dev_groups[] = { | ||
1734 | &pcie_dev_group, | ||
1735 | NULL, | ||
1736 | }; | ||
1737 | |||
1560 | static struct attribute_group pci_dev_hp_attr_group = { | 1738 | static struct attribute_group pci_dev_hp_attr_group = { |
1561 | .attrs = pci_dev_hp_attrs, | 1739 | .attrs = pci_dev_hp_attrs, |
1562 | .is_visible = pci_dev_hp_attrs_are_visible, | 1740 | .is_visible = pci_dev_hp_attrs_are_visible, |
@@ -1592,12 +1770,24 @@ static struct attribute_group pci_dev_attr_group = { | |||
1592 | .is_visible = pci_dev_attrs_are_visible, | 1770 | .is_visible = pci_dev_attrs_are_visible, |
1593 | }; | 1771 | }; |
1594 | 1772 | ||
1773 | static struct attribute_group pci_bridge_attr_group = { | ||
1774 | .attrs = pci_bridge_attrs, | ||
1775 | .is_visible = pci_bridge_attrs_are_visible, | ||
1776 | }; | ||
1777 | |||
1778 | static struct attribute_group pcie_dev_attr_group = { | ||
1779 | .attrs = pcie_dev_attrs, | ||
1780 | .is_visible = pcie_dev_attrs_are_visible, | ||
1781 | }; | ||
1782 | |||
1595 | static const struct attribute_group *pci_dev_attr_groups[] = { | 1783 | static const struct attribute_group *pci_dev_attr_groups[] = { |
1596 | &pci_dev_attr_group, | 1784 | &pci_dev_attr_group, |
1597 | &pci_dev_hp_attr_group, | 1785 | &pci_dev_hp_attr_group, |
1598 | #ifdef CONFIG_PCI_IOV | 1786 | #ifdef CONFIG_PCI_IOV |
1599 | &sriov_dev_attr_group, | 1787 | &sriov_dev_attr_group, |
1600 | #endif | 1788 | #endif |
1789 | &pci_bridge_attr_group, | ||
1790 | &pcie_dev_attr_group, | ||
1601 | NULL, | 1791 | NULL, |
1602 | }; | 1792 | }; |
1603 | 1793 | ||