/** * arch_setup_msi_irq-Setup MSI interrupt * @pdev: Pointer to current pci device structure * @desc: Pointer to MSI description structure * * @return: Error/ no-error * * @note: This function is called when pci_enable_msi is called */ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { int irq = irq_alloc_desc_from(xaxipcie_msi_irq_base, -1); struct msi_msg msg; if (irq < 0) return irq; if (irq >= (xaxipcie_msi_irq_base + XILINX_NUM_MSI_IRQS + 1)) { irq_free_desc(irq); return -ENOSPC; } irq_set_msi_desc(irq, desc); msg.address_hi = 0x00000000; msg.address_lo = xaxipcie_msg_addr; msg.data = irq; pr_debug("irq %d addr_hi %08x low %08x data %08x\n", irq, msg.address_hi, msg.address_lo, msg.data); write_msi_msg(irq, &msg); irq_set_chip_and_handler(irq, &xilinx_msi_chip, handle_simple_irq); return 0; }
/** * intel_lpe_audio_teardown() - destroy the bridge between HDMI LPE * audio driver and i915 * @dev_priv: the i915 drm device private data * * release all the resources for LPE audio <-> i915 bridge. */ void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv) { struct irq_desc *desc; if (!HAS_LPE_AUDIO(dev_priv)) return; desc = irq_to_desc(dev_priv->lpe_audio.irq); lpe_audio_platdev_destroy(dev_priv); irq_free_desc(dev_priv->lpe_audio.irq); }
void mcp2210_irq_remove(struct mcp2210_device *dev) { mcp2210_info(); if (dev->is_irq_probed) { const int virq_end = dev->irq_base + dev->nr_irqs; int virq; for (virq = dev->irq_base; virq < virq_end; ++virq) { irq_free_desc(virq); dev->irq_descs[virq] = NULL; } dev->is_irq_probed = 0; } }
static void sunxi_gpio_irq_remove(struct sunxi_gpio_chip *sgpio) { int irq; int base = sgpio->irq_base; /* irq_base < 0 on unsupported platforms */ if (base < 0) return; for (irq = base; irq < base + EINT_NUM; irq++) { irq_set_handler(irq, NULL); irq_set_chip(irq, NULL); irq_set_chip_data(irq, NULL); irq_free_desc(irq); } }
static int lpe_audio_setup(struct drm_i915_private *dev_priv) { int ret; dev_priv->lpe_audio.irq = irq_alloc_desc(0); if (dev_priv->lpe_audio.irq < 0) { DRM_ERROR("Failed to allocate IRQ desc: %d\n", dev_priv->lpe_audio.irq); ret = dev_priv->lpe_audio.irq; goto err; } DRM_DEBUG("irq = %d\n", dev_priv->lpe_audio.irq); ret = lpe_audio_irq_init(dev_priv); if (ret) { DRM_ERROR("Failed to initialize irqchip for lpe audio: %d\n", ret); goto err_free_irq; } dev_priv->lpe_audio.platdev = lpe_audio_platdev_create(dev_priv); if (IS_ERR(dev_priv->lpe_audio.platdev)) { ret = PTR_ERR(dev_priv->lpe_audio.platdev); DRM_ERROR("Failed to create lpe audio platform device: %d\n", ret); goto err_free_irq; } /* enable chicken bit; at least this is required for Dell Wyse 3040 * with DP outputs (but only sometimes by some reason!) */ I915_WRITE(VLV_AUD_CHICKEN_BIT_REG, VLV_CHICKEN_BIT_DBG_ENABLE); return 0; err_free_irq: irq_free_desc(dev_priv->lpe_audio.irq); err: dev_priv->lpe_audio.irq = -1; dev_priv->lpe_audio.platdev = NULL; return ret; }
static void mcuio_soft_hc_release(struct device *device) { struct mcuio_hc_platform_data *plat = dev_get_platdata(device); struct mcuio_soft_hc *shc; int i; if (!plat) { WARN_ON(1); return; } shc = plat->data; bus_unregister_notifier(&mcuio_bus_type, &device_nb); /* Unregister all irq controllers */ for (i = 0; i < MCUIO_DEVS_PER_BUS; i++) if (shc->irq_controllers[i]) mcuio_device_unregister(shc->irq_controllers[i]); irq_set_handler(shc->irqno, NULL); irq_set_chip(shc->irqno, NULL); irq_free_desc(shc->irqno); kfree(shc); mcuio_hc_dev_default_release(device); }
/* * This routine finds the Nth virtqueue described in the configuration of * this device and sets it up. * * This is kind of an ugly duckling. It'd be nicer to have a standard * representation of a virtqueue in the configuration space, but it seems that * everyone wants to do it differently. The KVM coders want the Guest to * allocate its own pages and tell the Host where they are, but for lguest it's * simpler for the Host to simply tell us where the pages are. */ static struct virtqueue *lg_find_vq(struct virtio_device *vdev, unsigned index, void (*callback)(struct virtqueue *vq), const char *name) { struct lguest_device *ldev = to_lgdev(vdev); struct lguest_vq_info *lvq; struct virtqueue *vq; int err; if (!name) return NULL; /* We must have this many virtqueues. */ if (index >= ldev->desc->num_vq) return ERR_PTR(-ENOENT); lvq = kmalloc(sizeof(*lvq), GFP_KERNEL); if (!lvq) return ERR_PTR(-ENOMEM); /* * Make a copy of the "struct lguest_vqconfig" entry, which sits after * the descriptor. We need a copy because the config space might not * be aligned correctly. */ memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config)); printk("Mapping virtqueue %i addr %lx\n", index, (unsigned long)lvq->config.pfn << PAGE_SHIFT); /* Figure out how many pages the ring will take, and map that memory */ lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT, DIV_ROUND_UP(vring_size(lvq->config.num, LGUEST_VRING_ALIGN), PAGE_SIZE)); if (!lvq->pages) { err = -ENOMEM; goto free_lvq; } /* * OK, tell virtio_ring.c to set up a virtqueue now we know its size * and we've got a pointer to its pages. Note that we set weak_barriers * to 'true': the host just a(nother) SMP CPU, so we only need inter-cpu * barriers. */ vq = vring_new_virtqueue(index, lvq->config.num, LGUEST_VRING_ALIGN, vdev, true, lvq->pages, lg_notify, callback, name); if (!vq) { err = -ENOMEM; goto unmap; } /* Make sure the interrupt is allocated. */ err = lguest_setup_irq(lvq->config.irq); if (err) goto destroy_vring; /* * Tell the interrupt for this virtqueue to go to the virtio_ring * interrupt handler. * * FIXME: We used to have a flag for the Host to tell us we could use * the interrupt as a source of randomness: it'd be nice to have that * back. */ err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED, dev_name(&vdev->dev), vq); if (err) goto free_desc; /* * Last of all we hook up our 'struct lguest_vq_info" to the * virtqueue's priv pointer. */ vq->priv = lvq; return vq; free_desc: irq_free_desc(lvq->config.irq); destroy_vring: vring_del_virtqueue(vq); unmap: lguest_unmap(lvq->pages); free_lvq: kfree(lvq); return ERR_PTR(err); }
void destroy_irq(unsigned int irq) { irq_free_desc(irq); }
/** * arch_teardown_msi_irq-Teardown the Interrupt * @irq: Interrupt number to teardown * * @return: None * * @note: This function is called when pci_disable_msi is called */ void arch_teardown_msi_irq(unsigned int irq) { irq_free_desc(irq); }