コード例 #1
0
ファイル: msi.c プロジェクト: rcplay/snake-os
/**
 * pci_enable_msi - configure device's MSI capability structure
 * @dev: pointer to the pci_dev data structure of MSI device function
 *
 * Setup the MSI capability structure of device function with
 * a single MSI vector upon its software driver call to request for
 * MSI mode enabled on its hardware device function. A return of zero
 * indicates the successful setup of an entry zero with the new MSI
 * vector or non-zero for otherwise.
 **/
int pci_enable_msi(struct pci_dev* dev)
{
    int pos, temp, status = -EINVAL;
    u16 control;

    if (!pci_msi_enable || !dev)
        return status;

    if (dev->no_msi)
        return status;

    temp = dev->irq;

    if ((status = msi_init()) < 0)
        return status;

    if (!(pos = pci_find_capability(dev, PCI_CAP_ID_MSI)))
        return -EINVAL;

    pci_read_config_word(dev, msi_control_reg(pos), &control);
    if (control & PCI_MSI_FLAGS_ENABLE)
        return 0;			/* Already in MSI mode */

    if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
        /* Lookup Sucess */
        unsigned long flags;

        spin_lock_irqsave(&msi_lock, flags);
        if (!vector_irq[dev->irq]) {
            msi_desc[dev->irq]->msi_attrib.state = 0;
            vector_irq[dev->irq] = -1;
            nr_released_vectors--;
            spin_unlock_irqrestore(&msi_lock, flags);
            enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
            return 0;
        }
        spin_unlock_irqrestore(&msi_lock, flags);
        dev->irq = temp;
    }
    /* Check whether driver already requested for MSI-X vectors */
    if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)) > 0 &&
            !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
        printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
               "Device already has MSI-X vectors assigned\n",
               pci_name(dev));
        dev->irq = temp;
        return -EINVAL;
    }
    status = msi_capability_init(dev);
    if (!status) {
        if (!pos)
            nr_reserved_vectors--;	/* Only MSI capable */
        else if (nr_msix_devices > 0)
            nr_msix_devices--;	/* Both MSI and MSI-X capable,
						   but choose enabling MSI */
    }

    return status;
}
コード例 #2
0
ファイル: msi.c プロジェクト: xf739645524/kernel-rhel5
/**
 * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
 * @dev: pointer to the pci_dev data structure of MSI(X) device function
 *
 * Being called during hotplug remove, from which the device function
 * is hot-removed. All previous assigned MSI/MSI-X vectors, if
 * allocated for this device function, are reclaimed to unused state,
 * which may be used later on.
 **/
