Ejemplo n.º 1
0
/**
 * msi_capability_init - 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, regardless of device function is capable of handling
 * multiple messages. A return of zero indicates the successful setup
 * of an entry zero with the new MSI vector or non-zero for otherwise.
 **/
static int msi_capability_init(struct pci_dev *dev)
{
	int status;
	struct msi_desc *entry;
	int pos, vector;
	u16 control;

   	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
	pci_read_config_word(dev, msi_control_reg(pos), &control);
	/* MSI Entry Initialization */
	entry = alloc_msi_entry();
	if (!entry)
		return -ENOMEM;

	vector = get_msi_vector(dev);
	if (vector < 0) {
		kmem_cache_free(msi_cachep, entry);
		return -EBUSY;
	}
	entry->link.head = vector;
	entry->link.tail = vector;
	entry->msi_attrib.type = PCI_CAP_ID_MSI;
	entry->msi_attrib.state = 0;			/* Mark it not active */
	entry->msi_attrib.entry_nr = 0;
	entry->msi_attrib.maskbit = is_mask_bit_support(control);
	entry->msi_attrib.default_vector = dev->irq;	/* Save IOAPIC IRQ */
	dev->irq = vector;
	entry->dev = dev;
	if (is_mask_bit_support(control)) {
		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
				is_64bit_address(control));
	}
	/* Replace with MSI handler */
	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
	/* Configure MSI capability structure */
	status = msi_register_init(dev, entry);
	if (status != 0) {
		dev->irq = entry->msi_attrib.default_vector;
		kmem_cache_free(msi_cachep, entry);
		return status;
	}

	attach_msi_entry(entry, vector);
	/* Set MSI enabled bits	 */
	enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);

	return 0;
}
Ejemplo n.º 2
0
/**
 * msix_capability_init - configure device's MSI-X capability
 * @dev: pointer to the pci_dev data structure of MSI-X device function
 * @entries: pointer to an array of struct msix_entry entries
 * @nvec: number of @entries
 *
 * Setup the MSI-X capability structure of device function with a
 * single MSI-X vector. A return of zero indicates the successful setup of
 * requested MSI-X entries with allocated vectors or non-zero for otherwise.
 **/
static int msix_capability_init(struct pci_dev *dev,
				struct msix_entry *entries, int nvec)
{
	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
	u32 address_hi;
	u32 address_lo;
	u32 data;
	int status;
	int vector, pos, i, j, nr_entries, temp = 0;
	unsigned long phys_addr;
	u32 table_offset;
 	u16 control;
	u8 bir;
	void __iomem *base;

   	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
	/* Request & Map MSI-X table region */
 	pci_read_config_word(dev, msi_control_reg(pos), &control);
	nr_entries = multi_msix_capable(control);

 	pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset);
	bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
	table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;
	phys_addr = pci_resource_start (dev, bir) + table_offset;
	base = ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
	if (base == NULL)
		return -ENOMEM;

	/* MSI-X Table Initialization */
	for (i = 0; i < nvec; i++) {
		entry = alloc_msi_entry();
		if (!entry)
			break;
		vector = get_msi_vector(dev);
		if (vector < 0) {
			kmem_cache_free(msi_cachep, entry);
			break;
		}

 		j = entries[i].entry;
 		entries[i].vector = vector;
		entry->msi_attrib.type = PCI_CAP_ID_MSIX;
 		entry->msi_attrib.state = 0;		/* Mark it not active */
		entry->msi_attrib.entry_nr = j;
		entry->msi_attrib.maskbit = 1;
		entry->msi_attrib.default_vector = dev->irq;
		entry->dev = dev;
		entry->mask_base = base;
		if (!head) {
			entry->link.head = vector;
			entry->link.tail = vector;
			head = entry;
		} else {
			entry->link.head = temp;
			entry->link.tail = tail->link.tail;
			tail->link.tail = vector;
			head->link.head = vector;
		}
		temp = vector;
		tail = entry;
		/* Replace with MSI-X handler */
		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
		/* Configure MSI-X capability structure */
		status = msi_ops->setup(dev, vector,
					&address_hi,
					&address_lo,
					&data);
		if (status < 0)
			break;

		writel(address_lo,
			base + j * PCI_MSIX_ENTRY_SIZE +
			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
		writel(address_hi,
			base + j * PCI_MSIX_ENTRY_SIZE +
			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
		writel(data,
			base + j * PCI_MSIX_ENTRY_SIZE +
			PCI_MSIX_ENTRY_DATA_OFFSET);
		attach_msi_entry(entry, vector);
	}
	if (i != nvec) {
		i--;
		for (; i >= 0; i--) {
			vector = (entries + i)->vector;
			msi_free_vector(dev, vector, 0);
			(entries + i)->vector = 0;
		}
		return -EBUSY;
	}
	/* Set MSI-X enabled bits */
	enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);

	return 0;
}
Ejemplo n.º 3
0
/**
 * msix_capability_init - configure device's MSI-X capability
 * @dev: pointer to the pci_dev data structure of MSI-X device function
 * @entries: pointer to an array of struct msix_entry entries
 * @nvec: number of @entries
 *
 * Setup the MSI-X capability structure of device function with a
 * single MSI-X vector. A return of zero indicates the successful setup of
 * requested MSI-X entries with allocated vectors or non-zero for otherwise.
 **/
