Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
035e111f JN |
2 | /* |
3 | * Memory arbiter functions. Allocates bandwidth through the | |
4 | * arbiter and sets up arbiter breakpoints. | |
5 | * | |
6 | * The algorithm first assigns slots to the clients that has specified | |
7 | * bandwidth (e.g. ethernet) and then the remaining slots are divided | |
8 | * on all the active clients. | |
9 | * | |
10 | * Copyright (c) 2004-2007 Axis Communications AB. | |
11 | */ | |
12 | ||
13 | #include <hwregs/reg_map.h> | |
14 | #include <hwregs/reg_rdwr.h> | |
15 | #include <hwregs/marb_defs.h> | |
16 | #include <arbiter.h> | |
17 | #include <hwregs/intr_vect.h> | |
18 | #include <linux/interrupt.h> | |
19 | #include <linux/signal.h> | |
20 | #include <linux/errno.h> | |
21 | #include <linux/spinlock.h> | |
22 | #include <asm/io.h> | |
23 | #include <asm/irq_regs.h> | |
24 | ||
25 | struct crisv32_watch_entry { | |
26 | unsigned long instance; | |
27 | watch_callback *cb; | |
28 | unsigned long start; | |
29 | unsigned long end; | |
30 | int used; | |
31 | }; | |
32 | ||
33 | #define NUMBER_OF_BP 4 | |
34 | #define NBR_OF_CLIENTS 14 | |
35 | #define NBR_OF_SLOTS 64 | |
36 | #define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */ | |
37 | #define INTMEM_BANDWIDTH 400000000 | |
38 | #define NBR_OF_REGIONS 2 | |
39 | ||
40 | static struct crisv32_watch_entry watches[NUMBER_OF_BP] = { | |
41 | {regi_marb_bp0}, | |
42 | {regi_marb_bp1}, | |
43 | {regi_marb_bp2}, | |
44 | {regi_marb_bp3} | |
45 | }; | |
46 | ||
47 | static u8 requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS]; | |
48 | static u8 active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS]; | |
49 | static int max_bandwidth[NBR_OF_REGIONS] = | |
50 | { SDRAM_BANDWIDTH, INTMEM_BANDWIDTH }; | |
51 | ||
52 | DEFINE_SPINLOCK(arbiter_lock); | |
53 | ||
54 | static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id); | |
55 | ||
56 | /* | |
57 | * "I'm the arbiter, I know the score. | |
58 | * From square one I'll be watching all 64." | |
59 | * (memory arbiter slots, that is) | |
60 | * | |
61 | * Or in other words: | |
62 | * Program the memory arbiter slots for "region" according to what's | |
63 | * in requested_slots[] and active_clients[], while minimizing | |
64 | * latency. A caller may pass a non-zero positive amount for | |
65 | * "unused_slots", which must then be the unallocated, remaining | |
66 | * number of slots, free to hand out to any client. | |
67 | */ | |
68 | ||
69 | static void crisv32_arbiter_config(int region, int unused_slots) | |
70 | { | |
71 | int slot; | |
72 | int client; | |
73 | int interval = 0; | |
74 | ||
75 | /* | |
76 | * This vector corresponds to the hardware arbiter slots (see | |
77 | * the hardware documentation for semantics). We initialize | |
78 | * each slot with a suitable sentinel value outside the valid | |
79 | * range {0 .. NBR_OF_CLIENTS - 1} and replace them with | |
80 | * client indexes. Then it's fed to the hardware. | |
81 | */ | |
82 | s8 val[NBR_OF_SLOTS]; | |
83 | ||
84 | for (slot = 0; slot < NBR_OF_SLOTS; slot++) | |
85 | val[slot] = -1; | |
86 | ||
87 | for (client = 0; client < NBR_OF_CLIENTS; client++) { | |
88 | int pos; | |
89 | /* Allocate the requested non-zero number of slots, but | |
90 | * also give clients with zero-requests one slot each | |
91 | * while stocks last. We do the latter here, in client | |
92 | * order. This makes sure zero-request clients are the | |
93 | * first to get to any spare slots, else those slots | |
94 | * could, when bandwidth is allocated close to the limit, | |
95 | * all be allocated to low-index non-zero-request clients | |
96 | * in the default-fill loop below. Another positive but | |
97 | * secondary effect is a somewhat better spread of the | |
98 | * zero-bandwidth clients in the vector, avoiding some of | |
99 | * the latency that could otherwise be caused by the | |
100 | * partitioning of non-zero-bandwidth clients at low | |
101 | * indexes and zero-bandwidth clients at high | |
102 | * indexes. (Note that this spreading can only affect the | |
103 | * unallocated bandwidth.) All the above only matters for | |
104 | * memory-intensive situations, of course. | |
105 | */ | |
106 | if (!requested_slots[region][client]) { | |
107 | /* | |
108 | * Skip inactive clients. Also skip zero-slot | |
109 | * allocations in this pass when there are no known | |
110 | * free slots. | |
111 | */ | |
112 | if (!active_clients[region][client] | |
113 | || unused_slots <= 0) | |
114 | continue; | |
115 | ||
116 | unused_slots--; | |
117 | ||
118 | /* Only allocate one slot for this client. */ | |
119 | interval = NBR_OF_SLOTS; | |
120 | } else | |
121 | interval = | |
122 | NBR_OF_SLOTS / requested_slots[region][client]; | |
123 | ||
124 | pos = 0; | |
125 | while (pos < NBR_OF_SLOTS) { | |
126 | if (val[pos] >= 0) | |
127 | pos++; | |
128 | else { | |
129 | val[pos] = client; | |
130 | pos += interval; | |
131 | } | |
132 | } | |
133 | } | |
134 | ||
135 | client = 0; | |
136 | for (slot = 0; slot < NBR_OF_SLOTS; slot++) { | |
137 | /* | |
138 | * Allocate remaining slots in round-robin | |
139 | * client-number order for active clients. For this | |
140 | * pass, we ignore requested bandwidth and previous | |
141 | * allocations. | |
142 | */ | |
143 | if (val[slot] < 0) { | |
144 | int first = client; | |
145 | while (!active_clients[region][client]) { | |
146 | client = (client + 1) % NBR_OF_CLIENTS; | |
147 | if (client == first) | |
148 | break; | |
149 | } | |
150 | val[slot] = client; | |
151 | client = (client + 1) % NBR_OF_CLIENTS; | |
152 | } | |
153 | if (region == EXT_REGION) | |
154 | REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot, | |
155 | val[slot]); | |
156 | else if (region == INT_REGION) | |
157 | REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot, | |
158 | val[slot]); | |
159 | } | |
160 | } | |
161 | ||
c2579fee | 162 | extern char _stext[], _etext[]; |
035e111f JN |
163 | |
164 | static void crisv32_arbiter_init(void) | |
165 | { | |
166 | static int initialized; | |
167 | ||
168 | if (initialized) | |
169 | return; | |
170 | ||
171 | initialized = 1; | |
172 | ||
173 | /* | |
174 | * CPU caches are always set to active, but with zero | |
175 | * bandwidth allocated. It should be ok to allocate zero | |
176 | * bandwidth for the caches, because DMA for other channels | |
177 | * will supposedly finish, once their programmed amount is | |
178 | * done, and then the caches will get access according to the | |
179 | * "fixed scheme" for unclaimed slots. Though, if for some | |
180 | * use-case somewhere, there's a maximum CPU latency for | |
181 | * e.g. some interrupt, we have to start allocating specific | |
182 | * bandwidth for the CPU caches too. | |
183 | */ | |
184 | active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1; | |
185 | crisv32_arbiter_config(EXT_REGION, 0); | |
186 | crisv32_arbiter_config(INT_REGION, 0); | |
187 | ||
64d8ad93 | 188 | if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, 0, |
035e111f JN |
189 | "arbiter", NULL)) |
190 | printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); | |
191 | ||
192 | #ifndef CONFIG_ETRAX_KGDB | |
193 | /* Global watch for writes to kernel text segment. */ | |
c2579fee | 194 | crisv32_arbiter_watch(virt_to_phys(_stext), _etext - _stext, |
035e111f JN |
195 | arbiter_all_clients, arbiter_all_write, NULL); |
196 | #endif | |
197 | } | |
198 | ||
199 | /* Main entry for bandwidth allocation. */ | |
200 | ||
201 | int crisv32_arbiter_allocate_bandwidth(int client, int region, | |
202 | unsigned long bandwidth) | |
203 | { | |
204 | int i; | |
205 | int total_assigned = 0; | |
206 | int total_clients = 0; | |
207 | int req; | |
208 | ||
209 | crisv32_arbiter_init(); | |
210 | ||
211 | for (i = 0; i < NBR_OF_CLIENTS; i++) { | |
212 | total_assigned += requested_slots[region][i]; | |
213 | total_clients += active_clients[region][i]; | |
214 | } | |
215 | ||
216 | /* Avoid division by 0 for 0-bandwidth requests. */ | |
217 | req = bandwidth == 0 | |
218 | ? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth); | |
219 | ||
220 | /* | |
221 | * We make sure that there are enough slots only for non-zero | |
222 | * requests. Requesting 0 bandwidth *may* allocate slots, | |
223 | * though if all bandwidth is allocated, such a client won't | |
224 | * get any and will have to rely on getting memory access | |
225 | * according to the fixed scheme that's the default when one | |
226 | * of the slot-allocated clients doesn't claim their slot. | |
227 | */ | |
228 | if (total_assigned + req > NBR_OF_SLOTS) | |
229 | return -ENOMEM; | |
230 | ||
231 | active_clients[region][client] = 1; | |
232 | requested_slots[region][client] = req; | |
233 | crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned); | |
234 | ||
235 | return 0; | |
236 | } | |
237 | ||
238 | /* | |
239 | * Main entry for bandwidth deallocation. | |
240 | * | |
241 | * Strictly speaking, for a somewhat constant set of clients where | |
242 | * each client gets a constant bandwidth and is just enabled or | |
243 | * disabled (somewhat dynamically), no action is necessary here to | |
244 | * avoid starvation for non-zero-allocation clients, as the allocated | |
245 | * slots will just be unused. However, handing out those unused slots | |
246 | * to active clients avoids needless latency if the "fixed scheme" | |
247 | * would give unclaimed slots to an eager low-index client. | |
248 | */ | |
249 | ||
250 | void crisv32_arbiter_deallocate_bandwidth(int client, int region) | |
251 | { | |
252 | int i; | |
253 | int total_assigned = 0; | |
254 | ||
255 | requested_slots[region][client] = 0; | |
256 | active_clients[region][client] = 0; | |
257 | ||
258 | for (i = 0; i < NBR_OF_CLIENTS; i++) | |
259 | total_assigned += requested_slots[region][i]; | |
260 | ||
261 | crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned); | |
262 | } | |
263 | ||
264 | int crisv32_arbiter_watch(unsigned long start, unsigned long size, | |
265 | unsigned long clients, unsigned long accesses, | |
266 | watch_callback *cb) | |
267 | { | |
268 | int i; | |
269 | ||
270 | crisv32_arbiter_init(); | |
271 | ||
272 | if (start > 0x80000000) { | |
273 | printk(KERN_ERR "Arbiter: %lX doesn't look like a " | |
274 | "physical address", start); | |
275 | return -EFAULT; | |
276 | } | |
277 | ||
278 | spin_lock(&arbiter_lock); | |
279 | ||
280 | for (i = 0; i < NUMBER_OF_BP; i++) { | |
281 | if (!watches[i].used) { | |
282 | reg_marb_rw_intr_mask intr_mask = | |
283 | REG_RD(marb, regi_marb, rw_intr_mask); | |
284 | ||
285 | watches[i].used = 1; | |
286 | watches[i].start = start; | |
287 | watches[i].end = start + size; | |
288 | watches[i].cb = cb; | |
289 | ||
290 | REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr, | |
291 | watches[i].start); | |
292 | REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr, | |
293 | watches[i].end); | |
294 | REG_WR_INT(marb_bp, watches[i].instance, rw_op, | |
295 | accesses); | |
296 | REG_WR_INT(marb_bp, watches[i].instance, rw_clients, | |
297 | clients); | |
298 | ||
299 | if (i == 0) | |
300 | intr_mask.bp0 = regk_marb_yes; | |
301 | else if (i == 1) | |
302 | intr_mask.bp1 = regk_marb_yes; | |
303 | else if (i == 2) | |
304 | intr_mask.bp2 = regk_marb_yes; | |
305 | else if (i == 3) | |
306 | intr_mask.bp3 = regk_marb_yes; | |
307 | ||
308 | REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); | |
309 | spin_unlock(&arbiter_lock); | |
310 | ||
311 | return i; | |
312 | } | |
313 | } | |
314 | spin_unlock(&arbiter_lock); | |
315 | return -ENOMEM; | |
316 | } | |
317 | ||
318 | int crisv32_arbiter_unwatch(int id) | |
319 | { | |
320 | reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask); | |
321 | ||
322 | crisv32_arbiter_init(); | |
323 | ||
324 | spin_lock(&arbiter_lock); | |
325 | ||
326 | if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) { | |
327 | spin_unlock(&arbiter_lock); | |
328 | return -EINVAL; | |
329 | } | |
330 | ||
331 | memset(&watches[id], 0, sizeof(struct crisv32_watch_entry)); | |
332 | ||
333 | if (id == 0) | |
334 | intr_mask.bp0 = regk_marb_no; | |
335 | else if (id == 1) | |
be149452 | 336 | intr_mask.bp1 = regk_marb_no; |
035e111f JN |
337 | else if (id == 2) |
338 | intr_mask.bp2 = regk_marb_no; | |
339 | else if (id == 3) | |
340 | intr_mask.bp3 = regk_marb_no; | |
341 | ||
342 | REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); | |
343 | ||
344 | spin_unlock(&arbiter_lock); | |
345 | return 0; | |
346 | } | |
347 | ||
348 | extern void show_registers(struct pt_regs *regs); | |
349 | ||
350 | static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id) | |
351 | { | |
352 | reg_marb_r_masked_intr masked_intr = | |
353 | REG_RD(marb, regi_marb, r_masked_intr); | |
354 | reg_marb_bp_r_brk_clients r_clients; | |
355 | reg_marb_bp_r_brk_addr r_addr; | |
356 | reg_marb_bp_r_brk_op r_op; | |
357 | reg_marb_bp_r_brk_first_client r_first; | |
358 | reg_marb_bp_r_brk_size r_size; | |
359 | reg_marb_bp_rw_ack ack = { 0 }; | |
360 | reg_marb_rw_ack_intr ack_intr = { | |
361 | .bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1 | |
362 | }; | |
363 | struct crisv32_watch_entry *watch; | |
364 | ||
365 | if (masked_intr.bp0) { | |
366 | watch = &watches[0]; | |
367 | ack_intr.bp0 = regk_marb_yes; | |
368 | } else if (masked_intr.bp1) { | |
369 | watch = &watches[1]; | |
370 | ack_intr.bp1 = regk_marb_yes; | |
371 | } else if (masked_intr.bp2) { | |
372 | watch = &watches[2]; | |
373 | ack_intr.bp2 = regk_marb_yes; | |
374 | } else if (masked_intr.bp3) { | |
375 | watch = &watches[3]; | |
376 | ack_intr.bp3 = regk_marb_yes; | |
377 | } else { | |
378 | return IRQ_NONE; | |
379 | } | |
380 | ||
381 | /* Retrieve all useful information and print it. */ | |
382 | r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients); | |
383 | r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr); | |
384 | r_op = REG_RD(marb_bp, watch->instance, r_brk_op); | |
385 | r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client); | |
386 | r_size = REG_RD(marb_bp, watch->instance, r_brk_size); | |
387 | ||
388 | printk(KERN_INFO "Arbiter IRQ\n"); | |
389 | printk(KERN_INFO "Clients %X addr %X op %X first %X size %X\n", | |
390 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients), | |
391 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr), | |
392 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op), | |
393 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first), | |
394 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size)); | |
395 | ||
396 | REG_WR(marb_bp, watch->instance, rw_ack, ack); | |
397 | REG_WR(marb, regi_marb, rw_ack_intr, ack_intr); | |
398 | ||
25985edc | 399 | printk(KERN_INFO "IRQ occurred at %lX\n", get_irq_regs()->erp); |
035e111f JN |
400 | |
401 | if (watch->cb) | |
402 | watch->cb(); | |
403 | ||
404 | return IRQ_HANDLED; | |
405 | } |