| .. | .. |
|---|
| 36 | 36 | #include "mpp_common.h" |
|---|
| 37 | 37 | #include "mpp_iommu.h" |
|---|
| 38 | 38 | |
|---|
| 39 | | -#define MPP_WORK_TIMEOUT_DELAY (200) |
|---|
| 40 | 39 | #define MPP_WAIT_TIMEOUT_DELAY (2000) |
|---|
| 41 | 40 | |
|---|
| 42 | 41 | /* Use 'v' as magic number */ |
|---|
| .. | .. |
|---|
| 54 | 53 | __u64 data_ptr; |
|---|
| 55 | 54 | }; |
|---|
| 56 | 55 | |
|---|
| 56 | +#define MPP_BAT_MSG_DONE (0x00000001) |
|---|
| 57 | + |
|---|
| 58 | +struct mpp_bat_msg { |
|---|
| 59 | + __u64 flag; |
|---|
| 60 | + __u32 fd; |
|---|
| 61 | + __s32 ret; |
|---|
| 62 | +}; |
|---|
| 63 | + |
|---|
| 57 | 64 | #ifdef CONFIG_ROCKCHIP_MPP_PROC_FS |
|---|
| 58 | 65 | const char *mpp_device_name[MPP_DEVICE_BUTT] = { |
|---|
| 59 | 66 | [MPP_DEVICE_VDPU1] = "VDPU1", |
|---|
| 60 | 67 | [MPP_DEVICE_VDPU2] = "VDPU2", |
|---|
| 61 | 68 | [MPP_DEVICE_VDPU1_PP] = "VDPU1_PP", |
|---|
| 62 | 69 | [MPP_DEVICE_VDPU2_PP] = "VDPU2_PP", |
|---|
| 70 | + [MPP_DEVICE_AV1DEC] = "AV1DEC", |
|---|
| 63 | 71 | [MPP_DEVICE_HEVC_DEC] = "HEVC_DEC", |
|---|
| 64 | 72 | [MPP_DEVICE_RKVDEC] = "RKVDEC", |
|---|
| 65 | 73 | [MPP_DEVICE_AVSPLUS_DEC] = "AVSPLUS_DEC", |
|---|
| 74 | + [MPP_DEVICE_RKJPEGD] = "RKJPEGD", |
|---|
| 66 | 75 | [MPP_DEVICE_RKVENC] = "RKVENC", |
|---|
| 67 | 76 | [MPP_DEVICE_VEPU1] = "VEPU1", |
|---|
| 68 | 77 | [MPP_DEVICE_VEPU2] = "VEPU2", |
|---|
| 78 | + [MPP_DEVICE_VEPU2_JPEG] = "VEPU2", |
|---|
| 69 | 79 | [MPP_DEVICE_VEPU22] = "VEPU22", |
|---|
| 70 | 80 | [MPP_DEVICE_IEP2] = "IEP2", |
|---|
| 71 | 81 | [MPP_DEVICE_VDPP] = "VDPP", |
|---|
| .. | .. |
|---|
| 87 | 97 | |
|---|
| 88 | 98 | #endif |
|---|
| 89 | 99 | |
|---|
| 90 | | -static void mpp_free_task(struct kref *ref); |
|---|
| 91 | 100 | static void mpp_attach_workqueue(struct mpp_dev *mpp, |
|---|
| 92 | 101 | struct mpp_taskqueue *queue); |
|---|
| 93 | | - |
|---|
| 94 | | -/* task queue schedule */ |
|---|
| 95 | | -static int |
|---|
| 96 | | -mpp_taskqueue_push_pending(struct mpp_taskqueue *queue, |
|---|
| 97 | | - struct mpp_task *task) |
|---|
| 98 | | -{ |
|---|
| 99 | | - if (!task->session || !task->session->mpp) |
|---|
| 100 | | - return -EINVAL; |
|---|
| 101 | | - |
|---|
| 102 | | - kref_get(&task->ref); |
|---|
| 103 | | - mutex_lock(&queue->pending_lock); |
|---|
| 104 | | - list_add_tail(&task->queue_link, &queue->pending_list); |
|---|
| 105 | | - mutex_unlock(&queue->pending_lock); |
|---|
| 106 | | - |
|---|
| 107 | | - return 0; |
|---|
| 108 | | -} |
|---|
| 109 | 102 | |
|---|
| 110 | 103 | static int |
|---|
| 111 | 104 | mpp_taskqueue_pop_pending(struct mpp_taskqueue *queue, |
|---|
| .. | .. |
|---|
| 149 | 142 | return flag; |
|---|
| 150 | 143 | } |
|---|
| 151 | 144 | |
|---|
| 152 | | -static int |
|---|
| 153 | | -mpp_taskqueue_pending_to_run(struct mpp_taskqueue *queue, |
|---|
| 154 | | - struct mpp_task *task) |
|---|
| 145 | +int mpp_taskqueue_pending_to_run(struct mpp_taskqueue *queue, struct mpp_task *task) |
|---|
| 155 | 146 | { |
|---|
| 156 | 147 | unsigned long flags; |
|---|
| 157 | 148 | |
|---|
| .. | .. |
|---|
| 231 | 222 | return 0; |
|---|
| 232 | 223 | } |
|---|
| 233 | 224 | |
|---|
| 234 | | -static int mpp_session_clear(struct mpp_dev *mpp, |
|---|
| 235 | | - struct mpp_session *session) |
|---|
| 225 | +static void task_msgs_reset(struct mpp_task_msgs *msgs) |
|---|
| 226 | +{ |
|---|
| 227 | + list_del_init(&msgs->list); |
|---|
| 228 | + |
|---|
| 229 | + msgs->flags = 0; |
|---|
| 230 | + msgs->req_cnt = 0; |
|---|
| 231 | + msgs->set_cnt = 0; |
|---|
| 232 | + msgs->poll_cnt = 0; |
|---|
| 233 | +} |
|---|
| 234 | + |
|---|
| 235 | +static void task_msgs_init(struct mpp_task_msgs *msgs, struct mpp_session *session) |
|---|
| 236 | +{ |
|---|
| 237 | + INIT_LIST_HEAD(&msgs->list); |
|---|
| 238 | + |
|---|
| 239 | + msgs->session = session; |
|---|
| 240 | + msgs->queue = NULL; |
|---|
| 241 | + msgs->task = NULL; |
|---|
| 242 | + msgs->mpp = NULL; |
|---|
| 243 | + |
|---|
| 244 | + msgs->ext_fd = -1; |
|---|
| 245 | + |
|---|
| 246 | + task_msgs_reset(msgs); |
|---|
| 247 | +} |
|---|
| 248 | + |
|---|
| 249 | +static struct mpp_task_msgs *get_task_msgs(struct mpp_session *session) |
|---|
| 250 | +{ |
|---|
| 251 | + unsigned long flags; |
|---|
| 252 | + struct mpp_task_msgs *msgs; |
|---|
| 253 | + |
|---|
| 254 | + spin_lock_irqsave(&session->lock_msgs, flags); |
|---|
| 255 | + msgs = list_first_entry_or_null(&session->list_msgs_idle, |
|---|
| 256 | + struct mpp_task_msgs, list_session); |
|---|
| 257 | + if (msgs) { |
|---|
| 258 | + list_move_tail(&msgs->list_session, &session->list_msgs); |
|---|
| 259 | + spin_unlock_irqrestore(&session->lock_msgs, flags); |
|---|
| 260 | + |
|---|
| 261 | + return msgs; |
|---|
| 262 | + } |
|---|
| 263 | + spin_unlock_irqrestore(&session->lock_msgs, flags); |
|---|
| 264 | + |
|---|
| 265 | + msgs = kzalloc(sizeof(*msgs), GFP_KERNEL); |
|---|
| 266 | + task_msgs_init(msgs, session); |
|---|
| 267 | + INIT_LIST_HEAD(&msgs->list_session); |
|---|
| 268 | + |
|---|
| 269 | + spin_lock_irqsave(&session->lock_msgs, flags); |
|---|
| 270 | + list_move_tail(&msgs->list_session, &session->list_msgs); |
|---|
| 271 | + session->msgs_cnt++; |
|---|
| 272 | + spin_unlock_irqrestore(&session->lock_msgs, flags); |
|---|
| 273 | + |
|---|
| 274 | + mpp_debug_func(DEBUG_TASK_INFO, "session %d:%d msgs cnt %d\n", |
|---|
| 275 | + session->pid, session->index, session->msgs_cnt); |
|---|
| 276 | + |
|---|
| 277 | + return msgs; |
|---|
| 278 | +} |
|---|
| 279 | + |
|---|
| 280 | +static void put_task_msgs(struct mpp_task_msgs *msgs) |
|---|
| 281 | +{ |
|---|
| 282 | + struct mpp_session *session = msgs->session; |
|---|
| 283 | + unsigned long flags; |
|---|
| 284 | + |
|---|
| 285 | + if (!session) { |
|---|
| 286 | + pr_err("invalid msgs without session\n"); |
|---|
| 287 | + return; |
|---|
| 288 | + } |
|---|
| 289 | + |
|---|
| 290 | + if (msgs->ext_fd >= 0) { |
|---|
| 291 | + fdput(msgs->f); |
|---|
| 292 | + msgs->ext_fd = -1; |
|---|
| 293 | + } |
|---|
| 294 | + |
|---|
| 295 | + task_msgs_reset(msgs); |
|---|
| 296 | + |
|---|
| 297 | + spin_lock_irqsave(&session->lock_msgs, flags); |
|---|
| 298 | + list_move_tail(&msgs->list_session, &session->list_msgs_idle); |
|---|
| 299 | + spin_unlock_irqrestore(&session->lock_msgs, flags); |
|---|
| 300 | +} |
|---|
| 301 | + |
|---|
| 302 | +static void clear_task_msgs(struct mpp_session *session) |
|---|
| 303 | +{ |
|---|
| 304 | + struct mpp_task_msgs *msgs, *n; |
|---|
| 305 | + LIST_HEAD(list_to_free); |
|---|
| 306 | + unsigned long flags; |
|---|
| 307 | + |
|---|
| 308 | + spin_lock_irqsave(&session->lock_msgs, flags); |
|---|
| 309 | + |
|---|
| 310 | + list_for_each_entry_safe(msgs, n, &session->list_msgs, list_session) |
|---|
| 311 | + list_move_tail(&msgs->list_session, &list_to_free); |
|---|
| 312 | + |
|---|
| 313 | + list_for_each_entry_safe(msgs, n, &session->list_msgs_idle, list_session) |
|---|
| 314 | + list_move_tail(&msgs->list_session, &list_to_free); |
|---|
| 315 | + |
|---|
| 316 | + spin_unlock_irqrestore(&session->lock_msgs, flags); |
|---|
| 317 | + |
|---|
| 318 | + list_for_each_entry_safe(msgs, n, &list_to_free, list_session) |
|---|
| 319 | + kfree(msgs); |
|---|
| 320 | +} |
|---|
| 321 | + |
|---|
| 322 | +static void mpp_session_clear_pending(struct mpp_session *session) |
|---|
| 236 | 323 | { |
|---|
| 237 | 324 | struct mpp_task *task = NULL, *n; |
|---|
| 238 | | - |
|---|
| 239 | | - /* clear session done list */ |
|---|
| 240 | | - mutex_lock(&session->done_lock); |
|---|
| 241 | | - list_for_each_entry_safe(task, n, |
|---|
| 242 | | - &session->done_list, |
|---|
| 243 | | - done_link) { |
|---|
| 244 | | - list_del_init(&task->done_link); |
|---|
| 245 | | - kref_put(&task->ref, mpp_free_task); |
|---|
| 246 | | - } |
|---|
| 247 | | - mutex_unlock(&session->done_lock); |
|---|
| 248 | 325 | |
|---|
| 249 | 326 | /* clear session pending list */ |
|---|
| 250 | 327 | mutex_lock(&session->pending_lock); |
|---|
| .. | .. |
|---|
| 257 | 334 | kref_put(&task->ref, mpp_free_task); |
|---|
| 258 | 335 | } |
|---|
| 259 | 336 | mutex_unlock(&session->pending_lock); |
|---|
| 337 | +} |
|---|
| 260 | 338 | |
|---|
| 261 | | - return 0; |
|---|
| 339 | +void mpp_session_cleanup_detach(struct mpp_taskqueue *queue, struct kthread_work *work) |
|---|
| 340 | +{ |
|---|
| 341 | + struct mpp_session *session, *n; |
|---|
| 342 | + |
|---|
| 343 | + if (!atomic_read(&queue->detach_count)) |
|---|
| 344 | + return; |
|---|
| 345 | + |
|---|
| 346 | + mutex_lock(&queue->session_lock); |
|---|
| 347 | + list_for_each_entry_safe(session, n, &queue->session_detach, session_link) { |
|---|
| 348 | + s32 task_count = atomic_read(&session->task_count); |
|---|
| 349 | + |
|---|
| 350 | + if (!task_count) { |
|---|
| 351 | + list_del_init(&session->session_link); |
|---|
| 352 | + atomic_dec(&queue->detach_count); |
|---|
| 353 | + } |
|---|
| 354 | + |
|---|
| 355 | + mutex_unlock(&queue->session_lock); |
|---|
| 356 | + |
|---|
| 357 | + if (task_count) { |
|---|
| 358 | + mpp_dbg_session("session %d:%d task not finished %d\n", |
|---|
| 359 | + session->pid, session->index, |
|---|
| 360 | + atomic_read(&queue->detach_count)); |
|---|
| 361 | + |
|---|
| 362 | + mpp_session_clear_pending(session); |
|---|
| 363 | + } else { |
|---|
| 364 | + mpp_dbg_session("queue detach %d\n", |
|---|
| 365 | + atomic_read(&queue->detach_count)); |
|---|
| 366 | + |
|---|
| 367 | + mpp_session_deinit(session); |
|---|
| 368 | + } |
|---|
| 369 | + |
|---|
| 370 | + mutex_lock(&queue->session_lock); |
|---|
| 371 | + } |
|---|
| 372 | + mutex_unlock(&queue->session_lock); |
|---|
| 373 | + |
|---|
| 374 | + if (atomic_read(&queue->detach_count)) { |
|---|
| 375 | + mpp_dbg_session("queue detach %d again\n", |
|---|
| 376 | + atomic_read(&queue->detach_count)); |
|---|
| 377 | + |
|---|
| 378 | + kthread_queue_work(&queue->worker, work); |
|---|
| 379 | + } |
|---|
| 262 | 380 | } |
|---|
| 263 | 381 | |
|---|
| 264 | 382 | static struct mpp_session *mpp_session_init(void) |
|---|
| .. | .. |
|---|
| 271 | 389 | session->pid = current->pid; |
|---|
| 272 | 390 | |
|---|
| 273 | 391 | mutex_init(&session->pending_lock); |
|---|
| 274 | | - mutex_init(&session->done_lock); |
|---|
| 275 | 392 | INIT_LIST_HEAD(&session->pending_list); |
|---|
| 276 | | - INIT_LIST_HEAD(&session->done_list); |
|---|
| 277 | 393 | INIT_LIST_HEAD(&session->service_link); |
|---|
| 278 | 394 | INIT_LIST_HEAD(&session->session_link); |
|---|
| 279 | 395 | |
|---|
| 280 | | - init_waitqueue_head(&session->wait); |
|---|
| 281 | 396 | atomic_set(&session->task_count, 0); |
|---|
| 282 | 397 | atomic_set(&session->release_request, 0); |
|---|
| 398 | + |
|---|
| 399 | + INIT_LIST_HEAD(&session->list_msgs); |
|---|
| 400 | + INIT_LIST_HEAD(&session->list_msgs_idle); |
|---|
| 401 | + spin_lock_init(&session->lock_msgs); |
|---|
| 283 | 402 | |
|---|
| 284 | 403 | mpp_dbg_session("session %p init\n", session); |
|---|
| 285 | 404 | return session; |
|---|
| .. | .. |
|---|
| 293 | 412 | if (mpp->dev_ops->free_session) |
|---|
| 294 | 413 | mpp->dev_ops->free_session(session); |
|---|
| 295 | 414 | |
|---|
| 296 | | - mpp_session_clear(mpp, session); |
|---|
| 415 | + mpp_session_clear_pending(session); |
|---|
| 297 | 416 | |
|---|
| 298 | 417 | if (session->dma) { |
|---|
| 299 | 418 | mpp_iommu_down_read(mpp->iommu_info); |
|---|
| .. | .. |
|---|
| 314 | 433 | list_del_init(&session->session_link); |
|---|
| 315 | 434 | } |
|---|
| 316 | 435 | |
|---|
| 317 | | -int mpp_session_deinit(struct mpp_session *session) |
|---|
| 436 | +void mpp_session_deinit(struct mpp_session *session) |
|---|
| 318 | 437 | { |
|---|
| 319 | | - u32 task_count = atomic_read(&session->task_count); |
|---|
| 320 | | - |
|---|
| 321 | | - mpp_dbg_session("session %p:%d task %d release\n", |
|---|
| 322 | | - session, session->index, task_count); |
|---|
| 323 | | - if (task_count) |
|---|
| 324 | | - return -1; |
|---|
| 438 | + mpp_dbg_session("session %d:%d task %d deinit\n", session->pid, |
|---|
| 439 | + session->index, atomic_read(&session->task_count)); |
|---|
| 325 | 440 | |
|---|
| 326 | 441 | if (likely(session->deinit)) |
|---|
| 327 | 442 | session->deinit(session); |
|---|
| 328 | 443 | else |
|---|
| 329 | 444 | pr_err("invalid NULL session deinit function\n"); |
|---|
| 330 | 445 | |
|---|
| 331 | | - mpp_dbg_session("session %p:%d deinit\n", session, session->index); |
|---|
| 446 | + clear_task_msgs(session); |
|---|
| 332 | 447 | |
|---|
| 333 | 448 | kfree(session); |
|---|
| 334 | | - return 0; |
|---|
| 335 | 449 | } |
|---|
| 336 | 450 | |
|---|
| 337 | 451 | static void mpp_session_attach_workqueue(struct mpp_session *session, |
|---|
| 338 | 452 | struct mpp_taskqueue *queue) |
|---|
| 339 | 453 | { |
|---|
| 340 | | - mpp_dbg_session("session %p:%d attach\n", session, session->index); |
|---|
| 454 | + mpp_dbg_session("session %d:%d attach\n", session->pid, session->index); |
|---|
| 341 | 455 | mutex_lock(&queue->session_lock); |
|---|
| 342 | 456 | list_add_tail(&session->session_link, &queue->session_attach); |
|---|
| 343 | 457 | mutex_unlock(&queue->session_lock); |
|---|
| .. | .. |
|---|
| 351 | 465 | if (!session->mpp || !session->mpp->queue) |
|---|
| 352 | 466 | return; |
|---|
| 353 | 467 | |
|---|
| 354 | | - mpp_dbg_session("session %p:%d detach\n", session, session->index); |
|---|
| 468 | + mpp_dbg_session("session %d:%d detach\n", session->pid, session->index); |
|---|
| 355 | 469 | mpp = session->mpp; |
|---|
| 356 | 470 | queue = mpp->queue; |
|---|
| 357 | 471 | |
|---|
| 358 | 472 | mutex_lock(&queue->session_lock); |
|---|
| 359 | 473 | list_del_init(&session->session_link); |
|---|
| 360 | 474 | list_add_tail(&session->session_link, &queue->session_detach); |
|---|
| 361 | | - queue->detach_count++; |
|---|
| 475 | + atomic_inc(&queue->detach_count); |
|---|
| 362 | 476 | mutex_unlock(&queue->session_lock); |
|---|
| 363 | 477 | |
|---|
| 364 | 478 | mpp_taskqueue_trigger_work(mpp); |
|---|
| .. | .. |
|---|
| 370 | 484 | { |
|---|
| 371 | 485 | kref_get(&task->ref); |
|---|
| 372 | 486 | mutex_lock(&session->pending_lock); |
|---|
| 487 | + if (session->srv->timing_en) { |
|---|
| 488 | + task->on_pending = ktime_get(); |
|---|
| 489 | + set_bit(TASK_TIMING_PENDING, &task->state); |
|---|
| 490 | + } |
|---|
| 373 | 491 | list_add_tail(&task->pending_link, &session->pending_list); |
|---|
| 374 | 492 | mutex_unlock(&session->pending_lock); |
|---|
| 375 | 493 | |
|---|
| .. | .. |
|---|
| 402 | 520 | return task; |
|---|
| 403 | 521 | } |
|---|
| 404 | 522 | |
|---|
| 405 | | -static int mpp_session_push_done(struct mpp_session *session, |
|---|
| 406 | | - struct mpp_task *task) |
|---|
| 407 | | -{ |
|---|
| 408 | | - kref_get(&task->ref); |
|---|
| 409 | | - mutex_lock(&session->done_lock); |
|---|
| 410 | | - list_add_tail(&task->done_link, &session->done_list); |
|---|
| 411 | | - mutex_unlock(&session->done_lock); |
|---|
| 412 | | - |
|---|
| 413 | | - return 0; |
|---|
| 414 | | -} |
|---|
| 415 | | - |
|---|
| 416 | | -static int mpp_session_pop_done(struct mpp_session *session, |
|---|
| 417 | | - struct mpp_task *task) |
|---|
| 418 | | -{ |
|---|
| 419 | | - mutex_lock(&session->done_lock); |
|---|
| 420 | | - list_del_init(&task->done_link); |
|---|
| 421 | | - mutex_unlock(&session->done_lock); |
|---|
| 422 | | - set_bit(TASK_STATE_DONE, &task->state); |
|---|
| 423 | | - kref_put(&task->ref, mpp_free_task); |
|---|
| 424 | | - |
|---|
| 425 | | - return 0; |
|---|
| 426 | | -} |
|---|
| 427 | | - |
|---|
| 428 | | -static void mpp_free_task(struct kref *ref) |
|---|
| 523 | +void mpp_free_task(struct kref *ref) |
|---|
| 429 | 524 | { |
|---|
| 430 | 525 | struct mpp_dev *mpp; |
|---|
| 431 | 526 | struct mpp_session *session; |
|---|
| .. | .. |
|---|
| 437 | 532 | } |
|---|
| 438 | 533 | session = task->session; |
|---|
| 439 | 534 | |
|---|
| 440 | | - mpp_debug_func(DEBUG_TASK_INFO, |
|---|
| 441 | | - "session=%p, task=%p, state=0x%lx, abort_request=%d\n", |
|---|
| 442 | | - session, task, task->state, |
|---|
| 535 | + mpp_debug_func(DEBUG_TASK_INFO, "task %d:%d free state 0x%lx abort %d\n", |
|---|
| 536 | + session->index, task->task_id, task->state, |
|---|
| 443 | 537 | atomic_read(&task->abort_request)); |
|---|
| 444 | | - if (!session->mpp) { |
|---|
| 445 | | - mpp_err("session %p, session->mpp is null.\n", session); |
|---|
| 446 | | - return; |
|---|
| 447 | | - } |
|---|
| 448 | | - mpp = session->mpp; |
|---|
| 449 | 538 | |
|---|
| 539 | + mpp = mpp_get_task_used_device(task, session); |
|---|
| 450 | 540 | if (mpp->dev_ops->free_task) |
|---|
| 451 | 541 | mpp->dev_ops->free_task(session, task); |
|---|
| 542 | + |
|---|
| 452 | 543 | /* Decrease reference count */ |
|---|
| 453 | 544 | atomic_dec(&session->task_count); |
|---|
| 454 | 545 | atomic_dec(&mpp->task_count); |
|---|
| .. | .. |
|---|
| 462 | 553 | struct mpp_task, |
|---|
| 463 | 554 | timeout_work); |
|---|
| 464 | 555 | |
|---|
| 465 | | - if (!test_bit(TASK_STATE_START, &task->state)) { |
|---|
| 466 | | - mpp_err("task has not start\n"); |
|---|
| 467 | | - schedule_delayed_work(&task->timeout_work, |
|---|
| 468 | | - msecs_to_jiffies(MPP_WORK_TIMEOUT_DELAY)); |
|---|
| 469 | | - return; |
|---|
| 470 | | - } |
|---|
| 471 | | - |
|---|
| 472 | | - mpp_err("task %p processing time out!\n", task); |
|---|
| 473 | | - if (!task->session) { |
|---|
| 474 | | - mpp_err("task %p, task->session is null.\n", task); |
|---|
| 475 | | - return; |
|---|
| 476 | | - } |
|---|
| 477 | | - session = task->session; |
|---|
| 478 | | - |
|---|
| 479 | | - if (!session->mpp) { |
|---|
| 480 | | - mpp_err("session %p, session->mpp is null.\n", session); |
|---|
| 481 | | - return; |
|---|
| 482 | | - } |
|---|
| 483 | | - mpp = session->mpp; |
|---|
| 484 | | - |
|---|
| 485 | | - synchronize_hardirq(mpp->irq); |
|---|
| 486 | | - |
|---|
| 487 | 556 | if (test_and_set_bit(TASK_STATE_HANDLE, &task->state)) { |
|---|
| 488 | 557 | mpp_err("task has been handled\n"); |
|---|
| 489 | 558 | return; |
|---|
| 490 | 559 | } |
|---|
| 560 | + |
|---|
| 561 | + if (!task->session) { |
|---|
| 562 | + mpp_err("task %p, task->session is null.\n", task); |
|---|
| 563 | + return; |
|---|
| 564 | + } |
|---|
| 565 | + |
|---|
| 566 | + session = task->session; |
|---|
| 567 | + mpp_err("task %d:%d:%d processing time out!\n", session->pid, |
|---|
| 568 | + session->index, task->task_id); |
|---|
| 569 | + |
|---|
| 570 | + if (!session->mpp) { |
|---|
| 571 | + mpp_err("session %d:%d, session mpp is null.\n", session->pid, |
|---|
| 572 | + session->index); |
|---|
| 573 | + return; |
|---|
| 574 | + } |
|---|
| 575 | + |
|---|
| 576 | + mpp_task_dump_timing(task, ktime_us_delta(ktime_get(), task->on_create)); |
|---|
| 577 | + |
|---|
| 578 | + mpp = mpp_get_task_used_device(task, session); |
|---|
| 579 | + |
|---|
| 580 | + /* disable core irq */ |
|---|
| 581 | + disable_irq(mpp->irq); |
|---|
| 582 | + /* disable mmu irq */ |
|---|
| 583 | + if (mpp->iommu_info && mpp->iommu_info->got_irq) |
|---|
| 584 | + disable_irq(mpp->iommu_info->irq); |
|---|
| 491 | 585 | |
|---|
| 492 | 586 | /* hardware maybe dead, reset it */ |
|---|
| 493 | 587 | mpp_reset_up_read(mpp->reset_group); |
|---|
| 494 | 588 | mpp_dev_reset(mpp); |
|---|
| 495 | 589 | mpp_power_off(mpp); |
|---|
| 496 | 590 | |
|---|
| 497 | | - mpp_session_push_done(session, task); |
|---|
| 591 | + set_bit(TASK_STATE_TIMEOUT, &task->state); |
|---|
| 592 | + set_bit(TASK_STATE_DONE, &task->state); |
|---|
| 498 | 593 | /* Wake up the GET thread */ |
|---|
| 499 | | - wake_up(&session->wait); |
|---|
| 594 | + wake_up(&task->wait); |
|---|
| 500 | 595 | |
|---|
| 501 | 596 | /* remove task from taskqueue running list */ |
|---|
| 502 | | - set_bit(TASK_STATE_TIMEOUT, &task->state); |
|---|
| 503 | 597 | mpp_taskqueue_pop_running(mpp->queue, task); |
|---|
| 598 | + |
|---|
| 599 | + /* enable core irq */ |
|---|
| 600 | + enable_irq(mpp->irq); |
|---|
| 601 | + /* enable mmu irq */ |
|---|
| 602 | + if (mpp->iommu_info && mpp->iommu_info->got_irq) |
|---|
| 603 | + enable_irq(mpp->iommu_info->irq); |
|---|
| 604 | + |
|---|
| 605 | + mpp_taskqueue_trigger_work(mpp); |
|---|
| 504 | 606 | } |
|---|
| 505 | 607 | |
|---|
| 506 | 608 | static int mpp_process_task_default(struct mpp_session *session, |
|---|
| 507 | | - struct mpp_task_msgs *msgs) |
|---|
| 609 | + struct mpp_task_msgs *msgs) |
|---|
| 508 | 610 | { |
|---|
| 509 | 611 | struct mpp_task *task = NULL; |
|---|
| 510 | 612 | struct mpp_dev *mpp = session->mpp; |
|---|
| 613 | + u32 timing_en; |
|---|
| 614 | + ktime_t on_create; |
|---|
| 511 | 615 | |
|---|
| 512 | 616 | if (unlikely(!mpp)) { |
|---|
| 513 | | - mpp_err("pid %d clinet %d found invalid process function\n", |
|---|
| 617 | + mpp_err("pid %d client %d found invalid process function\n", |
|---|
| 514 | 618 | session->pid, session->device_type); |
|---|
| 515 | 619 | return -EINVAL; |
|---|
| 516 | 620 | } |
|---|
| 621 | + |
|---|
| 622 | + timing_en = session->srv->timing_en; |
|---|
| 623 | + if (timing_en) |
|---|
| 624 | + on_create = ktime_get(); |
|---|
| 517 | 625 | |
|---|
| 518 | 626 | if (mpp->dev_ops->alloc_task) |
|---|
| 519 | 627 | task = mpp->dev_ops->alloc_task(session, msgs); |
|---|
| .. | .. |
|---|
| 521 | 629 | mpp_err("alloc_task failed.\n"); |
|---|
| 522 | 630 | return -ENOMEM; |
|---|
| 523 | 631 | } |
|---|
| 632 | + |
|---|
| 633 | + if (timing_en) { |
|---|
| 634 | + task->on_create_end = ktime_get(); |
|---|
| 635 | + task->on_create = on_create; |
|---|
| 636 | + set_bit(TASK_TIMING_CREATE_END, &task->state); |
|---|
| 637 | + set_bit(TASK_TIMING_CREATE, &task->state); |
|---|
| 638 | + } |
|---|
| 639 | + |
|---|
| 640 | + /* ensure current device */ |
|---|
| 641 | + mpp = mpp_get_task_used_device(task, session); |
|---|
| 642 | + |
|---|
| 524 | 643 | kref_init(&task->ref); |
|---|
| 644 | + init_waitqueue_head(&task->wait); |
|---|
| 525 | 645 | atomic_set(&task->abort_request, 0); |
|---|
| 526 | 646 | task->task_index = atomic_fetch_inc(&mpp->task_index); |
|---|
| 647 | + task->task_id = atomic_fetch_inc(&mpp->queue->task_id); |
|---|
| 527 | 648 | INIT_DELAYED_WORK(&task->timeout_work, mpp_task_timeout_work); |
|---|
| 528 | 649 | |
|---|
| 529 | 650 | if (mpp->auto_freq_en && mpp->hw_ops->get_freq) |
|---|
| 530 | 651 | mpp->hw_ops->get_freq(mpp, task); |
|---|
| 652 | + |
|---|
| 653 | + msgs->queue = mpp->queue; |
|---|
| 654 | + msgs->task = task; |
|---|
| 655 | + msgs->mpp = mpp; |
|---|
| 531 | 656 | |
|---|
| 532 | 657 | /* |
|---|
| 533 | 658 | * Push task to session should be in front of push task to queue. |
|---|
| .. | .. |
|---|
| 537 | 662 | */ |
|---|
| 538 | 663 | atomic_inc(&session->task_count); |
|---|
| 539 | 664 | mpp_session_push_pending(session, task); |
|---|
| 540 | | - /* push current task to queue */ |
|---|
| 541 | | - atomic_inc(&mpp->task_count); |
|---|
| 542 | | - mpp_taskqueue_push_pending(mpp->queue, task); |
|---|
| 543 | | - set_bit(TASK_STATE_PENDING, &task->state); |
|---|
| 544 | | - /* trigger current queue to run task */ |
|---|
| 545 | | - mpp_taskqueue_trigger_work(mpp); |
|---|
| 546 | | - kref_put(&task->ref, mpp_free_task); |
|---|
| 547 | 665 | |
|---|
| 548 | 666 | return 0; |
|---|
| 549 | 667 | } |
|---|
| .. | .. |
|---|
| 628 | 746 | mpp_iommu_down_write(mpp->iommu_info); |
|---|
| 629 | 747 | mpp_reset_down_write(mpp->reset_group); |
|---|
| 630 | 748 | atomic_set(&mpp->reset_request, 0); |
|---|
| 631 | | - rockchip_save_qos(mpp->dev); |
|---|
| 749 | + |
|---|
| 632 | 750 | if (mpp->hw_ops->reset) |
|---|
| 633 | 751 | mpp->hw_ops->reset(mpp); |
|---|
| 634 | | - rockchip_restore_qos(mpp->dev); |
|---|
| 635 | 752 | |
|---|
| 636 | 753 | /* Note: if the domain does not change, iommu attach will be return |
|---|
| 637 | 754 | * as an empty operation. Therefore, force to close and then open, |
|---|
| .. | .. |
|---|
| 647 | 764 | return 0; |
|---|
| 648 | 765 | } |
|---|
| 649 | 766 | |
|---|
| 767 | +void mpp_task_run_begin(struct mpp_task *task, u32 timing_en, u32 timeout) |
|---|
| 768 | +{ |
|---|
| 769 | + preempt_disable(); |
|---|
| 770 | + |
|---|
| 771 | + set_bit(TASK_STATE_START, &task->state); |
|---|
| 772 | + |
|---|
| 773 | + mpp_time_record(task); |
|---|
| 774 | + schedule_delayed_work(&task->timeout_work, msecs_to_jiffies(timeout)); |
|---|
| 775 | + |
|---|
| 776 | + if (timing_en) { |
|---|
| 777 | + task->on_sched_timeout = ktime_get(); |
|---|
| 778 | + set_bit(TASK_TIMING_TO_SCHED, &task->state); |
|---|
| 779 | + } |
|---|
| 780 | +} |
|---|
| 781 | + |
|---|
| 782 | +void mpp_task_run_end(struct mpp_task *task, u32 timing_en) |
|---|
| 783 | +{ |
|---|
| 784 | + if (timing_en) { |
|---|
| 785 | + task->on_run_end = ktime_get(); |
|---|
| 786 | + set_bit(TASK_TIMING_RUN_END, &task->state); |
|---|
| 787 | + } |
|---|
| 788 | + |
|---|
| 789 | +#ifdef MODULE |
|---|
| 790 | + preempt_enable(); |
|---|
| 791 | +#else |
|---|
| 792 | + preempt_enable_no_resched(); |
|---|
| 793 | +#endif |
|---|
| 794 | +} |
|---|
| 795 | + |
|---|
| 650 | 796 | static int mpp_task_run(struct mpp_dev *mpp, |
|---|
| 651 | 797 | struct mpp_task *task) |
|---|
| 652 | 798 | { |
|---|
| 653 | 799 | int ret; |
|---|
| 800 | + u32 timing_en; |
|---|
| 654 | 801 | |
|---|
| 655 | 802 | mpp_debug_enter(); |
|---|
| 803 | + |
|---|
| 804 | + timing_en = mpp->srv->timing_en; |
|---|
| 805 | + if (timing_en) { |
|---|
| 806 | + task->on_run = ktime_get(); |
|---|
| 807 | + set_bit(TASK_TIMING_RUN, &task->state); |
|---|
| 808 | + } |
|---|
| 656 | 809 | |
|---|
| 657 | 810 | /* |
|---|
| 658 | 811 | * before running, we have to switch grf ctrl bit to ensure |
|---|
| .. | .. |
|---|
| 678 | 831 | } |
|---|
| 679 | 832 | |
|---|
| 680 | 833 | mpp_power_on(mpp); |
|---|
| 681 | | - mpp_time_record(task); |
|---|
| 682 | | - mpp_debug(DEBUG_TASK_INFO, "pid %d, start hw %s\n", |
|---|
| 683 | | - task->session->pid, dev_name(mpp->dev)); |
|---|
| 834 | + mpp_debug_func(DEBUG_TASK_INFO, "pid %d run %s\n", |
|---|
| 835 | + task->session->pid, dev_name(mpp->dev)); |
|---|
| 684 | 836 | |
|---|
| 685 | 837 | if (mpp->auto_freq_en && mpp->hw_ops->set_freq) |
|---|
| 686 | 838 | mpp->hw_ops->set_freq(mpp, task); |
|---|
| .. | .. |
|---|
| 690 | 842 | */ |
|---|
| 691 | 843 | mpp_reset_down_read(mpp->reset_group); |
|---|
| 692 | 844 | |
|---|
| 693 | | - schedule_delayed_work(&task->timeout_work, |
|---|
| 694 | | - msecs_to_jiffies(MPP_WORK_TIMEOUT_DELAY)); |
|---|
| 845 | + mpp_iommu_dev_activate(mpp->iommu_info, mpp); |
|---|
| 695 | 846 | if (mpp->dev_ops->run) |
|---|
| 696 | 847 | mpp->dev_ops->run(mpp, task); |
|---|
| 697 | | - set_bit(TASK_STATE_START, &task->state); |
|---|
| 698 | 848 | |
|---|
| 699 | 849 | mpp_debug_leave(); |
|---|
| 700 | 850 | |
|---|
| .. | .. |
|---|
| 709 | 859 | |
|---|
| 710 | 860 | mpp_debug_enter(); |
|---|
| 711 | 861 | |
|---|
| 862 | +again: |
|---|
| 712 | 863 | task = mpp_taskqueue_get_pending_task(queue); |
|---|
| 713 | 864 | if (!task) |
|---|
| 714 | 865 | goto done; |
|---|
| .. | .. |
|---|
| 716 | 867 | /* if task timeout and aborted, remove it */ |
|---|
| 717 | 868 | if (atomic_read(&task->abort_request) > 0) { |
|---|
| 718 | 869 | mpp_taskqueue_pop_pending(queue, task); |
|---|
| 719 | | - goto done; |
|---|
| 870 | + goto again; |
|---|
| 720 | 871 | } |
|---|
| 721 | 872 | |
|---|
| 722 | 873 | /* get device for current task */ |
|---|
| .. | .. |
|---|
| 741 | 892 | */ |
|---|
| 742 | 893 | /* Push a pending task to running queue */ |
|---|
| 743 | 894 | if (task) { |
|---|
| 895 | + struct mpp_dev *task_mpp = mpp_get_task_used_device(task, task->session); |
|---|
| 896 | + |
|---|
| 897 | + atomic_inc(&task_mpp->task_count); |
|---|
| 744 | 898 | mpp_taskqueue_pending_to_run(queue, task); |
|---|
| 745 | 899 | set_bit(TASK_STATE_RUNNING, &task->state); |
|---|
| 746 | | - if (mpp_task_run(mpp, task)) |
|---|
| 747 | | - mpp_taskqueue_pop_running(mpp->queue, task); |
|---|
| 900 | + if (mpp_task_run(task_mpp, task)) |
|---|
| 901 | + mpp_taskqueue_pop_running(queue, task); |
|---|
| 902 | + else |
|---|
| 903 | + goto again; |
|---|
| 748 | 904 | } |
|---|
| 749 | 905 | |
|---|
| 750 | 906 | done: |
|---|
| 751 | | - mutex_lock(&queue->session_lock); |
|---|
| 752 | | - while (queue->detach_count) { |
|---|
| 753 | | - struct mpp_session *session = NULL; |
|---|
| 754 | | - |
|---|
| 755 | | - session = list_first_entry_or_null(&queue->session_detach, struct mpp_session, |
|---|
| 756 | | - session_link); |
|---|
| 757 | | - if (session) { |
|---|
| 758 | | - list_del_init(&session->session_link); |
|---|
| 759 | | - queue->detach_count--; |
|---|
| 760 | | - } |
|---|
| 761 | | - |
|---|
| 762 | | - mutex_unlock(&queue->session_lock); |
|---|
| 763 | | - |
|---|
| 764 | | - if (session) { |
|---|
| 765 | | - mpp_dbg_session("%s detach count %d\n", dev_name(mpp->dev), |
|---|
| 766 | | - queue->detach_count); |
|---|
| 767 | | - mpp_session_deinit(session); |
|---|
| 768 | | - } |
|---|
| 769 | | - |
|---|
| 770 | | - mutex_lock(&queue->session_lock); |
|---|
| 771 | | - } |
|---|
| 772 | | - mutex_unlock(&queue->session_lock); |
|---|
| 907 | + mpp_session_cleanup_detach(queue, work_s); |
|---|
| 773 | 908 | } |
|---|
| 774 | 909 | |
|---|
| 775 | 910 | static int mpp_wait_result_default(struct mpp_session *session, |
|---|
| 776 | | - struct mpp_task_msgs *msgs) |
|---|
| 911 | + struct mpp_task_msgs *msgs) |
|---|
| 777 | 912 | { |
|---|
| 778 | 913 | int ret; |
|---|
| 779 | 914 | struct mpp_task *task; |
|---|
| 780 | | - struct mpp_dev *mpp = session->mpp; |
|---|
| 781 | | - |
|---|
| 782 | | - if (unlikely(!mpp)) { |
|---|
| 783 | | - mpp_err("pid %d clinet %d found invalid wait result function\n", |
|---|
| 784 | | - session->pid, session->device_type); |
|---|
| 785 | | - return -EINVAL; |
|---|
| 786 | | - } |
|---|
| 787 | | - |
|---|
| 788 | | - ret = wait_event_timeout(session->wait, |
|---|
| 789 | | - !list_empty(&session->done_list), |
|---|
| 790 | | - msecs_to_jiffies(MPP_WAIT_TIMEOUT_DELAY)); |
|---|
| 915 | + struct mpp_dev *mpp; |
|---|
| 791 | 916 | |
|---|
| 792 | 917 | task = mpp_session_get_pending_task(session); |
|---|
| 793 | 918 | if (!task) { |
|---|
| 794 | | - mpp_err("session %p pending list is empty!\n", session); |
|---|
| 919 | + mpp_err("session %d:%d pending list is empty!\n", |
|---|
| 920 | + session->pid, session->index); |
|---|
| 795 | 921 | return -EIO; |
|---|
| 796 | 922 | } |
|---|
| 923 | + mpp = mpp_get_task_used_device(task, session); |
|---|
| 797 | 924 | |
|---|
| 925 | + ret = wait_event_timeout(task->wait, |
|---|
| 926 | + test_bit(TASK_STATE_DONE, &task->state), |
|---|
| 927 | + msecs_to_jiffies(MPP_WAIT_TIMEOUT_DELAY)); |
|---|
| 798 | 928 | if (ret > 0) { |
|---|
| 799 | | - u32 task_found = 0; |
|---|
| 800 | | - struct mpp_task *loop = NULL, *n; |
|---|
| 801 | | - |
|---|
| 802 | | - /* find task in session done list */ |
|---|
| 803 | | - mutex_lock(&session->done_lock); |
|---|
| 804 | | - list_for_each_entry_safe(loop, n, |
|---|
| 805 | | - &session->done_list, |
|---|
| 806 | | - done_link) { |
|---|
| 807 | | - if (loop == task) { |
|---|
| 808 | | - task_found = 1; |
|---|
| 809 | | - break; |
|---|
| 810 | | - } |
|---|
| 811 | | - } |
|---|
| 812 | | - mutex_unlock(&session->done_lock); |
|---|
| 813 | | - if (task_found) { |
|---|
| 814 | | - if (mpp->dev_ops->result) |
|---|
| 815 | | - ret = mpp->dev_ops->result(mpp, task, msgs); |
|---|
| 816 | | - mpp_session_pop_done(session, task); |
|---|
| 817 | | - |
|---|
| 818 | | - if (test_bit(TASK_STATE_TIMEOUT, &task->state)) |
|---|
| 819 | | - ret = -ETIMEDOUT; |
|---|
| 820 | | - } else { |
|---|
| 821 | | - mpp_err("session %p task %p, not found in done list!\n", |
|---|
| 822 | | - session, task); |
|---|
| 823 | | - ret = -EIO; |
|---|
| 824 | | - } |
|---|
| 929 | + if (mpp->dev_ops->result) |
|---|
| 930 | + ret = mpp->dev_ops->result(mpp, task, msgs); |
|---|
| 825 | 931 | } else { |
|---|
| 826 | 932 | atomic_inc(&task->abort_request); |
|---|
| 827 | | - mpp_err("timeout, pid %d session %p:%d count %d cur_task %p index %d.\n", |
|---|
| 828 | | - session->pid, session, session->index, |
|---|
| 933 | + set_bit(TASK_STATE_ABORT, &task->state); |
|---|
| 934 | + mpp_err("timeout, pid %d session %d:%d count %d cur_task %p id %d\n", |
|---|
| 935 | + session->pid, session->pid, session->index, |
|---|
| 829 | 936 | atomic_read(&session->task_count), task, |
|---|
| 830 | | - task->task_index); |
|---|
| 831 | | - /* if twice and return timeout, otherwise, re-wait */ |
|---|
| 832 | | - if (atomic_read(&task->abort_request) > 1) { |
|---|
| 833 | | - mpp_err("session %p:%d, task %p index %d abort wait twice!\n", |
|---|
| 834 | | - session, session->index, |
|---|
| 835 | | - task, task->task_index); |
|---|
| 836 | | - ret = -ETIMEDOUT; |
|---|
| 837 | | - } else { |
|---|
| 838 | | - return mpp_wait_result_default(session, msgs); |
|---|
| 839 | | - } |
|---|
| 937 | + task->task_id); |
|---|
| 840 | 938 | } |
|---|
| 841 | 939 | |
|---|
| 842 | | - mpp_debug_func(DEBUG_TASK_INFO, |
|---|
| 843 | | - "kref_read=%d, ret=%d\n", kref_read(&task->ref), ret); |
|---|
| 940 | + mpp_debug_func(DEBUG_TASK_INFO, "task %d kref_%d\n", |
|---|
| 941 | + task->task_id, kref_read(&task->ref)); |
|---|
| 942 | + |
|---|
| 844 | 943 | mpp_session_pop_pending(session, task); |
|---|
| 845 | 944 | |
|---|
| 846 | 945 | return ret; |
|---|
| .. | .. |
|---|
| 875 | 974 | of_node_put(np); |
|---|
| 876 | 975 | if (!pdev) { |
|---|
| 877 | 976 | dev_err(dev, "failed to get mpp service from node\n"); |
|---|
| 878 | | - ret = -ENODEV; |
|---|
| 879 | | - goto err_put_pdev; |
|---|
| 977 | + return -ENODEV; |
|---|
| 880 | 978 | } |
|---|
| 881 | 979 | |
|---|
| 882 | | - mpp->pdev_srv = pdev; |
|---|
| 883 | 980 | mpp->srv = platform_get_drvdata(pdev); |
|---|
| 981 | + platform_device_put(pdev); |
|---|
| 884 | 982 | if (!mpp->srv) { |
|---|
| 885 | | - dev_err(&pdev->dev, "failed attach service\n"); |
|---|
| 886 | | - ret = -EINVAL; |
|---|
| 887 | | - goto err_put_pdev; |
|---|
| 983 | + dev_err(dev, "failed attach service\n"); |
|---|
| 984 | + return -EINVAL; |
|---|
| 888 | 985 | } |
|---|
| 889 | 986 | |
|---|
| 890 | 987 | ret = of_property_read_u32(dev->of_node, |
|---|
| 891 | 988 | "rockchip,taskqueue-node", &taskqueue_node); |
|---|
| 892 | 989 | if (ret) { |
|---|
| 893 | 990 | dev_err(dev, "failed to get taskqueue-node\n"); |
|---|
| 894 | | - goto err_put_pdev; |
|---|
| 991 | + return ret; |
|---|
| 895 | 992 | } else if (taskqueue_node >= mpp->srv->taskqueue_cnt) { |
|---|
| 896 | 993 | dev_err(dev, "taskqueue-node %d must less than %d\n", |
|---|
| 897 | 994 | taskqueue_node, mpp->srv->taskqueue_cnt); |
|---|
| 898 | | - ret = -ENODEV; |
|---|
| 899 | | - goto err_put_pdev; |
|---|
| 995 | + return -ENODEV; |
|---|
| 900 | 996 | } |
|---|
| 901 | 997 | /* set taskqueue according dtsi */ |
|---|
| 902 | 998 | queue = mpp->srv->task_queues[taskqueue_node]; |
|---|
| 903 | 999 | if (!queue) { |
|---|
| 904 | 1000 | dev_err(dev, "taskqueue attach to invalid node %d\n", |
|---|
| 905 | 1001 | taskqueue_node); |
|---|
| 906 | | - ret = -ENODEV; |
|---|
| 907 | | - goto err_put_pdev; |
|---|
| 1002 | + return -ENODEV; |
|---|
| 908 | 1003 | } |
|---|
| 909 | 1004 | mpp_attach_workqueue(mpp, queue); |
|---|
| 910 | 1005 | |
|---|
| .. | .. |
|---|
| 915 | 1010 | if (reset_group_node >= mpp->srv->reset_group_cnt) { |
|---|
| 916 | 1011 | dev_err(dev, "resetgroup-node %d must less than %d\n", |
|---|
| 917 | 1012 | reset_group_node, mpp->srv->reset_group_cnt); |
|---|
| 918 | | - ret = -ENODEV; |
|---|
| 919 | | - goto err_put_pdev; |
|---|
| 1013 | + return -ENODEV; |
|---|
| 920 | 1014 | } else { |
|---|
| 921 | 1015 | mpp->reset_group = mpp->srv->reset_groups[reset_group_node]; |
|---|
| 922 | 1016 | } |
|---|
| 923 | 1017 | } |
|---|
| 924 | 1018 | |
|---|
| 925 | 1019 | return 0; |
|---|
| 926 | | - |
|---|
| 927 | | -err_put_pdev: |
|---|
| 928 | | - platform_device_put(pdev); |
|---|
| 929 | | - |
|---|
| 930 | | - return ret; |
|---|
| 931 | 1020 | } |
|---|
| 932 | 1021 | |
|---|
| 933 | 1022 | struct mpp_taskqueue *mpp_taskqueue_init(struct device *dev) |
|---|
| .. | .. |
|---|
| 951 | 1040 | |
|---|
| 952 | 1041 | /* default taskqueue has max 16 task capacity */ |
|---|
| 953 | 1042 | queue->task_capacity = MPP_MAX_TASK_CAPACITY; |
|---|
| 1043 | + atomic_set(&queue->reset_request, 0); |
|---|
| 1044 | + atomic_set(&queue->detach_count, 0); |
|---|
| 1045 | + atomic_set(&queue->task_id, 0); |
|---|
| 1046 | + queue->dev_active_flags = 0; |
|---|
| 954 | 1047 | |
|---|
| 955 | 1048 | return queue; |
|---|
| 956 | 1049 | } |
|---|
| .. | .. |
|---|
| 958 | 1051 | static void mpp_attach_workqueue(struct mpp_dev *mpp, |
|---|
| 959 | 1052 | struct mpp_taskqueue *queue) |
|---|
| 960 | 1053 | { |
|---|
| 961 | | - mpp->queue = queue; |
|---|
| 1054 | + s32 core_id; |
|---|
| 1055 | + |
|---|
| 962 | 1056 | INIT_LIST_HEAD(&mpp->queue_link); |
|---|
| 1057 | + |
|---|
| 963 | 1058 | mutex_lock(&queue->dev_lock); |
|---|
| 1059 | + |
|---|
| 1060 | + if (mpp->core_id >= 0) |
|---|
| 1061 | + core_id = mpp->core_id; |
|---|
| 1062 | + else |
|---|
| 1063 | + core_id = queue->core_count; |
|---|
| 1064 | + |
|---|
| 1065 | + if (core_id < 0 || core_id >= MPP_MAX_CORE_NUM) { |
|---|
| 1066 | + dev_err(mpp->dev, "invalid core id %d\n", core_id); |
|---|
| 1067 | + goto done; |
|---|
| 1068 | + } |
|---|
| 1069 | + |
|---|
| 1070 | + /* |
|---|
| 1071 | + * multi devices with no multicores share one queue, |
|---|
| 1072 | + * the core_id is default value 0. |
|---|
| 1073 | + */ |
|---|
| 1074 | + if (queue->cores[core_id]) { |
|---|
| 1075 | + if (queue->cores[core_id] == mpp) |
|---|
| 1076 | + goto done; |
|---|
| 1077 | + |
|---|
| 1078 | + core_id = queue->core_count; |
|---|
| 1079 | + } |
|---|
| 1080 | + |
|---|
| 1081 | + queue->cores[core_id] = mpp; |
|---|
| 1082 | + queue->core_count++; |
|---|
| 1083 | + |
|---|
| 1084 | + set_bit(core_id, &queue->core_idle); |
|---|
| 964 | 1085 | list_add_tail(&mpp->queue_link, &queue->dev_list); |
|---|
| 1086 | + if (queue->core_id_max < (u32)core_id) |
|---|
| 1087 | + queue->core_id_max = (u32)core_id; |
|---|
| 1088 | + |
|---|
| 1089 | + mpp->core_id = core_id; |
|---|
| 1090 | + mpp->queue = queue; |
|---|
| 1091 | + |
|---|
| 1092 | + mpp_dbg_core("%s attach queue as core %d\n", |
|---|
| 1093 | + dev_name(mpp->dev), mpp->core_id); |
|---|
| 1094 | + |
|---|
| 965 | 1095 | if (queue->task_capacity > mpp->task_capacity) |
|---|
| 966 | 1096 | queue->task_capacity = mpp->task_capacity; |
|---|
| 1097 | + |
|---|
| 1098 | +done: |
|---|
| 967 | 1099 | mutex_unlock(&queue->dev_lock); |
|---|
| 968 | 1100 | } |
|---|
| 969 | 1101 | |
|---|
| .. | .. |
|---|
| 973 | 1105 | |
|---|
| 974 | 1106 | if (queue) { |
|---|
| 975 | 1107 | mutex_lock(&queue->dev_lock); |
|---|
| 1108 | + |
|---|
| 1109 | + queue->cores[mpp->core_id] = NULL; |
|---|
| 1110 | + queue->core_count--; |
|---|
| 1111 | + |
|---|
| 1112 | + clear_bit(mpp->core_id, &queue->core_idle); |
|---|
| 976 | 1113 | list_del_init(&mpp->queue_link); |
|---|
| 1114 | + |
|---|
| 1115 | + mpp->queue = NULL; |
|---|
| 1116 | + |
|---|
| 977 | 1117 | mutex_unlock(&queue->dev_lock); |
|---|
| 978 | 1118 | } |
|---|
| 979 | 1119 | } |
|---|
| .. | .. |
|---|
| 989 | 1129 | found = (cmd >= MPP_CMD_CONTROL_BASE && cmd < MPP_CMD_CONTROL_BUTT) ? true : found; |
|---|
| 990 | 1130 | |
|---|
| 991 | 1131 | return found ? 0 : -EINVAL; |
|---|
| 992 | | -} |
|---|
| 993 | | - |
|---|
| 994 | | -static int mpp_parse_msg_v1(struct mpp_msg_v1 *msg, |
|---|
| 995 | | - struct mpp_request *req) |
|---|
| 996 | | -{ |
|---|
| 997 | | - int ret = 0; |
|---|
| 998 | | - |
|---|
| 999 | | - req->cmd = msg->cmd; |
|---|
| 1000 | | - req->flags = msg->flags; |
|---|
| 1001 | | - req->size = msg->size; |
|---|
| 1002 | | - req->offset = msg->offset; |
|---|
| 1003 | | - req->data = (void __user *)(unsigned long)msg->data_ptr; |
|---|
| 1004 | | - |
|---|
| 1005 | | - mpp_debug(DEBUG_IOCTL, "cmd %x, flags %08x, size %d, offset %x\n", |
|---|
| 1006 | | - req->cmd, req->flags, req->size, req->offset); |
|---|
| 1007 | | - |
|---|
| 1008 | | - ret = mpp_check_cmd_v1(req->cmd); |
|---|
| 1009 | | - if (ret) |
|---|
| 1010 | | - mpp_err("mpp cmd %x is not supproted.\n", req->cmd); |
|---|
| 1011 | | - |
|---|
| 1012 | | - return ret; |
|---|
| 1013 | 1132 | } |
|---|
| 1014 | 1133 | |
|---|
| 1015 | 1134 | static inline int mpp_msg_is_last(struct mpp_request *req) |
|---|
| .. | .. |
|---|
| 1061 | 1180 | int ret; |
|---|
| 1062 | 1181 | struct mpp_dev *mpp; |
|---|
| 1063 | 1182 | |
|---|
| 1064 | | - mpp_debug(DEBUG_IOCTL, "req->cmd %x\n", req->cmd); |
|---|
| 1183 | + mpp_debug(DEBUG_IOCTL, "cmd %x process\n", req->cmd); |
|---|
| 1184 | + |
|---|
| 1065 | 1185 | switch (req->cmd) { |
|---|
| 1066 | 1186 | case MPP_CMD_QUERY_HW_SUPPORT: { |
|---|
| 1067 | 1187 | u32 hw_support = srv->hw_support; |
|---|
| .. | .. |
|---|
| 1087 | 1207 | if (test_bit(client_type, &srv->hw_support)) |
|---|
| 1088 | 1208 | mpp = srv->sub_devices[client_type]; |
|---|
| 1089 | 1209 | } |
|---|
| 1210 | + |
|---|
| 1090 | 1211 | if (!mpp) |
|---|
| 1091 | 1212 | return -EINVAL; |
|---|
| 1213 | + |
|---|
| 1092 | 1214 | hw_info = mpp->var->hw_info; |
|---|
| 1093 | 1215 | mpp_debug(DEBUG_IOCTL, "hw_id %08x\n", hw_info->hw_id); |
|---|
| 1094 | 1216 | if (put_user(hw_info->hw_id, (u32 __user *)req->data)) |
|---|
| .. | .. |
|---|
| 1119 | 1241 | mpp = srv->sub_devices[client_type]; |
|---|
| 1120 | 1242 | if (!mpp) |
|---|
| 1121 | 1243 | return -EINVAL; |
|---|
| 1244 | + |
|---|
| 1122 | 1245 | session->device_type = (enum MPP_DEVICE_TYPE)client_type; |
|---|
| 1123 | 1246 | session->dma = mpp_dma_session_create(mpp->dev, mpp->session_max_buffers); |
|---|
| 1124 | 1247 | session->mpp = mpp; |
|---|
| .. | .. |
|---|
| 1140 | 1263 | if (ret) |
|---|
| 1141 | 1264 | return ret; |
|---|
| 1142 | 1265 | } |
|---|
| 1266 | + |
|---|
| 1143 | 1267 | mpp_session_attach_workqueue(session, mpp->queue); |
|---|
| 1144 | 1268 | } break; |
|---|
| 1145 | 1269 | case MPP_CMD_INIT_DRIVER_DATA: { |
|---|
| .. | .. |
|---|
| 1182 | 1306 | case MPP_CMD_POLL_HW_FINISH: { |
|---|
| 1183 | 1307 | msgs->flags |= req->flags; |
|---|
| 1184 | 1308 | msgs->poll_cnt++; |
|---|
| 1309 | + msgs->poll_req = NULL; |
|---|
| 1310 | + } break; |
|---|
| 1311 | + case MPP_CMD_POLL_HW_IRQ: { |
|---|
| 1312 | + if (msgs->poll_cnt || msgs->poll_req) |
|---|
| 1313 | + mpp_err("Do NOT poll hw irq when previous call not return\n"); |
|---|
| 1314 | + |
|---|
| 1315 | + msgs->flags |= req->flags; |
|---|
| 1316 | + msgs->poll_cnt++; |
|---|
| 1317 | + |
|---|
| 1318 | + if (req->size && req->data) { |
|---|
| 1319 | + if (!msgs->poll_req) |
|---|
| 1320 | + msgs->poll_req = req; |
|---|
| 1321 | + } else { |
|---|
| 1322 | + msgs->poll_req = NULL; |
|---|
| 1323 | + } |
|---|
| 1185 | 1324 | } break; |
|---|
| 1186 | 1325 | case MPP_CMD_RESET_SESSION: { |
|---|
| 1187 | 1326 | int ret; |
|---|
| .. | .. |
|---|
| 1197 | 1336 | if (!mpp) |
|---|
| 1198 | 1337 | return -EINVAL; |
|---|
| 1199 | 1338 | |
|---|
| 1200 | | - mpp_session_clear(mpp, session); |
|---|
| 1339 | + mpp_session_clear_pending(session); |
|---|
| 1201 | 1340 | mpp_iommu_down_write(mpp->iommu_info); |
|---|
| 1202 | 1341 | ret = mpp_dma_session_destroy(session->dma); |
|---|
| 1203 | 1342 | mpp_iommu_up_write(mpp->iommu_info); |
|---|
| .. | .. |
|---|
| 1271 | 1410 | default: { |
|---|
| 1272 | 1411 | mpp = session->mpp; |
|---|
| 1273 | 1412 | if (!mpp) { |
|---|
| 1274 | | - mpp_err("pid %d not find clinet %d\n", |
|---|
| 1413 | + mpp_err("pid %d not find client %d\n", |
|---|
| 1275 | 1414 | session->pid, session->device_type); |
|---|
| 1276 | 1415 | return -EINVAL; |
|---|
| 1277 | 1416 | } |
|---|
| .. | .. |
|---|
| 1285 | 1424 | return 0; |
|---|
| 1286 | 1425 | } |
|---|
| 1287 | 1426 | |
|---|
| 1288 | | -static long mpp_dev_ioctl(struct file *filp, |
|---|
| 1289 | | - unsigned int cmd, |
|---|
| 1290 | | - unsigned long arg) |
|---|
| 1427 | +static void task_msgs_add(struct mpp_task_msgs *msgs, struct list_head *head) |
|---|
| 1291 | 1428 | { |
|---|
| 1429 | + struct mpp_session *session = msgs->session; |
|---|
| 1292 | 1430 | int ret = 0; |
|---|
| 1293 | | - struct mpp_service *srv; |
|---|
| 1294 | | - void __user *msg; |
|---|
| 1431 | + |
|---|
| 1432 | + /* process each task */ |
|---|
| 1433 | + if (msgs->set_cnt) { |
|---|
| 1434 | + /* NOTE: update msg_flags for fd over 1024 */ |
|---|
| 1435 | + session->msg_flags = msgs->flags; |
|---|
| 1436 | + ret = mpp_process_task(session, msgs); |
|---|
| 1437 | + } |
|---|
| 1438 | + |
|---|
| 1439 | + if (!ret) { |
|---|
| 1440 | + INIT_LIST_HEAD(&msgs->list); |
|---|
| 1441 | + list_add_tail(&msgs->list, head); |
|---|
| 1442 | + } else { |
|---|
| 1443 | + put_task_msgs(msgs); |
|---|
| 1444 | + } |
|---|
| 1445 | +} |
|---|
| 1446 | + |
|---|
| 1447 | +static int mpp_collect_msgs(struct list_head *head, struct mpp_session *session, |
|---|
| 1448 | + unsigned int cmd, void __user *msg) |
|---|
| 1449 | +{ |
|---|
| 1450 | + struct mpp_msg_v1 msg_v1; |
|---|
| 1295 | 1451 | struct mpp_request *req; |
|---|
| 1296 | | - struct mpp_task_msgs task_msgs; |
|---|
| 1297 | | - struct mpp_session *session = |
|---|
| 1298 | | - (struct mpp_session *)filp->private_data; |
|---|
| 1452 | + struct mpp_task_msgs *msgs = NULL; |
|---|
| 1453 | + int last = 1; |
|---|
| 1454 | + int ret; |
|---|
| 1455 | + |
|---|
| 1456 | + if (cmd != MPP_IOC_CFG_V1) { |
|---|
| 1457 | + mpp_err("unknown ioctl cmd %x\n", cmd); |
|---|
| 1458 | + return -EINVAL; |
|---|
| 1459 | + } |
|---|
| 1460 | + |
|---|
| 1461 | +next: |
|---|
| 1462 | + /* first, parse to fixed struct */ |
|---|
| 1463 | + if (copy_from_user(&msg_v1, msg, sizeof(msg_v1))) |
|---|
| 1464 | + return -EFAULT; |
|---|
| 1465 | + |
|---|
| 1466 | + msg += sizeof(msg_v1); |
|---|
| 1467 | + |
|---|
| 1468 | + mpp_debug(DEBUG_IOCTL, "cmd %x collect flags %08x, size %d, offset %x\n", |
|---|
| 1469 | + msg_v1.cmd, msg_v1.flags, msg_v1.size, msg_v1.offset); |
|---|
| 1470 | + |
|---|
| 1471 | + if (mpp_check_cmd_v1(msg_v1.cmd)) { |
|---|
| 1472 | + mpp_err("mpp cmd %x is not supported.\n", msg_v1.cmd); |
|---|
| 1473 | + return -EFAULT; |
|---|
| 1474 | + } |
|---|
| 1475 | + |
|---|
| 1476 | + if (msg_v1.flags & MPP_FLAGS_MULTI_MSG) |
|---|
| 1477 | + last = (msg_v1.flags & MPP_FLAGS_LAST_MSG) ? 1 : 0; |
|---|
| 1478 | + else |
|---|
| 1479 | + last = 1; |
|---|
| 1480 | + |
|---|
| 1481 | + /* check cmd for change msgs session */ |
|---|
| 1482 | + if (msg_v1.cmd == MPP_CMD_SET_SESSION_FD) { |
|---|
| 1483 | + struct mpp_bat_msg bat_msg; |
|---|
| 1484 | + struct mpp_bat_msg __user *usr_cmd; |
|---|
| 1485 | + struct fd f; |
|---|
| 1486 | + |
|---|
| 1487 | + /* try session switch here */ |
|---|
| 1488 | + usr_cmd = (struct mpp_bat_msg __user *)(unsigned long)msg_v1.data_ptr; |
|---|
| 1489 | + |
|---|
| 1490 | + if (copy_from_user(&bat_msg, usr_cmd, sizeof(bat_msg))) |
|---|
| 1491 | + return -EFAULT; |
|---|
| 1492 | + |
|---|
| 1493 | + /* skip finished message */ |
|---|
| 1494 | + if (bat_msg.flag & MPP_BAT_MSG_DONE) |
|---|
| 1495 | + goto session_switch_done; |
|---|
| 1496 | + |
|---|
| 1497 | + f = fdget(bat_msg.fd); |
|---|
| 1498 | + if (!f.file) { |
|---|
| 1499 | + int ret = -EBADF; |
|---|
| 1500 | + |
|---|
| 1501 | + mpp_err("fd %d get session failed\n", bat_msg.fd); |
|---|
| 1502 | + |
|---|
| 1503 | + if (copy_to_user(&usr_cmd->ret, &ret, sizeof(usr_cmd->ret))) |
|---|
| 1504 | + mpp_err("copy_to_user failed.\n"); |
|---|
| 1505 | + goto session_switch_done; |
|---|
| 1506 | + } |
|---|
| 1507 | + |
|---|
| 1508 | + /* NOTE: add previous ready task to queue and drop empty task */ |
|---|
| 1509 | + if (msgs) { |
|---|
| 1510 | + if (msgs->req_cnt) |
|---|
| 1511 | + task_msgs_add(msgs, head); |
|---|
| 1512 | + else |
|---|
| 1513 | + put_task_msgs(msgs); |
|---|
| 1514 | + |
|---|
| 1515 | + msgs = NULL; |
|---|
| 1516 | + } |
|---|
| 1517 | + |
|---|
| 1518 | + /* switch session */ |
|---|
| 1519 | + session = f.file->private_data; |
|---|
| 1520 | + msgs = get_task_msgs(session); |
|---|
| 1521 | + |
|---|
| 1522 | + if (f.file->private_data == session) |
|---|
| 1523 | + msgs->ext_fd = bat_msg.fd; |
|---|
| 1524 | + |
|---|
| 1525 | + msgs->f = f; |
|---|
| 1526 | + |
|---|
| 1527 | + mpp_debug(DEBUG_IOCTL, "fd %d, session %d msg_cnt %d\n", |
|---|
| 1528 | + bat_msg.fd, session->index, session->msgs_cnt); |
|---|
| 1529 | + |
|---|
| 1530 | +session_switch_done: |
|---|
| 1531 | + /* session id should NOT be the last message */ |
|---|
| 1532 | + if (last) |
|---|
| 1533 | + return 0; |
|---|
| 1534 | + |
|---|
| 1535 | + goto next; |
|---|
| 1536 | + } |
|---|
| 1537 | + |
|---|
| 1538 | + if (!msgs) |
|---|
| 1539 | + msgs = get_task_msgs(session); |
|---|
| 1540 | + |
|---|
| 1541 | + if (!msgs) { |
|---|
| 1542 | + pr_err("session %d:%d failed to get task msgs", |
|---|
| 1543 | + session->pid, session->index); |
|---|
| 1544 | + return -EINVAL; |
|---|
| 1545 | + } |
|---|
| 1546 | + |
|---|
| 1547 | + if (msgs->req_cnt >= MPP_MAX_MSG_NUM) { |
|---|
| 1548 | + mpp_err("session %d message count %d more than %d.\n", |
|---|
| 1549 | + session->index, msgs->req_cnt, MPP_MAX_MSG_NUM); |
|---|
| 1550 | + return -EINVAL; |
|---|
| 1551 | + } |
|---|
| 1552 | + |
|---|
| 1553 | + req = &msgs->reqs[msgs->req_cnt++]; |
|---|
| 1554 | + req->cmd = msg_v1.cmd; |
|---|
| 1555 | + req->flags = msg_v1.flags; |
|---|
| 1556 | + req->size = msg_v1.size; |
|---|
| 1557 | + req->offset = msg_v1.offset; |
|---|
| 1558 | + req->data = (void __user *)(unsigned long)msg_v1.data_ptr; |
|---|
| 1559 | + |
|---|
| 1560 | + ret = mpp_process_request(session, session->srv, req, msgs); |
|---|
| 1561 | + if (ret) { |
|---|
| 1562 | + mpp_err("session %d process cmd %x ret %d\n", |
|---|
| 1563 | + session->index, req->cmd, ret); |
|---|
| 1564 | + return ret; |
|---|
| 1565 | + } |
|---|
| 1566 | + |
|---|
| 1567 | + if (!last) |
|---|
| 1568 | + goto next; |
|---|
| 1569 | + |
|---|
| 1570 | + task_msgs_add(msgs, head); |
|---|
| 1571 | + msgs = NULL; |
|---|
| 1572 | + |
|---|
| 1573 | + return 0; |
|---|
| 1574 | +} |
|---|
| 1575 | + |
|---|
| 1576 | +static void mpp_msgs_trigger(struct list_head *msgs_list) |
|---|
| 1577 | +{ |
|---|
| 1578 | + struct mpp_task_msgs *msgs, *n; |
|---|
| 1579 | + struct mpp_dev *mpp_prev = NULL; |
|---|
| 1580 | + struct mpp_taskqueue *queue_prev = NULL; |
|---|
| 1581 | + |
|---|
| 1582 | + /* push task to queue */ |
|---|
| 1583 | + list_for_each_entry_safe(msgs, n, msgs_list, list) { |
|---|
| 1584 | + struct mpp_dev *mpp; |
|---|
| 1585 | + struct mpp_task *task; |
|---|
| 1586 | + struct mpp_taskqueue *queue; |
|---|
| 1587 | + |
|---|
| 1588 | + if (!msgs->set_cnt || !msgs->queue) |
|---|
| 1589 | + continue; |
|---|
| 1590 | + |
|---|
| 1591 | + mpp = msgs->mpp; |
|---|
| 1592 | + task = msgs->task; |
|---|
| 1593 | + queue = msgs->queue; |
|---|
| 1594 | + |
|---|
| 1595 | + if (queue_prev != queue) { |
|---|
| 1596 | + if (queue_prev && mpp_prev) { |
|---|
| 1597 | + mutex_unlock(&queue_prev->pending_lock); |
|---|
| 1598 | + mpp_taskqueue_trigger_work(mpp_prev); |
|---|
| 1599 | + } |
|---|
| 1600 | + |
|---|
| 1601 | + if (queue) |
|---|
| 1602 | + mutex_lock(&queue->pending_lock); |
|---|
| 1603 | + |
|---|
| 1604 | + mpp_prev = mpp; |
|---|
| 1605 | + queue_prev = queue; |
|---|
| 1606 | + } |
|---|
| 1607 | + |
|---|
| 1608 | + if (test_bit(TASK_STATE_ABORT, &task->state)) |
|---|
| 1609 | + pr_info("try to trigger abort task %d\n", task->task_id); |
|---|
| 1610 | + |
|---|
| 1611 | + set_bit(TASK_STATE_PENDING, &task->state); |
|---|
| 1612 | + list_add_tail(&task->queue_link, &queue->pending_list); |
|---|
| 1613 | + } |
|---|
| 1614 | + |
|---|
| 1615 | + if (mpp_prev && queue_prev) { |
|---|
| 1616 | + mutex_unlock(&queue_prev->pending_lock); |
|---|
| 1617 | + mpp_taskqueue_trigger_work(mpp_prev); |
|---|
| 1618 | + } |
|---|
| 1619 | +} |
|---|
| 1620 | + |
|---|
| 1621 | +static void mpp_msgs_wait(struct list_head *msgs_list) |
|---|
| 1622 | +{ |
|---|
| 1623 | + struct mpp_task_msgs *msgs, *n; |
|---|
| 1624 | + |
|---|
| 1625 | + /* poll and release each task */ |
|---|
| 1626 | + list_for_each_entry_safe(msgs, n, msgs_list, list) { |
|---|
| 1627 | + struct mpp_session *session = msgs->session; |
|---|
| 1628 | + |
|---|
| 1629 | + if (msgs->poll_cnt) { |
|---|
| 1630 | + int ret = mpp_wait_result(session, msgs); |
|---|
| 1631 | + |
|---|
| 1632 | + if (ret) { |
|---|
| 1633 | + mpp_err("session %d wait result ret %d\n", |
|---|
| 1634 | + session->index, ret); |
|---|
| 1635 | + } |
|---|
| 1636 | + } |
|---|
| 1637 | + |
|---|
| 1638 | + put_task_msgs(msgs); |
|---|
| 1639 | + |
|---|
| 1640 | + } |
|---|
| 1641 | +} |
|---|
| 1642 | + |
|---|
| 1643 | +static long mpp_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
|---|
| 1644 | +{ |
|---|
| 1645 | + struct mpp_service *srv; |
|---|
| 1646 | + struct mpp_session *session = (struct mpp_session *)filp->private_data; |
|---|
| 1647 | + struct list_head msgs_list; |
|---|
| 1648 | + int ret = 0; |
|---|
| 1299 | 1649 | |
|---|
| 1300 | 1650 | mpp_debug_enter(); |
|---|
| 1301 | 1651 | |
|---|
| .. | .. |
|---|
| 1303 | 1653 | mpp_err("session %p\n", session); |
|---|
| 1304 | 1654 | return -EINVAL; |
|---|
| 1305 | 1655 | } |
|---|
| 1656 | + |
|---|
| 1306 | 1657 | srv = session->srv; |
|---|
| 1658 | + |
|---|
| 1307 | 1659 | if (atomic_read(&session->release_request) > 0) { |
|---|
| 1308 | 1660 | mpp_debug(DEBUG_IOCTL, "release session had request\n"); |
|---|
| 1309 | 1661 | return -EBUSY; |
|---|
| .. | .. |
|---|
| 1313 | 1665 | return -EBUSY; |
|---|
| 1314 | 1666 | } |
|---|
| 1315 | 1667 | |
|---|
| 1316 | | - msg = (void __user *)arg; |
|---|
| 1317 | | - memset(&task_msgs, 0, sizeof(task_msgs)); |
|---|
| 1318 | | - do { |
|---|
| 1319 | | - req = &task_msgs.reqs[task_msgs.req_cnt]; |
|---|
| 1320 | | - /* first, parse to fixed struct */ |
|---|
| 1321 | | - switch (cmd) { |
|---|
| 1322 | | - case MPP_IOC_CFG_V1: { |
|---|
| 1323 | | - struct mpp_msg_v1 msg_v1; |
|---|
| 1668 | + INIT_LIST_HEAD(&msgs_list); |
|---|
| 1324 | 1669 | |
|---|
| 1325 | | - memset(&msg_v1, 0, sizeof(msg_v1)); |
|---|
| 1326 | | - if (copy_from_user(&msg_v1, msg, sizeof(msg_v1))) |
|---|
| 1327 | | - return -EFAULT; |
|---|
| 1328 | | - ret = mpp_parse_msg_v1(&msg_v1, req); |
|---|
| 1329 | | - if (ret) |
|---|
| 1330 | | - return -EFAULT; |
|---|
| 1670 | + ret = mpp_collect_msgs(&msgs_list, session, cmd, (void __user *)arg); |
|---|
| 1671 | + if (ret) |
|---|
| 1672 | + mpp_err("collect msgs failed %d\n", ret); |
|---|
| 1331 | 1673 | |
|---|
| 1332 | | - msg += sizeof(msg_v1); |
|---|
| 1333 | | - } break; |
|---|
| 1334 | | - default: |
|---|
| 1335 | | - mpp_err("unknown ioctl cmd %x\n", cmd); |
|---|
| 1336 | | - return -EINVAL; |
|---|
| 1337 | | - } |
|---|
| 1338 | | - task_msgs.req_cnt++; |
|---|
| 1339 | | - /* check loop times */ |
|---|
| 1340 | | - if (task_msgs.req_cnt > MPP_MAX_MSG_NUM) { |
|---|
| 1341 | | - mpp_err("fail, message count %d more than %d.\n", |
|---|
| 1342 | | - task_msgs.req_cnt, MPP_MAX_MSG_NUM); |
|---|
| 1343 | | - return -EINVAL; |
|---|
| 1344 | | - } |
|---|
| 1345 | | - /* second, process request */ |
|---|
| 1346 | | - ret = mpp_process_request(session, srv, req, &task_msgs); |
|---|
| 1347 | | - if (ret) |
|---|
| 1348 | | - return -EFAULT; |
|---|
| 1349 | | - /* last, process task message */ |
|---|
| 1350 | | - if (mpp_msg_is_last(req)) { |
|---|
| 1351 | | - session->msg_flags = task_msgs.flags; |
|---|
| 1352 | | - if (task_msgs.set_cnt > 0) { |
|---|
| 1353 | | - ret = mpp_process_task(session, &task_msgs); |
|---|
| 1354 | | - if (ret) |
|---|
| 1355 | | - return ret; |
|---|
| 1356 | | - } |
|---|
| 1357 | | - if (task_msgs.poll_cnt > 0) { |
|---|
| 1358 | | - ret = mpp_wait_result(session, &task_msgs); |
|---|
| 1359 | | - if (ret) |
|---|
| 1360 | | - return ret; |
|---|
| 1361 | | - } |
|---|
| 1362 | | - } |
|---|
| 1363 | | - } while (!mpp_msg_is_last(req)); |
|---|
| 1674 | + mpp_msgs_trigger(&msgs_list); |
|---|
| 1675 | + |
|---|
| 1676 | + mpp_msgs_wait(&msgs_list); |
|---|
| 1364 | 1677 | |
|---|
| 1365 | 1678 | mpp_debug_leave(); |
|---|
| 1366 | 1679 | |
|---|
| .. | .. |
|---|
| 1410 | 1723 | /* wait for task all done */ |
|---|
| 1411 | 1724 | atomic_inc(&session->release_request); |
|---|
| 1412 | 1725 | |
|---|
| 1413 | | - if (session->mpp) |
|---|
| 1726 | + if (session->mpp || atomic_read(&session->task_count)) |
|---|
| 1414 | 1727 | mpp_session_detach_workqueue(session); |
|---|
| 1415 | 1728 | else |
|---|
| 1416 | 1729 | mpp_session_deinit(session); |
|---|
| .. | .. |
|---|
| 1421 | 1734 | return 0; |
|---|
| 1422 | 1735 | } |
|---|
| 1423 | 1736 | |
|---|
| 1424 | | -static unsigned int |
|---|
| 1425 | | -mpp_dev_poll(struct file *filp, poll_table *wait) |
|---|
| 1426 | | -{ |
|---|
| 1427 | | - unsigned int mask = 0; |
|---|
| 1428 | | - struct mpp_session *session = |
|---|
| 1429 | | - (struct mpp_session *)filp->private_data; |
|---|
| 1430 | | - |
|---|
| 1431 | | - poll_wait(filp, &session->wait, wait); |
|---|
| 1432 | | - if (!list_empty(&session->done_list)) |
|---|
| 1433 | | - mask |= POLLIN | POLLRDNORM; |
|---|
| 1434 | | - |
|---|
| 1435 | | - return mask; |
|---|
| 1436 | | -} |
|---|
| 1437 | | - |
|---|
| 1438 | 1737 | const struct file_operations rockchip_mpp_fops = { |
|---|
| 1439 | 1738 | .open = mpp_dev_open, |
|---|
| 1440 | 1739 | .release = mpp_dev_release, |
|---|
| 1441 | | - .poll = mpp_dev_poll, |
|---|
| 1442 | 1740 | .unlocked_ioctl = mpp_dev_ioctl, |
|---|
| 1443 | 1741 | #ifdef CONFIG_COMPAT |
|---|
| 1444 | 1742 | .compat_ioctl = mpp_dev_ioctl, |
|---|
| .. | .. |
|---|
| 1479 | 1777 | mpp_iommu_down_read(mpp->iommu_info); |
|---|
| 1480 | 1778 | buffer = mpp_dma_import_fd(mpp->iommu_info, dma, fd); |
|---|
| 1481 | 1779 | mpp_iommu_up_read(mpp->iommu_info); |
|---|
| 1482 | | - if (IS_ERR_OR_NULL(buffer)) { |
|---|
| 1780 | + if (IS_ERR(buffer)) { |
|---|
| 1483 | 1781 | mpp_err("can't import dma-buf %d\n", fd); |
|---|
| 1484 | | - return ERR_PTR(-ENOMEM); |
|---|
| 1782 | + return ERR_CAST(buffer); |
|---|
| 1485 | 1783 | } |
|---|
| 1486 | 1784 | |
|---|
| 1487 | 1785 | mem_region->hdl = buffer; |
|---|
| .. | .. |
|---|
| 1511 | 1809 | cnt = session->trans_count; |
|---|
| 1512 | 1810 | tbl = session->trans_table; |
|---|
| 1513 | 1811 | } else { |
|---|
| 1514 | | - struct mpp_dev *mpp = session->mpp; |
|---|
| 1812 | + struct mpp_dev *mpp = mpp_get_task_used_device(task, session); |
|---|
| 1515 | 1813 | struct mpp_trans_info *trans_info = mpp->var->trans_info; |
|---|
| 1516 | 1814 | |
|---|
| 1517 | 1815 | cnt = trans_info[fmt].count; |
|---|
| .. | .. |
|---|
| 1647 | 1945 | return 0; |
|---|
| 1648 | 1946 | } |
|---|
| 1649 | 1947 | |
|---|
| 1650 | | -int mpp_task_init(struct mpp_session *session, |
|---|
| 1651 | | - struct mpp_task *task) |
|---|
| 1948 | +int mpp_task_init(struct mpp_session *session, struct mpp_task *task) |
|---|
| 1652 | 1949 | { |
|---|
| 1653 | 1950 | INIT_LIST_HEAD(&task->pending_link); |
|---|
| 1654 | 1951 | INIT_LIST_HEAD(&task->queue_link); |
|---|
| .. | .. |
|---|
| 1663 | 1960 | int mpp_task_finish(struct mpp_session *session, |
|---|
| 1664 | 1961 | struct mpp_task *task) |
|---|
| 1665 | 1962 | { |
|---|
| 1666 | | - struct mpp_dev *mpp = session->mpp; |
|---|
| 1963 | + struct mpp_dev *mpp = mpp_get_task_used_device(task, session); |
|---|
| 1667 | 1964 | |
|---|
| 1668 | 1965 | if (mpp->dev_ops->finish) |
|---|
| 1669 | 1966 | mpp->dev_ops->finish(mpp, task); |
|---|
| .. | .. |
|---|
| 1673 | 1970 | mpp_dev_reset(mpp); |
|---|
| 1674 | 1971 | mpp_power_off(mpp); |
|---|
| 1675 | 1972 | |
|---|
| 1676 | | - if (!atomic_read(&task->abort_request)) { |
|---|
| 1677 | | - mpp_session_push_done(session, task); |
|---|
| 1678 | | - /* Wake up the GET thread */ |
|---|
| 1679 | | - wake_up(&session->wait); |
|---|
| 1680 | | - } |
|---|
| 1681 | 1973 | set_bit(TASK_STATE_FINISH, &task->state); |
|---|
| 1974 | + set_bit(TASK_STATE_DONE, &task->state); |
|---|
| 1975 | + |
|---|
| 1976 | + if (session->srv->timing_en) { |
|---|
| 1977 | + s64 time_diff; |
|---|
| 1978 | + |
|---|
| 1979 | + task->on_finish = ktime_get(); |
|---|
| 1980 | + set_bit(TASK_TIMING_FINISH, &task->state); |
|---|
| 1981 | + |
|---|
| 1982 | + time_diff = ktime_us_delta(task->on_finish, task->on_create); |
|---|
| 1983 | + |
|---|
| 1984 | + if (mpp->timing_check && time_diff > (s64)mpp->timing_check) |
|---|
| 1985 | + mpp_task_dump_timing(task, time_diff); |
|---|
| 1986 | + } |
|---|
| 1987 | + |
|---|
| 1988 | + /* Wake up the GET thread */ |
|---|
| 1989 | + wake_up(&task->wait); |
|---|
| 1682 | 1990 | mpp_taskqueue_pop_running(mpp->queue, task); |
|---|
| 1683 | 1991 | |
|---|
| 1684 | 1992 | return 0; |
|---|
| .. | .. |
|---|
| 1688 | 1996 | struct mpp_task *task) |
|---|
| 1689 | 1997 | { |
|---|
| 1690 | 1998 | struct mpp_mem_region *mem_region = NULL, *n; |
|---|
| 1691 | | - struct mpp_dev *mpp = session->mpp; |
|---|
| 1999 | + struct mpp_dev *mpp = mpp_get_task_used_device(task, session); |
|---|
| 1692 | 2000 | |
|---|
| 1693 | 2001 | /* release memory region attach to this registers table. */ |
|---|
| 1694 | 2002 | list_for_each_entry_safe(mem_region, n, |
|---|
| .. | .. |
|---|
| 1713 | 2021 | if (!task) |
|---|
| 1714 | 2022 | return -EIO; |
|---|
| 1715 | 2023 | |
|---|
| 1716 | | - mpp_err("--- dump mem region ---\n"); |
|---|
| 2024 | + mpp_err("--- dump task %d mem region ---\n", task->task_index); |
|---|
| 1717 | 2025 | if (!list_empty(&task->mem_region_list)) { |
|---|
| 1718 | 2026 | list_for_each_entry_safe(mem, n, |
|---|
| 1719 | 2027 | &task->mem_region_list, |
|---|
| .. | .. |
|---|
| 1753 | 2061 | return 0; |
|---|
| 1754 | 2062 | } |
|---|
| 1755 | 2063 | |
|---|
| 1756 | | -int mpp_task_dump_hw_reg(struct mpp_dev *mpp, struct mpp_task *task) |
|---|
| 2064 | +int mpp_task_dump_hw_reg(struct mpp_dev *mpp) |
|---|
| 1757 | 2065 | { |
|---|
| 1758 | | - if (!task) |
|---|
| 1759 | | - return -EIO; |
|---|
| 2066 | + u32 i; |
|---|
| 2067 | + u32 s = mpp->var->hw_info->reg_start; |
|---|
| 2068 | + u32 e = mpp->var->hw_info->reg_end; |
|---|
| 1760 | 2069 | |
|---|
| 1761 | | - if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG)) { |
|---|
| 1762 | | - u32 i; |
|---|
| 1763 | | - u32 s = task->hw_info->reg_start; |
|---|
| 1764 | | - u32 e = task->hw_info->reg_end; |
|---|
| 2070 | + mpp_err("--- dump hardware register ---\n"); |
|---|
| 2071 | + for (i = s; i <= e; i++) { |
|---|
| 2072 | + u32 reg = i * sizeof(u32); |
|---|
| 1765 | 2073 | |
|---|
| 1766 | | - mpp_err("--- dump hardware register ---\n"); |
|---|
| 1767 | | - for (i = s; i <= e; i++) { |
|---|
| 1768 | | - u32 reg = i * sizeof(u32); |
|---|
| 1769 | | - |
|---|
| 1770 | | - mpp_err("reg[%03d]: %04x: 0x%08x\n", |
|---|
| 2074 | + mpp_err("reg[%03d]: %04x: 0x%08x\n", |
|---|
| 1771 | 2075 | i, reg, readl_relaxed(mpp->reg_base + reg)); |
|---|
| 1772 | | - } |
|---|
| 1773 | 2076 | } |
|---|
| 1774 | 2077 | |
|---|
| 1775 | 2078 | return 0; |
|---|
| 1776 | 2079 | } |
|---|
| 1777 | 2080 | |
|---|
| 1778 | | -static int mpp_iommu_handle(struct iommu_domain *iommu, |
|---|
| 1779 | | - struct device *iommu_dev, |
|---|
| 1780 | | - unsigned long iova, |
|---|
| 1781 | | - int status, void *arg) |
|---|
| 2081 | +void mpp_reg_show(struct mpp_dev *mpp, u32 offset) |
|---|
| 1782 | 2082 | { |
|---|
| 1783 | | - struct mpp_taskqueue *queue = (struct mpp_taskqueue *)arg; |
|---|
| 1784 | | - struct mpp_task *task = mpp_taskqueue_get_running_task(queue); |
|---|
| 1785 | | - struct mpp_dev *mpp; |
|---|
| 2083 | + if (!mpp) |
|---|
| 2084 | + return; |
|---|
| 1786 | 2085 | |
|---|
| 1787 | | - /* |
|---|
| 1788 | | - * NOTE: In link mode, this task may not be the task of the current |
|---|
| 1789 | | - * hardware processing error |
|---|
| 1790 | | - */ |
|---|
| 1791 | | - if (!task || !task->session) |
|---|
| 1792 | | - return -EIO; |
|---|
| 1793 | | - /* get mpp from cur task */ |
|---|
| 1794 | | - mpp = task->session->mpp; |
|---|
| 1795 | | - dev_err(mpp->dev, "fault addr 0x%08lx status %x\n", iova, status); |
|---|
| 2086 | + dev_err(mpp->dev, "reg[%03d]: %04x: 0x%08x\n", |
|---|
| 2087 | + offset >> 2, offset, mpp_read_relaxed(mpp, offset)); |
|---|
| 2088 | +} |
|---|
| 1796 | 2089 | |
|---|
| 1797 | | - mpp_task_dump_mem_region(mpp, task); |
|---|
| 1798 | | - mpp_task_dump_hw_reg(mpp, task); |
|---|
| 2090 | +void mpp_reg_show_range(struct mpp_dev *mpp, u32 start, u32 end) |
|---|
| 2091 | +{ |
|---|
| 2092 | + u32 offset; |
|---|
| 1799 | 2093 | |
|---|
| 1800 | | - if (mpp->iommu_info->hdl) |
|---|
| 1801 | | - mpp->iommu_info->hdl(iommu, iommu_dev, iova, status, arg); |
|---|
| 2094 | + if (!mpp) |
|---|
| 2095 | + return; |
|---|
| 1802 | 2096 | |
|---|
| 1803 | | - return 0; |
|---|
| 2097 | + for (offset = start; offset < end; offset += sizeof(u32)) |
|---|
| 2098 | + mpp_reg_show(mpp, offset); |
|---|
| 1804 | 2099 | } |
|---|
| 1805 | 2100 | |
|---|
| 1806 | 2101 | /* The device will do more probing work after this */ |
|---|
| .. | .. |
|---|
| 1815 | 2110 | |
|---|
| 1816 | 2111 | /* Get disable auto frequent flag from dtsi */ |
|---|
| 1817 | 2112 | mpp->auto_freq_en = !device_property_read_bool(dev, "rockchip,disable-auto-freq"); |
|---|
| 2113 | + /* read flag for pum idle request */ |
|---|
| 2114 | + mpp->skip_idle = device_property_read_bool(dev, "rockchip,skip-pmu-idle-request"); |
|---|
| 2115 | + |
|---|
| 2116 | + /* read link table capacity */ |
|---|
| 2117 | + ret = of_property_read_u32(np, "rockchip,task-capacity", |
|---|
| 2118 | + &mpp->task_capacity); |
|---|
| 2119 | + if (ret) |
|---|
| 2120 | + mpp->task_capacity = 1; |
|---|
| 2121 | + |
|---|
| 2122 | + mpp->dev = dev; |
|---|
| 2123 | + mpp->hw_ops = mpp->var->hw_ops; |
|---|
| 2124 | + mpp->dev_ops = mpp->var->dev_ops; |
|---|
| 1818 | 2125 | |
|---|
| 1819 | 2126 | /* Get and attach to service */ |
|---|
| 1820 | 2127 | ret = mpp_attach_service(mpp, dev); |
|---|
| .. | .. |
|---|
| 1823 | 2130 | return -ENODEV; |
|---|
| 1824 | 2131 | } |
|---|
| 1825 | 2132 | |
|---|
| 1826 | | - mpp->dev = dev; |
|---|
| 1827 | | - mpp->hw_ops = mpp->var->hw_ops; |
|---|
| 1828 | | - mpp->dev_ops = mpp->var->dev_ops; |
|---|
| 1829 | | - |
|---|
| 1830 | | - /* read link table capacity */ |
|---|
| 1831 | | - ret = of_property_read_u32(np, "rockchip,task-capacity", |
|---|
| 1832 | | - &mpp->task_capacity); |
|---|
| 1833 | | - if (ret) { |
|---|
| 1834 | | - mpp->task_capacity = 1; |
|---|
| 1835 | | - |
|---|
| 1836 | | - /* power domain autosuspend delay 2s */ |
|---|
| 1837 | | - pm_runtime_set_autosuspend_delay(dev, 2000); |
|---|
| 1838 | | - pm_runtime_use_autosuspend(dev); |
|---|
| 1839 | | - } else { |
|---|
| 1840 | | - dev_info(dev, "%d task capacity link mode detected\n", |
|---|
| 1841 | | - mpp->task_capacity); |
|---|
| 1842 | | - /* do not setup autosuspend on multi task device */ |
|---|
| 1843 | | - } |
|---|
| 2133 | + /* power domain autosuspend delay 2s */ |
|---|
| 2134 | + pm_runtime_set_autosuspend_delay(dev, 2000); |
|---|
| 2135 | + pm_runtime_use_autosuspend(dev); |
|---|
| 1844 | 2136 | |
|---|
| 1845 | 2137 | kthread_init_work(&mpp->work, mpp_task_worker_default); |
|---|
| 1846 | 2138 | |
|---|
| .. | .. |
|---|
| 1851 | 2143 | |
|---|
| 1852 | 2144 | device_init_wakeup(dev, true); |
|---|
| 1853 | 2145 | pm_runtime_enable(dev); |
|---|
| 1854 | | - |
|---|
| 1855 | 2146 | mpp->irq = platform_get_irq(pdev, 0); |
|---|
| 1856 | 2147 | if (mpp->irq < 0) { |
|---|
| 1857 | 2148 | dev_err(dev, "No interrupt resource found\n"); |
|---|
| .. | .. |
|---|
| 1878 | 2169 | ret = -ENOMEM; |
|---|
| 1879 | 2170 | goto failed; |
|---|
| 1880 | 2171 | } |
|---|
| 2172 | + mpp->io_base = res->start; |
|---|
| 1881 | 2173 | |
|---|
| 1882 | | - pm_runtime_get_sync(dev); |
|---|
| 1883 | 2174 | /* |
|---|
| 1884 | 2175 | * TODO: here or at the device itself, some device does not |
|---|
| 1885 | 2176 | * have the iommu, maybe in the device is better. |
|---|
| 1886 | 2177 | */ |
|---|
| 1887 | 2178 | mpp->iommu_info = mpp_iommu_probe(dev); |
|---|
| 1888 | 2179 | if (IS_ERR(mpp->iommu_info)) { |
|---|
| 1889 | | - dev_err(dev, "failed to attach iommu: %ld\n", |
|---|
| 1890 | | - PTR_ERR(mpp->iommu_info)); |
|---|
| 2180 | + dev_err(dev, "failed to attach iommu\n"); |
|---|
| 2181 | + mpp->iommu_info = NULL; |
|---|
| 1891 | 2182 | } |
|---|
| 1892 | 2183 | if (mpp->hw_ops->init) { |
|---|
| 1893 | 2184 | ret = mpp->hw_ops->init(mpp); |
|---|
| 1894 | 2185 | if (ret) |
|---|
| 1895 | | - goto failed_init; |
|---|
| 2186 | + goto failed; |
|---|
| 1896 | 2187 | } |
|---|
| 1897 | | - /* set iommu fault handler */ |
|---|
| 1898 | | - if (!IS_ERR(mpp->iommu_info)) |
|---|
| 1899 | | - iommu_set_fault_handler(mpp->iommu_info->domain, |
|---|
| 1900 | | - mpp_iommu_handle, mpp->queue); |
|---|
| 1901 | 2188 | |
|---|
| 1902 | 2189 | /* read hardware id */ |
|---|
| 1903 | 2190 | if (hw_info->reg_id >= 0) { |
|---|
| 2191 | + pm_runtime_get_sync(dev); |
|---|
| 1904 | 2192 | if (mpp->hw_ops->clk_on) |
|---|
| 1905 | 2193 | mpp->hw_ops->clk_on(mpp); |
|---|
| 1906 | 2194 | |
|---|
| 1907 | 2195 | hw_info->hw_id = mpp_read(mpp, hw_info->reg_id * sizeof(u32)); |
|---|
| 1908 | 2196 | if (mpp->hw_ops->clk_off) |
|---|
| 1909 | 2197 | mpp->hw_ops->clk_off(mpp); |
|---|
| 2198 | + pm_runtime_put_sync(dev); |
|---|
| 1910 | 2199 | } |
|---|
| 1911 | 2200 | |
|---|
| 1912 | | - pm_runtime_put_sync(dev); |
|---|
| 1913 | | - |
|---|
| 1914 | 2201 | return ret; |
|---|
| 1915 | | -failed_init: |
|---|
| 1916 | | - pm_runtime_put_sync(dev); |
|---|
| 1917 | 2202 | failed: |
|---|
| 1918 | 2203 | mpp_detach_workqueue(mpp); |
|---|
| 1919 | 2204 | device_init_wakeup(dev, false); |
|---|
| .. | .. |
|---|
| 1928 | 2213 | mpp->hw_ops->exit(mpp); |
|---|
| 1929 | 2214 | |
|---|
| 1930 | 2215 | mpp_iommu_remove(mpp->iommu_info); |
|---|
| 1931 | | - platform_device_put(mpp->pdev_srv); |
|---|
| 1932 | 2216 | mpp_detach_workqueue(mpp); |
|---|
| 1933 | 2217 | device_init_wakeup(mpp->dev, false); |
|---|
| 1934 | 2218 | pm_runtime_disable(mpp->dev); |
|---|
| 1935 | 2219 | |
|---|
| 1936 | 2220 | return 0; |
|---|
| 2221 | +} |
|---|
| 2222 | + |
|---|
| 2223 | +void mpp_dev_shutdown(struct platform_device *pdev) |
|---|
| 2224 | +{ |
|---|
| 2225 | + int ret; |
|---|
| 2226 | + int val; |
|---|
| 2227 | + struct device *dev = &pdev->dev; |
|---|
| 2228 | + struct mpp_dev *mpp = dev_get_drvdata(dev); |
|---|
| 2229 | + |
|---|
| 2230 | + dev_info(dev, "shutdown device\n"); |
|---|
| 2231 | + |
|---|
| 2232 | + atomic_inc(&mpp->srv->shutdown_request); |
|---|
| 2233 | + ret = readx_poll_timeout(atomic_read, |
|---|
| 2234 | + &mpp->task_count, |
|---|
| 2235 | + val, val == 0, 20000, 200000); |
|---|
| 2236 | + if (ret == -ETIMEDOUT) |
|---|
| 2237 | + dev_err(dev, "wait total %d running time out\n", |
|---|
| 2238 | + atomic_read(&mpp->task_count)); |
|---|
| 2239 | + else |
|---|
| 2240 | + dev_info(dev, "shutdown success\n"); |
|---|
| 1937 | 2241 | } |
|---|
| 1938 | 2242 | |
|---|
| 1939 | 2243 | int mpp_dev_register_srv(struct mpp_dev *mpp, struct mpp_service *srv) |
|---|
| .. | .. |
|---|
| 1951 | 2255 | struct mpp_dev *mpp = param; |
|---|
| 1952 | 2256 | struct mpp_task *task = mpp->cur_task; |
|---|
| 1953 | 2257 | irqreturn_t irq_ret = IRQ_NONE; |
|---|
| 2258 | + u32 timing_en = mpp->srv->timing_en; |
|---|
| 2259 | + |
|---|
| 2260 | + if (task && timing_en) { |
|---|
| 2261 | + task->on_irq = ktime_get(); |
|---|
| 2262 | + set_bit(TASK_TIMING_IRQ, &task->state); |
|---|
| 2263 | + } |
|---|
| 1954 | 2264 | |
|---|
| 1955 | 2265 | if (mpp->dev_ops->irq) |
|---|
| 1956 | 2266 | irq_ret = mpp->dev_ops->irq(mpp); |
|---|
| .. | .. |
|---|
| 1966 | 2276 | irq_ret = IRQ_HANDLED; |
|---|
| 1967 | 2277 | goto done; |
|---|
| 1968 | 2278 | } |
|---|
| 2279 | + if (timing_en) { |
|---|
| 2280 | + task->on_cancel_timeout = ktime_get(); |
|---|
| 2281 | + set_bit(TASK_TIMING_TO_CANCEL, &task->state); |
|---|
| 2282 | + } |
|---|
| 1969 | 2283 | cancel_delayed_work(&task->timeout_work); |
|---|
| 1970 | 2284 | /* normal condition, set state and wake up isr thread */ |
|---|
| 1971 | 2285 | set_bit(TASK_STATE_IRQ, &task->state); |
|---|
| 1972 | 2286 | } |
|---|
| 2287 | + |
|---|
| 2288 | + if (irq_ret == IRQ_WAKE_THREAD) |
|---|
| 2289 | + mpp_iommu_dev_deactivate(mpp->iommu_info, mpp); |
|---|
| 1973 | 2290 | } else { |
|---|
| 1974 | 2291 | mpp_debug(DEBUG_IRQ_CHECK, "error, task is null\n"); |
|---|
| 1975 | 2292 | } |
|---|
| .. | .. |
|---|
| 1981 | 2298 | { |
|---|
| 1982 | 2299 | irqreturn_t ret = IRQ_NONE; |
|---|
| 1983 | 2300 | struct mpp_dev *mpp = param; |
|---|
| 2301 | + struct mpp_task *task = mpp->cur_task; |
|---|
| 2302 | + |
|---|
| 2303 | + if (task && mpp->srv->timing_en) { |
|---|
| 2304 | + task->on_isr = ktime_get(); |
|---|
| 2305 | + set_bit(TASK_TIMING_ISR, &task->state); |
|---|
| 2306 | + } |
|---|
| 1984 | 2307 | |
|---|
| 1985 | 2308 | if (mpp->auto_freq_en && |
|---|
| 1986 | 2309 | mpp->hw_ops->reduce_freq && |
|---|
| .. | .. |
|---|
| 2030 | 2353 | |
|---|
| 2031 | 2354 | int mpp_time_record(struct mpp_task *task) |
|---|
| 2032 | 2355 | { |
|---|
| 2033 | | - if (mpp_debug_unlikely(DEBUG_TIMING) && task) |
|---|
| 2034 | | - do_gettimeofday(&task->start); |
|---|
| 2356 | + if (mpp_debug_unlikely(DEBUG_TIMING) && task) { |
|---|
| 2357 | + task->start = ktime_get(); |
|---|
| 2358 | + task->part = task->start; |
|---|
| 2359 | + } |
|---|
| 2360 | + |
|---|
| 2361 | + return 0; |
|---|
| 2362 | +} |
|---|
| 2363 | + |
|---|
| 2364 | +int mpp_time_part_diff(struct mpp_task *task) |
|---|
| 2365 | +{ |
|---|
| 2366 | + if (mpp_debug_unlikely(DEBUG_TIMING)) { |
|---|
| 2367 | + ktime_t end; |
|---|
| 2368 | + struct mpp_dev *mpp = mpp_get_task_used_device(task, task->session); |
|---|
| 2369 | + |
|---|
| 2370 | + end = ktime_get(); |
|---|
| 2371 | + mpp_debug(DEBUG_PART_TIMING, "%s:%d session %d:%d part time: %lld us\n", |
|---|
| 2372 | + dev_name(mpp->dev), task->core_id, task->session->pid, |
|---|
| 2373 | + task->session->index, ktime_us_delta(end, task->part)); |
|---|
| 2374 | + task->part = end; |
|---|
| 2375 | + } |
|---|
| 2035 | 2376 | |
|---|
| 2036 | 2377 | return 0; |
|---|
| 2037 | 2378 | } |
|---|
| 2038 | 2379 | |
|---|
| 2039 | 2380 | int mpp_time_diff(struct mpp_task *task) |
|---|
| 2040 | 2381 | { |
|---|
| 2041 | | - struct timeval end; |
|---|
| 2042 | | - struct mpp_dev *mpp = task->session->mpp; |
|---|
| 2382 | + if (mpp_debug_unlikely(DEBUG_TIMING)) { |
|---|
| 2383 | + ktime_t end; |
|---|
| 2384 | + struct mpp_dev *mpp = mpp_get_task_used_device(task, task->session); |
|---|
| 2043 | 2385 | |
|---|
| 2044 | | - do_gettimeofday(&end); |
|---|
| 2045 | | - mpp_debug(DEBUG_TIMING, "%s: pid: %d, session: %p, time: %ld us\n", |
|---|
| 2046 | | - dev_name(mpp->dev), task->session->pid, task->session, |
|---|
| 2047 | | - (end.tv_sec - task->start.tv_sec) * 1000000 + |
|---|
| 2048 | | - (end.tv_usec - task->start.tv_usec)); |
|---|
| 2386 | + end = ktime_get(); |
|---|
| 2387 | + mpp_debug(DEBUG_TIMING, "%s:%d session %d:%d time: %lld us\n", |
|---|
| 2388 | + dev_name(mpp->dev), task->core_id, task->session->pid, |
|---|
| 2389 | + task->session->index, ktime_us_delta(end, task->start)); |
|---|
| 2390 | + } |
|---|
| 2049 | 2391 | |
|---|
| 2050 | 2392 | return 0; |
|---|
| 2393 | +} |
|---|
| 2394 | + |
|---|
| 2395 | +int mpp_time_diff_with_hw_time(struct mpp_task *task, u32 clk_hz) |
|---|
| 2396 | +{ |
|---|
| 2397 | + if (mpp_debug_unlikely(DEBUG_TIMING)) { |
|---|
| 2398 | + ktime_t end; |
|---|
| 2399 | + struct mpp_dev *mpp = mpp_get_task_used_device(task, task->session); |
|---|
| 2400 | + |
|---|
| 2401 | + end = ktime_get(); |
|---|
| 2402 | + |
|---|
| 2403 | + if (clk_hz) |
|---|
| 2404 | + mpp_debug(DEBUG_TIMING, "%s:%d session %d:%d time: %lld us hw %d us\n", |
|---|
| 2405 | + dev_name(mpp->dev), task->core_id, task->session->pid, |
|---|
| 2406 | + task->session->index, ktime_us_delta(end, task->start), |
|---|
| 2407 | + task->hw_cycles / (clk_hz / 1000000)); |
|---|
| 2408 | + else |
|---|
| 2409 | + mpp_debug(DEBUG_TIMING, "%s:%d session %d:%d time: %lld us\n", |
|---|
| 2410 | + dev_name(mpp->dev), task->core_id, task->session->pid, |
|---|
| 2411 | + task->session->index, ktime_us_delta(end, task->start)); |
|---|
| 2412 | + } |
|---|
| 2413 | + |
|---|
| 2414 | + return 0; |
|---|
| 2415 | +} |
|---|
| 2416 | + |
|---|
| 2417 | +#define LOG_TIMING(state, id, stage, time, base) \ |
|---|
| 2418 | + do { \ |
|---|
| 2419 | + if (test_bit(id, &state)) \ |
|---|
| 2420 | + pr_info("timing: %-14s : %lld us\n", stage, ktime_us_delta(time, base)); \ |
|---|
| 2421 | + else \ |
|---|
| 2422 | + pr_info("timing: %-14s : invalid\n", stage); \ |
|---|
| 2423 | + } while (0) |
|---|
| 2424 | + |
|---|
| 2425 | +void mpp_task_dump_timing(struct mpp_task *task, s64 time_diff) |
|---|
| 2426 | +{ |
|---|
| 2427 | + ktime_t s = task->on_create; |
|---|
| 2428 | + unsigned long state = task->state; |
|---|
| 2429 | + |
|---|
| 2430 | + pr_info("task %d dump timing at %lld us:", task->task_id, time_diff); |
|---|
| 2431 | + |
|---|
| 2432 | + pr_info("timing: %-14s : %lld us\n", "create", ktime_to_us(s)); |
|---|
| 2433 | + LOG_TIMING(state, TASK_TIMING_CREATE_END, "create end", task->on_create_end, s); |
|---|
| 2434 | + LOG_TIMING(state, TASK_TIMING_PENDING, "pending", task->on_pending, s); |
|---|
| 2435 | + LOG_TIMING(state, TASK_TIMING_RUN, "run", task->on_run, s); |
|---|
| 2436 | + LOG_TIMING(state, TASK_TIMING_TO_SCHED, "timeout start", task->on_sched_timeout, s); |
|---|
| 2437 | + LOG_TIMING(state, TASK_TIMING_RUN_END, "run end", task->on_run_end, s); |
|---|
| 2438 | + LOG_TIMING(state, TASK_TIMING_IRQ, "irq", task->on_irq, s); |
|---|
| 2439 | + LOG_TIMING(state, TASK_TIMING_TO_CANCEL, "timeout cancel", task->on_cancel_timeout, s); |
|---|
| 2440 | + LOG_TIMING(state, TASK_TIMING_ISR, "isr", task->on_isr, s); |
|---|
| 2441 | + LOG_TIMING(state, TASK_TIMING_FINISH, "finish", task->on_finish, s); |
|---|
| 2051 | 2442 | } |
|---|
| 2052 | 2443 | |
|---|
| 2053 | 2444 | int mpp_write_req(struct mpp_dev *mpp, u32 *regs, |
|---|
| .. | .. |
|---|
| 2184 | 2575 | if (clk_rate_hz) { |
|---|
| 2185 | 2576 | clk_info->used_rate_hz = clk_rate_hz; |
|---|
| 2186 | 2577 | clk_set_rate(clk_info->clk, clk_rate_hz); |
|---|
| 2578 | + clk_info->real_rate_hz = clk_get_rate(clk_info->clk); |
|---|
| 2187 | 2579 | } |
|---|
| 2188 | 2580 | |
|---|
| 2189 | 2581 | return 0; |
|---|
| .. | .. |
|---|
| 2217 | 2609 | return count; |
|---|
| 2218 | 2610 | } |
|---|
| 2219 | 2611 | |
|---|
| 2220 | | -static const struct file_operations procfs_fops_u32 = { |
|---|
| 2221 | | - .open = fops_open_u32, |
|---|
| 2222 | | - .read = seq_read, |
|---|
| 2223 | | - .release = single_release, |
|---|
| 2224 | | - .write = fops_write_u32, |
|---|
| 2612 | +static const struct proc_ops procfs_fops_u32 = { |
|---|
| 2613 | + .proc_open = fops_open_u32, |
|---|
| 2614 | + .proc_read = seq_read, |
|---|
| 2615 | + .proc_release = single_release, |
|---|
| 2616 | + .proc_write = fops_write_u32, |
|---|
| 2225 | 2617 | }; |
|---|
| 2226 | 2618 | |
|---|
| 2227 | 2619 | struct proc_dir_entry * |
|---|
| .. | .. |
|---|
| 2230 | 2622 | { |
|---|
| 2231 | 2623 | return proc_create_data(name, mode, parent, &procfs_fops_u32, data); |
|---|
| 2232 | 2624 | } |
|---|
| 2625 | + |
|---|
| 2626 | +void mpp_procfs_create_common(struct proc_dir_entry *parent, struct mpp_dev *mpp) |
|---|
| 2627 | +{ |
|---|
| 2628 | + mpp_procfs_create_u32("disable_work", 0644, parent, &mpp->disable); |
|---|
| 2629 | + mpp_procfs_create_u32("timing_check", 0644, parent, &mpp->timing_check); |
|---|
| 2630 | +} |
|---|
| 2233 | 2631 | #endif |
|---|