Add device pci init implementation,<br />to obtain PCI capability and read configuration, etc.<br /> <br />Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn> <br />---<br /> drivers/net/zxdh/meson.build   |   1 +<br /> drivers/net/zxdh/zxdh_ethdev.c |  44 +++++<br /> drivers/net/zxdh/zxdh_ethdev.h |  18 ++-<br /> drivers/net/zxdh/zxdh_pci.c    | 283 +++++++++++++++++++++++++++++++++<br /> drivers/net/zxdh/zxdh_pci.h    | 138 ++++++++++++++++<br /> 5 files changed, 483 insertions(+), 1 deletion(-)<br /> create mode 100644 drivers/net/zxdh/zxdh_pci.c<br /> create mode 100644 drivers/net/zxdh/zxdh_pci.h<br /> <br />diff --git a/drivers/net/zxdh/meson.build b/drivers/net/zxdh/meson.build<br />index 932fb1c835..7db4e7bc71 100644<br />--- a/drivers/net/zxdh/meson.build<br />+++ b/drivers/net/zxdh/meson.build<br />@@ -15,4 +15,5 @@ endif<br />  <br /> sources = files(<br />         'zxdh_ethdev.c',<br />+        'zxdh_pci.c',<br /> )<br />diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c<br />index b64dddc91e..ae20e00317 100644<br />--- a/drivers/net/zxdh/zxdh_ethdev.c<br />+++ b/drivers/net/zxdh/zxdh_ethdev.c<br />@@ -8,6 +8,41 @@<br />  <br /> #include "zxdh_ethdev.h" <br /> #include "zxdh_logs.h" <br />+#include "zxdh_pci.h" <br />+<br />+struct zxdh_hw_internal zxdh_hw_internal[RTE_MAX_ETHPORTS];<br />+<br />+static int32_t<br />+zxdh_init_device(struct rte_eth_dev *eth_dev)<br />+{<br />+    struct zxdh_hw *hw = eth_dev->data->dev_private;<br />+    struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);<br />+    int ret = 0;<br />+<br />+    ret = zxdh_read_pci_caps(pci_dev, hw);<br />+    if (ret) {<br />+        PMD_DRV_LOG(ERR, "port 0x%x pci caps read failed .", hw->port_id);<br />+        goto err;<br />+    }<br />+<br />+    zxdh_hw_internal[hw->port_id].zxdh_vtpci_ops = &zxdh_dev_pci_ops;<br />+    zxdh_pci_reset(hw);<br />+    zxdh_get_pci_dev_config(hw);<br />+<br />+    rte_ether_addr_copy((struct rte_ether_addr *)hw->mac_addr, &eth_dev->data->mac_addrs[0]);<br />+<br />+    /* If host does not support both status and MSI-X then disable LSC */<br />+    if (vtpci_with_feature(hw, ZXDH_NET_F_STATUS) && hw->use_msix != ZXDH_MSIX_NONE)<br />+        eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;<br />+    else<br />+        eth_dev->data->dev_flags &= ~RTE_ETH_DEV_INTR_LSC;<br />+<br />+    return 0;<br />+<br />+err:<br />+    PMD_DRV_LOG(ERR, "port %d init device failed", eth_dev->data->port_id);<br />+    return ret;<br />+}<br />  <br /> static int<br /> zxdh_eth_dev_init(struct rte_eth_dev *eth_dev)<br />@@ -46,6 +81,15 @@ zxdh_eth_dev_init(struct rte_eth_dev *eth_dev)<br />         hw->is_pf = 1;<br />     }<br />  <br />+    ret = zxdh_init_device(eth_dev);<br />+    if (ret < 0)<br />+        goto err_zxdh_init;<br />+<br />+    return ret;<br />+<br />+err_zxdh_init:<br />+    rte_free(eth_dev->data->mac_addrs);<br />+    eth_dev->data->mac_addrs = NULL;<br />     return ret;<br /> }<br />  <br />diff --git a/drivers/net/zxdh/zxdh_ethdev.h b/drivers/net/zxdh/zxdh_ethdev.h<br />index a11e3624a9..a22ac15065 100644<br />--- a/drivers/net/zxdh/zxdh_ethdev.h<br />+++ b/drivers/net/zxdh/zxdh_ethdev.h<br />@@ -5,6 +5,7 @@<br /> #ifndef ZXDH_ETHDEV_H<br /> #define ZXDH_ETHDEV_H<br />  <br />+#include <rte_ether.h> <br /> #include "ethdev_driver.h" <br />  <br /> #ifdef __cplusplus<br />@@ -24,15 +25,30 @@ extern "C" {<br /> #define ZXDH_MAX_MAC_ADDRS        (ZXDH_MAX_UC_MAC_ADDRS + ZXDH_MAX_MC_MAC_ADDRS)<br />  <br /> #define ZXDH_NUM_BARS             2<br />+#define ZXDH_RX_QUEUES_MAX        128U<br />+#define ZXDH_TX_QUEUES_MAX        128U<br />  <br /> struct zxdh_hw {<br />     struct rte_eth_dev *eth_dev;<br />-    uint64_t bar_addr[ZXDH_NUM_BARS];<br />+    struct zxdh_pci_common_cfg *common_cfg;<br />+    struct zxdh_net_config *dev_cfg;<br />  <br />+    uint64_t bar_addr[ZXDH_NUM_BARS];<br />+    uint64_t host_features;<br />+    uint64_t guest_features;<br />+    uint32_t max_queue_pairs;<br />     uint32_t speed;<br />+    uint32_t notify_off_multiplier;<br />+    uint16_t *notify_base;<br />+    uint16_t pcie_id;<br />     uint16_t device_id;<br />     uint16_t port_id;<br />  <br />+    uint8_t *isr;<br />+    uint8_t weak_barriers;<br />+    uint8_t use_msix;<br />+    uint8_t mac_addr[RTE_ETHER_ADDR_LEN];<br />+<br />     uint8_t duplex;<br />     uint8_t is_pf;<br /> };<br />diff --git a/drivers/net/zxdh/zxdh_pci.c b/drivers/net/zxdh/zxdh_pci.c<br />new file mode 100644<br />index 0000000000..68785aa03e<br />--- /dev/null<br />+++ b/drivers/net/zxdh/zxdh_pci.c<br />@@ -0,0 +1,283 @@<br />+/* SPDX-License-Identifier: BSD-3-Clause<br />+ * Copyright(c) 2024 ZTE Corporation<br />+ */<br />+<br />+#include <stdint.h> <br />+#include <unistd.h> <br />+<br />+#include <rte_io.h> <br />+#include <rte_bus.h> <br />+#include <rte_pci.h> <br />+#include <rte_common.h> <br />+#include <rte_cycles.h> <br />+<br />+#include "zxdh_ethdev.h" <br />+#include "zxdh_pci.h" <br />+#include "zxdh_logs.h" <br />+<br />+#define ZXDH_PMD_DEFAULT_GUEST_FEATURES   \<br />+        (1ULL << ZXDH_NET_F_MRG_RXBUF | \<br />+        1ULL << ZXDH_NET_F_STATUS    | \<br />+        1ULL << ZXDH_NET_F_MQ        | \<br />+        1ULL << ZXDH_F_ANY_LAYOUT    | \<br />+        1ULL << ZXDH_F_VERSION_1     | \<br />+        1ULL << ZXDH_F_RING_PACKED   | \<br />+        1ULL << ZXDH_F_IN_ORDER      | \<br />+        1ULL << ZXDH_F_NOTIFICATION_DATA | \<br />+        1ULL << ZXDH_NET_F_MAC)<br />+<br />+static void<br />+zxdh_read_dev_config(struct zxdh_hw *hw, size_t offset,<br />+        void *dst, int32_t length)<br />+{<br />+    int32_t i       = 0;<br />+    uint8_t *p      = NULL;<br />+    uint8_t old_gen = 0;<br />+    uint8_t new_gen = 0;<br />+<br />+    do {<br />+        old_gen = rte_read8(&hw->common_cfg->config_generation);<br />+<br />+        p = dst;<br />+        for (i = 0;  i < length; i++)<br />+            *p++ = rte_read8((uint8_t *)hw->dev_cfg + offset + i);<br />+<br />+        new_gen = rte_read8(&hw->common_cfg->config_generation);<br />+    } while (old_gen != new_gen);<br />+}<br />+<br />+static void<br />+zxdh_write_dev_config(struct zxdh_hw *hw, size_t offset,<br />+        const void *src, int32_t length)<br />+{<br />+    int32_t i = 0;<br />+    const uint8_t *p = src;<br />+<br />+    for (i = 0;  i < length; i++)<br />+        rte_write8((*p++), (((uint8_t *)hw->dev_cfg) + offset + i));<br />+}<br />+<br />+static uint8_t<br />+zxdh_get_status(struct zxdh_hw *hw)<br />+{<br />+    return rte_read8(&hw->common_cfg->device_status);<br />+}<br />+<br />+static void<br />+zxdh_set_status(struct zxdh_hw *hw, uint8_t status)<br />+{<br />+    rte_write8(status, &hw->common_cfg->device_status);<br />+}<br />+<br />+static uint64_t<br />+zxdh_get_features(struct zxdh_hw *hw)<br />+{<br />+    uint32_t features_lo = 0;<br />+    uint32_t features_hi = 0;<br />+<br />+    rte_write32(0, &hw->common_cfg->device_feature_select);<br />+    features_lo = rte_read32(&hw->common_cfg->device_feature);<br />+<br />+    rte_write32(1, &hw->common_cfg->device_feature_select);<br />+    features_hi = rte_read32(&hw->common_cfg->device_feature);<br />+<br />+    return ((uint64_t)features_hi << 32) | features_lo;<br />+}<br />+<br />+static void<br />+zxdh_set_features(struct zxdh_hw *hw, uint64_t features)<br />+{<br />+    rte_write32(0, &hw->common_cfg->guest_feature_select);<br />+    rte_write32(features & ((1ULL << 32) - 1), &hw->common_cfg->guest_feature);<br />+    rte_write32(1, &hw->common_cfg->guest_feature_select);<br />+    rte_write32(features >> 32, &hw->common_cfg->guest_feature);<br />+}<br />+<br />+const struct zxdh_pci_ops zxdh_dev_pci_ops = {<br />+    .read_dev_cfg   = zxdh_read_dev_config,<br />+    .write_dev_cfg  = zxdh_write_dev_config,<br />+    .get_status     = zxdh_get_status,<br />+    .set_status     = zxdh_set_status,<br />+    .get_features   = zxdh_get_features,<br />+    .set_features   = zxdh_set_features,<br />+};<br />+<br />+uint16_t<br />+zxdh_pci_get_features(struct zxdh_hw *hw)<br />+{<br />+    return ZXDH_VTPCI_OPS(hw)->get_features(hw);<br />+}<br />+<br />+void<br />+zxdh_pci_reset(struct zxdh_hw *hw)<br />+{<br />+    PMD_DRV_LOG(INFO, "port %u device start reset, just wait...", hw->port_id);<br />+    uint32_t retry = 0;<br />+<br />+    ZXDH_VTPCI_OPS(hw)->set_status(hw, ZXDH_CONFIG_STATUS_RESET);<br />+    /* Flush status write and wait device ready max 3 seconds. */<br />+    while (ZXDH_VTPCI_OPS(hw)->get_status(hw) != ZXDH_CONFIG_STATUS_RESET) {<br />+        ++retry;<br />+        rte_delay_ms(1);<br />+    }<br />+    PMD_DRV_LOG(INFO, "port %u device reset %u ms done", hw->port_id, retry);<br />+}<br />+<br />+static void<br />+*get_cfg_addr(struct rte_pci_device *dev, struct zxdh_pci_cap *cap)<br />+{<br />+    uint8_t  bar    = cap->bar;<br />+    uint32_t length = cap->length;<br />+    uint32_t offset = cap->offset;<br />+<br />+    if (bar >= PCI_MAX_RESOURCE) {<br />+        PMD_DRV_LOG(ERR, "invalid bar: %u", bar);<br />+        return NULL;<br />+    }<br />+    if (offset + length < offset) {<br />+        PMD_DRV_LOG(ERR, "offset(%u) + length(%u) overflows", offset, length);<br />+        return NULL;<br />+    }<br />+    if (offset + length > dev->mem_resource[bar].len) {<br />+        PMD_DRV_LOG(ERR, "invalid cap: overflows bar space");<br />+        return NULL;<br />+    }<br />+    uint8_t *base = dev->mem_resource[bar].addr;<br />+<br />+    if (base == NULL) {<br />+        PMD_DRV_LOG(ERR, "bar %u base addr is NULL", bar);<br />+        return NULL;<br />+    }<br />+    return base + offset;<br />+}<br />+<br />+int32_t<br />+zxdh_read_pci_caps(struct rte_pci_device *dev, struct zxdh_hw *hw)<br />+{<br />+    struct zxdh_pci_cap cap;<br />+    uint8_t pos = 0;<br />+    int32_t ret = 0;<br />+<br />+    if (dev->mem_resource[0].addr == NULL) {<br />+        PMD_DRV_LOG(ERR, "bar0 base addr is NULL");<br />+        return -1;<br />+    }<br />+<br />+    hw->use_msix = zxdh_pci_msix_detect(dev);<br />+<br />+    pos = rte_pci_find_capability(dev, RTE_PCI_CAP_ID_VNDR);<br />+    while (pos) {<br />+        ret = rte_pci_read_config(dev, &cap, sizeof(cap), pos);<br />+        if (ret != sizeof(cap)) {<br />+            PMD_DRV_LOG(ERR, "failed to read pci cap at pos: %x ret %d", pos, ret);<br />+            break;<br />+        }<br />+        if (cap.cap_vndr != RTE_PCI_CAP_ID_VNDR) {<br />+            PMD_DRV_LOG(DEBUG, "[%2x] skipping non VNDR cap id: %02x",<br />+                pos, cap.cap_vndr);<br />+            goto next;<br />+        }<br />+        PMD_DRV_LOG(DEBUG, "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",<br />+            pos, cap.cfg_type, cap.bar, cap.offset, cap.length);<br />+<br />+        switch (cap.cfg_type) {<br />+        case ZXDH_PCI_CAP_COMMON_CFG:<br />+            hw->common_cfg = get_cfg_addr(dev, &cap);<br />+            break;<br />+        case ZXDH_PCI_CAP_NOTIFY_CFG: {<br />+            ret = rte_pci_read_config(dev, &hw->notify_off_multiplier,<br />+                        4, pos + sizeof(cap));<br />+            if (ret != 4)<br />+                PMD_DRV_LOG(ERR,<br />+                    "failed to read notify_off_multiplier, ret %d", ret);<br />+            else<br />+                hw->notify_base = get_cfg_addr(dev, &cap);<br />+            break;<br />+        }<br />+        case ZXDH_PCI_CAP_DEVICE_CFG:<br />+            hw->dev_cfg = get_cfg_addr(dev, &cap);<br />+            break;<br />+        case ZXDH_PCI_CAP_ISR_CFG:<br />+            hw->isr = get_cfg_addr(dev, &cap);<br />+            break;<br />+        case ZXDH_PCI_CAP_PCI_CFG: {<br />+            hw->pcie_id = *(uint16_t *)&cap.padding[1];<br />+            PMD_DRV_LOG(DEBUG, "get pcie id 0x%x", hw->pcie_id);<br />+<br />+            if ((hw->pcie_id >> 11) & 0x1) /* PF */ {<br />+                PMD_DRV_LOG(DEBUG, "EP %u PF %u",<br />+                    hw->pcie_id >> 12, (hw->pcie_id >> 8) & 0x7);<br />+            } else { /* VF */<br />+                PMD_DRV_LOG(DEBUG, "EP %u PF %u VF %u",<br />+                    hw->pcie_id >> 12,<br />+                    (hw->pcie_id >> 8) & 0x7,<br />+                    hw->pcie_id & 0xff);<br />+            }<br />+            break;<br />+        }<br />+        }<br />+next:<br />+    pos = cap.cap_next;<br />+    }<br />+    if (hw->common_cfg == NULL || hw->notify_base == NULL ||<br />+        hw->dev_cfg == NULL || hw->isr == NULL) {<br />+        PMD_DRV_LOG(ERR, "no zxdh pci device found.");<br />+        return -1;<br />+    }<br />+    return 0;<br />+}<br />+<br />+void<br />+zxdh_pci_read_dev_config(struct zxdh_hw *hw, size_t offset, void *dst, int32_t length)<br />+{<br />+    ZXDH_VTPCI_OPS(hw)->read_dev_cfg(hw, offset, dst, length);<br />+}<br />+<br />+void<br />+zxdh_get_pci_dev_config(struct zxdh_hw *hw)<br />+{<br />+    uint64_t guest_features = 0;<br />+    uint64_t nego_features = 0;<br />+    uint32_t max_queue_pairs = 0;<br />+<br />+    hw->host_features = zxdh_pci_get_features(hw);<br />+<br />+    guest_features = (uint64_t)ZXDH_PMD_DEFAULT_GUEST_FEATURES;<br />+    nego_features = guest_features & hw->host_features;<br />+<br />+    hw->guest_features = nego_features;<br />+<br />+    if (hw->guest_features & (1ULL << ZXDH_NET_F_MAC)) {<br />+        zxdh_pci_read_dev_config(hw, offsetof(struct zxdh_net_config, mac),<br />+                &hw->mac_addr, RTE_ETHER_ADDR_LEN);<br />+    } else {<br />+        rte_eth_random_addr(&hw->mac_addr[0]);<br />+    }<br />+<br />+    zxdh_pci_read_dev_config(hw, offsetof(struct zxdh_net_config, max_virtqueue_pairs),<br />+            &max_queue_pairs, sizeof(max_queue_pairs));<br />+<br />+    if (max_queue_pairs == 0)<br />+        hw->max_queue_pairs = ZXDH_RX_QUEUES_MAX;<br />+    else<br />+        hw->max_queue_pairs = RTE_MIN(ZXDH_RX_QUEUES_MAX, max_queue_pairs);<br />+    PMD_DRV_LOG(DEBUG, "set max queue pairs %d", hw->max_queue_pairs);<br />+}<br />+<br />+enum zxdh_msix_status zxdh_pci_msix_detect(struct rte_pci_device *dev)<br />+{<br />+    uint16_t flags = 0;<br />+    uint8_t pos = 0;<br />+    int16_t ret = 0;<br />+<br />+    pos = rte_pci_find_capability(dev, RTE_PCI_CAP_ID_MSIX);<br />+<br />+    if (pos > 0) {<br />+        ret = rte_pci_read_config(dev, &flags, 2, pos + RTE_PCI_MSIX_FLAGS);<br />+        if (ret == 2 && flags & RTE_PCI_MSIX_FLAGS_ENABLE)<br />+            return ZXDH_MSIX_ENABLED;<br />+        else<br />+            return ZXDH_MSIX_DISABLED;<br />+    }<br />+    return ZXDH_MSIX_NONE;<br />+}<br />diff --git a/drivers/net/zxdh/zxdh_pci.h b/drivers/net/zxdh/zxdh_pci.h<br />new file mode 100644<br />index 0000000000..7905911a34<br />--- /dev/null<br />+++ b/drivers/net/zxdh/zxdh_pci.h<br />@@ -0,0 +1,138 @@<br />+/* SPDX-License-Identifier: BSD-3-Clause<br />+ * Copyright(c) 2024 ZTE Corporation<br />+ */<br />+<br />+#ifndef ZXDH_PCI_H<br />+#define ZXDH_PCI_H<br />+<br />+#include <stdint.h> <br />+#include <stdbool.h> <br />+<br />+#include <bus_pci_driver.h> <br />+<br />+#include "zxdh_ethdev.h" <br />+<br />+#ifdef __cplusplus<br />+extern "C" {<br />+#endif<br />+<br />+enum zxdh_msix_status {<br />+    ZXDH_MSIX_NONE     = 0,<br />+    ZXDH_MSIX_DISABLED = 1,<br />+    ZXDH_MSIX_ENABLED  = 2<br />+};<br />+<br />+#define ZXDH_NET_F_MAC               5   /* Host has given MAC address. */<br />+#define ZXDH_NET_F_MRG_RXBUF         15  /* Host can merge receive buffers. */<br />+#define ZXDH_NET_F_STATUS            16  /* zxdh_net_config.status available */<br />+#define ZXDH_NET_F_MQ                22  /* Device supports Receive Flow Steering */<br />+#define ZXDH_F_ANY_LAYOUT            27 /* Can the device handle any descriptor layout */<br />+#define ZXDH_F_VERSION_1             32<br />+#define ZXDH_F_RING_PACKED           34<br />+#define ZXDH_F_IN_ORDER              35<br />+#define ZXDH_F_NOTIFICATION_DATA     38<br />+<br />+#define ZXDH_PCI_CAP_COMMON_CFG  1 /* Common configuration */<br />+#define ZXDH_PCI_CAP_NOTIFY_CFG  2 /* Notifications */<br />+#define ZXDH_PCI_CAP_ISR_CFG     3 /* ISR Status */<br />+#define ZXDH_PCI_CAP_DEVICE_CFG  4 /* Device specific configuration */<br />+#define ZXDH_PCI_CAP_PCI_CFG     5 /* PCI configuration access */<br />+<br />+/* Status byte for guest to report progress. */<br />+#define ZXDH_CONFIG_STATUS_RESET           0x00<br />+#define ZXDH_CONFIG_STATUS_ACK             0x01<br />+#define ZXDH_CONFIG_STATUS_DRIVER          0x02<br />+#define ZXDH_CONFIG_STATUS_DRIVER_OK       0x04<br />+#define ZXDH_CONFIG_STATUS_FEATURES_OK     0x08<br />+#define ZXDH_CONFIG_STATUS_DEV_NEED_RESET  0x40<br />+#define ZXDH_CONFIG_STATUS_FAILED          0x80<br />+<br />+struct zxdh_net_config {<br />+    /* The config defining mac address (if ZXDH_NET_F_MAC) */<br />+    uint8_t    mac[RTE_ETHER_ADDR_LEN];<br />+    /* See ZXDH_NET_F_STATUS and ZXDH_NET_S_* above */<br />+    uint16_t   status;<br />+    uint16_t   max_virtqueue_pairs;<br />+    uint16_t   mtu;<br />+    uint32_t   speed;<br />+    uint8_t    duplex;<br />+} __rte_packed;<br />+<br />+/* This is the PCI capability header: */<br />+struct zxdh_pci_cap {<br />+    uint8_t  cap_vndr;   /* Generic PCI field: PCI_CAP_ID_VNDR */<br />+    uint8_t  cap_next;   /* Generic PCI field: next ptr. */<br />+    uint8_t  cap_len;    /* Generic PCI field: capability length */<br />+    uint8_t  cfg_type;   /* Identifies the structure. */<br />+    uint8_t  bar;        /* Where to find it. */<br />+    uint8_t  padding[3]; /* Pad to full dword. */<br />+    uint32_t offset;     /* Offset within bar. */<br />+    uint32_t length;     /* Length of the structure, in bytes. */<br />+};<br />+<br />+/* Fields in ZXDH_PCI_CAP_COMMON_CFG: */<br />+struct zxdh_pci_common_cfg {<br />+    /* About the whole device. */<br />+    uint32_t device_feature_select; /* read-write */<br />+    uint32_t device_feature;    /* read-only */<br />+    uint32_t guest_feature_select;  /* read-write */<br />+    uint32_t guest_feature;     /* read-write */<br />+    uint16_t msix_config;       /* read-write */<br />+    uint16_t num_queues;        /* read-only */<br />+    uint8_t  device_status;     /* read-write */<br />+    uint8_t  config_generation; /* read-only */<br />+<br />+    /* About a specific virtqueue. */<br />+    uint16_t queue_select;      /* read-write */<br />+    uint16_t queue_size;        /* read-write, power of 2. */<br />+    uint16_t queue_msix_vector; /* read-write */<br />+    uint16_t queue_enable;      /* read-write */<br />+    uint16_t queue_notify_off;  /* read-only */<br />+    uint32_t queue_desc_lo;     /* read-write */<br />+    uint32_t queue_desc_hi;     /* read-write */<br />+    uint32_t queue_avail_lo;    /* read-write */<br />+    uint32_t queue_avail_hi;    /* read-write */<br />+    uint32_t queue_used_lo;     /* read-write */<br />+    uint32_t queue_used_hi;     /* read-write */<br />+};<br />+<br />+static inline int32_t vtpci_with_feature(struct zxdh_hw *hw, uint64_t bit)<br />+{<br />+    return (hw->guest_features & (1ULL << bit)) != 0;<br />+}<br />+<br />+struct zxdh_pci_ops {<br />+    void     (*read_dev_cfg)(struct zxdh_hw *hw, size_t offset, void *dst, int32_t len);<br />+    void     (*write_dev_cfg)(struct zxdh_hw *hw, size_t offset, const void *src, int32_t len);<br />+<br />+    uint8_t  (*get_status)(struct zxdh_hw *hw);<br />+    void     (*set_status)(struct zxdh_hw *hw, uint8_t status);<br />+<br />+    uint64_t (*get_features)(struct zxdh_hw *hw);<br />+    void     (*set_features)(struct zxdh_hw *hw, uint64_t features);<br />+};<br />+<br />+struct zxdh_hw_internal {<br />+    const struct zxdh_pci_ops *zxdh_vtpci_ops;<br />+};<br />+<br />+#define ZXDH_VTPCI_OPS(hw)  (zxdh_hw_internal[(hw)->port_id].zxdh_vtpci_ops)<br />+<br />+extern struct zxdh_hw_internal zxdh_hw_internal[RTE_MAX_ETHPORTS];<br />+extern const struct zxdh_pci_ops zxdh_dev_pci_ops;<br />+<br />+void zxdh_pci_reset(struct zxdh_hw *hw);<br />+void zxdh_pci_read_dev_config(struct zxdh_hw *hw, size_t offset,<br />+        void *dst, int32_t length);<br />+<br />+int32_t zxdh_read_pci_caps(struct rte_pci_device *dev, struct zxdh_hw *hw);<br />+void zxdh_get_pci_dev_config(struct zxdh_hw *hw);<br />+<br />+uint16_t zxdh_pci_get_features(struct zxdh_hw *hw);<br />+enum zxdh_msix_status zxdh_pci_msix_detect(struct rte_pci_device *dev);<br />+<br />+#ifdef __cplusplus<br />+}<br />+#endif<br />+<br />+#endif /* ZXDH_PCI_H */<br />--  <br />2.27.0<br />