From bc5787c6125cc2c868eaace46c46ce6e83dcfcb6 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Tue, 15 Nov 2011 15:29:55 +0000 Subject: net: remove legacy ethtool ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As all drivers are converted, we may now remove discrete offload setting callback handling. Signed-off-by: Michał Mirosław Acked-by: Ben Hutchings Signed-off-by: David S. Miller --- include/linux/ethtool.h | 53 ------------------------------------------------- 1 file changed, 53 deletions(-) (limited to 'include/linux/ethtool.h') diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index de33de1e2052..20db5b275c3f 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -724,9 +724,6 @@ enum ethtool_sfeatures_retval_bits { #include -/* needed by dev_disable_lro() */ -extern int __ethtool_set_flags(struct net_device *dev, u32 flags); - extern int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); @@ -750,19 +747,6 @@ struct net_device; /* Some generic methods drivers may use in their ethtool_ops */ u32 ethtool_op_get_link(struct net_device *dev); -u32 ethtool_op_get_tx_csum(struct net_device *dev); -int ethtool_op_set_tx_csum(struct net_device *dev, u32 data); -int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data); -int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data); -u32 ethtool_op_get_sg(struct net_device *dev); -int ethtool_op_set_sg(struct net_device *dev, u32 data); -u32 ethtool_op_get_tso(struct net_device *dev); -int ethtool_op_set_tso(struct net_device *dev, u32 data); -u32 ethtool_op_get_ufo(struct net_device *dev); -int ethtool_op_set_ufo(struct net_device *dev, u32 data); -u32 ethtool_op_get_flags(struct net_device *dev); -int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported); -bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); /** * struct ethtool_ops - optional netdev operations @@ -807,22 +791,6 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); * @get_pauseparam: Report pause parameters * @set_pauseparam: Set pause parameters. Returns a negative error code * or zero. - * @get_rx_csum: Deprecated in favour of the netdev feature %NETIF_F_RXCSUM. - * Report whether receive checksums are turned on or off. - * @set_rx_csum: Deprecated in favour of generic netdev features. Turn - * receive checksum on or off. Returns a negative error code or zero. - * @get_tx_csum: Deprecated as redundant. Report whether transmit checksums - * are turned on or off. - * @set_tx_csum: Deprecated in favour of generic netdev features. Turn - * transmit checksums on or off. Returns a negative error code or zero. - * @get_sg: Deprecated as redundant. Report whether scatter-gather is - * enabled. - * @set_sg: Deprecated in favour of generic netdev features. Turn - * scatter-gather on or off. Returns a negative error code or zero. - * @get_tso: Deprecated as redundant. Report whether TCP segmentation - * offload is enabled. - * @set_tso: Deprecated in favour of generic netdev features. Turn TCP - * segmentation offload on or off. Returns a negative error code or zero. * @self_test: Run specified self-tests * @get_strings: Return a set of strings that describe the requested objects * @set_phys_id: Identify the physical devices, e.g. by flashing an LED @@ -844,15 +812,6 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); * negative error code or zero. * @complete: Function to be called after any other operation except * @begin. Will be called even if the other operation failed. - * @get_ufo: Deprecated as redundant. Report whether UDP fragmentation - * offload is enabled. - * @set_ufo: Deprecated in favour of generic netdev features. Turn UDP - * fragmentation offload on or off. Returns a negative error code or zero. - * @get_flags: Deprecated as redundant. Report features included in - * &enum ethtool_flags that are enabled. - * @set_flags: Deprecated in favour of generic netdev features. Turn - * features included in &enum ethtool_flags on or off. Returns a - * negative error code or zero. * @get_priv_flags: Report driver-specific feature flags. * @set_priv_flags: Set driver-specific feature flags. Returns a negative * error code or zero. @@ -917,14 +876,6 @@ struct ethtool_ops { struct ethtool_pauseparam*); int (*set_pauseparam)(struct net_device *, struct ethtool_pauseparam*); - u32 (*get_rx_csum)(struct net_device *); - int (*set_rx_csum)(struct net_device *, u32); - u32 (*get_tx_csum)(struct net_device *); - int (*set_tx_csum)(struct net_device *, u32); - u32 (*get_sg)(struct net_device *); - int (*set_sg)(struct net_device *, u32); - u32 (*get_tso)(struct net_device *); - int (*set_tso)(struct net_device *, u32); void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); void (*get_strings)(struct net_device *, u32 stringset, u8 *); int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state); @@ -932,10 +883,6 @@ struct ethtool_ops { struct ethtool_stats *, u64 *); int (*begin)(struct net_device *); void (*complete)(struct net_device *); - u32 (*get_ufo)(struct net_device *); - int (*set_ufo)(struct net_device *, u32); - u32 (*get_flags)(struct net_device *); - int (*set_flags)(struct net_device *, u32); u32 (*get_priv_flags)(struct net_device *); int (*set_priv_flags)(struct net_device *, u32); int (*get_sset_count)(struct net_device *, int); -- cgit v1.2.3 From 14596f7006297b67516e2b6a2b26bcb11fe08fb3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 15 Dec 2011 13:51:16 +0000 Subject: ethtool: Clarify use of size field for ETHTOOL_GRXFHINDIR In order to find out the device's RX flow hash table size, ethtool initially uses ETHTOOL_GRXFHINDIR with a buffer size of zero. This must be supported, but it is not necessary to support any other user buffer size less than the device table size. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- include/linux/ethtool.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include/linux/ethtool.h') diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 20db5b275c3f..0ec2fd412d03 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -543,8 +543,9 @@ struct compat_ethtool_rxnfc { /** * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR - * @size: On entry, the array size of the user buffer. On return from - * %ETHTOOL_GRXFHINDIR, the array size of the hardware indirection table. + * @size: On entry, the array size of the user buffer, which may be zero + * for %ETHTOOL_GRXFHINDIR. On return from %ETHTOOL_GRXFHINDIR, the + * array size of the hardware indirection table. * @ring_index: RX ring/queue index for each hash value */ struct ethtool_rxfh_indir { -- cgit v1.2.3 From 7850f63f1620512631445b901ae11cd149e7375c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 15 Dec 2011 13:55:01 +0000 Subject: ethtool: Centralise validation of ETHTOOL_{G, S}RXFHINDIR parameters Add a new ethtool operation (get_rxfh_indir_size) to get the indirectional table size. Use this to validate the user buffer size before calling get_rxfh_indir or set_rxfh_indir. Use get_rxnfc to get the number of RX rings, and validate the contents of the new indirection table before calling set_rxfh_indir. Remove this validation from drivers. Signed-off-by: Ben Hutchings Acked-by: Dimitris Michailidis Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 39 ++++------- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 27 ++++---- drivers/net/ethernet/sfc/ethtool.c | 35 ++++------ drivers/net/vmxnet3/vmxnet3_ethtool.c | 35 ++++------ include/linux/ethtool.h | 11 +-- net/core/ethtool.c | 81 +++++++++++++++------- 6 files changed, 117 insertions(+), 111 deletions(-) (limited to 'include/linux/ethtool.h') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 90d44af85600..a688b9d975a2 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -2302,18 +2302,20 @@ static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, } } -static int bnx2x_get_rxfh_indir(struct net_device *dev, - struct ethtool_rxfh_indir *indir) +static u32 bnx2x_get_rxfh_indir_size(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + return (bp->multi_mode == ETH_RSS_MODE_DISABLED ? + 0 : T_ETH_INDIRECTION_TABLE_SIZE); +} + +static int bnx2x_get_rxfh_indir(struct net_device *dev, u32 *indir) { struct bnx2x *bp = netdev_priv(dev); - size_t copy_size = - min_t(size_t, indir->size, T_ETH_INDIRECTION_TABLE_SIZE); u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; size_t i; - if (bp->multi_mode == ETH_RSS_MODE_DISABLED) - return -EOPNOTSUPP; - /* Get the current configuration of the RSS indirection table */ bnx2x_get_rss_ind_table(&bp->rss_conf_obj, ind_table); @@ -2326,33 +2328,19 @@ static int bnx2x_get_rxfh_indir(struct net_device *dev, * align the returned table to the Client ID of the leading RSS * queue. */ - for (i = 0; i < copy_size; i++) - indir->ring_index[i] = ind_table[i] - bp->fp->cl_id; - - indir->size = T_ETH_INDIRECTION_TABLE_SIZE; + for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) + indir[i] = ind_table[i] - bp->fp->cl_id; return 0; } -static int bnx2x_set_rxfh_indir(struct net_device *dev, - const struct ethtool_rxfh_indir *indir) +static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir) { struct bnx2x *bp = netdev_priv(dev); size_t i; u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; - u32 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp); - - if (bp->multi_mode == ETH_RSS_MODE_DISABLED) - return -EOPNOTSUPP; - - /* validate the size */ - if (indir->size != T_ETH_INDIRECTION_TABLE_SIZE) - return -EINVAL; for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { - /* validate the indices */ - if (indir->ring_index[i] >= num_eth_queues) - return -EINVAL; /* * The same as in bnx2x_get_rxfh_indir: we can't use a memcpy() * as an internal storage of an indirection table is a u8 array @@ -2362,7 +2350,7 @@ static int bnx2x_set_rxfh_indir(struct net_device *dev, * align the received table to the Client ID of the leading RSS * queue */ - ind_table[i] = indir->ring_index[i] + bp->fp->cl_id; + ind_table[i] = indir[i] + bp->fp->cl_id; } return bnx2x_config_rss_pf(bp, ind_table, false); @@ -2395,6 +2383,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { .set_phys_id = bnx2x_set_phys_id, .get_ethtool_stats = bnx2x_get_ethtool_stats, .get_rxnfc = bnx2x_get_rxnfc, + .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, .get_rxfh_indir = bnx2x_get_rxfh_indir, .set_rxfh_indir = bnx2x_set_rxfh_indir, }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index a34e7ce7e214..8ffd55bdef3d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1871,30 +1871,30 @@ static int cxgb_set_features(struct net_device *dev, netdev_features_t features) return err; } -static int get_rss_table(struct net_device *dev, struct ethtool_rxfh_indir *p) +static u32 get_rss_table_size(struct net_device *dev) { const struct port_info *pi = netdev_priv(dev); - unsigned int n = min_t(unsigned int, p->size, pi->rss_size); - p->size = pi->rss_size; + return pi->rss_size; +} + +static int get_rss_table(struct net_device *dev, u32 *p) +{ + const struct port_info *pi = netdev_priv(dev); + unsigned int n = pi->rss_size; + while (n--) - p->ring_index[n] = pi->rss[n]; + p[n] = pi->rss[n]; return 0; } -static int set_rss_table(struct net_device *dev, - const struct ethtool_rxfh_indir *p) +static int set_rss_table(struct net_device *dev, const u32 *p) { unsigned int i; struct port_info *pi = netdev_priv(dev); - if (p->size != pi->rss_size) - return -EINVAL; - for (i = 0; i < p->size; i++) - if (p->ring_index[i] >= pi->nqsets) - return -EINVAL; - for (i = 0; i < p->size; i++) - pi->rss[i] = p->ring_index[i]; + for (i = 0; i < pi->rss_size; i++) + pi->rss[i] = p[i]; if (pi->adapter->flags & FULL_INIT_DONE) return write_rss(pi, pi->rss); return 0; @@ -1989,6 +1989,7 @@ static struct ethtool_ops cxgb_ethtool_ops = { .get_wol = get_wol, .set_wol = set_wol, .get_rxnfc = get_rxnfc, + .get_rxfh_indir_size = get_rss_table_size, .get_rxfh_indir = get_rss_table, .set_rxfh_indir = set_rss_table, .flash_device = set_flash, diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index f3cd96dfa398..1be51b2bfa42 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -956,40 +956,28 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, return rc < 0 ? rc : 0; } -static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, - struct ethtool_rxfh_indir *indir) +static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); - size_t copy_size = - min_t(size_t, indir->size, ARRAY_SIZE(efx->rx_indir_table)); - if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) - return -EOPNOTSUPP; + return (efx_nic_rev(efx) < EFX_REV_FALCON_B0 ? + 0 : ARRAY_SIZE(efx->rx_indir_table)); +} + +static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir) +{ + struct efx_nic *efx = netdev_priv(net_dev); - indir->size = ARRAY_SIZE(efx->rx_indir_table); - memcpy(indir->ring_index, efx->rx_indir_table, - copy_size * sizeof(indir->ring_index[0])); + memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table)); return 0; } static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, - const struct ethtool_rxfh_indir *indir) + const u32 *indir) { struct efx_nic *efx = netdev_priv(net_dev); - size_t i; - - if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) - return -EOPNOTSUPP; - - /* Validate size and indices */ - if (indir->size != ARRAY_SIZE(efx->rx_indir_table)) - return -EINVAL; - for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) - if (indir->ring_index[i] >= efx->n_rx_channels) - return -EINVAL; - memcpy(efx->rx_indir_table, indir->ring_index, - sizeof(efx->rx_indir_table)); + memcpy(efx->rx_indir_table, indir, sizeof(efx->rx_indir_table)); efx_nic_push_rx_indir_table(efx); return 0; } @@ -1020,6 +1008,7 @@ const struct ethtool_ops efx_ethtool_ops = { .reset = efx_ethtool_reset, .get_rxnfc = efx_ethtool_get_rxnfc, .set_rx_ntuple = efx_ethtool_set_rx_ntuple, + .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, .get_rxfh_indir = efx_ethtool_get_rxfh_indir, .set_rxfh_indir = efx_ethtool_set_rxfh_indir, }; diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index b492ee1e5f17..a3eb75a62ea9 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -565,44 +565,38 @@ vmxnet3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info, } #ifdef VMXNET3_RSS +static u32 +vmxnet3_get_rss_indir_size(struct net_device *netdev) +{ + struct vmxnet3_adapter *adapter = netdev_priv(netdev); + struct UPT1_RSSConf *rssConf = adapter->rss_conf; + + return rssConf->indTableSize; +} + static int -vmxnet3_get_rss_indir(struct net_device *netdev, - struct ethtool_rxfh_indir *p) +vmxnet3_get_rss_indir(struct net_device *netdev, u32 *p) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); struct UPT1_RSSConf *rssConf = adapter->rss_conf; - unsigned int n = min_t(unsigned int, p->size, rssConf->indTableSize); + unsigned int n = rssConf->indTableSize; - p->size = rssConf->indTableSize; while (n--) - p->ring_index[n] = rssConf->indTable[n]; + p[n] = rssConf->indTable[n]; return 0; } static int -vmxnet3_set_rss_indir(struct net_device *netdev, - const struct ethtool_rxfh_indir *p) +vmxnet3_set_rss_indir(struct net_device *netdev, const u32 *p) { unsigned int i; unsigned long flags; struct vmxnet3_adapter *adapter = netdev_priv(netdev); struct UPT1_RSSConf *rssConf = adapter->rss_conf; - if (p->size != rssConf->indTableSize) - return -EINVAL; - for (i = 0; i < rssConf->indTableSize; i++) { - /* - * Return with error code if any of the queue indices - * is out of range - */ - if (p->ring_index[i] < 0 || - p->ring_index[i] >= adapter->num_rx_queues) - return -EINVAL; - } - for (i = 0; i < rssConf->indTableSize; i++) - rssConf->indTable[i] = p->ring_index[i]; + rssConf->indTable[i] = p[i]; spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, @@ -629,6 +623,7 @@ static struct ethtool_ops vmxnet3_ethtool_ops = { .set_ringparam = vmxnet3_set_ringparam, .get_rxnfc = vmxnet3_get_rxnfc, #ifdef VMXNET3_RSS + .get_rxfh_indir_size = vmxnet3_get_rss_indir_size, .get_rxfh_indir = vmxnet3_get_rss_indir, .set_rxfh_indir = vmxnet3_set_rss_indir, #endif diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 0ec2fd412d03..3b9f09d55b5c 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -828,9 +828,13 @@ u32 ethtool_op_get_link(struct net_device *dev); * error code or zero. * @set_rx_ntuple: Set an RX n-tuple rule. Returns a negative error code * or zero. + * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table. + * Returns zero if not supported for this specific device. * @get_rxfh_indir: Get the contents of the RX flow hash indirection table. + * Will not be called if @get_rxfh_indir_size returns zero. * Returns a negative error code or zero. * @set_rxfh_indir: Set the contents of the RX flow hash indirection table. + * Will not be called if @get_rxfh_indir_size returns zero. * Returns a negative error code or zero. * @get_channels: Get number of channels. * @set_channels: Set number of channels. Returns a negative error code or @@ -894,10 +898,9 @@ struct ethtool_ops { int (*reset)(struct net_device *, u32 *); int (*set_rx_ntuple)(struct net_device *, struct ethtool_rx_ntuple *); - int (*get_rxfh_indir)(struct net_device *, - struct ethtool_rxfh_indir *); - int (*set_rxfh_indir)(struct net_device *, - const struct ethtool_rxfh_indir *); + u32 (*get_rxfh_indir_size)(struct net_device *); + int (*get_rxfh_indir)(struct net_device *, u32 *); + int (*set_rxfh_indir)(struct net_device *, const u32 *); void (*get_channels)(struct net_device *, struct ethtool_channels *); int (*set_channels)(struct net_device *, struct ethtool_channels *); int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 31b0b7f5383e..69f71b86b035 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -515,34 +515,44 @@ err_out: static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, void __user *useraddr) { - struct ethtool_rxfh_indir *indir; - u32 table_size; - size_t full_size; + u32 user_size, dev_size; + u32 *indir; int ret; - if (!dev->ethtool_ops->get_rxfh_indir) + if (!dev->ethtool_ops->get_rxfh_indir_size || + !dev->ethtool_ops->get_rxfh_indir) + return -EOPNOTSUPP; + dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev); + if (dev_size == 0) return -EOPNOTSUPP; - if (copy_from_user(&table_size, + if (copy_from_user(&user_size, useraddr + offsetof(struct ethtool_rxfh_indir, size), - sizeof(table_size))) + sizeof(user_size))) return -EFAULT; - if (table_size > - (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index)) - return -ENOMEM; - full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size; - indir = kzalloc(full_size, GFP_USER); + if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh_indir, size), + &dev_size, sizeof(dev_size))) + return -EFAULT; + + /* If the user buffer size is 0, this is just a query for the + * device table size. Otherwise, if it's smaller than the + * device table size it's an error. + */ + if (user_size < dev_size) + return user_size == 0 ? 0 : -EINVAL; + + indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER); if (!indir) return -ENOMEM; - indir->cmd = ETHTOOL_GRXFHINDIR; - indir->size = table_size; ret = dev->ethtool_ops->get_rxfh_indir(dev, indir); if (ret) goto out; - if (copy_to_user(useraddr, indir, full_size)) + if (copy_to_user(useraddr + + offsetof(struct ethtool_rxfh_indir, ring_index[0]), + indir, dev_size * sizeof(indir[0]))) ret = -EFAULT; out: @@ -553,32 +563,51 @@ out: static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, void __user *useraddr) { - struct ethtool_rxfh_indir *indir; - u32 table_size; - size_t full_size; + struct ethtool_rxnfc rx_rings; + u32 user_size, dev_size, i; + u32 *indir; int ret; - if (!dev->ethtool_ops->set_rxfh_indir) + if (!dev->ethtool_ops->get_rxfh_indir_size || + !dev->ethtool_ops->set_rxfh_indir || + !dev->ethtool_ops->get_rxnfc) + return -EOPNOTSUPP; + dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev); + if (dev_size == 0) return -EOPNOTSUPP; - if (copy_from_user(&table_size, + if (copy_from_user(&user_size, useraddr + offsetof(struct ethtool_rxfh_indir, size), - sizeof(table_size))) + sizeof(user_size))) return -EFAULT; - if (table_size > - (KMALLOC_MAX_SIZE - sizeof(*indir)) / sizeof(*indir->ring_index)) - return -ENOMEM; - full_size = sizeof(*indir) + sizeof(*indir->ring_index) * table_size; - indir = kmalloc(full_size, GFP_USER); + if (user_size != dev_size) + return -EINVAL; + + indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER); if (!indir) return -ENOMEM; - if (copy_from_user(indir, useraddr, full_size)) { + if (copy_from_user(indir, + useraddr + + offsetof(struct ethtool_rxfh_indir, ring_index[0]), + dev_size * sizeof(indir[0]))) { ret = -EFAULT; goto out; } + /* Validate ring indices */ + rx_rings.cmd = ETHTOOL_GRXRINGS; + ret = dev->ethtool_ops->get_rxnfc(dev, &rx_rings, NULL); + if (ret) + goto out; + for (i = 0; i < dev_size; i++) { + if (indir[i] >= rx_rings.data) { + ret = -EINVAL; + goto out; + } + } + ret = dev->ethtool_ops->set_rxfh_indir(dev, indir); out: -- cgit v1.2.3 From 278bc4296bd64ffd1d3913b487dc8a520e423a7a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 15 Dec 2011 13:56:49 +0000 Subject: ethtool: Define and apply a default policy for RX flow hash indirection All drivers that support modification of the RX flow hash indirection table initialise it in the same way: RX rings are assigned to table entries in rotation. Make that default policy explicit by having them call a ethtool_rxfh_indir_default() function. In the ethtool core, add support for a zero size value for ETHTOOL_SRXFHINDIR, which resets the table to this default. Partly-suggested-by: Matt Carlson Signed-off-by: Ben Hutchings Acked-by: Shreyas N Bhatewara Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 3 ++- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +- drivers/net/ethernet/sfc/efx.c | 3 ++- drivers/net/vmxnet3/vmxnet3_drv.c | 3 ++- include/linux/ethtool.h | 23 ++++++++++++++--- net/core/ethtool.c | 33 +++++++++++++++---------- 6 files changed, 47 insertions(+), 20 deletions(-) (limited to 'include/linux/ethtool.h') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 64f5cf5c68d1..2b731b253598 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1545,7 +1545,8 @@ static inline int bnx2x_init_rss_pf(struct bnx2x *bp) if (bp->multi_mode != ETH_RSS_MODE_DISABLED) { for (i = 0; i < sizeof(ind_table); i++) ind_table[i] = - bp->fp->cl_id + (i % num_eth_queues); + bp->fp->cl_id + + ethtool_rxfh_indir_default(i, num_eth_queues); } /* diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 8ffd55bdef3d..fccbe490c7f0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3449,7 +3449,7 @@ static int __devinit init_rss(struct adapter *adap) if (!pi->rss) return -ENOMEM; for (j = 0; j < pi->rss_size; j++) - pi->rss[j] = j % pi->nqsets; + pi->rss[j] = ethtool_rxfh_indir_default(j, pi->nqsets); } return 0; } diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 14e134d3b4d7..44a82c6c60a7 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1336,7 +1336,8 @@ static int efx_probe_nic(struct efx_nic *efx) if (efx->n_channels > 1) get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key)); for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) - efx->rx_indir_table[i] = i % efx->n_rx_channels; + efx->rx_indir_table[i] = + ethtool_rxfh_indir_default(i, efx->n_rx_channels); efx_set_channels(efx); netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 1c2ae11a9e35..de7fc345148a 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2167,7 +2167,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter) rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE; get_random_bytes(&rssConf->hashKey[0], rssConf->hashKeySize); for (i = 0; i < rssConf->indTableSize; i++) - rssConf->indTable[i] = i % adapter->num_rx_queues; + rssConf->indTable[i] = ethtool_rxfh_indir_default( + i, adapter->num_rx_queues); devRead->rssConfDesc.confVer = 1; devRead->rssConfDesc.confLen = sizeof(*rssConf); diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 3b9f09d55b5c..b38bf69310ee 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -543,10 +543,15 @@ struct compat_ethtool_rxnfc { /** * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR - * @size: On entry, the array size of the user buffer, which may be zero - * for %ETHTOOL_GRXFHINDIR. On return from %ETHTOOL_GRXFHINDIR, the - * array size of the hardware indirection table. + * @size: On entry, the array size of the user buffer, which may be zero. + * On return from %ETHTOOL_GRXFHINDIR, the array size of the hardware + * indirection table. * @ring_index: RX ring/queue index for each hash value + * + * For %ETHTOOL_GRXFHINDIR, a @size of zero means that only the size + * should be returned. For %ETHTOOL_SRXFHINDIR, a @size of zero means + * the table should be reset to default values. This last feature + * is not supported by the original implementations. */ struct ethtool_rxfh_indir { __u32 cmd; @@ -749,6 +754,18 @@ struct net_device; /* Some generic methods drivers may use in their ethtool_ops */ u32 ethtool_op_get_link(struct net_device *dev); +/** + * ethtool_rxfh_indir_default - get default value for RX flow hash indirection + * @index: Index in RX flow hash indirection table + * @n_rx_rings: Number of RX rings to use + * + * This function provides the default policy for RX flow hash indirection. + */ +static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings) +{ + return index % n_rx_rings; +} + /** * struct ethtool_ops - optional netdev operations * @get_settings: Get various device settings including Ethernet link diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 69f71b86b035..597732c989ca 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -581,31 +581,38 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, sizeof(user_size))) return -EFAULT; - if (user_size != dev_size) + if (user_size != 0 && user_size != dev_size) return -EINVAL; indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER); if (!indir) return -ENOMEM; - if (copy_from_user(indir, - useraddr + - offsetof(struct ethtool_rxfh_indir, ring_index[0]), - dev_size * sizeof(indir[0]))) { - ret = -EFAULT; - goto out; - } - - /* Validate ring indices */ rx_rings.cmd = ETHTOOL_GRXRINGS; ret = dev->ethtool_ops->get_rxnfc(dev, &rx_rings, NULL); if (ret) goto out; - for (i = 0; i < dev_size; i++) { - if (indir[i] >= rx_rings.data) { - ret = -EINVAL; + + if (user_size == 0) { + for (i = 0; i < dev_size; i++) + indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); + } else { + if (copy_from_user(indir, + useraddr + + offsetof(struct ethtool_rxfh_indir, + ring_index[0]), + dev_size * sizeof(indir[0]))) { + ret = -EFAULT; goto out; } + + /* Validate ring indices */ + for (i = 0; i < dev_size; i++) { + if (indir[i] >= rx_rings.data) { + ret = -EINVAL; + goto out; + } + } } ret = dev->ethtool_ops->set_rxfh_indir(dev, indir); -- cgit v1.2.3 From 55664f324c2a1a6386dc88492c5c94aa3d336b93 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 3 Jan 2012 12:04:51 +0000 Subject: ethtool: Allow drivers to select RX NFC rule locations Define special location values for RX NFC that request the driver to select the actual rule location. This allows for implementation on devices that use hash-based filter lookup, whereas currently the API is more suited to devices with TCAM lookup or linear search. In ethtool_set_rxnfc() and the compat wrapper ethtool_ioctl(), copy the structure back to user-space after insertion so that the actual location is returned. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- include/linux/ethtool.h | 26 ++++++++++++++++++++++++-- net/core/ethtool.c | 11 ++++++++++- net/socket.c | 2 +- 3 files changed, 35 insertions(+), 4 deletions(-) (limited to 'include/linux/ethtool.h') diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index b38bf69310ee..d901714120a3 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -489,7 +489,10 @@ struct ethtool_rx_flow_spec { * on return. * * For %ETHTOOL_GRXCLSRLCNT, @rule_cnt is set to the number of defined - * rules on return. + * rules on return. If @data is non-zero on return then it is the + * size of the rule table, plus the flag %RX_CLS_LOC_SPECIAL if the + * driver supports any special location values. If that flag is not + * set in @data then special location values should not be used. * * For %ETHTOOL_GRXCLSRULE, @fs.@location specifies the location of an * existing rule on entry and @fs contains the rule on return. @@ -501,10 +504,23 @@ struct ethtool_rx_flow_spec { * must use the second parameter to get_rxnfc() instead of @rule_locs. * * For %ETHTOOL_SRXCLSRLINS, @fs specifies the rule to add or update. - * @fs.@location specifies the location to use and must not be ignored. + * @fs.@location either specifies the location to use or is a special + * location value with %RX_CLS_LOC_SPECIAL flag set. On return, + * @fs.@location is the actual rule location. * * For %ETHTOOL_SRXCLSRLDEL, @fs.@location specifies the location of an * existing rule on entry. + * + * A driver supporting the special location values for + * %ETHTOOL_SRXCLSRLINS may add the rule at any suitable unused + * location, and may remove a rule at a later location (lower + * priority) that matches exactly the same set of flows. The special + * values are: %RX_CLS_LOC_ANY, selecting any location; + * %RX_CLS_LOC_FIRST, selecting the first suitable location (maximum + * priority); and %RX_CLS_LOC_LAST, selecting the last suitable + * location (minimum priority). Additional special values may be + * defined in future and drivers must return -%EINVAL for any + * unrecognised value. */ struct ethtool_rxnfc { __u32 cmd; @@ -1141,6 +1157,12 @@ struct ethtool_ops { #define RX_CLS_FLOW_DISC 0xffffffffffffffffULL +/* Special RX classification rule insert location values */ +#define RX_CLS_LOC_SPECIAL 0x80000000 /* flag */ +#define RX_CLS_LOC_ANY 0xffffffff +#define RX_CLS_LOC_FIRST 0xfffffffe +#define RX_CLS_LOC_LAST 0xfffffffd + /* Reset flags */ /* The reset() operation must clear the flags for the components which * were actually reset. On successful return, the flags indicate the diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 597732c989ca..e88b80d41f73 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -439,6 +439,7 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, { struct ethtool_rxnfc info; size_t info_size = sizeof(info); + int rc; if (!dev->ethtool_ops->set_rxnfc) return -EOPNOTSUPP; @@ -454,7 +455,15 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, if (copy_from_user(&info, useraddr, info_size)) return -EFAULT; - return dev->ethtool_ops->set_rxnfc(dev, &info); + rc = dev->ethtool_ops->set_rxnfc(dev, &info); + if (rc) + return rc; + + if (cmd == ETHTOOL_SRXCLSRLINS && + copy_to_user(useraddr, &info, info_size)) + return -EFAULT; + + return 0; } static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, diff --git a/net/socket.c b/net/socket.c index e62b4f055071..2cad581318fe 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2758,10 +2758,10 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) case ETHTOOL_GRXRINGS: case ETHTOOL_GRXCLSRLCNT: case ETHTOOL_GRXCLSRULE: + case ETHTOOL_SRXCLSRLINS: convert_out = true; /* fall through */ case ETHTOOL_SRXCLSRLDEL: - case ETHTOOL_SRXCLSRLINS: buf_size += sizeof(struct ethtool_rxnfc); convert_in = true; break; -- cgit v1.2.3 From 6cfb5e759d47f037cbd0953ec2c3ceb220ed9e96 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 3 Jan 2012 12:07:59 +0000 Subject: ethtool: Remove ethtool_ops::set_rx_ntuple operation All implementations have been converted to implement set_rxnfc instead. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- include/linux/ethtool.h | 4 ---- net/core/ethtool.c | 55 ------------------------------------------------- 2 files changed, 59 deletions(-) (limited to 'include/linux/ethtool.h') diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index d901714120a3..da5b2de99ae4 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -859,8 +859,6 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings) * @reset: Reset (part of) the device, as specified by a bitmask of * flags from &enum ethtool_reset_flags. Returns a negative * error code or zero. - * @set_rx_ntuple: Set an RX n-tuple rule. Returns a negative error code - * or zero. * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table. * Returns zero if not supported for this specific device. * @get_rxfh_indir: Get the contents of the RX flow hash indirection table. @@ -929,8 +927,6 @@ struct ethtool_ops { int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); int (*flash_device)(struct net_device *, struct ethtool_flash *); int (*reset)(struct net_device *, u32 *); - int (*set_rx_ntuple)(struct net_device *, - struct ethtool_rx_ntuple *); u32 (*get_rxfh_indir_size)(struct net_device *); int (*get_rxfh_indir)(struct net_device *, u32 *); int (*set_rxfh_indir)(struct net_device *, const u32 *); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index e88b80d41f73..921aa2b4b415 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -631,58 +631,6 @@ out: return ret; } -/* - * ethtool does not (or did not) set masks for flow parameters that are - * not specified, so if both value and mask are 0 then this must be - * treated as equivalent to a mask with all bits set. Implement that - * here rather than in drivers. - */ -static void rx_ntuple_fix_masks(struct ethtool_rx_ntuple_flow_spec *fs) -{ - struct ethtool_tcpip4_spec *entry = &fs->h_u.tcp_ip4_spec; - struct ethtool_tcpip4_spec *mask = &fs->m_u.tcp_ip4_spec; - - if (fs->flow_type != TCP_V4_FLOW && - fs->flow_type != UDP_V4_FLOW && - fs->flow_type != SCTP_V4_FLOW) - return; - - if (!(entry->ip4src | mask->ip4src)) - mask->ip4src = htonl(0xffffffff); - if (!(entry->ip4dst | mask->ip4dst)) - mask->ip4dst = htonl(0xffffffff); - if (!(entry->psrc | mask->psrc)) - mask->psrc = htons(0xffff); - if (!(entry->pdst | mask->pdst)) - mask->pdst = htons(0xffff); - if (!(entry->tos | mask->tos)) - mask->tos = 0xff; - if (!(fs->vlan_tag | fs->vlan_tag_mask)) - fs->vlan_tag_mask = 0xffff; - if (!(fs->data | fs->data_mask)) - fs->data_mask = 0xffffffffffffffffULL; -} - -static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev, - void __user *useraddr) -{ - struct ethtool_rx_ntuple cmd; - const struct ethtool_ops *ops = dev->ethtool_ops; - - if (!ops->set_rx_ntuple) - return -EOPNOTSUPP; - - if (!(dev->features & NETIF_F_NTUPLE)) - return -EINVAL; - - if (copy_from_user(&cmd, useraddr, sizeof(cmd))) - return -EFAULT; - - rx_ntuple_fix_masks(&cmd.fs); - - return ops->set_rx_ntuple(dev, &cmd); -} - static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) { struct ethtool_regs regs; @@ -1495,9 +1443,6 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_RESET: rc = ethtool_reset(dev, useraddr); break; - case ETHTOOL_SRXNTUPLE: - rc = ethtool_set_rx_ntuple(dev, useraddr); - break; case ETHTOOL_GSSET_INFO: rc = ethtool_get_sset_info(dev, useraddr); break; -- cgit v1.2.3