summaryrefslogtreecommitdiffstats
path: root/arch/m68k/mach-mcfv4e/fecbd.c
blob: a8e732b3aca94a47e64ea3127cc8177159438cdf (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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/*
 * File:    fecbd.c
 * Purpose: Provide a simple buffer management driver
 *
 * Notes:
 */
#include <common.h>
#include <linux/types.h>

#include <mach/mcf54xx-regs.h>
#include <proc/mcdapi/MCD_dma.h>
#include <proc/net/net.h>
#include <proc/fecbd.h>
#include <proc/fec.h>
#include <proc/dma_utils.h>

#define ASSERT(x) if (!(x)) hang();

/*
 * This implements a simple static buffer descriptor
 * ring for each channel and each direction
 *
 * FEC Buffer Descriptors need to be aligned to a 4-byte boundary.
 * In order to accomplish this, data is over-allocated and manually
 * aligned at runtime
 *
 * Enough space is allocated for each of the two FEC channels to have
 * NRXBD Rx BDs and NTXBD Tx BDs
 *
 */
FECBD unaligned_bds[(2 * NRXBD) + (2 * NTXBD) + 1];

/*
 * These pointers are used to reference into the chunck of data set
 * aside for buffer descriptors
 */
FECBD *RxBD;
FECBD *TxBD;

/*
 * Macros to easier access to the BD ring
 */
#define RxBD(ch,i)      RxBD[(ch * NRXBD) + i]
#define TxBD(ch,i)      TxBD[(ch * NTXBD) + i]

/*
 * Buffer descriptor indexes
 */
static int iTxbd_new;
static int iTxbd_old;
static int iRxbd;

/*
 * Initialize the FEC Buffer Descriptor ring
 * Buffer Descriptor format is defined by the MCDAPI
 *
 * Parameters:
 *  ch      FEC channel
 */
void
fecbd_init(uint8_t ch)
{
    NBUF *nbuf;
    int i;

    /*
     * Align Buffer Descriptors to 4-byte boundary
     */
    RxBD = (FECBD *)(((int)unaligned_bds + 3) & 0xFFFFFFFC);
    TxBD = (FECBD *)((int)RxBD + (sizeof(FECBD) * 2 * NRXBD));

    /*
     * Initialize the Rx Buffer Descriptor ring
     */
    for (i = 0; i < NRXBD; ++i)
    {
        /* Grab a network buffer from the free list */
        nbuf = nbuf_alloc();
        ASSERT(nbuf);

        /* Initialize the BD */
        RxBD(ch,i).status = RX_BD_E | RX_BD_INTERRUPT;
        RxBD(ch,i).length = RX_BUF_SZ;
        RxBD(ch,i).data =  nbuf->data;

        /* Add the network buffer to the Rx queue */
        nbuf_add(NBUF_RX_RING, nbuf);
    }

    /*
     * Set the WRAP bit on the last one
     */
    RxBD(ch,i-1).status |= RX_BD_W;

    /*
     * Initialize the Tx Buffer Descriptor ring
     */
    for (i = 0; i < NTXBD; ++i)
    {
        TxBD(ch,i).status = TX_BD_INTERRUPT;
        TxBD(ch,i).length = 0;
        TxBD(ch,i).data = NULL;
    }

    /*
     * Set the WRAP bit on the last one
     */
    TxBD(ch,i-1).status |= TX_BD_W;

    /*
     * Initialize the buffer descriptor indexes
     */
    iTxbd_new = iTxbd_old = iRxbd = 0;
}

void
fecbd_dump(uint8_t ch)
{
    #ifdef CONFIG_DRIVER_NET_MCF54XX_DEBUG
    int i;

    printf("\n------------ FEC%d BDs -----------\n",ch);
    printf("RxBD Ring\n");
    for (i=0; i<NRXBD; i++)
    {
        printf("%02d: BD Addr=0x%08x, Ctrl=0x%04x, Lgth=%04d, DataPtr=0x%08x\n",
            i, &RxBD(ch,i),
            RxBD(ch,i).status,
            RxBD(ch,i).length,
            RxBD(ch,i).data);
    }
    printf("TxBD Ring\n");
    for (i=0; i<NTXBD; i++)
    {
        printf("%02d: BD Addr=0x%08x, Ctrl=0x%04x, Lgth=%04d, DataPtr=0x%08x\n",
            i, &TxBD(ch,i),
            TxBD(ch,i).status,
            TxBD(ch,i).length,
            TxBD(ch,i).data);
    }
    printf("--------------------------------\n\n");
    #endif
}

/*
 * Return the address of the first buffer descriptor in the ring.
 *
 * Parameters:
 *  ch          FEC channel
 *  direction   Rx or Tx Macro
 *
 * Return Value:
 *  The start address of the selected Buffer Descriptor ring
 */
uint32_t
fecbd_get_start(uint8_t ch, uint8_t direction)
{
    switch (direction)
    {
        case Rx:
            return (uint32_t)((int)RxBD + (ch * sizeof(FECBD) * NRXBD));
        case Tx:
        default:
            return (uint32_t)((int)TxBD + (ch * sizeof(FECBD) * NTXBD));
    }
}

FECBD *
fecbd_rx_alloc(uint8_t ch)
{
    int i = iRxbd;

    /* Check to see if the ring of BDs is full */
    if (RxBD(ch,i).status & RX_BD_E)
        return NULL;

    /* Increment the circular index */
    iRxbd = (uint8_t)((iRxbd + 1) % NRXBD);

    return &RxBD(ch,i);
}

/*
 * This function keeps track of the next available Tx BD in the ring
 *
 * Parameters:
 *  ch  FEC channel
 *
 * Return Value:
 *  Pointer to next available buffer descriptor.
 *  NULL if the BD ring is full
 */
FECBD *
fecbd_tx_alloc(uint8_t ch)
{
    int i = iTxbd_new;

    /* Check to see if the ring of BDs is full */
    if (TxBD(ch,i).status & TX_BD_R)
        return NULL;

    /* Increment the circular index */
    iTxbd_new = (uint8_t)((iTxbd_new + 1) % NTXBD);

    return &TxBD(ch,i);
}

/*
 * This function keeps track of the Tx BDs that have already been
 * processed by the FEC
 *
 * Parameters:
 *  ch  FEC channel
 *
 * Return Value:
 *  Pointer to the oldest buffer descriptor that has already been sent
 *  by the FEC, NULL if the BD ring is empty
 */
FECBD *
fecbd_tx_free(uint8_t ch)
{
    int i = iTxbd_old;

    /* Check to see if the ring of BDs is empty */
    if ((TxBD(ch,i).data == NULL) || (TxBD(ch,i).status & TX_BD_R))
        return NULL;

    /* Increment the circular index */
    iTxbd_old = (uint8_t)((iTxbd_old + 1) % NTXBD);

    return &TxBD(ch,i);
}