static int fm10k_mbx_test(struct fm10k_intfc *interface, u64 *data) { struct fm10k_hw *hw = &interface->hw; struct fm10k_mbx_info *mbx = &hw->mbx; u32 attr_flag, test_msg[6]; unsigned long timeout; int err; /* For now this is a VF only feature */ if (hw->mac.type != fm10k_mac_vf) return 0; /* loop through both nested and unnested attribute types */ for (attr_flag = (1 << FM10K_TEST_MSG_UNSET); attr_flag < (1 << (2 * FM10K_TEST_MSG_NESTED)); attr_flag += attr_flag) { /* generate message to be tested */ fm10k_tlv_msg_test_create(test_msg, attr_flag); fm10k_mbx_lock(interface); mbx->test_result = FM10K_NOT_IMPLEMENTED; err = mbx->ops.enqueue_tx(hw, mbx, test_msg); fm10k_mbx_unlock(interface); /* wait up to 1 second for response */ timeout = jiffies + HZ; do { if (err < 0) goto err_out; usleep_range(500, 1000); fm10k_mbx_lock(interface); mbx->ops.process(hw, mbx); fm10k_mbx_unlock(interface); err = mbx->test_result; if (!err) break; } while (time_is_after_jiffies(timeout)); /* reporting errors */ if (err) goto err_out; } err_out: *data = err < 0 ? (attr_flag) : (err > 0); return err; }
static int fm10k_set_mac(struct net_device *dev, void *p) { struct fm10k_intfc *interface = netdev_priv(dev); struct fm10k_hw *hw = &interface->hw; struct sockaddr *addr = p; s32 err = 0; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; if (dev->flags & IFF_UP) { /* setting MAC address requires mailbox */ fm10k_mbx_lock(interface); err = fm10k_uc_sync(dev, addr->sa_data); if (!err) fm10k_uc_unsync(dev, hw->mac.addr); fm10k_mbx_unlock(interface); } if (!err) { ether_addr_copy(dev->dev_addr, addr->sa_data); ether_addr_copy(hw->mac.addr, addr->sa_data); dev->addr_assign_type &= ~NET_ADDR_RANDOM; } /* if we had a mailbox error suggest trying again */ return err ? -EAGAIN : 0; }
void fm10k_restore_rx_state(struct fm10k_intfc *interface) { struct net_device *netdev = interface->netdev; struct fm10k_hw *hw = &interface->hw; int xcast_mode; u16 vid, glort; /* record glort for this interface */ glort = interface->glort; /* convert interface flags to xcast mode */ if (netdev->flags & IFF_PROMISC) xcast_mode = FM10K_XCAST_MODE_PROMISC; else if (netdev->flags & IFF_ALLMULTI) xcast_mode = FM10K_XCAST_MODE_ALLMULTI; else if (netdev->flags & (IFF_BROADCAST | IFF_MULTICAST)) xcast_mode = FM10K_XCAST_MODE_MULTI; else xcast_mode = FM10K_XCAST_MODE_NONE; fm10k_mbx_lock(interface); /* Enable logical port */ hw->mac.ops.update_lport_state(hw, glort, interface->glort_count, true); /* update VLAN table */ hw->mac.ops.update_vlan(hw, FM10K_VLAN_ALL, 0, xcast_mode == FM10K_XCAST_MODE_PROMISC); /* Add filter for VLAN 0 */ hw->mac.ops.update_vlan(hw, 0, 0, true); /* update table with current entries */ for (vid = hw->mac.default_vid ? fm10k_find_next_vlan(interface, 0) : 1; vid < VLAN_N_VID; vid = fm10k_find_next_vlan(interface, vid)) { hw->mac.ops.update_vlan(hw, vid, 0, true); hw->mac.ops.update_uc_addr(hw, glort, hw->mac.addr, vid, true, 0); } /* update xcast mode before synchronizing addresses */ hw->mac.ops.update_xcast_mode(hw, glort, xcast_mode); /* synchronize all of the addresses */ __dev_uc_sync(netdev, fm10k_uc_sync, fm10k_uc_unsync); __dev_mc_sync(netdev, fm10k_mc_sync, fm10k_mc_unsync); fm10k_mbx_unlock(interface); /* record updated xcast mode state */ interface->xcast_mode = xcast_mode; /* Restore tunnel configuration */ fm10k_restore_udp_port_info(interface); }
static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) { struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_hw *hw = &interface->hw; s32 err; /* updates do not apply to VLAN 0 */ if (!vid) return 0; if (vid >= VLAN_N_VID) return -EINVAL; /* Verify we have permission to add VLANs */ if (hw->mac.vlan_override) return -EACCES; /* if default VLAN is already present do nothing */ if (vid == hw->mac.default_vid) return -EBUSY; /* update active_vlans bitmask */ set_bit(vid, interface->active_vlans); if (!set) clear_bit(vid, interface->active_vlans); fm10k_mbx_lock(interface); /* only need to update the VLAN if not in promiscous mode */ if (!(netdev->flags & IFF_PROMISC)) { err = hw->mac.ops.update_vlan(hw, vid, 0, set); if (err) goto err_out; } /* update our base MAC address */ err = hw->mac.ops.update_uc_addr(hw, interface->glort, hw->mac.addr, vid, set, 0); if (err) goto err_out; /* set vid prior to syncing/unsyncing the VLAN */ interface->vid = vid + (set ? VLAN_N_VID : 0); /* Update the unicast and multicast address list to add/drop VLAN */ __dev_uc_unsync(netdev, fm10k_uc_vlan_unsync); __dev_mc_unsync(netdev, fm10k_mc_vlan_unsync); err_out: fm10k_mbx_unlock(interface); return err; }
static void fm10k_set_rx_mode(struct net_device *dev) { struct fm10k_intfc *interface = netdev_priv(dev); struct fm10k_hw *hw = &interface->hw; int xcast_mode; /* no need to update the harwdare if we are not running */ if (!(dev->flags & IFF_UP)) return; /* determine new mode based on flags */ xcast_mode = (dev->flags & IFF_PROMISC) ? FM10K_XCAST_MODE_PROMISC : (dev->flags & IFF_ALLMULTI) ? FM10K_XCAST_MODE_ALLMULTI : (dev->flags & (IFF_BROADCAST | IFF_MULTICAST)) ? FM10K_XCAST_MODE_MULTI : FM10K_XCAST_MODE_NONE; fm10k_mbx_lock(interface); /* syncronize all of the addresses */ if (xcast_mode != FM10K_XCAST_MODE_PROMISC) { __dev_uc_sync(dev, fm10k_uc_sync, fm10k_uc_unsync); if (xcast_mode != FM10K_XCAST_MODE_ALLMULTI) __dev_mc_sync(dev, fm10k_mc_sync, fm10k_mc_unsync); } /* if we aren't changing modes there is nothing to do */ if (interface->xcast_mode != xcast_mode) { /* update VLAN table */ if (xcast_mode == FM10K_XCAST_MODE_PROMISC) hw->mac.ops.update_vlan(hw, FM10K_VLAN_ALL, 0, true); if (interface->xcast_mode == FM10K_XCAST_MODE_PROMISC) fm10k_clear_unused_vlans(interface); /* update xcast mode */ hw->mac.ops.update_xcast_mode(hw, interface->glort, xcast_mode); /* record updated xcast mode state */ interface->xcast_mode = xcast_mode; } fm10k_mbx_unlock(interface); }
void fm10k_reset_rx_state(struct fm10k_intfc *interface) { struct net_device *netdev = interface->netdev; struct fm10k_hw *hw = &interface->hw; fm10k_mbx_lock(interface); /* clear the logical port state on lower device */ hw->mac.ops.update_lport_state(hw, interface->glort, interface->glort_count, false); fm10k_mbx_unlock(interface); /* reset flags to default state */ interface->xcast_mode = FM10K_XCAST_MODE_NONE; /* clear the sync flag since the lport has been dropped */ __dev_uc_unsync(netdev, NULL); __dev_mc_unsync(netdev, NULL); }
void fm10k_restore_rx_state(struct fm10k_intfc *interface) { struct net_device *netdev = interface->netdev; struct fm10k_hw *hw = &interface->hw; int xcast_mode; u16 vid, glort; /* restore our address if perm_addr is set */ if (hw->mac.type == fm10k_mac_vf) { if (is_valid_ether_addr(hw->mac.perm_addr)) { ether_addr_copy(hw->mac.addr, hw->mac.perm_addr); ether_addr_copy(netdev->perm_addr, hw->mac.perm_addr); ether_addr_copy(netdev->dev_addr, hw->mac.perm_addr); netdev->addr_assign_type &= ~NET_ADDR_RANDOM; } if (hw->mac.vlan_override) netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; else netdev->features |= NETIF_F_HW_VLAN_CTAG_RX; } /* record glort for this interface */ glort = interface->glort; /* convert interface flags to xcast mode */ if (netdev->flags & IFF_PROMISC) xcast_mode = FM10K_XCAST_MODE_PROMISC; else if (netdev->flags & IFF_ALLMULTI) xcast_mode = FM10K_XCAST_MODE_ALLMULTI; else if (netdev->flags & (IFF_BROADCAST | IFF_MULTICAST)) xcast_mode = FM10K_XCAST_MODE_MULTI; else xcast_mode = FM10K_XCAST_MODE_NONE; fm10k_mbx_lock(interface); /* Enable logical port */ hw->mac.ops.update_lport_state(hw, glort, interface->glort_count, true); /* update VLAN table */ hw->mac.ops.update_vlan(hw, FM10K_VLAN_ALL, 0, xcast_mode == FM10K_XCAST_MODE_PROMISC); /* Add filter for VLAN 0 */ hw->mac.ops.update_vlan(hw, 0, 0, true); /* update table with current entries */ for (vid = hw->mac.default_vid ? fm10k_find_next_vlan(interface, 0) : 0; vid < VLAN_N_VID; vid = fm10k_find_next_vlan(interface, vid)) { hw->mac.ops.update_vlan(hw, vid, 0, true); hw->mac.ops.update_uc_addr(hw, glort, hw->mac.addr, vid, true, 0); } /* syncronize all of the addresses */ if (xcast_mode != FM10K_XCAST_MODE_PROMISC) { __dev_uc_sync(netdev, fm10k_uc_sync, fm10k_uc_unsync); if (xcast_mode != FM10K_XCAST_MODE_ALLMULTI) __dev_mc_sync(netdev, fm10k_mc_sync, fm10k_mc_unsync); } /* update xcast mode */ hw->mac.ops.update_xcast_mode(hw, glort, xcast_mode); fm10k_mbx_unlock(interface); /* record updated xcast mode state */ interface->xcast_mode = xcast_mode; /* Restore tunnel configuration */ fm10k_restore_vxlan_port(interface); }
static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) { struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_hw *hw = &interface->hw; s32 err; int i; /* updates do not apply to VLAN 0 */ if (!vid) return 0; if (vid >= VLAN_N_VID) return -EINVAL; /* Verify we have permission to add VLANs */ if (hw->mac.vlan_override) return -EACCES; /* update active_vlans bitmask */ set_bit(vid, interface->active_vlans); if (!set) clear_bit(vid, interface->active_vlans); /* disable the default VLAN ID on ring if we have an active VLAN */ for (i = 0; i < interface->num_rx_queues; i++) { struct fm10k_ring *rx_ring = interface->rx_ring[i]; u16 rx_vid = rx_ring->vid & (VLAN_N_VID - 1); if (test_bit(rx_vid, interface->active_vlans)) rx_ring->vid |= FM10K_VLAN_CLEAR; else rx_ring->vid &= ~FM10K_VLAN_CLEAR; } /* Do not remove default VLAN ID related entries from VLAN and MAC * tables */ if (!set && vid == hw->mac.default_vid) return 0; /* Do not throw an error if the interface is down. We will sync once * we come up */ if (test_bit(__FM10K_DOWN, &interface->state)) return 0; fm10k_mbx_lock(interface); /* only need to update the VLAN if not in promiscuous mode */ if (!(netdev->flags & IFF_PROMISC)) { err = hw->mac.ops.update_vlan(hw, vid, 0, set); if (err) goto err_out; } /* update our base MAC address */ err = hw->mac.ops.update_uc_addr(hw, interface->glort, hw->mac.addr, vid, set, 0); if (err) goto err_out; /* set VLAN ID prior to syncing/unsyncing the VLAN */ interface->vid = vid + (set ? VLAN_N_VID : 0); /* Update the unicast and multicast address list to add/drop VLAN */ __dev_uc_unsync(netdev, fm10k_uc_vlan_unsync); __dev_mc_unsync(netdev, fm10k_mc_vlan_unsync); err_out: fm10k_mbx_unlock(interface); return err; }