* acpi-pci:
  PCI: ACPI: Add support for PCI device DMA coherency
  PCI: OF: Move of_pci_dma_configure() to pci_dma_configure()
  of/pci: Fix pci_get_host_bridge_device leak
  device property: ACPI: Remove unused DMA APIs
  device property: ACPI: Make use of the new DMA Attribute APIs
  device property: Adding DMA Attribute APIs for Generic Devices
  ACPI: Adding DMA Attribute APIs for ACPI Device
  device property: Introducing enum dev_dma_attr
  ACPI: Honor ACPI _CCA attribute setting

Conflicts:
	drivers/crypto/ccp/ccp-platform.c
This commit is contained in:
Rafael J. Wysocki 2015-11-07 01:30:10 +01:00
Родитель 0d51ce9ca1 29dbe1f0af
Коммит f2115faaf0
12 изменённых файлов: 146 добавлений и 78 удалений

Просмотреть файл

@ -103,7 +103,12 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
pdevinfo.res = resources;
pdevinfo.num_res = count;
pdevinfo.fwnode = acpi_fwnode_handle(adev);
pdevinfo.dma_mask = acpi_check_dma(adev, NULL) ? DMA_BIT_MASK(32) : 0;
if (acpi_dma_supported(adev))
pdevinfo.dma_mask = DMA_BIT_MASK(32);
else
pdevinfo.dma_mask = 0;
pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev))
dev_err(&adev->dev, "platform device creation failed: %ld\n",

Просмотреть файл

@ -168,7 +168,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
struct list_head *physnode_list;
unsigned int node_id;
int retval = -EINVAL;
bool coherent;
enum dev_dma_attr attr;
if (has_acpi_companion(dev)) {
if (acpi_dev) {
@ -225,8 +225,10 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
if (!has_acpi_companion(dev))
ACPI_COMPANION_SET(dev, acpi_dev);
if (acpi_check_dma(acpi_dev, &coherent))
arch_setup_dma_ops(dev, 0, 0, NULL, coherent);
attr = acpi_get_dma_attr(acpi_dev);
if (attr != DEV_DMA_NOT_SUPPORTED)
arch_setup_dma_ops(dev, 0, 0, NULL,
attr == DEV_DMA_COHERENT);
acpi_physnode_link_name(physical_node_name, node_id);
retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,

Просмотреть файл

@ -1308,6 +1308,48 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
kfree(pnp->unique_id);
}
/**
* acpi_dma_supported - Check DMA support for the specified device.
* @adev: The pointer to acpi device
*
* Return false if DMA is not supported. Otherwise, return true
*/
bool acpi_dma_supported(struct acpi_device *adev)
{
if (!adev)
return false;
if (adev->flags.cca_seen)
return true;
/*
* Per ACPI 6.0 sec 6.2.17, assume devices can do cache-coherent
* DMA on "Intel platforms". Presumably that includes all x86 and
* ia64, and other arches will set CONFIG_ACPI_CCA_REQUIRED=y.
*/
if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED))
return true;
return false;
}
/**
* acpi_get_dma_attr - Check the supported DMA attr for the specified device.
* @adev: The pointer to acpi device
*
* Return enum dev_dma_attr.
*/
enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
{
if (!acpi_dma_supported(adev))
return DEV_DMA_NOT_SUPPORTED;
if (adev->flags.coherent_dma)
return DEV_DMA_COHERENT;
else
return DEV_DMA_NON_COHERENT;
}
static void acpi_init_coherency(struct acpi_device *adev)
{
unsigned long long cca = 0;

Просмотреть файл

@ -598,18 +598,34 @@ unsigned int device_get_child_node_count(struct device *dev)
}
EXPORT_SYMBOL_GPL(device_get_child_node_count);
bool device_dma_is_coherent(struct device *dev)
bool device_dma_supported(struct device *dev)
{
bool coherent = false;
/* For DT, this is always supported.
* For ACPI, this depends on CCA, which
* is determined by the acpi_dma_supported().
*/
if (IS_ENABLED(CONFIG_OF) && dev->of_node)
coherent = of_dma_is_coherent(dev->of_node);
else
acpi_check_dma(ACPI_COMPANION(dev), &coherent);
return true;
return coherent;
return acpi_dma_supported(ACPI_COMPANION(dev));
}
EXPORT_SYMBOL_GPL(device_dma_is_coherent);
EXPORT_SYMBOL_GPL(device_dma_supported);
enum dev_dma_attr device_get_dma_attr(struct device *dev)
{
enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED;
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
if (of_dma_is_coherent(dev->of_node))
attr = DEV_DMA_COHERENT;
else
attr = DEV_DMA_NON_COHERENT;
} else
attr = acpi_get_dma_attr(ACPI_COMPANION(dev));
return attr;
}
EXPORT_SYMBOL_GPL(device_get_dma_attr);
/**
* device_get_phy_mode - Get phy mode for given device

Просмотреть файл

@ -94,6 +94,7 @@ static int ccp_platform_probe(struct platform_device *pdev)
struct ccp_device *ccp;
struct ccp_platform *ccp_platform;
struct device *dev = &pdev->dev;
enum dev_dma_attr attr;
struct resource *ior;
int ret;
@ -118,18 +119,24 @@ static int ccp_platform_probe(struct platform_device *pdev)
}
ccp->io_regs = ccp->io_map;
attr = device_get_dma_attr(dev);
if (attr == DEV_DMA_NOT_SUPPORTED) {
dev_err(dev, "DMA is not supported");
goto e_err;
}
ccp_platform->coherent = (attr == DEV_DMA_COHERENT);
if (ccp_platform->coherent)
ccp->axcache = CACHE_WB_NO_ALLOC;
else
ccp->axcache = CACHE_NONE;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
if (ret) {
dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
goto e_err;
}
ccp_platform->coherent = device_dma_is_coherent(ccp->dev);
if (ccp_platform->coherent)
ccp->axcache = CACHE_WB_NO_ALLOC;
else
ccp->axcache = CACHE_NONE;
dev_set_drvdata(dev, ccp);
ret = ccp_init(ccp);

Просмотреть файл

@ -342,6 +342,7 @@ static int xgbe_probe(struct platform_device *pdev)
struct resource *res;
const char *phy_mode;
unsigned int i, phy_memnum, phy_irqnum;
enum dev_dma_attr attr;
int ret;
DBGPR("--> xgbe_probe\n");
@ -609,7 +610,12 @@ static int xgbe_probe(struct platform_device *pdev)
goto err_io;
/* Set the DMA coherency values */
pdata->coherent = device_dma_is_coherent(pdata->dev);
attr = device_get_dma_attr(dev);
if (attr == DEV_DMA_NOT_SUPPORTED) {
dev_err(dev, "DMA is not supported");
goto err_io;
}
pdata->coherent = (attr == DEV_DMA_COHERENT);
if (pdata->coherent) {
pdata->axdomain = XGBE_DMA_OS_AXDOMAIN;
pdata->arcache = XGBE_DMA_OS_ARCACHE;

Просмотреть файл

@ -117,26 +117,6 @@ int of_get_pci_domain_nr(struct device_node *node)
}
EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
/**
* of_pci_dma_configure - Setup DMA configuration
* @dev: ptr to pci_dev struct of the PCI device
*
* Function to update PCI devices's DMA configuration using the same
* info from the OF node of host bridge's parent (if any).
*/
void of_pci_dma_configure(struct pci_dev *pci_dev)
{
struct device *dev = &pci_dev->dev;
struct device *bridge = pci_get_host_bridge_device(pci_dev);
if (!bridge->parent)
return;
of_dma_configure(dev, bridge->parent->of_node);
pci_put_host_bridge_device(bridge);
}
EXPORT_SYMBOL_GPL(of_pci_dma_configure);
#if defined(CONFIG_OF_ADDRESS)
/**
* of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT

Просмотреть файл

@ -6,12 +6,14 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/of_device.h>
#include <linux/of_pci.h>
#include <linux/pci_hotplug.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/cpumask.h>
#include <linux/pci-aspm.h>
#include <linux/acpi.h>
#include <asm-generic/pci-bridge.h>
#include "pci.h"
@ -1666,6 +1668,34 @@ static void pci_set_msi_domain(struct pci_dev *dev)
dev_set_msi_domain(&dev->dev, d);
}
/**
* pci_dma_configure - Setup DMA configuration
* @dev: ptr to pci_dev struct of the PCI device
*
* Function to update PCI devices's DMA configuration using the same
* info from the OF node or ACPI node of host bridge's parent (if any).
*/
static void pci_dma_configure(struct pci_dev *dev)
{
struct device *bridge = pci_get_host_bridge_device(dev);
if (IS_ENABLED(CONFIG_OF) && dev->dev.of_node) {
if (bridge->parent)
of_dma_configure(&dev->dev, bridge->parent->of_node);
} else if (has_acpi_companion(bridge)) {
struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
enum dev_dma_attr attr = acpi_get_dma_attr(adev);
if (attr == DEV_DMA_NOT_SUPPORTED)
dev_warn(&dev->dev, "DMA not supported.\n");
else
arch_setup_dma_ops(&dev->dev, 0, 0, NULL,
attr == DEV_DMA_COHERENT);
}
pci_put_host_bridge_device(bridge);
}
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
{
int ret;
@ -1679,7 +1709,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.dma_parms = &dev->dma_parms;
dev->dev.coherent_dma_mask = 0xffffffffull;
of_pci_dma_configure(dev);
pci_dma_configure(dev);
pci_set_dma_max_seg_size(dev, 65536);
pci_set_dma_seg_boundary(dev, 0xffffffff);

Просмотреть файл

@ -390,39 +390,6 @@ struct acpi_data_node {
struct completion kobj_done;
};
static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
{
bool ret = false;
if (!adev)
return ret;
/**
* Currently, we only support _CCA=1 (i.e. coherent_dma=1)
* This should be equivalent to specifyig dma-coherent for
* a device in OF.
*
* For the case when _CCA=0 (i.e. coherent_dma=0 && cca_seen=1),
* There are two cases:
* case 1. Do not support and disable DMA.
* case 2. Support but rely on arch-specific cache maintenance for
* non-coherence DMA operations.
* Currently, we implement case 1 above.
*
* For the case when _CCA is missing (i.e. cca_seen=0) and
* platform specifies ACPI_CCA_REQUIRED, we do not support DMA,
* and fallback to arch-specific default handling.
*
* See acpi_init_coherency() for more info.
*/
if (adev->flags.coherent_dma) {
ret = true;
if (coherent)
*coherent = adev->flags.coherent_dma;
}
return ret;
}
static inline bool is_acpi_node(struct fwnode_handle *fwnode)
{
return fwnode && (fwnode->type == FWNODE_ACPI
@ -595,6 +562,9 @@ struct acpi_pci_root {
/* helper */
bool acpi_dma_supported(struct acpi_device *adev);
enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
u64 address, bool check_children);
int acpi_is_root_bridge(acpi_handle);

Просмотреть файл

@ -596,11 +596,16 @@ static inline int acpi_device_modalias(struct device *dev,
return -ENODEV;
}
static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
static inline bool acpi_dma_supported(struct acpi_device *adev)
{
return false;
}
static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
{
return DEV_DMA_NOT_SUPPORTED;
}
#define ACPI_PTR(_ptr) (NULL)
#endif /* !CONFIG_ACPI */

Просмотреть файл

@ -16,7 +16,6 @@ int of_pci_get_devfn(struct device_node *np);
int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
int of_get_pci_domain_nr(struct device_node *node);
void of_pci_dma_configure(struct pci_dev *pci_dev);
#else
static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
{
@ -51,8 +50,6 @@ of_get_pci_domain_nr(struct device_node *node)
{
return -1;
}
static inline void of_pci_dma_configure(struct pci_dev *pci_dev) { }
#endif
#if defined(CONFIG_OF_ADDRESS)

Просмотреть файл

@ -27,6 +27,12 @@ enum dev_prop_type {
DEV_PROP_MAX,
};
enum dev_dma_attr {
DEV_DMA_NOT_SUPPORTED,
DEV_DMA_NON_COHERENT,
DEV_DMA_COHERENT,
};
bool device_property_present(struct device *dev, const char *propname);
int device_property_read_u8_array(struct device *dev, const char *propname,
u8 *val, size_t nval);
@ -168,7 +174,9 @@ struct property_set {
void device_add_property_set(struct device *dev, struct property_set *pset);
bool device_dma_is_coherent(struct device *dev);
bool device_dma_supported(struct device *dev);
enum dev_dma_attr device_get_dma_attr(struct device *dev);
int device_get_phy_mode(struct device *dev);