OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [services/] [blib/] [current/] [src/] [blib.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      blib.c
4
//
5
//      Block cache and access library  
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2003 Free Software Foundation, Inc.                        
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):     savin 
43
// Date:          2003-08-29
44
// Description: 
45
//
46
//####DESCRIPTIONEND####
47
//
48
//==========================================================================
49
 
50
#include <cyg/io/io.h>
51
#include <cyg/infra/cyg_type.h>    
52
#include <cyg/infra/cyg_ass.h>      // assertion support
53
#include <cyg/infra/diag.h>         // diagnostic output
54
#include <blib/blib.h>
55
 
56
#include <string.h>  // memcpy
57
 
58
#include <linux/rbtree.h>
59
#include <linux/list.h>
60
 
61
// --------------------------------------------------------------------
62
 
63
//#define DEBUG 1
64
 
65
#ifdef DEBUG
66
# define D(_args_) diag_printf _args_
67
#else
68
# define D(_args_) CYG_EMPTY_STATEMENT
69
#endif
70
 
71
#define ALIGN(_x_) (((_x_) + (CYGARC_ALIGNMENT-1)) & ~(CYGARC_ALIGNMENT-1))
72
 
73
#ifdef CYGIMP_BLOCK_LIB_STATISTICS
74
 
75
#define STAT_INIT(_bl_) do {    \
76
        bl->stat.n_gets   = 0;  \
77
        bl->stat.n_reads  = 0;  \
78
        bl->stat.n_writes = 0;  \
79
    } while (0)
80
 
81
#define STAT(_bl_, _group_) \
82
    ((_bl_)->stat._group_++)
83
 
84
#else // CYGIMP_BLOCK_LIB_STATISTICS
85
 
86
#define STAT_INIT(_bl_)     CYG_EMPTY_STATEMENT
87
#define STAT(_bl_, _group_) CYG_EMPTY_STATEMENT
88
 
89
#endif // not CYGIMP_BLOCK_LIB_STATISTICS
90
 
91
// --------------------------------------------------------------------
92
 
93
typedef struct {
94
    struct list_head  list_node; // list node
95
    struct rb_node    rb_node;   // red-black tree node
96
    cyg_uint32        num;       // block number
97
    cyg_bool          modified;  // is this block data modified (needs write)
98
    cyg_uint8         data[0];   // block data
99
} blib_block_t;
100
 
101
// --------------------------------------------------------------------
102
 
103
static blib_block_t *
104
rb_find_block(cyg_blib_t *bl, cyg_uint32 num)
105
{
106
    struct rb_node *node  = bl->rb_root.rb_node;
107
    blib_block_t   *block = NULL;
108
 
109
    while (NULL != node)
110
    {
111
        block = rb_entry(node, blib_block_t, rb_node);
112
 
113
        if (block->num == num)
114
            return block;
115
 
116
        node = (block->num > num) ? node->rb_left : node->rb_right;
117
    }
118
    return NULL;
119
}
120
 
121
static void
122
rb_add_block(cyg_blib_t *bl, blib_block_t *block)
123
{
124
    struct rb_node *node = bl->rb_root.rb_node;
125
 
126
    if (NULL == node)
127
    {
128
        rb_link_node(&block->rb_node, NULL, &bl->rb_root.rb_node);
129
    }
130
    else
131
    {
132
        struct rb_node **link;
133
        blib_block_t    *b = NULL;
134
 
135
        while (NULL != node)
136
        {
137
            b = rb_entry(node, blib_block_t, rb_node);
138
 
139
            CYG_ASSERTC(b->num != block->num);
140
 
141
            link = (b->num > block->num) ? &node->rb_left : &node->rb_right;
142
            node = *link;
143
        }
144
        rb_link_node(&block->rb_node, &b->rb_node, link);
145
    }
146
    rb_insert_color(&block->rb_node, &bl->rb_root);
147
}
148
 
