source: trunk/src/os2ahci/trace.c@ 122

Last change on this file since 122 was 122, checked in by Markus Thielen, 14 years ago
  • added support for /q switch (#7)
  • added cv#printf macros to support verbosity setting from command line
File size: 8.6 KB
Line 
1/******************************************************************************
2 * trace.c - code for our internal trace ring buffer
3 *
4 * Copyright (c) 2011 thi.guten Software Development
5 * Copyright (c) 2011 Mensys B.V.
6 *
7 * Authors: Christian Mueller, Markus Thielen
8 *
9 * Parts copied from/inspired by the Linux AHCI driver;
10 * those parts are (c) Linux AHCI/ATA maintainers
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#include "os2ahci.h"
28
29/* -------------------------- macros and constants ------------------------- */
30
31#define AHCI_TRACE_BUF_SIZE 0x8000U /* 32k */
32
33/* ------------------------ typedefs and structures ------------------------ */
34
35/* -------------------------- function prototypes -------------------------- */
36
37/* ------------------------ global/static variables ------------------------ */
38
39struct {
40 u32 phys_addr; /* physical address of allocated buffer */
41 u8 _far *tbuf; /* mapped address of trace buffer */
42 u16 writep; /* current write offset in buffer */
43 u16 readp; /* current read offset in buffer */
44 int empty; /* != 0 if buffer is empty */
45} ahci_trace_buf;
46
47/* ----------------------------- start of code ----------------------------- */
48
49/******************************************************************************
50 * initialize AHCI circular trace buffer
51 *
52 * NOTE: this func must be called during INIT time since it allocates
53 * a GDT selector for the trace ring buffer
54 */
55void trace_init(void)
56{
57 SEL sel = 0;
58
59 /* initialize ring buffer logic */
60 ahci_trace_buf.writep = 0;
61 ahci_trace_buf.readp = 0;
62 ahci_trace_buf.empty = 1;
63
64 if (ahci_trace_buf.phys_addr == 0) {
65 /* allocate buffer */
66 if (DevHelp_AllocPhys((ULONG) AHCI_TRACE_BUF_SIZE, MEMTYPE_ABOVE_1M,
67 &(ahci_trace_buf.phys_addr))) {
68 /* failed above 1MB, try below */
69 if (DevHelp_AllocPhys((ULONG) AHCI_TRACE_BUF_SIZE, MEMTYPE_BELOW_1M,
70 &(ahci_trace_buf.phys_addr))) {
71 /* failed, too. Give up */
72 ahci_trace_buf.phys_addr = 0;
73 cprintf("%s warning: failed to allocate %dk trace buffer\n",
74 drv_name, AHCI_TRACE_BUF_SIZE / 1024);
75 return;
76 }
77 }
78
79 /* allocate GDT selector and map our physical trace buffer to it */
80 if (DevHelp_AllocGDTSelector(&sel, 1) ||
81 DevHelp_PhysToGDTSelector(ahci_trace_buf.phys_addr,
82 AHCI_TRACE_BUF_SIZE, sel)) {
83 /* failed; free GDT selector and physical memory we allocated before */
84 if (sel) {
85 DevHelp_FreeGDTSelector(sel);
86 sel = 0;
87 }
88 DevHelp_FreePhys(ahci_trace_buf.phys_addr);
89 ahci_trace_buf.phys_addr = 0;
90 return;
91 }
92
93 /* create ring buffer address */
94 ahci_trace_buf.tbuf = (u8 _far *) ((u32) sel << 16);
95
96 }
97
98
99}
100
101/******************************************************************************
102 * cleanup trace buffer
103 *
104 * NOTE: this function is here for completeness; the trace buffer should not
105 * be deallocated and then reallocated.
106 */
107void trace_exit(void)
108{
109 /* free physical address */
110 if (ahci_trace_buf.phys_addr) {
111 DevHelp_FreePhys(ahci_trace_buf.phys_addr);
112 ahci_trace_buf.phys_addr = 0;
113 }
114
115 /* free GDT selector */
116 if (ahci_trace_buf.tbuf) {
117 DevHelp_FreeGDTSelector((SEL) ((u32) (ahci_trace_buf.tbuf) >> 16));
118 ahci_trace_buf.tbuf = NULL;
119 }
120}
121
122
123/******************************************************************************
124 * write a string to the circular trace buffer
125 *
126 * Note: This func wraps the buffer if necessary, so the caller does not
127 * need to call repeatedly until everything is written.
128 *
129 */
130void trace_write(u8 _far *s, int len)
131{
132 u16 cbw; /* bytes we can store before buffer wrap occurrs */
133 u16 cb;
134 USHORT awake_cnt;
135
136 if (ahci_trace_buf.phys_addr == 0) {
137 /* tracing not active */
138 return;
139 }
140
141 cbw = AHCI_TRACE_BUF_SIZE - ahci_trace_buf.writep;
142
143 while (len > 0) {
144 cb = cbw < len ? cbw : len;
145 if (cb && ahci_trace_buf.empty) {
146 ahci_trace_buf.empty = 0;
147 }
148 memcpy(ahci_trace_buf.tbuf + ahci_trace_buf.writep, s, cb);
149 s += cb;
150 ahci_trace_buf.writep += cb;
151 len -= cb;
152
153 /* wrap? */
154 if (ahci_trace_buf.writep >= AHCI_TRACE_BUF_SIZE) {
155 ahci_trace_buf.writep = 0;
156 cbw = AHCI_TRACE_BUF_SIZE;
157 }
158 }
159
160 /* wake up processes waiting for data from trace buffer */
161 DevHelp_ProcRun(ahci_trace_buf.phys_addr, &awake_cnt);
162
163}
164
165/******************************************************************************
166 * read data from circular trace buffer
167 * returns the number of bytes written to the caller's buffer
168 *
169 * NOTE: the caller is expected to call this func repeatedly
170 * (up to two times) until it returns 0
171 */
172u16 trace_read(void _far *buf, u16 cb_buf)
173{
174 u16 cb_avail;
175 u16 cb_read;
176
177 if (ahci_trace_buf.phys_addr == NULL || ahci_trace_buf.empty) {
178 return 0;
179 }
180
181 /* get number of bytes in buffer */
182 if (ahci_trace_buf.readp < ahci_trace_buf.writep) {
183 /* read pointer is smaller than write pointer; no wrap in between */
184 cb_avail = ahci_trace_buf.writep - ahci_trace_buf.readp;
185 } else {
186 /* read pointer is larger than (or same as) write pointer;
187 * read up to buffer end and let caller come again (if necessary)
188 */
189 cb_avail = AHCI_TRACE_BUF_SIZE - ahci_trace_buf.readp;
190 }
191
192 /* determine number of bytes we actually can return */
193 cb_read = cb_buf > cb_avail ? cb_avail : cb_buf;
194
195 memcpy(buf, ahci_trace_buf.tbuf + ahci_trace_buf.readp, cb_read);
196
197 /* update read pointer */
198 ahci_trace_buf.readp += cb_read;
199 if (ahci_trace_buf.readp >= AHCI_TRACE_BUF_SIZE) {
200 ahci_trace_buf.readp = 0;
201 }
202
203 /* check if buffer is empty now */
204 if (ahci_trace_buf.readp == ahci_trace_buf.writep) {
205 ahci_trace_buf.empty = 1;
206 }
207
208 return cb_read;
209}
210
211/******************************************************************************
212 * return number of bytes we can read from the trace buffer
213 */
214u16 trace_bytes_avail(void)
215{
216
217 if (ahci_trace_buf.empty) {
218 return 0;
219 }
220
221 if (ahci_trace_buf.readp <= ahci_trace_buf.writep) {
222 /* read pointer is smaller than write pointer; no wrap in between */
223 if (ahci_trace_buf.writep == ahci_trace_buf.readp) {
224 /* full buffer available */
225 return AHCI_TRACE_BUF_SIZE;
226 }
227 return ahci_trace_buf.writep - ahci_trace_buf.readp;
228 }
229
230 /* read pointer is larger than write pointer; buffer wrapped */
231 return AHCI_TRACE_BUF_SIZE - ahci_trace_buf.readp + ahci_trace_buf.writep;
232}
233
234
235/******************************************************************************
236 * copy trace buffer content to character device reader (request block buffer)
237 */
238u16 trace_char_dev(RP_RWV _far *rwrb)
239{
240 u8 _far *to_buf;
241 u16 cb_read = 0;
242 u16 cb;
243 USHORT mode = 0;
244
245 /* block process until data is available in the trace buffer;
246 * see also comment in ioctl.c next to DevHelp_ProcBlock
247 * concerning spin_lock and ProcBlock interaction
248 */
249 while (ahci_trace_buf.empty) {
250 spin_lock(com_lock);
251# ifndef OS2AHCI_SMP
252 com_lock = 0;
253# endif
254 if (DevHelp_ProcBlock((ULONG) ahci_trace_buf.phys_addr,
255 (ULONG) -1, 0) == WAIT_INTERRUPTED) {
256 /* user pressed Ctrl+C or whatever */
257 rwrb->NumSectors = 0;
258 return STDON;
259 }
260 spin_lock(com_lock);
261 }
262
263 /* get pointer to caller's buffer */
264 if (DevHelp_PhysToVirt(rwrb->XferAddr, rwrb->NumSectors, &to_buf, &mode)) {
265 spin_unlock(com_lock);
266 return (STATUS_DONE | STERR);
267 }
268
269 /* loop until caller's buffer is full or no more data in trace buffer */
270 do {
271 cb = trace_read(to_buf + cb_read, rwrb->NumSectors - cb_read);
272 cb_read += cb;
273 } while (cb > 0 && cb_read < rwrb->NumSectors);
274
275 spin_unlock(com_lock);
276 rwrb->NumSectors = cb_read;
277
278 return(STDON);
279}
Note: See TracBrowser for help on using the repository browser.