Skip to content

Commit 4fdc51b

Browse files
Xue Chaojingdavem330
authored andcommitted
hinic: add support for rss parameters with ethtool
This patch adds support rss parameters with ethtool, user can change hash key, hash indirection table, hash function by ethtool -X, and show rss parameters by ethtool -x. Signed-off-by: Xue Chaojing <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent eb8ce9a commit 4fdc51b

File tree

5 files changed

+479
-1
lines changed

5 files changed

+479
-1
lines changed

drivers/net/ethernet/huawei/hinic/hinic_dev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ struct hinic_dev {
7676
u16 num_rss;
7777
u16 rss_limit;
7878
struct hinic_rss_type rss_type;
79+
u8 *rss_hkey_user;
80+
s32 *rss_indir_user;
7981
};
8082

8183
#endif

drivers/net/ethernet/huawei/hinic/hinic_ethtool.c

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,307 @@ static void hinic_get_channels(struct net_device *netdev,
149149
channels->combined_count = 0;
150150
}
151151

152+
static int hinic_get_rss_hash_opts(struct hinic_dev *nic_dev,
153+
struct ethtool_rxnfc *cmd)
154+
{
155+
struct hinic_rss_type rss_type = { 0 };
156+
int err;
157+
158+
cmd->data = 0;
159+
160+
if (!(nic_dev->flags & HINIC_RSS_ENABLE))
161+
return 0;
162+
163+
err = hinic_get_rss_type(nic_dev, nic_dev->rss_tmpl_idx,
164+
&rss_type);
165+
if (err)
166+
return err;
167+
168+
cmd->data = RXH_IP_SRC | RXH_IP_DST;
169+
switch (cmd->flow_type) {
170+
case TCP_V4_FLOW:
171+
if (rss_type.tcp_ipv4)
172+
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
173+
break;
174+
case TCP_V6_FLOW:
175+
if (rss_type.tcp_ipv6)
176+
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
177+
break;
178+
case UDP_V4_FLOW:
179+
if (rss_type.udp_ipv4)
180+
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
181+
break;
182+
case UDP_V6_FLOW:
183+
if (rss_type.udp_ipv6)
184+
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
185+
break;
186+
case IPV4_FLOW:
187+
case IPV6_FLOW:
188+
break;
189+
default:
190+
cmd->data = 0;
191+
return -EINVAL;
192+
}
193+
194+
return 0;
195+
}
196+
197+
static int set_l4_rss_hash_ops(struct ethtool_rxnfc *cmd,
198+
struct hinic_rss_type *rss_type)
199+
{
200+
u8 rss_l4_en = 0;
201+
202+
switch (cmd->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
203+
case 0:
204+
rss_l4_en = 0;
205+
break;
206+
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
207+
rss_l4_en = 1;
208+
break;
209+
default:
210+
return -EINVAL;
211+
}
212+
213+
switch (cmd->flow_type) {
214+
case TCP_V4_FLOW:
215+
rss_type->tcp_ipv4 = rss_l4_en;
216+
break;
217+
case TCP_V6_FLOW:
218+
rss_type->tcp_ipv6 = rss_l4_en;
219+
break;
220+
case UDP_V4_FLOW:
221+
rss_type->udp_ipv4 = rss_l4_en;
222+
break;
223+
case UDP_V6_FLOW:
224+
rss_type->udp_ipv6 = rss_l4_en;
225+
break;
226+
default:
227+
return -EINVAL;
228+
}
229+
230+
return 0;
231+
}
232+
233+
static int hinic_set_rss_hash_opts(struct hinic_dev *nic_dev,
234+
struct ethtool_rxnfc *cmd)
235+
{
236+
struct hinic_rss_type *rss_type = &nic_dev->rss_type;
237+
int err;
238+
239+
if (!(nic_dev->flags & HINIC_RSS_ENABLE)) {
240+
cmd->data = 0;
241+
return -EOPNOTSUPP;
242+
}
243+
244+
/* RSS does not support anything other than hashing
245+
* to queues on src and dst IPs and ports
246+
*/
247+
if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 |
248+
RXH_L4_B_2_3))
249+
return -EINVAL;
250+
251+
/* We need at least the IP SRC and DEST fields for hashing */
252+
if (!(cmd->data & RXH_IP_SRC) || !(cmd->data & RXH_IP_DST))
253+
return -EINVAL;
254+
255+
err = hinic_get_rss_type(nic_dev,
256+
nic_dev->rss_tmpl_idx, rss_type);
257+
if (err)
258+
return -EFAULT;
259+
260+
switch (cmd->flow_type) {
261+
case TCP_V4_FLOW:
262+
case TCP_V6_FLOW:
263+
case UDP_V4_FLOW:
264+
case UDP_V6_FLOW:
265+
err = set_l4_rss_hash_ops(cmd, rss_type);
266+
if (err)
267+
return err;
268+
break;
269+
case IPV4_FLOW:
270+
rss_type->ipv4 = 1;
271+
break;
272+
case IPV6_FLOW:
273+
rss_type->ipv6 = 1;
274+
break;
275+
default:
276+
return -EINVAL;
277+
}
278+
279+
err = hinic_set_rss_type(nic_dev, nic_dev->rss_tmpl_idx,
280+
*rss_type);
281+
if (err)
282+
return -EFAULT;
283+
284+
return 0;
285+
}
286+
287+
static int __set_rss_rxfh(struct net_device *netdev,
288+
const u32 *indir, const u8 *key)
289+
{
290+
struct hinic_dev *nic_dev = netdev_priv(netdev);
291+
int err;
292+
293+
if (indir) {
294+
if (!nic_dev->rss_indir_user) {
295+
nic_dev->rss_indir_user =
296+
kzalloc(sizeof(u32) * HINIC_RSS_INDIR_SIZE,
297+
GFP_KERNEL);
298+
if (!nic_dev->rss_indir_user)
299+
return -ENOMEM;
300+
}
301+
302+
memcpy(nic_dev->rss_indir_user, indir,
303+
sizeof(u32) * HINIC_RSS_INDIR_SIZE);
304+
305+
err = hinic_rss_set_indir_tbl(nic_dev,
306+
nic_dev->rss_tmpl_idx, indir);
307+
if (err)
308+
return -EFAULT;
309+
}
310+
311+
if (key) {
312+
if (!nic_dev->rss_hkey_user) {
313+
nic_dev->rss_hkey_user =
314+
kzalloc(HINIC_RSS_KEY_SIZE * 2, GFP_KERNEL);
315+
316+
if (!nic_dev->rss_hkey_user)
317+
return -ENOMEM;
318+
}
319+
320+
memcpy(nic_dev->rss_hkey_user, key, HINIC_RSS_KEY_SIZE);
321+
322+
err = hinic_rss_set_template_tbl(nic_dev,
323+
nic_dev->rss_tmpl_idx, key);
324+
if (err)
325+
return -EFAULT;
326+
}
327+
328+
return 0;
329+
}
330+
331+
static int hinic_get_rxnfc(struct net_device *netdev,
332+
struct ethtool_rxnfc *cmd, u32 *rule_locs)
333+
{
334+
struct hinic_dev *nic_dev = netdev_priv(netdev);
335+
int err = 0;
336+
337+
switch (cmd->cmd) {
338+
case ETHTOOL_GRXRINGS:
339+
cmd->data = nic_dev->num_qps;
340+
break;
341+
case ETHTOOL_GRXFH:
342+
err = hinic_get_rss_hash_opts(nic_dev, cmd);
343+
break;
344+
default:
345+
err = -EOPNOTSUPP;
346+
break;
347+
}
348+
349+
return err;
350+
}
351+
352+
static int hinic_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
353+
{
354+
struct hinic_dev *nic_dev = netdev_priv(netdev);
355+
int err = 0;
356+
357+
switch (cmd->cmd) {
358+
case ETHTOOL_SRXFH:
359+
err = hinic_set_rss_hash_opts(nic_dev, cmd);
360+
break;
361+
default:
362+
err = -EOPNOTSUPP;
363+
break;
364+
}
365+
366+
return err;
367+
}
368+
369+
static int hinic_get_rxfh(struct net_device *netdev,
370+
u32 *indir, u8 *key, u8 *hfunc)
371+
{
372+
struct hinic_dev *nic_dev = netdev_priv(netdev);
373+
u8 hash_engine_type = 0;
374+
int err = 0;
375+
376+
if (!(nic_dev->flags & HINIC_RSS_ENABLE))
377+
return -EOPNOTSUPP;
378+
379+
if (hfunc) {
380+
err = hinic_rss_get_hash_engine(nic_dev,
381+
nic_dev->rss_tmpl_idx,
382+
&hash_engine_type);
383+
if (err)
384+
return -EFAULT;
385+
386+
*hfunc = hash_engine_type ? ETH_RSS_HASH_TOP : ETH_RSS_HASH_XOR;
387+
}
388+
389+
if (indir) {
390+
err = hinic_rss_get_indir_tbl(nic_dev,
391+
nic_dev->rss_tmpl_idx, indir);
392+
if (err)
393+
return -EFAULT;
394+
}
395+
396+
if (key)
397+
err = hinic_rss_get_template_tbl(nic_dev,
398+
nic_dev->rss_tmpl_idx, key);
399+
400+
return err;
401+
}
402+
403+
static int hinic_set_rxfh(struct net_device *netdev, const u32 *indir,
404+
const u8 *key, const u8 hfunc)
405+
{
406+
struct hinic_dev *nic_dev = netdev_priv(netdev);
407+
int err = 0;
408+
409+
if (!(nic_dev->flags & HINIC_RSS_ENABLE))
410+
return -EOPNOTSUPP;
411+
412+
if (hfunc != ETH_RSS_HASH_NO_CHANGE) {
413+
if (hfunc != ETH_RSS_HASH_TOP && hfunc != ETH_RSS_HASH_XOR)
414+
return -EOPNOTSUPP;
415+
416+
nic_dev->rss_hash_engine = (hfunc == ETH_RSS_HASH_XOR) ?
417+
HINIC_RSS_HASH_ENGINE_TYPE_XOR :
418+
HINIC_RSS_HASH_ENGINE_TYPE_TOEP;
419+
err = hinic_rss_set_hash_engine
420+
(nic_dev, nic_dev->rss_tmpl_idx,
421+
nic_dev->rss_hash_engine);
422+
if (err)
423+
return -EFAULT;
424+
}
425+
426+
err = __set_rss_rxfh(netdev, indir, key);
427+
428+
return err;
429+
}
430+
431+
static u32 hinic_get_rxfh_key_size(struct net_device *netdev)
432+
{
433+
return HINIC_RSS_KEY_SIZE;
434+
}
435+
436+
static u32 hinic_get_rxfh_indir_size(struct net_device *netdev)
437+
{
438+
return HINIC_RSS_INDIR_SIZE;
439+
}
440+
152441
static const struct ethtool_ops hinic_ethtool_ops = {
153442
.get_link_ksettings = hinic_get_link_ksettings,
154443
.get_drvinfo = hinic_get_drvinfo,
155444
.get_link = ethtool_op_get_link,
156445
.get_ringparam = hinic_get_ringparam,
157446
.get_channels = hinic_get_channels,
447+
.get_rxnfc = hinic_get_rxnfc,
448+
.set_rxnfc = hinic_set_rxnfc,
449+
.get_rxfh_key_size = hinic_get_rxfh_key_size,
450+
.get_rxfh_indir_size = hinic_get_rxfh_indir_size,
451+
.get_rxfh = hinic_get_rxfh,
452+
.set_rxfh = hinic_set_rxfh,
158453
};
159454

160455
void hinic_set_ethtool_ops(struct net_device *netdev)

drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,21 @@ enum hinic_port_cmd {
4545

4646
HINIC_PORT_CMD_SET_RX_CSUM = 26,
4747

48+
HINIC_PORT_CMD_GET_RSS_TEMPLATE_INDIR_TBL = 37,
49+
4850
HINIC_PORT_CMD_SET_PORT_STATE = 41,
4951

5052
HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL = 43,
5153

52-
HINIC_PORT_CMD_SET_RSS_HASH_ENGINE = 45,
54+
HINIC_PORT_CMD_GET_RSS_TEMPLATE_TBL = 44,
55+
56+
HINIC_PORT_CMD_SET_RSS_HASH_ENGINE = 45,
57+
58+
HINIC_PORT_CMD_GET_RSS_HASH_ENGINE = 46,
59+
60+
HINIC_PORT_CMD_GET_RSS_CTX_TBL = 47,
61+
62+
HINIC_PORT_CMD_SET_RSS_CTX_TBL = 48,
5363

5464
HINIC_PORT_CMD_RSS_TEMP_MGR = 49,
5565

0 commit comments

Comments
 (0)