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