Merge branch 'acpi-cca'
* acpi-cca: ufs: fix TRUE and FALSE re-define build error megaraid_sas: fix TRUE and FALSE re-define build error amd-xgbe: Unify coherency checking logic with device_dma_is_coherent() crypto: ccp - Unify coherency checking logic with device_dma_is_coherent() device property: Introduces device_dma_is_coherent() arm64 : Introduce support for ACPI _CCA object ACPI / scan: Parse _CCA and setup device coherency
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
config ARM64
|
||||
def_bool y
|
||||
select ACPI_CCA_REQUIRED if ACPI
|
||||
select ACPI_GENERIC_GSI if ACPI
|
||||
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
|
||||
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
@ -28,13 +29,23 @@
|
||||
|
||||
#define DMA_ERROR_CODE (~(dma_addr_t)0)
|
||||
extern struct dma_map_ops *dma_ops;
|
||||
extern struct dma_map_ops dummy_dma_ops;
|
||||
|
||||
static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
|
||||
{
|
||||
if (unlikely(!dev) || !dev->archdata.dma_ops)
|
||||
if (unlikely(!dev))
|
||||
return dma_ops;
|
||||
else
|
||||
else if (dev->archdata.dma_ops)
|
||||
return dev->archdata.dma_ops;
|
||||
else if (acpi_disabled)
|
||||
return dma_ops;
|
||||
|
||||
/*
|
||||
* When ACPI is enabled, if arch_set_dma_ops is not called,
|
||||
* we will disable device DMA capability by setting it
|
||||
* to dummy_dma_ops.
|
||||
*/
|
||||
return &dummy_dma_ops;
|
||||
}
|
||||
|
||||
static inline struct dma_map_ops *get_dma_ops(struct device *dev)
|
||||
@ -48,6 +59,9 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
|
||||
static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
|
||||
struct iommu_ops *iommu, bool coherent)
|
||||
{
|
||||
if (!acpi_disabled && !dev->archdata.dma_ops)
|
||||
dev->archdata.dma_ops = dma_ops;
|
||||
|
||||
dev->archdata.dma_coherent = coherent;
|
||||
}
|
||||
#define arch_setup_dma_ops arch_setup_dma_ops
|
||||
|
@ -414,6 +414,98 @@ out:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* The following APIs are for dummy DMA ops *
|
||||
********************************************/
|
||||
|
||||
static void *__dummy_alloc(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flags,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void __dummy_free(struct device *dev, size_t size,
|
||||
void *vaddr, dma_addr_t dma_handle,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
}
|
||||
|
||||
static int __dummy_mmap(struct device *dev,
|
||||
struct vm_area_struct *vma,
|
||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static dma_addr_t __dummy_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction dir,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
return DMA_ERROR_CODE;
|
||||
}
|
||||
|
||||
static void __dummy_unmap_page(struct device *dev, dma_addr_t dev_addr,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
}
|
||||
|
||||
static int __dummy_map_sg(struct device *dev, struct scatterlist *sgl,
|
||||
int nelems, enum dma_data_direction dir,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __dummy_unmap_sg(struct device *dev,
|
||||
struct scatterlist *sgl, int nelems,
|
||||
enum dma_data_direction dir,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
}
|
||||
|
||||
static void __dummy_sync_single(struct device *dev,
|
||||
dma_addr_t dev_addr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
}
|
||||
|
||||
static void __dummy_sync_sg(struct device *dev,
|
||||
struct scatterlist *sgl, int nelems,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
}
|
||||
|
||||
static int __dummy_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __dummy_dma_supported(struct device *hwdev, u64 mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dma_map_ops dummy_dma_ops = {
|
||||
.alloc = __dummy_alloc,
|
||||
.free = __dummy_free,
|
||||
.mmap = __dummy_mmap,
|
||||
.map_page = __dummy_map_page,
|
||||
.unmap_page = __dummy_unmap_page,
|
||||
.map_sg = __dummy_map_sg,
|
||||
.unmap_sg = __dummy_unmap_sg,
|
||||
.sync_single_for_cpu = __dummy_sync_single,
|
||||
.sync_single_for_device = __dummy_sync_single,
|
||||
.sync_sg_for_cpu = __dummy_sync_sg,
|
||||
.sync_sg_for_device = __dummy_sync_sg,
|
||||
.mapping_error = __dummy_mapping_error,
|
||||
.dma_supported = __dummy_dma_supported,
|
||||
};
|
||||
EXPORT_SYMBOL(dummy_dma_ops);
|
||||
|
||||
static int __init arm64_dma_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -54,6 +54,9 @@ config ACPI_GENERIC_GSI
|
||||
config ACPI_SYSTEM_POWER_STATES_SUPPORT
|
||||
bool
|
||||
|
||||
config ACPI_CCA_REQUIRED
|
||||
bool
|
||||
|
||||
config ACPI_SLEEP
|
||||
bool
|
||||
depends on SUSPEND || HIBERNATION
|
||||
|
@ -103,7 +103,7 @@ 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 = DMA_BIT_MASK(32);
|
||||
pdevinfo.dma_mask = acpi_check_dma(adev, NULL) ? DMA_BIT_MASK(32) : 0;
|
||||
pdev = platform_device_register_full(&pdevinfo);
|
||||
if (IS_ERR(pdev))
|
||||
dev_err(&adev->dev, "platform device creation failed: %ld\n",
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@ -167,6 +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;
|
||||
|
||||
if (has_acpi_companion(dev)) {
|
||||
if (acpi_dev) {
|
||||
@ -223,6 +225,9 @@ 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);
|
||||
|
||||
acpi_physnode_link_name(physical_node_name, node_id);
|
||||
retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
|
||||
physical_node_name);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
@ -2153,6 +2154,39 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
|
||||
kfree(pnp->unique_id);
|
||||
}
|
||||
|
||||
static void acpi_init_coherency(struct acpi_device *adev)
|
||||
{
|
||||
unsigned long long cca = 0;
|
||||
acpi_status status;
|
||||
struct acpi_device *parent = adev->parent;
|
||||
|
||||
if (parent && parent->flags.cca_seen) {
|
||||
/*
|
||||
* From ACPI spec, OSPM will ignore _CCA if an ancestor
|
||||
* already saw one.
|
||||
*/
|
||||
adev->flags.cca_seen = 1;
|
||||
cca = parent->flags.coherent_dma;
|
||||
} else {
|
||||
status = acpi_evaluate_integer(adev->handle, "_CCA",
|
||||
NULL, &cca);
|
||||
if (ACPI_SUCCESS(status))
|
||||
adev->flags.cca_seen = 1;
|
||||
else if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED))
|
||||
/*
|
||||
* If architecture does not specify that _CCA is
|
||||
* required for DMA-able devices (e.g. x86),
|
||||
* we default to _CCA=1.
|
||||
*/
|
||||
cca = 1;
|
||||
else
|
||||
acpi_handle_debug(adev->handle,
|
||||
"ACPI device is missing _CCA.\n");
|
||||
}
|
||||
|
||||
adev->flags.coherent_dma = cca;
|
||||
}
|
||||
|
||||
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
|
||||
int type, unsigned long long sta)
|
||||
{
|
||||
@ -2171,6 +2205,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
|
||||
device->flags.visited = false;
|
||||
device_initialize(&device->dev);
|
||||
dev_set_uevent_suppress(&device->dev, true);
|
||||
acpi_init_coherency(device);
|
||||
}
|
||||
|
||||
void acpi_device_add_finalize(struct acpi_device *device)
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
/**
|
||||
@ -519,3 +520,16 @@ unsigned int device_get_child_node_count(struct device *dev)
|
||||
return count;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_get_child_node_count);
|
||||
|
||||
bool device_dma_is_coherent(struct device *dev)
|
||||
{
|
||||
bool coherent = false;
|
||||
|
||||
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 coherent;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_dma_is_coherent);
|
||||
|
@ -90,58 +90,6 @@ static struct resource *ccp_find_mmio_area(struct ccp_device *ccp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static int ccp_acpi_support(struct ccp_device *ccp)
|
||||
{
|
||||
struct ccp_platform *ccp_platform = ccp->dev_specific;
|
||||
struct acpi_device *adev = ACPI_COMPANION(ccp->dev);
|
||||
acpi_handle handle;
|
||||
acpi_status status;
|
||||
unsigned long long data;
|
||||
int cca;
|
||||
|
||||
/* Retrieve the device cache coherency value */
|
||||
handle = adev->handle;
|
||||
do {
|
||||
status = acpi_evaluate_integer(handle, "_CCA", NULL, &data);
|
||||
if (!ACPI_FAILURE(status)) {
|
||||
cca = data;
|
||||
break;
|
||||
}
|
||||
} while (!ACPI_FAILURE(status));
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(ccp->dev, "error obtaining acpi coherency value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ccp_platform->coherent = !!cca;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* CONFIG_ACPI */
|
||||
static int ccp_acpi_support(struct ccp_device *ccp)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int ccp_of_support(struct ccp_device *ccp)
|
||||
{
|
||||
struct ccp_platform *ccp_platform = ccp->dev_specific;
|
||||
|
||||
ccp_platform->coherent = of_dma_is_coherent(ccp->dev->of_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int ccp_of_support(struct ccp_device *ccp)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ccp_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ccp_device *ccp;
|
||||
@ -182,13 +130,7 @@ static int ccp_platform_probe(struct platform_device *pdev)
|
||||
goto e_err;
|
||||
}
|
||||
|
||||
if (ccp_platform->use_acpi)
|
||||
ret = ccp_acpi_support(ccp);
|
||||
else
|
||||
ret = ccp_of_support(ccp);
|
||||
if (ret)
|
||||
goto e_err;
|
||||
|
||||
ccp_platform->coherent = device_dma_is_coherent(ccp->dev);
|
||||
if (ccp_platform->coherent)
|
||||
ccp->axcache = CACHE_WB_NO_ALLOC;
|
||||
else
|
||||
|
@ -168,13 +168,8 @@ static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata)
|
||||
#ifdef CONFIG_ACPI
|
||||
static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct acpi_device *adev = pdata->adev;
|
||||
struct device *dev = pdata->dev;
|
||||
u32 property;
|
||||
acpi_handle handle;
|
||||
acpi_status status;
|
||||
unsigned long long data;
|
||||
int cca;
|
||||
int ret;
|
||||
|
||||
/* Obtain the system clock setting */
|
||||
@ -195,24 +190,6 @@ static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
|
||||
}
|
||||
pdata->ptpclk_rate = property;
|
||||
|
||||
/* Retrieve the device cache coherency value */
|
||||
handle = adev->handle;
|
||||
do {
|
||||
status = acpi_evaluate_integer(handle, "_CCA", NULL, &data);
|
||||
if (!ACPI_FAILURE(status)) {
|
||||
cca = data;
|
||||
break;
|
||||
}
|
||||
|
||||
status = acpi_get_parent(handle, &handle);
|
||||
} while (!ACPI_FAILURE(status));
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(dev, "error obtaining acpi coherency value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pdata->coherent = !!cca;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* CONFIG_ACPI */
|
||||
@ -243,9 +220,6 @@ static int xgbe_of_support(struct xgbe_prv_data *pdata)
|
||||
}
|
||||
pdata->ptpclk_rate = clk_get_rate(pdata->ptpclk);
|
||||
|
||||
/* Retrieve the device cache coherency value */
|
||||
pdata->coherent = of_dma_is_coherent(dev->of_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
@ -364,6 +338,7 @@ static int xgbe_probe(struct platform_device *pdev)
|
||||
goto err_io;
|
||||
|
||||
/* Set the DMA coherency values */
|
||||
pdata->coherent = device_dma_is_coherent(pdata->dev);
|
||||
if (pdata->coherent) {
|
||||
pdata->axdomain = XGBE_DMA_OS_AXDOMAIN;
|
||||
pdata->arcache = XGBE_DMA_OS_ARCACHE;
|
||||
|
@ -66,7 +66,15 @@ MODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding "
|
||||
|
||||
#define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
|
||||
#define MR_LD_STATE_OPTIMAL 3
|
||||
|
||||
#ifdef FALSE
|
||||
#undef FALSE
|
||||
#endif
|
||||
#define FALSE 0
|
||||
|
||||
#ifdef TRUE
|
||||
#undef TRUE
|
||||
#endif
|
||||
#define TRUE 1
|
||||
|
||||
#define SPAN_DEBUG 0
|
||||
|
@ -198,6 +198,14 @@ enum ufs_hs_gear_tag {
|
||||
#define T_TC0TXMAXSDUSIZE 0x4060
|
||||
#define T_TC1TXMAXSDUSIZE 0x4061
|
||||
|
||||
#ifdef FALSE
|
||||
#undef FALSE
|
||||
#endif
|
||||
|
||||
#ifdef TRUE
|
||||
#undef TRUE
|
||||
#endif
|
||||
|
||||
/* Boolean attribute values */
|
||||
enum {
|
||||
FALSE = 0,
|
||||
|
@ -209,7 +209,9 @@ struct acpi_device_flags {
|
||||
u32 hotplug_notify:1;
|
||||
u32 is_dock_station:1;
|
||||
u32 of_compatible_ok:1;
|
||||
u32 reserved:22;
|
||||
u32 coherent_dma:1;
|
||||
u32 cca_seen:1;
|
||||
u32 reserved:20;
|
||||
};
|
||||
|
||||
/* File System */
|
||||
@ -380,6 +382,39 @@ struct acpi_device {
|
||||
void (*remove)(struct acpi_device *);
|
||||
};
|
||||
|
||||
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;
|
||||
|
@ -553,6 +553,11 @@ static inline int acpi_device_modalias(struct device *dev,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#define ACPI_PTR(_ptr) (NULL)
|
||||
|
||||
#endif /* !CONFIG_ACPI */
|
||||
|
@ -164,4 +164,6 @@ struct property_set {
|
||||
|
||||
void device_add_property_set(struct device *dev, struct property_set *pset);
|
||||
|
||||
bool device_dma_is_coherent(struct device *dev);
|
||||
|
||||
#endif /* _LINUX_PROPERTY_H_ */
|
||||
|
Reference in New Issue
Block a user