blob: 2759b5511d2d5acfe2d8316387eddd8ff65186ab [file] [log] [blame]
Harald Welte9d3e3822015-11-09 00:50:54 +01001/* USB Request Context for OpenPCD / OpenPICC / SIMtrace
2 * (C) 2006-2015 by Harald Welte <hwelte@hmw-consulting.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20#include <unistd.h>
21#include <stdlib.h>
22#include <stdint.h>
23
24#include "utils.h"
25#include "trace.h"
26#include "req_ctx.h"
27
28#define NUM_RCTX_SMALL 0
29#define NUM_RCTX_LARGE 20
30
31#define NUM_REQ_CTX (NUM_RCTX_SMALL+NUM_RCTX_LARGE)
32
33static uint8_t rctx_data[NUM_RCTX_SMALL][RCTX_SIZE_SMALL];
34static uint8_t rctx_data_large[NUM_RCTX_LARGE][RCTX_SIZE_LARGE];
35
36static struct req_ctx req_ctx[NUM_REQ_CTX];
37
38#ifdef REQ_CTX_LISTS
39/* queue of RCTX indexed by their current state */
40static struct req_ctx *req_ctx_queues[RCTX_STATE_COUNT], *req_ctx_tails[RCTX_STATE_COUNT];
41static unsigned req_counts[RCTX_STATE_COUNT];
42#endif
43
44struct req_ctx __ramfunc *
45req_ctx_find_get(int large, uint32_t old_state, uint32_t new_state)
46{
47 struct req_ctx *toReturn = NULL;
48 unsigned long flags;
49
50 if (old_state >= RCTX_STATE_COUNT || new_state >= RCTX_STATE_COUNT) {
51 TRACE_DEBUG("Invalid parameters for req_ctx_find_get");
52 return NULL;
53 }
54 local_irq_save(flags);
55#ifdef REQ_CTX_LISTS
56 toReturn = req_ctx_queues[old_state];
57 if (toReturn) {
58 if ((req_ctx_queues[old_state] = toReturn->next))
59 toReturn->next->prev = NULL;
60 else
61 req_ctx_tails[old_state] = NULL;
62 req_counts[old_state]--;
63 if ((toReturn->prev = req_ctx_tails[new_state]))
64 toReturn->prev->next = toReturn;
65 else
66 req_ctx_queues[new_state] = toReturn;
67 req_ctx_tails[new_state] = toReturn;
68 toReturn->next = NULL;
69 req_counts[new_state]++;
70 toReturn->state = new_state;
71 }
72#else
73 {
74 unsigned int i;
75 for (i = 0; i < ARRAY_SIZE(req_ctx); i++) {
76 if (req_ctx[i].state == old_state) {
77 toReturn = &req_ctx[i];
78 toReturn->state = new_state;
79 }
80 }
81 }
82#endif
83 local_irq_restore(flags);
84 return toReturn;
85}
86
87uint8_t req_ctx_num(struct req_ctx *ctx)
88{
89 return ctx - req_ctx;
90}
91
92void req_ctx_set_state(struct req_ctx *ctx, uint32_t new_state)
93{
94 unsigned long flags;
95 unsigned old_state;
96
97 TRACE_DEBUG("rctx_set_state(ctx=%p, new_state=%u)\n", ctx, new_state);
98
99 if (new_state >= RCTX_STATE_COUNT) {
100 TRACE_DEBUG("Invalid new_state for req_ctx_set_state\n");
101 return;
102 }
103 local_irq_save(flags);
104 old_state = ctx->state;
105#ifdef REQ_CTX_LISTS
106 if (ctx->prev)
107 ctx->prev->next = ctx->next;
108 else
109 req_ctx_queues[old_state] = ctx->next;
110 if (ctx->next)
111 ctx->next->prev = ctx->prev;
112 else
113 req_ctx_tails[old_state] = ctx->prev;
114 req_counts[old_state]--;
115 if ((ctx->prev = req_ctx_tails[new_state]))
116 ctx->prev->next = ctx;
117 else
118 req_ctx_queues[new_state] = ctx;
119 req_ctx_tails[new_state] = ctx;
120 ctx->next = NULL;
121 req_counts[new_state]++;
122#endif
123 ctx->state = new_state;
124 local_irq_restore(flags);
125}
126
127#ifdef DEBUG_REQCTX
128void req_print(int state) {
129 int count = 0;
130 struct req_ctx *ctx, *last = NULL;
131 DEBUGP("State [%02i] start <==> ", state);
132 ctx = req_ctx_queues[state];
133 while (ctx) {
134 if (last != ctx->prev)
135 DEBUGP("*INV_PREV* ");
136 DEBUGP("%08X => ", ctx);
137 last = ctx;
138 ctx = ctx->next;
139 count++;
140 if (count > NUM_REQ_CTX) {
141 DEBUGP("*WILD POINTER* => ");
142 break;
143 }
144 }
145 TRACE_DEBUG("NULL");
146 if (!req_ctx_queues[state] && req_ctx_tails[state]) {
147 TRACE_DEBUG("NULL head, NON-NULL tail");
148 }
149 if (last != req_ctx_tails[state]) {
150 TRACE_DEBUG("Tail does not match last element");
151 }
152}
153#endif
154
155void req_ctx_put(struct req_ctx *ctx)
156{
157 return req_ctx_set_state(ctx, RCTX_S_FREE);
158}
159
160#ifdef REQ_CTX_LISTS
161unsigned int req_ctx_count(uint32_t state)
162{
163 if (state >= RCTX_STATE_COUNT)
164 return 0;
165 return req_counts[state];
166}
167#endif
168
169void req_ctx_init(void)
170{
171 int i;
172 for (i = 0; i < NUM_RCTX_SMALL; i++) {
173#ifdef REQ_CTX_LISTS
174 req_ctx[i].prev = req_ctx + i - 1;
175 req_ctx[i].next = req_ctx + i + 1;
176#endif
177 req_ctx[i].size = RCTX_SIZE_SMALL;
178 req_ctx[i].tot_len = 0;
179 req_ctx[i].data = rctx_data[i];
180 req_ctx[i].state = RCTX_S_FREE;
181 TRACE_DEBUG("SMALL req_ctx[%02i] initialized at %08X, Data: %08X => %08X\n",
182 i, req_ctx + i, req_ctx[i].data, req_ctx[i].data + RCTX_SIZE_SMALL);
183 }
184
185 for (; i < NUM_REQ_CTX; i++) {
186#ifdef REQ_CTX_LISTS
187 req_ctx[i].prev = req_ctx + i - 1;
188 req_ctx[i].next = req_ctx + i + 1;
189#endif
190 req_ctx[i].size = RCTX_SIZE_LARGE;
191 req_ctx[i].tot_len = 0;
192 req_ctx[i].data = rctx_data_large[i];
193 req_ctx[i].state = RCTX_S_FREE;
194 TRACE_DEBUG("LARGE req_ctx[%02i] initialized at %08X, Data: %08X => %08X\n",
195 i, req_ctx + i, req_ctx[i].data, req_ctx[i].data + RCTX_SIZE_LARGE);
196 }
197#ifdef REQ_CTX_LISTS
198 req_ctx[0].prev = NULL;
199 req_ctx[NUM_REQ_CTX - 1].next = NULL;
200
201 req_ctx_queues[RCTX_S_FREE] = req_ctx;
202 req_ctx_tails[RCTX_S_FREE] = req_ctx + NUM_REQ_CTX - 1;
203 req_counts[RCTX_S_FREE] = NUM_REQ_CTX;
204
205 for (i = RCTX_S_FREE + 1; i < RCTX_STATE_COUNT; i++) {
206 req_ctx_queues[i] = req_ctx_tails[i] = NULL;
207 req_counts[i] = 0;
208 }
209#endif
210}