iommu.lists.linux-foundation.org archive mirror
 help / color / mirror / Atom feed
From: Don Dutile <ddutile-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
To: Alex Williamson
	<alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>,
	dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org
Subject: Re: [RFC PATCH v2 1/2] pci: Create PCIe requester ID interface
Date: Thu, 25 Jul 2013 14:38:21 -0400	[thread overview]
Message-ID: <51F1709D.4090402@redhat.com> (raw)
In-Reply-To: <1374700966.16522.19.camel-85EaTFmN5p//9pzu0YdTqQ@public.gmane.org>

On 07/24/2013 05:22 PM, Alex Williamson wrote:
> On Wed, 2013-07-24 at 16:42 -0400, Don Dutile wrote:
>> On 07/23/2013 06:35 PM, Bjorn Helgaas wrote:
>>> On Thu, Jul 11, 2013 at 03:03:27PM -0600, Alex Williamson wrote:
>>>> This provides interfaces for drivers to discover the visible PCIe
>>>> requester ID for a device, for things like IOMMU setup, and iterate
>>>
>>> IDs (plural)
>>>
>> a single device does not have multiple requester id's;
>> can have multiple tag-id's (that are ignored in this situation, but
>> can be used by switches for ordering purposes), but there's only 1/fcn
>> (except for those quirker pdevs!).
>>
>>>> over the device chain from requestee to requester, including DMA
>>>> quirks at each step.
>>>
>>> "requestee" doesn't make sense to me.  The "-ee" suffix added to a verb
>>> normally makes a noun that refers to the object of the action.  So
>>> "requestee" sounds like it means something like "target" or "responder,"
>>> but that's not what you mean here.
>>>
>> sorry, I didn't follow the requester/requestee terminology either...
>>
>>>> Suggested-by: Bjorn Helgaas<bhelgaas@google.com>
>>>> Signed-off-by: Alex Williamson<alex.williamson@redhat.com>
>>>> ---
>>>>    drivers/pci/search.c |  198 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>    include/linux/pci.h  |    7 ++
>>>>    2 files changed, 205 insertions(+)
>>>>
>>>> diff --git a/drivers/pci/search.c b/drivers/pci/search.c
>>>> index d0627fa..4759c02 100644
>>>> --- a/drivers/pci/search.c
>>>> +++ b/drivers/pci/search.c
>>>> @@ -18,6 +18,204 @@ DECLARE_RWSEM(pci_bus_sem);
>>>>    EXPORT_SYMBOL_GPL(pci_bus_sem);
>>>>
>>>>    /*
>>>> + * pci_has_pcie_requester_id - Does @dev have a PCIe requester ID
>>>> + * @dev: device to test
>>>> + */
>>>> +static bool pci_has_pcie_requester_id(struct pci_dev *dev)
>>>> +{
>>>> +	/*
>>>> +	 * XXX There's no indicator of the bus type, conventional PCI vs
>>>> +	 * PCI-X vs PCI-e, but we assume that a caller looking for a PCIe
>>>> +	 * requester ID is a native PCIe based system (such as VT-d or
>>>> +	 * AMD-Vi).  It's common that PCIe root complex devices do not
>> could the above comment be x86-iommu-neutral?
>> by definition of PCIe, all devices have a requester id (min. to accept cfg cycles);
>> req'd if source of read/write requests, read completions.
>
> I agree completely, the question is whether we have a PCIe root complex
> or a conventional PCI host bus.  I don't think we have any way to tell,
> so I'm assuming pci_is_root_bus() indicates we're on a PCIe root complex
> and therefore have requester IDs.  If there's some way to determine this
> let me know and we can avoid any kind of assumption.
>
>>>> +	 * include a PCIe capability, but we can assume they are PCIe
>>>> +	 * devices based on their topology.
>>>> +	 */
>>>> +	if (pci_is_pcie(dev) || pci_is_root_bus(dev->bus))
>>>> +		return true;
>>>> +
>>>> +	/*
>>>> +	 * PCI-X devices have a requester ID, but the bridge may still take
>>>> +	 * ownership of transactions and create a requester ID.  We therefore
>>>> +	 * assume that the PCI-X requester ID is not the same one used on PCIe.
>>>> +	 */
>>>> +
>>>> +#ifdef CONFIG_PCI_QUIRKS
>>>> +	/*
>>>> +	 * Quirk for PCIe-to-PCI bridges which do not expose a PCIe capability.
>>>> +	 * If the device is a bridge, look to the next device upstream of it.
>>>> +	 * If that device is PCIe and not a PCIe-to-PCI bridge, then by
>>>> +	 * deduction, the device must be PCIe and therefore has a requester ID.
>>>> +	 */
>>>> +	if (dev->subordinate) {
>>>> +		struct pci_dev *parent = dev->bus->self;
>>>> +
>>>> +		if (pci_is_pcie(parent)&&
>>>> +		    pci_pcie_type(parent) != PCI_EXP_TYPE_PCI_BRIDGE)
>>>> +			return true;
>>>> +	}
>>>> +#endif
>>>> +
>>>> +	return false;
>>>> +}
>>>> +
>>>> +/*
>>>> + * pci_has_visible_pcie_requester_id - Can @bridge see @dev's requester ID?
>>>> + * @dev: requester device
>>>> + * @bridge: upstream bridge (or NULL for root bus)
>>>> + */
>>>> +static bool pci_has_visible_pcie_requester_id(struct pci_dev *dev,
>>>> +					      struct pci_dev *bridge)
>>>> +{
>>>> +	/*
>>>> +	 * The entire path must be tested, if any step does not have a
>>>> +	 * requester ID, the chain is broken.  This allows us to support
>>>> +	 * topologies with PCIe requester ID gaps, ex: PCIe-PCI-PCIe
>>>> +	 */
>>>> +	while (dev != bridge) {
>>>> +		if (!pci_has_pcie_requester_id(dev))
>>>> +			return false;
>>>> +
>>>> +		if (pci_is_root_bus(dev->bus))
>>>> +			return !bridge; /* false if we don't hit @bridge */
>>>> +
>>>> +		dev = dev->bus->self;
>>>> +	}
>>>> +
>>>> +	return true;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Legacy PCI bridges within a root complex (ex. Intel 82801) report
>>>> + * a different requester ID than a standard PCIe-to-PCI bridge.  Instead
>> First, I'm assuming you mean that devices behind a Legacy PCI bridge within a root complex
>> get assigned IDs different than std PCIe-to-PCI bridges (as quoted below).
>
> Yes
>
>>>> + * of using (subordinate<<   8 | 0) the use (bus<<   8 | devfn), like a
>>>
>>> s/the/they/
>>>
>> well, the PPBs should inject their (secondary<<  8 | 0), not subordinate.
>>   From the PCI Express to PCI/PCI-X Bridge spec, v1.0:
>> The Tag is reassigned by the bridge according to the rules outlined in the following sections. If the
>> bridge generates a new Requester ID for a transaction forwarded from the secondary interface to the
>> primary interface, the bridge assigns the PCI Express Requester ID using its secondary interface’s
>>                                                                                ^^^^^^^^^
>> Bus Number and sets both the Device Number and Function Number fields to zero.
>> ^^^^^^^^^^
>
> I'm referring to (pdev->subordinate->number<<  8 | 0) vs
> (pdev->bus->number<<  8 | pdev->devfn).  The subordinate struct pci_bus
> is the secondary interface bus.
>
>> As for the 82801, looks like they took this part of the PCIe spec to heart:
>> (PCIe v3 spec, section 2.2.6.2 Transaction Descriptor - Transaction ID Field):
>> Exception: The assignment of Bus and Device Numbers to the Devices within a Root Complex,
>> and the Device Numbers to the Downstream Ports within a Switch, may be done in an
>> implementation specific way.
>> Obviously, you're missing the 'implementation-specific way' compiler... ;-)
>
> So this is potentially Intel specific.  How can we tell it's an Intel
> root complex?
>
Good question. ... another question to ask Intel.... :(

>> aw: which 'bus' do you mean above in  '(bus<<   8 | devfn)' ?
>
> (pdev->bus->number<<  8 | pdev->devfn)
>
k.

>>> Did you learn about this empirically?  Intel spec?  I wonder if there's
>>> some way to derive this from the PCIe specs.
>>>
>>>> + * standard PCIe endpoint.  This function detects them.
>>>> + *
>>>> + * XXX Is this Intel vendor ID specific?
>>>> + */
>>>> +static bool pci_bridge_uses_endpoint_requester(struct pci_dev *bridge)
>>>> +{
>>>> +	if (!pci_is_pcie(bridge)&&   pci_is_root_bus(bridge->bus))
>>>> +		return true;
>>>> +
>>>> +	return false;
>>>> +}
>>>> +
>>>> +#define PCI_REQUESTER_ID(dev)	(((dev)->bus->number<<   8) | (dev)->devfn)
>>>> +#define PCI_BRIDGE_REQUESTER_ID(dev)	((dev)->subordinate->number<<   8)
>>>> +
>>>> +/*
>>>> + * pci_get_visible_pcie_requester - Get requester and requester ID for
>>>> + *                                  @requestee below @bridge
>>>> + * @requestee: requester device
>>>> + * @bridge: upstream bridge (or NULL for root bus)
>>>> + * @requester_id: location to store requester ID or NULL
>>>> + */
>>>> +struct pci_dev *pci_get_visible_pcie_requester(struct pci_dev *requestee,
>>>> +					       struct pci_dev *bridge,
>>>> +					       u16 *requester_id)
>>>
>>> I'm not sure it makes sense to return a struct pci_dev here because
>>> there's no requirement that a requester ID correspond to an actual
>>> pci_dev.
>>>
>> well, I would expect the only callers would be for subsys (iommu's)
>> searching to find requester-id for a pdev, b/c if a pdev doesn't exist,
>> then the device (and requester-id) doesn't exist... :-/
>
> One of the cases Bjorn is referring to is probably the simple case of a
> PCIe-to-PCI bridge.  The requester ID is (bridge->subordinate->number<<
> 8 | 0), which is not an actual device.  As coded here, the function
> returns bridge, but requester_id is (bridge->subordinate->number<<  8 |
> 0).
>
right, that requester-id doesn't map (most likely) to a pdev w/matching BDF.

>>>> +{
>>>> +	struct pci_dev *requester = requestee;
>>>> +
>>>> +	while (requester != bridge) {
>>>> +		requester = pci_get_dma_source(requester);
>>>> +		pci_dev_put(requester); /* XXX skip ref cnt */
>>>> +
>>>> +		if (pci_has_visible_pcie_requester_id(requester, bridge))
>>>
>>> If we acquire the "requester" pointer via a ref-counting interface,
>>> it's illegal to use the pointer after dropping the reference, isn't it?
>>> Maybe that's what you mean by the "XXX" comment.
>>>
>>>> +			break;
>>>> +
>>>> +		if (pci_is_root_bus(requester->bus))
>>>> +			return NULL; /* @bridge not parent to @requestee */
>>>> +
>>>> +		requester = requester->bus->self;
>>>> +	}
>>>> +
>>>> +	if (requester_id) {
>>>> +		if (requester->bus != requestee->bus&&
>>>> +		    !pci_bridge_uses_endpoint_requester(requester))
>>>> +			*requester_id = PCI_BRIDGE_REQUESTER_ID(requester);
>>>> +		else
>>>> +			*requester_id = PCI_REQUESTER_ID(requester);
>>>> +	}
>>>> +
>>>> +	return requester;
>>>> +}
>>>> +
>>>> +static int pci_do_requester_callback(struct pci_dev **dev,
>>>> +				     int (*fn)(struct pci_dev *,
>>>> +					       u16 id, void *),
>>>> +				     void *data)
>>>> +{
>>>> +	struct pci_dev *dma_dev;
>>>> +	int ret;
>>>> +
>>>> +	ret = fn(*dev, PCI_REQUESTER_ID(*dev), data);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	dma_dev = pci_get_dma_source(*dev);
>>>> +	pci_dev_put(dma_dev); /* XXX skip ref cnt */
>>>> +	if (dma_dev == *dev)
>>>
>>> Same ref count question as above.
>>>
>>>> +		return 0;
>>>> +
>>>> +	ret = fn(dma_dev, PCI_REQUESTER_ID(dma_dev), data);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	*dev = dma_dev;
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +/*
>>>> + * pcie_for_each_requester - Call callback @fn on each devices and DMA source
>>>> + *                           from @requestee to the PCIe requester ID visible
>>>> + *                           to @bridge.
>>>
>>> Transactions from a device may appear with one of several requester IDs,
>>> but there's not necessarily an actual pci_dev for each ID, so I think the
>> ditto above; have to have a pdev for each id....
>>
>>> caller reads better if it's "...for_each_requester_id()"
>>>
>>> The "Call X on each devices and DMA source from Y to the requester ID"
>>> part doesn't quite make a sentence.
>>>
>>>> + * @requestee: Starting device
>>>> + * @bridge: upstream bridge (or NULL for root bus)
>>>
>>> You should say something about the significance of @bridge.  I think the
>>> point is to call @fn for every possible requester ID @bridge could see for
>>> transactions from @requestee.  This is a way to learn the requester IDs an
>>> IOMMU at @bridge needs to be prepared for.
>>>
>>>> + * @fn: callback function
>>>> + * @data: data to pass to callback
>>>> + */
>>>> +int pcie_for_each_requester(struct pci_dev *requestee, struct pci_dev *bridge,
>>>> +			    int (*fn)(struct pci_dev *, u16 id, void *),
>>>> +			    void *data)
>>>> +{
>>>> +	struct pci_dev *requester;
>>>> +	struct pci_dev *dev = requestee;
>>>> +	int ret = 0;
>>>> +
>>>> +	requester = pci_get_visible_pcie_requester(requestee, bridge, NULL);
>>>> +	if (!requester)
>>>> +		return -EINVAL;
>>>> +
>>>> +	do {
>>>> +		ret = pci_do_requester_callback(&dev, fn, data);
>>>> +		if (ret)
>>>> +			return ret;
>>>> +
>>>> +		if (dev == requester)
>>>> +			return 0;
>>>> +
>>>> +		/*
>>>> +		 * We always consider root bus devices to have a visible
>>>> +		 * requester ID, therefore this should never be true.
>>>> +		 */
>>>> +		BUG_ON(pci_is_root_bus(dev->bus));
>>>
>>> What are we going to do if somebody hits this BUG_ON()?  If it's impossible
>>> to hit, we should just remove it.  If it's possible to hit it in some weird
>>> topology you didn't consider, we should see IOMMU faults for any requester
>>> ID we neglected to map, and that fault would be a better debugging hint
>>> than a BUG_ON() here.
>>>
>> according to spec, all pdev's have a requester-id, even RC ones, albeit
>> "implementation specific"...
>>
>>>> +
>>>> +		dev = dev->bus->self;
>>>> +
>>>> +	} while (dev != requester);
>>>> +
>>>> +	/*
>>>> +	 * If we've made it here, @requester is a bridge upstream from
>>>> +	 * @requestee.
>>>> +	 */
>>>> +	if (pci_bridge_uses_endpoint_requester(requester))
>>>> +		return pci_do_requester_callback(&requester, fn, data);
>>>> +
>>>> +	return fn(requester, PCI_BRIDGE_REQUESTER_ID(requester), data);
>>>> +}
>>>> +
>>>> +/*
>>>>     * find the upstream PCIe-to-PCI bridge of a PCI device
>>>>     * if the device is PCIE, return NULL
>>>>     * if the device isn't connected to a PCIe bridge (that is its parent is a
>>>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>>>> index 3a24e4f..94e81d1 100644
>>>> --- a/include/linux/pci.h
>>>> +++ b/include/linux/pci.h
>>>> @@ -1873,6 +1873,13 @@ static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
>>>>    }
>>>>    #endif
>>>>
>>>> +struct pci_dev *pci_get_visible_pcie_requester(struct pci_dev *requestee,
>>>> +					       struct pci_dev *bridge,
>>>> +					       u16 *requester_id);
>>>
>>> The structure of this interface implies that there is only one visible
>>> requester ID, but the whole point of this patch is that a transaction from
>>> @requestee may appear with one of several requester IDs.  So which one will
>>> this return?
>>>
>> Are there devices that use multiple requester id's?
>> I know we have ones that use the wrong id.
>> If we want to handle the multiple requester-id's per pdev,
>> we could pass in a ptr to an initial requester-id; if null, give me first;
>> if !null, give me next one;  would also need a flag returned to indicate
>> there is more than 1.
>> null-rtn when pass in !null ref, means the end.
>>    ... sledge-hammer + nail ???
>
> That does not sound safe.  Again, this is why I think the
> pcie_for_each_requester() works.  Given a requester, call fn() on every
> device with the same requester ID.  That means when you have a bridge,
> we call it for the bridge and every device and every device quirk behind
> the bridge, fully populating context entries for all of them.  Thanks,
>
> Alex
>
ok.

>>>> +int pcie_for_each_requester(struct pci_dev *requestee, struct pci_dev *bridge,
>>>> +			    int (*fn)(struct pci_dev *, u16 id, void *),
>>>> +			    void *data);
>>>> +
>>>>    /**
>>>>     * pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device
>>>>     * @pdev: the PCI device
>>>>
>>
>
>
>

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

  parent reply	other threads:[~2013-07-25 18:38 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-07-11 21:03 [RFC PATCH v2 0/2] pci/iommu: PCIe requester ID interface Alex Williamson
     [not found] ` <20130711204439.1701.90503.stgit-xdHQ/5r00wBBDLzU/O5InQ@public.gmane.org>
2013-07-11 21:03   ` [RFC PATCH v2 1/2] pci: Create " Alex Williamson
     [not found]     ` <20130711210326.1701.56478.stgit-xdHQ/5r00wBBDLzU/O5InQ@public.gmane.org>
2013-07-23 22:35       ` Bjorn Helgaas
     [not found]         ` <20130723223533.GB19765-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
2013-07-23 23:21           ` Alex Williamson
     [not found]             ` <1374621703.15429.98.camel-85EaTFmN5p//9pzu0YdTqQ@public.gmane.org>
2013-07-24 15:03               ` Andrew Cooks
     [not found]                 ` <CAJtEV7b3JR9J7UN_gzL6deD1JDBTfhQjGQzd_TRMLcWX2aoUfg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-07-24 15:50                   ` Alex Williamson
2013-07-24 16:47               ` Bjorn Helgaas
     [not found]                 ` <CAErSpo6bcGCjqdxn-bz_vjo+HsAiOxDu=--mD7veEZ9f7k+gyA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-07-24 18:12                   ` Alex Williamson
2013-07-24 23:24                     ` Bjorn Helgaas
     [not found]                       ` <20130724232427.GA9272-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
2013-07-25 17:56                         ` Alex Williamson
2013-07-26 21:54                           ` Bjorn Helgaas
2013-07-29 16:06                             ` Alex Williamson
2013-07-29 21:02                               ` Bjorn Helgaas
     [not found]                                 ` <CAErSpo7pfCtTm5Cq=VixPTKMpM4VQpDr+ZmS5qMw32z6ABu0xQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-07-29 22:32                                   ` Alex Williamson
2013-08-01 22:08                                     ` Bjorn Helgaas
     [not found]                                       ` <CAErSpo5+-r3qMca1_Kvt3jJ6OP6Q7--4VmTo3fWJ0y4CPewgEQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-08-02 16:59                                         ` Alex Williamson
     [not found]                                           ` <1375462795.31262.327.camel-85EaTFmN5p//9pzu0YdTqQ@public.gmane.org>
2014-04-03 21:48                                             ` Bjorn Helgaas
     [not found]                                               ` <CAErSpo5p+6yt8ZyVuLnJTiKAWZWq9ixQQu78nD-bNFkw4ntWmw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-04  2:51                                                 ` Alex Williamson
     [not found]                                                   ` <1396579914.3215.36.camel-85EaTFmN5p//9pzu0YdTqQ@public.gmane.org>
2014-04-04 15:00                                                     ` Bjorn Helgaas
2013-07-29 21:03                               ` Don Dutile
     [not found]                                 ` <51F6D8BB.4040901-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-07-29 22:55                                   ` Alex Williamson
2013-07-24 20:42           ` Don Dutile
     [not found]             ` <51F03C1B.2070002-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-07-24 21:22               ` Alex Williamson
     [not found]                 ` <1374700966.16522.19.camel-85EaTFmN5p//9pzu0YdTqQ@public.gmane.org>
2013-07-25 18:38                   ` Don Dutile [this message]
2013-07-25 17:19               ` Bjorn Helgaas
     [not found]                 ` <20130725171958.GB9272-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
2013-07-25 18:25                   ` Don Dutile
     [not found]                     ` <51F16D80.5040208-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-07-26 19:48                       ` Bjorn Helgaas
     [not found]                         ` <20130726194813.GA20021-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
2013-07-26 20:04                           ` Don Dutile
2013-07-11 21:03   ` [RFC PATCH v2 2/2] iommu/intel: Make use of " Alex Williamson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=51F1709D.4090402@redhat.com \
    --to=ddutile-h+wxahxf7alqt0dzr+alfa@public.gmane.org \
    --cc=alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \
    --cc=bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org \
    --cc=dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org \
    --cc=iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org \
    --cc=linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).