/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
1
#define _BSD_SOURCE
303 by Suren A. Chilingaryan
Initial integration of XML support
2
#define _DEFAULT_SOURCE
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
3
#define _POSIX_C_SOURCE 200809L
4
5
#include <stdio.h>
6
#include <string.h>
7
#include <strings.h>
8
#include <stdlib.h>
9
#include <stdint.h>
10
#include <fcntl.h>
11
#include <unistd.h>
12
#include <sys/ioctl.h>
13
#include <sys/mman.h>
14
#include <arpa/inet.h>
15
#include <errno.h>
16
#include <assert.h>
17
18
#include "pcilib.h"
19
#include "pci.h"
20
#include "tools.h"
21
#include "error.h"
22
#include "model.h"
23
#include "plugin.h"
24
25
pcilib_bar_t pcilib_detect_bar(pcilib_t *ctx, uintptr_t addr, size_t size) {
26
    int n = 0;
331 by Suren A. Chilingaryan
Provide pcilib_get_bar_info & pcilib_get_bar_list API calls, remove obsolete pcilib_resolve_register_address
27
    pcilib_bar_t i = ctx->reg_bar;
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
28
	
29
    const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
30
    if (!board_info) return PCILIB_BAR_INVALID;
331 by Suren A. Chilingaryan
Provide pcilib_get_bar_info & pcilib_get_bar_list API calls, remove obsolete pcilib_resolve_register_address
31
32
	// First checking the default register bar
33
    if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + size))) return i;
34
35
	// Otherwise iterate
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
36
    for (i = 0; i < PCILIB_MAX_BARS; i++) {
37
	if (board_info->bar_length[i] > 0) {
38
	    if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + size))) return i;
39
40
	    if (n) n = -1;
41
	    else n = i + 1;
42
	}
43
    }
44
45
    if (n > 0) return n - 1;
46
47
    return PCILIB_BAR_INVALID;
48
}
49
50
int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size) {
51
    const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
52
    if (!board_info) return PCILIB_ERROR_NOTFOUND;
53
    
54
    if (*bar == PCILIB_BAR_DETECT) {
55
	*bar = pcilib_detect_bar(ctx, *addr, size);
56
	if (*bar == PCILIB_BAR_INVALID) {
57
	    pcilib_error("The requested data block at address 0x%x with size %zu does not belongs to any available memory bar", *addr, size);
58
	    return PCILIB_ERROR_NOTFOUND;
59
	}
60
	if (*addr < board_info->bar_start[*bar]) 
61
	    *addr += board_info->bar_start[*bar];
62
    } else {
63
	if ((*addr < board_info->bar_start[*bar])||((board_info->bar_start[*bar] + board_info->bar_length[*bar]) < (((uintptr_t)*addr) + size))) {
64
	    if ((board_info->bar_length[*bar]) >= (((uintptr_t)*addr) + size)) {
65
		*addr += board_info->bar_start[*bar];
66
	    } else {
67
		pcilib_error("The requested data block at address 0x%x with size %zu does not belong the specified memory bar (Bar %i: starting at 0x%x with size 0x%x)", *addr, size, *bar, board_info->bar_start[*bar], board_info->bar_length[*bar]);
68
		return PCILIB_ERROR_NOTFOUND;
69
	    }
70
	}
71
    }
72
73
    *addr -= board_info->bar_start[*bar];
74
    *addr += board_info->bar_start[*bar] & ctx->page_mask;
75
76
    return 0;
77
}
78
79
void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar) {
80
    void *res;
284 by Suren A. Chilingaryan
Protect mmaping BARs as well
81
    int err, ret; 
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
82
83
    const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
84
    if (!board_info) return NULL;
284 by Suren A. Chilingaryan
Protect mmaping BARs as well
85
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
86
    if (ctx->bar_space[bar]) return ctx->bar_space[bar];
284 by Suren A. Chilingaryan
Protect mmaping BARs as well
87
285 by Suren A. Chilingaryan
Use global locks to protect kmem allocation to prevent race while allocating simmultaneously locking kmem pages and any other type of kmem
88
    err = pcilib_lock_global(ctx);
284 by Suren A. Chilingaryan
Protect mmaping BARs as well
89
    if (err) {
90
	pcilib_error("Error (%i) acquiring mmap lock", err);
91
	return NULL;
92
    }
93
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
94
    ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_PCI );
