Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1511023
  • 博文数量: 487
  • 博客积分: 161
  • 博客等级: 入伍新兵
  • 技术积分: 5064
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-01 07:37
个人简介

只有偏执狂才能生存

文章分类

全部博文(487)

文章存档

2016年(10)

2015年(111)

2014年(66)

2013年(272)

2012年(28)

分类: LINUX

2013-07-31 09:19:36

1.中断两任务:
1).当设备的配置信息发生改变(config changed),会产生一个中断(称为change中断),中断处理程序需要调用相应的处理函数(需要驱动定义)。
2).当设备向队列中写入信息时,会产生一个中断(称为vq中断),中断处理函数需要调用相应的队列的回调函数(需要驱动定义)。

2.三种中断处理方式:
1).不用msix中断,则change中断和所有vq中断共用一个中断irq。
 中断处理函数:vp_interrupt。
 vp_interrupt函数中包含了对change中断和vq中断的处理。

2).使用msix中断,但只有2个vector,一个用来对应change中断,一个对应所有队列的vq中断。
 change中断处理函数:vp_config_changed
 vq中断处理函数:vp_vring_interrupt
3).使用msix中断,有n+1个vector,一个用来对应change中断,n个分别对应n个队列的vq中断。每个vq一个vector。
 change中断处理函数:vp_config_changed
 vq中断处理函数:vring_interrupt

static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs,
         struct virtqueue *vqs[],
         vq_callback_t *callbacks[],
         const char *names[],
         bool use_msix,
         bool per_vq_vectors)
{
 struct virtio_pci_device *vp_dev = to_vp_device(vdev);
 u16 msix_vec;
 int i, err, nvectors, allocated_vectors;

 if (!use_msix) { /* 不用msix,所有vq共用一个irq */
  /* Old style: one normal interrupt for change and all vqs. */
  err = vp_request_intx(vdev);
  if (err)
   goto error_request;
 } else {
  if (per_vq_vectors) {/* 每个vq一个vector */
   /* Best option: one for change interrupt, one per vq. */
   nvectors = 1;
   for (i = 0; i < nvqs; ++i)
    if (callbacks[i])
     ++nvectors;
  } else {
   /* Second best: one for change, shared for all vqs. */
   nvectors = 2;
  }
  /* vp_request_msix_vectors函数完成任务:
    1.分配nvectors个msix中断用vector,并使用1个vector来指定vp_config_changed为change中断处理函数。
     2.如果per_vq_vectors为0,则nvectors就是2,再用掉另一个vector来指定n个队列共用的vq中断处理函数vp_vring_interrupt,
   如果per_vq_vectors为1,则在下面代码中为每个队列指定一个vector,vq中断处理函数为vring_interrupt */
  err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors);
  if (err)
   goto error_request;
 }
 /* per_vq_vectors,标识是不是每一个队列分配一个vector */
 vp_dev->per_vq_vectors = per_vq_vectors;
 allocated_vectors = vp_dev->msix_used_vectors;
 for (i = 0; i < nvqs; ++i) {
  if (!names[i]) {
   vqs[i] = NULL;
   continue;
  } else if (!callbacks[i] || !vp_dev->msix_enabled)
   msix_vec = VIRTIO_MSI_NO_VECTOR;
  else if (vp_dev->per_vq_vectors)
   msix_vec = allocated_vectors++;
  else
   msix_vec = VP_MSIX_VQ_VECTOR;
  vqs[i] = setup_vq(vdev, i, callbacks[i], names[i], msix_vec);
  if (IS_ERR(vqs[i])) {
   err = PTR_ERR(vqs[i]);
   goto error_find;
  }
  /* 如果vp_dev->per_vq_vectors不为1,或者VIRTIO_MSI_NO_VECTOR,则不执行下文 */
  if (!vp_dev->per_vq_vectors || msix_vec == VIRTIO_MSI_NO_VECTOR)
   continue;

  /* allocate per-vq irq if available and necessary */
  snprintf(vp_dev->msix_names[msix_vec],
    sizeof *vp_dev->msix_names,
    "%s-%s",
    dev_name(&vp_dev->vdev.dev), names[i]);
  /*  如果per_vq_vectors为1,则为每个队列指定一个vector,vq中断处理函数为vring_interrupt */
  err = request_irq(vp_dev->msix_entries[msix_vec].vector,
      vring_interrupt, 0,
      vp_dev->msix_names[msix_vec],
      vqs[i]);
  if (err) {
   vp_del_vq(vqs[i]);
   goto error_find;
  }
 }
 return 0;

