summaryrefslogtreecommitdiff
path: root/cesar/hal/hle/src/ipmbox.c
blob: 002d5c9863329913e058e484964b1c66a4a31209 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/* Cesar project {{{
 *
 * Copyright (C) 2008 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    hal/hle/src/ipmbox.c
 * \brief   HAL HLE mailbox layer.
 * \ingroup hal_hle
 *
 * this layer provide all mechanisms to manage mailboxes.
 */

#include "common/std.h"

#include "hal/hle/inc/hal_ipmbox.h"
#include "hal/hle/ipmbox.h"
#include "hal/hle/inc/ipmbox.h"
#include "hal/hle/defs.h"

/** Rx Mailbox interrupt number */
#define MAILBOX_RX_IT_NUM       CYGNUM_HAL_INTERRUPT_GIC2_14

/** RX budget.  Number of words which can be handled in one execution.
 * Warning: this works if all messages have the same size because input
 * mailbox will be cut without analysis. */
#define MAILBOX_RX_BUDGET 256

/** Global context variable */
static ipmbox_t context;
/** Ipmbox Rx buffer */
static u32 rx_msgs[A2L_RING_WORDS];

/**
 * Activate ipmbox interruptions.
 * \param  ctx  ipmbox context
 * \param  activation  indicates if interruptions are activated or deactivated
 */
void ipmbox_activate (ipmbox_t *ctx, bool activation)
{
    if(activation)
    {
        //Unmask receive interrupt.
        A2Lt_it_enable();
    }
    else
    {
        //Mask receive interrupt.
        A2Lt_it_disable();
    }
}

/**
 * Transmit an Ethernet packet.
 * \param  ctx  ipmbox context
 * \param  first_msg  pointer to the first received message header
 * \param  length  total length (in word) of messages to transmit
 */
void ipmbox_tx (ipmbox_t *ctx, u32 *first_msg, uint length)
{
    //Check args.
    dbg_assert(ctx);
    dbg_assert(first_msg);
    dbg_assert(length != 0);

    //Copy messages to the ring buffer.
    halmbx_copy_to_ring (first_msg, length);
}

/**
 * Mailbox receive ISR handler function.
 * \param  vector  interrupt vector number
 * \param  data  user interrupt arguments
 * \return  isr status and if DSR is needed
 */
cyg_uint32 mailbox_rx_isr (cyg_vector_t vector, cyg_addrword_t data)
{
    //Block this interrupt from occurring until the DSR completes.
    A2Lt_it_disable ();
    //Acknowledge interrupt (because of shared child interrupt).
    ipmbox_interrupt_acknowledge (MAILBOX_RX_IT_NUM);

    //Tell the kernel that chained interrupt processing is done and the DSR needs to be executed next.
    return(CYG_ISR_HANDLED | CYG_ISR_CALL_DSR);
}

/**
 * Mailbox receive DSR handler function.
 * \param  vector  interrupt vector number
 * \param  count  ?
 * \param  data  user interrupt arguments
 */
void mailbox_rx_dsr (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    ipmbox_t *ctx = (ipmbox_t*) data;
    uint budget = MAILBOX_RX_BUDGET;
    uint size;

    do
    {
        /* Clear interrupt. */
        clr_A2Lt_interrupt ();

        /* Try to slurp all RX queue. */
        size = A2L_RING_USED_WORDS (A2L_HEAD, A2L_TAIL);
        if (size)
        {
            /* Check and update budget. */
            if (budget == 0)
            {
                /* Ask to be executed again, do not activate interrupts. */
                cyg_interrupt_post_dsr (ctx->rx_it_handle);
                return;
            }
            if (size > budget)
                size = budget;
            budget -= size;
            /* Copy messages out of mailbox, because callback can not handle
             * circular buffers. */
            halmbx_copy_from_ring (rx_msgs, size);
            /* Send all received messages to the upper layer. */
            ctx->rx_cb (ctx->rx_cb_user_data, rx_msgs, size);
        }
    } while (size);

    /* Allow this interrupt to occur again. */
    A2Lt_it_enable ();
}

/**
 * Uninitialise the HAL HLE.
 * \param  ctx  ipmbox context
 */
void ipmbox_uninit (ipmbox_t *ctx)
{
    //Stop all mailbox interrupts.
    L2Aa_it_disable();
    A2Lt_it_disable();

    /* Mask. */
    cyg_drv_interrupt_mask (MAILBOX_RX_IT_NUM);
}

/**
 * Initialise the HAL HLE.
 * \param  user_data  user data passed to any callback
 * \param  rx_cb  RX DSR callback, callback used when an Ethernet packet is received
 * \return  the newly created context
 */
ipmbox_t * ipmbox_init (void *user_data, ipmbox_rx_cb_t rx_cb)
{
    ipmbox_t *ctx = &context;

    //Check args.
    dbg_assert(rx_cb);

    //Store user informations.
    ctx->rx_cb_user_data = user_data;
    ctx->rx_cb = rx_cb;

    //Stop all mailbox interrupts.
    L2Aa_it_disable();
    A2Lt_it_disable();

    //Create interrupt for Rx messages.
    cyg_drv_interrupt_create (MAILBOX_RX_IT_NUM,
                              0,
                              (cyg_addrword_t) ctx,
                              &mailbox_rx_isr,
                              &mailbox_rx_dsr,
                              &ctx->rx_it_handle,
                              &ctx->rx_it);

    //Initialize Hardware.
    halmbx_init();

    //Attach this interrupt.
    cyg_drv_interrupt_attach (ctx->rx_it_handle);

    /* Unmask. */
    cyg_drv_interrupt_unmask (MAILBOX_RX_IT_NUM);

    return ctx;
}