void msi_remove_pci_irq_vectors(struct pci_dev* dev)
{
	int state, pos, temp;
	unsigned long flags;

	if (!pci_msi_enable || !dev)
 		return;

	temp = dev->irq;		/* Save IOAPIC IRQ */
	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
	if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
		spin_lock_irqsave(&msi_lock, flags);
		state = msi_desc[dev->irq]->msi_attrib.state;
		spin_unlock_irqrestore(&msi_lock, flags);
		if (state) {
			printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
			       "called without free_irq() on MSI vector %d\n",
			       pci_name(dev), dev->irq);
			BUG_ON(state > 0);
		} else /* Release MSI vector assigned to this device */
			msi_free_vector(dev, dev->irq, 0);
		dev->irq = temp;		/* Restore IOAPIC IRQ */
	}
	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
	if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
		int vector, head, tail = 0, warning = 0;
		void __iomem *base = NULL;

		vector = head = dev->irq;
		while (head != tail) {
			spin_lock_irqsave(&msi_lock, flags);
			state = msi_desc[vector]->msi_attrib.state;
			tail = msi_desc[vector]->link.tail;
			base = msi_desc[vector]->mask_base;
			spin_unlock_irqrestore(&msi_lock, flags);
			if (state)
				warning = 1;
			else if (vector != head) /* Release MSI-X vector */
				msi_free_vector(dev, vector, 0);
			vector = tail;
		}
		msi_free_vector(dev, vector, 0);
		if (warning) {
			iounmap(base);
			printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
			       "called without free_irq() on all MSI-X vectors\n",
			       pci_name(dev));
			BUG_ON(warning > 0);
		}
		dev->irq = temp;		/* Restore IOAPIC IRQ */
	}
}
コード例 #3
0
ファイル: msi.c プロジェクト: xf739645524/kernel-rhel5
int pci_save_msix_state(struct pci_dev *dev)
{
	int pos;
	int temp;
	int vector, head, tail = 0;
	u16 control;
	struct pci_cap_saved_state *save_state;

	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
	if (pos <= 0 || dev->no_msi)
		return 0;

	/* save the capability */
	pci_read_config_word(dev, msi_control_reg(pos), &control);
	if (!(control & PCI_MSIX_FLAGS_ENABLE))
		return 0;
	save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16),
		GFP_KERNEL);
	if (!save_state) {
		printk(KERN_ERR "Out of memory in pci_save_msix_state\n");
		return -ENOMEM;
	}
	*((u16 *)&save_state->data[0]) = control;

	/* save the table */
	temp = dev->irq;
	if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
		kfree(save_state);
		return -EINVAL;
	}

	vector = head = dev->irq;
	while (head != tail) {
		int j;
		void __iomem *base;
		struct msi_desc *entry;

		entry = msi_desc[vector];
		base = entry->mask_base;
		j = entry->msi_attrib.entry_nr;

		entry->address_lo_save =
			readl(base + j * PCI_MSIX_ENTRY_SIZE +
			      PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
		entry->address_hi_save =
			readl(base + j * PCI_MSIX_ENTRY_SIZE +
			      PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
		entry->data_save =
			readl(base + j * PCI_MSIX_ENTRY_SIZE +
			      PCI_MSIX_ENTRY_DATA_OFFSET);

		tail = msi_desc[vector]->link.tail;
		vector = tail;
	}
	dev->irq = temp;

	save_state->cap_nr = PCI_CAP_ID_MSIX;
	pci_add_saved_cap(dev, save_state);
	return 0;
}
コード例 #4
0
ファイル: msi.c プロジェクト: xf739645524/kernel-rhel5
void pci_restore_msix_state(struct pci_dev *dev)
{
	u16 save;
	int pos;
	int vector, head, tail = 0;
	void __iomem *base;
	int j;
	struct msi_desc *entry;
	int temp;
	struct pci_cap_saved_state *save_state;

	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
	if (!save_state)
		return;
	save = *((u16 *)&save_state->data[0]);
	pci_remove_saved_cap(save_state);
	kfree(save_state);

	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
	if (pos <= 0)
		return;

	/* route the table */
	temp = dev->irq;
	if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX))
		return;
	vector = head = dev->irq;
	while (head != tail) {
		entry = msi_desc[vector];
		base = entry->mask_base;
		j = entry->msi_attrib.entry_nr;

		writel(entry->address_lo_save,
			base + j * PCI_MSIX_ENTRY_SIZE +
			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
		writel(entry->address_hi_save,
			base + j * PCI_MSIX_ENTRY_SIZE +
			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
		writel(entry->data_save,
			base + j * PCI_MSIX_ENTRY_SIZE +
			PCI_MSIX_ENTRY_DATA_OFFSET);

		tail = msi_desc[vector]->link.tail;
		vector = tail;
	}
	dev->irq = temp;

	pci_write_config_word(dev, msi_control_reg(pos), save);
	enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
}
コード例 #5
0
ファイル: msi.c プロジェクト: xf739645524/kernel-rhel5
/**
 * pci_enable_msi - configure device's MSI capability structure
 * @dev: pointer to the pci_dev data structure of MSI device function
 *
 * Setup the MSI capability structure of device function with
 * a single MSI vector upon its software driver call to request for
 * MSI mode enabled on its hardware device function. A return of zero
 * indicates the successful setup of an entry zero with the new MSI
 * vector or non-zero for otherwise.
 **/
int pci_enable_msi(struct pci_dev* dev)
{
	int pos, temp, status;

	if (pci_msi_supported(dev) < 0)
		return -EINVAL;

	temp = dev->irq;

	status = msi_init();
	if (status < 0)
		return status;

	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
	if (!pos)
		return -EINVAL;

	WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSI));

	/* Check whether driver already requested for MSI-X vectors */
	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
	if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
			printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
			       "Device already has MSI-X vectors assigned\n",
			       pci_name(dev));
			dev->irq = temp;
			return -EINVAL;
	}
	status = msi_capability_init(dev);
	if (!status) {
   		if (!pos)
			nr_reserved_vectors--;	/* Only MSI capable */
	}

	return status;
}
コード例 #6
0
ファイル: msi.c プロジェクト: xf739645524/kernel-rhel5
void pci_disable_msix(struct pci_dev* dev)
{
	int pos, temp;
	u16 control;

	if (!pci_msi_enable)
		return;
	if (!dev)
		return;
	if (!dev->msix_enabled)
		return;

	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
	if (pos) {
		pci_read_config_word(dev, msi_control_reg(pos), &control);
		if (control & PCI_MSIX_FLAGS_ENABLE)
			disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
	}

	temp = dev->irq;
	if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
		int state, vector, head, tail = 0, warning = 0;
		unsigned long flags;

		vector = head = dev->irq;
		dev->irq = temp;			/* Restore pin IRQ */
		while (head != tail) {
			spin_lock_irqsave(&msi_lock, flags);
			state = msi_desc[vector]->msi_attrib.state;
			tail = msi_desc[vector]->link.tail;
			spin_unlock_irqrestore(&msi_lock, flags);
			if (state)
				warning = 1;
			else if (vector != head)	/* Release MSI-X vector */
				msi_free_vector(dev, vector, 0);
			vector = tail;
		}
		msi_free_vector(dev, vector, 0);
		if (warning) {
			printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
			       "free_irq() on all MSI-X vectors\n",
			       pci_name(dev));
			BUG_ON(warning > 0);
		}
	}
}
コード例 #7
0
ファイル: msi.c プロジェクト: rcplay/snake-os
void pci_disable_msix(struct pci_dev* dev)
{
    int pos, temp;
    u16 control;

    if (!dev || !(pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)))
        return;

    pci_read_config_word(dev, msi_control_reg(pos), &control);
    if (!(control & PCI_MSIX_FLAGS_ENABLE))
        return;

    temp = dev->irq;
    if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
        int state, vector, head, tail = 0, warning = 0;
        unsigned long flags;

        vector = head = dev->irq;
        spin_lock_irqsave(&msi_lock, flags);
        while (head != tail) {
            state = msi_desc[vector]->msi_attrib.state;
            if (state)
                warning = 1;
            else {
                vector_irq[vector] = 0; /* free it */
                nr_released_vectors++;
            }
            tail = msi_desc[vector]->link.tail;
            vector = tail;
        }
        spin_unlock_irqrestore(&msi_lock, flags);
        if (warning) {
            dev->irq = temp;
            printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
                   "free_irq() on all MSI-X vectors\n",
                   pci_name(dev));
            BUG_ON(warning > 0);
        } else {
            dev->irq = temp;
            disable_msi_mode(dev,
                             pci_find_capability(dev, PCI_CAP_ID_MSIX),
                             PCI_CAP_ID_MSIX);

        }
    }
}
コード例 #8
0
ファイル: msi.c プロジェクト: BackupTheBerlios/tuxap
void pci_disable_msix(struct pci_dev* dev)
{
	int pos, temp;
	u16 control;

   	if (!dev || !(pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)))
		return;

	pci_read_config_word(dev, msi_control_reg(pos), &control);
	if (!(control & PCI_MSIX_FLAGS_ENABLE))
		return;

	temp = dev->irq;
	if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
		int state, vector, head, tail = 0, warning = 0;
		unsigned long flags;

		vector = head = dev->irq;
		spin_lock_irqsave(&msi_lock, flags);
		while (head != tail) {
			state = msi_desc[vector]->msi_attrib.state;
			if (state)
				warning = 1;
			else {
				vector_irq[vector] = 0; /* free it */
				nr_released_vectors++;
			}
			tail = msi_desc[vector]->link.tail;
			vector = tail;
		}
		spin_unlock_irqrestore(&msi_lock, flags);
		if (warning) {
			dev->irq = temp;
			printk(KERN_DEBUG "Driver[%d:%d:%d] unloaded wo doing free_irq on all vectors\n",
			dev->bus->number, PCI_SLOT(dev->devfn),
			PCI_FUNC(dev->devfn));
			BUG_ON(warning > 0);
		} else {
			dev->irq = temp;
			disable_msi_mode(dev,
				pci_find_capability(dev, PCI_CAP_ID_MSIX),
				PCI_CAP_ID_MSIX);

		}
	}
}
コード例 #9
0
ファイル: msi.c プロジェクト: xf739645524/kernel-rhel5
/**
 * pci_enable_msix - configure device's MSI-X capability structure
 * @dev: pointer to the pci_dev data structure of MSI-X device function
 * @entries: pointer to an array of MSI-X entries
 * @nvec: number of MSI-X vectors requested for allocation by device driver
 *
 * Setup the MSI-X capability structure of device function with the number
 * of requested vectors upon its software driver call to request for
 * MSI-X mode enabled on its hardware device function. A return of zero
 * indicates the successful configuration of MSI-X capability structure
 * with new allocated MSI-X vectors. A return of < 0 indicates a failure.
 * Or a return of > 0 indicates that driver request is exceeding the number
 * of vectors available. Driver should use the returned value to re-send
 * its request.
 **/
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
{
	int status, pos, nr_entries, free_vectors;
	int i, j, temp;
	u16 control;
	unsigned long flags;

	if (!entries || pci_msi_supported(dev) < 0)
 		return -EINVAL;

	status = msi_init();
	if (status < 0)
		return status;

	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
	if (!pos)
 		return -EINVAL;

	pci_read_config_word(dev, msi_control_reg(pos), &control);
	nr_entries = multi_msix_capable(control);
	if (nvec > nr_entries)
		return -EINVAL;

	/* Check for any invalid entries */
	for (i = 0; i < nvec; i++) {
		if (entries[i].entry >= nr_entries)
			return -EINVAL;		/* invalid entry */
		for (j = i + 1; j < nvec; j++) {
			if (entries[i].entry == entries[j].entry)
				return -EINVAL;	/* duplicate entry */
		}
	}
	temp = dev->irq;
	WARN_ON(!msi_lookup_vector(dev, PCI_CAP_ID_MSIX));

	/* Check whether driver already requested for MSI vector */
   	if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
		!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
		printk(KERN_INFO "PCI: %s: Can't enable MSI-X.  "
		       "Device already has an MSI vector assigned\n",
		       pci_name(dev));
		dev->irq = temp;
		return -EINVAL;
	}

	spin_lock_irqsave(&msi_lock, flags);
	/*
	 * msi_lock is provided to ensure that enough vectors resources are
	 * available before granting.
	 */
	free_vectors = pci_vector_resources(last_alloc_vector,
				nr_released_vectors);
	/* Ensure that each MSI/MSI-X device has one vector reserved by
	   default to avoid any MSI-X driver to take all available
 	   resources */
	free_vectors -= nr_reserved_vectors;
	spin_unlock_irqrestore(&msi_lock, flags);

	if (nvec > free_vectors) {
		if (free_vectors > 0)
			return free_vectors;
		else
			return -EBUSY;
	}

	status = msix_capability_init(dev, entries, nvec);

	return status;
}
コード例 #10
0
ファイル: msi.c プロジェクト: rcplay/snake-os
/**
 * pci_enable_msix - configure device's MSI-X capability structure
 * @dev: pointer to the pci_dev data structure of MSI-X device function
 * @entries: pointer to an array of MSI-X entries
 * @nvec: number of MSI-X vectors requested for allocation by device driver
 *
 * Setup the MSI-X capability structure of device function with the number
 * of requested vectors upon its software driver call to request for
 * MSI-X mode enabled on its hardware device function. A return of zero
 * indicates the successful configuration of MSI-X capability structure
 * with new allocated MSI-X vectors. A return of < 0 indicates a failure.
 * Or a return of > 0 indicates that driver request is exceeding the number
 * of vectors available. Driver should use the returned value to re-send
 * its request.
 **/
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
{
    int status, pos, nr_entries, free_vectors;
    int i, j, temp;
    u16 control;
    unsigned long flags;

    if (!pci_msi_enable || !dev || !entries)
        return -EINVAL;

    if ((status = msi_init()) < 0)
        return status;

    if (!(pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)))
        return -EINVAL;

    pci_read_config_word(dev, msi_control_reg(pos), &control);
    if (control & PCI_MSIX_FLAGS_ENABLE)
        return -EINVAL;			/* Already in MSI-X mode */

    nr_entries = multi_msix_capable(control);
    if (nvec > nr_entries)
        return -EINVAL;

    /* Check for any invalid entries */
    for (i = 0; i < nvec; i++) {
        if (entries[i].entry >= nr_entries)
            return -EINVAL;		/* invalid entry */
        for (j = i + 1; j < nvec; j++) {
            if (entries[i].entry == entries[j].entry)
                return -EINVAL;	/* duplicate entry */
        }
    }
    temp = dev->irq;
    if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
        /* Lookup Sucess */
        nr_entries = nvec;
        /* Reroute MSI-X table */
        if (reroute_msix_table(dev->irq, entries, &nr_entries)) {
            /* #requested > #previous-assigned */
            dev->irq = temp;
            return nr_entries;
        }
        dev->irq = temp;
        enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
        return 0;
    }
    /* Check whether driver already requested for MSI vector */
    if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
            !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
        printk(KERN_INFO "PCI: %s: Can't enable MSI-X.  "
               "Device already has an MSI vector assigned\n",
               pci_name(dev));
        dev->irq = temp;
        return -EINVAL;
    }

    spin_lock_irqsave(&msi_lock, flags);
    /*
     * msi_lock is provided to ensure that enough vectors resources are
     * available before granting.
     */
    free_vectors = pci_vector_resources(last_alloc_vector,
                                        nr_released_vectors);
    /* Ensure that each MSI/MSI-X device has one vector reserved by
       default to avoid any MSI-X driver to take all available
       resources */
    free_vectors -= nr_reserved_vectors;
    /* Find the average of free vectors among MSI-X devices */
    if (nr_msix_devices > 0)
        free_vectors /= nr_msix_devices;
    spin_unlock_irqrestore(&msi_lock, flags);

    if (nvec > free_vectors) {
        if (free_vectors > 0)
            return free_vectors;
        else
            return -EBUSY;
    }

    status = msix_capability_init(dev, entries, nvec);
    if (!status && nr_msix_devices > 0)
        nr_msix_devices--;

    return status;
}
コード例 #11
0
ファイル: msi.c プロジェクト: rcplay/snake-os
/**
 * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
 * @dev: pointer to the pci_dev data structure of MSI(X) device function
 *
 * Being called during hotplug remove, from which the device function
 * is hot-removed. All previous assigned MSI/MSI-X vectors, if
 * allocated for this device function, are reclaimed to unused state,
 * which may be used later on.
 **/