95
    if (ret) {
285 by Suren A. Chilingaryan
Use global locks to protect kmem allocation to prevent race while allocating simmultaneously locking kmem pages and any other type of kmem
96
	pcilib_unlock_global(ctx);
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
97
	pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed", bar);
98
	return NULL;
99
    }
100
101
    ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_AREA, PCIDRIVER_BAR0 + bar );
102
    if (ret) {
285 by Suren A. Chilingaryan
Use global locks to protect kmem allocation to prevent race while allocating simmultaneously locking kmem pages and any other type of kmem
103
	pcilib_unlock_global(ctx);
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
104
	pcilib_error("PCIDRIVER_IOC_MMAP_AREA ioctl have failed for bank %i", bar);
105
	return NULL;
106
    }
107
108
#ifdef PCILIB_FILE_IO
109
    file_io_handle = open("/root/data", O_RDWR);
110
    res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->file_io_handle, 0 );
111
#else
112
    res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 );
113
#endif
285 by Suren A. Chilingaryan
Use global locks to protect kmem allocation to prevent race while allocating simmultaneously locking kmem pages and any other type of kmem
114
115
    pcilib_unlock_global(ctx);
284 by Suren A. Chilingaryan
Protect mmaping BARs as well
116
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
117
    if ((!res)||(res == MAP_FAILED)) {
118
	pcilib_error("Failed to mmap data bank %i", bar);
119
	return NULL;
120
    }
121
345 by Suren A. Chilingaryan
64-bit access to BAR memory
122
    ctx->bar_space[bar] = res;
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
123
    return res;
