X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fethernet%2Fintel%2Ffm10k%2Ffm10k_netdev.c;h=05629381be6be5de004680f6f27fd5b577851e63;hb=4c4a8a5d34b7a7a78b0e501c88573262692db7b3;hp=20a5bbe3f53617e29a10027925decbb58009c410;hpb=9e0243db6169d7d1fc39a087e78fed22a2fe7071;p=deliverable%2Flinux.git diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 20a5bbe3f536..05629381be6b 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -384,129 +384,171 @@ static void fm10k_request_glort_range(struct fm10k_intfc *interface) } /** - * fm10k_del_vxlan_port_all + * fm10k_free_udp_port_info * @interface: board private structure * - * This function frees the entire vxlan_port list + * This function frees both geneve_port and vxlan_port structures **/ -static void fm10k_del_vxlan_port_all(struct fm10k_intfc *interface) +static void fm10k_free_udp_port_info(struct fm10k_intfc *interface) { - struct fm10k_vxlan_port *vxlan_port; - - /* flush all entries from list */ - vxlan_port = list_first_entry_or_null(&interface->vxlan_port, - struct fm10k_vxlan_port, list); - while (vxlan_port) { - list_del(&vxlan_port->list); - kfree(vxlan_port); - vxlan_port = list_first_entry_or_null(&interface->vxlan_port, - struct fm10k_vxlan_port, - list); + struct fm10k_udp_port *port; + + /* flush all entries from vxlan list */ + port = list_first_entry_or_null(&interface->vxlan_port, + struct fm10k_udp_port, list); + while (port) { + list_del(&port->list); + kfree(port); + port = list_first_entry_or_null(&interface->vxlan_port, + struct fm10k_udp_port, + list); + } + + /* flush all entries from geneve list */ + port = list_first_entry_or_null(&interface->geneve_port, + struct fm10k_udp_port, list); + while (port) { + list_del(&port->list); + kfree(port); + port = list_first_entry_or_null(&interface->vxlan_port, + struct fm10k_udp_port, + list); } } /** - * fm10k_restore_vxlan_port + * fm10k_restore_udp_port_info * @interface: board private structure * - * This function restores the value in the tunnel_cfg register after reset + * This function restores the value in the tunnel_cfg register(s) after reset **/ -static void fm10k_restore_vxlan_port(struct fm10k_intfc *interface) +static void fm10k_restore_udp_port_info(struct fm10k_intfc *interface) { struct fm10k_hw *hw = &interface->hw; - struct fm10k_vxlan_port *vxlan_port; + struct fm10k_udp_port *port; /* only the PF supports configuring tunnels */ if (hw->mac.type != fm10k_mac_pf) return; - vxlan_port = list_first_entry_or_null(&interface->vxlan_port, - struct fm10k_vxlan_port, list); + port = list_first_entry_or_null(&interface->vxlan_port, + struct fm10k_udp_port, list); /* restore tunnel configuration register */ fm10k_write_reg(hw, FM10K_TUNNEL_CFG, - (vxlan_port ? ntohs(vxlan_port->port) : 0) | + (port ? ntohs(port->port) : 0) | (ETH_P_TEB << FM10K_TUNNEL_CFG_NVGRE_SHIFT)); + + port = list_first_entry_or_null(&interface->geneve_port, + struct fm10k_udp_port, list); + + /* restore Geneve tunnel configuration register */ + fm10k_write_reg(hw, FM10K_TUNNEL_CFG_GENEVE, + (port ? ntohs(port->port) : 0)); +} + +static struct fm10k_udp_port * +fm10k_remove_tunnel_port(struct list_head *ports, + struct udp_tunnel_info *ti) +{ + struct fm10k_udp_port *port; + + list_for_each_entry(port, ports, list) { + if ((port->port == ti->port) && + (port->sa_family == ti->sa_family)) { + list_del(&port->list); + return port; + } + } + + return NULL; +} + +static void fm10k_insert_tunnel_port(struct list_head *ports, + struct udp_tunnel_info *ti) +{ + struct fm10k_udp_port *port; + + /* remove existing port entry from the list so that the newest items + * are always at the tail of the list. + */ + port = fm10k_remove_tunnel_port(ports, ti); + if (!port) { + port = kmalloc(sizeof(*port), GFP_ATOMIC); + if (!port) + return; + port->port = ti->port; + port->sa_family = ti->sa_family; + } + + list_add_tail(&port->list, ports); } /** - * fm10k_add_vxlan_port + * fm10k_udp_tunnel_add * @netdev: network interface device structure * @ti: Tunnel endpoint information * - * This function is called when a new VXLAN interface has added a new port - * number to the range that is currently in use for VXLAN. The new port - * number is always added to the tail so that the port number list should - * match the order in which the ports were allocated. The head of the list - * is always used as the VXLAN port number for offloads. + * This function is called when a new UDP tunnel port has been added. + * Due to hardware restrictions, only one port per type can be offloaded at + * once. **/ -static void fm10k_add_vxlan_port(struct net_device *dev, +static void fm10k_udp_tunnel_add(struct net_device *dev, struct udp_tunnel_info *ti) { struct fm10k_intfc *interface = netdev_priv(dev); - struct fm10k_vxlan_port *vxlan_port; - if (ti->type != UDP_TUNNEL_TYPE_VXLAN) - return; /* only the PF supports configuring tunnels */ if (interface->hw.mac.type != fm10k_mac_pf) return; - /* existing ports are pulled out so our new entry is always last */ - fm10k_vxlan_port_for_each(vxlan_port, interface) { - if ((vxlan_port->port == ti->port) && - (vxlan_port->sa_family == ti->sa_family)) { - list_del(&vxlan_port->list); - goto insert_tail; - } - } - - /* allocate memory to track ports */ - vxlan_port = kmalloc(sizeof(*vxlan_port), GFP_ATOMIC); - if (!vxlan_port) + switch (ti->type) { + case UDP_TUNNEL_TYPE_VXLAN: + fm10k_insert_tunnel_port(&interface->vxlan_port, ti); + break; + case UDP_TUNNEL_TYPE_GENEVE: + fm10k_insert_tunnel_port(&interface->geneve_port, ti); + break; + default: return; - vxlan_port->port = ti->port; - vxlan_port->sa_family = ti->sa_family; - -insert_tail: - /* add new port value to list */ - list_add_tail(&vxlan_port->list, &interface->vxlan_port); + } - fm10k_restore_vxlan_port(interface); + fm10k_restore_udp_port_info(interface); } /** - * fm10k_del_vxlan_port + * fm10k_udp_tunnel_del * @netdev: network interface device structure * @ti: Tunnel endpoint information * - * This function is called when a new VXLAN interface has freed a port - * number from the range that is currently in use for VXLAN. The freed - * port is removed from the list and the new head is used to determine - * the port number for offloads. + * This function is called when a new UDP tunnel port is deleted. The freed + * port will be removed from the list, then we reprogram the offloaded port + * based on the head of the list. **/ -static void fm10k_del_vxlan_port(struct net_device *dev, +static void fm10k_udp_tunnel_del(struct net_device *dev, struct udp_tunnel_info *ti) { struct fm10k_intfc *interface = netdev_priv(dev); - struct fm10k_vxlan_port *vxlan_port; + struct fm10k_udp_port *port = NULL; - if (ti->type != UDP_TUNNEL_TYPE_VXLAN) - return; if (interface->hw.mac.type != fm10k_mac_pf) return; - /* find the port in the list and free it */ - fm10k_vxlan_port_for_each(vxlan_port, interface) { - if ((vxlan_port->port == ti->port) && - (vxlan_port->sa_family == ti->sa_family)) { - list_del(&vxlan_port->list); - kfree(vxlan_port); - break; - } + switch (ti->type) { + case UDP_TUNNEL_TYPE_VXLAN: + port = fm10k_remove_tunnel_port(&interface->vxlan_port, ti); + break; + case UDP_TUNNEL_TYPE_GENEVE: + port = fm10k_remove_tunnel_port(&interface->geneve_port, ti); + break; + default: + return; } - fm10k_restore_vxlan_port(interface); + /* if we did remove a port we need to free its memory */ + kfree(port); + + fm10k_restore_udp_port_info(interface); } /** @@ -555,7 +597,6 @@ int fm10k_open(struct net_device *netdev) if (err) goto err_set_queues; - /* update VXLAN port configuration */ udp_tunnel_get_rx_info(netdev); fm10k_up(interface); @@ -591,7 +632,7 @@ int fm10k_close(struct net_device *netdev) fm10k_qv_free_irq(interface); - fm10k_del_vxlan_port_all(interface); + fm10k_free_udp_port_info(interface); fm10k_free_all_tx_resources(interface); fm10k_free_all_rx_resources(interface); @@ -1055,7 +1096,7 @@ void fm10k_restore_rx_state(struct fm10k_intfc *interface) interface->xcast_mode = xcast_mode; /* Restore tunnel configuration */ - fm10k_restore_vxlan_port(interface); + fm10k_restore_udp_port_info(interface); } void fm10k_reset_rx_state(struct fm10k_intfc *interface) @@ -1098,7 +1139,7 @@ static struct rtnl_link_stats64 *fm10k_get_stats64(struct net_device *netdev, rcu_read_lock(); for (i = 0; i < interface->num_rx_queues; i++) { - ring = ACCESS_ONCE(interface->rx_ring[i]); + ring = READ_ONCE(interface->rx_ring[i]); if (!ring) continue; @@ -1114,7 +1155,7 @@ static struct rtnl_link_stats64 *fm10k_get_stats64(struct net_device *netdev, } for (i = 0; i < interface->num_tx_queues; i++) { - ring = ACCESS_ONCE(interface->tx_ring[i]); + ring = READ_ONCE(interface->tx_ring[i]); if (!ring) continue; @@ -1299,7 +1340,7 @@ static void *fm10k_dfwd_add_station(struct net_device *dev, static void fm10k_dfwd_del_station(struct net_device *dev, void *priv) { struct fm10k_intfc *interface = netdev_priv(dev); - struct fm10k_l2_accel *l2_accel = ACCESS_ONCE(interface->l2_accel); + struct fm10k_l2_accel *l2_accel = READ_ONCE(interface->l2_accel); struct fm10k_dglort_cfg dglort = { 0 }; struct fm10k_hw *hw = &interface->hw; struct net_device *sdev = priv; @@ -1375,8 +1416,8 @@ static const struct net_device_ops fm10k_netdev_ops = { .ndo_set_vf_vlan = fm10k_ndo_set_vf_vlan, .ndo_set_vf_rate = fm10k_ndo_set_vf_bw, .ndo_get_vf_config = fm10k_ndo_get_vf_config, - .ndo_udp_tunnel_add = fm10k_add_vxlan_port, - .ndo_udp_tunnel_del = fm10k_del_vxlan_port, + .ndo_udp_tunnel_add = fm10k_udp_tunnel_add, + .ndo_udp_tunnel_del = fm10k_udp_tunnel_del, .ndo_dfwd_add_station = fm10k_dfwd_add_station, .ndo_dfwd_del_station = fm10k_dfwd_del_station, #ifdef CONFIG_NET_POLL_CONTROLLER