Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mlx4: Replace the mlx4_interface.event callback with a notifier

Use a notifier to implement mlx4_dispatch_event() in preparation to
switch mlx4_en and mlx4_ib to be an auxiliary device.

A problem is that if the mlx4_interface.event callback was replaced with
something as mlx4_adrv.event then the implementation of
mlx4_dispatch_event() would need to acquire a lock on a given device
before executing this callback. That is necessary because otherwise
there is no guarantee that the associated driver cannot get unbound when
the callback is running. However, taking this lock is not possible
because mlx4_dispatch_event() can be invoked from the hardirq context.
Using an atomic notifier allows the driver to accurately record when it
wants to receive these events and solves this problem.

A handler registration is done by both mlx4_en and mlx4_ib at the end of
their mlx4_interface.add callback. This matches the current situation
when mlx4_add_device() would enable events for a given device
immediately after this callback, by adding the device on the
mlx4_priv.list.

Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Tested-by: Leon Romanovsky <leonro@nvidia.com>
Acked-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Petr Pavlu and committed by
David S. Miller
73d68002 7ba189ac

+77 -33
+26 -14
drivers/infiniband/hw/mlx4/main.c
··· 82 82 static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init); 83 83 static enum rdma_link_layer mlx4_ib_port_link_layer(struct ib_device *device, 84 84 u32 port_num); 85 + static int mlx4_ib_event(struct notifier_block *this, unsigned long event, 86 + void *param); 85 87 86 88 static struct workqueue_struct *wq; 87 89 ··· 2838 2836 do_slave_init(ibdev, j, 1); 2839 2837 } 2840 2838 } 2839 + 2840 + /* register mlx4 core notifier */ 2841 + ibdev->mlx_nb.notifier_call = mlx4_ib_event; 2842 + err = mlx4_register_event_notifier(dev, &ibdev->mlx_nb); 2843 + WARN(err, "failed to register mlx4 event notifier (%d)", err); 2844 + 2841 2845 return ibdev; 2842 2846 2843 2847 err_notif: ··· 2960 2952 struct mlx4_ib_dev *ibdev = ibdev_ptr; 2961 2953 int p; 2962 2954 int i; 2955 + 2956 + mlx4_unregister_event_notifier(dev, &ibdev->mlx_nb); 2963 2957 2964 2958 mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) 2965 2959 devlink_port_type_clear(mlx4_get_devlink_port(dev, i)); ··· 3183 3173 } 3184 3174 } 3185 3175 3186 - static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, 3187 - enum mlx4_dev_event event, void *param) 3176 + static int mlx4_ib_event(struct notifier_block *this, unsigned long event, 3177 + void *param) 3188 3178 { 3179 + struct mlx4_ib_dev *ibdev = 3180 + container_of(this, struct mlx4_ib_dev, mlx_nb); 3181 + struct mlx4_dev *dev = ibdev->dev; 3189 3182 struct ib_event ibev; 3190 - struct mlx4_ib_dev *ibdev = to_mdev((struct ib_device *) ibdev_ptr); 3191 3183 struct mlx4_eqe *eqe = NULL; 3192 3184 struct ib_event_work *ew; 3193 3185 int p = 0; ··· 3199 3187 (event == MLX4_DEV_EVENT_PORT_DOWN))) { 3200 3188 ew = kmalloc(sizeof(*ew), GFP_ATOMIC); 3201 3189 if (!ew) 3202 - return; 3190 + return NOTIFY_DONE; 3203 3191 INIT_WORK(&ew->work, handle_bonded_port_state_event); 3204 3192 ew->ib_dev = ibdev; 3205 3193 queue_work(wq, &ew->work); 3206 - return; 3194 + return NOTIFY_DONE; 3207 3195 } 3208 3196 3209 3197 switch (event) { ··· 3220 3208 switch (event) { 3221 3209 case MLX4_DEV_EVENT_PORT_UP: 3222 3210 if (p > ibdev->num_ports) 3223 - return; 3211 + return NOTIFY_DONE; 3224 3212 if (!mlx4_is_slave(dev) && 3225 3213 rdma_port_get_link_layer(&ibdev->ib_dev, p) == 3226 3214 IB_LINK_LAYER_INFINIBAND) { ··· 3235 3223 3236 3224 case MLX4_DEV_EVENT_PORT_DOWN: 3237 3225 if (p > ibdev->num_ports) 3238 - return; 3226 + return NOTIFY_DONE; 3239 3227 ibev.event = IB_EVENT_PORT_ERR; 3240 3228 break; 3241 3229 ··· 3248 3236 case MLX4_DEV_EVENT_PORT_MGMT_CHANGE: 3249 3237 ew = kmalloc(sizeof *ew, GFP_ATOMIC); 3250 3238 if (!ew) 3251 - return; 3239 + return NOTIFY_DONE; 3252 3240 3253 3241 INIT_WORK(&ew->work, handle_port_mgmt_change_event); 3254 3242 memcpy(&ew->ib_eqe, eqe, sizeof *eqe); ··· 3258 3246 queue_work(wq, &ew->work); 3259 3247 else 3260 3248 handle_port_mgmt_change_event(&ew->work); 3261 - return; 3249 + return NOTIFY_DONE; 3262 3250 3263 3251 case MLX4_DEV_EVENT_SLAVE_INIT: 3264 3252 /* here, p is the slave id */ ··· 3274 3262 1); 3275 3263 } 3276 3264 } 3277 - return; 3265 + return NOTIFY_DONE; 3278 3266 3279 3267 case MLX4_DEV_EVENT_SLAVE_SHUTDOWN: 3280 3268 if (mlx4_is_master(dev)) { ··· 3290 3278 } 3291 3279 /* here, p is the slave id */ 3292 3280 do_slave_init(ibdev, p, 0); 3293 - return; 3281 + return NOTIFY_DONE; 3294 3282 3295 3283 default: 3296 - return; 3284 + return NOTIFY_DONE; 3297 3285 } 3298 3286 3299 - ibev.device = ibdev_ptr; 3287 + ibev.device = &ibdev->ib_dev; 3300 3288 ibev.element.port_num = mlx4_is_bonded(ibdev->dev) ? 1 : (u8)p; 3301 3289 3302 3290 ib_dispatch_event(&ibev); 3291 + return NOTIFY_DONE; 3303 3292 } 3304 3293 3305 3294 static struct mlx4_interface mlx4_ib_interface = { 3306 3295 .add = mlx4_ib_add, 3307 3296 .remove = mlx4_ib_remove, 3308 - .event = mlx4_ib_event, 3309 3297 .protocol = MLX4_PROT_IB_IPV6, 3310 3298 .flags = MLX4_INTFF_BONDING 3311 3299 };
+2
drivers/infiniband/hw/mlx4/mlx4_ib.h
··· 38 38 #include <linux/list.h> 39 39 #include <linux/mutex.h> 40 40 #include <linux/idr.h> 41 + #include <linux/notifier.h> 41 42 42 43 #include <rdma/ib_verbs.h> 43 44 #include <rdma/ib_umem.h> ··· 645 644 spinlock_t reset_flow_resource_lock; 646 645 struct list_head qp_list; 647 646 struct mlx4_ib_diag_counters diag_counters[MLX4_DIAG_COUNTERS_TYPES]; 647 + struct notifier_block mlx_nb; 648 648 }; 649 649 650 650 struct ib_event_work {
+18 -8
drivers/net/ethernet/mellanox/mlx4/en_main.c
··· 183 183 } 184 184 } 185 185 186 - static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr, 187 - enum mlx4_dev_event event, void *param) 186 + static int mlx4_en_event(struct notifier_block *this, unsigned long event, 187 + void *param) 188 188 { 189 - struct mlx4_en_dev *mdev = (struct mlx4_en_dev *) endev_ptr; 189 + struct mlx4_en_dev *mdev = 190 + container_of(this, struct mlx4_en_dev, mlx_nb); 191 + struct mlx4_dev *dev = mdev->dev; 190 192 struct mlx4_en_priv *priv; 191 193 int port; 192 194 ··· 207 205 case MLX4_DEV_EVENT_PORT_UP: 208 206 case MLX4_DEV_EVENT_PORT_DOWN: 209 207 if (!mdev->pndev[port]) 210 - return; 208 + return NOTIFY_DONE; 211 209 priv = netdev_priv(mdev->pndev[port]); 212 210 /* To prevent races, we poll the link state in a separate 213 211 task rather than changing it here */ ··· 226 224 default: 227 225 if (port < 1 || port > dev->caps.num_ports || 228 226 !mdev->pndev[port]) 229 - return; 230 - mlx4_warn(mdev, "Unhandled event %d for port %d\n", event, 227 + return NOTIFY_DONE; 228 + mlx4_warn(mdev, "Unhandled event %d for port %d\n", (int)event, 231 229 port); 232 230 } 231 + 232 + return NOTIFY_DONE; 233 233 } 234 234 235 235 static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr) 236 236 { 237 237 struct mlx4_en_dev *mdev = endev_ptr; 238 238 int i; 239 + 240 + mlx4_unregister_event_notifier(dev, &mdev->mlx_nb); 239 241 240 242 mutex_lock(&mdev->state_lock); 241 243 mdev->device_up = false; ··· 282 276 static void *mlx4_en_add(struct mlx4_dev *dev) 283 277 { 284 278 struct mlx4_en_dev *mdev; 285 - int i; 279 + int err, i; 286 280 287 281 printk_once(KERN_INFO "%s", mlx4_en_version); 288 282 ··· 345 339 mutex_init(&mdev->state_lock); 346 340 mdev->device_up = true; 347 341 342 + /* register mlx4 core notifier */ 343 + mdev->mlx_nb.notifier_call = mlx4_en_event; 344 + err = mlx4_register_event_notifier(dev, &mdev->mlx_nb); 345 + WARN(err, "failed to register mlx4 event notifier (%d)", err); 346 + 348 347 return mdev; 349 348 350 349 err_mr: ··· 370 359 static struct mlx4_interface mlx4_en_interface = { 371 360 .add = mlx4_en_add, 372 361 .remove = mlx4_en_remove, 373 - .event = mlx4_en_event, 374 362 .protocol = MLX4_PROT_ETH, 375 363 .activate = mlx4_en_activate, 376 364 };
+19 -9
drivers/net/ethernet/mellanox/mlx4/intf.c
··· 183 183 void *param) 184 184 { 185 185 struct mlx4_priv *priv = mlx4_priv(dev); 186 - struct mlx4_device_context *dev_ctx; 187 - unsigned long flags; 188 186 189 - spin_lock_irqsave(&priv->ctx_lock, flags); 190 - 191 - list_for_each_entry(dev_ctx, &priv->ctx_list, list) 192 - if (dev_ctx->intf->event) 193 - dev_ctx->intf->event(dev, dev_ctx->context, type, param); 194 - 195 - spin_unlock_irqrestore(&priv->ctx_lock, flags); 187 + atomic_notifier_call_chain(&priv->event_nh, type, param); 196 188 } 189 + 190 + int mlx4_register_event_notifier(struct mlx4_dev *dev, 191 + struct notifier_block *nb) 192 + { 193 + struct mlx4_priv *priv = mlx4_priv(dev); 194 + 195 + return atomic_notifier_chain_register(&priv->event_nh, nb); 196 + } 197 + EXPORT_SYMBOL(mlx4_register_event_notifier); 198 + 199 + int mlx4_unregister_event_notifier(struct mlx4_dev *dev, 200 + struct notifier_block *nb) 201 + { 202 + struct mlx4_priv *priv = mlx4_priv(dev); 203 + 204 + return atomic_notifier_chain_unregister(&priv->event_nh, nb); 205 + } 206 + EXPORT_SYMBOL(mlx4_unregister_event_notifier); 197 207 198 208 int mlx4_register_device(struct mlx4_dev *dev) 199 209 {
+2
drivers/net/ethernet/mellanox/mlx4/main.c
··· 3378 3378 INIT_LIST_HEAD(&priv->ctx_list); 3379 3379 spin_lock_init(&priv->ctx_lock); 3380 3380 3381 + ATOMIC_INIT_NOTIFIER_HEAD(&priv->event_nh); 3382 + 3381 3383 mutex_init(&priv->port_mutex); 3382 3384 mutex_init(&priv->bond_mutex); 3383 3385
+2
drivers/net/ethernet/mellanox/mlx4/mlx4.h
··· 47 47 #include <linux/spinlock.h> 48 48 #include <net/devlink.h> 49 49 #include <linux/rwsem.h> 50 + #include <linux/notifier.h> 50 51 51 52 #include <linux/mlx4/device.h> 52 53 #include <linux/mlx4/driver.h> ··· 879 878 struct list_head dev_list; 880 879 struct list_head ctx_list; 881 880 spinlock_t ctx_lock; 881 + struct atomic_notifier_head event_nh; 882 882 883 883 int pci_dev_data; 884 884 int removed;
+2
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
··· 49 49 #include <linux/ptp_clock_kernel.h> 50 50 #include <linux/irq.h> 51 51 #include <net/xdp.h> 52 + #include <linux/notifier.h> 52 53 53 54 #include <linux/mlx4/device.h> 54 55 #include <linux/mlx4/qp.h> ··· 434 433 struct ptp_clock *ptp_clock; 435 434 struct ptp_clock_info ptp_clock_info; 436 435 struct notifier_block netdev_nb; 436 + struct notifier_block mlx_nb; 437 437 }; 438 438 439 439
+6 -2
include/linux/mlx4/driver.h
··· 34 34 #define MLX4_DRIVER_H 35 35 36 36 #include <net/devlink.h> 37 + #include <linux/notifier.h> 37 38 #include <linux/mlx4/device.h> 38 39 39 40 struct mlx4_dev; ··· 58 57 struct mlx4_interface { 59 58 void * (*add) (struct mlx4_dev *dev); 60 59 void (*remove)(struct mlx4_dev *dev, void *context); 61 - void (*event) (struct mlx4_dev *dev, void *context, 62 - enum mlx4_dev_event event, void *param); 63 60 void (*activate)(struct mlx4_dev *dev, void *context); 64 61 struct list_head list; 65 62 enum mlx4_protocol protocol; ··· 85 86 }; 86 87 87 88 int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p); 89 + 90 + int mlx4_register_event_notifier(struct mlx4_dev *dev, 91 + struct notifier_block *nb); 92 + int mlx4_unregister_event_notifier(struct mlx4_dev *dev, 93 + struct notifier_block *nb); 88 94 89 95 struct devlink_port *mlx4_get_devlink_port(struct mlx4_dev *dev, int port); 90 96