1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 3 4 #include <linux/rtnetlink.h> 5 #include <net/devlink.h> 6 7 #include "nfpcore/nfp_nsp.h" 8 #include "nfp_app.h" 9 #include "nfp_main.h" 10 #include "nfp_port.h" 11 12 static int 13 nfp_devlink_fill_eth_port(struct nfp_port *port, 14 struct nfp_eth_table_port *copy) 15 { 16 struct nfp_eth_table_port *eth_port; 17 18 eth_port = __nfp_port_get_eth_port(port); 19 if (!eth_port) 20 return -EINVAL; 21 22 memcpy(copy, eth_port, sizeof(*eth_port)); 23 24 return 0; 25 } 26 27 static int 28 nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf, unsigned int port_index, 29 struct nfp_eth_table_port *copy) 30 { 31 struct nfp_port *port; 32 33 port = nfp_port_from_id(pf, NFP_PORT_PHYS_PORT, port_index); 34 35 return nfp_devlink_fill_eth_port(port, copy); 36 } 37 38 static int 39 nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes) 40 { 41 struct nfp_nsp *nsp; 42 int ret; 43 44 nsp = nfp_eth_config_start(pf->cpp, idx); 45 if (IS_ERR(nsp)) 46 return PTR_ERR(nsp); 47 48 ret = __nfp_eth_set_split(nsp, lanes); 49 if (ret) { 50 nfp_eth_config_cleanup_end(nsp); 51 return ret; 52 } 53 54 ret = nfp_eth_config_commit_end(nsp); 55 if (ret < 0) 56 return ret; 57 if (ret) /* no change */ 58 return 0; 59 60 return nfp_net_refresh_port_table_sync(pf); 61 } 62 63 static int 64 nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index, 65 unsigned int count, struct netlink_ext_ack *extack) 66 { 67 struct nfp_pf *pf = devlink_priv(devlink); 68 struct nfp_eth_table_port eth_port; 69 unsigned int lanes; 70 int ret; 71 72 if (count < 2) 73 return -EINVAL; 74 75 mutex_lock(&pf->lock); 76 77 rtnl_lock(); 78 ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, ð_port); 79 rtnl_unlock(); 80 if (ret) 81 goto out; 82 83 if (eth_port.is_split || eth_port.port_lanes % count) { 84 ret = -EINVAL; 85 goto out; 86 } 87 88 /* Special case the 100G CXP -> 2x40G split */ 89 lanes = eth_port.port_lanes / count; 90 if (eth_port.lanes == 10 && count == 2) 91 lanes = 8 / count; 92 93 ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes); 94 out: 95 mutex_unlock(&pf->lock); 96 97 return ret; 98 } 99 100 static int 101 nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index, 102 struct netlink_ext_ack *extack) 103 { 104 struct nfp_pf *pf = devlink_priv(devlink); 105 struct nfp_eth_table_port eth_port; 106 unsigned int lanes; 107 int ret; 108 109 mutex_lock(&pf->lock); 110 111 rtnl_lock(); 112 ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, ð_port); 113 rtnl_unlock(); 114 if (ret) 115 goto out; 116 117 if (!eth_port.is_split) { 118 ret = -EINVAL; 119 goto out; 120 } 121 122 /* Special case the 100G CXP -> 2x40G unsplit */ 123 lanes = eth_port.port_lanes; 124 if (eth_port.port_lanes == 8) 125 lanes = 10; 126 127 ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes); 128 out: 129 mutex_unlock(&pf->lock); 130 131 return ret; 132 } 133 134 static int 135 nfp_devlink_sb_pool_get(struct devlink *devlink, unsigned int sb_index, 136 u16 pool_index, struct devlink_sb_pool_info *pool_info) 137 { 138 struct nfp_pf *pf = devlink_priv(devlink); 139 140 return nfp_shared_buf_pool_get(pf, sb_index, pool_index, pool_info); 141 } 142 143 static int 144 nfp_devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index, 145 u16 pool_index, 146 u32 size, enum devlink_sb_threshold_type threshold_type) 147 { 148 struct nfp_pf *pf = devlink_priv(devlink); 149 150 return nfp_shared_buf_pool_set(pf, sb_index, pool_index, 151 size, threshold_type); 152 } 153 154 static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) 155 { 156 struct nfp_pf *pf = devlink_priv(devlink); 157 158 return nfp_app_eswitch_mode_get(pf->app, mode); 159 } 160 161 static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, 162 struct netlink_ext_ack *extack) 163 { 164 struct nfp_pf *pf = devlink_priv(devlink); 165 int ret; 166 167 mutex_lock(&pf->lock); 168 ret = nfp_app_eswitch_mode_set(pf->app, mode); 169 mutex_unlock(&pf->lock); 170 171 return ret; 172 } 173 174 const struct devlink_ops nfp_devlink_ops = { 175 .port_split = nfp_devlink_port_split, 176 .port_unsplit = nfp_devlink_port_unsplit, 177 .sb_pool_get = nfp_devlink_sb_pool_get, 178 .sb_pool_set = nfp_devlink_sb_pool_set, 179 .eswitch_mode_get = nfp_devlink_eswitch_mode_get, 180 .eswitch_mode_set = nfp_devlink_eswitch_mode_set, 181 }; 182 183 int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port) 184 { 185 struct nfp_eth_table_port eth_port; 186 struct devlink *devlink; 187 int ret; 188 189 rtnl_lock(); 190 ret = nfp_devlink_fill_eth_port(port, ð_port); 191 rtnl_unlock(); 192 if (ret) 193 return ret; 194 195 devlink_port_type_eth_set(&port->dl_port, port->netdev); 196 devlink_port_attrs_set(&port->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL, 197 eth_port.label_port, eth_port.is_split, 198 eth_port.label_subport); 199 200 devlink = priv_to_devlink(app->pf); 201 202 return devlink_port_register(devlink, &port->dl_port, port->eth_id); 203 } 204 205 void nfp_devlink_port_unregister(struct nfp_port *port) 206 { 207 devlink_port_unregister(&port->dl_port); 208 } 209