void msi_remove_pci_irq_vectors(struct pci_dev* dev)
{
    int state, pos, temp;
    unsigned long flags;

    if (!pci_msi_enable || !dev)
        return;

    temp = dev->irq;		/* Save IOAPIC IRQ */
    if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) > 0 &&
            !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
        spin_lock_irqsave(&msi_lock, flags);
        state = msi_desc[dev->irq]->msi_attrib.state;
        spin_unlock_irqrestore(&msi_lock, flags);
        if (state) {
            printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
                   "called without free_irq() on MSI vector %d\n",
                   pci_name(dev), dev->irq);
            BUG_ON(state > 0);
        } else /* Release MSI vector assigned to this device */
            msi_free_vector(dev, dev->irq, 0);
        dev->irq = temp;		/* Restore IOAPIC IRQ */
    }
    if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)) > 0 &&
            !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
        int vector, head, tail = 0, warning = 0;
        void __iomem *base = NULL;

        vector = head = dev->irq;
        while (head != tail) {
            spin_lock_irqsave(&msi_lock, flags);
            state = msi_desc[vector]->msi_attrib.state;
            tail = msi_desc[vector]->link.tail;
            base = msi_desc[vector]->mask_base;
            spin_unlock_irqrestore(&msi_lock, flags);
            if (state)
                warning = 1;
            else if (vector != head) /* Release MSI-X vector */
                msi_free_vector(dev, vector, 0);
            vector = tail;
        }
        msi_free_vector(dev, vector, 0);
        if (warning) {
            /* Force to release the MSI-X memory-mapped table */
            u32 phys_addr, table_offset;
            u16 control;
            u8 bir;

            pci_read_config_word(dev, msi_control_reg(pos),
                                 &control);
            pci_read_config_dword(dev, msix_table_offset_reg(pos),
                                  &table_offset);
            bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
            phys_addr = pci_resource_start (dev, bir);
            phys_addr += (u32)(table_offset &
                               ~PCI_MSIX_FLAGS_BIRMASK);
            iounmap(base);
            printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
                   "called without free_irq() on all MSI-X vectors\n",
                   pci_name(dev));
            BUG_ON(warning > 0);
        }
        dev->irq = temp;		/* Restore IOAPIC IRQ */
    }
}
コード例 #12
0
ファイル: msi.c プロジェクト: BackupTheBerlios/tuxap
/**
 * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
 * @dev: pointer to the pci_dev data structure of MSI(X) device function
 *
 * Being called during hotplug remove, from which the device funciton
 * is hot-removed. All previous assigned MSI/MSI-X vectors, if
 * allocated for this device function, are reclaimed to unused state,
 * which may be used later on.
 **/
