1 /*********************************\r
2 * FILE: pktio.c\r
3 * PURPOSE: pktio library for NETAPI\r
4 **************************************************************\r
5 * FILE: pktio.c\r
6 * \r
7 * DESCRIPTION: pktio source file for user space transport\r
8 * library\r
9 * \r
10 * REVISION HISTORY: rev 0.0.1 \r
11 *\r
12 * Copyright (c) Texas Instruments Incorporated 2010-2011\r
13 * \r
14 * Redistribution and use in source and binary forms, with or without \r
15 * modification, are permitted provided that the following conditions \r
16 * are met:\r
17 *\r
18 * Redistributions of source code must retain the above copyright \r
19 * notice, this list of conditions and the following disclaimer.\r
20 *\r
21 * Redistributions in binary form must reproduce the above copyright\r
22 * notice, this list of conditions and the following disclaimer in the \r
23 * documentation and/or other materials provided with the \r
24 * distribution.\r
25 *\r
26 * Neither the name of Texas Instruments Incorporated nor the names of\r
27 * its contributors may be used to endorse or promote products derived\r
28 * from this software without specific prior written permission.\r
29 *\r
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
41 \r
42 ********************************/\r
43 #include <stdio.h>\r
44 #include <stdlib.h>\r
45 #include <unistd.h>\r
46 #include <string.h>\r
47 #include "netapi.h"\r
48 \r
49 /*--------------------Utilites-----------------*/\r
50 static PKTIO_HANDLE_T * pktiop_get_free_channel_slot(NETAPI_T n)\r
51 {\r
52 PKTIO_HANDLE_T ** pp = (PKTIO_HANDLE_T **) netapi_get_pktio_list(n);\r
53 int i;\r
54 for(i=0;i<NETAPI_MAX_PKTIO;i++)\r
55 {\r
56 if (pp[i]->inuse != PKTIO_INUSE)\r
57 {\r
58 return pp[i];\r
59 }\r
60 }\r
61 return NULL;\r
62 }\r
63 \r
64 /*-----------------------MAIN API----------------------*/\r
65 /* create a channel */\r
66 PKTIO_HANDLE_T * pktio_create(NETAPI_T n, char * name,\r
67 PKTIO_CB cb, PKTIO_CFG_T * p_cfg, int * err)\r
68 {\r
69 int r = 0;\r
70 PKTIO_HANDLE_T *p;\r
71 uint8_t isAllocated;\r
72 \r
73 *err=0;\r
74 \r
75 if ((!p_cfg)||(!name)) {*err=NETAPI_ERR_BAD_INPUT; return NULL;}\r
76 \r
77 /* get a free channel handle */\r
78 p=pktiop_get_free_channel_slot(n);\r
79 if (!p) {*err = PKTIO_NOMEM; return (p); }\r
80 \r
81 p->inuse= PKTIO_INUSE;\r
82 p->back = n;\r
83 p->cb = cb;\r
84 p->max_n = p_cfg->max_n;\r
85 memcpy((char *)&p->cfg, (char*) p_cfg, sizeof(PKTIO_CFG_T));\r
86 \r
87 /* create a general queue (for now). todo: allow qnum to be passed in */\r
88 p->q = Qmss_queueOpen(Qmss_QueueType_GENERAL_PURPOSE_QUEUE,\r
89 QMSS_PARAM_NOT_SPECIFIED, &isAllocated);\r
90 if (p->q == (Qmss_QueueHnd) NULL)\r
91 {\r
92 printf(">pktio_create: queueOpen failed\n");\r
93 p->inuse=0;\r
94 *err= NETAPI_ERR_QLLD; ///queue lld error\r
95 return NULL;\r
96 }\r
97 p->qInfo = Qmss_getQueueNumber(p->q);\r
98 if (p->cfg.flags2 & PKTIO_PKT) \r
99 {\r
100 p->use_nwal =1; \r
101 p->nwalInstanceHandle = netapi_return_nwal_instance_handle(n); \r
102 }\r
103 else p->use_nwal=0;\r
104 \r
105 /* save name */ \r
106 strncpy(p->name,name,\r
107 strlen(name)<PKTIO_MAX_NAME ?\r
108 strlen(name):PKTIO_MAX_NAME); \r
109 \r
110 /* add name, qnum to global name list */\r
111 if ((strcmp(name,NETCP_RX)) && (strcmp(name,NETCP_TX)) &&\r
112 (p_cfg->flags1 & PKTIO_GLOBAL) )\r
113 {\r
114 //todo: make sure this succeeds..\r
115 r=netapi_add_global_pktio(n, name, &p->qInfo);\r
116 }\r
117 ((NETAPI_HANDLE_T *)n )->n_pktios+=1;\r
118 return p;\r
119 }\r
120 \r
121 \r
122 /***********************************************************/\r
123 /************** open an existing channel. *****************/\r
124 /***********************************************************/\r
125 PKTIO_HANDLE_T * pktio_open(NETAPI_T n, char *name,\r
126 PKTIO_CB cb, PKTIO_CFG_T * p_cfg, int * err)\r
127 {\r
128 int r=0;\r
129 PKTIO_HANDLE_T *p, *p2;\r
130 uint8_t isAllocated;\r
131 *err=0;\r
132 Qmss_Queue *p_qnum;\r
133 \r
134 if ((!p_cfg)||(!name)) {*err=NETAPI_ERR_BAD_INPUT; return NULL;}\r
135 \r
136 /* get a free channel handle */\r
137 p=pktiop_get_free_channel_slot(n);\r
138 if (!p) {*err = PKTIO_NOMEM; return (p); }\r
139 ((NETAPI_HANDLE_T *)n)->n_pktios+=1;\r
140 \r
141 p->inuse= PKTIO_INUSE;\r
142 p->back = n;\r
143 p->cb = cb;\r
144 p->max_n = p_cfg->max_n;\r
145 memcpy((char *)&p->cfg, (char*) p_cfg, sizeof(PKTIO_CFG_T));\r
146 \r
147 /* special handling of NETCP_RX, NETCP_TX */\r
148 if( (!strcmp(name, NETCP_RX)) || (!strcmp(name,NETCP_TX)) )\r
149 {\r
150 /* these have already been opened internally, so don't search in global list */\r
151 p->use_nwal = 2;\r
152 p->q = 0; \r
153 p->nwalInstanceHandle = netapi_return_nwal_instance_handle(n); \r
154 }\r
155 else\r
156 {\r
157 /* find queue in global list */\r
158 p_qnum = netapi_find_global_pktio(n, name);\r
159 if (!p_qnum ) \r
160 {\r
161 printf(">pktio_open: can't find %s\n",name);\r
162 p->inuse=0;\r
163 *err= NETAPI_ERR_NOTFOUND; ///queue lld error\r
164 return NULL;\r
165 }\r
166 \r
167 /* open a general queue (for now). use qnum that was just found */\r
168 p->q = Qmss_queueOpen(Qmss_QueueType_GENERAL_PURPOSE_QUEUE,\r
169 p_qnum->qNum , &isAllocated);\r
170 if (p->q == (Qmss_QueueHnd) NULL)\r
171 {\r
172 printf(">pktio_create: queueOpen failed\n");\r
173 p->inuse=0;\r
174 *err= NETAPI_ERR_QLLD; ///queue lld error\r
175 return NULL;\r
176 }\r
177 p->qInfo = Qmss_getQueueNumber(p->q);\r
178 if (p_cfg->flags2 & PKTIO_PKT)\r
179 {\r
180 p->use_nwal =1; \r
181 p->nwalInstanceHandle = netapi_return_nwal_instance_handle(n); \r
182 } \r
183 else p->use_nwal=0;\r
184 }\r
185 \r
186 /* save name */\r
187 strncpy(p->name,name,\r
188 strlen(name)<PKTIO_MAX_NAME ?\r
189 strlen(name):PKTIO_MAX_NAME);\r
190 \r
191 \r
192 \r
193 return p;\r
194 }\r
195 \r
196 /***********************************************************/\r
197 /************** control the channel ****************/\r
198 /***********************************************************/\r
199 void pktio_control(PKTIO_HANDLE_T * p,\r
200 PKTIO_CB cb,\r
201 PKTIO_CFG_T * p_cfg,\r
202 PKTIO_CONTROL_T * p_control,\r
203 int *err)\r
204 {\r
205 if (!p) { *err=1; return;}\r
206 if (cb) \r
207 {\r
208 p->cb = cb;\r
209 }\r
210 if (p_control)\r
211 {\r
212 /* todo: implement divert */\r
213 switch(p_control->op)\r
214 {\r
215 //clear the queue\r
216 case(PKTIO_CLEAR):\r
217 netapi_zapQ(p->q);\r
218 break;\r
219 case(PKTIO_DIVERT):\r
220 default:\r
221 printf(">pktio_control: pktio_control op %d not implemented\n",p_control->op);\r
222 *err= NETAPI_ERR_NOT_IMPLEMENTED;\r
223 break;\r
224 }\r
225 }\r
226 //all we configure is max_n. Can't change type of queue, rx/tx, etc\r
227 if (p_cfg)\r
228 {\r
229 p->max_n = p_cfg->max_n;\r
230 }\r
231 *err=0;\r
232 return;\r
233 }\r
234 \r
235 /***********************************************************/\r
236 /*****************close ***************************/\r
237 /***********************************************************/\r
238 void pktio_close(PKTIO_HANDLE_T * p, int * err)\r
239 {\r
240 if(!p) { *err=1; return;}\r
241 *err=0;\r
242 Qmss_queueClose(p->q); //LLD keeps reference count\r
243 p->q=-1;\r
244 p->inuse=0;\r
245 ((NETAPI_HANDLE_T *)p->back)->n_pktios-=1;\r
246 return;\r
247 }\r
248 \r
249 /***********************************************************/\r
250 /*****************Delete***************************/\r
251 /***********************************************************/\r
252 void pktio_delete(PKTIO_HANDLE_T * p, int * err)\r
253 {\r
254 if(!p) { *err=1; return;}\r
255 *err=0;\r
256 /* remove from name list */\r
257 netapi_del_global_pktio((NETAPI_HANDLE_T *)p->back, p->name);\r
258 if(p->use_nwal !=2)\r
259 {\r
260 Qmss_queueClose(p->q);\r
261 }\r
262 p->q=-1;\r
263 p->inuse=0;\r
264 ((NETAPI_HANDLE_T *)p->back)->n_pktios-=1;\r
265 return ;\r
266 }\r
267 \r
268 \r
269 /***********************************************************/\r
270 /*****************send *************************/\r
271 /***********************************************************/\r
272 int pktio_send(PKTIO_HANDLE_T * p, Ti_Pkt *pkt, PKTIO_METADATA_T *m, int * err)\r
273 {\r
274 nwalTxPktInfo_t * pPktInfo=m->u.tx_meta;\r
275 nwal_RetValue res;\r
276 *err=0;\r
277 if(! (p->cfg.flags1&PKTIO_W)) return 0;\r
278 if (p->use_nwal)\r
279 {\r
280 pPktInfo->pPkt = pkt;\r
281 res=nwal_send(p->nwalInstanceHandle, nwal_HANDLE_INVALID,pPktInfo);\r
282 if (res != nwal_OK) *err = NETAPI_ERR_NWAL_TX_ERR -res;\r
283 }\r
284 else\r
285 {\r
286 /* tod: meta data for non netcp xfers */\r
287 /* process meta data */\r
288 Qmss_queuePushDesc (p->q, (void*)pkt);\r
289 }\r
290 return 1;\r
291 }\r
292 \r
293 /***********************************************************/\r
294 /*******************send multiple**************************/\r
295 /***********************************************************/\r
296 int pktio_sendMulti(PKTIO_HANDLE_T * p, Ti_Pkt * pkt[], PKTIO_METADATA_T * m[], int np, int* err)\r
297 {\r
298 int r=0;\r
299 *err=0;\r
300 if(! p->cfg.flags1&PKTIO_W) return 0;\r
301 if (p->use_nwal)\r
302 {\r
303 for(r=0;r<np;r++)\r
304 {\r
305 nwalTxPktInfo_t *pPktInfo= m[r]->u.tx_meta;\r
306 nwal_RetValue res;\r
307 pPktInfo->pPkt = pkt[r];\r
308 res=nwal_send(p->nwalInstanceHandle,nwal_HANDLE_INVALID,pPktInfo);\r
309 if (res != nwal_OK) *err = NETAPI_ERR_NWAL_TX_ERR -res;\r
310 }\r
311 }\r
312 else\r
313 {\r
314 for(r=0;r<np;r++)\r
315 {\r
316 /* process meta data */\r
317 Qmss_queuePushDesc(p->q, (void*) pkt[r]);\r
318 }\r
319 } \r
320 return r;\r
321 }\r
322 \r
323 /***********************************************************/\r
324 /******************* polling **********************/\r
325 /***********************************************************/\r
326 \r
327 /* poll a particular channel */\r
328 int pktio_poll(PKTIO_HANDLE_T * p, PKTIO_POLL_T * p_poll_cfg, int * err)\r
329 {\r
330 int r=0;\r
331 int n;\r
332 Ti_Pkt * temp;\r
333 Ti_Pkt * pkt_list[PKTIO_MAX_RECV];\r
334 PKTIO_METADATA_T meta_s[PKTIO_MAX_RECV];\r
335 uint64_t ts= netapi_getTimestamp(); //get_ts\r
336 \r
337 if(! p->cfg.flags1&PKTIO_R) return 0;\r
338 \r
339 /** poll the netcp default RX queue we squirt out below */\r
340 if (p->use_nwal==2)\r
341 {\r
342 /* Poll for common L2/L3 packets */\r
343 nwal_pollPkt(p->nwalInstanceHandle,\r
344 nwal_POLL_DEFAULT_GLOB_PKT_Q,\r
345 (uint32_t) p,\r
346 p->max_n,\r
347 QMSS_PARAM_NOT_SPECIFIED,\r
348 (void*) NULL);\r
349 }\r
350 /** poll a netcp RX queue. we squirt out below */\r
351 else if (p->use_nwal==1)\r
352 {\r
353 /* Poll an additional NETCP RX queue */\r
354 nwal_pollPkt(p->nwalInstanceHandle,\r
355 nwal_POLL_APP_MANAGED_PKT_Q,\r
356 (uint32_t) p,\r
357 p->max_n,\r
358 p->q,\r
359 (void *) NULL);\r
360 }\r
361 /* poll an IPC queue */\r
362 else \r
363 {\r
364 *err=0;\r
365 n= (p->max_n< PKTIO_MAX_RECV) ? p->max_n : PKTIO_MAX_RECV;\r
366 for(r=0;r<n;r++)\r
367 {\r
368 temp=(Cppi_HostDesc*)QMSS_DESC_PTR(Qmss_queuePop(p->q));\r
369 if(!temp) break;\r
370 /* process meta data */\r
371 pkt_list[r]= temp;\r
372 meta_s[r].flags1=0x1;\r
373 } \r
374 if (r) p->cb((struct PKTIO_HANDLE_tag *)p, pkt_list, &meta_s[0], r, ts);\r
375 }\r
376 return r;\r
377 }\r
378 \r
379 /***********************************************************/\r
380 /** poll all channels attached to this handle */\r
381 /***********************************************************/\r
382 int pktio_pollAll(NETAPI_T handle, PKTIO_POLL_T * p_poll_cfg, int *err)\r
383 {\r
384 int i=0;\r
385 int r=0;\r
386 int err2;\r
387 int cnt=0;\r
388 PKTIO_HANDLE_T *pp =( PKTIO_HANDLE_T *) netapi_get_pktio_list(handle);\r
389 \r
390 *err=0;\r
391 for(i=0;i<NETAPI_MAX_PKTIO && cnt < ((NETAPI_HANDLE_T *)handle)->n_pktios;i++,pp+=1)\r
392 {\r
393 if (pp->inuse != PKTIO_INUSE) continue;\r
394 if(!(pp->cfg.flags1&PKTIO_R)) continue;\r
395 r+=pktio_poll(pp, p_poll_cfg, &err2); cnt+=1;\r
396 if (err2) { *err = err2; break;}\r
397 }\r
398 return r;\r
399 \r
400 }\r
401 \r
402 /***** this is the callback we registered with NWAL for pkt reception *****/\r
403 /* appcookie -> pktio handle */\r
404 void netapi_NWALRxPktCallback (uint32_t appCookie,\r
405 uint16_t numPkts,\r
406 nwalRxPktInfo_t* pPktInfo,\r
407 uint64_t timestamp,\r
408 nwal_Bool_t* pFreePkt)\r
409 {\r
410 PKTIO_HANDLE_T * p = (PKTIO_HANDLE_T *) appCookie;\r
411 int r=0;\r
412 int n;\r
413 Ti_Pkt * pkt_list[PKTIO_MAX_RECV];\r
414 PKTIO_METADATA_T meta_s[PKTIO_MAX_RECV];\r
415 for(r=0;r<numPkts;r++)\r
416 {\r
417 pkt_list[r] = pPktInfo[r].pPkt;\r
418 meta_s[r].flags1 = PKTIO_META_RX;\r
419 meta_s[r].u.rx_meta = &pPktInfo[r];\r
420 }\r
421 if (r) p->cb((struct PKTIO_HANDLE_tag *)p, pkt_list, &meta_s[0], r, timestamp);\r
422 \r
423 }\r
424 \r
425 \r