Module Name:    src
Committed By:   mrg
Date:           Mon Oct 17 03:05:32 UTC 2022

Modified Files:
        src/sys/dev/pci: pcireg.h
        src/sys/external/bsd/drm2/dist/drm/amd/amdgpu: amdgpu_cik.c amdgpu_si.c
        src/sys/external/bsd/drm2/dist/drm/radeon: radeon_cik.c radeon_si.c
        src/sys/external/bsd/drm2/include/linux: pci.h
        src/sys/external/bsd/drm2/linux: linux_pci.c

Log Message:
add pcie capability and read request size linux compat, some pci root support

implement support for:
- pcie_capability_read_dword()
- pcie_capability_read_word()
- pcie_capability_write_dword()
- pcie_capability_write_word()
- pcie_get_readrq()
- pcie_set_readrq()

implement the "struct pci_dev" bus->self member by creating a minimal fake
"struct pci_dev" for the pci bus itself.  this is kind of gross.  it checks
that the current device's parent is a netbsd "pci" device, and that it has
a (grand) parent "ppb" device, and then fills in the fake device based upon
the pci and ppb devices.

add some PCIE_LCSR2_TGT_LSPEED encodings, and map them to linux names.
map several other PCIE_LCSR and PCIE_LCAP names.

uncomment several pcie code segments in radeon and amdgpu.  (not sure that
we can test the amdgpu_si.c change, as we use the radeon version and the
amdgpu version hangs on the one machine i have.)

tested on amdgpu (RX550) and radeon (7750 & 3650).

ok @riastradh


To generate a diff of this commit:
cvs rdiff -u -r1.167 -r1.168 src/sys/dev/pci/pcireg.h
cvs rdiff -u -r1.5 -r1.6 \
    src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cik.c
cvs rdiff -u -r1.3 -r1.4 \
    src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_si.c
cvs rdiff -u -r1.6 -r1.7 \
    src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cik.c
cvs rdiff -u -r1.4 -r1.5 \
    src/sys/external/bsd/drm2/dist/drm/radeon/radeon_si.c
cvs rdiff -u -r1.54 -r1.55 src/sys/external/bsd/drm2/include/linux/pci.h
cvs rdiff -u -r1.24 -r1.25 src/sys/external/bsd/drm2/linux/linux_pci.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/pcireg.h
diff -u src/sys/dev/pci/pcireg.h:1.167 src/sys/dev/pci/pcireg.h:1.168
--- src/sys/dev/pci/pcireg.h:1.167	Sat Oct  1 12:40:42 2022
+++ src/sys/dev/pci/pcireg.h	Mon Oct 17 03:05:32 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: pcireg.h,v 1.167 2022/10/01 12:40:42 rin Exp $	*/
+/*	$NetBSD: pcireg.h,v 1.168 2022/10/17 03:05:32 mrg Exp $	*/
 
 /*
  * Copyright (c) 1995, 1996, 1999, 2000
@@ -1186,6 +1186,9 @@ typedef u_int8_t pci_revision_t;
 #define PCIE_LCAP2_DRS		__BIT(31)       /* DRS Supported */
 #define PCIE_LCSR2	0x30	/* Link Control & Status 2 Register */
 #define PCIE_LCSR2_TGT_LSPEED	__BITS(3, 0)   /* Target Link Speed */
+#define  PCIE_LCSR2_TGT_LSPEED_2_5G  0x1       /* 2.5GT/s supported */
+#define  PCIE_LCSR2_TGT_LSPEED_5G    0x2       /* 5.0GT/s supported */
+#define  PCIE_LCSR2_TGT_LSPEED_8G    0x3       /* 8.0GT/s supported */
 #define PCIE_LCSR2_ENT_COMPL	__BIT(4)       /* Enter Compliance */
 #define PCIE_LCSR2_HW_AS_DIS	__BIT(5)       /* HW Autonomous Speed Disabl */
 #define PCIE_LCSR2_SEL_DEEMP	__BIT(6)       /* Selectable De-emphasis */

