struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, struct cx18_queue *q, int to_front)
{ /* clear the mdl if it is not to be enqueued to the full queue */ if (q != &s->q_full) {
mdl->bytesused = 0;
mdl->readpos = 0;
mdl->m_flags = 0;
mdl->skipped = 0;
mdl->curr_buf = NULL;
}
/* q_busy is restricted to a max buffer count imposed by firmware */ if (q == &s->q_busy &&
atomic_read(&q->depth) >= CX18_MAX_FW_MDLS_PER_STREAM)
q = &s->q_free;
/* *Wedon'thavetoacquiremultipleqlockshere,becauseweare *serializedbythesinglethreadedworkhandler. *MDLsfromthefirmwarewillthusremaininorderas *theyaremovedfromq_busytoq_fullortothedvbringbuffer.
*/
spin_lock(&s->q_busy.lock);
list_for_each_entry_safe(mdl, tmp, &s->q_busy.list, list) { /* *Weshouldfindwhatthefirmwaretoldusisdone, *rightatthefrontofthequeue.Ifwedon't,welikelyhave *missedanmdldonemessagefromthefirmware. *Onceweskipanmdlrepeatedly,relativetothesizeof *q_busy,wehavehighconfidencewe'vemissedit.
*/ if (mdl->id != id) {
mdl->skipped++; if (mdl->skipped >= atomic_read(&s->q_busy.depth)-1) { /* mdl must have fallen out of rotation */
CX18_WARN("Skipped %s, MDL %d, %d times - it must have dropped out of rotation\n",
s->name, mdl->id,
mdl->skipped); /* Sweep it up to put it back into rotation */
list_move_tail(&mdl->list, &sweep_up);
atomic_dec(&s->q_busy.depth);
} continue;
} /* *Wepullthedesiredmdloffofthequeuehere.Something *willhavetoputitbackonaqueuelater.
*/
list_del_init(&mdl->list);
atomic_dec(&s->q_busy.depth);
ret = mdl; break;
}
spin_unlock(&s->q_busy.lock);
/* *Wefoundthemdlforwhichwewerelooking.Getitreadyfor *thecallertoputonq_fullorinthedvbringbuffer.
*/ if (ret != NULL) {
ret->bytesused = bytesused;
ret->skipped = 0; /* 0'ed readpos, m_flags & curr_buf when mdl went on q_busy */
cx18_mdl_update_bufs_for_cpu(s, ret); if (s->type != CX18_ENC_STREAM_TYPE_TS)
set_bit(CX18_F_M_NEED_SWAP, &ret->m_flags);
}
/* Put any mdls the firmware is ignoring back into normal rotation */
list_for_each_entry_safe(mdl, tmp, &sweep_up, list) {
list_del_init(&mdl->list);
cx18_enqueue(s, mdl, &s->q_free);
} return ret;
}
/* Move all mdls of a queue, while flushing the mdl */ staticvoid cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q_src, struct cx18_queue *q_dst)
{ struct cx18_mdl *mdl;
/* It only makes sense to flush to q_free or q_idle */ if (q_src == q_dst || q_dst == &s->q_full || q_dst == &s->q_busy) return;
/* Move all MDLS to q_idle */
cx18_queue_flush(s, &s->q_busy, q_idle);
cx18_queue_flush(s, &s->q_full, q_idle);
cx18_queue_flush(s, &s->q_free, q_idle);
/* Reset MDL id's and move all buffers back to the stream's buf_pool */
spin_lock(&q_idle->lock);
list_for_each_entry(mdl, &q_idle->list, list) { while (!list_empty(&mdl->buf_list)) {
buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, list);
list_move_tail(&buf->list, &s->buf_pool);
buf->bytesused = 0;
buf->readpos = 0;
}
mdl->id = s->mdl_base_idx; /* reset id to a "safe" value */ /* all other mdl fields were cleared by cx18_queue_flush() */
}
spin_unlock(&q_idle->lock);
}
CX18_ERR("Too many buffers, cannot fit in SCB area\n");
CX18_ERR("Max buffers = %zu\n",
bufsz / sizeof(struct cx18_mdl_ent)); return -ENOMEM;
}
s->mdl_base_idx = cx->free_mdl_idx;
/* allocate stream buffers and MDLs */ for (i = 0; i < s->buffers; i++) { struct cx18_mdl *mdl; struct cx18_buffer *buf;
/* 1 MDL per buffer to handle the worst & also default case */
mdl = kzalloc(sizeof(struct cx18_mdl), GFP_KERNEL|__GFP_NOWARN); if (mdl == NULL) break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.