Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2024, Intel Corporation. */
  3#include "ice.h"
  4#include "ice_lib.h"
  5#include "ice_txrx.h"
  6#include "ice_fltr.h"
  7#include "ice_sf_eth.h"
  8#include "devlink/devlink_port.h"
  9#include "devlink/devlink.h"
 10
 11static const struct net_device_ops ice_sf_netdev_ops = {
 12	.ndo_open = ice_open,
 13	.ndo_stop = ice_stop,
 14	.ndo_start_xmit = ice_start_xmit,
 15	.ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid,
 16	.ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid,
 17	.ndo_change_mtu = ice_change_mtu,
 18	.ndo_get_stats64 = ice_get_stats64,
 19	.ndo_tx_timeout = ice_tx_timeout,
 20	.ndo_bpf = ice_xdp,
 21	.ndo_xdp_xmit = ice_xdp_xmit,
 22	.ndo_xsk_wakeup = ice_xsk_wakeup,
 23};
 24
 25/**
 26 * ice_sf_cfg_netdev - Allocate, configure and register a netdev
 27 * @dyn_port: subfunction associated with configured netdev
 28 * @devlink_port: subfunction devlink port to be linked with netdev
 29 *
 30 * Return: 0 on success, negative value on failure
 31 */
 32static int ice_sf_cfg_netdev(struct ice_dynamic_port *dyn_port,
 33			     struct devlink_port *devlink_port)
 34{
 35	struct ice_vsi *vsi = dyn_port->vsi;
 36	struct ice_netdev_priv *np;
 37	struct net_device *netdev;
 38	int err;
 39
 40	netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq,
 41				    vsi->alloc_rxq);
 42	if (!netdev)
 43		return -ENOMEM;
 44
 45	SET_NETDEV_DEV(netdev, &vsi->back->pdev->dev);
 46	set_bit(ICE_VSI_NETDEV_ALLOCD, vsi->state);
 47	vsi->netdev = netdev;
 48	np = netdev_priv(netdev);
 49	np->vsi = vsi;
 50
 51	ice_set_netdev_features(netdev);
 52
 53	netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
 54			       NETDEV_XDP_ACT_XSK_ZEROCOPY |
 55			       NETDEV_XDP_ACT_RX_SG;
 56	netdev->xdp_zc_max_segs = ICE_MAX_BUF_TXD;
 57
 58	eth_hw_addr_set(netdev, dyn_port->hw_addr);
 59	ether_addr_copy(netdev->perm_addr, dyn_port->hw_addr);
 60	netdev->netdev_ops = &ice_sf_netdev_ops;
 61	SET_NETDEV_DEVLINK_PORT(netdev, devlink_port);
 62
 63	err = register_netdev(netdev);
 64	if (err) {
 65		free_netdev(netdev);
 66		vsi->netdev = NULL;
 67		return -ENOMEM;
 68	}
 69	set_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
 70	netif_carrier_off(netdev);
 71	netif_tx_stop_all_queues(netdev);
 72
 73	return 0;
 74}
 75
 76static void ice_sf_decfg_netdev(struct ice_vsi *vsi)
 77{
 78	unregister_netdev(vsi->netdev);
 79	clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
 80	free_netdev(vsi->netdev);
 81	vsi->netdev = NULL;
 82	clear_bit(ICE_VSI_NETDEV_ALLOCD, vsi->state);
 83}
 84
 85/**
 86 * ice_sf_dev_probe - subfunction driver probe function
 87 * @adev: pointer to the auxiliary device
 88 * @id: pointer to the auxiliary_device id
 89 *
 90 * Configure VSI and netdev resources for the subfunction device.
 91 *
 92 * Return: zero on success or an error code on failure.
 93 */
 94static int ice_sf_dev_probe(struct auxiliary_device *adev,
 95			    const struct auxiliary_device_id *id)
 96{
 97	struct ice_sf_dev *sf_dev = ice_adev_to_sf_dev(adev);
 98	struct ice_dynamic_port *dyn_port = sf_dev->dyn_port;
 99	struct ice_vsi *vsi = dyn_port->vsi;
100	struct ice_pf *pf = dyn_port->pf;
101	struct device *dev = &adev->dev;
102	struct ice_sf_priv *priv;
103	struct devlink *devlink;
104	int err;
105
106	vsi->type = ICE_VSI_SF;
107	vsi->port_info = pf->hw.port_info;
108	vsi->flags = ICE_VSI_FLAG_INIT;
109
110	priv = ice_allocate_sf(&adev->dev, pf);
111	if (IS_ERR(priv)) {
112		dev_err(dev, "Subfunction devlink alloc failed");
113		return PTR_ERR(priv);
114	}
115
116	priv->dev = sf_dev;
117	sf_dev->priv = priv;
118	devlink = priv_to_devlink(priv);
119
120	devl_lock(devlink);
121
122	err = ice_vsi_cfg(vsi);
123	if (err) {
124		dev_err(dev, "Subfunction vsi config failed");
125		goto err_free_devlink;
126	}
127	vsi->sf = dyn_port;
128
129	ice_eswitch_update_repr(&dyn_port->repr_id, vsi);
130
131	err = ice_devlink_create_sf_dev_port(sf_dev);
132	if (err) {
133		dev_err(dev, "Cannot add ice virtual devlink port for subfunction");
134		goto err_vsi_decfg;
135	}
136
137	err = ice_sf_cfg_netdev(dyn_port, &sf_dev->priv->devlink_port);
138	if (err) {
139		dev_err(dev, "Subfunction netdev config failed");
140		goto err_devlink_destroy;
141	}
142
143	err = devl_port_fn_devlink_set(&dyn_port->devlink_port, devlink);
144	if (err) {
145		dev_err(dev, "Can't link devlink instance to SF devlink port");
146		goto err_netdev_decfg;
147	}
148
149	ice_napi_add(vsi);
150
151	devl_register(devlink);
152	devl_unlock(devlink);
153
154	dyn_port->attached = true;
155
156	return 0;
157
158err_netdev_decfg:
159	ice_sf_decfg_netdev(vsi);
160err_devlink_destroy:
161	ice_devlink_destroy_sf_dev_port(sf_dev);
162err_vsi_decfg:
163	ice_vsi_decfg(vsi);
164err_free_devlink:
165	devl_unlock(devlink);
166	devlink_free(devlink);
167	return err;
168}
169
170/**
171 * ice_sf_dev_remove - subfunction driver remove function
172 * @adev: pointer to the auxiliary device
173 *
174 * Deinitalize VSI and netdev resources for the subfunction device.
175 */
176static void ice_sf_dev_remove(struct auxiliary_device *adev)
177{
178	struct ice_sf_dev *sf_dev = ice_adev_to_sf_dev(adev);
179	struct ice_dynamic_port *dyn_port = sf_dev->dyn_port;
180	struct ice_vsi *vsi = dyn_port->vsi;
181	struct devlink *devlink;
182
183	devlink = priv_to_devlink(sf_dev->priv);
184	devl_lock(devlink);
185
186	ice_vsi_close(vsi);
187
188	ice_sf_decfg_netdev(vsi);
189	ice_devlink_destroy_sf_dev_port(sf_dev);
190	devl_unregister(devlink);
191	devl_unlock(devlink);
192	devlink_free(devlink);
193	ice_vsi_decfg(vsi);
194
195	dyn_port->attached = false;
196}
197
198static const struct auxiliary_device_id ice_sf_dev_id_table[] = {
199	{ .name = "ice.sf", },
200	{ },
201};
202
203MODULE_DEVICE_TABLE(auxiliary, ice_sf_dev_id_table);
204
205static struct auxiliary_driver ice_sf_driver = {
206	.name = "sf",
207	.probe = ice_sf_dev_probe,
208	.remove = ice_sf_dev_remove,
209	.id_table = ice_sf_dev_id_table
210};
211
212static DEFINE_XARRAY_ALLOC1(ice_sf_aux_id);
213
214/**
215 * ice_sf_driver_register - Register new auxiliary subfunction driver
216 *
217 * Return: zero on success or an error code on failure.
218 */
219int ice_sf_driver_register(void)
220{
221	return auxiliary_driver_register(&ice_sf_driver);
222}
223
224/**
225 * ice_sf_driver_unregister - Unregister new auxiliary subfunction driver
226 *
227 */
228void ice_sf_driver_unregister(void)
229{
230	auxiliary_driver_unregister(&ice_sf_driver);
231}
232
233/**
234 * ice_sf_dev_release - Release device associated with auxiliary device
235 * @device: pointer to the device
236 *
237 * Since most of the code for subfunction deactivation is handled in
238 * the remove handler, here just free tracking resources.
239 */
240static void ice_sf_dev_release(struct device *device)
241{
242	struct auxiliary_device *adev = to_auxiliary_dev(device);
243	struct ice_sf_dev *sf_dev = ice_adev_to_sf_dev(adev);
244
245	xa_erase(&ice_sf_aux_id, adev->id);
246	kfree(sf_dev);
247}
248
249/**
250 * ice_sf_eth_activate - Activate Ethernet subfunction port
251 * @dyn_port: the dynamic port instance for this subfunction
252 * @extack: extack for reporting error messages
253 *
254 * Activate the dynamic port as an Ethernet subfunction. Setup the netdev
255 * resources associated and initialize the auxiliary device.
256 *
257 * Return: zero on success or an error code on failure.
258 */
259int
260ice_sf_eth_activate(struct ice_dynamic_port *dyn_port,
261		    struct netlink_ext_ack *extack)
262{
263	struct ice_pf *pf = dyn_port->pf;
264	struct ice_sf_dev *sf_dev;
265	struct pci_dev *pdev;
266	int err;
267	u32 id;
268
269	err = xa_alloc(&ice_sf_aux_id, &id, NULL, xa_limit_32b,
270		       GFP_KERNEL);
271	if (err) {
272		NL_SET_ERR_MSG_MOD(extack, "Could not allocate SF ID");
273		return err;
274	}
275
276	sf_dev = kzalloc(sizeof(*sf_dev), GFP_KERNEL);
277	if (!sf_dev) {
278		err = -ENOMEM;
279		NL_SET_ERR_MSG_MOD(extack, "Could not allocate SF memory");
280		goto xa_erase;
281	}
282	pdev = pf->pdev;
283
284	sf_dev->dyn_port = dyn_port;
285	sf_dev->adev.id = id;
286	sf_dev->adev.name = "sf";
287	sf_dev->adev.dev.release = ice_sf_dev_release;
288	sf_dev->adev.dev.parent = &pdev->dev;
289
290	err = auxiliary_device_init(&sf_dev->adev);
291	if (err) {
292		NL_SET_ERR_MSG_MOD(extack, "Failed to initialize SF device");
293		goto sf_dev_free;
294	}
295
296	err = auxiliary_device_add(&sf_dev->adev);
297	if (err) {
298		NL_SET_ERR_MSG_MOD(extack, "Failed to add SF device");
299		goto aux_dev_uninit;
300	}
301
302	dyn_port->sf_dev = sf_dev;
303
304	return 0;
305
306aux_dev_uninit:
307	auxiliary_device_uninit(&sf_dev->adev);
308sf_dev_free:
309	kfree(sf_dev);
310xa_erase:
311	xa_erase(&ice_sf_aux_id, id);
312
313	return err;
314}
315
316/**
317 * ice_sf_eth_deactivate - Deactivate Ethernet subfunction port
318 * @dyn_port: the dynamic port instance for this subfunction
319 *
320 * Deactivate the Ethernet subfunction, removing its auxiliary device and the
321 * associated resources.
322 */
323void ice_sf_eth_deactivate(struct ice_dynamic_port *dyn_port)
324{
325	struct ice_sf_dev *sf_dev = dyn_port->sf_dev;
326
327	auxiliary_device_delete(&sf_dev->adev);
328	auxiliary_device_uninit(&sf_dev->adev);
329}