免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1855 | 回复: 2
打印 上一主题 下一主题

[硬件及驱动] 请教USB子系统EHCI控制器驱动关于同步端点调度的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-11-14 16:27 |只看该作者 |倒序浏览
最近在看EHCI控制器驱动,看到iso_stream_schedule这个函数的时候就看不懂了,在网上也找不到相关的资料,不知道有哪位大神研究过这个函数的实现原理?哎,好多天了,还没想明白,请各位赐教,多谢了!!

论坛徽章:
0
2 [报告]
发表于 2014-11-14 16:43 |只看该作者
贴上源代码:

  1. /*
  2. * This scheduler plans almost as far into the future as it has actual
  3. * periodic schedule slots.  (Affected by TUNE_FLS, which defaults to
  4. * "as small as possible" to be cache-friendlier.)  That limits the size
  5. * transfers you can stream reliably; avoid more than 64 msec per urb.
  6. * Also avoid queue depths of less than ehci's worst irq latency (affected
  7. * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
  8. * and other factors); or more than about 230 msec total (for portability,
  9. * given EHCI_TUNE_FLS and the slop).  Or, write a smarter scheduler!
  10. */

  11. static int
  12. iso_stream_schedule (
  13.         struct ehci_hcd                *ehci,
  14.         struct urb                *urb,
  15.         struct ehci_iso_stream        *stream
  16. )
  17. {
  18.         u32                        now, base, next, start, period, span, now2;
  19.         u32                        wrap = 0, skip = 0;
  20.         int                        status = 0;
  21.         unsigned                mod = ehci->periodic_size << 3;        /* ehci->periodic_size can be 1024/512/256 */
  22.         struct ehci_iso_sched        *sched = urb->hcpriv;
  23.         bool                        empty = list_empty(&stream->td_list);
  24.         bool                        new_stream = false;

  25.         period = stream->uperiod;        /* urb->interval */
  26.         span = sched->span;        /* urb->number_of_packets * (urb->interval >> 3) */
  27.         if (!stream->highspeed)
  28.                 span <<= 3;

  29.         /* Start a new isochronous stream? */
  30.         if (unlikely(empty && !hcd_periodic_completion_in_progress(
  31.                         ehci_to_hcd(ehci), urb->ep))) {

  32.                 /* Schedule the endpoint */
  33.                 if (stream->ps.phase == NO_FRAME) {
  34.                         int                done = 0;
  35.                         struct ehci_tt        *tt = find_tt(stream->ps.udev);/* check where we attach */

  36.                         if (IS_ERR(tt)) {
  37.                                 status = PTR_ERR(tt);
  38.                                 goto fail;
  39.                         }
  40.                         compute_tt_budget(ehci->tt_budget, tt);

  41.                         start = ((-(++ehci->random_frame)) << 3) & (period - 1);

  42.                         /* find a uframe slot with enough bandwidth.
  43.                          * Early uframes are more precious because full-speed
  44.                          * iso IN transfers can't use late uframes,
  45.                          * and therefore they should be allocated last.
  46.                          */
  47.                         next = start;
  48.                         start += period;
  49.                         do {
  50.                                 start--;
  51.                                 /* check schedule: enough space? */
  52.                                 if (stream->highspeed) {
  53.                                         if (itd_slot_ok(ehci, stream, start))
  54.                                                 done = 1;
  55.                                 } else {
  56.                                         if ((start % 8) >= 6)
  57.                                                 continue;
  58.                                         if (sitd_slot_ok(ehci, stream, start,
  59.                                                         sched, tt))
  60.                                                 done = 1;
  61.                                 }
  62.                         } while (start > next && !done);

  63.                         /* no room in the schedule */
  64.                         if (!done) {
  65.                                 ehci_dbg(ehci, "iso sched full %p", urb);
  66.                                 status = -ENOSPC;
  67.                                 goto fail;
  68.                         }
  69.                         stream->ps.phase = (start >> 3) &
  70.                                         (stream->ps.period - 1);
  71.                         stream->ps.bw_phase = stream->ps.phase &
  72.                                         (stream->ps.bw_period - 1);
  73.                         stream->ps.phase_uf = start & 7;
  74.                         reserve_release_iso_bandwidth(ehci, stream, 1);
  75.                 }

  76.                 /* New stream is already scheduled; use the upcoming slot */
  77.                 else {
  78.                         start = (stream->ps.phase << 3) + stream->ps.phase_uf;
  79.                 }

  80.                 stream->next_uframe = start;
  81.                 new_stream = true;
  82.         }

  83.         now = ehci_read_frame_index(ehci) & (mod - 1);

  84.         /* Take the isochronous scheduling threshold into account */
  85.         if (ehci->i_thresh)
  86.                 next = now + ehci->i_thresh;        /* uframe cache */
  87.         else
  88.                 next = (now + 2 + 7) & ~0x07;        /* full frame cache */

  89.         /*
  90.          * Use ehci->last_iso_frame as the base.  There can't be any
  91.          * TDs scheduled for earlier than that.
  92.          */
  93.         base = ehci->last_iso_frame << 3;
  94.         next = (next - base) & (mod - 1);
  95.         start = (stream->next_uframe - base) & (mod - 1);

  96.         if (unlikely(new_stream))
  97.                 goto do_ASAP;

  98.         /*
  99.          * Typical case: reuse current schedule, stream may still be active.
  100.          * Hopefully there are no gaps from the host falling behind
  101.          * (irq delays etc).  If there are, the behavior depends on
  102.          * whether URB_ISO_ASAP is set.
  103.          */
  104.         now2 = (now - base) & (mod - 1);

  105.         /* Is the schedule already full? */
  106.         if (unlikely(!empty && start < period)) {
  107.                 ehci_dbg(ehci, "iso sched full %p (%u-%u < %u mod %u)\n",
  108.                                 urb, stream->next_uframe, base, period, mod);
  109.                 status = -ENOSPC;
  110.                 goto fail;
  111.         }

  112.         /* Is the next packet scheduled after the base time? */
  113.         if (likely(!empty || start <= now2 + period)) {

  114.                 /* URB_ISO_ASAP: make sure that start >= next */
  115.                 if (unlikely(start < next &&
  116.                                 (urb->transfer_flags & URB_ISO_ASAP)))
  117.                         goto do_ASAP;

  118.                 /* Otherwise use start, if it's not in the past */
  119.                 if (likely(start >= now2))
  120.                         goto use_start;

  121.         /* Otherwise we got an underrun while the queue was empty */
  122.         } else {
  123.                 if (urb->transfer_flags & URB_ISO_ASAP)
  124.                         goto do_ASAP;
  125.                 wrap = mod;
  126.                 now2 += mod;
  127.         }

  128.         /* How many uframes and packets do we need to skip? */
  129.         skip = (now2 - start + period - 1) & -period;
  130.         if (skip >= span) {                /* Entirely in the past? */
  131.                 ehci_dbg(ehci, "iso underrun %p (%u+%u < %u) [%u]\n",
  132.                                 urb, start + base, span - period, now2 + base,
  133.                                 base);

  134.                 /* Try to keep the last TD intact for scanning later */
  135.                 skip = span - period;

  136.                 /* Will it come before the current scan position? */
  137.                 if (empty) {
  138.                         skip = span;        /* Skip the entire URB */
  139.                         status = 1;        /* and give it back immediately */
  140.                         iso_sched_free(stream, sched);
  141.                         sched = NULL;
  142.                 }
  143.         }
  144.         urb->error_count = skip / period;
  145.         if (sched)
  146.                 sched->first_packet = urb->error_count;
  147.         goto use_start;

  148. do_ASAP:
  149.         /* Use the first slot after "next" */
  150.         start = next + ((start - next) & (period - 1));

  151. use_start:
  152.         /* Tried to schedule too far into the future? */
  153.         if (unlikely(start + span - period >= mod + wrap)) {
  154.                 ehci_dbg(ehci, "request %p would overflow (%u+%u >= %u)\n",
  155.                                 urb, start, span - period, mod + wrap);
  156.                 status = -EFBIG;
  157.                 goto fail;
  158.         }

  159.         start += base;
  160.         stream->next_uframe = (start + skip) & (mod - 1);

  161.         /* report high speed start in uframes; full speed, in frames */
  162.         urb->start_frame = start & (mod - 1);
  163.         if (!stream->highspeed)
  164.                 urb->start_frame >>= 3;

  165.         /* Make sure scan_isoc() sees these */
  166.         if (ehci->isoc_count == 0)
  167.                 ehci->last_iso_frame = now >> 3;
  168.         return status;

  169. fail:
  170.         iso_sched_free(stream, sched);
  171.         urb->hcpriv = NULL;
  172.         return status;
  173. }
复制代码

论坛徽章:
0
3 [报告]
发表于 2014-11-20 16:40 |只看该作者
顶一下,哪位大神研习过?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP