X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fqede%2Fbase%2Fecore_dev.c;h=6060f9eee865a9f93cad453579d3831d1eda22b5;hb=73db5badb042c2ba668cdc096168932c5d5e692d;hp=9e32279f496f48478b54c296c8365369bfe03512;hpb=3cbc0bd272c3ffbe691b4a4296ae4d2ffa18088a;p=dpdk.git diff --git a/drivers/net/qede/base/ecore_dev.c b/drivers/net/qede/base/ecore_dev.c index 9e32279f49..6060f9eee8 100644 --- a/drivers/net/qede/base/ecore_dev.c +++ b/drivers/net/qede/base/ecore_dev.c @@ -29,11 +29,20 @@ #include "ecore_iro.h" #include "nvm_cfg.h" #include "ecore_dev_api.h" -#include "ecore_attn_values.h" #include "ecore_dcbx.h" +/* TODO - there's a bug in DCBx re-configuration flows in MF, as the QM + * registers involved are not split and thus configuration is a race where + * some of the PFs configuration might be lost. + * Eventually, this needs to move into a MFW-covered HW-lock as arbitration + * mechanism as this doesn't cover some cases [E.g., PDA or scenarios where + * there's more than a single compiled ecore component in system]. + */ +static osal_spinlock_t qm_lock; +static bool qm_lock_init; + /* Configurable */ -#define ECORE_MIN_DPIS (4) /* The minimal number of DPIs required +#define ECORE_MIN_DPIS (4) /* The minimal num of DPIs required to * load the driver. The number was * arbitrarily set. */ @@ -50,7 +59,17 @@ static u32 ecore_hw_bar_size(struct ecore_hwfn *p_hwfn, enum BAR_ID bar_id) { u32 bar_reg = (bar_id == BAR_ID_0 ? PGLUE_B_REG_PF_BAR0_SIZE : PGLUE_B_REG_PF_BAR1_SIZE); - u32 val = ecore_rd(p_hwfn, p_hwfn->p_main_ptt, bar_reg); + u32 val; + + if (IS_VF(p_hwfn->p_dev)) { + /* TODO - assume each VF hwfn has 64Kb for Bar0; Bar1 can be + * read from actual register, but we're currently not using + * it for actual doorbelling. + */ + return 1 << 17; + } + + val = ecore_rd(p_hwfn, p_hwfn->p_main_ptt, bar_reg); /* The above registers were updated in the past only in CMT mode. Since * they were found to be useful MFW started updating them from 8.7.7.0. @@ -59,16 +78,18 @@ static u32 ecore_hw_bar_size(struct ecore_hwfn *p_hwfn, enum BAR_ID bar_id) if (!val) { if (p_hwfn->p_dev->num_hwfns > 1) { DP_NOTICE(p_hwfn, false, - "BAR size not configured. Assuming BAR" - " size of 256kB for GRC and 512kB for DB\n"); + "BAR size not configured. Assuming BAR size"); + DP_NOTICE(p_hwfn, false, + "of 256kB for GRC and 512kB for DB\n"); return BAR_ID_0 ? 256 * 1024 : 512 * 1024; - } - + } else { DP_NOTICE(p_hwfn, false, - "BAR size not configured. Assuming BAR" - " size of 512kB for GRC and 512kB for DB\n"); + "BAR size not configured. Assuming BAR size"); + DP_NOTICE(p_hwfn, false, + "of 512kB for GRC and 512kB for DB\n"); return 512 * 1024; } + } return 1 << (val + 15); } @@ -156,6 +177,9 @@ void ecore_resc_free(struct ecore_dev *p_dev) ecore_eq_free(p_hwfn, p_hwfn->p_eq); ecore_consq_free(p_hwfn, p_hwfn->p_consq); ecore_int_free(p_hwfn); +#ifdef CONFIG_ECORE_LL2 + ecore_ll2_free(p_hwfn, p_hwfn->p_ll2_info); +#endif ecore_iov_free(p_hwfn); ecore_dmae_info_free(p_hwfn); ecore_dcbx_info_free(p_hwfn, p_hwfn->p_dcbx_info); @@ -166,16 +190,28 @@ void ecore_resc_free(struct ecore_dev *p_dev) static enum _ecore_status_t ecore_init_qm_info(struct ecore_hwfn *p_hwfn, bool b_sleepable) { - u8 num_vports, vf_offset = 0, i, vport_id, num_ports; + u8 num_vports, vf_offset = 0, i, vport_id, num_ports, curr_queue; struct ecore_qm_info *qm_info = &p_hwfn->qm_info; struct init_qm_port_params *p_qm_port; - u16 num_pqs, multi_cos_tcs = 1; -#ifdef CONFIG_ECORE_SRIOV - u16 num_vfs = p_hwfn->p_dev->sriov_info.total_vfs; -#else + bool init_rdma_offload_pq = false; + bool init_pure_ack_pq = false; + bool init_ooo_pq = false; + u16 num_pqs, protocol_pqs; + u16 num_pf_rls = 0; u16 num_vfs = 0; -#endif + u32 pf_rl; + u8 pf_wfq; + + /* @TMP - saving the existing min/max bw config before resetting the + * qm_info to restore them. + */ + pf_rl = qm_info->pf_rl; + pf_wfq = qm_info->pf_wfq; +#ifdef CONFIG_ECORE_SRIOV + if (p_hwfn->p_dev->p_iov_info) + num_vfs = p_hwfn->p_dev->p_iov_info->total_vfs; +#endif OSAL_MEM_ZERO(qm_info, sizeof(*qm_info)); #ifndef ASIC_ONLY @@ -187,20 +223,74 @@ static enum _ecore_status_t ecore_init_qm_info(struct ecore_hwfn *p_hwfn, } #endif - num_pqs = multi_cos_tcs + num_vfs + 1; /* The '1' is for pure-LB */ + /* ethernet PFs require a pq per tc. Even if only a subset of the TCs + * active, we want physical queues allocated for all of them, since we + * don't have a good recycle flow. Non ethernet PFs require only a + * single physical queue. + */ + if (p_hwfn->hw_info.personality == ECORE_PCI_ETH_ROCE || + p_hwfn->hw_info.personality == ECORE_PCI_IWARP || + p_hwfn->hw_info.personality == ECORE_PCI_ETH) + protocol_pqs = p_hwfn->hw_info.num_hw_tc; + else + protocol_pqs = 1; + + num_pqs = protocol_pqs + num_vfs + 1; /* The '1' is for pure-LB */ num_vports = (u8)RESC_NUM(p_hwfn, ECORE_VPORT); + if (p_hwfn->hw_info.personality == ECORE_PCI_ETH_ROCE) { + num_pqs++; /* for RoCE queue */ + init_rdma_offload_pq = true; + if (p_hwfn->pf_params.rdma_pf_params.enable_dcqcn) { + /* Due to FW assumption that rl==vport, we limit the + * number of rate limiters by the minimum between its + * allocated number and the allocated number of vports. + * Another limitation is the number of supported qps + * with rate limiters in FW. + */ + num_pf_rls = + (u16)OSAL_MIN_T(u32, RESC_NUM(p_hwfn, ECORE_RL), + RESC_NUM(p_hwfn, ECORE_VPORT)); + + /* we subtract num_vfs because each one requires a rate + * limiter, and one default rate limiter. + */ + if (num_pf_rls < num_vfs + 1) { + DP_ERR(p_hwfn, "No RL for DCQCN"); + DP_ERR(p_hwfn, "[num_pf_rls %d num_vfs %d]\n", + num_pf_rls, num_vfs); + return ECORE_INVAL; + } + num_pf_rls -= num_vfs + 1; + } + + num_pqs += num_pf_rls; + qm_info->num_pf_rls = (u8)num_pf_rls; + } + + if (p_hwfn->hw_info.personality == ECORE_PCI_IWARP) { + num_pqs += 3; /* for iwarp queue / pure-ack / ooo */ + init_rdma_offload_pq = true; + init_pure_ack_pq = true; + init_ooo_pq = true; + } + + if (p_hwfn->hw_info.personality == ECORE_PCI_ISCSI) { + num_pqs += 2; /* for iSCSI pure-ACK / OOO queue */ + init_pure_ack_pq = true; + init_ooo_pq = true; + } + /* Sanity checking that setup requires legal number of resources */ if (num_pqs > RESC_NUM(p_hwfn, ECORE_PQ)) { DP_ERR(p_hwfn, - "Need too many Physical queues - 0x%04x when" - " only %04x are available\n", + "Need too many Physical queues - 0x%04x avail %04x", num_pqs, RESC_NUM(p_hwfn, ECORE_PQ)); return ECORE_INVAL; } /* PQs will be arranged as follows: First per-TC PQ, then pure-LB queue, - * then special queues, then per-VF PQ. + * then special queues (iSCSI pure-ACK / RoCE), then per-VF PQ. */ qm_info->qm_pq_params = OSAL_ZALLOC(p_hwfn->p_dev, b_sleepable ? GFP_KERNEL : @@ -238,13 +328,40 @@ static enum _ecore_status_t ecore_init_qm_info(struct ecore_hwfn *p_hwfn, vport_id = (u8)RESC_START(p_hwfn, ECORE_VPORT); - /* First init per-TC PQs */ - for (i = 0; i < multi_cos_tcs; i++) { - struct init_qm_pq_params *params = &qm_info->qm_pq_params[i]; + /* First init rate limited queues ( Due to RoCE assumption of + * qpid=rlid ) + */ + for (curr_queue = 0; curr_queue < num_pf_rls; curr_queue++) { + qm_info->qm_pq_params[curr_queue].vport_id = vport_id++; + qm_info->qm_pq_params[curr_queue].tc_id = + p_hwfn->hw_info.offload_tc; + qm_info->qm_pq_params[curr_queue].wrr_group = 1; + qm_info->qm_pq_params[curr_queue].rl_valid = 1; + }; + + /* Protocol PQs */ + for (i = 0; i < protocol_pqs; i++) { + struct init_qm_pq_params *params = + &qm_info->qm_pq_params[curr_queue++]; - if (p_hwfn->hw_info.personality == ECORE_PCI_ETH) { + if (p_hwfn->hw_info.personality == ECORE_PCI_ETH_ROCE || + p_hwfn->hw_info.personality == ECORE_PCI_IWARP || + p_hwfn->hw_info.personality == ECORE_PCI_ETH) { params->vport_id = vport_id; - params->tc_id = p_hwfn->hw_info.non_offload_tc; + params->tc_id = i; + /* Note: this assumes that if we had a configuration + * with N tcs and subsequently another configuration + * With Fewer TCs, the in flight traffic (in QM queues, + * in FW, from driver to FW) will still trickle out and + * not get "stuck" in the QM. This is determined by the + * NIG_REG_TX_ARB_CLIENT_IS_SUBJECT2WFQ. Unused TCs are + * supposed to be cleared in this map, allowing traffic + * to flush out. If this is not the case, we would need + * to set the TC of unused queues to 0, and reconfigure + * QM every time num of TCs changes. Unused queues in + * this context would mean those intended for TCs where + * tc_id > hw_info.num_active_tcs. + */ params->wrr_group = 1; /* @@@TBD ECORE_WRR_MEDIUM */ } else { params->vport_id = vport_id; @@ -254,22 +371,50 @@ static enum _ecore_status_t ecore_init_qm_info(struct ecore_hwfn *p_hwfn, } /* Then init pure-LB PQ */ - qm_info->pure_lb_pq = i; - qm_info->qm_pq_params[i].vport_id = + qm_info->pure_lb_pq = curr_queue; + qm_info->qm_pq_params[curr_queue].vport_id = (u8)RESC_START(p_hwfn, ECORE_VPORT); - qm_info->qm_pq_params[i].tc_id = PURE_LB_TC; - qm_info->qm_pq_params[i].wrr_group = 1; - i++; + qm_info->qm_pq_params[curr_queue].tc_id = PURE_LB_TC; + qm_info->qm_pq_params[curr_queue].wrr_group = 1; + curr_queue++; + + qm_info->offload_pq = 0; /* Already initialized for iSCSI/FCoE */ + if (init_rdma_offload_pq) { + qm_info->offload_pq = curr_queue; + qm_info->qm_pq_params[curr_queue].vport_id = vport_id; + qm_info->qm_pq_params[curr_queue].tc_id = + p_hwfn->hw_info.offload_tc; + qm_info->qm_pq_params[curr_queue].wrr_group = 1; + curr_queue++; + } + + if (init_pure_ack_pq) { + qm_info->pure_ack_pq = curr_queue; + qm_info->qm_pq_params[curr_queue].vport_id = vport_id; + qm_info->qm_pq_params[curr_queue].tc_id = + p_hwfn->hw_info.offload_tc; + qm_info->qm_pq_params[curr_queue].wrr_group = 1; + curr_queue++; + } + + if (init_ooo_pq) { + qm_info->ooo_pq = curr_queue; + qm_info->qm_pq_params[curr_queue].vport_id = vport_id; + qm_info->qm_pq_params[curr_queue].tc_id = DCBX_ISCSI_OOO_TC; + qm_info->qm_pq_params[curr_queue].wrr_group = 1; + curr_queue++; + } /* Then init per-VF PQs */ - vf_offset = i; + vf_offset = curr_queue; for (i = 0; i < num_vfs; i++) { /* First vport is used by the PF */ - qm_info->qm_pq_params[vf_offset + i].vport_id = vport_id + - i + 1; - qm_info->qm_pq_params[vf_offset + i].tc_id = - p_hwfn->hw_info.non_offload_tc; - qm_info->qm_pq_params[vf_offset + i].wrr_group = 1; + qm_info->qm_pq_params[curr_queue].vport_id = vport_id + i + 1; + /* @@@TBD VF Multi-cos */ + qm_info->qm_pq_params[curr_queue].tc_id = 0; + qm_info->qm_pq_params[curr_queue].wrr_group = 1; + qm_info->qm_pq_params[curr_queue].rl_valid = 1; + curr_queue++; }; qm_info->vf_queues_offset = vf_offset; @@ -281,6 +426,13 @@ static enum _ecore_status_t ecore_init_qm_info(struct ecore_hwfn *p_hwfn, for (i = 0; i < num_ports; i++) { p_qm_port = &qm_info->qm_port_params[i]; p_qm_port->active = 1; + /* @@@TMP - was NUM_OF_PHYS_TCS; Changed until dcbx will + * be in place + */ + if (num_ports == 4) + p_qm_port->active_phys_tcs = 0xf; + else + p_qm_port->active_phys_tcs = 0x9f; p_qm_port->num_pbf_cmd_lines = PBF_MAX_CMD_LINES / num_ports; p_qm_port->num_btb_blocks = BTB_MAX_BLOCKS / num_ports; } @@ -298,10 +450,10 @@ static enum _ecore_status_t ecore_init_qm_info(struct ecore_hwfn *p_hwfn, for (i = 0; i < qm_info->num_vports; i++) qm_info->qm_vport_params[i].vport_wfq = 1; - qm_info->pf_wfq = 0; - qm_info->pf_rl = 0; qm_info->vport_rl_en = 1; qm_info->vport_wfq_en = 1; + qm_info->pf_rl = pf_rl; + qm_info->pf_wfq = pf_wfq; return ECORE_SUCCESS; @@ -323,8 +475,8 @@ enum _ecore_status_t ecore_qm_reconf(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) { struct ecore_qm_info *qm_info = &p_hwfn->qm_info; - enum _ecore_status_t rc; bool b_rc; + enum _ecore_status_t rc; /* qm_info is allocated in ecore_init_qm_info() which is already called * from ecore_resc_alloc() or previous call of ecore_qm_reconf(). @@ -339,8 +491,10 @@ enum _ecore_status_t ecore_qm_reconf(struct ecore_hwfn *p_hwfn, return rc; /* stop PF's qm queues */ + OSAL_SPIN_LOCK(&qm_lock); b_rc = ecore_send_qm_stop_cmd(p_hwfn, p_ptt, false, true, qm_info->start_pq, qm_info->num_pqs); + OSAL_SPIN_UNLOCK(&qm_lock); if (!b_rc) return ECORE_INVAL; @@ -357,9 +511,11 @@ enum _ecore_status_t ecore_qm_reconf(struct ecore_hwfn *p_hwfn, return rc; /* start PF's qm queues */ + OSAL_SPIN_LOCK(&qm_lock); b_rc = ecore_send_qm_stop_cmd(p_hwfn, p_ptt, true, true, qm_info->start_pq, qm_info->num_pqs); - if (!rc) + OSAL_SPIN_UNLOCK(&qm_lock); + if (!b_rc) return ECORE_INVAL; return ECORE_SUCCESS; @@ -367,16 +523,19 @@ enum _ecore_status_t ecore_qm_reconf(struct ecore_hwfn *p_hwfn, enum _ecore_status_t ecore_resc_alloc(struct ecore_dev *p_dev) { - enum _ecore_status_t rc = ECORE_SUCCESS; struct ecore_consq *p_consq; struct ecore_eq *p_eq; +#ifdef CONFIG_ECORE_LL2 + struct ecore_ll2_info *p_ll2_info; +#endif + enum _ecore_status_t rc = ECORE_SUCCESS; int i; if (IS_VF(p_dev)) return rc; p_dev->fw_data = OSAL_ZALLOC(p_dev, GFP_KERNEL, - sizeof(struct ecore_fw_data)); + sizeof(*p_dev->fw_data)); if (!p_dev->fw_data) return ECORE_NOMEM; @@ -409,6 +568,7 @@ enum _ecore_status_t ecore_resc_alloc(struct ecore_dev *p_dev) for_each_hwfn(p_dev, i) { struct ecore_hwfn *p_hwfn = &p_dev->hwfns[i]; + u32 n_eqes, num_cons; /* First allocate the context manager structure */ rc = ecore_cxt_mngr_alloc(p_hwfn); @@ -457,7 +617,60 @@ enum _ecore_status_t ecore_resc_alloc(struct ecore_dev *p_dev) goto alloc_err; /* EQ */ - p_eq = ecore_eq_alloc(p_hwfn, 256); + n_eqes = ecore_chain_get_capacity(&p_hwfn->p_spq->chain); + if ((p_hwfn->hw_info.personality == ECORE_PCI_ETH_ROCE) || + (p_hwfn->hw_info.personality == ECORE_PCI_IWARP)) { + /* Calculate the EQ size + * --------------------- + * Each ICID may generate up to one event at a time i.e. + * the event must be handled/cleared before a new one + * can be generated. We calculate the sum of events per + * protocol and create an EQ deep enough to handle the + * worst case: + * - Core - according to SPQ. + * - RoCE - per QP there are a couple of ICIDs, one + * responder and one requester, each can + * generate an EQE => n_eqes_qp = 2 * n_qp. + * Each CQ can generate an EQE. There are 2 CQs + * per QP => n_eqes_cq = 2 * n_qp. + * Hence the RoCE total is 4 * n_qp or + * 2 * num_cons. + * - ENet - There can be up to two events per VF. One + * for VF-PF channel and another for VF FLR + * initial cleanup. The number of VFs is + * bounded by MAX_NUM_VFS_BB, and is much + * smaller than RoCE's so we avoid exact + * calculation. + */ + if (p_hwfn->hw_info.personality == ECORE_PCI_ETH_ROCE) { + num_cons = + ecore_cxt_get_proto_cid_count( + p_hwfn, + PROTOCOLID_ROCE, + 0); + num_cons *= 2; + } else { + num_cons = ecore_cxt_get_proto_cid_count( + p_hwfn, + PROTOCOLID_IWARP, + 0); + } + n_eqes += num_cons + 2 * MAX_NUM_VFS_BB; + } else if (p_hwfn->hw_info.personality == ECORE_PCI_ISCSI) { + num_cons = + ecore_cxt_get_proto_cid_count(p_hwfn, + PROTOCOLID_ISCSI, 0); + n_eqes += 2 * num_cons; + } + + if (n_eqes > 0xFFFF) { + DP_ERR(p_hwfn, "Cannot allocate 0x%x EQ elements." + "The maximum of a u16 chain is 0x%x\n", + n_eqes, 0xFFFF); + goto alloc_err; + } + + p_eq = ecore_eq_alloc(p_hwfn, (u16)n_eqes); if (!p_eq) goto alloc_no_mem; p_hwfn->p_eq = p_eq; @@ -467,12 +680,20 @@ enum _ecore_status_t ecore_resc_alloc(struct ecore_dev *p_dev) goto alloc_no_mem; p_hwfn->p_consq = p_consq; +#ifdef CONFIG_ECORE_LL2 + if (p_hwfn->using_ll2) { + p_ll2_info = ecore_ll2_alloc(p_hwfn); + if (!p_ll2_info) + goto alloc_no_mem; + p_hwfn->p_ll2_info = p_ll2_info; + } +#endif + /* DMA info initialization */ rc = ecore_dmae_info_alloc(p_hwfn); if (rc) { DP_NOTICE(p_hwfn, true, - "Failed to allocate memory for" - " dmae_info structure\n"); + "Failed to allocate memory for dmae_info structure\n"); goto alloc_err; } @@ -480,7 +701,7 @@ enum _ecore_status_t ecore_resc_alloc(struct ecore_dev *p_dev) rc = ecore_dcbx_info_alloc(p_hwfn); if (rc) { DP_NOTICE(p_hwfn, true, - "Failed to allocate memory for dcbxstruct\n"); + "Failed to allocate memory for dcbx structure\n"); goto alloc_err; } } @@ -525,6 +746,10 @@ void ecore_resc_setup(struct ecore_dev *p_dev) ecore_int_setup(p_hwfn, p_hwfn->p_main_ptt); ecore_iov_setup(p_hwfn, p_hwfn->p_main_ptt); +#ifdef CONFIG_ECORE_LL2 + if (p_hwfn->using_ll2) + ecore_ll2_setup(p_hwfn, p_hwfn->p_ll2_info); +#endif } } @@ -558,9 +783,11 @@ enum _ecore_status_t ecore_final_cleanup(struct ecore_hwfn *p_hwfn, command |= SDM_COMP_TYPE_AGG_INT << SDM_OP_GEN_COMP_TYPE_SHIFT; /* Make sure notification is not set before initiating final cleanup */ + if (REG_RD(p_hwfn, addr)) { DP_NOTICE(p_hwfn, false, - "Unexpected; Found final cleanup notification " + "Unexpected; Found final cleanup notification"); + DP_NOTICE(p_hwfn, false, " before initiating final cleanup\n"); REG_WR(p_hwfn, addr, 0); } @@ -588,7 +815,7 @@ enum _ecore_status_t ecore_final_cleanup(struct ecore_hwfn *p_hwfn, return rc; } -static void ecore_calc_hw_mode(struct ecore_hwfn *p_hwfn) +static enum _ecore_status_t ecore_calc_hw_mode(struct ecore_hwfn *p_hwfn) { int hw_mode = 0; @@ -601,7 +828,7 @@ static void ecore_calc_hw_mode(struct ecore_hwfn *p_hwfn) } else { DP_NOTICE(p_hwfn, true, "Unknown chip type %#x\n", p_hwfn->p_dev->type); - return; + return ECORE_INVAL; } /* Ports per engine is based on the values in CNIG_REG_NW_PORT_MODE */ @@ -619,7 +846,7 @@ static void ecore_calc_hw_mode(struct ecore_hwfn *p_hwfn) DP_NOTICE(p_hwfn, true, "num_ports_in_engine = %d not supported\n", p_hwfn->p_dev->num_ports_in_engines); - return; + return ECORE_INVAL; } switch (p_hwfn->p_dev->mf_mode) { @@ -650,8 +877,10 @@ static void ecore_calc_hw_mode(struct ecore_hwfn *p_hwfn) #endif hw_mode |= 1 << MODE_ASIC; +#ifndef REAL_ASIC_ONLY if (ENABLE_EAGLE_ENG1_WORKAROUND(p_hwfn)) hw_mode |= 1 << MODE_EAGLE_ENG1_WORKAROUND; +#endif if (p_hwfn->p_dev->num_hwfns > 1) hw_mode |= 1 << MODE_100G; @@ -661,11 +890,13 @@ static void ecore_calc_hw_mode(struct ecore_hwfn *p_hwfn) DP_VERBOSE(p_hwfn, (ECORE_MSG_PROBE | ECORE_MSG_IFUP), "Configuring function for hw_mode: 0x%08x\n", p_hwfn->hw_info.hw_mode); + + return ECORE_SUCCESS; } #ifndef ASIC_ONLY /* MFW-replacement initializations for non-ASIC */ -static void ecore_hw_init_chip(struct ecore_hwfn *p_hwfn, +static enum _ecore_status_t ecore_hw_init_chip(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) { u32 pl_hv = 1; @@ -703,6 +934,8 @@ static void ecore_hw_init_chip(struct ecore_hwfn *p_hwfn, if (i == 100) DP_NOTICE(p_hwfn, true, "RBC done failed to complete in PSWRQ2\n"); + + return ECORE_SUCCESS; } #endif @@ -742,11 +975,11 @@ static enum _ecore_status_t ecore_hw_init_common(struct ecore_hwfn *p_hwfn, int hw_mode) { struct ecore_qm_info *qm_info = &p_hwfn->qm_info; - enum _ecore_status_t rc = ECORE_SUCCESS; struct ecore_dev *p_dev = p_hwfn->p_dev; u8 vf_id, max_num_vfs; u16 num_pfs, pf_id; u32 concrete_fid; + enum _ecore_status_t rc = ECORE_SUCCESS; ecore_init_cau_rt_data(p_dev); @@ -754,8 +987,11 @@ static enum _ecore_status_t ecore_hw_init_common(struct ecore_hwfn *p_hwfn, ecore_gtt_init(p_hwfn); #ifndef ASIC_ONLY - if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) - ecore_hw_init_chip(p_hwfn, p_hwfn->p_main_ptt); + if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) { + rc = ecore_hw_init_chip(p_hwfn, p_hwfn->p_main_ptt); + if (rc != ECORE_SUCCESS) + return rc; + } #endif if (p_hwfn->mcp_info) { @@ -797,9 +1033,15 @@ static enum _ecore_status_t ecore_hw_init_common(struct ecore_hwfn *p_hwfn, ecore_wr(p_hwfn, p_ptt, PGLUE_B_REG_USE_CLIENTID_IN_TAG, 1); if (ECORE_IS_BB(p_hwfn->p_dev)) { + /* Workaround clears ROCE search for all functions to prevent + * involving non initialized function in processing ROCE packet. + */ num_pfs = NUM_OF_ENG_PFS(p_hwfn->p_dev); - if (num_pfs == 1) - return rc; + for (pf_id = 0; pf_id < num_pfs; pf_id++) { + ecore_fid_pretend(p_hwfn, p_ptt, pf_id); + ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0); + ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0); + } /* pretend to original PF */ ecore_fid_pretend(p_hwfn, p_ptt, p_hwfn->rel_pf_id); } @@ -816,6 +1058,9 @@ static enum _ecore_status_t ecore_hw_init_common(struct ecore_hwfn *p_hwfn, concrete_fid = ecore_vfid_to_concrete(p_hwfn, vf_id); ecore_fid_pretend(p_hwfn, p_ptt, (u16)concrete_fid); ecore_wr(p_hwfn, p_ptt, CCFC_REG_STRONG_ENABLE_VF, 0x1); + ecore_wr(p_hwfn, p_ptt, CCFC_REG_WEAK_ENABLE_VF, 0x0); + ecore_wr(p_hwfn, p_ptt, TCFC_REG_STRONG_ENABLE_VF, 0x1); + ecore_wr(p_hwfn, p_ptt, TCFC_REG_WEAK_ENABLE_VF, 0x0); } /* pretend to original PF */ ecore_fid_pretend(p_hwfn, p_ptt, p_hwfn->rel_pf_id); @@ -906,11 +1151,15 @@ static void ecore_emul_link_init(struct ecore_hwfn *p_hwfn, return; } + /* XLPORT MAC MODE *//* 0 Quad, 4 Single... */ ecore_wr_nw_port(p_hwfn, p_ptt, XLPORT_MODE_REG, (0x4 << 4) | 0x4, 1, port); ecore_wr_nw_port(p_hwfn, p_ptt, XLPORT_MAC_CONTROL, 0, 1, port); + /* XLMAC: SOFT RESET */ ecore_wr_nw_port(p_hwfn, p_ptt, XLMAC_CTRL, 0x40, 0, port); + /* XLMAC: Port Speed >= 10Gbps */ ecore_wr_nw_port(p_hwfn, p_ptt, XLMAC_MODE, 0x40, 0, port); + /* XLMAC: Max Size */ ecore_wr_nw_port(p_hwfn, p_ptt, XLMAC_RX_MAX_SIZE, 0x3fff, 0, port); ecore_wr_nw_port(p_hwfn, p_ptt, XLMAC_TX_CTRL, 0x01000000800ULL | (0xa << 12) | ((u64)1 << 38), @@ -919,10 +1168,14 @@ static void ecore_emul_link_init(struct ecore_hwfn *p_hwfn, ecore_wr_nw_port(p_hwfn, p_ptt, XLMAC_PFC_CTRL, 0x30ffffc000ULL, 0, port); ecore_wr_nw_port(p_hwfn, p_ptt, XLMAC_CTRL, 0x3 | (loopback << 2), 0, - port); - ecore_wr_nw_port(p_hwfn, p_ptt, XLMAC_CTRL, 0x1003 | (loopback << 2), - 0, port); + port); /* XLMAC: TX_EN, RX_EN */ + /* XLMAC: TX_EN, RX_EN, SW_LINK_STATUS */ + ecore_wr_nw_port(p_hwfn, p_ptt, XLMAC_CTRL, + 0x1003 | (loopback << 2), 0, port); + /* Enabled Parallel PFC interface */ ecore_wr_nw_port(p_hwfn, p_ptt, XLPORT_FLOW_CONTROL_CONFIG, 1, 0, port); + + /* XLPORT port enable */ ecore_wr_nw_port(p_hwfn, p_ptt, XLPORT_ENABLE_REG, 0xf, 1, port); } @@ -977,12 +1230,10 @@ static enum _ecore_status_t ecore_hw_init_port(struct ecore_hwfn *p_hwfn, { enum _ecore_status_t rc = ECORE_SUCCESS; - /* Init sequence */ rc = ecore_init_run(p_hwfn, p_ptt, PHASE_PORT, p_hwfn->port_id, hw_mode); if (rc != ECORE_SUCCESS) return rc; - #ifndef ASIC_ONLY if (CHIP_REV_IS_ASIC(p_hwfn->p_dev)) return ECORE_SUCCESS; @@ -1020,6 +1271,65 @@ static enum _ecore_status_t ecore_hw_init_port(struct ecore_hwfn *p_hwfn, return rc; } +static enum _ecore_status_t +ecore_hw_init_dpi_size(struct ecore_hwfn *p_hwfn, + struct ecore_ptt *p_ptt, u32 pwm_region_size, u32 n_cpus) +{ + u32 dpi_page_size_1, dpi_page_size_2, dpi_page_size; + u32 dpi_bit_shift, dpi_count; + u32 min_dpis; + + /* Calculate DPI size + * ------------------ + * The PWM region contains Doorbell Pages. The first is reserverd for + * the kernel for, e.g, L2. The others are free to be used by non- + * trusted applications, typically from user space. Each page, called a + * doorbell page is sectioned into windows that allow doorbells to be + * issued in parallel by the kernel/application. The size of such a + * window (a.k.a. WID) is 1kB. + * Summary: + * 1kB WID x N WIDS = DPI page size + * DPI page size x N DPIs = PWM region size + * Notes: + * The size of the DPI page size must be in multiples of OSAL_PAGE_SIZE + * in order to ensure that two applications won't share the same page. + * It also must contain at least one WID per CPU to allow parallelism. + * It also must be a power of 2, since it is stored as a bit shift. + * + * The DPI page size is stored in a register as 'dpi_bit_shift' so that + * 0 is 4kB, 1 is 8kB and etc. Hence the minimum size is 4,096 + * containing 4 WIDs. + */ + dpi_page_size_1 = ECORE_WID_SIZE * n_cpus; + dpi_page_size_2 = OSAL_MAX_T(u32, ECORE_WID_SIZE, OSAL_PAGE_SIZE); + dpi_page_size = OSAL_MAX_T(u32, dpi_page_size_1, dpi_page_size_2); + dpi_page_size = OSAL_ROUNDUP_POW_OF_TWO(dpi_page_size); + dpi_bit_shift = OSAL_LOG2(dpi_page_size / 4096); + + dpi_count = pwm_region_size / dpi_page_size; + + min_dpis = p_hwfn->pf_params.rdma_pf_params.min_dpis; + min_dpis = OSAL_MAX_T(u32, ECORE_MIN_DPIS, min_dpis); + + /* Update hwfn */ + p_hwfn->dpi_size = dpi_page_size; + p_hwfn->dpi_count = dpi_count; + + /* Update registers */ + ecore_wr(p_hwfn, p_ptt, DORQ_REG_PF_DPI_BIT_SHIFT, dpi_bit_shift); + + if (dpi_count < min_dpis) + return ECORE_NORESOURCES; + + return ECORE_SUCCESS; +} + +enum ECORE_ROCE_EDPM_MODE { + ECORE_ROCE_EDPM_MODE_ENABLE = 0, + ECORE_ROCE_EDPM_MODE_FORCE_ON = 1, + ECORE_ROCE_EDPM_MODE_DISABLE = 2, +}; + static enum _ecore_status_t ecore_hw_init_pf_doorbell_bar(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) @@ -1027,8 +1337,10 @@ ecore_hw_init_pf_doorbell_bar(struct ecore_hwfn *p_hwfn, u32 pwm_regsize, norm_regsize; u32 non_pwm_conn, min_addr_reg1; u32 db_bar_size, n_cpus; + u32 roce_edpm_mode; u32 pf_dems_shift; int rc = ECORE_SUCCESS; + u8 cond; db_bar_size = ecore_hw_bar_size(p_hwfn, BAR_ID_1); if (p_hwfn->p_dev->num_hwfns > 1) @@ -1059,26 +1371,62 @@ ecore_hw_init_pf_doorbell_bar(struct ecore_hwfn *p_hwfn, /* Check that the normal and PWM sizes are valid */ if (db_bar_size < norm_regsize) { DP_ERR(p_hwfn->p_dev, - "Doorbell BAR size 0x%x is too" - " small (normal region is 0x%0x )\n", + "Doorbell BAR size 0x%x is too small (normal region is 0x%0x )\n", db_bar_size, norm_regsize); return ECORE_NORESOURCES; } if (pwm_regsize < ECORE_MIN_PWM_REGION) { DP_ERR(p_hwfn->p_dev, - "PWM region size 0x%0x is too small." - " Should be at least 0x%0x (Doorbell BAR size" - " is 0x%x and normal region size is 0x%0x)\n", + "PWM region size 0x%0x is too small. Should be at least 0x%0x (Doorbell BAR size is 0x%x and normal region size is 0x%0x)\n", pwm_regsize, ECORE_MIN_PWM_REGION, db_bar_size, norm_regsize); return ECORE_NORESOURCES; } - /* Update hwfn */ - p_hwfn->dpi_start_offset = norm_regsize; /* this is later used to - * calculate the doorbell - * address + /* Calculate number of DPIs */ + roce_edpm_mode = p_hwfn->pf_params.rdma_pf_params.roce_edpm_mode; + if ((roce_edpm_mode == ECORE_ROCE_EDPM_MODE_ENABLE) || + ((roce_edpm_mode == ECORE_ROCE_EDPM_MODE_FORCE_ON))) { + /* Either EDPM is mandatory, or we are attempting to allocate a + * WID per CPU. + */ + n_cpus = OSAL_NUM_ACTIVE_CPU(); + rc = ecore_hw_init_dpi_size(p_hwfn, p_ptt, pwm_regsize, n_cpus); + } + + cond = ((rc) && (roce_edpm_mode == ECORE_ROCE_EDPM_MODE_ENABLE)) || + (roce_edpm_mode == ECORE_ROCE_EDPM_MODE_DISABLE); + if (cond || p_hwfn->dcbx_no_edpm) { + /* Either EDPM is disabled from user configuration, or it is + * disabled via DCBx, or it is not mandatory and we failed to + * allocated a WID per CPU. */ + n_cpus = 1; + rc = ecore_hw_init_dpi_size(p_hwfn, p_ptt, pwm_regsize, n_cpus); + + /* If we entered this flow due to DCBX then the DPM register is + * already configured. + */ + } + + DP_INFO(p_hwfn, + "doorbell bar: normal_region_size=%d, pwm_region_size=%d", + norm_regsize, pwm_regsize); + DP_INFO(p_hwfn, + " dpi_size=%d, dpi_count=%d, roce_edpm=%s\n", + p_hwfn->dpi_size, p_hwfn->dpi_count, + ((p_hwfn->dcbx_no_edpm) || (p_hwfn->db_bar_no_edpm)) ? + "disabled" : "enabled"); + + /* Check return codes from above calls */ + if (rc) { + DP_ERR(p_hwfn, + "Failed to allocate enough DPIs\n"); + return ECORE_NORESOURCES; + } + + /* Update hwfn */ + p_hwfn->dpi_start_offset = norm_regsize; /* Update registers */ /* DEMS size is configured log2 of DWORDs, hence the division by 4 */ @@ -1086,12 +1434,6 @@ ecore_hw_init_pf_doorbell_bar(struct ecore_hwfn *p_hwfn, ecore_wr(p_hwfn, p_ptt, DORQ_REG_PF_ICID_BIT_SHIFT_NORM, pf_dems_shift); ecore_wr(p_hwfn, p_ptt, DORQ_REG_PF_MIN_ADDR_REG1, min_addr_reg1); - DP_INFO(p_hwfn, - "Doorbell size 0x%x, Normal region 0x%x, PWM region 0x%x\n", - db_bar_size, norm_regsize, pwm_regsize); - DP_INFO(p_hwfn, "DPI size 0x%x, DPI count 0x%x\n", p_hwfn->dpi_size, - p_hwfn->dpi_count); - return ECORE_SUCCESS; } @@ -1103,13 +1445,12 @@ ecore_hw_init_pf(struct ecore_hwfn *p_hwfn, bool b_hw_start, enum ecore_int_mode int_mode, bool allow_npar_tx_switch) { - enum _ecore_status_t rc = ECORE_SUCCESS; u8 rel_pf_id = p_hwfn->rel_pf_id; u32 prs_reg; + enum _ecore_status_t rc = ECORE_SUCCESS; u16 ctrl; int pos; - /* ILT/DQ/CM/QM */ if (p_hwfn->mcp_info) { struct ecore_mcp_function_info *p_info; @@ -1118,11 +1459,11 @@ ecore_hw_init_pf(struct ecore_hwfn *p_hwfn, p_hwfn->qm_info.pf_wfq = p_info->bandwidth_min; /* Update rate limit once we'll actually have a link */ - p_hwfn->qm_info.pf_rl = 100; + p_hwfn->qm_info.pf_rl = 100000; } ecore_cxt_hw_init_pf(p_hwfn); - ecore_int_igu_init_rt(p_hwfn); /* @@@TBD TODO MichalS multi hwfn ?? */ + ecore_int_igu_init_rt(p_hwfn); /* Set VLAN in NIG if needed */ if (hw_mode & (1 << MODE_MF_SD)) { @@ -1141,7 +1482,11 @@ ecore_hw_init_pf(struct ecore_hwfn *p_hwfn, } /* Protocl Configuration - @@@TBD - should we set 0 otherwise? */ - STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_TCP_RT_OFFSET, 0); + STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_TCP_RT_OFFSET, + (p_hwfn->hw_info.personality == ECORE_PCI_ISCSI) ? 1 : 0); + STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_FCOE_RT_OFFSET, + (p_hwfn->hw_info.personality == ECORE_PCI_FCOE) ? 1 : 0); + STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0); /* perform debug configuration when chip is out of reset */ OSAL_BEFORE_PF_START((void *)p_hwfn->p_dev, p_hwfn->my_id); @@ -1171,24 +1516,20 @@ ecore_hw_init_pf(struct ecore_hwfn *p_hwfn, * PCI config space. */ /* Not in use @DPDK - * pos = OSAL_PCI_FIND_CAPABILITY(p_hwfn->p_dev, PCI_CAP_ID_EXP); - * if (!pos) { - * DP_NOTICE(p_hwfn, true, - * "Failed to find the PCI Express" - * " Capability structure in the PCI config space\n"); - * return ECORE_IO; - * } - * OSAL_PCI_READ_CONFIG_WORD(p_hwfn->p_dev, pos + PCI_EXP_DEVCTL, - * &ctrl); - * ctrl &= ~PCI_EXP_DEVCTL_RELAX_EN; - * OSAL_PCI_WRITE_CONFIG_WORD(p_hwfn->p_dev, pos + PCI_EXP_DEVCTL, - * &ctrl); - */ + * pos = OSAL_PCI_FIND_CAPABILITY(p_hwfn->p_dev, PCI_CAP_ID_EXP); + * if (!pos) { + * DP_NOTICE(p_hwfn, true, + * "Failed to find the PCIe Cap\n"); + * return ECORE_IO; + * } + * OSAL_PCI_READ_CONFIG_WORD(p_hwfn->p_dev, pos + PCI_EXP_DEVCTL, &ctrl); + * ctrl &= ~PCI_EXP_DEVCTL_RELAX_EN; + * OSAL_PCI_WRITE_CONFIG_WORD(p_hwfn->p_dev, pos + PCI_EXP_DEVCTL, ctrl); + */ rc = ecore_hw_init_pf_doorbell_bar(p_hwfn, p_ptt); if (rc) return rc; - if (b_hw_start) { /* enable interrupts */ ecore_int_igu_enable(p_hwfn, p_ptt, int_mode); @@ -1204,14 +1545,27 @@ ecore_hw_init_pf(struct ecore_hwfn *p_hwfn, DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE, "PRS_REG_SEARCH_TAG1: %x\n", prs_reg); + if (p_hwfn->hw_info.personality == ECORE_PCI_FCOE) { + ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TAG1, + (1 << 2)); + ecore_wr(p_hwfn, p_ptt, + PRS_REG_PKT_LEN_STAT_TAGS_NOT_COUNTED_FIRST, + 0x100); + } DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE, - "PRS_REG_SEARCH register after start PFn\n"); + "PRS_REG_SEARCH registers after start PFn\n"); prs_reg = ecore_rd(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP); DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE, "PRS_REG_SEARCH_TCP: %x\n", prs_reg); prs_reg = ecore_rd(p_hwfn, p_ptt, PRS_REG_SEARCH_UDP); DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE, "PRS_REG_SEARCH_UDP: %x\n", prs_reg); + prs_reg = ecore_rd(p_hwfn, p_ptt, PRS_REG_SEARCH_FCOE); + DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE, + "PRS_REG_SEARCH_FCOE: %x\n", prs_reg); + prs_reg = ecore_rd(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE); + DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE, + "PRS_REG_SEARCH_ROCE: %x\n", prs_reg); prs_reg = ecore_rd(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP_FIRST_FRAG); DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE, @@ -1265,18 +1619,20 @@ static void ecore_reset_mb_shadow(struct ecore_hwfn *p_hwfn, } enum _ecore_status_t ecore_hw_init(struct ecore_dev *p_dev, - struct ecore_tunn_start_params *p_tunn, - bool b_hw_start, - enum ecore_int_mode int_mode, - bool allow_npar_tx_switch, - const u8 *bin_fw_data) + struct ecore_hw_init_params *p_params) { enum _ecore_status_t rc, mfw_rc; u32 load_code, param; int i, j; + if (p_params->int_mode == ECORE_INT_MODE_MSI && p_dev->num_hwfns > 1) { + DP_NOTICE(p_dev, false, + "MSI mode is not supported for CMT devices\n"); + return ECORE_INVAL; + } + if (IS_PF(p_dev)) { - rc = ecore_init_fw_data(p_dev, bin_fw_data); + rc = ecore_init_fw_data(p_dev, p_params->bin_fw_data); if (rc != ECORE_SUCCESS) return rc; } @@ -1285,16 +1641,19 @@ enum _ecore_status_t ecore_hw_init(struct ecore_dev *p_dev, struct ecore_hwfn *p_hwfn = &p_dev->hwfns[i]; if (IS_VF(p_dev)) { - rc = ecore_vf_pf_init(p_hwfn); - if (rc) - return rc; + p_hwfn->b_int_enabled = 1; continue; } /* Enable DMAE in PXP */ rc = ecore_change_pci_hwfn(p_hwfn, p_hwfn->p_main_ptt, true); + if (rc != ECORE_SUCCESS) + return rc; + + rc = ecore_calc_hw_mode(p_hwfn); + if (rc != ECORE_SUCCESS) + return rc; - ecore_calc_hw_mode(p_hwfn); /* @@@TBD need to add here: * Check for fan failure * Prev_unload @@ -1331,6 +1690,11 @@ enum _ecore_status_t ecore_hw_init(struct ecore_dev *p_dev, p_hwfn->first_on_engine = (load_code == FW_MSG_CODE_DRV_LOAD_ENGINE); + if (!qm_lock_init) { + OSAL_SPIN_LOCK_INIT(&qm_lock); + qm_lock_init = true; + } + switch (load_code) { case FW_MSG_CODE_DRV_LOAD_ENGINE: rc = ecore_hw_init_common(p_hwfn, p_hwfn->p_main_ptt, @@ -1344,6 +1708,7 @@ enum _ecore_status_t ecore_hw_init(struct ecore_dev *p_dev, if (rc) break; +#ifndef REAL_ASIC_ONLY if (ENABLE_EAGLE_ENG1_WORKAROUND(p_hwfn)) { struct init_nig_pri_tc_map_req tc_map; @@ -1360,12 +1725,15 @@ enum _ecore_status_t ecore_hw_init(struct ecore_dev *p_dev, p_hwfn->p_main_ptt, &tc_map); } - /* fallthrough */ +#endif + /* Fall into */ case FW_MSG_CODE_DRV_LOAD_FUNCTION: rc = ecore_hw_init_pf(p_hwfn, p_hwfn->p_main_ptt, - p_tunn, p_hwfn->hw_info.hw_mode, - b_hw_start, int_mode, - allow_npar_tx_switch); + p_params->p_tunn, + p_hwfn->hw_info.hw_mode, + p_params->b_hw_start, + p_params->int_mode, + p_params->allow_npar_tx_switch); break; default: rc = ECORE_NOTIMPL; @@ -1374,7 +1742,7 @@ enum _ecore_status_t ecore_hw_init(struct ecore_dev *p_dev, if (rc != ECORE_SUCCESS) DP_NOTICE(p_hwfn, true, - "init phase failed loadcode 0x%x (rc %d)\n", + "init phase failed for loadcode 0x%x (rc %d)\n", load_code, rc); /* ACK mfw regardless of success or failure of initialization */ @@ -1389,10 +1757,13 @@ enum _ecore_status_t ecore_hw_init(struct ecore_dev *p_dev, return mfw_rc; } + ecore_mcp_mdump_get_info(p_hwfn, p_hwfn->p_main_ptt); + ecore_mcp_mdump_set_values(p_hwfn, p_hwfn->p_main_ptt, + p_params->epoch); + /* send DCBX attention request command */ DP_VERBOSE(p_hwfn, ECORE_MSG_DCB, - "sending phony dcbx set command to trigger DCBx" - " attention handling\n"); + "sending phony dcbx set command to trigger DCBx attention handling\n"); mfw_rc = ecore_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, DRV_MSG_CODE_SET_DCBX, 1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT, @@ -1410,7 +1781,7 @@ enum _ecore_status_t ecore_hw_init(struct ecore_dev *p_dev, } #define ECORE_HW_STOP_RETRY_LIMIT (10) -static OSAL_INLINE void ecore_hw_timers_stop(struct ecore_dev *p_dev, +static void ecore_hw_timers_stop(struct ecore_dev *p_dev, struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) { @@ -1419,8 +1790,8 @@ static OSAL_INLINE void ecore_hw_timers_stop(struct ecore_dev *p_dev, /* close timers */ ecore_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0); ecore_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0); - for (i = 0; i < ECORE_HW_STOP_RETRY_LIMIT && - !p_dev->recov_in_prog; i++) { + for (i = 0; i < ECORE_HW_STOP_RETRY_LIMIT && !p_dev->recov_in_prog; + i++) { if ((!ecore_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_CONN)) && (!ecore_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_TASK))) @@ -1433,8 +1804,7 @@ static OSAL_INLINE void ecore_hw_timers_stop(struct ecore_dev *p_dev, } if (i == ECORE_HW_STOP_RETRY_LIMIT) DP_NOTICE(p_hwfn, true, - "Timers linear scans are not over" - " [Connection %02x Tasks %02x]\n", + "Timers linear scans are not over [Connection %02x Tasks %02x]\n", (u8)ecore_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_CONN), (u8)ecore_rd(p_hwfn, p_ptt, @@ -1475,9 +1845,7 @@ enum _ecore_status_t ecore_hw_stop(struct ecore_dev *p_dev) rc = ecore_sp_pf_stop(p_hwfn); if (rc) DP_NOTICE(p_hwfn, true, - "Failed to close PF against FW. Continue to" - " stop HW to prevent illegal host access" - " by the device\n"); + "Failed to close PF against FW. Continue to stop HW to prevent illegal host access by the device\n"); /* perform debug action after PF stop was sent */ OSAL_AFTER_PF_STOP((void *)p_hwfn->p_dev, p_hwfn->my_id); @@ -1489,6 +1857,8 @@ enum _ecore_status_t ecore_hw_stop(struct ecore_dev *p_dev) /* close parser */ ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0); ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_UDP, 0x0); + ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_FCOE, 0x0); + ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0); ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0); /* @@@TBD - clean transmission queues (5.b) */ @@ -1542,6 +1912,8 @@ void ecore_hw_stop_fastpath(struct ecore_dev *p_dev) ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0); ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_UDP, 0x0); + ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_FCOE, 0x0); + ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0); ecore_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0); /* @@@TBD - clean transmission queues (5.b) */ @@ -1562,6 +1934,16 @@ void ecore_hw_start_fastpath(struct ecore_hwfn *p_hwfn) if (IS_VF(p_hwfn->p_dev)) return; + /* If roce info is allocated it means roce is initialized and should + * be enabled in searcher. + */ + if (p_hwfn->p_rdma_info) { + if (p_hwfn->b_rdma_enabled_in_prs) + ecore_wr(p_hwfn, p_ptt, + p_hwfn->rdma_prs_search_reg, 0x1); + ecore_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x1); + } + /* Re-open incoming traffic */ ecore_wr(p_hwfn, p_hwfn->p_main_ptt, NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x0); @@ -1612,15 +1994,10 @@ enum _ecore_status_t ecore_hw_reset(struct ecore_dev *p_dev) /* Disable PF in HW blocks */ ecore_wr(p_hwfn, p_hwfn->p_main_ptt, DORQ_REG_PF_DB_ENABLE, 0); ecore_wr(p_hwfn, p_hwfn->p_main_ptt, QM_REG_PF_EN, 0); - ecore_wr(p_hwfn, p_hwfn->p_main_ptt, - TCFC_REG_STRONG_ENABLE_PF, 0); - ecore_wr(p_hwfn, p_hwfn->p_main_ptt, - CCFC_REG_STRONG_ENABLE_PF, 0); if (p_dev->recov_in_prog) { DP_VERBOSE(p_hwfn, ECORE_MSG_IFDOWN, - "Recovery is in progress -> skip " - "sending unload_req/done\n"); + "Recovery is in progress -> skip sending unload_req/done\n"); break; } @@ -1661,10 +2038,25 @@ static void ecore_hw_hwfn_free(struct ecore_hwfn *p_hwfn) static void ecore_hw_hwfn_prepare(struct ecore_hwfn *p_hwfn) { /* clear indirect access */ - ecore_wr(p_hwfn, p_hwfn->p_main_ptt, PGLUE_B_REG_PGL_ADDR_88_F0, 0); - ecore_wr(p_hwfn, p_hwfn->p_main_ptt, PGLUE_B_REG_PGL_ADDR_8C_F0, 0); - ecore_wr(p_hwfn, p_hwfn->p_main_ptt, PGLUE_B_REG_PGL_ADDR_90_F0, 0); - ecore_wr(p_hwfn, p_hwfn->p_main_ptt, PGLUE_B_REG_PGL_ADDR_94_F0, 0); + if (ECORE_IS_AH(p_hwfn->p_dev)) { + ecore_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_PGL_ADDR_E8_F0, 0); + ecore_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_PGL_ADDR_EC_F0, 0); + ecore_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_PGL_ADDR_F0_F0, 0); + ecore_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_PGL_ADDR_F4_F0, 0); + } else { + ecore_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_PGL_ADDR_88_F0, 0); + ecore_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_PGL_ADDR_8C_F0, 0); + ecore_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_PGL_ADDR_90_F0, 0); + ecore_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_PGL_ADDR_94_F0, 0); + } /* Clean Previous errors if such exist */ ecore_wr(p_hwfn, p_hwfn->p_main_ptt, @@ -1684,7 +2076,6 @@ static void get_function_id(struct ecore_hwfn *p_hwfn) p_hwfn->hw_info.concrete_fid = REG_RD(p_hwfn, PXP_PF_ME_CONCRETE_ADDR); /* Bits 16-19 from the ME registers are the pf_num */ - /* @@ @TBD - check, may be wrong after B0 implementation for CMT */ p_hwfn->abs_pf_id = (p_hwfn->hw_info.concrete_fid >> 16) & 0xf; p_hwfn->rel_pf_id = GET_FIELD(p_hwfn->hw_info.concrete_fid, PXP_CONCRETE_FID_PFID); @@ -1708,59 +2099,285 @@ static void ecore_hw_set_feat(struct ecore_hwfn *p_hwfn) RESC_NUM(p_hwfn, ECORE_L2_QUEUE)); DP_VERBOSE(p_hwfn, ECORE_MSG_PROBE, - "#PF_L2_QUEUES=%d #SBS=%d num_features=%d\n", + "#PF_L2_QUEUES=%d #ROCE_CNQ=%d #SBS=%d num_features=%d\n", feat_num[ECORE_PF_L2_QUE], + feat_num[ECORE_RDMA_CNQ], RESC_NUM(p_hwfn, ECORE_SB), num_features); } -/* @@@TBD MK RESC: This info is currently hard code and set as if we were MF - * need to read it from shmem... - */ -static enum _ecore_status_t ecore_hw_get_resc(struct ecore_hwfn *p_hwfn) +static enum resource_id_enum +ecore_hw_get_mfw_res_id(enum ecore_resources res_id) +{ + enum resource_id_enum mfw_res_id = RESOURCE_NUM_INVALID; + + switch (res_id) { + case ECORE_SB: + mfw_res_id = RESOURCE_NUM_SB_E; + break; + case ECORE_L2_QUEUE: + mfw_res_id = RESOURCE_NUM_L2_QUEUE_E; + break; + case ECORE_VPORT: + mfw_res_id = RESOURCE_NUM_VPORT_E; + break; + case ECORE_RSS_ENG: + mfw_res_id = RESOURCE_NUM_RSS_ENGINES_E; + break; + case ECORE_PQ: + mfw_res_id = RESOURCE_NUM_PQ_E; + break; + case ECORE_RL: + mfw_res_id = RESOURCE_NUM_RL_E; + break; + case ECORE_MAC: + case ECORE_VLAN: + /* Each VFC resource can accommodate both a MAC and a VLAN */ + mfw_res_id = RESOURCE_VFC_FILTER_E; + break; + case ECORE_ILT: + mfw_res_id = RESOURCE_ILT_E; + break; + case ECORE_LL2_QUEUE: + mfw_res_id = RESOURCE_LL2_QUEUE_E; + break; + case ECORE_RDMA_CNQ_RAM: + case ECORE_CMDQS_CQS: + /* CNQ/CMDQS are the same resource */ + mfw_res_id = RESOURCE_CQS_E; + break; + case ECORE_RDMA_STATS_QUEUE: + mfw_res_id = RESOURCE_RDMA_STATS_QUEUE_E; + break; + default: + break; + } + + return mfw_res_id; +} + +static u32 ecore_hw_get_dflt_resc_num(struct ecore_hwfn *p_hwfn, + enum ecore_resources res_id) { - u32 *resc_start = p_hwfn->hw_info.resc_start; u8 num_funcs = p_hwfn->num_funcs_on_engine; - u32 *resc_num = p_hwfn->hw_info.resc_num; - int i, max_vf_vlan_filters; - struct ecore_sb_cnt_info sb_cnt_info; bool b_ah = ECORE_IS_AH(p_hwfn->p_dev); + struct ecore_sb_cnt_info sb_cnt_info; + u32 dflt_resc_num = 0; + switch (res_id) { + case ECORE_SB: OSAL_MEM_ZERO(&sb_cnt_info, sizeof(sb_cnt_info)); - -#ifdef CONFIG_ECORE_SRIOV - max_vf_vlan_filters = ECORE_ETH_MAX_VF_NUM_VLAN_FILTERS; -#else - max_vf_vlan_filters = 0; -#endif - ecore_int_get_num_sbs(p_hwfn, &sb_cnt_info); - resc_num[ECORE_SB] = OSAL_MIN_T(u32, - (MAX_SB_PER_PATH_BB / num_funcs), - sb_cnt_info.sb_cnt); - - resc_num[ECORE_L2_QUEUE] = (b_ah ? MAX_NUM_L2_QUEUES_K2 : + dflt_resc_num = sb_cnt_info.sb_cnt; + break; + case ECORE_L2_QUEUE: + dflt_resc_num = (b_ah ? MAX_NUM_L2_QUEUES_K2 : MAX_NUM_L2_QUEUES_BB) / num_funcs; - resc_num[ECORE_VPORT] = (b_ah ? MAX_NUM_VPORTS_K2 : + break; + case ECORE_VPORT: + dflt_resc_num = (b_ah ? MAX_NUM_VPORTS_K2 : MAX_NUM_VPORTS_BB) / num_funcs; - resc_num[ECORE_RSS_ENG] = (b_ah ? ETH_RSS_ENGINE_NUM_K2 : + break; + case ECORE_RSS_ENG: + dflt_resc_num = (b_ah ? ETH_RSS_ENGINE_NUM_K2 : ETH_RSS_ENGINE_NUM_BB) / num_funcs; - resc_num[ECORE_PQ] = (b_ah ? MAX_QM_TX_QUEUES_K2 : + break; + case ECORE_PQ: + dflt_resc_num = (b_ah ? MAX_QM_TX_QUEUES_K2 : MAX_QM_TX_QUEUES_BB) / num_funcs; - resc_num[ECORE_RL] = 8; - resc_num[ECORE_MAC] = ETH_NUM_MAC_FILTERS / num_funcs; - resc_num[ECORE_VLAN] = (ETH_NUM_VLAN_FILTERS - - max_vf_vlan_filters + - 1 /*For vlan0 */) / num_funcs; - - /* TODO - there will be a problem in AH - there are only 11k lines */ - resc_num[ECORE_ILT] = (b_ah ? PXP_NUM_ILT_RECORDS_K2 : + break; + case ECORE_RL: + dflt_resc_num = MAX_QM_GLOBAL_RLS / num_funcs; + break; + case ECORE_MAC: + case ECORE_VLAN: + /* Each VFC resource can accommodate both a MAC and a VLAN */ + dflt_resc_num = ETH_NUM_MAC_FILTERS / num_funcs; + break; + case ECORE_ILT: + dflt_resc_num = (b_ah ? PXP_NUM_ILT_RECORDS_K2 : PXP_NUM_ILT_RECORDS_BB) / num_funcs; + break; + case ECORE_LL2_QUEUE: + dflt_resc_num = MAX_NUM_LL2_RX_QUEUES / num_funcs; + break; + case ECORE_RDMA_CNQ_RAM: + case ECORE_CMDQS_CQS: + /* CNQ/CMDQS are the same resource */ + /* @DPDK */ + dflt_resc_num = (NUM_OF_GLOBAL_QUEUES / 2) / num_funcs; + break; + case ECORE_RDMA_STATS_QUEUE: + /* @DPDK */ + dflt_resc_num = (b_ah ? MAX_NUM_VPORTS_K2 : + MAX_NUM_VPORTS_BB) / num_funcs; + break; + default: + break; + } + + return dflt_resc_num; +} + +static enum _ecore_status_t ecore_hw_set_resc_info(struct ecore_hwfn *p_hwfn, + enum ecore_resources res_id, + bool drv_resc_alloc) +{ + u32 dflt_resc_num = 0, dflt_resc_start = 0, mcp_resp, mcp_param; + u32 *p_resc_num, *p_resc_start; + struct resource_info resc_info; + enum _ecore_status_t rc; + + p_resc_num = &RESC_NUM(p_hwfn, res_id); + p_resc_start = &RESC_START(p_hwfn, res_id); + + dflt_resc_num = ecore_hw_get_dflt_resc_num(p_hwfn, res_id); + if (!dflt_resc_num) { + DP_ERR(p_hwfn, "Failed to get default amount for resource %d\n", + res_id); + return ECORE_INVAL; + } + dflt_resc_start = dflt_resc_num * p_hwfn->enabled_func_idx; + +#ifndef ASIC_ONLY + if (CHIP_REV_IS_SLOW(p_hwfn->p_dev)) { + *p_resc_num = dflt_resc_num; + *p_resc_start = dflt_resc_start; + goto out; + } +#endif + + OSAL_MEM_ZERO(&resc_info, sizeof(resc_info)); + resc_info.res_id = ecore_hw_get_mfw_res_id(res_id); + if (resc_info.res_id == RESOURCE_NUM_INVALID) { + DP_ERR(p_hwfn, + "Failed to match resource %d with MFW resources\n", + res_id); + return ECORE_INVAL; + } + + rc = ecore_mcp_get_resc_info(p_hwfn, p_hwfn->p_main_ptt, &resc_info, + &mcp_resp, &mcp_param); + if (rc != ECORE_SUCCESS) { + DP_NOTICE(p_hwfn, true, + "MFW resp failure for a resc alloc req [res_id %d]\n", + res_id); + return rc; + } + + /* Default driver values are applied in the following cases: + * - The resource allocation MB command is not supported by the MFW + * - There is an internal error in the MFW while processing the request + * - The resource ID is unknown to the MFW + */ + if (mcp_resp != FW_MSG_CODE_RESOURCE_ALLOC_OK && + mcp_resp != FW_MSG_CODE_RESOURCE_ALLOC_DEPRECATED) { + /* @DPDK */ + DP_INFO(p_hwfn, + "No allocation info for resc %d [mcp_resp 0x%x].", + res_id, mcp_resp); + DP_INFO(p_hwfn, + "Applying default values [num %d, start %d].\n", + dflt_resc_num, dflt_resc_start); + + *p_resc_num = dflt_resc_num; + *p_resc_start = dflt_resc_start; + goto out; + } + + /* TBD - remove this when revising the handling of the SB resource */ + if (res_id == ECORE_SB) { + /* Excluding the slowpath SB */ + resc_info.size -= 1; + resc_info.offset -= p_hwfn->enabled_func_idx; + } + + *p_resc_num = resc_info.size; + *p_resc_start = resc_info.offset; + + if (*p_resc_num != dflt_resc_num || *p_resc_start != dflt_resc_start) { + DP_NOTICE(p_hwfn, false, + "Resource %d: MFW allocation [num %d, start %d]", + res_id, *p_resc_num, *p_resc_start); + DP_NOTICE(p_hwfn, false, + "differs from default values [num %d, start %d]%s\n", + dflt_resc_num, + dflt_resc_start, + drv_resc_alloc ? " - applying default values" : ""); + if (drv_resc_alloc) { + *p_resc_num = dflt_resc_num; + *p_resc_start = dflt_resc_start; + } + } + out: + return ECORE_SUCCESS; +} + +static const char *ecore_hw_get_resc_name(enum ecore_resources res_id) +{ + switch (res_id) { + case ECORE_SB: + return "SB"; + case ECORE_L2_QUEUE: + return "L2_QUEUE"; + case ECORE_VPORT: + return "VPORT"; + case ECORE_RSS_ENG: + return "RSS_ENG"; + case ECORE_PQ: + return "PQ"; + case ECORE_RL: + return "RL"; + case ECORE_MAC: + return "MAC"; + case ECORE_VLAN: + return "VLAN"; + case ECORE_RDMA_CNQ_RAM: + return "RDMA_CNQ_RAM"; + case ECORE_ILT: + return "ILT"; + case ECORE_LL2_QUEUE: + return "LL2_QUEUE"; + case ECORE_CMDQS_CQS: + return "CMDQS_CQS"; + case ECORE_RDMA_STATS_QUEUE: + return "RDMA_STATS_QUEUE"; + default: + return "UNKNOWN_RESOURCE"; + } +} + +static enum _ecore_status_t ecore_hw_get_resc(struct ecore_hwfn *p_hwfn, + bool drv_resc_alloc) +{ + bool b_ah = ECORE_IS_AH(p_hwfn->p_dev); + enum _ecore_status_t rc; + u8 res_id; +#ifndef ASIC_ONLY + u32 *resc_start = p_hwfn->hw_info.resc_start; + u32 *resc_num = p_hwfn->hw_info.resc_num; + /* For AH, an equal share of the ILT lines between the maximal number of + * PFs is not enough for RoCE. This would be solved by the future + * resource allocation scheme, but isn't currently present for + * FPGA/emulation. For now we keep a number that is sufficient for RoCE + * to work - the BB number of ILT lines divided by its max PFs number. + */ + u32 roce_min_ilt_lines = PXP_NUM_ILT_RECORDS_BB / MAX_NUM_PFS_BB; +#endif + + for (res_id = 0; res_id < ECORE_MAX_RESC; res_id++) { + rc = ecore_hw_set_resc_info(p_hwfn, res_id, drv_resc_alloc); + if (rc != ECORE_SUCCESS) + return rc; + } #ifndef ASIC_ONLY if (CHIP_REV_IS_SLOW(p_hwfn->p_dev)) { /* Reduced build contains less PQs */ - if (!(p_hwfn->p_dev->b_is_emul_full)) + if (!(p_hwfn->p_dev->b_is_emul_full)) { resc_num[ECORE_PQ] = 32; + resc_start[ECORE_PQ] = resc_num[ECORE_PQ] * + p_hwfn->enabled_func_idx; + } /* For AH emulation, since we have a possible maximal number of * 16 enabled PFs, in case there are not enough ILT lines - @@ -1768,19 +2385,17 @@ static enum _ecore_status_t ecore_hw_get_resc(struct ecore_hwfn *p_hwfn) * only with less ILT lines. */ if (!p_hwfn->rel_pf_id && p_hwfn->p_dev->b_is_emul_full) - resc_num[ECORE_ILT] = resc_num[ECORE_ILT]; + resc_num[ECORE_ILT] = OSAL_MAX_T(u32, + resc_num[ECORE_ILT], + roce_min_ilt_lines); } -#endif - - for (i = 0; i < ECORE_MAX_RESC; i++) - resc_start[i] = resc_num[i] * p_hwfn->rel_pf_id; -#ifndef ASIC_ONLY /* Correct the common ILT calculation if PF0 has more */ if (CHIP_REV_IS_SLOW(p_hwfn->p_dev) && p_hwfn->p_dev->b_is_emul_full && - p_hwfn->rel_pf_id && resc_num[ECORE_ILT]) - resc_start[ECORE_ILT] += resc_num[ECORE_ILT]; + p_hwfn->rel_pf_id && resc_num[ECORE_ILT] < roce_min_ilt_lines) + resc_start[ECORE_ILT] += roce_min_ilt_lines - + resc_num[ECORE_ILT]; #endif /* Sanity for ILT */ @@ -1797,29 +2412,12 @@ static enum _ecore_status_t ecore_hw_get_resc(struct ecore_hwfn *p_hwfn) ecore_hw_set_feat(p_hwfn); DP_VERBOSE(p_hwfn, ECORE_MSG_PROBE, - "The numbers for each resource are:\n" - "SB = %d start = %d\n" - "L2_QUEUE = %d start = %d\n" - "VPORT = %d start = %d\n" - "PQ = %d start = %d\n" - "RL = %d start = %d\n" - "MAC = %d start = %d\n" - "VLAN = %d start = %d\n" - "ILT = %d start = %d\n" - "CMDQS_CQS = %d start = %d\n", - RESC_NUM(p_hwfn, ECORE_SB), RESC_START(p_hwfn, ECORE_SB), - RESC_NUM(p_hwfn, ECORE_L2_QUEUE), - RESC_START(p_hwfn, ECORE_L2_QUEUE), - RESC_NUM(p_hwfn, ECORE_VPORT), - RESC_START(p_hwfn, ECORE_VPORT), - RESC_NUM(p_hwfn, ECORE_PQ), RESC_START(p_hwfn, ECORE_PQ), - RESC_NUM(p_hwfn, ECORE_RL), RESC_START(p_hwfn, ECORE_RL), - RESC_NUM(p_hwfn, ECORE_MAC), RESC_START(p_hwfn, ECORE_MAC), - RESC_NUM(p_hwfn, ECORE_VLAN), - RESC_START(p_hwfn, ECORE_VLAN), - RESC_NUM(p_hwfn, ECORE_ILT), RESC_START(p_hwfn, ECORE_ILT), - RESC_NUM(p_hwfn, ECORE_CMDQS_CQS), - RESC_START(p_hwfn, ECORE_CMDQS_CQS)); + "The numbers for each resource are:\n"); + for (res_id = 0; res_id < ECORE_MAX_RESC; res_id++) + DP_VERBOSE(p_hwfn, ECORE_MSG_PROBE, "%s = %d start = %d\n", + ecore_hw_get_resc_name(res_id), + RESC_NUM(p_hwfn, res_id), + RESC_START(p_hwfn, res_id)); return ECORE_SUCCESS; } @@ -1828,19 +2426,20 @@ static enum _ecore_status_t ecore_hw_get_nvm_info(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) { u32 nvm_cfg1_offset, mf_mode, addr, generic_cont0, core_cfg; - u32 port_cfg_addr, link_temp, device_capabilities; + u32 port_cfg_addr, link_temp, nvm_cfg_addr, device_capabilities; struct ecore_mcp_link_params *link; /* Read global nvm_cfg address */ - u32 nvm_cfg_addr = ecore_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); + nvm_cfg_addr = ecore_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); /* Verify MCP has initialized it */ - if (nvm_cfg_addr == 0) { + if (!nvm_cfg_addr) { DP_NOTICE(p_hwfn, false, "Shared memory not initialized\n"); return ECORE_INVAL; } /* Read nvm_cfg1 (Notice this is just offset, and not offsize (TBD) */ + nvm_cfg1_offset = ecore_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); addr = MCP_REG_SCRATCH + nvm_cfg1_offset + @@ -1851,33 +2450,36 @@ static enum _ecore_status_t ecore_hw_get_nvm_info(struct ecore_hwfn *p_hwfn, switch ((core_cfg & NVM_CFG1_GLOB_NETWORK_PORT_MODE_MASK) >> NVM_CFG1_GLOB_NETWORK_PORT_MODE_OFFSET) { - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X40G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_2X40G: p_hwfn->hw_info.port_mode = ECORE_PORT_MODE_DE_2X40G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X50G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X50G: p_hwfn->hw_info.port_mode = ECORE_PORT_MODE_DE_2X50G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X100G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_1X100G: p_hwfn->hw_info.port_mode = ECORE_PORT_MODE_DE_1X100G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X10G_F: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X10G_F: p_hwfn->hw_info.port_mode = ECORE_PORT_MODE_DE_4X10G_F; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X10G_E: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X10G_E: p_hwfn->hw_info.port_mode = ECORE_PORT_MODE_DE_4X10G_E; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X20G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X20G: p_hwfn->hw_info.port_mode = ECORE_PORT_MODE_DE_4X20G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X40G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X40G: p_hwfn->hw_info.port_mode = ECORE_PORT_MODE_DE_1X40G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X25G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X25G: p_hwfn->hw_info.port_mode = ECORE_PORT_MODE_DE_2X25G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X25G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X25G: p_hwfn->hw_info.port_mode = ECORE_PORT_MODE_DE_1X25G; break; + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X25G: + p_hwfn->hw_info.port_mode = ECORE_PORT_MODE_DE_4X25G; + break; default: DP_NOTICE(p_hwfn, true, "Unknown port mode in 0x%08x\n", core_cfg); @@ -1920,13 +2522,18 @@ static enum _ecore_status_t ecore_hw_get_nvm_info(struct ecore_hwfn *p_hwfn, case NVM_CFG1_PORT_DRV_LINK_SPEED_50G: link->speed.forced_speed = 50000; break; - case NVM_CFG1_PORT_DRV_LINK_SPEED_100G: + case NVM_CFG1_PORT_DRV_LINK_SPEED_BB_100G: link->speed.forced_speed = 100000; break; default: DP_NOTICE(p_hwfn, true, "Unknown Speed in 0x%08x\n", link_temp); } + p_hwfn->mcp_info->link_capabilities.default_speed = + link->speed.forced_speed; + p_hwfn->mcp_info->link_capabilities.default_speed_autoneg = + link->speed.autoneg; + link_temp &= NVM_CFG1_PORT_DRV_FLOW_CONTROL_MASK; link_temp >>= NVM_CFG1_PORT_DRV_FLOW_CONTROL_OFFSET; link->pause.autoneg = !!(link_temp & @@ -1938,8 +2545,7 @@ static enum _ecore_status_t ecore_hw_get_nvm_info(struct ecore_hwfn *p_hwfn, link->loopback_mode = 0; DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, - "Read default link: Speed 0x%08x, Adv. Speed 0x%08x," - " AN: 0x%02x, PAUSE AN: 0x%02x\n", + "Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x\n", link->speed.forced_speed, link->speed.advertised_speeds, link->speed.autoneg, link->pause.autoneg); @@ -1976,6 +2582,18 @@ static enum _ecore_status_t ecore_hw_get_nvm_info(struct ecore_hwfn *p_hwfn, if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET) OSAL_SET_BIT(ECORE_DEV_CAP_ETH, &p_hwfn->hw_info.device_capabilities); + if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_FCOE) + OSAL_SET_BIT(ECORE_DEV_CAP_FCOE, + &p_hwfn->hw_info.device_capabilities); + if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ISCSI) + OSAL_SET_BIT(ECORE_DEV_CAP_ISCSI, + &p_hwfn->hw_info.device_capabilities); + if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ROCE) + OSAL_SET_BIT(ECORE_DEV_CAP_ROCE, + &p_hwfn->hw_info.device_capabilities); + if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_IWARP) + OSAL_SET_BIT(ECORE_DEV_CAP_IWARP, + &p_hwfn->hw_info.device_capabilities); return ecore_mcp_fill_shmem_func_info(p_hwfn, p_ptt); } @@ -1983,52 +2601,69 @@ static enum _ecore_status_t ecore_hw_get_nvm_info(struct ecore_hwfn *p_hwfn, static void ecore_get_num_funcs(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) { - u8 num_funcs; - u32 tmp, mask; + u8 num_funcs, enabled_func_idx = p_hwfn->rel_pf_id; + u32 reg_function_hide, tmp, eng_mask, low_pfs_mask; + struct ecore_dev *p_dev = p_hwfn->p_dev; - num_funcs = ECORE_IS_AH(p_hwfn->p_dev) ? MAX_NUM_PFS_K2 - : MAX_NUM_PFS_BB; + num_funcs = ECORE_IS_AH(p_dev) ? MAX_NUM_PFS_K2 : MAX_NUM_PFS_BB; /* Bit 0 of MISCS_REG_FUNCTION_HIDE indicates whether the bypass values * in the other bits are selected. * Bits 1-15 are for functions 1-15, respectively, and their value is * '0' only for enabled functions (function 0 always exists and * enabled). - * In case of CMT, only the "even" functions are enabled, and thus the - * number of functions for both hwfns is learnt from the same bits. + * In case of CMT in BB, only the "even" functions are enabled, and thus + * the number of functions for both hwfns is learnt from the same bits. */ + reg_function_hide = ecore_rd(p_hwfn, p_ptt, MISCS_REG_FUNCTION_HIDE); - tmp = ecore_rd(p_hwfn, p_ptt, MISCS_REG_FUNCTION_HIDE); - if (tmp & 0x1) { - if (ECORE_PATH_ID(p_hwfn) && p_hwfn->p_dev->num_hwfns == 1) { - num_funcs = 0; - mask = 0xaaaa; + if (reg_function_hide & 0x1) { + if (ECORE_IS_BB(p_dev)) { + if (ECORE_PATH_ID(p_hwfn) && p_dev->num_hwfns == 1) { + num_funcs = 0; + eng_mask = 0xaaaa; } else { num_funcs = 1; - mask = 0x5554; + eng_mask = 0x5554; + } + } else { + num_funcs = 1; + eng_mask = 0xfffe; } - tmp = (tmp ^ 0xffffffff) & mask; + /* Get the number of the enabled functions on the engine */ + tmp = (reg_function_hide ^ 0xffffffff) & eng_mask; while (tmp) { if (tmp & 0x1) num_funcs++; tmp >>= 0x1; } + + /* Get the PF index within the enabled functions */ + low_pfs_mask = (0x1 << p_hwfn->abs_pf_id) - 1; + tmp = reg_function_hide & eng_mask & low_pfs_mask; + while (tmp) { + if (tmp & 0x1) + enabled_func_idx--; + tmp >>= 0x1; + } } p_hwfn->num_funcs_on_engine = num_funcs; + p_hwfn->enabled_func_idx = enabled_func_idx; #ifndef ASIC_ONLY - if (CHIP_REV_IS_FPGA(p_hwfn->p_dev)) { + if (CHIP_REV_IS_FPGA(p_dev)) { DP_NOTICE(p_hwfn, false, - "FPGA: Limit number of PFs to 4 [would affect" - " resource allocation, needed for IOV]\n"); + "FPGA: Limit number of PFs to 4 [would affect resource allocation, needed for IOV]\n"); p_hwfn->num_funcs_on_engine = 4; } #endif - DP_VERBOSE(p_hwfn, ECORE_MSG_PROBE, "num_funcs_on_engine = %d\n", - p_hwfn->num_funcs_on_engine); + DP_VERBOSE(p_hwfn, ECORE_MSG_PROBE, + "PF [rel_id %d, abs_id %d] occupies index %d within the %d enabled functions on the engine\n", + p_hwfn->rel_pf_id, p_hwfn->abs_pf_id, + p_hwfn->enabled_func_idx, p_hwfn->num_funcs_on_engine); } static void ecore_hw_info_port_num_bb(struct ecore_hwfn *p_hwfn, @@ -2070,6 +2705,26 @@ static void ecore_hw_info_port_num_ah(struct ecore_hwfn *p_hwfn, p_hwfn->p_dev->num_ports_in_engines = 0; +#ifndef ASIC_ONLY + if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) { + port = ecore_rd(p_hwfn, p_ptt, MISCS_REG_ECO_RESERVED); + switch ((port & 0xf000) >> 12) { + case 1: + p_hwfn->p_dev->num_ports_in_engines = 1; + break; + case 3: + p_hwfn->p_dev->num_ports_in_engines = 2; + break; + case 0xf: + p_hwfn->p_dev->num_ports_in_engines = 4; + break; + default: + DP_NOTICE(p_hwfn, false, + "Unknown port mode in ECO_RESERVED %08x\n", + port); + } + } else +#endif for (i = 0; i < MAX_NUM_PORTS_K2; i++) { port = ecore_rd(p_hwfn, p_ptt, CNIG_REG_NIG_PORT0_CONF_K2 + (i * 4)); @@ -2088,15 +2743,17 @@ static void ecore_hw_info_port_num(struct ecore_hwfn *p_hwfn, } static enum _ecore_status_t -ecore_get_hw_info(struct ecore_hwfn *p_hwfn, - struct ecore_ptt *p_ptt, - enum ecore_pci_personality personality) +ecore_get_hw_info(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, + enum ecore_pci_personality personality, bool drv_resc_alloc) { enum _ecore_status_t rc; - rc = ecore_iov_hw_info(p_hwfn, p_hwfn->p_main_ptt); + /* Since all information is common, only first hwfns should do this */ + if (IS_LEAD_HWFN(p_hwfn)) { + rc = ecore_iov_hw_info(p_hwfn); if (rc) return rc; + } /* TODO In get_hw_info, amoungst others: * Get MCP FW revision and determine according to it the supported @@ -2148,21 +2805,39 @@ ecore_get_hw_info(struct ecore_hwfn *p_hwfn, /* To overcome ILT lack for emulation, until at least until we'll have * a definite answer from system about it, allow only PF0 to be RoCE. */ - if (CHIP_REV_IS_EMUL(p_hwfn->p_dev) && ECORE_IS_AH(p_hwfn->p_dev)) - p_hwfn->hw_info.personality = ECORE_PCI_ETH; + if (CHIP_REV_IS_EMUL(p_hwfn->p_dev) && ECORE_IS_AH(p_hwfn->p_dev)) { + if (!p_hwfn->rel_pf_id) + p_hwfn->hw_info.personality = ECORE_PCI_ETH_ROCE; + else + p_hwfn->hw_info.personality = ECORE_PCI_ETH; + } #endif + /* although in BB some constellations may support more than 4 tcs, + * that can result in performance penalty in some cases. 4 + * represents a good tradeoff between performance and flexibility. + */ + p_hwfn->hw_info.num_hw_tc = NUM_PHYS_TCS_4PORT_K2; + + /* start out with a single active tc. This can be increased either + * by dcbx negotiation or by upper layer driver + */ + p_hwfn->hw_info.num_active_tc = 1; + ecore_get_num_funcs(p_hwfn, p_ptt); - /* Feat num is dependent on personality and on the number of functions - * on the engine. Therefore it should be come after personality - * initialization and after getting the number of functions. + /* In case of forcing the driver's default resource allocation, calling + * ecore_hw_get_resc() should come after initializing the personality + * and after getting the number of functions, since the calculation of + * the resources/features depends on them. + * This order is not harmful if not forcing. */ - return ecore_hw_get_resc(p_hwfn); + return ecore_hw_get_resc(p_hwfn, drv_resc_alloc); } -/* @TMP - this should move to a proper .h */ -#define CHIP_NUM_AH 0x8070 +#define ECORE_DEV_ID_MASK 0xff00 +#define ECORE_DEV_ID_MASK_BB 0x1600 +#define ECORE_DEV_ID_MASK_AH 0x8000 static enum _ecore_status_t ecore_get_dev_info(struct ecore_dev *p_dev) { @@ -2175,6 +2850,12 @@ static enum _ecore_status_t ecore_get_dev_info(struct ecore_dev *p_dev) OSAL_PCI_READ_CONFIG_WORD(p_dev, PCICFG_DEVICE_ID_OFFSET, &p_dev->device_id); + /* Determine type */ + if ((p_dev->device_id & ECORE_DEV_ID_MASK) == ECORE_DEV_ID_MASK_AH) + p_dev->type = ECORE_DEV_TYPE_AH; + else + p_dev->type = ECORE_DEV_TYPE_BB; + p_dev->chip_num = (u16)ecore_rd(p_hwfn, p_hwfn->p_main_ptt, MISCS_REG_CHIP_NUM); p_dev->chip_rev = (u16)ecore_rd(p_hwfn, p_hwfn->p_main_ptt, @@ -2182,12 +2863,6 @@ static enum _ecore_status_t ecore_get_dev_info(struct ecore_dev *p_dev) MASK_FIELD(CHIP_REV, p_dev->chip_rev); - /* Determine type */ - if (p_dev->device_id == CHIP_NUM_AH) - p_dev->type = ECORE_DEV_TYPE_AH; - else - p_dev->type = ECORE_DEV_TYPE_BB; - /* Learn number of HW-functions */ tmp = ecore_rd(p_hwfn, p_hwfn->p_main_ptt, MISCS_REG_CMT_ENABLED_FOR_PAIR); @@ -2217,8 +2892,7 @@ static enum _ecore_status_t ecore_get_dev_info(struct ecore_dev *p_dev) MISCS_REG_CHIP_METAL); MASK_FIELD(CHIP_METAL, p_dev->chip_metal); DP_INFO(p_dev->hwfns, - "Chip details - %s%d, Num: %04x Rev: %04x Bond id: %04x" - " Metal: %04x\n", + "Chip details - %s%d, Num: %04x Rev: %04x Bond id: %04x Metal: %04x\n", ECORE_IS_BB(p_dev) ? "BB" : "AH", CHIP_REV_IS_A0(p_dev) ? 0 : 1, p_dev->chip_num, p_dev->chip_rev, p_dev->chip_bond_id, @@ -2251,6 +2925,7 @@ static enum _ecore_status_t ecore_get_dev_info(struct ecore_dev *p_dev) return ECORE_SUCCESS; } +#ifndef LINUX_REMOVE void ecore_prepare_hibernate(struct ecore_dev *p_dev) { int j; @@ -2266,26 +2941,31 @@ void ecore_prepare_hibernate(struct ecore_dev *p_dev) p_hwfn->hw_init_done = false; p_hwfn->first_on_engine = false; + + ecore_ptt_invalidate(p_hwfn); } } +#endif static enum _ecore_status_t -ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, - void OSAL_IOMEM *p_regview, +ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, void OSAL_IOMEM *p_regview, void OSAL_IOMEM *p_doorbells, - enum ecore_pci_personality personality) + struct ecore_hw_prepare_params *p_params) { + struct ecore_dev *p_dev = p_hwfn->p_dev; enum _ecore_status_t rc = ECORE_SUCCESS; /* Split PCI bars evenly between hwfns */ p_hwfn->regview = p_regview; p_hwfn->doorbells = p_doorbells; + if (IS_VF(p_dev)) + return ecore_vf_hw_prepare(p_hwfn); + /* Validate that chip access is feasible */ if (REG_RD(p_hwfn, PXP_PF_ME_OPAQUE_ADDR) == 0xffffffff) { DP_ERR(p_hwfn, - "Reading the ME register returns all Fs;" - " Preventing further chip access\n"); + "Reading the ME register returns all Fs; Preventing further chip access\n"); return ECORE_INVAL; } @@ -2303,7 +2983,7 @@ ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, /* First hwfn learns basic information, e.g., number of hwfns */ if (!p_hwfn->my_id) { - rc = ecore_get_dev_info(p_hwfn->p_dev); + rc = ecore_get_dev_info(p_dev); if (rc != ECORE_SUCCESS) goto err1; } @@ -2317,8 +2997,15 @@ ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, goto err1; } + if (p_hwfn == ECORE_LEADING_HWFN(p_dev) && !p_dev->recov_in_prog) { + rc = ecore_mcp_initiate_pf_flr(p_hwfn, p_hwfn->p_main_ptt); + if (rc != ECORE_SUCCESS) + DP_NOTICE(p_hwfn, false, "Failed to initiate PF FLR\n"); + } + /* Read the device configuration information from the HW and SHMEM */ - rc = ecore_get_hw_info(p_hwfn, p_hwfn->p_main_ptt, personality); + rc = ecore_get_hw_info(p_hwfn, p_hwfn->p_main_ptt, + p_params->personality, p_params->drv_resc_alloc); if (rc) { DP_NOTICE(p_hwfn, true, "Failed to get HW information\n"); goto err2; @@ -2331,7 +3018,7 @@ ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, goto err2; } #ifndef ASIC_ONLY - if (CHIP_REV_IS_FPGA(p_hwfn->p_dev)) { + if (CHIP_REV_IS_FPGA(p_dev)) { DP_NOTICE(p_hwfn, false, "FPGA: workaround; Prevent DMAE parities\n"); ecore_wr(p_hwfn, p_hwfn->p_main_ptt, PCIE_REG_PRTY_MASK, 7); @@ -2345,6 +3032,8 @@ ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, return rc; err2: + if (IS_LEAD_HWFN(p_hwfn)) + ecore_iov_free_hw_info(p_dev); ecore_mcp_free(p_hwfn); err1: ecore_hw_hwfn_free(p_hwfn); @@ -2352,27 +3041,28 @@ ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, return rc; } -enum _ecore_status_t ecore_hw_prepare(struct ecore_dev *p_dev, int personality) +enum _ecore_status_t ecore_hw_prepare(struct ecore_dev *p_dev, + struct ecore_hw_prepare_params *p_params) { struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev); enum _ecore_status_t rc; - if (IS_VF(p_dev)) - return ecore_vf_hw_prepare(p_dev); + p_dev->chk_reg_fifo = p_params->chk_reg_fifo; /* Store the precompiled init data ptrs */ + if (IS_PF(p_dev)) ecore_init_iro_array(p_dev); /* Initialize the first hwfn - will learn number of hwfns */ rc = ecore_hw_prepare_single(p_hwfn, p_dev->regview, - p_dev->doorbells, personality); + p_dev->doorbells, p_params); if (rc != ECORE_SUCCESS) return rc; - personality = p_hwfn->hw_info.personality; + p_params->personality = p_hwfn->hw_info.personality; - /* initialalize 2nd hwfn if necessary */ + /* initilalize 2nd hwfn if necessary */ if (p_dev->num_hwfns > 1) { void OSAL_IOMEM *p_regview, *p_doorbell; u8 OSAL_IOMEM *addr; @@ -2388,15 +3078,20 @@ enum _ecore_status_t ecore_hw_prepare(struct ecore_dev *p_dev, int personality) /* prepare second hw function */ rc = ecore_hw_prepare_single(&p_dev->hwfns[1], p_regview, - p_doorbell, personality); + p_doorbell, p_params); /* in case of error, need to free the previously - * initialiazed hwfn 0 + * initiliazed hwfn 0. */ if (rc != ECORE_SUCCESS) { - ecore_init_free(p_hwfn); - ecore_mcp_free(p_hwfn); - ecore_hw_hwfn_free(p_hwfn); + if (IS_PF(p_dev)) { + ecore_init_free(p_hwfn); + ecore_mcp_free(p_hwfn); + ecore_hw_hwfn_free(p_hwfn); + } else { + DP_NOTICE(p_dev, true, + "What do we need to free when VF hwfn1 init fails\n"); + } return rc; } } @@ -2422,6 +3117,8 @@ void ecore_hw_remove(struct ecore_dev *p_dev) OSAL_MUTEX_DEALLOC(&p_hwfn->dmae_info.mutex); } + + ecore_iov_free_hw_info(p_dev); } static void ecore_chain_free_next_ptr(struct ecore_dev *p_dev, @@ -2527,8 +3224,7 @@ ecore_chain_alloc_sanity_check(struct ecore_dev *p_dev, (cnt_type == ECORE_CHAIN_CNT_TYPE_U32 && chain_size > ECORE_U32_MAX)) { DP_NOTICE(p_dev, true, - "The actual chain size (0x%lx) is larger than" - " the maximal possible value\n", + "The actual chain size (0x%lx) is larger than the maximal possible value\n", (unsigned long)chain_size); return ECORE_INVAL; } @@ -2603,25 +3299,26 @@ static enum _ecore_status_t ecore_chain_alloc_pbl(struct ecore_dev *p_dev, pp_virt_addr_tbl = (void **)OSAL_VALLOC(p_dev, size); if (!pp_virt_addr_tbl) { DP_NOTICE(p_dev, true, - "Failed to allocate memory for the chain" - " virtual addresses table\n"); + "Failed to allocate memory for the chain virtual addresses table\n"); return ECORE_NOMEM; } OSAL_MEM_ZERO(pp_virt_addr_tbl, size); /* The allocation of the PBL table is done with its full size, since it * is expected to be successive. + * ecore_chain_init_pbl_mem() is called even in a case of an allocation + * failure, since pp_virt_addr_tbl was previously allocated, and it + * should be saved to allow its freeing during the error flow. */ size = page_cnt * ECORE_CHAIN_PBL_ENTRY_SIZE; p_pbl_virt = OSAL_DMA_ALLOC_COHERENT(p_dev, &p_pbl_phys, size); + ecore_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys, + pp_virt_addr_tbl); if (!p_pbl_virt) { DP_NOTICE(p_dev, true, "Failed to allocate chain pbl memory\n"); return ECORE_NOMEM; } - ecore_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys, - pp_virt_addr_tbl); - for (i = 0; i < page_cnt; i++) { p_virt = OSAL_DMA_ALLOC_COHERENT(p_dev, &p_phys, ECORE_CHAIN_PAGE_SIZE); @@ -2667,14 +3364,13 @@ enum _ecore_status_t ecore_chain_alloc(struct ecore_dev *p_dev, if (rc) { DP_NOTICE(p_dev, true, "Cannot allocate a chain with the given arguments:\n" - " [use_mode %d, mode %d, cnt_type %d, num_elems %d," - " elem_size %zu]\n", + "[use_mode %d, mode %d, cnt_type %d, num_elems %d, elem_size %zu]\n", intended_use, mode, cnt_type, num_elems, elem_size); return rc; } ecore_chain_init_params(p_chain, page_cnt, (u8)elem_size, intended_use, - mode, cnt_type); + mode, cnt_type, p_dev->dp_ctx); switch (mode) { case ECORE_CHAIN_MODE_NEXT_PTR: @@ -2706,8 +3402,7 @@ enum _ecore_status_t ecore_fw_l2_queue(struct ecore_hwfn *p_hwfn, min = (u16)RESC_START(p_hwfn, ECORE_L2_QUEUE); max = min + RESC_NUM(p_hwfn, ECORE_L2_QUEUE); DP_NOTICE(p_hwfn, true, - "l2_queue id [%d] is not valid, available" - " indices [%d - %d]\n", + "l2_queue id [%d] is not valid, available indices [%d - %d]\n", src_id, min, max); return ECORE_INVAL; @@ -2727,8 +3422,7 @@ enum _ecore_status_t ecore_fw_vport(struct ecore_hwfn *p_hwfn, min = (u8)RESC_START(p_hwfn, ECORE_VPORT); max = min + RESC_NUM(p_hwfn, ECORE_VPORT); DP_NOTICE(p_hwfn, true, - "vport id [%d] is not valid, available" - " indices [%d - %d]\n", + "vport id [%d] is not valid, available indices [%d - %d]\n", src_id, min, max); return ECORE_INVAL; @@ -2748,7 +3442,7 @@ enum _ecore_status_t ecore_fw_rss_eng(struct ecore_hwfn *p_hwfn, min = (u8)RESC_START(p_hwfn, ECORE_RSS_ENG); max = min + RESC_NUM(p_hwfn, ECORE_RSS_ENG); DP_NOTICE(p_hwfn, true, - "rss_eng id [%d] is not valid,avail idx [%d - %d]\n", + "rss_eng id [%d] is not valid, available indices [%d - %d]\n", src_id, min, max); return ECORE_INVAL; @@ -2847,9 +3541,12 @@ void ecore_llh_remove_mac_filter(struct ecore_hwfn *p_hwfn, "Tried to remove a non-configured filter\n"); } -enum _ecore_status_t ecore_llh_add_ethertype_filter(struct ecore_hwfn *p_hwfn, +enum _ecore_status_t +ecore_llh_add_protocol_filter(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, - u16 filter) + u16 source_port_or_eth_type, + u16 dest_port, + enum ecore_llh_port_filter_type_t type) { u32 high, low, en; int i; @@ -2857,9 +3554,29 @@ enum _ecore_status_t ecore_llh_add_ethertype_filter(struct ecore_hwfn *p_hwfn, if (!(IS_MF_SI(p_hwfn) || IS_MF_DEFAULT(p_hwfn))) return ECORE_SUCCESS; - high = filter; + high = 0; low = 0; - + switch (type) { + case ECORE_LLH_FILTER_ETHERTYPE: + high = source_port_or_eth_type; + break; + case ECORE_LLH_FILTER_TCP_SRC_PORT: + case ECORE_LLH_FILTER_UDP_SRC_PORT: + low = source_port_or_eth_type << 16; + break; + case ECORE_LLH_FILTER_TCP_DEST_PORT: + case ECORE_LLH_FILTER_UDP_DEST_PORT: + low = dest_port; + break; + case ECORE_LLH_FILTER_TCP_SRC_AND_DEST_PORT: + case ECORE_LLH_FILTER_UDP_SRC_AND_DEST_PORT: + low = (source_port_or_eth_type << 16) | dest_port; + break; + default: + DP_NOTICE(p_hwfn, true, + "Non valid LLH protocol filter type %d\n", type); + return ECORE_INVAL; + } /* Find a free entry and utilize it */ for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) { en = ecore_rd(p_hwfn, p_ptt, @@ -2876,7 +3593,7 @@ enum _ecore_status_t ecore_llh_add_ethertype_filter(struct ecore_hwfn *p_hwfn, NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32), 1); ecore_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE + - i * sizeof(u32), 1); + i * sizeof(u32), 1 << type); ecore_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32), 1); break; @@ -2884,17 +3601,52 @@ enum _ecore_status_t ecore_llh_add_ethertype_filter(struct ecore_hwfn *p_hwfn, if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE) { DP_NOTICE(p_hwfn, false, "Failed to find an empty LLH filter to utilize\n"); - return ECORE_INVAL; + return ECORE_NORESOURCES; } - + switch (type) { + case ECORE_LLH_FILTER_ETHERTYPE: DP_VERBOSE(p_hwfn, ECORE_MSG_HW, - "ETH type: %x is added at %d\n", filter, i); - + "ETH type %x is added at %d\n", + source_port_or_eth_type, i); + break; + case ECORE_LLH_FILTER_TCP_SRC_PORT: + DP_VERBOSE(p_hwfn, ECORE_MSG_HW, + "TCP src port %x is added at %d\n", + source_port_or_eth_type, i); + break; + case ECORE_LLH_FILTER_UDP_SRC_PORT: + DP_VERBOSE(p_hwfn, ECORE_MSG_HW, + "UDP src port %x is added at %d\n", + source_port_or_eth_type, i); + break; + case ECORE_LLH_FILTER_TCP_DEST_PORT: + DP_VERBOSE(p_hwfn, ECORE_MSG_HW, + "TCP dst port %x is added at %d\n", dest_port, i); + break; + case ECORE_LLH_FILTER_UDP_DEST_PORT: + DP_VERBOSE(p_hwfn, ECORE_MSG_HW, + "UDP dst port %x is added at %d\n", dest_port, i); + break; + case ECORE_LLH_FILTER_TCP_SRC_AND_DEST_PORT: + DP_VERBOSE(p_hwfn, ECORE_MSG_HW, + "TCP src/dst ports %x/%x are added at %d\n", + source_port_or_eth_type, dest_port, i); + break; + case ECORE_LLH_FILTER_UDP_SRC_AND_DEST_PORT: + DP_VERBOSE(p_hwfn, ECORE_MSG_HW, + "UDP src/dst ports %x/%x are added at %d\n", + source_port_or_eth_type, dest_port, i); + break; + } return ECORE_SUCCESS; } -void ecore_llh_remove_ethertype_filter(struct ecore_hwfn *p_hwfn, - struct ecore_ptt *p_ptt, u16 filter) +void +ecore_llh_remove_protocol_filter(struct ecore_hwfn *p_hwfn, + struct ecore_ptt *p_ptt, + u16 source_port_or_eth_type, + u16 dest_port, + enum ecore_llh_port_filter_type_t type) { u32 high, low; int i; @@ -2902,11 +3654,41 @@ void ecore_llh_remove_ethertype_filter(struct ecore_hwfn *p_hwfn, if (!(IS_MF_SI(p_hwfn) || IS_MF_DEFAULT(p_hwfn))) return; - high = filter; + high = 0; low = 0; + switch (type) { + case ECORE_LLH_FILTER_ETHERTYPE: + high = source_port_or_eth_type; + break; + case ECORE_LLH_FILTER_TCP_SRC_PORT: + case ECORE_LLH_FILTER_UDP_SRC_PORT: + low = source_port_or_eth_type << 16; + break; + case ECORE_LLH_FILTER_TCP_DEST_PORT: + case ECORE_LLH_FILTER_UDP_DEST_PORT: + low = dest_port; + break; + case ECORE_LLH_FILTER_TCP_SRC_AND_DEST_PORT: + case ECORE_LLH_FILTER_UDP_SRC_AND_DEST_PORT: + low = (source_port_or_eth_type << 16) | dest_port; + break; + default: + DP_NOTICE(p_hwfn, true, + "Non valid LLH protocol filter type %d\n", type); + return; + } - /* Find the entry and clean it */ for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) { + if (!ecore_rd(p_hwfn, p_ptt, + NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32))) + continue; + if (!ecore_rd(p_hwfn, p_ptt, + NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32))) + continue; + if (!(ecore_rd(p_hwfn, p_ptt, + NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE + + i * sizeof(u32)) & (1 << type))) + continue; if (ecore_rd(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * i * sizeof(u32)) != low) @@ -2918,6 +3700,11 @@ void ecore_llh_remove_ethertype_filter(struct ecore_hwfn *p_hwfn, ecore_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32), 0); + ecore_wr(p_hwfn, p_ptt, + NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32), 0); + ecore_wr(p_hwfn, p_ptt, + NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE + + i * sizeof(u32), 0); ecore_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * i * sizeof(u32), 0); @@ -2926,6 +3713,7 @@ void ecore_llh_remove_ethertype_filter(struct ecore_hwfn *p_hwfn, (2 * i + 1) * sizeof(u32), 0); break; } + if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE) DP_NOTICE(p_hwfn, false, "Tried to remove a non-configured filter\n"); @@ -2951,97 +3739,30 @@ void ecore_llh_clear_all_filters(struct ecore_hwfn *p_hwfn, } } -enum _ecore_status_t ecore_test_registers(struct ecore_hwfn *p_hwfn, +enum _ecore_status_t +ecore_llh_set_function_as_default(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) { - u32 reg_tbl[] = { - BRB_REG_HEADER_SIZE, - BTB_REG_HEADER_SIZE, - CAU_REG_LONG_TIMEOUT_THRESHOLD, - CCFC_REG_ACTIVITY_COUNTER, - CDU_REG_CID_ADDR_PARAMS, - DBG_REG_CLIENT_ENABLE, - DMAE_REG_INIT, - DORQ_REG_IFEN, - GRC_REG_TIMEOUT_EN, - IGU_REG_BLOCK_CONFIGURATION, - MCM_REG_INIT, - MCP2_REG_DBG_DWORD_ENABLE, - MISC_REG_PORT_MODE, - MISCS_REG_CLK_100G_MODE, - MSDM_REG_ENABLE_IN1, - MSEM_REG_ENABLE_IN, - NIG_REG_CM_HDR, - NCSI_REG_CONFIG, - PBF_REG_INIT, - PTU_REG_ATC_INIT_ARRAY, - PCM_REG_INIT, - PGLUE_B_REG_ADMIN_PER_PF_REGION, - PRM_REG_DISABLE_PRM, - PRS_REG_SOFT_RST, - PSDM_REG_ENABLE_IN1, - PSEM_REG_ENABLE_IN, - PSWRQ_REG_DBG_SELECT, - PSWRQ2_REG_CDUT_P_SIZE, - PSWHST_REG_DISCARD_INTERNAL_WRITES, - PSWHST2_REG_DBGSYN_ALMOST_FULL_THR, - PSWRD_REG_DBG_SELECT, - PSWRD2_REG_CONF11, - PSWWR_REG_USDM_FULL_TH, - PSWWR2_REG_CDU_FULL_TH2, - QM_REG_MAXPQSIZE_0, - RSS_REG_RSS_INIT_EN, - RDIF_REG_STOP_ON_ERROR, - SRC_REG_SOFT_RST, - TCFC_REG_ACTIVITY_COUNTER, - TCM_REG_INIT, - TM_REG_PXP_READ_DATA_FIFO_INIT, - TSDM_REG_ENABLE_IN1, - TSEM_REG_ENABLE_IN, - TDIF_REG_STOP_ON_ERROR, - UCM_REG_INIT, - UMAC_REG_IPG_HD_BKP_CNTL_BB_B0, - USDM_REG_ENABLE_IN1, - USEM_REG_ENABLE_IN, - XCM_REG_INIT, - XSDM_REG_ENABLE_IN1, - XSEM_REG_ENABLE_IN, - YCM_REG_INIT, - YSDM_REG_ENABLE_IN1, - YSEM_REG_ENABLE_IN, - XYLD_REG_SCBD_STRICT_PRIO, - TMLD_REG_SCBD_STRICT_PRIO, - MULD_REG_SCBD_STRICT_PRIO, - YULD_REG_SCBD_STRICT_PRIO, - }; - u32 test_val[] = { 0x0, 0x1 }; - u32 val, save_val, i, j; - - for (i = 0; i < OSAL_ARRAY_SIZE(test_val); i++) { - for (j = 0; j < OSAL_ARRAY_SIZE(reg_tbl); j++) { - save_val = ecore_rd(p_hwfn, p_ptt, reg_tbl[j]); - ecore_wr(p_hwfn, p_ptt, reg_tbl[j], test_val[i]); - val = ecore_rd(p_hwfn, p_ptt, reg_tbl[j]); - /* Restore the original register's value */ - ecore_wr(p_hwfn, p_ptt, reg_tbl[j], save_val); - if (val != test_val[i]) { - DP_INFO(p_hwfn->p_dev, - "offset 0x%x: val 0x%x != 0x%x\n", - reg_tbl[j], val, test_val[i]); - return ECORE_AGAIN; - } - } - } + if (IS_MF_DEFAULT(p_hwfn) && ECORE_IS_BB(p_hwfn->p_dev)) { + ecore_wr(p_hwfn, p_ptt, + NIG_REG_LLH_TAGMAC_DEF_PF_VECTOR, + 1 << p_hwfn->abs_pf_id / 2); + ecore_wr(p_hwfn, p_ptt, PRS_REG_MSG_INFO, 0); return ECORE_SUCCESS; } + DP_NOTICE(p_hwfn, false, + "This function can't be set as default\n"); + return ECORE_INVAL; +} + static enum _ecore_status_t ecore_set_coalesce(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, - u32 hw_addr, void *p_qzone, - osal_size_t qzone_size, + u32 hw_addr, void *p_eth_qzone, + osal_size_t eth_qzone_size, u8 timeset) { - struct coalescing_timeset *p_coalesce_timeset; + struct coalescing_timeset *p_coal_timeset; if (IS_VF(p_hwfn->p_dev)) { DP_NOTICE(p_hwfn, true, "VF coalescing config not supported\n"); @@ -3054,34 +3775,49 @@ static enum _ecore_status_t ecore_set_coalesce(struct ecore_hwfn *p_hwfn, return ECORE_INVAL; } - OSAL_MEMSET(p_qzone, 0, qzone_size); - p_coalesce_timeset = p_qzone; - ecore_memcpy_to(p_hwfn, p_ptt, hw_addr, p_qzone, qzone_size); + OSAL_MEMSET(p_eth_qzone, 0, eth_qzone_size); + p_coal_timeset = p_eth_qzone; + SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_TIMESET, timeset); + SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_VALID, 1); + ecore_memcpy_to(p_hwfn, p_ptt, hw_addr, p_eth_qzone, eth_qzone_size); return ECORE_SUCCESS; } enum _ecore_status_t ecore_set_rxq_coalesce(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, - u8 coalesce, u8 qid) + u16 coalesce, u8 qid, u16 sb_id) { - struct ustorm_eth_queue_zone qzone; + struct ustorm_eth_queue_zone eth_qzone; u16 fw_qid = 0; u32 address; - u8 timeset; enum _ecore_status_t rc; + u8 timeset, timer_res; + + /* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */ + if (coalesce <= 0x7F) { + timer_res = 0; + } else if (coalesce <= 0xFF) { + timer_res = 1; + } else if (coalesce <= 0x1FF) { + timer_res = 2; + } else { + DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce); + return ECORE_INVAL; + } + timeset = (u8)(coalesce >> timer_res); rc = ecore_fw_l2_queue(p_hwfn, (u16)qid, &fw_qid); if (rc != ECORE_SUCCESS) return rc; + rc = ecore_int_set_timer_res(p_hwfn, p_ptt, timer_res, sb_id, false); + if (rc != ECORE_SUCCESS) + goto out; + address = BAR0_MAP_REG_USDM_RAM + USTORM_ETH_QUEUE_ZONE_OFFSET(fw_qid); - /* Translate the coalescing time into a timeset, according to: - * Timeout[Rx] = TimeSet[Rx] << (TimerRes[Rx] + 1) - */ - timeset = coalesce >> (ECORE_CAU_DEF_RX_TIMER_RES + 1); - rc = ecore_set_coalesce(p_hwfn, p_ptt, address, &qzone, + rc = ecore_set_coalesce(p_hwfn, p_ptt, address, ð_qzone, sizeof(struct ustorm_eth_queue_zone), timeset); if (rc != ECORE_SUCCESS) goto out; @@ -3093,26 +3829,40 @@ enum _ecore_status_t ecore_set_rxq_coalesce(struct ecore_hwfn *p_hwfn, enum _ecore_status_t ecore_set_txq_coalesce(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, - u8 coalesce, u8 qid) + u16 coalesce, u8 qid, u16 sb_id) { - struct ystorm_eth_queue_zone qzone; + struct xstorm_eth_queue_zone eth_qzone; u16 fw_qid = 0; u32 address; - u8 timeset; enum _ecore_status_t rc; + u8 timeset, timer_res; + + /* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */ + if (coalesce <= 0x7F) { + timer_res = 0; + } else if (coalesce <= 0xFF) { + timer_res = 1; + } else if (coalesce <= 0x1FF) { + timer_res = 2; + } else { + DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce); + return ECORE_INVAL; + } + + timeset = (u8)(coalesce >> timer_res); rc = ecore_fw_l2_queue(p_hwfn, (u16)qid, &fw_qid); if (rc != ECORE_SUCCESS) return rc; - address = BAR0_MAP_REG_YSDM_RAM + YSTORM_ETH_QUEUE_ZONE_OFFSET(fw_qid); - /* Translate the coalescing time into a timeset, according to: - * Timeout[Tx] = TimeSet[Tx] << (TimerRes[Tx] + 1) - */ - timeset = coalesce >> (ECORE_CAU_DEF_TX_TIMER_RES + 1); + rc = ecore_int_set_timer_res(p_hwfn, p_ptt, timer_res, sb_id, true); + if (rc != ECORE_SUCCESS) + goto out; + + address = BAR0_MAP_REG_XSDM_RAM + XSTORM_ETH_QUEUE_ZONE_OFFSET(fw_qid); - rc = ecore_set_coalesce(p_hwfn, p_ptt, address, &qzone, - sizeof(struct ystorm_eth_queue_zone), timeset); + rc = ecore_set_coalesce(p_hwfn, p_ptt, address, ð_qzone, + sizeof(struct xstorm_eth_queue_zone), timeset); if (rc != ECORE_SUCCESS) goto out; @@ -3130,16 +3880,15 @@ static void ecore_configure_wfq_for_all_vports(struct ecore_hwfn *p_hwfn, u32 min_pf_rate) { struct init_qm_vport_params *vport_params; - int i, num_vports; + int i; vport_params = p_hwfn->qm_info.qm_vport_params; - num_vports = p_hwfn->qm_info.num_vports; - for (i = 0; i < num_vports; i++) { + for (i = 0; i < p_hwfn->qm_info.num_vports; i++) { u32 wfq_speed = p_hwfn->qm_info.wfq_data[i].min_speed; - vport_params[i].vport_wfq = - (wfq_speed * ECORE_WFQ_UNIT) / min_pf_rate; + vport_params[i].vport_wfq = (wfq_speed * ECORE_WFQ_UNIT) / + min_pf_rate; ecore_init_vport_wfq(p_hwfn, p_ptt, vport_params[i].first_tx_pq_id, vport_params[i].vport_wfq); @@ -3149,16 +3898,10 @@ static void ecore_configure_wfq_for_all_vports(struct ecore_hwfn *p_hwfn, static void ecore_init_wfq_default_param(struct ecore_hwfn *p_hwfn, u32 min_pf_rate) { - int i, num_vports; - u32 min_speed; - - num_vports = p_hwfn->qm_info.num_vports; - min_speed = min_pf_rate / num_vports; + int i; - for (i = 0; i < num_vports; i++) { + for (i = 0; i < p_hwfn->qm_info.num_vports; i++) p_hwfn->qm_info.qm_vport_params[i].vport_wfq = 1; - p_hwfn->qm_info.wfq_data[i].default_min_speed = min_speed; - } } static void ecore_disable_wfq_for_all_vports(struct ecore_hwfn *p_hwfn, @@ -3166,12 +3909,11 @@ static void ecore_disable_wfq_for_all_vports(struct ecore_hwfn *p_hwfn, u32 min_pf_rate) { struct init_qm_vport_params *vport_params; - int i, num_vports; + int i; vport_params = p_hwfn->qm_info.qm_vport_params; - num_vports = p_hwfn->qm_info.num_vports; - for (i = 0; i < num_vports; i++) { + for (i = 0; i < p_hwfn->qm_info.num_vports; i++) { ecore_init_wfq_default_param(p_hwfn, min_pf_rate); ecore_init_vport_wfq(p_hwfn, p_ptt, vport_params[i].first_tx_pq_id, @@ -3179,7 +3921,13 @@ static void ecore_disable_wfq_for_all_vports(struct ecore_hwfn *p_hwfn, } } -/* validate wfq for a given vport and required min rate */ +/* This function performs several validations for WFQ + * configuration and required min rate for a given vport + * 1. req_rate must be greater than one percent of min_pf_rate. + * 2. req_rate should not cause other vports [not configured for WFQ explicitly] + * rates to get less than one percent of min_pf_rate. + * 3. total_req_min_rate [all vports min rate sum] shouldn't exceed min_pf_rate. + */ static enum _ecore_status_t ecore_init_wfq_param(struct ecore_hwfn *p_hwfn, u16 vport_id, u32 req_rate, u32 min_pf_rate) @@ -3189,7 +3937,8 @@ static enum _ecore_status_t ecore_init_wfq_param(struct ecore_hwfn *p_hwfn, num_vports = p_hwfn->qm_info.num_vports; - /* Check pre-set data for some of the vports */ +/* Accounting for the vports which are configured for WFQ explicitly */ + for (i = 0; i < num_vports; i++) { u32 tmp_speed; @@ -3203,36 +3952,34 @@ static enum _ecore_status_t ecore_init_wfq_param(struct ecore_hwfn *p_hwfn, /* Include current vport data as well */ req_count++; total_req_min_rate += req_rate; - non_requested_count = p_hwfn->qm_info.num_vports - req_count; + non_requested_count = num_vports - req_count; /* validate possible error cases */ if (req_rate > min_pf_rate) { DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, - "Vport [%d] - Requested rate[%d Mbps] is greater" - " than configured PF min rate[%d Mbps]\n", + "Vport [%d] - Requested rate[%d Mbps] is greater than configured PF min rate[%d Mbps]\n", vport_id, req_rate, min_pf_rate); return ECORE_INVAL; } - if (req_rate * ECORE_WFQ_UNIT / min_pf_rate < 1) { + if (req_rate < min_pf_rate / ECORE_WFQ_UNIT) { DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, - "Vport [%d] - Requested rate[%d Mbps] is less than" - " one percent of configured PF min rate[%d Mbps]\n", + "Vport [%d] - Requested rate[%d Mbps] is less than one percent of configured PF min rate[%d Mbps]\n", vport_id, req_rate, min_pf_rate); return ECORE_INVAL; } /* TBD - for number of vports greater than 100 */ - if (ECORE_WFQ_UNIT / p_hwfn->qm_info.num_vports < 1) { + if (num_vports > ECORE_WFQ_UNIT) { DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, - "Number of vports are greater than 100\n"); + "Number of vports is greater than %d\n", + ECORE_WFQ_UNIT); return ECORE_INVAL; } if (total_req_min_rate > min_pf_rate) { DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, - "Total requested min rate for all vports[%d Mbps]" - "is greater than configured PF min rate[%d Mbps]\n", + "Total requested min rate for all vports[%d Mbps] is greater than configured PF min rate[%d Mbps]\n", total_req_min_rate, min_pf_rate); return ECORE_INVAL; } @@ -3242,8 +3989,12 @@ static enum _ecore_status_t ecore_init_wfq_param(struct ecore_hwfn *p_hwfn, left_rate_per_vp = total_left_rate / non_requested_count; /* validate if non requested get < 1% of min bw */ - if (left_rate_per_vp * ECORE_WFQ_UNIT / min_pf_rate < 1) + if (left_rate_per_vp < min_pf_rate / ECORE_WFQ_UNIT) { + DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, + "Non WFQ configured vports rate [%d Mbps] is less than one percent of configured PF min rate[%d Mbps]\n", + left_rate_per_vp, min_pf_rate); return ECORE_INVAL; + } /* now req_rate for given vport passes all scenarios. * assign final wfq rates to all vports. @@ -3292,27 +4043,27 @@ static int __ecore_configure_vp_wfq_on_link_change(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, u32 min_pf_rate) { - int rc = ECORE_SUCCESS; bool use_wfq = false; - u16 i, num_vports; - - num_vports = p_hwfn->qm_info.num_vports; + int rc = ECORE_SUCCESS; + u16 i; /* Validate all pre configured vports for wfq */ - for (i = 0; i < num_vports; i++) { - if (p_hwfn->qm_info.wfq_data[i].configured) { - u32 rate = p_hwfn->qm_info.wfq_data[i].min_speed; + for (i = 0; i < p_hwfn->qm_info.num_vports; i++) { + u32 rate; + + if (!p_hwfn->qm_info.wfq_data[i].configured) + continue; + rate = p_hwfn->qm_info.wfq_data[i].min_speed; use_wfq = true; + rc = ecore_init_wfq_param(p_hwfn, i, rate, min_pf_rate); - if (rc == ECORE_INVAL) { + if (rc != ECORE_SUCCESS) { DP_NOTICE(p_hwfn, false, - "Validation failed while" - " configuring min rate\n"); + "WFQ validation failed while configuring min rate\n"); break; } } - } if (rc == ECORE_SUCCESS && use_wfq) ecore_configure_wfq_for_all_vports(p_hwfn, p_ptt, min_pf_rate); @@ -3333,7 +4084,7 @@ int ecore_configure_vport_wfq(struct ecore_dev *p_dev, u16 vp_id, u32 rate) /* TBD - for multiple hardware functions - that is 100 gig */ if (p_dev->num_hwfns > 1) { DP_NOTICE(p_dev, false, - "WFQ configuration is not supported for this dev\n"); + "WFQ configuration is not supported for this device\n"); return rc; } @@ -3367,7 +4118,7 @@ void ecore_configure_vp_wfq_on_link_change(struct ecore_dev *p_dev, /* TBD - for multiple hardware functions - that is 100 gig */ if (p_dev->num_hwfns > 1) { DP_VERBOSE(p_dev, ECORE_MSG_LINK, - "WFQ configuration is not supported for this dev\n"); + "WFQ configuration is not supported for this device\n"); return; } @@ -3389,12 +4140,21 @@ int __ecore_configure_pf_max_bandwidth(struct ecore_hwfn *p_hwfn, p_hwfn->mcp_info->func_info.bandwidth_max = max_bw; - if (!p_link->line_speed) + if (!p_link->line_speed && (max_bw != 100)) return rc; p_link->speed = (p_link->line_speed * max_bw) / 100; + p_hwfn->qm_info.pf_rl = p_link->speed; - rc = ecore_init_pf_rl(p_hwfn, p_ptt, p_hwfn->rel_pf_id, p_link->speed); + /* Since the limiter also affects Tx-switched traffic, we don't want it + * to limit such traffic in case there's no actual limit. + * In that case, set limit to imaginary high boundary. + */ + if (max_bw == 100) + p_hwfn->qm_info.pf_rl = 100000; + + rc = ecore_init_pf_rl(p_hwfn, p_ptt, p_hwfn->rel_pf_id, + p_hwfn->qm_info.pf_rl); DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, "Configured MAX bandwidth to be %08x Mb/sec\n", @@ -3427,12 +4187,11 @@ int ecore_configure_pf_max_bandwidth(struct ecore_dev *p_dev, u8 max_bw) rc = __ecore_configure_pf_max_bandwidth(p_hwfn, p_ptt, p_link, max_bw); - if (rc != ECORE_SUCCESS) { - ecore_ptt_release(p_hwfn, p_ptt); - return rc; - } ecore_ptt_release(p_hwfn, p_ptt); + + if (rc != ECORE_SUCCESS) + break; } return rc; @@ -3446,6 +4205,7 @@ int __ecore_configure_pf_min_bandwidth(struct ecore_hwfn *p_hwfn, int rc = ECORE_SUCCESS; p_hwfn->mcp_info->func_info.bandwidth_min = min_bw; + p_hwfn->qm_info.pf_wfq = min_bw; if (!p_link->line_speed) return rc;