aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVinod Koul <vinod.koul@intel.com>2016-10-02 23:48:20 -0400
committerVinod Koul <vinod.koul@intel.com>2016-10-02 23:48:20 -0400
commit4dfc9afe0d46caa309c5eaede841551d4056fefc (patch)
treee069fef612dc52417683ccb4a0ecbd52179361d1
parent850e0448a6db0650a6c41adacbc92f106094d1db (diff)
parent77ff7a706f014a56d38f07acf220f381a8fe0fd8 (diff)
Merge branch 'topic/mv_xor' into for-linus
-rw-r--r--drivers/dma/mv_xor.c95
-rw-r--r--drivers/dma/mv_xor.h7
-rw-r--r--include/linux/mbus.h18
3 files changed, 117 insertions, 3 deletions
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index f8b5e7424b3a..a4f0eb1d1d9c 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -467,12 +467,90 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan)
467 return mv_chan->slots_allocated ? : -ENOMEM; 467 return mv_chan->slots_allocated ? : -ENOMEM;
468} 468}
469 469
470/*
471 * Check if source or destination is an PCIe/IO address (non-SDRAM) and add
472 * a new MBus window if necessary. Use a cache for these check so that
473 * the MMIO mapped registers don't have to be accessed for this check
474 * to speed up this process.
475 */
476static int mv_xor_add_io_win(struct mv_xor_chan *mv_chan, u32 addr)
477{
478 struct mv_xor_device *xordev = mv_chan->xordev;
479 void __iomem *base = mv_chan->mmr_high_base;
480 u32 win_enable;
481 u32 size;
482 u8 target, attr;
483 int ret;
484 int i;
485
486 /* Nothing needs to get done for the Armada 3700 */
487 if (xordev->xor_type == XOR_ARMADA_37XX)
488 return 0;
489
490 /*
491 * Loop over the cached windows to check, if the requested area
492 * is already mapped. If this the case, nothing needs to be done
493 * and we can return.
494 */
495 for (i = 0; i < WINDOW_COUNT; i++) {
496 if (addr >= xordev->win_start[i] &&
497 addr <= xordev->win_end[i]) {
498 /* Window is already mapped */
499 return 0;
500 }
501 }
502
503 /*
504 * The window is not mapped, so we need to create the new mapping
505 */
506
507 /* If no IO window is found that addr has to be located in SDRAM */
508 ret = mvebu_mbus_get_io_win_info(addr, &size, &target, &attr);
509 if (ret < 0)
510 return 0;
511
512 /*
513 * Mask the base addr 'addr' according to 'size' read back from the
514 * MBus window. Otherwise we might end up with an address located
515 * somewhere in the middle of this area here.
516 */
517 size -= 1;
518 addr &= ~size;
519
520 /*
521 * Reading one of both enabled register is enough, as they are always
522 * programmed to the identical values
523 */
524 win_enable = readl(base + WINDOW_BAR_ENABLE(0));
525
526 /* Set 'i' to the first free window to write the new values to */
527 i = ffs(~win_enable) - 1;
528 if (i >= WINDOW_COUNT)
529 return -ENOMEM;
530
531 writel((addr & 0xffff0000) | (attr << 8) | target,
532 base + WINDOW_BASE(i));
533 writel(size & 0xffff0000, base + WINDOW_SIZE(i));
534
535 /* Fill the caching variables for later use */
536 xordev->win_start[i] = addr;
537 xordev->win_end[i] = addr + size;
538
539 win_enable |= (1 << i);
540 win_enable |= 3 << (16 + (2 * i));
541 writel(win_enable, base + WINDOW_BAR_ENABLE(0));
542 writel(win_enable, base + WINDOW_BAR_ENABLE(1));
543
544 return 0;
545}
546
470static struct dma_async_tx_descriptor * 547static struct dma_async_tx_descriptor *
471mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, 548mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
472 unsigned int src_cnt, size_t len, unsigned long flags) 549 unsigned int src_cnt, size_t len, unsigned long flags)
473{ 550{
474 struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); 551 struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan);
475 struct mv_xor_desc_slot *sw_desc; 552 struct mv_xor_desc_slot *sw_desc;
553 int ret;
476 554
477 if (unlikely(len < MV_XOR_MIN_BYTE_COUNT)) 555 if (unlikely(len < MV_XOR_MIN_BYTE_COUNT))
478 return NULL; 556 return NULL;
@@ -483,6 +561,11 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
483 "%s src_cnt: %d len: %zu dest %pad flags: %ld\n", 561 "%s src_cnt: %d len: %zu dest %pad flags: %ld\n",
484 __func__, src_cnt, len, &dest, flags); 562 __func__, src_cnt, len, &dest, flags);
485 563
564 /* Check if a new window needs to get added for 'dest' */
565 ret = mv_xor_add_io_win(mv_chan, dest);
566 if (ret)
567 return NULL;
568
486 sw_desc = mv_chan_alloc_slot(mv_chan); 569 sw_desc = mv_chan_alloc_slot(mv_chan);
487 if (sw_desc) { 570 if (sw_desc) {
488 sw_desc->type = DMA_XOR; 571 sw_desc->type = DMA_XOR;
@@ -490,8 +573,13 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
490 mv_desc_init(sw_desc, dest, len, flags); 573 mv_desc_init(sw_desc, dest, len, flags);
491 if (mv_chan->op_in_desc == XOR_MODE_IN_DESC) 574 if (mv_chan->op_in_desc == XOR_MODE_IN_DESC)
492 mv_desc_set_mode(sw_desc); 575 mv_desc_set_mode(sw_desc);
493 while (src_cnt--) 576 while (src_cnt--) {
577 /* Check if a new window needs to get added for 'src' */
578 ret = mv_xor_add_io_win(mv_chan, src[src_cnt]);
579 if (ret)
580 return NULL;
494 mv_desc_set_src_addr(sw_desc, src_cnt, src[src_cnt]); 581 mv_desc_set_src_addr(sw_desc, src_cnt, src[src_cnt]);
582 }
495 } 583 }
496 584
497 dev_dbg(mv_chan_to_devp(mv_chan), 585 dev_dbg(mv_chan_to_devp(mv_chan),
@@ -956,6 +1044,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
956 mv_chan->op_in_desc = XOR_MODE_IN_DESC; 1044 mv_chan->op_in_desc = XOR_MODE_IN_DESC;
957 1045
958 dma_dev = &mv_chan->dmadev; 1046 dma_dev = &mv_chan->dmadev;
1047 mv_chan->xordev = xordev;
959 1048
960 /* 1049 /*
961 * These source and destination dummy buffers are used to implement 1050 * These source and destination dummy buffers are used to implement
@@ -1083,6 +1172,10 @@ mv_xor_conf_mbus_windows(struct mv_xor_device *xordev,
1083 dram->mbus_dram_target_id, base + WINDOW_BASE(i)); 1172 dram->mbus_dram_target_id, base + WINDOW_BASE(i));
1084 writel((cs->size - 1) & 0xffff0000, base + WINDOW_SIZE(i)); 1173 writel((cs->size - 1) & 0xffff0000, base + WINDOW_SIZE(i));
1085 1174
1175 /* Fill the caching variables for later use */
1176 xordev->win_start[i] = cs->base;
1177 xordev->win_end[i] = cs->base + cs->size - 1;
1178
1086 win_enable |= (1 << i); 1179 win_enable |= (1 << i);
1087 win_enable |= 3 << (16 + (2 * i)); 1180 win_enable |= 3 << (16 + (2 * i));
1088 } 1181 }
diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h
index bf56e082e7cd..88eeab222a23 100644
--- a/drivers/dma/mv_xor.h
+++ b/drivers/dma/mv_xor.h
@@ -80,12 +80,17 @@
80#define WINDOW_BAR_ENABLE(chan) (0x40 + ((chan) << 2)) 80#define WINDOW_BAR_ENABLE(chan) (0x40 + ((chan) << 2))
81#define WINDOW_OVERRIDE_CTRL(chan) (0xA0 + ((chan) << 2)) 81#define WINDOW_OVERRIDE_CTRL(chan) (0xA0 + ((chan) << 2))
82 82
83#define WINDOW_COUNT 8
84
83struct mv_xor_device { 85struct mv_xor_device {
84 void __iomem *xor_base; 86 void __iomem *xor_base;
85 void __iomem *xor_high_base; 87 void __iomem *xor_high_base;
86 struct clk *clk; 88 struct clk *clk;
87 struct mv_xor_chan *channels[MV_XOR_MAX_CHANNELS]; 89 struct mv_xor_chan *channels[MV_XOR_MAX_CHANNELS];
88 int xor_type; 90 int xor_type;
91
92 u32 win_start[WINDOW_COUNT];
93 u32 win_end[WINDOW_COUNT];
89}; 94};
90 95
91/** 96/**
@@ -127,6 +132,8 @@ struct mv_xor_chan {
127 char dummy_dst[MV_XOR_MIN_BYTE_COUNT]; 132 char dummy_dst[MV_XOR_MIN_BYTE_COUNT];
128 dma_addr_t dummy_src_addr, dummy_dst_addr; 133 dma_addr_t dummy_src_addr, dummy_dst_addr;
129 u32 saved_config_reg, saved_int_mask_reg; 134 u32 saved_config_reg, saved_int_mask_reg;
135
136 struct mv_xor_device *xordev;
130}; 137};
131 138
132/** 139/**
diff --git a/include/linux/mbus.h b/include/linux/mbus.h
index d610232762e3..2931aa43dab1 100644
--- a/include/linux/mbus.h
+++ b/include/linux/mbus.h
@@ -11,6 +11,8 @@
11#ifndef __LINUX_MBUS_H 11#ifndef __LINUX_MBUS_H
12#define __LINUX_MBUS_H 12#define __LINUX_MBUS_H
13 13
14#include <linux/errno.h>
15
14struct resource; 16struct resource;
15 17
16struct mbus_dram_target_info 18struct mbus_dram_target_info
@@ -55,6 +57,8 @@ struct mbus_dram_target_info
55#ifdef CONFIG_PLAT_ORION 57#ifdef CONFIG_PLAT_ORION
56extern const struct mbus_dram_target_info *mv_mbus_dram_info(void); 58extern const struct mbus_dram_target_info *mv_mbus_dram_info(void);
57extern const struct mbus_dram_target_info *mv_mbus_dram_info_nooverlap(void); 59extern const struct mbus_dram_target_info *mv_mbus_dram_info_nooverlap(void);
60int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, u8 *target,
61 u8 *attr);
58#else 62#else
59static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void) 63static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void)
60{ 64{
@@ -64,14 +68,24 @@ static inline const struct mbus_dram_target_info *mv_mbus_dram_info_nooverlap(vo
64{ 68{
65 return NULL; 69 return NULL;
66} 70}
71static inline int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size,
72 u8 *target, u8 *attr)
73{
74 /*
75 * On all ARM32 MVEBU platforms with MBus support, this stub
76 * function will not get called. The real function from the
77 * MBus driver is called instead. ARM64 MVEBU platforms like
78 * the Armada 3700 could use the mv_xor device driver which calls
79 * into this function
80 */
81 return -EINVAL;
82}
67#endif 83#endif
68 84
69int mvebu_mbus_save_cpu_target(u32 __iomem *store_addr); 85int mvebu_mbus_save_cpu_target(u32 __iomem *store_addr);
70void mvebu_mbus_get_pcie_mem_aperture(struct resource *res); 86void mvebu_mbus_get_pcie_mem_aperture(struct resource *res);
71void mvebu_mbus_get_pcie_io_aperture(struct resource *res); 87void mvebu_mbus_get_pcie_io_aperture(struct resource *res);
72int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr); 88int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr);
73int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, u8 *target,
74 u8 *attr);
75int mvebu_mbus_add_window_remap_by_id(unsigned int target, 89int mvebu_mbus_add_window_remap_by_id(unsigned int target,
76 unsigned int attribute, 90 unsigned int attribute,
77 phys_addr_t base, size_t size, 91 phys_addr_t base, size_t size,