error_find:
 vp_del_vqs(vdev);

error_request:
 return err;
}


vp_request_msix_vectors函数完成任务:
1.分配nvectors个msix中断用vector,并使用1个vector来指定vp_config_changed为change中断处理函数。
2.如果per_vq_vectors为0,则nvectors就是2,再用掉另一个vector来指定n个队列共用的vq中断处理函数vp_vring_interrupt,
static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
       bool per_vq_vectors)
{
 struct virtio_pci_device *vp_dev = to_vp_device(vdev);
 const char *name = dev_name(&vp_dev->vdev.dev);
 unsigned i, v;
 int err = -ENOMEM;
 /* 各种分配空间和初始化... */
 vp_dev->msix_entries = kmalloc(nvectors * sizeof *vp_dev->msix_entries,
           GFP_KERNEL);
 if (!vp_dev->msix_entries)
  goto error;
 vp_dev->msix_names = kmalloc(nvectors * sizeof *vp_dev->msix_names,
         GFP_KERNEL);
 if (!vp_dev->msix_names)
  goto error;
 vp_dev->msix_affinity_masks
  = kzalloc(nvectors * sizeof *vp_dev->msix_affinity_masks,
     GFP_KERNEL);
 if (!vp_dev->msix_affinity_masks)
  goto error;
 for (i = 0; i < nvectors; ++i)
  if (!alloc_cpumask_var(&vp_dev->msix_affinity_masks[i],
     GFP_KERNEL))
   goto error;

 for (i = 0; i < nvectors; ++i)
  vp_dev->msix_entries[i].entry = i;

 /* pci_enable_msix returns positive if we can't get this many. */
 err = pci_enable_msix(vp_dev->pci_dev, vp_dev->msix_entries, nvectors);
 if (err > 0)
  err = -ENOSPC;
 if (err)
  goto error;
 vp_dev->msix_vectors = nvectors;
 vp_dev->msix_enabled = 1;

 /* Set the vector used for configuration */
 /* 使用一个vector,从vp_dev->msix_used_vectors读取下一个可用的vector,然后将这个vector同vp_config_changed绑定 */
 v = vp_dev->msix_used_vectors;
 snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
   "%s-config", name);
 err = request_irq(vp_dev->msix_entries[v].vector,
     vp_config_changed, 0, vp_dev->msix_names[v],
     vp_dev);
 if (err)
  goto error;
 ++vp_dev->msix_used_vectors; /* 上面用了一个vector,自增1 */

 iowrite16(v, vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
 /* Verify we had enough resources to assign the vector */
 v = ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
 if (v == VIRTIO_MSI_NO_VECTOR) {
  err = -EBUSY;
  goto error;
 }
 /* 如果per_vq_vectors为0,则为所有队列分配一个vector,指定所有队列的vq中断的处理函数为vp_vring_interrupt */
 if (!per_vq_vectors) {
  /* Shared vector for all VQs */
  v = vp_dev->msix_used_vectors;
  snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
    "%s-virtqueues", name);
  err = request_irq(vp_dev->msix_entries[v].vector,
      vp_vring_interrupt, 0, vp_dev->msix_names[v],
      vp_dev);
  if (err)
   goto error;
  ++vp_dev->msix_used_vectors;
 }
 return 0;
error:
 vp_free_vectors(vdev);
 return err;
}

 

阅读(1257) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~