Skip to content

Commit 0ea92dc

Browse files
author
Jacopo Mondi
committed
media: pisp_be: Split jobs creation and scheduling
Currently the 'pispbe_schedule()' function does two things: 1) Tries to assemble a job by inspecting all the video node queues to make sure all the required buffers are available 2) Submit the job to the hardware The pispbe_schedule() function is called at: - video device start_streaming() time - video device qbuf() time - irq handler As assembling a job requires inspecting all queues, it is a rather time consuming operation which is better not run in IRQ context. To avoid the executing the time consuming job creation in interrupt context split the job creation and job scheduling in two distinct operations. When a well-formed job is created, append it to the newly introduced 'pispbe->job_queue' where it will be dequeued from by the scheduling routine. As the per-node 'ready_queue' buffer list is only accessed in vb2 ops callbacks, protected by a mutex, it is not necessary to guard it with a dedicated spinlock so drop it. Also use the spin_lock_irq() variant in all functions not called from an IRQ context where the spin_lock_irqsave() version was used. Signed-off-by: Jacopo Mondi <[email protected]>
1 parent e6ab8e2 commit 0ea92dc

File tree

1 file changed

+86
-82
lines changed
  • drivers/media/platform/raspberrypi/pisp_be

1 file changed

+86
-82
lines changed

drivers/media/platform/raspberrypi/pisp_be/pisp_be.c

