drm: Enable drm_pcie_get_max_link_width()
authorFrançois Tigeot <ftigeot@wolfpond.org>
Tue, 27 Aug 2019 21:51:51 +0000 (23:51 +0200)
committerFrançois Tigeot <ftigeot@wolfpond.org>
Tue, 27 Aug 2019 21:51:51 +0000 (23:51 +0200)
Partially obtained from FreeBSD.

sys/dev/drm/drm_pci.c
sys/dev/drm/include/linux/pci.h
sys/dev/drm/include/uapi/linux/pci.h
sys/dev/drm/include/uapi/linux/pci_regs.h [copied from sys/dev/drm/include/uapi/linux/pci.h with 58% similarity]
sys/dev/video/vga/Makefile

index 94909c9..29441a4 100644 (file)
@@ -438,11 +438,22 @@ int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask)
 }
 EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask);
 
-#if 0
+static int
+pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *dst)
+{
+       if (pos & 3)
+               return -EINVAL;
+
+       if (!pcie_capability_reg_implemented(dev, pos))
+               return -EINVAL;
+
+       return pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, dst);
+}
+
 int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw)
 {
        struct pci_dev *root;
-       u32 lnkcap;
+       u32 lnkcap = 0;
 
        *mlw = 0;
        if (!dev->pdev)
@@ -458,7 +469,6 @@ int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw)
        return 0;
 }
 EXPORT_SYMBOL(drm_pcie_get_max_link_width);
-#endif
 
 #else
 
index 6c84312..4504f8e 100644 (file)
@@ -361,4 +361,110 @@ pci_pcie_cap(struct pci_dev *pdev)
 /* DRM_MAX_PCI_RESOURCE */
 #define DEVICE_COUNT_RESOURCE  6
 
