1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/device/devres.h> 4 #include <linux/netlink.h> 5 #include <linux/sprintf.h> 6 #include <linux/types.h> 7 #include <net/devlink.h> 8 9 #include "core.h" 10 #include "devlink.h" 11 #include "dpll.h" 12 #include "regs.h" 13 14 /** 15 * zl3073x_devlink_info_get - Devlink device info callback 16 * @devlink: devlink structure pointer 17 * @req: devlink request pointer to store information 18 * @extack: netlink extack pointer to report errors 19 * 20 * Return: 0 on success, <0 on error 21 */ 22 static int 23 zl3073x_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, 24 struct netlink_ext_ack *extack) 25 { 26 struct zl3073x_dev *zldev = devlink_priv(devlink); 27 u16 id, revision, fw_ver; 28 char buf[16]; 29 u32 cfg_ver; 30 int rc; 31 32 rc = zl3073x_read_u16(zldev, ZL_REG_ID, &id); 33 if (rc) 34 return rc; 35 36 snprintf(buf, sizeof(buf), "%X", id); 37 rc = devlink_info_version_fixed_put(req, 38 DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, 39 buf); 40 if (rc) 41 return rc; 42 43 rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision); 44 if (rc) 45 return rc; 46 47 snprintf(buf, sizeof(buf), "%X", revision); 48 rc = devlink_info_version_fixed_put(req, 49 DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, 50 buf); 51 if (rc) 52 return rc; 53 54 rc = zl3073x_read_u16(zldev, ZL_REG_FW_VER, &fw_ver); 55 if (rc) 56 return rc; 57 58 snprintf(buf, sizeof(buf), "%u", fw_ver); 59 rc = devlink_info_version_running_put(req, 60 DEVLINK_INFO_VERSION_GENERIC_FW, 61 buf); 62 if (rc) 63 return rc; 64 65 rc = zl3073x_read_u32(zldev, ZL_REG_CUSTOM_CONFIG_VER, &cfg_ver); 66 if (rc) 67 return rc; 68 69 /* No custom config version */ 70 if (cfg_ver == U32_MAX) 71 return 0; 72 73 snprintf(buf, sizeof(buf), "%lu.%lu.%lu.%lu", 74 FIELD_GET(GENMASK(31, 24), cfg_ver), 75 FIELD_GET(GENMASK(23, 16), cfg_ver), 76 FIELD_GET(GENMASK(15, 8), cfg_ver), 77 FIELD_GET(GENMASK(7, 0), cfg_ver)); 78 79 return devlink_info_version_running_put(req, "custom_cfg", buf); 80 } 81 82 static int 83 zl3073x_devlink_reload_down(struct devlink *devlink, bool netns_change, 84 enum devlink_reload_action action, 85 enum devlink_reload_limit limit, 86 struct netlink_ext_ack *extack) 87 { 88 struct zl3073x_dev *zldev = devlink_priv(devlink); 89 struct zl3073x_dpll *zldpll; 90 91 if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) 92 return -EOPNOTSUPP; 93 94 /* Unregister all DPLLs */ 95 list_for_each_entry(zldpll, &zldev->dplls, list) 96 zl3073x_dpll_unregister(zldpll); 97 98 return 0; 99 } 100 101 static int 102 zl3073x_devlink_reload_up(struct devlink *devlink, 103 enum devlink_reload_action action, 104 enum devlink_reload_limit limit, 105 u32 *actions_performed, 106 struct netlink_ext_ack *extack) 107 { 108 struct zl3073x_dev *zldev = devlink_priv(devlink); 109 union devlink_param_value val; 110 struct zl3073x_dpll *zldpll; 111 int rc; 112 113 if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) 114 return -EOPNOTSUPP; 115 116 rc = devl_param_driverinit_value_get(devlink, 117 DEVLINK_PARAM_GENERIC_ID_CLOCK_ID, 118 &val); 119 if (rc) 120 return rc; 121 122 if (zldev->clock_id != val.vu64) { 123 dev_dbg(zldev->dev, 124 "'clock_id' changed to %016llx\n", val.vu64); 125 zldev->clock_id = val.vu64; 126 } 127 128 /* Re-register all DPLLs */ 129 list_for_each_entry(zldpll, &zldev->dplls, list) { 130 rc = zl3073x_dpll_register(zldpll); 131 if (rc) 132 dev_warn(zldev->dev, 133 "Failed to re-register DPLL%u\n", zldpll->id); 134 } 135 136 *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 137 138 return 0; 139 } 140 141 static const struct devlink_ops zl3073x_devlink_ops = { 142 .info_get = zl3073x_devlink_info_get, 143 .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT), 144 .reload_down = zl3073x_devlink_reload_down, 145 .reload_up = zl3073x_devlink_reload_up, 146 }; 147 148 static void 149 zl3073x_devlink_free(void *ptr) 150 { 151 devlink_free(ptr); 152 } 153 154 /** 155 * zl3073x_devm_alloc - allocates zl3073x device structure 156 * @dev: pointer to device structure 157 * 158 * Allocates zl3073x device structure as device resource. 159 * 160 * Return: pointer to zl3073x device on success, error pointer on error 161 */ 162 struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev) 163 { 164 struct zl3073x_dev *zldev; 165 struct devlink *devlink; 166 int rc; 167 168 devlink = devlink_alloc(&zl3073x_devlink_ops, sizeof(*zldev), dev); 169 if (!devlink) 170 return ERR_PTR(-ENOMEM); 171 172 /* Add devres action to free devlink device */ 173 rc = devm_add_action_or_reset(dev, zl3073x_devlink_free, devlink); 174 if (rc) 175 return ERR_PTR(rc); 176 177 zldev = devlink_priv(devlink); 178 zldev->dev = dev; 179 dev_set_drvdata(zldev->dev, zldev); 180 181 return zldev; 182 } 183 EXPORT_SYMBOL_NS_GPL(zl3073x_devm_alloc, "ZL3073X"); 184 185 static int 186 zl3073x_devlink_param_clock_id_validate(struct devlink *devlink, u32 id, 187 union devlink_param_value val, 188 struct netlink_ext_ack *extack) 189 { 190 if (!val.vu64) { 191 NL_SET_ERR_MSG_MOD(extack, "'clock_id' must be non-zero"); 192 return -EINVAL; 193 } 194 195 return 0; 196 } 197 198 static const struct devlink_param zl3073x_devlink_params[] = { 199 DEVLINK_PARAM_GENERIC(CLOCK_ID, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 200 NULL, NULL, 201 zl3073x_devlink_param_clock_id_validate), 202 }; 203 204 static void 205 zl3073x_devlink_unregister(void *ptr) 206 { 207 struct devlink *devlink = priv_to_devlink(ptr); 208 209 devl_lock(devlink); 210 211 /* Unregister devlink params */ 212 devl_params_unregister(devlink, zl3073x_devlink_params, 213 ARRAY_SIZE(zl3073x_devlink_params)); 214 215 /* Unregister devlink instance */ 216 devl_unregister(devlink); 217 218 devl_unlock(devlink); 219 } 220 221 /** 222 * zl3073x_devlink_register - register devlink instance and params 223 * @zldev: zl3073x device to register the devlink for 224 * 225 * Register the devlink instance and parameters associated with the device. 226 * 227 * Return: 0 on success, <0 on error 228 */ 229 int zl3073x_devlink_register(struct zl3073x_dev *zldev) 230 { 231 struct devlink *devlink = priv_to_devlink(zldev); 232 union devlink_param_value value; 233 int rc; 234 235 devl_lock(devlink); 236 237 /* Register devlink params */ 238 rc = devl_params_register(devlink, zl3073x_devlink_params, 239 ARRAY_SIZE(zl3073x_devlink_params)); 240 if (rc) { 241 devl_unlock(devlink); 242 243 return rc; 244 } 245 246 value.vu64 = zldev->clock_id; 247 devl_param_driverinit_value_set(devlink, 248 DEVLINK_PARAM_GENERIC_ID_CLOCK_ID, 249 value); 250 251 /* Register devlink instance */ 252 devl_register(devlink); 253 254 devl_unlock(devlink); 255 256 /* Add devres action to unregister devlink device */ 257 return devm_add_action_or_reset(zldev->dev, zl3073x_devlink_unregister, 258 zldev); 259 } 260