xref: /linux/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c (revision 69684376eed517817251ea6a768cfc315350d5c1)
1bc610777SAlexander Duyck // SPDX-License-Identifier: GPL-2.0
2bc610777SAlexander Duyck /* Copyright (c) Meta Platforms, Inc. and affiliates. */
3bc610777SAlexander Duyck 
4bc610777SAlexander Duyck #include <linux/etherdevice.h>
5bc610777SAlexander Duyck #include <linux/ipv6.h>
6bc610777SAlexander Duyck #include <linux/types.h>
7bc610777SAlexander Duyck 
8bc610777SAlexander Duyck #include "fbnic.h"
9bc610777SAlexander Duyck #include "fbnic_netdev.h"
10bc610777SAlexander Duyck #include "fbnic_txrx.h"
11bc610777SAlexander Duyck 
12bc610777SAlexander Duyck int __fbnic_open(struct fbnic_net *fbn)
13bc610777SAlexander Duyck {
1420d2e88cSAlexander Duyck 	struct fbnic_dev *fbd = fbn->fbd;
15bc610777SAlexander Duyck 	int err;
16bc610777SAlexander Duyck 
17bc610777SAlexander Duyck 	err = fbnic_alloc_napi_vectors(fbn);
18bc610777SAlexander Duyck 	if (err)
19bc610777SAlexander Duyck 		return err;
20bc610777SAlexander Duyck 
2140bf06a1SAlexander Duyck 	err = fbnic_alloc_resources(fbn);
2240bf06a1SAlexander Duyck 	if (err)
2340bf06a1SAlexander Duyck 		goto free_napi_vectors;
2440bf06a1SAlexander Duyck 
25bc610777SAlexander Duyck 	err = netif_set_real_num_tx_queues(fbn->netdev,
26bc610777SAlexander Duyck 					   fbn->num_tx_queues);
27bc610777SAlexander Duyck 	if (err)
28bc610777SAlexander Duyck 		goto free_resources;
29bc610777SAlexander Duyck 
30bc610777SAlexander Duyck 	err = netif_set_real_num_rx_queues(fbn->netdev,
31bc610777SAlexander Duyck 					   fbn->num_rx_queues);
32bc610777SAlexander Duyck 	if (err)
33bc610777SAlexander Duyck 		goto free_resources;
34bc610777SAlexander Duyck 
3520d2e88cSAlexander Duyck 	/* Send ownership message and flush to verify FW has seen it */
3620d2e88cSAlexander Duyck 	err = fbnic_fw_xmit_ownership_msg(fbd, true);
3720d2e88cSAlexander Duyck 	if (err) {
3820d2e88cSAlexander Duyck 		dev_warn(fbd->dev,
3920d2e88cSAlexander Duyck 			 "Error %d sending host ownership message to the firmware\n",
4020d2e88cSAlexander Duyck 			 err);
4120d2e88cSAlexander Duyck 		goto free_resources;
4220d2e88cSAlexander Duyck 	}
4320d2e88cSAlexander Duyck 
4420d2e88cSAlexander Duyck 	err = fbnic_fw_init_heartbeat(fbd, false);
4520d2e88cSAlexander Duyck 	if (err)
4620d2e88cSAlexander Duyck 		goto release_ownership;
4720d2e88cSAlexander Duyck 
4869684376SAlexander Duyck 	err = fbnic_pcs_irq_enable(fbd);
4969684376SAlexander Duyck 	if (err)
5069684376SAlexander Duyck 		goto release_ownership;
5169684376SAlexander Duyck 
52bc610777SAlexander Duyck 	return 0;
5320d2e88cSAlexander Duyck release_ownership:
5420d2e88cSAlexander Duyck 	fbnic_fw_xmit_ownership_msg(fbn->fbd, false);
55bc610777SAlexander Duyck free_resources:
5640bf06a1SAlexander Duyck 	fbnic_free_resources(fbn);
5740bf06a1SAlexander Duyck free_napi_vectors:
58bc610777SAlexander Duyck 	fbnic_free_napi_vectors(fbn);
59bc610777SAlexander Duyck 	return err;
60bc610777SAlexander Duyck }
61bc610777SAlexander Duyck 
62bc610777SAlexander Duyck static int fbnic_open(struct net_device *netdev)
63bc610777SAlexander Duyck {
64bc610777SAlexander Duyck 	struct fbnic_net *fbn = netdev_priv(netdev);
65bc610777SAlexander Duyck 	int err;
66bc610777SAlexander Duyck 
67bc610777SAlexander Duyck 	err = __fbnic_open(fbn);
68bc610777SAlexander Duyck 	if (!err)
69bc610777SAlexander Duyck 		fbnic_up(fbn);
70bc610777SAlexander Duyck 
71bc610777SAlexander Duyck 	return err;
72bc610777SAlexander Duyck }
73bc610777SAlexander Duyck 
74bc610777SAlexander Duyck static int fbnic_stop(struct net_device *netdev)
75bc610777SAlexander Duyck {
76bc610777SAlexander Duyck 	struct fbnic_net *fbn = netdev_priv(netdev);
77bc610777SAlexander Duyck 
78bc610777SAlexander Duyck 	fbnic_down(fbn);
7969684376SAlexander Duyck 	fbnic_pcs_irq_disable(fbn->fbd);
80bc610777SAlexander Duyck 
8120d2e88cSAlexander Duyck 	fbnic_fw_xmit_ownership_msg(fbn->fbd, false);
8220d2e88cSAlexander Duyck 
8340bf06a1SAlexander Duyck 	fbnic_free_resources(fbn);
84bc610777SAlexander Duyck 	fbnic_free_napi_vectors(fbn);
85bc610777SAlexander Duyck 
86bc610777SAlexander Duyck 	return 0;
87bc610777SAlexander Duyck }
88bc610777SAlexander Duyck 
89bc610777SAlexander Duyck static const struct net_device_ops fbnic_netdev_ops = {
90bc610777SAlexander Duyck 	.ndo_open		= fbnic_open,
91bc610777SAlexander Duyck 	.ndo_stop		= fbnic_stop,
92bc610777SAlexander Duyck 	.ndo_validate_addr	= eth_validate_addr,
93bc610777SAlexander Duyck 	.ndo_start_xmit		= fbnic_xmit_frame,
94bc610777SAlexander Duyck };
95bc610777SAlexander Duyck 
96bc610777SAlexander Duyck void fbnic_reset_queues(struct fbnic_net *fbn,
97bc610777SAlexander Duyck 			unsigned int tx, unsigned int rx)
98bc610777SAlexander Duyck {
99bc610777SAlexander Duyck 	struct fbnic_dev *fbd = fbn->fbd;
100bc610777SAlexander Duyck 	unsigned int max_napis;
101bc610777SAlexander Duyck 
102bc610777SAlexander Duyck 	max_napis = fbd->num_irqs - FBNIC_NON_NAPI_VECTORS;
103bc610777SAlexander Duyck 
104bc610777SAlexander Duyck 	tx = min(tx, max_napis);
105bc610777SAlexander Duyck 	fbn->num_tx_queues = tx;
106bc610777SAlexander Duyck 
107bc610777SAlexander Duyck 	rx = min(rx, max_napis);
108bc610777SAlexander Duyck 	fbn->num_rx_queues = rx;
109bc610777SAlexander Duyck 
110bc610777SAlexander Duyck 	fbn->num_napi = max(tx, rx);
111bc610777SAlexander Duyck }
112bc610777SAlexander Duyck 
113bc610777SAlexander Duyck /**
114bc610777SAlexander Duyck  * fbnic_netdev_free - Free the netdev associate with fbnic
115bc610777SAlexander Duyck  * @fbd: Driver specific structure to free netdev from
116bc610777SAlexander Duyck  *
117bc610777SAlexander Duyck  * Allocate and initialize the netdev and netdev private structure. Bind
118bc610777SAlexander Duyck  * together the hardware, netdev, and pci data structures.
119bc610777SAlexander Duyck  **/
120bc610777SAlexander Duyck void fbnic_netdev_free(struct fbnic_dev *fbd)
121bc610777SAlexander Duyck {
12269684376SAlexander Duyck 	struct fbnic_net *fbn = netdev_priv(fbd->netdev);
12369684376SAlexander Duyck 
12469684376SAlexander Duyck 	if (fbn->phylink)
12569684376SAlexander Duyck 		phylink_destroy(fbn->phylink);
12669684376SAlexander Duyck 
127bc610777SAlexander Duyck 	free_netdev(fbd->netdev);
128bc610777SAlexander Duyck 	fbd->netdev = NULL;
129bc610777SAlexander Duyck }
130bc610777SAlexander Duyck 
131bc610777SAlexander Duyck /**
132bc610777SAlexander Duyck  * fbnic_netdev_alloc - Allocate a netdev and associate with fbnic
133bc610777SAlexander Duyck  * @fbd: Driver specific structure to associate netdev with
134bc610777SAlexander Duyck  *
135bc610777SAlexander Duyck  * Allocate and initialize the netdev and netdev private structure. Bind
136bc610777SAlexander Duyck  * together the hardware, netdev, and pci data structures.
137bc610777SAlexander Duyck  *
138bc610777SAlexander Duyck  *  Return: 0 on success, negative on failure
139bc610777SAlexander Duyck  **/
140bc610777SAlexander Duyck struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
141bc610777SAlexander Duyck {
142bc610777SAlexander Duyck 	struct net_device *netdev;
143bc610777SAlexander Duyck 	struct fbnic_net *fbn;
144bc610777SAlexander Duyck 	int default_queues;
145bc610777SAlexander Duyck 
146bc610777SAlexander Duyck 	netdev = alloc_etherdev_mq(sizeof(*fbn), FBNIC_MAX_RXQS);
147bc610777SAlexander Duyck 	if (!netdev)
148bc610777SAlexander Duyck 		return NULL;
149bc610777SAlexander Duyck 
150bc610777SAlexander Duyck 	SET_NETDEV_DEV(netdev, fbd->dev);
151bc610777SAlexander Duyck 	fbd->netdev = netdev;
152bc610777SAlexander Duyck 
153bc610777SAlexander Duyck 	netdev->netdev_ops = &fbnic_netdev_ops;
154bc610777SAlexander Duyck 
155bc610777SAlexander Duyck 	fbn = netdev_priv(netdev);
156bc610777SAlexander Duyck 
157bc610777SAlexander Duyck 	fbn->netdev = netdev;
158bc610777SAlexander Duyck 	fbn->fbd = fbd;
159bc610777SAlexander Duyck 	INIT_LIST_HEAD(&fbn->napis);
160bc610777SAlexander Duyck 
16140bf06a1SAlexander Duyck 	fbn->txq_size = FBNIC_TXQ_SIZE_DEFAULT;
1620cb4c0a1SAlexander Duyck 	fbn->hpq_size = FBNIC_HPQ_SIZE_DEFAULT;
1630cb4c0a1SAlexander Duyck 	fbn->ppq_size = FBNIC_PPQ_SIZE_DEFAULT;
1640cb4c0a1SAlexander Duyck 	fbn->rcq_size = FBNIC_RCQ_SIZE_DEFAULT;
16540bf06a1SAlexander Duyck 
166bc610777SAlexander Duyck 	default_queues = netif_get_num_default_rss_queues();
167bc610777SAlexander Duyck 	if (default_queues > fbd->max_num_queues)
168bc610777SAlexander Duyck 		default_queues = fbd->max_num_queues;
169bc610777SAlexander Duyck 
170bc610777SAlexander Duyck 	fbnic_reset_queues(fbn, default_queues, default_queues);
171bc610777SAlexander Duyck 
172bc610777SAlexander Duyck 	netdev->min_mtu = IPV6_MIN_MTU;
173bc610777SAlexander Duyck 	netdev->max_mtu = FBNIC_MAX_JUMBO_FRAME_SIZE - ETH_HLEN;
174bc610777SAlexander Duyck 
17569684376SAlexander Duyck 	/* TBD: This is workaround for BMC as phylink doesn't have support
17669684376SAlexander Duyck 	 * for leavling the link enabled if a BMC is present.
17769684376SAlexander Duyck 	 */
17869684376SAlexander Duyck 	netdev->ethtool->wol_enabled = true;
17969684376SAlexander Duyck 
18069684376SAlexander Duyck 	fbn->fec = FBNIC_FEC_AUTO | FBNIC_FEC_RS;
18169684376SAlexander Duyck 	fbn->link_mode = FBNIC_LINK_AUTO | FBNIC_LINK_50R2;
182bc610777SAlexander Duyck 	netif_carrier_off(netdev);
183bc610777SAlexander Duyck 
184bc610777SAlexander Duyck 	netif_tx_stop_all_queues(netdev);
185bc610777SAlexander Duyck 
18669684376SAlexander Duyck 	if (fbnic_phylink_init(netdev)) {
18769684376SAlexander Duyck 		fbnic_netdev_free(fbd);
18869684376SAlexander Duyck 		return NULL;
18969684376SAlexander Duyck 	}
19069684376SAlexander Duyck 
191bc610777SAlexander Duyck 	return netdev;
192bc610777SAlexander Duyck }
193bc610777SAlexander Duyck 
194bc610777SAlexander Duyck static int fbnic_dsn_to_mac_addr(u64 dsn, char *addr)
195bc610777SAlexander Duyck {
196bc610777SAlexander Duyck 	addr[0] = (dsn >> 56) & 0xFF;
197bc610777SAlexander Duyck 	addr[1] = (dsn >> 48) & 0xFF;
198bc610777SAlexander Duyck 	addr[2] = (dsn >> 40) & 0xFF;
199bc610777SAlexander Duyck 	addr[3] = (dsn >> 16) & 0xFF;
200bc610777SAlexander Duyck 	addr[4] = (dsn >> 8) & 0xFF;
201bc610777SAlexander Duyck 	addr[5] = dsn & 0xFF;
202bc610777SAlexander Duyck 
203bc610777SAlexander Duyck 	return is_valid_ether_addr(addr) ? 0 : -EINVAL;
204bc610777SAlexander Duyck }
205bc610777SAlexander Duyck 
206bc610777SAlexander Duyck /**
207bc610777SAlexander Duyck  * fbnic_netdev_register - Initialize general software structures
208bc610777SAlexander Duyck  * @netdev: Netdev containing structure to initialize and register
209bc610777SAlexander Duyck  *
210bc610777SAlexander Duyck  * Initialize the MAC address for the netdev and register it.
211bc610777SAlexander Duyck  *
212bc610777SAlexander Duyck  *  Return: 0 on success, negative on failure
213bc610777SAlexander Duyck  **/
214bc610777SAlexander Duyck int fbnic_netdev_register(struct net_device *netdev)
215bc610777SAlexander Duyck {
216bc610777SAlexander Duyck 	struct fbnic_net *fbn = netdev_priv(netdev);
217bc610777SAlexander Duyck 	struct fbnic_dev *fbd = fbn->fbd;
218bc610777SAlexander Duyck 	u64 dsn = fbd->dsn;
219bc610777SAlexander Duyck 	u8 addr[ETH_ALEN];
220bc610777SAlexander Duyck 	int err;
221bc610777SAlexander Duyck 
222bc610777SAlexander Duyck 	err = fbnic_dsn_to_mac_addr(dsn, addr);
223bc610777SAlexander Duyck 	if (!err) {
224bc610777SAlexander Duyck 		ether_addr_copy(netdev->perm_addr, addr);
225bc610777SAlexander Duyck 		eth_hw_addr_set(netdev, addr);
226bc610777SAlexander Duyck 	} else {
227bc610777SAlexander Duyck 		/* A randomly assigned MAC address will cause provisioning
228bc610777SAlexander Duyck 		 * issues so instead just fail to spawn the netdev and
229bc610777SAlexander Duyck 		 * avoid any confusion.
230bc610777SAlexander Duyck 		 */
231bc610777SAlexander Duyck 		dev_err(fbd->dev, "MAC addr %pM invalid\n", addr);
232bc610777SAlexander Duyck 		return err;
233bc610777SAlexander Duyck 	}
234bc610777SAlexander Duyck 
235bc610777SAlexander Duyck 	return register_netdev(netdev);
236bc610777SAlexander Duyck }
237bc610777SAlexander Duyck 
238bc610777SAlexander Duyck void fbnic_netdev_unregister(struct net_device *netdev)
239bc610777SAlexander Duyck {
240bc610777SAlexander Duyck 	unregister_netdev(netdev);
241bc610777SAlexander Duyck }
242