diff options
Diffstat (limited to 'drivers/virtio')
-rw-r--r-- | drivers/virtio/virtio_pci.c | 53 |
1 files changed, 34 insertions, 19 deletions
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index 027f13fbe493..951e673e50a4 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c | |||
@@ -164,6 +164,37 @@ static void vp_notify(struct virtqueue *vq) | |||
164 | iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY); | 164 | iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY); |
165 | } | 165 | } |
166 | 166 | ||
167 | /* Handle a configuration change: Tell driver if it wants to know. */ | ||
168 | static irqreturn_t vp_config_changed(int irq, void *opaque) | ||
169 | { | ||
170 | struct virtio_pci_device *vp_dev = opaque; | ||
171 | struct virtio_driver *drv; | ||
172 | drv = container_of(vp_dev->vdev.dev.driver, | ||
173 | struct virtio_driver, driver); | ||
174 | |||
175 | if (drv && drv->config_changed) | ||
176 | drv->config_changed(&vp_dev->vdev); | ||
177 | return IRQ_HANDLED; | ||
178 | } | ||
179 | |||
180 | /* Notify all virtqueues on an interrupt. */ | ||
181 | static irqreturn_t vp_vring_interrupt(int irq, void *opaque) | ||
182 | { | ||
183 | struct virtio_pci_device *vp_dev = opaque; | ||
184 | struct virtio_pci_vq_info *info; | ||
185 | irqreturn_t ret = IRQ_NONE; | ||
186 | unsigned long flags; | ||
187 | |||
188 | spin_lock_irqsave(&vp_dev->lock, flags); | ||
189 | list_for_each_entry(info, &vp_dev->virtqueues, node) { | ||
190 | if (vring_interrupt(irq, info->vq) == IRQ_HANDLED) | ||
191 | ret = IRQ_HANDLED; | ||
192 | } | ||
193 | spin_unlock_irqrestore(&vp_dev->lock, flags); | ||
194 | |||
195 | return ret; | ||
196 | } | ||
197 | |||
167 | /* A small wrapper to also acknowledge the interrupt when it's handled. | 198 | /* A small wrapper to also acknowledge the interrupt when it's handled. |
168 | * I really need an EIO hook for the vring so I can ack the interrupt once we | 199 | * I really need an EIO hook for the vring so I can ack the interrupt once we |
169 | * know that we'll be handling the IRQ but before we invoke the callback since | 200 | * know that we'll be handling the IRQ but before we invoke the callback since |
@@ -173,9 +204,6 @@ static void vp_notify(struct virtqueue *vq) | |||
173 | static irqreturn_t vp_interrupt(int irq, void *opaque) | 204 | static irqreturn_t vp_interrupt(int irq, void *opaque) |
174 | { | 205 | { |
175 | struct virtio_pci_device *vp_dev = opaque; | 206 | struct virtio_pci_device *vp_dev = opaque; |
176 | struct virtio_pci_vq_info *info; | ||
177 | irqreturn_t ret = IRQ_NONE; | ||
178 | unsigned long flags; | ||
179 | u8 isr; | 207 | u8 isr; |
180 | 208 | ||
181 | /* reading the ISR has the effect of also clearing it so it's very | 209 | /* reading the ISR has the effect of also clearing it so it's very |
@@ -187,23 +215,10 @@ static irqreturn_t vp_interrupt(int irq, void *opaque) | |||
187 | return IRQ_NONE; | 215 | return IRQ_NONE; |
188 | 216 | ||
189 | /* Configuration change? Tell driver if it wants to know. */ | 217 | /* Configuration change? Tell driver if it wants to know. */ |
190 | if (isr & VIRTIO_PCI_ISR_CONFIG) { | 218 | if (isr & VIRTIO_PCI_ISR_CONFIG) |
191 | struct virtio_driver *drv; | 219 | vp_config_changed(irq, opaque); |
192 | drv = container_of(vp_dev->vdev.dev.driver, | ||
193 | struct virtio_driver, driver); | ||
194 | |||
195 | if (drv && drv->config_changed) | ||
196 | drv->config_changed(&vp_dev->vdev); | ||
197 | } | ||
198 | 220 | ||
199 | spin_lock_irqsave(&vp_dev->lock, flags); | 221 | return vp_vring_interrupt(irq, opaque); |
200 | list_for_each_entry(info, &vp_dev->virtqueues, node) { | ||
201 | if (vring_interrupt(irq, info->vq) == IRQ_HANDLED) | ||
202 | ret = IRQ_HANDLED; | ||
203 | } | ||
204 | spin_unlock_irqrestore(&vp_dev->lock, flags); | ||
205 | |||
206 | return ret; | ||
207 | } | 222 | } |
208 | 223 | ||
209 | /* the config->find_vq() implementation */ | 224 | /* the config->find_vq() implementation */ |