/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool

« back to all changes in this revision

Viewing changes to pcilib/kmem.c

  • Committer: Suren A. Chilingaryan
  • Date: 2015-11-20 13:24:17 UTC
  • Revision ID: csa@suren.me-20151120132417-fzm9hulvh7rs47gb
Configure number of DMA buffers in IPEDMA and improve checking and reporting inconsistent kmem buffers while re-using

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
    if (last_flags) {
47
47
        pcilib_kmem_flags_t failed_flags = flags;
48
48
        
49
 
        if (last_flags&KMEM_FLAG_REUSED_PERSISTENT) flags&=~PCILIB_KMEM_FLAG_PERSISTENT;
50
 
        if (last_flags&KMEM_FLAG_REUSED_HW) flags&=~PCILIB_KMEM_FLAG_HARDWARE;
 
49
        if (last_flags&KMEM_FLAG_REUSED_PERSISTENT) failed_flags&=~PCILIB_KMEM_FLAG_PERSISTENT;
 
50
        if (last_flags&KMEM_FLAG_REUSED_HW) failed_flags&=~PCILIB_KMEM_FLAG_HARDWARE;
51
51
        
52
52
        if (failed_flags != flags) {
53
53
            ret = pcilib_free_kernel_buffer(ctx, kbuf, --kbuf->buf.n_blocks, failed_flags);
60
60
 
61
61
pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type_t type, size_t nmemb, size_t size, size_t alignment, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags) {
62
62
    int err = 0;
63
 
    const char *error = NULL;
 
63
    char error[256];
64
64
    
65
65
    int ret;
66
 
    int i;
 
66
    size_t i, allocated = nmemb;
67
67
    void *addr;
68
68
    
69
69
    pcilib_tristate_t reused = PCILIB_TRISTATE_NO;
92
92
        pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed");
93
93
        return NULL;
94
94
    }
95
 
    
 
95
 
96
96
    kh.type = type;
97
97
    kh.size = size;
98
98
    kh.align = alignment;
104
104
        kh.size += alignment;
105
105
    }
106
106
 
107
 
    for ( i = 0; i < nmemb; i++) {
 
107
    for ( i = 0; (i < nmemb)||(flags&PCILIB_KMEM_FLAG_MASS); i++) {
108
108
        kh.item = i;
109
109
        kh.flags = flags;
110
110
 
 
111
        if (i >= nmemb) 
 
112
            kh.flags |= KMEM_FLAG_TRY;
 
113
 
111
114
        if ((type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) {
112
115
            kh.pa = alignment + i * size;
113
116
        }
115
118
        ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh);
116
119
        if (ret) {
117
120
            kbuf->buf.n_blocks = i;
118
 
            error = "PCIDRIVER_IOC_KMEM_ALLOC ioctl have failed";
 
121
            if ((i < nmemb)||(errno != ENOENT)) {
 
122
                err = PCILIB_ERROR_FAILED;
 
123
                if (errno == EINVAL) {
 
124
                    if (kh.type != type)
 
125
                        sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu),  we have requested type %u but buffer is of type %lu", use, i, type, kh.type);
 
126
                    else if (kh.size != size)
 
127
                        sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu),  we have requested size %lu but buffer is of size %lu", use, i, size, kh.size);
 
128
                    else if (kh.align != alignment)
 
129
                        sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu),  we have requested alignment %lu but buffer is of alignment %lu", use, i, size, kh.size);
 
130
                    else if ((kh.flags&KMEM_FLAG_EXCLUSIVE) != (flags&KMEM_FLAG_EXCLUSIVE))
 
131
                        sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu),  we have requested size %s but buffer is of size %s", use, i, ((flags&KMEM_FLAG_EXCLUSIVE)?"exclusive":"non-exclusive"), ((kh.flags&KMEM_FLAG_EXCLUSIVE)?"exclusive":"non exclusive"));
 
132
                    else 
 
133
                        sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu),  unknown consistency error", use, i);
 
134
                } else if (errno == EBUSY) {
 
135
                    sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu),  reuse counter of kmem_entry is overflown", use, i);
 
136
                } else if (errno == ENOMEM) {
 
137
                    sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu),  memory allocation (%zu bytes) failed", use, i, size);
 
138
                } else {
 
139
                    sprintf(error, "Driver prevents us from re-using buffer (use 0x%x, block: %zu),  PCIDRIVER_IOC_KMEM_ALLOC ioctl have failed with errno %i", use, i, errno);
 
140
                }
 
141
            }
119
142
            break;
120
143
        }