149
static __inline__ void
150
rb_del_block(cyg_blib_t *bl, blib_block_t *block)
151
{
152
    rb_erase(&block->rb_node, &bl->rb_root);
153
}
154
 
155
// --------------------------------------------------------------------
156
 
157
static __inline__ void
158
list_add_block(cyg_blib_t *bl, blib_block_t *block)
159
{
160
    list_add(&block->list_node, &bl->list_head);
161
}
162
 
163
static __inline__ void
164
list_del_block(cyg_blib_t *bl, blib_block_t *block)
165
{
166
    list_del(&block->list_node);
167
}
168
 
169
static __inline__ blib_block_t *
170
list_get_first_block(cyg_blib_t *bl)
171
{
172
    return(list_entry(bl->list_head.next, blib_block_t, list_node));
173
}
174
 
175
static __inline__ blib_block_t *
176
list_get_last_block(cyg_blib_t *bl)
177
{
178
    return(list_entry(bl->list_head.prev, blib_block_t, list_node));
179
}
180
 
181
static void
182
list_move_block_to_head(cyg_blib_t *bl, blib_block_t *block)
183
{
184
    list_del(&block->list_node);
185
    list_add(&block->list_node, &bl->list_head);
186
}
187
 
188
// --------------------------------------------------------------------
189
 
190
static __inline__ void
191
free_block(cyg_blib_t *bl, blib_block_t *block)
192
{
193
    list_add(&block->list_node, &bl->free_list_head);
194
}
195
 
196
static __inline__ blib_block_t *
197
alloc_block(cyg_blib_t *bl)
198
{
199
    if ( !list_empty(&bl->free_list_head) )
200
    {
201
        blib_block_t *new;
202
 
203
        new = list_entry(bl->free_list_head.next, blib_block_t, list_node);
204
        list_del(bl->free_list_head.next);
205
 
206
        return new;
207
    }
208
    else
209
        return NULL;
210
}
211
 
212
static void
213
init_block_mem_pool(cyg_blib_t *bl)
214
{
215
    cyg_uint8  *block_mem;
216
    cyg_uint32  avail_mem_size, block_mem_size;
217
 
218
    INIT_LIST_HEAD(&bl->free_list_head);
219
 
220
    block_mem      = bl->mem_base;
221
    avail_mem_size = bl->mem_size;
222
    block_mem_size = ALIGN(sizeof(blib_block_t) + bl->block_size);
223
 
224
    while (avail_mem_size >= block_mem_size)
225
    {
226
        blib_block_t *block = (blib_block_t *)block_mem;
227
 
228
        list_add(&block->list_node, &bl->free_list_head);
229
 
230
        block_mem      += block_mem_size;
231
        avail_mem_size -= block_mem_size;
232
    }
233
}
234
 
235
// --------------------------------------------------------------------
236
 
237
static cyg_uint32
238
get_val_log2(cyg_uint32 val)
239
{
240
    cyg_uint32 i, log2;
241
 
242
    i = val;
243
    log2 = 0;
244
    while (0 == (i & 1))
245
    {
246
        i >>= 1;
247
        log2++;
248
    }
249
    if (i != 1)
250
        return 0;
251
    else
252
        return log2;
253
}
254
 
255
static int
256
blib_sync_block(cyg_blib_t *bl, blib_block_t *block)
257
{
258
    int ret = ENOERR;
259
 
260
    if (block->modified)
261
    {
262
        cyg_uint32 len = 1;
263
 
264
        D(("blib writting block=%d\n", block->num));
265
 
266
        STAT(bl, n_writes);
267
 
268
        ret = bl->bwrite_fn(bl->priv, (void *)block->data, &len, block->num);
269
 
270
        if (ENOERR == ret)
271
            block->modified = false;
272
    }
273
    return ret;
274
}
275
 
