| 5418 | } |
| 5419 | |
| 5420 | int |
| 5421 | rte_eth_dev_callback_register(uint16_t port_id, |
| 5422 | enum rte_eth_event_type event, |
| 5423 | rte_eth_dev_cb_fn cb_fn, void *cb_arg) |
| 5424 | { |
| 5425 | struct rte_eth_dev *dev; |
| 5426 | struct rte_eth_dev_callback *user_cb; |
| 5427 | uint16_t next_port; |
| 5428 | uint16_t last_port; |
| 5429 | |
| 5430 | if (cb_fn == NULL) { |
| 5431 | RTE_ETHDEV_LOG(ERR, |
| 5432 | "Cannot register ethdev port %u callback from NULL\n", |
| 5433 | port_id); |
| 5434 | return -EINVAL; |
| 5435 | } |
| 5436 | |
| 5437 | if (!rte_eth_dev_is_valid_port(port_id) && port_id != RTE_ETH_ALL) { |
| 5438 | RTE_ETHDEV_LOG(ERR, "Invalid port_id=%d\n", port_id); |
| 5439 | return -EINVAL; |
| 5440 | } |
| 5441 | |
| 5442 | if (port_id == RTE_ETH_ALL) { |
| 5443 | next_port = 0; |
| 5444 | last_port = RTE_MAX_ETHPORTS - 1; |
| 5445 | } else { |
| 5446 | next_port = last_port = port_id; |
| 5447 | } |
| 5448 | |
| 5449 | rte_spinlock_lock(ð_dev_cb_lock); |
| 5450 | |
| 5451 | do { |
| 5452 | dev = &rte_eth_devices[next_port]; |
| 5453 | |
| 5454 | TAILQ_FOREACH(user_cb, &(dev->link_intr_cbs), next) { |
| 5455 | if (user_cb->cb_fn == cb_fn && |
| 5456 | user_cb->cb_arg == cb_arg && |
| 5457 | user_cb->event == event) { |
| 5458 | break; |
| 5459 | } |
| 5460 | } |
| 5461 | |
| 5462 | /* create a new callback. */ |
| 5463 | if (user_cb == NULL) { |
| 5464 | user_cb = rte_zmalloc("INTR_USER_CALLBACK", |
| 5465 | sizeof(struct rte_eth_dev_callback), 0); |
| 5466 | if (user_cb != NULL) { |
| 5467 | user_cb->cb_fn = cb_fn; |
| 5468 | user_cb->cb_arg = cb_arg; |
| 5469 | user_cb->event = event; |
| 5470 | TAILQ_INSERT_TAIL(&(dev->link_intr_cbs), |
| 5471 | user_cb, next); |
| 5472 | } else { |
| 5473 | rte_spinlock_unlock(ð_dev_cb_lock); |
| 5474 | rte_eth_dev_callback_unregister(port_id, event, |
| 5475 | cb_fn, cb_arg); |
| 5476 | return -ENOMEM; |
| 5477 | } |