121
144
        
 
145
        if (i >= allocated) {
 
146
            void *kbuf_new = realloc(kbuf, sizeof(pcilib_kmem_list_t) + 2 * allocated * sizeof(pcilib_kmem_addr_t));
 
147
            if (!kbuf_new) {
 
148
                kbuf->buf.n_blocks = i;
 
149
                err = PCILIB_ERROR_MEMORY;
 
150
                sprintf(error, "Failed to allocate extra %zu bytes of user-space memory for kmem structures", allocated * sizeof(pcilib_kmem_addr_t));
 
151
                break;
 
152
            }
 
153
            memset(kbuf_new + sizeof(pcilib_kmem_list_t) + allocated * sizeof(pcilib_kmem_addr_t) , 0, allocated * sizeof(pcilib_kmem_addr_t));
 
154
            kbuf = kbuf_new;
 
155
            allocated *= 2;
 
156
        }
 
157
        
122
158
        kbuf->buf.blocks[i].handle_id = kh.handle_id;
123
159
        kbuf->buf.blocks[i].pa = kh.pa;
124
160
        kbuf->buf.blocks[i].size = kh.size;
135
171
                    else*/ persistent = (kh.flags&KMEM_FLAG_REUSED_PERSISTENT)?1:0;
136
172
                } else if ((kh.flags&KMEM_FLAG_REUSED_PERSISTENT) == 0) err = PCILIB_ERROR_INVALID_STATE;
137
173
            } else if (kh.flags&KMEM_FLAG_REUSED_PERSISTENT) err = PCILIB_ERROR_INVALID_STATE;
138
 
            
 
174
            if (err) {
 
175
                kbuf->buf.n_blocks = i + 1;
 
176
                sprintf(error,  "Mistmatch in persistent modes of the re-used kmem blocks. Current buffer (use 0x%x, block: %zu) is %s, but prior ones %s", 
 
177
                    use, i, ((kh.flags&KMEM_FLAG_REUSED_PERSISTENT)?"persistent":"not persistent"), (persistent?"are":"are not"));
 
178
                break;
 
179
            }
 
180
 
139
181
            if (hardware) {
140
182
                if (hardware < 0) {
141
183
                    /*if (((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)&&(kh.flags&KMEM_FLAG_REUSED_HW)) err = PCILIB_ERROR_INVALID_STATE;
142
184
                    else*/ hardware = (kh.flags&KMEM_FLAG_REUSED_HW)?1:0;
143
185
                } else if ((kh.flags&KMEM_FLAG_REUSED_HW) == 0) err = PCILIB_ERROR_INVALID_STATE;
144
186
            } else if (kh.flags&KMEM_FLAG_REUSED_HW) err = PCILIB_ERROR_INVALID_STATE;
145
 
            
 
187
            if (err) {
 
188
                kbuf->buf.n_blocks = i + 1;
 
189
                sprintf(error,  "Mistmatch in hardware modes of the re-used kmem blocks. Current buffer (use 0x%x, block: %zu) is %s, but prior ones %s", 
 
190
                    use, i, ((kh.flags&KMEM_FLAG_REUSED_HW)?"hardware-locked":"not hardware-locked"), (hardware?"are":"are not"));
 
191
                break;
 
192
            }
