2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-29 07:34:06 +08:00

Merge branch 'sfc-rx-vlan-filtering'

Edward Cree says:

====================
sfc: RX VLAN filtering

Adds support for VLAN-qualified receive filters on EF10 hardware.
This is needed when running as a guest if the hypervisor has enabled
vfs-vlan-restrict, in which case the firmware rejects filters not qualified
with VLAN 0.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2016-06-15 22:26:27 -07:00
commit b478af0cd7
8 changed files with 2054 additions and 205 deletions

File diff suppressed because it is too large Load Diff

View File

@ -232,6 +232,35 @@ fail:
return rc; return rc;
} }
static int efx_ef10_vadaptor_alloc_set_features(struct efx_nic *efx)
{
struct efx_ef10_nic_data *nic_data = efx->nic_data;
u32 port_flags;
int rc;
rc = efx_ef10_vadaptor_alloc(efx, nic_data->vport_id);
if (rc)
goto fail_vadaptor_alloc;
rc = efx_ef10_vadaptor_query(efx, nic_data->vport_id,
&port_flags, NULL, NULL);
if (rc)
goto fail_vadaptor_query;
if (port_flags &
(1 << MC_CMD_VPORT_ALLOC_IN_FLAG_VLAN_RESTRICT_LBN))
efx->fixed_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
else
efx->fixed_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
return 0;
fail_vadaptor_query:
efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED);
fail_vadaptor_alloc:
return rc;
}
/* On top of the default firmware vswitch setup, create a VEB vswitch and /* On top of the default firmware vswitch setup, create a VEB vswitch and
* expansion vport for use by this function. * expansion vport for use by this function.
*/ */
@ -243,7 +272,7 @@ int efx_ef10_vswitching_probe_pf(struct efx_nic *efx)
if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0) { if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0) {
/* vswitch not needed as we have no VFs */ /* vswitch not needed as we have no VFs */
efx_ef10_vadaptor_alloc(efx, nic_data->vport_id); efx_ef10_vadaptor_alloc_set_features(efx);
return 0; return 0;
} }
@ -263,7 +292,7 @@ int efx_ef10_vswitching_probe_pf(struct efx_nic *efx)
goto fail3; goto fail3;
ether_addr_copy(nic_data->vport_mac, net_dev->dev_addr); ether_addr_copy(nic_data->vport_mac, net_dev->dev_addr);
rc = efx_ef10_vadaptor_alloc(efx, nic_data->vport_id); rc = efx_ef10_vadaptor_alloc_set_features(efx);
if (rc) if (rc)
goto fail4; goto fail4;
@ -282,9 +311,7 @@ fail1:
int efx_ef10_vswitching_probe_vf(struct efx_nic *efx) int efx_ef10_vswitching_probe_vf(struct efx_nic *efx)
{ {
struct efx_ef10_nic_data *nic_data = efx->nic_data; return efx_ef10_vadaptor_alloc_set_features(efx);
return efx_ef10_vadaptor_alloc(efx, nic_data->vport_id);
} }
int efx_ef10_vswitching_restore_pf(struct efx_nic *efx) int efx_ef10_vswitching_restore_pf(struct efx_nic *efx)
@ -554,6 +581,7 @@ int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan,
efx_device_detach_sync(vf->efx); efx_device_detach_sync(vf->efx);
efx_net_stop(vf->efx->net_dev); efx_net_stop(vf->efx->net_dev);
mutex_lock(&vf->efx->mac_lock);
down_write(&vf->efx->filter_sem); down_write(&vf->efx->filter_sem);
vf->efx->type->filter_table_remove(vf->efx); vf->efx->type->filter_table_remove(vf->efx);
@ -630,6 +658,7 @@ restore_filters:
goto reset_nic_up_write; goto reset_nic_up_write;
up_write(&vf->efx->filter_sem); up_write(&vf->efx->filter_sem);
mutex_unlock(&vf->efx->mac_lock);
up_write(&vf->efx->filter_sem); up_write(&vf->efx->filter_sem);
@ -642,9 +671,10 @@ restore_filters:
return rc; return rc;
reset_nic_up_write: reset_nic_up_write:
if (vf->efx) if (vf->efx) {
up_write(&vf->efx->filter_sem); up_write(&vf->efx->filter_sem);
mutex_unlock(&vf->efx->mac_lock);
}
reset_nic: reset_nic:
if (vf->efx) { if (vf->efx) {
netif_err(efx, drv, efx->net_dev, netif_err(efx, drv, efx->net_dev,

View File

@ -70,6 +70,9 @@ int efx_ef10_vport_add_mac(struct efx_nic *efx,
int efx_ef10_vport_del_mac(struct efx_nic *efx, int efx_ef10_vport_del_mac(struct efx_nic *efx,
unsigned int port_id, u8 *mac); unsigned int port_id, u8 *mac);
int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id); int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id);
int efx_ef10_vadaptor_query(struct efx_nic *efx, unsigned int port_id,
u32 *port_flags, u32 *vadaptor_flags,
unsigned int *vlan_tags);
int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id); int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id);
#endif /* EF10_SRIOV_H */ #endif /* EF10_SRIOV_H */

View File

@ -600,6 +600,7 @@ fail:
*/ */
static void efx_start_datapath(struct efx_nic *efx) static void efx_start_datapath(struct efx_nic *efx)
{ {
netdev_features_t old_features = efx->net_dev->features;
bool old_rx_scatter = efx->rx_scatter; bool old_rx_scatter = efx->rx_scatter;
struct efx_tx_queue *tx_queue; struct efx_tx_queue *tx_queue;
struct efx_rx_queue *rx_queue; struct efx_rx_queue *rx_queue;
@ -644,6 +645,15 @@ static void efx_start_datapath(struct efx_nic *efx)
efx->rx_dma_len, efx->rx_page_buf_step, efx->rx_dma_len, efx->rx_page_buf_step,
efx->rx_bufs_per_page, efx->rx_pages_per_batch); efx->rx_bufs_per_page, efx->rx_pages_per_batch);
/* Restore previously fixed features in hw_features and remove
* features which are fixed now
*/
efx->net_dev->hw_features |= efx->net_dev->features;
efx->net_dev->hw_features &= ~efx->fixed_features;
efx->net_dev->features |= efx->fixed_features;
if (efx->net_dev->features != old_features)
netdev_features_change(efx->net_dev);
/* RX filters may also have scatter-enabled flags */ /* RX filters may also have scatter-enabled flags */
if (efx->rx_scatter != old_rx_scatter) if (efx->rx_scatter != old_rx_scatter)
efx->type->filter_update_rx_scatter(efx); efx->type->filter_update_rx_scatter(efx);
@ -1719,6 +1729,7 @@ static int efx_probe_filters(struct efx_nic *efx)
spin_lock_init(&efx->filter_lock); spin_lock_init(&efx->filter_lock);
init_rwsem(&efx->filter_sem); init_rwsem(&efx->filter_sem);
mutex_lock(&efx->mac_lock);
down_write(&efx->filter_sem); down_write(&efx->filter_sem);
rc = efx->type->filter_table_probe(efx); rc = efx->type->filter_table_probe(efx);
if (rc) if (rc)
@ -1757,6 +1768,7 @@ static int efx_probe_filters(struct efx_nic *efx)
#endif #endif
out_unlock: out_unlock:
up_write(&efx->filter_sem); up_write(&efx->filter_sem);
mutex_unlock(&efx->mac_lock);
return rc; return rc;
} }
@ -2312,14 +2324,46 @@ static void efx_set_rx_mode(struct net_device *net_dev)
static int efx_set_features(struct net_device *net_dev, netdev_features_t data) static int efx_set_features(struct net_device *net_dev, netdev_features_t data)
{ {
struct efx_nic *efx = netdev_priv(net_dev); struct efx_nic *efx = netdev_priv(net_dev);
int rc;
/* If disabling RX n-tuple filtering, clear existing filters */ /* If disabling RX n-tuple filtering, clear existing filters */
if (net_dev->features & ~data & NETIF_F_NTUPLE) if (net_dev->features & ~data & NETIF_F_NTUPLE) {
return efx->type->filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL); rc = efx->type->filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL);
if (rc)
return rc;
}
/* If Rx VLAN filter is changed, update filters via mac_reconfigure */
if ((net_dev->features ^ data) & NETIF_F_HW_VLAN_CTAG_FILTER) {
/* efx_set_rx_mode() will schedule MAC work to update filters
* when a new features are finally set in net_dev.
*/
efx_set_rx_mode(net_dev);
}
return 0; return 0;
} }
static int efx_vlan_rx_add_vid(struct net_device *net_dev, __be16 proto, u16 vid)
{
struct efx_nic *efx = netdev_priv(net_dev);
if (efx->type->vlan_rx_add_vid)
return efx->type->vlan_rx_add_vid(efx, proto, vid);
else
return -EOPNOTSUPP;
}
static int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vid)
{
struct efx_nic *efx = netdev_priv(net_dev);
if (efx->type->vlan_rx_kill_vid)
return efx->type->vlan_rx_kill_vid(efx, proto, vid);
else
return -EOPNOTSUPP;
}
static const struct net_device_ops efx_netdev_ops = { static const struct net_device_ops efx_netdev_ops = {
.ndo_open = efx_net_open, .ndo_open = efx_net_open,
.ndo_stop = efx_net_stop, .ndo_stop = efx_net_stop,
@ -2332,6 +2376,8 @@ static const struct net_device_ops efx_netdev_ops = {
.ndo_set_mac_address = efx_set_mac_address, .ndo_set_mac_address = efx_set_mac_address,
.ndo_set_rx_mode = efx_set_rx_mode, .ndo_set_rx_mode = efx_set_rx_mode,
.ndo_set_features = efx_set_features, .ndo_set_features = efx_set_features,
.ndo_vlan_rx_add_vid = efx_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = efx_vlan_rx_kill_vid,
#ifdef CONFIG_SFC_SRIOV #ifdef CONFIG_SFC_SRIOV
.ndo_set_vf_mac = efx_sriov_set_vf_mac, .ndo_set_vf_mac = efx_sriov_set_vf_mac,
.ndo_set_vf_vlan = efx_sriov_set_vf_vlan, .ndo_set_vf_vlan = efx_sriov_set_vf_vlan,
@ -3147,17 +3193,25 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
return -ENOMEM; return -ENOMEM;
efx = netdev_priv(net_dev); efx = netdev_priv(net_dev);
efx->type = (const struct efx_nic_type *) entry->driver_data; efx->type = (const struct efx_nic_type *) entry->driver_data;
efx->fixed_features |= NETIF_F_HIGHDMA;
net_dev->features |= (efx->type->offload_features | NETIF_F_SG | net_dev->features |= (efx->type->offload_features | NETIF_F_SG |
NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_TSO | NETIF_F_RXCSUM);
NETIF_F_RXCSUM);
if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
net_dev->features |= NETIF_F_TSO6; net_dev->features |= NETIF_F_TSO6;
/* Mask for features that also apply to VLAN devices */ /* Mask for features that also apply to VLAN devices */
net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG | net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG |
NETIF_F_HIGHDMA | NETIF_F_ALL_TSO | NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
NETIF_F_RXCSUM); NETIF_F_RXCSUM);
/* All offloads can be toggled */
net_dev->hw_features = net_dev->features & ~NETIF_F_HIGHDMA; net_dev->hw_features = net_dev->features & ~efx->fixed_features;
/* Disable VLAN filtering by default. It may be enforced if
* the feature is fixed (i.e. VLAN filters are required to
* receive VLAN tagged packets due to vPort restrictions).
*/
net_dev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
net_dev->features |= efx->fixed_features;
pci_set_drvdata(pci_dev, efx); pci_set_drvdata(pci_dev, efx);
SET_NETDEV_DEV(net_dev, &pci_dev->dev); SET_NETDEV_DEV(net_dev, &pci_dev->dev);
rc = efx_init_struct(efx, pci_dev, net_dev); rc = efx_init_struct(efx, pci_dev, net_dev);

View File

@ -274,4 +274,13 @@ static inline void efx_device_detach_sync(struct efx_nic *efx)
netif_tx_unlock_bh(dev); netif_tx_unlock_bh(dev);
} }
static inline bool efx_rwsem_assert_write_locked(struct rw_semaphore *sem)
{
if (WARN_ON(down_read_trylock(sem))) {
up_read(sem);
return false;
}
return true;
}
#endif /* EFX_EFX_H */ #endif /* EFX_EFX_H */