void msi_remove_pci_irq_vectors(struct pci_dev* dev)
{
	int state, pos, temp;
	unsigned long flags;

	if (!pci_msi_enable || !dev)
 		return;

	temp = dev->irq;		/* Save IOAPIC IRQ */
   	if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) > 0 &&
		!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
		spin_lock_irqsave(&msi_lock, flags);
		state = msi_desc[dev->irq]->msi_attrib.state;
		spin_unlock_irqrestore(&msi_lock, flags);
		if (state) {
			printk(KERN_DEBUG "Driver[%d:%d:%d] unloaded wo doing free_irq on vector->%d\n",
			dev->bus->number, PCI_SLOT(dev->devfn),
			PCI_FUNC(dev->devfn), dev->irq);
			BUG_ON(state > 0);
		} else /* Release MSI vector assigned to this device */
			msi_free_vector(dev, dev->irq, 0);
		dev->irq = temp;		/* Restore IOAPIC IRQ */
	}
   	if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)) > 0 &&
		!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
		int vector, head, tail = 0, warning = 0;
		unsigned long base = 0L;

		vector = head = dev->irq;
		while (head != tail) {
			spin_lock_irqsave(&msi_lock, flags);
			state = msi_desc[vector]->msi_attrib.state;
			tail = msi_desc[vector]->link.tail;
			base = msi_desc[vector]->mask_base;
			spin_unlock_irqrestore(&msi_lock, flags);
			if (state)
				warning = 1;
			else if (vector != head) /* Release MSI-X vector */
				msi_free_vector(dev, vector, 0);
			vector = tail;
		}
		msi_free_vector(dev, vector, 0);
		if (warning) {
			/* Force to release the MSI-X memory-mapped table */
			u32 phys_addr, table_offset;
			u16 control;
			u8 bir;

			pci_read_config_word(dev, msi_control_reg(pos),
				&control);
			pci_read_config_dword(dev, msix_table_offset_reg(pos),
				&table_offset);
			bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
			phys_addr = pci_resource_start (dev, bir);
			phys_addr += (u32)(table_offset &
				~PCI_MSIX_FLAGS_BIRMASK);
			iounmap((void*)base);
			release_mem_region(phys_addr, PCI_MSIX_ENTRY_SIZE *
				multi_msix_capable(control));
			printk(KERN_DEBUG "Driver[%d:%d:%d] unloaded wo doing free_irq on all vectors\n",
				dev->bus->number, PCI_SLOT(dev->devfn),
				PCI_FUNC(dev->devfn));
			BUG_ON(warning > 0);
		}
		dev->irq = temp;		/* Restore IOAPIC IRQ */
	}
}