add hardware initialization as per qdma_access lib. Fetch hardware version and other details and bind to proper qdma layer.
Signed-off-by: Aman Kumar <aman.ku...@vvdntech.in> --- drivers/net/qdma/qdma.h | 13 +- drivers/net/qdma/qdma_common.c | 52 +++++++- drivers/net/qdma/qdma_ethdev.c | 225 ++++++++++++++++++++++++++++++++- 3 files changed, 286 insertions(+), 4 deletions(-) diff --git a/drivers/net/qdma/qdma.h b/drivers/net/qdma/qdma.h index 4bc61d2a08..db59cddd25 100644 --- a/drivers/net/qdma/qdma.h +++ b/drivers/net/qdma/qdma.h @@ -15,6 +15,8 @@ #include <rte_byteorder.h> #include <rte_memzone.h> #include <linux/pci.h> + +#include "qdma_resource_mgmt.h" #include "qdma_log.h" #define QDMA_NUM_BARS (6) @@ -23,6 +25,8 @@ #define QDMA_FUNC_ID_INVALID 0xFFFF +#define DEFAULT_QUEUE_BASE (0) + #define DEFAULT_TIMER_CNT_TRIG_MODE_TIMER (5) enum dma_data_direction { @@ -186,6 +190,9 @@ struct qdma_pci_dev { */ uint32_t dma_device_index; + /* Device capabilities */ + struct qdma_dev_attributes dev_cap; + uint8_t cmpt_desc_len; uint8_t c2h_bypass_mode; uint8_t h2c_bypass_mode; @@ -210,6 +217,9 @@ struct qdma_pci_dev { struct queue_info *q_info; uint8_t init_q_range; + /* Pointer to QDMA access layer function pointers */ + struct qdma_hw_access *hw_access; + struct qdma_vf_info *vfinfo; uint8_t vf_online_count; @@ -218,8 +228,9 @@ struct qdma_pci_dev { }; int qdma_identify_bars(struct rte_eth_dev *dev); +int qdma_get_hw_version(struct rte_eth_dev *dev); int qdma_check_kvargs(struct rte_devargs *devargs, struct qdma_pci_dev *qdma_dev); - +void qdma_check_errors(void *arg); #endif /* ifndef __QDMA_H__ */ diff --git a/drivers/net/qdma/qdma_common.c b/drivers/net/qdma/qdma_common.c index c0c5162f0f..0ea920f255 100644 --- a/drivers/net/qdma/qdma_common.c +++ b/drivers/net/qdma/qdma_common.c @@ -10,6 +10,7 @@ #include <rte_cycles.h> #include <rte_kvargs.h> #include "qdma.h" +#include "qdma_access_common.h" #include <fcntl.h> #include <unistd.h> @@ -199,7 +200,8 @@ int qdma_check_kvargs(struct rte_devargs *devargs, int qdma_identify_bars(struct rte_eth_dev *dev) { - int bar_len, i; + int bar_len, i, ret; + uint8_t usr_bar; struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); struct qdma_pci_dev *dma_priv; @@ -213,6 +215,24 @@ int qdma_identify_bars(struct rte_eth_dev *dev) return -1; } + /* Find AXI Master Lite(user bar) */ + ret = dma_priv->hw_access->qdma_get_user_bar(dev, + dma_priv->is_vf, dma_priv->func_id, &usr_bar); + if (ret != QDMA_SUCCESS || + pci_dev->mem_resource[usr_bar].len == 0) { + if (dma_priv->ip_type == QDMA_VERSAL_HARD_IP) { + if (pci_dev->mem_resource[1].len == 0) + dma_priv->user_bar_idx = 2; + else + dma_priv->user_bar_idx = 1; + } else { + dma_priv->user_bar_idx = -1; + PMD_DRV_LOG(INFO, "Cannot find AXI Master Lite BAR"); + } + } else { + dma_priv->user_bar_idx = usr_bar; + } + /* Find AXI Bridge Master bar(bypass bar) */ for (i = 0; i < QDMA_NUM_BARS; i++) { bar_len = pci_dev->mem_resource[i].len; @@ -234,3 +254,33 @@ int qdma_identify_bars(struct rte_eth_dev *dev) return 0; } +int qdma_get_hw_version(struct rte_eth_dev *dev) +{ + int ret; + struct qdma_pci_dev *dma_priv; + struct qdma_hw_version_info version_info; + + dma_priv = (struct qdma_pci_dev *)dev->data->dev_private; + ret = dma_priv->hw_access->qdma_get_version(dev, + dma_priv->is_vf, &version_info); + if (ret < 0) + return dma_priv->hw_access->qdma_get_error_code(ret); + + dma_priv->rtl_version = version_info.rtl_version; + dma_priv->vivado_rel = version_info.vivado_release; + dma_priv->device_type = version_info.device_type; + dma_priv->ip_type = version_info.ip_type; + + PMD_DRV_LOG(INFO, "QDMA RTL VERSION : %s\n", + version_info.qdma_rtl_version_str); + PMD_DRV_LOG(INFO, "QDMA DEVICE TYPE : %s\n", + version_info.qdma_device_type_str); + PMD_DRV_LOG(INFO, "QDMA VIVADO RELEASE ID : %s\n", + version_info.qdma_vivado_release_id_str); + if (version_info.ip_type == QDMA_VERSAL_HARD_IP) { + PMD_DRV_LOG(INFO, "QDMA VERSAL IP TYPE : %s\n", + version_info.qdma_ip_type_str); + } + + return 0; +} diff --git a/drivers/net/qdma/qdma_ethdev.c b/drivers/net/qdma/qdma_ethdev.c index c2ed6a52bb..bc902e607f 100644 --- a/drivers/net/qdma/qdma_ethdev.c +++ b/drivers/net/qdma/qdma_ethdev.c @@ -22,11 +22,27 @@ #include <rte_cycles.h> #include "qdma.h" +#include "qdma_version.h" +#include "qdma_access_common.h" +#include "qdma_access_export.h" +/* Poll for QDMA errors every 1 second */ +#define QDMA_ERROR_POLL_FRQ (1000000) #define PCI_CONFIG_BRIDGE_DEVICE (6) #define PCI_CONFIG_CLASS_CODE_SHIFT (16) #define MAX_PCIE_CAPABILITY (48) +static void qdma_device_attributes_get(struct rte_eth_dev *dev); + +/* Poll for any QDMA errors */ +void qdma_check_errors(void *arg) +{ + struct qdma_pci_dev *qdma_dev; + qdma_dev = ((struct rte_eth_dev *)arg)->data->dev_private; + qdma_dev->hw_access->qdma_hw_error_process(arg); + rte_eal_alarm_set(QDMA_ERROR_POLL_FRQ, qdma_check_errors, arg); +} + /* * The set of PCI devices this driver supports */ @@ -43,6 +59,92 @@ static struct rte_pci_id qdma_pci_id_tbl[] = { { .vendor_id = 0, /* sentinel */ }, }; +static void qdma_device_attributes_get(struct rte_eth_dev *dev) +{ + struct qdma_pci_dev *qdma_dev; + + qdma_dev = (struct qdma_pci_dev *)dev->data->dev_private; + qdma_dev->hw_access->qdma_get_device_attributes(dev, + &qdma_dev->dev_cap); + + /* Check DPDK configured queues per port */ + if (qdma_dev->dev_cap.num_qs > RTE_MAX_QUEUES_PER_PORT) + qdma_dev->dev_cap.num_qs = RTE_MAX_QUEUES_PER_PORT; + + PMD_DRV_LOG(INFO, "qmax = %d, mm %d, st %d.\n", + qdma_dev->dev_cap.num_qs, qdma_dev->dev_cap.mm_en, + qdma_dev->dev_cap.st_en); +} + +static inline uint8_t pcie_find_cap(const struct rte_pci_device *pci_dev, + uint8_t cap) +{ + uint8_t pcie_cap_pos = 0; + uint8_t pcie_cap_id = 0; + int ttl = MAX_PCIE_CAPABILITY; + int ret; + + ret = rte_pci_read_config(pci_dev, &pcie_cap_pos, sizeof(uint8_t), + PCI_CAPABILITY_LIST); + if (ret < 0) { + PMD_DRV_LOG(ERR, "PCIe config space read failed..\n"); + return 0; + } + + while (ttl-- && pcie_cap_pos >= PCI_STD_HEADER_SIZEOF) { + pcie_cap_pos &= ~3; + + ret = rte_pci_read_config(pci_dev, + &pcie_cap_id, sizeof(uint8_t), + (pcie_cap_pos + PCI_CAP_LIST_ID)); + if (ret < 0) { + PMD_DRV_LOG(ERR, "PCIe config space read failed..\n"); + return 0; + } + + if (pcie_cap_id == 0xff) + break; + + if (pcie_cap_id == cap) + return pcie_cap_pos; + + ret = rte_pci_read_config(pci_dev, + &pcie_cap_pos, sizeof(uint8_t), + (pcie_cap_pos + PCI_CAP_LIST_NEXT)); + if (ret < 0) { + PMD_DRV_LOG(ERR, "PCIe config space read failed..\n"); + return 0; + } + } + + return 0; +} + +static void pcie_perf_enable(const struct rte_pci_device *pci_dev) +{ + uint16_t value; + uint8_t pcie_cap_pos = pcie_find_cap(pci_dev, PCI_CAP_ID_EXP); + + if (!pcie_cap_pos) + return; + + if (pcie_cap_pos > 0) { + if (rte_pci_read_config(pci_dev, &value, sizeof(uint16_t), + pcie_cap_pos + PCI_EXP_DEVCTL) < 0) { + PMD_DRV_LOG(ERR, "PCIe config space read failed..\n"); + return; + } + + value |= (PCI_EXP_DEVCTL_EXT_TAG | PCI_EXP_DEVCTL_RELAX_EN); + + if (rte_pci_write_config(pci_dev, &value, sizeof(uint16_t), + pcie_cap_pos + PCI_EXP_DEVCTL) < 0) { + PMD_DRV_LOG(ERR, "PCIe config space write failed..\n"); + return; + } + } +} + /* parse a sysfs file containing one integer value */ static int parse_sysfs_value(const char *filename, uint32_t *val) { @@ -234,7 +336,7 @@ static int qdma_eth_dev_init(struct rte_eth_dev *dev) { struct qdma_pci_dev *dma_priv; uint8_t *baseaddr; - int i, idx, ret; + int i, idx, ret, qbase; struct rte_pci_device *pci_dev; uint16_t num_vfs; uint8_t max_pci_bus = 0; @@ -297,8 +399,30 @@ static int qdma_eth_dev_init(struct rte_eth_dev *dev) pci_dev->mem_resource[dma_priv->config_bar_idx].addr; dma_priv->bar_addr[dma_priv->config_bar_idx] = baseaddr; + /* Assigning QDMA access layer function pointers based on the HW design */ + dma_priv->hw_access = rte_zmalloc("hwaccess", + sizeof(struct qdma_hw_access), 0); + if (dma_priv->hw_access == NULL) { + rte_free(dev->data->mac_addrs); + return -ENOMEM; + } + idx = qdma_hw_access_init(dev, dma_priv->is_vf, dma_priv->hw_access); + if (idx < 0) { + rte_free(dma_priv->hw_access); + rte_free(dev->data->mac_addrs); + return -EINVAL; + } + + idx = qdma_get_hw_version(dev); + if (idx < 0) { + rte_free(dma_priv->hw_access); + rte_free(dev->data->mac_addrs); + return -EINVAL; + } + idx = qdma_identify_bars(dev); if (idx < 0) { + rte_free(dma_priv->hw_access); rte_free(dev->data->mac_addrs); return -EINVAL; } @@ -312,14 +436,99 @@ static int qdma_eth_dev_init(struct rte_eth_dev *dev) PMD_DRV_LOG(INFO, "QDMA device driver probe:"); + /* Getting the device attributes from the Hardware */ + qdma_device_attributes_get(dev); + + /* Create master resource node for queue management on the given + * bus number. Node will be created only once per bus number. + */ + qbase = DEFAULT_QUEUE_BASE; + ret = get_max_pci_bus_num(pci_dev->addr.bus, &max_pci_bus); - if (ret != 0 && !max_pci_bus) { + if (ret != QDMA_SUCCESS && !max_pci_bus) { PMD_DRV_LOG(ERR, "Failed to get max pci bus number\n"); + rte_free(dma_priv->hw_access); rte_free(dev->data->mac_addrs); return -EINVAL; } PMD_DRV_LOG(INFO, "PCI max bus number : 0x%x", max_pci_bus); + ret = qdma_master_resource_create(pci_dev->addr.bus, max_pci_bus, + qbase, dma_priv->dev_cap.num_qs, + &dma_priv->dma_device_index); + if (ret == -QDMA_ERR_NO_MEM) { + rte_free(dma_priv->hw_access); + rte_free(dev->data->mac_addrs); + return -ENOMEM; + } + + dma_priv->hw_access->qdma_get_function_number(dev, + &dma_priv->func_id); + PMD_DRV_LOG(INFO, "PF function ID: %d", dma_priv->func_id); + + /* CSR programming is done once per given board or bus number, + * done by the master PF + */ + if (ret == QDMA_SUCCESS) { + RTE_LOG(INFO, PMD, "QDMA PMD VERSION: %s\n", QDMA_PMD_VERSION); + dma_priv->hw_access->qdma_set_default_global_csr(dev); + for (i = 0; i < dma_priv->dev_cap.mm_channel_max; i++) { + if (dma_priv->dev_cap.mm_en) { + /* Enable MM C2H Channel */ + dma_priv->hw_access->qdma_mm_channel_conf(dev, + i, 1, 1); + /* Enable MM H2C Channel */ + dma_priv->hw_access->qdma_mm_channel_conf(dev, + i, 0, 1); + } else { + /* Disable MM C2H Channel */ + dma_priv->hw_access->qdma_mm_channel_conf(dev, + i, 1, 0); + /* Disable MM H2C Channel */ + dma_priv->hw_access->qdma_mm_channel_conf(dev, + i, 0, 0); + } + } + + ret = dma_priv->hw_access->qdma_init_ctxt_memory(dev); + if (ret < 0) { + PMD_DRV_LOG(ERR, + "%s: Failed to initialize ctxt memory, err = %d\n", + __func__, ret); + return -EINVAL; + } + + dma_priv->hw_access->qdma_hw_error_enable(dev, + dma_priv->hw_access->qdma_max_errors); + if (ret < 0) { + PMD_DRV_LOG(ERR, + "%s: Failed to enable hw errors, err = %d\n", + __func__, ret); + return -EINVAL; + } + + rte_eal_alarm_set(QDMA_ERROR_POLL_FRQ, qdma_check_errors, + (void *)dev); + dma_priv->is_master = 1; + } + + /* + * Create an entry for the device in board list if not already + * created + */ + ret = qdma_dev_entry_create(dma_priv->dma_device_index, + dma_priv->func_id); + if (ret != QDMA_SUCCESS && + ret != -QDMA_ERR_RM_DEV_EXISTS) { + PMD_DRV_LOG(ERR, "PF-%d(DEVFN) qdma_dev_entry_create failed: %d\n", + dma_priv->func_id, ret); + rte_free(dma_priv->hw_access); + rte_free(dev->data->mac_addrs); + return -ENOMEM; + } + + pcie_perf_enable(pci_dev); + if (!dma_priv->reset_in_progress) { num_vfs = pci_dev->max_vfs; if (num_vfs) { @@ -358,6 +567,14 @@ static int qdma_eth_dev_uninit(struct rte_eth_dev *dev) /* only uninitialize in the primary process */ if (rte_eal_process_type() != RTE_PROC_PRIMARY) return -EPERM; + /* cancel pending polls */ + if (qdma_dev->is_master) + rte_eal_alarm_cancel(qdma_check_errors, (void *)dev); + + /* Remove the device node from the board list */ + qdma_dev_entry_destroy(qdma_dev->dma_device_index, + qdma_dev->func_id); + qdma_master_resource_destroy(qdma_dev->dma_device_index); dev->dev_ops = NULL; dev->rx_pkt_burst = NULL; @@ -381,6 +598,10 @@ static int qdma_eth_dev_uninit(struct rte_eth_dev *dev) qdma_dev->q_info = NULL; } + if (qdma_dev->hw_access != NULL) { + rte_free(qdma_dev->hw_access); + qdma_dev->hw_access = NULL; + } return 0; } -- 2.36.1