cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

coalesce.c (14019B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2
      3#include "netlink.h"
      4#include "common.h"
      5
      6struct coalesce_req_info {
      7	struct ethnl_req_info		base;
      8};
      9
     10struct coalesce_reply_data {
     11	struct ethnl_reply_data		base;
     12	struct ethtool_coalesce		coalesce;
     13	struct kernel_ethtool_coalesce	kernel_coalesce;
     14	u32				supported_params;
     15};
     16
     17#define COALESCE_REPDATA(__reply_base) \
     18	container_of(__reply_base, struct coalesce_reply_data, base)
     19
     20#define __SUPPORTED_OFFSET ETHTOOL_A_COALESCE_RX_USECS
     21static u32 attr_to_mask(unsigned int attr_type)
     22{
     23	return BIT(attr_type - __SUPPORTED_OFFSET);
     24}
     25
     26/* build time check that indices in ethtool_ops::supported_coalesce_params
     27 * match corresponding attribute types with an offset
     28 */
     29#define __CHECK_SUPPORTED_OFFSET(x) \
     30	static_assert((ETHTOOL_ ## x) == \
     31		      BIT((ETHTOOL_A_ ## x) - __SUPPORTED_OFFSET))
     32__CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS);
     33__CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES);
     34__CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_IRQ);
     35__CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_IRQ);
     36__CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS);
     37__CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES);
     38__CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_IRQ);
     39__CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_IRQ);
     40__CHECK_SUPPORTED_OFFSET(COALESCE_STATS_BLOCK_USECS);
     41__CHECK_SUPPORTED_OFFSET(COALESCE_USE_ADAPTIVE_RX);
     42__CHECK_SUPPORTED_OFFSET(COALESCE_USE_ADAPTIVE_TX);
     43__CHECK_SUPPORTED_OFFSET(COALESCE_PKT_RATE_LOW);
     44__CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_LOW);
     45__CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_LOW);
     46__CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_LOW);
     47__CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_LOW);
     48__CHECK_SUPPORTED_OFFSET(COALESCE_PKT_RATE_HIGH);
     49__CHECK_SUPPORTED_OFFSET(COALESCE_RX_USECS_HIGH);
     50__CHECK_SUPPORTED_OFFSET(COALESCE_RX_MAX_FRAMES_HIGH);
     51__CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_HIGH);
     52__CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_HIGH);
     53__CHECK_SUPPORTED_OFFSET(COALESCE_RATE_SAMPLE_INTERVAL);
     54
     55const struct nla_policy ethnl_coalesce_get_policy[] = {
     56	[ETHTOOL_A_COALESCE_HEADER]		=
     57		NLA_POLICY_NESTED(ethnl_header_policy),
     58};
     59
     60static int coalesce_prepare_data(const struct ethnl_req_info *req_base,
     61				 struct ethnl_reply_data *reply_base,
     62				 struct genl_info *info)
     63{
     64	struct coalesce_reply_data *data = COALESCE_REPDATA(reply_base);
     65	struct netlink_ext_ack *extack = info ? info->extack : NULL;
     66	struct net_device *dev = reply_base->dev;
     67	int ret;
     68
     69	if (!dev->ethtool_ops->get_coalesce)
     70		return -EOPNOTSUPP;
     71	data->supported_params = dev->ethtool_ops->supported_coalesce_params;
     72	ret = ethnl_ops_begin(dev);
     73	if (ret < 0)
     74		return ret;
     75	ret = dev->ethtool_ops->get_coalesce(dev, &data->coalesce,
     76					     &data->kernel_coalesce, extack);
     77	ethnl_ops_complete(dev);
     78
     79	return ret;
     80}
     81
     82static int coalesce_reply_size(const struct ethnl_req_info *req_base,
     83			       const struct ethnl_reply_data *reply_base)
     84{
     85	return nla_total_size(sizeof(u32)) +	/* _RX_USECS */
     86	       nla_total_size(sizeof(u32)) +	/* _RX_MAX_FRAMES */
     87	       nla_total_size(sizeof(u32)) +	/* _RX_USECS_IRQ */
     88	       nla_total_size(sizeof(u32)) +	/* _RX_MAX_FRAMES_IRQ */
     89	       nla_total_size(sizeof(u32)) +	/* _TX_USECS */
     90	       nla_total_size(sizeof(u32)) +	/* _TX_MAX_FRAMES */
     91	       nla_total_size(sizeof(u32)) +	/* _TX_USECS_IRQ */
     92	       nla_total_size(sizeof(u32)) +	/* _TX_MAX_FRAMES_IRQ */
     93	       nla_total_size(sizeof(u32)) +	/* _STATS_BLOCK_USECS */
     94	       nla_total_size(sizeof(u8)) +	/* _USE_ADAPTIVE_RX */
     95	       nla_total_size(sizeof(u8)) +	/* _USE_ADAPTIVE_TX */
     96	       nla_total_size(sizeof(u32)) +	/* _PKT_RATE_LOW */
     97	       nla_total_size(sizeof(u32)) +	/* _RX_USECS_LOW */
     98	       nla_total_size(sizeof(u32)) +	/* _RX_MAX_FRAMES_LOW */
     99	       nla_total_size(sizeof(u32)) +	/* _TX_USECS_LOW */
    100	       nla_total_size(sizeof(u32)) +	/* _TX_MAX_FRAMES_LOW */
    101	       nla_total_size(sizeof(u32)) +	/* _PKT_RATE_HIGH */
    102	       nla_total_size(sizeof(u32)) +	/* _RX_USECS_HIGH */
    103	       nla_total_size(sizeof(u32)) +	/* _RX_MAX_FRAMES_HIGH */
    104	       nla_total_size(sizeof(u32)) +	/* _TX_USECS_HIGH */
    105	       nla_total_size(sizeof(u32)) +	/* _TX_MAX_FRAMES_HIGH */
    106	       nla_total_size(sizeof(u32)) +	/* _RATE_SAMPLE_INTERVAL */
    107	       nla_total_size(sizeof(u8)) +	/* _USE_CQE_MODE_TX */
    108	       nla_total_size(sizeof(u8));	/* _USE_CQE_MODE_RX */
    109}
    110
    111static bool coalesce_put_u32(struct sk_buff *skb, u16 attr_type, u32 val,
    112			     u32 supported_params)
    113{
    114	if (!val && !(supported_params & attr_to_mask(attr_type)))
    115		return false;
    116	return nla_put_u32(skb, attr_type, val);
    117}
    118
    119static bool coalesce_put_bool(struct sk_buff *skb, u16 attr_type, u32 val,
    120			      u32 supported_params)
    121{
    122	if (!val && !(supported_params & attr_to_mask(attr_type)))
    123		return false;
    124	return nla_put_u8(skb, attr_type, !!val);
    125}
    126
    127static int coalesce_fill_reply(struct sk_buff *skb,
    128			       const struct ethnl_req_info *req_base,
    129			       const struct ethnl_reply_data *reply_base)
    130{
    131	const struct coalesce_reply_data *data = COALESCE_REPDATA(reply_base);
    132	const struct kernel_ethtool_coalesce *kcoal = &data->kernel_coalesce;
    133	const struct ethtool_coalesce *coal = &data->coalesce;
    134	u32 supported = data->supported_params;
    135
    136	if (coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS,
    137			     coal->rx_coalesce_usecs, supported) ||
    138	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES,
    139			     coal->rx_max_coalesced_frames, supported) ||
    140	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS_IRQ,
    141			     coal->rx_coalesce_usecs_irq, supported) ||
    142	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ,
    143			     coal->rx_max_coalesced_frames_irq, supported) ||
    144	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS,
    145			     coal->tx_coalesce_usecs, supported) ||
    146	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES,
    147			     coal->tx_max_coalesced_frames, supported) ||
    148	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS_IRQ,
    149			     coal->tx_coalesce_usecs_irq, supported) ||
    150	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ,
    151			     coal->tx_max_coalesced_frames_irq, supported) ||
    152	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_STATS_BLOCK_USECS,
    153			     coal->stats_block_coalesce_usecs, supported) ||
    154	    coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX,
    155			      coal->use_adaptive_rx_coalesce, supported) ||
    156	    coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX,
    157			      coal->use_adaptive_tx_coalesce, supported) ||
    158	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_PKT_RATE_LOW,
    159			     coal->pkt_rate_low, supported) ||
    160	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS_LOW,
    161			     coal->rx_coalesce_usecs_low, supported) ||
    162	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW,
    163			     coal->rx_max_coalesced_frames_low, supported) ||
    164	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS_LOW,
    165			     coal->tx_coalesce_usecs_low, supported) ||
    166	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW,
    167			     coal->tx_max_coalesced_frames_low, supported) ||
    168	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_PKT_RATE_HIGH,
    169			     coal->pkt_rate_high, supported) ||
    170	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_USECS_HIGH,
    171			     coal->rx_coalesce_usecs_high, supported) ||
    172	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH,
    173			     coal->rx_max_coalesced_frames_high, supported) ||
    174	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_USECS_HIGH,
    175			     coal->tx_coalesce_usecs_high, supported) ||
    176	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH,
    177			     coal->tx_max_coalesced_frames_high, supported) ||
    178	    coalesce_put_u32(skb, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL,
    179			     coal->rate_sample_interval, supported) ||
    180	    coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_CQE_MODE_TX,
    181			      kcoal->use_cqe_mode_tx, supported) ||
    182	    coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_CQE_MODE_RX,
    183			      kcoal->use_cqe_mode_rx, supported))
    184		return -EMSGSIZE;
    185
    186	return 0;
    187}
    188
    189const struct ethnl_request_ops ethnl_coalesce_request_ops = {
    190	.request_cmd		= ETHTOOL_MSG_COALESCE_GET,
    191	.reply_cmd		= ETHTOOL_MSG_COALESCE_GET_REPLY,
    192	.hdr_attr		= ETHTOOL_A_COALESCE_HEADER,
    193	.req_info_size		= sizeof(struct coalesce_req_info),
    194	.reply_data_size	= sizeof(struct coalesce_reply_data),
    195
    196	.prepare_data		= coalesce_prepare_data,
    197	.reply_size		= coalesce_reply_size,
    198	.fill_reply		= coalesce_fill_reply,
    199};
    200
    201/* COALESCE_SET */
    202
    203const struct nla_policy ethnl_coalesce_set_policy[] = {
    204	[ETHTOOL_A_COALESCE_HEADER]		=
    205		NLA_POLICY_NESTED(ethnl_header_policy),
    206	[ETHTOOL_A_COALESCE_RX_USECS]		= { .type = NLA_U32 },
    207	[ETHTOOL_A_COALESCE_RX_MAX_FRAMES]	= { .type = NLA_U32 },
    208	[ETHTOOL_A_COALESCE_RX_USECS_IRQ]	= { .type = NLA_U32 },
    209	[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ]	= { .type = NLA_U32 },
    210	[ETHTOOL_A_COALESCE_TX_USECS]		= { .type = NLA_U32 },
    211	[ETHTOOL_A_COALESCE_TX_MAX_FRAMES]	= { .type = NLA_U32 },
    212	[ETHTOOL_A_COALESCE_TX_USECS_IRQ]	= { .type = NLA_U32 },
    213	[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ]	= { .type = NLA_U32 },
    214	[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS]	= { .type = NLA_U32 },
    215	[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX]	= { .type = NLA_U8 },
    216	[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX]	= { .type = NLA_U8 },
    217	[ETHTOOL_A_COALESCE_PKT_RATE_LOW]	= { .type = NLA_U32 },
    218	[ETHTOOL_A_COALESCE_RX_USECS_LOW]	= { .type = NLA_U32 },
    219	[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW]	= { .type = NLA_U32 },
    220	[ETHTOOL_A_COALESCE_TX_USECS_LOW]	= { .type = NLA_U32 },
    221	[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW]	= { .type = NLA_U32 },
    222	[ETHTOOL_A_COALESCE_PKT_RATE_HIGH]	= { .type = NLA_U32 },
    223	[ETHTOOL_A_COALESCE_RX_USECS_HIGH]	= { .type = NLA_U32 },
    224	[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH]	= { .type = NLA_U32 },
    225	[ETHTOOL_A_COALESCE_TX_USECS_HIGH]	= { .type = NLA_U32 },
    226	[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH]	= { .type = NLA_U32 },
    227	[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .type = NLA_U32 },
    228	[ETHTOOL_A_COALESCE_USE_CQE_MODE_TX]	= NLA_POLICY_MAX(NLA_U8, 1),
    229	[ETHTOOL_A_COALESCE_USE_CQE_MODE_RX]	= NLA_POLICY_MAX(NLA_U8, 1),
    230};
    231
    232int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info)
    233{
    234	struct kernel_ethtool_coalesce kernel_coalesce = {};
    235	struct ethtool_coalesce coalesce = {};
    236	struct ethnl_req_info req_info = {};
    237	struct nlattr **tb = info->attrs;
    238	const struct ethtool_ops *ops;
    239	struct net_device *dev;
    240	u32 supported_params;
    241	bool mod = false;
    242	int ret;
    243	u16 a;
    244
    245	ret = ethnl_parse_header_dev_get(&req_info,
    246					 tb[ETHTOOL_A_COALESCE_HEADER],
    247					 genl_info_net(info), info->extack,
    248					 true);
    249	if (ret < 0)
    250		return ret;
    251	dev = req_info.dev;
    252	ops = dev->ethtool_ops;
    253	ret = -EOPNOTSUPP;
    254	if (!ops->get_coalesce || !ops->set_coalesce)
    255		goto out_dev;
    256
    257	/* make sure that only supported parameters are present */
    258	supported_params = ops->supported_coalesce_params;
    259	for (a = ETHTOOL_A_COALESCE_RX_USECS; a < __ETHTOOL_A_COALESCE_CNT; a++)
    260		if (tb[a] && !(supported_params & attr_to_mask(a))) {
    261			ret = -EINVAL;
    262			NL_SET_ERR_MSG_ATTR(info->extack, tb[a],
    263					    "cannot modify an unsupported parameter");
    264			goto out_dev;
    265		}
    266
    267	rtnl_lock();
    268	ret = ethnl_ops_begin(dev);
    269	if (ret < 0)
    270		goto out_rtnl;
    271	ret = ops->get_coalesce(dev, &coalesce, &kernel_coalesce,
    272				info->extack);
    273	if (ret < 0)
    274		goto out_ops;
    275
    276	ethnl_update_u32(&coalesce.rx_coalesce_usecs,
    277			 tb[ETHTOOL_A_COALESCE_RX_USECS], &mod);
    278	ethnl_update_u32(&coalesce.rx_max_coalesced_frames,
    279			 tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES], &mod);
    280	ethnl_update_u32(&coalesce.rx_coalesce_usecs_irq,
    281			 tb[ETHTOOL_A_COALESCE_RX_USECS_IRQ], &mod);
    282	ethnl_update_u32(&coalesce.rx_max_coalesced_frames_irq,
    283			 tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ], &mod);
    284	ethnl_update_u32(&coalesce.tx_coalesce_usecs,
    285			 tb[ETHTOOL_A_COALESCE_TX_USECS], &mod);
    286	ethnl_update_u32(&coalesce.tx_max_coalesced_frames,
    287			 tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES], &mod);
    288	ethnl_update_u32(&coalesce.tx_coalesce_usecs_irq,
    289			 tb[ETHTOOL_A_COALESCE_TX_USECS_IRQ], &mod);
    290	ethnl_update_u32(&coalesce.tx_max_coalesced_frames_irq,
    291			 tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ], &mod);
    292	ethnl_update_u32(&coalesce.stats_block_coalesce_usecs,
    293			 tb[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS], &mod);
    294	ethnl_update_bool32(&coalesce.use_adaptive_rx_coalesce,
    295			    tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX], &mod);
    296	ethnl_update_bool32(&coalesce.use_adaptive_tx_coalesce,
    297			    tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX], &mod);
    298	ethnl_update_u32(&coalesce.pkt_rate_low,
    299			 tb[ETHTOOL_A_COALESCE_PKT_RATE_LOW], &mod);
    300	ethnl_update_u32(&coalesce.rx_coalesce_usecs_low,
    301			 tb[ETHTOOL_A_COALESCE_RX_USECS_LOW], &mod);
    302	ethnl_update_u32(&coalesce.rx_max_coalesced_frames_low,
    303			 tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW], &mod);
    304	ethnl_update_u32(&coalesce.tx_coalesce_usecs_low,
    305			 tb[ETHTOOL_A_COALESCE_TX_USECS_LOW], &mod);
    306	ethnl_update_u32(&coalesce.tx_max_coalesced_frames_low,
    307			 tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW], &mod);
    308	ethnl_update_u32(&coalesce.pkt_rate_high,
    309			 tb[ETHTOOL_A_COALESCE_PKT_RATE_HIGH], &mod);
    310	ethnl_update_u32(&coalesce.rx_coalesce_usecs_high,
    311			 tb[ETHTOOL_A_COALESCE_RX_USECS_HIGH], &mod);
    312	ethnl_update_u32(&coalesce.rx_max_coalesced_frames_high,
    313			 tb[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH], &mod);
    314	ethnl_update_u32(&coalesce.tx_coalesce_usecs_high,
    315			 tb[ETHTOOL_A_COALESCE_TX_USECS_HIGH], &mod);
    316	ethnl_update_u32(&coalesce.tx_max_coalesced_frames_high,
    317			 tb[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH], &mod);
    318	ethnl_update_u32(&coalesce.rate_sample_interval,
    319			 tb[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL], &mod);
    320	ethnl_update_u8(&kernel_coalesce.use_cqe_mode_tx,
    321			tb[ETHTOOL_A_COALESCE_USE_CQE_MODE_TX], &mod);
    322	ethnl_update_u8(&kernel_coalesce.use_cqe_mode_rx,
    323			tb[ETHTOOL_A_COALESCE_USE_CQE_MODE_RX], &mod);
    324	ret = 0;
    325	if (!mod)
    326		goto out_ops;
    327
    328	ret = dev->ethtool_ops->set_coalesce(dev, &coalesce, &kernel_coalesce,
    329					     info->extack);
    330	if (ret < 0)
    331		goto out_ops;
    332	ethtool_notify(dev, ETHTOOL_MSG_COALESCE_NTF, NULL);
    333
    334out_ops:
    335	ethnl_ops_complete(dev);
    336out_rtnl:
    337	rtnl_unlock();
    338out_dev:
    339	ethnl_parse_header_dev_put(&req_info);
    340	return ret;
    341}