source: rtems/bsps/shared/grlib/slink/grslink.c

Last change on this file was 5d5b9ee, checked in by Daniel Cederman <cederman@…>, on 11/14/22 at 09:59:08

bsps/shared/grlib: Change license to BSD-2 for files with Gaisler copyright

This patch changes the license to BSD-2 for all source files where the
copyright is held by Aeroflex Gaisler, Cobham Gaisler, or Gaisler Research.
Some files also includes copyright right statements from OAR and/or
embedded Brains in addition to Gaisler.

Updates #3053.

  • Property mode set to 100644
File size: 19.3 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/*
4 * This file contains the RTEMS GRSLINK SLINK master driver
5 *
6 * COPYRIGHT (c) 2009.
7 * Cobham Gaisler AB.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Comments concerning current driver implementation:
31 *
32 * The SLINK specification says that there are three IO cards that are capable
33 * of transmitting data. But these IO cards can have the address range 0 to 3,
34 * and an 'For information only' comment explains that the current
35 * implementation has receive buffers for ".. x 4 (IO cards)".
36 * Because of this the driver has four queues, one for each IO card 0 - 3.
37 * When the addressing convention used for the IO cards is known, the number of
38 * queues may be lowered to three.
39 *
40 */
41
42#include <stdlib.h>
43
44#include <bsp.h>
45#include <grlib/grslink.h>
46#include <grlib/ambapp.h>
47#include <grlib/grlib.h>
48
49#include <grlib/grlib_impl.h>
50
51#ifndef GAISLER_SLINK
52#define GAISLER_SLINK 0x02F
53#endif
54
55/* Enable debug output? */
56/* #define DEBUG */
57
58#ifdef DEBUG
59#define DBG(x...) printk(x)
60#else
61#define DBG(x...)
62#endif
63
64/* Bits and fields in SLINK transmit word */
65#define SLINK_RW (1 << 23)
66#define SLINK_CHAN_POS 16
67
68/* Local types */
69typedef struct {
70        volatile unsigned int clockscale;
71        volatile unsigned int ctrl;
72        volatile unsigned int nullwrd;
73        volatile unsigned int sts;
74        volatile unsigned int msk;
75        volatile unsigned int abase;
76        volatile unsigned int bbase;
77        volatile unsigned int td;
78        volatile unsigned int rd;
79} SLINK_regs;
80
81typedef struct {
82        char readstat;         /* Status of READ operation */
83        char seqstat;          /* Status of SEQUENCE operation */
84        unsigned char scnt;    /* Number of SEQUENCE words transferred */
85} SLINK_status;
86
87typedef struct {
88        int size;
89        unsigned int *buf;
90        unsigned int *first;
91        unsigned int *last;
92        unsigned int *max;
93        int full;
94} SLINK_queue;
95
96typedef struct {
97        SLINK_regs    *reg;     /* Pointer to core registers */
98        SLINK_status  *status;  /* Driver status information */
99        void          (*slink_irq_handler)(int); /* Handler for INTERRUPT */
100        void          (*slink_seq_change)(int); /* Callback on SEQUENCE change */
101        int           rword;    /* Placeholder for READ response */
102        rtems_id      read_sem; /* Semaphore for blocking SLINK_read */
103        SLINK_queue   *queues;  /* Receive queues */
104#ifdef SLINK_COLLECT_STATISTICS
105        SLINK_stats   *stats;   /* Core statistics, optional */
106#endif
107} SLINK_cfg;
108
109
110static SLINK_cfg *cfg = NULL;
111
112/**** SLINK driver queues for unsolicited and INTERRUPT requests ****/
113
114/* Function: SLINK_createqueues
115 * Arguments: size: Number of elements in each queue
116 * Returns: 0 on success, -1 on failure
117 * Description: Creates SLINK_NUMQUEUES queues, one for each IO card
118 * that can send data. The pointers to the queues is saved in the driver
119 * config structure.
120 */
121static int SLINK_createqueues(int size)
122{
123        SLINK_queue *q;
124        int i, j;
125
126        if ((q = grlib_malloc(SLINK_NUMQUEUES*sizeof(*q))) == NULL)
127                goto slink_qiniterr1;
128               
129        for (i = 0; i < SLINK_NUMQUEUES; i++) {
130                q[i].size = size;
131                if ((q[i].buf = grlib_malloc(size*sizeof(int))) == NULL)
132                        goto slink_qiniterr2;
133                q[i].first = q[i].last = q[i].buf;
134                q[i].max = q[i].buf + (size-1);
135                q[i].full = 0;
136        }
137
138        cfg->queues = q;
139
140        return 0;
141       
142 slink_qiniterr2:
143        for (j = 0; j < i; j++)
144                free(q[i].buf);
145        free(q);
146 slink_qiniterr1:
147        return -1;
148}
149
150/*
151 * Function: SLINK_destroyqueues
152 * Arguments: None
153 * Returns: Nothing
154 * Description: Frees the memory occupied by the queues in cfg->queues
155 */
156/*
157  static void SLINK_destroyqueues(void)
158  {
159        int i;
160       
161        for(i = 0; i < SLINK_NUMQUEUES; i++)
162                free(cfg->queues[i].buf);
163
164        free(cfg->queues);
165}
166*/
167
168/*
169 * Function: SLINK_enqueue
170 * Arguments: Received SLINK word
171 * Returns: Nothing
172 * Description:
173 */
174static void SLINK_enqueue(unsigned int slink_wrd)
175{
176        SLINK_queue *ioq = cfg->queues + SLINK_WRD_CARDNUM(slink_wrd);
177
178        if (!ioq->full && SLINK_WRD_CARDNUM(slink_wrd) < SLINK_NUMQUEUES) {
179                *ioq->last = slink_wrd;
180                ioq->last = (ioq->last >= ioq->max) ? ioq->buf : ioq->last+1;
181                ioq->full = ioq->last == ioq->first;
182                return;
183        }
184#ifdef SLINK_COLLECT_STATISTICS
185        cfg->stats->lostwords++;
186#endif
187}
188
189/**** SLINK driver helper functions ****/
190
191/*
192 * Function: SLINK_getaddr
193 * Arguments: amba_conf
194 *            base: assigned to base of core registers
195 *            irq: assigned to core irq lines
196 * Returns: Base address and IRQ via arguments, 0 if core is found, else -1
197 * Description: See above.
198 */
199static int SLINK_getaddr(int *base, int *irq)
200{       
201        struct ambapp_apb_info c;
202
203        if (ambapp_find_apbslv(ambapp_plb(),VENDOR_GAISLER,GAISLER_SLINK,&c) == 1) {
204                *base = c.start;
205                *irq = c.common.irq;
206                return 0;
207        }
208        return -1;
209}
210
211/* Function: SLINK_calcscaler
212 * Arguments: sysfreq: System frequency in Hz
213 * Returns: Clock scaler register value
214 * Description: Calculates value for SLINK clock scaler register to attain
215 * a SLINK bus frequency as close to 6 MHz as possible. Please see the IP core
216 * documentation for a description of how clock scaling is implemented.
217 */
218static int SLINK_calcscaler(int sysfreq)
219{
220        int fact = sysfreq / SLINK_FREQ_HZ;
221        return ((fact/2-1) << 16) | (fact % 2 ? fact/2 : fact/2-1); 
222}
223
224
225/*
226 * Function: SLINK_getsysfreq
227 * Arguments: None
228 * Returns: System frequency in Hz, or 0 if system timer is not found.
229 * Description: Looks at the timer to determine system frequency. Makes use
230 * of AMBA Plug'n'Play.
231 */
232static int SLINK_getsysfreq(void)
233{
234        struct ambapp_apb_info t;
235        struct gptimer_regs *tregs;
236               
237        if (ambapp_find_apbslv(ambapp_plb(),VENDOR_GAISLER,GAISLER_GPTIMER,&t)==1) {
238                tregs = (struct gptimer_regs *)t.start;
239                DBG("SLINK_getsysfreq returning %d\n",
240                    (tregs->scaler_reload+1)*1000*1000);
241                return (tregs->scaler_reload+1)*1000*1000;
242        }
243        return 0;
244}
245
246/*
247 * Function: SLINK_interrupt_handler
248 * Arguments: v: not used
249 * Returns: Nothing
250 * Description: Interrupt handles checks RNE, SEQUENCE and error status
251 * bits. Reads word from receive queue and distinguishes between INTERRUPT,
252 * READ responses and SLAVE-WORD-SEND. When an INTERRUPT transfer is detected
253 * the handler calls the user specified slink_irq_handler with the received
254 * word. READ responses are saved and given to SLINK_read via a private
255 * variable. SLAVE-WORD-SEND transfers are placed in the IO card's receive
256 * queue.
257 */
258static rtems_isr SLINK_interrupt_handler(void *v)
259{
260        unsigned int sts;
261        unsigned int wrd;
262
263        /* Read all words from Receive queue */
264        while ((sts = cfg->reg->sts) & SLINK_S_RNE) {
265
266                /* Read first word in receive queue */
267                wrd = cfg->reg->rd;
268       
269                /* Check channel value to determine action */
270                switch (SLINK_WRD_CHAN(wrd)) {
271                case 0: /* Interrupt */
272                        cfg->slink_irq_handler(wrd);
273#ifdef SLINK_COLLECT_STATISTICS
274                        cfg->stats->interrupts++;
275#endif
276                        break;
277                case 3: /* Read response, if no active READ, fall-through */
278                        if (cfg->status->readstat == SLINK_ACTIVE) {
279                                rtems_semaphore_release(cfg->read_sem);
280                                cfg->status->readstat = SLINK_COMPLETED;
281                                cfg->rword = wrd;
282                                break;
283                        }
284                default: /* Unsolicited request */
285                        SLINK_enqueue(wrd);
286                        break;
287                }
288        }
289
290        /* Check sequence operation */
291        if (sts & SLINK_S_SC) {
292                /* SEQUENCE completed */
293                cfg->status->seqstat = SLINK_COMPLETED;
294                if (cfg->slink_seq_change)
295                        cfg->slink_seq_change(SLINK_COMPLETED);
296#ifdef SLINK_COLLECT_STATISTICS
297                cfg->stats->seqcomp++;
298#endif
299        } else if (sts & SLINK_S_SA) {
300                /* SEQUENCE aborted */
301                cfg->status->seqstat = SLINK_ABORTED;
302                cfg->status->scnt = (sts >> SLINK_S_SI_POS);
303                if (cfg->slink_seq_change)
304                        cfg->slink_seq_change(SLINK_ABORTED);
305        }
306
307        /* Check error conditions */
308        if (sts & SLINK_S_PERR) {
309                /*
310                   Parity error detected, set seqstat if there is an ongoing
311                   sequence so that the calling application can decide if the
312                   sequence should be aborted
313                */
314                if (cfg->status->seqstat == SLINK_ACTIVE) {
315                        cfg->status->seqstat = SLINK_PARERR;
316                        if (cfg->slink_seq_change)
317                                cfg->slink_seq_change(SLINK_PARERR);
318                }
319                /* Abort READ operation */
320                if (cfg->status->readstat == SLINK_ACTIVE) {
321                        cfg->status->readstat = SLINK_PARERR;
322                        rtems_semaphore_release(cfg->read_sem);
323                }
324#ifdef SLINK_COLLECT_STATISTICS
325                cfg->stats->parerr++;
326#endif
327        }
328        if (sts & SLINK_S_AERR) {
329                /* AMBA error response, sequence aborted */
330                cfg->status->seqstat = SLINK_AMBAERR;
331                cfg->status->scnt = sts >> SLINK_S_SI_POS;
332                if (cfg->slink_seq_change)
333                        cfg->slink_seq_change(SLINK_AMBAERR);
334        }
335        if (sts & SLINK_S_ROV) {
336                /* Receive overflow, abort any ongoing READ */
337                if (cfg->status->readstat == SLINK_ACTIVE) {
338                        cfg->status->readstat = SLINK_ROV;
339                        rtems_semaphore_release(cfg->read_sem);
340                }
341#ifdef SLINK_COLLECT_STATISICS
342                cfg->status->recov++;
343#endif
344        }
345
346        /* Clear processed bits */
347        cfg->reg->sts = sts;
348}
349
350/**** SLINK driver interface starts here ****/
351
352/* Function: SLINK_init
353 * Arguments: nullwrd: NULL word
354 *            parity: Even (0) or Odd (1) parity
355 *            interrupt_trans_handler: Function that handles interrupt requests
356 *            sequence_callback: Callback on SEQUENCE status changes
357 *            qsize: Size of each receive queue
358 * Returns: 0 on success, -1 on failure
359 * Description: Initializes the SLINK core
360 */
361int SLINK_init(unsigned int nullwrd, int parity, int qsize,
362               void (*interrupt_trans_handler)(int),
363               void (*sequence_callback)(int))
364{
365        int base;
366        int irq;
367        rtems_status_code st;
368
369        /* Allocate private config structure */
370        if (cfg == NULL && (cfg = grlib_malloc(sizeof(*cfg))) == NULL) {
371                DBG("SLINK_init: Could not allocate cfg structure\n");
372                goto slink_initerr1;
373        }
374       
375        /* Create simple binary semaphore for blocking SLINK_read */
376        st = rtems_semaphore_create(rtems_build_name('S', 'L', 'R', '0'), 0,
377                                    (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
378                                     RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
379                                     RTEMS_NO_PRIORITY_CEILING), 0,
380                                    &cfg->read_sem);
381        if (st != RTEMS_SUCCESSFUL) {
382                DBG("SLINK_init: Could not create semaphore\n");
383                goto slink_initerr1;
384        }
385 
386        /* Initialize pointer to SLINK core registers and get IRQ line */
387        if (SLINK_getaddr(&base, &irq) == -1) {
388                DBG("SLINK_init: Could not find core\n");
389                goto slink_initerr2;
390        }
391        cfg->reg = (SLINK_regs*)base;
392
393        /* Allocate status structure and initialize members */
394        if ((cfg->status = grlib_calloc(1, sizeof(*cfg->status))) == NULL) {
395                DBG("SLINK_init: Could not allocate status structure\n");
396                goto slink_initerr2;
397        }
398        cfg->status->seqstat = SLINK_COMPLETED;
399        cfg->status->readstat = SLINK_COMPLETED;
400
401#ifdef SLINK_COLLECT_STATISTICS
402        /* Allocate statistics structure and initialize members */
403        if ((cfg->stats = grlib_calloc(1, sizeof(*cfg->stats))) == NULL) {
404                DBG("SLINK_init: Could not allocate statistics structure\n");
405                goto slink_initerr3;
406        }
407#endif
408
409        /* Allocate and initialize queues */
410        if (SLINK_createqueues(qsize) == -1) {
411                DBG("SLINK_init: Could not create queues\n");
412                goto slink_initerr3;
413        }
414
415        /* Configure core registers */
416        cfg->reg->clockscale = SLINK_calcscaler(SLINK_getsysfreq());
417        cfg->reg->ctrl = parity ? SLINK_C_PAR : 0;
418        cfg->reg->nullwrd = nullwrd;
419        cfg->reg->msk = (SLINK_M_PERRE | SLINK_M_AERRE | SLINK_M_ROVE |
420                         SLINK_M_RNEE | SLINK_M_SAE | SLINK_M_SCE);
421
422        /* Set-up INTERRUPT transfer handling */
423        cfg->slink_irq_handler = interrupt_trans_handler;
424
425        /* Save SEQUENCE callback */
426        cfg->slink_seq_change = sequence_callback;
427
428        /* Set-up IRQ handling */
429        rtems_interrupt_handler_install(irq, "slink",
430                        RTEMS_INTERRUPT_SHARED,
431                        SLINK_interrupt_handler, NULL);
432       
433        return 0;
434
435 slink_initerr3:
436        free(cfg->status);
437 slink_initerr2:
438        free(cfg);
439 slink_initerr1:
440        return -1;
441}
442
443/* Function: SLINK_start
444 * Description: Enables the core
445 */
446void SLINK_start(void)
447{   
448        if (cfg != NULL)
449                cfg->reg->ctrl |= SLINK_C_SLE;
450}
451
452/* Function: SLINK_stop
453 * Description: Disables the core
454 */
455void SLINK_stop(void)
456{
457        if (cfg != NULL)
458                cfg->reg->ctrl &= ~SLINK_C_SLE;
459}
460
461/*
462 * Function: SLINK_read
463 * Arguments: data: Payload of data word
464 *            channel: -
465 *            reply: Reply from IO card
466 * Returns: 0 on success
467 *          -(SLINK_PARERR, SLINK_ROV) on error or -SLINK_QFULL if transmit queue
468 *          is full and software should try again.
469 * Description: Reads one word and returns the response in *reply unless there
470 *              is an error. This function blocks until the READ operation is
471 *              completed or aborted.
472 */
473int SLINK_read(int data, int channel, int *reply)
474{       
475        DBG("SLINK_read: called..");
476
477        if (cfg->reg->sts & SLINK_S_TNF) {
478                cfg->status->readstat = SLINK_ACTIVE;
479                cfg->reg->td = SLINK_RW | channel << SLINK_CHAN_POS | data;
480        } else {
481                DBG("queue FULL\n");
482                return -SLINK_QFULL; /* Transmit queue full */
483        }
484
485        /* Block until the operation has completed or has been aborted */
486        rtems_semaphore_obtain(cfg->read_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
487
488        if (cfg->status->readstat == SLINK_COMPLETED) {
489                *reply = cfg->rword;
490#ifdef SLINK_COLLECT_STATISTICS
491                cfg->stats->reads++;
492#endif       
493                DBG("returning 0\n");
494                return 0;
495        } else {
496                DBG("returning error code\n");
497                return -cfg->status->readstat;
498        }
499}
500
501/*
502 * Function: SLINK_write
503 * Arguments: data: Payload of SLINK data word
504 *            channel: Channel value (bits 22 downto 16) of receive
505 *                     register word
506 * Returns: 0 if command was placed in transmit queue
507 *          -SLINK_QFULL if transmit queue was full (software should retry)
508 * Description: See above.
509 */
510int SLINK_write(int data, int channel)
511{
512        if (cfg->reg->sts & SLINK_S_TNF) {
513                cfg->reg->td = channel << SLINK_CHAN_POS | data;
514#ifdef SLINK_COLLECT_STATISTICS
515                cfg->stats->writes++;
516#endif
517                return 0;
518        }
519
520        return -SLINK_QFULL;   
521}
522
523/*
524 * Function: SLINK_sequence
525 * Arguments: a: Array containing sequence commands
526 *            b: Array where SEQUENCE responses will be stored
527 *            n: Number of commands in a array
528 *            channel: Sequence Channel Number
529 *            reconly: Set to 1 if the SEQUENCE operation is receive only
530 * Returns: 0 if SEQUENCE could be started (SUCCESS)
531 *          -1 if SEQUNCE was not started due to ongoing SEQUENCE
532 */
533int SLINK_seqstart(int *a, int *b, int n, int channel, int reconly)
534
535        /* Only start a new SEQUENCE of the former SEQUENCE has completed */
536        if (cfg->status->seqstat == SLINK_ACTIVE ||
537            cfg->status->seqstat == SLINK_PARERR)
538                return -1;
539
540        /* Tell core about arrays */
541        cfg->reg->abase = (int)a;
542        cfg->reg->bbase = (int)b;
543       
544        /* As far as software is concerned the sequence is now active */
545        cfg->status->seqstat = SLINK_ACTIVE;
546
547        /* Enable SEQUENCE operation with SCN = channel and SLEN = n-1 */
548        if (reconly == 1) {
549           cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) | SLINK_C_SRO |
550                             (channel << SLINK_C_SCN_POS) |
551                             SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
552        } else {
553           cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) |
554                             (channel << SLINK_C_SCN_POS) |
555                             SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
556        }
557
558#ifdef SLINK_COLLECT_STATISTICS
559        cfg->stats->sequences++;
560#endif
561
562        return 0;
563}
564
565
566/* Function: SLINK_seqabort
567 * Description: This function aborts an ongoing SEQUENCE. Software can tell
568 * when the SEQUENCE is aborted by polling SLINK_seqstat().
569 */
570void SLINK_seqabort(void)
571{
572        cfg->reg->ctrl = cfg->reg->ctrl | SLINK_C_AS;
573}
574
575
576/*
577 * Function: SLINK_seqstatus
578 * Returns: The current or status of the SEQUENCE operation:
579 *          SLINK_COMPLETED, SLINK_ACTIVE, SLINK_PARERR, SLINK_AMBAERR,
580 *          SLINK_ABORTED (these are defined in bsp/grslink.h)
581 * Description: Meaning of returned values:
582 *              SLINK_ABORTED: Aborted before all operations completed.
583 *              SLINK_ACTIVE: The core is busy processing the SEQUENCE
584 *              SLINK_AMBAERR: The last SEQUENCE was aborted by an AMBA ERROR
585 *              SLINK_COMPLETED: All words were transferred in the last SEQUENCE
586 *              SLINK_PARERR: Parity error detected. Software may want to abort
587 *
588 *              If the SEQUENCE was aborted SLINK_seqwrds() can be used to
589 *              determine the number of completed operations.
590 */
591int SLINK_seqstatus(void)
592{
593        return cfg->status->seqstat;
594}
595
596/*
597 * Function: SLINK_seqwrds
598 * Returns: -1 for ongoing sequence
599 *          0 if all words were transferred in the last sequence
600 *          number of words if the last SEQUENCE did not complete
601 *          (SLINK_AMBAERR or SLINK_ABORTED is reported ny SLINK_seqstatus())
602 */
603int SLINK_seqwrds(void)
604{
605        switch (cfg->status->seqstat) {
606        case SLINK_COMPLETED: return 0;
607        case SLINK_ACTIVE | SLINK_PARERR: return -1;
608        default: return cfg->status->scnt;
609        }
610}
611
612/*
613 * Function: SLINK_hwstatus
614 * Returns: The SLINK core's status register. The register values can be
615 *          interpreted with the help of macros defined in bsp/grslink.h.
616 */
617int SLINK_hwstatus(void)
618{
619        return cfg->reg->sts;
620}
621
622/*
623 * Function: SLINK_queuestatus
624 * Arguments: iocard: Queue which to check status for
625 * Returns: Number of elements in queue or -1 on non-existent queue
626 * Description: SLINK_queuestatus(queue) returns the number of elements in
627 *              queue 'iocard'
628 */
629int SLINK_queuestatus(int iocard)
630{       
631        unsigned int first, last;
632        SLINK_queue *ioq;
633       
634        if (iocard >= SLINK_NUMQUEUES)
635                return -1;
636
637        ioq = cfg->queues + iocard;
638
639        if (ioq->full)
640                return ioq->size;
641        if (ioq->first == ioq->last)
642                return 0;
643
644        first = ((unsigned int)ioq->first)/sizeof(unsigned int);
645        last = ((unsigned int)ioq->last)/sizeof(unsigned int);
646       
647        return first < last ? last - first : ioq->size - first + last;
648}
649
650/*
651 * Function: SLINK_dequeue
652 * Arguments: iocard: IO card number
653 *            elem: First element in IO card queue
654 * Returns: 0 on success or -1 on empty or non-existent queue
655 * Description:
656 */
657int SLINK_dequeue(int iocard, int *elem)
658{       
659        if (iocard >= SLINK_NUMQUEUES)
660                return -1;
661       
662        SLINK_queue *ioq = cfg->queues + iocard;
663       
664        if (ioq->last != ioq->first || ioq->full) {
665                *elem = *ioq->first;
666                ioq->first = (ioq->first >= ioq->max) ? ioq->buf : ioq->first+1;
667                ioq->full = 0;
668                return 0;
669        }
670        return -1;
671}
672
673/*
674 * Function: SLINK_statistics
675 * Returns: If the core has statistics colletion enabled this function returns
676 * a pointer to a struct containing statistics information, otherwise NULL.
677 */
678SLINK_stats *SLINK_statistics(void)
679{
680#ifdef SLINK_COLLECT_STATISTICS
681        return cfg->stats;
682#else
683        return NULL;
684#endif
685}
Note: See TracBrowser for help on using the repository browser.