Changeset ab9b447 in rtems


Ignore:
Timestamp:
Jan 22, 2017, 2:01:55 PM (4 years ago)
Author:
Daniel Hellstrom <daniel@…>
Branches:
5, master
Children:
29c2304
Parents:
f46f5f84
git-author:
Daniel Hellstrom <daniel@…> (01/22/17 14:01:55)
git-committer:
Daniel Hellstrom <daniel@…> (03/06/17 06:54:55)
Message:

leon, grspw_pkt: added work-task configuration options

Following changes:

  • possible for user to create work-tasks and assign custom message queues.
  • possible for user to override default ISR message to implement custom handling of DMA error, DMA RX/TX and link error from ISR.
  • work-task now checks message to determine which work to perform rather than looking at registers only, this makes it possible for user to implement custom handling.
  • exported work-queue message definitions and separated them so that a user can assign custom DMA RX/TX handling of a specific DMA channel.
  • added a work-task event callback to let user add custom handling or monitoring of DMA Stop, DMA error, Link Error or work-task exits etc.
Location:
c/src/lib/libbsp/sparc/shared
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h

    rf46f5f84 rab9b447  
    312312};
    313313
     314/* ISR message sending call back. Compatible with rtems_message_queue_send().
     315 * The 'buf' parameter has a pointer to a WORK-TASK message defined by the
     316 * WORK_* macros below. The message indicates what GRSPW device operations
     317 * are pending, thus what caused the interrupt.
     318 *
     319 * \param data   defined by grspw_work_config.msgisr_arg, default a rtems_id.
     320 * \param buf    Pointer to a 32-bit message word
     321 * \param n      Always 4 (byte size of buf).
     322 */
     323typedef int (*grspw_msgqisr_t)(void *data, unsigned int *buf, unsigned int n);
     324
     325/* Work message definitions, the int sent to *buf
     326 * Bits 31..24: reserved.
     327 * Bits 23..16: GRSPW device number message is associated with.
     328 * Bit  15:     reserved.
     329 * Bit  14:     work-task shall delete message queue on exit.
     330 * Bit  13:     work-task shall exit and delete itself.
     331 * Bit  12:     link error - shut down all DMA operations (stop DMA channels).
     332 * Bit  11..8:  Indicats DMA error on DMA channel 3..0.
     333 * Bit  7..0:   Indicats RX and/or TX packets completed on channel 3..0.
     334 */
     335#define WORK_NONE         0
     336#define WORK_SHUTDOWN     0x1000 /* Signal shut down */
     337#define WORK_QUIT_TASK    0x2000 /* Work task shall exit (delete itself) */
     338#define WORK_FREE_MSGQ    0x4000 /* Delete MsgQ (valid when WORK_QUIT_TASK) */
     339#define WORK_DMA(chan, rxtx) (((rxtx) & 0x3) << ((chan) * 2))
     340#define WORK_DMA_TX(chan) WORK_DMA(chan, 1)
     341#define WORK_DMA_RX(chan) WORK_DMA(chan, 2)
     342#define WORK_DMA_ER(chan) (0x1 << ((chan) + 8))
     343#define WORK_DMA_MASK     0xfff /* max 4 channels all work */
     344#define WORK_DMA_TX_MASK  0x055 /* max 4 channels TX work */
     345#define WORK_DMA_RX_MASK  0x0aa /* max 4 channels RX work */
     346#define WORK_DMA_ER_MASK  0xf00 /* max 4 channels Error work */
     347#define WORK_DMA_CHAN_MASK(chan) (WORK_DMA_ER(chan) | WORK_DMA(chan, 0x3))
     348#define WORK_CORE_BIT     16
     349#define WORK_CORE_MASK    0x00ff0000
     350#define WORK_CORE(device) ((device) << WORK_CORE_BIT)
     351
     352/* Message Q used to send messages to work task */
     353struct grspw_work_config {
     354        grspw_msgqisr_t msgisr;
     355        void *msgisr_arg; /* example: rtems_id to Msg Q */
     356};
     357
    314358extern void grspw_initialize_user(
    315359        /* Callback every time a GRSPW device is found. Args: DeviceIndex */
     
    321365        void (*devremove)(int,void*)
    322366        );
     367
     368/* Creates a MsgQ (optional) and spawns a worker task associated with the
     369 * message Q. The task can also be associated with a custom msgQ if *msgQ.
     370 * is non-zero.
     371 *
     372 * \param prio     Task priority, set to -1 for default.
     373 * \param stack    Task stack size, set to 0 for default.
     374 * \param msgQ     pMsgQ=NULL: illegal,
     375 *                 pMsqQ==0: create new MsgQ with task and place in *pMsgQ,
     376 *                 *pmsqQ!=0: pointer to MsgQ used for task.
     377 * \param msgMax   Maximum number of messages, set to 0 for default.
     378 * \return         0 on failure, task id on success.
     379 */
     380extern rtems_id grspw_work_spawn(int prio, int stack, rtems_id *pMsgQ, int msgMax);
     381
     382/* Free task associated with message queue and optionally also the message
     383 * queue itself. The message queue is deleted by the work task and is therefore
     384 * delayed until it the work task resumes its execution.
     385 */
     386extern rtems_status_code grspw_work_free(rtems_id msgQ, int freeMsgQ);
     387
     388/* Configure a GRSPW device Work task and Message Q set up.
     389 * This affects messages to:
     390 *  - DMA AHB error interrupt handling (mandatory)
     391 *  - Link status interrupt handling (optional)
     392 *  - RX DMA, defaults to common msgQ (configured per DMA channel)
     393 */
     394extern void grspw_work_cfg(void *d, struct grspw_work_config *wc);
     395
     396/* Work-task function, called only from the work task. The function is provided
     397 * as a way for the user to create its own work tasks.
     398 * The argument determines which message queue the task shall read its
     399 * work jobs from.
     400 *
     401 * The messages are always 32-bit words and follows the format defined by the
     402 * WORK_* macros above.
     403 */
     404extern void grspw_work_func(rtems_id msgQ);
     405
     406enum grspw_worktask_ev {
     407        WORKTASK_EV_NONE = 0,
     408        WORKTASK_EV_QUIT = 1,
     409        WORKTASK_EV_SHUTDOWN = 2,
     410        WORKTASK_EV_DMA_STOP = 3,
     411};
     412
     413/* Weak function to let user override. Function called every time one of the
     414 * events above is handled by the work-task. The message 'msg' is the current
     415 * message being processed by the work-task.
     416 * The user can for example add custom code to invoke on a DMA error, link
     417 * error or monitor when the work-task exits after a call to grspw_work_free().
     418 */
     419extern void grspw_work_event(enum grspw_worktask_ev ev, unsigned int msg);
     420
    323421extern int grspw_dev_count(void);
    324422extern void *grspw_open(int dev_no);
  • c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c

    rf46f5f84 rab9b447  
    479479        unsigned int stscfg;
    480480
     481        /*** Message Queue Handling ***/
     482        struct grspw_work_config wc;
     483
    481484        /* "Core Global" Statistics gathered, not dependent on DMA channel */
    482485        struct grspw_core_stats stats;
     
    485488int grspw_initialized = 0;
    486489int grspw_count = 0;
    487 struct workqueue_struct *grspw_workq = NULL;
    488490rtems_id grspw_sem;
    489491static struct grspw_priv *priv_tab[GRSPW_MAX];
     
    492494void *(*grspw_dev_add)(int) = NULL;
    493495void (*grspw_dev_del)(int,void*) = NULL;
     496
     497/* Defaults to do nothing - user can override this function.
     498 * Called from work-task.
     499 */
     500void __attribute__((weak)) grspw_work_event(
     501        enum grspw_worktask_ev ev,
     502        unsigned int msg)
     503{
     504
     505}
    494506
    495507/* USER OVERRIDABLE - The work task priority. Set to -1 to disable creating
     
    497509 */
    498510int grspw_work_task_priority __attribute__((weak)) = 100;
    499 int grspw_task_stop = 0;
    500511rtems_id grspw_work_task;
    501 rtems_id grspw_work_queue = 0;
    502 #define WORK_NONE         0
    503 #define WORK_SHUTDOWN     0x100
    504 #define WORK_DMA(channel) (0x1 << (channel))
    505 #define WORK_DMA_MASK     0xf /* max 4 channels */
    506 #define WORK_CORE_BIT     16
    507 #define WORK_CORE_MASK    0xffff
    508 #define WORK_CORE(device) ((device) << WORK_CORE_BIT)
     512static struct grspw_work_config grspw_wc_def;
    509513
    510514STATIC void grspw_hw_stop(struct grspw_priv *priv);
     
    546550        priv->icisr_arg = NULL;
    547551        priv->stscfg = LINKSTS_MASK;
     552
     553        /* Default to common work queue and message queue, if not created
     554         * during initialization then its disabled.
     555         */
     556        grspw_work_cfg(priv, &grspw_wc_def);
    548557
    549558        grspw_stats_clr(priv);
     
    25322541
    25332542/* Do DMA work on one channel, invoked indirectly from ISR */
    2534 static void grspw_work_dma_func(struct grspw_dma_priv *dma)
     2543static void grspw_work_dma_func(struct grspw_dma_priv *dma, unsigned int msg)
    25352544{
    25362545        int tx_cond_true, rx_cond_true;
     
    25582567                /* DMA error -> Stop DMA channel (both RX and TX) */
    25592568                SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
    2560                 grspw_dma_stop(dma);
    2561         } else if (ctrl & (GRSPW_DMACTRL_PR | GRSPW_DMACTRL_PS)) {
    2562                 /* DMA has finished a TX/RX packet */
     2569                if (msg & WORK_DMA_ER_MASK) {
     2570                        /* DMA error and user wants work-task to handle error */
     2571                        grspw_dma_stop(dma);
     2572                        grspw_work_event(WORKTASK_EV_DMA_STOP, msg);
     2573                }
     2574        } else if (((msg & WORK_DMA_RX_MASK) && (ctrl & GRSPW_DMACTRL_PR)) ||
     2575                   ((msg & WORK_DMA_TX_MASK) && (ctrl & GRSPW_DMACTRL_PS))) {
     2576                /* DMA has finished a TX/RX packet and user wants work-task to
     2577                 * take care of DMA table processing.
     2578                 */
    25632579                ctrl &= ~GRSPW_DMACTRL_AT;
    2564                 if (dma->cfg.rx_irq_en_cnt != 0 ||
    2565                     (dma->cfg.flags & DMAFLAG2_RXIE))
     2580
     2581                if ((msg & WORK_DMA_RX_MASK) == 0)
     2582                        ctrl &= ~GRSPW_DMACTRL_PR;
     2583                else if (dma->cfg.rx_irq_en_cnt != 0 ||
     2584                         (dma->cfg.flags & DMAFLAG2_RXIE))
    25662585                        ctrl |= GRSPW_DMACTRL_RI;
    2567                 if (dma->cfg.tx_irq_en_cnt != 0 ||
    2568                     (dma->cfg.flags & DMAFLAG2_TXIE))
     2586                if ((msg & WORK_DMA_TX_MASK) == 0)
     2587                        ctrl &= ~GRSPW_DMACTRL_PS;
     2588                else if ((dma->cfg.tx_irq_en_cnt != 0 ||
     2589                         (dma->cfg.flags & DMAFLAG2_TXIE)))
    25692590                        ctrl |= GRSPW_DMACTRL_TI;
     2591
    25702592                REG_WRITE(&dma->regs->ctrl, ctrl);
    25712593                SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
    2572                 if (ctrl & GRSPW_DMACTRL_PR) {
     2594                if ((msg & WORK_DMA_RX_MASK) && (ctrl & GRSPW_DMACTRL_PR)) {
    25732595                        /* Do RX Work */
    25742596
     
    25912613                        rtems_semaphore_release(dma->sem_rxdma);
    25922614                }
    2593                 if (ctrl & GRSPW_DMACTRL_PS) {
     2615                if ((msg & WORK_DMA_TX_MASK) && (ctrl & GRSPW_DMACTRL_PS)) {
    25942616                        /* Do TX Work */
    25952617
     
    26252647 * the ISR.
    26262648 */
    2627 static void grspw_work_func(rtems_task_argument unused)
    2628 {
    2629         rtems_status_code status;
    2630         unsigned int message;
     2649void grspw_work_func(rtems_id msgQ)
     2650{
     2651        unsigned int message = 0, msg;
    26312652        size_t size;
    26322653        struct grspw_priv *priv;
    26332654        int i;
    26342655
    2635         while (grspw_task_stop == 0) {
    2636                 /* Wait for ISR to schedule work */
    2637                 status = rtems_message_queue_receive(
    2638                         grspw_work_queue, &message,
    2639                         &size, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    2640                 if (status != RTEMS_SUCCESSFUL)
     2656        /* Wait for ISR to schedule work */
     2657        while (rtems_message_queue_receive(msgQ, &message, &size,
     2658               RTEMS_WAIT, RTEMS_NO_TIMEOUT) == RTEMS_SUCCESSFUL) {
     2659                if (message & WORK_QUIT_TASK)
    26412660                        break;
    26422661
    26432662                /* Handle work */
    26442663                priv = priv_tab[message >> WORK_CORE_BIT];
    2645                 if (message & WORK_SHUTDOWN)
     2664                if (message & WORK_SHUTDOWN) {
    26462665                        grspw_work_shutdown_func(priv);
    2647                 else if (message & WORK_DMA_MASK) {
    2648                         for (i = 0; i < 4; i++) {
    2649                                 if (message & WORK_DMA(i))
    2650                                         grspw_work_dma_func(&priv->dma[i]);
     2666                               
     2667                        grspw_work_event(WORKTASK_EV_SHUTDOWN, message);
     2668                } else if (message & WORK_DMA_MASK) {
     2669                        for (i = 0; i < priv->hwsup.ndma_chans; i++) {
     2670                                msg = message &
     2671                                      (WORK_CORE_MASK | WORK_DMA_CHAN_MASK(i));
     2672                                if (msg)
     2673                                        grspw_work_dma_func(&priv->dma[i], msg);
    26512674                        }
    26522675                }
    2653         }
     2676                message = 0;
     2677        }
     2678
     2679        if (message & WORK_FREE_MSGQ)
     2680                rtems_message_queue_delete(msgQ);
     2681
     2682        grspw_work_event(WORKTASK_EV_QUIT, message);
    26542683        rtems_task_delete(RTEMS_SELF);
    26552684}
     
    26582687{
    26592688        struct grspw_priv *priv = data;
    2660         unsigned int dma_stat, stat, stat_clrmsk, ctrl, icctrl, timecode;
     2689        unsigned int dma_stat, stat, stat_clrmsk, ctrl, icctrl, timecode, irqs;
    26612690        unsigned int rxirq, rxack, intto;
    2662         int i, handled = 0, message = WORK_NONE, call_user_int_isr;
     2691        int i, handled = 0, call_user_int_isr;
     2692        unsigned int message = WORK_NONE;
    26632693#ifdef RTEMS_HAS_SMP
    26642694        IRQFLAGS_TYPE irqflags;
     
    27682798                 * respective IRQ are enabled
    27692799                 */
    2770 #ifdef HW_WITH_GI
    2771                 if ( dma_stat & (GRSPW_DMA_STATUS_ERROR | GRSPW_DMACTRL_GI) ) {
    2772 #else
    2773                 if ( (((dma_stat << 3) & (GRSPW_DMACTRL_PR | GRSPW_DMACTRL_PS))
    2774                      | GRSPW_DMA_STATUS_ERROR) & dma_stat ) {
    2775 #endif
    2776                         /* Disable Further IRQs (until enabled again)
    2777                          * from this DMA channel. Let the status
    2778                          * bit remain so that they can be handled by
    2779                          * work function.
    2780                          */
    2781                         REG_WRITE(&priv->regs->dma[i].ctrl, dma_stat &
    2782                                 ~(GRSPW_DMACTRL_RI|GRSPW_DMACTRL_TI|
    2783                                 GRSPW_DMACTRL_PR|GRSPW_DMACTRL_PS|
    2784                                 GRSPW_DMACTRL_RA|GRSPW_DMACTRL_TA|
    2785                                 GRSPW_DMACTRL_AT));
    2786                         message |= WORK_DMA(i);
    2787                         handled = 1;
     2800                irqs = (((dma_stat << 3) & (GRSPW_DMACTRL_PR | GRSPW_DMACTRL_PS))
     2801                        | GRSPW_DMA_STATUS_ERROR) & dma_stat;
     2802                if (!irqs)
     2803                        continue;
     2804
     2805                /* Disable Further IRQs (until enabled again)
     2806                 * from this DMA channel. Let the status
     2807                 * bit remain so that they can be handled by
     2808                 * work function.
     2809                 */
     2810                REG_WRITE(&priv->regs->dma[i].ctrl, dma_stat &
     2811                        ~(GRSPW_DMACTRL_RI|GRSPW_DMACTRL_TI|
     2812                        GRSPW_DMACTRL_PR|GRSPW_DMACTRL_PS|
     2813                        GRSPW_DMACTRL_RA|GRSPW_DMACTRL_TA|
     2814                        GRSPW_DMACTRL_AT));
     2815                handled = 1;
     2816
     2817                /* DMA error has priority, if error happens it is assumed that
     2818                 * the common work-queue stops the DMA operation for that
     2819                 * channel and makes the DMA tasks exit from their waiting
     2820                 * functions (both RX and TX tasks).
     2821                 */
     2822                if (irqs & GRSPW_DMA_STATUS_ERROR) {
     2823                        message |= WORK_DMA_ER(i);
     2824                } else {
     2825                        message |= WORK_DMA(i, irqs >> GRSPW_DMACTRL_PS_BIT);
    27882826                }
    27892827        }
     
    27942832
    27952833        /* Schedule work by sending message to work thread */
    2796         if ((message != WORK_NONE) && grspw_work_queue) {
     2834        if (message != WORK_NONE && priv->wc.msgisr) {
     2835                int status;
    27972836                message |= WORK_CORE(priv->index);
    2798                 stat = rtems_message_queue_send(grspw_work_queue, &message, 4);
    2799                 if (stat != RTEMS_SUCCESSFUL)
     2837                /* func interface compatible with msgQSend() on purpose, but
     2838                 * at the same time the user can assign a custom function to
     2839                 * handle DMA RX/TX operations as indicated by the "message"
     2840                 * and clear the handled bits before given to msgQSend().
     2841                 */
     2842                status = priv->wc.msgisr(priv->wc.msgisr_arg, &message, 4);
     2843                if (status != RTEMS_SUCCESSFUL) {
    28002844                        printk("grspw_isr(%d): message fail %d (0x%x)\n",
    2801                                 priv->index, stat, message);
     2845                                priv->index, status, message);
     2846                }
    28022847        }
    28032848}
     
    30713116
    30723117/******************* Driver Implementation ***********************/
     3118/* Creates a MsgQ (optional) and spawns a worker task associated with the
     3119 * message Q. The task can also be associated with a custom msgQ if *msgQ.
     3120 * is non-zero.
     3121 */
     3122rtems_id grspw_work_spawn(int prio, int stack, rtems_id *pMsgQ, int msgMax)
     3123{
     3124        rtems_id tid;
     3125        int created_msgq = 0;
     3126
     3127        if (pMsgQ == NULL)
     3128                return OBJECTS_ID_NONE;
     3129
     3130        if (*pMsgQ == OBJECTS_ID_NONE) {
     3131                if (msgMax <= 0)
     3132                        msgMax = 32;
     3133
     3134                if (rtems_message_queue_create(
     3135                        rtems_build_name('S', 'G', 'L', 'Q'),
     3136                        msgMax, 4, RTEMS_FIFO, pMsgQ) !=
     3137                        RTEMS_SUCCESSFUL)
     3138                        return OBJECTS_ID_NONE;
     3139                created_msgq = 1;
     3140        }
     3141
     3142        if (prio < 0)
     3143                prio = grspw_work_task_priority; /* default prio */
     3144        if (stack < 0x800)
     3145                stack = RTEMS_MINIMUM_STACK_SIZE; /* default stack size */
     3146
     3147        if (rtems_task_create(rtems_build_name('S', 'G', 'L', 'T'),
     3148                prio, stack, RTEMS_PREEMPT | RTEMS_NO_ASR,
     3149                RTEMS_NO_FLOATING_POINT, &tid) != RTEMS_SUCCESSFUL)
     3150                tid = OBJECTS_ID_NONE;
     3151        else if (rtems_task_start(tid, (rtems_task_entry)grspw_work_func, *pMsgQ) !=
     3152                    RTEMS_SUCCESSFUL) {
     3153                rtems_task_delete(tid);
     3154                tid = OBJECTS_ID_NONE;
     3155        }
     3156
     3157        if (tid == OBJECTS_ID_NONE && created_msgq) {
     3158                rtems_message_queue_delete(*pMsgQ);
     3159                *pMsgQ = OBJECTS_ID_NONE;
     3160        }
     3161        return tid;
     3162}
     3163
     3164/* Free task associated with message queue and optionally also the message
     3165 * queue itself. The message queue is deleted by the work task and is therefore
     3166 * delayed until it the work task resumes its execution.
     3167 */
     3168rtems_status_code grspw_work_free(rtems_id msgQ, int freeMsgQ)
     3169{
     3170        int msg = WORK_QUIT_TASK;
     3171        if (freeMsgQ)
     3172                msg |= WORK_FREE_MSGQ;
     3173        return rtems_message_queue_send(msgQ, &msg, 4);
     3174}
     3175
     3176void grspw_work_cfg(void *d, struct grspw_work_config *wc)
     3177{
     3178        struct grspw_priv *priv = (struct grspw_priv *)d;
     3179
     3180        if (wc == NULL)
     3181                wc = &grspw_wc_def; /* use default config */
     3182        priv->wc = *wc;
     3183}
    30733184
    30743185static int grspw_common_init(void)
     
    30913202         */
    30923203        if (grspw_work_task_priority != -1) {
    3093                 if (rtems_message_queue_create(
    3094                     rtems_build_name('S', 'G', 'L', 'Q'), 32, 4, RTEMS_FIFO,
    3095                     &grspw_work_queue) != RTEMS_SUCCESSFUL)
    3096                         return -1;
    3097 
    3098                 if (rtems_task_create(rtems_build_name('S', 'G', 'L', 'T'),
    3099                     grspw_work_task_priority, RTEMS_MINIMUM_STACK_SIZE,
    3100                     RTEMS_PREEMPT | RTEMS_NO_ASR, RTEMS_NO_FLOATING_POINT,
    3101                     &grspw_work_task) != RTEMS_SUCCESSFUL)
    3102                         return -1;
    3103 
    3104                 if (rtems_task_start(grspw_work_task, grspw_work_func, 0) !=
    3105                     RTEMS_SUCCESSFUL)
    3106                         return -1;
    3107 }
     3204                grspw_work_task = grspw_work_spawn(-1, 0,
     3205                        (rtems_id *)&grspw_wc_def.msgisr_arg, 0);
     3206                if (grspw_work_task == OBJECTS_ID_NONE)
     3207                        return -2;
     3208                grspw_wc_def.msgisr =
     3209                        (grspw_msgqisr_t) rtems_message_queue_send;
     3210        } else {
     3211                grspw_wc_def.msgisr = NULL;
     3212                grspw_wc_def.msgisr_arg = NULL;
     3213        }
    31083214
    31093215        grspw_initialized = 1;
Note: See TracChangeset for help on using the changeset viewer.