Index: src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cik.c
diff -u src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cik.c:1.5 src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cik.c:1.6
--- src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cik.c:1.5	Sun Dec 19 10:59:01 2021
+++ src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_cik.c	Mon Oct 17 03:05:32 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: amdgpu_cik.c,v 1.5 2021/12/19 10:59:01 riastradh Exp $	*/
+/*	$NetBSD: amdgpu_cik.c,v 1.6 2022/10/17 03:05:32 mrg Exp $	*/
 
 /*
  * Copyright 2012 Advanced Micro Devices, Inc.
@@ -24,7 +24,7 @@
  * Authors: Alex Deucher
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdgpu_cik.c,v 1.5 2021/12/19 10:59:01 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amdgpu_cik.c,v 1.6 2022/10/17 03:05:32 mrg Exp $");
 
 #include <linux/firmware.h>
 #include <linux/slab.h>
@@ -1461,7 +1461,6 @@ static int cik_set_vce_clocks(struct amd
 
 static void cik_pcie_gen3_enable(struct amdgpu_device *adev)
 {
-#ifndef __NetBSD__		/* XXX amdgpu pcie */
 	struct pci_dev *root = adev->pdev->bus->self;
 	u32 speed_cntl, current_data_rate;
 	int i;
@@ -1644,7 +1643,6 @@ static void cik_pcie_gen3_enable(struct 
 			break;
 		udelay(1);
 	}
-#endif
 }
 
 static void cik_program_aspm(struct amdgpu_device *adev)

Index: src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_si.c
diff -u src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_si.c:1.3 src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_si.c:1.4
--- src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_si.c:1.3	Sun Dec 19 12:21:29 2021
+++ src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_si.c	Mon Oct 17 03:05:32 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: amdgpu_si.c,v 1.3 2021/12/19 12:21:29 riastradh Exp $	*/
+/*	$NetBSD: amdgpu_si.c,v 1.4 2022/10/17 03:05:32 mrg Exp $	*/
 
 /*
  * Copyright 2015 Advanced Micro Devices, Inc.
@@ -24,7 +24,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdgpu_si.c,v 1.3 2021/12/19 12:21:29 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amdgpu_si.c,v 1.4 2022/10/17 03:05:32 mrg Exp $");
 
 #include <linux/firmware.h>
 #include <linux/slab.h>
@@ -1656,7 +1656,6 @@ static void si_init_golden_registers(str
 
 static void si_pcie_gen3_enable(struct amdgpu_device *adev)
 {
-#ifndef __NetBSD__		/* XXX amdgpu pcie */
 	struct pci_dev *root = adev->pdev->bus->self;
 	u32 speed_cntl, current_data_rate;
 	int i;
@@ -1827,7 +1826,6 @@ static void si_pcie_gen3_enable(struct a
 			break;
 		udelay(1);
 	}
-#endif	/* __NetBSD__ */
 }
 
 static inline u32 si_pif_phy0_rreg(struct amdgpu_device *adev, u32 reg)
@@ -2002,9 +2000,6 @@ static void si_program_aspm(struct amdgp
 
 			if (!disable_clkreq &&
 			    !pci_is_root_bus(adev->pdev->bus)) {
-#ifdef __NetBSD__		/* XXX amdgpu pcie */
-				clk_req_support = false;
-#else
 				struct pci_dev *root = adev->pdev->bus->self;
 				u32 lnkcap;
 
@@ -2012,7 +2007,6 @@ static void si_program_aspm(struct amdgp
 				pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap);
 				if (lnkcap & PCI_EXP_LNKCAP_CLKPM)
 					clk_req_support = true;
-#endif
 			} else {
 				clk_req_support = false;
 			}

Index: src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cik.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cik.c:1.6 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cik.c:1.7
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cik.c:1.6	Sun Dec 19 09:54:20 2021
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_cik.c	Mon Oct 17 03:05:32 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: radeon_cik.c,v 1.6 2021/12/19 09:54:20 riastradh Exp $	*/
+/*	$NetBSD: radeon_cik.c,v 1.7 2022/10/17 03:05:32 mrg Exp $	*/
 
 /*
  * Copyright 2012 Advanced Micro Devices, Inc.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: radeon_cik.c,v 1.6 2021/12/19 09:54:20 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: radeon_cik.c,v 1.7 2022/10/17 03:05:32 mrg Exp $");
 
 #include <linux/firmware.h>
 #include <linux/module.h>
@@ -9564,7 +9564,6 @@ int cik_set_vce_clocks(struct radeon_dev
 
 static void cik_pcie_gen3_enable(struct radeon_device *rdev)
 {
-#ifndef __NetBSD__		/* XXX radeon pcie */
 	struct pci_dev *root = rdev->pdev->bus->self;
 	enum pci_bus_speed speed_cap;
 	u32 speed_cntl, current_data_rate;
@@ -9747,7 +9746,6 @@ static void cik_pcie_gen3_enable(struct 
 			break;
 		udelay(1);
 	}
-#endif
 }
 
 static void cik_program_aspm(struct radeon_device *rdev)

