Skip to content

Commit eda69d6

Browse files
praczynsanguy11
authored andcommitted
ice: add basic devlink subfunctions support
Implement devlink port handlers responsible for ethernet type devlink subfunctions. Create subfunction devlink port and setup all resources needed for a subfunction netdev to operate. Configure new VSI for each new subfunction, initialize and configure interrupts and Tx/Rx resources. Set correct MAC filters and create new netdev. For now, subfunction is limited to only one Tx/Rx queue pair. Only allocate new subfunction VSI with devlink port new command. Allocate and free subfunction MSIX interrupt vectors using new API calls with pci_msix_alloc_irq_at and pci_msix_free_irq. Support both automatic and manual subfunction numbers. If no subfunction number is provided, use xa_alloc to pick a number automatically. This will find the first free index and use that as the number. This reduces burden on users in the simple case where a specific number is not required. It may also be slightly faster to check that a number exists since xarray lookup should be faster than a linear scan of the dyn_ports xarray. Co-developed-by: Jacob Keller <[email protected]> Signed-off-by: Jacob Keller <[email protected]> Signed-off-by: Piotr Raczynski <[email protected]> Signed-off-by: Michal Swiatkowski <[email protected]> Tested-by: Rafal Romanowski <[email protected]> Signed-off-by: Tony Nguyen <[email protected]>
1 parent 004688c commit eda69d6

File tree

7 files changed

+341
-2
lines changed

7 files changed

+341
-2
lines changed

drivers/net/ethernet/intel/ice/devlink/devlink.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "ice.h"
77
#include "ice_lib.h"
88
#include "devlink.h"
9+
#include "devlink_port.h"
910
#include "ice_eswitch.h"
1011
#include "ice_fw_update.h"
1112
#include "ice_dcb_lib.h"
@@ -1277,6 +1278,8 @@ static const struct devlink_ops ice_devlink_ops = {
12771278

12781279
.rate_leaf_parent_set = ice_devlink_set_parent,
12791280
.rate_node_parent_set = ice_devlink_set_parent,
1281+
1282+
.port_new = ice_devlink_port_new,
12801283
};
12811284

12821285
static int

drivers/net/ethernet/intel/ice/devlink/devlink_port.c

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
#include "ice.h"
77
#include "devlink.h"
8+
#include "devlink_port.h"
9+
#include "ice_lib.h"
10+
#include "ice_fltr.h"
811

912
static int ice_active_port_option = -1;
1013

