|
@@ -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
|
|
* @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
|
|
* @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_hw *hw = &interface->hw;
|
|
- struct fm10k_vxlan_port *vxlan_port;
|
|
|
|
|
|
+ struct fm10k_udp_port *port;
|
|
|
|
|
|
/* only the PF supports configuring tunnels */
|
|
/* only the PF supports configuring tunnels */
|
|
if (hw->mac.type != fm10k_mac_pf)
|
|
if (hw->mac.type != fm10k_mac_pf)
|
|
return;
|
|
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 */
|
|
/* restore tunnel configuration register */
|
|
fm10k_write_reg(hw, FM10K_TUNNEL_CFG,
|
|
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));
|
|
(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
|
|
* @netdev: network interface device structure
|
|
* @ti: Tunnel endpoint information
|
|
* @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 udp_tunnel_info *ti)
|
|
{
|
|
{
|
|
struct fm10k_intfc *interface = netdev_priv(dev);
|
|
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 */
|
|
/* only the PF supports configuring tunnels */
|
|
if (interface->hw.mac.type != fm10k_mac_pf)
|
|
if (interface->hw.mac.type != fm10k_mac_pf)
|
|
return;
|
|
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;
|
|
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
|
|
* @netdev: network interface device structure
|
|
* @ti: Tunnel endpoint information
|
|
* @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 udp_tunnel_info *ti)
|
|
{
|
|
{
|
|
struct fm10k_intfc *interface = netdev_priv(dev);
|
|
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)
|
|
if (interface->hw.mac.type != fm10k_mac_pf)
|
|
return;
|
|
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)
|
|
if (err)
|
|
goto err_set_queues;
|
|
goto err_set_queues;
|
|
|
|
|
|
- /* update VXLAN port configuration */
|
|
|
|
udp_tunnel_get_rx_info(netdev);
|
|
udp_tunnel_get_rx_info(netdev);
|
|
|
|
|
|
fm10k_up(interface);
|
|
fm10k_up(interface);
|
|
@@ -591,7 +632,7 @@ int fm10k_close(struct net_device *netdev)
|
|
|
|
|
|
fm10k_qv_free_irq(interface);
|
|
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_tx_resources(interface);
|
|
fm10k_free_all_rx_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;
|
|
interface->xcast_mode = xcast_mode;
|
|
|
|
|
|
/* Restore tunnel configuration */
|
|
/* Restore tunnel configuration */
|
|
- fm10k_restore_vxlan_port(interface);
|
|
|
|
|
|
+ fm10k_restore_udp_port_info(interface);
|
|
}
|
|
}
|
|
|
|
|
|
void fm10k_reset_rx_state(struct fm10k_intfc *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();
|
|
rcu_read_lock();
|
|
|
|
|
|
for (i = 0; i < interface->num_rx_queues; i++) {
|
|
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)
|
|
if (!ring)
|
|
continue;
|
|
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++) {
|
|
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)
|
|
if (!ring)
|
|
continue;
|
|
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)
|
|
static void fm10k_dfwd_del_station(struct net_device *dev, void *priv)
|
|
{
|
|
{
|
|
struct fm10k_intfc *interface = netdev_priv(dev);
|
|
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_dglort_cfg dglort = { 0 };
|
|
struct fm10k_hw *hw = &interface->hw;
|
|
struct fm10k_hw *hw = &interface->hw;
|
|
struct net_device *sdev = priv;
|
|
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_vlan = fm10k_ndo_set_vf_vlan,
|
|
.ndo_set_vf_rate = fm10k_ndo_set_vf_bw,
|
|
.ndo_set_vf_rate = fm10k_ndo_set_vf_bw,
|
|
.ndo_get_vf_config = fm10k_ndo_get_vf_config,
|
|
.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_add_station = fm10k_dfwd_add_station,
|
|
.ndo_dfwd_del_station = fm10k_dfwd_del_station,
|
|
.ndo_dfwd_del_station = fm10k_dfwd_del_station,
|
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|