EM-ODP  3.7.0
Event Machine on ODP
em_event.c
1 /*
2  * Copyright (c) 2015, Nokia Solutions and Networks
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * * Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "em_include.h"
32 
33 /*
34  * Sanity check that no extra padding is added to the event_hdr_t by
35  * alignment directives etc.
36  */
37 typedef event_hdr_t _ev_hdr__size_check__arr_t[3];
38 COMPILE_TIME_ASSERT(sizeof(_ev_hdr__size_check__arr_t) ==
39  3 * sizeof(event_hdr_t), EVENT_HDR_SIZE_ERROR2);
40 
41 /*
42  * Verify the value set for EM_CHECK_LEVEL - this define is set either from
43  * the include/event_machine/platform/event_machine_config.h file or by the
44  * configure.ac option --enable-check-level=N.
45  */
46 COMPILE_TIME_ASSERT(EM_CHECK_LEVEL >= 0 && EM_CHECK_LEVEL <= 3,
47  EM_CHECK_LEVEL__BAD_VALUE);
48 
49 em_status_t event_init(void)
50 {
51  return EM_OK;
52 }
53 
54 void print_event_info(void)
55 {
56  EM_PRINT("\n"
57  "EM Events\n"
58  "---------\n"
59  "event-hdr size: %zu B\n",
60  sizeof(event_hdr_t));
61 
62  EM_DBG("\t\toffset\tsize\n"
63  "\t\t------\t----\n"
64  "esv.state_cnt:\t%3zu B\t%2zu B\n"
65  "esv.state:\t%3zu B\t%2zu B\n"
66  "flags:\t\t%3zu B\t%2zu B\n"
67  "align_offset:\t%3zu B\t%2zu B\n"
68  "event_type:\t%3zu B\t%2zu B\n"
69  "event:\t\t%3zu B\t%2zu B\n"
70  "event_size:\t%3zu B\t%2zu B\n"
71  "egrp_gen:\t%3zu B\t%2zu B\n"
72  "egrp:\t\t%3zu B\t%2zu B\n"
73  "tmo:\t\t%3zu B\t%2zu B\n"
74  "user_area info:\t%3zu B\t%2zu B\n"
75  "end_hdr_data:\t%3zu B\t%2zu B\n"
76  " <pad>\t\t%3zu B\n"
77  "end:\t\t%3zu B\t%2zu B\n",
78  offsetof(event_hdr_t, state_cnt), sizeof_field(event_hdr_t, state_cnt),
79  offsetof(event_hdr_t, state), sizeof_field(event_hdr_t, state),
80  offsetof(event_hdr_t, flags), sizeof_field(event_hdr_t, flags),
81  offsetof(event_hdr_t, align_offset), sizeof_field(event_hdr_t, align_offset),
82  offsetof(event_hdr_t, event_type), sizeof_field(event_hdr_t, event_type),
83  offsetof(event_hdr_t, event), sizeof_field(event_hdr_t, event),
84  offsetof(event_hdr_t, event_size), sizeof_field(event_hdr_t, event_size),
85  offsetof(event_hdr_t, egrp_gen), sizeof_field(event_hdr_t, egrp_gen),
86  offsetof(event_hdr_t, egrp), sizeof_field(event_hdr_t, egrp),
87  offsetof(event_hdr_t, tmo), sizeof_field(event_hdr_t, tmo),
88  offsetof(event_hdr_t, user_area), sizeof_field(event_hdr_t, user_area),
89  offsetof(event_hdr_t, end_hdr_data), sizeof_field(event_hdr_t, end_hdr_data),
90  offsetof(event_hdr_t, end) - offsetof(event_hdr_t, end_hdr_data),
91  offsetof(event_hdr_t, end), sizeof_field(event_hdr_t, end));
92 
93  EM_PRINT("\n");
94 }
95 
96 /**
97  * Helper for em_event_clone().
98  *
99  * Clone an event originating from an external odp pkt-pool.
100  * Initialize the new cloned event as an EM event and return it.
101  *
102  * Alloc and copy content via ODP.
103  * Also the ev_hdr in the odp-pkt user_area is copied.
104  */
105 em_event_t pkt_clone_odp(odp_packet_t pkt, odp_pool_t pkt_pool,
106  uint32_t offset, uint32_t size, bool is_clone_part)
107 {
108  odp_packet_t clone_pkt;
109 
110  if (is_clone_part)
111  clone_pkt = odp_packet_copy_part(pkt, offset, size, pkt_pool);
112  else
113  clone_pkt = odp_packet_copy(pkt, pkt_pool);
114 
115  if (unlikely(clone_pkt == ODP_PACKET_INVALID))
116  return EM_EVENT_UNDEF;
117 
118  odp_packet_user_flag_set(clone_pkt, USER_FLAG_SET);
119 
120  odp_event_t odp_clone_event = odp_packet_to_event(clone_pkt);
121  event_hdr_t *clone_hdr = odp_packet_user_area(clone_pkt);
122  em_event_t clone_event = event_odp2em(odp_clone_event);
123 
124  /*
125  * Init hdr of event, also ESV init if needed.
126  * The clone_hdr is a copy of parent's, update only relevant fields.
127  */
128  if (esv_enabled())
129  clone_event = evstate_init(clone_event, clone_hdr, false);
130  else
131  clone_hdr->event = clone_event;
132 
133  /* clone_hdr->event_type = use parent's type as is */
134  clone_hdr->egrp = EM_EVENT_GROUP_UNDEF;
135  clone_hdr->flags.all = 0;
136 
137  return clone_event;
138 }
139 
140 void
141 output_queue_track(queue_elem_t *const output_q_elem)
142 {
143  output_queue_track_t *const track =
145  const uint32_t qidx = output_q_elem->output.idx;
146 
147  if (track->used_queues[qidx] == NULL) {
148  track->used_queues[qidx] = output_q_elem;
149  track->idx[track->idx_cnt++] = qidx;
150  }
151 }
152 
153 void
154 output_queue_drain(const queue_elem_t *output_q_elem)
155 {
156  const em_queue_t output_queue = (em_queue_t)(uintptr_t)output_q_elem->queue;
157  const em_output_func_t output_fn =
158  output_q_elem->output.output_conf.output_fn;
159  void *const output_fn_args =
160  output_q_elem->output.output_conf.output_fn_args;
161 
162  const int deq_max = 32;
163 
164  em_event_t output_ev_tbl[deq_max];
165  /* use same event-tbl, dequeue odp events into the EM event-tbl */
166  odp_event_t *const odp_deq_events = (odp_event_t *)output_ev_tbl;
167 
168  const odp_queue_t odp_queue = output_q_elem->odp_queue;
169  unsigned int output_num;
170  int deq;
171  int ret;
172 
173  const bool esv_ena = esv_enabled();
174 
175  do {
176  deq = odp_queue_deq_multi(odp_queue,
177  odp_deq_events/*out=output_ev_tbl[]*/,
178  deq_max);
179  if (unlikely(deq <= 0))
180  return;
181 
182  output_num = (unsigned int)deq;
183  /* odp_deq_events[] == output_ev_tbl[] */
184  if (esv_ena) {
185  event_hdr_t *ev_hdrs[output_num];
186 
187  /* Restore hdls from ev_hdrs, odp-ev conv lost evgen */
188  event_to_hdr_multi(output_ev_tbl, ev_hdrs, output_num);
189  for (unsigned int i = 0; i < output_num; i++)
190  output_ev_tbl[i] = ev_hdrs[i]->event;
191  }
192 
193  ret = output_fn(output_ev_tbl, output_num,
194  output_queue, output_fn_args);
195 
196  if (unlikely((unsigned int)ret != output_num))
197  em_free_multi(&output_ev_tbl[ret], output_num - ret);
198  } while (deq > 0);
199 }
200 
201 void
202 output_queue_buffering_drain(void)
203 {
205 
206  for (unsigned int i = 0; i < track->idx_cnt; i++) {
207  int qidx = track->idx[i];
208  queue_elem_t *output_q_elem = track->used_queues[qidx];
209  env_spinlock_t *lock = &output_q_elem->output.lock;
210 
211  /*
212  * drain if lock available, otherwise another core is already
213  * draining so no need to do anything.
214  */
215  if (env_spinlock_trylock(lock)) {
216  output_queue_drain(output_q_elem);
217  env_spinlock_unlock(lock);
218  }
219 
220  track->idx[i] = 0;
221  track->used_queues[qidx] = NULL;
222  }
223  track->idx_cnt = 0;
224 }
225 
226 uint32_t event_vector_tbl(em_event_t vector_event,
227  em_event_t **event_tbl /*out*/)
228 {
229  odp_event_t odp_event = event_em2odp(vector_event);
230  odp_packet_vector_t pkt_vec = odp_packet_vector_from_event(odp_event);
231  odp_packet_t *pkt_tbl = NULL;
232  const int pkts = odp_packet_vector_tbl(pkt_vec, &pkt_tbl/*out*/);
233 
234  *event_tbl = (em_event_t *)pkt_tbl; /* Careful! Points to same table */
235 
236  if (!pkts)
237  return 0;
238 
239  event_hdr_t *ev_hdr_tbl[pkts];
240 
241  /*
242  * Init the event-table as needed, might contain EM events or
243  * ODP packets depending on source.
244  */
245  if (esv_enabled()) {
246  odp_packet_t odp_pkttbl[pkts];
247 
248  /*
249  * Drop ESV generation from event handles by converting to
250  * odp-packets, then init as needed as EM events.
251  */
252  events_em2pkt(*event_tbl/*in*/, odp_pkttbl/*out*/, pkts);
253 
254  event_init_pkt_multi(odp_pkttbl /*in*/, *event_tbl /*in,out*/,
255  ev_hdr_tbl /*out*/, pkts, false);
256  } else {
257  event_init_pkt_multi(pkt_tbl /*in*/, *event_tbl /*in,out*/,
258  ev_hdr_tbl /*out*/, pkts, false);
259  }
260 
261  return pkts;
262 }
263 
264 em_status_t event_vector_max_size(em_event_t vector_event, uint32_t *max_size /*out*/,
265  em_escope_t escope)
266 {
267  odp_event_t odp_event = event_em2odp(vector_event);
268  odp_packet_vector_t pktvec = odp_packet_vector_from_event(odp_event);
269  odp_pool_t odp_pool = odp_packet_vector_pool(pktvec);
270  pool_subpool_t pool_subpool = pool_subpool_odp2em(odp_pool);
271  em_pool_t pool = (em_pool_t)(uintptr_t)pool_subpool.pool;
272  int subpool = pool_subpool.subpool;
273 
274  if (unlikely(pool == EM_POOL_UNDEF)) {
275  /*
276  * Don't report an error if 'pool == EM_POOL_UNDEF' since that
277  * might happen if the vector is input from pktio that is using
278  * external (to EM) odp vector pools.
279  */
280  *max_size = 0;
281  return EM_OK; /* EM does not have the max_size info */
282  }
283 
284  const mpool_elem_t *pool_elem = pool_elem_get(pool);
285 
286  if (unlikely(!pool_elem ||
287  (EM_CHECK_LEVEL > 2 && !pool_allocated(pool_elem)))) {
288  *max_size = 0;
289  return INTERNAL_ERROR(EM_ERR_BAD_STATE, escope,
290  "Invalid pool:%" PRI_POOL "", pool);
291  }
292 
293  if (unlikely(subpool >= pool_elem->num_subpools)) {
294  /* not found */
295  *max_size = 0;
296  return INTERNAL_ERROR(EM_ERR_NOT_FOUND, escope,
297  "Subpool not found, pool:%" PRI_POOL "", pool);
298  }
299 
300  /* subpool index found, store corresponding size */
301  *max_size = pool_elem->size[subpool];
302 
303  return EM_OK;
304 }
mpool_elem_t::size
uint16_t size
Definition: em_pool_types.h:55
EM_OK
#define EM_OK
Definition: event_machine_types.h:329
em_locm_t::output_queue_track
output_queue_track_t output_queue_track
Definition: em_mem.h:242
pool_subpool_t
Definition: em_pool_types.h:100
em_output_func_t
int(* em_output_func_t)(const em_event_t events[], const unsigned int num, const em_queue_t output_queue, void *output_fn_args)
Definition: event_machine_hw_types.h:387
EM_EVENT_UNDEF
#define EM_EVENT_UNDEF
Definition: event_machine_types.h:62
USER_FLAG_SET
#define USER_FLAG_SET
Definition: em_event_types.h:56
em_output_queue_conf_t::output_fn
em_output_func_t output_fn
Definition: event_machine_hw_types.h:402
PRI_POOL
#define PRI_POOL
Definition: event_machine_hw_types.h:62
em_locm
ENV_LOCAL em_locm_t em_locm
em_output_queue_conf_t::output_fn_args
void * output_fn_args
Definition: event_machine_hw_types.h:406
q_elem_output_::lock
env_spinlock_t lock
Definition: em_queue_types.h:174
evstate_init
em_event_t evstate_init(const em_event_t event, event_hdr_t *const ev_hdr, bool is_extev)
Definition: em_event_state.c:788
output_queue_track_t
Definition: em_queue_types.h:316
event_hdr::flags
union event_hdr::@34 flags
pkt_clone_odp
em_event_t pkt_clone_odp(odp_packet_t pkt, odp_pool_t pkt_pool, uint32_t offset, uint32_t size, bool is_clone_part)
Definition: em_event.c:105
event_hdr::event
em_event_t event
Definition: em_event_types.h:246
q_elem_output_::output_conf
em_output_queue_conf_t output_conf
Definition: em_queue_types.h:168
event_hdr
Definition: em_event_types.h:184
queue_elem_t::odp_queue
odp_queue_t odp_queue
Definition: em_queue_types.h:228
mpool_elem_t
Definition: em_pool_types.h:47
queue_elem_t::queue
uint32_t queue
Definition: em_queue_types.h:225
INTERNAL_ERROR
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition: em_error.h:43
mpool_elem_t::num_subpools
int num_subpools
Definition: em_pool_types.h:65
em_escope_t
uint32_t em_escope_t
Definition: event_machine_types.h:348
em_status_t
uint32_t em_status_t
Definition: event_machine_types.h:321
EM_CHECK_LEVEL
#define EM_CHECK_LEVEL
Definition: event_machine_config.h:253
event_hdr::egrp
em_event_group_t egrp
Definition: em_event_types.h:265
em_include.h
EM_ERR_NOT_FOUND
@ EM_ERR_NOT_FOUND
Definition: event_machine_hw_types.h:278
EM_POOL_UNDEF
#define EM_POOL_UNDEF
Definition: event_machine_hw_types.h:60
em_free_multi
void em_free_multi(em_event_t events[], int num)
Definition: event_machine_event.c:370
EM_ERR_BAD_STATE
@ EM_ERR_BAD_STATE
Definition: event_machine_hw_types.h:263
EM_EVENT_GROUP_UNDEF
#define EM_EVENT_GROUP_UNDEF
Definition: event_machine_types.h:141
queue_elem_t
Definition: em_queue_types.h:180
q_elem_output_::idx
uint32_t idx
Definition: em_queue_types.h:172