276
static int
277
blib_sync(cyg_blib_t *bl)
278
{
279
    struct list_head *node = bl->list_head.next;
280
    blib_block_t     *block;
281
    int ret = ENOERR;
282
 
283
    D(("blib cache sync\n"));
284
 
285
    while (node != &bl->list_head)
286
    {
287
        block = list_entry(node, blib_block_t, list_node);
288
 
289
        ret = blib_sync_block(bl, block);
290
        if (ENOERR != ret)
291
           break;
292
 
293
        node = node->next;
294
    }
295
    return ret;
296
}
297
 
298
static int
299
blib_get_block(cyg_blib_t    *bl,
300
               cyg_uint32     num,
301
               cyg_bool       read_data,
302
               blib_block_t **dblock)
303
{
304
    blib_block_t *block = NULL;
305
    int ret = ENOERR;
306
    cyg_uint32 len;
307
 
308
    D(("blib get block=%d\n", num));
309
 
310
    STAT(bl, n_gets);
311
 
312
    // first check if the most recently used block is the requested block,
313
    // this can improve performance when using byte access functions
314
    if (!list_empty(&bl->list_head))
315
    {
316
        blib_block_t *first_block = list_get_first_block(bl);
317
        if (first_block->num == num)
318
            block = first_block;
319
        else
320
            block = rb_find_block(bl, num);
321
    }
322
 
323
    if (NULL != block)
324
    {
325
        D(("blib block=%d found in cache\n", num));
326
 
327
        list_move_block_to_head(bl, block);
328
        *dblock = block;
329
        return ret;
330
    }
331
 
332
    D(("blib block=%d NOT found in cache\n", num));
333
 
334
    block = alloc_block(bl);
335
 
336
    if (NULL == block)
337
    {
338
        CYG_ASSERTC(!list_empty(&bl->list_head));
339
 
340
        block = list_get_last_block(bl);
341
 
342
        D(("blib reusing block=%d space\n", block->num));
343
 
344
        ret = blib_sync_block(bl, block);
345
        if (ENOERR != ret)
346
            return ret;
347
 
348
        list_del_block(bl, block);
349
        rb_del_block(bl, block);
350
    }
351
 
352
    block->num      = num;
353
    block->modified = false;
354
 
355
    if (read_data)
356
    {
357
        D(("blib reading block=%d\n", block->num));
358
 
359
        STAT(bl, n_reads);
360
 
361
        len = 1;
362
        ret = bl->bread_fn(bl->priv, (void *)block->data, &len, block->num);
363
        if (ENOERR != ret)
364
        {
365
            free_block(bl, block);
366
            return ret;
367
        }
368
    }
369
    rb_add_block(bl, block);
370
    list_add_block(bl, block);
371
 
372
    *dblock = block;
373
    return ret;
374
}
375
 
376
static int
377
blib_init_cache(cyg_blib_t *bl,
378
                void       *mem_base,
379
                cyg_uint32  mem_size,
380
                cyg_uint32  block_size,
381
                cyg_bool    reinit)
382
{
383
    int ret = ENOERR;
384
 
385
    if (reinit)
386
    {
387
        ret = blib_sync(bl);
388
        if (ENOERR != ret)
389
            return ret;
390
    }
391
 
392
    bl->rb_root = RB_ROOT;
393
    INIT_LIST_HEAD(&bl->list_head);
394
 
395
    bl->mem_base   = mem_base;
396
    bl->mem_size   = mem_size;
397
    bl->block_size = block_size;
398
 
399
    bl->block_size_log2 = get_val_log2(block_size);
400
    if (0 == bl->block_size_log2)
401
        return -EINVAL;
402
 
403
    init_block_mem_pool(bl);
404
 
405
    STAT_INIT(bl);
406
 
407
    return ret;
408
}
409
 
410
// --------------------------------------------------------------------
411
 
412
static int
413
io_bread(void *priv, void *buf, cyg_uint32 *len, cyg_uint32 pos)
414
{
415
    return cyg_io_bread((cyg_io_handle_t)priv, buf, len, pos);
416
}
417
 
