1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2025, Intel Corporation. */ 3 4 #include "ixgbe.h" 5 #include "devlink.h" 6 7 struct ixgbe_info_ctx { 8 char buf[128]; 9 }; 10 11 static void ixgbe_info_get_dsn(struct ixgbe_adapter *adapter, 12 struct ixgbe_info_ctx *ctx) 13 { 14 u8 dsn[8]; 15 16 /* Copy the DSN into an array in Big Endian format */ 17 put_unaligned_be64(pci_get_dsn(adapter->pdev), dsn); 18 19 snprintf(ctx->buf, sizeof(ctx->buf), "%8phD", dsn); 20 } 21 22 static void ixgbe_info_orom_ver(struct ixgbe_adapter *adapter, 23 struct ixgbe_info_ctx *ctx) 24 { 25 struct ixgbe_hw *hw = &adapter->hw; 26 struct ixgbe_nvm_version nvm_ver; 27 28 ctx->buf[0] = '\0'; 29 30 if (hw->mac.type == ixgbe_mac_e610) { 31 struct ixgbe_orom_info *orom = &adapter->hw.flash.orom; 32 33 snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", 34 orom->major, orom->build, orom->patch); 35 return; 36 } 37 38 ixgbe_get_oem_prod_version(hw, &nvm_ver); 39 if (nvm_ver.oem_valid) { 40 snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x", 41 nvm_ver.oem_major, nvm_ver.oem_minor, 42 nvm_ver.oem_release); 43 44 return; 45 } 46 47 ixgbe_get_orom_version(hw, &nvm_ver); 48 if (nvm_ver.or_valid) 49 snprintf(ctx->buf, sizeof(ctx->buf), "%d.%d.%d", 50 nvm_ver.or_major, nvm_ver.or_build, nvm_ver.or_patch); 51 } 52 53 static void ixgbe_info_eetrack(struct ixgbe_adapter *adapter, 54 struct ixgbe_info_ctx *ctx) 55 { 56 struct ixgbe_hw *hw = &adapter->hw; 57 struct ixgbe_nvm_version nvm_ver; 58 59 if (hw->mac.type == ixgbe_mac_e610) { 60 snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", 61 hw->flash.nvm.eetrack); 62 return; 63 } 64 65 ixgbe_get_oem_prod_version(hw, &nvm_ver); 66 67 /* No ETRACK version for OEM */ 68 if (nvm_ver.oem_valid) { 69 ctx->buf[0] = '\0'; 70 return; 71 } 72 73 ixgbe_get_etk_id(hw, &nvm_ver); 74 snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm_ver.etk_id); 75 } 76 77 static void ixgbe_info_fw_api(struct ixgbe_adapter *adapter, 78 struct ixgbe_info_ctx *ctx) 79 { 80 struct ixgbe_hw *hw = &adapter->hw; 81 82 snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", 83 hw->api_maj_ver, hw->api_min_ver, hw->api_patch); 84 } 85 86 static void ixgbe_info_fw_build(struct ixgbe_adapter *adapter, 87 struct ixgbe_info_ctx *ctx) 88 { 89 struct ixgbe_hw *hw = &adapter->hw; 90 91 snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", hw->fw_build); 92 } 93 94 static void ixgbe_info_fw_srev(struct ixgbe_adapter *adapter, 95 struct ixgbe_info_ctx *ctx) 96 { 97 struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm; 98 99 snprintf(ctx->buf, sizeof(ctx->buf), "%u", nvm->srev); 100 } 101 102 static void ixgbe_info_orom_srev(struct ixgbe_adapter *adapter, 103 struct ixgbe_info_ctx *ctx) 104 { 105 struct ixgbe_orom_info *orom = &adapter->hw.flash.orom; 106 107 snprintf(ctx->buf, sizeof(ctx->buf), "%u", orom->srev); 108 } 109 110 static void ixgbe_info_nvm_ver(struct ixgbe_adapter *adapter, 111 struct ixgbe_info_ctx *ctx) 112 { 113 struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm; 114 115 snprintf(ctx->buf, sizeof(ctx->buf), "%x.%02x", nvm->major, nvm->minor); 116 } 117 118 static void ixgbe_info_netlist_ver(struct ixgbe_adapter *adapter, 119 struct ixgbe_info_ctx *ctx) 120 { 121 struct ixgbe_netlist_info *netlist = &adapter->hw.flash.netlist; 122 123 /* The netlist version fields are BCD formatted */ 124 snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x-%x.%x.%x", 125 netlist->major, netlist->minor, 126 netlist->type >> 16, netlist->type & 0xFFFF, 127 netlist->rev, netlist->cust_ver); 128 } 129 130 static void ixgbe_info_netlist_build(struct ixgbe_adapter *adapter, 131 struct ixgbe_info_ctx *ctx) 132 { 133 struct ixgbe_netlist_info *netlist = &adapter->hw.flash.netlist; 134 135 snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash); 136 } 137 138 static int ixgbe_devlink_info_get_e610(struct ixgbe_adapter *adapter, 139 struct devlink_info_req *req, 140 struct ixgbe_info_ctx *ctx) 141 { 142 int err; 143 144 ixgbe_info_fw_api(adapter, ctx); 145 err = devlink_info_version_running_put(req, 146 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API, 147 ctx->buf); 148 if (err) 149 return err; 150 151 ixgbe_info_fw_build(adapter, ctx); 152 err = devlink_info_version_running_put(req, "fw.mgmt.build", ctx->buf); 153 if (err) 154 return err; 155 156 ixgbe_info_fw_srev(adapter, ctx); 157 err = devlink_info_version_running_put(req, "fw.mgmt.srev", ctx->buf); 158 if (err) 159 return err; 160 161 ixgbe_info_orom_srev(adapter, ctx); 162 err = devlink_info_version_running_put(req, "fw.undi.srev", ctx->buf); 163 if (err) 164 return err; 165 166 ixgbe_info_nvm_ver(adapter, ctx); 167 err = devlink_info_version_running_put(req, "fw.psid.api", ctx->buf); 168 if (err) 169 return err; 170 171 ixgbe_info_netlist_ver(adapter, ctx); 172 err = devlink_info_version_running_put(req, "fw.netlist", ctx->buf); 173 if (err) 174 return err; 175 176 ixgbe_info_netlist_build(adapter, ctx); 177 return devlink_info_version_running_put(req, "fw.netlist.build", 178 ctx->buf); 179 } 180 181 static int ixgbe_devlink_info_get(struct devlink *devlink, 182 struct devlink_info_req *req, 183 struct netlink_ext_ack *extack) 184 { 185 struct ixgbe_adapter *adapter = devlink_priv(devlink); 186 struct ixgbe_hw *hw = &adapter->hw; 187 struct ixgbe_info_ctx *ctx; 188 int err; 189 190 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); 191 if (!ctx) 192 return -ENOMEM; 193 194 ixgbe_info_get_dsn(adapter, ctx); 195 err = devlink_info_serial_number_put(req, ctx->buf); 196 if (err) 197 goto free_ctx; 198 199 err = ixgbe_read_pba_string_generic(hw, ctx->buf, sizeof(ctx->buf)); 200 if (err) 201 goto free_ctx; 202 203 err = devlink_info_version_fixed_put(req, 204 DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, 205 ctx->buf); 206 if (err) 207 goto free_ctx; 208 209 ixgbe_info_orom_ver(adapter, ctx); 210 err = devlink_info_version_running_put(req, 211 DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, 212 ctx->buf); 213 if (err) 214 goto free_ctx; 215 216 ixgbe_info_eetrack(adapter, ctx); 217 err = devlink_info_version_running_put(req, 218 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, 219 ctx->buf); 220 if (err || hw->mac.type != ixgbe_mac_e610) 221 goto free_ctx; 222 223 err = ixgbe_devlink_info_get_e610(adapter, req, ctx); 224 free_ctx: 225 kfree(ctx); 226 return err; 227 } 228 229 static const struct devlink_ops ixgbe_devlink_ops = { 230 .info_get = ixgbe_devlink_info_get, 231 }; 232 233 /** 234 * ixgbe_allocate_devlink - Allocate devlink instance 235 * @dev: device to allocate devlink for 236 * 237 * Allocate a devlink instance for this physical function. 238 * 239 * Return: pointer to the device adapter structure on success, 240 * ERR_PTR(-ENOMEM) when allocation failed. 241 */ 242 struct ixgbe_adapter *ixgbe_allocate_devlink(struct device *dev) 243 { 244 struct ixgbe_adapter *adapter; 245 struct devlink *devlink; 246 247 devlink = devlink_alloc(&ixgbe_devlink_ops, sizeof(*adapter), dev); 248 if (!devlink) 249 return ERR_PTR(-ENOMEM); 250 251 adapter = devlink_priv(devlink); 252 adapter->devlink = devlink; 253 254 return adapter; 255 } 256 257 /** 258 * ixgbe_devlink_set_switch_id - Set unique switch ID based on PCI DSN 259 * @adapter: pointer to the device adapter structure 260 * @ppid: struct with switch id information 261 */ 262 static void ixgbe_devlink_set_switch_id(struct ixgbe_adapter *adapter, 263 struct netdev_phys_item_id *ppid) 264 { 265 u64 id = pci_get_dsn(adapter->pdev); 266 267 ppid->id_len = sizeof(id); 268 put_unaligned_be64(id, &ppid->id); 269 } 270 271 /** 272 * ixgbe_devlink_register_port - Register devlink port 273 * @adapter: pointer to the device adapter structure 274 * 275 * Create and register a devlink_port for this physical function. 276 * 277 * Return: 0 on success, error code on failure. 278 */ 279 int ixgbe_devlink_register_port(struct ixgbe_adapter *adapter) 280 { 281 struct devlink_port *devlink_port = &adapter->devlink_port; 282 struct devlink *devlink = adapter->devlink; 283 struct device *dev = &adapter->pdev->dev; 284 struct devlink_port_attrs attrs = {}; 285 int err; 286 287 attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 288 attrs.phys.port_number = adapter->hw.bus.func; 289 ixgbe_devlink_set_switch_id(adapter, &attrs.switch_id); 290 291 devlink_port_attrs_set(devlink_port, &attrs); 292 293 err = devl_port_register(devlink, devlink_port, 0); 294 if (err) { 295 dev_err(dev, 296 "devlink port registration failed, err %d\n", err); 297 } 298 299 return err; 300 } 301