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); |