Lines changed: 86 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,6 @@ struct pispbe_node {
172172
struct mutex node_lock;
173173
/* vb2_queue lock */
174174
struct mutex queue_lock;
175-
/* Protect pispbe_node->ready_queue and pispbe_buffer->ready_list */
176-
spinlock_t ready_lock;
177175
struct list_head ready_queue;
178176
struct vb2_queue queue;
179177
struct v4l2_format format;
@@ -219,6 +217,9 @@ struct pispbe_hw_enables {
219217

220218
/* Records a job configuration and memory addresses. */
221219
struct pispbe_job_descriptor {
220+
struct list_head queue;
221+
struct pispbe_buffer *buffers[PISPBE_NUM_NODES];
222+
struct pispbe_node_group *node_group;
222223
dma_addr_t hw_dma_addrs[N_HW_ADDRESSES];
223224
struct pisp_be_tiles_config *config;
224225
struct pispbe_hw_enables hw_enables;
@@ -235,8 +236,10 @@ struct pispbe_dev {
235236
struct clk *clk;
236237
struct pispbe_node_group node_group[PISPBE_NUM_NODE_GROUPS];
237238
struct pispbe_job queued_job, running_job;
238-
spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */
239+
/* protects "hw_busy" flag, streaming_map and job_queue */
240+
spinlock_t hw_lock;
239241
bool hw_busy; /* non-zero if a job is queued or is being started */
242+
struct list_head job_queue;
240243
int irq;
241244
u32 hw_version;
242245
u8 done, started;
@@ -460,42 +463,48 @@ static void pispbe_xlate_addrs(struct pispbe_job_descriptor *job,
460463
* For Output0, Output1, Tdn and Stitch, a buffer only needs to be
461464
* available if the blocks are enabled in the config.
462465
*
463-
* Needs to be called with hw_lock held.
466+
* If all the buffers required to form a job are available, append the
467+
* job descriptor to the job queue to be later queued to the HW.
464468
*
465469
* Returns 0 if a job has been successfully prepared, < 0 otherwise.
466470
*/
467-
static int pispbe_prepare_job(struct pispbe_node_group *node_group,
468-
struct pispbe_job_descriptor *job)
471+
static int pispbe_prepare_job(struct pispbe_node_group *node_group)
469472
{
470473
struct pispbe_buffer *buf[PISPBE_NUM_NODES] = {};
471474
struct pispbe_dev *pispbe = node_group->pispbe;
475+
struct pispbe_job_descriptor *job;
476+
unsigned int streaming_map;
472477
unsigned int config_index;
473478
struct pispbe_node *node;
474-
unsigned long flags;
475479

476-
lockdep_assert_held(&pispbe->hw_lock);
480+
scoped_guard(spinlock_irq, &pispbe->hw_lock) {
481+
static const u32 mask = BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE);
477482

478-
memset(job, 0, sizeof(struct pispbe_job_descriptor));
483+
if ((node_group->streaming_map & mask) != mask)
484+
return -ENODEV;
479485

480-
if (((BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)) &
481-
node_group->streaming_map) !=
482-
(BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)))
483-
return -ENODEV;
486+
/*
487+
* Take a copy of streaming_map: nodes activated after this
488+
* point are ignored when preparing this job.
489+
*/
490+
streaming_map = node_group->streaming_map;
491+
}
492+
493+
job = kzalloc(sizeof(*job), GFP_KERNEL);
494+
if (!job)
495+
return -ENOMEM;
484496

485497
node = &node_group->node[CONFIG_NODE];
486-
spin_lock_irqsave(&node->ready_lock, flags);
487498
buf[CONFIG_NODE] = list_first_entry_or_null(&node->ready_queue,
488499
struct pispbe_buffer,
489500
ready_list);
490-
if (buf[CONFIG_NODE]) {
491-
list_del(&buf[CONFIG_NODE]->ready_list);
492-
pispbe->queued_job.buf[CONFIG_NODE] = buf[CONFIG_NODE];
501+
if (!buf[CONFIG_NODE]) {
502+
kfree(job);
503+
return -ENODEV;
493504
}
494-
spin_unlock_irqrestore(&node->ready_lock, flags);
495505

496-
/* Exit early if no config buffer has been queued. */
497-
if (!buf[CONFIG_NODE])
498-
return -ENODEV;
506+
list_del(&buf[CONFIG_NODE]->ready_list);
507+
job->buffers[CONFIG_NODE] = buf[CONFIG_NODE];
499508

500509
config_index = buf[CONFIG_NODE]->vb.vb2_buf.index;
501510
job->config = &node_group->config[config_index];
@@ -516,7 +525,7 @@ static int pispbe_prepare_job(struct pispbe_node_group *node_group,
516525
continue;
517526

518527
buf[i] = NULL;
519-
if (!(node_group->streaming_map & BIT(i)))
528+
if (!(streaming_map & BIT(i)))
520529
continue;
521530

522531
if ((!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT0) &&
@@ -543,25 +552,27 @@ static int pispbe_prepare_job(struct pispbe_node_group *node_group,
543552
node = &node_group->node[i];
544553

545554
/* Pull a buffer from each V4L2 queue to form the queued job */
546-
spin_lock_irqsave(&node->ready_lock, flags);
547555
buf[i] = list_first_entry_or_null(&node->ready_queue,
548556
struct pispbe_buffer,
549557
ready_list);
550558
if (buf[i]) {
551559
list_del(&buf[i]->ready_list);
552-
pispbe->queued_job.buf[i] = buf[i];
560+
job->buffers[i] = buf[i];
553561
}
554-
spin_unlock_irqrestore(&node->ready_lock, flags);
555562

556563
if (!buf[i] && !ignore_buffers)
557564
goto err_return_buffers;
558565
}
559566

560-
pispbe->queued_job.node_group = node_group;
567+
job->node_group = node_group;
561568

562569
/* Convert buffers to DMA addresses for the hardware */
563570
pispbe_xlate_addrs(job, buf, node_group);
564571

572+
spin_lock(&pispbe->hw_lock);
573+
list_add_tail(&job->queue, &pispbe->job_queue);
574+
spin_unlock(&pispbe->hw_lock);
575+
565576
return 0;
566577

567578
err_return_buffers:
@@ -572,12 +583,10 @@ static int pispbe_prepare_job(struct pispbe_node_group *node_group,
572583
continue;
573584

574585
/* Return the buffer to the ready_list queue */
575-
spin_lock_irqsave(&n->ready_lock, flags);
576586
list_add(&buf[i]->ready_list, &n->ready_queue);
577-
spin_unlock_irqrestore(&n->ready_lock, flags);
578587
}
579588

580-
memset(&pispbe->queued_job, 0, sizeof(pispbe->queued_job));
589+
kfree(job);
581590

582591
return -ENODEV;
583592
}
@@ -586,49 +595,41 @@ static void pispbe_schedule(struct pispbe_dev *pispbe,
586595
struct pispbe_node_group *node_group,
587596
bool clear_hw_busy)
588597
{
589-
struct pispbe_job_descriptor job;
590-
unsigned long flags;
591-
592-
spin_lock_irqsave(&pispbe->hw_lock, flags);
593-
594-
if (clear_hw_busy)
595-
pispbe->hw_busy = false;
598+
struct pispbe_job_descriptor *job;
596599

597-
if (pispbe->hw_busy)
598-
goto unlock_and_return;
600+
scoped_guard(spinlock_irqsave, &pispbe->hw_lock) {
601+
if (clear_hw_busy)
602+
pispbe->hw_busy = false;
599603

600-
for (unsigned int i = 0; i < PISPBE_NUM_NODE_GROUPS; i++) {
601-
int ret;
604+
if (pispbe->hw_busy)
605+
return;
602606

603-
/* Schedule jobs only for a specific group. */
604-
if (node_group && &pispbe->node_group[i] != node_group)
605-
continue;
607+
job = list_first_entry_or_null(&pispbe->job_queue,
608+
struct pispbe_job_descriptor,
609+
queue);
610+
if (!job)
611+
return;
606612

607-
/*
608-
* Prepare a job for this group, if the group is not ready
609-
* continue and try with the next one.
610-
*/
611-
ret = pispbe_prepare_job(&pispbe->node_group[i], &job);
612-
if (ret)
613+
if (node_group && job->node_group != node_group)
613614
continue;
614615

615-
/*
616-
* We can kick the job off without the hw_lock, as this can
617-
* never run again until hw_busy is cleared, which will happen
618-
* only when the following job has been queued and an interrupt
619-
* is rised.
620-
*/
621-
pispbe->hw_busy = true;
622-
spin_unlock_irqrestore(&pispbe->hw_lock, flags);
616+
list_del(&job->queue);
623617

624-
pispbe_queue_job(pispbe, &job);
618+
for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++)
619+
pispbe->queued_job.buf[i] = job->buffers[i];
620+
pispbe->queued_job.node_group = job->node_group;
625621

626-
return;
622+
pispbe->hw_busy = true;
627623
}
628624

629-
unlock_and_return:
630-
/* No job has been queued, just release the lock and return. */
631-
spin_unlock_irqrestore(&pispbe->hw_lock, flags);
625+
/*
626+
* We can kick the job off without the hw_lock, as this can
627+
* never run again until hw_busy is cleared, which will happen
628+
* only when the following job has been queued and an interrupt
629+
* is rised.
630+
*/
631+
pispbe_queue_job(pispbe, job);
632+
kfree(job);
632633
}
633634

634635
static void pispbe_isr_jobdone(struct pispbe_dev *pispbe,
@@ -881,18 +882,16 @@ static void pispbe_node_buffer_queue(struct vb2_buffer *buf)
881882
struct pispbe_node *node = vb2_get_drv_priv(buf->vb2_queue);
882883
struct pispbe_node_group *node_group = node->node_group;
883884
struct pispbe_dev *pispbe = node->node_group->pispbe;
884-
unsigned long flags;
885885

886886
dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node));
887-
spin_lock_irqsave(&node->ready_lock, flags);
888887
list_add_tail(&buffer->ready_list, &node->ready_queue);
889-
spin_unlock_irqrestore(&node->ready_lock, flags);
890888

891889
/*
892890
* Every time we add a buffer, check if there's now some work for the hw
893891
* to do, but only for this client.
894892
*/
895-
pispbe_schedule(node_group->pispbe, node_group, false);
893+
if (!pispbe_prepare_job(node_group))
894+
pispbe_schedule(pispbe, node_group, false);
896895
}
897896

898897
static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count)
@@ -901,35 +900,33 @@ static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count)
901900
struct pispbe_node_group *node_group = node->node_group;
902901
struct pispbe_dev *pispbe = node_group->pispbe;
903902
struct pispbe_buffer *buf, *tmp;
904-
unsigned long flags;
905903
int ret;
906904

907905
ret = pm_runtime_resume_and_get(pispbe->dev);
908906
if (ret < 0)
909907
goto err_return_buffers;
910908

911-
spin_lock_irqsave(&pispbe->hw_lock, flags);
909+
spin_lock_irq(&pispbe->hw_lock);
912910
node->node_group->streaming_map |= BIT(node->id);
913911
node->node_group->sequence = 0;
914-
spin_unlock_irqrestore(&pispbe->hw_lock, flags);
912+
spin_unlock_irq(&pispbe->hw_lock);
915913

916914
dev_dbg(pispbe->dev, "%s: for node %s (count %u)\n",
917915
__func__, NODE_NAME(node), count);
918916
dev_dbg(pispbe->dev, "Nodes streaming for this group now 0x%x\n",
919917
node->node_group->streaming_map);
920918

921919
/* Maybe we're ready to run. */
922-
pispbe_schedule(node_group->pispbe, node_group, false);
920+
if (!pispbe_prepare_job(node_group))
921+
pispbe_schedule(pispbe, node_group, false);
923922

924923
return 0;
925924

926925
err_return_buffers:
927-
spin_lock_irqsave(&pispbe->hw_lock, flags);
928926
list_for_each_entry_safe(buf, tmp, &node->ready_queue, ready_list) {
929927
list_del(&buf->ready_list);
930928
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
931929
}
932-
spin_unlock_irqrestore(&pispbe->hw_lock, flags);
933930

934931
return ret;
935932
}
@@ -940,7 +937,6 @@ static void pispbe_node_stop_streaming(struct vb2_queue *q)
940937
struct pispbe_node_group *node_group = node->node_group;
941938
struct pispbe_dev *pispbe = node_group->pispbe;
942939
struct pispbe_buffer *buf;
943-
unsigned long flags;
944940

