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 mlx5_esw_devlink_port_supported(struct mlx5_eswitch *esw, u16 vport_num) 18 { 19 return vport_num == MLX5_VPORT_UPLINK || 20 (mlx5_core_is_ecpf(esw->dev) && vport_num == MLX5_VPORT_PF) || 21 mlx5_eswitch_is_vf_vport(esw, vport_num); 22 } 23 24 static struct devlink_port *mlx5_esw_dl_port_alloc(struct mlx5_eswitch *esw, u16 vport_num) 25 { 26 struct mlx5_core_dev *dev = esw->dev; 27 struct devlink_port_attrs attrs = {}; 28 struct netdev_phys_item_id ppid = {}; 29 struct devlink_port *dl_port; 30 u32 controller_num = 0; 31 bool external; 32 u16 pfnum; 33 34 dl_port = kzalloc(sizeof(*dl_port), GFP_KERNEL); 35 if (!dl_port) 36 return NULL; 37 38 mlx5_esw_get_port_parent_id(dev, &ppid); 39 pfnum = mlx5_get_dev_index(dev); 40 external = mlx5_core_is_ecpf_esw_manager(dev); 41 if (external) 42 controller_num = dev->priv.eswitch->offloads.host_number + 1; 43 44 if (vport_num == MLX5_VPORT_UPLINK) { 45 attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 46 attrs.phys.port_number = pfnum; 47 memcpy(attrs.switch_id.id, ppid.id, ppid.id_len); 48 attrs.switch_id.id_len = ppid.id_len; 49 devlink_port_attrs_set(dl_port, &attrs); 50 } else if (vport_num == MLX5_VPORT_PF) { 51 memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len); 52 dl_port->attrs.switch_id.id_len = ppid.id_len; 53 devlink_port_attrs_pci_pf_set(dl_port, controller_num, pfnum, external); 54 } else if (mlx5_eswitch_is_vf_vport(esw, vport_num)) { 55 memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len); 56 dl_port->attrs.switch_id.id_len = ppid.id_len; 57 devlink_port_attrs_pci_vf_set(dl_port, controller_num, pfnum, 58 vport_num - 1, external); 59 } 60 return dl_port; 61 } 62 63 static void mlx5_esw_dl_port_free(struct devlink_port *dl_port) 64 { 65 kfree(dl_port); 66 } 67 68 int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num) 69 { 70 struct mlx5_core_dev *dev = esw->dev; 71 struct devlink_port *dl_port; 72 unsigned int dl_port_index; 73 struct mlx5_vport *vport; 74 struct devlink *devlink; 75 int err; 76 77 if (!mlx5_esw_devlink_port_supported(esw, vport_num)) 78 return 0; 79 80 vport = mlx5_eswitch_get_vport(esw, vport_num); 81 if (IS_ERR(vport)) 82 return PTR_ERR(vport); 83 84 dl_port = mlx5_esw_dl_port_alloc(esw, vport_num); 85 if (!dl_port) 86 return -ENOMEM; 87 88 devlink = priv_to_devlink(dev); 89 dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num); 90 err = devlink_port_register(devlink, dl_port, dl_port_index); 91 if (err) 92 goto reg_err; 93 94 err = devlink_rate_leaf_create(dl_port, vport); 95 if (err) 96 goto rate_err; 97 98 vport->dl_port = dl_port; 99 return 0; 100 101 rate_err: 102 devlink_port_unregister(dl_port); 103 reg_err: 104 mlx5_esw_dl_port_free(dl_port); 105 return err; 106 } 107 108 void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, u16 vport_num) 109 { 110 struct mlx5_vport *vport; 111 112 if (!mlx5_esw_devlink_port_supported(esw, vport_num)) 113 return; 114 115 vport = mlx5_eswitch_get_vport(esw, vport_num); 116 if (IS_ERR(vport)) 117 return; 118 119 if (vport->dl_port->devlink_rate) { 120 mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL); 121 devlink_rate_leaf_destroy(vport->dl_port); 122 } 123 124 devlink_port_unregister(vport->dl_port); 125 mlx5_esw_dl_port_free(vport->dl_port); 126 vport->dl_port = NULL; 127 } 128 129 struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num) 130 { 131 struct mlx5_vport *vport; 132 133 vport = mlx5_eswitch_get_vport(esw, vport_num); 134 return IS_ERR(vport) ? ERR_CAST(vport) : vport->dl_port; 135 } 136 137 int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port, 138 u16 vport_num, u32 controller, u32 sfnum) 139 { 140 struct mlx5_core_dev *dev = esw->dev; 141 struct netdev_phys_item_id ppid = {}; 142 unsigned int dl_port_index; 143 struct mlx5_vport *vport; 144 struct devlink *devlink; 145 u16 pfnum; 146 int err; 147 148 vport = mlx5_eswitch_get_vport(esw, vport_num); 149 if (IS_ERR(vport)) 150 return PTR_ERR(vport); 151 152 pfnum = mlx5_get_dev_index(dev); 153 mlx5_esw_get_port_parent_id(dev, &ppid); 154 memcpy(dl_port->attrs.switch_id.id, &ppid.id[0], ppid.id_len); 155 dl_port->attrs.switch_id.id_len = ppid.id_len; 156 devlink_port_attrs_pci_sf_set(dl_port, controller, pfnum, sfnum, !!controller); 157 devlink = priv_to_devlink(dev); 158 dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num); 159 err = devlink_port_register(devlink, dl_port, dl_port_index); 160 if (err) 161 return err; 162 163 err = devlink_rate_leaf_create(dl_port, vport); 164 if (err) 165 goto rate_err; 166 167 vport->dl_port = dl_port; 168 return 0; 169 170 rate_err: 171 devlink_port_unregister(dl_port); 172 return err; 173 } 174 175 void mlx5_esw_devlink_sf_port_unregister(struct mlx5_eswitch *esw, u16 vport_num) 176 { 177 struct mlx5_vport *vport; 178 179 vport = mlx5_eswitch_get_vport(esw, vport_num); 180 if (IS_ERR(vport)) 181 return; 182 183 if (vport->dl_port->devlink_rate) { 184 mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL); 185 devlink_rate_leaf_destroy(vport->dl_port); 186 } 187 188 devlink_port_unregister(vport->dl_port); 189 vport->dl_port = NULL; 190 } 191