Index: src/sys/external/bsd/drm2/dist/drm/radeon/radeon_si.c
diff -u src/sys/external/bsd/drm2/dist/drm/radeon/radeon_si.c:1.4 src/sys/external/bsd/drm2/dist/drm/radeon/radeon_si.c:1.5
--- src/sys/external/bsd/drm2/dist/drm/radeon/radeon_si.c:1.4	Sun Dec 19 09:56:27 2021
+++ src/sys/external/bsd/drm2/dist/drm/radeon/radeon_si.c	Mon Oct 17 03:05:32 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: radeon_si.c,v 1.4 2021/12/19 09:56:27 riastradh Exp $	*/
+/*	$NetBSD: radeon_si.c,v 1.5 2022/10/17 03:05:32 mrg Exp $	*/
 
 /*
  * Copyright 2011 Advanced Micro Devices, Inc.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: radeon_si.c,v 1.4 2021/12/19 09:56:27 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: radeon_si.c,v 1.5 2022/10/17 03:05:32 mrg Exp $");
 
 #include <linux/firmware.h>
 #include <linux/module.h>
@@ -7099,7 +7099,6 @@ int si_set_uvd_clocks(struct radeon_devi
 
 static void si_pcie_gen3_enable(struct radeon_device *rdev)
 {
-#ifndef __NetBSD__		/* XXX radeon pcie */
 	struct pci_dev *root = rdev->pdev->bus->self;
 	enum pci_bus_speed speed_cap;
 	u32 speed_cntl, current_data_rate;
@@ -7283,7 +7282,6 @@ static void si_pcie_gen3_enable(struct r
 			break;
 		udelay(1);
 	}
-#endif
 }
 
 static void si_program_aspm(struct radeon_device *rdev)

Index: src/sys/external/bsd/drm2/include/linux/pci.h
diff -u src/sys/external/bsd/drm2/include/linux/pci.h:1.54 src/sys/external/bsd/drm2/include/linux/pci.h:1.55
--- src/sys/external/bsd/drm2/include/linux/pci.h:1.54	Tue Sep 20 23:01:42 2022
+++ src/sys/external/bsd/drm2/include/linux/pci.h	Mon Oct 17 03:05:32 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci.h,v 1.54 2022/09/20 23:01:42 mrg Exp $	*/
+/*	$NetBSD: pci.h,v 1.55 2022/10/17 03:05:32 mrg Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -49,6 +49,7 @@
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 #include <dev/pci/agpvar.h>
+#include <dev/pci/ppbvar.h>
 
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
@@ -60,6 +61,7 @@
 
 struct acpi_devnode;
 struct pci_driver;
+struct pci_dev;
 
 struct pci_bus {
 	/* NetBSD private members */