945941
/*
946942
* Now this is a bit awkward. In a simple M2M device we could just wait
@@ -952,27 +948,34 @@ static void pispbe_node_stop_streaming(struct vb2_queue *q)
952948
* This may return buffers out of order.
953949
*/
954950
dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node));
955-
spin_lock_irqsave(&pispbe->hw_lock, flags);
956951
do {
957-
unsigned long flags1;
958-
959-
spin_lock_irqsave(&node->ready_lock, flags1);
960952
buf = list_first_entry_or_null(&node->ready_queue,
961953
struct pispbe_buffer,
962954
ready_list);
963955
if (buf) {
964956
list_del(&buf->ready_list);
965957
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
966958
}
967-
spin_unlock_irqrestore(&node->ready_lock, flags1);
968959
} while (buf);
969-
spin_unlock_irqrestore(&pispbe->hw_lock, flags);
970960

971961
vb2_wait_for_all_buffers(&node->queue);
972962

973-
spin_lock_irqsave(&pispbe->hw_lock, flags);
963+
spin_lock_irq(&pispbe->hw_lock);
974964
node_group->streaming_map &= ~BIT(node->id);
975-
spin_unlock_irqrestore(&pispbe->hw_lock, flags);
965+
966+
/* Release all jobs in the group once all nodes have stopped streaming. */
967+
if (node_group->streaming_map == 0) {
968+
struct pispbe_job_descriptor *job, *temp;
969+
970+
list_for_each_entry_safe(job, temp, &pispbe->job_queue, queue) {
971+
if (job->node_group != node_group)
972+
continue;
973+
974+
list_del(&job->queue);
975+
kfree(job);
976+
}
977+
}
978+
spin_unlock_irq(&pispbe->hw_lock);
976979

977980
pm_runtime_mark_last_busy(pispbe->dev);
978981
pm_runtime_put_autosuspend(pispbe->dev);
@@ -1432,7 +1435,6 @@ static int pispbe_init_node(struct pispbe_node_group *node_group,
14321435
mutex_init(&node->node_lock);
14331436
mutex_init(&node->queue_lock);
14341437
INIT_LIST_HEAD(&node->ready_queue);
1435-
spin_lock_init(&node->ready_lock);
14361438

14371439
node->format.type = node->buf_type;
14381440
pispbe_node_def_fmt(node);
@@ -1731,6 +1733,8 @@ static int pispbe_probe(struct platform_device *pdev)
17311733
if (!pispbe)
17321734
return -ENOMEM;
17331735

1736+
INIT_LIST_HEAD(&pispbe->job_queue);
1737+
17341738
dev_set_drvdata(&pdev->dev, pispbe);
17351739
pispbe->dev = &pdev->dev;
17361740
platform_set_drvdata(pdev, pispbe);

0 commit comments

Comments
 (0)