1dbeeca81SMoshe Shemesh // SPDX-License-Identifier: GPL-2.0-or-later 2dbeeca81SMoshe Shemesh /* 3dbeeca81SMoshe Shemesh * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 4dbeeca81SMoshe Shemesh * Copyright (c) 2016 Jiri Pirko <[email protected]> 5dbeeca81SMoshe Shemesh */ 6dbeeca81SMoshe Shemesh 7dbeeca81SMoshe Shemesh #include <net/genetlink.h> 8c6ed7d6eSMoshe Shemesh #include <net/sock.h> 9dbeeca81SMoshe Shemesh #include "devl_internal.h" 10dbeeca81SMoshe Shemesh 11ec4a0ce9SMoshe Shemesh struct devlink_info_req { 12ec4a0ce9SMoshe Shemesh struct sk_buff *msg; 13ec4a0ce9SMoshe Shemesh void (*version_cb)(const char *version_name, 14ec4a0ce9SMoshe Shemesh enum devlink_info_version_type version_type, 15ec4a0ce9SMoshe Shemesh void *version_cb_priv); 16ec4a0ce9SMoshe Shemesh void *version_cb_priv; 17ec4a0ce9SMoshe Shemesh }; 18ec4a0ce9SMoshe Shemesh 19c6ed7d6eSMoshe Shemesh struct devlink_reload_combination { 20c6ed7d6eSMoshe Shemesh enum devlink_reload_action action; 21c6ed7d6eSMoshe Shemesh enum devlink_reload_limit limit; 22c6ed7d6eSMoshe Shemesh }; 23c6ed7d6eSMoshe Shemesh 24c6ed7d6eSMoshe Shemesh static const struct devlink_reload_combination devlink_reload_invalid_combinations[] = { 25c6ed7d6eSMoshe Shemesh { 26c6ed7d6eSMoshe Shemesh /* can't reinitialize driver with no down time */ 27c6ed7d6eSMoshe Shemesh .action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT, 28c6ed7d6eSMoshe Shemesh .limit = DEVLINK_RELOAD_LIMIT_NO_RESET, 29c6ed7d6eSMoshe Shemesh }, 30c6ed7d6eSMoshe Shemesh }; 31c6ed7d6eSMoshe Shemesh 32c6ed7d6eSMoshe Shemesh static bool 33c6ed7d6eSMoshe Shemesh devlink_reload_combination_is_invalid(enum devlink_reload_action action, 34c6ed7d6eSMoshe Shemesh enum devlink_reload_limit limit) 35c6ed7d6eSMoshe Shemesh { 36c6ed7d6eSMoshe Shemesh int i; 37c6ed7d6eSMoshe Shemesh 38c6ed7d6eSMoshe Shemesh for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++) 39c6ed7d6eSMoshe Shemesh if (devlink_reload_invalid_combinations[i].action == action && 40c6ed7d6eSMoshe Shemesh devlink_reload_invalid_combinations[i].limit == limit) 41c6ed7d6eSMoshe Shemesh return true; 42c6ed7d6eSMoshe Shemesh return false; 43c6ed7d6eSMoshe Shemesh } 44c6ed7d6eSMoshe Shemesh 45c6ed7d6eSMoshe Shemesh static bool 46c6ed7d6eSMoshe Shemesh devlink_reload_action_is_supported(struct devlink *devlink, enum devlink_reload_action action) 47c6ed7d6eSMoshe Shemesh { 48c6ed7d6eSMoshe Shemesh return test_bit(action, &devlink->ops->reload_actions); 49c6ed7d6eSMoshe Shemesh } 50c6ed7d6eSMoshe Shemesh 51c6ed7d6eSMoshe Shemesh static bool 52c6ed7d6eSMoshe Shemesh devlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_limit limit) 53c6ed7d6eSMoshe Shemesh { 54c6ed7d6eSMoshe Shemesh return test_bit(limit, &devlink->ops->reload_limits); 55c6ed7d6eSMoshe Shemesh } 56c6ed7d6eSMoshe Shemesh 57c6ed7d6eSMoshe Shemesh static int devlink_reload_stat_put(struct sk_buff *msg, 58c6ed7d6eSMoshe Shemesh enum devlink_reload_limit limit, u32 value) 59c6ed7d6eSMoshe Shemesh { 60c6ed7d6eSMoshe Shemesh struct nlattr *reload_stats_entry; 61c6ed7d6eSMoshe Shemesh 62c6ed7d6eSMoshe Shemesh reload_stats_entry = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS_ENTRY); 63c6ed7d6eSMoshe Shemesh if (!reload_stats_entry) 64c6ed7d6eSMoshe Shemesh return -EMSGSIZE; 65c6ed7d6eSMoshe Shemesh 66c6ed7d6eSMoshe Shemesh if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_STATS_LIMIT, limit) || 67c6ed7d6eSMoshe Shemesh nla_put_u32(msg, DEVLINK_ATTR_RELOAD_STATS_VALUE, value)) 68c6ed7d6eSMoshe Shemesh goto nla_put_failure; 69c6ed7d6eSMoshe Shemesh nla_nest_end(msg, reload_stats_entry); 70c6ed7d6eSMoshe Shemesh return 0; 71c6ed7d6eSMoshe Shemesh 72c6ed7d6eSMoshe Shemesh nla_put_failure: 73c6ed7d6eSMoshe Shemesh nla_nest_cancel(msg, reload_stats_entry); 74c6ed7d6eSMoshe Shemesh return -EMSGSIZE; 75c6ed7d6eSMoshe Shemesh } 76c6ed7d6eSMoshe Shemesh 77c6ed7d6eSMoshe Shemesh static int 78c6ed7d6eSMoshe Shemesh devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink, bool is_remote) 79c6ed7d6eSMoshe Shemesh { 80c6ed7d6eSMoshe Shemesh struct nlattr *reload_stats_attr, *act_info, *act_stats; 81c6ed7d6eSMoshe Shemesh int i, j, stat_idx; 82c6ed7d6eSMoshe Shemesh u32 value; 83c6ed7d6eSMoshe Shemesh 84c6ed7d6eSMoshe Shemesh if (!is_remote) 85c6ed7d6eSMoshe Shemesh reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS); 86c6ed7d6eSMoshe Shemesh else 87c6ed7d6eSMoshe Shemesh reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_REMOTE_RELOAD_STATS); 88c6ed7d6eSMoshe Shemesh 89c6ed7d6eSMoshe Shemesh if (!reload_stats_attr) 90c6ed7d6eSMoshe Shemesh return -EMSGSIZE; 91c6ed7d6eSMoshe Shemesh 92c6ed7d6eSMoshe Shemesh for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) { 93c6ed7d6eSMoshe Shemesh if ((!is_remote && 94c6ed7d6eSMoshe Shemesh !devlink_reload_action_is_supported(devlink, i)) || 95c6ed7d6eSMoshe Shemesh i == DEVLINK_RELOAD_ACTION_UNSPEC) 96c6ed7d6eSMoshe Shemesh continue; 97c6ed7d6eSMoshe Shemesh act_info = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_INFO); 98c6ed7d6eSMoshe Shemesh if (!act_info) 99c6ed7d6eSMoshe Shemesh goto nla_put_failure; 100c6ed7d6eSMoshe Shemesh 101c6ed7d6eSMoshe Shemesh if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, i)) 102c6ed7d6eSMoshe Shemesh goto action_info_nest_cancel; 103c6ed7d6eSMoshe Shemesh act_stats = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_STATS); 104c6ed7d6eSMoshe Shemesh if (!act_stats) 105c6ed7d6eSMoshe Shemesh goto action_info_nest_cancel; 106c6ed7d6eSMoshe Shemesh 107c6ed7d6eSMoshe Shemesh for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) { 108c6ed7d6eSMoshe Shemesh /* Remote stats are shown even if not locally supported. 109c6ed7d6eSMoshe Shemesh * Stats of actions with unspecified limit are shown 110c6ed7d6eSMoshe Shemesh * though drivers don't need to register unspecified 111c6ed7d6eSMoshe Shemesh * limit. 112c6ed7d6eSMoshe Shemesh */ 113c6ed7d6eSMoshe Shemesh if ((!is_remote && j != DEVLINK_RELOAD_LIMIT_UNSPEC && 114c6ed7d6eSMoshe Shemesh !devlink_reload_limit_is_supported(devlink, j)) || 115c6ed7d6eSMoshe Shemesh devlink_reload_combination_is_invalid(i, j)) 116c6ed7d6eSMoshe Shemesh continue; 117c6ed7d6eSMoshe Shemesh 118c6ed7d6eSMoshe Shemesh stat_idx = j * __DEVLINK_RELOAD_ACTION_MAX + i; 119c6ed7d6eSMoshe Shemesh if (!is_remote) 120c6ed7d6eSMoshe Shemesh value = devlink->stats.reload_stats[stat_idx]; 121c6ed7d6eSMoshe Shemesh else 122c6ed7d6eSMoshe Shemesh value = devlink->stats.remote_reload_stats[stat_idx]; 123c6ed7d6eSMoshe Shemesh if (devlink_reload_stat_put(msg, j, value)) 124c6ed7d6eSMoshe Shemesh goto action_stats_nest_cancel; 125c6ed7d6eSMoshe Shemesh } 126c6ed7d6eSMoshe Shemesh nla_nest_end(msg, act_stats); 127c6ed7d6eSMoshe Shemesh nla_nest_end(msg, act_info); 128c6ed7d6eSMoshe Shemesh } 129c6ed7d6eSMoshe Shemesh nla_nest_end(msg, reload_stats_attr); 130c6ed7d6eSMoshe Shemesh return 0; 131c6ed7d6eSMoshe Shemesh 132c6ed7d6eSMoshe Shemesh action_stats_nest_cancel: 133c6ed7d6eSMoshe Shemesh nla_nest_cancel(msg, act_stats); 134c6ed7d6eSMoshe Shemesh action_info_nest_cancel: 135c6ed7d6eSMoshe Shemesh nla_nest_cancel(msg, act_info); 136c6ed7d6eSMoshe Shemesh nla_put_failure: 137c6ed7d6eSMoshe Shemesh nla_nest_cancel(msg, reload_stats_attr); 138c6ed7d6eSMoshe Shemesh return -EMSGSIZE; 139c6ed7d6eSMoshe Shemesh } 140c6ed7d6eSMoshe Shemesh 141*c5e1bf8aSJiri Pirko static int devlink_nl_nested_fill(struct sk_buff *msg, struct devlink *devlink) 142*c5e1bf8aSJiri Pirko { 143*c5e1bf8aSJiri Pirko unsigned long rel_index; 144*c5e1bf8aSJiri Pirko void *unused; 145*c5e1bf8aSJiri Pirko int err; 146*c5e1bf8aSJiri Pirko 147*c5e1bf8aSJiri Pirko xa_for_each(&devlink->nested_rels, rel_index, unused) { 148*c5e1bf8aSJiri Pirko err = devlink_rel_devlink_handle_put(msg, devlink, 149*c5e1bf8aSJiri Pirko rel_index, 150*c5e1bf8aSJiri Pirko DEVLINK_ATTR_NESTED_DEVLINK, 151*c5e1bf8aSJiri Pirko NULL); 152*c5e1bf8aSJiri Pirko if (err) 153*c5e1bf8aSJiri Pirko return err; 154*c5e1bf8aSJiri Pirko } 155*c5e1bf8aSJiri Pirko return 0; 156*c5e1bf8aSJiri Pirko } 157*c5e1bf8aSJiri Pirko 158dbeeca81SMoshe Shemesh static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink, 159dbeeca81SMoshe Shemesh enum devlink_command cmd, u32 portid, 160dbeeca81SMoshe Shemesh u32 seq, int flags) 161dbeeca81SMoshe Shemesh { 162dbeeca81SMoshe Shemesh struct nlattr *dev_stats; 163dbeeca81SMoshe Shemesh void *hdr; 164dbeeca81SMoshe Shemesh 165dbeeca81SMoshe Shemesh hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 166dbeeca81SMoshe Shemesh if (!hdr) 167dbeeca81SMoshe Shemesh return -EMSGSIZE; 168dbeeca81SMoshe Shemesh 169dbeeca81SMoshe Shemesh if (devlink_nl_put_handle(msg, devlink)) 170dbeeca81SMoshe Shemesh goto nla_put_failure; 171dbeeca81SMoshe Shemesh if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed)) 172dbeeca81SMoshe Shemesh goto nla_put_failure; 173dbeeca81SMoshe Shemesh 174dbeeca81SMoshe Shemesh dev_stats = nla_nest_start(msg, DEVLINK_ATTR_DEV_STATS); 175dbeeca81SMoshe Shemesh if (!dev_stats) 176dbeeca81SMoshe Shemesh goto nla_put_failure; 177dbeeca81SMoshe Shemesh 178dbeeca81SMoshe Shemesh if (devlink_reload_stats_put(msg, devlink, false)) 179dbeeca81SMoshe Shemesh goto dev_stats_nest_cancel; 180dbeeca81SMoshe Shemesh if (devlink_reload_stats_put(msg, devlink, true)) 181dbeeca81SMoshe Shemesh goto dev_stats_nest_cancel; 182dbeeca81SMoshe Shemesh 183dbeeca81SMoshe Shemesh nla_nest_end(msg, dev_stats); 184*c5e1bf8aSJiri Pirko 185*c5e1bf8aSJiri Pirko if (devlink_nl_nested_fill(msg, devlink)) 186*c5e1bf8aSJiri Pirko goto nla_put_failure; 187*c5e1bf8aSJiri Pirko 188dbeeca81SMoshe Shemesh genlmsg_end(msg, hdr); 189dbeeca81SMoshe Shemesh return 0; 190dbeeca81SMoshe Shemesh 191dbeeca81SMoshe Shemesh dev_stats_nest_cancel: 192dbeeca81SMoshe Shemesh nla_nest_cancel(msg, dev_stats); 193dbeeca81SMoshe Shemesh nla_put_failure: 194dbeeca81SMoshe Shemesh genlmsg_cancel(msg, hdr); 195dbeeca81SMoshe Shemesh return -EMSGSIZE; 196dbeeca81SMoshe Shemesh } 197dbeeca81SMoshe Shemesh 19871179ac5SJiri Pirko static void devlink_notify(struct devlink *devlink, enum devlink_command cmd) 199dbeeca81SMoshe Shemesh { 200dbeeca81SMoshe Shemesh struct sk_buff *msg; 201dbeeca81SMoshe Shemesh int err; 202dbeeca81SMoshe Shemesh 203dbeeca81SMoshe Shemesh WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL); 204dbeeca81SMoshe Shemesh WARN_ON(!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED)); 205dbeeca81SMoshe Shemesh 206dbeeca81SMoshe Shemesh msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 207dbeeca81SMoshe Shemesh if (!msg) 208dbeeca81SMoshe Shemesh return; 209dbeeca81SMoshe Shemesh 210dbeeca81SMoshe Shemesh err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0); 211dbeeca81SMoshe Shemesh if (err) { 212dbeeca81SMoshe Shemesh nlmsg_free(msg); 213dbeeca81SMoshe Shemesh return; 214dbeeca81SMoshe Shemesh } 215dbeeca81SMoshe Shemesh 216dbeeca81SMoshe Shemesh genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 217dbeeca81SMoshe Shemesh msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 218dbeeca81SMoshe Shemesh } 219dbeeca81SMoshe Shemesh 220d61aedcfSJiri Pirko int devlink_nl_get_doit(struct sk_buff *skb, struct genl_info *info) 221dbeeca81SMoshe Shemesh { 222dbeeca81SMoshe Shemesh struct devlink *devlink = info->user_ptr[0]; 223dbeeca81SMoshe Shemesh struct sk_buff *msg; 224dbeeca81SMoshe Shemesh int err; 225dbeeca81SMoshe Shemesh 226dbeeca81SMoshe Shemesh msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 227dbeeca81SMoshe Shemesh if (!msg) 228dbeeca81SMoshe Shemesh return -ENOMEM; 229dbeeca81SMoshe Shemesh 230dbeeca81SMoshe Shemesh err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW, 231dbeeca81SMoshe Shemesh info->snd_portid, info->snd_seq, 0); 232dbeeca81SMoshe Shemesh if (err) { 233dbeeca81SMoshe Shemesh nlmsg_free(msg); 234dbeeca81SMoshe Shemesh return err; 235dbeeca81SMoshe Shemesh } 236dbeeca81SMoshe Shemesh 237dbeeca81SMoshe Shemesh return genlmsg_reply(msg, info); 238dbeeca81SMoshe Shemesh } 239dbeeca81SMoshe Shemesh 240dbeeca81SMoshe Shemesh static int 241491a2487SJiri Pirko devlink_nl_get_dump_one(struct sk_buff *msg, struct devlink *devlink, 2427d3c6fecSJiri Pirko struct netlink_callback *cb, int flags) 243dbeeca81SMoshe Shemesh { 244dbeeca81SMoshe Shemesh return devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW, 245dbeeca81SMoshe Shemesh NETLINK_CB(cb->skb).portid, 2467d3c6fecSJiri Pirko cb->nlh->nlmsg_seq, flags); 247dbeeca81SMoshe Shemesh } 248dbeeca81SMoshe Shemesh 249491a2487SJiri Pirko int devlink_nl_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb) 250491a2487SJiri Pirko { 251491a2487SJiri Pirko return devlink_nl_dumpit(msg, cb, devlink_nl_get_dump_one); 252491a2487SJiri Pirko } 253c6ed7d6eSMoshe Shemesh 254*c5e1bf8aSJiri Pirko static void devlink_rel_notify_cb(struct devlink *devlink, u32 obj_index) 255*c5e1bf8aSJiri Pirko { 256*c5e1bf8aSJiri Pirko devlink_notify(devlink, DEVLINK_CMD_NEW); 257*c5e1bf8aSJiri Pirko } 258*c5e1bf8aSJiri Pirko 259*c5e1bf8aSJiri Pirko static void devlink_rel_cleanup_cb(struct devlink *devlink, u32 obj_index, 260*c5e1bf8aSJiri Pirko u32 rel_index) 261*c5e1bf8aSJiri Pirko { 262*c5e1bf8aSJiri Pirko xa_erase(&devlink->nested_rels, rel_index); 263*c5e1bf8aSJiri Pirko } 264*c5e1bf8aSJiri Pirko 265*c5e1bf8aSJiri Pirko int devl_nested_devlink_set(struct devlink *devlink, 266*c5e1bf8aSJiri Pirko struct devlink *nested_devlink) 267*c5e1bf8aSJiri Pirko { 268*c5e1bf8aSJiri Pirko u32 rel_index; 269*c5e1bf8aSJiri Pirko int err; 270*c5e1bf8aSJiri Pirko 271*c5e1bf8aSJiri Pirko err = devlink_rel_nested_in_add(&rel_index, devlink->index, 0, 272*c5e1bf8aSJiri Pirko devlink_rel_notify_cb, 273*c5e1bf8aSJiri Pirko devlink_rel_cleanup_cb, 274*c5e1bf8aSJiri Pirko nested_devlink); 275*c5e1bf8aSJiri Pirko if (err) 276*c5e1bf8aSJiri Pirko return err; 277*c5e1bf8aSJiri Pirko return xa_insert(&devlink->nested_rels, rel_index, 278*c5e1bf8aSJiri Pirko xa_mk_value(0), GFP_KERNEL); 279*c5e1bf8aSJiri Pirko } 280*c5e1bf8aSJiri Pirko EXPORT_SYMBOL_GPL(devl_nested_devlink_set); 281*c5e1bf8aSJiri Pirko 28271179ac5SJiri Pirko void devlink_notify_register(struct devlink *devlink) 28371179ac5SJiri Pirko { 28471179ac5SJiri Pirko devlink_notify(devlink, DEVLINK_CMD_NEW); 28571179ac5SJiri Pirko devlink_linecards_notify_register(devlink); 28671179ac5SJiri Pirko devlink_ports_notify_register(devlink); 28771179ac5SJiri Pirko devlink_trap_policers_notify_register(devlink); 28871179ac5SJiri Pirko devlink_trap_groups_notify_register(devlink); 28971179ac5SJiri Pirko devlink_traps_notify_register(devlink); 29071179ac5SJiri Pirko devlink_rates_notify_register(devlink); 29171179ac5SJiri Pirko devlink_regions_notify_register(devlink); 29271179ac5SJiri Pirko devlink_params_notify_register(devlink); 29371179ac5SJiri Pirko } 29471179ac5SJiri Pirko 29571179ac5SJiri Pirko void devlink_notify_unregister(struct devlink *devlink) 29671179ac5SJiri Pirko { 29771179ac5SJiri Pirko devlink_params_notify_unregister(devlink); 29871179ac5SJiri Pirko devlink_regions_notify_unregister(devlink); 29971179ac5SJiri Pirko devlink_rates_notify_unregister(devlink); 30071179ac5SJiri Pirko devlink_traps_notify_unregister(devlink); 30171179ac5SJiri Pirko devlink_trap_groups_notify_unregister(devlink); 30271179ac5SJiri Pirko devlink_trap_policers_notify_unregister(devlink); 30371179ac5SJiri Pirko devlink_ports_notify_unregister(devlink); 30471179ac5SJiri Pirko devlink_linecards_notify_unregister(devlink); 30571179ac5SJiri Pirko devlink_notify(devlink, DEVLINK_CMD_DEL); 30671179ac5SJiri Pirko } 30771179ac5SJiri Pirko 308c6ed7d6eSMoshe Shemesh static void devlink_reload_failed_set(struct devlink *devlink, 309c6ed7d6eSMoshe Shemesh bool reload_failed) 310c6ed7d6eSMoshe Shemesh { 311c6ed7d6eSMoshe Shemesh if (devlink->reload_failed == reload_failed) 312c6ed7d6eSMoshe Shemesh return; 313c6ed7d6eSMoshe Shemesh devlink->reload_failed = reload_failed; 314c6ed7d6eSMoshe Shemesh devlink_notify(devlink, DEVLINK_CMD_NEW); 315c6ed7d6eSMoshe Shemesh } 316c6ed7d6eSMoshe Shemesh 317c6ed7d6eSMoshe Shemesh bool devlink_is_reload_failed(const struct devlink *devlink) 318c6ed7d6eSMoshe Shemesh { 319c6ed7d6eSMoshe Shemesh return devlink->reload_failed; 320c6ed7d6eSMoshe Shemesh } 321c6ed7d6eSMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_is_reload_failed); 322c6ed7d6eSMoshe Shemesh 323c6ed7d6eSMoshe Shemesh static void 324c6ed7d6eSMoshe Shemesh __devlink_reload_stats_update(struct devlink *devlink, u32 *reload_stats, 325c6ed7d6eSMoshe Shemesh enum devlink_reload_limit limit, u32 actions_performed) 326c6ed7d6eSMoshe Shemesh { 327c6ed7d6eSMoshe Shemesh unsigned long actions = actions_performed; 328c6ed7d6eSMoshe Shemesh int stat_idx; 329c6ed7d6eSMoshe Shemesh int action; 330c6ed7d6eSMoshe Shemesh 331c6ed7d6eSMoshe Shemesh for_each_set_bit(action, &actions, __DEVLINK_RELOAD_ACTION_MAX) { 332c6ed7d6eSMoshe Shemesh stat_idx = limit * __DEVLINK_RELOAD_ACTION_MAX + action; 333c6ed7d6eSMoshe Shemesh reload_stats[stat_idx]++; 334c6ed7d6eSMoshe Shemesh } 335c6ed7d6eSMoshe Shemesh devlink_notify(devlink, DEVLINK_CMD_NEW); 336c6ed7d6eSMoshe Shemesh } 337c6ed7d6eSMoshe Shemesh 338c6ed7d6eSMoshe Shemesh static void 339c6ed7d6eSMoshe Shemesh devlink_reload_stats_update(struct devlink *devlink, enum devlink_reload_limit limit, 340c6ed7d6eSMoshe Shemesh u32 actions_performed) 341c6ed7d6eSMoshe Shemesh { 342c6ed7d6eSMoshe Shemesh __devlink_reload_stats_update(devlink, devlink->stats.reload_stats, limit, 343c6ed7d6eSMoshe Shemesh actions_performed); 344c6ed7d6eSMoshe Shemesh } 345c6ed7d6eSMoshe Shemesh 346c6ed7d6eSMoshe Shemesh /** 347c6ed7d6eSMoshe Shemesh * devlink_remote_reload_actions_performed - Update devlink on reload actions 348c6ed7d6eSMoshe Shemesh * performed which are not a direct result of devlink reload call. 349c6ed7d6eSMoshe Shemesh * 350c6ed7d6eSMoshe Shemesh * This should be called by a driver after performing reload actions in case it was not 351c6ed7d6eSMoshe Shemesh * a result of devlink reload call. For example fw_activate was performed as a result 352c6ed7d6eSMoshe Shemesh * of devlink reload triggered fw_activate on another host. 353c6ed7d6eSMoshe Shemesh * The motivation for this function is to keep data on reload actions performed on this 354c6ed7d6eSMoshe Shemesh * function whether it was done due to direct devlink reload call or not. 355c6ed7d6eSMoshe Shemesh * 356c6ed7d6eSMoshe Shemesh * @devlink: devlink 357c6ed7d6eSMoshe Shemesh * @limit: reload limit 358c6ed7d6eSMoshe Shemesh * @actions_performed: bitmask of actions performed 359c6ed7d6eSMoshe Shemesh */ 360c6ed7d6eSMoshe Shemesh void devlink_remote_reload_actions_performed(struct devlink *devlink, 361c6ed7d6eSMoshe Shemesh enum devlink_reload_limit limit, 362c6ed7d6eSMoshe Shemesh u32 actions_performed) 363c6ed7d6eSMoshe Shemesh { 364c6ed7d6eSMoshe Shemesh if (WARN_ON(!actions_performed || 365c6ed7d6eSMoshe Shemesh actions_performed & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) || 366c6ed7d6eSMoshe Shemesh actions_performed >= BIT(__DEVLINK_RELOAD_ACTION_MAX) || 367c6ed7d6eSMoshe Shemesh limit > DEVLINK_RELOAD_LIMIT_MAX)) 368c6ed7d6eSMoshe Shemesh return; 369c6ed7d6eSMoshe Shemesh 370c6ed7d6eSMoshe Shemesh __devlink_reload_stats_update(devlink, devlink->stats.remote_reload_stats, limit, 371c6ed7d6eSMoshe Shemesh actions_performed); 372c6ed7d6eSMoshe Shemesh } 373c6ed7d6eSMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_remote_reload_actions_performed); 374c6ed7d6eSMoshe Shemesh 375c6ed7d6eSMoshe Shemesh static struct net *devlink_netns_get(struct sk_buff *skb, 376c6ed7d6eSMoshe Shemesh struct genl_info *info) 377c6ed7d6eSMoshe Shemesh { 378c6ed7d6eSMoshe Shemesh struct nlattr *netns_pid_attr = info->attrs[DEVLINK_ATTR_NETNS_PID]; 379c6ed7d6eSMoshe Shemesh struct nlattr *netns_fd_attr = info->attrs[DEVLINK_ATTR_NETNS_FD]; 380c6ed7d6eSMoshe Shemesh struct nlattr *netns_id_attr = info->attrs[DEVLINK_ATTR_NETNS_ID]; 381c6ed7d6eSMoshe Shemesh struct net *net; 382c6ed7d6eSMoshe Shemesh 383c6ed7d6eSMoshe Shemesh if (!!netns_pid_attr + !!netns_fd_attr + !!netns_id_attr > 1) { 3846d86bb0aSJacob Keller NL_SET_ERR_MSG(info->extack, "multiple netns identifying attributes specified"); 385c6ed7d6eSMoshe Shemesh return ERR_PTR(-EINVAL); 386c6ed7d6eSMoshe Shemesh } 387c6ed7d6eSMoshe Shemesh 388c6ed7d6eSMoshe Shemesh if (netns_pid_attr) { 389c6ed7d6eSMoshe Shemesh net = get_net_ns_by_pid(nla_get_u32(netns_pid_attr)); 390c6ed7d6eSMoshe Shemesh } else if (netns_fd_attr) { 391c6ed7d6eSMoshe Shemesh net = get_net_ns_by_fd(nla_get_u32(netns_fd_attr)); 392c6ed7d6eSMoshe Shemesh } else if (netns_id_attr) { 393c6ed7d6eSMoshe Shemesh net = get_net_ns_by_id(sock_net(skb->sk), 394c6ed7d6eSMoshe Shemesh nla_get_u32(netns_id_attr)); 395c6ed7d6eSMoshe Shemesh if (!net) 396c6ed7d6eSMoshe Shemesh net = ERR_PTR(-EINVAL); 397c6ed7d6eSMoshe Shemesh } else { 398c6ed7d6eSMoshe Shemesh WARN_ON(1); 399c6ed7d6eSMoshe Shemesh net = ERR_PTR(-EINVAL); 400c6ed7d6eSMoshe Shemesh } 401c6ed7d6eSMoshe Shemesh if (IS_ERR(net)) { 4026d86bb0aSJacob Keller NL_SET_ERR_MSG(info->extack, "Unknown network namespace"); 403c6ed7d6eSMoshe Shemesh return ERR_PTR(-EINVAL); 404c6ed7d6eSMoshe Shemesh } 405c6ed7d6eSMoshe Shemesh if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { 406c6ed7d6eSMoshe Shemesh put_net(net); 407c6ed7d6eSMoshe Shemesh return ERR_PTR(-EPERM); 408c6ed7d6eSMoshe Shemesh } 409c6ed7d6eSMoshe Shemesh return net; 410c6ed7d6eSMoshe Shemesh } 411c6ed7d6eSMoshe Shemesh 412c6ed7d6eSMoshe Shemesh static void devlink_reload_netns_change(struct devlink *devlink, 413c6ed7d6eSMoshe Shemesh struct net *curr_net, 414c6ed7d6eSMoshe Shemesh struct net *dest_net) 415c6ed7d6eSMoshe Shemesh { 416c6ed7d6eSMoshe Shemesh /* Userspace needs to be notified about devlink objects 417c6ed7d6eSMoshe Shemesh * removed from original and entering new network namespace. 418c6ed7d6eSMoshe Shemesh * The rest of the devlink objects are re-created during 419c6ed7d6eSMoshe Shemesh * reload process so the notifications are generated separatelly. 420c6ed7d6eSMoshe Shemesh */ 421c6ed7d6eSMoshe Shemesh devlink_notify_unregister(devlink); 422c6ed7d6eSMoshe Shemesh write_pnet(&devlink->_net, dest_net); 423c6ed7d6eSMoshe Shemesh devlink_notify_register(devlink); 424c137743bSJiri Pirko devlink_rel_nested_in_notify(devlink); 425c6ed7d6eSMoshe Shemesh } 426c6ed7d6eSMoshe Shemesh 427c6ed7d6eSMoshe Shemesh int devlink_reload(struct devlink *devlink, struct net *dest_net, 428c6ed7d6eSMoshe Shemesh enum devlink_reload_action action, 429c6ed7d6eSMoshe Shemesh enum devlink_reload_limit limit, 430c6ed7d6eSMoshe Shemesh u32 *actions_performed, struct netlink_ext_ack *extack) 431c6ed7d6eSMoshe Shemesh { 432c6ed7d6eSMoshe Shemesh u32 remote_reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE]; 433c6ed7d6eSMoshe Shemesh struct net *curr_net; 434c6ed7d6eSMoshe Shemesh int err; 435c6ed7d6eSMoshe Shemesh 436c6ed7d6eSMoshe Shemesh memcpy(remote_reload_stats, devlink->stats.remote_reload_stats, 437c6ed7d6eSMoshe Shemesh sizeof(remote_reload_stats)); 438c6ed7d6eSMoshe Shemesh 439c6ed7d6eSMoshe Shemesh err = devlink->ops->reload_down(devlink, !!dest_net, action, limit, extack); 440c6ed7d6eSMoshe Shemesh if (err) 441c6ed7d6eSMoshe Shemesh return err; 442c6ed7d6eSMoshe Shemesh 443c6ed7d6eSMoshe Shemesh curr_net = devlink_net(devlink); 444c6ed7d6eSMoshe Shemesh if (dest_net && !net_eq(dest_net, curr_net)) 445c6ed7d6eSMoshe Shemesh devlink_reload_netns_change(devlink, curr_net, dest_net); 446c6ed7d6eSMoshe Shemesh 447afd888c3SJiri Pirko if (action == DEVLINK_RELOAD_ACTION_DRIVER_REINIT) 448afd888c3SJiri Pirko devlink_params_driverinit_load_new(devlink); 449afd888c3SJiri Pirko 450c6ed7d6eSMoshe Shemesh err = devlink->ops->reload_up(devlink, action, limit, actions_performed, extack); 451c6ed7d6eSMoshe Shemesh devlink_reload_failed_set(devlink, !!err); 452c6ed7d6eSMoshe Shemesh if (err) 453c6ed7d6eSMoshe Shemesh return err; 454c6ed7d6eSMoshe Shemesh 455c6ed7d6eSMoshe Shemesh WARN_ON(!(*actions_performed & BIT(action))); 456c6ed7d6eSMoshe Shemesh /* Catch driver on updating the remote action within devlink reload */ 457c6ed7d6eSMoshe Shemesh WARN_ON(memcmp(remote_reload_stats, devlink->stats.remote_reload_stats, 458c6ed7d6eSMoshe Shemesh sizeof(remote_reload_stats))); 459c6ed7d6eSMoshe Shemesh devlink_reload_stats_update(devlink, limit, *actions_performed); 460c6ed7d6eSMoshe Shemesh return 0; 461c6ed7d6eSMoshe Shemesh } 462c6ed7d6eSMoshe Shemesh 463c6ed7d6eSMoshe Shemesh static int 464c6ed7d6eSMoshe Shemesh devlink_nl_reload_actions_performed_snd(struct devlink *devlink, u32 actions_performed, 465c6ed7d6eSMoshe Shemesh enum devlink_command cmd, struct genl_info *info) 466c6ed7d6eSMoshe Shemesh { 467c6ed7d6eSMoshe Shemesh struct sk_buff *msg; 468c6ed7d6eSMoshe Shemesh void *hdr; 469c6ed7d6eSMoshe Shemesh 470c6ed7d6eSMoshe Shemesh msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 471c6ed7d6eSMoshe Shemesh if (!msg) 472c6ed7d6eSMoshe Shemesh return -ENOMEM; 473c6ed7d6eSMoshe Shemesh 474c6ed7d6eSMoshe Shemesh hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &devlink_nl_family, 0, cmd); 475c6ed7d6eSMoshe Shemesh if (!hdr) 476c6ed7d6eSMoshe Shemesh goto free_msg; 477c6ed7d6eSMoshe Shemesh 478c6ed7d6eSMoshe Shemesh if (devlink_nl_put_handle(msg, devlink)) 479c6ed7d6eSMoshe Shemesh goto nla_put_failure; 480c6ed7d6eSMoshe Shemesh 481c6ed7d6eSMoshe Shemesh if (nla_put_bitfield32(msg, DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED, actions_performed, 482c6ed7d6eSMoshe Shemesh actions_performed)) 483c6ed7d6eSMoshe Shemesh goto nla_put_failure; 484c6ed7d6eSMoshe Shemesh genlmsg_end(msg, hdr); 485c6ed7d6eSMoshe Shemesh 486c6ed7d6eSMoshe Shemesh return genlmsg_reply(msg, info); 487c6ed7d6eSMoshe Shemesh 488c6ed7d6eSMoshe Shemesh nla_put_failure: 489c6ed7d6eSMoshe Shemesh genlmsg_cancel(msg, hdr); 490c6ed7d6eSMoshe Shemesh free_msg: 491c6ed7d6eSMoshe Shemesh nlmsg_free(msg); 492c6ed7d6eSMoshe Shemesh return -EMSGSIZE; 493c6ed7d6eSMoshe Shemesh } 494c6ed7d6eSMoshe Shemesh 495c6ed7d6eSMoshe Shemesh int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info) 496c6ed7d6eSMoshe Shemesh { 497c6ed7d6eSMoshe Shemesh struct devlink *devlink = info->user_ptr[0]; 498c6ed7d6eSMoshe Shemesh enum devlink_reload_action action; 499c6ed7d6eSMoshe Shemesh enum devlink_reload_limit limit; 500c6ed7d6eSMoshe Shemesh struct net *dest_net = NULL; 501c6ed7d6eSMoshe Shemesh u32 actions_performed; 502c6ed7d6eSMoshe Shemesh int err; 503c6ed7d6eSMoshe Shemesh 504c6ed7d6eSMoshe Shemesh err = devlink_resources_validate(devlink, NULL, info); 505c6ed7d6eSMoshe Shemesh if (err) { 5066d86bb0aSJacob Keller NL_SET_ERR_MSG(info->extack, "resources size validation failed"); 507c6ed7d6eSMoshe Shemesh return err; 508c6ed7d6eSMoshe Shemesh } 509c6ed7d6eSMoshe Shemesh 510c6ed7d6eSMoshe Shemesh if (info->attrs[DEVLINK_ATTR_RELOAD_ACTION]) 511c6ed7d6eSMoshe Shemesh action = nla_get_u8(info->attrs[DEVLINK_ATTR_RELOAD_ACTION]); 512c6ed7d6eSMoshe Shemesh else 513c6ed7d6eSMoshe Shemesh action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT; 514c6ed7d6eSMoshe Shemesh 515c6ed7d6eSMoshe Shemesh if (!devlink_reload_action_is_supported(devlink, action)) { 5166d86bb0aSJacob Keller NL_SET_ERR_MSG(info->extack, "Requested reload action is not supported by the driver"); 517c6ed7d6eSMoshe Shemesh return -EOPNOTSUPP; 518c6ed7d6eSMoshe Shemesh } 519c6ed7d6eSMoshe Shemesh 520c6ed7d6eSMoshe Shemesh limit = DEVLINK_RELOAD_LIMIT_UNSPEC; 521c6ed7d6eSMoshe Shemesh if (info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]) { 522c6ed7d6eSMoshe Shemesh struct nla_bitfield32 limits; 523c6ed7d6eSMoshe Shemesh u32 limits_selected; 524c6ed7d6eSMoshe Shemesh 525c6ed7d6eSMoshe Shemesh limits = nla_get_bitfield32(info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]); 526c6ed7d6eSMoshe Shemesh limits_selected = limits.value & limits.selector; 527c6ed7d6eSMoshe Shemesh if (!limits_selected) { 5286d86bb0aSJacob Keller NL_SET_ERR_MSG(info->extack, "Invalid limit selected"); 529c6ed7d6eSMoshe Shemesh return -EINVAL; 530c6ed7d6eSMoshe Shemesh } 531c6ed7d6eSMoshe Shemesh for (limit = 0 ; limit <= DEVLINK_RELOAD_LIMIT_MAX ; limit++) 532c6ed7d6eSMoshe Shemesh if (limits_selected & BIT(limit)) 533c6ed7d6eSMoshe Shemesh break; 534c6ed7d6eSMoshe Shemesh /* UAPI enables multiselection, but currently it is not used */ 535c6ed7d6eSMoshe Shemesh if (limits_selected != BIT(limit)) { 5366d86bb0aSJacob Keller NL_SET_ERR_MSG(info->extack, "Multiselection of limit is not supported"); 537c6ed7d6eSMoshe Shemesh return -EOPNOTSUPP; 538c6ed7d6eSMoshe Shemesh } 539c6ed7d6eSMoshe Shemesh if (!devlink_reload_limit_is_supported(devlink, limit)) { 5406d86bb0aSJacob Keller NL_SET_ERR_MSG(info->extack, "Requested limit is not supported by the driver"); 541c6ed7d6eSMoshe Shemesh return -EOPNOTSUPP; 542c6ed7d6eSMoshe Shemesh } 543c6ed7d6eSMoshe Shemesh if (devlink_reload_combination_is_invalid(action, limit)) { 5446d86bb0aSJacob Keller NL_SET_ERR_MSG(info->extack, "Requested limit is invalid for this action"); 545c6ed7d6eSMoshe Shemesh return -EINVAL; 546c6ed7d6eSMoshe Shemesh } 547c6ed7d6eSMoshe Shemesh } 548c6ed7d6eSMoshe Shemesh if (info->attrs[DEVLINK_ATTR_NETNS_PID] || 549c6ed7d6eSMoshe Shemesh info->attrs[DEVLINK_ATTR_NETNS_FD] || 550c6ed7d6eSMoshe Shemesh info->attrs[DEVLINK_ATTR_NETNS_ID]) { 551c6ed7d6eSMoshe Shemesh dest_net = devlink_netns_get(skb, info); 552c6ed7d6eSMoshe Shemesh if (IS_ERR(dest_net)) 553c6ed7d6eSMoshe Shemesh return PTR_ERR(dest_net); 5542edd9257SJiri Pirko if (!net_eq(dest_net, devlink_net(devlink)) && 5552edd9257SJiri Pirko action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) { 5562edd9257SJiri Pirko NL_SET_ERR_MSG_MOD(info->extack, 5572edd9257SJiri Pirko "Changing namespace is only supported for reinit action"); 5582edd9257SJiri Pirko return -EOPNOTSUPP; 5592edd9257SJiri Pirko } 560c6ed7d6eSMoshe Shemesh } 561c6ed7d6eSMoshe Shemesh 562c6ed7d6eSMoshe Shemesh err = devlink_reload(devlink, dest_net, action, limit, &actions_performed, info->extack); 563c6ed7d6eSMoshe Shemesh 564c6ed7d6eSMoshe Shemesh if (dest_net) 565c6ed7d6eSMoshe Shemesh put_net(dest_net); 566c6ed7d6eSMoshe Shemesh 567c6ed7d6eSMoshe Shemesh if (err) 568c6ed7d6eSMoshe Shemesh return err; 569c6ed7d6eSMoshe Shemesh /* For backward compatibility generate reply only if attributes used by user */ 570c6ed7d6eSMoshe Shemesh if (!info->attrs[DEVLINK_ATTR_RELOAD_ACTION] && !info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]) 571c6ed7d6eSMoshe Shemesh return 0; 572c6ed7d6eSMoshe Shemesh 573c6ed7d6eSMoshe Shemesh return devlink_nl_reload_actions_performed_snd(devlink, actions_performed, 574c6ed7d6eSMoshe Shemesh DEVLINK_CMD_RELOAD, info); 575c6ed7d6eSMoshe Shemesh } 576c6ed7d6eSMoshe Shemesh 577c6ed7d6eSMoshe Shemesh bool devlink_reload_actions_valid(const struct devlink_ops *ops) 578c6ed7d6eSMoshe Shemesh { 579c6ed7d6eSMoshe Shemesh const struct devlink_reload_combination *comb; 580c6ed7d6eSMoshe Shemesh int i; 581c6ed7d6eSMoshe Shemesh 582c6ed7d6eSMoshe Shemesh if (!devlink_reload_supported(ops)) { 583c6ed7d6eSMoshe Shemesh if (WARN_ON(ops->reload_actions)) 584c6ed7d6eSMoshe Shemesh return false; 585c6ed7d6eSMoshe Shemesh return true; 586c6ed7d6eSMoshe Shemesh } 587c6ed7d6eSMoshe Shemesh 588c6ed7d6eSMoshe Shemesh if (WARN_ON(!ops->reload_actions || 589c6ed7d6eSMoshe Shemesh ops->reload_actions & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) || 590c6ed7d6eSMoshe Shemesh ops->reload_actions >= BIT(__DEVLINK_RELOAD_ACTION_MAX))) 591c6ed7d6eSMoshe Shemesh return false; 592c6ed7d6eSMoshe Shemesh 593c6ed7d6eSMoshe Shemesh if (WARN_ON(ops->reload_limits & BIT(DEVLINK_RELOAD_LIMIT_UNSPEC) || 594c6ed7d6eSMoshe Shemesh ops->reload_limits >= BIT(__DEVLINK_RELOAD_LIMIT_MAX))) 595c6ed7d6eSMoshe Shemesh return false; 596c6ed7d6eSMoshe Shemesh 597c6ed7d6eSMoshe Shemesh for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++) { 598c6ed7d6eSMoshe Shemesh comb = &devlink_reload_invalid_combinations[i]; 599c6ed7d6eSMoshe Shemesh if (ops->reload_actions == BIT(comb->action) && 600c6ed7d6eSMoshe Shemesh ops->reload_limits == BIT(comb->limit)) 601c6ed7d6eSMoshe Shemesh return false; 602c6ed7d6eSMoshe Shemesh } 603c6ed7d6eSMoshe Shemesh return true; 604c6ed7d6eSMoshe Shemesh } 605af2f8c1fSMoshe Shemesh 606af2f8c1fSMoshe Shemesh static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink, 607af2f8c1fSMoshe Shemesh enum devlink_command cmd, u32 portid, 608af2f8c1fSMoshe Shemesh u32 seq, int flags) 609af2f8c1fSMoshe Shemesh { 610af2f8c1fSMoshe Shemesh const struct devlink_ops *ops = devlink->ops; 611af2f8c1fSMoshe Shemesh enum devlink_eswitch_encap_mode encap_mode; 612af2f8c1fSMoshe Shemesh u8 inline_mode; 613af2f8c1fSMoshe Shemesh void *hdr; 614af2f8c1fSMoshe Shemesh int err = 0; 615af2f8c1fSMoshe Shemesh u16 mode; 616af2f8c1fSMoshe Shemesh 617af2f8c1fSMoshe Shemesh hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 618af2f8c1fSMoshe Shemesh if (!hdr) 619af2f8c1fSMoshe Shemesh return -EMSGSIZE; 620af2f8c1fSMoshe Shemesh 621af2f8c1fSMoshe Shemesh err = devlink_nl_put_handle(msg, devlink); 622af2f8c1fSMoshe Shemesh if (err) 623af2f8c1fSMoshe Shemesh goto nla_put_failure; 624af2f8c1fSMoshe Shemesh 625af2f8c1fSMoshe Shemesh if (ops->eswitch_mode_get) { 626af2f8c1fSMoshe Shemesh err = ops->eswitch_mode_get(devlink, &mode); 627af2f8c1fSMoshe Shemesh if (err) 628af2f8c1fSMoshe Shemesh goto nla_put_failure; 629af2f8c1fSMoshe Shemesh err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode); 630af2f8c1fSMoshe Shemesh if (err) 631af2f8c1fSMoshe Shemesh goto nla_put_failure; 632af2f8c1fSMoshe Shemesh } 633af2f8c1fSMoshe Shemesh 634af2f8c1fSMoshe Shemesh if (ops->eswitch_inline_mode_get) { 635af2f8c1fSMoshe Shemesh err = ops->eswitch_inline_mode_get(devlink, &inline_mode); 636af2f8c1fSMoshe Shemesh if (err) 637af2f8c1fSMoshe Shemesh goto nla_put_failure; 638af2f8c1fSMoshe Shemesh err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE, 639af2f8c1fSMoshe Shemesh inline_mode); 640af2f8c1fSMoshe Shemesh if (err) 641af2f8c1fSMoshe Shemesh goto nla_put_failure; 642af2f8c1fSMoshe Shemesh } 643af2f8c1fSMoshe Shemesh 644af2f8c1fSMoshe Shemesh if (ops->eswitch_encap_mode_get) { 645af2f8c1fSMoshe Shemesh err = ops->eswitch_encap_mode_get(devlink, &encap_mode); 646af2f8c1fSMoshe Shemesh if (err) 647af2f8c1fSMoshe Shemesh goto nla_put_failure; 648af2f8c1fSMoshe Shemesh err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode); 649af2f8c1fSMoshe Shemesh if (err) 650af2f8c1fSMoshe Shemesh goto nla_put_failure; 651af2f8c1fSMoshe Shemesh } 652af2f8c1fSMoshe Shemesh 653af2f8c1fSMoshe Shemesh genlmsg_end(msg, hdr); 654af2f8c1fSMoshe Shemesh return 0; 655af2f8c1fSMoshe Shemesh 656af2f8c1fSMoshe Shemesh nla_put_failure: 657af2f8c1fSMoshe Shemesh genlmsg_cancel(msg, hdr); 658af2f8c1fSMoshe Shemesh return err; 659af2f8c1fSMoshe Shemesh } 660af2f8c1fSMoshe Shemesh 661af2f8c1fSMoshe Shemesh int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info) 662af2f8c1fSMoshe Shemesh { 663af2f8c1fSMoshe Shemesh struct devlink *devlink = info->user_ptr[0]; 664af2f8c1fSMoshe Shemesh struct sk_buff *msg; 665af2f8c1fSMoshe Shemesh int err; 666af2f8c1fSMoshe Shemesh 667af2f8c1fSMoshe Shemesh msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 668af2f8c1fSMoshe Shemesh if (!msg) 669af2f8c1fSMoshe Shemesh return -ENOMEM; 670af2f8c1fSMoshe Shemesh 671af2f8c1fSMoshe Shemesh err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET, 672af2f8c1fSMoshe Shemesh info->snd_portid, info->snd_seq, 0); 673af2f8c1fSMoshe Shemesh 674af2f8c1fSMoshe Shemesh if (err) { 675af2f8c1fSMoshe Shemesh nlmsg_free(msg); 676af2f8c1fSMoshe Shemesh return err; 677af2f8c1fSMoshe Shemesh } 678af2f8c1fSMoshe Shemesh 679af2f8c1fSMoshe Shemesh return genlmsg_reply(msg, info); 680af2f8c1fSMoshe Shemesh } 681af2f8c1fSMoshe Shemesh 682af2f8c1fSMoshe Shemesh int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info) 683af2f8c1fSMoshe Shemesh { 684af2f8c1fSMoshe Shemesh struct devlink *devlink = info->user_ptr[0]; 685af2f8c1fSMoshe Shemesh const struct devlink_ops *ops = devlink->ops; 686af2f8c1fSMoshe Shemesh enum devlink_eswitch_encap_mode encap_mode; 687af2f8c1fSMoshe Shemesh u8 inline_mode; 688af2f8c1fSMoshe Shemesh int err = 0; 689af2f8c1fSMoshe Shemesh u16 mode; 690af2f8c1fSMoshe Shemesh 691af2f8c1fSMoshe Shemesh if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) { 692af2f8c1fSMoshe Shemesh if (!ops->eswitch_mode_set) 693af2f8c1fSMoshe Shemesh return -EOPNOTSUPP; 694af2f8c1fSMoshe Shemesh mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]); 695af2f8c1fSMoshe Shemesh err = devlink_rate_nodes_check(devlink, mode, info->extack); 696af2f8c1fSMoshe Shemesh if (err) 697af2f8c1fSMoshe Shemesh return err; 698af2f8c1fSMoshe Shemesh err = ops->eswitch_mode_set(devlink, mode, info->extack); 699af2f8c1fSMoshe Shemesh if (err) 700af2f8c1fSMoshe Shemesh return err; 701af2f8c1fSMoshe Shemesh } 702af2f8c1fSMoshe Shemesh 703af2f8c1fSMoshe Shemesh if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) { 704af2f8c1fSMoshe Shemesh if (!ops->eswitch_inline_mode_set) 705af2f8c1fSMoshe Shemesh return -EOPNOTSUPP; 706af2f8c1fSMoshe Shemesh inline_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]); 707af2f8c1fSMoshe Shemesh err = ops->eswitch_inline_mode_set(devlink, inline_mode, 708af2f8c1fSMoshe Shemesh info->extack); 709af2f8c1fSMoshe Shemesh if (err) 710af2f8c1fSMoshe Shemesh return err; 711af2f8c1fSMoshe Shemesh } 712af2f8c1fSMoshe Shemesh 713af2f8c1fSMoshe Shemesh if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) { 714af2f8c1fSMoshe Shemesh if (!ops->eswitch_encap_mode_set) 715af2f8c1fSMoshe Shemesh return -EOPNOTSUPP; 716af2f8c1fSMoshe Shemesh encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]); 717af2f8c1fSMoshe Shemesh err = ops->eswitch_encap_mode_set(devlink, encap_mode, 718af2f8c1fSMoshe Shemesh info->extack); 719af2f8c1fSMoshe Shemesh if (err) 720af2f8c1fSMoshe Shemesh return err; 721af2f8c1fSMoshe Shemesh } 722af2f8c1fSMoshe Shemesh 723af2f8c1fSMoshe Shemesh return 0; 724af2f8c1fSMoshe Shemesh } 725d60191c4SMoshe Shemesh 726d60191c4SMoshe Shemesh int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn) 727d60191c4SMoshe Shemesh { 728d60191c4SMoshe Shemesh if (!req->msg) 729d60191c4SMoshe Shemesh return 0; 730d60191c4SMoshe Shemesh return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn); 731d60191c4SMoshe Shemesh } 732d60191c4SMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_info_serial_number_put); 733d60191c4SMoshe Shemesh 734d60191c4SMoshe Shemesh int devlink_info_board_serial_number_put(struct devlink_info_req *req, 735d60191c4SMoshe Shemesh const char *bsn) 736d60191c4SMoshe Shemesh { 737d60191c4SMoshe Shemesh if (!req->msg) 738d60191c4SMoshe Shemesh return 0; 739d60191c4SMoshe Shemesh return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER, 740d60191c4SMoshe Shemesh bsn); 741d60191c4SMoshe Shemesh } 742d60191c4SMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put); 743d60191c4SMoshe Shemesh 744d60191c4SMoshe Shemesh static int devlink_info_version_put(struct devlink_info_req *req, int attr, 745d60191c4SMoshe Shemesh const char *version_name, 746d60191c4SMoshe Shemesh const char *version_value, 747d60191c4SMoshe Shemesh enum devlink_info_version_type version_type) 748d60191c4SMoshe Shemesh { 749d60191c4SMoshe Shemesh struct nlattr *nest; 750d60191c4SMoshe Shemesh int err; 751d60191c4SMoshe Shemesh 752d60191c4SMoshe Shemesh if (req->version_cb) 753d60191c4SMoshe Shemesh req->version_cb(version_name, version_type, 754d60191c4SMoshe Shemesh req->version_cb_priv); 755d60191c4SMoshe Shemesh 756d60191c4SMoshe Shemesh if (!req->msg) 757d60191c4SMoshe Shemesh return 0; 758d60191c4SMoshe Shemesh 759d60191c4SMoshe Shemesh nest = nla_nest_start_noflag(req->msg, attr); 760d60191c4SMoshe Shemesh if (!nest) 761d60191c4SMoshe Shemesh return -EMSGSIZE; 762d60191c4SMoshe Shemesh 763d60191c4SMoshe Shemesh err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME, 764d60191c4SMoshe Shemesh version_name); 765d60191c4SMoshe Shemesh if (err) 766d60191c4SMoshe Shemesh goto nla_put_failure; 767d60191c4SMoshe Shemesh 768d60191c4SMoshe Shemesh err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE, 769d60191c4SMoshe Shemesh version_value); 770d60191c4SMoshe Shemesh if (err) 771d60191c4SMoshe Shemesh goto nla_put_failure; 772d60191c4SMoshe Shemesh 773d60191c4SMoshe Shemesh nla_nest_end(req->msg, nest); 774d60191c4SMoshe Shemesh 775d60191c4SMoshe Shemesh return 0; 776d60191c4SMoshe Shemesh 777d60191c4SMoshe Shemesh nla_put_failure: 778d60191c4SMoshe Shemesh nla_nest_cancel(req->msg, nest); 779d60191c4SMoshe Shemesh return err; 780d60191c4SMoshe Shemesh } 781d60191c4SMoshe Shemesh 782d60191c4SMoshe Shemesh int devlink_info_version_fixed_put(struct devlink_info_req *req, 783d60191c4SMoshe Shemesh const char *version_name, 784d60191c4SMoshe Shemesh const char *version_value) 785d60191c4SMoshe Shemesh { 786d60191c4SMoshe Shemesh return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED, 787d60191c4SMoshe Shemesh version_name, version_value, 788d60191c4SMoshe Shemesh DEVLINK_INFO_VERSION_TYPE_NONE); 789d60191c4SMoshe Shemesh } 790d60191c4SMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put); 791d60191c4SMoshe Shemesh 792d60191c4SMoshe Shemesh int devlink_info_version_stored_put(struct devlink_info_req *req, 793d60191c4SMoshe Shemesh const char *version_name, 794d60191c4SMoshe Shemesh const char *version_value) 795d60191c4SMoshe Shemesh { 796d60191c4SMoshe Shemesh return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED, 797d60191c4SMoshe Shemesh version_name, version_value, 798d60191c4SMoshe Shemesh DEVLINK_INFO_VERSION_TYPE_NONE); 799d60191c4SMoshe Shemesh } 800d60191c4SMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_info_version_stored_put); 801d60191c4SMoshe Shemesh 802d60191c4SMoshe Shemesh int devlink_info_version_stored_put_ext(struct devlink_info_req *req, 803d60191c4SMoshe Shemesh const char *version_name, 804d60191c4SMoshe Shemesh const char *version_value, 805d60191c4SMoshe Shemesh enum devlink_info_version_type version_type) 806d60191c4SMoshe Shemesh { 807d60191c4SMoshe Shemesh return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED, 808d60191c4SMoshe Shemesh version_name, version_value, 809d60191c4SMoshe Shemesh version_type); 810d60191c4SMoshe Shemesh } 811d60191c4SMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_info_version_stored_put_ext); 812d60191c4SMoshe Shemesh 813d60191c4SMoshe Shemesh int devlink_info_version_running_put(struct devlink_info_req *req, 814d60191c4SMoshe Shemesh const char *version_name, 815d60191c4SMoshe Shemesh const char *version_value) 816d60191c4SMoshe Shemesh { 817d60191c4SMoshe Shemesh return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING, 818d60191c4SMoshe Shemesh version_name, version_value, 819d60191c4SMoshe Shemesh DEVLINK_INFO_VERSION_TYPE_NONE); 820d60191c4SMoshe Shemesh } 821d60191c4SMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_info_version_running_put); 822d60191c4SMoshe Shemesh 823d60191c4SMoshe Shemesh int devlink_info_version_running_put_ext(struct devlink_info_req *req, 824d60191c4SMoshe Shemesh const char *version_name, 825d60191c4SMoshe Shemesh const char *version_value, 826d60191c4SMoshe Shemesh enum devlink_info_version_type version_type) 827d60191c4SMoshe Shemesh { 828d60191c4SMoshe Shemesh return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING, 829d60191c4SMoshe Shemesh version_name, version_value, 830d60191c4SMoshe Shemesh version_type); 831d60191c4SMoshe Shemesh } 832d60191c4SMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_info_version_running_put_ext); 833d60191c4SMoshe Shemesh 834d60191c4SMoshe Shemesh static int devlink_nl_driver_info_get(struct device_driver *drv, 835d60191c4SMoshe Shemesh struct devlink_info_req *req) 836d60191c4SMoshe Shemesh { 837d60191c4SMoshe Shemesh if (!drv) 838d60191c4SMoshe Shemesh return 0; 839d60191c4SMoshe Shemesh 840d60191c4SMoshe Shemesh if (drv->name[0]) 841d60191c4SMoshe Shemesh return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, 842d60191c4SMoshe Shemesh drv->name); 843d60191c4SMoshe Shemesh 844d60191c4SMoshe Shemesh return 0; 845d60191c4SMoshe Shemesh } 846d60191c4SMoshe Shemesh 847d60191c4SMoshe Shemesh static int 848d60191c4SMoshe Shemesh devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink, 849d60191c4SMoshe Shemesh enum devlink_command cmd, u32 portid, 850d60191c4SMoshe Shemesh u32 seq, int flags, struct netlink_ext_ack *extack) 851d60191c4SMoshe Shemesh { 852d60191c4SMoshe Shemesh struct device *dev = devlink_to_dev(devlink); 853d60191c4SMoshe Shemesh struct devlink_info_req req = {}; 854d60191c4SMoshe Shemesh void *hdr; 855d60191c4SMoshe Shemesh int err; 856d60191c4SMoshe Shemesh 857d60191c4SMoshe Shemesh hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 858d60191c4SMoshe Shemesh if (!hdr) 859d60191c4SMoshe Shemesh return -EMSGSIZE; 860d60191c4SMoshe Shemesh 861d60191c4SMoshe Shemesh err = -EMSGSIZE; 862d60191c4SMoshe Shemesh if (devlink_nl_put_handle(msg, devlink)) 863d60191c4SMoshe Shemesh goto err_cancel_msg; 864d60191c4SMoshe Shemesh 865d60191c4SMoshe Shemesh req.msg = msg; 866d60191c4SMoshe Shemesh if (devlink->ops->info_get) { 867d60191c4SMoshe Shemesh err = devlink->ops->info_get(devlink, &req, extack); 868d60191c4SMoshe Shemesh if (err) 869d60191c4SMoshe Shemesh goto err_cancel_msg; 870d60191c4SMoshe Shemesh } 871d60191c4SMoshe Shemesh 872d60191c4SMoshe Shemesh err = devlink_nl_driver_info_get(dev->driver, &req); 873d60191c4SMoshe Shemesh if (err) 874d60191c4SMoshe Shemesh goto err_cancel_msg; 875d60191c4SMoshe Shemesh 876d60191c4SMoshe Shemesh genlmsg_end(msg, hdr); 877d60191c4SMoshe Shemesh return 0; 878d60191c4SMoshe Shemesh 879d60191c4SMoshe Shemesh err_cancel_msg: 880d60191c4SMoshe Shemesh genlmsg_cancel(msg, hdr); 881d60191c4SMoshe Shemesh return err; 882d60191c4SMoshe Shemesh } 883d60191c4SMoshe Shemesh 884d61aedcfSJiri Pirko int devlink_nl_info_get_doit(struct sk_buff *skb, struct genl_info *info) 885d60191c4SMoshe Shemesh { 886d60191c4SMoshe Shemesh struct devlink *devlink = info->user_ptr[0]; 887d60191c4SMoshe Shemesh struct sk_buff *msg; 888d60191c4SMoshe Shemesh int err; 889d60191c4SMoshe Shemesh 890d60191c4SMoshe Shemesh msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 891d60191c4SMoshe Shemesh if (!msg) 892d60191c4SMoshe Shemesh return -ENOMEM; 893d60191c4SMoshe Shemesh 894d60191c4SMoshe Shemesh err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET, 895d60191c4SMoshe Shemesh info->snd_portid, info->snd_seq, 0, 896d60191c4SMoshe Shemesh info->extack); 897d60191c4SMoshe Shemesh if (err) { 898d60191c4SMoshe Shemesh nlmsg_free(msg); 899d60191c4SMoshe Shemesh return err; 900d60191c4SMoshe Shemesh } 901d60191c4SMoshe Shemesh 902d60191c4SMoshe Shemesh return genlmsg_reply(msg, info); 903d60191c4SMoshe Shemesh } 904d60191c4SMoshe Shemesh 905d60191c4SMoshe Shemesh static int 906491a2487SJiri Pirko devlink_nl_info_get_dump_one(struct sk_buff *msg, struct devlink *devlink, 9077d3c6fecSJiri Pirko struct netlink_callback *cb, int flags) 908d60191c4SMoshe Shemesh { 909d60191c4SMoshe Shemesh int err; 910d60191c4SMoshe Shemesh 911d60191c4SMoshe Shemesh err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET, 912d60191c4SMoshe Shemesh NETLINK_CB(cb->skb).portid, 9137d3c6fecSJiri Pirko cb->nlh->nlmsg_seq, flags, 914d60191c4SMoshe Shemesh cb->extack); 915d60191c4SMoshe Shemesh if (err == -EOPNOTSUPP) 916d60191c4SMoshe Shemesh err = 0; 917d60191c4SMoshe Shemesh return err; 918d60191c4SMoshe Shemesh } 919d60191c4SMoshe Shemesh 920491a2487SJiri Pirko int devlink_nl_info_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb) 921491a2487SJiri Pirko { 922491a2487SJiri Pirko return devlink_nl_dumpit(msg, cb, devlink_nl_info_get_dump_one); 923491a2487SJiri Pirko } 924d60191c4SMoshe Shemesh 925a13aab66SMoshe Shemesh static int devlink_nl_flash_update_fill(struct sk_buff *msg, 926a13aab66SMoshe Shemesh struct devlink *devlink, 927a13aab66SMoshe Shemesh enum devlink_command cmd, 928a13aab66SMoshe Shemesh struct devlink_flash_notify *params) 929a13aab66SMoshe Shemesh { 930a13aab66SMoshe Shemesh void *hdr; 931a13aab66SMoshe Shemesh 932a13aab66SMoshe Shemesh hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd); 933a13aab66SMoshe Shemesh if (!hdr) 934a13aab66SMoshe Shemesh return -EMSGSIZE; 935a13aab66SMoshe Shemesh 936a13aab66SMoshe Shemesh if (devlink_nl_put_handle(msg, devlink)) 937a13aab66SMoshe Shemesh goto nla_put_failure; 938a13aab66SMoshe Shemesh 939a13aab66SMoshe Shemesh if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS) 940a13aab66SMoshe Shemesh goto out; 941a13aab66SMoshe Shemesh 942a13aab66SMoshe Shemesh if (params->status_msg && 943a13aab66SMoshe Shemesh nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG, 944a13aab66SMoshe Shemesh params->status_msg)) 945a13aab66SMoshe Shemesh goto nla_put_failure; 946a13aab66SMoshe Shemesh if (params->component && 947a13aab66SMoshe Shemesh nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, 948a13aab66SMoshe Shemesh params->component)) 949a13aab66SMoshe Shemesh goto nla_put_failure; 950a13aab66SMoshe Shemesh if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE, 951a13aab66SMoshe Shemesh params->done, DEVLINK_ATTR_PAD)) 952a13aab66SMoshe Shemesh goto nla_put_failure; 953a13aab66SMoshe Shemesh if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL, 954a13aab66SMoshe Shemesh params->total, DEVLINK_ATTR_PAD)) 955a13aab66SMoshe Shemesh goto nla_put_failure; 956a13aab66SMoshe Shemesh if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT, 957a13aab66SMoshe Shemesh params->timeout, DEVLINK_ATTR_PAD)) 958a13aab66SMoshe Shemesh goto nla_put_failure; 959a13aab66SMoshe Shemesh 960a13aab66SMoshe Shemesh out: 961a13aab66SMoshe Shemesh genlmsg_end(msg, hdr); 962a13aab66SMoshe Shemesh return 0; 963a13aab66SMoshe Shemesh 964a13aab66SMoshe Shemesh nla_put_failure: 965a13aab66SMoshe Shemesh genlmsg_cancel(msg, hdr); 966a13aab66SMoshe Shemesh return -EMSGSIZE; 967a13aab66SMoshe Shemesh } 968a13aab66SMoshe Shemesh 969a13aab66SMoshe Shemesh static void __devlink_flash_update_notify(struct devlink *devlink, 970a13aab66SMoshe Shemesh enum devlink_command cmd, 971a13aab66SMoshe Shemesh struct devlink_flash_notify *params) 972a13aab66SMoshe Shemesh { 973a13aab66SMoshe Shemesh struct sk_buff *msg; 974a13aab66SMoshe Shemesh int err; 975a13aab66SMoshe Shemesh 976a13aab66SMoshe Shemesh WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE && 977a13aab66SMoshe Shemesh cmd != DEVLINK_CMD_FLASH_UPDATE_END && 978a13aab66SMoshe Shemesh cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS); 979a13aab66SMoshe Shemesh 980a13aab66SMoshe Shemesh if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED)) 981a13aab66SMoshe Shemesh return; 982a13aab66SMoshe Shemesh 983a13aab66SMoshe Shemesh msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 984a13aab66SMoshe Shemesh if (!msg) 985a13aab66SMoshe Shemesh return; 986a13aab66SMoshe Shemesh 987a13aab66SMoshe Shemesh err = devlink_nl_flash_update_fill(msg, devlink, cmd, params); 988a13aab66SMoshe Shemesh if (err) 989a13aab66SMoshe Shemesh goto out_free_msg; 990a13aab66SMoshe Shemesh 991a13aab66SMoshe Shemesh genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 992a13aab66SMoshe Shemesh msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 993a13aab66SMoshe Shemesh return; 994a13aab66SMoshe Shemesh 995a13aab66SMoshe Shemesh out_free_msg: 996a13aab66SMoshe Shemesh nlmsg_free(msg); 997a13aab66SMoshe Shemesh } 998a13aab66SMoshe Shemesh 999a13aab66SMoshe Shemesh static void devlink_flash_update_begin_notify(struct devlink *devlink) 1000a13aab66SMoshe Shemesh { 1001a13aab66SMoshe Shemesh struct devlink_flash_notify params = {}; 1002a13aab66SMoshe Shemesh 1003a13aab66SMoshe Shemesh __devlink_flash_update_notify(devlink, 1004a13aab66SMoshe Shemesh DEVLINK_CMD_FLASH_UPDATE, 1005a13aab66SMoshe Shemesh ¶ms); 1006a13aab66SMoshe Shemesh } 1007a13aab66SMoshe Shemesh 1008a13aab66SMoshe Shemesh static void devlink_flash_update_end_notify(struct devlink *devlink) 1009a13aab66SMoshe Shemesh { 1010a13aab66SMoshe Shemesh struct devlink_flash_notify params = {}; 1011a13aab66SMoshe Shemesh 1012a13aab66SMoshe Shemesh __devlink_flash_update_notify(devlink, 1013a13aab66SMoshe Shemesh DEVLINK_CMD_FLASH_UPDATE_END, 1014a13aab66SMoshe Shemesh ¶ms); 1015a13aab66SMoshe Shemesh } 1016a13aab66SMoshe Shemesh 1017a13aab66SMoshe Shemesh void devlink_flash_update_status_notify(struct devlink *devlink, 1018a13aab66SMoshe Shemesh const char *status_msg, 1019a13aab66SMoshe Shemesh const char *component, 1020a13aab66SMoshe Shemesh unsigned long done, 1021a13aab66SMoshe Shemesh unsigned long total) 1022a13aab66SMoshe Shemesh { 1023a13aab66SMoshe Shemesh struct devlink_flash_notify params = { 1024a13aab66SMoshe Shemesh .status_msg = status_msg, 1025a13aab66SMoshe Shemesh .component = component, 1026a13aab66SMoshe Shemesh .done = done, 1027a13aab66SMoshe Shemesh .total = total, 1028a13aab66SMoshe Shemesh }; 1029a13aab66SMoshe Shemesh 1030a13aab66SMoshe Shemesh __devlink_flash_update_notify(devlink, 1031a13aab66SMoshe Shemesh DEVLINK_CMD_FLASH_UPDATE_STATUS, 1032a13aab66SMoshe Shemesh ¶ms); 1033a13aab66SMoshe Shemesh } 1034a13aab66SMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify); 1035a13aab66SMoshe Shemesh 1036a13aab66SMoshe Shemesh void devlink_flash_update_timeout_notify(struct devlink *devlink, 1037a13aab66SMoshe Shemesh const char *status_msg, 1038a13aab66SMoshe Shemesh const char *component, 1039a13aab66SMoshe Shemesh unsigned long timeout) 1040a13aab66SMoshe Shemesh { 1041a13aab66SMoshe Shemesh struct devlink_flash_notify params = { 1042a13aab66SMoshe Shemesh .status_msg = status_msg, 1043a13aab66SMoshe Shemesh .component = component, 1044a13aab66SMoshe Shemesh .timeout = timeout, 1045a13aab66SMoshe Shemesh }; 1046a13aab66SMoshe Shemesh 1047a13aab66SMoshe Shemesh __devlink_flash_update_notify(devlink, 1048a13aab66SMoshe Shemesh DEVLINK_CMD_FLASH_UPDATE_STATUS, 1049a13aab66SMoshe Shemesh ¶ms); 1050a13aab66SMoshe Shemesh } 1051a13aab66SMoshe Shemesh EXPORT_SYMBOL_GPL(devlink_flash_update_timeout_notify); 1052a13aab66SMoshe Shemesh 1053a13aab66SMoshe Shemesh struct devlink_flash_component_lookup_ctx { 1054a13aab66SMoshe Shemesh const char *lookup_name; 1055a13aab66SMoshe Shemesh bool lookup_name_found; 1056a13aab66SMoshe Shemesh }; 1057a13aab66SMoshe Shemesh 1058a13aab66SMoshe Shemesh static void 1059a13aab66SMoshe Shemesh devlink_flash_component_lookup_cb(const char *version_name, 1060a13aab66SMoshe Shemesh enum devlink_info_version_type version_type, 1061a13aab66SMoshe Shemesh void *version_cb_priv) 1062a13aab66SMoshe Shemesh { 1063a13aab66SMoshe Shemesh struct devlink_flash_component_lookup_ctx *lookup_ctx = version_cb_priv; 1064a13aab66SMoshe Shemesh 1065a13aab66SMoshe Shemesh if (version_type != DEVLINK_INFO_VERSION_TYPE_COMPONENT || 1066a13aab66SMoshe Shemesh lookup_ctx->lookup_name_found) 1067a13aab66SMoshe Shemesh return; 1068a13aab66SMoshe Shemesh 1069a13aab66SMoshe Shemesh lookup_ctx->lookup_name_found = 1070a13aab66SMoshe Shemesh !strcmp(lookup_ctx->lookup_name, version_name); 1071a13aab66SMoshe Shemesh } 1072a13aab66SMoshe Shemesh 1073a13aab66SMoshe Shemesh static int devlink_flash_component_get(struct devlink *devlink, 1074a13aab66SMoshe Shemesh struct nlattr *nla_component, 1075a13aab66SMoshe Shemesh const char **p_component, 1076a13aab66SMoshe Shemesh struct netlink_ext_ack *extack) 1077a13aab66SMoshe Shemesh { 1078a13aab66SMoshe Shemesh struct devlink_flash_component_lookup_ctx lookup_ctx = {}; 1079a13aab66SMoshe Shemesh struct devlink_info_req req = {}; 1080a13aab66SMoshe Shemesh const char *component; 1081a13aab66SMoshe Shemesh int ret; 1082a13aab66SMoshe Shemesh 1083a13aab66SMoshe Shemesh if (!nla_component) 1084a13aab66SMoshe Shemesh return 0; 1085a13aab66SMoshe Shemesh 1086a13aab66SMoshe Shemesh component = nla_data(nla_component); 1087a13aab66SMoshe Shemesh 1088a13aab66SMoshe Shemesh if (!devlink->ops->info_get) { 1089a13aab66SMoshe Shemesh NL_SET_ERR_MSG_ATTR(extack, nla_component, 1090a13aab66SMoshe Shemesh "component update is not supported by this device"); 1091a13aab66SMoshe Shemesh return -EOPNOTSUPP; 1092a13aab66SMoshe Shemesh } 1093a13aab66SMoshe Shemesh 1094a13aab66SMoshe Shemesh lookup_ctx.lookup_name = component; 1095a13aab66SMoshe Shemesh req.version_cb = devlink_flash_component_lookup_cb; 1096a13aab66SMoshe Shemesh req.version_cb_priv = &lookup_ctx; 1097a13aab66SMoshe Shemesh 1098a13aab66SMoshe Shemesh ret = devlink->ops->info_get(devlink, &req, NULL); 1099a13aab66SMoshe Shemesh if (ret) 1100a13aab66SMoshe Shemesh return ret; 1101a13aab66SMoshe Shemesh 1102a13aab66SMoshe Shemesh if (!lookup_ctx.lookup_name_found) { 1103a13aab66SMoshe Shemesh NL_SET_ERR_MSG_ATTR(extack, nla_component, 1104a13aab66SMoshe Shemesh "selected component is not supported by this device"); 1105a13aab66SMoshe Shemesh return -EINVAL; 1106a13aab66SMoshe Shemesh } 1107a13aab66SMoshe Shemesh *p_component = component; 1108a13aab66SMoshe Shemesh return 0; 1109a13aab66SMoshe Shemesh } 1110a13aab66SMoshe Shemesh 1111a13aab66SMoshe Shemesh int devlink_nl_cmd_flash_update(struct sk_buff *skb, struct genl_info *info) 1112a13aab66SMoshe Shemesh { 1113a13aab66SMoshe Shemesh struct nlattr *nla_overwrite_mask, *nla_file_name; 1114a13aab66SMoshe Shemesh struct devlink_flash_update_params params = {}; 1115a13aab66SMoshe Shemesh struct devlink *devlink = info->user_ptr[0]; 1116a13aab66SMoshe Shemesh const char *file_name; 1117a13aab66SMoshe Shemesh u32 supported_params; 1118a13aab66SMoshe Shemesh int ret; 1119a13aab66SMoshe Shemesh 1120a13aab66SMoshe Shemesh if (!devlink->ops->flash_update) 1121a13aab66SMoshe Shemesh return -EOPNOTSUPP; 1122a13aab66SMoshe Shemesh 1123a13aab66SMoshe Shemesh if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME)) 1124a13aab66SMoshe Shemesh return -EINVAL; 1125a13aab66SMoshe Shemesh 1126a13aab66SMoshe Shemesh ret = devlink_flash_component_get(devlink, 1127a13aab66SMoshe Shemesh info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT], 1128a13aab66SMoshe Shemesh ¶ms.component, info->extack); 1129a13aab66SMoshe Shemesh if (ret) 1130a13aab66SMoshe Shemesh return ret; 1131a13aab66SMoshe Shemesh 1132a13aab66SMoshe Shemesh supported_params = devlink->ops->supported_flash_update_params; 1133a13aab66SMoshe Shemesh 1134a13aab66SMoshe Shemesh nla_overwrite_mask = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK]; 1135a13aab66SMoshe Shemesh if (nla_overwrite_mask) { 1136a13aab66SMoshe Shemesh struct nla_bitfield32 sections; 1137a13aab66SMoshe Shemesh 1138a13aab66SMoshe Shemesh if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK)) { 1139a13aab66SMoshe Shemesh NL_SET_ERR_MSG_ATTR(info->extack, nla_overwrite_mask, 1140a13aab66SMoshe Shemesh "overwrite settings are not supported by this device"); 1141a13aab66SMoshe Shemesh return -EOPNOTSUPP; 1142a13aab66SMoshe Shemesh } 1143a13aab66SMoshe Shemesh sections = nla_get_bitfield32(nla_overwrite_mask); 1144a13aab66SMoshe Shemesh params.overwrite_mask = sections.value & sections.selector; 1145a13aab66SMoshe Shemesh } 1146a13aab66SMoshe Shemesh 1147a13aab66SMoshe Shemesh nla_file_name = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]; 1148a13aab66SMoshe Shemesh file_name = nla_data(nla_file_name); 1149a13aab66SMoshe Shemesh ret = request_firmware(¶ms.fw, file_name, devlink->dev); 1150a13aab66SMoshe Shemesh if (ret) { 1151a13aab66SMoshe Shemesh NL_SET_ERR_MSG_ATTR(info->extack, nla_file_name, 1152a13aab66SMoshe Shemesh "failed to locate the requested firmware file"); 1153a13aab66SMoshe Shemesh return ret; 1154a13aab66SMoshe Shemesh } 1155a13aab66SMoshe Shemesh 1156a13aab66SMoshe Shemesh devlink_flash_update_begin_notify(devlink); 1157a13aab66SMoshe Shemesh ret = devlink->ops->flash_update(devlink, ¶ms, info->extack); 1158a13aab66SMoshe Shemesh devlink_flash_update_end_notify(devlink); 1159a13aab66SMoshe Shemesh 1160a13aab66SMoshe Shemesh release_firmware(params.fw); 1161a13aab66SMoshe Shemesh 1162a13aab66SMoshe Shemesh return ret; 1163a13aab66SMoshe Shemesh } 1164a13aab66SMoshe Shemesh 1165d60191c4SMoshe Shemesh static void __devlink_compat_running_version(struct devlink *devlink, 1166d60191c4SMoshe Shemesh char *buf, size_t len) 1167d60191c4SMoshe Shemesh { 1168d60191c4SMoshe Shemesh struct devlink_info_req req = {}; 1169d60191c4SMoshe Shemesh const struct nlattr *nlattr; 1170d60191c4SMoshe Shemesh struct sk_buff *msg; 1171d60191c4SMoshe Shemesh int rem, err; 1172d60191c4SMoshe Shemesh 1173d60191c4SMoshe Shemesh msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 1174d60191c4SMoshe Shemesh if (!msg) 1175d60191c4SMoshe Shemesh return; 1176d60191c4SMoshe Shemesh 1177d60191c4SMoshe Shemesh req.msg = msg; 1178d60191c4SMoshe Shemesh err = devlink->ops->info_get(devlink, &req, NULL); 1179d60191c4SMoshe Shemesh if (err) 1180d60191c4SMoshe Shemesh goto free_msg; 1181d60191c4SMoshe Shemesh 1182d60191c4SMoshe Shemesh nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) { 1183d60191c4SMoshe Shemesh const struct nlattr *kv; 1184d60191c4SMoshe Shemesh int rem_kv; 1185d60191c4SMoshe Shemesh 1186d60191c4SMoshe Shemesh if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING) 1187d60191c4SMoshe Shemesh continue; 1188d60191c4SMoshe Shemesh 1189d60191c4SMoshe Shemesh nla_for_each_nested(kv, nlattr, rem_kv) { 1190d60191c4SMoshe Shemesh if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE) 1191d60191c4SMoshe Shemesh continue; 1192d60191c4SMoshe Shemesh 1193d60191c4SMoshe Shemesh strlcat(buf, nla_data(kv), len); 1194d60191c4SMoshe Shemesh strlcat(buf, " ", len); 1195d60191c4SMoshe Shemesh } 1196d60191c4SMoshe Shemesh } 1197d60191c4SMoshe Shemesh free_msg: 1198d60191c4SMoshe Shemesh nlmsg_free(msg); 1199d60191c4SMoshe Shemesh } 1200d60191c4SMoshe Shemesh 1201d60191c4SMoshe Shemesh void devlink_compat_running_version(struct devlink *devlink, 1202d60191c4SMoshe Shemesh char *buf, size_t len) 1203d60191c4SMoshe Shemesh { 1204d60191c4SMoshe Shemesh if (!devlink->ops->info_get) 1205d60191c4SMoshe Shemesh return; 1206d60191c4SMoshe Shemesh 1207d60191c4SMoshe Shemesh devl_lock(devlink); 1208d60191c4SMoshe Shemesh if (devl_is_registered(devlink)) 1209d60191c4SMoshe Shemesh __devlink_compat_running_version(devlink, buf, len); 1210d60191c4SMoshe Shemesh devl_unlock(devlink); 1211d60191c4SMoshe Shemesh } 1212a13aab66SMoshe Shemesh 1213a13aab66SMoshe Shemesh int devlink_compat_flash_update(struct devlink *devlink, const char *file_name) 1214a13aab66SMoshe Shemesh { 1215a13aab66SMoshe Shemesh struct devlink_flash_update_params params = {}; 1216a13aab66SMoshe Shemesh int ret; 1217a13aab66SMoshe Shemesh 1218a13aab66SMoshe Shemesh devl_lock(devlink); 1219a13aab66SMoshe Shemesh if (!devl_is_registered(devlink)) { 1220a13aab66SMoshe Shemesh ret = -ENODEV; 1221a13aab66SMoshe Shemesh goto out_unlock; 1222a13aab66SMoshe Shemesh } 1223a13aab66SMoshe Shemesh 1224a13aab66SMoshe Shemesh if (!devlink->ops->flash_update) { 1225a13aab66SMoshe Shemesh ret = -EOPNOTSUPP; 1226a13aab66SMoshe Shemesh goto out_unlock; 1227a13aab66SMoshe Shemesh } 1228a13aab66SMoshe Shemesh 1229a13aab66SMoshe Shemesh ret = request_firmware(¶ms.fw, file_name, devlink->dev); 1230a13aab66SMoshe Shemesh if (ret) 1231a13aab66SMoshe Shemesh goto out_unlock; 1232a13aab66SMoshe Shemesh 1233a13aab66SMoshe Shemesh devlink_flash_update_begin_notify(devlink); 1234a13aab66SMoshe Shemesh ret = devlink->ops->flash_update(devlink, ¶ms, NULL); 1235a13aab66SMoshe Shemesh devlink_flash_update_end_notify(devlink); 1236a13aab66SMoshe Shemesh 1237a13aab66SMoshe Shemesh release_firmware(params.fw); 1238a13aab66SMoshe Shemesh out_unlock: 1239a13aab66SMoshe Shemesh devl_unlock(devlink); 1240a13aab66SMoshe Shemesh 1241a13aab66SMoshe Shemesh return ret; 1242a13aab66SMoshe Shemesh } 12437c976c7cSMoshe Shemesh 12447c976c7cSMoshe Shemesh static int 12457c976c7cSMoshe Shemesh devlink_nl_selftests_fill(struct sk_buff *msg, struct devlink *devlink, 12467c976c7cSMoshe Shemesh u32 portid, u32 seq, int flags, 12477c976c7cSMoshe Shemesh struct netlink_ext_ack *extack) 12487c976c7cSMoshe Shemesh { 12497c976c7cSMoshe Shemesh struct nlattr *selftests; 12507c976c7cSMoshe Shemesh void *hdr; 12517c976c7cSMoshe Shemesh int err; 12527c976c7cSMoshe Shemesh int i; 12537c976c7cSMoshe Shemesh 12547c976c7cSMoshe Shemesh hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, 12557c976c7cSMoshe Shemesh DEVLINK_CMD_SELFTESTS_GET); 12567c976c7cSMoshe Shemesh if (!hdr) 12577c976c7cSMoshe Shemesh return -EMSGSIZE; 12587c976c7cSMoshe Shemesh 12597c976c7cSMoshe Shemesh err = -EMSGSIZE; 12607c976c7cSMoshe Shemesh if (devlink_nl_put_handle(msg, devlink)) 12617c976c7cSMoshe Shemesh goto err_cancel_msg; 12627c976c7cSMoshe Shemesh 12637c976c7cSMoshe Shemesh selftests = nla_nest_start(msg, DEVLINK_ATTR_SELFTESTS); 12647c976c7cSMoshe Shemesh if (!selftests) 12657c976c7cSMoshe Shemesh goto err_cancel_msg; 12667c976c7cSMoshe Shemesh 12677c976c7cSMoshe Shemesh for (i = DEVLINK_ATTR_SELFTEST_ID_UNSPEC + 1; 12687c976c7cSMoshe Shemesh i <= DEVLINK_ATTR_SELFTEST_ID_MAX; i++) { 12697c976c7cSMoshe Shemesh if (devlink->ops->selftest_check(devlink, i, extack)) { 12707c976c7cSMoshe Shemesh err = nla_put_flag(msg, i); 12717c976c7cSMoshe Shemesh if (err) 12727c976c7cSMoshe Shemesh goto err_cancel_msg; 12737c976c7cSMoshe Shemesh } 12747c976c7cSMoshe Shemesh } 12757c976c7cSMoshe Shemesh 12767c976c7cSMoshe Shemesh nla_nest_end(msg, selftests); 12777c976c7cSMoshe Shemesh genlmsg_end(msg, hdr); 12787c976c7cSMoshe Shemesh return 0; 12797c976c7cSMoshe Shemesh 12807c976c7cSMoshe Shemesh err_cancel_msg: 12817c976c7cSMoshe Shemesh genlmsg_cancel(msg, hdr); 12827c976c7cSMoshe Shemesh return err; 12837c976c7cSMoshe Shemesh } 12847c976c7cSMoshe Shemesh 12858fa995adSJiri Pirko int devlink_nl_selftests_get_doit(struct sk_buff *skb, struct genl_info *info) 12867c976c7cSMoshe Shemesh { 12877c976c7cSMoshe Shemesh struct devlink *devlink = info->user_ptr[0]; 12887c976c7cSMoshe Shemesh struct sk_buff *msg; 12897c976c7cSMoshe Shemesh int err; 12907c976c7cSMoshe Shemesh 12917c976c7cSMoshe Shemesh if (!devlink->ops->selftest_check) 12927c976c7cSMoshe Shemesh return -EOPNOTSUPP; 12937c976c7cSMoshe Shemesh 12947c976c7cSMoshe Shemesh msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 12957c976c7cSMoshe Shemesh if (!msg) 12967c976c7cSMoshe Shemesh return -ENOMEM; 12977c976c7cSMoshe Shemesh 12987c976c7cSMoshe Shemesh err = devlink_nl_selftests_fill(msg, devlink, info->snd_portid, 12997c976c7cSMoshe Shemesh info->snd_seq, 0, info->extack); 13007c976c7cSMoshe Shemesh if (err) { 13017c976c7cSMoshe Shemesh nlmsg_free(msg); 13027c976c7cSMoshe Shemesh return err; 13037c976c7cSMoshe Shemesh } 13047c976c7cSMoshe Shemesh 13057c976c7cSMoshe Shemesh return genlmsg_reply(msg, info); 13067c976c7cSMoshe Shemesh } 13077c976c7cSMoshe Shemesh 130824c8e56dSJiri Pirko static int devlink_nl_selftests_get_dump_one(struct sk_buff *msg, 13097c976c7cSMoshe Shemesh struct devlink *devlink, 13107d3c6fecSJiri Pirko struct netlink_callback *cb, 13117d3c6fecSJiri Pirko int flags) 13127c976c7cSMoshe Shemesh { 13137c976c7cSMoshe Shemesh if (!devlink->ops->selftest_check) 13147c976c7cSMoshe Shemesh return 0; 13157c976c7cSMoshe Shemesh 13167c976c7cSMoshe Shemesh return devlink_nl_selftests_fill(msg, devlink, 13177c976c7cSMoshe Shemesh NETLINK_CB(cb->skb).portid, 13187d3c6fecSJiri Pirko cb->nlh->nlmsg_seq, flags, 13197c976c7cSMoshe Shemesh cb->extack); 13207c976c7cSMoshe Shemesh } 13217c976c7cSMoshe Shemesh 132224c8e56dSJiri Pirko int devlink_nl_selftests_get_dumpit(struct sk_buff *skb, 132324c8e56dSJiri Pirko struct netlink_callback *cb) 132424c8e56dSJiri Pirko { 132524c8e56dSJiri Pirko return devlink_nl_dumpit(skb, cb, devlink_nl_selftests_get_dump_one); 132624c8e56dSJiri Pirko } 13277c976c7cSMoshe Shemesh 13287c976c7cSMoshe Shemesh static int devlink_selftest_result_put(struct sk_buff *skb, unsigned int id, 13297c976c7cSMoshe Shemesh enum devlink_selftest_status test_status) 13307c976c7cSMoshe Shemesh { 13317c976c7cSMoshe Shemesh struct nlattr *result_attr; 13327c976c7cSMoshe Shemesh 13337c976c7cSMoshe Shemesh result_attr = nla_nest_start(skb, DEVLINK_ATTR_SELFTEST_RESULT); 13347c976c7cSMoshe Shemesh if (!result_attr) 13357c976c7cSMoshe Shemesh return -EMSGSIZE; 13367c976c7cSMoshe Shemesh 13377c976c7cSMoshe Shemesh if (nla_put_u32(skb, DEVLINK_ATTR_SELFTEST_RESULT_ID, id) || 13387c976c7cSMoshe Shemesh nla_put_u8(skb, DEVLINK_ATTR_SELFTEST_RESULT_STATUS, 13397c976c7cSMoshe Shemesh test_status)) 13407c976c7cSMoshe Shemesh goto nla_put_failure; 13417c976c7cSMoshe Shemesh 13427c976c7cSMoshe Shemesh nla_nest_end(skb, result_attr); 13437c976c7cSMoshe Shemesh return 0; 13447c976c7cSMoshe Shemesh 13457c976c7cSMoshe Shemesh nla_put_failure: 13467c976c7cSMoshe Shemesh nla_nest_cancel(skb, result_attr); 13477c976c7cSMoshe Shemesh return -EMSGSIZE; 13487c976c7cSMoshe Shemesh } 13497c976c7cSMoshe Shemesh 13507c976c7cSMoshe Shemesh static const struct nla_policy devlink_selftest_nl_policy[DEVLINK_ATTR_SELFTEST_ID_MAX + 1] = { 13517c976c7cSMoshe Shemesh [DEVLINK_ATTR_SELFTEST_ID_FLASH] = { .type = NLA_FLAG }, 13527c976c7cSMoshe Shemesh }; 13537c976c7cSMoshe Shemesh 13547c976c7cSMoshe Shemesh int devlink_nl_cmd_selftests_run(struct sk_buff *skb, struct genl_info *info) 13557c976c7cSMoshe Shemesh { 13567c976c7cSMoshe Shemesh struct nlattr *tb[DEVLINK_ATTR_SELFTEST_ID_MAX + 1]; 13577c976c7cSMoshe Shemesh struct devlink *devlink = info->user_ptr[0]; 13587c976c7cSMoshe Shemesh struct nlattr *attrs, *selftests; 13597c976c7cSMoshe Shemesh struct sk_buff *msg; 13607c976c7cSMoshe Shemesh void *hdr; 13617c976c7cSMoshe Shemesh int err; 13627c976c7cSMoshe Shemesh int i; 13637c976c7cSMoshe Shemesh 13647c976c7cSMoshe Shemesh if (!devlink->ops->selftest_run || !devlink->ops->selftest_check) 13657c976c7cSMoshe Shemesh return -EOPNOTSUPP; 13667c976c7cSMoshe Shemesh 13677c976c7cSMoshe Shemesh if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SELFTESTS)) 13687c976c7cSMoshe Shemesh return -EINVAL; 13697c976c7cSMoshe Shemesh 13707c976c7cSMoshe Shemesh attrs = info->attrs[DEVLINK_ATTR_SELFTESTS]; 13717c976c7cSMoshe Shemesh 13727c976c7cSMoshe Shemesh err = nla_parse_nested(tb, DEVLINK_ATTR_SELFTEST_ID_MAX, attrs, 13737c976c7cSMoshe Shemesh devlink_selftest_nl_policy, info->extack); 13747c976c7cSMoshe Shemesh if (err < 0) 13757c976c7cSMoshe Shemesh return err; 13767c976c7cSMoshe Shemesh 13777c976c7cSMoshe Shemesh msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 13787c976c7cSMoshe Shemesh if (!msg) 13797c976c7cSMoshe Shemesh return -ENOMEM; 13807c976c7cSMoshe Shemesh 13817c976c7cSMoshe Shemesh err = -EMSGSIZE; 13827c976c7cSMoshe Shemesh hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, 13837c976c7cSMoshe Shemesh &devlink_nl_family, 0, DEVLINK_CMD_SELFTESTS_RUN); 13847c976c7cSMoshe Shemesh if (!hdr) 13857c976c7cSMoshe Shemesh goto free_msg; 13867c976c7cSMoshe Shemesh 13877c976c7cSMoshe Shemesh if (devlink_nl_put_handle(msg, devlink)) 13887c976c7cSMoshe Shemesh goto genlmsg_cancel; 13897c976c7cSMoshe Shemesh 13907c976c7cSMoshe Shemesh selftests = nla_nest_start(msg, DEVLINK_ATTR_SELFTESTS); 13917c976c7cSMoshe Shemesh if (!selftests) 13927c976c7cSMoshe Shemesh goto genlmsg_cancel; 13937c976c7cSMoshe Shemesh 13947c976c7cSMoshe Shemesh for (i = DEVLINK_ATTR_SELFTEST_ID_UNSPEC + 1; 13957c976c7cSMoshe Shemesh i <= DEVLINK_ATTR_SELFTEST_ID_MAX; i++) { 13967c976c7cSMoshe Shemesh enum devlink_selftest_status test_status; 13977c976c7cSMoshe Shemesh 13987c976c7cSMoshe Shemesh if (nla_get_flag(tb[i])) { 13997c976c7cSMoshe Shemesh if (!devlink->ops->selftest_check(devlink, i, 14007c976c7cSMoshe Shemesh info->extack)) { 14017c976c7cSMoshe Shemesh if (devlink_selftest_result_put(msg, i, 14027c976c7cSMoshe Shemesh DEVLINK_SELFTEST_STATUS_SKIP)) 14037c976c7cSMoshe Shemesh goto selftests_nest_cancel; 14047c976c7cSMoshe Shemesh continue; 14057c976c7cSMoshe Shemesh } 14067c976c7cSMoshe Shemesh 14077c976c7cSMoshe Shemesh test_status = devlink->ops->selftest_run(devlink, i, 14087c976c7cSMoshe Shemesh info->extack); 14097c976c7cSMoshe Shemesh if (devlink_selftest_result_put(msg, i, test_status)) 14107c976c7cSMoshe Shemesh goto selftests_nest_cancel; 14117c976c7cSMoshe Shemesh } 14127c976c7cSMoshe Shemesh } 14137c976c7cSMoshe Shemesh 14147c976c7cSMoshe Shemesh nla_nest_end(msg, selftests); 14157c976c7cSMoshe Shemesh genlmsg_end(msg, hdr); 14167c976c7cSMoshe Shemesh return genlmsg_reply(msg, info); 14177c976c7cSMoshe Shemesh 14187c976c7cSMoshe Shemesh selftests_nest_cancel: 14197c976c7cSMoshe Shemesh nla_nest_cancel(msg, selftests); 14207c976c7cSMoshe Shemesh genlmsg_cancel: 14217c976c7cSMoshe Shemesh genlmsg_cancel(msg, hdr); 14227c976c7cSMoshe Shemesh free_msg: 14237c976c7cSMoshe Shemesh nlmsg_free(msg); 14247c976c7cSMoshe Shemesh return err; 14257c976c7cSMoshe Shemesh } 1426