124
}
125
126
void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data) {
127
    const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
128
    if (!board_info) return;
129
130
    if (ctx->bar_space[bar]) return;
131
    
132
    munmap(data, board_info->bar_length[bar]);
133
#ifdef PCILIB_FILE_IO
134
    close(ctx->file_io_handle);
135
#endif
136
}
137
324 by Suren A. Chilingaryan
Documentation update
138
char *pcilib_resolve_bar_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr) {
331 by Suren A. Chilingaryan
Provide pcilib_get_bar_info & pcilib_get_bar_list API calls, remove obsolete pcilib_resolve_register_address
139
    if (bar == PCILIB_BAR_DETECT) {
324 by Suren A. Chilingaryan
Documentation update
140
	bar = pcilib_detect_bar(ctx, addr, 1);
331 by Suren A. Chilingaryan
Provide pcilib_get_bar_info & pcilib_get_bar_list API calls, remove obsolete pcilib_resolve_register_address
141
	if (bar == PCILIB_BAR_INVALID) return NULL;
142
	
143
	if ((!ctx->bar_space[bar])&&(!pcilib_map_bar(ctx, bar))) {
144
	    pcilib_error("Failed to map the requested bar (%i)", bar);
145
	    return NULL;
324 by Suren A. Chilingaryan
Documentation update
146
	}
331 by Suren A. Chilingaryan
Provide pcilib_get_bar_info & pcilib_get_bar_list API calls, remove obsolete pcilib_resolve_register_address
147
148
	return ctx->bar_space[bar] + (addr - ctx->board_info.bar_start[bar]) + (ctx->board_info.bar_start[bar] & ctx->page_mask);
324 by Suren A. Chilingaryan
Documentation update
149
    } else {
331 by Suren A. Chilingaryan
Provide pcilib_get_bar_info & pcilib_get_bar_list API calls, remove obsolete pcilib_resolve_register_address
150
	if ((!ctx->bar_space[bar])&&(!pcilib_map_bar(ctx, bar))) {
151
	    pcilib_error("Failed to map the requested bar (%i)", bar);
152
	    return NULL;
324 by Suren A. Chilingaryan
Documentation update
153
	}
154
	
155
	if (addr < ctx->board_info.bar_length[bar]) {
156
	    return ctx->bar_space[bar] + addr + (ctx->board_info.bar_start[bar] & ctx->page_mask);
157
	}
158
	
159
	if ((addr >= ctx->board_info.bar_start[bar])&&(addr < (ctx->board_info.bar_start[bar] + ctx->board_info.bar_length[ctx->reg_bar]))) {
160
	    return ctx->bar_space[bar] + (addr - ctx->board_info.bar_start[bar]) + (ctx->board_info.bar_start[bar] & ctx->page_mask);
161
	}
162
    }
163
164
    return NULL;
165
}
166
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
167
int pcilib_map_register_space(pcilib_t *ctx) {
168
    int err;
169
    pcilib_register_bank_t i;
170
    
171
    if (!ctx->reg_bar_mapped)  {
172
	const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
173
	const pcilib_register_bank_description_t *banks = model_info->banks;
174
    
175
	for (i = 0; ((banks)&&(banks[i].access)); i++) {
176
//	    uint32_t buf[2];
177
	    void *reg_space;
178
            pcilib_bar_t bar = banks[i].bar;
275 by Suren A. Chilingaryan
Integration of software registers
179
            
180
            if (bar == PCILIB_BAR_NOBAR)
181
        	continue;
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
182
183
	    if (bar == PCILIB_BAR_DETECT) {
184
		uintptr_t addr = banks[0].read_addr;
185
	    
186
		err = pcilib_detect_address(ctx, &bar, &addr, 1);
187
		if (err) return err;
188
		
189
		if (!ctx->bar_space[bar]) {
190
		    reg_space = pcilib_map_bar(ctx, bar);
191
//		    pcilib_memcpy(&buf, reg_space, 8);
192
	    
193
		    if (reg_space) {
194
			ctx->bar_space[bar] = reg_space;
195
		    } else {
196
			return PCILIB_ERROR_FAILED;
197
		    }
198
		}
199
	    } else if (!ctx->bar_space[bar]) {
200
		reg_space = pcilib_map_bar(ctx, bar);
201
		if (reg_space) {
202
		    ctx->bar_space[bar] = reg_space;
203
		} else {
204
		    return PCILIB_ERROR_FAILED;
205
		}
206
//		pcilib_memcpy(&buf, reg_space, 8);
207
		
208
	    }
209
	    
210
	    if (!i) ctx->reg_bar = bar;
211
	}
212
	
213
	
214
	ctx->reg_bar_mapped = 1;
215
    }
216
    
217
    return 0;
218
}
219
324 by Suren A. Chilingaryan
Documentation update
220
221
int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr) {
222
    int err;
223
    pcilib_bar_t i;
224
    
225
    if (!ctx->data_bar_mapped) {
226
        const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
227
	if (!board_info) return PCILIB_ERROR_FAILED;
228
229
	err = pcilib_map_register_space(ctx);
230
	if (err) {
231
	    pcilib_error("Error mapping register space");
232
	    return err;
233
	}
234
	
235
	int data_bar = -1;
236
	
237
	for (i = 0; i < PCILIB_MAX_BARS; i++) {
238
	    if ((ctx->bar_space[i])||(!board_info->bar_length[i])) continue;
239
	    
240
	    if (addr) {
241
	        if (board_info->bar_start[i] == addr) {
242
		    data_bar = i;
243
		    break;
244
		}
245
	    } else {
246
		if (data_bar >= 0) {
247
		    data_bar = -1;
248
		    break;
249
		}
250
		
251
		data_bar = i;
252
	    }
253
	}
254
	    
255
256
	if (data_bar < 0) {
257
	    if (addr) pcilib_error("Unable to find the specified data space (%lx)", addr);
258
	    else pcilib_error("Unable to find the data space");
259
	    return PCILIB_ERROR_NOTFOUND;
260
	}
261
	
262
	ctx->data_bar = data_bar;
263
	
264
	if (!ctx->bar_space[data_bar]) {
265
	    char *data_space = pcilib_map_bar(ctx, data_bar);
266
	    if (data_space) ctx->bar_space[data_bar] = data_space;
267
	    else {
268
	        pcilib_error("Unable to map the data space");
269
		return PCILIB_ERROR_FAILED;
270
	    }
271
	}
272
	
273
	ctx->data_bar_mapped = 0;
274
    }
275
    
276
    return 0;
277
}
278
	
