42
42
#include <linux/platform_data/mailbox-bcm2708.h>
43
43
#include <linux/platform_device.h>
44
44
#include <linux/uaccess.h>
45
+ #include <linux/of.h>
45
46
#include <asm/pgtable.h>
46
47
47
48
#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
@@ -64,8 +65,10 @@ typedef struct vchiq_2835_state_struct {
64
65
} VCHIQ_2835_ARM_STATE_T ;
65
66
66
67
static void __iomem * g_regs ;
67
- static FRAGMENTS_T * g_fragments_base ;
68
- static FRAGMENTS_T * g_free_fragments ;
68
+ static unsigned int g_cache_line_size = sizeof (CACHE_LINE_SIZE );
69
+ static unsigned int g_fragments_size ;
70
+ static char * g_fragments_base ;
71
+ static char * g_free_fragments ;
69
72
static struct semaphore g_free_fragments_sema ;
70
73
static unsigned long g_virt_to_bus_offset ;
71
74
@@ -95,9 +98,13 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
95
98
96
99
g_virt_to_bus_offset = virt_to_dma (dev , (void * )0 );
97
100
101
+ (void )of_property_read_u32 (dev -> of_node , "cache-line-size" ,
102
+ & g_cache_line_size );
103
+ g_fragments_size = 2 * g_cache_line_size ;
104
+
98
105
/* Allocate space for the channels in coherent memory */
99
106
slot_mem_size = PAGE_ALIGN (TOTAL_SLOTS * VCHIQ_SLOT_SIZE );
100
- frag_mem_size = PAGE_ALIGN (sizeof ( FRAGMENTS_T ) * MAX_FRAGMENTS );
107
+ frag_mem_size = PAGE_ALIGN (g_fragments_size * MAX_FRAGMENTS );
101
108
102
109
slot_mem = dmam_alloc_coherent (dev , slot_mem_size + frag_mem_size ,
103
110
& slot_phys , GFP_KERNEL );
@@ -117,15 +124,15 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
117
124
vchiq_slot_zero -> platform_data [VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX ] =
118
125
MAX_FRAGMENTS ;
119
126
120
- g_fragments_base = (FRAGMENTS_T * )( slot_mem + slot_mem_size ) ;
127
+ g_fragments_base = (char * )slot_mem + slot_mem_size ;
121
128
slot_mem_size += frag_mem_size ;
122
129
123
130
g_free_fragments = g_fragments_base ;
124
131
for (i = 0 ; i < (MAX_FRAGMENTS - 1 ); i ++ ) {
125
- * (FRAGMENTS_T * * )& g_fragments_base [i ] =
126
- & g_fragments_base [i + 1 ];
132
+ * (char * * )& g_fragments_base [i * g_fragments_size ] =
133
+ & g_fragments_base [( i + 1 ) * g_fragments_size ];
127
134
}
128
- * (FRAGMENTS_T * * )& g_fragments_base [i ] = NULL ;
135
+ * (char * * )& g_fragments_base [i * g_fragments_size ] = NULL ;
129
136
sema_init (& g_free_fragments_sema , MAX_FRAGMENTS );
130
137
131
138
if (vchiq_init_state (state , vchiq_slot_zero , 0 ) != VCHIQ_SUCCESS )
@@ -344,7 +351,7 @@ vchiq_doorbell_irq(int irq, void *dev_id)
344
351
** cached area.
345
352
346
353
** N.B. This implementation plays slightly fast and loose with the Linux
347
- ** driver programming rules, e.g. its use of __virt_to_bus instead of
354
+ ** driver programming rules, e.g. its use of dmac_map_area instead of
348
355
** dma_map_single, but it isn't a multi-platform driver and it benefits
349
356
** from increased speed as a result.
350
357
*/
@@ -355,7 +362,6 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
355
362
{
356
363
PAGELIST_T * pagelist ;
357
364
struct page * * pages ;
358
- struct page * page ;
359
365
unsigned long * addrs ;
360
366
unsigned int num_pages , offset , i ;
361
367
char * addr , * base_addr , * next_addr ;
@@ -386,10 +392,25 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
386
392
pages = (struct page * * )(addrs + num_pages + 1 );
387
393
388
394
if (is_vmalloc_addr (buf )) {
389
- for (actual_pages = 0 ; actual_pages < num_pages ; actual_pages ++ ) {
390
- pages [actual_pages ] = vmalloc_to_page (buf + (actual_pages * PAGE_SIZE ));
395
+ int dir = (type == PAGELIST_WRITE ) ?
396
+ DMA_TO_DEVICE : DMA_FROM_DEVICE ;
397
+ unsigned long length = pagelist -> length ;
398
+ unsigned int offset = pagelist -> offset ;
399
+
400
+ for (actual_pages = 0 ; actual_pages < num_pages ;
401
+ actual_pages ++ ) {
402
+ struct page * pg = vmalloc_to_page (buf + (actual_pages *
403
+ PAGE_SIZE ));
404
+ size_t bytes = PAGE_SIZE - offset ;
405
+
406
+ if (bytes > length )
407
+ bytes = length ;
408
+ pages [actual_pages ] = pg ;
409
+ dmac_map_area (page_address (pg ) + offset , bytes , dir );
410
+ length -= bytes ;
411
+ offset = 0 ;
391
412
}
392
- * need_release = 0 ; /* do not try and release vmalloc pages */
413
+ * need_release = 0 ; /* do not try and release vmalloc pages */
393
414
} else {
394
415
down_read (& task -> mm -> mmap_sem );
395
416
actual_pages = get_user_pages (task , task -> mm ,
@@ -418,7 +439,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
418
439
actual_pages = - ENOMEM ;
419
440
return actual_pages ;
420
441
}
421
- * need_release = 1 ; /* release user pages */
442
+ * need_release = 1 ; /* release user pages */
422
443
}
423
444
424
445
pagelist -> length = count ;
@@ -451,10 +472,10 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
451
472
452
473
/* Partial cache lines (fragments) require special measures */
453
474
if ((type == PAGELIST_READ ) &&
454
- ((pagelist -> offset & (CACHE_LINE_SIZE - 1 )) ||
475
+ ((pagelist -> offset & (g_cache_line_size - 1 )) ||
455
476
((pagelist -> offset + pagelist -> length ) &
456
- (CACHE_LINE_SIZE - 1 )))) {
457
- FRAGMENTS_T * fragments ;
477
+ (g_cache_line_size - 1 )))) {
478
+ char * fragments ;
458
479
459
480
if (down_interruptible (& g_free_fragments_sema ) != 0 ) {
460
481
kfree (pagelist );
@@ -464,19 +485,15 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
464
485
WARN_ON (g_free_fragments == NULL );
465
486
466
487
down (& g_free_fragments_mutex );
467
- fragments = ( FRAGMENTS_T * ) g_free_fragments ;
488
+ fragments = g_free_fragments ;
468
489
WARN_ON (fragments == NULL );
469
- g_free_fragments = * (FRAGMENTS_T * * ) g_free_fragments ;
490
+ g_free_fragments = * (char * * ) g_free_fragments ;
470
491
up (& g_free_fragments_mutex );
471
- pagelist -> type =
472
- PAGELIST_READ_WITH_FRAGMENTS + (fragments -
473
- g_fragments_base );
492
+ pagelist -> type = PAGELIST_READ_WITH_FRAGMENTS +
493
+ (fragments - g_fragments_base ) / g_fragments_size ;
474
494
}
475
495
476
- for (page = virt_to_page (pagelist );
477
- page <= virt_to_page (addrs + num_pages - 1 ); page ++ ) {
478
- flush_dcache_page (page );
479
- }
496
+ dmac_flush_range (pagelist , addrs + num_pages );
480
497
481
498
* ppagelist = pagelist ;
482
499
@@ -502,46 +519,61 @@ free_pagelist(PAGELIST_T *pagelist, int actual)
502
519
503
520
/* Deal with any partial cache lines (fragments) */
504
521
if (pagelist -> type >= PAGELIST_READ_WITH_FRAGMENTS ) {
505
- FRAGMENTS_T * fragments = g_fragments_base +
506
- (pagelist -> type - PAGELIST_READ_WITH_FRAGMENTS );
522
+ char * fragments = g_fragments_base +
523
+ (pagelist -> type - PAGELIST_READ_WITH_FRAGMENTS ) *
524
+ g_fragments_size ;
507
525
int head_bytes , tail_bytes ;
508
- head_bytes = (CACHE_LINE_SIZE - pagelist -> offset ) &
509
- (CACHE_LINE_SIZE - 1 );
526
+ head_bytes = (g_cache_line_size - pagelist -> offset ) &
527
+ (g_cache_line_size - 1 );
510
528
tail_bytes = (pagelist -> offset + actual ) &
511
- (CACHE_LINE_SIZE - 1 );
529
+ (g_cache_line_size - 1 );
512
530
513
531
if ((actual >= 0 ) && (head_bytes != 0 )) {
514
532
if (head_bytes > actual )
515
533
head_bytes = actual ;
516
534
517
535
memcpy ((char * )page_address (pages [0 ]) +
518
536
pagelist -> offset ,
519
- fragments -> headbuf ,
537
+ fragments ,
520
538
head_bytes );
521
539
}
522
540
if ((actual >= 0 ) && (head_bytes < actual ) &&
523
541
(tail_bytes != 0 )) {
524
542
memcpy ((char * )page_address (pages [num_pages - 1 ]) +
525
543
((pagelist -> offset + actual ) &
526
- (PAGE_SIZE - 1 ) & ~(CACHE_LINE_SIZE - 1 )),
527
- fragments -> tailbuf , tail_bytes );
544
+ (PAGE_SIZE - 1 ) & ~(g_cache_line_size - 1 )),
545
+ fragments + g_cache_line_size ,
546
+ tail_bytes );
528
547
}
529
548
530
549
down (& g_free_fragments_mutex );
531
- * (FRAGMENTS_T * * ) fragments = g_free_fragments ;
550
+ * (char * * )fragments = g_free_fragments ;
532
551
g_free_fragments = fragments ;
533
552
up (& g_free_fragments_mutex );
534
553
up (& g_free_fragments_sema );
535
554
}
536
555
537
- if (* need_release ) {
538
- for (i = 0 ; i < num_pages ; i ++ ) {
539
- if (pagelist -> type != PAGELIST_WRITE )
540
- set_page_dirty (pages [i ]);
556
+ if (* need_release ) {
557
+ unsigned int length = pagelist -> length ;
558
+ unsigned int offset = pagelist -> offset ;
541
559
542
- page_cache_release (pages [i ]);
560
+ for (i = 0 ; i < num_pages ; i ++ ) {
561
+ struct page * pg = pages [i ];
562
+
563
+ if (pagelist -> type != PAGELIST_WRITE ) {
564
+ unsigned int bytes = PAGE_SIZE - offset ;
565
+
566
+ if (bytes > length )
567
+ bytes = length ;
568
+ dmac_unmap_area (page_address (pg ) + offset ,
569
+ bytes , DMA_FROM_DEVICE );
570
+ length -= bytes ;
571
+ offset = 0 ;
572
+ set_page_dirty (pg );
573
+ }
574
+ page_cache_release (pg );
543
575
}
544
- }
576
+ }
545
577
546
578
kfree (pagelist );
547
579
}
0 commit comments