1ff7b0479SSaeed Bishara /* 2ff7b0479SSaeed Bishara * offload engine driver for the Marvell XOR engine 3ff7b0479SSaeed Bishara * Copyright (C) 2007, 2008, Marvell International Ltd. 4ff7b0479SSaeed Bishara * 5ff7b0479SSaeed Bishara * This program is free software; you can redistribute it and/or modify it 6ff7b0479SSaeed Bishara * under the terms and conditions of the GNU General Public License, 7ff7b0479SSaeed Bishara * version 2, as published by the Free Software Foundation. 8ff7b0479SSaeed Bishara * 9ff7b0479SSaeed Bishara * This program is distributed in the hope it will be useful, but WITHOUT 10ff7b0479SSaeed Bishara * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11ff7b0479SSaeed Bishara * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12ff7b0479SSaeed Bishara * more details. 13ff7b0479SSaeed Bishara * 14ff7b0479SSaeed Bishara * You should have received a copy of the GNU General Public License along with 15ff7b0479SSaeed Bishara * this program; if not, write to the Free Software Foundation, Inc., 16ff7b0479SSaeed Bishara * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17ff7b0479SSaeed Bishara */ 18ff7b0479SSaeed Bishara 19ff7b0479SSaeed Bishara #include <linux/init.h> 20ff7b0479SSaeed Bishara #include <linux/module.h> 215a0e3ad6STejun Heo #include <linux/slab.h> 22ff7b0479SSaeed Bishara #include <linux/delay.h> 23ff7b0479SSaeed Bishara #include <linux/dma-mapping.h> 24ff7b0479SSaeed Bishara #include <linux/spinlock.h> 25ff7b0479SSaeed Bishara #include <linux/interrupt.h> 26ff7b0479SSaeed Bishara #include <linux/platform_device.h> 27ff7b0479SSaeed Bishara #include <linux/memory.h> 28c510182bSAndrew Lunn #include <linux/clk.h> 29f7d12ef5SThomas Petazzoni #include <linux/of.h> 30f7d12ef5SThomas Petazzoni #include <linux/of_irq.h> 31f7d12ef5SThomas Petazzoni #include <linux/irqdomain.h> 32c02cecb9SArnd Bergmann #include <linux/platform_data/dma-mv_xor.h> 33d2ebfb33SRussell King - ARM Linux 34d2ebfb33SRussell King - ARM Linux #include "dmaengine.h" 35ff7b0479SSaeed Bishara #include "mv_xor.h" 36ff7b0479SSaeed Bishara 37ff7b0479SSaeed Bishara static void mv_xor_issue_pending(struct dma_chan *chan); 38ff7b0479SSaeed Bishara 39ff7b0479SSaeed Bishara #define to_mv_xor_chan(chan) \ 4098817b99SThomas Petazzoni container_of(chan, struct mv_xor_chan, dmachan) 41ff7b0479SSaeed Bishara 42ff7b0479SSaeed Bishara #define to_mv_xor_slot(tx) \ 43ff7b0479SSaeed Bishara container_of(tx, struct mv_xor_desc_slot, async_tx) 44ff7b0479SSaeed Bishara 45c98c1781SThomas Petazzoni #define mv_chan_to_devp(chan) \ 461ef48a26SThomas Petazzoni ((chan)->dmadev.dev) 47c98c1781SThomas Petazzoni 48*dfc97661SLior Amsalem static void mv_desc_init(struct mv_xor_desc_slot *desc, 49*dfc97661SLior Amsalem dma_addr_t addr, u32 byte_count) 50ff7b0479SSaeed Bishara { 51ff7b0479SSaeed Bishara struct mv_xor_desc *hw_desc = desc->hw_desc; 52ff7b0479SSaeed Bishara 53ff7b0479SSaeed Bishara hw_desc->status = (1 << 31); 54ff7b0479SSaeed Bishara hw_desc->phy_next_desc = 0; 55ff7b0479SSaeed Bishara hw_desc->desc_command = (1 << 31); 56*dfc97661SLior Amsalem hw_desc->phy_dest_addr = addr; 57ff7b0479SSaeed Bishara hw_desc->byte_count = byte_count; 58ff7b0479SSaeed Bishara } 59ff7b0479SSaeed Bishara 60ff7b0479SSaeed Bishara static void mv_desc_set_next_desc(struct mv_xor_desc_slot *desc, 61ff7b0479SSaeed Bishara u32 next_desc_addr) 62ff7b0479SSaeed Bishara { 63ff7b0479SSaeed Bishara struct mv_xor_desc *hw_desc = desc->hw_desc; 64ff7b0479SSaeed Bishara BUG_ON(hw_desc->phy_next_desc); 65ff7b0479SSaeed Bishara hw_desc->phy_next_desc = next_desc_addr; 66ff7b0479SSaeed Bishara } 67ff7b0479SSaeed Bishara 68ff7b0479SSaeed Bishara static void mv_desc_clear_next_desc(struct mv_xor_desc_slot *desc) 69ff7b0479SSaeed Bishara { 70ff7b0479SSaeed Bishara struct mv_xor_desc *hw_desc = desc->hw_desc; 71ff7b0479SSaeed Bishara hw_desc->phy_next_desc = 0; 72ff7b0479SSaeed Bishara } 73ff7b0479SSaeed Bishara 74ff7b0479SSaeed Bishara static void mv_desc_set_src_addr(struct mv_xor_desc_slot *desc, 75ff7b0479SSaeed Bishara int index, dma_addr_t addr) 76ff7b0479SSaeed Bishara { 77ff7b0479SSaeed Bishara struct mv_xor_desc *hw_desc = desc->hw_desc; 78e03bc654SThomas Petazzoni hw_desc->phy_src_addr[mv_phy_src_idx(index)] = addr; 79ff7b0479SSaeed Bishara if (desc->type == DMA_XOR) 80ff7b0479SSaeed Bishara hw_desc->desc_command |= (1 << index); 81ff7b0479SSaeed Bishara } 82ff7b0479SSaeed Bishara 83ff7b0479SSaeed Bishara static u32 mv_chan_get_current_desc(struct mv_xor_chan *chan) 84ff7b0479SSaeed Bishara { 855733c38aSThomas Petazzoni return readl_relaxed(XOR_CURR_DESC(chan)); 86ff7b0479SSaeed Bishara } 87ff7b0479SSaeed Bishara 88ff7b0479SSaeed Bishara static void mv_chan_set_next_descriptor(struct mv_xor_chan *chan, 89ff7b0479SSaeed Bishara u32 next_desc_addr) 90ff7b0479SSaeed Bishara { 915733c38aSThomas Petazzoni writel_relaxed(next_desc_addr, XOR_NEXT_DESC(chan)); 92ff7b0479SSaeed Bishara } 93ff7b0479SSaeed Bishara 94ff7b0479SSaeed Bishara static void mv_chan_unmask_interrupts(struct mv_xor_chan *chan) 95ff7b0479SSaeed Bishara { 965733c38aSThomas Petazzoni u32 val = readl_relaxed(XOR_INTR_MASK(chan)); 97ff7b0479SSaeed Bishara val |= XOR_INTR_MASK_VALUE << (chan->idx * 16); 985733c38aSThomas Petazzoni writel_relaxed(val, XOR_INTR_MASK(chan)); 99ff7b0479SSaeed Bishara } 100ff7b0479SSaeed Bishara 101ff7b0479SSaeed Bishara static u32 mv_chan_get_intr_cause(struct mv_xor_chan *chan) 102ff7b0479SSaeed Bishara { 1035733c38aSThomas Petazzoni u32 intr_cause = readl_relaxed(XOR_INTR_CAUSE(chan)); 104ff7b0479SSaeed Bishara intr_cause = (intr_cause >> (chan->idx * 16)) & 0xFFFF; 105ff7b0479SSaeed Bishara return intr_cause; 106ff7b0479SSaeed Bishara } 107ff7b0479SSaeed Bishara 108ff7b0479SSaeed Bishara static int mv_is_err_intr(u32 intr_cause) 109ff7b0479SSaeed Bishara { 110ff7b0479SSaeed Bishara if (intr_cause & ((1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9))) 111ff7b0479SSaeed Bishara return 1; 112ff7b0479SSaeed Bishara 113ff7b0479SSaeed Bishara return 0; 114ff7b0479SSaeed Bishara } 115ff7b0479SSaeed Bishara 116ff7b0479SSaeed Bishara static void mv_xor_device_clear_eoc_cause(struct mv_xor_chan *chan) 117ff7b0479SSaeed Bishara { 11886363682SSimon Guinot u32 val = ~(1 << (chan->idx * 16)); 119c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(chan), "%s, val 0x%08x\n", __func__, val); 1205733c38aSThomas Petazzoni writel_relaxed(val, XOR_INTR_CAUSE(chan)); 121ff7b0479SSaeed Bishara } 122ff7b0479SSaeed Bishara 123ff7b0479SSaeed Bishara static void mv_xor_device_clear_err_status(struct mv_xor_chan *chan) 124ff7b0479SSaeed Bishara { 125ff7b0479SSaeed Bishara u32 val = 0xFFFF0000 >> (chan->idx * 16); 1265733c38aSThomas Petazzoni writel_relaxed(val, XOR_INTR_CAUSE(chan)); 127ff7b0479SSaeed Bishara } 128ff7b0479SSaeed Bishara 129ff7b0479SSaeed Bishara static void mv_set_mode(struct mv_xor_chan *chan, 130ff7b0479SSaeed Bishara enum dma_transaction_type type) 131ff7b0479SSaeed Bishara { 132ff7b0479SSaeed Bishara u32 op_mode; 1335733c38aSThomas Petazzoni u32 config = readl_relaxed(XOR_CONFIG(chan)); 134ff7b0479SSaeed Bishara 135ff7b0479SSaeed Bishara switch (type) { 136ff7b0479SSaeed Bishara case DMA_XOR: 137ff7b0479SSaeed Bishara op_mode = XOR_OPERATION_MODE_XOR; 138ff7b0479SSaeed Bishara break; 139ff7b0479SSaeed Bishara case DMA_MEMCPY: 140ff7b0479SSaeed Bishara op_mode = XOR_OPERATION_MODE_MEMCPY; 141ff7b0479SSaeed Bishara break; 142ff7b0479SSaeed Bishara default: 143c98c1781SThomas Petazzoni dev_err(mv_chan_to_devp(chan), 1441ba151cdSJoe Perches "error: unsupported operation %d\n", 145ff7b0479SSaeed Bishara type); 146ff7b0479SSaeed Bishara BUG(); 147ff7b0479SSaeed Bishara return; 148ff7b0479SSaeed Bishara } 149ff7b0479SSaeed Bishara 150ff7b0479SSaeed Bishara config &= ~0x7; 151ff7b0479SSaeed Bishara config |= op_mode; 152e03bc654SThomas Petazzoni 153e03bc654SThomas Petazzoni #if defined(__BIG_ENDIAN) 154e03bc654SThomas Petazzoni config |= XOR_DESCRIPTOR_SWAP; 155e03bc654SThomas Petazzoni #else 156e03bc654SThomas Petazzoni config &= ~XOR_DESCRIPTOR_SWAP; 157e03bc654SThomas Petazzoni #endif 158e03bc654SThomas Petazzoni 1595733c38aSThomas Petazzoni writel_relaxed(config, XOR_CONFIG(chan)); 160ff7b0479SSaeed Bishara chan->current_type = type; 161ff7b0479SSaeed Bishara } 162ff7b0479SSaeed Bishara 163ff7b0479SSaeed Bishara static void mv_chan_activate(struct mv_xor_chan *chan) 164ff7b0479SSaeed Bishara { 165c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(chan), " activate chan.\n"); 1665a9a55bfSEzequiel Garcia 1675a9a55bfSEzequiel Garcia /* writel ensures all descriptors are flushed before activation */ 1685a9a55bfSEzequiel Garcia writel(BIT(0), XOR_ACTIVATION(chan)); 169ff7b0479SSaeed Bishara } 170ff7b0479SSaeed Bishara 171ff7b0479SSaeed Bishara static char mv_chan_is_busy(struct mv_xor_chan *chan) 172ff7b0479SSaeed Bishara { 1735733c38aSThomas Petazzoni u32 state = readl_relaxed(XOR_ACTIVATION(chan)); 174ff7b0479SSaeed Bishara 175ff7b0479SSaeed Bishara state = (state >> 4) & 0x3; 176ff7b0479SSaeed Bishara 177ff7b0479SSaeed Bishara return (state == 1) ? 1 : 0; 178ff7b0479SSaeed Bishara } 179ff7b0479SSaeed Bishara 180ff7b0479SSaeed Bishara /** 181ff7b0479SSaeed Bishara * mv_xor_free_slots - flags descriptor slots for reuse 182ff7b0479SSaeed Bishara * @slot: Slot to free 183ff7b0479SSaeed Bishara * Caller must hold &mv_chan->lock while calling this function 184ff7b0479SSaeed Bishara */ 185ff7b0479SSaeed Bishara static void mv_xor_free_slots(struct mv_xor_chan *mv_chan, 186ff7b0479SSaeed Bishara struct mv_xor_desc_slot *slot) 187ff7b0479SSaeed Bishara { 188c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), "%s %d slot %p\n", 189ff7b0479SSaeed Bishara __func__, __LINE__, slot); 190ff7b0479SSaeed Bishara 191*dfc97661SLior Amsalem slot->slot_used = 0; 192ff7b0479SSaeed Bishara 193ff7b0479SSaeed Bishara } 194ff7b0479SSaeed Bishara 195ff7b0479SSaeed Bishara /* 196ff7b0479SSaeed Bishara * mv_xor_start_new_chain - program the engine to operate on new chain headed by 197ff7b0479SSaeed Bishara * sw_desc 198ff7b0479SSaeed Bishara * Caller must hold &mv_chan->lock while calling this function 199ff7b0479SSaeed Bishara */ 200ff7b0479SSaeed Bishara static void mv_xor_start_new_chain(struct mv_xor_chan *mv_chan, 201ff7b0479SSaeed Bishara struct mv_xor_desc_slot *sw_desc) 202ff7b0479SSaeed Bishara { 203c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), "%s %d: sw_desc %p\n", 204ff7b0479SSaeed Bishara __func__, __LINE__, sw_desc); 205ff7b0479SSaeed Bishara 206ff7b0479SSaeed Bishara /* set the hardware chain */ 207ff7b0479SSaeed Bishara mv_chan_set_next_descriptor(mv_chan, sw_desc->async_tx.phys); 20848a9db46SBartlomiej Zolnierkiewicz 209*dfc97661SLior Amsalem mv_chan->pending++; 21098817b99SThomas Petazzoni mv_xor_issue_pending(&mv_chan->dmachan); 211ff7b0479SSaeed Bishara } 212ff7b0479SSaeed Bishara 213ff7b0479SSaeed Bishara static dma_cookie_t 214ff7b0479SSaeed Bishara mv_xor_run_tx_complete_actions(struct mv_xor_desc_slot *desc, 215ff7b0479SSaeed Bishara struct mv_xor_chan *mv_chan, dma_cookie_t cookie) 216ff7b0479SSaeed Bishara { 217ff7b0479SSaeed Bishara BUG_ON(desc->async_tx.cookie < 0); 218ff7b0479SSaeed Bishara 219ff7b0479SSaeed Bishara if (desc->async_tx.cookie > 0) { 220ff7b0479SSaeed Bishara cookie = desc->async_tx.cookie; 221ff7b0479SSaeed Bishara 222ff7b0479SSaeed Bishara /* call the callback (must not sleep or submit new 223ff7b0479SSaeed Bishara * operations to this channel) 224ff7b0479SSaeed Bishara */ 225ff7b0479SSaeed Bishara if (desc->async_tx.callback) 226ff7b0479SSaeed Bishara desc->async_tx.callback( 227ff7b0479SSaeed Bishara desc->async_tx.callback_param); 228ff7b0479SSaeed Bishara 229d38a8c62SDan Williams dma_descriptor_unmap(&desc->async_tx); 230ff7b0479SSaeed Bishara } 231ff7b0479SSaeed Bishara 232ff7b0479SSaeed Bishara /* run dependent operations */ 23307f2211eSDan Williams dma_run_dependencies(&desc->async_tx); 234ff7b0479SSaeed Bishara 235ff7b0479SSaeed Bishara return cookie; 236ff7b0479SSaeed Bishara } 237ff7b0479SSaeed Bishara 238ff7b0479SSaeed Bishara static int 239ff7b0479SSaeed Bishara mv_xor_clean_completed_slots(struct mv_xor_chan *mv_chan) 240ff7b0479SSaeed Bishara { 241ff7b0479SSaeed Bishara struct mv_xor_desc_slot *iter, *_iter; 242ff7b0479SSaeed Bishara 243c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), "%s %d\n", __func__, __LINE__); 244ff7b0479SSaeed Bishara list_for_each_entry_safe(iter, _iter, &mv_chan->completed_slots, 245ff7b0479SSaeed Bishara completed_node) { 246ff7b0479SSaeed Bishara 247ff7b0479SSaeed Bishara if (async_tx_test_ack(&iter->async_tx)) { 248ff7b0479SSaeed Bishara list_del(&iter->completed_node); 249ff7b0479SSaeed Bishara mv_xor_free_slots(mv_chan, iter); 250ff7b0479SSaeed Bishara } 251ff7b0479SSaeed Bishara } 252ff7b0479SSaeed Bishara return 0; 253ff7b0479SSaeed Bishara } 254ff7b0479SSaeed Bishara 255ff7b0479SSaeed Bishara static int 256ff7b0479SSaeed Bishara mv_xor_clean_slot(struct mv_xor_desc_slot *desc, 257ff7b0479SSaeed Bishara struct mv_xor_chan *mv_chan) 258ff7b0479SSaeed Bishara { 259c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), "%s %d: desc %p flags %d\n", 260ff7b0479SSaeed Bishara __func__, __LINE__, desc, desc->async_tx.flags); 261ff7b0479SSaeed Bishara list_del(&desc->chain_node); 262ff7b0479SSaeed Bishara /* the client is allowed to attach dependent operations 263ff7b0479SSaeed Bishara * until 'ack' is set 264ff7b0479SSaeed Bishara */ 265ff7b0479SSaeed Bishara if (!async_tx_test_ack(&desc->async_tx)) { 266ff7b0479SSaeed Bishara /* move this slot to the completed_slots */ 267ff7b0479SSaeed Bishara list_add_tail(&desc->completed_node, &mv_chan->completed_slots); 268ff7b0479SSaeed Bishara return 0; 269ff7b0479SSaeed Bishara } 270ff7b0479SSaeed Bishara 271ff7b0479SSaeed Bishara mv_xor_free_slots(mv_chan, desc); 272ff7b0479SSaeed Bishara return 0; 273ff7b0479SSaeed Bishara } 274ff7b0479SSaeed Bishara 275ff7b0479SSaeed Bishara static void __mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) 276ff7b0479SSaeed Bishara { 277ff7b0479SSaeed Bishara struct mv_xor_desc_slot *iter, *_iter; 278ff7b0479SSaeed Bishara dma_cookie_t cookie = 0; 279ff7b0479SSaeed Bishara int busy = mv_chan_is_busy(mv_chan); 280ff7b0479SSaeed Bishara u32 current_desc = mv_chan_get_current_desc(mv_chan); 281ff7b0479SSaeed Bishara int seen_current = 0; 282ff7b0479SSaeed Bishara 283c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), "%s %d\n", __func__, __LINE__); 284c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), "current_desc %x\n", current_desc); 285ff7b0479SSaeed Bishara mv_xor_clean_completed_slots(mv_chan); 286ff7b0479SSaeed Bishara 287ff7b0479SSaeed Bishara /* free completed slots from the chain starting with 288ff7b0479SSaeed Bishara * the oldest descriptor 289ff7b0479SSaeed Bishara */ 290ff7b0479SSaeed Bishara 291ff7b0479SSaeed Bishara list_for_each_entry_safe(iter, _iter, &mv_chan->chain, 292ff7b0479SSaeed Bishara chain_node) { 293ff7b0479SSaeed Bishara prefetch(_iter); 294ff7b0479SSaeed Bishara prefetch(&_iter->async_tx); 295ff7b0479SSaeed Bishara 296ff7b0479SSaeed Bishara /* do not advance past the current descriptor loaded into the 297ff7b0479SSaeed Bishara * hardware channel, subsequent descriptors are either in 298ff7b0479SSaeed Bishara * process or have not been submitted 299ff7b0479SSaeed Bishara */ 300ff7b0479SSaeed Bishara if (seen_current) 301ff7b0479SSaeed Bishara break; 302ff7b0479SSaeed Bishara 303ff7b0479SSaeed Bishara /* stop the search if we reach the current descriptor and the 304ff7b0479SSaeed Bishara * channel is busy 305ff7b0479SSaeed Bishara */ 306ff7b0479SSaeed Bishara if (iter->async_tx.phys == current_desc) { 307ff7b0479SSaeed Bishara seen_current = 1; 308ff7b0479SSaeed Bishara if (busy) 309ff7b0479SSaeed Bishara break; 310ff7b0479SSaeed Bishara } 311ff7b0479SSaeed Bishara 312ff7b0479SSaeed Bishara cookie = mv_xor_run_tx_complete_actions(iter, mv_chan, cookie); 313ff7b0479SSaeed Bishara 314ff7b0479SSaeed Bishara if (mv_xor_clean_slot(iter, mv_chan)) 315ff7b0479SSaeed Bishara break; 316ff7b0479SSaeed Bishara } 317ff7b0479SSaeed Bishara 318ff7b0479SSaeed Bishara if ((busy == 0) && !list_empty(&mv_chan->chain)) { 319ff7b0479SSaeed Bishara struct mv_xor_desc_slot *chain_head; 320ff7b0479SSaeed Bishara chain_head = list_entry(mv_chan->chain.next, 321ff7b0479SSaeed Bishara struct mv_xor_desc_slot, 322ff7b0479SSaeed Bishara chain_node); 323ff7b0479SSaeed Bishara 324ff7b0479SSaeed Bishara mv_xor_start_new_chain(mv_chan, chain_head); 325ff7b0479SSaeed Bishara } 326ff7b0479SSaeed Bishara 327ff7b0479SSaeed Bishara if (cookie > 0) 32898817b99SThomas Petazzoni mv_chan->dmachan.completed_cookie = cookie; 329ff7b0479SSaeed Bishara } 330ff7b0479SSaeed Bishara 331ff7b0479SSaeed Bishara static void 332ff7b0479SSaeed Bishara mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) 333ff7b0479SSaeed Bishara { 334ff7b0479SSaeed Bishara spin_lock_bh(&mv_chan->lock); 335ff7b0479SSaeed Bishara __mv_xor_slot_cleanup(mv_chan); 336ff7b0479SSaeed Bishara spin_unlock_bh(&mv_chan->lock); 337ff7b0479SSaeed Bishara } 338ff7b0479SSaeed Bishara 339ff7b0479SSaeed Bishara static void mv_xor_tasklet(unsigned long data) 340ff7b0479SSaeed Bishara { 341ff7b0479SSaeed Bishara struct mv_xor_chan *chan = (struct mv_xor_chan *) data; 3428333f65eSSaeed Bishara mv_xor_slot_cleanup(chan); 343ff7b0479SSaeed Bishara } 344ff7b0479SSaeed Bishara 345ff7b0479SSaeed Bishara static struct mv_xor_desc_slot * 346*dfc97661SLior Amsalem mv_xor_alloc_slot(struct mv_xor_chan *mv_chan) 347ff7b0479SSaeed Bishara { 348*dfc97661SLior Amsalem struct mv_xor_desc_slot *iter, *_iter; 349*dfc97661SLior Amsalem int retry = 0; 350ff7b0479SSaeed Bishara 351ff7b0479SSaeed Bishara /* start search from the last allocated descrtiptor 352ff7b0479SSaeed Bishara * if a contiguous allocation can not be found start searching 353ff7b0479SSaeed Bishara * from the beginning of the list 354ff7b0479SSaeed Bishara */ 355ff7b0479SSaeed Bishara retry: 356ff7b0479SSaeed Bishara if (retry == 0) 357ff7b0479SSaeed Bishara iter = mv_chan->last_used; 358ff7b0479SSaeed Bishara else 359ff7b0479SSaeed Bishara iter = list_entry(&mv_chan->all_slots, 360ff7b0479SSaeed Bishara struct mv_xor_desc_slot, 361ff7b0479SSaeed Bishara slot_node); 362ff7b0479SSaeed Bishara 363ff7b0479SSaeed Bishara list_for_each_entry_safe_continue( 364ff7b0479SSaeed Bishara iter, _iter, &mv_chan->all_slots, slot_node) { 365*dfc97661SLior Amsalem 366ff7b0479SSaeed Bishara prefetch(_iter); 367ff7b0479SSaeed Bishara prefetch(&_iter->async_tx); 368*dfc97661SLior Amsalem if (iter->slot_used) { 369ff7b0479SSaeed Bishara /* give up after finding the first busy slot 370ff7b0479SSaeed Bishara * on the second pass through the list 371ff7b0479SSaeed Bishara */ 372ff7b0479SSaeed Bishara if (retry) 373ff7b0479SSaeed Bishara break; 374ff7b0479SSaeed Bishara continue; 375ff7b0479SSaeed Bishara } 376ff7b0479SSaeed Bishara 377*dfc97661SLior Amsalem /* pre-ack descriptor */ 378ff7b0479SSaeed Bishara async_tx_ack(&iter->async_tx); 379ff7b0479SSaeed Bishara 380*dfc97661SLior Amsalem iter->slot_used = 1; 381*dfc97661SLior Amsalem INIT_LIST_HEAD(&iter->chain_node); 382*dfc97661SLior Amsalem iter->async_tx.cookie = -EBUSY; 383*dfc97661SLior Amsalem mv_chan->last_used = iter; 384*dfc97661SLior Amsalem mv_desc_clear_next_desc(iter); 385*dfc97661SLior Amsalem 386*dfc97661SLior Amsalem return iter; 387*dfc97661SLior Amsalem 388ff7b0479SSaeed Bishara } 389ff7b0479SSaeed Bishara if (!retry++) 390ff7b0479SSaeed Bishara goto retry; 391ff7b0479SSaeed Bishara 392ff7b0479SSaeed Bishara /* try to free some slots if the allocation fails */ 393ff7b0479SSaeed Bishara tasklet_schedule(&mv_chan->irq_tasklet); 394ff7b0479SSaeed Bishara 395ff7b0479SSaeed Bishara return NULL; 396ff7b0479SSaeed Bishara } 397ff7b0479SSaeed Bishara 398ff7b0479SSaeed Bishara /************************ DMA engine API functions ****************************/ 399ff7b0479SSaeed Bishara static dma_cookie_t 400ff7b0479SSaeed Bishara mv_xor_tx_submit(struct dma_async_tx_descriptor *tx) 401ff7b0479SSaeed Bishara { 402ff7b0479SSaeed Bishara struct mv_xor_desc_slot *sw_desc = to_mv_xor_slot(tx); 403ff7b0479SSaeed Bishara struct mv_xor_chan *mv_chan = to_mv_xor_chan(tx->chan); 404*dfc97661SLior Amsalem struct mv_xor_desc_slot *old_chain_tail; 405ff7b0479SSaeed Bishara dma_cookie_t cookie; 406ff7b0479SSaeed Bishara int new_hw_chain = 1; 407ff7b0479SSaeed Bishara 408c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), 409ff7b0479SSaeed Bishara "%s sw_desc %p: async_tx %p\n", 410ff7b0479SSaeed Bishara __func__, sw_desc, &sw_desc->async_tx); 411ff7b0479SSaeed Bishara 412ff7b0479SSaeed Bishara spin_lock_bh(&mv_chan->lock); 413884485e1SRussell King - ARM Linux cookie = dma_cookie_assign(tx); 414ff7b0479SSaeed Bishara 415ff7b0479SSaeed Bishara if (list_empty(&mv_chan->chain)) 416*dfc97661SLior Amsalem list_add_tail(&sw_desc->chain_node, &mv_chan->chain); 417ff7b0479SSaeed Bishara else { 418ff7b0479SSaeed Bishara new_hw_chain = 0; 419ff7b0479SSaeed Bishara 420ff7b0479SSaeed Bishara old_chain_tail = list_entry(mv_chan->chain.prev, 421ff7b0479SSaeed Bishara struct mv_xor_desc_slot, 422ff7b0479SSaeed Bishara chain_node); 423*dfc97661SLior Amsalem list_add_tail(&sw_desc->chain_node, &mv_chan->chain); 424ff7b0479SSaeed Bishara 42531fd8f5bSOlof Johansson dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %pa\n", 42631fd8f5bSOlof Johansson &old_chain_tail->async_tx.phys); 427ff7b0479SSaeed Bishara 428ff7b0479SSaeed Bishara /* fix up the hardware chain */ 429*dfc97661SLior Amsalem mv_desc_set_next_desc(old_chain_tail, sw_desc->async_tx.phys); 430ff7b0479SSaeed Bishara 431ff7b0479SSaeed Bishara /* if the channel is not busy */ 432ff7b0479SSaeed Bishara if (!mv_chan_is_busy(mv_chan)) { 433ff7b0479SSaeed Bishara u32 current_desc = mv_chan_get_current_desc(mv_chan); 434ff7b0479SSaeed Bishara /* 435ff7b0479SSaeed Bishara * and the curren desc is the end of the chain before 436ff7b0479SSaeed Bishara * the append, then we need to start the channel 437ff7b0479SSaeed Bishara */ 438ff7b0479SSaeed Bishara if (current_desc == old_chain_tail->async_tx.phys) 439ff7b0479SSaeed Bishara new_hw_chain = 1; 440ff7b0479SSaeed Bishara } 441ff7b0479SSaeed Bishara } 442ff7b0479SSaeed Bishara 443ff7b0479SSaeed Bishara if (new_hw_chain) 444*dfc97661SLior Amsalem mv_xor_start_new_chain(mv_chan, sw_desc); 445ff7b0479SSaeed Bishara 446ff7b0479SSaeed Bishara spin_unlock_bh(&mv_chan->lock); 447ff7b0479SSaeed Bishara 448ff7b0479SSaeed Bishara return cookie; 449ff7b0479SSaeed Bishara } 450ff7b0479SSaeed Bishara 451ff7b0479SSaeed Bishara /* returns the number of allocated descriptors */ 452aa1e6f1aSDan Williams static int mv_xor_alloc_chan_resources(struct dma_chan *chan) 453ff7b0479SSaeed Bishara { 45431fd8f5bSOlof Johansson void *virt_desc; 45531fd8f5bSOlof Johansson dma_addr_t dma_desc; 456ff7b0479SSaeed Bishara int idx; 457ff7b0479SSaeed Bishara struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); 458ff7b0479SSaeed Bishara struct mv_xor_desc_slot *slot = NULL; 459b503fa01SThomas Petazzoni int num_descs_in_pool = MV_XOR_POOL_SIZE/MV_XOR_SLOT_SIZE; 460ff7b0479SSaeed Bishara 461ff7b0479SSaeed Bishara /* Allocate descriptor slots */ 462ff7b0479SSaeed Bishara idx = mv_chan->slots_allocated; 463ff7b0479SSaeed Bishara while (idx < num_descs_in_pool) { 464ff7b0479SSaeed Bishara slot = kzalloc(sizeof(*slot), GFP_KERNEL); 465ff7b0479SSaeed Bishara if (!slot) { 466b8291ddeSEzequiel Garcia dev_info(mv_chan_to_devp(mv_chan), 467b8291ddeSEzequiel Garcia "channel only initialized %d descriptor slots", 468b8291ddeSEzequiel Garcia idx); 469ff7b0479SSaeed Bishara break; 470ff7b0479SSaeed Bishara } 47131fd8f5bSOlof Johansson virt_desc = mv_chan->dma_desc_pool_virt; 47231fd8f5bSOlof Johansson slot->hw_desc = virt_desc + idx * MV_XOR_SLOT_SIZE; 473ff7b0479SSaeed Bishara 474ff7b0479SSaeed Bishara dma_async_tx_descriptor_init(&slot->async_tx, chan); 475ff7b0479SSaeed Bishara slot->async_tx.tx_submit = mv_xor_tx_submit; 476ff7b0479SSaeed Bishara INIT_LIST_HEAD(&slot->chain_node); 477ff7b0479SSaeed Bishara INIT_LIST_HEAD(&slot->slot_node); 47831fd8f5bSOlof Johansson dma_desc = mv_chan->dma_desc_pool; 47931fd8f5bSOlof Johansson slot->async_tx.phys = dma_desc + idx * MV_XOR_SLOT_SIZE; 480ff7b0479SSaeed Bishara slot->idx = idx++; 481ff7b0479SSaeed Bishara 482ff7b0479SSaeed Bishara spin_lock_bh(&mv_chan->lock); 483ff7b0479SSaeed Bishara mv_chan->slots_allocated = idx; 484ff7b0479SSaeed Bishara list_add_tail(&slot->slot_node, &mv_chan->all_slots); 485ff7b0479SSaeed Bishara spin_unlock_bh(&mv_chan->lock); 486ff7b0479SSaeed Bishara } 487ff7b0479SSaeed Bishara 488ff7b0479SSaeed Bishara if (mv_chan->slots_allocated && !mv_chan->last_used) 489ff7b0479SSaeed Bishara mv_chan->last_used = list_entry(mv_chan->all_slots.next, 490ff7b0479SSaeed Bishara struct mv_xor_desc_slot, 491ff7b0479SSaeed Bishara slot_node); 492ff7b0479SSaeed Bishara 493c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), 494ff7b0479SSaeed Bishara "allocated %d descriptor slots last_used: %p\n", 495ff7b0479SSaeed Bishara mv_chan->slots_allocated, mv_chan->last_used); 496ff7b0479SSaeed Bishara 497ff7b0479SSaeed Bishara return mv_chan->slots_allocated ? : -ENOMEM; 498ff7b0479SSaeed Bishara } 499ff7b0479SSaeed Bishara 500ff7b0479SSaeed Bishara static struct dma_async_tx_descriptor * 501ff7b0479SSaeed Bishara mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, 502ff7b0479SSaeed Bishara unsigned int src_cnt, size_t len, unsigned long flags) 503ff7b0479SSaeed Bishara { 504ff7b0479SSaeed Bishara struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); 505*dfc97661SLior Amsalem struct mv_xor_desc_slot *sw_desc; 506ff7b0479SSaeed Bishara 507ff7b0479SSaeed Bishara if (unlikely(len < MV_XOR_MIN_BYTE_COUNT)) 508ff7b0479SSaeed Bishara return NULL; 509ff7b0479SSaeed Bishara 5107912d300SColy Li BUG_ON(len > MV_XOR_MAX_BYTE_COUNT); 511ff7b0479SSaeed Bishara 512c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), 51331fd8f5bSOlof Johansson "%s src_cnt: %d len: %u dest %pad flags: %ld\n", 51431fd8f5bSOlof Johansson __func__, src_cnt, len, &dest, flags); 515ff7b0479SSaeed Bishara 516ff7b0479SSaeed Bishara spin_lock_bh(&mv_chan->lock); 517*dfc97661SLior Amsalem sw_desc = mv_xor_alloc_slot(mv_chan); 518ff7b0479SSaeed Bishara if (sw_desc) { 519ff7b0479SSaeed Bishara sw_desc->type = DMA_XOR; 520ff7b0479SSaeed Bishara sw_desc->async_tx.flags = flags; 521*dfc97661SLior Amsalem mv_desc_init(sw_desc, dest, len); 522ff7b0479SSaeed Bishara sw_desc->unmap_src_cnt = src_cnt; 523ff7b0479SSaeed Bishara sw_desc->unmap_len = len; 524ff7b0479SSaeed Bishara while (src_cnt--) 525*dfc97661SLior Amsalem mv_desc_set_src_addr(sw_desc, src_cnt, src[src_cnt]); 526ff7b0479SSaeed Bishara } 527ff7b0479SSaeed Bishara spin_unlock_bh(&mv_chan->lock); 528c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), 529ff7b0479SSaeed Bishara "%s sw_desc %p async_tx %p \n", 530ff7b0479SSaeed Bishara __func__, sw_desc, &sw_desc->async_tx); 531ff7b0479SSaeed Bishara return sw_desc ? &sw_desc->async_tx : NULL; 532ff7b0479SSaeed Bishara } 533ff7b0479SSaeed Bishara 5343e4f52e2SLior Amsalem static struct dma_async_tx_descriptor * 5353e4f52e2SLior Amsalem mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, 5363e4f52e2SLior Amsalem size_t len, unsigned long flags) 5373e4f52e2SLior Amsalem { 5383e4f52e2SLior Amsalem /* 5393e4f52e2SLior Amsalem * A MEMCPY operation is identical to an XOR operation with only 5403e4f52e2SLior Amsalem * a single source address. 5413e4f52e2SLior Amsalem */ 5423e4f52e2SLior Amsalem return mv_xor_prep_dma_xor(chan, dest, &src, 1, len, flags); 5433e4f52e2SLior Amsalem } 5443e4f52e2SLior Amsalem 545ff7b0479SSaeed Bishara static void mv_xor_free_chan_resources(struct dma_chan *chan) 546ff7b0479SSaeed Bishara { 547ff7b0479SSaeed Bishara struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); 548ff7b0479SSaeed Bishara struct mv_xor_desc_slot *iter, *_iter; 549ff7b0479SSaeed Bishara int in_use_descs = 0; 550ff7b0479SSaeed Bishara 551ff7b0479SSaeed Bishara mv_xor_slot_cleanup(mv_chan); 552ff7b0479SSaeed Bishara 553ff7b0479SSaeed Bishara spin_lock_bh(&mv_chan->lock); 554ff7b0479SSaeed Bishara list_for_each_entry_safe(iter, _iter, &mv_chan->chain, 555ff7b0479SSaeed Bishara chain_node) { 556ff7b0479SSaeed Bishara in_use_descs++; 557ff7b0479SSaeed Bishara list_del(&iter->chain_node); 558ff7b0479SSaeed Bishara } 559ff7b0479SSaeed Bishara list_for_each_entry_safe(iter, _iter, &mv_chan->completed_slots, 560ff7b0479SSaeed Bishara completed_node) { 561ff7b0479SSaeed Bishara in_use_descs++; 562ff7b0479SSaeed Bishara list_del(&iter->completed_node); 563ff7b0479SSaeed Bishara } 564ff7b0479SSaeed Bishara list_for_each_entry_safe_reverse( 565ff7b0479SSaeed Bishara iter, _iter, &mv_chan->all_slots, slot_node) { 566ff7b0479SSaeed Bishara list_del(&iter->slot_node); 567ff7b0479SSaeed Bishara kfree(iter); 568ff7b0479SSaeed Bishara mv_chan->slots_allocated--; 569ff7b0479SSaeed Bishara } 570ff7b0479SSaeed Bishara mv_chan->last_used = NULL; 571ff7b0479SSaeed Bishara 572c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(mv_chan), "%s slots_allocated %d\n", 573ff7b0479SSaeed Bishara __func__, mv_chan->slots_allocated); 574ff7b0479SSaeed Bishara spin_unlock_bh(&mv_chan->lock); 575ff7b0479SSaeed Bishara 576ff7b0479SSaeed Bishara if (in_use_descs) 577c98c1781SThomas Petazzoni dev_err(mv_chan_to_devp(mv_chan), 578ff7b0479SSaeed Bishara "freeing %d in use descriptors!\n", in_use_descs); 579ff7b0479SSaeed Bishara } 580ff7b0479SSaeed Bishara 581ff7b0479SSaeed Bishara /** 58207934481SLinus Walleij * mv_xor_status - poll the status of an XOR transaction 583ff7b0479SSaeed Bishara * @chan: XOR channel handle 584ff7b0479SSaeed Bishara * @cookie: XOR transaction identifier 58507934481SLinus Walleij * @txstate: XOR transactions state holder (or NULL) 586ff7b0479SSaeed Bishara */ 58707934481SLinus Walleij static enum dma_status mv_xor_status(struct dma_chan *chan, 588ff7b0479SSaeed Bishara dma_cookie_t cookie, 58907934481SLinus Walleij struct dma_tx_state *txstate) 590ff7b0479SSaeed Bishara { 591ff7b0479SSaeed Bishara struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); 592ff7b0479SSaeed Bishara enum dma_status ret; 593ff7b0479SSaeed Bishara 59496a2af41SRussell King - ARM Linux ret = dma_cookie_status(chan, cookie, txstate); 595b3efb8fcSVinod Koul if (ret == DMA_COMPLETE) { 596ff7b0479SSaeed Bishara mv_xor_clean_completed_slots(mv_chan); 597ff7b0479SSaeed Bishara return ret; 598ff7b0479SSaeed Bishara } 599ff7b0479SSaeed Bishara mv_xor_slot_cleanup(mv_chan); 600ff7b0479SSaeed Bishara 60196a2af41SRussell King - ARM Linux return dma_cookie_status(chan, cookie, txstate); 602ff7b0479SSaeed Bishara } 603ff7b0479SSaeed Bishara 604ff7b0479SSaeed Bishara static void mv_dump_xor_regs(struct mv_xor_chan *chan) 605ff7b0479SSaeed Bishara { 606ff7b0479SSaeed Bishara u32 val; 607ff7b0479SSaeed Bishara 6085733c38aSThomas Petazzoni val = readl_relaxed(XOR_CONFIG(chan)); 6091ba151cdSJoe Perches dev_err(mv_chan_to_devp(chan), "config 0x%08x\n", val); 610ff7b0479SSaeed Bishara 6115733c38aSThomas Petazzoni val = readl_relaxed(XOR_ACTIVATION(chan)); 6121ba151cdSJoe Perches dev_err(mv_chan_to_devp(chan), "activation 0x%08x\n", val); 613ff7b0479SSaeed Bishara 6145733c38aSThomas Petazzoni val = readl_relaxed(XOR_INTR_CAUSE(chan)); 6151ba151cdSJoe Perches dev_err(mv_chan_to_devp(chan), "intr cause 0x%08x\n", val); 616ff7b0479SSaeed Bishara 6175733c38aSThomas Petazzoni val = readl_relaxed(XOR_INTR_MASK(chan)); 6181ba151cdSJoe Perches dev_err(mv_chan_to_devp(chan), "intr mask 0x%08x\n", val); 619ff7b0479SSaeed Bishara 6205733c38aSThomas Petazzoni val = readl_relaxed(XOR_ERROR_CAUSE(chan)); 6211ba151cdSJoe Perches dev_err(mv_chan_to_devp(chan), "error cause 0x%08x\n", val); 622ff7b0479SSaeed Bishara 6235733c38aSThomas Petazzoni val = readl_relaxed(XOR_ERROR_ADDR(chan)); 6241ba151cdSJoe Perches dev_err(mv_chan_to_devp(chan), "error addr 0x%08x\n", val); 625ff7b0479SSaeed Bishara } 626ff7b0479SSaeed Bishara 627ff7b0479SSaeed Bishara static void mv_xor_err_interrupt_handler(struct mv_xor_chan *chan, 628ff7b0479SSaeed Bishara u32 intr_cause) 629ff7b0479SSaeed Bishara { 630ff7b0479SSaeed Bishara if (intr_cause & (1 << 4)) { 631c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(chan), 632ff7b0479SSaeed Bishara "ignore this error\n"); 633ff7b0479SSaeed Bishara return; 634ff7b0479SSaeed Bishara } 635ff7b0479SSaeed Bishara 636c98c1781SThomas Petazzoni dev_err(mv_chan_to_devp(chan), 6371ba151cdSJoe Perches "error on chan %d. intr cause 0x%08x\n", 638ff7b0479SSaeed Bishara chan->idx, intr_cause); 639ff7b0479SSaeed Bishara 640ff7b0479SSaeed Bishara mv_dump_xor_regs(chan); 641ff7b0479SSaeed Bishara BUG(); 642ff7b0479SSaeed Bishara } 643ff7b0479SSaeed Bishara 644ff7b0479SSaeed Bishara static irqreturn_t mv_xor_interrupt_handler(int irq, void *data) 645ff7b0479SSaeed Bishara { 646ff7b0479SSaeed Bishara struct mv_xor_chan *chan = data; 647ff7b0479SSaeed Bishara u32 intr_cause = mv_chan_get_intr_cause(chan); 648ff7b0479SSaeed Bishara 649c98c1781SThomas Petazzoni dev_dbg(mv_chan_to_devp(chan), "intr cause %x\n", intr_cause); 650ff7b0479SSaeed Bishara 651ff7b0479SSaeed Bishara if (mv_is_err_intr(intr_cause)) 652ff7b0479SSaeed Bishara mv_xor_err_interrupt_handler(chan, intr_cause); 653ff7b0479SSaeed Bishara 654ff7b0479SSaeed Bishara tasklet_schedule(&chan->irq_tasklet); 655ff7b0479SSaeed Bishara 656ff7b0479SSaeed Bishara mv_xor_device_clear_eoc_cause(chan); 657ff7b0479SSaeed Bishara 658ff7b0479SSaeed Bishara return IRQ_HANDLED; 659ff7b0479SSaeed Bishara } 660ff7b0479SSaeed Bishara 661ff7b0479SSaeed Bishara static void mv_xor_issue_pending(struct dma_chan *chan) 662ff7b0479SSaeed Bishara { 663ff7b0479SSaeed Bishara struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); 664ff7b0479SSaeed Bishara 665ff7b0479SSaeed Bishara if (mv_chan->pending >= MV_XOR_THRESHOLD) { 666ff7b0479SSaeed Bishara mv_chan->pending = 0; 667ff7b0479SSaeed Bishara mv_chan_activate(mv_chan); 668ff7b0479SSaeed Bishara } 669ff7b0479SSaeed Bishara } 670ff7b0479SSaeed Bishara 671ff7b0479SSaeed Bishara /* 672ff7b0479SSaeed Bishara * Perform a transaction to verify the HW works. 673ff7b0479SSaeed Bishara */ 674ff7b0479SSaeed Bishara 675c2714334SLinus Torvalds static int mv_xor_memcpy_self_test(struct mv_xor_chan *mv_chan) 676ff7b0479SSaeed Bishara { 677ff7b0479SSaeed Bishara int i; 678ff7b0479SSaeed Bishara void *src, *dest; 679ff7b0479SSaeed Bishara dma_addr_t src_dma, dest_dma; 680ff7b0479SSaeed Bishara struct dma_chan *dma_chan; 681ff7b0479SSaeed Bishara dma_cookie_t cookie; 682ff7b0479SSaeed Bishara struct dma_async_tx_descriptor *tx; 683d16695a7SEzequiel Garcia struct dmaengine_unmap_data *unmap; 684ff7b0479SSaeed Bishara int err = 0; 685ff7b0479SSaeed Bishara 686d16695a7SEzequiel Garcia src = kmalloc(sizeof(u8) * PAGE_SIZE, GFP_KERNEL); 687ff7b0479SSaeed Bishara if (!src) 688ff7b0479SSaeed Bishara return -ENOMEM; 689ff7b0479SSaeed Bishara 690d16695a7SEzequiel Garcia dest = kzalloc(sizeof(u8) * PAGE_SIZE, GFP_KERNEL); 691ff7b0479SSaeed Bishara if (!dest) { 692ff7b0479SSaeed Bishara kfree(src); 693ff7b0479SSaeed Bishara return -ENOMEM; 694ff7b0479SSaeed Bishara } 695ff7b0479SSaeed Bishara 696ff7b0479SSaeed Bishara /* Fill in src buffer */ 697d16695a7SEzequiel Garcia for (i = 0; i < PAGE_SIZE; i++) 698ff7b0479SSaeed Bishara ((u8 *) src)[i] = (u8)i; 699ff7b0479SSaeed Bishara 700275cc0c8SThomas Petazzoni dma_chan = &mv_chan->dmachan; 701aa1e6f1aSDan Williams if (mv_xor_alloc_chan_resources(dma_chan) < 1) { 702ff7b0479SSaeed Bishara err = -ENODEV; 703ff7b0479SSaeed Bishara goto out; 704ff7b0479SSaeed Bishara } 705ff7b0479SSaeed Bishara 706d16695a7SEzequiel Garcia unmap = dmaengine_get_unmap_data(dma_chan->device->dev, 2, GFP_KERNEL); 707d16695a7SEzequiel Garcia if (!unmap) { 708d16695a7SEzequiel Garcia err = -ENOMEM; 709d16695a7SEzequiel Garcia goto free_resources; 710d16695a7SEzequiel Garcia } 711ff7b0479SSaeed Bishara 712d16695a7SEzequiel Garcia src_dma = dma_map_page(dma_chan->device->dev, virt_to_page(src), 0, 713d16695a7SEzequiel Garcia PAGE_SIZE, DMA_TO_DEVICE); 714d16695a7SEzequiel Garcia unmap->to_cnt = 1; 715d16695a7SEzequiel Garcia unmap->addr[0] = src_dma; 716d16695a7SEzequiel Garcia 717d16695a7SEzequiel Garcia dest_dma = dma_map_page(dma_chan->device->dev, virt_to_page(dest), 0, 718d16695a7SEzequiel Garcia PAGE_SIZE, DMA_FROM_DEVICE); 719d16695a7SEzequiel Garcia unmap->from_cnt = 1; 720d16695a7SEzequiel Garcia unmap->addr[1] = dest_dma; 721d16695a7SEzequiel Garcia 722d16695a7SEzequiel Garcia unmap->len = PAGE_SIZE; 723ff7b0479SSaeed Bishara 724ff7b0479SSaeed Bishara tx = mv_xor_prep_dma_memcpy(dma_chan, dest_dma, src_dma, 725d16695a7SEzequiel Garcia PAGE_SIZE, 0); 726ff7b0479SSaeed Bishara cookie = mv_xor_tx_submit(tx); 727ff7b0479SSaeed Bishara mv_xor_issue_pending(dma_chan); 728ff7b0479SSaeed Bishara async_tx_ack(tx); 729ff7b0479SSaeed Bishara msleep(1); 730ff7b0479SSaeed Bishara 73107934481SLinus Walleij if (mv_xor_status(dma_chan, cookie, NULL) != 732b3efb8fcSVinod Koul DMA_COMPLETE) { 733a3fc74bcSThomas Petazzoni dev_err(dma_chan->device->dev, 734ff7b0479SSaeed Bishara "Self-test copy timed out, disabling\n"); 735ff7b0479SSaeed Bishara err = -ENODEV; 736ff7b0479SSaeed Bishara goto free_resources; 737ff7b0479SSaeed Bishara } 738ff7b0479SSaeed Bishara 739c35064c4SThomas Petazzoni dma_sync_single_for_cpu(dma_chan->device->dev, dest_dma, 740d16695a7SEzequiel Garcia PAGE_SIZE, DMA_FROM_DEVICE); 741d16695a7SEzequiel Garcia if (memcmp(src, dest, PAGE_SIZE)) { 742a3fc74bcSThomas Petazzoni dev_err(dma_chan->device->dev, 743ff7b0479SSaeed Bishara "Self-test copy failed compare, disabling\n"); 744ff7b0479SSaeed Bishara err = -ENODEV; 745ff7b0479SSaeed Bishara goto free_resources; 746ff7b0479SSaeed Bishara } 747ff7b0479SSaeed Bishara 748ff7b0479SSaeed Bishara free_resources: 749d16695a7SEzequiel Garcia dmaengine_unmap_put(unmap); 750ff7b0479SSaeed Bishara mv_xor_free_chan_resources(dma_chan); 751ff7b0479SSaeed Bishara out: 752ff7b0479SSaeed Bishara kfree(src); 753ff7b0479SSaeed Bishara kfree(dest); 754ff7b0479SSaeed Bishara return err; 755ff7b0479SSaeed Bishara } 756ff7b0479SSaeed Bishara 757ff7b0479SSaeed Bishara #define MV_XOR_NUM_SRC_TEST 4 /* must be <= 15 */ 758463a1f8bSBill Pemberton static int 759275cc0c8SThomas Petazzoni mv_xor_xor_self_test(struct mv_xor_chan *mv_chan) 760ff7b0479SSaeed Bishara { 761ff7b0479SSaeed Bishara int i, src_idx; 762ff7b0479SSaeed Bishara struct page *dest; 763ff7b0479SSaeed Bishara struct page *xor_srcs[MV_XOR_NUM_SRC_TEST]; 764ff7b0479SSaeed Bishara dma_addr_t dma_srcs[MV_XOR_NUM_SRC_TEST]; 765ff7b0479SSaeed Bishara dma_addr_t dest_dma; 766ff7b0479SSaeed Bishara struct dma_async_tx_descriptor *tx; 767d16695a7SEzequiel Garcia struct dmaengine_unmap_data *unmap; 768ff7b0479SSaeed Bishara struct dma_chan *dma_chan; 769ff7b0479SSaeed Bishara dma_cookie_t cookie; 770ff7b0479SSaeed Bishara u8 cmp_byte = 0; 771ff7b0479SSaeed Bishara u32 cmp_word; 772ff7b0479SSaeed Bishara int err = 0; 773d16695a7SEzequiel Garcia int src_count = MV_XOR_NUM_SRC_TEST; 774ff7b0479SSaeed Bishara 775d16695a7SEzequiel Garcia for (src_idx = 0; src_idx < src_count; src_idx++) { 776ff7b0479SSaeed Bishara xor_srcs[src_idx] = alloc_page(GFP_KERNEL); 777a09b09aeSRoel Kluin if (!xor_srcs[src_idx]) { 778a09b09aeSRoel Kluin while (src_idx--) 779ff7b0479SSaeed Bishara __free_page(xor_srcs[src_idx]); 780ff7b0479SSaeed Bishara return -ENOMEM; 781ff7b0479SSaeed Bishara } 782ff7b0479SSaeed Bishara } 783ff7b0479SSaeed Bishara 784ff7b0479SSaeed Bishara dest = alloc_page(GFP_KERNEL); 785a09b09aeSRoel Kluin if (!dest) { 786a09b09aeSRoel Kluin while (src_idx--) 787ff7b0479SSaeed Bishara __free_page(xor_srcs[src_idx]); 788ff7b0479SSaeed Bishara return -ENOMEM; 789ff7b0479SSaeed Bishara } 790ff7b0479SSaeed Bishara 791ff7b0479SSaeed Bishara /* Fill in src buffers */ 792d16695a7SEzequiel Garcia for (src_idx = 0; src_idx < src_count; src_idx++) { 793ff7b0479SSaeed Bishara u8 *ptr = page_address(xor_srcs[src_idx]); 794ff7b0479SSaeed Bishara for (i = 0; i < PAGE_SIZE; i++) 795ff7b0479SSaeed Bishara ptr[i] = (1 << src_idx); 796ff7b0479SSaeed Bishara } 797ff7b0479SSaeed Bishara 798d16695a7SEzequiel Garcia for (src_idx = 0; src_idx < src_count; src_idx++) 799ff7b0479SSaeed Bishara cmp_byte ^= (u8) (1 << src_idx); 800ff7b0479SSaeed Bishara 801ff7b0479SSaeed Bishara cmp_word = (cmp_byte << 24) | (cmp_byte << 16) | 802ff7b0479SSaeed Bishara (cmp_byte << 8) | cmp_byte; 803ff7b0479SSaeed Bishara 804ff7b0479SSaeed Bishara memset(page_address(dest), 0, PAGE_SIZE); 805ff7b0479SSaeed Bishara 806275cc0c8SThomas Petazzoni dma_chan = &mv_chan->dmachan; 807aa1e6f1aSDan Williams if (mv_xor_alloc_chan_resources(dma_chan) < 1) { 808ff7b0479SSaeed Bishara err = -ENODEV; 809ff7b0479SSaeed Bishara goto out; 810ff7b0479SSaeed Bishara } 811ff7b0479SSaeed Bishara 812d16695a7SEzequiel Garcia unmap = dmaengine_get_unmap_data(dma_chan->device->dev, src_count + 1, 813d16695a7SEzequiel Garcia GFP_KERNEL); 814d16695a7SEzequiel Garcia if (!unmap) { 815d16695a7SEzequiel Garcia err = -ENOMEM; 816d16695a7SEzequiel Garcia goto free_resources; 817d16695a7SEzequiel Garcia } 818ff7b0479SSaeed Bishara 819d16695a7SEzequiel Garcia /* test xor */ 820d16695a7SEzequiel Garcia for (i = 0; i < src_count; i++) { 821d16695a7SEzequiel Garcia unmap->addr[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i], 822ff7b0479SSaeed Bishara 0, PAGE_SIZE, DMA_TO_DEVICE); 823d16695a7SEzequiel Garcia dma_srcs[i] = unmap->addr[i]; 824d16695a7SEzequiel Garcia unmap->to_cnt++; 825d16695a7SEzequiel Garcia } 826d16695a7SEzequiel Garcia 827d16695a7SEzequiel Garcia unmap->addr[src_count] = dma_map_page(dma_chan->device->dev, dest, 0, PAGE_SIZE, 828d16695a7SEzequiel Garcia DMA_FROM_DEVICE); 829d16695a7SEzequiel Garcia dest_dma = unmap->addr[src_count]; 830d16695a7SEzequiel Garcia unmap->from_cnt = 1; 831d16695a7SEzequiel Garcia unmap->len = PAGE_SIZE; 832ff7b0479SSaeed Bishara 833ff7b0479SSaeed Bishara tx = mv_xor_prep_dma_xor(dma_chan, dest_dma, dma_srcs, 834d16695a7SEzequiel Garcia src_count, PAGE_SIZE, 0); 835ff7b0479SSaeed Bishara 836ff7b0479SSaeed Bishara cookie = mv_xor_tx_submit(tx); 837ff7b0479SSaeed Bishara mv_xor_issue_pending(dma_chan); 838ff7b0479SSaeed Bishara async_tx_ack(tx); 839ff7b0479SSaeed Bishara msleep(8); 840ff7b0479SSaeed Bishara 84107934481SLinus Walleij if (mv_xor_status(dma_chan, cookie, NULL) != 842b3efb8fcSVinod Koul DMA_COMPLETE) { 843a3fc74bcSThomas Petazzoni dev_err(dma_chan->device->dev, 844ff7b0479SSaeed Bishara "Self-test xor timed out, disabling\n"); 845ff7b0479SSaeed Bishara err = -ENODEV; 846ff7b0479SSaeed Bishara goto free_resources; 847ff7b0479SSaeed Bishara } 848ff7b0479SSaeed Bishara 849c35064c4SThomas Petazzoni dma_sync_single_for_cpu(dma_chan->device->dev, dest_dma, 850ff7b0479SSaeed Bishara PAGE_SIZE, DMA_FROM_DEVICE); 851ff7b0479SSaeed Bishara for (i = 0; i < (PAGE_SIZE / sizeof(u32)); i++) { 852ff7b0479SSaeed Bishara u32 *ptr = page_address(dest); 853ff7b0479SSaeed Bishara if (ptr[i] != cmp_word) { 854a3fc74bcSThomas Petazzoni dev_err(dma_chan->device->dev, 8551ba151cdSJoe Perches "Self-test xor failed compare, disabling. index %d, data %x, expected %x\n", 8561ba151cdSJoe Perches i, ptr[i], cmp_word); 857ff7b0479SSaeed Bishara err = -ENODEV; 858ff7b0479SSaeed Bishara goto free_resources; 859ff7b0479SSaeed Bishara } 860ff7b0479SSaeed Bishara } 861ff7b0479SSaeed Bishara 862ff7b0479SSaeed Bishara free_resources: 863d16695a7SEzequiel Garcia dmaengine_unmap_put(unmap); 864ff7b0479SSaeed Bishara mv_xor_free_chan_resources(dma_chan); 865ff7b0479SSaeed Bishara out: 866d16695a7SEzequiel Garcia src_idx = src_count; 867ff7b0479SSaeed Bishara while (src_idx--) 868ff7b0479SSaeed Bishara __free_page(xor_srcs[src_idx]); 869ff7b0479SSaeed Bishara __free_page(dest); 870ff7b0479SSaeed Bishara return err; 871ff7b0479SSaeed Bishara } 872ff7b0479SSaeed Bishara 87334c93c86SAndrew Lunn /* This driver does not implement any of the optional DMA operations. */ 87434c93c86SAndrew Lunn static int 87534c93c86SAndrew Lunn mv_xor_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, 87634c93c86SAndrew Lunn unsigned long arg) 877ff7b0479SSaeed Bishara { 87834c93c86SAndrew Lunn return -ENOSYS; 87934c93c86SAndrew Lunn } 88034c93c86SAndrew Lunn 8811ef48a26SThomas Petazzoni static int mv_xor_channel_remove(struct mv_xor_chan *mv_chan) 882ff7b0479SSaeed Bishara { 883ff7b0479SSaeed Bishara struct dma_chan *chan, *_chan; 8841ef48a26SThomas Petazzoni struct device *dev = mv_chan->dmadev.dev; 885ff7b0479SSaeed Bishara 8861ef48a26SThomas Petazzoni dma_async_device_unregister(&mv_chan->dmadev); 887ff7b0479SSaeed Bishara 888b503fa01SThomas Petazzoni dma_free_coherent(dev, MV_XOR_POOL_SIZE, 8891ef48a26SThomas Petazzoni mv_chan->dma_desc_pool_virt, mv_chan->dma_desc_pool); 890ff7b0479SSaeed Bishara 8911ef48a26SThomas Petazzoni list_for_each_entry_safe(chan, _chan, &mv_chan->dmadev.channels, 892ff7b0479SSaeed Bishara device_node) { 893ff7b0479SSaeed Bishara list_del(&chan->device_node); 894ff7b0479SSaeed Bishara } 895ff7b0479SSaeed Bishara 89688eb92cbSThomas Petazzoni free_irq(mv_chan->irq, mv_chan); 89788eb92cbSThomas Petazzoni 898ff7b0479SSaeed Bishara return 0; 899ff7b0479SSaeed Bishara } 900ff7b0479SSaeed Bishara 9011ef48a26SThomas Petazzoni static struct mv_xor_chan * 902297eedbaSThomas Petazzoni mv_xor_channel_add(struct mv_xor_device *xordev, 903a6b4a9d2SThomas Petazzoni struct platform_device *pdev, 904b503fa01SThomas Petazzoni int idx, dma_cap_mask_t cap_mask, int irq) 905ff7b0479SSaeed Bishara { 906ff7b0479SSaeed Bishara int ret = 0; 907ff7b0479SSaeed Bishara struct mv_xor_chan *mv_chan; 908ff7b0479SSaeed Bishara struct dma_device *dma_dev; 909ff7b0479SSaeed Bishara 9101ef48a26SThomas Petazzoni mv_chan = devm_kzalloc(&pdev->dev, sizeof(*mv_chan), GFP_KERNEL); 911a577659fSSachin Kamat if (!mv_chan) 912a577659fSSachin Kamat return ERR_PTR(-ENOMEM); 913ff7b0479SSaeed Bishara 9149aedbdbaSThomas Petazzoni mv_chan->idx = idx; 91588eb92cbSThomas Petazzoni mv_chan->irq = irq; 916ff7b0479SSaeed Bishara 9171ef48a26SThomas Petazzoni dma_dev = &mv_chan->dmadev; 918ff7b0479SSaeed Bishara 919ff7b0479SSaeed Bishara /* allocate coherent memory for hardware descriptors 920ff7b0479SSaeed Bishara * note: writecombine gives slightly better performance, but 921ff7b0479SSaeed Bishara * requires that we explicitly flush the writes 922ff7b0479SSaeed Bishara */ 9231ef48a26SThomas Petazzoni mv_chan->dma_desc_pool_virt = 924b503fa01SThomas Petazzoni dma_alloc_writecombine(&pdev->dev, MV_XOR_POOL_SIZE, 9251ef48a26SThomas Petazzoni &mv_chan->dma_desc_pool, GFP_KERNEL); 9261ef48a26SThomas Petazzoni if (!mv_chan->dma_desc_pool_virt) 927a6b4a9d2SThomas Petazzoni return ERR_PTR(-ENOMEM); 928ff7b0479SSaeed Bishara 929ff7b0479SSaeed Bishara /* discover transaction capabilites from the platform data */ 930a6b4a9d2SThomas Petazzoni dma_dev->cap_mask = cap_mask; 931ff7b0479SSaeed Bishara 932ff7b0479SSaeed Bishara INIT_LIST_HEAD(&dma_dev->channels); 933ff7b0479SSaeed Bishara 934ff7b0479SSaeed Bishara /* set base routines */ 935ff7b0479SSaeed Bishara dma_dev->device_alloc_chan_resources = mv_xor_alloc_chan_resources; 936ff7b0479SSaeed Bishara dma_dev->device_free_chan_resources = mv_xor_free_chan_resources; 93707934481SLinus Walleij dma_dev->device_tx_status = mv_xor_status; 938ff7b0479SSaeed Bishara dma_dev->device_issue_pending = mv_xor_issue_pending; 93934c93c86SAndrew Lunn dma_dev->device_control = mv_xor_control; 940ff7b0479SSaeed Bishara dma_dev->dev = &pdev->dev; 941ff7b0479SSaeed Bishara 942ff7b0479SSaeed Bishara /* set prep routines based on capability */ 943ff7b0479SSaeed Bishara if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) 944ff7b0479SSaeed Bishara dma_dev->device_prep_dma_memcpy = mv_xor_prep_dma_memcpy; 945ff7b0479SSaeed Bishara if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { 946c019894eSJoe Perches dma_dev->max_xor = 8; 947ff7b0479SSaeed Bishara dma_dev->device_prep_dma_xor = mv_xor_prep_dma_xor; 948ff7b0479SSaeed Bishara } 949ff7b0479SSaeed Bishara 950297eedbaSThomas Petazzoni mv_chan->mmr_base = xordev->xor_base; 95182a1402eSEzequiel Garcia mv_chan->mmr_high_base = xordev->xor_high_base; 952ff7b0479SSaeed Bishara tasklet_init(&mv_chan->irq_tasklet, mv_xor_tasklet, (unsigned long) 953ff7b0479SSaeed Bishara mv_chan); 954ff7b0479SSaeed Bishara 955ff7b0479SSaeed Bishara /* clear errors before enabling interrupts */ 956ff7b0479SSaeed Bishara mv_xor_device_clear_err_status(mv_chan); 957ff7b0479SSaeed Bishara 9582d0a0745SThomas Petazzoni ret = request_irq(mv_chan->irq, mv_xor_interrupt_handler, 959ff7b0479SSaeed Bishara 0, dev_name(&pdev->dev), mv_chan); 960ff7b0479SSaeed Bishara if (ret) 961ff7b0479SSaeed Bishara goto err_free_dma; 962ff7b0479SSaeed Bishara 963ff7b0479SSaeed Bishara mv_chan_unmask_interrupts(mv_chan); 964ff7b0479SSaeed Bishara 9653e4f52e2SLior Amsalem mv_set_mode(mv_chan, DMA_XOR); 966ff7b0479SSaeed Bishara 967ff7b0479SSaeed Bishara spin_lock_init(&mv_chan->lock); 968ff7b0479SSaeed Bishara INIT_LIST_HEAD(&mv_chan->chain); 969ff7b0479SSaeed Bishara INIT_LIST_HEAD(&mv_chan->completed_slots); 970ff7b0479SSaeed Bishara INIT_LIST_HEAD(&mv_chan->all_slots); 97198817b99SThomas Petazzoni mv_chan->dmachan.device = dma_dev; 97298817b99SThomas Petazzoni dma_cookie_init(&mv_chan->dmachan); 973ff7b0479SSaeed Bishara 97498817b99SThomas Petazzoni list_add_tail(&mv_chan->dmachan.device_node, &dma_dev->channels); 975ff7b0479SSaeed Bishara 976ff7b0479SSaeed Bishara if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) { 977275cc0c8SThomas Petazzoni ret = mv_xor_memcpy_self_test(mv_chan); 978ff7b0479SSaeed Bishara dev_dbg(&pdev->dev, "memcpy self test returned %d\n", ret); 979ff7b0479SSaeed Bishara if (ret) 9802d0a0745SThomas Petazzoni goto err_free_irq; 981ff7b0479SSaeed Bishara } 982ff7b0479SSaeed Bishara 983ff7b0479SSaeed Bishara if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { 984275cc0c8SThomas Petazzoni ret = mv_xor_xor_self_test(mv_chan); 985ff7b0479SSaeed Bishara dev_dbg(&pdev->dev, "xor self test returned %d\n", ret); 986ff7b0479SSaeed Bishara if (ret) 9872d0a0745SThomas Petazzoni goto err_free_irq; 988ff7b0479SSaeed Bishara } 989ff7b0479SSaeed Bishara 99048a9db46SBartlomiej Zolnierkiewicz dev_info(&pdev->dev, "Marvell XOR: ( %s%s%s)\n", 991ff7b0479SSaeed Bishara dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "xor " : "", 992ff7b0479SSaeed Bishara dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "cpy " : "", 993ff7b0479SSaeed Bishara dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : ""); 994ff7b0479SSaeed Bishara 995ff7b0479SSaeed Bishara dma_async_device_register(dma_dev); 9961ef48a26SThomas Petazzoni return mv_chan; 997ff7b0479SSaeed Bishara 9982d0a0745SThomas Petazzoni err_free_irq: 9992d0a0745SThomas Petazzoni free_irq(mv_chan->irq, mv_chan); 1000ff7b0479SSaeed Bishara err_free_dma: 1001b503fa01SThomas Petazzoni dma_free_coherent(&pdev->dev, MV_XOR_POOL_SIZE, 10021ef48a26SThomas Petazzoni mv_chan->dma_desc_pool_virt, mv_chan->dma_desc_pool); 1003a6b4a9d2SThomas Petazzoni return ERR_PTR(ret); 1004ff7b0479SSaeed Bishara } 1005ff7b0479SSaeed Bishara 1006ff7b0479SSaeed Bishara static void 1007297eedbaSThomas Petazzoni mv_xor_conf_mbus_windows(struct mv_xor_device *xordev, 100863a9332bSAndrew Lunn const struct mbus_dram_target_info *dram) 1009ff7b0479SSaeed Bishara { 101082a1402eSEzequiel Garcia void __iomem *base = xordev->xor_high_base; 1011ff7b0479SSaeed Bishara u32 win_enable = 0; 1012ff7b0479SSaeed Bishara int i; 1013ff7b0479SSaeed Bishara 1014ff7b0479SSaeed Bishara for (i = 0; i < 8; i++) { 1015ff7b0479SSaeed Bishara writel(0, base + WINDOW_BASE(i)); 1016ff7b0479SSaeed Bishara writel(0, base + WINDOW_SIZE(i)); 1017ff7b0479SSaeed Bishara if (i < 4) 1018ff7b0479SSaeed Bishara writel(0, base + WINDOW_REMAP_HIGH(i)); 1019ff7b0479SSaeed Bishara } 1020ff7b0479SSaeed Bishara 1021ff7b0479SSaeed Bishara for (i = 0; i < dram->num_cs; i++) { 102263a9332bSAndrew Lunn const struct mbus_dram_window *cs = dram->cs + i; 1023ff7b0479SSaeed Bishara 1024ff7b0479SSaeed Bishara writel((cs->base & 0xffff0000) | 1025ff7b0479SSaeed Bishara (cs->mbus_attr << 8) | 1026ff7b0479SSaeed Bishara dram->mbus_dram_target_id, base + WINDOW_BASE(i)); 1027ff7b0479SSaeed Bishara writel((cs->size - 1) & 0xffff0000, base + WINDOW_SIZE(i)); 1028ff7b0479SSaeed Bishara 1029ff7b0479SSaeed Bishara win_enable |= (1 << i); 1030ff7b0479SSaeed Bishara win_enable |= 3 << (16 + (2 * i)); 1031ff7b0479SSaeed Bishara } 1032ff7b0479SSaeed Bishara 1033ff7b0479SSaeed Bishara writel(win_enable, base + WINDOW_BAR_ENABLE(0)); 1034ff7b0479SSaeed Bishara writel(win_enable, base + WINDOW_BAR_ENABLE(1)); 1035c4b4b732SThomas Petazzoni writel(0, base + WINDOW_OVERRIDE_CTRL(0)); 1036c4b4b732SThomas Petazzoni writel(0, base + WINDOW_OVERRIDE_CTRL(1)); 1037ff7b0479SSaeed Bishara } 1038ff7b0479SSaeed Bishara 1039c2714334SLinus Torvalds static int mv_xor_probe(struct platform_device *pdev) 1040ff7b0479SSaeed Bishara { 104163a9332bSAndrew Lunn const struct mbus_dram_target_info *dram; 1042297eedbaSThomas Petazzoni struct mv_xor_device *xordev; 1043d4adcc01SJingoo Han struct mv_xor_platform_data *pdata = dev_get_platdata(&pdev->dev); 1044ff7b0479SSaeed Bishara struct resource *res; 104560d151f3SThomas Petazzoni int i, ret; 1046ff7b0479SSaeed Bishara 10471ba151cdSJoe Perches dev_notice(&pdev->dev, "Marvell shared XOR driver\n"); 1048ff7b0479SSaeed Bishara 1049297eedbaSThomas Petazzoni xordev = devm_kzalloc(&pdev->dev, sizeof(*xordev), GFP_KERNEL); 1050297eedbaSThomas Petazzoni if (!xordev) 1051ff7b0479SSaeed Bishara return -ENOMEM; 1052ff7b0479SSaeed Bishara 1053ff7b0479SSaeed Bishara res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1054ff7b0479SSaeed Bishara if (!res) 1055ff7b0479SSaeed Bishara return -ENODEV; 1056ff7b0479SSaeed Bishara 1057297eedbaSThomas Petazzoni xordev->xor_base = devm_ioremap(&pdev->dev, res->start, 10584de1ba15SH Hartley Sweeten resource_size(res)); 1059297eedbaSThomas Petazzoni if (!xordev->xor_base) 1060ff7b0479SSaeed Bishara return -EBUSY; 1061ff7b0479SSaeed Bishara 1062ff7b0479SSaeed Bishara res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 1063ff7b0479SSaeed Bishara if (!res) 1064ff7b0479SSaeed Bishara return -ENODEV; 1065ff7b0479SSaeed Bishara 1066297eedbaSThomas Petazzoni xordev->xor_high_base = devm_ioremap(&pdev->dev, res->start, 10674de1ba15SH Hartley Sweeten resource_size(res)); 1068297eedbaSThomas Petazzoni if (!xordev->xor_high_base) 1069ff7b0479SSaeed Bishara return -EBUSY; 1070ff7b0479SSaeed Bishara 1071297eedbaSThomas Petazzoni platform_set_drvdata(pdev, xordev); 1072ff7b0479SSaeed Bishara 1073ff7b0479SSaeed Bishara /* 1074ff7b0479SSaeed Bishara * (Re-)program MBUS remapping windows if we are asked to. 1075ff7b0479SSaeed Bishara */ 107663a9332bSAndrew Lunn dram = mv_mbus_dram_info(); 107763a9332bSAndrew Lunn if (dram) 1078297eedbaSThomas Petazzoni mv_xor_conf_mbus_windows(xordev, dram); 1079ff7b0479SSaeed Bishara 1080c510182bSAndrew Lunn /* Not all platforms can gate the clock, so it is not 1081c510182bSAndrew Lunn * an error if the clock does not exists. 1082c510182bSAndrew Lunn */ 1083297eedbaSThomas Petazzoni xordev->clk = clk_get(&pdev->dev, NULL); 1084297eedbaSThomas Petazzoni if (!IS_ERR(xordev->clk)) 1085297eedbaSThomas Petazzoni clk_prepare_enable(xordev->clk); 1086c510182bSAndrew Lunn 1087f7d12ef5SThomas Petazzoni if (pdev->dev.of_node) { 1088f7d12ef5SThomas Petazzoni struct device_node *np; 1089f7d12ef5SThomas Petazzoni int i = 0; 1090f7d12ef5SThomas Petazzoni 1091f7d12ef5SThomas Petazzoni for_each_child_of_node(pdev->dev.of_node, np) { 10920be8253fSRussell King struct mv_xor_chan *chan; 1093f7d12ef5SThomas Petazzoni dma_cap_mask_t cap_mask; 1094f7d12ef5SThomas Petazzoni int irq; 1095f7d12ef5SThomas Petazzoni 1096f7d12ef5SThomas Petazzoni dma_cap_zero(cap_mask); 1097f7d12ef5SThomas Petazzoni if (of_property_read_bool(np, "dmacap,memcpy")) 1098f7d12ef5SThomas Petazzoni dma_cap_set(DMA_MEMCPY, cap_mask); 1099f7d12ef5SThomas Petazzoni if (of_property_read_bool(np, "dmacap,xor")) 1100f7d12ef5SThomas Petazzoni dma_cap_set(DMA_XOR, cap_mask); 1101f7d12ef5SThomas Petazzoni if (of_property_read_bool(np, "dmacap,interrupt")) 1102f7d12ef5SThomas Petazzoni dma_cap_set(DMA_INTERRUPT, cap_mask); 1103f7d12ef5SThomas Petazzoni 1104f7d12ef5SThomas Petazzoni irq = irq_of_parse_and_map(np, 0); 1105f8eb9e7dSThomas Petazzoni if (!irq) { 1106f8eb9e7dSThomas Petazzoni ret = -ENODEV; 1107f7d12ef5SThomas Petazzoni goto err_channel_add; 1108f7d12ef5SThomas Petazzoni } 1109f7d12ef5SThomas Petazzoni 11100be8253fSRussell King chan = mv_xor_channel_add(xordev, pdev, i, 1111f7d12ef5SThomas Petazzoni cap_mask, irq); 11120be8253fSRussell King if (IS_ERR(chan)) { 11130be8253fSRussell King ret = PTR_ERR(chan); 1114f7d12ef5SThomas Petazzoni irq_dispose_mapping(irq); 1115f7d12ef5SThomas Petazzoni goto err_channel_add; 1116f7d12ef5SThomas Petazzoni } 1117f7d12ef5SThomas Petazzoni 11180be8253fSRussell King xordev->channels[i] = chan; 1119f7d12ef5SThomas Petazzoni i++; 1120f7d12ef5SThomas Petazzoni } 1121f7d12ef5SThomas Petazzoni } else if (pdata && pdata->channels) { 112260d151f3SThomas Petazzoni for (i = 0; i < MV_XOR_MAX_CHANNELS; i++) { 1123e39f6ec1SThomas Petazzoni struct mv_xor_channel_data *cd; 11240be8253fSRussell King struct mv_xor_chan *chan; 112560d151f3SThomas Petazzoni int irq; 112660d151f3SThomas Petazzoni 112760d151f3SThomas Petazzoni cd = &pdata->channels[i]; 112860d151f3SThomas Petazzoni if (!cd) { 112960d151f3SThomas Petazzoni ret = -ENODEV; 113060d151f3SThomas Petazzoni goto err_channel_add; 113160d151f3SThomas Petazzoni } 113260d151f3SThomas Petazzoni 113360d151f3SThomas Petazzoni irq = platform_get_irq(pdev, i); 113460d151f3SThomas Petazzoni if (irq < 0) { 113560d151f3SThomas Petazzoni ret = irq; 113660d151f3SThomas Petazzoni goto err_channel_add; 113760d151f3SThomas Petazzoni } 113860d151f3SThomas Petazzoni 11390be8253fSRussell King chan = mv_xor_channel_add(xordev, pdev, i, 1140b503fa01SThomas Petazzoni cd->cap_mask, irq); 11410be8253fSRussell King if (IS_ERR(chan)) { 11420be8253fSRussell King ret = PTR_ERR(chan); 114360d151f3SThomas Petazzoni goto err_channel_add; 114460d151f3SThomas Petazzoni } 11450be8253fSRussell King 11460be8253fSRussell King xordev->channels[i] = chan; 114760d151f3SThomas Petazzoni } 114860d151f3SThomas Petazzoni } 114960d151f3SThomas Petazzoni 1150ff7b0479SSaeed Bishara return 0; 115160d151f3SThomas Petazzoni 115260d151f3SThomas Petazzoni err_channel_add: 115360d151f3SThomas Petazzoni for (i = 0; i < MV_XOR_MAX_CHANNELS; i++) 1154f7d12ef5SThomas Petazzoni if (xordev->channels[i]) { 1155ab6e439fSThomas Petazzoni mv_xor_channel_remove(xordev->channels[i]); 1156f7d12ef5SThomas Petazzoni if (pdev->dev.of_node) 1157f7d12ef5SThomas Petazzoni irq_dispose_mapping(xordev->channels[i]->irq); 1158f7d12ef5SThomas Petazzoni } 115960d151f3SThomas Petazzoni 1160dab92064SThomas Petazzoni if (!IS_ERR(xordev->clk)) { 1161297eedbaSThomas Petazzoni clk_disable_unprepare(xordev->clk); 1162297eedbaSThomas Petazzoni clk_put(xordev->clk); 1163dab92064SThomas Petazzoni } 1164dab92064SThomas Petazzoni 116560d151f3SThomas Petazzoni return ret; 1166ff7b0479SSaeed Bishara } 1167ff7b0479SSaeed Bishara 1168c2714334SLinus Torvalds static int mv_xor_remove(struct platform_device *pdev) 1169ff7b0479SSaeed Bishara { 1170297eedbaSThomas Petazzoni struct mv_xor_device *xordev = platform_get_drvdata(pdev); 117160d151f3SThomas Petazzoni int i; 117260d151f3SThomas Petazzoni 117360d151f3SThomas Petazzoni for (i = 0; i < MV_XOR_MAX_CHANNELS; i++) { 1174297eedbaSThomas Petazzoni if (xordev->channels[i]) 1175297eedbaSThomas Petazzoni mv_xor_channel_remove(xordev->channels[i]); 117660d151f3SThomas Petazzoni } 1177c510182bSAndrew Lunn 1178297eedbaSThomas Petazzoni if (!IS_ERR(xordev->clk)) { 1179297eedbaSThomas Petazzoni clk_disable_unprepare(xordev->clk); 1180297eedbaSThomas Petazzoni clk_put(xordev->clk); 1181c510182bSAndrew Lunn } 1182c510182bSAndrew Lunn 1183ff7b0479SSaeed Bishara return 0; 1184ff7b0479SSaeed Bishara } 1185ff7b0479SSaeed Bishara 1186f7d12ef5SThomas Petazzoni #ifdef CONFIG_OF 1187c2714334SLinus Torvalds static struct of_device_id mv_xor_dt_ids[] = { 1188f7d12ef5SThomas Petazzoni { .compatible = "marvell,orion-xor", }, 1189f7d12ef5SThomas Petazzoni {}, 1190f7d12ef5SThomas Petazzoni }; 1191f7d12ef5SThomas Petazzoni MODULE_DEVICE_TABLE(of, mv_xor_dt_ids); 1192f7d12ef5SThomas Petazzoni #endif 1193f7d12ef5SThomas Petazzoni 1194ff7b0479SSaeed Bishara static struct platform_driver mv_xor_driver = { 1195ff7b0479SSaeed Bishara .probe = mv_xor_probe, 1196a7d6e3ecSBill Pemberton .remove = mv_xor_remove, 1197ff7b0479SSaeed Bishara .driver = { 1198ff7b0479SSaeed Bishara .owner = THIS_MODULE, 1199ff7b0479SSaeed Bishara .name = MV_XOR_NAME, 1200f7d12ef5SThomas Petazzoni .of_match_table = of_match_ptr(mv_xor_dt_ids), 1201ff7b0479SSaeed Bishara }, 1202ff7b0479SSaeed Bishara }; 1203ff7b0479SSaeed Bishara 1204ff7b0479SSaeed Bishara 1205ff7b0479SSaeed Bishara static int __init mv_xor_init(void) 1206ff7b0479SSaeed Bishara { 120761971656SThomas Petazzoni return platform_driver_register(&mv_xor_driver); 1208ff7b0479SSaeed Bishara } 1209ff7b0479SSaeed Bishara module_init(mv_xor_init); 1210ff7b0479SSaeed Bishara 1211ff7b0479SSaeed Bishara /* it's currently unsafe to unload this module */ 1212ff7b0479SSaeed Bishara #if 0 1213ff7b0479SSaeed Bishara static void __exit mv_xor_exit(void) 1214ff7b0479SSaeed Bishara { 1215ff7b0479SSaeed Bishara platform_driver_unregister(&mv_xor_driver); 1216ff7b0479SSaeed Bishara return; 1217ff7b0479SSaeed Bishara } 1218ff7b0479SSaeed Bishara 1219ff7b0479SSaeed Bishara module_exit(mv_xor_exit); 1220ff7b0479SSaeed Bishara #endif 1221ff7b0479SSaeed Bishara 1222ff7b0479SSaeed Bishara MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>"); 1223ff7b0479SSaeed Bishara MODULE_DESCRIPTION("DMA engine driver for Marvell's XOR engine"); 1224ff7b0479SSaeed Bishara MODULE_LICENSE("GPL"); 1225