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
mlx5_esw_get_port_parent_id(struct mlx5_core_dev * dev,struct netdev_phys_item_id * ppid)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
mlx5_esw_devlink_port_supported(const struct mlx5_eswitch * esw,u16 vport_num)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
mlx5_esw_dl_port_alloc(struct mlx5_eswitch * esw,u16 vport_num)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
mlx5_esw_dl_port_free(struct devlink_port * dl_port)64 static void mlx5_esw_dl_port_free(struct devlink_port *dl_port)
65 {
66 kfree(dl_port);
67 }
68
mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch * esw,u16 vport_num)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
mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch * esw,u16 vport_num)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
mlx5_esw_offloads_devlink_port(struct mlx5_eswitch * esw,u16 vport_num)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 }
125