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.

vdpa/mlx5: Avoid losing link state updates

Current code ignores link state updates if VIRTIO_NET_F_STATUS was not
negotiated. However, link state updates could be received before feature
negotiation was completed , therefore causing link state events to be
lost, possibly leaving the link state down.

Modify the code so link state notifier is registered after DRIVER_OK was
negotiated and carry the registration only if
VIRTIO_NET_F_STATUS was negotiated. Unregister the notifier when the
device is reset.

Fixes: 033779a708f0 ("vdpa/mlx5: make MTU/STATUS presence conditional on feature bits")
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Eli Cohen <elic@nvidia.com>
Message-Id: <20230417110343.138319-1-elic@nvidia.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Eli Cohen and committed by
Michael S. Tsirkin
c384c240 6a8f57ae

+114 -89
+114 -89
drivers/vdpa/mlx5/net/mlx5_vnet.c
··· 2298 2298 } 2299 2299 } 2300 2300 2301 + static u8 query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport) 2302 + { 2303 + u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {}; 2304 + u32 in[MLX5_ST_SZ_DW(query_vport_state_in)] = {}; 2305 + int err; 2306 + 2307 + MLX5_SET(query_vport_state_in, in, opcode, MLX5_CMD_OP_QUERY_VPORT_STATE); 2308 + MLX5_SET(query_vport_state_in, in, op_mod, opmod); 2309 + MLX5_SET(query_vport_state_in, in, vport_number, vport); 2310 + if (vport) 2311 + MLX5_SET(query_vport_state_in, in, other_vport, 1); 2312 + 2313 + err = mlx5_cmd_exec_inout(mdev, query_vport_state, in, out); 2314 + if (err) 2315 + return 0; 2316 + 2317 + return MLX5_GET(query_vport_state_out, out, state); 2318 + } 2319 + 2320 + static bool get_link_state(struct mlx5_vdpa_dev *mvdev) 2321 + { 2322 + if (query_vport_state(mvdev->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0) == 2323 + VPORT_STATE_UP) 2324 + return true; 2325 + 2326 + return false; 2327 + } 2328 + 2329 + static void update_carrier(struct work_struct *work) 2330 + { 2331 + struct mlx5_vdpa_wq_ent *wqent; 2332 + struct mlx5_vdpa_dev *mvdev; 2333 + struct mlx5_vdpa_net *ndev; 2334 + 2335 + wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); 2336 + mvdev = wqent->mvdev; 2337 + ndev = to_mlx5_vdpa_ndev(mvdev); 2338 + if (get_link_state(mvdev)) 2339 + ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); 2340 + else 2341 + ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); 2342 + 2343 + if (ndev->config_cb.callback) 2344 + ndev->config_cb.callback(ndev->config_cb.private); 2345 + 2346 + kfree(wqent); 2347 + } 2348 + 2349 + static int queue_link_work(struct mlx5_vdpa_net *ndev) 2350 + { 2351 + struct mlx5_vdpa_wq_ent *wqent; 2352 + 2353 + wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); 2354 + if (!wqent) 2355 + return -ENOMEM; 2356 + 2357 + wqent->mvdev = &ndev->mvdev; 2358 + INIT_WORK(&wqent->work, update_carrier); 2359 + queue_work(ndev->mvdev.wq, &wqent->work); 2360 + return 0; 2361 + } 2362 + 2363 + static int event_handler(struct notifier_block *nb, unsigned long event, void *param) 2364 + { 2365 + struct mlx5_vdpa_net *ndev = container_of(nb, struct mlx5_vdpa_net, nb); 2366 + struct mlx5_eqe *eqe = param; 2367 + int ret = NOTIFY_DONE; 2368 + 2369 + if (event == MLX5_EVENT_TYPE_PORT_CHANGE) { 2370 + switch (eqe->sub_type) { 2371 + case MLX5_PORT_CHANGE_SUBTYPE_DOWN: 2372 + case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: 2373 + if (queue_link_work(ndev)) 2374 + return NOTIFY_DONE; 2375 + 2376 + ret = NOTIFY_OK; 2377 + break; 2378 + default: 2379 + return NOTIFY_DONE; 2380 + } 2381 + return ret; 2382 + } 2383 + return ret; 2384 + } 2385 + 2386 + static void register_link_notifier(struct mlx5_vdpa_net *ndev) 2387 + { 2388 + if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_STATUS))) 2389 + return; 2390 + 2391 + ndev->nb.notifier_call = event_handler; 2392 + mlx5_notifier_register(ndev->mvdev.mdev, &ndev->nb); 2393 + ndev->nb_registered = true; 2394 + queue_link_work(ndev); 2395 + } 2396 + 2397 + static void unregister_link_notifier(struct mlx5_vdpa_net *ndev) 2398 + { 2399 + if (!ndev->nb_registered) 2400 + return; 2401 + 2402 + ndev->nb_registered = false; 2403 + mlx5_notifier_unregister(ndev->mvdev.mdev, &ndev->nb); 2404 + if (ndev->mvdev.wq) 2405 + flush_workqueue(ndev->mvdev.wq); 2406 + } 2407 + 2301 2408 static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) 2302 2409 { 2303 2410 struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); ··· 2674 2567 mlx5_vdpa_warn(mvdev, "failed to setup control VQ vring\n"); 2675 2568 goto err_setup; 2676 2569 } 2570 + register_link_notifier(ndev); 2677 2571 err = setup_driver(mvdev); 2678 2572 if (err) { 2679 2573 mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); 2680 - goto err_setup; 2574 + goto err_driver; 2681 2575 } 2682 2576 } else { 2683 2577 mlx5_vdpa_warn(mvdev, "did not expect DRIVER_OK to be cleared\n"); ··· 2690 2582 up_write(&ndev->reslock); 2691 2583 return; 2692 2584 2585 + err_driver: 2586 + unregister_link_notifier(ndev); 2693 2587 err_setup: 2694 2588 mlx5_vdpa_destroy_mr(&ndev->mvdev); 2695 2589 ndev->mvdev.status |= VIRTIO_CONFIG_S_FAILED; ··· 2717 2607 mlx5_vdpa_info(mvdev, "performing device reset\n"); 2718 2608 2719 2609 down_write(&ndev->reslock); 2610 + unregister_link_notifier(ndev); 2720 2611 teardown_driver(ndev); 2721 2612 clear_vqs_ready(ndev); 2722 2613 mlx5_vdpa_destroy_mr(&ndev->mvdev); ··· 2972 2861 mlx5_vdpa_info(mvdev, "suspending device\n"); 2973 2862 2974 2863 down_write(&ndev->reslock); 2975 - ndev->nb_registered = false; 2976 - mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); 2977 - flush_workqueue(ndev->mvdev.wq); 2864 + unregister_link_notifier(ndev); 2978 2865 for (i = 0; i < ndev->cur_num_vqs; i++) { 2979 2866 mvq = &ndev->vqs[i]; 2980 2867 suspend_vq(ndev, mvq); ··· 3108 2999 struct mlx5_adev *madev; 3109 3000 struct mlx5_vdpa_net *ndev; 3110 3001 }; 3111 - 3112 - static u8 query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport) 3113 - { 3114 - u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {}; 3115 - u32 in[MLX5_ST_SZ_DW(query_vport_state_in)] = {}; 3116 - int err; 3117 - 3118 - MLX5_SET(query_vport_state_in, in, opcode, MLX5_CMD_OP_QUERY_VPORT_STATE); 3119 - MLX5_SET(query_vport_state_in, in, op_mod, opmod); 3120 - MLX5_SET(query_vport_state_in, in, vport_number, vport); 3121 - if (vport) 3122 - MLX5_SET(query_vport_state_in, in, other_vport, 1); 3123 - 3124 - err = mlx5_cmd_exec_inout(mdev, query_vport_state, in, out); 3125 - if (err) 3126 - return 0; 3127 - 3128 - return MLX5_GET(query_vport_state_out, out, state); 3129 - } 3130 - 3131 - static bool get_link_state(struct mlx5_vdpa_dev *mvdev) 3132 - { 3133 - if (query_vport_state(mvdev->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0) == 3134 - VPORT_STATE_UP) 3135 - return true; 3136 - 3137 - return false; 3138 - } 3139 - 3140 - static void update_carrier(struct work_struct *work) 3141 - { 3142 - struct mlx5_vdpa_wq_ent *wqent; 3143 - struct mlx5_vdpa_dev *mvdev; 3144 - struct mlx5_vdpa_net *ndev; 3145 - 3146 - wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); 3147 - mvdev = wqent->mvdev; 3148 - ndev = to_mlx5_vdpa_ndev(mvdev); 3149 - if (get_link_state(mvdev)) 3150 - ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); 3151 - else 3152 - ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); 3153 - 3154 - if (ndev->nb_registered && ndev->config_cb.callback) 3155 - ndev->config_cb.callback(ndev->config_cb.private); 3156 - 3157 - kfree(wqent); 3158 - } 3159 - 3160 - static int event_handler(struct notifier_block *nb, unsigned long event, void *param) 3161 - { 3162 - struct mlx5_vdpa_net *ndev = container_of(nb, struct mlx5_vdpa_net, nb); 3163 - struct mlx5_eqe *eqe = param; 3164 - int ret = NOTIFY_DONE; 3165 - struct mlx5_vdpa_wq_ent *wqent; 3166 - 3167 - if (event == MLX5_EVENT_TYPE_PORT_CHANGE) { 3168 - if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_STATUS))) 3169 - return NOTIFY_DONE; 3170 - switch (eqe->sub_type) { 3171 - case MLX5_PORT_CHANGE_SUBTYPE_DOWN: 3172 - case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: 3173 - wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); 3174 - if (!wqent) 3175 - return NOTIFY_DONE; 3176 - 3177 - wqent->mvdev = &ndev->mvdev; 3178 - INIT_WORK(&wqent->work, update_carrier); 3179 - queue_work(ndev->mvdev.wq, &wqent->work); 3180 - ret = NOTIFY_OK; 3181 - break; 3182 - default: 3183 - return NOTIFY_DONE; 3184 - } 3185 - return ret; 3186 - } 3187 - return ret; 3188 - } 3189 3002 3190 3003 static int config_func_mtu(struct mlx5_core_dev *mdev, u16 mtu) 3191 3004 { ··· 3289 3258 goto err_res2; 3290 3259 } 3291 3260 3292 - ndev->nb.notifier_call = event_handler; 3293 - mlx5_notifier_register(mdev, &ndev->nb); 3294 - ndev->nb_registered = true; 3295 3261 mvdev->vdev.mdev = &mgtdev->mgtdev; 3296 3262 err = _vdpa_register_device(&mvdev->vdev, max_vqs + 1); 3297 3263 if (err) ··· 3322 3294 3323 3295 mlx5_vdpa_remove_debugfs(ndev->debugfs); 3324 3296 ndev->debugfs = NULL; 3325 - if (ndev->nb_registered) { 3326 - ndev->nb_registered = false; 3327 - mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); 3328 - } 3297 + unregister_link_notifier(ndev); 3329 3298 wq = mvdev->wq; 3330 3299 mvdev->wq = NULL; 3331 3300 destroy_workqueue(wq);