Re: [PATCH] pci: Enable bus master till the FLR completes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jul 26, 2013 at 4:53 PM, Casey Leedom <leedom@xxxxxxxxxxx> wrote:
> Thanks for the review comments. I'll work with Vipul to get these properly
> incorporated. Answers to your comments are inline below:
>
>
>
> On 07/26/13 15:27, Bjorn Helgaas wrote:
>>
>> On Mon, Jul 1, 2013 at 5:22 AM, Vipul Pandya <vipul@xxxxxxxxxxx> wrote:
>>>
>>> From: Casey Leedom <leedom@xxxxxxxxxxx>
>>>
>>> T4 can wedge if there are DMAs in flight within the chip and Bus master
>>> has
>>> been disabled.  We need to have it on till the Function Level Reset
>>> completes.
>>> T4 can also suffer a Head Of Line blocking problem if MSI-X interrupts
>>> are
>>> disabled before the FLR has completed.
>>>
>>> Signed-off-by: Casey Leedom <leedom@xxxxxxxxxxx>
>>> ---
>>>   drivers/pci/quirks.c | 91
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   1 file changed, 91 insertions(+)
>>>
>>> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
>>> index e85d230..6357ba1 100644
>>> --- a/drivers/pci/quirks.c
>>> +++ b/drivers/pci/quirks.c
>>> @@ -3208,6 +3208,95 @@ reset_complete:
>>>          return 0;
>>>   }
>>>
>>> +/*
>>> + * Device-specific reset method for Chelsio T4-based adapters.
>>> + */
>>> +static int reset_chelsio_generic_dev(struct pci_dev *dev, int probe)
>>> +{
>>> +       u16 old_command;
>>> +       u16 status, msix_flags;
>>> +       int i, rc, msix_pos;
>>> +
>>> +       /*
>>> +        * If this isn't a Chelsio T4-based device, return -ENOTTY
>>> indicating
>>> +        * that we have no device-specific reset method.
>>> +        */
>>> +       if ((dev->device & 0xf000) != 0x4000)
>>> +               return -ENOTTY;
>>> +
>>> +       /*
>>> +        * If this is the "probe" phase, return 0 indicating that we can
>>> +        * reset this device.
>>> +        */
>>> +       if (probe)
>>> +               return 0;
>>> +
>>> +       /*
>>> +        * T4 can wedge if their are DMAs in flight within the chip and
>>> Bus
>>> +        * master has been disabled.  We need to have it on till the
>>> Function
>>> +        * Level Reset completes.
>>> +        */
>>> +       pci_read_config_word(dev, PCI_COMMAND, &old_command);
>>> +       pci_write_config_word(dev, PCI_COMMAND,
>>> +                             old_command | PCI_COMMAND_MASTER);
>>> +
>>> +       /*
>>> +        * Perform the actual device function reset, saving and restoring
>>> +        * configuration information around the reset.
>>> +        */
>>> +       pci_save_state(dev);
>>> +
>>> +       /*
>>> +        * T4 also suffers a Head-Of-Line blocking problem if MSI-X
>>> interrupts
>>> +        * are disabled when an MSI-X interrupt message needs to be
>>> delivered.
>>> +        * So we briefly re-enable MSI-X interrupts for the duration of
>>> the
>>> +        * FLR.  The pci_restore_state() below will restore the original
>>> +        * MSI-X state.
>>> +        */
>>> +       msix_pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
>>
>> dev->msix_cap contains the capability offset already.
>
>
> Thanks. I didn't know about that.
>
>
>>> +       pci_read_config_word(dev, msix_pos+PCI_MSIX_FLAGS, &msix_flags);
>>> +       if ((msix_flags & PCI_MSIX_FLAGS_ENABLE) == 0)
>>> +               pci_write_config_word(dev, msix_pos+PCI_MSIX_FLAGS,
>>> +                                     msix_flags |
>>> +                                     PCI_MSIX_FLAGS_ENABLE |
>>> +                                     PCI_MSIX_FLAGS_MASKALL);
>>> +
>>> +       /*
>>> +        * This reset code is a copy of the guts of pcie_flr() because
>>> that's
>>> +        * not an exported function.
>>> +        */
>>> +
>>> +       /* Wait for Transaction Pending bit clean */
>>> +       for (i = 0; i < 4; i++) {
>>> +               if (i)
>>> +                       msleep((1 << (i - 1)) * 100);
>>> +
>>> +               pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
>>> +               if (!(status & PCI_EXP_DEVSTA_TRPND))
>>> +                       goto clear;
>>> +       }
>>
>> This is at least the fifth copy of this loop:
>>
>>    pcie_flr()
>>    pci_af_flr()
>>    bnx2x_do_flr()
>>    reset_intel_82599_sfp_virtfn()
>>
>> Can we factor this out and just implement it once?  Maybe even make it
>> smart enough to look at the PCIe DEVSTA if it exists, and fall back to
>> using PCI_AF_STATUS register if *it* exists?
>
>
> Should such a task be taken up in the patch we're trying to submit or should
> it be a follow on patch? I had thought that, in general, patches were
> supposed to essentially do "one thing." Thanks for your insight on this.

You're right.  The *ideal* thing would be a series like this:

  1 add pci_wait_for_pending_transactions() and use it in drivers/pci
  2 convert bnx2x to use it
  3 chelsio patch (this one) using it

But I wouldn't hold your feet to the fire about the bnx2x one because
that's outside of your control.  It's just good citizenship if you can
propose the patch.

>>> +
>>> +       dev_err(&dev->dev, "transaction is not cleared; proceeding with
>>> reset anyway\n");
>>> +
>>> +clear:
>>> +       pcie_capability_set_word(dev, PCI_EXP_DEVCTL,
>>> PCI_EXP_DEVCTL_BCR_FLR);
>>> +       msleep(100);
>>> +
>>> +       /*
>>> +        * End of pcie_flr() code sequence.
>>> +        */
>>> +
>>> +       rc = 0;
>>> +       pci_restore_state(dev);
>>> +
>>> +       /*
>>> +        * Restore the original PCI Configuration Space Command word
>>> (which
>>> +        * probably had Bus Master disabled).
>>
>> Why was Bus Master probably originally disabled?  I don't see anything
>> in the pci_reset_function() path that would have disabled it before
>> getting to this function.
>>
>> But I don't think you need the comment anyway.  "Probably had Bus
>> Master disabled" isn't anything one can rely on.
>
>
> Sorry, I probably should have included our example. In this case it's coming
> from KVM's kvm_free_assigned_device() routine which calls
> pci_reset_function() where we do:
>
> /*
> * both INTx and MSI are disabled after the Interrupt Disable bit
> * is set and the Bus Master bit is cleared.
> */
> pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);

Wow, I must be blind to have missed that :)  Personally I would just
drop the whole comment and not worry about it.

Bjorn
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux