forked from Minki/linux
Add hardware I/O coherency support for Armada 370/XP
The purpose of this patch set is to add hardware I/O Coherency support for Armada 370 and Armada XP. Theses SoCs come with an unit called coherency fabric. A beginning of the support for this unit have been introduced with the SMP patch set. This series extend this support: the coherency fabric unit allows to use the Armada XP and the Armada 370 as nearly coherent architectures. The third patches enables this new feature and register our own set of DMA ops, to benefit this hardware enhancement. The first patches exports a dma operation function needed to register our own set of dma ops. The second patch introduces a new flag for the address decoding configuration in order to be able to set the memory windows as shared memory. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iEYEABECAAYFAlCs/LcACgkQCwYYjhRyO9WrOgCfeWpA9XdQnwexySw5tPXS7Qdp aJEAn2ql07SECpTRWezTJptHL0oI1dFF =b0T7 -----END PGP SIGNATURE----- Merge tag 'marvell-hwiocc-for-3.8' of git://github.com/MISL-EBU-System-SW/mainline-public into mvebu/everything Add hardware I/O coherency support for Armada 370/XP The purpose of this patch set is to add hardware I/O Coherency support for Armada 370 and Armada XP. Theses SoCs come with an unit called coherency fabric. A beginning of the support for this unit have been introduced with the SMP patch set. This series extend this support: the coherency fabric unit allows to use the Armada XP and the Armada 370 as nearly coherent architectures. The third patches enables this new feature and register our own set of DMA ops, to benefit this hardware enhancement. The first patches exports a dma operation function needed to register our own set of dma ops. The second patch introduces a new flag for the address decoding configuration in order to be able to set the memory windows as shared memory.
This commit is contained in:
commit
32d6448a08
@ -5,12 +5,17 @@ Available on Marvell SOCs: Armada 370 and Armada XP
|
|||||||
Required properties:
|
Required properties:
|
||||||
|
|
||||||
- compatible: "marvell,coherency-fabric"
|
- compatible: "marvell,coherency-fabric"
|
||||||
- reg: Should contain,coherency fabric registers location and length.
|
|
||||||
|
- reg: Should contain coherency fabric registers location and
|
||||||
|
length. First pair for the coherency fabric registers, second pair
|
||||||
|
for the per-CPU fabric registers registers.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
coherency-fabric@d0020200 {
|
coherency-fabric@d0020200 {
|
||||||
compatible = "marvell,coherency-fabric";
|
compatible = "marvell,coherency-fabric";
|
||||||
reg = <0xd0020200 0xb0>;
|
reg = <0xd0020200 0xb0>,
|
||||||
|
<0xd0021810 0x1c>;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
|
|
||||||
coherency-fabric@d0020200 {
|
coherency-fabric@d0020200 {
|
||||||
compatible = "marvell,coherency-fabric";
|
compatible = "marvell,coherency-fabric";
|
||||||
reg = <0xd0020200 0xb0>;
|
reg = <0xd0020200 0xb0>,
|
||||||
|
<0xd0021810 0x1c>;
|
||||||
};
|
};
|
||||||
|
|
||||||
soc {
|
soc {
|
||||||
|
@ -111,6 +111,8 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size,
|
|||||||
|
|
||||||
extern int dma_supported(struct device *dev, u64 mask);
|
extern int dma_supported(struct device *dev, u64 mask);
|
||||||
|
|
||||||
|
extern int arm_dma_set_mask(struct device *dev, u64 dma_mask);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* arm_dma_alloc - allocate consistent memory for DMA
|
* arm_dma_alloc - allocate consistent memory for DMA
|
||||||
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
|
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
|
||||||
|
@ -108,6 +108,9 @@ static int __init armada_setup_cpu_mbus(void)
|
|||||||
|
|
||||||
addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base;
|
addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base;
|
||||||
|
|
||||||
|
if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"))
|
||||||
|
addr_map_cfg.hw_io_coherency = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable, clear and configure windows.
|
* Disable, clear and configure windows.
|
||||||
*/
|
*/
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
#include <asm/smp_plat.h>
|
#include <asm/smp_plat.h>
|
||||||
#include "armada-370-xp.h"
|
#include "armada-370-xp.h"
|
||||||
|
|
||||||
@ -33,10 +35,13 @@
|
|||||||
* value matching its virtual mapping
|
* value matching its virtual mapping
|
||||||
*/
|
*/
|
||||||
static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200;
|
static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200;
|
||||||
|
static void __iomem *coherency_cpu_base;
|
||||||
|
|
||||||
/* Coherency fabric registers */
|
/* Coherency fabric registers */
|
||||||
#define COHERENCY_FABRIC_CFG_OFFSET 0x4
|
#define COHERENCY_FABRIC_CFG_OFFSET 0x4
|
||||||
|
|
||||||
|
#define IO_SYNC_BARRIER_CTL_OFFSET 0x0
|
||||||
|
|
||||||
static struct of_device_id of_coherency_table[] = {
|
static struct of_device_id of_coherency_table[] = {
|
||||||
{.compatible = "marvell,coherency-fabric"},
|
{.compatible = "marvell,coherency-fabric"},
|
||||||
{ /* end of list */ },
|
{ /* end of list */ },
|
||||||
@ -68,6 +73,70 @@ int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id)
|
|||||||
return ll_set_cpu_coherent(coherency_base, hw_cpu_id);
|
return ll_set_cpu_coherent(coherency_base, hw_cpu_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void mvebu_hwcc_sync_io_barrier(void)
|
||||||
|
{
|
||||||
|
writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
|
||||||
|
while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dma_addr_t mvebu_hwcc_dma_map_page(struct device *dev, struct page *page,
|
||||||
|
unsigned long offset, size_t size,
|
||||||
|
enum dma_data_direction dir,
|
||||||
|
struct dma_attrs *attrs)
|
||||||
|
{
|
||||||
|
if (dir != DMA_TO_DEVICE)
|
||||||
|
mvebu_hwcc_sync_io_barrier();
|
||||||
|
return pfn_to_dma(dev, page_to_pfn(page)) + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void mvebu_hwcc_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
|
||||||
|
size_t size, enum dma_data_direction dir,
|
||||||
|
struct dma_attrs *attrs)
|
||||||
|
{
|
||||||
|
if (dir != DMA_TO_DEVICE)
|
||||||
|
mvebu_hwcc_sync_io_barrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mvebu_hwcc_dma_sync(struct device *dev, dma_addr_t dma_handle,
|
||||||
|
size_t size, enum dma_data_direction dir)
|
||||||
|
{
|
||||||
|
if (dir != DMA_TO_DEVICE)
|
||||||
|
mvebu_hwcc_sync_io_barrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dma_map_ops mvebu_hwcc_dma_ops = {
|
||||||
|
.alloc = arm_dma_alloc,
|
||||||
|
.free = arm_dma_free,
|
||||||
|
.mmap = arm_dma_mmap,
|
||||||
|
.map_page = mvebu_hwcc_dma_map_page,
|
||||||
|
.unmap_page = mvebu_hwcc_dma_unmap_page,
|
||||||
|
.get_sgtable = arm_dma_get_sgtable,
|
||||||
|
.map_sg = arm_dma_map_sg,
|
||||||
|
.unmap_sg = arm_dma_unmap_sg,
|
||||||
|
.sync_single_for_cpu = mvebu_hwcc_dma_sync,
|
||||||
|
.sync_single_for_device = mvebu_hwcc_dma_sync,
|
||||||
|
.sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
|
||||||
|
.sync_sg_for_device = arm_dma_sync_sg_for_device,
|
||||||
|
.set_dma_mask = arm_dma_set_mask,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mvebu_hwcc_platform_notifier(struct notifier_block *nb,
|
||||||
|
unsigned long event, void *__dev)
|
||||||
|
{
|
||||||
|
struct device *dev = __dev;
|
||||||
|
|
||||||
|
if (event != BUS_NOTIFY_ADD_DEVICE)
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
set_dma_ops(dev, &mvebu_hwcc_dma_ops);
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block mvebu_hwcc_platform_nb = {
|
||||||
|
.notifier_call = mvebu_hwcc_platform_notifier,
|
||||||
|
};
|
||||||
|
|
||||||
int __init coherency_init(void)
|
int __init coherency_init(void)
|
||||||
{
|
{
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
@ -76,6 +145,10 @@ int __init coherency_init(void)
|
|||||||
if (np) {
|
if (np) {
|
||||||
pr_info("Initializing Coherency fabric\n");
|
pr_info("Initializing Coherency fabric\n");
|
||||||
coherency_base = of_iomap(np, 0);
|
coherency_base = of_iomap(np, 0);
|
||||||
|
coherency_cpu_base = of_iomap(np, 1);
|
||||||
|
set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
|
||||||
|
bus_register_notifier(&platform_bus_type,
|
||||||
|
&mvebu_hwcc_platform_nb);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -124,8 +124,6 @@ static void arm_dma_sync_single_for_device(struct device *dev,
|
|||||||
__dma_page_cpu_to_dev(page, offset, size, dir);
|
__dma_page_cpu_to_dev(page, offset, size, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arm_dma_set_mask(struct device *dev, u64 dma_mask);
|
|
||||||
|
|
||||||
struct dma_map_ops arm_dma_ops = {
|
struct dma_map_ops arm_dma_ops = {
|
||||||
.alloc = arm_dma_alloc,
|
.alloc = arm_dma_alloc,
|
||||||
.free = arm_dma_free,
|
.free = arm_dma_free,
|
||||||
@ -971,7 +969,7 @@ int dma_supported(struct device *dev, u64 mask)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_supported);
|
EXPORT_SYMBOL(dma_supported);
|
||||||
|
|
||||||
static int arm_dma_set_mask(struct device *dev, u64 dma_mask)
|
int arm_dma_set_mask(struct device *dev, u64 dma_mask)
|
||||||
{
|
{
|
||||||
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
|
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -42,6 +42,8 @@ EXPORT_SYMBOL_GPL(mv_mbus_dram_info);
|
|||||||
#define WIN_REMAP_LO_OFF 0x0008
|
#define WIN_REMAP_LO_OFF 0x0008
|
||||||
#define WIN_REMAP_HI_OFF 0x000c
|
#define WIN_REMAP_HI_OFF 0x000c
|
||||||
|
|
||||||
|
#define ATTR_HW_COHERENCY (0x1 << 4)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default implementation
|
* Default implementation
|
||||||
*/
|
*/
|
||||||
@ -163,6 +165,8 @@ void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg,
|
|||||||
w = &orion_mbus_dram_info.cs[cs++];
|
w = &orion_mbus_dram_info.cs[cs++];
|
||||||
w->cs_index = i;
|
w->cs_index = i;
|
||||||
w->mbus_attr = 0xf & ~(1 << i);
|
w->mbus_attr = 0xf & ~(1 << i);
|
||||||
|
if (cfg->hw_io_coherency)
|
||||||
|
w->mbus_attr |= ATTR_HW_COHERENCY;
|
||||||
w->base = base & 0xffff0000;
|
w->base = base & 0xffff0000;
|
||||||
w->size = (size | 0x0000ffff) + 1;
|
w->size = (size | 0x0000ffff) + 1;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ struct orion_addr_map_cfg {
|
|||||||
const int num_wins; /* Total number of windows */
|
const int num_wins; /* Total number of windows */
|
||||||
const int remappable_wins;
|
const int remappable_wins;
|
||||||
void __iomem *bridge_virt_base;
|
void __iomem *bridge_virt_base;
|
||||||
|
int hw_io_coherency;
|
||||||
|
|
||||||
/* If NULL, the default cpu_win_can_remap will be used, using
|
/* If NULL, the default cpu_win_can_remap will be used, using
|
||||||
the value in remappable_wins */
|
the value in remappable_wins */
|
||||||
|
Loading…
Reference in New Issue
Block a user