static int msix_capability_init(struct pci_dev *dev,
                                struct msix_entry *entries, int nvec)
{
    struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
    struct msg_address address;
    struct msg_data data;
    int vector, pos, i, j, nr_entries, temp = 0;
    u32 phys_addr, table_offset;
    u16 control;
    u8 bir;
    void __iomem *base;

    pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
    /* Request & Map MSI-X table region */
    pci_read_config_word(dev, msi_control_reg(pos), &control);
    nr_entries = multi_msix_capable(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);
    base = ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
    if (base == NULL)
        return -ENOMEM;

    /* MSI-X Table Initialization */
    for (i = 0; i < nvec; i++) {
        entry = alloc_msi_entry();
        if (!entry)
            break;
        if ((vector = get_msi_vector(dev)) < 0)
            break;

        j = entries[i].entry;
        entries[i].vector = vector;
        entry->msi_attrib.type = PCI_CAP_ID_MSIX;
        entry->msi_attrib.state = 0;		/* Mark it not active */
        entry->msi_attrib.entry_nr = j;
        entry->msi_attrib.maskbit = 1;
        entry->msi_attrib.default_vector = dev->irq;
        entry->dev = dev;
        entry->mask_base = base;
        if (!head) {
            entry->link.head = vector;
            entry->link.tail = vector;
            head = entry;
        } else {
            entry->link.head = temp;
            entry->link.tail = tail->link.tail;
            tail->link.tail = vector;
            head->link.head = vector;
        }
        temp = vector;
        tail = entry;
        /* Replace with MSI-X handler */
        irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
        /* Configure MSI-X capability structure */
        msi_address_init(&address);
        msi_data_init(&data, vector);
        entry->msi_attrib.current_cpu =
            ((address.lo_address.u.dest_id >>
              MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
        writel(address.lo_address.value,
               base + j * PCI_MSIX_ENTRY_SIZE +
               PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
        writel(address.hi_address,
               base + j * PCI_MSIX_ENTRY_SIZE +
               PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
        writel(*(u32*)&data,
               base + j * PCI_MSIX_ENTRY_SIZE +
               PCI_MSIX_ENTRY_DATA_OFFSET);
        attach_msi_entry(entry, vector);
    }
    if (i != nvec) {
        i--;
        for (; i >= 0; i--) {
            vector = (entries + i)->vector;
            msi_free_vector(dev, vector, 0);
            (entries + i)->vector = 0;
        }
        return -EBUSY;
    }
    /* Set MSI-X enabled bits */
    enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);

    return 0;
}
Ejemplo n.º 4
0
/**
 * msi_capability_init - 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, regardless of device function is capable of handling
 * multiple messages. A return of zero indicates the successful setup
 * of an entry zero with the new MSI vector or non-zero for otherwise.
 **/
static int msi_capability_init(struct pci_dev *dev)
{
    struct msi_desc *entry;
    struct msg_address address;
    struct msg_data data;
    int pos, vector;
    u16 control;

    pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
    pci_read_config_word(dev, msi_control_reg(pos), &control);
    /* MSI Entry Initialization */
    if (!(entry = alloc_msi_entry()))
        return -ENOMEM;

    if ((vector = get_msi_vector(dev)) < 0) {
        kmem_cache_free(msi_cachep, entry);
        return -EBUSY;
    }
    entry->link.head = vector;
    entry->link.tail = vector;
    entry->msi_attrib.type = PCI_CAP_ID_MSI;
    entry->msi_attrib.state = 0;			/* Mark it not active */
    entry->msi_attrib.entry_nr = 0;
    entry->msi_attrib.maskbit = is_mask_bit_support(control);
    entry->msi_attrib.default_vector = dev->irq;	/* Save IOAPIC IRQ */
    dev->irq = vector;
    entry->dev = dev;
    if (is_mask_bit_support(control)) {
        entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
                           is_64bit_address(control));
    }
    /* Replace with MSI handler */
    irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
    /* Configure MSI capability structure */
    msi_address_init(&address);
    msi_data_init(&data, vector);
    entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
                                      MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
    pci_write_config_dword(dev, msi_lower_address_reg(pos),
                           address.lo_address.value);
    if (is_64bit_address(control)) {
        pci_write_config_dword(dev,
                               msi_upper_address_reg(pos), address.hi_address);
        pci_write_config_word(dev,
                              msi_data_reg(pos, 1), *((u32*)&data));
    } else
        pci_write_config_word(dev,
                              msi_data_reg(pos, 0), *((u32*)&data));
    if (entry->msi_attrib.maskbit) {
        unsigned int maskbits, temp;
        /* All MSIs are unmasked by default, Mask them all */
        pci_read_config_dword(dev,
                              msi_mask_bits_reg(pos, is_64bit_address(control)),
                              &maskbits);
        temp = (1 << multi_msi_capable(control));
        temp = ((temp - 1) & ~temp);
        maskbits |= temp;
        pci_write_config_dword(dev,
                               msi_mask_bits_reg(pos, is_64bit_address(control)),
                               maskbits);
    }
    attach_msi_entry(entry, vector);
    /* Set MSI enabled bits	 */
    enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);

    return 0;
}