+void
+iosapic_unregister_intr (unsigned int gsi)
+{
+ unsigned long flags;
+ int irq, vector, index;
+ irq_desc_t *idesc;
+ u32 low32;
+ unsigned long trigger, polarity;
+ unsigned int dest;
+ struct iosapic_rte_info *rte;
+
+ /*
+ * If the irq associated with the gsi is not found,
+ * iosapic_unregister_intr() is unbalanced. We need to check
+ * this again after getting locks.
+ */
+ irq = gsi_to_irq(gsi);
+ if (irq < 0) {
+ printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n",
+ gsi);
+ WARN_ON(1);
+ return;
+ }
+ vector = irq_to_vector(irq);
+
+ idesc = irq_descp(irq);
+ spin_lock_irqsave(&idesc->lock, flags);
+ spin_lock(&iosapic_lock);
+ {
+ if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
+ printk(KERN_ERR
+ "iosapic_unregister_intr(%u) unbalanced\n",
+ gsi);
+ WARN_ON(1);
+ goto out;
+ }
+
+ if (--rte->refcnt > 0)
+ goto out;
+
+ /* Mask the interrupt */
+ low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
+ iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index),
+ low32);
+
+ /* Remove the rte entry from the list */
+ list_del(&rte->rte_list);
+ iosapic_intr_info[vector].count--;
+ iosapic_free_rte(rte);
+ index = find_iosapic(gsi);
+ iosapic_lists[index].rtes_inuse--;
+ WARN_ON(iosapic_lists[index].rtes_inuse < 0);
+
+ trigger = iosapic_intr_info[vector].trigger;
+ polarity = iosapic_intr_info[vector].polarity;
+ dest = iosapic_intr_info[vector].dest;
+ printk(KERN_INFO
+ "GSI %u (%s, %s) -> CPU %d (0x%04x)"
+ " vector %d unregistered\n",
+ gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+ (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+ cpu_logical_id(dest), dest, vector);
+
+ if (list_empty(&iosapic_intr_info[vector].rtes)) {
+ /* Sanity check */
+ BUG_ON(iosapic_intr_info[vector].count);
+
+ /* Clear the interrupt controller descriptor */
+ idesc->handler = &no_irq_type;
+
+ /* Clear the interrupt information */
+ memset(&iosapic_intr_info[vector], 0,
+ sizeof(struct iosapic_intr_info));
+ iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
+ INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+
+ if (idesc->action) {
+ printk(KERN_ERR
+ "interrupt handlers still exist on"
+ "IRQ %u\n", irq);
+ WARN_ON(1);
+ }
+
+ /* Free the interrupt vector */
+ free_irq_vector(vector);
+ }
+ }
+ out:
+ spin_unlock(&iosapic_lock);
+ spin_unlock_irqrestore(&idesc->lock, flags);
+}
+