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 mlx5_core_is_ec_vf_vport(esw->dev, 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 = mlx5_get_dev_index(dev); 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 } else if (mlx5_core_is_ec_vf_vport(esw->dev, vport_num)) { 61 memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len); 62 dl_port->attrs.switch_id.id_len = ppid.id_len; 63 devlink_port_attrs_pci_vf_set(dl_port, controller_num, pfnum, 64 vport_num - 1, false); 65 } 66 return dl_port; 67 } 68 69 static void mlx5_esw_dl_port_free(struct devlink_port *dl_port) 70 { 71 kfree(dl_port); 72 } 73 74 static const struct devlink_port_ops mlx5_esw_dl_port_ops = { 75 .port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get, 76 .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set, 77 .port_fn_roce_get = mlx5_devlink_port_fn_roce_get, 78 .port_fn_roce_set = mlx5_devlink_port_fn_roce_set, 79 .port_fn_migratable_get = mlx5_devlink_port_fn_migratable_get, 80 .port_fn_migratable_set = mlx5_devlink_port_fn_migratable_set, 81 }; 82 83 int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num) 84 { 85 struct mlx5_core_dev *dev = esw->dev; 86 struct devlink_port *dl_port; 87 unsigned int dl_port_index; 88 struct mlx5_vport *vport; 89 struct devlink *devlink; 90 int err; 91 92 if (!mlx5_esw_devlink_port_supported(esw, vport_num)) 93 return 0; 94 95 vport = mlx5_eswitch_get_vport(esw, vport_num); 96 if (IS_ERR(vport)) 97 return PTR_ERR(vport); 98 99 dl_port = mlx5_esw_dl_port_alloc(esw, vport_num); 100 if (!dl_port) 101 return -ENOMEM; 102 103 devlink = priv_to_devlink(dev); 104 dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num); 105 err = devl_port_register_with_ops(devlink, dl_port, dl_port_index, 106 &mlx5_esw_dl_port_ops); 107 if (err) 108 goto reg_err; 109 110 err = devl_rate_leaf_create(dl_port, vport, NULL); 111 if (err) 112 goto rate_err; 113 114 vport->dl_port = dl_port; 115 return 0; 116 117 rate_err: 118 devl_port_unregister(dl_port); 119 reg_err: 120 mlx5_esw_dl_port_free(dl_port); 121 return err; 122 } 123 124 void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, u16 vport_num) 125 { 126 struct mlx5_vport *vport; 127 128 if (!mlx5_esw_devlink_port_supported(esw, vport_num)) 129 return; 130 131 vport = mlx5_eswitch_get_vport(esw, vport_num); 132 if (IS_ERR(vport)) 133 return; 134 135 if (vport->dl_port->devlink_rate) { 136 mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL); 137 devl_rate_leaf_destroy(vport->dl_port); 138 } 139 140 devl_port_unregister(vport->dl_port); 141 mlx5_esw_dl_port_free(vport->dl_port); 142 vport->dl_port = NULL; 143 } 144 145 struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num) 146 { 147 struct mlx5_vport *vport; 148 149 vport = mlx5_eswitch_get_vport(esw, vport_num); 150 return IS_ERR(vport) ? ERR_CAST(vport) : vport->dl_port; 151 } 152 153 static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = { 154 #ifdef CONFIG_MLX5_SF_MANAGER 155 .port_del = mlx5_devlink_sf_port_del, 156 #endif 157 .port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get, 158 .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set, 159 .port_fn_roce_get = mlx5_devlink_port_fn_roce_get, 160 .port_fn_roce_set = mlx5_devlink_port_fn_roce_set, 161 #ifdef CONFIG_MLX5_SF_MANAGER 162 .port_fn_state_get = mlx5_devlink_sf_port_fn_state_get, 163 .port_fn_state_set = mlx5_devlink_sf_port_fn_state_set, 164 #endif 165 }; 166 167 int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port, 168 u16 vport_num, u32 controller, u32 sfnum) 169 { 170 struct mlx5_core_dev *dev = esw->dev; 171 struct netdev_phys_item_id ppid = {}; 172 unsigned int dl_port_index; 173 struct mlx5_vport *vport; 174 struct devlink *devlink; 175 u16 pfnum; 176 int err; 177 178 vport = mlx5_eswitch_get_vport(esw, vport_num); 179 if (IS_ERR(vport)) 180 return PTR_ERR(vport); 181 182 pfnum = mlx5_get_dev_index(dev); 183 mlx5_esw_get_port_parent_id(dev, &ppid); 184 memcpy(dl_port->attrs.switch_id.id, &ppid.id[0], ppid.id_len); 185 dl_port->attrs.switch_id.id_len = ppid.id_len; 186 devlink_port_attrs_pci_sf_set(dl_port, controller, pfnum, sfnum, !!controller); 187 devlink = priv_to_devlink(dev); 188 dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num); 189 err = devl_port_register_with_ops(devlink, dl_port, dl_port_index, 190 &mlx5_esw_dl_sf_port_ops); 191 if (err) 192 return err; 193 194 err = devl_rate_leaf_create(dl_port, vport, NULL); 195 if (err) 196 goto rate_err; 197 198 vport->dl_port = dl_port; 199 return 0; 200 201 rate_err: 202 devl_port_unregister(dl_port); 203 return err; 204 } 205 206 void mlx5_esw_devlink_sf_port_unregister(struct mlx5_eswitch *esw, u16 vport_num) 207 { 208 struct mlx5_vport *vport; 209 210 vport = mlx5_eswitch_get_vport(esw, vport_num); 211 if (IS_ERR(vport)) 212 return; 213 214 if (vport->dl_port->devlink_rate) { 215 mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL); 216 devl_rate_leaf_destroy(vport->dl_port); 217 } 218 219 devl_port_unregister(vport->dl_port); 220 vport->dl_port = NULL; 221 } 222