Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:43

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  GRSPW/GRSPW2 SpaceWire Kernel Library Interface
0005  *
0006  *  COPYRIGHT (c) 2011
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 
0031 #ifndef __GRSPW_PKT_H__
0032 #define __GRSPW_PKT_H__
0033 
0034 struct grspw_pkt;
0035 
0036 /* Maximum number of GRSPW devices supported by driver */
0037 #define GRSPW_MAX 32
0038 
0039 /* Weak overridable variable the user can use to define the worker-task
0040  * priority (0..255) or to disable (-1) the creation of the worker-task
0041  * and the message queue to save space */
0042 extern int grspw_work_task_priority;
0043 
0044 #ifndef GRSPW_PKT_FLAGS
0045 #define GRSPW_PKT_FLAGS
0046 /*** TX Packet flags ***/
0047 
0048 /* Enable IRQ generation */
0049 #define TXPKT_FLAG_IE 0x0040
0050 
0051 /* Enable Header CRC generation (if CRC is available in HW)
0052  * Header CRC will be appended (one byte at end of header)
0053  */
0054 #define TXPKT_FLAG_HCRC 0x0100
0055 
0056 /* Enable Data CRC generation (if CRC is available in HW)
0057  * Data CRC will be appended (one or two byte at end of packet, depending on
0058  * Data CRC type)
0059  */
0060 #define TXPKT_FLAG_DCRC 0x0200
0061 
0062 /* Data CRC type */
0063 #define TXPKT_FLAG_DCRCT_MASK   0x0c00
0064 /* RMAP CRC. 1 byte */
0065 #define TXPKT_FLAG_DCRCT_RMAP   0x0000
0066 /* CCSDS/CCITT CRC-16. 2 byte */
0067 #define TXPKT_FLAG_DCRCT_CCSDS  0x0400
0068 /* 16-bit ISO-checksum (J.G. Fletcher, ISO 8473-1:1998). 2 byte */
0069 #define TXPKT_FLAG_DCRCT_ISO16  0x0800
0070 
0071 /* Control how many bytes the beginning of the Header 
0072  * the CRC should not be calculated for */
0073 #define TXPKT_FLAG_NOCRC_MASK 0x0000000f
0074 #define TXPKT_FLAG_NOCRC_LEN0 0x00000000
0075 #define TXPKT_FLAG_NOCRC_LEN1 0x00000001
0076 #define TXPKT_FLAG_NOCRC_LEN2 0x00000002
0077 #define TXPKT_FLAG_NOCRC_LEN3 0x00000003
0078 #define TXPKT_FLAG_NOCRC_LEN4 0x00000004
0079 #define TXPKT_FLAG_NOCRC_LEN5 0x00000005
0080 #define TXPKT_FLAG_NOCRC_LEN6 0x00000006
0081 #define TXPKT_FLAG_NOCRC_LEN7 0x00000007
0082 #define TXPKT_FLAG_NOCRC_LEN8 0x00000008
0083 #define TXPKT_FLAG_NOCRC_LEN9 0x00000009
0084 #define TXPKT_FLAG_NOCRC_LENa 0x0000000a
0085 #define TXPKT_FLAG_NOCRC_LENb 0x0000000b
0086 #define TXPKT_FLAG_NOCRC_LENc 0x0000000c
0087 #define TXPKT_FLAG_NOCRC_LENd 0x0000000d
0088 #define TXPKT_FLAG_NOCRC_LENe 0x0000000e
0089 #define TXPKT_FLAG_NOCRC_LENf 0x0000000f
0090 
0091 #define TXPKT_FLAG_INPUT_MASK (TXPKT_FLAG_NOCRC_MASK | TXPKT_FLAG_IE | \
0092                 TXPKT_FLAG_HCRC | TXPKT_FLAG_DCRC | \
0093                 TXPKT_FLAG_DCRCT_MASK)
0094 
0095 /* Marks if packet was transmitted or not */
0096 #define TXPKT_FLAG_TX 0x4000
0097 
0098 /* Link Error */
0099 #define TXPKT_FLAG_LINKERR 0x8000
0100 
0101 #define TXPKT_FLAG_OUTPUT_MASK (TXPKT_FLAG_TX | TXPKT_FLAG_LINKERR)
0102 
0103 /*** RX Packet Flags ***/
0104 
0105 /* Enable IRQ generation */
0106 #define RXPKT_FLAG_IE 0x0010
0107 
0108 #define RXPKT_FLAG_INPUT_MASK (RXPKT_FLAG_IE)
0109 
0110 /* Packet was truncated */
0111 #define RXPKT_FLAG_TRUNK 0x0800
0112 /* Data CRC error (only valid if RMAP CRC is enabled) */
0113 #define RXPKT_FLAG_DCRC 0x0400
0114 /* Header CRC error (only valid if RMAP CRC is enabled) */
0115 #define RXPKT_FLAG_HCRC 0x0200
0116 /* Error in End-of-Packet */
0117 #define RXPKT_FLAG_EEOP 0x0100
0118 /* Marks if packet was recevied or not */
0119 #define RXPKT_FLAG_RX 0x8000
0120 
0121 #define RXPKT_FLAG_OUTPUT_MASK (RXPKT_FLAG_TRUNK | RXPKT_FLAG_DCRC | \
0122                 RXPKT_FLAG_HCRC | RXPKT_FLAG_EEOP)
0123 
0124 /*** General packet flag options ***/
0125 
0126 /* Translate Hdr and/or Payload address */
0127 #define PKT_FLAG_TR_DATA 0x1000
0128 #define PKT_FLAG_TR_HDR 0x2000
0129 /* All General options */
0130 #define PKT_FLAG_MASK 0x3000
0131 
0132 #endif
0133 /* GRSPW RX/TX Packet structure.
0134  *
0135  * - For RX the 'hdr' and 'hlen' fields are not used, they are not written
0136  *   by driver.
0137  *
0138  * - The 'pkt_id' field is untouched by driver, it is intended for packet
0139  *   numbering or user-custom data.
0140  *
0141  * - The last packet in a list must have 'next' set to NULL.
0142  *
0143  * - data and hdr pointers are written without modification to hardware,
0144  *   this means that caller must do address translation to hardware
0145  *   address itself.
0146  *
0147  * - the 'flags' field are interpreted differently depending on transfer
0148  *   type (RX/TX). See XXPKT_FLAG_* options above.
0149  */
0150 struct grspw_pkt {
0151     struct grspw_pkt *next; /* Next packet in list. NULL if last packet */
0152     unsigned int pkt_id;    /* User assigned ID (not touched by driver) */
0153     unsigned short flags;   /* RX/TX Options and status */
0154     unsigned char reserved; /* Reserved, must be zero */
0155     unsigned char hlen; /* Length of Header Buffer (only TX) */
0156     unsigned int dlen;  /* Length of Data Buffer */
0157     void *data; /* 4-byte or byte aligned depends on HW */
0158     void *hdr;  /* 4-byte or byte aligned depends on HW (only TX) */
0159 };
0160 
0161 /* GRSPW SpaceWire Packet List */
0162 struct grspw_list {
0163     struct grspw_pkt *head;
0164     struct grspw_pkt *tail;
0165 };
0166 
0167 /* SpaceWire Link State */
0168 typedef enum {
0169     SPW_LS_ERRRST = 0,
0170     SPW_LS_ERRWAIT = 1,
0171     SPW_LS_READY = 2,
0172     SPW_LS_STARTED = 3,
0173     SPW_LS_CONNECTING = 4,
0174     SPW_LS_RUN = 5
0175 } spw_link_state_t;
0176 
0177 /* Address Configuration */
0178 struct grspw_addr_config {
0179     /* Ignore address field and put all received packets to first
0180      * DMA channel.
0181      */
0182     int promiscuous;
0183 
0184     /* Default Node Address and Mask */
0185     unsigned char def_addr;
0186     unsigned char def_mask;
0187     /* DMA Channel custom Node Address and Mask */
0188     struct {
0189         char node_en;           /* Enable Separate Addr */
0190         unsigned char node_addr;    /* Node address */
0191         unsigned char node_mask;    /* Node address mask */
0192     } dma_nacfg[4];
0193 };
0194 
0195 /* Hardware Support in GRSPW Core */
0196 struct grspw_hw_sup {
0197     char    rmap;       /* If RMAP in HW is available */
0198     char    rmap_crc;   /* If RMAP CRC is available */
0199     char    rx_unalign; /* RX unaligned (byte boundary) access allowed*/
0200     char    nports;     /* Number of Ports (1 or 2) */
0201     char    ndma_chans; /* Number of DMA Channels (1..4) */
0202     char    strip_adr;  /* Hardware can strip ADR from packet data */
0203     char    strip_pid;  /* Hardware can strip PID from packet data */
0204     int hw_version; /* GRSPW Hardware Version */
0205     char    reserved[2];
0206     char    irq;        /* SpW Distributed Interrupt available if 1 */
0207     char    irq_num;    /* Number of interrupts that can be generated */
0208     char    itmr_width; /* SpW Intr. ISR timers bit width. 0=no timer */
0209     char    ccsds_crc;  /* CCSDS CRC-16 and 16-bit ISO is available */
0210 };
0211 
0212 struct grspw_core_stats {
0213     int irq_cnt;
0214     int err_credit;
0215     int err_eeop;
0216     int err_addr;
0217     int err_parity;
0218     int err_disconnect;
0219     int err_escape;
0220     int err_wsync; /* only in GRSPW1 */
0221 };
0222 
0223 /* grspw_link_ctrl() options */
0224 #define LINKOPTS_ENABLE     0x0000
0225 #define LINKOPTS_DISABLE    0x0001
0226 #define LINKOPTS_START      0x0002
0227 #define LINKOPTS_AUTOSTART  0x0004
0228 #define LINKOPTS_DIS_ONERR  0x0008  /* Disable DMA transmitter on link error
0229                      * Controls LE bit in DMACTRL register.
0230                      */
0231 #define LINKOPTS_DIS_ON_CE  0x0020000/* Disable Link on Credit error */
0232 #define LINKOPTS_DIS_ON_ER  0x0040000/* Disable Link on Escape error */
0233 #define LINKOPTS_DIS_ON_DE  0x0080000/* Disable Link on Disconnect error */
0234 #define LINKOPTS_DIS_ON_PE  0x0100000/* Disable Link on Parity error */
0235 #define LINKOPTS_DIS_ON_WE  0x0400000/* Disable Link on write synchonization
0236                       * error (GRSPW1 only)
0237                       */
0238 #define LINKOPTS_DIS_ON_EE  0x1000000/* Disable Link on Early EOP/EEP error*/
0239 
0240 /*#define LINKOPTS_TICK_OUT_IRQ 0x0100*//* Enable Tick-out IRQ */
0241 #define LINKOPTS_EIRQ       0x0200  /* Enable Error Link IRQ */
0242 
0243 #define LINKOPTS_MASK       0x15e020f/* All above options */
0244 #define LINKOPTS_MASK_DIS_ON    0x15e0000/* All disable link on error options
0245                       * On a certain error the link disable
0246                       * bit will be written and the work
0247                       * task will call dma_stop() for all
0248                       * channels.
0249                       */
0250 
0251 #define LINKSTS_CE      0x002   /* Credit error */
0252 #define LINKSTS_ER      0x004   /* Escape error */
0253 #define LINKSTS_DE      0x008   /* Disconnect error */
0254 #define LINKSTS_PE      0x010   /* Parity error */
0255 #define LINKSTS_WE      0x040   /* Write synchonization error (GRSPW1 only) */
0256 #define LINKSTS_IA      0x080   /* Invalid address */
0257 #define LINKSTS_EE      0x100   /* Early EOP/EEP */
0258 #define LINKSTS_MASK        0x1de
0259 
0260 /* grspw_tc_ctrl() options */
0261 #define TCOPTS_EN_RXIRQ 0x0001  /* Tick-Out IRQ */
0262 #define TCOPTS_EN_TX    0x0004
0263 #define TCOPTS_EN_RX    0x0008
0264 
0265 /* grspw_ic_ctrl() options:
0266  * Corresponds code duplicatingly to GRSPW_CTRL_XX_BIT defines
0267  */
0268 #define ICOPTS_INTNUM       (0x1f << 27)
0269 #define ICOPTS_EN_SPWIRQ_ON_EE  (1 << 24)
0270 #define ICOPTS_EN_SPWIRQ_ON_IA  (1 << 23)
0271 #define ICOPTS_EN_PRIO      (1 << 22)
0272 #define ICOPTS_EN_TIMEOUTIRQ    (1 << 20)
0273 #define ICOPTS_EN_ACKIRQ    (1 << 19)
0274 #define ICOPTS_EN_TICKOUTIRQ    (1 << 18)
0275 #define ICOPTS_EN_RX        (1 << 17)
0276 #define ICOPTS_EN_TX        (1 << 16)
0277 #define ICOPTS_BASEIRQ      (0x1f << 8)
0278 #define ICOPTS_EN_FLAGFILTER    (1 << 0) /* NOTE: Not in icctrl. CTRL.bit12 */
0279 
0280 /* grspw_ic_rlisr() and grspw_ic_rlintack()  */
0281 #define ICRELOAD_EN     (1 << 31)
0282 #define ICRELOAD_MASK       0x7fffffff
0283 
0284 /* grspw_rmap_ctrl() options */
0285 #define RMAPOPTS_EN_RMAP    0x0001
0286 #define RMAPOPTS_EN_BUF     0x0002
0287 
0288 /* grspw_dma_config.flags options */
0289 #define DMAFLAG_NO_SPILL    0x0001  /* See HW doc DMA-CTRL NS bit */
0290 #define DMAFLAG_RESV1       0x0002  /* HAS NO EFFECT */
0291 #define DMAFLAG_STRIP_ADR   0x0004  /* See HW doc DMA-CTRL SA bit */
0292 #define DMAFLAG_STRIP_PID   0x0008  /* See HW doc DMA-CTRL SP bit */
0293 #define DMAFLAG_RESV2       0x0010  /* HAS NO EFFECT */
0294 #define DMAFLAG_MASK    (DMAFLAG_NO_SPILL|DMAFLAG_STRIP_ADR|DMAFLAG_STRIP_PID)
0295 /* grspw_dma_config.flags misc options (not shifted internally) */
0296 #define DMAFLAG2_TXIE   0x00100000  /* See HW doc DMA-CTRL TI bit. 
0297                      * Used to enable TX DMA interrupt
0298                      * when tx_irq_en_cnt=0.
0299                      */
0300 #define DMAFLAG2_RXIE   0x00200000  /* See HW doc DMA-CTRL RI bit.
0301                      * Used to enable RX DMA interrupt
0302                      * when rx_irq_en_cnt=0.
0303                      */
0304 /* Defines how the ISR will disable RX/TX DMA interrupt source when a DMA RX/TX
0305  * interrupt has happended. DMA Error Interrupt always disables both RX/TX DMA
0306  * interrupt. By default both RX/TX IRQs are disabled when either a RX, TX or
0307  * both RX/TX DMA interrupt has been requested. The work-task, custom
0308  * application handler or custom ISR handler is responsible to re-enable
0309  * DMA interrupts.
0310  */
0311 #define DMAFLAG2_IRQD_SRC  0x01000000   /* Disable triggering RX/TX source */
0312 #define DMAFLAG2_IRQD_NONE 0x00c00000   /* Never disable RX/TX IRQ in ISR */
0313 #define DMAFLAG2_IRQD_BOTH 0x00000000   /* Always disable both RX/TX sources */
0314 #define DMAFLAG2_IRQD_MASK 0x01c00000   /* Mask of options */
0315 #define DMAFLAG2_IRQD_BIT  22
0316 
0317 #define DMAFLAG2_MASK   (DMAFLAG2_TXIE | DMAFLAG2_RXIE | DMAFLAG2_IRQD_MASK)
0318 
0319 struct grspw_dma_config {
0320     int flags;      /* DMA config flags, see DMAFLAG1&2_* options */
0321     int rxmaxlen;       /* RX Max Packet Length */
0322     int rx_irq_en_cnt;  /* Enable RX IRQ every cnt descriptors */
0323     int tx_irq_en_cnt;  /* Enable TX IRQ every cnt descriptors */
0324 };
0325 
0326 /* Statistics per DMA channel */
0327 struct grspw_dma_stats {
0328     /* IRQ Statistics */
0329     int irq_cnt;        /* Number of DMA IRQs generated by channel */
0330 
0331     /* Descriptor Statistics */
0332     int tx_pkts;        /* Number of Transmitted packets */
0333     int tx_err_link;    /* Number of Transmitted packets with Link Error*/
0334     int rx_pkts;        /* Number of Received packets */
0335     int rx_err_trunk;   /* Number of Received Truncated packets */
0336     int rx_err_endpkt;  /* Number of Received packets with bad ending */
0337 
0338     /* Diagnostics to help developers sizing their number buffers to avoid
0339      * out-of-buffers or other phenomenons.
0340      */
0341     int send_cnt_min;   /* Minimum number of packets in TX SEND Q */
0342     int send_cnt_max;   /* Maximum number of packets in TX SEND Q */
0343     int tx_sched_cnt_min;   /* Minimum number of packets in TX SCHED Q */
0344     int tx_sched_cnt_max;   /* Maximum number of packets in TX SCHED Q */
0345     int sent_cnt_max;   /* Maximum number of packets in TX SENT Q */
0346     int tx_work_cnt;    /* Times the work thread processed TX BDs */
0347     int tx_work_enabled;    /* No. RX BDs enabled by work thread */
0348 
0349     int ready_cnt_min;  /* Minimum number of packets in RX READY Q */
0350     int ready_cnt_max;  /* Maximum number of packets in RX READY Q */
0351     int rx_sched_cnt_min;   /* Minimum number of packets in RX SCHED Q */
0352     int rx_sched_cnt_max;   /* Maximum number of packets in RX SCHED Q */
0353     int recv_cnt_max;   /* Maximum number of packets in RX RECV Q */
0354     int rx_work_cnt;    /* Times the work thread processed RX BDs */
0355     int rx_work_enabled;    /* No. RX BDs enabled by work thread */
0356 };
0357 
0358 /* ISR message sending call back. Compatible with rtems_message_queue_send().
0359  * The 'buf' parameter has a pointer to a WORK-TASK message defined by the
0360  * WORK_* macros below. The message indicates what GRSPW device operations
0361  * are pending, thus what caused the interrupt.
0362  *
0363  * \param data   defined by grspw_work_config.msgisr_arg, default a rtems_id.
0364  * \param buf    Pointer to a 32-bit message word
0365  * \param n      Always 4 (byte size of buf).
0366  */
0367 typedef int (*grspw_msgqisr_t)(void *data, unsigned int *buf, unsigned int n);
0368 
0369 /* Work message definitions, the int sent to *buf
0370  * Bits 31..24: reserved.
0371  * Bits 23..16: GRSPW device number message is associated with.
0372  * Bit  15:     reserved.
0373  * Bit  14:     work-task shall delete message queue on exit.
0374  * Bit  13:     work-task shall exit and delete itself.
0375  * Bit  12:     link error - shut down all DMA operations (stop DMA channels).
0376  * Bit  11..8:  Indicats DMA error on DMA channel 3..0.
0377  * Bit  7..0:   Indicats RX and/or TX packets completed on channel 3..0.
0378  */
0379 #define WORK_NONE         0
0380 #define WORK_SHUTDOWN     0x1000 /* Signal shut down */
0381 #define WORK_QUIT_TASK    0x2000 /* Work task shall exit (delete itself) */
0382 #define WORK_FREE_MSGQ    0x4000 /* Delete MsgQ (valid when WORK_QUIT_TASK) */
0383 #define WORK_DMA(chan, rxtx) (((rxtx) & 0x3) << ((chan) * 2))
0384 #define WORK_DMA_TX(chan) WORK_DMA(chan, 1)
0385 #define WORK_DMA_RX(chan) WORK_DMA(chan, 2)
0386 #define WORK_DMA_ER(chan) (0x1 << ((chan) + 8))
0387 #define WORK_DMA_MASK     0xfff /* max 4 channels all work */
0388 #define WORK_DMA_TX_MASK  0x055 /* max 4 channels TX work */
0389 #define WORK_DMA_RX_MASK  0x0aa /* max 4 channels RX work */
0390 #define WORK_DMA_ER_MASK  0xf00 /* max 4 channels Error work */
0391 #define WORK_DMA_CHAN_MASK(chan) (WORK_DMA_ER(chan) | WORK_DMA(chan, 0x3))
0392 #define WORK_CORE_BIT     16
0393 #define WORK_CORE_MASK    0x00ff0000
0394 #define WORK_CORE(device) ((device) << WORK_CORE_BIT)
0395 
0396 /* Message Q used to send messages to work task */
0397 struct grspw_work_config {
0398     grspw_msgqisr_t msgisr;
0399     void *msgisr_arg; /* example: rtems_id to Msg Q */
0400 };
0401 
0402 extern void grspw_initialize_user(
0403     /* Callback every time a GRSPW device is found. Args: DeviceIndex */
0404     void *(*devfound)(int),
0405     /* Callback every time a GRSPW device is removed. Args:
0406      * int   = DeviceIndex
0407      * void* = Return Value from devfound()
0408      */
0409     void (*devremove)(int,void*)
0410     );
0411 
0412 /* Creates a MsgQ (optional) and spawns a worker task associated with the
0413  * message Q. The task can also be associated with a custom msgQ if *msgQ.
0414  * is non-zero.
0415  *
0416  * \param prio     Task priority, set to -1 for default.
0417  * \param stack    Task stack size, set to 0 for default.
0418  * \param msgQ     pMsgQ=NULL: illegal,
0419  *                 pMsqQ==0: create new MsgQ with task and place in *pMsgQ,
0420  *                 *pmsqQ!=0: pointer to MsgQ used for task.
0421  * \param msgMax   Maximum number of messages, set to 0 for default.
0422  * \return         0 on failure, task id on success.
0423  */
0424 extern rtems_id grspw_work_spawn(int prio, int stack, rtems_id *pMsgQ, int msgMax);
0425 
0426 /* Free task associated with message queue and optionally also the message
0427  * queue itself. The message queue is deleted by the work task and is therefore
0428  * delayed until it the work task resumes its execution.
0429  */
0430 extern rtems_status_code grspw_work_free(rtems_id msgQ, int freeMsgQ);
0431 
0432 /* Configure a GRSPW device Work task and Message Q set up.
0433  * This affects messages to:
0434  *  - DMA AHB error interrupt handling (mandatory)
0435  *  - Link status interrupt handling (optional)
0436  *  - RX DMA, defaults to common msgQ (configured per DMA channel) 
0437  */
0438 extern void grspw_work_cfg(void *d, struct grspw_work_config *wc);
0439 
0440 /* Work-task function, called only from the work task. The function is provided
0441  * as a way for the user to create its own work tasks.
0442  * The argument determines which message queue the task shall read its
0443  * work jobs from.
0444  *
0445  * The messages are always 32-bit words and follows the format defined by the
0446  * WORK_* macros above.
0447  */
0448 extern void grspw_work_func(rtems_id msgQ);
0449 
0450 enum grspw_worktask_ev {
0451     WORKTASK_EV_NONE = 0,
0452     WORKTASK_EV_QUIT = 1,
0453     WORKTASK_EV_SHUTDOWN = 2,
0454     WORKTASK_EV_DMA_STOP = 3,
0455 };
0456 
0457 /* Weak function to let user override. Function called every time one of the
0458  * events above is handled by the work-task. The message 'msg' is the current
0459  * message being processed by the work-task.
0460  * The user can for example add custom code to invoke on a DMA error, link
0461  * error or monitor when the work-task exits after a call to grspw_work_free().
0462  */
0463 extern void grspw_work_event(enum grspw_worktask_ev ev, unsigned int msg);
0464 
0465 #ifdef RTEMS_SMP
0466 /* Set ISR interrupt affinity. The LEON IRQCtrl requires that the cpumask shall
0467  * always have one bit set.
0468  */
0469 extern int grspw_isr_affinity(void *d, const cpu_set_t *cpus);
0470 #endif
0471 
0472 extern int grspw_dev_count(void);
0473 extern void *grspw_open(int dev_no);
0474 extern int grspw_close(void *d);
0475 extern void grspw_hw_support(void *d, struct grspw_hw_sup *hw);
0476 extern void grspw_stats_read(void *d, struct grspw_core_stats *sts);
0477 extern void grspw_stats_clr(void *d);
0478 
0479 /* Set and Read current node address configuration. The dma_nacfg[N] field
0480  * represents the configuration for DMA Channel N.
0481  *
0482  * Set cfg->promiscous to -1 in order to only read current configuration.
0483  */
0484 extern void grspw_addr_ctrl(void *d, struct grspw_addr_config *cfg);
0485 
0486 /*** Link Control interface ***/
0487 /* Read Link State */
0488 extern spw_link_state_t grspw_link_state(void *d);
0489 /* options [in/out]: set to -1 to only read current config
0490  *
0491  * CLKDIV register contain:
0492  *  bits 7..0  : Clock Div RUN (only run-state)
0493  *  bits 15..8 : Clock Div During Startup (all link states except run-state)
0494  */
0495 extern void grspw_link_ctrl(void *d, int *options, int *stscfg, int *clkdiv);
0496 /* Read the current value of the status register */
0497 extern unsigned int grspw_link_status(void *d);
0498 /* Clear bits in the status register */
0499 extern void grspw_link_status_clr(void *d, unsigned int clearmask);
0500 
0501 /*** Time Code Interface ***/
0502 /* Generate Tick-In (increment Time Counter, Send Time Code) */
0503 extern void grspw_tc_tx(void *d);
0504 /* Control Timcode settings of core */
0505 extern void grspw_tc_ctrl(void *d, int *options);
0506 /* Assign ISR Function to TimeCode RX IRQ */
0507 extern void grspw_tc_isr(void *d, void (*tcisr)(void *data, int tc), void *data);
0508 /* Read/Write TCTRL and TIMECNT. Write if not -1, always read current value
0509  * TCTRL   = bits 7 and 6
0510  * TIMECNT = bits 5 to 0
0511  */
0512 extern void grspw_tc_time(void *d, int *time);
0513 
0514 /*** Interrupt-code Interface ***/
0515 struct spwpkt_ic_config {
0516     unsigned int tomask;
0517     unsigned int aamask;
0518     unsigned int scaler;
0519     unsigned int isr_reload;
0520     unsigned int ack_reload;
0521 };
0522 /* Function Interrupt-Code ISR callback prototype. Called when respective
0523  * interrupt handling option has been enabled by grspw_ic_ctrl(), the
0524  * arguments rxirq, rxack and intto are read from the registers of the
0525  * GRSPW core read by the GRSPW ISR, they are individually valid only when
0526  * repective handling been turned on.
0527  *
0528  * data    - Custom data provided by user
0529  * rxirq   - Interrupt-Code Recevie register of the GRSPW core read by ISR
0530  *           (only defined if IQ bit enabled through grspw_ic_ctrl())
0531  * rxack   - Interrupt-Ack-Code Recevie register of the GRSPW core read by ISR
0532  *           (only defined if AQ bit enabled through grspw_ic_ctrl())
0533  * intto   - Interrupt Tick-out Recevie register of the GRSPW core read by ISR
0534  *           (only defined if TQ bit enabled through grspw_ic_ctrl()) 
0535  */
0536 typedef void (*spwpkt_ic_isr_t)(void *data, unsigned int rxirq,
0537                 unsigned int rxack, unsigned int intto);
0538 /* Control Interrupt-code settings of core
0539  * Write if 'options' not pointing to -1, always read current value
0540  */
0541 extern void grspw_ic_ctrl(void *d, unsigned int *options);
0542 /* Write (rw&1 == 1) configuration parameters to registers and/or,
0543  * Read  (rw&2 == 1) configuration parameters from registers, in that sequence.
0544  */
0545 extern void grspw_ic_config(void *d, int rw, struct spwpkt_ic_config *cfg);
0546 /* Read or Write Interrupt-code status registers.
0547  * If pointer argument *ptr == 0 then only read, if *ptr != 0 then only write.
0548  * If *ptr is NULL no operation.
0549  */
0550 extern void grspw_ic_sts(void *d, unsigned int *rxirq, unsigned int *rxack,
0551             unsigned int *intto);
0552 /* Generate Tick-In for the given Interrupt-code
0553  * Returns zero on success and non-zero on failure
0554  *
0555  * Interrupt code bits (ic):
0556  * Bit 5 - ACK if 1
0557  * Bits 4-0 Interrupt-code number
0558  */
0559 extern int grspw_ic_tickin(void *d, int ic);
0560 /* Assign handler function to Interrupt-code timeout IRQ */
0561 extern void grspw_ic_isr(void *d, spwpkt_ic_isr_t handler, void *data);
0562 
0563 /*** RMAP Control Interface ***/
0564 /* Set (not -1) and/or read RMAP options. */
0565 extern int grspw_rmap_ctrl(void *d, int *options, int *dstkey);
0566 extern void grspw_rmap_support(void *d, char *rmap, char *rmap_crc);
0567 
0568 /*** SpW Port Control Interface ***/
0569 
0570 /* Select port, if
0571  * -1=The current selected port is returned
0572  * 0=Port 0
0573  * 1=Port 1
0574  * Other positive values=Both Port0 and Port1
0575  */
0576 extern int grspw_port_ctrl(void *d, int *port);
0577 /* Returns Number ports available in hardware */
0578 extern int grspw_port_count(void *d);
0579 /* Returns the current active port */
0580 extern int grspw_port_active(void *d);
0581 
0582 /*** DMA Interface ***/
0583 extern void *grspw_dma_open(void *d, int chan_no);
0584 extern int grspw_dma_close(void *c);
0585 
0586 extern int grspw_dma_start(void *c);
0587 extern void grspw_dma_stop(void *c);
0588 
0589 /* Enable interrupt manually */
0590 extern unsigned int grspw_dma_enable_int(void *c, int rxtx, int force);
0591 
0592 /* Return Current DMA Control & Status Register */
0593 extern unsigned int grspw_dma_ctrlsts(void *c);
0594 
0595 /* Schedule List of packets for transmission at some point in
0596  * future.
0597  *
0598  * 1. Move transmitted packets to SENT List (SCHED->SENT)
0599  * 2. Add the requested packets to the SEND List (USER->SEND)
0600  * 3. Schedule as many packets as possible for transmission (SEND->SCHED)
0601  *
0602  * Call this function with pkts=NULL to just do step 1 and 3. This may be
0603  * required in Polling-mode.
0604  *
0605  * The above steps 1 and 3 may be skipped by setting 'opts':
0606  *  bit0 = 1: Skip Step 1.
0607  *  bit1 = 1: Skip Step 3.
0608  * Skipping both step 1 and 3 may be usefull when IRQ is enabled, then
0609  * the work queue will be totaly responsible for handling descriptors.
0610  *
0611  * The fastest solution in retreiving sent TX packets and sending new frames
0612  * is to call:
0613  *  A. grspw_dma_tx_reclaim(opts=0)
0614  *  B. grspw_dma_tx_send(opts=1)
0615  *
0616  * NOTE: the TXPKT_FLAG_TX flag must not be set.
0617  *
0618  * Return Code
0619  *  -1   Error
0620  *  0    Successfully added pkts to send/sched list
0621  *  1    DMA stopped. No operation.
0622  */
0623 extern int grspw_dma_tx_send(void *c, int opts, struct grspw_list *pkts, int count);
0624 
0625 /* Reclaim TX packet buffers that has previously been scheduled for transmission
0626  * with grspw_dma_tx_send().
0627  *
0628  * 1. Move transmitted packets to SENT List (SCHED->SENT)
0629  * 2. Move all SENT List to pkts list (SENT->USER)
0630  * 3. Schedule as many packets as possible for transmission (SEND->SCHED)
0631  *
0632  * The above steps 1 may be skipped by setting 'opts':
0633  *  bit0 = 1: Skip Step 1.
0634  *  bit1 = 1: Skip Step 3.
0635  *
0636  * The fastest solution in retreiving sent TX packets and sending new frames
0637  * is to call:
0638  *  A. grspw_dma_tx_reclaim(opts=2) (Skip step 3)
0639  *  B. grspw_dma_tx_send(opts=1) (Skip step 1)
0640  *
0641  * Return Code
0642  *  -1   Error
0643  *  0    Successful. pkts list filled with all packets from sent list
0644  *  1    Same as 0, but indicates that DMA stopped
0645  */
0646 extern int grspw_dma_tx_reclaim(void *c, int opts, struct grspw_list *pkts, int *count);
0647 
0648 /* Get current number of Packets in respective TX Queue. */
0649 extern void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent, int *hw);
0650 
0651 #define GRSPW_OP_AND 0
0652 #define GRSPW_OP_OR 1
0653 /* Block until send_cnt or fewer packets are Queued in "Send and Scheduled" Q,
0654  * op (AND or OR), sent_cnt or more packet "have been sent" (Sent Q) condition
0655  * is met.
0656  * If a link error occurs and the Stop on Link error is defined, this function
0657  * will also return to caller.
0658  * The timeout argument is used to return after timeout ticks, regardless of
0659  * the other conditions. If timeout is zero, the function will wait forever
0660  * until the condition is satisfied.
0661  *
0662  * NOTE: if IRQ of TX descriptors are not enabled conditions are never
0663  *       checked, this may hang infinitely unless a timeout has been specified
0664  *
0665  * Return Code
0666  *  -1   Error
0667  *  0    Returing to caller because specified conditions are now fullfilled
0668  *  1    DMA stopped
0669  *  2    Timeout, conditions are not met
0670  *  3    Another task is already waiting. Service is Busy.
0671  */
0672 extern int grspw_dma_tx_wait(void *c, int send_cnt, int op, int sent_cnt, int timeout);
0673 
0674 /* Get received RX packet buffers that has previously been scheduled for 
0675  * reception with grspw_dma_rx_prepare().
0676  *
0677  * 1. Move Scheduled packets to RECV List (SCHED->RECV)
0678  * 2. Move all RECV packet to the callers list (RECV->USER)
0679  * 3. Schedule as many free packet buffers as possible (READY->SCHED)
0680  *
0681  * The above steps 1 may be skipped by setting 'opts':
0682  *  bit0 = 1: Skip Step 1.
0683  *  bit1 = 1: Skip Step 3.
0684  *
0685  * The fastest solution in retreiving received RX packets and preparing new
0686  * packet buffers for future receive, is to call:
0687  *  A. grspw_dma_rx_recv(opts=2, &recvlist) (Skip step 3)
0688  *  B. grspw_dma_rx_prepare(opts=1, &freelist) (Skip step 1)
0689  *
0690  * Return Code
0691  *  -1   Error
0692  *  0    Successfully filled pkts list with packets from recv list.
0693  *  1    DMA stopped
0694  */
0695 extern int grspw_dma_rx_recv(void *c, int opts, struct grspw_list *pkts, int *count);
0696 
0697 /* Add more RX packet buffers for future for reception. The received packets
0698  * can later be read out with grspw_dma_rx_recv().
0699  *
0700  * 1. Move Received packets to RECV List (SCHED->RECV)
0701  * 2. Add the "free/ready" packet buffers to the READY List (USER->READY)
0702  * 3. Schedule as many packets as possible (READY->SCHED)
0703  *
0704  * The above steps 1 may be skipped by setting 'opts':
0705  *  bit0 = 1: Skip Step 1.
0706  *  bit1 = 1: Skip Step 3.
0707  *
0708  * The fastest solution in retreiving received RX packets and preparing new
0709  * packet buffers for future receive, is to call:
0710  *  A. grspw_dma_rx_recv(opts=2, &recvlist) (Skip step 3)
0711  *  B. grspw_dma_rx_prepare(opts=1, &freelist) (Skip step 1)
0712  *
0713  * Return Code
0714  *  -1   Error
0715  *  0    Successfully added packet buffers from pkt list into the ready queue
0716  *  1    DMA stopped
0717  */
0718 extern int grspw_dma_rx_prepare(void *c, int opts, struct grspw_list *pkts, int count);
0719 
0720 /* Get current number of Packets in respective RX Queue. */
0721 extern void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv, int *hw);
0722 
0723 /* Block until recv_cnt or more packets are Queued in RECV Q, op (AND or OR), 
0724  * ready_cnt or fewer packet buffers are available in the "READY and Scheduled" Q,
0725  * condition is met.
0726  * If a link error occurs and the Stop on Link error is defined, this function
0727  * will also return to caller, however with an error.
0728  * The timeout argument is used to return after timeout ticks, regardless of
0729  * the other conditions. If timeout is zero, the function will wait forever
0730  * until the condition is satisfied.
0731  *
0732  * NOTE: if IRQ of RX descriptors are not enabled conditions are never
0733  *       checked, this may hang infinitely unless a timeout has been specified
0734  *
0735  * Return Code
0736  *  -1   Error
0737  *  0    Returing to caller because specified conditions are now fullfilled
0738  *  1    DMA stopped
0739  *  2    Timeout, conditions are not met
0740  *  3    Another task is already waiting. Service is Busy.
0741  */
0742 extern int grspw_dma_rx_wait(void *c, int recv_cnt, int op, int ready_cnt, int timeout);
0743 
0744 extern int grspw_dma_config(void *c, struct grspw_dma_config *cfg);
0745 extern void grspw_dma_config_read(void *c, struct grspw_dma_config *cfg);
0746 
0747 extern void grspw_dma_stats_read(void *c, struct grspw_dma_stats *sts);
0748 extern void grspw_dma_stats_clr(void *c);
0749 
0750 /* Register GRSPW packet driver to Driver Manager */
0751 void grspw2_register_drv (void);
0752 
0753 /*** GRSPW SpaceWire Packet List Handling Routines ***/
0754 
0755 static inline void grspw_list_clr(struct grspw_list *list)
0756 {
0757         list->head = NULL;
0758         list->tail = NULL;
0759 }
0760 
0761 static inline int grspw_list_is_empty(struct grspw_list *list)
0762 {
0763         return (list->head == NULL);
0764 }
0765 
0766 /* Return Number of entries in list */
0767 static inline int grspw_list_cnt(struct grspw_list *list)
0768 {
0769     struct grspw_pkt *lastpkt = NULL, *pkt = list->head;
0770     int cnt = 0;
0771     while ( pkt ) {
0772         cnt++;
0773         lastpkt = pkt;
0774         pkt = pkt->next;
0775     }
0776     if ( lastpkt && (list->tail != lastpkt) )
0777         return -1;
0778     return cnt;
0779 }
0780 
0781 static inline void
0782 grspw_list_append(struct grspw_list *list, struct grspw_pkt *pkt)
0783 {
0784     pkt->next = NULL;
0785     if ( list->tail == NULL ) {
0786         list->head = pkt;
0787     } else {
0788         list->tail->next = pkt;
0789     }
0790     list->tail = pkt;
0791 }
0792 
0793 static inline void 
0794 grspw_list_prepend(struct grspw_list *list, struct grspw_pkt *pkt)
0795 {
0796     pkt->next = list->head;
0797     if ( list->head == NULL ) {
0798         list->tail = pkt;
0799     }
0800     list->head = pkt;
0801 }
0802 
0803 static inline void
0804 grspw_list_append_list(struct grspw_list *list, struct grspw_list *alist)
0805 {
0806     if (grspw_list_is_empty(alist)) {
0807         return;
0808     }
0809     alist->tail->next = NULL;
0810     if ( list->tail == NULL ) {
0811         list->head = alist->head;
0812     } else {
0813         list->tail->next = alist->head;
0814     }
0815     list->tail = alist->tail;
0816 }
0817 
0818 static inline void
0819 grspw_list_prepend_list(struct grspw_list *list, struct grspw_list *alist)
0820 {
0821     if (grspw_list_is_empty(alist)) {
0822         return;
0823     }
0824     if ( list->head == NULL ) {
0825         list->tail = alist->tail;
0826         alist->tail->next = NULL;
0827     } else {
0828         alist->tail->next = list->head;
0829     }
0830     list->head = alist->head;
0831 }
0832 
0833 /* Remove dlist (delete-list) from head of list */
0834 static inline void
0835 grspw_list_remove_head_list(struct grspw_list *list, struct grspw_list *dlist)
0836 {
0837     if (grspw_list_is_empty(dlist)) {
0838         return;
0839     }
0840     list->head = dlist->tail->next;
0841     if ( list->head == NULL ) {
0842         list->tail = NULL;
0843     }
0844     dlist->tail->next = NULL;
0845 }
0846 
0847 /* Take A number of entries from head of list 'list' and put the entires
0848  * to rlist (result list).
0849  */
0850 static inline int
0851 grspw_list_take_head_list(struct grspw_list *list, struct grspw_list *rlist, int max)
0852 {
0853     int cnt;
0854     struct grspw_pkt *pkt, *last;
0855 
0856     pkt = list->head;
0857 
0858     if ( (max < 1) || (pkt == NULL) ) {
0859         grspw_list_clr(rlist);
0860         return 0;
0861     }
0862 
0863     cnt = 0;
0864     rlist->head = pkt;
0865     last = pkt;
0866     while ((cnt < max) && pkt) {
0867         last = pkt;
0868         pkt = pkt->next;
0869         cnt++;
0870     }
0871     rlist->tail = last;
0872     grspw_list_remove_head_list(list, rlist);
0873     return cnt;
0874 }
0875 
0876 #endif