diff mbox series

[v3,08/11] vpci/header: Emulate PCI_COMMAND register for guests

Message ID 20210930075223.860329-9-andr2000@gmail.com (mailing list archive)
State Superseded
Headers show
Series PCI devices passthrough on Arm, part 3 | expand

Commit Message

Oleksandr Andrushchenko Sept. 30, 2021, 7:52 a.m. UTC
From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>

Add basic emulation support for guests. At the moment only emulate
PCI_COMMAND_INTX_DISABLE bit, the rest is not emulated yet and left
as TODO.

Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@arm.com>
---
New in v2
---
 xen/drivers/vpci/header.c | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

Comments

Roger Pau Monné Oct. 26, 2021, 10:52 a.m. UTC | #1
On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
> From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> 
> Add basic emulation support for guests. At the moment only emulate
> PCI_COMMAND_INTX_DISABLE bit, the rest is not emulated yet and left
> as TODO.
> 
> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> Reviewed-by: Michal Orzel <michal.orzel@arm.com>
> ---
> New in v2
> ---
>  xen/drivers/vpci/header.c | 35 ++++++++++++++++++++++++++++++++---
>  1 file changed, 32 insertions(+), 3 deletions(-)
> 
> diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
> index f23c956cde6c..754aeb5a584f 100644
> --- a/xen/drivers/vpci/header.c
> +++ b/xen/drivers/vpci/header.c
> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>          pci_conf_write16(pdev->sbdf, reg, cmd);
>  }
>  
> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
> +                            uint32_t cmd, void *data)
> +{
> +    /* TODO: Add proper emulation for all bits of the command register. */
> +
> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
> +    {
> +        /*
> +         * Guest wants to enable INTx. It can't be enabled if:
> +         *  - host has INTx disabled
> +         *  - MSI/MSI-X enabled
> +         */
> +        if ( pdev->vpci->msi->enabled )
> +            cmd |= PCI_COMMAND_INTX_DISABLE;
> +        else
> +        {
> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
> +
> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
> +                cmd |= PCI_COMMAND_INTX_DISABLE;
> +        }

This last part should be Arm specific. On other architectures we
likely want the guest to modify INTx disable in order to select the
interrupt delivery mode for the device.

I really wonder if we should allow the guest to play with any other
bit apart from INTx disable and memory and IO decoding on the command
register.

Thanks, Roger.
Oleksandr Andrushchenko Nov. 2, 2021, 10:48 a.m. UTC | #2
Hi, Roger!

On 26.10.21 13:52, Roger Pau Monné wrote:
> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>> From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
>>
>> Add basic emulation support for guests. At the moment only emulate
>> PCI_COMMAND_INTX_DISABLE bit, the rest is not emulated yet and left
>> as TODO.
>>
>> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
>> Reviewed-by: Michal Orzel <michal.orzel@arm.com>
>> ---
>> New in v2
>> ---
>>   xen/drivers/vpci/header.c | 35 ++++++++++++++++++++++++++++++++---
>>   1 file changed, 32 insertions(+), 3 deletions(-)
>>
>> diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
>> index f23c956cde6c..754aeb5a584f 100644
>> --- a/xen/drivers/vpci/header.c
>> +++ b/xen/drivers/vpci/header.c
>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>           pci_conf_write16(pdev->sbdf, reg, cmd);
>>   }
>>   
>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>> +                            uint32_t cmd, void *data)
>> +{
>> +    /* TODO: Add proper emulation for all bits of the command register. */
>> +
>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>> +    {
>> +        /*
>> +         * Guest wants to enable INTx. It can't be enabled if:
>> +         *  - host has INTx disabled
>> +         *  - MSI/MSI-X enabled
>> +         */
>> +        if ( pdev->vpci->msi->enabled )
>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>> +        else
>> +        {
>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>> +
>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>> +        }
> This last part should be Arm specific. On other architectures we
> likely want the guest to modify INTx disable in order to select the
> interrupt delivery mode for the device.
This is not arch specific as we just do not allow INTx to be enabled
if MSI/MSI-X has been enabled before. This was discussed previously
(Jan) and this was pointed as an acceptable approach to limit the
guest from having inconsistent configuration
>
> I really wonder if we should allow the guest to play with any other
> bit apart from INTx disable and memory and IO decoding on the command
> register.
This needs to be implemented one day when we understand what
this emulation should look like. This is why I have a "TODO" above.
>
> Thanks, Roger.
Thank you,
Oleksandr
Jan Beulich Nov. 2, 2021, 11:19 a.m. UTC | #3
On 26.10.2021 12:52, Roger Pau Monné wrote:
> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>> --- a/xen/drivers/vpci/header.c
>> +++ b/xen/drivers/vpci/header.c
>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>          pci_conf_write16(pdev->sbdf, reg, cmd);
>>  }
>>  
>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>> +                            uint32_t cmd, void *data)
>> +{
>> +    /* TODO: Add proper emulation for all bits of the command register. */
>> +
>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>> +    {
>> +        /*
>> +         * Guest wants to enable INTx. It can't be enabled if:
>> +         *  - host has INTx disabled
>> +         *  - MSI/MSI-X enabled
>> +         */
>> +        if ( pdev->vpci->msi->enabled )
>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>> +        else
>> +        {
>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>> +
>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>> +        }
> 
> This last part should be Arm specific. On other architectures we
> likely want the guest to modify INTx disable in order to select the
> interrupt delivery mode for the device.

We cannot allow a guest to clear the bit when it has MSI / MSI-X
enabled - only one of the three is supposed to be active at a time.
(IOW similarly we cannot allow a guest to enable MSI / MSI-X when
the bit is clear.)

Jan
Roger Pau Monné Nov. 2, 2021, 11:50 a.m. UTC | #4
On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
> On 26.10.2021 12:52, Roger Pau Monné wrote:
> > On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
> >> --- a/xen/drivers/vpci/header.c
> >> +++ b/xen/drivers/vpci/header.c
> >> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
> >>          pci_conf_write16(pdev->sbdf, reg, cmd);
> >>  }
> >>  
> >> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
> >> +                            uint32_t cmd, void *data)
> >> +{
> >> +    /* TODO: Add proper emulation for all bits of the command register. */
> >> +
> >> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
> >> +    {
> >> +        /*
> >> +         * Guest wants to enable INTx. It can't be enabled if:
> >> +         *  - host has INTx disabled
> >> +         *  - MSI/MSI-X enabled
> >> +         */
> >> +        if ( pdev->vpci->msi->enabled )
> >> +            cmd |= PCI_COMMAND_INTX_DISABLE;
> >> +        else
> >> +        {
> >> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
> >> +
> >> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
> >> +                cmd |= PCI_COMMAND_INTX_DISABLE;
> >> +        }
> > 
> > This last part should be Arm specific. On other architectures we
> > likely want the guest to modify INTx disable in order to select the
> > interrupt delivery mode for the device.
> 
> We cannot allow a guest to clear the bit when it has MSI / MSI-X
> enabled - only one of the three is supposed to be active at a time.
> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
> the bit is clear.)

Sure, but this code is making the bit sticky, by not allowing
INTX_DISABLE to be cleared once set. We do not want that behavior on
x86, as a guest can decide to use MSI or INTx. The else branch needs
to be Arm only.

Regards, Roger.
Jan Beulich Nov. 2, 2021, 1:54 p.m. UTC | #5
On 02.11.2021 12:50, Roger Pau Monné wrote:
> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>> --- a/xen/drivers/vpci/header.c
>>>> +++ b/xen/drivers/vpci/header.c
>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>          pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>  }
>>>>  
>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>> +                            uint32_t cmd, void *data)
>>>> +{
>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>> +
>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>> +    {
>>>> +        /*
>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>> +         *  - host has INTx disabled
>>>> +         *  - MSI/MSI-X enabled
>>>> +         */
>>>> +        if ( pdev->vpci->msi->enabled )
>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>> +        else
>>>> +        {
>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>> +
>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>> +        }
>>>
>>> This last part should be Arm specific. On other architectures we
>>> likely want the guest to modify INTx disable in order to select the
>>> interrupt delivery mode for the device.
>>
>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>> enabled - only one of the three is supposed to be active at a time.
>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>> the bit is clear.)
> 
> Sure, but this code is making the bit sticky, by not allowing
> INTX_DISABLE to be cleared once set. We do not want that behavior on
> x86, as a guest can decide to use MSI or INTx. The else branch needs
> to be Arm only.

Isn't the "else" part questionable even on Arm?

Jan
Oleksandr Andrushchenko Nov. 2, 2021, 2:10 p.m. UTC | #6
On 02.11.21 15:54, Jan Beulich wrote:
> On 02.11.2021 12:50, Roger Pau Monné wrote:
>> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>>> --- a/xen/drivers/vpci/header.c
>>>>> +++ b/xen/drivers/vpci/header.c
>>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>           pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>>   }
>>>>>   
>>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>> +                            uint32_t cmd, void *data)
>>>>> +{
>>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>>> +
>>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>> +    {
>>>>> +        /*
>>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>>> +         *  - host has INTx disabled
>>>>> +         *  - MSI/MSI-X enabled
>>>>> +         */
>>>>> +        if ( pdev->vpci->msi->enabled )
>>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>> +        else
>>>>> +        {
>>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>>> +
>>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>> +        }
>>>> This last part should be Arm specific. On other architectures we
>>>> likely want the guest to modify INTx disable in order to select the
>>>> interrupt delivery mode for the device.
>>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>>> enabled - only one of the three is supposed to be active at a time.
>>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>>> the bit is clear.)
>> Sure, but this code is making the bit sticky, by not allowing
>> INTX_DISABLE to be cleared once set. We do not want that behavior on
>> x86, as a guest can decide to use MSI or INTx. The else branch needs
>> to be Arm only.
> Isn't the "else" part questionable even on Arm?
It is. Once fixed I can't see anything Arm specific here
>
> Jan
>
Julien Grall Nov. 2, 2021, 2:17 p.m. UTC | #7
Hi Roger,

On 02/11/2021 11:50, Roger Pau Monné wrote:
> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>> --- a/xen/drivers/vpci/header.c
>>>> +++ b/xen/drivers/vpci/header.c
>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>           pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>   }
>>>>   
>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>> +                            uint32_t cmd, void *data)
>>>> +{
>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>> +
>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>> +    {
>>>> +        /*
>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>> +         *  - host has INTx disabled
>>>> +         *  - MSI/MSI-X enabled
>>>> +         */
>>>> +        if ( pdev->vpci->msi->enabled )
>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>> +        else
>>>> +        {
>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>> +
>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>> +        }
>>>
>>> This last part should be Arm specific. On other architectures we
>>> likely want the guest to modify INTx disable in order to select the
>>> interrupt delivery mode for the device.
>>
>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>> enabled - only one of the three is supposed to be active at a time.
>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>> the bit is clear.)
> 
> Sure, but this code is making the bit sticky, by not allowing
> INTX_DISABLE to be cleared once set. We do not want that behavior on
> x86, as a guest can decide to use MSI or INTx.

On Arm, I am aware of some hosbridges (e.g. Thunder-X) where legacy 
interrupts are not supported. Do such hostbridges exist x86?

Cheers,
Oleksandr Andrushchenko Nov. 3, 2021, 8:53 a.m. UTC | #8
On 02.11.21 16:10, Oleksandr Andrushchenko wrote:
>
> On 02.11.21 15:54, Jan Beulich wrote:
>> On 02.11.2021 12:50, Roger Pau Monné wrote:
>>> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>>>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>>>> --- a/xen/drivers/vpci/header.c
>>>>>> +++ b/xen/drivers/vpci/header.c
>>>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>            pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>>>    }
>>>>>>    
>>>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>> +                            uint32_t cmd, void *data)
>>>>>> +{
>>>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>>>> +
>>>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>>> +    {
>>>>>> +        /*
>>>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>>>> +         *  - host has INTx disabled
>>>>>> +         *  - MSI/MSI-X enabled
>>>>>> +         */
>>>>>> +        if ( pdev->vpci->msi->enabled )
>>>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>> +        else
>>>>>> +        {
>>>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>>>> +
>>>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>> +        }
>>>>> This last part should be Arm specific. On other architectures we
>>>>> likely want the guest to modify INTx disable in order to select the
>>>>> interrupt delivery mode for the device.
>>>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>>>> enabled - only one of the three is supposed to be active at a time.
>>>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>>>> the bit is clear.)
>>> Sure, but this code is making the bit sticky, by not allowing
>>> INTX_DISABLE to be cleared once set. We do not want that behavior on
>>> x86, as a guest can decide to use MSI or INTx. The else branch needs
>>> to be Arm only.
>> Isn't the "else" part questionable even on Arm?
> It is. Once fixed I can't see anything Arm specific here
Well, I have looked at the code one more time and everything seems to
be ok wrt that sticky bit: we have 2 handlers which are cmd_write and
guest_cmd_write. The former is used for the hardware domain and has
*no restrictions* on writing PCI_COMMAND register contents and the later
is only used for guests and which does have restrictions applied in
emulate_cmd_reg function.

So, for the hardware domain, there is no "sticky" bit possible and for the
guest domains if the physical contents of the PCI_COMMAND register
has PCI_COMMAND_INTX_DISABLE bit set then the guest is enforced to
use PCI_COMMAND_INTX_DISABLE bit set.

So, from hardware domain POV, this should not be a problem, but from
guests view it can. Let's imagine that the hardware domain can handle
all types of interrupts, e.g. INTx, MSI, MSI-X. In this case the hardware
domain can decide what can be used for the interrupt source (again, no
restriction here) and program PCI_COMMAND accordingly.
Guest domains need to align with this configuration, e.g. if INTx was disabled
by the hardware domain then INTx cannot be enabled for guests: yes, this doesn't
cover dom0less etc. so we do rely on some entity before the guest to set the
PCI_COMMAND correctly.
This is how it is implemented in the patch.
Please also see the discussion we had before [1].

What is not now covered is that if there is a hardware domain and the same PCI
device is first passed to one of the guests and then assigned to another. In this case:

hwdom (or any other entity) programs PCI_COMMAND
assign domU1
deassign domU1
*assign domIO*
assign domU2

So in this scenario the host assigned value is lost after assigning to domU1
and domU2 will use the value used by domU1.
So, it seems that this is the only use-case not covered by the patch.

Jan [1]:
"In the absence of Dom0 controlling the device, I think we ought to take
Xen's view as the "host" one. Which will want the bit set at least as
long as either MSI or MSI-X is enabled for the device."

So, for the PCI_COMMAND register we might want to have a reference value
to be stored so we can restore it while assigning the PCI device to a guest.
For the current implementation the best I can probably do is to read this value
in init_bars when it is called for the hardware domain:

if ( is_hardware_domain(d) )
   vpci->pci_command_reference = pci_read(PCI_COMMAND)

And when I want to reset PCI_COMMAND while assigning to a guest I will
use it instead of 0 as it is now.
>> Jan
>>
[1] https://lore.kernel.org/xen-devel/20210903100831.177748-9-andr2000@gmail.com/
Jan Beulich Nov. 3, 2021, 9:11 a.m. UTC | #9
On 03.11.2021 09:53, Oleksandr Andrushchenko wrote:
> 
> 
> On 02.11.21 16:10, Oleksandr Andrushchenko wrote:
>>
>> On 02.11.21 15:54, Jan Beulich wrote:
>>> On 02.11.2021 12:50, Roger Pau Monné wrote:
>>>> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>>>>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>>>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>>>>> --- a/xen/drivers/vpci/header.c
>>>>>>> +++ b/xen/drivers/vpci/header.c
>>>>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>            pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>>>>    }
>>>>>>>    
>>>>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>> +                            uint32_t cmd, void *data)
>>>>>>> +{
>>>>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>>>>> +
>>>>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>>>> +    {
>>>>>>> +        /*
>>>>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>>>>> +         *  - host has INTx disabled
>>>>>>> +         *  - MSI/MSI-X enabled
>>>>>>> +         */
>>>>>>> +        if ( pdev->vpci->msi->enabled )
>>>>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>> +        else
>>>>>>> +        {
>>>>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>>>>> +
>>>>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>> +        }
>>>>>> This last part should be Arm specific. On other architectures we
>>>>>> likely want the guest to modify INTx disable in order to select the
>>>>>> interrupt delivery mode for the device.
>>>>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>>>>> enabled - only one of the three is supposed to be active at a time.
>>>>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>>>>> the bit is clear.)
>>>> Sure, but this code is making the bit sticky, by not allowing
>>>> INTX_DISABLE to be cleared once set. We do not want that behavior on
>>>> x86, as a guest can decide to use MSI or INTx. The else branch needs
>>>> to be Arm only.
>>> Isn't the "else" part questionable even on Arm?
>> It is. Once fixed I can't see anything Arm specific here
> Well, I have looked at the code one more time and everything seems to
> be ok wrt that sticky bit: we have 2 handlers which are cmd_write and
> guest_cmd_write. The former is used for the hardware domain and has
> *no restrictions* on writing PCI_COMMAND register contents and the later
> is only used for guests and which does have restrictions applied in
> emulate_cmd_reg function.
> 
> So, for the hardware domain, there is no "sticky" bit possible and for the
> guest domains if the physical contents of the PCI_COMMAND register
> has PCI_COMMAND_INTX_DISABLE bit set then the guest is enforced to
> use PCI_COMMAND_INTX_DISABLE bit set.
> 
> So, from hardware domain POV, this should not be a problem, but from
> guests view it can. Let's imagine that the hardware domain can handle
> all types of interrupts, e.g. INTx, MSI, MSI-X. In this case the hardware
> domain can decide what can be used for the interrupt source (again, no
> restriction here) and program PCI_COMMAND accordingly.
> Guest domains need to align with this configuration, e.g. if INTx was disabled
> by the hardware domain then INTx cannot be enabled for guests

Why? It's the DomU that's in control of the device, so it ought to
be able to pick any of the three. I don't think Dom0 is involved in
handling of interrupts from the device, and hence its own "dislike"
of INTx ought to only extend to the period of time where Dom0 is
controlling the device. This would be different if Xen's view was
different, but as we seem to agree Xen's role here is solely to
prevent invalid combinations getting established in hardware.

Jan
Oleksandr Andrushchenko Nov. 3, 2021, 9:18 a.m. UTC | #10
On 03.11.21 11:11, Jan Beulich wrote:
> On 03.11.2021 09:53, Oleksandr Andrushchenko wrote:
>>
>> On 02.11.21 16:10, Oleksandr Andrushchenko wrote:
>>> On 02.11.21 15:54, Jan Beulich wrote:
>>>> On 02.11.2021 12:50, Roger Pau Monné wrote:
>>>>> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>>>>>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>>>>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>>>>>> --- a/xen/drivers/vpci/header.c
>>>>>>>> +++ b/xen/drivers/vpci/header.c
>>>>>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>             pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>>>>>     }
>>>>>>>>     
>>>>>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>> +                            uint32_t cmd, void *data)
>>>>>>>> +{
>>>>>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>>>>>> +
>>>>>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>>>>> +    {
>>>>>>>> +        /*
>>>>>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>>>>>> +         *  - host has INTx disabled
>>>>>>>> +         *  - MSI/MSI-X enabled
>>>>>>>> +         */
>>>>>>>> +        if ( pdev->vpci->msi->enabled )
>>>>>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>> +        else
>>>>>>>> +        {
>>>>>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>>>>>> +
>>>>>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>>>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>> +        }
>>>>>>> This last part should be Arm specific. On other architectures we
>>>>>>> likely want the guest to modify INTx disable in order to select the
>>>>>>> interrupt delivery mode for the device.
>>>>>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>>>>>> enabled - only one of the three is supposed to be active at a time.
>>>>>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>>>>>> the bit is clear.)
>>>>> Sure, but this code is making the bit sticky, by not allowing
>>>>> INTX_DISABLE to be cleared once set. We do not want that behavior on
>>>>> x86, as a guest can decide to use MSI or INTx. The else branch needs
>>>>> to be Arm only.
>>>> Isn't the "else" part questionable even on Arm?
>>> It is. Once fixed I can't see anything Arm specific here
>> Well, I have looked at the code one more time and everything seems to
>> be ok wrt that sticky bit: we have 2 handlers which are cmd_write and
>> guest_cmd_write. The former is used for the hardware domain and has
>> *no restrictions* on writing PCI_COMMAND register contents and the later
>> is only used for guests and which does have restrictions applied in
>> emulate_cmd_reg function.
>>
>> So, for the hardware domain, there is no "sticky" bit possible and for the
>> guest domains if the physical contents of the PCI_COMMAND register
>> has PCI_COMMAND_INTX_DISABLE bit set then the guest is enforced to
>> use PCI_COMMAND_INTX_DISABLE bit set.
>>
>> So, from hardware domain POV, this should not be a problem, but from
>> guests view it can. Let's imagine that the hardware domain can handle
>> all types of interrupts, e.g. INTx, MSI, MSI-X. In this case the hardware
>> domain can decide what can be used for the interrupt source (again, no
>> restriction here) and program PCI_COMMAND accordingly.
>> Guest domains need to align with this configuration, e.g. if INTx was disabled
>> by the hardware domain then INTx cannot be enabled for guests
> Why? It's the DomU that's in control of the device, so it ought to
> be able to pick any of the three. I don't think Dom0 is involved in
> handling of interrupts from the device, and hence its own "dislike"
> of INTx ought to only extend to the period of time where Dom0 is
> controlling the device. This would be different if Xen's view was
> different, but as we seem to agree Xen's role here is solely to
> prevent invalid combinations getting established in hardware.
On top of a PCI device there is a physical host bridge and
physical bus topology which may impose restrictions from
Dom0 POV on that particular device. So, every PCI device
being passed through to a DomU may have different INTx
settings which do depend on Dom0 in our case.
>
> Jan
>
>
Jan Beulich Nov. 3, 2021, 9:24 a.m. UTC | #11
On 03.11.2021 10:18, Oleksandr Andrushchenko wrote:
> 
> 
> On 03.11.21 11:11, Jan Beulich wrote:
>> On 03.11.2021 09:53, Oleksandr Andrushchenko wrote:
>>>
>>> On 02.11.21 16:10, Oleksandr Andrushchenko wrote:
>>>> On 02.11.21 15:54, Jan Beulich wrote:
>>>>> On 02.11.2021 12:50, Roger Pau Monné wrote:
>>>>>> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>>>>>>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>>>>>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>>>>>>> --- a/xen/drivers/vpci/header.c
>>>>>>>>> +++ b/xen/drivers/vpci/header.c
>>>>>>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>>             pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>>>>>>     }
>>>>>>>>>     
>>>>>>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>> +                            uint32_t cmd, void *data)
>>>>>>>>> +{
>>>>>>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>>>>>>> +
>>>>>>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>>>>>> +    {
>>>>>>>>> +        /*
>>>>>>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>>>>>>> +         *  - host has INTx disabled
>>>>>>>>> +         *  - MSI/MSI-X enabled
>>>>>>>>> +         */
>>>>>>>>> +        if ( pdev->vpci->msi->enabled )
>>>>>>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>>> +        else
>>>>>>>>> +        {
>>>>>>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>>>>>>> +
>>>>>>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>>>>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>>> +        }
>>>>>>>> This last part should be Arm specific. On other architectures we
>>>>>>>> likely want the guest to modify INTx disable in order to select the
>>>>>>>> interrupt delivery mode for the device.
>>>>>>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>>>>>>> enabled - only one of the three is supposed to be active at a time.
>>>>>>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>>>>>>> the bit is clear.)
>>>>>> Sure, but this code is making the bit sticky, by not allowing
>>>>>> INTX_DISABLE to be cleared once set. We do not want that behavior on
>>>>>> x86, as a guest can decide to use MSI or INTx. The else branch needs
>>>>>> to be Arm only.
>>>>> Isn't the "else" part questionable even on Arm?
>>>> It is. Once fixed I can't see anything Arm specific here
>>> Well, I have looked at the code one more time and everything seems to
>>> be ok wrt that sticky bit: we have 2 handlers which are cmd_write and
>>> guest_cmd_write. The former is used for the hardware domain and has
>>> *no restrictions* on writing PCI_COMMAND register contents and the later
>>> is only used for guests and which does have restrictions applied in
>>> emulate_cmd_reg function.
>>>
>>> So, for the hardware domain, there is no "sticky" bit possible and for the
>>> guest domains if the physical contents of the PCI_COMMAND register
>>> has PCI_COMMAND_INTX_DISABLE bit set then the guest is enforced to
>>> use PCI_COMMAND_INTX_DISABLE bit set.
>>>
>>> So, from hardware domain POV, this should not be a problem, but from
>>> guests view it can. Let's imagine that the hardware domain can handle
>>> all types of interrupts, e.g. INTx, MSI, MSI-X. In this case the hardware
>>> domain can decide what can be used for the interrupt source (again, no
>>> restriction here) and program PCI_COMMAND accordingly.
>>> Guest domains need to align with this configuration, e.g. if INTx was disabled
>>> by the hardware domain then INTx cannot be enabled for guests
>> Why? It's the DomU that's in control of the device, so it ought to
>> be able to pick any of the three. I don't think Dom0 is involved in
>> handling of interrupts from the device, and hence its own "dislike"
>> of INTx ought to only extend to the period of time where Dom0 is
>> controlling the device. This would be different if Xen's view was
>> different, but as we seem to agree Xen's role here is solely to
>> prevent invalid combinations getting established in hardware.
> On top of a PCI device there is a physical host bridge and
> physical bus topology which may impose restrictions from
> Dom0 POV on that particular device.

Well, such physical restrictions may mean INTx doesn't actually work,
but this won't mean the DomU isn't free in choosing the bit's setting.
The bit merely controls whether the device is allowed to assert its
interrupt pin. Hence ...

> So, every PCI device
> being passed through to a DomU may have different INTx
> settings which do depend on Dom0 in our case.

... I'm still unconvinced of this.

Jan
Oleksandr Andrushchenko Nov. 3, 2021, 9:30 a.m. UTC | #12
On 03.11.21 11:24, Jan Beulich wrote:
> On 03.11.2021 10:18, Oleksandr Andrushchenko wrote:
>>
>> On 03.11.21 11:11, Jan Beulich wrote:
>>> On 03.11.2021 09:53, Oleksandr Andrushchenko wrote:
>>>> On 02.11.21 16:10, Oleksandr Andrushchenko wrote:
>>>>> On 02.11.21 15:54, Jan Beulich wrote:
>>>>>> On 02.11.2021 12:50, Roger Pau Monné wrote:
>>>>>>> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>>>>>>>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>>>>>>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>>>>>>>> --- a/xen/drivers/vpci/header.c
>>>>>>>>>> +++ b/xen/drivers/vpci/header.c
>>>>>>>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>>>              pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>>>>>>>      }
>>>>>>>>>>      
>>>>>>>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>>> +                            uint32_t cmd, void *data)
>>>>>>>>>> +{
>>>>>>>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>>>>>>>> +
>>>>>>>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>>>>>>> +    {
>>>>>>>>>> +        /*
>>>>>>>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>>>>>>>> +         *  - host has INTx disabled
>>>>>>>>>> +         *  - MSI/MSI-X enabled
>>>>>>>>>> +         */
>>>>>>>>>> +        if ( pdev->vpci->msi->enabled )
>>>>>>>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>>>> +        else
>>>>>>>>>> +        {
>>>>>>>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>>>>>>>> +
>>>>>>>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>>>>>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>>>> +        }
>>>>>>>>> This last part should be Arm specific. On other architectures we
>>>>>>>>> likely want the guest to modify INTx disable in order to select the
>>>>>>>>> interrupt delivery mode for the device.
>>>>>>>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>>>>>>>> enabled - only one of the three is supposed to be active at a time.
>>>>>>>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>>>>>>>> the bit is clear.)
>>>>>>> Sure, but this code is making the bit sticky, by not allowing
>>>>>>> INTX_DISABLE to be cleared once set. We do not want that behavior on
>>>>>>> x86, as a guest can decide to use MSI or INTx. The else branch needs
>>>>>>> to be Arm only.
>>>>>> Isn't the "else" part questionable even on Arm?
>>>>> It is. Once fixed I can't see anything Arm specific here
>>>> Well, I have looked at the code one more time and everything seems to
>>>> be ok wrt that sticky bit: we have 2 handlers which are cmd_write and
>>>> guest_cmd_write. The former is used for the hardware domain and has
>>>> *no restrictions* on writing PCI_COMMAND register contents and the later
>>>> is only used for guests and which does have restrictions applied in
>>>> emulate_cmd_reg function.
>>>>
>>>> So, for the hardware domain, there is no "sticky" bit possible and for the
>>>> guest domains if the physical contents of the PCI_COMMAND register
>>>> has PCI_COMMAND_INTX_DISABLE bit set then the guest is enforced to
>>>> use PCI_COMMAND_INTX_DISABLE bit set.
>>>>
>>>> So, from hardware domain POV, this should not be a problem, but from
>>>> guests view it can. Let's imagine that the hardware domain can handle
>>>> all types of interrupts, e.g. INTx, MSI, MSI-X. In this case the hardware
>>>> domain can decide what can be used for the interrupt source (again, no
>>>> restriction here) and program PCI_COMMAND accordingly.
>>>> Guest domains need to align with this configuration, e.g. if INTx was disabled
>>>> by the hardware domain then INTx cannot be enabled for guests
>>> Why? It's the DomU that's in control of the device, so it ought to
>>> be able to pick any of the three. I don't think Dom0 is involved in
>>> handling of interrupts from the device, and hence its own "dislike"
>>> of INTx ought to only extend to the period of time where Dom0 is
>>> controlling the device. This would be different if Xen's view was
>>> different, but as we seem to agree Xen's role here is solely to
>>> prevent invalid combinations getting established in hardware.
>> On top of a PCI device there is a physical host bridge and
>> physical bus topology which may impose restrictions from
>> Dom0 POV on that particular device.
> Well, such physical restrictions may mean INTx doesn't actually work,
> but this won't mean the DomU isn't free in choosing the bit's setting.
> The bit merely controls whether the device is allowed to assert its
> interrupt pin. Hence ...
>
>> So, every PCI device
>> being passed through to a DomU may have different INTx
>> settings which do depend on Dom0 in our case.
> ... I'm still unconvinced of this.
Ok, so I can accept any suggestion how to solve this. It seems that
we already have number of no go scenarios here, but still it is not
clear to me what could be an acceptable approach here. Namely:
what do we do with INTx bit for guests?
1. I can leave it as is in the patch
2. I can remove INTx emulation and let the guest decide and program INTx
3. What else can I do?
>
> Jan
>
>
Thank you,
Oleksandr
Roger Pau Monné Nov. 3, 2021, 9:39 a.m. UTC | #13
On Wed, Nov 03, 2021 at 09:18:03AM +0000, Oleksandr Andrushchenko wrote:
> 
> 
> On 03.11.21 11:11, Jan Beulich wrote:
> > On 03.11.2021 09:53, Oleksandr Andrushchenko wrote:
> >>
> >> On 02.11.21 16:10, Oleksandr Andrushchenko wrote:
> >>> On 02.11.21 15:54, Jan Beulich wrote:
> >>>> On 02.11.2021 12:50, Roger Pau Monné wrote:
> >>>>> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
> >>>>>> On 26.10.2021 12:52, Roger Pau Monné wrote:
> >>>>>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
> >>>>>>>> --- a/xen/drivers/vpci/header.c
> >>>>>>>> +++ b/xen/drivers/vpci/header.c
> >>>>>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
> >>>>>>>>             pci_conf_write16(pdev->sbdf, reg, cmd);
> >>>>>>>>     }
> >>>>>>>>     
> >>>>>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
> >>>>>>>> +                            uint32_t cmd, void *data)
> >>>>>>>> +{
> >>>>>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
> >>>>>>>> +
> >>>>>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
> >>>>>>>> +    {
> >>>>>>>> +        /*
> >>>>>>>> +         * Guest wants to enable INTx. It can't be enabled if:
> >>>>>>>> +         *  - host has INTx disabled
> >>>>>>>> +         *  - MSI/MSI-X enabled
> >>>>>>>> +         */
> >>>>>>>> +        if ( pdev->vpci->msi->enabled )
> >>>>>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
> >>>>>>>> +        else
> >>>>>>>> +        {
> >>>>>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
> >>>>>>>> +
> >>>>>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
> >>>>>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
> >>>>>>>> +        }
> >>>>>>> This last part should be Arm specific. On other architectures we
> >>>>>>> likely want the guest to modify INTx disable in order to select the
> >>>>>>> interrupt delivery mode for the device.
> >>>>>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
> >>>>>> enabled - only one of the three is supposed to be active at a time.
> >>>>>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
> >>>>>> the bit is clear.)
> >>>>> Sure, but this code is making the bit sticky, by not allowing
> >>>>> INTX_DISABLE to be cleared once set. We do not want that behavior on
> >>>>> x86, as a guest can decide to use MSI or INTx. The else branch needs
> >>>>> to be Arm only.
> >>>> Isn't the "else" part questionable even on Arm?
> >>> It is. Once fixed I can't see anything Arm specific here
> >> Well, I have looked at the code one more time and everything seems to
> >> be ok wrt that sticky bit: we have 2 handlers which are cmd_write and
> >> guest_cmd_write. The former is used for the hardware domain and has
> >> *no restrictions* on writing PCI_COMMAND register contents and the later
> >> is only used for guests and which does have restrictions applied in
> >> emulate_cmd_reg function.
> >>
> >> So, for the hardware domain, there is no "sticky" bit possible and for the
> >> guest domains if the physical contents of the PCI_COMMAND register
> >> has PCI_COMMAND_INTX_DISABLE bit set then the guest is enforced to
> >> use PCI_COMMAND_INTX_DISABLE bit set.
> >>
> >> So, from hardware domain POV, this should not be a problem, but from
> >> guests view it can. Let's imagine that the hardware domain can handle
> >> all types of interrupts, e.g. INTx, MSI, MSI-X. In this case the hardware
> >> domain can decide what can be used for the interrupt source (again, no
> >> restriction here) and program PCI_COMMAND accordingly.
> >> Guest domains need to align with this configuration, e.g. if INTx was disabled
> >> by the hardware domain then INTx cannot be enabled for guests
> > Why? It's the DomU that's in control of the device, so it ought to
> > be able to pick any of the three. I don't think Dom0 is involved in
> > handling of interrupts from the device, and hence its own "dislike"
> > of INTx ought to only extend to the period of time where Dom0 is
> > controlling the device. This would be different if Xen's view was
> > different, but as we seem to agree Xen's role here is solely to
> > prevent invalid combinations getting established in hardware.
> On top of a PCI device there is a physical host bridge and
> physical bus topology which may impose restrictions from
> Dom0 POV on that particular device. So, every PCI device
> being passed through to a DomU may have different INTx
> settings which do depend on Dom0 in our case.

Hm, it's kind of weird. What happens if you play with this bit and the
bridge doesn't support it?

Also note that your current code would allow a domU to set the bit if
previously unset, but it then won't allow the domU to clear it, which
doesn't seem to be exactly what you are aiming for.

Thanks, Roger.
Jan Beulich Nov. 3, 2021, 9:49 a.m. UTC | #14
On 03.11.2021 10:30, Oleksandr Andrushchenko wrote:
> 
> 
> On 03.11.21 11:24, Jan Beulich wrote:
>> On 03.11.2021 10:18, Oleksandr Andrushchenko wrote:
>>>
>>> On 03.11.21 11:11, Jan Beulich wrote:
>>>> On 03.11.2021 09:53, Oleksandr Andrushchenko wrote:
>>>>> On 02.11.21 16:10, Oleksandr Andrushchenko wrote:
>>>>>> On 02.11.21 15:54, Jan Beulich wrote:
>>>>>>> On 02.11.2021 12:50, Roger Pau Monné wrote:
>>>>>>>> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>>>>>>>>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>>>>>>>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>>>>>>>>> --- a/xen/drivers/vpci/header.c
>>>>>>>>>>> +++ b/xen/drivers/vpci/header.c
>>>>>>>>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>>>>              pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>>>>>>>>      }
>>>>>>>>>>>      
>>>>>>>>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>>>> +                            uint32_t cmd, void *data)
>>>>>>>>>>> +{
>>>>>>>>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>>>>>>>>> +
>>>>>>>>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>>>>>>>> +    {
>>>>>>>>>>> +        /*
>>>>>>>>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>>>>>>>>> +         *  - host has INTx disabled
>>>>>>>>>>> +         *  - MSI/MSI-X enabled
>>>>>>>>>>> +         */
>>>>>>>>>>> +        if ( pdev->vpci->msi->enabled )
>>>>>>>>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>>>>> +        else
>>>>>>>>>>> +        {
>>>>>>>>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>>>>>>>>> +
>>>>>>>>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>>>>>>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>>>>> +        }
>>>>>>>>>> This last part should be Arm specific. On other architectures we
>>>>>>>>>> likely want the guest to modify INTx disable in order to select the
>>>>>>>>>> interrupt delivery mode for the device.
>>>>>>>>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>>>>>>>>> enabled - only one of the three is supposed to be active at a time.
>>>>>>>>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>>>>>>>>> the bit is clear.)
>>>>>>>> Sure, but this code is making the bit sticky, by not allowing
>>>>>>>> INTX_DISABLE to be cleared once set. We do not want that behavior on
>>>>>>>> x86, as a guest can decide to use MSI or INTx. The else branch needs
>>>>>>>> to be Arm only.
>>>>>>> Isn't the "else" part questionable even on Arm?
>>>>>> It is. Once fixed I can't see anything Arm specific here
>>>>> Well, I have looked at the code one more time and everything seems to
>>>>> be ok wrt that sticky bit: we have 2 handlers which are cmd_write and
>>>>> guest_cmd_write. The former is used for the hardware domain and has
>>>>> *no restrictions* on writing PCI_COMMAND register contents and the later
>>>>> is only used for guests and which does have restrictions applied in
>>>>> emulate_cmd_reg function.
>>>>>
>>>>> So, for the hardware domain, there is no "sticky" bit possible and for the
>>>>> guest domains if the physical contents of the PCI_COMMAND register
>>>>> has PCI_COMMAND_INTX_DISABLE bit set then the guest is enforced to
>>>>> use PCI_COMMAND_INTX_DISABLE bit set.
>>>>>
>>>>> So, from hardware domain POV, this should not be a problem, but from
>>>>> guests view it can. Let's imagine that the hardware domain can handle
>>>>> all types of interrupts, e.g. INTx, MSI, MSI-X. In this case the hardware
>>>>> domain can decide what can be used for the interrupt source (again, no
>>>>> restriction here) and program PCI_COMMAND accordingly.
>>>>> Guest domains need to align with this configuration, e.g. if INTx was disabled
>>>>> by the hardware domain then INTx cannot be enabled for guests
>>>> Why? It's the DomU that's in control of the device, so it ought to
>>>> be able to pick any of the three. I don't think Dom0 is involved in
>>>> handling of interrupts from the device, and hence its own "dislike"
>>>> of INTx ought to only extend to the period of time where Dom0 is
>>>> controlling the device. This would be different if Xen's view was
>>>> different, but as we seem to agree Xen's role here is solely to
>>>> prevent invalid combinations getting established in hardware.
>>> On top of a PCI device there is a physical host bridge and
>>> physical bus topology which may impose restrictions from
>>> Dom0 POV on that particular device.
>> Well, such physical restrictions may mean INTx doesn't actually work,
>> but this won't mean the DomU isn't free in choosing the bit's setting.
>> The bit merely controls whether the device is allowed to assert its
>> interrupt pin. Hence ...
>>
>>> So, every PCI device
>>> being passed through to a DomU may have different INTx
>>> settings which do depend on Dom0 in our case.
>> ... I'm still unconvinced of this.
> Ok, so I can accept any suggestion how to solve this. It seems that
> we already have number of no go scenarios here, but still it is not
> clear to me what could be an acceptable approach here. Namely:
> what do we do with INTx bit for guests?
> 1. I can leave it as is in the patch
> 2. I can remove INTx emulation and let the guest decide and program INTx
> 3. What else can I do?

Aiui you want to prevent the guest from clearing the bit if either
MSI or MSI-X are in use. Symmetrically, when the guest enables MSI
or MSI-X, you will want to force the bit set (which may well be in
a separate, future patch).

Jan
Oleksandr Andrushchenko Nov. 3, 2021, 9:50 a.m. UTC | #15
On 03.11.21 11:39, Roger Pau Monné wrote:
> On Wed, Nov 03, 2021 at 09:18:03AM +0000, Oleksandr Andrushchenko wrote:
>>
>> On 03.11.21 11:11, Jan Beulich wrote:
>>> On 03.11.2021 09:53, Oleksandr Andrushchenko wrote:
>>>> On 02.11.21 16:10, Oleksandr Andrushchenko wrote:
>>>>> On 02.11.21 15:54, Jan Beulich wrote:
>>>>>> On 02.11.2021 12:50, Roger Pau Monné wrote:
>>>>>>> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>>>>>>>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>>>>>>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>>>>>>>> --- a/xen/drivers/vpci/header.c
>>>>>>>>>> +++ b/xen/drivers/vpci/header.c
>>>>>>>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>>>              pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>>>>>>>      }
>>>>>>>>>>      
>>>>>>>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>>> +                            uint32_t cmd, void *data)
>>>>>>>>>> +{
>>>>>>>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>>>>>>>> +
>>>>>>>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>>>>>>> +    {
>>>>>>>>>> +        /*
>>>>>>>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>>>>>>>> +         *  - host has INTx disabled
>>>>>>>>>> +         *  - MSI/MSI-X enabled
>>>>>>>>>> +         */
>>>>>>>>>> +        if ( pdev->vpci->msi->enabled )
>>>>>>>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>>>> +        else
>>>>>>>>>> +        {
>>>>>>>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>>>>>>>> +
>>>>>>>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>>>>>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>>>> +        }
>>>>>>>>> This last part should be Arm specific. On other architectures we
>>>>>>>>> likely want the guest to modify INTx disable in order to select the
>>>>>>>>> interrupt delivery mode for the device.
>>>>>>>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>>>>>>>> enabled - only one of the three is supposed to be active at a time.
>>>>>>>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>>>>>>>> the bit is clear.)
>>>>>>> Sure, but this code is making the bit sticky, by not allowing
>>>>>>> INTX_DISABLE to be cleared once set. We do not want that behavior on
>>>>>>> x86, as a guest can decide to use MSI or INTx. The else branch needs
>>>>>>> to be Arm only.
>>>>>> Isn't the "else" part questionable even on Arm?
>>>>> It is. Once fixed I can't see anything Arm specific here
>>>> Well, I have looked at the code one more time and everything seems to
>>>> be ok wrt that sticky bit: we have 2 handlers which are cmd_write and
>>>> guest_cmd_write. The former is used for the hardware domain and has
>>>> *no restrictions* on writing PCI_COMMAND register contents and the later
>>>> is only used for guests and which does have restrictions applied in
>>>> emulate_cmd_reg function.
>>>>
>>>> So, for the hardware domain, there is no "sticky" bit possible and for the
>>>> guest domains if the physical contents of the PCI_COMMAND register
>>>> has PCI_COMMAND_INTX_DISABLE bit set then the guest is enforced to
>>>> use PCI_COMMAND_INTX_DISABLE bit set.
>>>>
>>>> So, from hardware domain POV, this should not be a problem, but from
>>>> guests view it can. Let's imagine that the hardware domain can handle
>>>> all types of interrupts, e.g. INTx, MSI, MSI-X. In this case the hardware
>>>> domain can decide what can be used for the interrupt source (again, no
>>>> restriction here) and program PCI_COMMAND accordingly.
>>>> Guest domains need to align with this configuration, e.g. if INTx was disabled
>>>> by the hardware domain then INTx cannot be enabled for guests
>>> Why? It's the DomU that's in control of the device, so it ought to
>>> be able to pick any of the three. I don't think Dom0 is involved in
>>> handling of interrupts from the device, and hence its own "dislike"
>>> of INTx ought to only extend to the period of time where Dom0 is
>>> controlling the device. This would be different if Xen's view was
>>> different, but as we seem to agree Xen's role here is solely to
>>> prevent invalid combinations getting established in hardware.
>> On top of a PCI device there is a physical host bridge and
>> physical bus topology which may impose restrictions from
>> Dom0 POV on that particular device. So, every PCI device
>> being passed through to a DomU may have different INTx
>> settings which do depend on Dom0 in our case.
> Hm, it's kind of weird. What happens if you play with this bit and the
> bridge doesn't support it?
For that reason I think it is enough to relay on some reference value
which shows if INTx can be used. For that I suggest we depend on
Dom0 for now and read this reference PCI_COMMAND value while
in init_bars + is_hardware_domain. Then this can be used to feed
the initial value of the PCI_COMMAND for guests.
This way Dom0 solves the problem "what is supported for this
PCI device with respect to the bus topology and host bridge"
>
> Also note that your current code would allow a domU to set the bit if
> previously unset, but it then won't allow the domU to clear it, which
> doesn't seem to be exactly what you are aiming for.
That was noted before. If we use the reference value and use it
as an initial value of the PCI_COMMAND for the guests (remember
I use 0 in the patch which resets PCI_COMMAND for the guests
and check the real PCI_COMMAND contents to decide on INTx).
So, this reference value can be used in checks:
         if ( pdev->vpci->msi->enabled )
             cmd |= PCI_COMMAND_INTX_DISABLE;
         else
         {
             if ( pdev->cmd_ref_value & PCI_COMMAND_INTX_DISABLE )
                  ^^^^^^^^^^^^^^
                 cmd |= PCI_COMMAND_INTX_DISABLE;
         }

init_bars:
if (hwdom)
  pdev->cmd_ref_value = read(PCI_COMMAND)
>
> Thanks, Roger.
>
Oleksandr Andrushchenko Nov. 3, 2021, 10:24 a.m. UTC | #16
On 03.11.21 11:49, Jan Beulich wrote:
> On 03.11.2021 10:30, Oleksandr Andrushchenko wrote:
>>
>> On 03.11.21 11:24, Jan Beulich wrote:
>>> On 03.11.2021 10:18, Oleksandr Andrushchenko wrote:
>>>> On 03.11.21 11:11, Jan Beulich wrote:
>>>>> On 03.11.2021 09:53, Oleksandr Andrushchenko wrote:
>>>>>> On 02.11.21 16:10, Oleksandr Andrushchenko wrote:
>>>>>>> On 02.11.21 15:54, Jan Beulich wrote:
>>>>>>>> On 02.11.2021 12:50, Roger Pau Monné wrote:
>>>>>>>>> On Tue, Nov 02, 2021 at 12:19:13PM +0100, Jan Beulich wrote:
>>>>>>>>>> On 26.10.2021 12:52, Roger Pau Monné wrote:
>>>>>>>>>>> On Thu, Sep 30, 2021 at 10:52:20AM +0300, Oleksandr Andrushchenko wrote:
>>>>>>>>>>>> --- a/xen/drivers/vpci/header.c
>>>>>>>>>>>> +++ b/xen/drivers/vpci/header.c
>>>>>>>>>>>> @@ -451,6 +451,32 @@ static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>>>>>               pci_conf_write16(pdev->sbdf, reg, cmd);
>>>>>>>>>>>>       }
>>>>>>>>>>>>       
>>>>>>>>>>>> +static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
>>>>>>>>>>>> +                            uint32_t cmd, void *data)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +    /* TODO: Add proper emulation for all bits of the command register. */
>>>>>>>>>>>> +
>>>>>>>>>>>> +    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>>>>>>>>> +    {
>>>>>>>>>>>> +        /*
>>>>>>>>>>>> +         * Guest wants to enable INTx. It can't be enabled if:
>>>>>>>>>>>> +         *  - host has INTx disabled
>>>>>>>>>>>> +         *  - MSI/MSI-X enabled
>>>>>>>>>>>> +         */
>>>>>>>>>>>> +        if ( pdev->vpci->msi->enabled )
>>>>>>>>>>>> +            cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>>>>>> +        else
>>>>>>>>>>>> +        {
>>>>>>>>>>>> +            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
>>>>>>>>>>>> +
>>>>>>>>>>>> +            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
>>>>>>>>>>>> +                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>>>>>>>> +        }
>>>>>>>>>>> This last part should be Arm specific. On other architectures we
>>>>>>>>>>> likely want the guest to modify INTx disable in order to select the
>>>>>>>>>>> interrupt delivery mode for the device.
>>>>>>>>>> We cannot allow a guest to clear the bit when it has MSI / MSI-X
>>>>>>>>>> enabled - only one of the three is supposed to be active at a time.
>>>>>>>>>> (IOW similarly we cannot allow a guest to enable MSI / MSI-X when
>>>>>>>>>> the bit is clear.)
>>>>>>>>> Sure, but this code is making the bit sticky, by not allowing
>>>>>>>>> INTX_DISABLE to be cleared once set. We do not want that behavior on
>>>>>>>>> x86, as a guest can decide to use MSI or INTx. The else branch needs
>>>>>>>>> to be Arm only.
>>>>>>>> Isn't the "else" part questionable even on Arm?
>>>>>>> It is. Once fixed I can't see anything Arm specific here
>>>>>> Well, I have looked at the code one more time and everything seems to
>>>>>> be ok wrt that sticky bit: we have 2 handlers which are cmd_write and
>>>>>> guest_cmd_write. The former is used for the hardware domain and has
>>>>>> *no restrictions* on writing PCI_COMMAND register contents and the later
>>>>>> is only used for guests and which does have restrictions applied in
>>>>>> emulate_cmd_reg function.
>>>>>>
>>>>>> So, for the hardware domain, there is no "sticky" bit possible and for the
>>>>>> guest domains if the physical contents of the PCI_COMMAND register
>>>>>> has PCI_COMMAND_INTX_DISABLE bit set then the guest is enforced to
>>>>>> use PCI_COMMAND_INTX_DISABLE bit set.
>>>>>>
>>>>>> So, from hardware domain POV, this should not be a problem, but from
>>>>>> guests view it can. Let's imagine that the hardware domain can handle
>>>>>> all types of interrupts, e.g. INTx, MSI, MSI-X. In this case the hardware
>>>>>> domain can decide what can be used for the interrupt source (again, no
>>>>>> restriction here) and program PCI_COMMAND accordingly.
>>>>>> Guest domains need to align with this configuration, e.g. if INTx was disabled
>>>>>> by the hardware domain then INTx cannot be enabled for guests
>>>>> Why? It's the DomU that's in control of the device, so it ought to
>>>>> be able to pick any of the three. I don't think Dom0 is involved in
>>>>> handling of interrupts from the device, and hence its own "dislike"
>>>>> of INTx ought to only extend to the period of time where Dom0 is
>>>>> controlling the device. This would be different if Xen's view was
>>>>> different, but as we seem to agree Xen's role here is solely to
>>>>> prevent invalid combinations getting established in hardware.
>>>> On top of a PCI device there is a physical host bridge and
>>>> physical bus topology which may impose restrictions from
>>>> Dom0 POV on that particular device.
>>> Well, such physical restrictions may mean INTx doesn't actually work,
>>> but this won't mean the DomU isn't free in choosing the bit's setting.
>>> The bit merely controls whether the device is allowed to assert its
>>> interrupt pin. Hence ...
>>>
>>>> So, every PCI device
>>>> being passed through to a DomU may have different INTx
>>>> settings which do depend on Dom0 in our case.
>>> ... I'm still unconvinced of this.
>> Ok, so I can accept any suggestion how to solve this. It seems that
>> we already have number of no go scenarios here, but still it is not
>> clear to me what could be an acceptable approach here. Namely:
>> what do we do with INTx bit for guests?
>> 1. I can leave it as is in the patch
>> 2. I can remove INTx emulation and let the guest decide and program INTx
>> 3. What else can I do?
> Aiui you want to prevent the guest from clearing the bit if either
> MSI or MSI-X are in use. Symmetrically, when the guest enables MSI
> or MSI-X, you will want to force the bit set (which may well be in
> a separate, future patch).
static uint32_t emulate_cmd_reg(const struct pci_dev *pdev, uint32_t cmd)
{
     /* TODO: Add proper emulation for all bits of the command register. */

     if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
     {
         /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
#ifdef CONFIG_HAS_PCI_MSI
         if ( pdev->vpci->msi->enabled )
             cmd |= PCI_COMMAND_INTX_DISABLE;
#endif
     }

     return cmd;
}

Is this what you mean?
> Jan
>
Thank you,
Oleksandr
Jan Beulich Nov. 3, 2021, 10:34 a.m. UTC | #17
On 03.11.2021 11:24, Oleksandr Andrushchenko wrote:
> On 03.11.21 11:49, Jan Beulich wrote:
>> Aiui you want to prevent the guest from clearing the bit if either
>> MSI or MSI-X are in use. Symmetrically, when the guest enables MSI
>> or MSI-X, you will want to force the bit set (which may well be in
>> a separate, future patch).
> static uint32_t emulate_cmd_reg(const struct pci_dev *pdev, uint32_t cmd)
> {
>      /* TODO: Add proper emulation for all bits of the command register. */
> 
>      if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>      {
>          /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
> #ifdef CONFIG_HAS_PCI_MSI
>          if ( pdev->vpci->msi->enabled )
>              cmd |= PCI_COMMAND_INTX_DISABLE;
> #endif
>      }
> 
>      return cmd;
> }
> 
> Is this what you mean?

Something along these lines, yes. I'd omit the outer if() for clarity /
brevity.

Jan
Oleksandr Andrushchenko Nov. 3, 2021, 10:36 a.m. UTC | #18
On 03.11.21 12:34, Jan Beulich wrote:
> On 03.11.2021 11:24, Oleksandr Andrushchenko wrote:
>> On 03.11.21 11:49, Jan Beulich wrote:
>>> Aiui you want to prevent the guest from clearing the bit if either
>>> MSI or MSI-X are in use. Symmetrically, when the guest enables MSI
>>> or MSI-X, you will want to force the bit set (which may well be in
>>> a separate, future patch).
>> static uint32_t emulate_cmd_reg(const struct pci_dev *pdev, uint32_t cmd)
>> {
>>       /* TODO: Add proper emulation for all bits of the command register. */
>>
>>       if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>       {
>>           /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
>> #ifdef CONFIG_HAS_PCI_MSI
>>           if ( pdev->vpci->msi->enabled )
>>               cmd |= PCI_COMMAND_INTX_DISABLE;
>> #endif
>>       }
>>
>>       return cmd;
>> }
>>
>> Is this what you mean?
> Something along these lines, yes. I'd omit the outer if() for clarity /
> brevity.
Sure, thank you!
@Roger are you ok with this approach?
>
> Jan
>
>
Roger Pau Monné Nov. 3, 2021, 11:01 a.m. UTC | #19
On Wed, Nov 03, 2021 at 10:36:36AM +0000, Oleksandr Andrushchenko wrote:
> 
> 
> On 03.11.21 12:34, Jan Beulich wrote:
> > On 03.11.2021 11:24, Oleksandr Andrushchenko wrote:
> >> On 03.11.21 11:49, Jan Beulich wrote:
> >>> Aiui you want to prevent the guest from clearing the bit if either
> >>> MSI or MSI-X are in use. Symmetrically, when the guest enables MSI
> >>> or MSI-X, you will want to force the bit set (which may well be in
> >>> a separate, future patch).
> >> static uint32_t emulate_cmd_reg(const struct pci_dev *pdev, uint32_t cmd)
> >> {
> >>       /* TODO: Add proper emulation for all bits of the command register. */
> >>
> >>       if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
> >>       {
> >>           /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
> >> #ifdef CONFIG_HAS_PCI_MSI
> >>           if ( pdev->vpci->msi->enabled )
> >>               cmd |= PCI_COMMAND_INTX_DISABLE;
> >> #endif
> >>       }
> >>
> >>       return cmd;
> >> }
> >>
> >> Is this what you mean?
> > Something along these lines, yes. I'd omit the outer if() for clarity /
> > brevity.
> Sure, thank you!
> @Roger are you ok with this approach?

Sure, I would even do:

#ifdef CONFIG_HAS_PCI_MSI
if ( !(cmd & PCI_COMMAND_INTX_DISABLE) && pdev->vpci->msi->enabled )
{
    /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
    cmd |= PCI_COMMAND_INTX_DISABLE;
}
#endif

There's no need for the outer check if there's no support for MSI.

Thanks, Roger.
Oleksandr Andrushchenko Nov. 3, 2021, 11:02 a.m. UTC | #20
On 03.11.21 13:01, Roger Pau Monné wrote:
> On Wed, Nov 03, 2021 at 10:36:36AM +0000, Oleksandr Andrushchenko wrote:
>>
>> On 03.11.21 12:34, Jan Beulich wrote:
>>> On 03.11.2021 11:24, Oleksandr Andrushchenko wrote:
>>>> On 03.11.21 11:49, Jan Beulich wrote:
>>>>> Aiui you want to prevent the guest from clearing the bit if either
>>>>> MSI or MSI-X are in use. Symmetrically, when the guest enables MSI
>>>>> or MSI-X, you will want to force the bit set (which may well be in
>>>>> a separate, future patch).
>>>> static uint32_t emulate_cmd_reg(const struct pci_dev *pdev, uint32_t cmd)
>>>> {
>>>>        /* TODO: Add proper emulation for all bits of the command register. */
>>>>
>>>>        if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>        {
>>>>            /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
>>>> #ifdef CONFIG_HAS_PCI_MSI
>>>>            if ( pdev->vpci->msi->enabled )
>>>>                cmd |= PCI_COMMAND_INTX_DISABLE;
>>>> #endif
>>>>        }
>>>>
>>>>        return cmd;
>>>> }
>>>>
>>>> Is this what you mean?
>>> Something along these lines, yes. I'd omit the outer if() for clarity /
>>> brevity.
>> Sure, thank you!
>> @Roger are you ok with this approach?
> Sure, I would even do:
>
> #ifdef CONFIG_HAS_PCI_MSI
> if ( !(cmd & PCI_COMMAND_INTX_DISABLE) && pdev->vpci->msi->enabled )
> {
>      /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
>      cmd |= PCI_COMMAND_INTX_DISABLE;
> }
> #endif
>
> There's no need for the outer check if there's no support for MSI.
Ok, sounds good!
Thank you both!!
>
> Thanks, Roger.
Roger Pau Monné Nov. 3, 2021, 11:26 a.m. UTC | #21
On Wed, Nov 03, 2021 at 11:02:37AM +0000, Oleksandr Andrushchenko wrote:
> 
> 
> On 03.11.21 13:01, Roger Pau Monné wrote:
> > On Wed, Nov 03, 2021 at 10:36:36AM +0000, Oleksandr Andrushchenko wrote:
> >>
> >> On 03.11.21 12:34, Jan Beulich wrote:
> >>> On 03.11.2021 11:24, Oleksandr Andrushchenko wrote:
> >>>> On 03.11.21 11:49, Jan Beulich wrote:
> >>>>> Aiui you want to prevent the guest from clearing the bit if either
> >>>>> MSI or MSI-X are in use. Symmetrically, when the guest enables MSI
> >>>>> or MSI-X, you will want to force the bit set (which may well be in
> >>>>> a separate, future patch).
> >>>> static uint32_t emulate_cmd_reg(const struct pci_dev *pdev, uint32_t cmd)
> >>>> {
> >>>>        /* TODO: Add proper emulation for all bits of the command register. */
> >>>>
> >>>>        if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
> >>>>        {
> >>>>            /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
> >>>> #ifdef CONFIG_HAS_PCI_MSI
> >>>>            if ( pdev->vpci->msi->enabled )
> >>>>                cmd |= PCI_COMMAND_INTX_DISABLE;
> >>>> #endif
> >>>>        }
> >>>>
> >>>>        return cmd;
> >>>> }
> >>>>
> >>>> Is this what you mean?
> >>> Something along these lines, yes. I'd omit the outer if() for clarity /
> >>> brevity.
> >> Sure, thank you!
> >> @Roger are you ok with this approach?
> > Sure, I would even do:
> >
> > #ifdef CONFIG_HAS_PCI_MSI
> > if ( !(cmd & PCI_COMMAND_INTX_DISABLE) && pdev->vpci->msi->enabled )
> > {
> >      /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
> >      cmd |= PCI_COMMAND_INTX_DISABLE;
> > }
> > #endif
> >
> > There's no need for the outer check if there's no support for MSI.
> Ok, sounds good!
> Thank you both!!

In fact you could even remove the check for !(cmd &
PCI_COMMAND_INTX_DISABLE) and always set PCI_COMMAND_INTX_DISABLE if
MSI is enabled, which I think is what Jan was pointing to in his
previous reply.

Regards, Roger.
Oleksandr Andrushchenko Nov. 3, 2021, 11:34 a.m. UTC | #22
On 03.11.21 13:26, Roger Pau Monné wrote:
> On Wed, Nov 03, 2021 at 11:02:37AM +0000, Oleksandr Andrushchenko wrote:
>>
>> On 03.11.21 13:01, Roger Pau Monné wrote:
>>> On Wed, Nov 03, 2021 at 10:36:36AM +0000, Oleksandr Andrushchenko wrote:
>>>> On 03.11.21 12:34, Jan Beulich wrote:
>>>>> On 03.11.2021 11:24, Oleksandr Andrushchenko wrote:
>>>>>> On 03.11.21 11:49, Jan Beulich wrote:
>>>>>>> Aiui you want to prevent the guest from clearing the bit if either
>>>>>>> MSI or MSI-X are in use. Symmetrically, when the guest enables MSI
>>>>>>> or MSI-X, you will want to force the bit set (which may well be in
>>>>>>> a separate, future patch).
>>>>>> static uint32_t emulate_cmd_reg(const struct pci_dev *pdev, uint32_t cmd)
>>>>>> {
>>>>>>         /* TODO: Add proper emulation for all bits of the command register. */
>>>>>>
>>>>>>         if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
>>>>>>         {
>>>>>>             /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
>>>>>> #ifdef CONFIG_HAS_PCI_MSI
>>>>>>             if ( pdev->vpci->msi->enabled )
>>>>>>                 cmd |= PCI_COMMAND_INTX_DISABLE;
>>>>>> #endif
>>>>>>         }
>>>>>>
>>>>>>         return cmd;
>>>>>> }
>>>>>>
>>>>>> Is this what you mean?
>>>>> Something along these lines, yes. I'd omit the outer if() for clarity /
>>>>> brevity.
>>>> Sure, thank you!
>>>> @Roger are you ok with this approach?
>>> Sure, I would even do:
>>>
>>> #ifdef CONFIG_HAS_PCI_MSI
>>> if ( !(cmd & PCI_COMMAND_INTX_DISABLE) && pdev->vpci->msi->enabled )
>>> {
>>>       /* Guest wants to enable INTx. It can't be enabled if MSI/MSI-X enabled. */
>>>       cmd |= PCI_COMMAND_INTX_DISABLE;
>>> }
>>> #endif
>>>
>>> There's no need for the outer check if there's no support for MSI.
>> Ok, sounds good!
>> Thank you both!!
> In fact you could even remove the check for !(cmd &
> PCI_COMMAND_INTX_DISABLE) and always set PCI_COMMAND_INTX_DISABLE if
> MSI is enabled, which I think is what Jan was pointing to in his
> previous reply.
Ok, I will
>
> Regards, Roger.
>
diff mbox series

Patch

diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
index f23c956cde6c..754aeb5a584f 100644
--- a/xen/drivers/vpci/header.c
+++ b/xen/drivers/vpci/header.c
@@ -451,6 +451,32 @@  static void cmd_write(const struct pci_dev *pdev, unsigned int reg,
         pci_conf_write16(pdev->sbdf, reg, cmd);
 }
 
+static void guest_cmd_write(const struct pci_dev *pdev, unsigned int reg,
+                            uint32_t cmd, void *data)
+{
+    /* TODO: Add proper emulation for all bits of the command register. */
+
+    if ( (cmd & PCI_COMMAND_INTX_DISABLE) == 0 )
+    {
+        /*
+         * Guest wants to enable INTx. It can't be enabled if:
+         *  - host has INTx disabled
+         *  - MSI/MSI-X enabled
+         */
+        if ( pdev->vpci->msi->enabled )
+            cmd |= PCI_COMMAND_INTX_DISABLE;
+        else
+        {
+            uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
+
+            if ( current_cmd & PCI_COMMAND_INTX_DISABLE )
+                cmd |= PCI_COMMAND_INTX_DISABLE;
+        }
+    }
+
+    cmd_write(pdev, reg, cmd, data);
+}
+
 static void bar_write(const struct pci_dev *pdev, unsigned int reg,
                       uint32_t val, void *data)
 {
@@ -598,9 +624,12 @@  static int add_bar_handlers(const struct pci_dev *pdev, bool is_hwdom)
     struct vpci_bar *bars = header->bars;
     int rc;
 
-    /* Setup a handler for the command register: same for hwdom and guests. */
-    rc = vpci_add_register(pdev->vpci, vpci_hw_read16, cmd_write, PCI_COMMAND,
-                           2, header);
+    if ( is_hwdom )
+        rc = vpci_add_register(pdev->vpci, vpci_hw_read16, cmd_write,
+                               PCI_COMMAND, 2, header);
+    else
+        rc = vpci_add_register(pdev->vpci, vpci_hw_read16, guest_cmd_write,
+                               PCI_COMMAND, 2, header);
     if ( rc )
         return rc;