| 5487 | } |
| 5488 | |
| 5489 | int |
| 5490 | rte_eth_dev_callback_unregister(uint16_t port_id, |
| 5491 | enum rte_eth_event_type event, |
| 5492 | rte_eth_dev_cb_fn cb_fn, void *cb_arg) |
| 5493 | { |
| 5494 | int ret; |
| 5495 | struct rte_eth_dev *dev; |
| 5496 | struct rte_eth_dev_callback *cb, *next; |
| 5497 | uint16_t next_port; |
| 5498 | uint16_t last_port; |
| 5499 | |
| 5500 | if (cb_fn == NULL) { |
| 5501 | RTE_ETHDEV_LOG(ERR, |
| 5502 | "Cannot unregister ethdev port %u callback from NULL\n", |
| 5503 | port_id); |
| 5504 | return -EINVAL; |
| 5505 | } |
| 5506 | |
| 5507 | if (!rte_eth_dev_is_valid_port(port_id) && port_id != RTE_ETH_ALL) { |
| 5508 | RTE_ETHDEV_LOG(ERR, "Invalid port_id=%d\n", port_id); |
| 5509 | return -EINVAL; |
| 5510 | } |
| 5511 | |
| 5512 | if (port_id == RTE_ETH_ALL) { |
| 5513 | next_port = 0; |
| 5514 | last_port = RTE_MAX_ETHPORTS - 1; |
| 5515 | } else { |
| 5516 | next_port = last_port = port_id; |
| 5517 | } |
| 5518 | |
| 5519 | rte_spinlock_lock(ð_dev_cb_lock); |
| 5520 | |
| 5521 | do { |
| 5522 | dev = &rte_eth_devices[next_port]; |
| 5523 | ret = 0; |
| 5524 | for (cb = TAILQ_FIRST(&dev->link_intr_cbs); cb != NULL; |
| 5525 | cb = next) { |
| 5526 | |
| 5527 | next = TAILQ_NEXT(cb, next); |
| 5528 | |
| 5529 | if (cb->cb_fn != cb_fn || cb->event != event || |
| 5530 | (cb_arg != (void *)-1 && cb->cb_arg != cb_arg)) |
| 5531 | continue; |
| 5532 | |
| 5533 | /* |
| 5534 | * if this callback is not executing right now, |
| 5535 | * then remove it. |
| 5536 | */ |
| 5537 | if (cb->active == 0) { |
| 5538 | TAILQ_REMOVE(&(dev->link_intr_cbs), cb, next); |
| 5539 | rte_free(cb); |
| 5540 | } else { |
| 5541 | ret = -EAGAIN; |
| 5542 | } |
| 5543 | } |
| 5544 | } while (++next_port <= last_port); |
| 5545 | |
| 5546 | rte_spinlock_unlock(ð_dev_cb_lock); |