|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | +/* Copyright (c) 2018, Intel Corporation. */ |
| 3 | + |
| 4 | +#include "ice.h" |
| 5 | +#include "ice_lib.h" |
| 6 | + |
| 7 | +/** |
| 8 | + * ice_add_mac_to_list - Add a mac address filter entry to the list |
| 9 | + * @vsi: the VSI to be forwarded to |
| 10 | + * @add_list: pointer to the list which contains MAC filter entries |
| 11 | + * @macaddr: the MAC address to be added. |
| 12 | + * |
| 13 | + * Adds mac address filter entry to the temp list |
| 14 | + * |
| 15 | + * Returns 0 on success or ENOMEM on failure. |
| 16 | + */ |
| 17 | +int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, |
| 18 | + const u8 *macaddr) |
| 19 | +{ |
| 20 | + struct ice_fltr_list_entry *tmp; |
| 21 | + struct ice_pf *pf = vsi->back; |
| 22 | + |
| 23 | + tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_ATOMIC); |
| 24 | + if (!tmp) |
| 25 | + return -ENOMEM; |
| 26 | + |
| 27 | + tmp->fltr_info.flag = ICE_FLTR_TX; |
| 28 | + tmp->fltr_info.src = vsi->vsi_num; |
| 29 | + tmp->fltr_info.lkup_type = ICE_SW_LKUP_MAC; |
| 30 | + tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; |
| 31 | + tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; |
| 32 | + ether_addr_copy(tmp->fltr_info.l_data.mac.mac_addr, macaddr); |
| 33 | + |
| 34 | + INIT_LIST_HEAD(&tmp->list_entry); |
| 35 | + list_add(&tmp->list_entry, add_list); |
| 36 | + |
| 37 | + return 0; |
| 38 | +} |
| 39 | + |
| 40 | +/** |
| 41 | + * ice_update_eth_stats - Update VSI-specific ethernet statistics counters |
| 42 | + * @vsi: the VSI to be updated |
| 43 | + */ |
| 44 | +void ice_update_eth_stats(struct ice_vsi *vsi) |
| 45 | +{ |
| 46 | + struct ice_eth_stats *prev_es, *cur_es; |
| 47 | + struct ice_hw *hw = &vsi->back->hw; |
| 48 | + u16 vsi_num = vsi->vsi_num; /* HW absolute index of a VSI */ |
| 49 | + |
| 50 | + prev_es = &vsi->eth_stats_prev; |
| 51 | + cur_es = &vsi->eth_stats; |
| 52 | + |
| 53 | + ice_stat_update40(hw, GLV_GORCH(vsi_num), GLV_GORCL(vsi_num), |
| 54 | + vsi->stat_offsets_loaded, &prev_es->rx_bytes, |
| 55 | + &cur_es->rx_bytes); |
| 56 | + |
| 57 | + ice_stat_update40(hw, GLV_UPRCH(vsi_num), GLV_UPRCL(vsi_num), |
| 58 | + vsi->stat_offsets_loaded, &prev_es->rx_unicast, |
| 59 | + &cur_es->rx_unicast); |
| 60 | + |
| 61 | + ice_stat_update40(hw, GLV_MPRCH(vsi_num), GLV_MPRCL(vsi_num), |
| 62 | + vsi->stat_offsets_loaded, &prev_es->rx_multicast, |
| 63 | + &cur_es->rx_multicast); |
| 64 | + |
| 65 | + ice_stat_update40(hw, GLV_BPRCH(vsi_num), GLV_BPRCL(vsi_num), |
| 66 | + vsi->stat_offsets_loaded, &prev_es->rx_broadcast, |
| 67 | + &cur_es->rx_broadcast); |
| 68 | + |
| 69 | + ice_stat_update32(hw, GLV_RDPC(vsi_num), vsi->stat_offsets_loaded, |
| 70 | + &prev_es->rx_discards, &cur_es->rx_discards); |
| 71 | + |
| 72 | + ice_stat_update40(hw, GLV_GOTCH(vsi_num), GLV_GOTCL(vsi_num), |
| 73 | + vsi->stat_offsets_loaded, &prev_es->tx_bytes, |
| 74 | + &cur_es->tx_bytes); |
| 75 | + |
| 76 | + ice_stat_update40(hw, GLV_UPTCH(vsi_num), GLV_UPTCL(vsi_num), |
| 77 | + vsi->stat_offsets_loaded, &prev_es->tx_unicast, |
| 78 | + &cur_es->tx_unicast); |
| 79 | + |
| 80 | + ice_stat_update40(hw, GLV_MPTCH(vsi_num), GLV_MPTCL(vsi_num), |
| 81 | + vsi->stat_offsets_loaded, &prev_es->tx_multicast, |
| 82 | + &cur_es->tx_multicast); |
| 83 | + |
| 84 | + ice_stat_update40(hw, GLV_BPTCH(vsi_num), GLV_BPTCL(vsi_num), |
| 85 | + vsi->stat_offsets_loaded, &prev_es->tx_broadcast, |
| 86 | + &cur_es->tx_broadcast); |
| 87 | + |
| 88 | + ice_stat_update32(hw, GLV_TEPC(vsi_num), vsi->stat_offsets_loaded, |
| 89 | + &prev_es->tx_errors, &cur_es->tx_errors); |
| 90 | + |
| 91 | + vsi->stat_offsets_loaded = true; |
| 92 | +} |
| 93 | + |
| 94 | +/** |
| 95 | + * ice_free_fltr_list - free filter lists helper |
| 96 | + * @dev: pointer to the device struct |
| 97 | + * @h: pointer to the list head to be freed |
| 98 | + * |
| 99 | + * Helper function to free filter lists previously created using |
| 100 | + * ice_add_mac_to_list |
| 101 | + */ |
| 102 | +void ice_free_fltr_list(struct device *dev, struct list_head *h) |
| 103 | +{ |
| 104 | + struct ice_fltr_list_entry *e, *tmp; |
| 105 | + |
| 106 | + list_for_each_entry_safe(e, tmp, h, list_entry) { |
| 107 | + list_del(&e->list_entry); |
| 108 | + devm_kfree(dev, e); |
| 109 | + } |
| 110 | +} |
| 111 | + |
| 112 | +/** |
| 113 | + * ice_vsi_add_vlan - Add VSI membership for given VLAN |
| 114 | + * @vsi: the VSI being configured |
| 115 | + * @vid: VLAN id to be added |
| 116 | + */ |
| 117 | +int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid) |
| 118 | +{ |
| 119 | + struct ice_fltr_list_entry *tmp; |
| 120 | + struct ice_pf *pf = vsi->back; |
| 121 | + LIST_HEAD(tmp_add_list); |
| 122 | + enum ice_status status; |
| 123 | + int err = 0; |
| 124 | + |
| 125 | + tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_KERNEL); |
| 126 | + if (!tmp) |
| 127 | + return -ENOMEM; |
| 128 | + |
| 129 | + tmp->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; |
| 130 | + tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI; |
| 131 | + tmp->fltr_info.flag = ICE_FLTR_TX; |
| 132 | + tmp->fltr_info.src = vsi->vsi_num; |
| 133 | + tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num; |
| 134 | + tmp->fltr_info.l_data.vlan.vlan_id = vid; |
| 135 | + |
| 136 | + INIT_LIST_HEAD(&tmp->list_entry); |
| 137 | + list_add(&tmp->list_entry, &tmp_add_list); |
| 138 | + |
| 139 | + status = ice_add_vlan(&pf->hw, &tmp_add_list); |
| 140 | + if (status) { |
| 141 | + err = -ENODEV; |
| 142 | + dev_err(&pf->pdev->dev, "Failure Adding VLAN %d on VSI %i\n", |
| 143 | + vid, vsi->vsi_num); |
| 144 | + } |
| 145 | + |
| 146 | + ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); |
| 147 | + return err; |
| 148 | +} |
| 149 | + |
| 150 | +/** |
| 151 | + * ice_vsi_kill_vlan - Remove VSI membership for a given VLAN |
| 152 | + * @vsi: the VSI being configured |
| 153 | + * @vid: VLAN id to be removed |
| 154 | + * |
| 155 | + * Returns 0 on success and negative on failure |
| 156 | + */ |
| 157 | +int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) |
| 158 | +{ |
| 159 | + struct ice_fltr_list_entry *list; |
| 160 | + struct ice_pf *pf = vsi->back; |
| 161 | + LIST_HEAD(tmp_add_list); |
| 162 | + int status = 0; |
| 163 | + |
| 164 | + list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL); |
| 165 | + if (!list) |
| 166 | + return -ENOMEM; |
| 167 | + |
| 168 | + list->fltr_info.lkup_type = ICE_SW_LKUP_VLAN; |
| 169 | + list->fltr_info.fwd_id.vsi_id = vsi->vsi_num; |
| 170 | + list->fltr_info.fltr_act = ICE_FWD_TO_VSI; |
| 171 | + list->fltr_info.l_data.vlan.vlan_id = vid; |
| 172 | + list->fltr_info.flag = ICE_FLTR_TX; |
| 173 | + list->fltr_info.src = vsi->vsi_num; |
| 174 | + |
| 175 | + INIT_LIST_HEAD(&list->list_entry); |
| 176 | + list_add(&list->list_entry, &tmp_add_list); |
| 177 | + |
| 178 | + if (ice_remove_vlan(&pf->hw, &tmp_add_list)) { |
| 179 | + dev_err(&pf->pdev->dev, "Error removing VLAN %d on vsi %i\n", |
| 180 | + vid, vsi->vsi_num); |
| 181 | + status = -EIO; |
| 182 | + } |
| 183 | + |
| 184 | + ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); |
| 185 | + return status; |
| 186 | +} |
| 187 | + |
| 188 | +/** |
| 189 | + * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx |
| 190 | + * @vsi: the VSI being changed |
| 191 | + */ |
| 192 | +int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) |
| 193 | +{ |
| 194 | + struct device *dev = &vsi->back->pdev->dev; |
| 195 | + struct ice_hw *hw = &vsi->back->hw; |
| 196 | + struct ice_vsi_ctx ctxt = { 0 }; |
| 197 | + enum ice_status status; |
| 198 | + |
| 199 | + /* Here we are configuring the VSI to let the driver add VLAN tags by |
| 200 | + * setting vlan_flags to ICE_AQ_VSI_VLAN_MODE_ALL. The actual VLAN tag |
| 201 | + * insertion happens in the Tx hot path, in ice_tx_map. |
| 202 | + */ |
| 203 | + ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL; |
| 204 | + |
| 205 | + ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); |
| 206 | + ctxt.vsi_num = vsi->vsi_num; |
| 207 | + |
| 208 | + status = ice_aq_update_vsi(hw, &ctxt, NULL); |
| 209 | + if (status) { |
| 210 | + dev_err(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n", |
| 211 | + status, hw->adminq.sq_last_status); |
| 212 | + return -EIO; |
| 213 | + } |
| 214 | + |
| 215 | + vsi->info.vlan_flags = ctxt.info.vlan_flags; |
| 216 | + return 0; |
| 217 | +} |
| 218 | + |
| 219 | +/** |
| 220 | + * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx |
| 221 | + * @vsi: the VSI being changed |
| 222 | + * @ena: boolean value indicating if this is a enable or disable request |
| 223 | + */ |
| 224 | +int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) |
| 225 | +{ |
| 226 | + struct device *dev = &vsi->back->pdev->dev; |
| 227 | + struct ice_hw *hw = &vsi->back->hw; |
| 228 | + struct ice_vsi_ctx ctxt = { 0 }; |
| 229 | + enum ice_status status; |
| 230 | + |
| 231 | + /* Here we are configuring what the VSI should do with the VLAN tag in |
| 232 | + * the Rx packet. We can either leave the tag in the packet or put it in |
| 233 | + * the Rx descriptor. |
| 234 | + */ |
| 235 | + if (ena) { |
| 236 | + /* Strip VLAN tag from Rx packet and put it in the desc */ |
| 237 | + ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_STR_BOTH; |
| 238 | + } else { |
| 239 | + /* Disable stripping. Leave tag in packet */ |
| 240 | + ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_NOTHING; |
| 241 | + } |
| 242 | + |
| 243 | + /* Allow all packets untagged/tagged */ |
| 244 | + ctxt.info.vlan_flags |= ICE_AQ_VSI_VLAN_MODE_ALL; |
| 245 | + |
| 246 | + ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); |
| 247 | + ctxt.vsi_num = vsi->vsi_num; |
| 248 | + |
| 249 | + status = ice_aq_update_vsi(hw, &ctxt, NULL); |
| 250 | + if (status) { |
| 251 | + dev_err(dev, "update VSI for VLAN strip failed, ena = %d err %d aq_err %d\n", |
| 252 | + ena, status, hw->adminq.sq_last_status); |
| 253 | + return -EIO; |
| 254 | + } |
| 255 | + |
| 256 | + vsi->info.vlan_flags = ctxt.info.vlan_flags; |
| 257 | + return 0; |
| 258 | +} |
0 commit comments