Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'topic/mv_xor' into for-linus

+117 -3
+94 -1
drivers/dma/mv_xor.c
··· 467 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 + */ 476 + static 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 + 470 547 static struct dma_async_tx_descriptor * 471 548 mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, 472 549 unsigned int src_cnt, size_t len, unsigned long flags) 473 550 { 474 551 struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); 475 552 struct mv_xor_desc_slot *sw_desc; 553 + int ret; 476 554 477 555 if (unlikely(len < MV_XOR_MIN_BYTE_COUNT)) 478 556 return NULL; ··· 561 483 "%s src_cnt: %d len: %zu dest %pad flags: %ld\n", 562 484 __func__, src_cnt, len, &dest, flags); 563 485 486 + /* Check if a new window needs to get added for 'dest' */ 487 + ret = mv_xor_add_io_win(mv_chan, dest); 488 + if (ret) 489 + return NULL; 490 + 564 491 sw_desc = mv_chan_alloc_slot(mv_chan); 565 492 if (sw_desc) { 566 493 sw_desc->type = DMA_XOR; ··· 573 490 mv_desc_init(sw_desc, dest, len, flags); 574 491 if (mv_chan->op_in_desc == XOR_MODE_IN_DESC) 575 492 mv_desc_set_mode(sw_desc); 576 - while (src_cnt--) 493 + while (src_cnt--) { 494 + /* Check if a new window needs to get added for 'src' */ 495 + ret = mv_xor_add_io_win(mv_chan, src[src_cnt]); 496 + if (ret) 497 + return NULL; 577 498 mv_desc_set_src_addr(sw_desc, src_cnt, src[src_cnt]); 499 + } 578 500 } 579 501 580 502 dev_dbg(mv_chan_to_devp(mv_chan), ··· 1044 956 mv_chan->op_in_desc = XOR_MODE_IN_DESC; 1045 957 1046 958 dma_dev = &mv_chan->dmadev; 959 + mv_chan->xordev = xordev; 1047 960 1048 961 /* 1049 962 * These source and destination dummy buffers are used to implement ··· 1171 1082 (cs->mbus_attr << 8) | 1172 1083 dram->mbus_dram_target_id, base + WINDOW_BASE(i)); 1173 1084 writel((cs->size - 1) & 0xffff0000, base + WINDOW_SIZE(i)); 1085 + 1086 + /* Fill the caching variables for later use */ 1087 + xordev->win_start[i] = cs->base; 1088 + xordev->win_end[i] = cs->base + cs->size - 1; 1174 1089 1175 1090 win_enable |= (1 << i); 1176 1091 win_enable |= 3 << (16 + (2 * i));
+7
drivers/dma/mv_xor.h
··· 80 80 #define WINDOW_BAR_ENABLE(chan) (0x40 + ((chan) << 2)) 81 81 #define WINDOW_OVERRIDE_CTRL(chan) (0xA0 + ((chan) << 2)) 82 82 83 + #define WINDOW_COUNT 8 84 + 83 85 struct mv_xor_device { 84 86 void __iomem *xor_base; 85 87 void __iomem *xor_high_base; 86 88 struct clk *clk; 87 89 struct mv_xor_chan *channels[MV_XOR_MAX_CHANNELS]; 88 90 int xor_type; 91 + 92 + u32 win_start[WINDOW_COUNT]; 93 + u32 win_end[WINDOW_COUNT]; 89 94 }; 90 95 91 96 /** ··· 132 127 char dummy_dst[MV_XOR_MIN_BYTE_COUNT]; 133 128 dma_addr_t dummy_src_addr, dummy_dst_addr; 134 129 u32 saved_config_reg, saved_int_mask_reg; 130 + 131 + struct mv_xor_device *xordev; 135 132 }; 136 133 137 134 /**
+16 -2
include/linux/mbus.h
··· 11 11 #ifndef __LINUX_MBUS_H 12 12 #define __LINUX_MBUS_H 13 13 14 + #include <linux/errno.h> 15 + 14 16 struct resource; 15 17 16 18 struct mbus_dram_target_info ··· 57 55 #ifdef CONFIG_PLAT_ORION 58 56 extern const struct mbus_dram_target_info *mv_mbus_dram_info(void); 59 57 extern const struct mbus_dram_target_info *mv_mbus_dram_info_nooverlap(void); 58 + int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, u8 *target, 59 + u8 *attr); 60 60 #else 61 61 static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void) 62 62 { ··· 68 64 { 69 65 return NULL; 70 66 } 67 + static inline int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, 68 + u8 *target, u8 *attr) 69 + { 70 + /* 71 + * On all ARM32 MVEBU platforms with MBus support, this stub 72 + * function will not get called. The real function from the 73 + * MBus driver is called instead. ARM64 MVEBU platforms like 74 + * the Armada 3700 could use the mv_xor device driver which calls 75 + * into this function 76 + */ 77 + return -EINVAL; 78 + } 71 79 #endif 72 80 73 81 int mvebu_mbus_save_cpu_target(u32 __iomem *store_addr); 74 82 void mvebu_mbus_get_pcie_mem_aperture(struct resource *res); 75 83 void mvebu_mbus_get_pcie_io_aperture(struct resource *res); 76 84 int mvebu_mbus_get_dram_win_info(phys_addr_t phyaddr, u8 *target, u8 *attr); 77 - int mvebu_mbus_get_io_win_info(phys_addr_t phyaddr, u32 *size, u8 *target, 78 - u8 *attr); 79 85 int mvebu_mbus_add_window_remap_by_id(unsigned int target, 80 86 unsigned int attribute, 81 87 phys_addr_t base, size_t size,