Exemplo n.º 1
0
static int set_msi_sid(struct irte *irte, struct pci_dev *dev)
{
	struct set_msi_sid_data data;

	if (!irte || !dev)
		return -1;

	pci_for_each_dma_alias(dev, set_msi_sid_cb, &data);

	/*
	 * DMA alias provides us with a PCI device and alias.  The only case
	 * where the it will return an alias on a different bus than the
	 * device is the case of a PCIe-to-PCI bridge, where the alias is for
	 * the subordinate bus.  In this case we can only verify the bus.
	 *
	 * If the alias device is on a different bus than our source device
	 * then we have a topology based alias, use it.
	 *
	 * Otherwise, the alias is for a device DMA quirk and we cannot
	 * assume that MSI uses the same requester ID.  Therefore use the
	 * original device.
	 */
	if (PCI_BUS_NUM(data.alias) != data.pdev->bus->number)
		set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16,
			     PCI_DEVID(PCI_BUS_NUM(data.alias),
				       dev->bus->number));
	else if (data.pdev->bus->number != dev->bus->number)
		set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, data.alias);
	else
		set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
			     PCI_DEVID(dev->bus->number, dev->devfn));

	return 0;
}
static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
			       int nvec, msi_alloc_info_t *info)
{
	struct pci_dev *pdev, *alias_dev;
	struct msi_domain_info *msi_info;
	int alias_count = 0;

	if (!dev_is_pci(dev))
		return -EINVAL;

	msi_info = msi_get_domain_info(domain->parent);

	pdev = to_pci_dev(dev);
	/*
	 * If pdev is downstream of any aliasing bridges, take an upper
	 * bound of how many other vectors could map to the same DevID.
	 */
	pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev);
	if (alias_dev != pdev && alias_dev->subordinate)
		pci_walk_bus(alias_dev->subordinate, its_pci_msi_vec_count,
			     &alias_count);

	/* ITS specific DeviceID, as the core ITS ignores dev. */
	info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain, pdev);

	return msi_info->ops->msi_prepare(domain->parent,
					  dev, max(nvec, alias_count), info);
}
Exemplo n.º 3
0
/*
 * Allocate a pasid table for @dev. It should be called in a
 * single-thread context.
 */
int intel_pasid_alloc_table(struct device *dev)
{
	struct device_domain_info *info;
	struct pasid_table *pasid_table;
	struct pasid_table_opaque data;
	struct page *pages;
	size_t size, count;
	int ret, order;

	info = dev->archdata.iommu;
	if (WARN_ON(!info || !dev_is_pci(dev) ||
		    !info->pasid_supported || info->pasid_table))
		return -EINVAL;

	/* DMA alias device already has a pasid table, use it: */
	data.pasid_table = &pasid_table;
	ret = pci_for_each_dma_alias(to_pci_dev(dev),
				     &get_alias_pasid_table, &data);
	if (ret)
		goto attach_out;

	pasid_table = kzalloc(sizeof(*pasid_table), GFP_ATOMIC);
	if (!pasid_table)
		return -ENOMEM;
	INIT_LIST_HEAD(&pasid_table->dev);

	size = sizeof(struct pasid_entry);
	count = min_t(int, pci_max_pasids(to_pci_dev(dev)), intel_pasid_max_id);
	order = get_order(size * count);
	pages = alloc_pages_node(info->iommu->node,
				 GFP_ATOMIC | __GFP_ZERO,
				 order);
	if (!pages)
		return -ENOMEM;

	pasid_table->table = page_address(pages);
	pasid_table->order = order;
	pasid_table->max_pasid = count;

attach_out:
	device_attach_pasid_table(info, pasid_table);

	return 0;
}
Exemplo n.º 4
0
static int set_msi_sid(struct irte *irte, struct pci_dev *dev)
{
	struct set_msi_sid_data data;

	if (!irte || !dev)
		return -1;

	data.count = 0;
	data.busmatch_count = 0;
	pci_for_each_dma_alias(dev, set_msi_sid_cb, &data);

	/*
	 * DMA alias provides us with a PCI device and alias.  The only case
	 * where the it will return an alias on a different bus than the
	 * device is the case of a PCIe-to-PCI bridge, where the alias is for
	 * the subordinate bus.  In this case we can only verify the bus.
	 *
	 * If there are multiple aliases, all with the same bus number,
	 * then all we can do is verify the bus. This is typical in NTB
	 * hardware which use proxy IDs where the device will generate traffic
	 * from multiple devfn numbers on the same bus.
	 *
	 * If the alias device is on a different bus than our source device
	 * then we have a topology based alias, use it.
	 *
	 * Otherwise, the alias is for a device DMA quirk and we cannot
	 * assume that MSI uses the same requester ID.  Therefore use the
	 * original device.
	 */
	if (PCI_BUS_NUM(data.alias) != data.pdev->bus->number)
		set_irte_verify_bus(irte, PCI_BUS_NUM(data.alias),
				    dev->bus->number);
	else if (data.count >= 2 && data.busmatch_count == data.count)
		set_irte_verify_bus(irte, dev->bus->number, dev->bus->number);
	else if (data.pdev->bus->number != dev->bus->number)
		set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, data.alias);
	else
		set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
			     pci_dev_id(dev));

	return 0;
}
Exemplo n.º 5
0
static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
			       int nvec, msi_alloc_info_t *info)
{
	struct pci_dev *pdev;
	struct its_pci_alias dev_alias;
	struct msi_domain_info *msi_info;

	if (!dev_is_pci(dev))
		return -EINVAL;

	msi_info = msi_get_domain_info(domain->parent);

	pdev = to_pci_dev(dev);
	dev_alias.pdev = pdev;
	dev_alias.count = nvec;

	pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias);

	/* ITS specific DeviceID, as the core ITS ignores dev. */
	info->scratchpad[0].ul = dev_alias.dev_id;

	return msi_info->ops->msi_prepare(domain->parent,
					  dev, dev_alias.count, info);
}