418
static int
419
io_bwrite(void *priv, const void *buf, cyg_uint32 *len, cyg_uint32 pos)
420
{
421
    return cyg_io_bwrite((cyg_io_handle_t)priv, buf, len, pos);
422
}
423
 
424
// --------------------------------------------------------------------
425
 
426
int
427
cyg_blib_create(void               *priv_data,
428
                void               *mem_base,
429
                cyg_uint32          mem_size,
430
                cyg_uint32          block_size,
431
                cyg_blib_bread_fn   bread_fn,
432
                cyg_blib_bwrite_fn  bwrite_fn,
433
                cyg_blib_t         *bl)
434
{
435
    int ret;
436
 
437
    bl->priv      = priv_data;
438
    bl->bread_fn  = bread_fn;
439
    bl->bwrite_fn = bwrite_fn;
440
 
441
    ret = blib_init_cache(bl, mem_base, mem_size, block_size, false);
442
    return ret;
443
}
444
 
445
int
446
cyg_blib_io_create(cyg_io_handle_t     handle,
447
                   void               *mem_base,
448
                   cyg_uint32          mem_size,
449
                   cyg_uint32          block_size,
450
                   cyg_blib_t         *bl)
451
{
452
    return cyg_blib_create((void *)handle, mem_base, mem_size, block_size,
453
                           io_bread, io_bwrite, bl);
454
}
455
 
456
int
457
cyg_blib_delete(cyg_blib_t *bl)
458
{
459
    return blib_sync(bl);
460
}
461
 
462
int
463
cyg_blib_bread(cyg_blib_t *bl,
464
               void       *buf,
465
               cyg_uint32 *len,
466
               cyg_uint32  pos)
467
{
468
    blib_block_t *block;
469
    cyg_int32  size = *len;
470
    cyg_int32  bnum = pos;
471
    cyg_uint8 *bbuf = buf;
472
    Cyg_ErrNo  ret  = ENOERR;
473
 
474
    D(("blib bread block=%d len=%d buf=%p\n", pos, *len, buf));
475
 
476
    while (size > 0)
477
    {
478
        ret = blib_get_block(bl, bnum, true, &block);
479
        if (ENOERR != ret)
480
            break;
481
 
482
        memcpy((void *)bbuf, (void *)block->data, bl->block_size);
483
 
484
        bbuf += bl->block_size;
485
        bnum++;
486
        size--;
487
    }
488
    *len -= size;
489
    return ret;
490
}
491
 
492
int
493
cyg_blib_bwrite(cyg_blib_t *bl,
494
                const void *buf,
495
                cyg_uint32 *len,
496
                cyg_uint32  pos)
497
{
498
    blib_block_t *block;
499
    cyg_int32  size = *len;
500
    cyg_int32  bnum = pos;
501
    cyg_uint8 *bbuf = (cyg_uint8 * const) buf;
502
    Cyg_ErrNo  ret  = ENOERR;
503
 
504
    D(("blib bwrite block=%d len=%d buf=%p\n", pos, *len, buf));
505
 
506
    while (size > 0)
507
    {
508
        ret = blib_get_block(bl, bnum, false, &block);
509
        if (ENOERR != ret)
510
            break;
511
 
512
        memcpy((void *)block->data, (void *)bbuf, bl->block_size);
513
        block->modified = true;
514
 
515
        bbuf += bl->block_size;
516
        bnum++;
517
        size--;
518
    }
519
    *len -= size;
520
    return ret;
521
}
522
 
523
int
524
cyg_blib_read(cyg_blib_t *bl,
525
              void       *buf,
526
              cyg_uint32 *len,
527
              cyg_uint32  bnum,
528
              cyg_uint32  pos)
