/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2016-2020 Intel Corporation */ #include #include #include #include "dlb2_priv.h" #include "dlb2_inline_fns.h" enum dlb2_xstats_type { /* common to device and port */ rx_ok, /**< Receive an event */ rx_drop, /**< Error bit set in received QE */ rx_interrupt_wait, /**< Wait on an interrupt */ rx_umonitor_umwait, /**< Block using umwait */ tx_ok, /**< Transmit an event */ total_polls, /**< Call dequeue_burst */ zero_polls, /**< Call dequeue burst and return 0 */ tx_nospc_ldb_hw_credits, /**< Insufficient LDB h/w credits */ tx_nospc_dir_hw_credits, /**< Insufficient DIR h/w credits */ tx_nospc_inflight_max, /**< Reach the new_event_threshold */ tx_nospc_new_event_limit, /**< Insufficient s/w credits */ tx_nospc_inflight_credits, /**< Port has too few s/w credits */ /* device specific */ nb_events_limit, inflight_events, ldb_pool_size, dir_pool_size, /* port specific */ tx_new, /**< Send an OP_NEW event */ tx_fwd, /**< Send an OP_FORWARD event */ tx_rel, /**< Send an OP_RELEASE event */ tx_implicit_rel, /**< Issue an implicit event release */ tx_sched_ordered, /**< Send a SCHED_TYPE_ORDERED event */ tx_sched_unordered, /**< Send a SCHED_TYPE_PARALLEL event */ tx_sched_atomic, /**< Send a SCHED_TYPE_ATOMIC event */ tx_sched_directed, /**< Send a directed event */ tx_invalid, /**< Send an event with an invalid op */ outstanding_releases, /**< # of releases a port owes */ max_outstanding_releases, /**< max # of releases a port can owe */ rx_sched_ordered, /**< Dequeue an ordered event */ rx_sched_unordered, /**< Dequeue an unordered event */ rx_sched_atomic, /**< Dequeue an atomic event */ rx_sched_directed, /**< Dequeue an directed event */ rx_sched_invalid, /**< Dequeue event sched type invalid */ /* common to port and queue */ is_configured, /**< Port is configured */ is_load_balanced, /**< Port is LDB */ hw_id, /**< Hardware ID */ /* queue specific */ num_links, /**< Number of ports linked */ sched_type, /**< Queue sched type */ enq_ok, /**< # events enqueued to the queue */ current_depth, /**< Current queue depth */ depth_threshold, /**< Programmed depth threshold */ depth_le50_threshold, /**< Depth LE to 50% of the configured hardware threshold */ depth_gt50_le75_threshold, /**< Depth GT 50%, but LE to 75% of the configured hardware threshold */ depth_gt75_le100_threshold, /**< Depth GT 75%. but LE to the configured hardware threshold */ depth_gt100_threshold /**< Depth GT 100% of the configured hw threshold */ }; typedef uint64_t (*dlb2_xstats_fn)(struct dlb2_eventdev *dlb2, uint16_t obj_idx, /* port or queue id */ enum dlb2_xstats_type stat, int extra_arg); enum dlb2_xstats_fn_type { DLB2_XSTATS_FN_DEV, DLB2_XSTATS_FN_PORT, DLB2_XSTATS_FN_QUEUE }; struct dlb2_xstats_entry { struct rte_event_dev_xstats_name name; uint64_t reset_value; /* an offset to be taken away to emulate resets */ enum dlb2_xstats_fn_type fn_id; enum dlb2_xstats_type stat; enum rte_event_dev_xstats_mode mode; int extra_arg; uint16_t obj_idx; uint8_t reset_allowed; /* when set, this value can be reset */ }; /* Some device stats are simply a summation of the corresponding port values */ static uint64_t dlb2_device_traffic_stat_get(struct dlb2_eventdev *dlb2, int which_stat) { int i; uint64_t val = 0; for (i = 0; i < DLB2_MAX_NUM_PORTS; i++) { struct dlb2_eventdev_port *port = &dlb2->ev_ports[i]; if (!port->setup_done) continue; switch (which_stat) { case rx_ok: val += port->stats.traffic.rx_ok; break; case rx_drop: val += port->stats.traffic.rx_drop; break; case rx_interrupt_wait: val += port->stats.traffic.rx_interrupt_wait; break; case rx_umonitor_umwait: val += port->stats.traffic.rx_umonitor_umwait; break; case tx_ok: val += port->stats.traffic.tx_ok; break; case total_polls: val += port->stats.traffic.total_polls; break; case zero_polls: val += port->stats.traffic.zero_polls; break; case tx_nospc_ldb_hw_credits: val += port->stats.traffic.tx_nospc_ldb_hw_credits; break; case tx_nospc_dir_hw_credits: val += port->stats.traffic.tx_nospc_dir_hw_credits; break; case tx_nospc_inflight_max: val += port->stats.traffic.tx_nospc_inflight_max; break; case tx_nospc_new_event_limit: val += port->stats.traffic.tx_nospc_new_event_limit; break; case tx_nospc_inflight_credits: val += port->stats.traffic.tx_nospc_inflight_credits; break; default: return -1; } } return val; } static uint64_t get_dev_stat(struct dlb2_eventdev *dlb2, uint16_t obj_idx __rte_unused, enum dlb2_xstats_type type, int extra_arg __rte_unused) { switch (type) { case rx_ok: case rx_drop: case rx_interrupt_wait: case rx_umonitor_umwait: case tx_ok: case total_polls: case zero_polls: case tx_nospc_ldb_hw_credits: case tx_nospc_dir_hw_credits: case tx_nospc_inflight_max: case tx_nospc_new_event_limit: case tx_nospc_inflight_credits: return dlb2_device_traffic_stat_get(dlb2, type); case nb_events_limit: return dlb2->new_event_limit; case inflight_events: return __atomic_load_n(&dlb2->inflights, __ATOMIC_SEQ_CST); case ldb_pool_size: return dlb2->num_ldb_credits; case dir_pool_size: return dlb2->num_dir_credits; default: return -1; } } static uint64_t get_port_stat(struct dlb2_eventdev *dlb2, uint16_t obj_idx, enum dlb2_xstats_type type, int extra_arg __rte_unused) { struct dlb2_eventdev_port *ev_port = &dlb2->ev_ports[obj_idx]; switch (type) { case rx_ok: return ev_port->stats.traffic.rx_ok; case rx_drop: return ev_port->stats.traffic.rx_drop; case rx_interrupt_wait: return ev_port->stats.traffic.rx_interrupt_wait; case rx_umonitor_umwait: return ev_port->stats.traffic.rx_umonitor_umwait; case tx_ok: return ev_port->stats.traffic.tx_ok; case total_polls: return ev_port->stats.traffic.total_polls; case zero_polls: return ev_port->stats.traffic.zero_polls; case tx_nospc_ldb_hw_credits: return ev_port->stats.traffic.tx_nospc_ldb_hw_credits; case tx_nospc_dir_hw_credits: return ev_port->stats.traffic.tx_nospc_dir_hw_credits; case tx_nospc_inflight_max: return ev_port->stats.traffic.tx_nospc_inflight_max; case tx_nospc_new_event_limit: return ev_port->stats.traffic.tx_nospc_new_event_limit; case tx_nospc_inflight_credits: return ev_port->stats.traffic.tx_nospc_inflight_credits; case is_configured: return ev_port->setup_done; case is_load_balanced: return !ev_port->qm_port.is_directed; case hw_id: return ev_port->qm_port.id; case tx_new: return ev_port->stats.tx_op_cnt[RTE_EVENT_OP_NEW]; case tx_fwd: return ev_port->stats.tx_op_cnt[RTE_EVENT_OP_FORWARD]; case tx_rel: return ev_port->stats.tx_op_cnt[RTE_EVENT_OP_RELEASE]; case tx_implicit_rel: return ev_port->stats.tx_implicit_rel; case tx_sched_ordered: return ev_port->stats.tx_sched_cnt[DLB2_SCHED_ORDERED]; case tx_sched_unordered: return ev_port->stats.tx_sched_cnt[DLB2_SCHED_UNORDERED]; case tx_sched_atomic: return ev_port->stats.tx_sched_cnt[DLB2_SCHED_ATOMIC]; case tx_sched_directed: return ev_port->stats.tx_sched_cnt[DLB2_SCHED_DIRECTED]; case tx_invalid: return ev_port->stats.tx_invalid; case outstanding_releases: return ev_port->outstanding_releases; case max_outstanding_releases: return DLB2_NUM_HIST_LIST_ENTRIES_PER_LDB_PORT; case rx_sched_ordered: return ev_port->stats.rx_sched_cnt[DLB2_SCHED_ORDERED]; case rx_sched_unordered: return ev_port->stats.rx_sched_cnt[DLB2_SCHED_UNORDERED]; case rx_sched_atomic: return ev_port->stats.rx_sched_cnt[DLB2_SCHED_ATOMIC]; case rx_sched_directed: return ev_port->stats.rx_sched_cnt[DLB2_SCHED_DIRECTED]; case rx_sched_invalid: return ev_port->stats.rx_sched_invalid; default: return -1; } } static uint64_t dlb2_get_threshold_stat(struct dlb2_eventdev *dlb2, int qid, int stat) { int port = 0; uint64_t tally = 0; for (port = 0; port < DLB2_MAX_NUM_PORTS; port++) tally += dlb2->ev_ports[port].stats.queue[qid].qid_depth[stat]; return tally; } static uint64_t dlb2_get_enq_ok_stat(struct dlb2_eventdev *dlb2, int qid) { int port = 0; uint64_t enq_ok_tally = 0; for (port = 0; port < DLB2_MAX_NUM_PORTS; port++) enq_ok_tally += dlb2->ev_ports[port].stats.queue[qid].enq_ok; return enq_ok_tally; } static uint64_t get_queue_stat(struct dlb2_eventdev *dlb2, uint16_t obj_idx, enum dlb2_xstats_type type, int extra_arg __rte_unused) { struct dlb2_eventdev_queue *ev_queue = &dlb2->ev_queues[obj_idx]; switch (type) { case is_configured: return ev_queue->setup_done; case is_load_balanced: return !ev_queue->qm_queue.is_directed; case hw_id: return ev_queue->qm_queue.id; case num_links: return ev_queue->num_links; case sched_type: return ev_queue->qm_queue.sched_type; case enq_ok: return dlb2_get_enq_ok_stat(dlb2, obj_idx); case current_depth: return dlb2_get_queue_depth(dlb2, ev_queue); case depth_threshold: return ev_queue->depth_threshold; case depth_le50_threshold: return dlb2_get_threshold_stat(dlb2, ev_queue->id, DLB2_QID_DEPTH_LE50); case depth_gt50_le75_threshold: return dlb2_get_threshold_stat(dlb2, ev_queue->id, DLB2_QID_DEPTH_GT50_LE75); case depth_gt75_le100_threshold: return dlb2_get_threshold_stat(dlb2, ev_queue->id, DLB2_QID_DEPTH_GT75_LE100); case depth_gt100_threshold: return dlb2_get_threshold_stat(dlb2, ev_queue->id, DLB2_QID_DEPTH_GT100); default: return -1; } } int dlb2_xstats_init(struct dlb2_eventdev *dlb2) { /* * define the stats names and types. Used to build up the device * xstats array * There are multiple set of stats: * - device-level, * - per-port, * - per-qid, * * For each of these sets, we have three parallel arrays, one for the * names, the other for the stat type parameter to be passed in the fn * call to get that stat. The third array allows resetting or not. * All these arrays must be kept in sync */ static const char * const dev_stats[] = { "rx_ok", "rx_drop", "rx_interrupt_wait", "rx_umonitor_umwait", "tx_ok", "total_polls", "zero_polls", "tx_nospc_ldb_hw_credits", "tx_nospc_dir_hw_credits", "tx_nospc_inflight_max", "tx_nospc_new_event_limit", "tx_nospc_inflight_credits", "nb_events_limit", "inflight_events", "ldb_pool_size", "dir_pool_size", }; static const enum dlb2_xstats_type dev_types[] = { rx_ok, rx_drop, rx_interrupt_wait, rx_umonitor_umwait, tx_ok, total_polls, zero_polls, tx_nospc_ldb_hw_credits, tx_nospc_dir_hw_credits, tx_nospc_inflight_max, tx_nospc_new_event_limit, tx_nospc_inflight_credits, nb_events_limit, inflight_events, ldb_pool_size, dir_pool_size, }; /* Note: generated device stats are not allowed to be reset. */ static const uint8_t dev_reset_allowed[] = { 0, /* rx_ok */ 0, /* rx_drop */ 0, /* rx_interrupt_wait */ 0, /* rx_umonitor_umwait */ 0, /* tx_ok */ 0, /* total_polls */ 0, /* zero_polls */ 0, /* tx_nospc_ldb_hw_credits */ 0, /* tx_nospc_dir_hw_credits */ 0, /* tx_nospc_inflight_max */ 0, /* tx_nospc_new_event_limit */ 0, /* tx_nospc_inflight_credits */ 0, /* nb_events_limit */ 0, /* inflight_events */ 0, /* ldb_pool_size */ 0, /* dir_pool_size */ }; static const char * const port_stats[] = { "is_configured", "is_load_balanced", "hw_id", "rx_ok", "rx_drop", "rx_interrupt_wait", "rx_umonitor_umwait", "tx_ok", "total_polls", "zero_polls", "tx_nospc_ldb_hw_credits", "tx_nospc_dir_hw_credits", "tx_nospc_inflight_max", "tx_nospc_new_event_limit", "tx_nospc_inflight_credits", "tx_new", "tx_fwd", "tx_rel", "tx_implicit_rel", "tx_sched_ordered", "tx_sched_unordered", "tx_sched_atomic", "tx_sched_directed", "tx_invalid", "outstanding_releases", "max_outstanding_releases", "rx_sched_ordered", "rx_sched_unordered", "rx_sched_atomic", "rx_sched_directed", "rx_sched_invalid" }; static const enum dlb2_xstats_type port_types[] = { is_configured, is_load_balanced, hw_id, rx_ok, rx_drop, rx_interrupt_wait, rx_umonitor_umwait, tx_ok, total_polls, zero_polls, tx_nospc_ldb_hw_credits, tx_nospc_dir_hw_credits, tx_nospc_inflight_max, tx_nospc_new_event_limit, tx_nospc_inflight_credits, tx_new, tx_fwd, tx_rel, tx_implicit_rel, tx_sched_ordered, tx_sched_unordered, tx_sched_atomic, tx_sched_directed, tx_invalid, outstanding_releases, max_outstanding_releases, rx_sched_ordered, rx_sched_unordered, rx_sched_atomic, rx_sched_directed, rx_sched_invalid }; static const uint8_t port_reset_allowed[] = { 0, /* is_configured */ 0, /* is_load_balanced */ 0, /* hw_id */ 1, /* rx_ok */ 1, /* rx_drop */ 1, /* rx_interrupt_wait */ 1, /* rx_umonitor_umwait */ 1, /* tx_ok */ 1, /* total_polls */ 1, /* zero_polls */ 1, /* tx_nospc_ldb_hw_credits */ 1, /* tx_nospc_dir_hw_credits */ 1, /* tx_nospc_inflight_max */ 1, /* tx_nospc_new_event_limit */ 1, /* tx_nospc_inflight_credits */ 1, /* tx_new */ 1, /* tx_fwd */ 1, /* tx_rel */ 1, /* tx_implicit_rel */ 1, /* tx_sched_ordered */ 1, /* tx_sched_unordered */ 1, /* tx_sched_atomic */ 1, /* tx_sched_directed */ 1, /* tx_invalid */ 0, /* outstanding_releases */ 0, /* max_outstanding_releases */ 1, /* rx_sched_ordered */ 1, /* rx_sched_unordered */ 1, /* rx_sched_atomic */ 1, /* rx_sched_directed */ 1 /* rx_sched_invalid */ }; /* QID specific stats */ static const char * const qid_stats[] = { "is_configured", "is_load_balanced", "hw_id", "num_links", "sched_type", "enq_ok", "current_depth", "depth_threshold", "depth_le50_threshold", "depth_gt50_le75_threshold", "depth_gt75_le100_threshold", "depth_gt100_threshold", }; static const enum dlb2_xstats_type qid_types[] = { is_configured, is_load_balanced, hw_id, num_links, sched_type, enq_ok, current_depth, depth_threshold, depth_le50_threshold, depth_gt50_le75_threshold, depth_gt75_le100_threshold, depth_gt100_threshold, }; static const uint8_t qid_reset_allowed[] = { 0, /* is_configured */ 0, /* is_load_balanced */ 0, /* hw_id */ 0, /* num_links */ 0, /* sched_type */ 1, /* enq_ok */ 0, /* current_depth */ 0, /* depth_threshold */ 1, /* depth_le50_threshold */ 1, /* depth_gt50_le75_threshold */ 1, /* depth_gt75_le100_threshold */ 1, /* depth_gt100_threshold */ }; /* ---- end of stat definitions ---- */ /* check sizes, since a missed comma can lead to strings being * joined by the compiler. */ RTE_BUILD_BUG_ON(RTE_DIM(dev_stats) != RTE_DIM(dev_types)); RTE_BUILD_BUG_ON(RTE_DIM(port_stats) != RTE_DIM(port_types)); RTE_BUILD_BUG_ON(RTE_DIM(qid_stats) != RTE_DIM(qid_types)); RTE_BUILD_BUG_ON(RTE_DIM(dev_stats) != RTE_DIM(dev_reset_allowed)); RTE_BUILD_BUG_ON(RTE_DIM(port_stats) != RTE_DIM(port_reset_allowed)); RTE_BUILD_BUG_ON(RTE_DIM(qid_stats) != RTE_DIM(qid_reset_allowed)); /* other vars */ const unsigned int count = RTE_DIM(dev_stats) + DLB2_MAX_NUM_PORTS * RTE_DIM(port_stats) + DLB2_MAX_NUM_QUEUES * RTE_DIM(qid_stats); unsigned int i, port, qid, stat_id = 0; dlb2->xstats = rte_zmalloc_socket(NULL, sizeof(dlb2->xstats[0]) * count, 0, dlb2->qm_instance.info.socket_id); if (dlb2->xstats == NULL) return -ENOMEM; #define sname dlb2->xstats[stat_id].name.name for (i = 0; i < RTE_DIM(dev_stats); i++, stat_id++) { dlb2->xstats[stat_id] = (struct dlb2_xstats_entry) { .fn_id = DLB2_XSTATS_FN_DEV, .stat = dev_types[i], .mode = RTE_EVENT_DEV_XSTATS_DEVICE, .reset_allowed = dev_reset_allowed[i], }; snprintf(sname, sizeof(sname), "dev_%s", dev_stats[i]); } dlb2->xstats_count_mode_dev = stat_id; for (port = 0; port < DLB2_MAX_NUM_PORTS; port++) { dlb2->xstats_offset_for_port[port] = stat_id; uint32_t count_offset = stat_id; for (i = 0; i < RTE_DIM(port_stats); i++, stat_id++) { dlb2->xstats[stat_id] = (struct dlb2_xstats_entry){ .fn_id = DLB2_XSTATS_FN_PORT, .obj_idx = port, .stat = port_types[i], .mode = RTE_EVENT_DEV_XSTATS_PORT, .reset_allowed = port_reset_allowed[i], }; snprintf(sname, sizeof(sname), "port_%u_%s", port, port_stats[i]); } dlb2->xstats_count_per_port[port] = stat_id - count_offset; } dlb2->xstats_count_mode_port = stat_id - dlb2->xstats_count_mode_dev; for (qid = 0; qid < DLB2_MAX_NUM_QUEUES; qid++) { uint32_t count_offset = stat_id; dlb2->xstats_offset_for_qid[qid] = stat_id; for (i = 0; i < RTE_DIM(qid_stats); i++, stat_id++) { dlb2->xstats[stat_id] = (struct dlb2_xstats_entry){ .fn_id = DLB2_XSTATS_FN_QUEUE, .obj_idx = qid, .stat = qid_types[i], .mode = RTE_EVENT_DEV_XSTATS_QUEUE, .reset_allowed = qid_reset_allowed[i], }; snprintf(sname, sizeof(sname), "qid_%u_%s", qid, qid_stats[i]); } dlb2->xstats_count_per_qid[qid] = stat_id - count_offset; } dlb2->xstats_count_mode_queue = stat_id - (dlb2->xstats_count_mode_dev + dlb2->xstats_count_mode_port); #undef sname dlb2->xstats_count = stat_id; return 0; } void dlb2_xstats_uninit(struct dlb2_eventdev *dlb2) { rte_free(dlb2->xstats); dlb2->xstats_count = 0; } int dlb2_eventdev_xstats_get_names(const struct rte_eventdev *dev, enum rte_event_dev_xstats_mode mode, uint8_t queue_port_id, struct rte_event_dev_xstats_name *xstats_names, unsigned int *ids, unsigned int size) { const struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev); unsigned int i; unsigned int xidx = 0; uint32_t xstats_mode_count = 0; uint32_t start_offset = 0; switch (mode) { case RTE_EVENT_DEV_XSTATS_DEVICE: xstats_mode_count = dlb2->xstats_count_mode_dev; break; case RTE_EVENT_DEV_XSTATS_PORT: if (queue_port_id >= DLB2_MAX_NUM_PORTS) break; xstats_mode_count = dlb2->xstats_count_per_port[queue_port_id]; start_offset = dlb2->xstats_offset_for_port[queue_port_id]; break; case RTE_EVENT_DEV_XSTATS_QUEUE: #if (DLB2_MAX_NUM_QUEUES <= 255) /* max 8 bit value */ if (queue_port_id >= DLB2_MAX_NUM_QUEUES) break; #endif xstats_mode_count = dlb2->xstats_count_per_qid[queue_port_id]; start_offset = dlb2->xstats_offset_for_qid[queue_port_id]; break; default: return -EINVAL; }; if (xstats_mode_count > size || ids == NULL || xstats_names == NULL) return xstats_mode_count; for (i = 0; i < dlb2->xstats_count && xidx < size; i++) { if (dlb2->xstats[i].mode != mode) continue; if (mode != RTE_EVENT_DEV_XSTATS_DEVICE && queue_port_id != dlb2->xstats[i].obj_idx) continue; xstats_names[xidx] = dlb2->xstats[i].name; if (ids) ids[xidx] = start_offset + xidx; xidx++; } return xidx; } static int dlb2_xstats_update(struct dlb2_eventdev *dlb2, enum rte_event_dev_xstats_mode mode, uint8_t queue_port_id, const unsigned int ids[], uint64_t values[], unsigned int n, const uint32_t reset) { unsigned int i; unsigned int xidx = 0; uint32_t xstats_mode_count = 0; switch (mode) { case RTE_EVENT_DEV_XSTATS_DEVICE: xstats_mode_count = dlb2->xstats_count_mode_dev; break; case RTE_EVENT_DEV_XSTATS_PORT: if (queue_port_id >= DLB2_MAX_NUM_PORTS) goto invalid_value; xstats_mode_count = dlb2->xstats_count_per_port[queue_port_id]; break; case RTE_EVENT_DEV_XSTATS_QUEUE: #if (DLB2_MAX_NUM_QUEUES <= 255) /* max 8 bit value */ if (queue_port_id >= DLB2_MAX_NUM_QUEUES) goto invalid_value; #endif xstats_mode_count = dlb2->xstats_count_per_qid[queue_port_id]; break; default: goto invalid_value; }; for (i = 0; i < n && xidx < xstats_mode_count; i++) { struct dlb2_xstats_entry *xs = &dlb2->xstats[ids[i]]; dlb2_xstats_fn fn; if (ids[i] > dlb2->xstats_count || xs->mode != mode) continue; if (mode != RTE_EVENT_DEV_XSTATS_DEVICE && queue_port_id != xs->obj_idx) continue; switch (xs->fn_id) { case DLB2_XSTATS_FN_DEV: fn = get_dev_stat; break; case DLB2_XSTATS_FN_PORT: fn = get_port_stat; break; case DLB2_XSTATS_FN_QUEUE: fn = get_queue_stat; break; default: DLB2_LOG_ERR("Unexpected xstat fn_id %d\n", xs->fn_id); goto invalid_value; } uint64_t val = fn(dlb2, xs->obj_idx, xs->stat, xs->extra_arg) - xs->reset_value; if (values) values[xidx] = val; if (xs->reset_allowed && reset) xs->reset_value += val; xidx++; } return xidx; invalid_value: return -EINVAL; } int dlb2_eventdev_xstats_get(const struct rte_eventdev *dev, enum rte_event_dev_xstats_mode mode, uint8_t queue_port_id, const unsigned int ids[], uint64_t values[], unsigned int n) { struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev); const uint32_t reset = 0; return dlb2_xstats_update(dlb2, mode, queue_port_id, ids, values, n, reset); } uint64_t dlb2_eventdev_xstats_get_by_name(const struct rte_eventdev *dev, const char *name, unsigned int *id) { struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev); unsigned int i; dlb2_xstats_fn fn; for (i = 0; i < dlb2->xstats_count; i++) { struct dlb2_xstats_entry *xs = &dlb2->xstats[i]; if (strncmp(xs->name.name, name, RTE_EVENT_DEV_XSTATS_NAME_SIZE) == 0){ if (id != NULL) *id = i; switch (xs->fn_id) { case DLB2_XSTATS_FN_DEV: fn = get_dev_stat; break; case DLB2_XSTATS_FN_PORT: fn = get_port_stat; break; case DLB2_XSTATS_FN_QUEUE: fn = get_queue_stat; break; default: DLB2_LOG_ERR("Unexpected xstat fn_id %d\n", xs->fn_id); return (uint64_t)-1; } return fn(dlb2, xs->obj_idx, xs->stat, xs->extra_arg) - xs->reset_value; } } if (id != NULL) *id = (uint32_t)-1; return (uint64_t)-1; } static void dlb2_xstats_reset_range(struct dlb2_eventdev *dlb2, uint32_t start, uint32_t num) { uint32_t i; dlb2_xstats_fn fn; for (i = start; i < start + num; i++) { struct dlb2_xstats_entry *xs = &dlb2->xstats[i]; if (!xs->reset_allowed) continue; switch (xs->fn_id) { case DLB2_XSTATS_FN_DEV: fn = get_dev_stat; break; case DLB2_XSTATS_FN_PORT: fn = get_port_stat; break; case DLB2_XSTATS_FN_QUEUE: fn = get_queue_stat; break; default: DLB2_LOG_ERR("Unexpected xstat fn_id %d\n", xs->fn_id); return; } uint64_t val = fn(dlb2, xs->obj_idx, xs->stat, xs->extra_arg); xs->reset_value = val; } } static int dlb2_xstats_reset_queue(struct dlb2_eventdev *dlb2, uint8_t queue_id, const uint32_t ids[], uint32_t nb_ids) { const uint32_t reset = 1; if (ids) { uint32_t nb_reset = dlb2_xstats_update(dlb2, RTE_EVENT_DEV_XSTATS_QUEUE, queue_id, ids, NULL, nb_ids, reset); return nb_reset == nb_ids ? 0 : -EINVAL; } if (ids == NULL) dlb2_xstats_reset_range(dlb2, dlb2->xstats_offset_for_qid[queue_id], dlb2->xstats_count_per_qid[queue_id]); return 0; } static int dlb2_xstats_reset_port(struct dlb2_eventdev *dlb2, uint8_t port_id, const uint32_t ids[], uint32_t nb_ids) { const uint32_t reset = 1; int offset = dlb2->xstats_offset_for_port[port_id]; int nb_stat = dlb2->xstats_count_per_port[port_id]; if (ids) { uint32_t nb_reset = dlb2_xstats_update(dlb2, RTE_EVENT_DEV_XSTATS_PORT, port_id, ids, NULL, nb_ids, reset); return nb_reset == nb_ids ? 0 : -EINVAL; } dlb2_xstats_reset_range(dlb2, offset, nb_stat); return 0; } static int dlb2_xstats_reset_dev(struct dlb2_eventdev *dlb2, const uint32_t ids[], uint32_t nb_ids) { uint32_t i; if (ids) { for (i = 0; i < nb_ids; i++) { uint32_t id = ids[i]; if (id >= dlb2->xstats_count_mode_dev) return -EINVAL; dlb2_xstats_reset_range(dlb2, id, 1); } } else { for (i = 0; i < dlb2->xstats_count_mode_dev; i++) dlb2_xstats_reset_range(dlb2, i, 1); } return 0; } int dlb2_eventdev_xstats_reset(struct rte_eventdev *dev, enum rte_event_dev_xstats_mode mode, int16_t queue_port_id, const uint32_t ids[], uint32_t nb_ids) { struct dlb2_eventdev *dlb2 = dlb2_pmd_priv(dev); uint32_t i; /* handle -1 for queue_port_id here, looping over all ports/queues */ switch (mode) { case RTE_EVENT_DEV_XSTATS_DEVICE: if (dlb2_xstats_reset_dev(dlb2, ids, nb_ids)) return -EINVAL; break; case RTE_EVENT_DEV_XSTATS_PORT: if (queue_port_id == -1) { for (i = 0; i < DLB2_MAX_NUM_PORTS; i++) { if (dlb2_xstats_reset_port(dlb2, i, ids, nb_ids)) return -EINVAL; } } else if (queue_port_id < DLB2_MAX_NUM_PORTS) { if (dlb2_xstats_reset_port(dlb2, queue_port_id, ids, nb_ids)) return -EINVAL; } break; case RTE_EVENT_DEV_XSTATS_QUEUE: if (queue_port_id == -1) { for (i = 0; i < DLB2_MAX_NUM_QUEUES; i++) { if (dlb2_xstats_reset_queue(dlb2, i, ids, nb_ids)) return -EINVAL; } } else if (queue_port_id < DLB2_MAX_NUM_QUEUES) { if (dlb2_xstats_reset_queue(dlb2, queue_port_id, ids, nb_ids)) return -EINVAL; } break; }; return 0; } void dlb2_eventdev_dump(struct rte_eventdev *dev, FILE *f) { struct dlb2_eventdev *dlb2; struct dlb2_hw_dev *handle; int i; dlb2 = dlb2_pmd_priv(dev); if (dlb2 == NULL) { fprintf(f, "DLB2 Event device cannot be dumped!\n"); return; } if (!dlb2->configured) fprintf(f, "DLB2 Event device is not configured\n"); handle = &dlb2->qm_instance; fprintf(f, "================\n"); fprintf(f, "DLB2 Device Dump\n"); fprintf(f, "================\n"); fprintf(f, "Processor supports umonitor/umwait instructions = %s\n", dlb2->umwait_allowed ? "yes" : "no"); /* Generic top level device information */ fprintf(f, "device is configured and run state ="); if (dlb2->run_state == DLB2_RUN_STATE_STOPPED) fprintf(f, "STOPPED\n"); else if (dlb2->run_state == DLB2_RUN_STATE_STOPPING) fprintf(f, "STOPPING\n"); else if (dlb2->run_state == DLB2_RUN_STATE_STARTING) fprintf(f, "STARTING\n"); else if (dlb2->run_state == DLB2_RUN_STATE_STARTED) fprintf(f, "STARTED\n"); else fprintf(f, "UNEXPECTED\n"); fprintf(f, "domain ID=%u, socket_id=%u, evdev=%p\n", handle->domain_id, handle->info.socket_id, dlb2->event_dev); fprintf(f, "num dir ports=%u, num dir queues=%u\n", dlb2->num_dir_ports, dlb2->num_dir_queues); fprintf(f, "num ldb ports=%u, num ldb queues=%u\n", dlb2->num_ldb_ports, dlb2->num_ldb_queues); fprintf(f, "num atomic inflights=%u, hist list entries=%u\n", handle->cfg.resources.num_atomic_inflights, handle->cfg.resources.num_hist_list_entries); fprintf(f, "results from most recent hw resource query:\n"); fprintf(f, "\tnum_sched_domains = %u\n", dlb2->hw_rsrc_query_results.num_sched_domains); fprintf(f, "\tnum_ldb_queues = %u\n", dlb2->hw_rsrc_query_results.num_ldb_queues); fprintf(f, "\tnum_ldb_ports = %u\n", dlb2->hw_rsrc_query_results.num_ldb_ports); fprintf(f, "\tnum_dir_ports = %u\n", dlb2->hw_rsrc_query_results.num_dir_ports); fprintf(f, "\tnum_atomic_inflights = %u\n", dlb2->hw_rsrc_query_results.num_atomic_inflights); fprintf(f, "\tnum_hist_list_entries = %u\n", dlb2->hw_rsrc_query_results.num_hist_list_entries); fprintf(f, "\tmax_contiguous_hist_list_entries = %u\n", dlb2->hw_rsrc_query_results.max_contiguous_hist_list_entries); fprintf(f, "\tnum_ldb_credits = %u\n", dlb2->hw_rsrc_query_results.num_ldb_credits); fprintf(f, "\tnum_dir_credits = %u\n", dlb2->hw_rsrc_query_results.num_dir_credits); /* Port level information */ for (i = 0; i < dlb2->num_ports; i++) { struct dlb2_eventdev_port *p = &dlb2->ev_ports[i]; int j; if (!p->enq_configured) fprintf(f, "Port_%d is not configured\n", i); fprintf(f, "Port_%d\n", i); fprintf(f, "=======\n"); fprintf(f, "\tevport_%u is configured, setup done=%d\n", p->id, p->setup_done); fprintf(f, "\tconfig state=%d, port state=%d\n", p->qm_port.config_state, p->qm_port.state); fprintf(f, "\tport is %s\n", p->qm_port.is_directed ? "directed" : "load balanced"); fprintf(f, "\toutstanding releases=%u\n", p->outstanding_releases); fprintf(f, "\tinflight max=%u, inflight credits=%u\n", p->inflight_max, p->inflight_credits); fprintf(f, "\tcredit update quanta=%u, implicit release =%u\n", p->credit_update_quanta, p->implicit_release); fprintf(f, "\tnum_links=%d, queues -> ", p->num_links); for (j = 0; j < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; j++) { if (p->link[j].valid) fprintf(f, "id=%u prio=%u ", p->link[j].queue_id, p->link[j].priority); } fprintf(f, "\n"); fprintf(f, "\thardware port id=%u\n", p->qm_port.id); fprintf(f, "\tcached_ldb_credits=%u\n", p->qm_port.cached_ldb_credits); fprintf(f, "\tldb_credits = %u\n", p->qm_port.ldb_credits); fprintf(f, "\tcached_dir_credits = %u\n", p->qm_port.cached_dir_credits); fprintf(f, "\tdir_credits = %u\n", p->qm_port.dir_credits); fprintf(f, "\tgenbit=%d, cq_idx=%d, cq_depth=%d\n", p->qm_port.gen_bit, p->qm_port.cq_idx, p->qm_port.cq_depth); fprintf(f, "\tinterrupt armed=%d\n", p->qm_port.int_armed); fprintf(f, "\tPort statistics\n"); fprintf(f, "\t\trx_ok %" PRIu64 "\n", p->stats.traffic.rx_ok); fprintf(f, "\t\trx_drop %" PRIu64 "\n", p->stats.traffic.rx_drop); fprintf(f, "\t\trx_interrupt_wait %" PRIu64 "\n", p->stats.traffic.rx_interrupt_wait); fprintf(f, "\t\trx_umonitor_umwait %" PRIu64 "\n", p->stats.traffic.rx_umonitor_umwait); fprintf(f, "\t\ttx_ok %" PRIu64 "\n", p->stats.traffic.tx_ok); fprintf(f, "\t\ttotal_polls %" PRIu64 "\n", p->stats.traffic.total_polls); fprintf(f, "\t\tzero_polls %" PRIu64 "\n", p->stats.traffic.zero_polls); fprintf(f, "\t\ttx_nospc_ldb_hw_credits %" PRIu64 "\n", p->stats.traffic.tx_nospc_ldb_hw_credits); fprintf(f, "\t\ttx_nospc_dir_hw_credits %" PRIu64 "\n", p->stats.traffic.tx_nospc_dir_hw_credits); fprintf(f, "\t\ttx_nospc_inflight_max %" PRIu64 "\n", p->stats.traffic.tx_nospc_inflight_max); fprintf(f, "\t\ttx_nospc_new_event_limit %" PRIu64 "\n", p->stats.traffic.tx_nospc_new_event_limit); fprintf(f, "\t\ttx_nospc_inflight_credits %" PRIu64 "\n", p->stats.traffic.tx_nospc_inflight_credits); fprintf(f, "\t\ttx_new %" PRIu64 "\n", p->stats.tx_op_cnt[RTE_EVENT_OP_NEW]); fprintf(f, "\t\ttx_fwd %" PRIu64 "\n", p->stats.tx_op_cnt[RTE_EVENT_OP_FORWARD]); fprintf(f, "\t\ttx_rel %" PRIu64 "\n", p->stats.tx_op_cnt[RTE_EVENT_OP_RELEASE]); fprintf(f, "\t\ttx_implicit_rel %" PRIu64 "\n", p->stats.tx_implicit_rel); fprintf(f, "\t\ttx_sched_ordered %" PRIu64 "\n", p->stats.tx_sched_cnt[DLB2_SCHED_ORDERED]); fprintf(f, "\t\ttx_sched_unordered %" PRIu64 "\n", p->stats.tx_sched_cnt[DLB2_SCHED_UNORDERED]); fprintf(f, "\t\ttx_sched_atomic %" PRIu64 "\n", p->stats.tx_sched_cnt[DLB2_SCHED_ATOMIC]); fprintf(f, "\t\ttx_sched_directed %" PRIu64 "\n", p->stats.tx_sched_cnt[DLB2_SCHED_DIRECTED]); fprintf(f, "\t\ttx_invalid %" PRIu64 "\n", p->stats.tx_invalid); fprintf(f, "\t\trx_sched_ordered %" PRIu64 "\n", p->stats.rx_sched_cnt[DLB2_SCHED_ORDERED]); fprintf(f, "\t\trx_sched_unordered %" PRIu64 "\n", p->stats.rx_sched_cnt[DLB2_SCHED_UNORDERED]); fprintf(f, "\t\trx_sched_atomic %" PRIu64 "\n", p->stats.rx_sched_cnt[DLB2_SCHED_ATOMIC]); fprintf(f, "\t\trx_sched_directed %" PRIu64 "\n", p->stats.rx_sched_cnt[DLB2_SCHED_DIRECTED]); fprintf(f, "\t\trx_sched_invalid %" PRIu64 "\n", p->stats.rx_sched_invalid); } /* Queue level information */ for (i = 0; i < dlb2->num_queues; i++) { struct dlb2_eventdev_queue *q = &dlb2->ev_queues[i]; int j, k; if (!q->setup_done) fprintf(f, "Queue_%d is not configured\n", i); fprintf(f, "Queue_%d\n", i); fprintf(f, "========\n"); fprintf(f, "\tevqueue_%u is set up\n", q->id); fprintf(f, "\tqueue is %s\n", q->qm_queue.is_directed ? "directed" : "load balanced"); fprintf(f, "\tnum_links=%d, ports -> ", q->num_links); for (j = 0; j < dlb2->num_ports; j++) { struct dlb2_eventdev_port *p = &dlb2->ev_ports[j]; for (k = 0; k < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; k++) { if (p->link[k].valid && p->link[k].queue_id == q->id) fprintf(f, "id=%u prio=%u ", p->id, p->link[k].priority); } } fprintf(f, "\n"); fprintf(f, "\tcurrent depth: %u events\n", dlb2_get_queue_depth(dlb2, q)); fprintf(f, "\tnum qid inflights=%u, sched_type=%d\n", q->qm_queue.num_qid_inflights, q->qm_queue.sched_type); } }