be2net: VxLAN offload should be re-enabled when only 1 UDP port is left
We disable VxLAN offload when more than 1 UDP port is added to the driver, since Skyhawk doesn't support offload with multiple ports. The existing driver design expects the user to delete all port configurations and create a configuration with a single UDP port for VxLAN offload to be re-enabled. Remove this restriction by tracking the ports added and re-enabling offload when ports get deleted and only 1 port is left. Signed-off-by: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com> Reviewed-by: Sathya Perla <sathya.perla@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e05ddafd89
commit
bf8d9dfb9b
@ -567,6 +567,12 @@ struct be_error_recovery {
|
|||||||
/* Ethtool priv_flags */
|
/* Ethtool priv_flags */
|
||||||
#define BE_DISABLE_TPE_RECOVERY 0x1
|
#define BE_DISABLE_TPE_RECOVERY 0x1
|
||||||
|
|
||||||
|
struct be_vxlan_port {
|
||||||
|
struct list_head list;
|
||||||
|
__be16 port; /* VxLAN UDP dst port */
|
||||||
|
int port_aliases; /* alias count */
|
||||||
|
};
|
||||||
|
|
||||||
struct be_adapter {
|
struct be_adapter {
|
||||||
struct pci_dev *pdev;
|
struct pci_dev *pdev;
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
@ -671,9 +677,9 @@ struct be_adapter {
|
|||||||
u32 sli_family;
|
u32 sli_family;
|
||||||
u8 hba_port_num;
|
u8 hba_port_num;
|
||||||
u16 pvid;
|
u16 pvid;
|
||||||
__be16 vxlan_port;
|
__be16 vxlan_port; /* offloaded vxlan port num */
|
||||||
int vxlan_port_count;
|
int vxlan_port_count; /* active vxlan port count */
|
||||||
int vxlan_port_aliases;
|
struct list_head vxlan_port_list; /* vxlan port list */
|
||||||
struct phy_info phy;
|
struct phy_info phy;
|
||||||
u8 wol_cap;
|
u8 wol_cap;
|
||||||
bool wol_en;
|
bool wol_en;
|
||||||
|
@ -3857,6 +3857,44 @@ static void be_cancel_err_detection(struct be_adapter *adapter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int be_enable_vxlan_offloads(struct be_adapter *adapter)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = adapter->netdev;
|
||||||
|
struct device *dev = &adapter->pdev->dev;
|
||||||
|
struct be_vxlan_port *vxlan_port;
|
||||||
|
__be16 port;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
vxlan_port = list_first_entry(&adapter->vxlan_port_list,
|
||||||
|
struct be_vxlan_port, list);
|
||||||
|
port = vxlan_port->port;
|
||||||
|
|
||||||
|
status = be_cmd_manage_iface(adapter, adapter->if_handle,
|
||||||
|
OP_CONVERT_NORMAL_TO_TUNNEL);
|
||||||
|
if (status) {
|
||||||
|
dev_warn(dev, "Failed to convert normal interface to tunnel\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
adapter->flags |= BE_FLAGS_VXLAN_OFFLOADS;
|
||||||
|
|
||||||
|
status = be_cmd_set_vxlan_port(adapter, port);
|
||||||
|
if (status) {
|
||||||
|
dev_warn(dev, "Failed to add VxLAN port\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
adapter->vxlan_port = port;
|
||||||
|
|
||||||
|
netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
|
||||||
|
NETIF_F_TSO | NETIF_F_TSO6 |
|
||||||
|
NETIF_F_GSO_UDP_TUNNEL;
|
||||||
|
netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
|
||||||
|
netdev->features |= NETIF_F_GSO_UDP_TUNNEL;
|
||||||
|
|
||||||
|
dev_info(dev, "Enabled VxLAN offloads for UDP port %d\n",
|
||||||
|
be16_to_cpu(port));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void be_disable_vxlan_offloads(struct be_adapter *adapter)
|
static void be_disable_vxlan_offloads(struct be_adapter *adapter)
|
||||||
{
|
{
|
||||||
struct net_device *netdev = adapter->netdev;
|
struct net_device *netdev = adapter->netdev;
|
||||||
@ -4903,63 +4941,59 @@ static struct be_cmd_work *be_alloc_work(struct be_adapter *adapter,
|
|||||||
* those other tunnels are unexported on the fly through ndo_features_check().
|
* those other tunnels are unexported on the fly through ndo_features_check().
|
||||||
*
|
*
|
||||||
* Skyhawk supports VxLAN offloads only for one UDP dport. So, if the stack
|
* Skyhawk supports VxLAN offloads only for one UDP dport. So, if the stack
|
||||||
* adds more than one port, disable offloads and don't re-enable them again
|
* adds more than one port, disable offloads and re-enable them again when
|
||||||
* until after all the tunnels are removed.
|
* there's only one port left. We maintain a list of ports for this purpose.
|
||||||
*/
|
*/
|
||||||
static void be_work_add_vxlan_port(struct work_struct *work)
|
static void be_work_add_vxlan_port(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct be_cmd_work *cmd_work =
|
struct be_cmd_work *cmd_work =
|
||||||
container_of(work, struct be_cmd_work, work);
|
container_of(work, struct be_cmd_work, work);
|
||||||
struct be_adapter *adapter = cmd_work->adapter;
|
struct be_adapter *adapter = cmd_work->adapter;
|
||||||
struct net_device *netdev = adapter->netdev;
|
|
||||||
struct device *dev = &adapter->pdev->dev;
|
struct device *dev = &adapter->pdev->dev;
|
||||||
__be16 port = cmd_work->info.vxlan_port;
|
__be16 port = cmd_work->info.vxlan_port;
|
||||||
|
struct be_vxlan_port *vxlan_port;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (adapter->vxlan_port == port && adapter->vxlan_port_count) {
|
/* Bump up the alias count if it is an existing port */
|
||||||
adapter->vxlan_port_aliases++;
|
list_for_each_entry(vxlan_port, &adapter->vxlan_port_list, list) {
|
||||||
goto done;
|
if (vxlan_port->port == port) {
|
||||||
|
vxlan_port->port_aliases++;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add a new port to our list. We don't need a lock here since port
|
||||||
|
* add/delete are done only in the context of a single-threaded work
|
||||||
|
* queue (be_wq).
|
||||||
|
*/
|
||||||
|
vxlan_port = kzalloc(sizeof(*vxlan_port), GFP_KERNEL);
|
||||||
|
if (!vxlan_port)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
vxlan_port->port = port;
|
||||||
|
INIT_LIST_HEAD(&vxlan_port->list);
|
||||||
|
list_add_tail(&vxlan_port->list, &adapter->vxlan_port_list);
|
||||||
|
adapter->vxlan_port_count++;
|
||||||
|
|
||||||
if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) {
|
if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) {
|
||||||
dev_info(dev,
|
dev_info(dev,
|
||||||
"Only one UDP port supported for VxLAN offloads\n");
|
"Only one UDP port supported for VxLAN offloads\n");
|
||||||
dev_info(dev, "Disabling VxLAN offloads\n");
|
dev_info(dev, "Disabling VxLAN offloads\n");
|
||||||
adapter->vxlan_port_count++;
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adapter->vxlan_port_count++ >= 1)
|
if (adapter->vxlan_port_count > 1)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
status = be_cmd_manage_iface(adapter, adapter->if_handle,
|
status = be_enable_vxlan_offloads(adapter);
|
||||||
OP_CONVERT_NORMAL_TO_TUNNEL);
|
if (!status)
|
||||||
if (status) {
|
goto done;
|
||||||
dev_warn(dev, "Failed to convert normal interface to tunnel\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = be_cmd_set_vxlan_port(adapter, port);
|
|
||||||
if (status) {
|
|
||||||
dev_warn(dev, "Failed to add VxLAN port\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
adapter->flags |= BE_FLAGS_VXLAN_OFFLOADS;
|
|
||||||
adapter->vxlan_port = port;
|
|
||||||
|
|
||||||
netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
|
|
||||||
NETIF_F_TSO | NETIF_F_TSO6 |
|
|
||||||
NETIF_F_GSO_UDP_TUNNEL;
|
|
||||||
netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
|
|
||||||
netdev->features |= NETIF_F_GSO_UDP_TUNNEL;
|
|
||||||
|
|
||||||
dev_info(dev, "Enabled VxLAN offloads for UDP port %d\n",
|
|
||||||
be16_to_cpu(port));
|
|
||||||
goto done;
|
|
||||||
err:
|
err:
|
||||||
be_disable_vxlan_offloads(adapter);
|
be_disable_vxlan_offloads(adapter);
|
||||||
done:
|
done:
|
||||||
kfree(cmd_work);
|
kfree(cmd_work);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void be_work_del_vxlan_port(struct work_struct *work)
|
static void be_work_del_vxlan_port(struct work_struct *work)
|
||||||
@ -4968,23 +5002,40 @@ static void be_work_del_vxlan_port(struct work_struct *work)
|
|||||||
container_of(work, struct be_cmd_work, work);
|
container_of(work, struct be_cmd_work, work);
|
||||||
struct be_adapter *adapter = cmd_work->adapter;
|
struct be_adapter *adapter = cmd_work->adapter;
|
||||||
__be16 port = cmd_work->info.vxlan_port;
|
__be16 port = cmd_work->info.vxlan_port;
|
||||||
|
struct be_vxlan_port *vxlan_port;
|
||||||
|
|
||||||
if (adapter->vxlan_port != port)
|
/* Nothing to be done if a port alias is being deleted */
|
||||||
goto done;
|
list_for_each_entry(vxlan_port, &adapter->vxlan_port_list, list) {
|
||||||
|
if (vxlan_port->port == port) {
|
||||||
|
if (vxlan_port->port_aliases) {
|
||||||
|
vxlan_port->port_aliases--;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (adapter->vxlan_port_aliases) {
|
/* No port aliases left; delete the port from the list */
|
||||||
adapter->vxlan_port_aliases--;
|
list_del(&vxlan_port->list);
|
||||||
|
adapter->vxlan_port_count--;
|
||||||
|
|
||||||
|
/* Disable VxLAN offload if this is the offloaded port */
|
||||||
|
if (adapter->vxlan_port == vxlan_port->port) {
|
||||||
|
WARN_ON(adapter->vxlan_port_count);
|
||||||
|
be_disable_vxlan_offloads(adapter);
|
||||||
|
dev_info(&adapter->pdev->dev,
|
||||||
|
"Disabled VxLAN offloads for UDP port %d\n",
|
||||||
|
be16_to_cpu(port));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
be_disable_vxlan_offloads(adapter);
|
/* If only 1 port is left, re-enable VxLAN offload */
|
||||||
|
if (adapter->vxlan_port_count == 1)
|
||||||
|
be_enable_vxlan_offloads(adapter);
|
||||||
|
|
||||||
dev_info(&adapter->pdev->dev,
|
|
||||||
"Disabled VxLAN offloads for UDP port %d\n",
|
|
||||||
be16_to_cpu(port));
|
|
||||||
done:
|
|
||||||
adapter->vxlan_port_count--;
|
|
||||||
out:
|
out:
|
||||||
|
kfree(vxlan_port);
|
||||||
|
done:
|
||||||
kfree(cmd_work);
|
kfree(cmd_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5626,6 +5677,7 @@ static int be_drv_init(struct be_adapter *adapter)
|
|||||||
/* Must be a power of 2 or else MODULO will BUG_ON */
|
/* Must be a power of 2 or else MODULO will BUG_ON */
|
||||||
adapter->be_get_temp_freq = 64;
|
adapter->be_get_temp_freq = 64;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&adapter->vxlan_port_list);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_rx_filter:
|
free_rx_filter:
|
||||||
|
Loading…
Reference in New Issue
Block a user