Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:07

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * This file contains the RTEMS GRSLINK SLINK master driver
0005  *
0006  * COPYRIGHT (c) 2009.
0007  * Cobham Gaisler AB.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  *
0030  * Comments concerning current driver implementation:
0031  *
0032  * The SLINK specification says that there are three IO cards that are capable 
0033  * of transmitting data. But these IO cards can have the address range 0 to 3, 
0034  * and an 'For information only' comment explains that the current 
0035  * implementation has receive buffers for ".. x 4 (IO cards)".
0036  * Because of this the driver has four queues, one for each IO card 0 - 3. 
0037  * When the addressing convention used for the IO cards is known, the number of
0038  * queues may be lowered to three.
0039  *
0040  */
0041 
0042 #include <stdlib.h>
0043 
0044 #include <bsp.h>
0045 #include <grlib/grslink.h>
0046 #include <grlib/ambapp.h>
0047 #include <grlib/grlib.h>
0048 
0049 #include <grlib/grlib_impl.h>
0050 
0051 #ifndef GAISLER_SLINK
0052 #define GAISLER_SLINK 0x02F
0053 #endif
0054 
0055 /* Enable debug output? */
0056 /* #define DEBUG */
0057 
0058 #ifdef DEBUG
0059 #define DBG(x...) printk(x)
0060 #else
0061 #define DBG(x...) 
0062 #endif
0063 
0064 /* Bits and fields in SLINK transmit word */
0065 #define SLINK_RW (1 << 23)
0066 #define SLINK_CHAN_POS 16
0067 
0068 /* Local types */
0069 typedef struct {
0070     volatile unsigned int clockscale;
0071     volatile unsigned int ctrl;
0072     volatile unsigned int nullwrd;
0073     volatile unsigned int sts;
0074     volatile unsigned int msk;
0075     volatile unsigned int abase;
0076     volatile unsigned int bbase;
0077     volatile unsigned int td;
0078     volatile unsigned int rd;
0079 } SLINK_regs;
0080 
0081 typedef struct {
0082     char readstat;         /* Status of READ operation */
0083     char seqstat;          /* Status of SEQUENCE operation */
0084     unsigned char scnt;    /* Number of SEQUENCE words transferred */
0085 } SLINK_status;
0086 
0087 typedef struct {
0088     int size;
0089     unsigned int *buf;
0090     unsigned int *first;
0091     unsigned int *last;
0092     unsigned int *max;
0093     int full;
0094 } SLINK_queue;
0095 
0096 typedef struct {
0097     SLINK_regs    *reg;     /* Pointer to core registers */
0098     SLINK_status  *status;  /* Driver status information */
0099     void          (*slink_irq_handler)(int); /* Handler for INTERRUPT */
0100     void          (*slink_seq_change)(int); /* Callback on SEQUENCE change */
0101     int           rword;    /* Placeholder for READ response */
0102     rtems_id      read_sem; /* Semaphore for blocking SLINK_read */
0103     SLINK_queue   *queues;  /* Receive queues */
0104 #ifdef SLINK_COLLECT_STATISTICS
0105     SLINK_stats   *stats;   /* Core statistics, optional */
0106 #endif
0107 } SLINK_cfg;
0108 
0109 
0110 static SLINK_cfg *cfg = NULL;
0111 
0112 /**** SLINK driver queues for unsolicited and INTERRUPT requests ****/
0113 
0114 /* Function: SLINK_createqueues
0115  * Arguments: size: Number of elements in each queue
0116  * Returns: 0 on success, -1 on failure
0117  * Description: Creates SLINK_NUMQUEUES queues, one for each IO card 
0118  * that can send data. The pointers to the queues is saved in the driver 
0119  * config structure.
0120  */
0121 static int SLINK_createqueues(int size)
0122 {
0123     SLINK_queue *q;
0124     int i, j;
0125 
0126     if ((q = grlib_malloc(SLINK_NUMQUEUES*sizeof(*q))) == NULL)
0127         goto slink_qiniterr1;
0128         
0129     for (i = 0; i < SLINK_NUMQUEUES; i++) {
0130         q[i].size = size;
0131         if ((q[i].buf = grlib_malloc(size*sizeof(int))) == NULL)
0132             goto slink_qiniterr2;
0133         q[i].first = q[i].last = q[i].buf;
0134         q[i].max = q[i].buf + (size-1);
0135         q[i].full = 0;
0136     }
0137 
0138         cfg->queues = q;
0139 
0140     return 0;
0141     
0142  slink_qiniterr2:
0143     for (j = 0; j < i; j++)
0144         free(q[i].buf);
0145     free(q);
0146  slink_qiniterr1:
0147     return -1;
0148 }
0149 
0150 /*
0151  * Function: SLINK_destroyqueues
0152  * Arguments: None
0153  * Returns: Nothing
0154  * Description: Frees the memory occupied by the queues in cfg->queues
0155  */
0156 /*
0157   static void SLINK_destroyqueues(void)
0158   {
0159         int i;
0160     
0161     for(i = 0; i < SLINK_NUMQUEUES; i++)
0162         free(cfg->queues[i].buf);
0163 
0164     free(cfg->queues);
0165 }
0166 */
0167 
0168 /*
0169  * Function: SLINK_enqueue
0170  * Arguments: Received SLINK word
0171  * Returns: Nothing
0172  * Description: 
0173  */
0174 static void SLINK_enqueue(unsigned int slink_wrd)
0175 {
0176     SLINK_queue *ioq = cfg->queues + SLINK_WRD_CARDNUM(slink_wrd); 
0177 
0178     if (!ioq->full && SLINK_WRD_CARDNUM(slink_wrd) < SLINK_NUMQUEUES) {
0179         *ioq->last = slink_wrd;
0180         ioq->last = (ioq->last >= ioq->max) ? ioq->buf : ioq->last+1;
0181         ioq->full = ioq->last == ioq->first;
0182         return;
0183     }
0184 #ifdef SLINK_COLLECT_STATISTICS
0185     cfg->stats->lostwords++;
0186 #endif
0187 }
0188 
0189 /**** SLINK driver helper functions ****/
0190 
0191 /*
0192  * Function: SLINK_getaddr
0193  * Arguments: amba_conf 
0194  *            base: assigned to base of core registers
0195  *            irq: assigned to core irq lines
0196  * Returns: Base address and IRQ via arguments, 0 if core is found, else -1
0197  * Description: See above.
0198  */
0199 static int SLINK_getaddr(int *base, int *irq)
0200 {   
0201     struct ambapp_apb_info c;
0202 
0203     if (ambapp_find_apbslv(ambapp_plb(),VENDOR_GAISLER,GAISLER_SLINK,&c) == 1) {
0204         *base = c.start;
0205         *irq = c.common.irq;
0206         return 0;
0207     }
0208     return -1;
0209 }
0210 
0211 /* Function: SLINK_calcscaler
0212  * Arguments: sysfreq: System frequency in Hz
0213  * Returns: Clock scaler register value
0214  * Description: Calculates value for SLINK clock scaler register to attain
0215  * a SLINK bus frequency as close to 6 MHz as possible. Please see the IP core 
0216  * documentation for a description of how clock scaling is implemented. 
0217  */
0218 static int SLINK_calcscaler(int sysfreq)
0219 {
0220     int fact = sysfreq / SLINK_FREQ_HZ;
0221     return ((fact/2-1) << 16) | (fact % 2 ? fact/2 : fact/2-1);  
0222 }
0223 
0224 
0225 /*
0226  * Function: SLINK_getsysfreq
0227  * Arguments: None
0228  * Returns: System frequency in Hz, or 0 if system timer is not found.
0229  * Description: Looks at the timer to determine system frequency. Makes use
0230  * of AMBA Plug'n'Play. 
0231  */
0232 static int SLINK_getsysfreq(void)
0233 {
0234     struct ambapp_apb_info t;
0235     struct gptimer_regs *tregs;
0236         
0237     if (ambapp_find_apbslv(ambapp_plb(),VENDOR_GAISLER,GAISLER_GPTIMER,&t)==1) {
0238         tregs = (struct gptimer_regs *)t.start;
0239         DBG("SLINK_getsysfreq returning %d\n", 
0240             (tregs->scaler_reload+1)*1000*1000);
0241         return (tregs->scaler_reload+1)*1000*1000;
0242     }
0243     return 0;
0244 }
0245 
0246 /*
0247  * Function: SLINK_interrupt_handler
0248  * Arguments: v: not used
0249  * Returns: Nothing
0250  * Description: Interrupt handles checks RNE, SEQUENCE and error status
0251  * bits. Reads word from receive queue and distinguishes between INTERRUPT,
0252  * READ responses and SLAVE-WORD-SEND. When an INTERRUPT transfer is detected
0253  * the handler calls the user specified slink_irq_handler with the received
0254  * word. READ responses are saved and given to SLINK_read via a private
0255  * variable. SLAVE-WORD-SEND transfers are placed in the IO card's receive
0256  * queue.
0257  */
0258 static rtems_isr SLINK_interrupt_handler(void *v)
0259 {
0260     unsigned int sts;
0261     unsigned int wrd;
0262 
0263     /* Read all words from Receive queue */
0264     while ((sts = cfg->reg->sts) & SLINK_S_RNE) {
0265 
0266         /* Read first word in receive queue */
0267         wrd = cfg->reg->rd;
0268     
0269         /* Check channel value to determine action */
0270         switch (SLINK_WRD_CHAN(wrd)) {
0271         case 0: /* Interrupt */
0272             cfg->slink_irq_handler(wrd);
0273 #ifdef SLINK_COLLECT_STATISTICS
0274             cfg->stats->interrupts++;
0275 #endif
0276             break;
0277         case 3: /* Read response, if no active READ, fall-through */
0278             if (cfg->status->readstat == SLINK_ACTIVE) {
0279                 rtems_semaphore_release(cfg->read_sem);
0280                 cfg->status->readstat = SLINK_COMPLETED;
0281                 cfg->rword = wrd;
0282                 break;
0283             }
0284         default: /* Unsolicited request */
0285             SLINK_enqueue(wrd);
0286             break;
0287         }
0288     }
0289 
0290     /* Check sequence operation */
0291     if (sts & SLINK_S_SC) {
0292         /* SEQUENCE completed */
0293         cfg->status->seqstat = SLINK_COMPLETED;
0294         if (cfg->slink_seq_change)
0295             cfg->slink_seq_change(SLINK_COMPLETED);
0296 #ifdef SLINK_COLLECT_STATISTICS
0297         cfg->stats->seqcomp++;
0298 #endif
0299     } else if (sts & SLINK_S_SA) {
0300         /* SEQUENCE aborted */
0301         cfg->status->seqstat = SLINK_ABORTED;
0302         cfg->status->scnt = (sts >> SLINK_S_SI_POS);
0303         if (cfg->slink_seq_change)
0304             cfg->slink_seq_change(SLINK_ABORTED);
0305     }
0306 
0307     /* Check error conditions */
0308     if (sts & SLINK_S_PERR) {
0309         /* 
0310            Parity error detected, set seqstat if there is an ongoing 
0311            sequence so that the calling application can decide if the
0312            sequence should be aborted 
0313         */
0314         if (cfg->status->seqstat == SLINK_ACTIVE) {
0315             cfg->status->seqstat = SLINK_PARERR;
0316             if (cfg->slink_seq_change)
0317                 cfg->slink_seq_change(SLINK_PARERR);
0318         }
0319         /* Abort READ operation */
0320         if (cfg->status->readstat == SLINK_ACTIVE) {
0321             cfg->status->readstat = SLINK_PARERR;
0322             rtems_semaphore_release(cfg->read_sem);
0323         }
0324 #ifdef SLINK_COLLECT_STATISTICS
0325         cfg->stats->parerr++;
0326 #endif
0327     } 
0328     if (sts & SLINK_S_AERR) {
0329         /* AMBA error response, sequence aborted */
0330         cfg->status->seqstat = SLINK_AMBAERR;
0331         cfg->status->scnt = sts >> SLINK_S_SI_POS;
0332         if (cfg->slink_seq_change)
0333             cfg->slink_seq_change(SLINK_AMBAERR);
0334     }
0335     if (sts & SLINK_S_ROV) {
0336         /* Receive overflow, abort any ongoing READ */ 
0337         if (cfg->status->readstat == SLINK_ACTIVE) {
0338             cfg->status->readstat = SLINK_ROV;
0339             rtems_semaphore_release(cfg->read_sem);
0340         }
0341 #ifdef SLINK_COLLECT_STATISICS
0342         cfg->status->recov++;
0343 #endif
0344     }
0345 
0346     /* Clear processed bits */
0347     cfg->reg->sts = sts;
0348 }
0349 
0350 /**** SLINK driver interface starts here ****/
0351 
0352 /* Function: SLINK_init
0353  * Arguments: nullwrd: NULL word
0354  *            parity: Even (0) or Odd (1) parity
0355  *            interrupt_trans_handler: Function that handles interrupt requests
0356  *            sequence_callback: Callback on SEQUENCE status changes
0357  *            qsize: Size of each receive queue
0358  * Returns: 0 on success, -1 on failure
0359  * Description: Initializes the SLINK core
0360  */
0361 int SLINK_init(unsigned int nullwrd, int parity, int qsize,
0362            void (*interrupt_trans_handler)(int),
0363            void (*sequence_callback)(int))
0364 {
0365     int base;
0366     int irq;
0367     rtems_status_code st;
0368 
0369     /* Allocate private config structure */
0370     if (cfg == NULL && (cfg = grlib_malloc(sizeof(*cfg))) == NULL) {
0371         DBG("SLINK_init: Could not allocate cfg structure\n");
0372         goto slink_initerr1;
0373     }
0374     
0375     /* Create simple binary semaphore for blocking SLINK_read */
0376     st = rtems_semaphore_create(rtems_build_name('S', 'L', 'R', '0'), 0, 
0377                     (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
0378                      RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
0379                      RTEMS_NO_PRIORITY_CEILING), 0,
0380                     &cfg->read_sem);
0381     if (st != RTEMS_SUCCESSFUL) {
0382         DBG("SLINK_init: Could not create semaphore\n");
0383         goto slink_initerr1;
0384     }
0385   
0386     /* Initialize pointer to SLINK core registers and get IRQ line */
0387     if (SLINK_getaddr(&base, &irq) == -1) {
0388         DBG("SLINK_init: Could not find core\n");
0389         goto slink_initerr2;
0390     }
0391     cfg->reg = (SLINK_regs*)base;
0392 
0393     /* Allocate status structure and initialize members */
0394     if ((cfg->status = grlib_calloc(1, sizeof(*cfg->status))) == NULL) {
0395         DBG("SLINK_init: Could not allocate status structure\n");
0396         goto slink_initerr2;
0397     }
0398     cfg->status->seqstat = SLINK_COMPLETED;
0399     cfg->status->readstat = SLINK_COMPLETED;
0400 
0401 #ifdef SLINK_COLLECT_STATISTICS
0402     /* Allocate statistics structure and initialize members */
0403     if ((cfg->stats = grlib_calloc(1, sizeof(*cfg->stats))) == NULL) {
0404         DBG("SLINK_init: Could not allocate statistics structure\n");
0405         goto slink_initerr3;
0406     }
0407 #endif
0408 
0409     /* Allocate and initialize queues */
0410     if (SLINK_createqueues(qsize) == -1) {
0411         DBG("SLINK_init: Could not create queues\n");
0412         goto slink_initerr3;
0413     }
0414 
0415     /* Configure core registers */
0416     cfg->reg->clockscale = SLINK_calcscaler(SLINK_getsysfreq());
0417     cfg->reg->ctrl = parity ? SLINK_C_PAR : 0;
0418     cfg->reg->nullwrd = nullwrd;
0419     cfg->reg->msk = (SLINK_M_PERRE | SLINK_M_AERRE | SLINK_M_ROVE |
0420              SLINK_M_RNEE | SLINK_M_SAE | SLINK_M_SCE);
0421 
0422     /* Set-up INTERRUPT transfer handling */
0423     cfg->slink_irq_handler = interrupt_trans_handler;
0424 
0425     /* Save SEQUENCE callback */
0426     cfg->slink_seq_change = sequence_callback;
0427 
0428     /* Set-up IRQ handling */
0429     rtems_interrupt_handler_install(irq, "slink",
0430             RTEMS_INTERRUPT_SHARED,
0431             SLINK_interrupt_handler, NULL);
0432     
0433     return 0;
0434 
0435  slink_initerr3:
0436     free(cfg->status);
0437  slink_initerr2:
0438     free(cfg);
0439  slink_initerr1:
0440     return -1;
0441 }
0442 
0443 /* Function: SLINK_start
0444  * Description: Enables the core
0445  */
0446 void SLINK_start(void)
0447 {   
0448     if (cfg != NULL)
0449         cfg->reg->ctrl |= SLINK_C_SLE;
0450 }
0451 
0452 /* Function: SLINK_stop
0453  * Description: Disables the core
0454  */
0455 void SLINK_stop(void)
0456 {
0457     if (cfg != NULL)
0458         cfg->reg->ctrl &= ~SLINK_C_SLE;
0459 }
0460 
0461 /*
0462  * Function: SLINK_read
0463  * Arguments: data: Payload of data word
0464  *            channel: -
0465  *            reply: Reply from IO card
0466  * Returns: 0 on success
0467  *          -(SLINK_PARERR, SLINK_ROV) on error or -SLINK_QFULL if transmit queue
0468  *          is full and software should try again.
0469  * Description: Reads one word and returns the response in *reply unless there
0470  *              is an error. This function blocks until the READ operation is
0471  *              completed or aborted.
0472  */
0473 int SLINK_read(int data, int channel, int *reply)
0474 {   
0475     DBG("SLINK_read: called..");
0476 
0477     if (cfg->reg->sts & SLINK_S_TNF) {
0478         cfg->status->readstat = SLINK_ACTIVE;
0479         cfg->reg->td = SLINK_RW | channel << SLINK_CHAN_POS | data;
0480     } else {
0481         DBG("queue FULL\n");
0482         return -SLINK_QFULL; /* Transmit queue full */
0483     }
0484 
0485     /* Block until the operation has completed or has been aborted */
0486     rtems_semaphore_obtain(cfg->read_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0487 
0488     if (cfg->status->readstat == SLINK_COMPLETED) {
0489         *reply = cfg->rword; 
0490 #ifdef SLINK_COLLECT_STATISTICS
0491         cfg->stats->reads++;
0492 #endif       
0493         DBG("returning 0\n");
0494         return 0;
0495     } else {
0496         DBG("returning error code\n");
0497         return -cfg->status->readstat;
0498     }
0499 }
0500 
0501 /*
0502  * Function: SLINK_write
0503  * Arguments: data: Payload of SLINK data word
0504  *            channel: Channel value (bits 22 downto 16) of receive 
0505  *                     register word
0506  * Returns: 0 if command was placed in transmit queue
0507  *          -SLINK_QFULL if transmit queue was full (software should retry)
0508  * Description: See above.
0509  */
0510 int SLINK_write(int data, int channel)
0511 { 
0512     if (cfg->reg->sts & SLINK_S_TNF) {
0513         cfg->reg->td = channel << SLINK_CHAN_POS | data;
0514 #ifdef SLINK_COLLECT_STATISTICS
0515         cfg->stats->writes++;
0516 #endif
0517         return 0;
0518     }
0519 
0520     return -SLINK_QFULL;    
0521 }
0522 
0523 /*
0524  * Function: SLINK_sequence
0525  * Arguments: a: Array containing sequence commands
0526  *            b: Array where SEQUENCE responses will be stored
0527  *            n: Number of commands in a array
0528  *            channel: Sequence Channel Number
0529  *            reconly: Set to 1 if the SEQUENCE operation is receive only
0530  * Returns: 0 if SEQUENCE could be started (SUCCESS)
0531  *          -1 if SEQUNCE was not started due to ongoing SEQUENCE
0532  */
0533 int SLINK_seqstart(int *a, int *b, int n, int channel, int reconly)
0534 {  
0535     /* Only start a new SEQUENCE of the former SEQUENCE has completed */
0536     if (cfg->status->seqstat == SLINK_ACTIVE || 
0537         cfg->status->seqstat == SLINK_PARERR)
0538         return -1;
0539 
0540     /* Tell core about arrays */
0541     cfg->reg->abase = (int)a;
0542     cfg->reg->bbase = (int)b;
0543     
0544     /* As far as software is concerned the sequence is now active */
0545     cfg->status->seqstat = SLINK_ACTIVE;
0546 
0547     /* Enable SEQUENCE operation with SCN = channel and SLEN = n-1 */
0548         if (reconly == 1) {
0549            cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) | SLINK_C_SRO |
0550                              (channel << SLINK_C_SCN_POS) |
0551                              SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
0552         } else {
0553            cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) |
0554                              (channel << SLINK_C_SCN_POS) |
0555                              SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
0556         }
0557 
0558 #ifdef SLINK_COLLECT_STATISTICS
0559     cfg->stats->sequences++;
0560 #endif
0561 
0562     return 0;
0563 }
0564 
0565 
0566 /* Function: SLINK_seqabort
0567  * Description: This function aborts an ongoing SEQUENCE. Software can tell
0568  * when the SEQUENCE is aborted by polling SLINK_seqstat().
0569  */
0570 void SLINK_seqabort(void)
0571 {
0572     cfg->reg->ctrl = cfg->reg->ctrl | SLINK_C_AS;
0573 }
0574 
0575 
0576 /*
0577  * Function: SLINK_seqstatus
0578  * Returns: The current or status of the SEQUENCE operation:
0579  *          SLINK_COMPLETED, SLINK_ACTIVE, SLINK_PARERR, SLINK_AMBAERR,
0580  *          SLINK_ABORTED (these are defined in bsp/grslink.h)
0581  * Description: Meaning of returned values:
0582  *              SLINK_ABORTED: Aborted before all operations completed.
0583  *              SLINK_ACTIVE: The core is busy processing the SEQUENCE
0584  *              SLINK_AMBAERR: The last SEQUENCE was aborted by an AMBA ERROR
0585  *              SLINK_COMPLETED: All words were transferred in the last SEQUENCE
0586  *              SLINK_PARERR: Parity error detected. Software may want to abort
0587  *
0588  *              If the SEQUENCE was aborted SLINK_seqwrds() can be used to
0589  *              determine the number of completed operations.
0590  */
0591 int SLINK_seqstatus(void)
0592 {
0593     return cfg->status->seqstat;
0594 }
0595 
0596 /*
0597  * Function: SLINK_seqwrds
0598  * Returns: -1 for ongoing sequence
0599  *          0 if all words were transferred in the last sequence
0600  *          number of words if the last SEQUENCE did not complete 
0601  *          (SLINK_AMBAERR or SLINK_ABORTED is reported ny SLINK_seqstatus()) 
0602  */
0603 int SLINK_seqwrds(void)
0604 {
0605     switch (cfg->status->seqstat) {
0606     case SLINK_COMPLETED: return 0;
0607     case SLINK_ACTIVE | SLINK_PARERR: return -1;
0608     default: return cfg->status->scnt;
0609     }
0610 }
0611 
0612 /* 
0613  * Function: SLINK_hwstatus
0614  * Returns: The SLINK core's status register. The register values can be 
0615  *          interpreted with the help of macros defined in bsp/grslink.h.
0616  */
0617 int SLINK_hwstatus(void)
0618 {
0619     return cfg->reg->sts;
0620 }
0621 
0622 /*
0623  * Function: SLINK_queuestatus
0624  * Arguments: iocard: Queue which to check status for
0625  * Returns: Number of elements in queue or -1 on non-existent queue
0626  * Description: SLINK_queuestatus(queue) returns the number of elements in
0627  *              queue 'iocard'
0628  */
0629 int SLINK_queuestatus(int iocard)
0630 {   
0631     unsigned int first, last;
0632     SLINK_queue *ioq;
0633     
0634     if (iocard >= SLINK_NUMQUEUES)
0635         return -1;
0636 
0637     ioq = cfg->queues + iocard;
0638 
0639     if (ioq->full)
0640         return ioq->size;
0641     if (ioq->first == ioq->last)
0642         return 0;
0643 
0644     first = ((unsigned int)ioq->first)/sizeof(unsigned int);
0645     last = ((unsigned int)ioq->last)/sizeof(unsigned int);
0646     
0647     return first < last ? last - first : ioq->size - first + last; 
0648 }
0649 
0650 /*
0651  * Function: SLINK_dequeue
0652  * Arguments: iocard: IO card number
0653  *            elem: First element in IO card queue
0654  * Returns: 0 on success or -1 on empty or non-existent queue
0655  * Description: 
0656  */
0657 int SLINK_dequeue(int iocard, int *elem)
0658 {   
0659     if (iocard >= SLINK_NUMQUEUES)
0660         return -1;
0661     
0662     SLINK_queue *ioq = cfg->queues + iocard;
0663     
0664     if (ioq->last != ioq->first || ioq->full) {
0665         *elem = *ioq->first;
0666         ioq->first = (ioq->first >= ioq->max) ? ioq->buf : ioq->first+1;
0667         ioq->full = 0;
0668         return 0;
0669     }
0670     return -1;
0671 }
0672 
0673 /*
0674  * Function: SLINK_statistics
0675  * Returns: If the core has statistics colletion enabled this function returns
0676  * a pointer to a struct containing statistics information, otherwise NULL.
0677  */
0678 SLINK_stats *SLINK_statistics(void)
0679 {
0680 #ifdef SLINK_COLLECT_STATISTICS
0681     return cfg->stats;
0682 #else
0683     return NULL;
0684 #endif
0685 }