Merge remote-tracking branch 'origin/master' into perf/core
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlx5 / core / esw / devlink_port.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2020 Mellanox Technologies Ltd. */
3
4 #include <linux/mlx5/driver.h>
5 #include "eswitch.h"
6
7 static void
8 mlx5_esw_get_port_parent_id(struct mlx5_core_dev *dev, struct netdev_phys_item_id *ppid)
9 {
10         u64 parent_id;
11
12         parent_id = mlx5_query_nic_system_image_guid(dev);
13         ppid->id_len = sizeof(parent_id);
14         memcpy(ppid->id, &parent_id, sizeof(parent_id));
15 }
16
17 static bool
18 mlx5_esw_devlink_port_supported(const struct mlx5_eswitch *esw, u16 vport_num)
19 {
20         return vport_num == MLX5_VPORT_UPLINK ||
21                (mlx5_core_is_ecpf(esw->dev) && vport_num == MLX5_VPORT_PF) ||
22                mlx5_eswitch_is_vf_vport(esw, vport_num);
23 }
24
25 static struct devlink_port *mlx5_esw_dl_port_alloc(struct mlx5_eswitch *esw, u16 vport_num)
26 {
27         struct mlx5_core_dev *dev = esw->dev;
28         struct devlink_port_attrs attrs = {};
29         struct netdev_phys_item_id ppid = {};
30         struct devlink_port *dl_port;
31         u32 controller_num = 0;
32         bool external;
33         u16 pfnum;
34
35         dl_port = kzalloc(sizeof(*dl_port), GFP_KERNEL);
36         if (!dl_port)
37                 return NULL;
38
39         mlx5_esw_get_port_parent_id(dev, &ppid);
40         pfnum = PCI_FUNC(dev->pdev->devfn);
41         external = mlx5_core_is_ecpf_esw_manager(dev);
42         if (external)
43                 controller_num = dev->priv.eswitch->offloads.host_number + 1;
44
45         if (vport_num == MLX5_VPORT_UPLINK) {
46                 attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
47                 attrs.phys.port_number = pfnum;
48                 memcpy(attrs.switch_id.id, ppid.id, ppid.id_len);
49                 attrs.switch_id.id_len = ppid.id_len;
50                 devlink_port_attrs_set(dl_port, &attrs);
51         } else if (vport_num == MLX5_VPORT_PF) {
52                 memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len);
53                 dl_port->attrs.switch_id.id_len = ppid.id_len;
54                 devlink_port_attrs_pci_pf_set(dl_port, controller_num, pfnum, external);
55         } else if (mlx5_eswitch_is_vf_vport(esw, vport_num)) {
56                 memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len);
57                 dl_port->attrs.switch_id.id_len = ppid.id_len;
58                 devlink_port_attrs_pci_vf_set(dl_port, controller_num, pfnum,
59                                               vport_num - 1, external);
60         }
61         return dl_port;
62 }
63
64 static void mlx5_esw_dl_port_free(struct devlink_port *dl_port)
65 {
66         kfree(dl_port);
67 }
68
69 int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num)
70 {
71         struct mlx5_core_dev *dev = esw->dev;
72         struct devlink_port *dl_port;
73         unsigned int dl_port_index;
74         struct mlx5_vport *vport;
75         struct devlink *devlink;
76         int err;
77
78         if (!mlx5_esw_devlink_port_supported(esw, vport_num))
79                 return 0;
80
81         vport = mlx5_eswitch_get_vport(esw, vport_num);
82         if (IS_ERR(vport))
83                 return PTR_ERR(vport);
84
85         dl_port = mlx5_esw_dl_port_alloc(esw, vport_num);
86         if (!dl_port)
87                 return -ENOMEM;
88
89         devlink = priv_to_devlink(dev);
90         dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num);
91         err = devlink_port_register(devlink, dl_port, dl_port_index);
92         if (err)
93                 goto reg_err;
94
95         vport->dl_port = dl_port;
96         return 0;
97
98 reg_err:
99         mlx5_esw_dl_port_free(dl_port);
100         return err;
101 }
102
103 void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, u16 vport_num)
104 {
105         struct mlx5_vport *vport;
106
107         if (!mlx5_esw_devlink_port_supported(esw, vport_num))
108                 return;
109
110         vport = mlx5_eswitch_get_vport(esw, vport_num);
111         if (IS_ERR(vport))
112                 return;
113         devlink_port_unregister(vport->dl_port);
114         mlx5_esw_dl_port_free(vport->dl_port);
115         vport->dl_port = NULL;
116 }
117
118 struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num)
119 {
120         struct mlx5_vport *vport;
121
122         vport = mlx5_eswitch_get_vport(esw, vport_num);
123         return vport->dl_port;
124 }