@@ -485,3 +488,288 @@ void ice_devlink_destroy_vf_port(struct ice_vf *vf)
485488
devl_rate_leaf_destroy(&vf->devlink_port);
486489
devl_port_unregister(&vf->devlink_port);
487490
}
491+
492+
/**
493+
* ice_dealloc_dynamic_port - Deallocate and remove a dynamic port
494+
* @dyn_port: dynamic port instance to deallocate
495+
*
496+
* Free resources associated with a dynamically added devlink port. Will
497+
* deactivate the port if its currently active.
498+
*/
499+
static void ice_dealloc_dynamic_port(struct ice_dynamic_port *dyn_port)
500+
{
501+
struct devlink_port *devlink_port = &dyn_port->devlink_port;
502+
struct ice_pf *pf = dyn_port->pf;
503+
504+
xa_erase(&pf->sf_nums, devlink_port->attrs.pci_sf.sf);
505+
devl_port_unregister(devlink_port);
506+
ice_vsi_free(dyn_port->vsi);
507+
xa_erase(&pf->dyn_ports, dyn_port->vsi->idx);
508+
kfree(dyn_port);
509+
}
510+
511+
/**
512+
* ice_dealloc_all_dynamic_ports - Deallocate all dynamic devlink ports
513+
* @pf: pointer to the pf structure
514+
*/
515+
void ice_dealloc_all_dynamic_ports(struct ice_pf *pf)
516+
{
517+
struct ice_dynamic_port *dyn_port;
518+
unsigned long index;
519+
520+
xa_for_each(&pf->dyn_ports, index, dyn_port)
521+
ice_dealloc_dynamic_port(dyn_port);
522+
}
523+
524+
/**
525+
* ice_devlink_port_new_check_attr - Check that new port attributes are valid
526+
* @pf: pointer to the PF structure
527+
* @new_attr: the attributes for the new port
528+
* @extack: extack for reporting error messages
529+
*
530+
* Check that the attributes for the new port are valid before continuing to
531+
* allocate the devlink port.
532+
*
533+
* Return: zero on success or an error code on failure.
534+
*/
535+
static int
536+
ice_devlink_port_new_check_attr(struct ice_pf *pf,
537+
const struct devlink_port_new_attrs *new_attr,
538+
struct netlink_ext_ack *extack)
539+
{
540+
if (new_attr->flavour != DEVLINK_PORT_FLAVOUR_PCI_SF) {
541+
NL_SET_ERR_MSG_MOD(extack, "Flavour other than pcisf is not supported");
542+
return -EOPNOTSUPP;
543+
}
544+
545+
if (new_attr->controller_valid) {
546+
NL_SET_ERR_MSG_MOD(extack, "Setting controller is not supported");
547+
return -EOPNOTSUPP;
548+
}
549+
550+
if (new_attr->port_index_valid) {
551+
NL_SET_ERR_MSG_MOD(extack, "Driver does not support user defined port index assignment");
552+
return -EOPNOTSUPP;
553+
}
554+
555+
if (new_attr->pfnum != pf->hw.pf_id) {
556+
NL_SET_ERR_MSG_MOD(extack, "Incorrect pfnum supplied");
557+
return -EINVAL;
558+
}
559+
560+
if (!pci_msix_can_alloc_dyn(pf->pdev)) {
561+
NL_SET_ERR_MSG_MOD(extack, "Dynamic MSIX-X interrupt allocation is not supported");
562+
return -EOPNOTSUPP;
563+
}
564+
565+
return 0;
566+
}
567+
568+
/**
569+
* ice_devlink_port_del - devlink handler for port delete
570+
* @devlink: pointer to devlink
571+
* @port: devlink port to be deleted
572+
* @extack: pointer to extack
573+
*
574+
* Deletes devlink port and deallocates all resources associated with
575+
* created subfunction.
576+
*
577+
* Return: zero on success or an error code on failure.
578+
*/
579+
static int
580+
ice_devlink_port_del(struct devlink *devlink, struct devlink_port *port,
581+
struct netlink_ext_ack *extack)
582+
{
583+
struct ice_dynamic_port *dyn_port;
584+
585+
dyn_port = ice_devlink_port_to_dyn(port);
586+
ice_dealloc_dynamic_port(dyn_port);
587+
588+
return 0;
589+
}
590+
591+
static const struct devlink_port_ops ice_devlink_port_sf_ops = {
592+
.port_del = ice_devlink_port_del,
593+
};
594+
595+
/**
596+
* ice_reserve_sf_num - Reserve a subfunction number for this port
597+
* @pf: pointer to the pf structure
598+
* @new_attr: devlink port attributes requested
599+
* @extack: extack for reporting error messages
600+
* @sfnum: on success, the sf number reserved
601+
*
602+
* Reserve a subfunction number for this port. Only called for
603+
* DEVLINK_PORT_FLAVOUR_PCI_SF ports.
604+
*
605+
* Return: zero on success or an error code on failure.
606+
*/
607+
static int
608+
ice_reserve_sf_num(struct ice_pf *pf,
609+
const struct devlink_port_new_attrs *new_attr,
610+
struct netlink_ext_ack *extack, u32 *sfnum)
611+
{
612+
int err;
613+
614+
/* If user didn't request an explicit number, pick one */
615+
if (!new_attr->sfnum_valid)
616+
return xa_alloc(&pf->sf_nums, sfnum, NULL, xa_limit_32b,
617+
GFP_KERNEL);
618+
619+
/* Otherwise, check and use the number provided */
620+
err = xa_insert(&pf->sf_nums, new_attr->sfnum, NULL, GFP_KERNEL);
621+
if (err) {
622+
if (err == -EBUSY)
623+
NL_SET_ERR_MSG_MOD(extack, "Subfunction with given sfnum already exists");
624+
return err;
625+
}
626+
627+
*sfnum = new_attr->sfnum;
628+
629+
return 0;
630+
}
631+
632+
/**
633+
* ice_devlink_create_sf_port - Register PCI subfunction devlink port
634+
* @dyn_port: the dynamic port instance structure for this subfunction
635+
*
636+
* Register PCI subfunction flavour devlink port for a dynamically added
637+
* subfunction port.
638+
*
639+
* Return: zero on success or an error code on failure.
640+
*/
641+
int ice_devlink_create_sf_port(struct ice_dynamic_port *dyn_port)
642+
{
643+
struct devlink_port_attrs attrs = {};
644+
struct devlink_port *devlink_port;
645+
struct devlink *devlink;
646+
struct ice_vsi *vsi;
647+
struct ice_pf *pf;
648+
649+
vsi = dyn_port->vsi;
650+
pf = dyn_port->pf;
651+
652+
devlink_port = &dyn_port->devlink_port;
653+
654+
attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_SF;
655+
attrs.pci_sf.pf = pf->hw.pf_id;
656+
attrs.pci_sf.sf = dyn_port->sfnum;
657+
658+
devlink_port_attrs_set(devlink_port, &attrs);
659+
devlink = priv_to_devlink(pf);
660+
661+
return devl_port_register_with_ops(devlink, devlink_port, vsi->idx,
662+
&ice_devlink_port_sf_ops);
663+
}
664+
665+
/**
666+
* ice_devlink_destroy_sf_port - Destroy the devlink_port for this SF
667+
* @dyn_port: the dynamic port instance structure for this subfunction
668+
*
669+
* Unregisters the devlink_port structure associated with this SF.
670+
*/
671+
void ice_devlink_destroy_sf_port(struct ice_dynamic_port *dyn_port)
672+
{
673+
devl_port_unregister(&dyn_port->devlink_port);
674+
}
675+
676+
/**
677+
* ice_alloc_dynamic_port - Allocate new dynamic port
678+
* @pf: pointer to the pf structure
679+
* @new_attr: devlink port attributes requested
680+
* @extack: extack for reporting error messages
681+
* @devlink_port: index of newly created devlink port
682+
*
683+
* Allocate a new dynamic port instance and prepare it for configuration
684+
* with devlink.
685+
*
686+
* Return: zero on success or an error code on failure.
687+
*/
688+
static int
689+
ice_alloc_dynamic_port(struct ice_pf *pf,
690+
const struct devlink_port_new_attrs *new_attr,
691+
struct netlink_ext_ack *extack,
692+
struct devlink_port **devlink_port)
693+
{
694+
struct ice_dynamic_port *dyn_port;
695+
struct ice_vsi *vsi;
696+
u32 sfnum;
697+
int err;
698+
699+
err = ice_reserve_sf_num(pf, new_attr, extack, &sfnum);
700+
if (err)
701+
return err;
702+
703+
dyn_port = kzalloc(sizeof(*dyn_port), GFP_KERNEL);
704+
if (!dyn_port) {
705+
err = -ENOMEM;
706+
goto unroll_reserve_sf_num;
707+
}
708+
709+
vsi = ice_vsi_alloc(pf);
710+
if (!vsi) {
711+
NL_SET_ERR_MSG_MOD(extack, "Unable to allocate VSI");
712+
err = -ENOMEM;
713+
goto unroll_dyn_port_alloc;
714+
}
715+
716+
dyn_port->vsi = vsi;
717+
dyn_port->pf = pf;
718+
dyn_port->sfnum = sfnum;
719+
eth_random_addr(dyn_port->hw_addr);
720+
721+
err = xa_insert(&pf->dyn_ports, vsi->idx, dyn_port, GFP_KERNEL);
722+
if (err) {
723+
NL_SET_ERR_MSG_MOD(extack, "Port index reservation failed");
724+
goto unroll_vsi_alloc;
725+
}
726+
727+
err = ice_devlink_create_sf_port(dyn_port);
728+
if (err) {
729+
NL_SET_ERR_MSG_MOD(extack, "Port registration failed");
730+
goto unroll_xa_insert;
731+
}
732+
733+
*devlink_port = &dyn_port->devlink_port;
734+
735+
return 0;
736+
737+
unroll_xa_insert:
738+
xa_erase(&pf->dyn_ports, vsi->idx);
739+
unroll_vsi_alloc:
740+
ice_vsi_free(vsi);
741+
unroll_dyn_port_alloc:
742+
kfree(dyn_port);
743+
unroll_reserve_sf_num:
744+
xa_erase(&pf->sf_nums, sfnum);
745+
746+
return err;
747+
}
748+
749+
/**
750+
* ice_devlink_port_new - devlink handler for the new port
751+
* @devlink: pointer to devlink
752+
* @new_attr: pointer to the port new attributes
753+
* @extack: extack for reporting error messages
754+
* @devlink_port: pointer to a new port
755+
*
756+
* Creates new devlink port, checks new port attributes and reject
757+
* any unsupported parameters, allocates new subfunction for that port.
758+
*
759+
* Return: zero on success or an error code on failure.
760+
*/
761+
int
762+
ice_devlink_port_new(struct devlink *devlink,
763+
const struct devlink_port_new_attrs *new_attr,
764+
struct netlink_ext_ack *extack,
765+
struct devlink_port **devlink_port)
766+
{
767+
struct ice_pf *pf = devlink_priv(devlink);
768+
int err;
769+
770+
err = ice_devlink_port_new_check_attr(pf, new_attr, extack);
771+
if (err)
772+
return err;
773+
774+
return ice_alloc_dynamic_port(pf, new_attr, extack, devlink_port);
775+
}