279
char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size) {
280
    int err;
281
    
282
    err = pcilib_map_data_space(ctx, addr);
283
    if (err) {
284
	pcilib_error("Failed to map the specified address space (%lx)", addr);
285
	return NULL;
286
    }
287
    
288
    if (size) *size = ctx->board_info.bar_length[ctx->data_bar];
289
    
290
    return ctx->bar_space[ctx->data_bar] + (ctx->board_info.bar_start[ctx->data_bar] & ctx->page_mask);
291
}
292
331 by Suren A. Chilingaryan
Provide pcilib_get_bar_info & pcilib_get_bar_list API calls, remove obsolete pcilib_resolve_register_address
293
const pcilib_bar_info_t *pcilib_get_bar_list(pcilib_t *ctx) {
294
    int i, bars = 0;
295
296
    const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
297
    if (!board_info) return NULL;
298
299
    for (i = 0; i < PCILIB_MAX_BARS; i++) {
300
	if (board_info->bar_length[i] > 0) {
301
	    ctx->bar_info[bars++] = (pcilib_bar_info_t) {
302
		.bar = i,
303
		.size = board_info->bar_length[i],
304
		.phys_addr =  board_info->bar_start[i],
305
		.virt_addr = ctx->bar_space[i]
306
	    };
307
	}
308
    }
309
310
    return ctx->bar_info;
311
}
312
313
const pcilib_bar_info_t *pcilib_get_bar_info(pcilib_t *ctx, pcilib_bar_t bar) {
314
    int i;
315
316
    const pcilib_bar_info_t *info = pcilib_get_bar_list(ctx);
317
    if (!info) return NULL;
318
319
    for (i = 0; info[i].size; i++) {
320
	if (info[i].bar == bar)
321
	    return &info[i];
322
    }
323
324
    return NULL;
325
}
324 by Suren A. Chilingaryan
Documentation update
326
345 by Suren A. Chilingaryan
64-bit access to BAR memory
327
int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t access, size_t n, void *buf) {
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
328
    void *data;
329
345 by Suren A. Chilingaryan
64-bit access to BAR memory
330
    pcilib_detect_address(ctx, &bar, &addr, access * n);
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
331
    data = pcilib_map_bar(ctx, bar);
332
345 by Suren A. Chilingaryan
64-bit access to BAR memory
333
    pcilib_memcpy(buf, data + addr, access, n);
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
334
335
    pcilib_unmap_bar(ctx, bar, data);
336
337
    return 0;
338
}
339
345 by Suren A. Chilingaryan
64-bit access to BAR memory
340
int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t access, size_t n, void *buf) {
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
341
    void *data;
342
345 by Suren A. Chilingaryan
64-bit access to BAR memory
343
    pcilib_detect_address(ctx, &bar, &addr, access * n);
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
344
    data = pcilib_map_bar(ctx, bar);
345
345 by Suren A. Chilingaryan
64-bit access to BAR memory
346
    pcilib_memcpy(data + addr, buf, access, n);
258 by Suren A. Chilingaryan
Split bar manipulation and fifo operations in stand-alone source and publish kmem and bar headers
347
348
    pcilib_unmap_bar(ctx, bar, data);
349
350
    return 0;
351
}
352