14ab0c6a8SSathya Perla /* Broadcom NetXtreme-C/E network driver.
24ab0c6a8SSathya Perla  *
34ab0c6a8SSathya Perla  * Copyright (c) 2016-2017 Broadcom Limited
44ab0c6a8SSathya Perla  *
54ab0c6a8SSathya Perla  * This program is free software; you can redistribute it and/or modify
64ab0c6a8SSathya Perla  * it under the terms of the GNU General Public License as published by
74ab0c6a8SSathya Perla  * the Free Software Foundation.
84ab0c6a8SSathya Perla  */
94ab0c6a8SSathya Perla #include <linux/pci.h>
104ab0c6a8SSathya Perla #include <linux/netdevice.h>
114ab0c6a8SSathya Perla #include <linux/etherdevice.h>
124ab0c6a8SSathya Perla #include <linux/rtnetlink.h>
134ab0c6a8SSathya Perla #include <linux/jhash.h>
142ae7408fSSathya Perla #include <net/pkt_cls.h>
154ab0c6a8SSathya Perla 
164ab0c6a8SSathya Perla #include "bnxt_hsi.h"
174ab0c6a8SSathya Perla #include "bnxt.h"
184ab0c6a8SSathya Perla #include "bnxt_vfr.h"
193c467bf3SSteve Lin #include "bnxt_devlink.h"
202ae7408fSSathya Perla #include "bnxt_tc.h"
214ab0c6a8SSathya Perla 
22d3e3beceSSathya Perla #ifdef CONFIG_BNXT_SRIOV
23d3e3beceSSathya Perla 
244ab0c6a8SSathya Perla #define CFA_HANDLE_INVALID		0xffff
25ee5c7fb3SSathya Perla #define VF_IDX_INVALID			0xffff
26ee5c7fb3SSathya Perla 
27ee5c7fb3SSathya Perla static int hwrm_cfa_vfr_alloc(struct bnxt *bp, u16 vf_idx,
28ee5c7fb3SSathya Perla 			      u16 *tx_cfa_action, u16 *rx_cfa_code)
29ee5c7fb3SSathya Perla {
30ee5c7fb3SSathya Perla 	struct hwrm_cfa_vfr_alloc_output *resp = bp->hwrm_cmd_resp_addr;
31ee5c7fb3SSathya Perla 	struct hwrm_cfa_vfr_alloc_input req = { 0 };
32ee5c7fb3SSathya Perla 	int rc;
33ee5c7fb3SSathya Perla 
34ee5c7fb3SSathya Perla 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_CFA_VFR_ALLOC, -1, -1);
35ee5c7fb3SSathya Perla 	req.vf_id = cpu_to_le16(vf_idx);
36ee5c7fb3SSathya Perla 	sprintf(req.vfr_name, "vfr%d", vf_idx);
37ee5c7fb3SSathya Perla 
38ee5c7fb3SSathya Perla 	mutex_lock(&bp->hwrm_cmd_lock);
39ee5c7fb3SSathya Perla 	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
40ee5c7fb3SSathya Perla 	if (!rc) {
41ee5c7fb3SSathya Perla 		*tx_cfa_action = le16_to_cpu(resp->tx_cfa_action);
42ee5c7fb3SSathya Perla 		*rx_cfa_code = le16_to_cpu(resp->rx_cfa_code);
43ee5c7fb3SSathya Perla 		netdev_dbg(bp->dev, "tx_cfa_action=0x%x, rx_cfa_code=0x%x",
44ee5c7fb3SSathya Perla 			   *tx_cfa_action, *rx_cfa_code);
45ee5c7fb3SSathya Perla 	} else {
46ee5c7fb3SSathya Perla 		netdev_info(bp->dev, "%s error rc=%d", __func__, rc);
47ee5c7fb3SSathya Perla 	}
48ee5c7fb3SSathya Perla 
49ee5c7fb3SSathya Perla 	mutex_unlock(&bp->hwrm_cmd_lock);
50ee5c7fb3SSathya Perla 	return rc;
51ee5c7fb3SSathya Perla }
52ee5c7fb3SSathya Perla 
53ee5c7fb3SSathya Perla static int hwrm_cfa_vfr_free(struct bnxt *bp, u16 vf_idx)
54ee5c7fb3SSathya Perla {
55ee5c7fb3SSathya Perla 	struct hwrm_cfa_vfr_free_input req = { 0 };
56ee5c7fb3SSathya Perla 	int rc;
57ee5c7fb3SSathya Perla 
58ee5c7fb3SSathya Perla 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_CFA_VFR_FREE, -1, -1);
59ee5c7fb3SSathya Perla 	sprintf(req.vfr_name, "vfr%d", vf_idx);
60ee5c7fb3SSathya Perla 
61ee5c7fb3SSathya Perla 	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
62ee5c7fb3SSathya Perla 	if (rc)
63ee5c7fb3SSathya Perla 		netdev_info(bp->dev, "%s error rc=%d", __func__, rc);
64ee5c7fb3SSathya Perla 	return rc;
65ee5c7fb3SSathya Perla }
66ee5c7fb3SSathya Perla 
679d96465bSSriharsha Basavapatna static int bnxt_hwrm_vfr_qcfg(struct bnxt *bp, struct bnxt_vf_rep *vf_rep,
689d96465bSSriharsha Basavapatna 			      u16 *max_mtu)
699d96465bSSriharsha Basavapatna {
709d96465bSSriharsha Basavapatna 	struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
719d96465bSSriharsha Basavapatna 	struct hwrm_func_qcfg_input req = {0};
729d96465bSSriharsha Basavapatna 	u16 mtu;
739d96465bSSriharsha Basavapatna 	int rc;
749d96465bSSriharsha Basavapatna 
759d96465bSSriharsha Basavapatna 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCFG, -1, -1);
769d96465bSSriharsha Basavapatna 	req.fid = cpu_to_le16(bp->pf.vf[vf_rep->vf_idx].fw_fid);
779d96465bSSriharsha Basavapatna 
789d96465bSSriharsha Basavapatna 	mutex_lock(&bp->hwrm_cmd_lock);
799d96465bSSriharsha Basavapatna 
809d96465bSSriharsha Basavapatna 	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
819d96465bSSriharsha Basavapatna 	if (!rc) {
829d96465bSSriharsha Basavapatna 		mtu = le16_to_cpu(resp->max_mtu_configured);
839d96465bSSriharsha Basavapatna 		if (!mtu)
849d96465bSSriharsha Basavapatna 			*max_mtu = BNXT_MAX_MTU;
859d96465bSSriharsha Basavapatna 		else
869d96465bSSriharsha Basavapatna 			*max_mtu = mtu;
879d96465bSSriharsha Basavapatna 	}
889d96465bSSriharsha Basavapatna 	mutex_unlock(&bp->hwrm_cmd_lock);
899d96465bSSriharsha Basavapatna 	return rc;
909d96465bSSriharsha Basavapatna }
919d96465bSSriharsha Basavapatna 
92ee5c7fb3SSathya Perla static int bnxt_vf_rep_open(struct net_device *dev)
93ee5c7fb3SSathya Perla {
94ee5c7fb3SSathya Perla 	struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
95ee5c7fb3SSathya Perla 	struct bnxt *bp = vf_rep->bp;
96ee5c7fb3SSathya Perla 
97ee5c7fb3SSathya Perla 	/* Enable link and TX only if the parent PF is open. */
98ee5c7fb3SSathya Perla 	if (netif_running(bp->dev)) {
99ee5c7fb3SSathya Perla 		netif_carrier_on(dev);
100ee5c7fb3SSathya Perla 		netif_tx_start_all_queues(dev);
101ee5c7fb3SSathya Perla 	}
102ee5c7fb3SSathya Perla 	return 0;
103ee5c7fb3SSathya Perla }
104ee5c7fb3SSathya Perla 
105ee5c7fb3SSathya Perla static int bnxt_vf_rep_close(struct net_device *dev)
106ee5c7fb3SSathya Perla {
107ee5c7fb3SSathya Perla 	netif_carrier_off(dev);
108ee5c7fb3SSathya Perla 	netif_tx_disable(dev);
109ee5c7fb3SSathya Perla 
110ee5c7fb3SSathya Perla 	return 0;
111ee5c7fb3SSathya Perla }
112ee5c7fb3SSathya Perla 
113ee5c7fb3SSathya Perla static netdev_tx_t bnxt_vf_rep_xmit(struct sk_buff *skb,
114ee5c7fb3SSathya Perla 				    struct net_device *dev)
115ee5c7fb3SSathya Perla {
116ee5c7fb3SSathya Perla 	struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
117ee5c7fb3SSathya Perla 	int rc, len = skb->len;
118ee5c7fb3SSathya Perla 
119ee5c7fb3SSathya Perla 	skb_dst_drop(skb);
120ee5c7fb3SSathya Perla 	dst_hold((struct dst_entry *)vf_rep->dst);
121ee5c7fb3SSathya Perla 	skb_dst_set(skb, (struct dst_entry *)vf_rep->dst);
122ee5c7fb3SSathya Perla 	skb->dev = vf_rep->dst->u.port_info.lower_dev;
123ee5c7fb3SSathya Perla 
124ee5c7fb3SSathya Perla 	rc = dev_queue_xmit(skb);
125ee5c7fb3SSathya Perla 	if (!rc) {
126ee5c7fb3SSathya Perla 		vf_rep->tx_stats.packets++;
127ee5c7fb3SSathya Perla 		vf_rep->tx_stats.bytes += len;
128ee5c7fb3SSathya Perla 	}
129ee5c7fb3SSathya Perla 	return rc;
130ee5c7fb3SSathya Perla }
131ee5c7fb3SSathya Perla 
132ee5c7fb3SSathya Perla static void
133ee5c7fb3SSathya Perla bnxt_vf_rep_get_stats64(struct net_device *dev,
134ee5c7fb3SSathya Perla 			struct rtnl_link_stats64 *stats)
135ee5c7fb3SSathya Perla {
136ee5c7fb3SSathya Perla 	struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
137ee5c7fb3SSathya Perla 
138ee5c7fb3SSathya Perla 	stats->rx_packets = vf_rep->rx_stats.packets;
139ee5c7fb3SSathya Perla 	stats->rx_bytes = vf_rep->rx_stats.bytes;
140ee5c7fb3SSathya Perla 	stats->tx_packets = vf_rep->tx_stats.packets;
141ee5c7fb3SSathya Perla 	stats->tx_bytes = vf_rep->tx_stats.bytes;
142ee5c7fb3SSathya Perla }
143ee5c7fb3SSathya Perla 
1449e0fd15dSJiri Pirko static int bnxt_vf_rep_setup_tc_block_cb(enum tc_setup_type type,
1459e0fd15dSJiri Pirko 					 void *type_data,
1469e0fd15dSJiri Pirko 					 void *cb_priv)
1472ae7408fSSathya Perla {
1489e0fd15dSJiri Pirko 	struct bnxt_vf_rep *vf_rep = cb_priv;
1492ae7408fSSathya Perla 	struct bnxt *bp = vf_rep->bp;
1502ae7408fSSathya Perla 	int vf_fid = bp->pf.vf[vf_rep->vf_idx].fw_fid;
1512ae7408fSSathya Perla 
152312324f1SJakub Kicinski 	if (!bnxt_tc_flower_enabled(vf_rep->bp) ||
153312324f1SJakub Kicinski 	    !tc_cls_can_offload_and_chain0(bp->dev, type_data))
154cd66358eSSathya Perla 		return -EOPNOTSUPP;
155cd66358eSSathya Perla 
1562ae7408fSSathya Perla 	switch (type) {
1572ae7408fSSathya Perla 	case TC_SETUP_CLSFLOWER:
1582ae7408fSSathya Perla 		return bnxt_tc_setup_flower(bp, vf_fid, type_data);
1592ae7408fSSathya Perla 	default:
1602ae7408fSSathya Perla 		return -EOPNOTSUPP;
1612ae7408fSSathya Perla 	}
1622ae7408fSSathya Perla }
1632ae7408fSSathya Perla 
1649e0fd15dSJiri Pirko static int bnxt_vf_rep_setup_tc_block(struct net_device *dev,
1659e0fd15dSJiri Pirko 				      struct tc_block_offload *f)
1669e0fd15dSJiri Pirko {
1679e0fd15dSJiri Pirko 	struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
1689e0fd15dSJiri Pirko 
1699e0fd15dSJiri Pirko 	if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
1709e0fd15dSJiri Pirko 		return -EOPNOTSUPP;
1719e0fd15dSJiri Pirko 
1729e0fd15dSJiri Pirko 	switch (f->command) {
1739e0fd15dSJiri Pirko 	case TC_BLOCK_BIND:
1749e0fd15dSJiri Pirko 		return tcf_block_cb_register(f->block,
1759e0fd15dSJiri Pirko 					     bnxt_vf_rep_setup_tc_block_cb,
1769e0fd15dSJiri Pirko 					     vf_rep, vf_rep);
1779e0fd15dSJiri Pirko 	case TC_BLOCK_UNBIND:
1789e0fd15dSJiri Pirko 		tcf_block_cb_unregister(f->block,
1799e0fd15dSJiri Pirko 					bnxt_vf_rep_setup_tc_block_cb, vf_rep);
1809e0fd15dSJiri Pirko 		return 0;
1819e0fd15dSJiri Pirko 	default:
1829e0fd15dSJiri Pirko 		return -EOPNOTSUPP;
1839e0fd15dSJiri Pirko 	}
1849e0fd15dSJiri Pirko }
1859e0fd15dSJiri Pirko 
1869e0fd15dSJiri Pirko static int bnxt_vf_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
1879e0fd15dSJiri Pirko 				void *type_data)
1889e0fd15dSJiri Pirko {
1899e0fd15dSJiri Pirko 	switch (type) {
1909e0fd15dSJiri Pirko 	case TC_SETUP_BLOCK:
1919e0fd15dSJiri Pirko 		return bnxt_vf_rep_setup_tc_block(dev, type_data);
1929e0fd15dSJiri Pirko 	default:
1939e0fd15dSJiri Pirko 		return -EOPNOTSUPP;
1949e0fd15dSJiri Pirko 	}
1959e0fd15dSJiri Pirko }
1969e0fd15dSJiri Pirko 
197ee5c7fb3SSathya Perla struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code)
198ee5c7fb3SSathya Perla {
199ee5c7fb3SSathya Perla 	u16 vf_idx;
200ee5c7fb3SSathya Perla 
201ee5c7fb3SSathya Perla 	if (cfa_code && bp->cfa_code_map && BNXT_PF(bp)) {
202ee5c7fb3SSathya Perla 		vf_idx = bp->cfa_code_map[cfa_code];
203ee5c7fb3SSathya Perla 		if (vf_idx != VF_IDX_INVALID)
204ee5c7fb3SSathya Perla 			return bp->vf_reps[vf_idx]->dev;
205ee5c7fb3SSathya Perla 	}
206ee5c7fb3SSathya Perla 	return NULL;
207ee5c7fb3SSathya Perla }
208ee5c7fb3SSathya Perla 
209ee5c7fb3SSathya Perla void bnxt_vf_rep_rx(struct bnxt *bp, struct sk_buff *skb)
210ee5c7fb3SSathya Perla {
211ee5c7fb3SSathya Perla 	struct bnxt_vf_rep *vf_rep = netdev_priv(skb->dev);
212ee5c7fb3SSathya Perla 	struct bnxt_vf_rep_stats *rx_stats;
213ee5c7fb3SSathya Perla 
214ee5c7fb3SSathya Perla 	rx_stats = &vf_rep->rx_stats;
215ee5c7fb3SSathya Perla 	vf_rep->rx_stats.bytes += skb->len;
216ee5c7fb3SSathya Perla 	vf_rep->rx_stats.packets++;
217ee5c7fb3SSathya Perla 
218ee5c7fb3SSathya Perla 	netif_receive_skb(skb);
219ee5c7fb3SSathya Perla }
220ee5c7fb3SSathya Perla 
221c124a62fSSathya Perla static int bnxt_vf_rep_get_phys_port_name(struct net_device *dev, char *buf,
222c124a62fSSathya Perla 					  size_t len)
223c124a62fSSathya Perla {
224c124a62fSSathya Perla 	struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
22553f70b8bSSathya Perla 	struct pci_dev *pf_pdev = vf_rep->bp->pdev;
226c124a62fSSathya Perla 	int rc;
227c124a62fSSathya Perla 
22853f70b8bSSathya Perla 	rc = snprintf(buf, len, "pf%dvf%d", PCI_FUNC(pf_pdev->devfn),
22953f70b8bSSathya Perla 		      vf_rep->vf_idx);
230c124a62fSSathya Perla 	if (rc >= len)
231c124a62fSSathya Perla 		return -EOPNOTSUPP;
232c124a62fSSathya Perla 	return 0;
233c124a62fSSathya Perla }
234c124a62fSSathya Perla 
235ee5c7fb3SSathya Perla static void bnxt_vf_rep_get_drvinfo(struct net_device *dev,
236ee5c7fb3SSathya Perla 				    struct ethtool_drvinfo *info)
237ee5c7fb3SSathya Perla {
238ee5c7fb3SSathya Perla 	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
239ee5c7fb3SSathya Perla 	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
240ee5c7fb3SSathya Perla }
241ee5c7fb3SSathya Perla 
242c124a62fSSathya Perla static int bnxt_vf_rep_port_attr_get(struct net_device *dev,
243c124a62fSSathya Perla 				     struct switchdev_attr *attr)
244c124a62fSSathya Perla {
245c124a62fSSathya Perla 	struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
246c124a62fSSathya Perla 
247c124a62fSSathya Perla 	/* as only PORT_PARENT_ID is supported currently use common code
248c124a62fSSathya Perla 	 * between PF and VF-rep for now.
249c124a62fSSathya Perla 	 */
250c124a62fSSathya Perla 	return bnxt_port_attr_get(vf_rep->bp, attr);
251c124a62fSSathya Perla }
252c124a62fSSathya Perla 
253c124a62fSSathya Perla static const struct switchdev_ops bnxt_vf_rep_switchdev_ops = {
254c124a62fSSathya Perla 	.switchdev_port_attr_get	= bnxt_vf_rep_port_attr_get
255c124a62fSSathya Perla };
256c124a62fSSathya Perla 
257ee5c7fb3SSathya Perla static const struct ethtool_ops bnxt_vf_rep_ethtool_ops = {
258ee5c7fb3SSathya Perla 	.get_drvinfo		= bnxt_vf_rep_get_drvinfo
259ee5c7fb3SSathya Perla };
260ee5c7fb3SSathya Perla 
261ee5c7fb3SSathya Perla static const struct net_device_ops bnxt_vf_rep_netdev_ops = {
262ee5c7fb3SSathya Perla 	.ndo_open		= bnxt_vf_rep_open,
263ee5c7fb3SSathya Perla 	.ndo_stop		= bnxt_vf_rep_close,
264ee5c7fb3SSathya Perla 	.ndo_start_xmit		= bnxt_vf_rep_xmit,
265c124a62fSSathya Perla 	.ndo_get_stats64	= bnxt_vf_rep_get_stats64,
2662ae7408fSSathya Perla 	.ndo_setup_tc		= bnxt_vf_rep_setup_tc,
267c124a62fSSathya Perla 	.ndo_get_phys_port_name = bnxt_vf_rep_get_phys_port_name
268ee5c7fb3SSathya Perla };
269ee5c7fb3SSathya Perla 
270dd4ea1daSSathya Perla bool bnxt_dev_is_vf_rep(struct net_device *dev)
271dd4ea1daSSathya Perla {
272dd4ea1daSSathya Perla 	return dev->netdev_ops == &bnxt_vf_rep_netdev_ops;
273dd4ea1daSSathya Perla }
274dd4ea1daSSathya Perla 
275ee5c7fb3SSathya Perla /* Called when the parent PF interface is closed:
276ee5c7fb3SSathya Perla  * As the mode transition from SWITCHDEV to LEGACY
277ee5c7fb3SSathya Perla  * happens under the rtnl_lock() this routine is safe
278ee5c7fb3SSathya Perla  * under the rtnl_lock()
279ee5c7fb3SSathya Perla  */
280ee5c7fb3SSathya Perla void bnxt_vf_reps_close(struct bnxt *bp)
281ee5c7fb3SSathya Perla {
282ee5c7fb3SSathya Perla 	struct bnxt_vf_rep *vf_rep;
283ee5c7fb3SSathya Perla 	u16 num_vfs, i;
284ee5c7fb3SSathya Perla 
285ee5c7fb3SSathya Perla 	if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV)
286ee5c7fb3SSathya Perla 		return;
287ee5c7fb3SSathya Perla 
288ee5c7fb3SSathya Perla 	num_vfs = pci_num_vf(bp->pdev);
289ee5c7fb3SSathya Perla 	for (i = 0; i < num_vfs; i++) {
290ee5c7fb3SSathya Perla 		vf_rep = bp->vf_reps[i];
291ee5c7fb3SSathya Perla 		if (netif_running(vf_rep->dev))
292ee5c7fb3SSathya Perla 			bnxt_vf_rep_close(vf_rep->dev);
293ee5c7fb3SSathya Perla 	}
294ee5c7fb3SSathya Perla }
295ee5c7fb3SSathya Perla 
296ee5c7fb3SSathya Perla /* Called when the parent PF interface is opened (re-opened):
297ee5c7fb3SSathya Perla  * As the mode transition from SWITCHDEV to LEGACY
298ee5c7fb3SSathya Perla  * happen under the rtnl_lock() this routine is safe
299ee5c7fb3SSathya Perla  * under the rtnl_lock()
300ee5c7fb3SSathya Perla  */
301ee5c7fb3SSathya Perla void bnxt_vf_reps_open(struct bnxt *bp)
302ee5c7fb3SSathya Perla {
303ee5c7fb3SSathya Perla 	int i;
304ee5c7fb3SSathya Perla 
305ee5c7fb3SSathya Perla 	if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV)
306ee5c7fb3SSathya Perla 		return;
307ee5c7fb3SSathya Perla 
308ee5c7fb3SSathya Perla 	for (i = 0; i < pci_num_vf(bp->pdev); i++)
309ee5c7fb3SSathya Perla 		bnxt_vf_rep_open(bp->vf_reps[i]->dev);
310ee5c7fb3SSathya Perla }
3114ab0c6a8SSathya Perla 
3124ab0c6a8SSathya Perla static void __bnxt_vf_reps_destroy(struct bnxt *bp)
3134ab0c6a8SSathya Perla {
3144ab0c6a8SSathya Perla 	u16 num_vfs = pci_num_vf(bp->pdev);
3154ab0c6a8SSathya Perla 	struct bnxt_vf_rep *vf_rep;
3164ab0c6a8SSathya Perla 	int i;
3174ab0c6a8SSathya Perla 
3184ab0c6a8SSathya Perla 	for (i = 0; i < num_vfs; i++) {
3194ab0c6a8SSathya Perla 		vf_rep = bp->vf_reps[i];
3204ab0c6a8SSathya Perla 		if (vf_rep) {
321ee5c7fb3SSathya Perla 			dst_release((struct dst_entry *)vf_rep->dst);
322ee5c7fb3SSathya Perla 
323ee5c7fb3SSathya Perla 			if (vf_rep->tx_cfa_action != CFA_HANDLE_INVALID)
324ee5c7fb3SSathya Perla 				hwrm_cfa_vfr_free(bp, vf_rep->vf_idx);
325ee5c7fb3SSathya Perla 
3264ab0c6a8SSathya Perla 			if (vf_rep->dev) {
3274ab0c6a8SSathya Perla 				/* if register_netdev failed, then netdev_ops
3284ab0c6a8SSathya Perla 				 * would have been set to NULL
3294ab0c6a8SSathya Perla 				 */
3304ab0c6a8SSathya Perla 				if (vf_rep->dev->netdev_ops)
3314ab0c6a8SSathya Perla 					unregister_netdev(vf_rep->dev);
3324ab0c6a8SSathya Perla 				free_netdev(vf_rep->dev);
3334ab0c6a8SSathya Perla 			}
3344ab0c6a8SSathya Perla 		}
3354ab0c6a8SSathya Perla 	}
3364ab0c6a8SSathya Perla 
3374ab0c6a8SSathya Perla 	kfree(bp->vf_reps);
3384ab0c6a8SSathya Perla 	bp->vf_reps = NULL;
3394ab0c6a8SSathya Perla }
3404ab0c6a8SSathya Perla 
3414ab0c6a8SSathya Perla void bnxt_vf_reps_destroy(struct bnxt *bp)
3424ab0c6a8SSathya Perla {
3434ab0c6a8SSathya Perla 	bool closed = false;
3444ab0c6a8SSathya Perla 
3454ab0c6a8SSathya Perla 	if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV)
3464ab0c6a8SSathya Perla 		return;
3474ab0c6a8SSathya Perla 
3484ab0c6a8SSathya Perla 	if (!bp->vf_reps)
3494ab0c6a8SSathya Perla 		return;
3504ab0c6a8SSathya Perla 
3514ab0c6a8SSathya Perla 	/* Ensure that parent PF's and VF-reps' RX/TX has been quiesced
3524ab0c6a8SSathya Perla 	 * before proceeding with VF-rep cleanup.
3534ab0c6a8SSathya Perla 	 */
3544ab0c6a8SSathya Perla 	rtnl_lock();
3554ab0c6a8SSathya Perla 	if (netif_running(bp->dev)) {
3564ab0c6a8SSathya Perla 		bnxt_close_nic(bp, false, false);
3574ab0c6a8SSathya Perla 		closed = true;
3584ab0c6a8SSathya Perla 	}
359ee5c7fb3SSathya Perla 	/* un-publish cfa_code_map so that RX path can't see it anymore */
360ee5c7fb3SSathya Perla 	kfree(bp->cfa_code_map);
361ee5c7fb3SSathya Perla 	bp->cfa_code_map = NULL;
3624ab0c6a8SSathya Perla 	bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
3634ab0c6a8SSathya Perla 
3644ab0c6a8SSathya Perla 	if (closed)
3654ab0c6a8SSathya Perla 		bnxt_open_nic(bp, false, false);
3664ab0c6a8SSathya Perla 	rtnl_unlock();
3674ab0c6a8SSathya Perla 
3684ab0c6a8SSathya Perla 	/* Need to call vf_reps_destroy() outside of rntl_lock
3694ab0c6a8SSathya Perla 	 * as unregister_netdev takes rtnl_lock
3704ab0c6a8SSathya Perla 	 */
3714ab0c6a8SSathya Perla 	__bnxt_vf_reps_destroy(bp);
3724ab0c6a8SSathya Perla }
3734ab0c6a8SSathya Perla 
3744ab0c6a8SSathya Perla /* Use the OUI of the PF's perm addr and report the same mac addr
3754ab0c6a8SSathya Perla  * for the same VF-rep each time
3764ab0c6a8SSathya Perla  */
3774ab0c6a8SSathya Perla static void bnxt_vf_rep_eth_addr_gen(u8 *src_mac, u16 vf_idx, u8 *mac)
3784ab0c6a8SSathya Perla {
3794ab0c6a8SSathya Perla 	u32 addr;
3804ab0c6a8SSathya Perla 
3814ab0c6a8SSathya Perla 	ether_addr_copy(mac, src_mac);
3824ab0c6a8SSathya Perla 
3834ab0c6a8SSathya Perla 	addr = jhash(src_mac, ETH_ALEN, 0) + vf_idx;
3844ab0c6a8SSathya Perla 	mac[3] = (u8)(addr & 0xFF);
3854ab0c6a8SSathya Perla 	mac[4] = (u8)((addr >> 8) & 0xFF);
3864ab0c6a8SSathya Perla 	mac[5] = (u8)((addr >> 16) & 0xFF);
3874ab0c6a8SSathya Perla }
3884ab0c6a8SSathya Perla 
3894ab0c6a8SSathya Perla static void bnxt_vf_rep_netdev_init(struct bnxt *bp, struct bnxt_vf_rep *vf_rep,
3904ab0c6a8SSathya Perla 				    struct net_device *dev)
3914ab0c6a8SSathya Perla {
3924ab0c6a8SSathya Perla 	struct net_device *pf_dev = bp->dev;
3939d96465bSSriharsha Basavapatna 	u16 max_mtu;
3944ab0c6a8SSathya Perla 
395ee5c7fb3SSathya Perla 	dev->netdev_ops = &bnxt_vf_rep_netdev_ops;
396ee5c7fb3SSathya Perla 	dev->ethtool_ops = &bnxt_vf_rep_ethtool_ops;
397e408ebdcSSathya Perla 	SWITCHDEV_SET_OPS(dev, &bnxt_vf_rep_switchdev_ops);
3984ab0c6a8SSathya Perla 	/* Just inherit all the featues of the parent PF as the VF-R
3994ab0c6a8SSathya Perla 	 * uses the RX/TX rings of the parent PF
4004ab0c6a8SSathya Perla 	 */
4014ab0c6a8SSathya Perla 	dev->hw_features = pf_dev->hw_features;
4024ab0c6a8SSathya Perla 	dev->gso_partial_features = pf_dev->gso_partial_features;
4034ab0c6a8SSathya Perla 	dev->vlan_features = pf_dev->vlan_features;
4044ab0c6a8SSathya Perla 	dev->hw_enc_features = pf_dev->hw_enc_features;
4054ab0c6a8SSathya Perla 	dev->features |= pf_dev->features;
4064ab0c6a8SSathya Perla 	bnxt_vf_rep_eth_addr_gen(bp->pf.mac_addr, vf_rep->vf_idx,
4074ab0c6a8SSathya Perla 				 dev->perm_addr);
4084ab0c6a8SSathya Perla 	ether_addr_copy(dev->dev_addr, dev->perm_addr);
4099d96465bSSriharsha Basavapatna 	/* Set VF-Rep's max-mtu to the corresponding VF's max-mtu */
4109d96465bSSriharsha Basavapatna 	if (!bnxt_hwrm_vfr_qcfg(bp, vf_rep, &max_mtu))
4119d96465bSSriharsha Basavapatna 		dev->max_mtu = max_mtu;
4129d96465bSSriharsha Basavapatna 	dev->min_mtu = ETH_ZLEN;
4134ab0c6a8SSathya Perla }
4144ab0c6a8SSathya Perla 
415dd4ea1daSSathya Perla static int bnxt_pcie_dsn_get(struct bnxt *bp, u8 dsn[])
416dd4ea1daSSathya Perla {
417dd4ea1daSSathya Perla 	struct pci_dev *pdev = bp->pdev;
418dd4ea1daSSathya Perla 	int pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN);
419dd4ea1daSSathya Perla 	u32 dw;
420dd4ea1daSSathya Perla 
421dd4ea1daSSathya Perla 	if (!pos) {
422dd4ea1daSSathya Perla 		netdev_info(bp->dev, "Unable do read adapter's DSN");
423dd4ea1daSSathya Perla 		return -EOPNOTSUPP;
424dd4ea1daSSathya Perla 	}
425dd4ea1daSSathya Perla 
426dd4ea1daSSathya Perla 	/* DSN (two dw) is at an offset of 4 from the cap pos */
427dd4ea1daSSathya Perla 	pos += 4;
428dd4ea1daSSathya Perla 	pci_read_config_dword(pdev, pos, &dw);
429dd4ea1daSSathya Perla 	put_unaligned_le32(dw, &dsn[0]);
430dd4ea1daSSathya Perla 	pci_read_config_dword(pdev, pos + 4, &dw);
431dd4ea1daSSathya Perla 	put_unaligned_le32(dw, &dsn[4]);
432dd4ea1daSSathya Perla 	return 0;
433dd4ea1daSSathya Perla }
434dd4ea1daSSathya Perla 
4354ab0c6a8SSathya Perla static int bnxt_vf_reps_create(struct bnxt *bp)
4364ab0c6a8SSathya Perla {
437ee5c7fb3SSathya Perla 	u16 *cfa_code_map = NULL, num_vfs = pci_num_vf(bp->pdev);
4384ab0c6a8SSathya Perla 	struct bnxt_vf_rep *vf_rep;
4394ab0c6a8SSathya Perla 	struct net_device *dev;
4404ab0c6a8SSathya Perla 	int rc, i;
4414ab0c6a8SSathya Perla 
4424ab0c6a8SSathya Perla 	bp->vf_reps = kcalloc(num_vfs, sizeof(vf_rep), GFP_KERNEL);
4434ab0c6a8SSathya Perla 	if (!bp->vf_reps)
4444ab0c6a8SSathya Perla 		return -ENOMEM;
4454ab0c6a8SSathya Perla 
446ee5c7fb3SSathya Perla 	/* storage for cfa_code to vf-idx mapping */
447ee5c7fb3SSathya Perla 	cfa_code_map = kmalloc(sizeof(*bp->cfa_code_map) * MAX_CFA_CODE,
448ee5c7fb3SSathya Perla 			       GFP_KERNEL);
449ee5c7fb3SSathya Perla 	if (!cfa_code_map) {
450ee5c7fb3SSathya Perla 		rc = -ENOMEM;
451ee5c7fb3SSathya Perla 		goto err;
452ee5c7fb3SSathya Perla 	}
453ee5c7fb3SSathya Perla 	for (i = 0; i < MAX_CFA_CODE; i++)
454ee5c7fb3SSathya Perla 		cfa_code_map[i] = VF_IDX_INVALID;
455ee5c7fb3SSathya Perla 
4564ab0c6a8SSathya Perla 	for (i = 0; i < num_vfs; i++) {
4574ab0c6a8SSathya Perla 		dev = alloc_etherdev(sizeof(*vf_rep));
4584ab0c6a8SSathya Perla 		if (!dev) {
4594ab0c6a8SSathya Perla 			rc = -ENOMEM;
4604ab0c6a8SSathya Perla 			goto err;
4614ab0c6a8SSathya Perla 		}
4624ab0c6a8SSathya Perla 
4634ab0c6a8SSathya Perla 		vf_rep = netdev_priv(dev);
4644ab0c6a8SSathya Perla 		bp->vf_reps[i] = vf_rep;
4654ab0c6a8SSathya Perla 		vf_rep->dev = dev;
4664ab0c6a8SSathya Perla 		vf_rep->bp = bp;
4674ab0c6a8SSathya Perla 		vf_rep->vf_idx = i;
4684ab0c6a8SSathya Perla 		vf_rep->tx_cfa_action = CFA_HANDLE_INVALID;
4694ab0c6a8SSathya Perla 
470ee5c7fb3SSathya Perla 		/* get cfa handles from FW */
471ee5c7fb3SSathya Perla 		rc = hwrm_cfa_vfr_alloc(bp, vf_rep->vf_idx,
472ee5c7fb3SSathya Perla 					&vf_rep->tx_cfa_action,
473ee5c7fb3SSathya Perla 					&vf_rep->rx_cfa_code);
474ee5c7fb3SSathya Perla 		if (rc) {
475ee5c7fb3SSathya Perla 			rc = -ENOLINK;
476ee5c7fb3SSathya Perla 			goto err;
477ee5c7fb3SSathya Perla 		}
478ee5c7fb3SSathya Perla 		cfa_code_map[vf_rep->rx_cfa_code] = vf_rep->vf_idx;
479ee5c7fb3SSathya Perla 
480ee5c7fb3SSathya Perla 		vf_rep->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX,
481ee5c7fb3SSathya Perla 						 GFP_KERNEL);
482ee5c7fb3SSathya Perla 		if (!vf_rep->dst) {
483ee5c7fb3SSathya Perla 			rc = -ENOMEM;
484ee5c7fb3SSathya Perla 			goto err;
485ee5c7fb3SSathya Perla 		}
486ee5c7fb3SSathya Perla 		/* only cfa_action is needed to mux a packet while TXing */
487ee5c7fb3SSathya Perla 		vf_rep->dst->u.port_info.port_id = vf_rep->tx_cfa_action;
488ee5c7fb3SSathya Perla 		vf_rep->dst->u.port_info.lower_dev = bp->dev;
489ee5c7fb3SSathya Perla 
4904ab0c6a8SSathya Perla 		bnxt_vf_rep_netdev_init(bp, vf_rep, dev);
4914ab0c6a8SSathya Perla 		rc = register_netdev(dev);
4924ab0c6a8SSathya Perla 		if (rc) {
4934ab0c6a8SSathya Perla 			/* no need for unregister_netdev in cleanup */
4944ab0c6a8SSathya Perla 			dev->netdev_ops = NULL;
4954ab0c6a8SSathya Perla 			goto err;
4964ab0c6a8SSathya Perla 		}
4974ab0c6a8SSathya Perla 	}
4984ab0c6a8SSathya Perla 
499dd4ea1daSSathya Perla 	/* Read the adapter's DSN to use as the eswitch switch_id */
500dd4ea1daSSathya Perla 	rc = bnxt_pcie_dsn_get(bp, bp->switch_id);
501dd4ea1daSSathya Perla 	if (rc)
502dd4ea1daSSathya Perla 		goto err;
503dd4ea1daSSathya Perla 
504ee5c7fb3SSathya Perla 	/* publish cfa_code_map only after all VF-reps have been initialized */
505ee5c7fb3SSathya Perla 	bp->cfa_code_map = cfa_code_map;
5064ab0c6a8SSathya Perla 	bp->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
507ee5c7fb3SSathya Perla 	netif_keep_dst(bp->dev);
5084ab0c6a8SSathya Perla 	return 0;
5094ab0c6a8SSathya Perla 
5104ab0c6a8SSathya Perla err:
5114ab0c6a8SSathya Perla 	netdev_info(bp->dev, "%s error=%d", __func__, rc);
512ee5c7fb3SSathya Perla 	kfree(cfa_code_map);
5134ab0c6a8SSathya Perla 	__bnxt_vf_reps_destroy(bp);
5144ab0c6a8SSathya Perla 	return rc;
5154ab0c6a8SSathya Perla }
5164ab0c6a8SSathya Perla 
5174ab0c6a8SSathya Perla /* Devlink related routines */
5183c467bf3SSteve Lin int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode)
5194ab0c6a8SSathya Perla {
5204ab0c6a8SSathya Perla 	struct bnxt *bp = bnxt_get_bp_from_dl(devlink);
5214ab0c6a8SSathya Perla 
5224ab0c6a8SSathya Perla 	*mode = bp->eswitch_mode;
5234ab0c6a8SSathya Perla 	return 0;
5244ab0c6a8SSathya Perla }
5254ab0c6a8SSathya Perla 
5263c467bf3SSteve Lin int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode)
5274ab0c6a8SSathya Perla {
5284ab0c6a8SSathya Perla 	struct bnxt *bp = bnxt_get_bp_from_dl(devlink);
5294ab0c6a8SSathya Perla 	int rc = 0;
5304ab0c6a8SSathya Perla 
5314ab0c6a8SSathya Perla 	mutex_lock(&bp->sriov_lock);
5324ab0c6a8SSathya Perla 	if (bp->eswitch_mode == mode) {
5334ab0c6a8SSathya Perla 		netdev_info(bp->dev, "already in %s eswitch mode",
5344ab0c6a8SSathya Perla 			    mode == DEVLINK_ESWITCH_MODE_LEGACY ?
5354ab0c6a8SSathya Perla 			    "legacy" : "switchdev");
5364ab0c6a8SSathya Perla 		rc = -EINVAL;
5374ab0c6a8SSathya Perla 		goto done;
5384ab0c6a8SSathya Perla 	}
5394ab0c6a8SSathya Perla 
5404ab0c6a8SSathya Perla 	switch (mode) {
5414ab0c6a8SSathya Perla 	case DEVLINK_ESWITCH_MODE_LEGACY:
5424ab0c6a8SSathya Perla 		bnxt_vf_reps_destroy(bp);
5434ab0c6a8SSathya Perla 		break;
5444ab0c6a8SSathya Perla 
5454ab0c6a8SSathya Perla 	case DEVLINK_ESWITCH_MODE_SWITCHDEV:
5464ab0c6a8SSathya Perla 		if (pci_num_vf(bp->pdev) == 0) {
5474ab0c6a8SSathya Perla 			netdev_info(bp->dev,
548bd76b879SColin Ian King 				    "Enable VFs before setting switchdev mode");
5494ab0c6a8SSathya Perla 			rc = -EPERM;
5504ab0c6a8SSathya Perla 			goto done;
5514ab0c6a8SSathya Perla 		}
5524ab0c6a8SSathya Perla 		rc = bnxt_vf_reps_create(bp);
5534ab0c6a8SSathya Perla 		break;
5544ab0c6a8SSathya Perla 
5554ab0c6a8SSathya Perla 	default:
5564ab0c6a8SSathya Perla 		rc = -EINVAL;
5574ab0c6a8SSathya Perla 		goto done;
5584ab0c6a8SSathya Perla 	}
5594ab0c6a8SSathya Perla done:
5604ab0c6a8SSathya Perla 	mutex_unlock(&bp->sriov_lock);
5614ab0c6a8SSathya Perla 	return rc;
5624ab0c6a8SSathya Perla }
5634ab0c6a8SSathya Perla 
564d3e3beceSSathya Perla #endif
565