drivers/net/ethernet/intel/ice/devlink/devlink_port.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,43 @@
44
#ifndef _DEVLINK_PORT_H_
55
#define _DEVLINK_PORT_H_
66

7+
#include "../ice.h"
8+
9+
/**
10+
* struct ice_dynamic_port - Track dynamically added devlink port instance
11+
* @hw_addr: the HW address for this port
12+
* @active: true if the port has been activated
13+
* @devlink_port: the associated devlink port structure
14+
* @pf: pointer to the PF private structure
15+
* @vsi: the VSI associated with this port
16+
* @sfnum: the subfunction ID
17+
*
18+
* An instance of a dynamically added devlink port. Each port flavour
19+
*/
20+
struct ice_dynamic_port {
21+
u8 hw_addr[ETH_ALEN];
22+
u8 active: 1;
23+
struct devlink_port devlink_port;
24+
struct ice_pf *pf;
25+
struct ice_vsi *vsi;
26+
u32 sfnum;
27+
};
28+
29+
void ice_dealloc_all_dynamic_ports(struct ice_pf *pf);
30+
731
int ice_devlink_create_pf_port(struct ice_pf *pf);
832
void ice_devlink_destroy_pf_port(struct ice_pf *pf);
933
int ice_devlink_create_vf_port(struct ice_vf *vf);
1034
void ice_devlink_destroy_vf_port(struct ice_vf *vf);
35+
int ice_devlink_create_sf_port(struct ice_dynamic_port *dyn_port);
36+
void ice_devlink_destroy_sf_port(struct ice_dynamic_port *dyn_port);
37+
38+
#define ice_devlink_port_to_dyn(port) \
39+
container_of(port, struct ice_dynamic_port, devlink_port)
1140

