You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'next-rebase' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci
* 'next-rebase' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci: PCI: Clean-up MPS debug output pci: Clamp pcie_set_readrq() when using "performance" settings PCI: enable MPS "performance" setting to properly handle bridge MPS PCI: Workaround for Intel MPS errata PCI: Add support for PASID capability PCI: Add implementation for PRI capability PCI: Export ATS functions to modules PCI: Move ATS implementation into own file PCI / PM: Remove unnecessary error variable from acpi_dev_run_wake() PCI hotplug: acpiphp: Prevent deadlock on PCI-to-PCI bridge remove PCI / PM: Extend PME polling to all PCI devices PCI quirk: mmc: Always check for lower base frequency quirk for Ricoh 1180:e823 PCI: Make pci_setup_bridge() non-static for use by arch code x86: constify PCI raw ops structures PCI: Add quirk for known incorrect MPSS PCI: Add Solarflare vendor ID and SFC4000 device IDs
This commit is contained in:
@@ -99,10 +99,10 @@ struct pci_raw_ops {
|
||||
int reg, int len, u32 val);
|
||||
};
|
||||
|
||||
extern struct pci_raw_ops *raw_pci_ops;
|
||||
extern struct pci_raw_ops *raw_pci_ext_ops;
|
||||
extern const struct pci_raw_ops *raw_pci_ops;
|
||||
extern const struct pci_raw_ops *raw_pci_ext_ops;
|
||||
|
||||
extern struct pci_raw_ops pci_direct_conf1;
|
||||
extern const struct pci_raw_ops pci_direct_conf1;
|
||||
extern bool port_cf9_safe;
|
||||
|
||||
/* arch_initcall level */
|
||||
|
||||
@@ -304,7 +304,7 @@ static int ce4100_conf_write(unsigned int seg, unsigned int bus,
|
||||
return pci_direct_conf1.write(seg, bus, devfn, reg, len, value);
|
||||
}
|
||||
|
||||
struct pci_raw_ops ce4100_pci_conf = {
|
||||
static const struct pci_raw_ops ce4100_pci_conf = {
|
||||
.read = ce4100_conf_read,
|
||||
.write = ce4100_conf_write,
|
||||
};
|
||||
|
||||
@@ -33,8 +33,8 @@ int noioapicreroute = 1;
|
||||
int pcibios_last_bus = -1;
|
||||
unsigned long pirq_table_addr;
|
||||
struct pci_bus *pci_root_bus;
|
||||
struct pci_raw_ops *raw_pci_ops;
|
||||
struct pci_raw_ops *raw_pci_ext_ops;
|
||||
const struct pci_raw_ops *__read_mostly raw_pci_ops;
|
||||
const struct pci_raw_ops *__read_mostly raw_pci_ext_ops;
|
||||
|
||||
int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
|
||||
int reg, int len, u32 *val)
|
||||
|
||||
@@ -79,7 +79,7 @@ static int pci_conf1_write(unsigned int seg, unsigned int bus,
|
||||
|
||||
#undef PCI_CONF1_ADDRESS
|
||||
|
||||
struct pci_raw_ops pci_direct_conf1 = {
|
||||
const struct pci_raw_ops pci_direct_conf1 = {
|
||||
.read = pci_conf1_read,
|
||||
.write = pci_conf1_write,
|
||||
};
|
||||
@@ -175,7 +175,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus,
|
||||
|
||||
#undef PCI_CONF2_ADDRESS
|
||||
|
||||
struct pci_raw_ops pci_direct_conf2 = {
|
||||
static const struct pci_raw_ops pci_direct_conf2 = {
|
||||
.read = pci_conf2_read,
|
||||
.write = pci_conf2_write,
|
||||
};
|
||||
@@ -191,7 +191,7 @@ struct pci_raw_ops pci_direct_conf2 = {
|
||||
* This should be close to trivial, but it isn't, because there are buggy
|
||||
* chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
|
||||
*/
|
||||
static int __init pci_sanity_check(struct pci_raw_ops *o)
|
||||
static int __init pci_sanity_check(const struct pci_raw_ops *o)
|
||||
{
|
||||
u32 x = 0;
|
||||
int year, devfn;
|
||||
|
||||
@@ -117,7 +117,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_raw_ops pci_mmcfg = {
|
||||
static const struct pci_raw_ops pci_mmcfg = {
|
||||
.read = pci_mmcfg_read,
|
||||
.write = pci_mmcfg_write,
|
||||
};
|
||||
|
||||
@@ -81,7 +81,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_raw_ops pci_mmcfg = {
|
||||
static const struct pci_raw_ops pci_mmcfg = {
|
||||
.read = pci_mmcfg_read,
|
||||
.write = pci_mmcfg_write,
|
||||
};
|
||||
|
||||
@@ -110,7 +110,7 @@ static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
|
||||
|
||||
#undef PCI_CONF1_MQ_ADDRESS
|
||||
|
||||
static struct pci_raw_ops pci_direct_conf1_mq = {
|
||||
static const struct pci_raw_ops pci_direct_conf1_mq = {
|
||||
.read = pci_conf1_mq_read,
|
||||
.write = pci_conf1_mq_write
|
||||
};
|
||||
|
||||
+1
-1
@@ -301,7 +301,7 @@ static int pci_olpc_write(unsigned int seg, unsigned int bus,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_raw_ops pci_olpc_conf = {
|
||||
static const struct pci_raw_ops pci_olpc_conf = {
|
||||
.read = pci_olpc_read,
|
||||
.write = pci_olpc_write,
|
||||
};
|
||||
|
||||
@@ -303,7 +303,7 @@ static int pci_bios_write(unsigned int seg, unsigned int bus,
|
||||
* Function table for BIOS32 access
|
||||
*/
|
||||
|
||||
static struct pci_raw_ops pci_bios_access = {
|
||||
static const struct pci_raw_ops pci_bios_access = {
|
||||
.read = pci_bios_read,
|
||||
.write = pci_bios_write
|
||||
};
|
||||
@@ -312,7 +312,7 @@ static struct pci_raw_ops pci_bios_access = {
|
||||
* Try to find PCI BIOS.
|
||||
*/
|
||||
|
||||
static struct pci_raw_ops * __devinit pci_find_bios(void)
|
||||
static const struct pci_raw_ops * __devinit pci_find_bios(void)
|
||||
{
|
||||
union bios32 *check;
|
||||
unsigned char sum;
|
||||
|
||||
+2
-1
@@ -80,7 +80,8 @@ static acpi_osd_handler acpi_irq_handler;
|
||||
static void *acpi_irq_context;
|
||||
static struct workqueue_struct *kacpid_wq;
|
||||
static struct workqueue_struct *kacpi_notify_wq;
|
||||
static struct workqueue_struct *kacpi_hotplug_wq;
|
||||
struct workqueue_struct *kacpi_hotplug_wq;
|
||||
EXPORT_SYMBOL(kacpi_hotplug_wq);
|
||||
|
||||
struct acpi_res_list {
|
||||
resource_size_t start;
|
||||
|
||||
@@ -2229,13 +2229,15 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
|
||||
|
||||
/* PCI device ID table */
|
||||
static DEFINE_PCI_DEVICE_TABLE(efx_pci_table) = {
|
||||
{PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID),
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE,
|
||||
PCI_DEVICE_ID_SOLARFLARE_SFC4000A_0),
|
||||
.driver_data = (unsigned long) &falcon_a1_nic_type},
|
||||
{PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID),
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE,
|
||||
PCI_DEVICE_ID_SOLARFLARE_SFC4000B),
|
||||
.driver_data = (unsigned long) &falcon_b0_nic_type},
|
||||
{PCI_DEVICE(EFX_VENDID_SFC, BETHPAGE_A_P_DEVID),
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, BETHPAGE_A_P_DEVID),
|
||||
.driver_data = (unsigned long) &siena_a0_nic_type},
|
||||
{PCI_DEVICE(EFX_VENDID_SFC, SIENA_A_P_DEVID),
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, SIENA_A_P_DEVID),
|
||||
.driver_data = (unsigned long) &siena_a0_nic_type},
|
||||
{0} /* end of list */
|
||||
};
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
#include "filter.h"
|
||||
|
||||
/* PCI IDs */
|
||||
#define EFX_VENDID_SFC 0x1924
|
||||
#define FALCON_A_P_DEVID 0x0703
|
||||
#define FALCON_A_S_DEVID 0x6703
|
||||
#define FALCON_B_P_DEVID 0x0710
|
||||
#define BETHPAGE_A_P_DEVID 0x0803
|
||||
#define SIENA_A_P_DEVID 0x0813
|
||||
|
||||
|
||||
@@ -1426,7 +1426,8 @@ static int falcon_probe_nic(struct efx_nic *efx)
|
||||
}
|
||||
|
||||
dev = pci_dev_get(efx->pci_dev);
|
||||
while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID,
|
||||
while ((dev = pci_get_device(PCI_VENDOR_ID_SOLARFLARE,
|
||||
PCI_DEVICE_ID_SOLARFLARE_SFC4000A_1,
|
||||
dev))) {
|
||||
if (dev->bus == efx->pci_dev->bus &&
|
||||
dev->devfn == efx->pci_dev->devfn + 1) {
|
||||
|
||||
@@ -764,7 +764,8 @@ int falcon_probe_board(struct efx_nic *efx, u16 revision_info)
|
||||
|
||||
if (board->type) {
|
||||
netif_info(efx, probe, efx->net_dev, "board is %s rev %c%d\n",
|
||||
(efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
|
||||
(efx->pci_dev->subsystem_vendor ==
|
||||
PCI_VENDOR_ID_SOLARFLARE)
|
||||
? board->type->ref_model : board->type->gen_type,
|
||||
'A' + board->major, board->minor);
|
||||
return 0;
|
||||
|
||||
@@ -71,9 +71,13 @@ config HT_IRQ
|
||||
|
||||
If unsure say Y.
|
||||
|
||||
config PCI_ATS
|
||||
bool
|
||||
|
||||
config PCI_IOV
|
||||
bool "PCI IOV support"
|
||||
depends on PCI
|
||||
select PCI_ATS
|
||||
help
|
||||
I/O Virtualization is a PCI feature supported by some devices
|
||||
which allows them to create virtual devices which share their
|
||||
@@ -81,6 +85,28 @@ config PCI_IOV
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PCI_PRI
|
||||
bool "PCI PRI support"
|
||||
select PCI_ATS
|
||||
help
|
||||
PRI is the PCI Page Request Interface. It allows PCI devices that are
|
||||
behind an IOMMU to recover from page faults.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PCI_PASID
|
||||
bool "PCI PASID support"
|
||||
depends on PCI
|
||||
select PCI_ATS
|
||||
help
|
||||
Process Address Space Identifiers (PASIDs) can be used by PCI devices
|
||||
to access more than one IO address space at the same time. To make
|
||||
use of this feature an IOMMU is required which also supports PASIDs.
|
||||
Select this option if you have such an IOMMU and want to compile the
|
||||
driver for it into your kernel.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PCI_IOAPIC
|
||||
bool
|
||||
depends on PCI
|
||||
|
||||
@@ -29,6 +29,7 @@ obj-$(CONFIG_PCI_MSI) += msi.o
|
||||
# Build the Hypertransport interrupt support
|
||||
obj-$(CONFIG_HT_IRQ) += htirq.o
|
||||
|
||||
obj-$(CONFIG_PCI_ATS) += ats.o
|
||||
obj-$(CONFIG_PCI_IOV) += iov.o
|
||||
|
||||
#
|
||||
|
||||
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* drivers/pci/ats.c
|
||||
*
|
||||
* Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
|
||||
* Copyright (C) 2011 Advanced Micro Devices,
|
||||
*
|
||||
* PCI Express I/O Virtualization (IOV) support.
|
||||
* Address Translation Service 1.0
|
||||
* Page Request Interface added by Joerg Roedel <joerg.roedel@amd.com>
|
||||
* PASID support added by Joerg Roedel <joerg.roedel@amd.com>
|
||||
*/
|
||||
|
||||
#include <linux/pci-ats.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "pci.h"
|
||||
|
||||
static int ats_alloc_one(struct pci_dev *dev, int ps)
|
||||
{
|
||||
int pos;
|
||||
u16 cap;
|
||||
struct pci_ats *ats;
|
||||
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
|
||||
if (!pos)
|
||||
return -ENODEV;
|
||||
|
||||
ats = kzalloc(sizeof(*ats), GFP_KERNEL);
|
||||
if (!ats)
|
||||
return -ENOMEM;
|
||||
|
||||
ats->pos = pos;
|
||||
ats->stu = ps;
|
||||
pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
|
||||
ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
|
||||
PCI_ATS_MAX_QDEP;
|
||||
dev->ats = ats;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ats_free_one(struct pci_dev *dev)
|
||||
{
|
||||
kfree(dev->ats);
|
||||
dev->ats = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_enable_ats - enable the ATS capability
|
||||
* @dev: the PCI device
|
||||
* @ps: the IOMMU page shift
|
||||
*
|
||||
* Returns 0 on success, or negative on failure.
|
||||
*/
|
||||
int pci_enable_ats(struct pci_dev *dev, int ps)
|
||||
{
|
||||
int rc;
|
||||
u16 ctrl;
|
||||
|
||||
BUG_ON(dev->ats && dev->ats->is_enabled);
|
||||
|
||||
if (ps < PCI_ATS_MIN_STU)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->is_physfn || dev->is_virtfn) {
|
||||
struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
|
||||
|
||||
mutex_lock(&pdev->sriov->lock);
|
||||
if (pdev->ats)
|
||||
rc = pdev->ats->stu == ps ? 0 : -EINVAL;
|
||||
else
|
||||
rc = ats_alloc_one(pdev, ps);
|
||||
|
||||
if (!rc)
|
||||
pdev->ats->ref_cnt++;
|
||||
mutex_unlock(&pdev->sriov->lock);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!dev->is_physfn) {
|
||||
rc = ats_alloc_one(dev, ps);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
ctrl = PCI_ATS_CTRL_ENABLE;
|
||||
if (!dev->is_virtfn)
|
||||
ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
|
||||
pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
|
||||
|
||||
dev->ats->is_enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_enable_ats);
|
||||
|
||||
/**
|
||||
* pci_disable_ats - disable the ATS capability
|
||||
* @dev: the PCI device
|
||||
*/
|
||||
void pci_disable_ats(struct pci_dev *dev)
|
||||
{
|
||||
u16 ctrl;
|
||||
|
||||
BUG_ON(!dev->ats || !dev->ats->is_enabled);
|
||||
|
||||
pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
|
||||
ctrl &= ~PCI_ATS_CTRL_ENABLE;
|
||||
pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
|
||||
|
||||
dev->ats->is_enabled = 0;
|
||||
|
||||
if (dev->is_physfn || dev->is_virtfn) {
|
||||
struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
|
||||
|
||||
mutex_lock(&pdev->sriov->lock);
|
||||
pdev->ats->ref_cnt--;
|
||||
if (!pdev->ats->ref_cnt)
|
||||
ats_free_one(pdev);
|
||||
mutex_unlock(&pdev->sriov->lock);
|
||||
}
|
||||
|
||||
if (!dev->is_physfn)
|
||||
ats_free_one(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_disable_ats);
|
||||
|
||||
/**
|
||||
* pci_ats_queue_depth - query the ATS Invalidate Queue Depth
|
||||
* @dev: the PCI device
|
||||
*
|
||||
* Returns the queue depth on success, or negative on failure.
|
||||
*
|
||||
* The ATS spec uses 0 in the Invalidate Queue Depth field to
|
||||
* indicate that the function can accept 32 Invalidate Request.
|
||||
* But here we use the `real' values (i.e. 1~32) for the Queue
|
||||
* Depth; and 0 indicates the function shares the Queue with
|
||||
* other functions (doesn't exclusively own a Queue).
|
||||
*/
|
||||
int pci_ats_queue_depth(struct pci_dev *dev)
|
||||
{
|
||||
int pos;
|
||||
u16 cap;
|
||||
|
||||
if (dev->is_virtfn)
|
||||
return 0;
|
||||
|
||||
if (dev->ats)
|
||||
return dev->ats->qdep;
|
||||
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
|
||||
if (!pos)
|
||||
return -ENODEV;
|
||||
|
||||
pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
|
||||
|
||||
return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
|
||||
PCI_ATS_MAX_QDEP;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
|
||||
|
||||
#ifdef CONFIG_PCI_PRI
|
||||
/**
|
||||
* pci_enable_pri - Enable PRI capability
|
||||
* @ pdev: PCI device structure
|
||||
*
|
||||
* Returns 0 on success, negative value on error
|
||||
*/
|
||||
int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
|
||||
{
|
||||
u16 control, status;
|
||||
u32 max_requests;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF, &status);
|
||||
if ((control & PCI_PRI_ENABLE) || !(status & PCI_PRI_STATUS_STOPPED))
|
||||
return -EBUSY;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ_OFF, &max_requests);
|
||||
reqs = min(max_requests, reqs);
|
||||
pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ_OFF, reqs);
|
||||
|
||||
control |= PCI_PRI_ENABLE;
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_enable_pri);
|
||||
|
||||
/**
|
||||
* pci_disable_pri - Disable PRI capability
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
* Only clears the enabled-bit, regardless of its former value
|
||||
*/
|
||||
void pci_disable_pri(struct pci_dev *pdev)
|
||||
{
|
||||
u16 control;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
control &= ~PCI_PRI_ENABLE;
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_disable_pri);
|
||||
|
||||
/**
|
||||
* pci_pri_enabled - Checks if PRI capability is enabled
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
* Returns true if PRI is enabled on the device, false otherwise
|
||||
*/
|
||||
bool pci_pri_enabled(struct pci_dev *pdev)
|
||||
{
|
||||
u16 control;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
if (!pos)
|
||||
return false;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
|
||||
return (control & PCI_PRI_ENABLE) ? true : false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_pri_enabled);
|
||||
|
||||
/**
|
||||
* pci_reset_pri - Resets device's PRI state
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
* The PRI capability must be disabled before this function is called.
|
||||
* Returns 0 on success, negative value on error.
|
||||
*/
|
||||
int pci_reset_pri(struct pci_dev *pdev)
|
||||
{
|
||||
u16 control;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
if (control & PCI_PRI_ENABLE)
|
||||
return -EBUSY;
|
||||
|
||||
control |= PCI_PRI_RESET;
|
||||
|
||||
pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_reset_pri);
|
||||
|
||||
/**
|
||||
* pci_pri_stopped - Checks whether the PRI capability is stopped
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
* Returns true if the PRI capability on the device is disabled and the
|
||||
* device has no outstanding PRI requests, false otherwise. The device
|
||||
* indicates this via the STOPPED bit in the status register of the
|
||||
* capability.
|
||||
* The device internal state can be cleared by resetting the PRI state
|
||||
* with pci_reset_pri(). This can force the capability into the STOPPED
|
||||
* state.
|
||||
*/
|
||||
bool pci_pri_stopped(struct pci_dev *pdev)
|
||||
{
|
||||
u16 control, status;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
if (!pos)
|
||||
return true;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF, &status);
|
||||
|
||||
if (control & PCI_PRI_ENABLE)
|
||||
return false;
|
||||
|
||||
return (status & PCI_PRI_STATUS_STOPPED) ? true : false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_pri_stopped);
|
||||
|
||||
/**
|
||||
* pci_pri_status - Request PRI status of a device
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
* Returns negative value on failure, status on success. The status can
|
||||
* be checked against status-bits. Supported bits are currently:
|
||||
* PCI_PRI_STATUS_RF: Response failure
|
||||
* PCI_PRI_STATUS_UPRGI: Unexpected Page Request Group Index
|
||||
* PCI_PRI_STATUS_STOPPED: PRI has stopped
|
||||
*/
|
||||
int pci_pri_status(struct pci_dev *pdev)
|
||||
{
|
||||
u16 status, control;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF, &status);
|
||||
|
||||
/* Stopped bit is undefined when enable == 1, so clear it */
|
||||
if (control & PCI_PRI_ENABLE)
|
||||
status &= ~PCI_PRI_STATUS_STOPPED;
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_pri_status);
|
||||
#endif /* CONFIG_PCI_PRI */
|
||||
|
||||
#ifdef CONFIG_PCI_PASID
|
||||
/**
|
||||
* pci_enable_pasid - Enable the PASID capability
|
||||
* @pdev: PCI device structure
|
||||
* @features: Features to enable
|
||||
*
|
||||
* Returns 0 on success, negative value on error. This function checks
|
||||
* whether the features are actually supported by the device and returns
|
||||
* an error if not.
|
||||
*/
|
||||
int pci_enable_pasid(struct pci_dev *pdev, int features)
|
||||
{
|
||||
u16 control, supported;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, &control);
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
|
||||
|
||||
if (!(supported & PCI_PASID_ENABLE))
|
||||
return -EINVAL;
|
||||
|
||||
supported &= PCI_PASID_EXEC | PCI_PASID_PRIV;
|
||||
|
||||
/* User wants to enable anything unsupported? */
|
||||
if ((supported & features) != features)
|
||||
return -EINVAL;
|
||||
|
||||
control = PCI_PASID_ENABLE | features;
|
||||
|
||||
pci_write_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_enable_pasid);
|
||||
|
||||
/**
|
||||
* pci_disable_pasid - Disable the PASID capability
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
*/
|
||||
void pci_disable_pasid(struct pci_dev *pdev)
|
||||
{
|
||||
u16 control = 0;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
pci_write_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, control);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_disable_pasid);
|
||||
|
||||
/**
|
||||
* pci_pasid_features - Check which PASID features are supported
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
* Returns a negative value when no PASI capability is present.
|
||||
* Otherwise is returns a bitmask with supported features. Current
|
||||
* features reported are:
|
||||
* PCI_PASID_ENABLE - PASID capability can be enabled
|
||||
* PCI_PASID_EXEC - Execute permission supported
|
||||
* PCI_PASID_PRIV - Priviledged mode supported
|
||||
*/
|
||||
int pci_pasid_features(struct pci_dev *pdev)
|
||||
{
|
||||
u16 supported;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
|
||||
|
||||
supported &= PCI_PASID_ENABLE | PCI_PASID_EXEC | PCI_PASID_PRIV;
|
||||
|
||||
return supported;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_pasid_features);
|
||||
|
||||
#define PASID_NUMBER_SHIFT 8
|
||||
#define PASID_NUMBER_MASK (0x1f << PASID_NUMBER_SHIFT)
|
||||
/**
|
||||
* pci_max_pasid - Get maximum number of PASIDs supported by device
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
* Returns negative value when PASID capability is not present.
|
||||
* Otherwise it returns the numer of supported PASIDs.
|
||||
*/
|
||||
int pci_max_pasids(struct pci_dev *pdev)
|
||||
{
|
||||
u16 supported;
|
||||
int pos;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
|
||||
if (!pos)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
|
||||
|
||||
supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
|
||||
|
||||
return (1 << supported);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_max_pasids);
|
||||
#endif /* CONFIG_PCI_PASID */
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <linux/pci-acpi.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "../pci.h"
|
||||
#include "acpiphp.h"
|
||||
@@ -1149,15 +1150,35 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
return AE_OK ;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_hotplug_event_bridge - handle ACPI event on bridges
|
||||
* @handle: Notify()'ed acpi_handle
|
||||
* @type: Notify code
|
||||
* @context: pointer to acpiphp_bridge structure
|
||||
*
|
||||
* Handles ACPI event notification on {host,p2p} bridges.
|
||||
*/
|
||||
static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context)
|
||||
struct acpiphp_hp_work {
|
||||
struct work_struct work;
|
||||
acpi_handle handle;
|
||||
u32 type;
|
||||
void *context;
|
||||
};
|
||||
|
||||
static void alloc_acpiphp_hp_work(acpi_handle handle, u32 type,
|
||||
void *context,
|
||||
void (*func)(struct work_struct *work))
|
||||
{
|
||||
struct acpiphp_hp_work *hp_work;
|
||||
int ret;
|
||||
|
||||
hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
|
||||
if (!hp_work)
|
||||
return;
|
||||
|
||||
hp_work->handle = handle;
|
||||
hp_work->type = type;
|
||||
hp_work->context = context;
|
||||
|
||||
INIT_WORK(&hp_work->work, func);
|
||||
ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
|
||||
if (!ret)
|
||||
kfree(hp_work);
|
||||
}
|
||||
|
||||
static void _handle_hotplug_event_bridge(struct work_struct *work)
|
||||
{
|
||||
struct acpiphp_bridge *bridge;
|
||||
char objname[64];
|
||||
@@ -1165,11 +1186,18 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
|
||||
.pointer = objname };
|
||||
struct acpi_device *device;
|
||||
int num_sub_bridges = 0;
|
||||
struct acpiphp_hp_work *hp_work;
|
||||
acpi_handle handle;
|
||||
u32 type;
|
||||
|
||||
hp_work = container_of(work, struct acpiphp_hp_work, work);
|
||||
handle = hp_work->handle;
|
||||
type = hp_work->type;
|
||||
|
||||
if (acpi_bus_get_device(handle, &device)) {
|
||||
/* This bridge must have just been physically inserted */
|
||||
handle_bridge_insertion(handle, type);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bridge = acpiphp_handle_to_bridge(handle);
|
||||
@@ -1180,7 +1208,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
|
||||
|
||||
if (!bridge && !num_sub_bridges) {
|
||||
err("cannot get bridge info\n");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
|
||||
@@ -1241,22 +1269,49 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
|
||||
warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
|
||||
* handle_hotplug_event_bridge - handle ACPI event on bridges
|
||||
* @handle: Notify()'ed acpi_handle
|
||||
* @type: Notify code
|
||||
* @context: pointer to acpiphp_func structure
|
||||
* @context: pointer to acpiphp_bridge structure
|
||||
*
|
||||
* Handles ACPI event notification on slots.
|
||||
* Handles ACPI event notification on {host,p2p} bridges.
|
||||
*/
|
||||
static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
|
||||
static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
|
||||
void *context)
|
||||
{
|
||||
/*
|
||||
* Currently the code adds all hotplug events to the kacpid_wq
|
||||
* queue when it should add hotplug events to the kacpi_hotplug_wq.
|
||||
* The proper way to fix this is to reorganize the code so that
|
||||
* drivers (dock, etc.) do not call acpi_os_execute(), etc.
|
||||
* For now just re-add this work to the kacpi_hotplug_wq so we
|
||||
* don't deadlock on hotplug actions.
|
||||
*/
|
||||
alloc_acpiphp_hp_work(handle, type, context,
|
||||
_handle_hotplug_event_bridge);
|
||||
}
|
||||
|
||||
static void _handle_hotplug_event_func(struct work_struct *work)
|
||||
{
|
||||
struct acpiphp_func *func;
|
||||
char objname[64];
|
||||
struct acpi_buffer buffer = { .length = sizeof(objname),
|
||||
.pointer = objname };
|
||||
struct acpiphp_hp_work *hp_work;
|
||||
acpi_handle handle;
|
||||
u32 type;
|
||||
void *context;
|
||||
|
||||
hp_work = container_of(work, struct acpiphp_hp_work, work);
|
||||
handle = hp_work->handle;
|
||||
type = hp_work->type;
|
||||
context = hp_work->context;
|
||||
|
||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
|
||||
|
||||
@@ -1291,8 +1346,32 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex
|
||||
warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(hp_work); /* allocated in handle_hotplug_event_func */
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
|
||||
* @handle: Notify()'ed acpi_handle
|
||||
* @type: Notify code
|
||||
* @context: pointer to acpiphp_func structure
|
||||
*
|
||||
* Handles ACPI event notification on slots.
|
||||
*/
|
||||
static void handle_hotplug_event_func(acpi_handle handle, u32 type,
|
||||
void *context)
|
||||
{
|
||||
/*
|
||||
* Currently the code adds all hotplug events to the kacpid_wq
|
||||
* queue when it should add hotplug events to the kacpi_hotplug_wq.
|
||||
* The proper way to fix this is to reorganize the code so that
|
||||
* drivers (dock, etc.) do not call acpi_os_execute(), etc.
|
||||
* For now just re-add this work to the kacpi_hotplug_wq so we
|
||||
* don't deadlock on hotplug actions.
|
||||
*/
|
||||
alloc_acpiphp_hp_work(handle, type, context,
|
||||
_handle_hotplug_event_func);
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
|
||||
|
||||
@@ -722,145 +722,3 @@ int pci_num_vf(struct pci_dev *dev)
|
||||
return dev->sriov->nr_virtfn;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_num_vf);
|
||||
|
||||
static int ats_alloc_one(struct pci_dev *dev, int ps)
|
||||
{
|
||||
int pos;
|
||||
u16 cap;
|
||||
struct pci_ats *ats;
|
||||
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
|
||||
if (!pos)
|
||||
return -ENODEV;
|
||||
|
||||
ats = kzalloc(sizeof(*ats), GFP_KERNEL);
|
||||
if (!ats)
|
||||
return -ENOMEM;
|
||||
|
||||
ats->pos = pos;
|
||||
ats->stu = ps;
|
||||
pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
|
||||
ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
|
||||
PCI_ATS_MAX_QDEP;
|
||||
dev->ats = ats;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ats_free_one(struct pci_dev *dev)
|
||||
{
|
||||
kfree(dev->ats);
|
||||
dev->ats = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_enable_ats - enable the ATS capability
|
||||
* @dev: the PCI device
|
||||
* @ps: the IOMMU page shift
|
||||
*
|
||||
* Returns 0 on success, or negative on failure.
|
||||
*/
|
||||
int pci_enable_ats(struct pci_dev *dev, int ps)
|
||||
{
|
||||
int rc;
|
||||
u16 ctrl;
|
||||
|
||||
BUG_ON(dev->ats && dev->ats->is_enabled);
|
||||
|
||||
if (ps < PCI_ATS_MIN_STU)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->is_physfn || dev->is_virtfn) {
|
||||
struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
|
||||
|
||||
mutex_lock(&pdev->sriov->lock);
|
||||
if (pdev->ats)
|
||||
rc = pdev->ats->stu == ps ? 0 : -EINVAL;
|
||||
else
|
||||
rc = ats_alloc_one(pdev, ps);
|
||||
|
||||
if (!rc)
|
||||
pdev->ats->ref_cnt++;
|
||||
mutex_unlock(&pdev->sriov->lock);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!dev->is_physfn) {
|
||||
rc = ats_alloc_one(dev, ps);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
ctrl = PCI_ATS_CTRL_ENABLE;
|
||||
if (!dev->is_virtfn)
|
||||
ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
|
||||
pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
|
||||
|
||||
dev->ats->is_enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_disable_ats - disable the ATS capability
|
||||
* @dev: the PCI device
|
||||
*/
|
||||
void pci_disable_ats(struct pci_dev *dev)
|
||||
{
|
||||
u16 ctrl;
|
||||
|
||||
BUG_ON(!dev->ats || !dev->ats->is_enabled);
|
||||
|
||||
pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
|
||||
ctrl &= ~PCI_ATS_CTRL_ENABLE;
|
||||
pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
|
||||
|
||||
dev->ats->is_enabled = 0;
|
||||
|
||||
if (dev->is_physfn || dev->is_virtfn) {
|
||||
struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
|
||||
|
||||
mutex_lock(&pdev->sriov->lock);
|
||||
pdev->ats->ref_cnt--;
|
||||
if (!pdev->ats->ref_cnt)
|
||||
ats_free_one(pdev);
|
||||
mutex_unlock(&pdev->sriov->lock);
|
||||
}
|
||||
|
||||
if (!dev->is_physfn)
|
||||
ats_free_one(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_ats_queue_depth - query the ATS Invalidate Queue Depth
|
||||
* @dev: the PCI device
|
||||
*
|
||||
* Returns the queue depth on success, or negative on failure.
|
||||
*
|
||||
* The ATS spec uses 0 in the Invalidate Queue Depth field to
|
||||
* indicate that the function can accept 32 Invalidate Request.
|
||||
* But here we use the `real' values (i.e. 1~32) for the Queue
|
||||
* Depth; and 0 indicates the function shares the Queue with
|
||||
* other functions (doesn't exclusively own a Queue).
|
||||
*/
|
||||
int pci_ats_queue_depth(struct pci_dev *dev)
|
||||
{
|
||||
int pos;
|
||||
u16 cap;
|
||||
|
||||
if (dev->is_virtfn)
|
||||
return 0;
|
||||
|
||||
if (dev->ats)
|
||||
return dev->ats->qdep;
|
||||
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
|
||||
if (!pos)
|
||||
return -ENODEV;
|
||||
|
||||
pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
|
||||
|
||||
return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
|
||||
PCI_ATS_MAX_QDEP;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
|
||||
struct pci_dev *pci_dev = context;
|
||||
|
||||
if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) {
|
||||
if (pci_dev->pme_poll)
|
||||
pci_dev->pme_poll = false;
|
||||
|
||||
pci_wakeup_event(pci_dev);
|
||||
pci_check_pme_status(pci_dev);
|
||||
pm_runtime_resume(&pci_dev->dev);
|
||||
@@ -282,7 +285,6 @@ static int acpi_dev_run_wake(struct device *phys_dev, bool enable)
|
||||
{
|
||||
struct acpi_device *dev;
|
||||
acpi_handle handle;
|
||||
int error = -ENODEV;
|
||||
|
||||
if (!device_run_wake(phys_dev))
|
||||
return -EINVAL;
|
||||
@@ -302,7 +304,7 @@ static int acpi_dev_run_wake(struct device *phys_dev, bool enable)
|
||||
acpi_disable_wakeup_device_power(dev);
|
||||
}
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_pci_propagate_run_wake(struct pci_bus *bus, bool enable)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user