diff options
Diffstat (limited to 'drivers/misc/cxl/file.c')
-rw-r--r-- | drivers/misc/cxl/file.c | 64 |
1 files changed, 56 insertions, 8 deletions
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index eec468f1612f..5fb9894b157f 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c | |||
@@ -293,6 +293,17 @@ int afu_mmap(struct file *file, struct vm_area_struct *vm) | |||
293 | return cxl_context_iomap(ctx, vm); | 293 | return cxl_context_iomap(ctx, vm); |
294 | } | 294 | } |
295 | 295 | ||
296 | static inline bool ctx_event_pending(struct cxl_context *ctx) | ||
297 | { | ||
298 | if (ctx->pending_irq || ctx->pending_fault || ctx->pending_afu_err) | ||
299 | return true; | ||
300 | |||
301 | if (ctx->afu_driver_ops && atomic_read(&ctx->afu_driver_events)) | ||
302 | return true; | ||
303 | |||
304 | return false; | ||
305 | } | ||
306 | |||
296 | unsigned int afu_poll(struct file *file, struct poll_table_struct *poll) | 307 | unsigned int afu_poll(struct file *file, struct poll_table_struct *poll) |
297 | { | 308 | { |
298 | struct cxl_context *ctx = file->private_data; | 309 | struct cxl_context *ctx = file->private_data; |
@@ -305,8 +316,7 @@ unsigned int afu_poll(struct file *file, struct poll_table_struct *poll) | |||
305 | pr_devel("afu_poll wait done pe: %i\n", ctx->pe); | 316 | pr_devel("afu_poll wait done pe: %i\n", ctx->pe); |
306 | 317 | ||
307 | spin_lock_irqsave(&ctx->lock, flags); | 318 | spin_lock_irqsave(&ctx->lock, flags); |
308 | if (ctx->pending_irq || ctx->pending_fault || | 319 | if (ctx_event_pending(ctx)) |
309 | ctx->pending_afu_err) | ||
310 | mask |= POLLIN | POLLRDNORM; | 320 | mask |= POLLIN | POLLRDNORM; |
311 | else if (ctx->status == CLOSED) | 321 | else if (ctx->status == CLOSED) |
312 | /* Only error on closed when there are no futher events pending | 322 | /* Only error on closed when there are no futher events pending |
@@ -319,16 +329,46 @@ unsigned int afu_poll(struct file *file, struct poll_table_struct *poll) | |||
319 | return mask; | 329 | return mask; |
320 | } | 330 | } |
321 | 331 | ||
322 | static inline int ctx_event_pending(struct cxl_context *ctx) | 332 | static ssize_t afu_driver_event_copy(struct cxl_context *ctx, |
333 | char __user *buf, | ||
334 | struct cxl_event *event, | ||
335 | struct cxl_event_afu_driver_reserved *pl) | ||
323 | { | 336 | { |
324 | return (ctx->pending_irq || ctx->pending_fault || | 337 | /* Check event */ |
325 | ctx->pending_afu_err || (ctx->status == CLOSED)); | 338 | if (!pl) { |
339 | ctx->afu_driver_ops->event_delivered(ctx, pl, -EINVAL); | ||
340 | return -EFAULT; | ||
341 | } | ||
342 | |||
343 | /* Check event size */ | ||
344 | event->header.size += pl->data_size; | ||
345 | if (event->header.size > CXL_READ_MIN_SIZE) { | ||
346 | ctx->afu_driver_ops->event_delivered(ctx, pl, -EINVAL); | ||
347 | return -EFAULT; | ||
348 | } | ||
349 | |||
350 | /* Copy event header */ | ||
351 | if (copy_to_user(buf, event, sizeof(struct cxl_event_header))) { | ||
352 | ctx->afu_driver_ops->event_delivered(ctx, pl, -EFAULT); | ||
353 | return -EFAULT; | ||
354 | } | ||
355 | |||
356 | /* Copy event data */ | ||
357 | buf += sizeof(struct cxl_event_header); | ||
358 | if (copy_to_user(buf, &pl->data, pl->data_size)) { | ||
359 | ctx->afu_driver_ops->event_delivered(ctx, pl, -EFAULT); | ||
360 | return -EFAULT; | ||
361 | } | ||
362 | |||
363 | ctx->afu_driver_ops->event_delivered(ctx, pl, 0); /* Success */ | ||
364 | return event->header.size; | ||
326 | } | 365 | } |
327 | 366 | ||
328 | ssize_t afu_read(struct file *file, char __user *buf, size_t count, | 367 | ssize_t afu_read(struct file *file, char __user *buf, size_t count, |
329 | loff_t *off) | 368 | loff_t *off) |
330 | { | 369 | { |
331 | struct cxl_context *ctx = file->private_data; | 370 | struct cxl_context *ctx = file->private_data; |
371 | struct cxl_event_afu_driver_reserved *pl = NULL; | ||
332 | struct cxl_event event; | 372 | struct cxl_event event; |
333 | unsigned long flags; | 373 | unsigned long flags; |
334 | int rc; | 374 | int rc; |
@@ -344,7 +384,7 @@ ssize_t afu_read(struct file *file, char __user *buf, size_t count, | |||
344 | 384 | ||
345 | for (;;) { | 385 | for (;;) { |
346 | prepare_to_wait(&ctx->wq, &wait, TASK_INTERRUPTIBLE); | 386 | prepare_to_wait(&ctx->wq, &wait, TASK_INTERRUPTIBLE); |
347 | if (ctx_event_pending(ctx)) | 387 | if (ctx_event_pending(ctx) || (ctx->status == CLOSED)) |
348 | break; | 388 | break; |
349 | 389 | ||
350 | if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu)) { | 390 | if (!cxl_ops->link_ok(ctx->afu->adapter, ctx->afu)) { |
@@ -374,7 +414,12 @@ ssize_t afu_read(struct file *file, char __user *buf, size_t count, | |||
374 | memset(&event, 0, sizeof(event)); | 414 | memset(&event, 0, sizeof(event)); |
375 | event.header.process_element = ctx->pe; | 415 | event.header.process_element = ctx->pe; |
376 | event.header.size = sizeof(struct cxl_event_header); | 416 | event.header.size = sizeof(struct cxl_event_header); |
377 | if (ctx->pending_irq) { | 417 | if (ctx->afu_driver_ops && atomic_read(&ctx->afu_driver_events)) { |
418 | pr_devel("afu_read delivering AFU driver specific event\n"); | ||
419 | pl = ctx->afu_driver_ops->fetch_event(ctx); | ||
420 | atomic_dec(&ctx->afu_driver_events); | ||
421 | event.header.type = CXL_EVENT_AFU_DRIVER; | ||
422 | } else if (ctx->pending_irq) { | ||
378 | pr_devel("afu_read delivering AFU interrupt\n"); | 423 | pr_devel("afu_read delivering AFU interrupt\n"); |
379 | event.header.size += sizeof(struct cxl_event_afu_interrupt); | 424 | event.header.size += sizeof(struct cxl_event_afu_interrupt); |
380 | event.header.type = CXL_EVENT_AFU_INTERRUPT; | 425 | event.header.type = CXL_EVENT_AFU_INTERRUPT; |
@@ -404,6 +449,9 @@ ssize_t afu_read(struct file *file, char __user *buf, size_t count, | |||
404 | 449 | ||
405 | spin_unlock_irqrestore(&ctx->lock, flags); | 450 | spin_unlock_irqrestore(&ctx->lock, flags); |
406 | 451 | ||
452 | if (event.header.type == CXL_EVENT_AFU_DRIVER) | ||
453 | return afu_driver_event_copy(ctx, buf, &event, pl); | ||
454 | |||
407 | if (copy_to_user(buf, &event, event.header.size)) | 455 | if (copy_to_user(buf, &event, event.header.size)) |
408 | return -EFAULT; | 456 | return -EFAULT; |
409 | return event.header.size; | 457 | return event.header.size; |
@@ -558,7 +606,7 @@ int __init cxl_file_init(void) | |||
558 | * If these change we really need to update API. Either change some | 606 | * If these change we really need to update API. Either change some |
559 | * flags or update API version number CXL_API_VERSION. | 607 | * flags or update API version number CXL_API_VERSION. |
560 | */ | 608 | */ |
561 | BUILD_BUG_ON(CXL_API_VERSION != 2); | 609 | BUILD_BUG_ON(CXL_API_VERSION != 3); |
562 | BUILD_BUG_ON(sizeof(struct cxl_ioctl_start_work) != 64); | 610 | BUILD_BUG_ON(sizeof(struct cxl_ioctl_start_work) != 64); |
563 | BUILD_BUG_ON(sizeof(struct cxl_event_header) != 8); | 611 | BUILD_BUG_ON(sizeof(struct cxl_event_header) != 8); |
564 | BUILD_BUG_ON(sizeof(struct cxl_event_afu_interrupt) != 8); | 612 | BUILD_BUG_ON(sizeof(struct cxl_event_afu_interrupt) != 8); |