146
193
        } else {
147
194
            if (!i) reused = PCILIB_TRISTATE_NO;
148
195
            else if (reused) reused = PCILIB_TRISTATE_PARTIAL;
149
 
            
150
 
            if ((persistent > 0)&&((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)) err = PCILIB_ERROR_INVALID_STATE;
151
 
            if ((hardware > 0)&&((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)) err = PCILIB_ERROR_INVALID_STATE;
 
196
 
 
197
            if ((persistent > 0)&&((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)) {
 
198
                err = PCILIB_ERROR_INVALID_STATE;
 
199
                sprintf(error, "Expecting to re-use persistent blocks, but buffer (use 0x%x, block: %zu) is not", use, i);
 
200
            }
 
201
            else if ((hardware > 0)&&((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)) {
 
202
                err = PCILIB_ERROR_INVALID_STATE;
 
203
                sprintf(error, "Expecting to re-use hardware-locked blocks, but buffer (use 0x%x, block: %zu) is not", use, i);
 
204
            }
 
205
            if (err) {
 
206
                kbuf->buf.n_blocks = i + 1;
 
207
                break;
 
208
            }
152
209
        }
153
210
        
154
 
        if (err) {
155
 
            kbuf->buf.n_blocks = i + 1;
156
 
            break;
157
 
        }
158
 
    
 
211
 
159
212
        if ((kh.align)&&((kh.type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE)) {
160
213
            if (kh.pa % kh.align) kbuf->buf.blocks[i].alignment_offset = kh.align - kh.pa % kh.align;
161
214
            kbuf->buf.blocks[i].size -= kh.align;
164
217
        addr = mmap( 0, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset, PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 );
165
218
        if ((!addr)||(addr == MAP_FAILED)) {
166
219
            kbuf->buf.n_blocks = i + 1;
167
 
            error = "Failed to mmap allocated kernel memory";
 
220
            err = PCILIB_ERROR_FAILED;
 
221
            sprintf(error, "Driver prevents us from mmaping buffer (use 0x%x, block: %zu), mmap have failed with errno %i", use, i, errno);
168
222
            break;
169
223
        }
170
224
 
171
225
        kbuf->buf.blocks[i].ua = addr;
172
 
//      if (use == PCILIB_KMEM_USE_DMA_PAGES) {
173
 
//      memset(addr, 10, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset);
174
 
//      }
175
 
        
176
226
        kbuf->buf.blocks[i].mmap_offset = kh.pa & ctx->page_mask;
177
227
    }
178
228
 
 
229
    if (err) kbuf->buf.n_blocks = i + 1;
 
230
    else kbuf->buf.n_blocks = i;
 
231
 
 
232
 
 
233
        // Check if there are more unpicked buffers
 
234
    if ((!err)&&((flags&PCILIB_KMEM_FLAG_MASS) == 0)&&(reused == PCILIB_TRISTATE_YES)&&((type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_REGION)) {
 
235
        kh.item = kbuf->buf.n_blocks;
 
236
        kh.flags = KMEM_FLAG_REUSE|KMEM_FLAG_TRY;
 
237
 
 
238
        ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh);
 
239
        if (!ret) {
 
240
            kh.flags = KMEM_FLAG_REUSE;
 
241
            ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh);
 
242
            reused = PCILIB_TRISTATE_PARTIAL;
 
243
        } else if (errno != ENOENT) {
 
244
            reused = PCILIB_TRISTATE_PARTIAL;
 
245
        }
 
246
    }
 
247
 
179
248
    pcilib_unlock_global(ctx);
180
249
 
181
250
 
183
252
    if (persistent < 0) persistent = 0;
184
253
    if (hardware < 0) hardware = 0;
185
254
 
186
 
    if (err||error) {
187
 
        pcilib_kmem_flags_t free_flags = 0;
188
 
        
189
 
            // for the sake of simplicity always clean partialy reused buffers
190
 
        if ((persistent == PCILIB_TRISTATE_PARTIAL)||((persistent <= 0)&&(flags&PCILIB_KMEM_FLAG_PERSISTENT))) {
191
 
            free_flags |= PCILIB_KMEM_FLAG_PERSISTENT;
192
 
        }
193
 
        
194
 
        if ((hardware <= 0)&&(flags&PCILIB_KMEM_FLAG_HARDWARE)) {
195
 
            free_flags |= PCILIB_KMEM_FLAG_HARDWARE;
196
 
        }
197
 
        
198
 
            // do not clean if we have reused peresistent buffers
199
 
            //  we don't care about -1, because it will be the value only if no buffers actually allocated
200
 
        if ((!persistent)||(reused != PCILIB_TRISTATE_YES)) {
201
 
            pcilib_cancel_kernel_memory(ctx, kbuf, free_flags, err?kh.flags:0);
202
 
        }
203
 
 
204
 
        if (!error) error = "Reused buffers are inconsistent";
205
 
        pcilib_error(error);
206
 
 
 
255
    if (err) {
 
256
            // do not clean if we have reused (even partially) persistent/hardware-locked buffers
 
257
        if (((persistent)||(hardware))&&(reused != PCILIB_TRISTATE_NO)) {
 
258
            pcilib_cancel_kernel_memory(ctx, kbuf, KMEM_FLAG_REUSE, 0);
 
259
        } else {
 
260
            pcilib_kmem_flags_t free_flags = 0;
 
261
            if (flags&PCILIB_KMEM_FLAG_PERSISTENT) {
 
262
                free_flags |= PCILIB_KMEM_FLAG_PERSISTENT;
 
263
            }
 
264
            if (flags&PCILIB_KMEM_FLAG_HARDWARE) {
 
265
                free_flags |= PCILIB_KMEM_FLAG_HARDWARE;
 
266
            }
 
267
                // err indicates consistensy error. The last ioctl have succeeded and we need to clean it in a special way
 
268
            pcilib_cancel_kernel_memory(ctx, kbuf, free_flags, (err == PCILIB_ERROR_INVALID_STATE)?kh.flags:0);
 
269
        }
 
270
 
 
271
        pcilib_warning("Error %i: %s", err, error);
207
272
        return NULL;
208
273
    }
209
274
    
210
275
    if (nmemb == 1) {
211
276
        memcpy(&kbuf->buf.addr, &kbuf->buf.blocks[0], sizeof(pcilib_kmem_addr_t));
212
277
    }
213
 
    
 
278
 
214
279
    kbuf->buf.reused = reused|(persistent?PCILIB_KMEM_REUSE_PERSISTENT:0)|(hardware?PCILIB_KMEM_REUSE_HARDWARE:0);
215
 
    kbuf->buf.n_blocks = nmemb;
216
 
    
 
280
 
217
281
    kbuf->prev = NULL;
218
282
    kbuf->next = ctx->kmem_list;
219
283
    if (ctx->kmem_list) ctx->kmem_list->prev = kbuf;