+ type = BNXT_FW_STATUS_REG_TYPE(reg);
+ offset = BNXT_FW_STATUS_REG_OFF(reg);
+
+ switch (type) {
+ case BNXT_FW_STATUS_REG_TYPE_CFG:
+ rte_pci_read_config(bp->pdev, &val, sizeof(val), offset);
+ break;
+ case BNXT_FW_STATUS_REG_TYPE_GRC:
+ offset = info->mapped_status_regs[index];
+ /* FALLTHROUGH */
+ case BNXT_FW_STATUS_REG_TYPE_BAR0:
+ val = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 +
+ offset));
+ break;
+ }
+
+ return val;
+}
+
+static int bnxt_fw_reset_all(struct bnxt *bp)
+{
+ struct bnxt_error_recovery_info *info = bp->recovery_info;
+ uint32_t i;
+ int rc = 0;
+
+ if (info->flags & BNXT_FLAG_ERROR_RECOVERY_HOST) {
+ /* Reset through master function driver */
+ for (i = 0; i < info->reg_array_cnt; i++)
+ bnxt_write_fw_reset_reg(bp, i);
+ /* Wait for time specified by FW after triggering reset */
+ rte_delay_ms(info->master_func_wait_period_after_reset);
+ } else if (info->flags & BNXT_FLAG_ERROR_RECOVERY_CO_CPU) {
+ /* Reset with the help of Kong processor */
+ rc = bnxt_hwrm_fw_reset(bp);
+ if (rc)
+ PMD_DRV_LOG(ERR, "Failed to reset FW\n");
+ }
+
+ return rc;
+}
+
+static void bnxt_fw_reset_cb(void *arg)
+{
+ struct bnxt *bp = arg;
+ struct bnxt_error_recovery_info *info = bp->recovery_info;
+ int rc = 0;
+
+ /* Only Master function can do FW reset */
+ if (bnxt_is_master_func(bp) &&
+ bnxt_is_recovery_enabled(bp)) {
+ rc = bnxt_fw_reset_all(bp);
+ if (rc) {
+ PMD_DRV_LOG(ERR, "Adapter recovery failed\n");
+ return;
+ }
+ }
+
+ /* if recovery method is ERROR_RECOVERY_CO_CPU, KONG will send
+ * EXCEPTION_FATAL_ASYNC event to all the functions
+ * (including MASTER FUNC). After receiving this Async, all the active
+ * drivers should treat this case as FW initiated recovery
+ */
+ if (info->flags & BNXT_FLAG_ERROR_RECOVERY_HOST) {
+ bp->fw_reset_min_msecs = BNXT_MIN_FW_READY_TIMEOUT;
+ bp->fw_reset_max_msecs = BNXT_MAX_FW_RESET_TIMEOUT;
+
+ /* To recover from error */
+ rte_eal_alarm_set(US_PER_MS, bnxt_dev_reset_and_resume,
+ (void *)bp);
+ }
+}
+
+/* Driver should poll FW heartbeat, reset_counter with the frequency
+ * advertised by FW in HWRM_ERROR_RECOVERY_QCFG.
+ * When the driver detects heartbeat stop or change in reset_counter,
+ * it has to trigger a reset to recover from the error condition.
+ * A “master PF” is the function who will have the privilege to
+ * initiate the chimp reset. The master PF will be elected by the
+ * firmware and will be notified through async message.
+ */
+static void bnxt_check_fw_health(void *arg)
+{
+ struct bnxt *bp = arg;
+ struct bnxt_error_recovery_info *info = bp->recovery_info;
+ uint32_t val = 0, wait_msec;
+
+ if (!info || !bnxt_is_recovery_enabled(bp) ||
+ is_bnxt_in_error(bp))
+ return;
+
+ val = bnxt_read_fw_status_reg(bp, BNXT_FW_HEARTBEAT_CNT_REG);
+ if (val == info->last_heart_beat)
+ goto reset;
+
+ info->last_heart_beat = val;
+
+ val = bnxt_read_fw_status_reg(bp, BNXT_FW_RECOVERY_CNT_REG);
+ if (val != info->last_reset_counter)
+ goto reset;
+
+ info->last_reset_counter = val;
+
+ rte_eal_alarm_set(US_PER_MS * info->driver_polling_freq,
+ bnxt_check_fw_health, (void *)bp);
+
+ return;
+reset:
+ /* Stop DMA to/from device */
+ bp->flags |= BNXT_FLAG_FATAL_ERROR;
+ bp->flags |= BNXT_FLAG_FW_RESET;
+
+ PMD_DRV_LOG(ERR, "Detected FW dead condition\n");
+
+ if (bnxt_is_master_func(bp))
+ wait_msec = info->master_func_wait_period;
+ else
+ wait_msec = info->normal_func_wait_period;
+
+ rte_eal_alarm_set(US_PER_MS * wait_msec,
+ bnxt_fw_reset_cb, (void *)bp);
+}
+
+void bnxt_schedule_fw_health_check(struct bnxt *bp)
+{
+ uint32_t polling_freq;
+
+ if (!bnxt_is_recovery_enabled(bp))
+ return;
+
+ if (bp->flags & BNXT_FLAG_FW_HEALTH_CHECK_SCHEDULED)
+ return;
+
+ polling_freq = bp->recovery_info->driver_polling_freq;
+
+ rte_eal_alarm_set(US_PER_MS * polling_freq,
+ bnxt_check_fw_health, (void *)bp);
+ bp->flags |= BNXT_FLAG_FW_HEALTH_CHECK_SCHEDULED;
+}
+
+static void bnxt_cancel_fw_health_check(struct bnxt *bp)
+{
+ if (!bnxt_is_recovery_enabled(bp))
+ return;
+
+ rte_eal_alarm_cancel(bnxt_check_fw_health, (void *)bp);
+ bp->flags &= ~BNXT_FLAG_FW_HEALTH_CHECK_SCHEDULED;
+}
+
+static bool bnxt_vf_pciid(uint16_t id)
+{
+ if (id == BROADCOM_DEV_ID_57304_VF ||
+ id == BROADCOM_DEV_ID_57406_VF ||
+ id == BROADCOM_DEV_ID_5731X_VF ||
+ id == BROADCOM_DEV_ID_5741X_VF ||
+ id == BROADCOM_DEV_ID_57414_VF ||
+ id == BROADCOM_DEV_ID_STRATUS_NIC_VF1 ||
+ id == BROADCOM_DEV_ID_STRATUS_NIC_VF2 ||
+ id == BROADCOM_DEV_ID_58802_VF ||
+ id == BROADCOM_DEV_ID_57500_VF1 ||
+ id == BROADCOM_DEV_ID_57500_VF2)
+ return true;
+ return false;
+}
+
+static bool bnxt_thor_device(uint16_t id)
+{
+ if (id == BROADCOM_DEV_ID_57508 ||
+ id == BROADCOM_DEV_ID_57504 ||
+ id == BROADCOM_DEV_ID_57502 ||
+ id == BROADCOM_DEV_ID_57508_MF1 ||
+ id == BROADCOM_DEV_ID_57504_MF1 ||
+ id == BROADCOM_DEV_ID_57502_MF1 ||
+ id == BROADCOM_DEV_ID_57508_MF2 ||
+ id == BROADCOM_DEV_ID_57504_MF2 ||
+ id == BROADCOM_DEV_ID_57502_MF2 ||
+ id == BROADCOM_DEV_ID_57500_VF1 ||
+ id == BROADCOM_DEV_ID_57500_VF2)
+ return true;
+
+ return false;
+}
+
+bool bnxt_stratus_device(struct bnxt *bp)
+{
+ uint16_t id = bp->pdev->id.device_id;
+
+ if (id == BROADCOM_DEV_ID_STRATUS_NIC ||
+ id == BROADCOM_DEV_ID_STRATUS_NIC_VF1 ||
+ id == BROADCOM_DEV_ID_STRATUS_NIC_VF2)
+ return true;
+ return false;
+}
+
+static int bnxt_init_board(struct rte_eth_dev *eth_dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct bnxt *bp = eth_dev->data->dev_private;
+
+ /* enable device (incl. PCI PM wakeup), and bus-mastering */
+ bp->bar0 = (void *)pci_dev->mem_resource[0].addr;
+ bp->doorbell_base = (void *)pci_dev->mem_resource[2].addr;
+ if (!bp->bar0 || !bp->doorbell_base) {
+ PMD_DRV_LOG(ERR, "Unable to access Hardware\n");
+ return -ENODEV;
+ }
+
+ bp->eth_dev = eth_dev;
+ bp->pdev = pci_dev;
+
+ return 0;
+}
+
+static int bnxt_alloc_ctx_mem_blk(__rte_unused struct bnxt *bp,
+ struct bnxt_ctx_pg_info *ctx_pg,
+ uint32_t mem_size,
+ const char *suffix,
+ uint16_t idx)
+{
+ struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem;
+ const struct rte_memzone *mz = NULL;
+ char mz_name[RTE_MEMZONE_NAMESIZE];
+ rte_iova_t mz_phys_addr;
+ uint64_t valid_bits = 0;
+ uint32_t sz;
+ int i;
+
+ if (!mem_size)
+ return 0;
+
+ rmem->nr_pages = RTE_ALIGN_MUL_CEIL(mem_size, BNXT_PAGE_SIZE) /
+ BNXT_PAGE_SIZE;
+ rmem->page_size = BNXT_PAGE_SIZE;
+ rmem->pg_arr = ctx_pg->ctx_pg_arr;
+ rmem->dma_arr = ctx_pg->ctx_dma_arr;
+ rmem->flags = BNXT_RMEM_VALID_PTE_FLAG;
+
+ valid_bits = PTU_PTE_VALID;
+
+ if (rmem->nr_pages > 1) {
+ snprintf(mz_name, RTE_MEMZONE_NAMESIZE,
+ "bnxt_ctx_pg_tbl%s_%x_%d",
+ suffix, idx, bp->eth_dev->data->port_id);
+ mz_name[RTE_MEMZONE_NAMESIZE - 1] = 0;
+ mz = rte_memzone_lookup(mz_name);
+ if (!mz) {
+ mz = rte_memzone_reserve_aligned(mz_name,
+ rmem->nr_pages * 8,
+ SOCKET_ID_ANY,
+ RTE_MEMZONE_2MB |
+ RTE_MEMZONE_SIZE_HINT_ONLY |
+ RTE_MEMZONE_IOVA_CONTIG,
+ BNXT_PAGE_SIZE);
+ if (mz == NULL)
+ return -ENOMEM;
+ }
+
+ memset(mz->addr, 0, mz->len);
+ mz_phys_addr = mz->iova;
+ if ((unsigned long)mz->addr == mz_phys_addr) {
+ PMD_DRV_LOG(DEBUG,
+ "physical address same as virtual\n");
+ PMD_DRV_LOG(DEBUG, "Using rte_mem_virt2iova()\n");
+ mz_phys_addr = rte_mem_virt2iova(mz->addr);
+ if (mz_phys_addr == RTE_BAD_IOVA) {
+ PMD_DRV_LOG(ERR,
+ "unable to map addr to phys memory\n");
+ return -ENOMEM;
+ }
+ }
+ rte_mem_lock_page(((char *)mz->addr));
+
+ rmem->pg_tbl = mz->addr;
+ rmem->pg_tbl_map = mz_phys_addr;
+ rmem->pg_tbl_mz = mz;
+ }
+
+ snprintf(mz_name, RTE_MEMZONE_NAMESIZE, "bnxt_ctx_%s_%x_%d",
+ suffix, idx, bp->eth_dev->data->port_id);
+ mz = rte_memzone_lookup(mz_name);
+ if (!mz) {
+ mz = rte_memzone_reserve_aligned(mz_name,
+ mem_size,
+ SOCKET_ID_ANY,
+ RTE_MEMZONE_1GB |
+ RTE_MEMZONE_SIZE_HINT_ONLY |
+ RTE_MEMZONE_IOVA_CONTIG,
+ BNXT_PAGE_SIZE);
+ if (mz == NULL)
+ return -ENOMEM;
+ }
+
+ memset(mz->addr, 0, mz->len);
+ mz_phys_addr = mz->iova;
+ if ((unsigned long)mz->addr == mz_phys_addr) {
+ PMD_DRV_LOG(DEBUG,
+ "Memzone physical address same as virtual.\n");
+ PMD_DRV_LOG(DEBUG, "Using rte_mem_virt2iova()\n");
+ for (sz = 0; sz < mem_size; sz += BNXT_PAGE_SIZE)
+ rte_mem_lock_page(((char *)mz->addr) + sz);
+ mz_phys_addr = rte_mem_virt2iova(mz->addr);
+ if (mz_phys_addr == RTE_BAD_IOVA) {
+ PMD_DRV_LOG(ERR,
+ "unable to map addr to phys memory\n");
+ return -ENOMEM;
+ }
+ }
+
+ for (sz = 0, i = 0; sz < mem_size; sz += BNXT_PAGE_SIZE, i++) {
+ rte_mem_lock_page(((char *)mz->addr) + sz);
+ rmem->pg_arr[i] = ((char *)mz->addr) + sz;
+ rmem->dma_arr[i] = mz_phys_addr + sz;
+
+ if (rmem->nr_pages > 1) {
+ if (i == rmem->nr_pages - 2 &&
+ (rmem->flags & BNXT_RMEM_RING_PTE_FLAG))
+ valid_bits |= PTU_PTE_NEXT_TO_LAST;
+ else if (i == rmem->nr_pages - 1 &&
+ (rmem->flags & BNXT_RMEM_RING_PTE_FLAG))
+ valid_bits |= PTU_PTE_LAST;
+
+ rmem->pg_tbl[i] = rte_cpu_to_le_64(rmem->dma_arr[i] |
+ valid_bits);
+ }
+ }
+
+ rmem->mz = mz;
+ if (rmem->vmem_size)
+ rmem->vmem = (void **)mz->addr;
+ rmem->dma_arr[0] = mz_phys_addr;
+ return 0;
+}
+
+static void bnxt_free_ctx_mem(struct bnxt *bp)
+{
+ int i;
+
+ if (!bp->ctx || !(bp->ctx->flags & BNXT_CTX_FLAG_INITED))
+ return;
+
+ bp->ctx->flags &= ~BNXT_CTX_FLAG_INITED;
+ rte_memzone_free(bp->ctx->qp_mem.ring_mem.mz);
+ rte_memzone_free(bp->ctx->srq_mem.ring_mem.mz);
+ rte_memzone_free(bp->ctx->cq_mem.ring_mem.mz);
+ rte_memzone_free(bp->ctx->vnic_mem.ring_mem.mz);
+ rte_memzone_free(bp->ctx->stat_mem.ring_mem.mz);
+ rte_memzone_free(bp->ctx->qp_mem.ring_mem.pg_tbl_mz);
+ rte_memzone_free(bp->ctx->srq_mem.ring_mem.pg_tbl_mz);
+ rte_memzone_free(bp->ctx->cq_mem.ring_mem.pg_tbl_mz);
+ rte_memzone_free(bp->ctx->vnic_mem.ring_mem.pg_tbl_mz);
+ rte_memzone_free(bp->ctx->stat_mem.ring_mem.pg_tbl_mz);
+
+ for (i = 0; i < BNXT_MAX_Q; i++) {
+ if (bp->ctx->tqm_mem[i])
+ rte_memzone_free(bp->ctx->tqm_mem[i]->ring_mem.mz);
+ }
+
+ rte_free(bp->ctx);
+ bp->ctx = NULL;
+}
+
+#define bnxt_roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+
+#define min_t(type, x, y) ({ \
+ type __min1 = (x); \
+ type __min2 = (y); \
+ __min1 < __min2 ? __min1 : __min2; })
+
+#define max_t(type, x, y) ({ \
+ type __max1 = (x); \
+ type __max2 = (y); \
+ __max1 > __max2 ? __max1 : __max2; })
+
+#define clamp_t(type, _x, min, max) min_t(type, max_t(type, _x, min), max)
+
+int bnxt_alloc_ctx_mem(struct bnxt *bp)
+{
+ struct bnxt_ctx_pg_info *ctx_pg;
+ struct bnxt_ctx_mem_info *ctx;
+ uint32_t mem_size, ena, entries;
+ int i, rc;
+
+ rc = bnxt_hwrm_func_backing_store_qcaps(bp);