-
Notifications
You must be signed in to change notification settings - Fork 0
/
bus_controller.c
589 lines (477 loc) · 18.4 KB
/
bus_controller.c
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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
#include <linux/bio.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "rust/libflashbench.h"
#include "main.h"
#include "bus_controller.h"
struct fb_operation_t {
enum fb_dev_op_t operation;
struct fb_bio_t *ptr_fb_bio;
};
struct fb_opr_queue_t {
u32 num_max_entries;
u32 num_entries;
u32 queue_head;
u32 queue_tail;
struct fb_operation_t *opr_list;
struct completion queue_lock;
};
struct fb_chip_busy_t {
u32 wakeup_time_in_us;
u32 issue_time_in_us;
struct completion chip_busy;
struct fb_bio_t *ptr_fb_bio;
};
struct fb_bus_controller_t {
u32 num_bus;
struct fb_opr_queue_t **ptr_opr_queue;
struct fb_chip_busy_t *chip_busies;
u32 flag_enable_thread;
struct task_struct *ptr_task;
};
// ---------------- prototypes of static functions: bus controller
// ----------------------------
// Creating an bus controller for a bus
static struct fb_bus_controller_t *create_bus_controller(
u32 num_max_entries_per_chip);
// Destroying the bus controller
static void destroy_bus_controller(
struct fb_bus_controller_t *ptr_bus_controller);
// Bus controllers management thread
// Phase 1: Release bus locks whose conditions are satisfied
// Phase 2: Acquire bus locks for requests waiting for avaliable chips
static int fb_bus_ctrl_thread(void *arg);
static int fb_init_bus_ctrl_thread(
struct fb_bus_controller_t *ptr_bus_controller, u32 bus);
static void fb_stop_bus_ctrl_thread(
struct fb_bus_controller_t *ptr_bus_controller);
// ---------------- prototypes of static functions: operation queue
// ----------------------------
// Creating an operation queue for a chip
static struct fb_opr_queue_t *create_opr_queue(u32 num_max_entries);
// Destroying the operation queue
static void destroy_opr_queue(struct fb_opr_queue_t *ptr_opr_queue);
// Put an entry into the target operation queue(success: 0, error: -1)
static int opr_queue_put_entry(struct fb_opr_queue_t *ptr_opr_queue,
enum fb_dev_op_t operation, struct fb_bio_t *ptr_fb_bio);
// Get informations of the first entry in the target operation queue(success: 0,
// error: -1)
static int opr_queue_get_first(struct fb_opr_queue_t *ptr_opr_queue,
enum fb_dev_op_t *ptr_operation,
struct fb_bio_t **ptr_fb_bio);
// Remove informations of the first entry in the target operation queue(success:
// 0, error: -1)
static int opr_queue_remove_first(struct fb_opr_queue_t *ptr_opr_queue);
static void release_busy_lock(struct fb_bus_controller_t *ptr_bus_controller,
u32 chip);
static void acquire_busy_lock(struct fb_bus_controller_t *ptr_bus_controller,
u32 chip, enum fb_dev_op_t operation,
struct fb_bio_t *ptr_fb_bio);
static bool is_acquired(const struct fb_chip_busy_t *busy) {
return busy->wakeup_time_in_us != 0 || busy->issue_time_in_us != 0;
}
static u32 timer_get_timestamp_in_us(void);
// ----------------- Public functions ----------------------------------------
// Creating and initialize bus controllers in the virtual device structure
int fb_bus_controller_init(struct vdevice_t *ptr_vdevice,
u32 num_max_entries_per_chip) {
// Allocating a pointer of the bus controller list
struct fb_bus_controller_t **ptr_bus_controller = kmalloc(sizeof(struct fb_bus_controller_t *) * NUM_BUSES, GFP_ATOMIC);
if (!ptr_bus_controller) {
printk(KERN_ERR
"flashbench: bus controller: Allocating the pointer of bus "
"controllers failed.\n");
goto ALLOC_PTR_BUS_CTRL_FAIL;
}
// Creating bus controllers(for the number of buses)
for (u32 loop_bus = 0; loop_bus < NUM_BUSES; loop_bus++) {
ptr_bus_controller[loop_bus] = create_bus_controller(num_max_entries_per_chip);
if (!ptr_bus_controller[loop_bus]) {
printk(KERN_ERR
"flashbench: bus controller: Creating bus controllers failed.\n");
goto CREATE_BUS_CTRL_FAIL;
}
}
// Initilaize bus control threads(for the number of buses)
for (u32 loop_bus = 0; loop_bus < NUM_BUSES; loop_bus++) {
ptr_bus_controller[loop_bus]->flag_enable_thread = 1;
ptr_bus_controller[loop_bus]->num_bus = loop_bus;
if (fb_init_bus_ctrl_thread(ptr_bus_controller[loop_bus], loop_bus) == -1) {
goto INIT_BUS_CTRL_THREAD_FAIL;
}
}
ptr_vdevice->ptr_bus_controller = ptr_bus_controller;
return 0;
INIT_BUS_CTRL_THREAD_FAIL:
for (u32 loop_bus = 0; loop_bus < NUM_BUSES; loop_bus++) {
ptr_bus_controller[loop_bus]->flag_enable_thread = 0;
fb_stop_bus_ctrl_thread(ptr_bus_controller[loop_bus]);
}
CREATE_BUS_CTRL_FAIL:
if (ptr_bus_controller) {
for (u32 loop_bus = 0; loop_bus < NUM_BUSES; loop_bus++) {
if (!ptr_bus_controller[loop_bus]) { break; }
destroy_bus_controller(ptr_bus_controller[loop_bus]);
}
kfree(ptr_bus_controller);
}
ALLOC_PTR_BUS_CTRL_FAIL:
return -1;
}
// Destory bus controllers
void fb_bus_controller_destroy(
struct fb_bus_controller_t **ptr_bus_controller) {
if (!ptr_bus_controller) { return; }
for (u32 loop_bus = 0; loop_bus < NUM_BUSES; loop_bus++) {
if (!ptr_bus_controller[loop_bus]) { continue; }
ptr_bus_controller[loop_bus]->flag_enable_thread = 0;
fb_stop_bus_ctrl_thread(ptr_bus_controller[loop_bus]);
}
for (u32 loop_bus = 0; loop_bus < NUM_BUSES; loop_bus++) {
if (!ptr_bus_controller[loop_bus]) { continue; }
destroy_bus_controller(ptr_bus_controller[loop_bus]);
}
kfree(ptr_bus_controller);
}
// Issue an operation for the target chip of the target bus
void fb_issue_operation(struct fb_bus_controller_t *ptr_bus_controller, u32 chip,
enum fb_dev_op_t operation, struct fb_bio_t *ptr_bio) {
while (opr_queue_put_entry(ptr_bus_controller->ptr_opr_queue[chip], operation,
ptr_bio) == -1);
}
// ---------------- Static functions: Bus contorller
// ----------------------------
// Creating an bus controller for a bus
static struct fb_bus_controller_t *create_bus_controller(
u32 num_max_entries_per_chip) {
// Allocating a pointer of bus contorller structure
struct fb_bus_controller_t *ptr_bus_controller = kmalloc(sizeof(struct fb_bus_controller_t), GFP_ATOMIC);
if (!ptr_bus_controller) {
printk(KERN_ERR
"flashbench: bus controller: Allocating bus controller failed.\n");
goto ALLOC_BUS_CTRL_FAIL;
}
// Allocating a pointer of operation queue list(for number of chips)
ptr_bus_controller->ptr_opr_queue = kmalloc(sizeof(struct fb_opr_queue_t *) * NUM_CHIPS_PER_BUS, GFP_ATOMIC);
if (!ptr_bus_controller->ptr_opr_queue) {
printk(KERN_ERR
"flashbench: bus controller: Allocating pointer of operation "
"queues failed.\n");
goto ALLOC_PTR_OPR_QUEUE_FAIL;
}
// Creating operation queues
for (u32 loop_chip = 0; loop_chip < NUM_CHIPS_PER_BUS; loop_chip++) {
ptr_bus_controller->ptr_opr_queue[loop_chip] = create_opr_queue(num_max_entries_per_chip);
if (!ptr_bus_controller->ptr_opr_queue[loop_chip]) {
printk(KERN_ERR
"flashbench: bus controller: Creating operation queues failed.\n");
goto CREATE_OPR_QUEUE_FAIL;
}
}
// Creating chip busy structures
ptr_bus_controller->chip_busies = kmalloc(sizeof(struct fb_chip_busy_t) * NUM_CHIPS_PER_BUS, GFP_ATOMIC);
if (!ptr_bus_controller->chip_busies) {
printk(KERN_ERR
"flashbench: bus controller: Allocating chip busy array failed.\n");
goto CREATE_OPR_QUEUE_FAIL;
}
// Initialize chip busy structrues
for (u32 loop_chip = 0; loop_chip < NUM_CHIPS_PER_BUS; loop_chip++) {
init_completion(&ptr_bus_controller->chip_busies[loop_chip].chip_busy);
complete(&ptr_bus_controller->chip_busies[loop_chip].chip_busy);
ptr_bus_controller->chip_busies[loop_chip].wakeup_time_in_us = 0;
ptr_bus_controller->chip_busies[loop_chip].issue_time_in_us = 0;
ptr_bus_controller->chip_busies[loop_chip].ptr_fb_bio = NULL;
}
// end of the function
return ptr_bus_controller;
CREATE_OPR_QUEUE_FAIL:
if (ptr_bus_controller->ptr_opr_queue) {
for (u32 loop_chip = 0; loop_chip < NUM_CHIPS_PER_BUS; loop_chip++) {
if (!ptr_bus_controller->ptr_opr_queue[loop_chip]) { break; }
destroy_opr_queue(ptr_bus_controller->ptr_opr_queue[loop_chip]);
}
kfree(ptr_bus_controller->ptr_opr_queue);
}
ALLOC_PTR_OPR_QUEUE_FAIL:
if (ptr_bus_controller) {
kfree(ptr_bus_controller);
}
ALLOC_BUS_CTRL_FAIL:
return NULL;
}
// Destroying the bus controller
static void destroy_bus_controller(
struct fb_bus_controller_t *ptr_bus_controller) {
if (ptr_bus_controller) {
if (ptr_bus_controller->chip_busies) {
kfree(ptr_bus_controller->chip_busies);
}
if (ptr_bus_controller->ptr_opr_queue) {
for (u32 loop_chip = 0; loop_chip < NUM_CHIPS_PER_BUS; loop_chip++) {
if (!ptr_bus_controller->ptr_opr_queue[loop_chip]) { break; }
destroy_opr_queue(ptr_bus_controller->ptr_opr_queue[loop_chip]);
}
kfree(ptr_bus_controller->ptr_opr_queue);
}
kfree(ptr_bus_controller);
}
}
// Bus controllers management thread
// Phase 1: Release bus locks whose conditions are satisfied
// Phase 2: Acquire bus locks for requests waiting for avaliable chips
static int fb_bus_ctrl_thread(void *arg) {
struct fb_bus_controller_t *ptr_bus_controller = (struct fb_bus_controller_t *)arg;
allow_signal(SIGKILL);
allow_signal(SIGSTOP);
allow_signal(SIGCONT);
ptr_bus_controller->ptr_task = current;
set_user_nice(current, -19);
set_freezable();
while ((ptr_bus_controller->flag_enable_thread) && !kthread_should_stop()) {
u32 signr = 0;
allow_signal(SIGHUP);
AGAIN:
while (signal_pending(current)) {
if (try_to_freeze()) {
goto AGAIN;
}
signr = kernel_dequeue_signal(NULL);
switch (signr) {
case SIGSTOP:
set_current_state(TASK_STOPPED);
break;
case SIGKILL:
goto FINISH;
default:
break;
}
break;
}
disallow_signal(SIGHUP);
// Phase 1: Release bus locks whose conditions are satisfied
// Get current time
u32 current_time_in_us = timer_get_timestamp_in_us();
// Release bus locks whose conditions are satisfied
for (u32 loop_chip = 0; loop_chip < NUM_CHIPS_PER_BUS; loop_chip++) {
// Get wakeup time, and check it is valid value.
u32 wakeup_time_in_us = ptr_bus_controller->chip_busies[loop_chip].wakeup_time_in_us;
if (wakeup_time_in_us > 0) {
// Check the condition
if (wakeup_time_in_us <= current_time_in_us) {
// Release lock
// If ptr_fb_bio for the chip is not null, the request count
// decreases.
// And if the request becomes zero, bio will be returned.
release_busy_lock(ptr_bus_controller, loop_chip);
}
}
}
// Phase 2: Acquire bus locks for requests waiting for avaliable chips
for (u32 loop_chip = 0; loop_chip < NUM_CHIPS_PER_BUS; loop_chip++) {
// Check whether the operation queue for the chip is empty or not,
// and the chip is available or not.
if (ptr_bus_controller->ptr_opr_queue[loop_chip]->num_entries == 0 ||
is_acquired(&ptr_bus_controller->chip_busies[loop_chip])) {
continue;
}
// Get informations of the first request for the chip
enum fb_dev_op_t operation;
struct fb_bio_t *ptr_fb_bio = NULL;
if (opr_queue_get_first(ptr_bus_controller->ptr_opr_queue[loop_chip],
&operation, &ptr_fb_bio) == -1) {
printk(KERN_ERR
"flashbench: bus controller: Operation queue should not be "
"empty.\n");
goto FINISH;
}
// Issue the request
acquire_busy_lock(ptr_bus_controller, loop_chip, operation, ptr_fb_bio);
// Remove the entry
opr_queue_remove_first(ptr_bus_controller->ptr_opr_queue[loop_chip]);
}
if (ptr_bus_controller->flag_enable_thread == 0) {
yield();
goto FINISH;
}
yield();
}
FINISH:
printk(KERN_INFO "flashbench: bus controller: End condition of thread\n");
ptr_bus_controller->flag_enable_thread = 0;
ptr_bus_controller->ptr_task = NULL;
return 0;
}
static int fb_init_bus_ctrl_thread(
struct fb_bus_controller_t *ptr_bus_controller, u32 bus) {
char thread_name[16];
sprintf(thread_name, "fb_bus_%d", bus);
ptr_bus_controller->ptr_task = kthread_run(fb_bus_ctrl_thread, ptr_bus_controller, thread_name);
int rc = IS_ERR(ptr_bus_controller->ptr_task);
if (rc < 0) {
printk(KERN_ERR
"flashbench: bus controller: Creating bus %d control task failed.\n",
bus);
return -1;
} else {
printk(KERN_INFO
"flashbench: bus controller: Bus %d controller is successfully "
"created.\n",
bus);
return 0;
}
}
static void fb_stop_bus_ctrl_thread(
struct fb_bus_controller_t *ptr_bus_controller) {
if (!ptr_bus_controller->ptr_task) { return; }
kthread_stop(ptr_bus_controller->ptr_task);
}
// ---------------- Static functions: Operation queue
// ----------------------------
// Creating an operation queue for a chip
static struct fb_opr_queue_t *create_opr_queue(u32 num_max_entries) {
// Allocating an operation queue
struct fb_opr_queue_t *ptr_opr_queue = kmalloc(sizeof(struct fb_opr_queue_t), GFP_ATOMIC);
if (!ptr_opr_queue) {
printk(KERN_ERR
"flashbench: bus controller: Allocating operation queue failed.\n");
goto ALLOC_OPR_QUEUE_FAIL;
}
// Allocating an operation list where data are actually stored
ptr_opr_queue->opr_list = kmalloc(sizeof(struct fb_operation_t) * num_max_entries, GFP_ATOMIC);
if (!ptr_opr_queue->opr_list) {
printk(KERN_ERR
"flashbench: bus controller: Allocating operation list failed.\n");
goto ALLOC_OPR_LIST_FAIL;
}
// Initialize values: operation queues are based on circular queue.
ptr_opr_queue->num_max_entries = num_max_entries;
ptr_opr_queue->num_entries = 0;
ptr_opr_queue->queue_head = 0;
ptr_opr_queue->queue_tail = 0;
// Initialize a lock for the queue
init_completion(&ptr_opr_queue->queue_lock);
complete(&ptr_opr_queue->queue_lock);
return ptr_opr_queue;
ALLOC_OPR_LIST_FAIL:
if (ptr_opr_queue) {
kfree(ptr_opr_queue);
}
ALLOC_OPR_QUEUE_FAIL:
return NULL;
}
// Destroying the operation queue
static void destroy_opr_queue(struct fb_opr_queue_t *ptr_opr_queue) {
if (!ptr_opr_queue) { return; }
if (ptr_opr_queue->opr_list) { kfree(ptr_opr_queue->opr_list); }
kfree(ptr_opr_queue);
}
// Put an entry into the target operation queue(success: 0, error: -1)
static int opr_queue_put_entry(struct fb_opr_queue_t *ptr_opr_queue,
enum fb_dev_op_t operation, struct fb_bio_t *ptr_fb_bio) {
int ret = 0;
// Acquiring the lock
wait_for_completion(&ptr_opr_queue->queue_lock);
reinit_completion(&ptr_opr_queue->queue_lock);
// Check whether the queue is full or not
// If it is full, return error for putting the request into it.
if (ptr_opr_queue->num_entries == ptr_opr_queue->num_max_entries) {
ret = -1;
goto FINISH;
}
// Storing information in the first entry of the queue
struct fb_operation_t *ptr_opr_entry = &ptr_opr_queue->opr_list[ptr_opr_queue->queue_head];
ptr_opr_entry->operation = operation;
ptr_opr_entry->ptr_fb_bio = ptr_fb_bio;
// Marching of head pointer
ptr_opr_queue->queue_head++;
if (ptr_opr_queue->queue_head == ptr_opr_queue->num_max_entries) {
ptr_opr_queue->queue_head = 0;
}
// Increasing the number of entries
ptr_opr_queue->num_entries++;
FINISH:
complete(&ptr_opr_queue->queue_lock);
return ret;
}
// Get informations of the first entry in the target operation queue(success: 0,
// error: -1)
// (The first entry means that it is the oldes entry(first come).)
static int opr_queue_get_first(struct fb_opr_queue_t *ptr_opr_queue,
enum fb_dev_op_t *ptr_operation,
struct fb_bio_t **ptr_fb_bio) {
int ret = 0;
// Acquiring the lock
wait_for_completion(&ptr_opr_queue->queue_lock);
reinit_completion(&ptr_opr_queue->queue_lock);
// Error if the queue is emptry
if (ptr_opr_queue->num_entries == 0) {
ret = -1;
goto FINISH;
}
// Get information of the tail entry
struct fb_operation_t *ptr_opr_entry = &ptr_opr_queue->opr_list[ptr_opr_queue->queue_tail];
// Storing information
*ptr_operation = ptr_opr_entry->operation;
*ptr_fb_bio = ptr_opr_entry->ptr_fb_bio;
FINISH:
complete(&ptr_opr_queue->queue_lock);
return ret;
}
// Remove informations of the first entry in the target operation queue(success:
// 0, error: -1)
// (The first entry means that it is the oldes entry(first come).)
static int opr_queue_remove_first(struct fb_opr_queue_t *ptr_opr_queue) {
int ret = 0;
// Acquiring the lock
wait_for_completion(&ptr_opr_queue->queue_lock);
reinit_completion(&ptr_opr_queue->queue_lock);
// Error if the queue is emptry
if (ptr_opr_queue->num_entries == 0) {
ret = -1;
goto FINISH;
}
// Marching of the tail pointer
ptr_opr_queue->queue_tail++;
if (ptr_opr_queue->queue_tail == ptr_opr_queue->num_max_entries) {
ptr_opr_queue->queue_tail = 0;
}
// Decrease the number of entries
ptr_opr_queue->num_entries--;
FINISH:
complete(&ptr_opr_queue->queue_lock);
return ret;
}
static void release_busy_lock(struct fb_bus_controller_t *ptr_bus_controller,
u32 chip) {
struct fb_chip_busy_t *busy = &ptr_bus_controller->chip_busies[chip];
// Reset time values
busy->wakeup_time_in_us = 0;
busy->issue_time_in_us = 0;
// Read block I/O management
if (!busy->ptr_fb_bio) { return; }
// Reduce the request count. If request count is zero, it means that the
// block I/O completes
if (dec_bio_req_count(busy->ptr_fb_bio) == 0) {
bio_endio(busy->ptr_fb_bio->bio);
vfree(busy->ptr_fb_bio);
}
busy->ptr_fb_bio = NULL;
}
static void acquire_busy_lock(struct fb_bus_controller_t *ptr_bus_controller,
u32 chip, enum fb_dev_op_t operation,
struct fb_bio_t *ptr_fb_bio) {
struct fb_chip_busy_t *busy = &ptr_bus_controller->chip_busies[chip];
// Set time values
const u32 time = timer_get_timestamp_in_us();
busy->issue_time_in_us = time;
busy->wakeup_time_in_us = time + operation_time(operation);
busy->ptr_fb_bio = ptr_fb_bio;
}
static u32 timer_get_timestamp_in_us(void) {
struct timeval tv;
do_gettimeofday(&tv);
return tv.tv_sec * 1000000 + tv.tv_usec;
}