529
{
530
    blib_block_t *block;
531
    cyg_uint8 *bbuf = buf;
532
    cyg_int32  size = *len;
533
    Cyg_ErrNo  ret  = ENOERR;
534
 
535
    size = *len;
536
 
537
    if (pos >= bl->block_size)
538
    {
539
        bnum += pos >> bl->block_size_log2;
540
        pos   = pos & (bl->block_size - 1);
541
    }
542
 
543
    D(("blib read len=%d pos=%d bnum=%d\n", *len, pos, bnum));
544
 
545
    while (size > 0)
546
    {
547
        cyg_uint32 csize;
548
 
549
        if ((size + pos) > bl->block_size)
550
            csize = bl->block_size - pos;
551
        else
552
            csize = size;
553
 
554
        ret = blib_get_block(bl, bnum, true, &block);
555
        if (ENOERR != ret)
556
            break;
557
 
558
        memcpy((void *)bbuf, (void *)(block->data+pos), csize);
559
 
560
        bbuf += csize;
561
        size -= csize;
562
        pos   = 0;
563
        bnum++;
564
    }
565
    *len -= size;
566
    return ret;
567
}
568
 
569
int
570
cyg_blib_write(cyg_blib_t *bl,
571
               const void *buf,
572
               cyg_uint32 *len,
573
               cyg_uint32  bnum,
574
               cyg_uint32  pos)
575
{
576
    blib_block_t *block;
577
    cyg_uint8 *bbuf = (cyg_uint8 * const) buf;
578
    cyg_int32  size = *len;
579
    Cyg_ErrNo  ret  = ENOERR;
580
 
581
    size = *len;
582
 
583
    if (pos >= bl->block_size)
584
    {
585
        bnum += pos >> bl->block_size_log2;
586
        pos   = pos & (bl->block_size - 1);
587
    }
588
 
589
    D(("blib write len=%d pos=%d bnum=%d\n", *len, pos, bnum));
590
 
591
    while (size > 0)
592
    {
593
        cyg_uint32 csize;
594
 
595
        if ((size + pos) > bl->block_size)
596
            csize = bl->block_size - pos;
597
        else
598
            csize = size;
599
 
600
        if (0 == pos && csize == bl->block_size)
601
            ret = blib_get_block(bl, bnum, false, &block);
602
        else
603
            ret = blib_get_block(bl, bnum, true, &block);
604
        if (ENOERR != ret)
605
            break;
606
 
607
        memcpy((void *)(block->data+pos), (void *)bbuf, csize);
608
        block->modified = true;
609
 
610
        bbuf += csize;
611
        size -= csize;
612
        pos   = 0;
613
        bnum++;
614
    }
615
    *len -= size;
616
    return ret;
617
}
618
 
619
int
620
cyg_blib_sync(cyg_blib_t *bl)
621
{
622
    return blib_sync(bl);
623
}
624
 
625
int
626
cyg_blib_sync_block(cyg_blib_t *bl, cyg_uint32 num)
627
{
628
    blib_block_t *block = rb_find_block(bl, num);
629
 
630
    if (NULL != block)
631
        return blib_sync_block(bl, block);
632
    else
633
        return -EINVAL;
634
}
635
 
636
int
637
cyg_blib_flush(cyg_blib_t *bl)
638
{
639
    return blib_init_cache(bl, bl->mem_base,  bl->mem_size,
640
                           bl->block_size, true);
641
}
642
 
643
int
644
cyg_blib_set_block_size(cyg_blib_t *bl, cyg_uint32 block_size)
645
{
646
    return blib_init_cache(bl, bl->mem_base, bl->mem_size,
647
                           block_size, true);
648
}
649
 
650
int
651
cyg_blib_get_stat(cyg_blib_t *bl, cyg_blib_stat_t *stat)
652
{
653
#ifdef CYGIMP_BLOCK_LIB_STATISTICS
654
    *stat = bl->stat;
655
    return ENOERR;
656
#else
657
    stat->n_gets   = 0;
658
    stat->n_reads  = 0;
659
    stat->n_writes = 0;
660
    return -EINVAL;
661
#endif
662
}
663
 
664
// --------------------------------------------------------------------
665
// EOF blib.c

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.