41+
int
42+
ice_devlink_port_new(struct devlink *devlink,
43+
const struct devlink_port_new_attrs *new_attr,
44+
struct netlink_ext_ack *extack,
45+
struct devlink_port **devlink_port);
1246
#endif /* _DEVLINK_PORT_H_ */

drivers/net/ethernet/intel/ice/ice.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,9 @@ struct ice_pf {
652652
struct ice_eswitch eswitch;
653653
struct ice_esw_br_port *br_port;
654654

655+
struct xarray dyn_ports;
656+
struct xarray sf_nums;
657+
655658
#define ICE_INVALID_AGG_NODE_ID 0
656659
#define ICE_PF_AGG_NODE_ID_START 1
657660
#define ICE_MAX_PF_AGG_NODES 32
@@ -918,6 +921,7 @@ int ice_vsi_open(struct ice_vsi *vsi);
918921
void ice_set_ethtool_ops(struct net_device *netdev);
919922
void ice_set_ethtool_repr_ops(struct net_device *netdev);
920923
void ice_set_ethtool_safe_mode_ops(struct net_device *netdev);
924+
void ice_set_ethtool_sf_ops(struct net_device *netdev);
921925
u16 ice_get_avail_txq_count(struct ice_pf *pf);
922926
u16 ice_get_avail_rxq_count(struct ice_pf *pf);
923927
int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked);

0 commit comments

Comments
 (0)