File diff suppressed because it is too large Load Diff

View File

@ -868,6 +868,7 @@ struct vfdi_status;
* be held to modify it. * be held to modify it.
* @port_initialized: Port initialized? * @port_initialized: Port initialized?
* @net_dev: Operating system network device. Consider holding the rtnl lock * @net_dev: Operating system network device. Consider holding the rtnl lock
* @fixed_features: Features which cannot be turned off
* @stats_buffer: DMA buffer for statistics * @stats_buffer: DMA buffer for statistics
* @phy_type: PHY type * @phy_type: PHY type
* @phy_op: PHY interface * @phy_op: PHY interface
@ -916,7 +917,6 @@ struct vfdi_status;
* @stats_lock: Statistics update lock. Must be held when calling * @stats_lock: Statistics update lock. Must be held when calling
* efx_nic_type::{update,start,stop}_stats. * efx_nic_type::{update,start,stop}_stats.
* @n_rx_noskb_drops: Count of RX packets dropped due to failure to allocate an skb * @n_rx_noskb_drops: Count of RX packets dropped due to failure to allocate an skb
* @mc_promisc: Whether in multicast promiscuous mode when last changed
* *
* This is stored in the private area of the &struct net_device. * This is stored in the private area of the &struct net_device.
*/ */
@ -1008,6 +1008,8 @@ struct efx_nic {
bool port_initialized; bool port_initialized;
struct net_device *net_dev; struct net_device *net_dev;
netdev_features_t fixed_features;
struct efx_buffer stats_buffer; struct efx_buffer stats_buffer;
u64 rx_nodesc_drops_total; u64 rx_nodesc_drops_total;
u64 rx_nodesc_drops_while_down; u64 rx_nodesc_drops_while_down;
@ -1065,7 +1067,6 @@ struct efx_nic {
int last_irq_cpu; int last_irq_cpu;
spinlock_t stats_lock; spinlock_t stats_lock;
atomic_t n_rx_noskb_drops; atomic_t n_rx_noskb_drops;
bool mc_promisc;
}; };
static inline int efx_dev_registered(struct efx_nic *efx) static inline int efx_dev_registered(struct efx_nic *efx)
@ -1333,6 +1334,8 @@ struct efx_nic_type {
int (*ptp_set_ts_config)(struct efx_nic *efx, int (*ptp_set_ts_config)(struct efx_nic *efx,
struct hwtstamp_config *init); struct hwtstamp_config *init);
int (*sriov_configure)(struct efx_nic *efx, int num_vfs); int (*sriov_configure)(struct efx_nic *efx, int num_vfs);
int (*vlan_rx_add_vid)(struct efx_nic *efx, __be16 proto, u16 vid);
int (*vlan_rx_kill_vid)(struct efx_nic *efx, __be16 proto, u16 vid);
int (*sriov_init)(struct efx_nic *efx); int (*sriov_init)(struct efx_nic *efx);
void (*sriov_fini)(struct efx_nic *efx); void (*sriov_fini)(struct efx_nic *efx);
bool (*sriov_wanted)(struct efx_nic *efx); bool (*sriov_wanted)(struct efx_nic *efx);
@ -1521,4 +1524,16 @@ static inline void efx_xmit_hwtstamp_pending(struct sk_buff *skb)
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
} }
/* Get all supported features.
* If a feature is not fixed, it is present in hw_features.
* If a feature is fixed, it does not present in hw_features, but
* always in features.
*/
static inline netdev_features_t efx_supported_features(const struct efx_nic *efx)
{
const struct net_device *net_dev = efx->net_dev;
return net_dev->features | net_dev->hw_features;
}
#endif /* EFX_NET_DRIVER_H */ #endif /* EFX_NET_DRIVER_H */

View File

@ -519,6 +519,9 @@ enum {
#ifdef CONFIG_SFC_SRIOV #ifdef CONFIG_SFC_SRIOV
* @vf: Pointer to VF data structure * @vf: Pointer to VF data structure
#endif #endif
* @vport_mac: The MAC address on the vport, only for PFs; VFs will be zero
* @vlan_list: List of VLANs added over the interface. Serialised by vlan_lock.
* @vlan_lock: Lock to serialize access to vlan_list.
*/ */
struct efx_ef10_nic_data { struct efx_ef10_nic_data {
struct efx_buffer mcdi_buf; struct efx_buffer mcdi_buf;
@ -550,6 +553,8 @@ struct efx_ef10_nic_data {
struct ef10_vf *vf; struct ef10_vf *vf;
#endif #endif
u8 vport_mac[ETH_ALEN]; u8 vport_mac[ETH_ALEN];
struct list_head vlan_list;
struct mutex vlan_lock;
}; };
int efx_init_sriov(void); int efx_init_sriov(void);