1687125b5SJakub Kicinski // SPDX-License-Identifier: GPL-2.0-or-later 2687125b5SJakub Kicinski /* 3687125b5SJakub Kicinski * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 4687125b5SJakub Kicinski * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> 5687125b5SJakub Kicinski */ 6687125b5SJakub Kicinski 7687125b5SJakub Kicinski #include <net/genetlink.h> 8*890c5566SJiri Pirko #define CREATE_TRACE_POINTS 9*890c5566SJiri Pirko #include <trace/events/devlink.h> 10687125b5SJakub Kicinski 11687125b5SJakub Kicinski #include "devl_internal.h" 12687125b5SJakub Kicinski 13*890c5566SJiri Pirko EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg); 14*890c5566SJiri Pirko EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr); 15*890c5566SJiri Pirko EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_trap_report); 16*890c5566SJiri Pirko 17687125b5SJakub Kicinski DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC); 18687125b5SJakub Kicinski 19687125b5SJakub Kicinski void *devlink_priv(struct devlink *devlink) 20687125b5SJakub Kicinski { 21687125b5SJakub Kicinski return &devlink->priv; 22687125b5SJakub Kicinski } 23687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devlink_priv); 24687125b5SJakub Kicinski 25687125b5SJakub Kicinski struct devlink *priv_to_devlink(void *priv) 26687125b5SJakub Kicinski { 27687125b5SJakub Kicinski return container_of(priv, struct devlink, priv); 28687125b5SJakub Kicinski } 29687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(priv_to_devlink); 30687125b5SJakub Kicinski 31687125b5SJakub Kicinski struct device *devlink_to_dev(const struct devlink *devlink) 32687125b5SJakub Kicinski { 33687125b5SJakub Kicinski return devlink->dev; 34687125b5SJakub Kicinski } 35687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devlink_to_dev); 36687125b5SJakub Kicinski 37687125b5SJakub Kicinski struct net *devlink_net(const struct devlink *devlink) 38687125b5SJakub Kicinski { 39687125b5SJakub Kicinski return read_pnet(&devlink->_net); 40687125b5SJakub Kicinski } 41687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devlink_net); 42687125b5SJakub Kicinski 43687125b5SJakub Kicinski void devl_assert_locked(struct devlink *devlink) 44687125b5SJakub Kicinski { 45687125b5SJakub Kicinski lockdep_assert_held(&devlink->lock); 46687125b5SJakub Kicinski } 47687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devl_assert_locked); 48687125b5SJakub Kicinski 49687125b5SJakub Kicinski #ifdef CONFIG_LOCKDEP 50687125b5SJakub Kicinski /* For use in conjunction with LOCKDEP only e.g. rcu_dereference_protected() */ 51687125b5SJakub Kicinski bool devl_lock_is_held(struct devlink *devlink) 52687125b5SJakub Kicinski { 53687125b5SJakub Kicinski return lockdep_is_held(&devlink->lock); 54687125b5SJakub Kicinski } 55687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devl_lock_is_held); 56687125b5SJakub Kicinski #endif 57687125b5SJakub Kicinski 58687125b5SJakub Kicinski void devl_lock(struct devlink *devlink) 59687125b5SJakub Kicinski { 60687125b5SJakub Kicinski mutex_lock(&devlink->lock); 61687125b5SJakub Kicinski } 62687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devl_lock); 63687125b5SJakub Kicinski 64687125b5SJakub Kicinski int devl_trylock(struct devlink *devlink) 65687125b5SJakub Kicinski { 66687125b5SJakub Kicinski return mutex_trylock(&devlink->lock); 67687125b5SJakub Kicinski } 68687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devl_trylock); 69687125b5SJakub Kicinski 70687125b5SJakub Kicinski void devl_unlock(struct devlink *devlink) 71687125b5SJakub Kicinski { 72687125b5SJakub Kicinski mutex_unlock(&devlink->lock); 73687125b5SJakub Kicinski } 74687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devl_unlock); 75687125b5SJakub Kicinski 76ed539ba6SJakub Kicinski /** 77ed539ba6SJakub Kicinski * devlink_try_get() - try to obtain a reference on a devlink instance 78ed539ba6SJakub Kicinski * @devlink: instance to reference 79ed539ba6SJakub Kicinski * 80ed539ba6SJakub Kicinski * Obtain a reference on a devlink instance. A reference on a devlink instance 81ed539ba6SJakub Kicinski * only implies that it's safe to take the instance lock. It does not imply 82ed539ba6SJakub Kicinski * that the instance is registered, use devl_is_registered() after taking 83ed539ba6SJakub Kicinski * the instance lock to check registration status. 84ed539ba6SJakub Kicinski */ 85687125b5SJakub Kicinski struct devlink *__must_check devlink_try_get(struct devlink *devlink) 86687125b5SJakub Kicinski { 87687125b5SJakub Kicinski if (refcount_inc_not_zero(&devlink->refcount)) 88687125b5SJakub Kicinski return devlink; 89687125b5SJakub Kicinski return NULL; 90687125b5SJakub Kicinski } 91687125b5SJakub Kicinski 9293e71edfSJakub Kicinski static void devlink_release(struct work_struct *work) 9393e71edfSJakub Kicinski { 9493e71edfSJakub Kicinski struct devlink *devlink; 9593e71edfSJakub Kicinski 9693e71edfSJakub Kicinski devlink = container_of(to_rcu_work(work), struct devlink, rwork); 9793e71edfSJakub Kicinski 9893e71edfSJakub Kicinski mutex_destroy(&devlink->lock); 9993e71edfSJakub Kicinski lockdep_unregister_key(&devlink->lock_key); 10093e71edfSJakub Kicinski kfree(devlink); 10193e71edfSJakub Kicinski } 10293e71edfSJakub Kicinski 103687125b5SJakub Kicinski void devlink_put(struct devlink *devlink) 104687125b5SJakub Kicinski { 105687125b5SJakub Kicinski if (refcount_dec_and_test(&devlink->refcount)) 10693e71edfSJakub Kicinski queue_rcu_work(system_wq, &devlink->rwork); 107687125b5SJakub Kicinski } 108687125b5SJakub Kicinski 109d7727819SJakub Kicinski struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp) 110687125b5SJakub Kicinski { 111d7727819SJakub Kicinski struct devlink *devlink = NULL; 112687125b5SJakub Kicinski 113687125b5SJakub Kicinski rcu_read_lock(); 114687125b5SJakub Kicinski retry: 115d7727819SJakub Kicinski devlink = xa_find(&devlinks, indexp, ULONG_MAX, DEVLINK_REGISTERED); 116687125b5SJakub Kicinski if (!devlink) 117687125b5SJakub Kicinski goto unlock; 118687125b5SJakub Kicinski 119687125b5SJakub Kicinski if (!devlink_try_get(devlink)) 120d7727819SJakub Kicinski goto next; 121687125b5SJakub Kicinski if (!net_eq(devlink_net(devlink), net)) { 122687125b5SJakub Kicinski devlink_put(devlink); 123d7727819SJakub Kicinski goto next; 124687125b5SJakub Kicinski } 125687125b5SJakub Kicinski unlock: 126687125b5SJakub Kicinski rcu_read_unlock(); 127687125b5SJakub Kicinski return devlink; 128687125b5SJakub Kicinski 129d7727819SJakub Kicinski next: 130d7727819SJakub Kicinski (*indexp)++; 131d7727819SJakub Kicinski goto retry; 132687125b5SJakub Kicinski } 133687125b5SJakub Kicinski 134687125b5SJakub Kicinski /** 1359053637eSJakub Kicinski * devl_register - Register devlink instance 136687125b5SJakub Kicinski * @devlink: devlink 137687125b5SJakub Kicinski */ 1389053637eSJakub Kicinski int devl_register(struct devlink *devlink) 139687125b5SJakub Kicinski { 140687125b5SJakub Kicinski ASSERT_DEVLINK_NOT_REGISTERED(devlink); 1419053637eSJakub Kicinski devl_assert_locked(devlink); 142687125b5SJakub Kicinski 143687125b5SJakub Kicinski xa_set_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); 144687125b5SJakub Kicinski devlink_notify_register(devlink); 1459053637eSJakub Kicinski 1469053637eSJakub Kicinski return 0; 1479053637eSJakub Kicinski } 1489053637eSJakub Kicinski EXPORT_SYMBOL_GPL(devl_register); 1499053637eSJakub Kicinski 1509053637eSJakub Kicinski void devlink_register(struct devlink *devlink) 1519053637eSJakub Kicinski { 1529053637eSJakub Kicinski devl_lock(devlink); 1539053637eSJakub Kicinski devl_register(devlink); 1549053637eSJakub Kicinski devl_unlock(devlink); 155687125b5SJakub Kicinski } 156687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devlink_register); 157687125b5SJakub Kicinski 158687125b5SJakub Kicinski /** 1599053637eSJakub Kicinski * devl_unregister - Unregister devlink instance 160687125b5SJakub Kicinski * @devlink: devlink 161687125b5SJakub Kicinski */ 1629053637eSJakub Kicinski void devl_unregister(struct devlink *devlink) 163687125b5SJakub Kicinski { 164687125b5SJakub Kicinski ASSERT_DEVLINK_REGISTERED(devlink); 1659053637eSJakub Kicinski devl_assert_locked(devlink); 166687125b5SJakub Kicinski 167687125b5SJakub Kicinski devlink_notify_unregister(devlink); 168687125b5SJakub Kicinski xa_clear_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); 1699053637eSJakub Kicinski } 1709053637eSJakub Kicinski EXPORT_SYMBOL_GPL(devl_unregister); 1719053637eSJakub Kicinski 1729053637eSJakub Kicinski void devlink_unregister(struct devlink *devlink) 1739053637eSJakub Kicinski { 1749053637eSJakub Kicinski devl_lock(devlink); 1759053637eSJakub Kicinski devl_unregister(devlink); 1769053637eSJakub Kicinski devl_unlock(devlink); 177687125b5SJakub Kicinski } 178687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devlink_unregister); 179687125b5SJakub Kicinski 180687125b5SJakub Kicinski /** 181687125b5SJakub Kicinski * devlink_alloc_ns - Allocate new devlink instance resources 182687125b5SJakub Kicinski * in specific namespace 183687125b5SJakub Kicinski * 184687125b5SJakub Kicinski * @ops: ops 185687125b5SJakub Kicinski * @priv_size: size of user private data 186687125b5SJakub Kicinski * @net: net namespace 187687125b5SJakub Kicinski * @dev: parent device 188687125b5SJakub Kicinski * 189687125b5SJakub Kicinski * Allocate new devlink instance resources, including devlink index 190687125b5SJakub Kicinski * and name. 191687125b5SJakub Kicinski */ 192687125b5SJakub Kicinski struct devlink *devlink_alloc_ns(const struct devlink_ops *ops, 193687125b5SJakub Kicinski size_t priv_size, struct net *net, 194687125b5SJakub Kicinski struct device *dev) 195687125b5SJakub Kicinski { 196687125b5SJakub Kicinski struct devlink *devlink; 197687125b5SJakub Kicinski static u32 last_id; 198687125b5SJakub Kicinski int ret; 199687125b5SJakub Kicinski 200687125b5SJakub Kicinski WARN_ON(!ops || !dev); 201687125b5SJakub Kicinski if (!devlink_reload_actions_valid(ops)) 202687125b5SJakub Kicinski return NULL; 203687125b5SJakub Kicinski 204687125b5SJakub Kicinski devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL); 205687125b5SJakub Kicinski if (!devlink) 206687125b5SJakub Kicinski return NULL; 207687125b5SJakub Kicinski 208687125b5SJakub Kicinski ret = xa_alloc_cyclic(&devlinks, &devlink->index, devlink, xa_limit_31b, 209687125b5SJakub Kicinski &last_id, GFP_KERNEL); 210687125b5SJakub Kicinski if (ret < 0) 211687125b5SJakub Kicinski goto err_xa_alloc; 212687125b5SJakub Kicinski 213687125b5SJakub Kicinski devlink->dev = dev; 214687125b5SJakub Kicinski devlink->ops = ops; 215687125b5SJakub Kicinski xa_init_flags(&devlink->ports, XA_FLAGS_ALLOC); 216a72e17b4SJiri Pirko xa_init_flags(&devlink->params, XA_FLAGS_ALLOC); 217687125b5SJakub Kicinski xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC); 218687125b5SJakub Kicinski write_pnet(&devlink->_net, net); 219687125b5SJakub Kicinski INIT_LIST_HEAD(&devlink->rate_list); 220687125b5SJakub Kicinski INIT_LIST_HEAD(&devlink->linecard_list); 221687125b5SJakub Kicinski INIT_LIST_HEAD(&devlink->sb_list); 222687125b5SJakub Kicinski INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list); 223687125b5SJakub Kicinski INIT_LIST_HEAD(&devlink->resource_list); 224687125b5SJakub Kicinski INIT_LIST_HEAD(&devlink->region_list); 225687125b5SJakub Kicinski INIT_LIST_HEAD(&devlink->reporter_list); 226687125b5SJakub Kicinski INIT_LIST_HEAD(&devlink->trap_list); 227687125b5SJakub Kicinski INIT_LIST_HEAD(&devlink->trap_group_list); 228687125b5SJakub Kicinski INIT_LIST_HEAD(&devlink->trap_policer_list); 22993e71edfSJakub Kicinski INIT_RCU_WORK(&devlink->rwork, devlink_release); 230687125b5SJakub Kicinski lockdep_register_key(&devlink->lock_key); 231687125b5SJakub Kicinski mutex_init(&devlink->lock); 232687125b5SJakub Kicinski lockdep_set_class(&devlink->lock, &devlink->lock_key); 233687125b5SJakub Kicinski refcount_set(&devlink->refcount, 1); 234687125b5SJakub Kicinski 235687125b5SJakub Kicinski return devlink; 236687125b5SJakub Kicinski 237687125b5SJakub Kicinski err_xa_alloc: 238687125b5SJakub Kicinski kfree(devlink); 239687125b5SJakub Kicinski return NULL; 240687125b5SJakub Kicinski } 241687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devlink_alloc_ns); 242687125b5SJakub Kicinski 243687125b5SJakub Kicinski /** 244687125b5SJakub Kicinski * devlink_free - Free devlink instance resources 245687125b5SJakub Kicinski * 246687125b5SJakub Kicinski * @devlink: devlink 247687125b5SJakub Kicinski */ 248687125b5SJakub Kicinski void devlink_free(struct devlink *devlink) 249687125b5SJakub Kicinski { 250687125b5SJakub Kicinski ASSERT_DEVLINK_NOT_REGISTERED(devlink); 251687125b5SJakub Kicinski 252687125b5SJakub Kicinski WARN_ON(!list_empty(&devlink->trap_policer_list)); 253687125b5SJakub Kicinski WARN_ON(!list_empty(&devlink->trap_group_list)); 254687125b5SJakub Kicinski WARN_ON(!list_empty(&devlink->trap_list)); 255687125b5SJakub Kicinski WARN_ON(!list_empty(&devlink->reporter_list)); 256687125b5SJakub Kicinski WARN_ON(!list_empty(&devlink->region_list)); 257687125b5SJakub Kicinski WARN_ON(!list_empty(&devlink->resource_list)); 258687125b5SJakub Kicinski WARN_ON(!list_empty(&devlink->dpipe_table_list)); 259687125b5SJakub Kicinski WARN_ON(!list_empty(&devlink->sb_list)); 260687125b5SJakub Kicinski WARN_ON(!list_empty(&devlink->rate_list)); 261687125b5SJakub Kicinski WARN_ON(!list_empty(&devlink->linecard_list)); 262687125b5SJakub Kicinski WARN_ON(!xa_empty(&devlink->ports)); 263687125b5SJakub Kicinski 264687125b5SJakub Kicinski xa_destroy(&devlink->snapshot_ids); 265a72e17b4SJiri Pirko xa_destroy(&devlink->params); 266687125b5SJakub Kicinski xa_destroy(&devlink->ports); 267687125b5SJakub Kicinski 268687125b5SJakub Kicinski xa_erase(&devlinks, devlink->index); 269687125b5SJakub Kicinski 2709053637eSJakub Kicinski devlink_put(devlink); 271687125b5SJakub Kicinski } 272687125b5SJakub Kicinski EXPORT_SYMBOL_GPL(devlink_free); 273687125b5SJakub Kicinski 274687125b5SJakub Kicinski static void __net_exit devlink_pernet_pre_exit(struct net *net) 275687125b5SJakub Kicinski { 276687125b5SJakub Kicinski struct devlink *devlink; 277687125b5SJakub Kicinski u32 actions_performed; 278687125b5SJakub Kicinski unsigned long index; 279687125b5SJakub Kicinski int err; 280687125b5SJakub Kicinski 281687125b5SJakub Kicinski /* In case network namespace is getting destroyed, reload 282687125b5SJakub Kicinski * all devlink instances from this namespace into init_net. 283687125b5SJakub Kicinski */ 284687125b5SJakub Kicinski devlinks_xa_for_each_registered_get(net, index, devlink) { 2857a54a519SJakub Kicinski devl_lock(devlink); 286ed539ba6SJakub Kicinski err = 0; 287ed539ba6SJakub Kicinski if (devl_is_registered(devlink)) 288687125b5SJakub Kicinski err = devlink_reload(devlink, &init_net, 289687125b5SJakub Kicinski DEVLINK_RELOAD_ACTION_DRIVER_REINIT, 290687125b5SJakub Kicinski DEVLINK_RELOAD_LIMIT_UNSPEC, 291687125b5SJakub Kicinski &actions_performed, NULL); 2927a54a519SJakub Kicinski devl_unlock(devlink); 2937a54a519SJakub Kicinski devlink_put(devlink); 294687125b5SJakub Kicinski if (err && err != -EOPNOTSUPP) 295687125b5SJakub Kicinski pr_warn("Failed to reload devlink instance into init_net\n"); 296687125b5SJakub Kicinski } 297687125b5SJakub Kicinski } 298687125b5SJakub Kicinski 299687125b5SJakub Kicinski static struct pernet_operations devlink_pernet_ops __net_initdata = { 300687125b5SJakub Kicinski .pre_exit = devlink_pernet_pre_exit, 301687125b5SJakub Kicinski }; 302687125b5SJakub Kicinski 303d6352daeSIdo Schimmel static struct notifier_block devlink_port_netdevice_nb = { 304e93c9378SJiri Pirko .notifier_call = devlink_port_netdevice_event, 305e93c9378SJiri Pirko }; 306e93c9378SJiri Pirko 307687125b5SJakub Kicinski static int __init devlink_init(void) 308687125b5SJakub Kicinski { 309687125b5SJakub Kicinski int err; 310687125b5SJakub Kicinski 311687125b5SJakub Kicinski err = genl_register_family(&devlink_nl_family); 312687125b5SJakub Kicinski if (err) 313687125b5SJakub Kicinski goto out; 314687125b5SJakub Kicinski err = register_pernet_subsys(&devlink_pernet_ops); 315e93c9378SJiri Pirko if (err) 316e93c9378SJiri Pirko goto out; 317e93c9378SJiri Pirko err = register_netdevice_notifier(&devlink_port_netdevice_nb); 318687125b5SJakub Kicinski 319687125b5SJakub Kicinski out: 320687125b5SJakub Kicinski WARN_ON(err); 321687125b5SJakub Kicinski return err; 322687125b5SJakub Kicinski } 323687125b5SJakub Kicinski 324687125b5SJakub Kicinski subsys_initcall(devlink_init); 325