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;