+#include <uapi/linux/pci_regs.h>
+
+/* From FreeBSD */
+static inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
+{
+               return true;
+}
+
+static inline int
+pci_find_capability(struct pci_dev *pdev, int capid)
+{
+       int reg;
+
+       if (pci_find_extcap(pdev->dev.bsddev, capid, &reg))
+               return (0);
+       return (reg);
+}
+
+static inline u16 pcie_flags_reg(struct pci_dev *dev)
+{
+       int pos;
+       u16 reg16;
+
+       pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+       if (!pos)
+               return 0;
+
+       pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
+
+       return reg16;
+}
+
+static inline int pci_pcie_type(struct pci_dev *dev)
+{
+       return (pcie_flags_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
+
+static inline int pcie_cap_version(struct pci_dev *dev)
+{
+       return pcie_flags_reg(dev) & PCI_EXP_FLAGS_VERS;
+}
+
+static inline bool pcie_cap_has_lnkctl(struct pci_dev *dev)
+{
+       int type = pci_pcie_type(dev);
+
+       return pcie_cap_version(dev) > 1 ||
+              type == PCI_EXP_TYPE_ROOT_PORT ||
+              type == PCI_EXP_TYPE_ENDPOINT ||
+              type == PCI_EXP_TYPE_LEG_END;
+}
+
+static inline bool pcie_cap_has_sltctl(struct pci_dev *dev)
+{
+       int type = pci_pcie_type(dev);
+
+       return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT ||
+           (type == PCI_EXP_TYPE_DOWNSTREAM &&
+           pcie_flags_reg(dev) & PCI_EXP_FLAGS_SLOT);
+}
+
+static inline bool pcie_cap_has_rtctl(struct pci_dev *dev)
+{
+       int type = pci_pcie_type(dev);
+
+       return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT ||
+           type == PCI_EXP_TYPE_RC_EC;
+}
+
+static inline bool
+pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
+{
+       if (!pci_is_pcie(dev->dev.bsddev))
+               return false;
+
+       switch (pos) {
+       case PCI_EXP_FLAGS_TYPE:
+               return true;
+       case PCI_EXP_DEVCAP:
+       case PCI_EXP_DEVCTL:
+       case PCI_EXP_DEVSTA:
+               return pcie_cap_has_devctl(dev);
+       case PCI_EXP_LNKCAP:
+       case PCI_EXP_LNKCTL:
+       case PCI_EXP_LNKSTA:
+               return pcie_cap_has_lnkctl(dev);
+       case PCI_EXP_SLTCAP:
+       case PCI_EXP_SLTCTL:
+       case PCI_EXP_SLTSTA:
+               return pcie_cap_has_sltctl(dev);
+       case PCI_EXP_RTCTL:
+       case PCI_EXP_RTCAP:
+       case PCI_EXP_RTSTA:
+               return pcie_cap_has_rtctl(dev);
+       case PCI_EXP_DEVCAP2:
+       case PCI_EXP_DEVCTL2:
+       case PCI_EXP_LNKCAP2:
+       case PCI_EXP_LNKCTL2:
+       case PCI_EXP_LNKSTA2:
+               return pcie_cap_version(dev) > 1;
+       default:
+               return false;
+       }
+}
+
 #endif /* LINUX_PCI_H */
index 9d3d470..65b1b23 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 François Tigeot
+ * Copyright (c) 2018-2019 François Tigeot <ftigeot@wolfpond.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,6 +27,8 @@
 #ifndef _UAPI_LINUX_PCI_H_
 #define _UAPI_LINUX_PCI_H_
 
+#include <linux/pci_regs.h>
+
 #define PCI_DEVFN(slot, func)  ((((slot) & 0x1f) << 3) | ((func) & 0x07))
 #define PCI_SLOT(devfn)                (((devfn) >> 3) & 0x1f)
 #define PCI_FUNC(devfn)                ((devfn) & 0x07)
similarity index 58%
copy from sys/dev/drm/include/uapi/linux/pci.h
copy to sys/dev/drm/include/uapi/linux/pci_regs.h
index 9d3d470..051f3e4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 François Tigeot
+ * Copyright (c) 2019 François Tigeot <ftigeot@wolfpond.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef _UAPI_LINUX_PCI_H_
-#define _UAPI_LINUX_PCI_H_
+#ifndef UAPI_LINUX_PCIREGS_H
+#define UAPI_LINUX_PCIREGS_H
 
-#define PCI_DEVFN(slot, func)  ((((slot) & 0x1f) << 3) | ((func) & 0x07))
-#define PCI_SLOT(devfn)                (((devfn) >> 3) & 0x1f)
-#define PCI_FUNC(devfn)                ((devfn) & 0x07)
+#define PCI_EXP_RTCAP          30
 
-#endif /* _UAPI_LINUX_PCI_H_ */
+#define PCI_EXP_FLAGS          2
+#define PCI_EXP_FLAGS_VERS     0x000f
+#define PCI_EXP_FLAGS_TYPE     0x00f0
+
+#define PCI_EXP_DEVCAP         4
+
+#define PCI_EXP_LNKCAP         12
+
+#define PCI_EXP_DEVCTL         8
+#define PCI_EXP_DEVCTL2                40
+
+#define PCI_EXP_LNKSTA         18
+#define PCI_EXP_LNKSTA2                50
+
+#define PCI_EXP_SLTCAP         20
+
+#define PCI_CAP_ID_EXP         0x10
+
+#define PCI_EXP_TYPE_ENDPOINT  0x0
+#define PCI_EXP_TYPE_LEG_END   0x1
+#define PCI_EXP_TYPE_ROOT_PORT 0x4
+#define PCI_EXP_TYPE_DOWNSTREAM 0x6
+#define PCI_EXP_TYPE_RC_EC     0xa
+
+#define PCI_EXP_SLTCTL         24
+
+#define PCI_EXP_SLTSTA         26
+
+#define PCI_EXP_FLAGS_SLOT     0x0100
+
+#define PCI_EXP_RTCTL          28
+
+#define PCI_EXP_RTSTA          32
+
+#define PCI_EXP_DEVCAP2                36
+
+#define PCI_EXP_LNKCAP2                44
+
+#define PCI_EXP_LNKCAP_MLW     0x000003f0
+
+#endif /* UAPI_LINUX_PCIREGS_H */
index cb8366f..27ee20b 100755 (executable)
@@ -3,5 +3,6 @@ SRCS=   vga_switcheroo.c
 SRCS+= device_if.h bus_if.h pci_if.h
 
 KCFLAGS+= -I${SYSDIR}/dev/drm/include
+KCFLAGS+= -I${SYSDIR}/dev/drm/include/uapi
 
 .include <bsd.kmod.mk>