blob: 455805198e26f89edee316355048d4b6c4fdd40c [file] [log] [blame]
Yida Wang0bf43bd2017-03-22 18:16:31 -04001/*
2 * Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
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 version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "seemp: %s: " fmt, __func__
15
16#include "seemp_logk.h"
17#include "seemp_ringbuf.h"
18#include "seemp_event_encoder.h"
19
20/*initial function no need to hold ring_lock*/
21int ringbuf_init(struct seemp_logk_dev *sdev)
22{
23 char *buf;
24 unsigned long virt_addr;
25
26 if (kmalloc_flag) {
27 sdev->ring = kmalloc(sdev->ring_sz, GFP_KERNEL);
28 if (sdev->ring == NULL) {
29 pr_err("kmalloc failed, ring_sz= %d\n", sdev->ring_sz);
30 return -ENOMEM;
31 }
32
33 buf = (char *)sdev->ring;
34
35 /*reserve kmalloc memory as pages to make them remapable*/
36 for (virt_addr = (unsigned long)buf;
37 virt_addr < (unsigned long)buf + sdev->ring_sz;
38 virt_addr += PAGE_SIZE) {
39 SetPageReserved(virt_to_page((virt_addr)));
40 }
41 } else {
42 sdev->ring = vmalloc(sdev->ring_sz);
43 if (sdev->ring == NULL) {
44 pr_err("vmalloc failed, ring_sz = %d\n", sdev->ring_sz);
45 return -ENOMEM;
46 }
47 buf = (char *)sdev->ring;
48
49 /*reserve vmalloc memory as pages to make them remapable*/
50 for (virt_addr = (unsigned long)buf;
51 virt_addr < (unsigned long)buf + sdev->ring_sz;
52 virt_addr += PAGE_SIZE) {
53 SetPageReserved(vmalloc_to_page(
54 (unsigned long *) virt_addr));
55 }
56 }
57
58 memset(sdev->ring, 0, sdev->ring_sz);
59
60 sdev->num_tot_blks = (sdev->ring_sz / BLK_SIZE);
61 sdev->num_writers = 0;
62 sdev->write_idx = 0;
63 sdev->read_idx = 0;
64
65 sdev->num_write_avail_blks = sdev->num_tot_blks;
66 /*no. of blocks available for write*/
67 sdev->num_write_in_prog_blks = 0;
68 /*no. of blocks held by writers to perform writes*/
69
70 sdev->num_read_avail_blks = 0;
71 /*no. of blocks ready for read*/
72 sdev->num_read_in_prog_blks = 0;
73 /*no. of blocks held by the reader to perform read*/
74
75 return 0;
76}
77
78void ringbuf_cleanup(struct seemp_logk_dev *sdev)
79{
80 unsigned long virt_addr;
81
82 if (kmalloc_flag) {
83 for (virt_addr = (unsigned long)sdev->ring;
84 virt_addr < (unsigned long)sdev->ring + sdev->ring_sz;
85 virt_addr += PAGE_SIZE) {
86 /*clear all pages*/
87 ClearPageReserved(virt_to_page((unsigned long *)
88 virt_addr));
89 }
90 kfree(sdev->ring);
91 } else {
92 for (virt_addr = (unsigned long)sdev->ring;
93 virt_addr < (unsigned long)sdev->ring + sdev->ring_sz;
94 virt_addr += PAGE_SIZE) {
95 /*clear all pages*/
96 ClearPageReserved(vmalloc_to_page((unsigned long *)
97 virt_addr));
98 }
99 vfree(sdev->ring);
100 }
101}
102
103struct seemp_logk_blk *ringbuf_fetch_wr_block
104 (struct seemp_logk_dev *sdev)
105{
106 struct seemp_logk_blk *blk = NULL;
107 int idx;
108
109 mutex_lock(&sdev->lock);
110 if (sdev->num_write_avail_blks == 0) {
111 idx = -1;
112 mutex_unlock(&sdev->lock);
113 return blk;
114 }
115
116 idx = sdev->write_idx;
117 sdev->write_idx = (sdev->write_idx + 1) % sdev->num_tot_blks;
118 sdev->num_write_avail_blks--;
119 sdev->num_write_in_prog_blks++;
120 sdev->num_writers++;
121
122 blk = &sdev->ring[idx];
123 blk->status = 0x0;
124
125 mutex_unlock(&sdev->lock);
126 return blk;
127}
128
129void ringbuf_finish_writer(struct seemp_logk_dev *sdev,
130 struct seemp_logk_blk *blk)
131{
132 /* Encode seemp parameters in multi-threaded mode (before mutex lock) */
133 encode_seemp_params(blk);
134
135 /*
136 * finish writing...
137 * the calling process will no longer access this block.
138 */
139 mutex_lock(&sdev->lock);
140
141 sdev->num_writers--;
142 sdev->num_write_in_prog_blks--;
143 sdev->num_read_avail_blks++;
144
145 /*wake up any readers*/
146 if (sdev->num_writers == 0)
147 wake_up_interruptible(&sdev->readers_wq);
148
149 mutex_unlock(&sdev->lock);
150}
151
152int ringbuf_count_marked(struct seemp_logk_dev *sdev)
153{
154 int i;
155 unsigned int marked;
156
157 mutex_lock(&sdev->lock);
158 for (marked = 0, i = 0; i < sdev->num_tot_blks; i++)
159 if (sdev->ring[i].status & 0x1)
160 marked++;
161 mutex_unlock(&sdev->lock);
162
163 return marked;
164}