Merge branch 'pci/resources'
- Restore VF resizable BAR state after reset (Michał Winiarski) - Add pci_resource_num_to_vf_bar() and pci_resource_num_from_vf_bar() to convert between VF BAR number and the dev->resource[] index (Michał Winiarski) - Allow IOV resources (VF BARs) to be resized (Michał Winiarski) - Add pci_iov_vf_bar_set_size() so drivers can control VF BAR size (Michał Winiarski) * pci/resources: PCI/IOV: Allow drivers to control VF BAR size PCI/IOV: Check that VF BAR fits within the reservation PCI/IOV: Allow IOV resources to be resized in pci_resize_resource() PCI/IOV: Add pci_resource_num_to_vf_bar() to convert VF BAR number to/from IOV resource PCI/IOV: Restore VF resizable BAR state after resetpull/1320/head
commit
29ccb7b97e
|
|
@ -7,11 +7,16 @@
|
|||
* Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/div64.h>
|
||||
#include "pci.h"
|
||||
|
||||
#define VIRTFN_ID_LEN 17 /* "virtfn%u\0" for 2^32 - 1 */
|
||||
|
|
@ -150,7 +155,28 @@ resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
|
|||
if (!dev->is_physfn)
|
||||
return 0;
|
||||
|
||||
return dev->sriov->barsz[resno - PCI_IOV_RESOURCES];
|
||||
return dev->sriov->barsz[pci_resource_num_to_vf_bar(resno)];
|
||||
}
|
||||
|
||||
void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
|
||||
resource_size_t size)
|
||||
{
|
||||
if (!pci_resource_is_iov(resno)) {
|
||||
pci_warn(dev, "%s is not an IOV resource\n",
|
||||
pci_resource_name(dev, resno));
|
||||
return;
|
||||
}
|
||||
|
||||
dev->sriov->barsz[pci_resource_num_to_vf_bar(resno)] = size;
|
||||
}
|
||||
|
||||
bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev)
|
||||
{
|
||||
u16 cmd;
|
||||
|
||||
pci_read_config_word(dev, dev->sriov->pos + PCI_SRIOV_CTRL, &cmd);
|
||||
|
||||
return cmd & PCI_SRIOV_CTRL_MSE;
|
||||
}
|
||||
|
||||
static void pci_read_vf_config_common(struct pci_dev *virtfn)
|
||||
|
|
@ -341,12 +367,14 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
|
|||
virtfn->multifunction = 0;
|
||||
|
||||
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
|
||||
res = &dev->resource[i + PCI_IOV_RESOURCES];
|
||||
int idx = pci_resource_num_from_vf_bar(i);
|
||||
|
||||
res = &dev->resource[idx];
|
||||
if (!res->parent)
|
||||
continue;
|
||||
virtfn->resource[i].name = pci_name(virtfn);
|
||||
virtfn->resource[i].flags = res->flags;
|
||||
size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES);
|
||||
size = pci_iov_resource_size(dev, idx);
|
||||
resource_set_range(&virtfn->resource[i],
|
||||
res->start + size * id, size);
|
||||
rc = request_resource(res, &virtfn->resource[i]);
|
||||
|
|
@ -643,8 +671,13 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
|
|||
|
||||
nres = 0;
|
||||
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
|
||||
bars |= (1 << (i + PCI_IOV_RESOURCES));
|
||||
res = &dev->resource[i + PCI_IOV_RESOURCES];
|
||||
int idx = pci_resource_num_from_vf_bar(i);
|
||||
resource_size_t vf_bar_sz = pci_iov_resource_size(dev, idx);
|
||||
|
||||
bars |= (1 << idx);
|
||||
res = &dev->resource[idx];
|
||||
if (vf_bar_sz * nr_virtfn > resource_size(res))
|
||||
continue;
|
||||
if (res->parent)
|
||||
nres++;
|
||||
}
|
||||
|
|
@ -810,8 +843,10 @@ found:
|
|||
|
||||
nres = 0;
|
||||
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
|
||||
res = &dev->resource[i + PCI_IOV_RESOURCES];
|
||||
res_name = pci_resource_name(dev, i + PCI_IOV_RESOURCES);
|
||||
int idx = pci_resource_num_from_vf_bar(i);
|
||||
|
||||
res = &dev->resource[idx];
|
||||
res_name = pci_resource_name(dev, idx);
|
||||
|
||||
/*
|
||||
* If it is already FIXED, don't change it, something
|
||||
|
|
@ -850,6 +885,7 @@ found:
|
|||
pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
|
||||
if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)
|
||||
iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link);
|
||||
iov->vf_rebar_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VF_REBAR);
|
||||
|
||||
if (pdev)
|
||||
iov->dev = pci_dev_get(pdev);
|
||||
|
|
@ -869,7 +905,7 @@ fail_max_buses:
|
|||
dev->is_physfn = 0;
|
||||
failed:
|
||||
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
|
||||
res = &dev->resource[i + PCI_IOV_RESOURCES];
|
||||
res = &dev->resource[pci_resource_num_from_vf_bar(i)];
|
||||
res->flags = 0;
|
||||
}
|
||||
|
||||
|
|
@ -888,6 +924,30 @@ static void sriov_release(struct pci_dev *dev)
|
|||
dev->sriov = NULL;
|
||||
}
|
||||
|
||||
static void sriov_restore_vf_rebar_state(struct pci_dev *dev)
|
||||
{
|
||||
unsigned int pos, nbars, i;
|
||||
u32 ctrl;
|
||||
|
||||
pos = pci_iov_vf_rebar_cap(dev);
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
|
||||
nbars = FIELD_GET(PCI_VF_REBAR_CTRL_NBAR_MASK, ctrl);
|
||||
|
||||
for (i = 0; i < nbars; i++, pos += 8) {
|
||||
int bar_idx, size;
|
||||
|
||||
pci_read_config_dword(dev, pos + PCI_VF_REBAR_CTRL, &ctrl);
|
||||
bar_idx = FIELD_GET(PCI_VF_REBAR_CTRL_BAR_IDX, ctrl);
|
||||
size = pci_rebar_bytes_to_size(dev->sriov->barsz[bar_idx]);
|
||||
ctrl &= ~PCI_VF_REBAR_CTRL_BAR_SIZE;
|
||||
ctrl |= FIELD_PREP(PCI_VF_REBAR_CTRL_BAR_SIZE, size);
|
||||
pci_write_config_dword(dev, pos + PCI_VF_REBAR_CTRL, ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
static void sriov_restore_state(struct pci_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -907,7 +967,7 @@ static void sriov_restore_state(struct pci_dev *dev)
|
|||
pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, ctrl);
|
||||
|
||||
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++)
|
||||
pci_update_resource(dev, i + PCI_IOV_RESOURCES);
|
||||
pci_update_resource(dev, pci_resource_num_from_vf_bar(i));
|
||||
|
||||
pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
|
||||
pci_iov_set_numvfs(dev, iov->num_VFs);
|
||||
|
|
@ -973,7 +1033,7 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno)
|
|||
{
|
||||
struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL;
|
||||
struct resource *res = pci_resource_n(dev, resno);
|
||||
int vf_bar = resno - PCI_IOV_RESOURCES;
|
||||
int vf_bar = pci_resource_num_to_vf_bar(resno);
|
||||
struct pci_bus_region region;
|
||||
u16 cmd;
|
||||
u32 new;
|
||||
|
|
@ -1047,8 +1107,10 @@ resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
|
|||
*/
|
||||
void pci_restore_iov_state(struct pci_dev *dev)
|
||||
{
|
||||
if (dev->is_physfn)
|
||||
if (dev->is_physfn) {
|
||||
sriov_restore_vf_rebar_state(dev);
|
||||
sriov_restore_state(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1255,3 +1317,72 @@ int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn)
|
|||
return nr_virtfn;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_sriov_configure_simple);
|
||||
|
||||
/**
|
||||
* pci_iov_vf_bar_set_size - set a new size for a VF BAR
|
||||
* @dev: the PCI device
|
||||
* @resno: the resource number
|
||||
* @size: new size as defined in the spec (0=1MB, 31=128TB)
|
||||
*
|
||||
* Set the new size of a VF BAR that supports VF resizable BAR capability.
|
||||
* Unlike pci_resize_resource(), this does not cause the resource that
|
||||
* reserves the MMIO space (originally up to total_VFs) to be resized, which
|
||||
* means that following calls to pci_enable_sriov() can fail if the resources
|
||||
* no longer fit.
|
||||
*
|
||||
* Return: 0 on success, or negative on failure.
|
||||
*/
|
||||
int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size)
|
||||
{
|
||||
u32 sizes;
|
||||
int ret;
|
||||
|
||||
if (!pci_resource_is_iov(resno))
|
||||
return -EINVAL;
|
||||
|
||||
if (pci_iov_is_memory_decoding_enabled(dev))
|
||||
return -EBUSY;
|
||||
|
||||
sizes = pci_rebar_get_possible_sizes(dev, resno);
|
||||
if (!sizes)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (!(sizes & BIT(size)))
|
||||
return -EINVAL;
|
||||
|
||||
ret = pci_rebar_set_size(dev, resno, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_iov_resource_set_size(dev, resno, pci_rebar_size_to_bytes(size));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_iov_vf_bar_set_size);
|
||||
|
||||
/**
|
||||
* pci_iov_vf_bar_get_sizes - get VF BAR sizes allowing to create up to num_vfs
|
||||
* @dev: the PCI device
|
||||
* @resno: the resource number
|
||||
* @num_vfs: number of VFs
|
||||
*
|
||||
* Get the sizes of a VF resizable BAR that can accommodate @num_vfs within
|
||||
* the currently assigned size of the resource @resno.
|
||||
*
|
||||
* Return: A bitmask of sizes in format defined in the spec (bit 0=1MB,
|
||||
* bit 31=128TB).
|
||||
*/
|
||||
u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs)
|
||||
{
|
||||
u64 vf_len = pci_resource_len(dev, resno);
|
||||
u32 sizes;
|
||||
|
||||
if (!num_vfs)
|
||||
return 0;
|
||||
|
||||
do_div(vf_len, num_vfs);
|
||||
sizes = (roundup_pow_of_two(vf_len + 1) - 1) >> ilog2(SZ_1M);
|
||||
|
||||
return sizes & pci_rebar_get_possible_sizes(dev, resno);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_iov_vf_bar_get_sizes);
|
||||
|
|
|
|||
|
|
@ -3756,7 +3756,13 @@ static int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
|
|||
unsigned int pos, nbars, i;
|
||||
u32 ctrl;
|
||||
|
||||
pos = pdev->rebar_cap;
|
||||
if (pci_resource_is_iov(bar)) {
|
||||
pos = pci_iov_vf_rebar_cap(pdev);
|
||||
bar = pci_resource_num_to_vf_bar(bar);
|
||||
} else {
|
||||
pos = pdev->rebar_cap;
|
||||
}
|
||||
|
||||
if (!pos)
|
||||
return -ENOTSUPP;
|
||||
|
||||
|
|
|
|||
|
|
@ -492,6 +492,7 @@ struct pci_sriov {
|
|||
u16 subsystem_vendor; /* VF subsystem vendor */
|
||||
u16 subsystem_device; /* VF subsystem device */
|
||||
resource_size_t barsz[PCI_SRIOV_NUM_BARS]; /* VF BAR size */
|
||||
u16 vf_rebar_cap; /* VF Resizable BAR capability offset */
|
||||
bool drivers_autoprobe; /* Auto probing of VFs by driver */
|
||||
};
|
||||
|
||||
|
|
@ -716,10 +717,28 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno);
|
|||
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
|
||||
void pci_restore_iov_state(struct pci_dev *dev);
|
||||
int pci_iov_bus_range(struct pci_bus *bus);
|
||||
void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
|
||||
resource_size_t size);
|
||||
bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev);
|
||||
static inline u16 pci_iov_vf_rebar_cap(struct pci_dev *dev)
|
||||
{
|
||||
if (!dev->is_physfn)
|
||||
return 0;
|
||||
|
||||
return dev->sriov->vf_rebar_cap;
|
||||
}
|
||||
static inline bool pci_resource_is_iov(int resno)
|
||||
{
|
||||
return resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END;
|
||||
}
|
||||
static inline int pci_resource_num_from_vf_bar(int resno)
|
||||
{
|
||||
return resno + PCI_IOV_RESOURCES;
|
||||
}
|
||||
static inline int pci_resource_num_to_vf_bar(int resno)
|
||||
{
|
||||
return resno - PCI_IOV_RESOURCES;
|
||||
}
|
||||
extern const struct attribute_group sriov_pf_dev_attr_group;
|
||||
extern const struct attribute_group sriov_vf_dev_attr_group;
|
||||
#else
|
||||
|
|
@ -740,10 +759,30 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void pci_iov_resource_set_size(struct pci_dev *dev, int resno,
|
||||
resource_size_t size) { }
|
||||
static inline bool pci_iov_is_memory_decoding_enabled(struct pci_dev *dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline u16 pci_iov_vf_rebar_cap(struct pci_dev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline bool pci_resource_is_iov(int resno)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline int pci_resource_num_from_vf_bar(int resno)
|
||||
{
|
||||
WARN_ON_ONCE(1);
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int pci_resource_num_to_vf_bar(int resno)
|
||||
{
|
||||
WARN_ON_ONCE(1);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_PCI_IOV */
|
||||
|
||||
#ifdef CONFIG_PCIE_TPH
|
||||
|
|
|
|||
|
|
@ -1888,7 +1888,8 @@ static int iov_resources_unassigned(struct pci_dev *dev, void *data)
|
|||
bool *unassigned = data;
|
||||
|
||||
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
|
||||
struct resource *r = &dev->resource[i + PCI_IOV_RESOURCES];
|
||||
int idx = pci_resource_num_from_vf_bar(i);
|
||||
struct resource *r = &dev->resource[idx];
|
||||
struct pci_bus_region region;
|
||||
|
||||
/* Not assigned or rejected by kernel? */
|
||||
|
|
|
|||
|
|
@ -423,13 +423,39 @@ void pci_release_resource(struct pci_dev *dev, int resno)
|
|||
}
|
||||
EXPORT_SYMBOL(pci_release_resource);
|
||||
|
||||
static bool pci_resize_is_memory_decoding_enabled(struct pci_dev *dev,
|
||||
int resno)
|
||||
{
|
||||
u16 cmd;
|
||||
|
||||
if (pci_resource_is_iov(resno))
|
||||
return pci_iov_is_memory_decoding_enabled(dev);
|
||||
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
|
||||
return cmd & PCI_COMMAND_MEMORY;
|
||||
}
|
||||
|
||||
static void pci_resize_resource_set_size(struct pci_dev *dev, int resno,
|
||||
int size)
|
||||
{
|
||||
resource_size_t res_size = pci_rebar_size_to_bytes(size);
|
||||
struct resource *res = pci_resource_n(dev, resno);
|
||||
|
||||
if (!pci_resource_is_iov(resno)) {
|
||||
resource_set_size(res, res_size);
|
||||
} else {
|
||||
resource_set_size(res, res_size * pci_sriov_get_totalvfs(dev));
|
||||
pci_iov_resource_set_size(dev, resno, res_size);
|
||||
}
|
||||
}
|
||||
|
||||
int pci_resize_resource(struct pci_dev *dev, int resno, int size)
|
||||
{
|
||||
struct resource *res = pci_resource_n(dev, resno);
|
||||
struct pci_host_bridge *host;
|
||||
int old, ret;
|
||||
u32 sizes;
|
||||
u16 cmd;
|
||||
|
||||
/* Check if we must preserve the firmware's resource assignment */
|
||||
host = pci_find_host_bridge(dev->bus);
|
||||
|
|
@ -440,8 +466,7 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
|
|||
if (!(res->flags & IORESOURCE_UNSET))
|
||||
return -EBUSY;
|
||||
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
if (cmd & PCI_COMMAND_MEMORY)
|
||||
if (pci_resize_is_memory_decoding_enabled(dev, resno))
|
||||
return -EBUSY;
|
||||
|
||||
sizes = pci_rebar_get_possible_sizes(dev, resno);
|
||||
|
|
@ -459,7 +484,7 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
resource_set_size(res, pci_rebar_size_to_bytes(size));
|
||||
pci_resize_resource_set_size(dev, resno, size);
|
||||
|
||||
/* Check if the new config works by trying to assign everything. */
|
||||
if (dev->bus->self) {
|
||||
|
|
@ -471,7 +496,7 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size)
|
|||
|
||||
error_resize:
|
||||
pci_rebar_set_size(dev, resno, old);
|
||||
resource_set_size(res, pci_rebar_size_to_bytes(old));
|
||||
pci_resize_resource_set_size(dev, resno, old);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_resize_resource);
|
||||
|
|
|
|||
|
|
@ -2459,6 +2459,8 @@ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
|
|||
int pci_sriov_get_totalvfs(struct pci_dev *dev);
|
||||
int pci_sriov_configure_simple(struct pci_dev *dev, int nr_virtfn);
|
||||
resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno);
|
||||
int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size);
|
||||
u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs);
|
||||
void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe);
|
||||
|
||||
/* Arch may override these (weak) */
|
||||
|
|
@ -2511,6 +2513,10 @@ static inline int pci_sriov_get_totalvfs(struct pci_dev *dev)
|
|||
#define pci_sriov_configure_simple NULL
|
||||
static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
|
||||
{ return 0; }
|
||||
static inline int pci_iov_vf_bar_set_size(struct pci_dev *dev, int resno, int size)
|
||||
{ return -ENODEV; }
|
||||
static inline u32 pci_iov_vf_bar_get_sizes(struct pci_dev *dev, int resno, int num_vfs)
|
||||
{ return 0; }
|
||||
static inline void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe) { }
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -745,6 +745,7 @@
|
|||
#define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */
|
||||
#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */
|
||||
#define PCI_EXT_CAP_ID_DVSEC 0x23 /* Designated Vendor-Specific */
|
||||
#define PCI_EXT_CAP_ID_VF_REBAR 0x24 /* VF Resizable BAR */
|
||||
#define PCI_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */
|
||||
#define PCI_EXT_CAP_ID_PL_16GT 0x26 /* Physical Layer 16.0 GT/s */
|
||||
#define PCI_EXT_CAP_ID_NPEM 0x29 /* Native PCIe Enclosure Management */
|
||||
|
|
@ -1141,6 +1142,14 @@
|
|||
#define PCI_DVSEC_HEADER2 0x8 /* Designated Vendor-Specific Header2 */
|
||||
#define PCI_DVSEC_HEADER2_ID(x) ((x) & 0xffff)
|
||||
|
||||
/* VF Resizable BARs, same layout as PCI_REBAR */
|
||||
#define PCI_VF_REBAR_CAP PCI_REBAR_CAP
|
||||
#define PCI_VF_REBAR_CAP_SIZES PCI_REBAR_CAP_SIZES
|
||||
#define PCI_VF_REBAR_CTRL PCI_REBAR_CTRL
|
||||
#define PCI_VF_REBAR_CTRL_BAR_IDX PCI_REBAR_CTRL_BAR_IDX
|
||||
#define PCI_VF_REBAR_CTRL_NBAR_MASK PCI_REBAR_CTRL_NBAR_MASK
|
||||
#define PCI_VF_REBAR_CTRL_BAR_SIZE PCI_REBAR_CTRL_BAR_SIZE
|
||||
|
||||
/* Data Link Feature */
|
||||
#define PCI_DLF_CAP 0x04 /* Capabilities Register */
|
||||
#define PCI_DLF_EXCHANGE_ENABLE 0x80000000 /* Data Link Feature Exchange Enable */
|
||||
|
|
|
|||
Loading…
Reference in New Issue