Merge remote-tracking branch 'sound-asoc/for-next'
[deliverable/linux.git] / drivers / net / ethernet / intel / fm10k / fm10k_netdev.c
index 20a5bbe3f53617e29a10027925decbb58009c410..05629381be6be5de004680f6f27fd5b577851e63 100644 (file)
@@ -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
This page took 0.028133 seconds and 5 git commands to generate.