+
+static void
+ecore_dcbx_set_pfc_data(struct ecore_hwfn *p_hwfn,
+ u32 *pfc, struct ecore_dcbx_params *p_params)
+{
+ u8 pfc_map = 0;
+ int i;
+
+ if (p_params->pfc.willing)
+ *pfc |= DCBX_PFC_WILLING_MASK;
+ else
+ *pfc &= ~DCBX_PFC_WILLING_MASK;
+
+ if (p_params->pfc.enabled)
+ *pfc |= DCBX_PFC_ENABLED_MASK;
+ else
+ *pfc &= ~DCBX_PFC_ENABLED_MASK;
+
+ *pfc &= ~DCBX_PFC_CAPS_MASK;
+ *pfc |= (u32)p_params->pfc.max_tc << DCBX_PFC_CAPS_SHIFT;
+
+ for (i = 0; i < ECORE_MAX_PFC_PRIORITIES; i++)
+ if (p_params->pfc.prio[i])
+ pfc_map |= (0x1 << i);
+
+ *pfc |= (pfc_map << DCBX_PFC_PRI_EN_BITMAP_SHIFT);
+
+ DP_VERBOSE(p_hwfn, ECORE_MSG_DCB, "pfc = 0x%x\n", *pfc);
+}
+
+static void
+ecore_dcbx_set_ets_data(struct ecore_hwfn *p_hwfn,
+ struct dcbx_ets_feature *p_ets,
+ struct ecore_dcbx_params *p_params)
+{
+ u8 *bw_map, *tsa_map;
+ int i;
+
+ if (p_params->ets_willing)
+ p_ets->flags |= DCBX_ETS_WILLING_MASK;
+ else
+ p_ets->flags &= ~DCBX_ETS_WILLING_MASK;
+
+ if (p_params->ets_cbs)
+ p_ets->flags |= DCBX_ETS_CBS_MASK;
+ else
+ p_ets->flags &= ~DCBX_ETS_CBS_MASK;
+
+ if (p_params->ets_enabled)
+ p_ets->flags |= DCBX_ETS_ENABLED_MASK;
+ else
+ p_ets->flags &= ~DCBX_ETS_ENABLED_MASK;
+
+ p_ets->flags &= ~DCBX_ETS_MAX_TCS_MASK;
+ p_ets->flags |= (u32)p_params->max_ets_tc << DCBX_ETS_MAX_TCS_SHIFT;
+
+ bw_map = (u8 *)&p_ets->tc_bw_tbl[0];
+ tsa_map = (u8 *)&p_ets->tc_tsa_tbl[0];
+ p_ets->pri_tc_tbl[0] = 0;
+ for (i = 0; i < ECORE_MAX_PFC_PRIORITIES; i++) {
+ bw_map[i] = p_params->ets_tc_bw_tbl[i];
+ tsa_map[i] = p_params->ets_tc_tsa_tbl[i];
+ p_ets->pri_tc_tbl[0] |= (((u32)p_params->ets_pri_tc_tbl[i]) <<
+ ((7 - i) * 4));
+ }
+ p_ets->pri_tc_tbl[0] = OSAL_CPU_TO_BE32(p_ets->pri_tc_tbl[0]);
+ for (i = 0; i < 2; i++) {
+ p_ets->tc_bw_tbl[i] = OSAL_CPU_TO_BE32(p_ets->tc_bw_tbl[i]);
+ p_ets->tc_tsa_tbl[i] = OSAL_CPU_TO_BE32(p_ets->tc_tsa_tbl[i]);
+ }
+}
+
+static void
+ecore_dcbx_set_app_data(struct ecore_hwfn *p_hwfn,
+ struct dcbx_app_priority_feature *p_app,
+ struct ecore_dcbx_params *p_params, bool ieee)
+{
+ u32 *entry;
+ int i;
+
+ if (p_params->app_willing)
+ p_app->flags |= DCBX_APP_WILLING_MASK;
+ else
+ p_app->flags &= ~DCBX_APP_WILLING_MASK;
+
+ if (p_params->app_valid)
+ p_app->flags |= DCBX_APP_ENABLED_MASK;
+ else
+ p_app->flags &= ~DCBX_APP_ENABLED_MASK;
+
+ p_app->flags &= ~DCBX_APP_NUM_ENTRIES_MASK;
+ p_app->flags |= (u32)p_params->num_app_entries <<
+ DCBX_APP_NUM_ENTRIES_SHIFT;
+
+ for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) {
+ entry = &p_app->app_pri_tbl[i].entry;
+ if (ieee) {
+ *entry &= ~DCBX_APP_SF_IEEE_MASK;
+ switch (p_params->app_entry[i].sf_ieee) {
+ case ECORE_DCBX_SF_IEEE_ETHTYPE:
+ *entry |= ((u32)DCBX_APP_SF_IEEE_ETHTYPE <<
+ DCBX_APP_SF_IEEE_SHIFT);
+ break;
+ case ECORE_DCBX_SF_IEEE_TCP_PORT:
+ *entry |= ((u32)DCBX_APP_SF_IEEE_TCP_PORT <<
+ DCBX_APP_SF_IEEE_SHIFT);
+ break;
+ case ECORE_DCBX_SF_IEEE_UDP_PORT:
+ *entry |= ((u32)DCBX_APP_SF_IEEE_UDP_PORT <<
+ DCBX_APP_SF_IEEE_SHIFT);
+ break;
+ case ECORE_DCBX_SF_IEEE_TCP_UDP_PORT:
+ *entry |= (u32)DCBX_APP_SF_IEEE_TCP_UDP_PORT <<
+ DCBX_APP_SF_IEEE_SHIFT;
+ break;
+ }
+ } else {
+ *entry &= ~DCBX_APP_SF_MASK;
+ if (p_params->app_entry[i].ethtype)
+ *entry |= ((u32)DCBX_APP_SF_ETHTYPE <<
+ DCBX_APP_SF_SHIFT);
+ else
+ *entry |= ((u32)DCBX_APP_SF_PORT <<
+ DCBX_APP_SF_SHIFT);
+ }
+ *entry &= ~DCBX_APP_PROTOCOL_ID_MASK;
+ *entry |= ((u32)p_params->app_entry[i].proto_id <<
+ DCBX_APP_PROTOCOL_ID_SHIFT);
+ *entry &= ~DCBX_APP_PRI_MAP_MASK;
+ *entry |= ((u32)(p_params->app_entry[i].prio) <<
+ DCBX_APP_PRI_MAP_SHIFT);
+ }
+}
+
+static enum _ecore_status_t
+ecore_dcbx_set_local_params(struct ecore_hwfn *p_hwfn,
+ struct dcbx_local_params *local_admin,
+ struct ecore_dcbx_set *params)
+{
+ bool ieee = false;
+
+ local_admin->flags = 0;
+ OSAL_MEMCPY(&local_admin->features,
+ &p_hwfn->p_dcbx_info->operational.features,
+ sizeof(struct dcbx_features));
+
+ if (params->enabled) {
+ local_admin->config = params->ver_num;
+ ieee = !!(params->ver_num & DCBX_CONFIG_VERSION_IEEE);
+ } else {
+ local_admin->config = DCBX_CONFIG_VERSION_DISABLED;
+ }
+
+ if (params->override_flags & ECORE_DCBX_OVERRIDE_PFC_CFG)
+ ecore_dcbx_set_pfc_data(p_hwfn, &local_admin->features.pfc,
+ ¶ms->config.params);
+
+ if (params->override_flags & ECORE_DCBX_OVERRIDE_ETS_CFG)
+ ecore_dcbx_set_ets_data(p_hwfn, &local_admin->features.ets,
+ ¶ms->config.params);
+
+ if (params->override_flags & ECORE_DCBX_OVERRIDE_APP_CFG)
+ ecore_dcbx_set_app_data(p_hwfn, &local_admin->features.app,
+ ¶ms->config.params, ieee);
+
+ return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t
+ecore_dcbx_set_dscp_params(struct ecore_hwfn *p_hwfn,
+ struct dcb_dscp_map *p_dscp_map,
+ struct ecore_dcbx_set *p_params)
+{
+ int entry, i, j;
+ u32 val;
+
+ OSAL_MEMCPY(p_dscp_map, &p_hwfn->p_dcbx_info->dscp_map,
+ sizeof(*p_dscp_map));
+
+ if (p_params->dscp.enabled)
+ p_dscp_map->flags |= DCB_DSCP_ENABLE_MASK;
+ else
+ p_dscp_map->flags &= ~DCB_DSCP_ENABLE_MASK;
+
+ for (i = 0, entry = 0; i < 8; i++) {
+ val = 0;
+ for (j = 0; j < 8; j++, entry++)
+ val |= (((u32)p_params->dscp.dscp_pri_map[entry]) <<
+ (j * 4));
+
+ p_dscp_map->dscp_pri_map[i] = OSAL_CPU_TO_BE32(val);
+ }
+
+ p_hwfn->p_dcbx_info->dscp_nig_update = true;
+
+ return ECORE_SUCCESS;
+}
+
+enum _ecore_status_t ecore_dcbx_config_params(struct ecore_hwfn *p_hwfn,
+ struct ecore_ptt *p_ptt,
+ struct ecore_dcbx_set *params,
+ bool hw_commit)
+{
+ enum _ecore_status_t rc = ECORE_SUCCESS;
+ struct ecore_dcbx_mib_meta_data data;
+ struct dcbx_local_params local_admin;
+ struct dcb_dscp_map dscp_map;
+ u32 resp = 0, param = 0;
+
+ if (!hw_commit) {
+ OSAL_MEMCPY(&p_hwfn->p_dcbx_info->set, params,
+ sizeof(struct ecore_dcbx_set));
+ return ECORE_SUCCESS;
+ }
+
+ /* clear set-parmas cache */
+ OSAL_MEMSET(&p_hwfn->p_dcbx_info->set, 0,
+ sizeof(struct ecore_dcbx_set));
+
+ OSAL_MEMSET(&local_admin, 0, sizeof(local_admin));
+ ecore_dcbx_set_local_params(p_hwfn, &local_admin, params);
+
+ data.addr = p_hwfn->mcp_info->port_addr +
+ offsetof(struct public_port, local_admin_dcbx_mib);
+ data.local_admin = &local_admin;
+ data.size = sizeof(struct dcbx_local_params);
+ ecore_memcpy_to(p_hwfn, p_ptt, data.addr, data.local_admin, data.size);
+
+ if (params->override_flags & ECORE_DCBX_OVERRIDE_DSCP_CFG) {
+ OSAL_MEMSET(&dscp_map, 0, sizeof(dscp_map));
+ ecore_dcbx_set_dscp_params(p_hwfn, &dscp_map, params);
+
+ data.addr = p_hwfn->mcp_info->port_addr +
+ offsetof(struct public_port, dcb_dscp_map);
+ data.dscp_map = &dscp_map;
+ data.size = sizeof(struct dcb_dscp_map);
+ ecore_memcpy_to(p_hwfn, p_ptt, data.addr, data.dscp_map,
+ data.size);
+ }
+
+ rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_DCBX,
+ 1 << DRV_MB_PARAM_LLDP_SEND_SHIFT, &resp, ¶m);
+ if (rc != ECORE_SUCCESS) {
+ DP_NOTICE(p_hwfn, false,
+ "Failed to send DCBX update request\n");
+ return rc;
+ }
+
+ return rc;
+}
+
+enum _ecore_status_t ecore_dcbx_get_config_params(struct ecore_hwfn *p_hwfn,
+ struct ecore_dcbx_set *params)
+{
+ struct ecore_dcbx_get *dcbx_info;
+ int rc;
+
+ if (p_hwfn->p_dcbx_info->set.config.valid) {
+ OSAL_MEMCPY(params, &p_hwfn->p_dcbx_info->set,
+ sizeof(struct ecore_dcbx_set));
+ return ECORE_SUCCESS;
+ }
+
+ dcbx_info = OSAL_ALLOC(p_hwfn->p_dev, GFP_KERNEL,
+ sizeof(struct ecore_dcbx_get));
+ if (!dcbx_info) {
+ DP_ERR(p_hwfn, "Failed to allocate struct ecore_dcbx_info\n");
+ return ECORE_NOMEM;
+ }
+
+ rc = ecore_dcbx_query_params(p_hwfn, dcbx_info,
+ ECORE_DCBX_OPERATIONAL_MIB);
+ if (rc) {
+ OSAL_FREE(p_hwfn->p_dev, dcbx_info);
+ return rc;
+ }
+ p_hwfn->p_dcbx_info->set.override_flags = 0;
+
+ p_hwfn->p_dcbx_info->set.ver_num = DCBX_CONFIG_VERSION_DISABLED;
+ if (dcbx_info->operational.cee)
+ p_hwfn->p_dcbx_info->set.ver_num |= DCBX_CONFIG_VERSION_CEE;
+ if (dcbx_info->operational.ieee)
+ p_hwfn->p_dcbx_info->set.ver_num |= DCBX_CONFIG_VERSION_IEEE;
+ if (dcbx_info->operational.local)
+ p_hwfn->p_dcbx_info->set.ver_num |= DCBX_CONFIG_VERSION_STATIC;
+
+ p_hwfn->p_dcbx_info->set.enabled = dcbx_info->operational.enabled;
+ OSAL_MEMCPY(&p_hwfn->p_dcbx_info->set.config.params,
+ &dcbx_info->operational.params,
+ sizeof(struct ecore_dcbx_admin_params));
+ p_hwfn->p_dcbx_info->set.config.valid = true;
+
+ OSAL_MEMCPY(params, &p_hwfn->p_dcbx_info->set,
+ sizeof(struct ecore_dcbx_set));
+
+ OSAL_FREE(p_hwfn->p_dev, dcbx_info);
+
+ return ECORE_SUCCESS;
+}