@@ -68,6 +70,8 @@ struct pci_bus {
 
 	/* Linux API */
 	u_int			number;
+
+	struct pci_dev		*self;
 };
 
 struct pci_device_id {
@@ -133,6 +137,21 @@ CTASSERT(PCI_CLASS_BRIDGE_ISA == 0x0601)
 
 #define	PCI_CAP_ID_AGP	PCI_CAP_AGP
 
+#define PCI_EXP_LNKCTL			PCIE_LCSR
+#define  PCI_EXP_LNKCTL_HAWD		PCIE_LCSR_HAWD
+#define PCI_EXP_DEVSTA			(PCIE_DCSR + 2)
+#define  PCI_EXP_DEVSTA_TRPND		(PCIE_DCSR_TRANSACTION_PND >> 16)
+#define PCI_EXP_LNKCTL2			PCIE_LCAP2
+#define  PCI_EXP_LNKCTL2_ENTER_COMP	PCIE_LCSR2_ENT_COMPL
+#define  PCI_EXP_LNKCTL2_TX_MARGIN	PCIE_LCSR2_TX_MARGIN
+#define  PCI_EXP_LNKCTL2_TLS		PCIE_LCSR2_TGT_LSPEED
+#define  PCI_EXP_LNKCTL2_TLS_2_5GT	PCIE_LCSR2_TGT_LSPEED_2_5G
+#define  PCI_EXP_LNKCTL2_TLS_5_0GT	PCIE_LCSR2_TGT_LSPEED_5G
+#define  PCI_EXP_LNKCTL2_TLS_8_0GT	PCIE_LCSR2_TGT_LSPEED_8G
+#define PCI_EXP_LNKCAP			PCIE_LCAP
+#define  PCI_EXP_LNKCAP_CLKPM		PCIE_LCAP_CLOCK_PM
+
+
 typedef int pci_power_t;
 
 #define	PCI_D0		0
@@ -262,6 +281,10 @@ enum pcie_link_width {
 #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
+#define	pcie_read_config_dword		linux_pcie_capability_read_dword
+#define	pcie_read_config_word		linux_pcie_capability_read_word
+#define	pcie_write_config_dword		linux_pcie_capability_write_dword
+#define	pcie_write_config_word		linux_pcie_capability_write_word
 
 /* NetBSD local additions.  */
 void		linux_pci_dev_init(struct pci_dev *, device_t, device_t,
@@ -292,6 +315,11 @@ int		pci_write_config_dword(struct pci_d
 int		pci_write_config_word(struct pci_dev *, int, uint16_t);
 int		pci_write_config_byte(struct pci_dev *, int, uint8_t);
 
+int		pcie_capability_read_dword(struct pci_dev *, int, uint32_t *);
+int		pcie_capability_read_word(struct pci_dev *, int, uint16_t *);
+int		pcie_capability_write_dword(struct pci_dev *, int, uint32_t);
+int		pcie_capability_write_word(struct pci_dev *, int, uint16_t);
+
 int		pci_bus_read_config_dword(struct pci_bus *, unsigned, int,
 		    uint32_t *);
 int		pci_bus_read_config_word(struct pci_bus *, unsigned, int,
@@ -310,6 +338,9 @@ void		pci_disable_msi(struct pci_dev *);
 void		pci_set_master(struct pci_dev *);
 void		pci_clear_master(struct pci_dev *);
 
+int		pcie_get_readrq(struct pci_dev *);
+int		pcie_set_readrq(struct pci_dev *, int);
+
 bus_addr_t	pcibios_align_resource(void *, const struct resource *,
 		    bus_addr_t, bus_size_t);
 int		pci_bus_alloc_resource(struct pci_bus *, struct resource *,

Index: src/sys/external/bsd/drm2/linux/linux_pci.c
diff -u src/sys/external/bsd/drm2/linux/linux_pci.c:1.24 src/sys/external/bsd/drm2/linux/linux_pci.c:1.25
--- src/sys/external/bsd/drm2/linux/linux_pci.c:1.24	Tue Sep 20 23:01:42 2022
+++ src/sys/external/bsd/drm2/linux/linux_pci.c	Mon Oct 17 03:05:32 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: linux_pci.c,v 1.24 2022/09/20 23:01:42 mrg Exp $	*/
+/*	$NetBSD: linux_pci.c,v 1.25 2022/10/17 03:05:32 mrg Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_pci.c,v 1.24 2022/09/20 23:01:42 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_pci.c,v 1.25 2022/10/17 03:05:32 mrg Exp $");
 
 #if NACPICA > 0
 #include <dev/acpi/acpivar.h>
@@ -73,6 +73,74 @@ pci_name(struct pci_dev *pdev)
 	return device_xname(pci_dev_dev(pdev));
 }
 
+/*
+ * Setup enough of a parent that we can access config space.
+ * This is gross and grovels pci(4) and ppb(4) internals.
+ */
+static struct pci_dev *
+alloc_fake_parent_device(device_t parent, const struct pci_attach_args *pa)
+{
+
+	if (parent == NULL || !device_is_a(parent, "pci"))
+		return NULL;
+
+	device_t pparent = device_parent(parent);
+	if (pparent == NULL || !device_is_a(pparent, "ppb"))
+		return NULL;
+
+	struct pci_softc *pcisc = device_private(parent);
+	struct ppb_softc *ppbsc = device_private(pparent);
+
+	struct pci_dev *parentdev = kmem_zalloc(sizeof(*parentdev), KM_SLEEP);
+
+	/* Copy this device's pci_attach_args{} as a base-line. */
+	struct pci_attach_args *npa = &parentdev->pd_pa;
+	*npa = *pa;
+
+	/* Now update with stuff found in parent. */
+	npa->pa_iot = pcisc->sc_iot;
+	npa->pa_memt = pcisc->sc_memt;
+	npa->pa_dmat = pcisc->sc_dmat;
+	npa->pa_dmat64 = pcisc->sc_dmat64;
+	npa->pa_pc = pcisc->sc_pc;
+	npa->pa_flags = 0;	/* XXX? */
+
+	/* Copy the parent tag, and read some info about it. */
+	npa->pa_tag = ppbsc->sc_tag;
+	pcireg_t id = pci_conf_read(npa->pa_pc, npa->pa_tag, PCI_ID_REG);
+	pcireg_t subid = pci_conf_read(npa->pa_pc, npa->pa_tag,
+	    PCI_SUBSYS_ID_REG);
+	pcireg_t class = pci_conf_read(npa->pa_pc, npa->pa_tag, PCI_CLASS_REG);
+
+	/*
+	 * Fill in as much of pci_attach_args and pci_dev as reasonably possible.
+	 * Most of this is not used currently.
+	 */
+	int bus, device, function;
+	pci_decompose_tag(npa->pa_pc, npa->pa_tag, &bus, &device, &function);
+	npa->pa_device = device;
+	npa->pa_function = function;
+	npa->pa_bus = bus;
+	npa->pa_id = id;
+	npa->pa_class = class;
+	npa->pa_intrswiz = pcisc->sc_intrswiz;
+	npa->pa_intrtag = pcisc->sc_intrtag;
+	npa->pa_intrpin = PCI_INTERRUPT_PIN_NONE;
+
+	parentdev->pd_dev = parent;
+
+	parentdev->bus = NULL;
+	parentdev->devfn = device << 3 | function;
+	parentdev->vendor = PCI_VENDOR(id);
+	parentdev->device = PCI_PRODUCT(id);
+	parentdev->subsystem_vendor = PCI_SUBSYS_VENDOR(subid);
+	parentdev->subsystem_device = PCI_SUBSYS_ID(subid);
+	parentdev->revision = PCI_REVISION(class);
+	parentdev->class = __SHIFTOUT(class, 0xffffff00UL); /* ? */
+
+	return parentdev;
+}
+
 void
 linux_pci_dev_init(struct pci_dev *pdev, device_t dev, device_t parent,
     const struct pci_attach_args *pa, int kludges)
@@ -101,6 +169,7 @@ linux_pci_dev_init(struct pci_dev *pdev,
 	pdev->bus->pb_pc = pa->pa_pc;
 	pdev->bus->pb_dev = parent;
 	pdev->bus->number = pa->pa_bus;
+	pdev->bus->self = alloc_fake_parent_device(parent, pa);
 	pdev->devfn = PCI_DEVFN(pa->pa_device, pa->pa_function);
 	pdev->vendor = PCI_VENDOR(pa->pa_id);
 	pdev->device = PCI_PRODUCT(pa->pa_id);
@@ -326,6 +395,132 @@ pci_clear_master(struct pci_dev *pdev)
 	    PCI_COMMAND_STATUS_REG, csr);
 }
 
+int
+pcie_capability_read_dword(struct pci_dev *pdev, int reg, uint32_t *valuep)
+{
+	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
+	pcitag_t tag = pdev->pd_pa.pa_tag;
+	int off;
+
+	*valuep = 0;
+
+	/* Must have capabilities. */
+	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
+		return 1;
+
+	*valuep = pci_conf_read(pc, tag, off + reg);
+
+	return 0;
+}
+
+int
+pcie_capability_read_word(struct pci_dev *pdev, int reg, uint16_t *valuep)
+{
+	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
+	pcitag_t tag = pdev->pd_pa.pa_tag;
+	int off;
+
+	*valuep = 0;
+
+	/* Must have capabilities. */
+	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
+		return 1;
+
+	*valuep = pci_conf_read(pc, tag, off + (reg &~ 2)) >> (8 * (reg & 2));
+
+	return 0;
+}
+
+int
+pcie_capability_write_dword(struct pci_dev *pdev, int reg, uint32_t value)
+{
+	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
+	pcitag_t tag = pdev->pd_pa.pa_tag;
+	int off;
+
+	/* Must have capabilities. */
+	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
+		return 1;
+
+	pci_conf_write(pc, tag, off + reg, value);
+
+	return 0;
+}
+
+int
+pcie_capability_write_word(struct pci_dev *pdev, int reg, uint16_t value)
+{
+	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
+	pcitag_t tag = pdev->pd_pa.pa_tag;
+	int off;
+
+	/* Must have capabilities. */
+	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
+		return 1;
+
+	pci_rmw_config(pc, tag, off + reg, 2, value);
+
+	return 0;
+}
+
+/* From PCIe 5.0 7.5.3.4 "Device Control Register" */
+static const unsigned readrqmax[] = {
+	128,
+	256,
+	512,
+	1024,
+	2048,
+	4096,
+};
+
+int
+pcie_get_readrq(struct pci_dev *pdev)
+{
+	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
+	pcitag_t tag = pdev->pd_pa.pa_tag;
+	unsigned val;
+	int off;
+
+	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
+		return -EINVAL; /* XXX NetBSD->Linux */
+
+	val = __SHIFTOUT(pci_conf_read(pc, tag, off + PCIE_DCSR),
+	    PCIE_DCSR_MAX_READ_REQ);
+
+	if (val >= __arraycount(readrqmax))
+		val = 0;
+	return readrqmax[val];
+}
+
+int
+pcie_set_readrq(struct pci_dev *pdev, int val)
+{
+	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
+	pcitag_t tag = pdev->pd_pa.pa_tag;
+	pcireg_t reg, newval = 0;
+	unsigned i;
+	int off;
+
+	for (i = 0; i < __arraycount(readrqmax); i++) {
+		if (readrqmax[i] == val) {
+			newval = i;
+			break;
+		}
+	}
+
+	if (i == __arraycount(readrqmax))
+		return -EINVAL;
+
+	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
+		return -EINVAL; /* XXX NetBSD->Linux */
+
+	reg = pci_conf_read(pc, tag, off + PCIE_DCSR);
+	reg &= ~PCIE_DCSR_MAX_READ_REQ | (newval << 12);
+	pci_conf_write(pc, tag, off + PCIE_DCSR, reg);
+
+	return 0;
+}
+
 bus_addr_t
 pcibios_align_resource(void *p, const struct resource *resource,
     bus_addr_t addr, bus_size_t size)
@@ -780,6 +975,9 @@ linux_pci_dev_destroy(struct pci_dev *pd
 {
 	unsigned i;
 
+	if (pdev->bus->self != NULL) {
+		kmem_free(pdev->bus->self, sizeof(*pdev->bus->self));
+	}
 	if (pdev->bus != NULL) {
 		kmem_free(pdev->bus, sizeof(*pdev->bus));
 		pdev->bus = NULL;

Reply via email to