1. 06 2月, 2014 4 次提交
  2. 04 2月, 2014 5 次提交
    • R
      ACPI / hotplug / PCI: Fix bridge removal race vs dock events · af9d8adc
      Rafael J. Wysocki 提交于
      If a PCI bridge with an ACPIPHP context attached is removed via
      sysfs, the code path executed as a result is the following:
      
      pci_stop_and_remove_bus_device_locked
       pci_remove_bus
        pcibios_remove_bus
         acpi_pci_remove_bus
          acpiphp_remove_slots
           cleanup_bridge
            unregister_hotplug_dock_device (drops dock references to the bridge)
           put_bridge
            free_bridge
             acpiphp_put_context (for each child, under context lock)
              kfree (context)
      
      Now, if a dock event affecting one of the bridge's child devices
      occurs (roughly at the same time), it will lead to the following code
      path:
      
      acpi_dock_deferred_cb
       dock_notify
        handle_eject_request
         hot_remove_dock_devices
          dock_hotplug_event
           hotplug_event (dereferences context)
      
      That may lead to a kernel crash in hotplug_event() if it is executed
      after the last kfree() in the bridge removal code path.
      
      To prevent that from happening, add a wrapper around hotplug_event()
      called dock_event() and point the .handler pointer in acpiphp_dock_ops
      to it.  Make that wrapper retrieve the device's ACPIPHP context using
      acpiphp_get_context() (instead of taking it from the data argument)
      under acpiphp_context_lock and check if the parent bridge's
      is_going_away flag is set.  If that flag is set, it will return
      immediately and if it is not set it will grab a reference to the
      device's parent bridge before executing hotplug_event().
      
      Then, in the above scenario, the reference to the parent bridge
      held by dock_event() will prevent free_bridge() from being executed
      for it until hotplug_event() returns.
      Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
      af9d8adc
    • R
      ACPI / hotplug / PCI: Fix bridge removal race in handle_hotplug_event() · 1b360f44
      Rafael J. Wysocki 提交于
      If a PCI bridge with an ACPIPHP context attached is removed via
      sysfs, the code path executed as a result is the following:
      
      pci_stop_and_remove_bus_device_locked
       pci_remove_bus
        pcibios_remove_bus
         acpi_pci_remove_bus
          acpiphp_remove_slots
           cleanup_bridge
           put_bridge
            free_bridge
             acpiphp_put_context (for each child, under context lock)
              kfree (child context)
      
      Now, if a hotplug notify is dispatched for one of the bridge's
      children and the timing is such that handle_hotplug_event() for
      that notify is executed while free_bridge() above is running,
      the get_bridge(context->func.parent) in handle_hotplug_event()
      will not really help, because it is too late to prevent the bridge
      from going away and the child's context may be freed before
      hotplug_event_work() scheduled from handle_hotplug_event()
      dereferences the pointer to it passed via the data argument.
      That will cause a kernel crash to happpen in hotplug_event_work().
      
      To prevent that from happening, make handle_hotplug_event()
      check the is_going_away flag of the function's parent bridge
      (under acpiphp_context_lock) and bail out if it's set.  Also,
      make cleanup_bridge() set the bridge's is_going_away flag under
      acpiphp_context_lock so that it cannot be changed between the
      check and the subsequent get_bridge(context->func.parent) in
      handle_hotplug_event().
      
      Then, in the above scenario, handle_hotplug_event() will notice
      that context->func.parent->is_going_away is already set and it
      will exit immediately preventing the crash from happening.
      Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
      1b360f44
    • R
      ACPI / hotplug / PCI: Scan root bus under the PCI rescan-remove lock · d42f5da2
      Rafael J. Wysocki 提交于
      Since acpiphp_check_bridge() called by acpiphp_check_host_bridge()
      does things that require PCI rescan-remove locking around it,
      make acpiphp_check_host_bridge() use that locking.
      Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
      Tested-by: NMika Westerberg <mika.westerberg@linux.intel.com>
      d42f5da2
    • R
      ACPI / hotplug / PCI: Move PCI rescan-remove locking to hotplug_event() · f41b3261
      Rafael J. Wysocki 提交于
      Commit 9217a984 (ACPI / hotplug / PCI: Use global PCI rescan-remove
      locking) modified ACPIPHP to protect its PCI device removal and addition
      code paths from races against sysfs-driven rescan and remove operations
      with the help of PCI rescan-remove locking.  However, it overlooked the
      fact that hotplug_event_work() is not the only caller of hotplug_event()
      which may also be called by dock_hotplug_event() and that code path
      is missing the PCI rescan-remove locking.  This means that, although
      the PCI rescan-remove lock is held as appropriate during the handling
      of events originating from handle_hotplug_event(), the ACPIPHP's
      operations resulting from dock events may still suffer the race
      conditions that commit 9217a984 was supposed to eliminate.
      
      To address that problem, move the PCI rescan-remove locking from
      hotplug_event_work() to hotplug_event() so that it is used regardless
      of the way that function is invoked.
      
      Revamps: 9217a984 (ACPI / hotplug / PCI: Use global PCI rescan-remove locking)
      Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
      Tested-by: NMika Westerberg <mika.westerberg@linux.intel.com>
      f41b3261
    • R
      ACPI / hotplug / PCI: Remove entries from bus->devices in reverse order · 2d7c1b77
      Rafael J. Wysocki 提交于
      According to the changelog of commit 29ed1f29 (PCI: pciehp: Fix null
      pointer deref when hot-removing SR-IOV device) it is unsafe to walk the
      bus->devices list of a PCI bus and remove devices from it in direct order,
      because that may lead to NULL pointer dereferences related to virtual
      functions.
      
      For this reason, change all of the bus->devices list walks in
      acpiphp_glue.c during which devices may be removed to be carried out in
      reverse order.
      Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
      Tested-by: NMika Westerberg <mika.westerberg@linux.intel.com>
      2d7c1b77
  3. 02 2月, 2014 1 次提交
    • R
      Revert "PCI: Remove from bus_list and release resources in pci_release_dev()" · 04480094
      Rafael J. Wysocki 提交于
      Revert commit ef83b078 "PCI: Remove from bus_list and release
      resources in pci_release_dev()" that made some nasty race conditions
      become possible.  For example, if a Thunderbolt link is unplugged
      and then replugged immediately, the pci_release_dev() resulting from
      the hot-remove code path may be racing with the hot-add code path
      which after that commit causes various kinds of breakage to happen
      (up to and including a hard crash of the whole system).
      
      Moreover, the problem that commit ef83b078 attempted to address
      cannot happen any more after commit 8a4c5c32 "PCI: Check parent
      kobject in pci_destroy_dev()", because pci_destroy_dev() will now
      return immediately if it has already been executed for the given
      device.
      
      Note, however, that the invocation of msi_remove_pci_irq_vectors()
      removed by commit ef83b078 from pci_free_resources() along with
      the other changes made by it is not added back because of subsequent
      code changes depending on that modification.
      
      Fixes: ef83b078 (PCI: Remove from bus_list and release resources in pci_release_dev())
      Reported-by: NMika Westerberg <mika.westerberg@linux.intel.com>
      Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      04480094
  4. 16 1月, 2014 2 次提交
    • R
      PCI: Check parent kobject in pci_destroy_dev() · 8a4c5c32
      Rafael J. Wysocki 提交于
      If pci_stop_and_remove_bus_device() is run concurrently for a device and
      its parent bridge via remove_callback(), both code paths attempt to acquire
      pci_rescan_remove_lock.  If the child device removal acquires it first,
      there will be no problems.  However, if the parent bridge removal acquires
      it first, it will eventually execute pci_destroy_dev() for the child
      device, but that device object will not be freed yet due to the reference
      held by the concurrent child removal.  Consequently, both
      pci_stop_bus_device() and pci_remove_bus_device() will be executed for that
      device unnecessarily and pci_destroy_dev() will see a corrupted list head
      in that object.  Moreover, an excess put_device() will be executed for that
      device in that case which may lead to a use-after-free in the final
      kobject_put() done by sysfs_schedule_callback_work().
      
      To avoid that problem, make pci_destroy_dev() check if the device's parent
      kobject is NULL, which only happens after device_del() has already run for
      it.  Make pci_destroy_dev() return immediately whithout doing anything in
      that case.
      Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
      Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
      8a4c5c32
    • R
      xen/pcifront: Use global PCI rescan-remove locking · a83919e0
      Rafael J. Wysocki 提交于
      Multiple race conditions are possible between the Xen pcifront device
      addition and removal and the generic PCI device addition and removal that
      can be triggered via sysfs.
      
      To avoid those race conditions make the Xen pcifront code use global PCI
      rescan-remove locking.
      Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
      Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
      a83919e0
  5. 15 1月, 2014 4 次提交
  6. 14 1月, 2014 9 次提交
  7. 11 1月, 2014 6 次提交
  8. 08 1月, 2014 3 次提交
    • Y
      PCI: Allocate 64-bit BARs above 4G when possible · d56dbf5b
      Yinghai Lu 提交于
      Try to allocate space for 64-bit BARs above 4G first, to preserve the space
      below 4G for 32-bit BARs.  If there's no space above 4G available, fall
      back to allocating anywhere.
      
      [bhelgaas: reworked starting from http://lkml.kernel.org/r/1387485843-17403-2-git-send-email-yinghai@kernel.org]
      Signed-off-by: NYinghai Lu <yinghai@kernel.org>
      Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
      d56dbf5b
    • Y
      PCI: Enforce bus address limits in resource allocation · f75b99d5
      Yinghai Lu 提交于
      When allocating space for 32-bit BARs, we previously limited RESOURCE
      addresses so they would fit in 32 bits.  However, the BUS address need not
      be the same as the resource address, and it's the bus address that must fit
      in the 32-bit BAR.
      
      This patch adds:
      
        - pci_clip_resource_to_region(), which clips a resource so it contains
          only the range that maps to the specified bus address region, e.g., to
          clip a resource to 32-bit bus addresses, and
      
        - pci_bus_alloc_from_region(), which allocates space for a resource from
          the specified bus address region,
      
      and changes pci_bus_alloc_resource() to allocate space for 64-bit BARs from
      the entire bus address region, and space for 32-bit BARs from only the bus
      address region below 4GB.
      
      If we had this window:
      
        pci_root HWP0002:0a: host bridge window [mem 0xf0180000000-0xf01fedfffff] (bus address [0x80000000-0xfedfffff])
      
      we previously could not put a 32-bit BAR there, because the CPU addresses
      don't fit in 32 bits.  This patch fixes this, so we can use this space for
      32-bit BARs.
      
      It's also possible (though unlikely) to have resources with 32-bit CPU
      addresses but bus addresses above 4GB.  In this case the previous code
      would allocate space that a 32-bit BAR could not map.
      
      Remove PCIBIOS_MAX_MEM_32, which is no longer used.
      
      [bhelgaas: reworked starting from http://lkml.kernel.org/r/1386658484-15774-3-git-send-email-yinghai@kernel.org]
      Signed-off-by: NYinghai Lu <yinghai@kernel.org>
      Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
      f75b99d5
    • B
      PCI: Split out bridge window override of minimum allocation address · 36e097a8
      Bjorn Helgaas 提交于
      pci_bus_alloc_resource() avoids allocating space below the "min" supplied
      by the caller (usually PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM).  This is to
      protect badly documented motherboard resources.  But if we're allocating
      space inside an already-configured PCI-PCI bridge window, we ignore "min".
      
      See 688d1918 ("pci: make bus resource start address override minimum IO
      address").
      
      This patch moves the check to make it more visible and simplify future
      patches.  No functional change.
      Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
      36e097a8
  9. 05 1月, 2014 3 次提交
  10. 04 1月, 2014 3 次提交
    • A
      PCI/MSI: Add pci_enable_msi_range() and pci_enable_msix_range() · 302a2523
      Alexander Gordeev 提交于
      This adds pci_enable_msi_range(), which supersedes the pci_enable_msi()
      and pci_enable_msi_block() MSI interfaces.
      
      It also adds pci_enable_msix_range(), which supersedes the
      pci_enable_msix() MSI-X interface.
      
      The old interfaces have three categories of return values:
      
          negative: failure; caller should not retry
          positive: failure; value indicates number of interrupts that *could*
      	have been allocated, and caller may retry with a smaller request
          zero: success; at least as many interrupts allocated as requested
      
      It is error-prone to handle these three cases correctly in drivers.
      
      The new functions return either a negative error code or a number of
      successfully allocated MSI/MSI-X interrupts, which is expected to lead to
      clearer device driver code.
      
      pci_enable_msi(), pci_enable_msi_block() and pci_enable_msix() still exist
      unchanged, but are deprecated and may be removed after callers are updated.
      
      [bhelgaas: tweak changelog]
      Suggested-by: NBen Hutchings <bhutchings@solarflare.com>
      Signed-off-by: NAlexander Gordeev <agordeev@redhat.com>
      Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
      Reviewed-by: NTejun Heo <tj@kernel.org>
      302a2523
    • A
      PCI/MSI: Add pci_msix_vec_count() · ff1aa430
      Alexander Gordeev 提交于
      This creates an MSI-X counterpart for pci_msi_vec_count().  Device drivers
      can use this function to obtain maximum number of MSI-X interrupts the
      device supports and use that number in a subsequent call to
      pci_enable_msix().
      
      pci_msix_vec_count() supersedes pci_msix_table_size() and returns a
      negative errno if device does not support MSI-X interrupts.  After this
      update, callers must always check the returned value.
      
      The only user of pci_msix_table_size() was the PCI-Express port driver,
      which is also updated by this change.
      Signed-off-by: NAlexander Gordeev <agordeev@redhat.com>
      Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
      Reviewed-by: NTejun Heo <tj@kernel.org>
      ff1aa430
    • A
      PCI/MSI: Remove pci_enable_msi_block_auto() · 7b92b4f6
      Alexander Gordeev 提交于
      The new pci_msi_vec_count() interface makes pci_enable_msi_block_auto()
      superfluous.
      
      Drivers can use pci_msi_vec_count() to learn the maximum number of MSIs
      supported by the device, and then call pci_enable_msi_block().
      
      pci_enable_msi_block_auto() was introduced recently, and its only user is
      the AHCI driver, which is also updated by this change.
      Signed-off-by: NAlexander Gordeev <agordeev@redhat.com>
      Signed-off-by: NBjorn Helgaas <bhelgaas@google.com>
      Acked-by: NTejun Heo <tj@kernel.org>
      7b92b4f6