xref: /openbmc/linux/drivers/net/ethernet/sfc/ef100_rep.c (revision 69bb5fa73d2b2d7fa3ccbf16e8b1f055fe2d26b1)
108135eecSEdward Cree // SPDX-License-Identifier: GPL-2.0-only
208135eecSEdward Cree /****************************************************************************
308135eecSEdward Cree  * Driver for Solarflare network controllers and boards
408135eecSEdward Cree  * Copyright 2019 Solarflare Communications Inc.
508135eecSEdward Cree  * Copyright 2020-2022 Xilinx Inc.
608135eecSEdward Cree  *
708135eecSEdward Cree  * This program is free software; you can redistribute it and/or modify it
808135eecSEdward Cree  * under the terms of the GNU General Public License version 2 as published
908135eecSEdward Cree  * by the Free Software Foundation, incorporated herein by reference.
1008135eecSEdward Cree  */
1108135eecSEdward Cree 
1208135eecSEdward Cree #include "ef100_rep.h"
13f72c38faSEdward Cree #include "ef100_netdev.h"
1408135eecSEdward Cree #include "ef100_nic.h"
15da56552dSEdward Cree #include "mae.h"
1608135eecSEdward Cree 
175687eb34SEdward Cree #define EFX_EF100_REP_DRIVER	"efx_ef100_rep"
185687eb34SEdward Cree 
19*69bb5fa7SEdward Cree static int efx_ef100_rep_poll(struct napi_struct *napi, int weight);
20*69bb5fa7SEdward Cree 
21e1479556SEdward Cree static int efx_ef100_rep_init_struct(struct efx_nic *efx, struct efx_rep *efv,
22e1479556SEdward Cree 				     unsigned int i)
2308135eecSEdward Cree {
2408135eecSEdward Cree 	efv->parent = efx;
25e1479556SEdward Cree 	efv->idx = i;
2608135eecSEdward Cree 	INIT_LIST_HEAD(&efv->list);
27*69bb5fa7SEdward Cree 	INIT_LIST_HEAD(&efv->rx_list);
28*69bb5fa7SEdward Cree 	spin_lock_init(&efv->rx_lock);
2908135eecSEdward Cree 	efv->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE |
3008135eecSEdward Cree 			  NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
3108135eecSEdward Cree 			  NETIF_MSG_IFUP | NETIF_MSG_RX_ERR |
3208135eecSEdward Cree 			  NETIF_MSG_TX_ERR | NETIF_MSG_HW;
3308135eecSEdward Cree 	return 0;
3408135eecSEdward Cree }
3508135eecSEdward Cree 
36*69bb5fa7SEdward Cree static int efx_ef100_rep_open(struct net_device *net_dev)
37*69bb5fa7SEdward Cree {
38*69bb5fa7SEdward Cree 	struct efx_rep *efv = netdev_priv(net_dev);
39*69bb5fa7SEdward Cree 
40*69bb5fa7SEdward Cree 	netif_napi_add(net_dev, &efv->napi, efx_ef100_rep_poll,
41*69bb5fa7SEdward Cree 		       NAPI_POLL_WEIGHT);
42*69bb5fa7SEdward Cree 	napi_enable(&efv->napi);
43*69bb5fa7SEdward Cree 	return 0;
44*69bb5fa7SEdward Cree }
45*69bb5fa7SEdward Cree 
46*69bb5fa7SEdward Cree static int efx_ef100_rep_close(struct net_device *net_dev)
47*69bb5fa7SEdward Cree {
48*69bb5fa7SEdward Cree 	struct efx_rep *efv = netdev_priv(net_dev);
49*69bb5fa7SEdward Cree 
50*69bb5fa7SEdward Cree 	napi_disable(&efv->napi);
51*69bb5fa7SEdward Cree 	netif_napi_del(&efv->napi);
52*69bb5fa7SEdward Cree 	return 0;
53*69bb5fa7SEdward Cree }
54*69bb5fa7SEdward Cree 
55f72c38faSEdward Cree static netdev_tx_t efx_ef100_rep_xmit(struct sk_buff *skb,
56f72c38faSEdward Cree 				      struct net_device *dev)
57f72c38faSEdward Cree {
58f72c38faSEdward Cree 	struct efx_rep *efv = netdev_priv(dev);
59f72c38faSEdward Cree 	struct efx_nic *efx = efv->parent;
60f72c38faSEdward Cree 	netdev_tx_t rc;
61f72c38faSEdward Cree 
62f72c38faSEdward Cree 	/* __ef100_hard_start_xmit() will always return success even in the
63f72c38faSEdward Cree 	 * case of TX drops, where it will increment efx's tx_dropped.  The
64f72c38faSEdward Cree 	 * efv stats really only count attempted TX, not success/failure.
65f72c38faSEdward Cree 	 */
66f72c38faSEdward Cree 	atomic64_inc(&efv->stats.tx_packets);
67f72c38faSEdward Cree 	atomic64_add(skb->len, &efv->stats.tx_bytes);
68f72c38faSEdward Cree 	netif_tx_lock(efx->net_dev);
69f72c38faSEdward Cree 	rc = __ef100_hard_start_xmit(skb, efx, dev, efv);
70f72c38faSEdward Cree 	netif_tx_unlock(efx->net_dev);
71f72c38faSEdward Cree 	return rc;
72f72c38faSEdward Cree }
73f72c38faSEdward Cree 
74e1479556SEdward Cree static int efx_ef100_rep_get_port_parent_id(struct net_device *dev,
75e1479556SEdward Cree 					    struct netdev_phys_item_id *ppid)
76e1479556SEdward Cree {
77e1479556SEdward Cree 	struct efx_rep *efv = netdev_priv(dev);
78e1479556SEdward Cree 	struct efx_nic *efx = efv->parent;
79e1479556SEdward Cree 	struct ef100_nic_data *nic_data;
80e1479556SEdward Cree 
81e1479556SEdward Cree 	nic_data = efx->nic_data;
82e1479556SEdward Cree 	/* nic_data->port_id is a u8[] */
83e1479556SEdward Cree 	ppid->id_len = sizeof(nic_data->port_id);
84e1479556SEdward Cree 	memcpy(ppid->id, nic_data->port_id, sizeof(nic_data->port_id));
85e1479556SEdward Cree 	return 0;
86e1479556SEdward Cree }
87e1479556SEdward Cree 
88e1479556SEdward Cree static int efx_ef100_rep_get_phys_port_name(struct net_device *dev,
89e1479556SEdward Cree 					    char *buf, size_t len)
90e1479556SEdward Cree {
91e1479556SEdward Cree 	struct efx_rep *efv = netdev_priv(dev);
92e1479556SEdward Cree 	struct efx_nic *efx = efv->parent;
93e1479556SEdward Cree 	struct ef100_nic_data *nic_data;
94e1479556SEdward Cree 	int ret;
95e1479556SEdward Cree 
96e1479556SEdward Cree 	nic_data = efx->nic_data;
97e1479556SEdward Cree 	ret = snprintf(buf, len, "p%upf%uvf%u", efx->port_num,
98e1479556SEdward Cree 		       nic_data->pf_index, efv->idx);
99e1479556SEdward Cree 	if (ret >= len)
100e1479556SEdward Cree 		return -EOPNOTSUPP;
101e1479556SEdward Cree 
102e1479556SEdward Cree 	return 0;
103e1479556SEdward Cree }
104e1479556SEdward Cree 
105a95115c4SEdward Cree static void efx_ef100_rep_get_stats64(struct net_device *dev,
106a95115c4SEdward Cree 				      struct rtnl_link_stats64 *stats)
107a95115c4SEdward Cree {
108a95115c4SEdward Cree 	struct efx_rep *efv = netdev_priv(dev);
109a95115c4SEdward Cree 
110a95115c4SEdward Cree 	stats->rx_packets = atomic64_read(&efv->stats.rx_packets);
111a95115c4SEdward Cree 	stats->tx_packets = atomic64_read(&efv->stats.tx_packets);
112a95115c4SEdward Cree 	stats->rx_bytes = atomic64_read(&efv->stats.rx_bytes);
113a95115c4SEdward Cree 	stats->tx_bytes = atomic64_read(&efv->stats.tx_bytes);
114a95115c4SEdward Cree 	stats->rx_dropped = atomic64_read(&efv->stats.rx_dropped);
115a95115c4SEdward Cree 	stats->tx_errors = atomic64_read(&efv->stats.tx_errors);
116a95115c4SEdward Cree }
117a95115c4SEdward Cree 
11808135eecSEdward Cree static const struct net_device_ops efx_ef100_rep_netdev_ops = {
119*69bb5fa7SEdward Cree 	.ndo_open		= efx_ef100_rep_open,
120*69bb5fa7SEdward Cree 	.ndo_stop		= efx_ef100_rep_close,
121f72c38faSEdward Cree 	.ndo_start_xmit		= efx_ef100_rep_xmit,
122e1479556SEdward Cree 	.ndo_get_port_parent_id	= efx_ef100_rep_get_port_parent_id,
123e1479556SEdward Cree 	.ndo_get_phys_port_name	= efx_ef100_rep_get_phys_port_name,
124a95115c4SEdward Cree 	.ndo_get_stats64	= efx_ef100_rep_get_stats64,
12508135eecSEdward Cree };
12608135eecSEdward Cree 
1275687eb34SEdward Cree static void efx_ef100_rep_get_drvinfo(struct net_device *dev,
1285687eb34SEdward Cree 				      struct ethtool_drvinfo *drvinfo)
1295687eb34SEdward Cree {
1305687eb34SEdward Cree 	strscpy(drvinfo->driver, EFX_EF100_REP_DRIVER, sizeof(drvinfo->driver));
1315687eb34SEdward Cree }
1325687eb34SEdward Cree 
1335687eb34SEdward Cree static u32 efx_ef100_rep_ethtool_get_msglevel(struct net_device *net_dev)
1345687eb34SEdward Cree {
1355687eb34SEdward Cree 	struct efx_rep *efv = netdev_priv(net_dev);
1365687eb34SEdward Cree 
1375687eb34SEdward Cree 	return efv->msg_enable;
1385687eb34SEdward Cree }
1395687eb34SEdward Cree 
1405687eb34SEdward Cree static void efx_ef100_rep_ethtool_set_msglevel(struct net_device *net_dev,
1415687eb34SEdward Cree 					       u32 msg_enable)
1425687eb34SEdward Cree {
1435687eb34SEdward Cree 	struct efx_rep *efv = netdev_priv(net_dev);
1445687eb34SEdward Cree 
1455687eb34SEdward Cree 	efv->msg_enable = msg_enable;
1465687eb34SEdward Cree }
1475687eb34SEdward Cree 
14808135eecSEdward Cree static const struct ethtool_ops efx_ef100_rep_ethtool_ops = {
1495687eb34SEdward Cree 	.get_drvinfo		= efx_ef100_rep_get_drvinfo,
1505687eb34SEdward Cree 	.get_msglevel		= efx_ef100_rep_ethtool_get_msglevel,
1515687eb34SEdward Cree 	.set_msglevel		= efx_ef100_rep_ethtool_set_msglevel,
15208135eecSEdward Cree };
15308135eecSEdward Cree 
15408135eecSEdward Cree static struct efx_rep *efx_ef100_rep_create_netdev(struct efx_nic *efx,
15508135eecSEdward Cree 						   unsigned int i)
15608135eecSEdward Cree {
15708135eecSEdward Cree 	struct net_device *net_dev;
15808135eecSEdward Cree 	struct efx_rep *efv;
15908135eecSEdward Cree 	int rc;
16008135eecSEdward Cree 
16108135eecSEdward Cree 	net_dev = alloc_etherdev_mq(sizeof(*efv), 1);
16208135eecSEdward Cree 	if (!net_dev)
16308135eecSEdward Cree 		return ERR_PTR(-ENOMEM);
16408135eecSEdward Cree 
16508135eecSEdward Cree 	efv = netdev_priv(net_dev);
166e1479556SEdward Cree 	rc = efx_ef100_rep_init_struct(efx, efv, i);
16708135eecSEdward Cree 	if (rc)
16808135eecSEdward Cree 		goto fail1;
16908135eecSEdward Cree 	efv->net_dev = net_dev;
17008135eecSEdward Cree 	rtnl_lock();
17108135eecSEdward Cree 	spin_lock_bh(&efx->vf_reps_lock);
17208135eecSEdward Cree 	list_add_tail(&efv->list, &efx->vf_reps);
17308135eecSEdward Cree 	spin_unlock_bh(&efx->vf_reps_lock);
17484e7fc25SEdward Cree 	if (netif_running(efx->net_dev) && efx->state == STATE_NET_UP) {
17584e7fc25SEdward Cree 		netif_device_attach(net_dev);
17684e7fc25SEdward Cree 		netif_carrier_on(net_dev);
17784e7fc25SEdward Cree 	} else {
17808135eecSEdward Cree 		netif_carrier_off(net_dev);
17908135eecSEdward Cree 		netif_tx_stop_all_queues(net_dev);
18084e7fc25SEdward Cree 	}
18108135eecSEdward Cree 	rtnl_unlock();
18208135eecSEdward Cree 
18308135eecSEdward Cree 	net_dev->netdev_ops = &efx_ef100_rep_netdev_ops;
18408135eecSEdward Cree 	net_dev->ethtool_ops = &efx_ef100_rep_ethtool_ops;
18508135eecSEdward Cree 	net_dev->min_mtu = EFX_MIN_MTU;
18608135eecSEdward Cree 	net_dev->max_mtu = EFX_MAX_MTU;
187f72c38faSEdward Cree 	net_dev->features |= NETIF_F_LLTX;
188f72c38faSEdward Cree 	net_dev->hw_features |= NETIF_F_LLTX;
18908135eecSEdward Cree 	return efv;
19008135eecSEdward Cree fail1:
19108135eecSEdward Cree 	free_netdev(net_dev);
19208135eecSEdward Cree 	return ERR_PTR(rc);
19308135eecSEdward Cree }
19408135eecSEdward Cree 
195da56552dSEdward Cree static int efx_ef100_configure_rep(struct efx_rep *efv)
196da56552dSEdward Cree {
197da56552dSEdward Cree 	struct efx_nic *efx = efv->parent;
198da56552dSEdward Cree 	u32 selector;
199da56552dSEdward Cree 	int rc;
200da56552dSEdward Cree 
201da56552dSEdward Cree 	/* Construct mport selector for corresponding VF */
202da56552dSEdward Cree 	efx_mae_mport_vf(efx, efv->idx, &selector);
203da56552dSEdward Cree 	/* Look up actual mport ID */
204da56552dSEdward Cree 	rc = efx_mae_lookup_mport(efx, selector, &efv->mport);
205da56552dSEdward Cree 	if (rc)
206da56552dSEdward Cree 		return rc;
207da56552dSEdward Cree 	pci_dbg(efx->pci_dev, "VF %u has mport ID %#x\n", efv->idx, efv->mport);
208da56552dSEdward Cree 	/* mport label should fit in 16 bits */
209da56552dSEdward Cree 	WARN_ON(efv->mport >> 16);
210da56552dSEdward Cree 
211da56552dSEdward Cree 	return 0;
212da56552dSEdward Cree }
213da56552dSEdward Cree 
21408135eecSEdward Cree static void efx_ef100_rep_destroy_netdev(struct efx_rep *efv)
21508135eecSEdward Cree {
21608135eecSEdward Cree 	struct efx_nic *efx = efv->parent;
21708135eecSEdward Cree 
21884e7fc25SEdward Cree 	rtnl_lock();
21908135eecSEdward Cree 	spin_lock_bh(&efx->vf_reps_lock);
22008135eecSEdward Cree 	list_del(&efv->list);
22108135eecSEdward Cree 	spin_unlock_bh(&efx->vf_reps_lock);
22284e7fc25SEdward Cree 	rtnl_unlock();
22308135eecSEdward Cree 	free_netdev(efv->net_dev);
22408135eecSEdward Cree }
22508135eecSEdward Cree 
22608135eecSEdward Cree int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i)
22708135eecSEdward Cree {
22808135eecSEdward Cree 	struct efx_rep *efv;
22908135eecSEdward Cree 	int rc;
23008135eecSEdward Cree 
23108135eecSEdward Cree 	efv = efx_ef100_rep_create_netdev(efx, i);
23208135eecSEdward Cree 	if (IS_ERR(efv)) {
23308135eecSEdward Cree 		rc = PTR_ERR(efv);
23408135eecSEdward Cree 		pci_err(efx->pci_dev,
23508135eecSEdward Cree 			"Failed to create representor for VF %d, rc %d\n", i,
23608135eecSEdward Cree 			rc);
23708135eecSEdward Cree 		return rc;
23808135eecSEdward Cree 	}
239da56552dSEdward Cree 	rc = efx_ef100_configure_rep(efv);
240da56552dSEdward Cree 	if (rc) {
241da56552dSEdward Cree 		pci_err(efx->pci_dev,
242da56552dSEdward Cree 			"Failed to configure representor for VF %d, rc %d\n",
243da56552dSEdward Cree 			i, rc);
244da56552dSEdward Cree 		goto fail;
245da56552dSEdward Cree 	}
24608135eecSEdward Cree 	rc = register_netdev(efv->net_dev);
24708135eecSEdward Cree 	if (rc) {
24808135eecSEdward Cree 		pci_err(efx->pci_dev,
24908135eecSEdward Cree 			"Failed to register representor for VF %d, rc %d\n",
25008135eecSEdward Cree 			i, rc);
25108135eecSEdward Cree 		goto fail;
25208135eecSEdward Cree 	}
25308135eecSEdward Cree 	pci_dbg(efx->pci_dev, "Representor for VF %d is %s\n", i,
25408135eecSEdward Cree 		efv->net_dev->name);
25508135eecSEdward Cree 	return 0;
25608135eecSEdward Cree fail:
25708135eecSEdward Cree 	efx_ef100_rep_destroy_netdev(efv);
25808135eecSEdward Cree 	return rc;
25908135eecSEdward Cree }
26008135eecSEdward Cree 
26108135eecSEdward Cree void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv)
26208135eecSEdward Cree {
26308135eecSEdward Cree 	struct net_device *rep_dev;
26408135eecSEdward Cree 
26508135eecSEdward Cree 	rep_dev = efv->net_dev;
26608135eecSEdward Cree 	if (!rep_dev)
26708135eecSEdward Cree 		return;
26808135eecSEdward Cree 	netif_dbg(efx, drv, rep_dev, "Removing VF representor\n");
26908135eecSEdward Cree 	unregister_netdev(rep_dev);
27008135eecSEdward Cree 	efx_ef100_rep_destroy_netdev(efv);
27108135eecSEdward Cree }
27208135eecSEdward Cree 
27308135eecSEdward Cree void efx_ef100_fini_vfreps(struct efx_nic *efx)
27408135eecSEdward Cree {
27508135eecSEdward Cree 	struct ef100_nic_data *nic_data = efx->nic_data;
27608135eecSEdward Cree 	struct efx_rep *efv, *next;
27708135eecSEdward Cree 
27808135eecSEdward Cree 	if (!nic_data->grp_mae)
27908135eecSEdward Cree 		return;
28008135eecSEdward Cree 
28108135eecSEdward Cree 	list_for_each_entry_safe(efv, next, &efx->vf_reps, list)
28208135eecSEdward Cree 		efx_ef100_vfrep_destroy(efx, efv);
28308135eecSEdward Cree }
284*69bb5fa7SEdward Cree 
285*69bb5fa7SEdward Cree static int efx_ef100_rep_poll(struct napi_struct *napi, int weight)
286*69bb5fa7SEdward Cree {
287*69bb5fa7SEdward Cree 	struct efx_rep *efv = container_of(napi, struct efx_rep, napi);
288*69bb5fa7SEdward Cree 	unsigned int read_index;
289*69bb5fa7SEdward Cree 	struct list_head head;
290*69bb5fa7SEdward Cree 	struct sk_buff *skb;
291*69bb5fa7SEdward Cree 	bool need_resched;
292*69bb5fa7SEdward Cree 	int spent = 0;
293*69bb5fa7SEdward Cree 
294*69bb5fa7SEdward Cree 	INIT_LIST_HEAD(&head);
295*69bb5fa7SEdward Cree 	/* Grab up to 'weight' pending SKBs */
296*69bb5fa7SEdward Cree 	spin_lock_bh(&efv->rx_lock);
297*69bb5fa7SEdward Cree 	read_index = efv->write_index;
298*69bb5fa7SEdward Cree 	while (spent < weight && !list_empty(&efv->rx_list)) {
299*69bb5fa7SEdward Cree 		skb = list_first_entry(&efv->rx_list, struct sk_buff, list);
300*69bb5fa7SEdward Cree 		list_del(&skb->list);
301*69bb5fa7SEdward Cree 		list_add_tail(&skb->list, &head);
302*69bb5fa7SEdward Cree 		spent++;
303*69bb5fa7SEdward Cree 	}
304*69bb5fa7SEdward Cree 	spin_unlock_bh(&efv->rx_lock);
305*69bb5fa7SEdward Cree 	/* Receive them */
306*69bb5fa7SEdward Cree 	netif_receive_skb_list(&head);
307*69bb5fa7SEdward Cree 	if (spent < weight)
308*69bb5fa7SEdward Cree 		if (napi_complete_done(napi, spent)) {
309*69bb5fa7SEdward Cree 			spin_lock_bh(&efv->rx_lock);
310*69bb5fa7SEdward Cree 			efv->read_index = read_index;
311*69bb5fa7SEdward Cree 			/* If write_index advanced while we were doing the
312*69bb5fa7SEdward Cree 			 * RX, then storing our read_index won't re-prime the
313*69bb5fa7SEdward Cree 			 * fake-interrupt.  In that case, we need to schedule
314*69bb5fa7SEdward Cree 			 * NAPI again to consume the additional packet(s).
315*69bb5fa7SEdward Cree 			 */
316*69bb5fa7SEdward Cree 			need_resched = efv->write_index != read_index;
317*69bb5fa7SEdward Cree 			spin_unlock_bh(&efv->rx_lock);
318*69bb5fa7SEdward Cree 			if (need_resched)
319*69bb5fa7SEdward Cree 				napi_schedule(&efv->napi);
320*69bb5fa7SEdward Cree 		}
321*69bb5fa7SEdward Cree 	return spent;
322*69bb5fa7SEdward Cree }
323