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;