fill out more of the linux pci API compat - implement pcie_get_speed_cap(), pcie_bandwidth_available(), and pci_is_root_bus(). - expand "enum pci_bus_speed" to add PCIe 5.x and 6.x speeds. - add "enum pcie_link_width". - add defines for PCIE_LCSR_LINKSPEED (PCIe generation) and PCIE_LCSR_NLW (negotiated lane width) to pcireg.h - enable amdgpu_device_get_pcie_info() code now it works. this is only the first step. we also need to add support for pcie_capability_read_word(), pcie_capability_write_word(), pcie_get_readrq(), and pcie_set_readrq(), which should enable a bunch more code for both amdgpu and radeon. ok riastradh@ Index: external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_device.c =================================================================== RCS file: /cvsroot/src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_device.c,v retrieving revision 1.16 diff -p -u -r1.16 amdgpu_device.c --- external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_device.c 19 Dec 2021 12:41:33 -0000 1.16 +++ external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_device.c 17 Sep 2022 01:05:08 -0000 @@ -4447,7 +4447,6 @@ skip_sched_resume: */ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) { -#ifndef __NetBSD__ /* XXX amdgpu pcie */ struct pci_dev *pdev; enum pci_bus_speed speed_cap, platform_speed_cap; enum pcie_link_width platform_link_width; @@ -4571,7 +4570,6 @@ static void amdgpu_device_get_pcie_info( } } } -#endif } int amdgpu_device_baco_enter(struct drm_device *dev) Index: external/bsd/drm2/include/linux/pci.h =================================================================== RCS file: /cvsroot/src/sys/external/bsd/drm2/include/linux/pci.h,v retrieving revision 1.53 diff -p -u -r1.53 pci.h --- external/bsd/drm2/include/linux/pci.h 27 Feb 2022 14:23:08 -0000 1.53 +++ external/bsd/drm2/include/linux/pci.h 17 Sep 2022 01:05:08 -0000 @@ -190,6 +190,21 @@ enum pci_bus_speed { PCIE_SPEED_5_0GT, PCIE_SPEED_8_0GT, PCIE_SPEED_16_0GT, + PCIE_SPEED_32_0GT, + PCIE_SPEED_64_0GT, +}; + +/* Actually values from the Link Status register, bits 16-19. */ +enum pcie_link_width { + PCIE_LNK_WIDTH_RESRV = 0, + PCIE_LNK_X1 = __BIT(0), + PCIE_LNK_X2 = __BIT(1), + PCIE_LNK_X4 = __BIT(2), + PCIE_LNK_X8 = __BIT(3), + PCIE_LNK_X12 = __BITS(2,3), + PCIE_LNK_X16 = __BIT(4), + PCIE_LNK_X32 = __BIT(5), + PCIE_LNK_WIDTH_UNKNOWN = __BITS(0, 7), }; #define PCIBIOS_MIN_MEM 0x100000 /* XXX bogus x86 kludge bollocks */ @@ -242,6 +257,8 @@ enum pci_bus_speed { #define pci_write_config_dword linux_pci_write_config_dword #define pci_write_config_word linux_pci_write_config_word #define pcibios_align_resource linux_pcibios_align_resource +#define pcie_get_speed_cap linux_pcie_get_speed_cap +#define pcie_bandwidth_available linux_pcie_bandwidth_available /* NetBSD local additions. */ void linux_pci_dev_init(struct pci_dev *, device_t, device_t, @@ -323,6 +340,12 @@ void pci_iounmap(struct pci_dev *, void void pci_save_state(struct pci_dev *); void pci_restore_state(struct pci_dev *); +enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev); +unsigned pcie_bandwidth_available(struct pci_dev *dev, + struct pci_dev **limiting_dev, + enum pci_bus_speed *speed, + enum pcie_link_width *width); + static inline bool dev_is_pci(struct device *dev) { Index: external/bsd/drm2/linux/linux_pci.c =================================================================== RCS file: /cvsroot/src/sys/external/bsd/drm2/linux/linux_pci.c,v retrieving revision 1.23 diff -p -u -r1.23 linux_pci.c --- external/bsd/drm2/linux/linux_pci.c 20 Jul 2022 01:20:20 -0000 1.23 +++ external/bsd/drm2/linux/linux_pci.c 17 Sep 2022 01:05:08 -0000 @@ -716,8 +716,7 @@ bool pci_is_root_bus(struct pci_bus *bus) { - /* XXX Cop-out. */ - return false; + return bus->number == 0; } int @@ -800,3 +799,141 @@ linux_pci_dev_destroy(struct pci_dev *pd KASSERT(pdev->pd_saved_state == NULL); KASSERT(pdev->pd_intr_handles == NULL); } + +enum pci_bus_speed +pcie_get_speed_cap(struct pci_dev *dev) +{ + pci_chipset_tag_t pc = dev->pd_pa.pa_pc; + pcitag_t tag = dev->pd_pa.pa_tag; + pcireg_t lcap, lcap2, xcap; + int off; + + /* Must have capabilities. */ + if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0) + return PCI_SPEED_UNKNOWN; + + /* Only PCIe 3.x has LCAP2. */ + xcap = pci_conf_read(pc, tag, off + PCIE_XCAP); + if (__SHIFTOUT(xcap, PCIE_XCAP_VER_MASK) >= 2) { + lcap2 = pci_conf_read(pc, tag, off + PCIE_LCAP2); + if (lcap2) { + if ((lcap2 & PCIE_LCAP2_SUP_LNKS64) != 0) { + return PCIE_SPEED_64_0GT; + } + if ((lcap2 & PCIE_LCAP2_SUP_LNKS32) != 0) { + return PCIE_SPEED_32_0GT; + } + if ((lcap2 & PCIE_LCAP2_SUP_LNKS16) != 0) { + return PCIE_SPEED_16_0GT; + } + if ((lcap2 & PCIE_LCAP2_SUP_LNKS8) != 0) { + return PCIE_SPEED_8_0GT; + } + if ((lcap2 & PCIE_LCAP2_SUP_LNKS5) != 0) { + return PCIE_SPEED_5_0GT; + } + if ((lcap2 & PCIE_LCAP2_SUP_LNKS2) != 0) { + return PCIE_SPEED_2_5GT; + } + } + } + + lcap = pci_conf_read(pc, tag, off + PCIE_LCAP); + if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_64) { + return PCIE_SPEED_64_0GT; + } + if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_32) { + return PCIE_SPEED_32_0GT; + } + if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_16) { + return PCIE_SPEED_16_0GT; + } + if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_8) { + return PCIE_SPEED_8_0GT; + } + if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_5) { + return PCIE_SPEED_5_0GT; + } + if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_2) { + return PCIE_SPEED_2_5GT; + } + + return PCI_SPEED_UNKNOWN; +} + +/* + * This should walk the tree, it only checks this device currently. + * It also does not write to limiting_dev (the only caller in drm2 + * currently does not use it.) + */ +unsigned +pcie_bandwidth_available(struct pci_dev *dev, + struct pci_dev **limiting_dev, + enum pci_bus_speed *speed, + enum pcie_link_width *width) +{ + pci_chipset_tag_t pc = dev->pd_pa.pa_pc; + pcitag_t tag = dev->pd_pa.pa_tag; + pcireg_t lcsr; + unsigned per_line_speed, num_lanes; + int off; + + /* Must have capabilities. */ + if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0) + return 0; + + if (speed) + *speed = PCI_SPEED_UNKNOWN; + if (width) + *width = 0; + + lcsr = pci_conf_read(pc, tag, off + PCIE_LCSR); + + switch (lcsr & PCIE_LCSR_NLW) { + case PCIE_LCSR_NLW_X1: + case PCIE_LCSR_NLW_X2: + case PCIE_LCSR_NLW_X4: + case PCIE_LCSR_NLW_X8: + case PCIE_LCSR_NLW_X12: + case PCIE_LCSR_NLW_X16: + case PCIE_LCSR_NLW_X32: + num_lanes = __SHIFTOUT(lcsr, PCIE_LCSR_NLW); + if (width) + *width = num_lanes; + break; + default: + num_lanes = 0; + break; + } + + switch (__SHIFTOUT(lcsr, PCIE_LCSR_LINKSPEED)) { + case PCIE_LCSR_LINKSPEED_2: + *speed = PCIE_SPEED_2_5GT; + per_line_speed = 2500 * 8 / 10; + break; + case PCIE_LCSR_LINKSPEED_5: + *speed = PCIE_SPEED_5_0GT; + per_line_speed = 5000 * 8 / 10; + break; + case PCIE_LCSR_LINKSPEED_8: + *speed = PCIE_SPEED_8_0GT; + per_line_speed = 8000 * 128 / 130; + break; + case PCIE_LCSR_LINKSPEED_16: + *speed = PCIE_SPEED_16_0GT; + per_line_speed = 16000 * 128 / 130; + break; + case PCIE_LCSR_LINKSPEED_32: + *speed = PCIE_SPEED_32_0GT; + per_line_speed = 32000 * 128 / 130; + break; + case PCIE_LCSR_LINKSPEED_64: + *speed = PCIE_SPEED_64_0GT; + per_line_speed = 64000 * 128 / 130; + break; + default: + per_line_speed = 0; + } + + return num_lanes * per_line_speed; +} Index: dev/pci/pcireg.h =================================================================== RCS file: /cvsroot/src/sys/dev/pci/pcireg.h,v retrieving revision 1.165 diff -p -u -r1.165 pcireg.h --- dev/pci/pcireg.h 31 Jan 2022 10:14:55 -0000 1.165 +++ dev/pci/pcireg.h 17 Sep 2022 01:05:08 -0000 @@ -1063,7 +1063,20 @@ typedef u_int8_t pci_revision_t; #define PCIE_LCSR_LABIE __BIT(11) /* Link Autonomous BW Intr En */ #define PCIE_LCSR_DRSSGNL __BITS(15, 14) /* DRS Signaling */ #define PCIE_LCSR_LINKSPEED __BITS(19, 16) /* Link Speed */ +#define PCIE_LCSR_LINKSPEED_2 1 /* 2.5GT/s */ +#define PCIE_LCSR_LINKSPEED_5 2 /* 5GT/s */ +#define PCIE_LCSR_LINKSPEED_8 3 /* 8GT/s */ +#define PCIE_LCSR_LINKSPEED_16 4 /* 16GT/s */ +#define PCIE_LCSR_LINKSPEED_32 5 /* 32GT/s */ +#define PCIE_LCSR_LINKSPEED_64 6 /* 64GT/s */ #define PCIE_LCSR_NLW __BITS(25, 20) /* Negotiated Link Width */ +#define PCIE_LCSR_NLW_X1 __BIT(20) /* Negotiated x1 */ +#define PCIE_LCSR_NLW_X2 __BIT(21) /* Negotiated x2 */ +#define PCIE_LCSR_NLW_X4 __BIT(22) /* Negotiated x4 */ +#define PCIE_LCSR_NLW_X8 __BIT(23) /* Negotiated x8 */ +#define PCIE_LCSR_NLW_X12 __BITS(22, 23) /* Negotiated x12 */ +#define PCIE_LCSR_NLW_X16 __BIT(24) /* Negotiated x16 */ +#define PCIE_LCSR_NLW_X32 __BIT(25) /* Negotiated x32 */ #define PCIE_LCSR_LINKTRAIN_ERR __BIT(10 + 16) /* Link Training Error */ #define PCIE_LCSR_LINKTRAIN __BIT(11 + 16) /* Link Training */ #define PCIE_LCSR_SLOTCLKCFG __BIT(12 + 16) /* Slot Clock Configuration */