148618fb4SAlexandre Bounine /* 248618fb4SAlexandre Bounine * RapidIO mport driver for Tsi721 PCIExpress-to-SRIO bridge 348618fb4SAlexandre Bounine * 448618fb4SAlexandre Bounine * Copyright 2011 Integrated Device Technology, Inc. 548618fb4SAlexandre Bounine * Alexandre Bounine <alexandre.bounine@idt.com> 648618fb4SAlexandre Bounine * Chul Kim <chul.kim@idt.com> 748618fb4SAlexandre Bounine * 848618fb4SAlexandre Bounine * This program is free software; you can redistribute it and/or modify it 948618fb4SAlexandre Bounine * under the terms of the GNU General Public License as published by the Free 1048618fb4SAlexandre Bounine * Software Foundation; either version 2 of the License, or (at your option) 1148618fb4SAlexandre Bounine * any later version. 1248618fb4SAlexandre Bounine * 1348618fb4SAlexandre Bounine * This program is distributed in the hope that it will be useful, but WITHOUT 1448618fb4SAlexandre Bounine * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1548618fb4SAlexandre Bounine * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1648618fb4SAlexandre Bounine * more details. 1748618fb4SAlexandre Bounine * 1848618fb4SAlexandre Bounine * You should have received a copy of the GNU General Public License along with 1948618fb4SAlexandre Bounine * this program; if not, write to the Free Software Foundation, Inc., 59 2048618fb4SAlexandre Bounine * Temple Place - Suite 330, Boston, MA 02111-1307, USA. 2148618fb4SAlexandre Bounine */ 2248618fb4SAlexandre Bounine 2348618fb4SAlexandre Bounine #include <linux/io.h> 2448618fb4SAlexandre Bounine #include <linux/errno.h> 2548618fb4SAlexandre Bounine #include <linux/init.h> 2648618fb4SAlexandre Bounine #include <linux/ioport.h> 2748618fb4SAlexandre Bounine #include <linux/kernel.h> 2848618fb4SAlexandre Bounine #include <linux/module.h> 2948618fb4SAlexandre Bounine #include <linux/pci.h> 3048618fb4SAlexandre Bounine #include <linux/rio.h> 3148618fb4SAlexandre Bounine #include <linux/rio_drv.h> 3248618fb4SAlexandre Bounine #include <linux/dma-mapping.h> 3348618fb4SAlexandre Bounine #include <linux/interrupt.h> 3448618fb4SAlexandre Bounine #include <linux/kfifo.h> 3548618fb4SAlexandre Bounine #include <linux/delay.h> 3648618fb4SAlexandre Bounine 3748618fb4SAlexandre Bounine #include "tsi721.h" 3848618fb4SAlexandre Bounine 3972d8a0d2SAlexandre Bounine #ifdef DEBUG 404785603bSRandy Dunlap u32 tsi_dbg_level; 414785603bSRandy Dunlap module_param_named(dbg_level, tsi_dbg_level, uint, S_IWUSR | S_IRUGO); 4272d8a0d2SAlexandre Bounine MODULE_PARM_DESC(dbg_level, "Debugging output level (default 0 = none)"); 4372d8a0d2SAlexandre Bounine #endif 4472d8a0d2SAlexandre Bounine 45cb782cddSAlexandre Bounine static int pcie_mrrs = -1; 46cb782cddSAlexandre Bounine module_param(pcie_mrrs, int, S_IRUGO); 47cb782cddSAlexandre Bounine MODULE_PARM_DESC(pcie_mrrs, "PCIe MRRS override value (0...5)"); 48cb782cddSAlexandre Bounine 49e519685dSAlexandre Bounine static u8 mbox_sel = 0x0f; 50e519685dSAlexandre Bounine module_param(mbox_sel, byte, S_IRUGO); 51e519685dSAlexandre Bounine MODULE_PARM_DESC(mbox_sel, 52e519685dSAlexandre Bounine "RIO Messaging MBOX Selection Mask (default: 0x0f = all)"); 53e519685dSAlexandre Bounine 54*31d1e130SIoan Nicu static DEFINE_SPINLOCK(tsi721_maint_lock); 55*31d1e130SIoan Nicu 5648618fb4SAlexandre Bounine static void tsi721_omsg_handler(struct tsi721_device *priv, int ch); 5748618fb4SAlexandre Bounine static void tsi721_imsg_handler(struct tsi721_device *priv, int ch); 5848618fb4SAlexandre Bounine 5948618fb4SAlexandre Bounine /** 6048618fb4SAlexandre Bounine * tsi721_lcread - read from local SREP config space 6148618fb4SAlexandre Bounine * @mport: RapidIO master port info 6248618fb4SAlexandre Bounine * @index: ID of RapdiIO interface 6348618fb4SAlexandre Bounine * @offset: Offset into configuration space 6448618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction 6548618fb4SAlexandre Bounine * @data: Value to be read into 6648618fb4SAlexandre Bounine * 6748618fb4SAlexandre Bounine * Generates a local SREP space read. Returns %0 on 6848618fb4SAlexandre Bounine * success or %-EINVAL on failure. 6948618fb4SAlexandre Bounine */ 7048618fb4SAlexandre Bounine static int tsi721_lcread(struct rio_mport *mport, int index, u32 offset, 7148618fb4SAlexandre Bounine int len, u32 *data) 7248618fb4SAlexandre Bounine { 7348618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 7448618fb4SAlexandre Bounine 7548618fb4SAlexandre Bounine if (len != sizeof(u32)) 7648618fb4SAlexandre Bounine return -EINVAL; /* only 32-bit access is supported */ 7748618fb4SAlexandre Bounine 7848618fb4SAlexandre Bounine *data = ioread32(priv->regs + offset); 7948618fb4SAlexandre Bounine 8048618fb4SAlexandre Bounine return 0; 8148618fb4SAlexandre Bounine } 8248618fb4SAlexandre Bounine 8348618fb4SAlexandre Bounine /** 8448618fb4SAlexandre Bounine * tsi721_lcwrite - write into local SREP config space 8548618fb4SAlexandre Bounine * @mport: RapidIO master port info 8648618fb4SAlexandre Bounine * @index: ID of RapdiIO interface 8748618fb4SAlexandre Bounine * @offset: Offset into configuration space 8848618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction 8948618fb4SAlexandre Bounine * @data: Value to be written 9048618fb4SAlexandre Bounine * 9148618fb4SAlexandre Bounine * Generates a local write into SREP configuration space. Returns %0 on 9248618fb4SAlexandre Bounine * success or %-EINVAL on failure. 9348618fb4SAlexandre Bounine */ 9448618fb4SAlexandre Bounine static int tsi721_lcwrite(struct rio_mport *mport, int index, u32 offset, 9548618fb4SAlexandre Bounine int len, u32 data) 9648618fb4SAlexandre Bounine { 9748618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 9848618fb4SAlexandre Bounine 9948618fb4SAlexandre Bounine if (len != sizeof(u32)) 10048618fb4SAlexandre Bounine return -EINVAL; /* only 32-bit access is supported */ 10148618fb4SAlexandre Bounine 10248618fb4SAlexandre Bounine iowrite32(data, priv->regs + offset); 10348618fb4SAlexandre Bounine 10448618fb4SAlexandre Bounine return 0; 10548618fb4SAlexandre Bounine } 10648618fb4SAlexandre Bounine 10748618fb4SAlexandre Bounine /** 10848618fb4SAlexandre Bounine * tsi721_maint_dma - Helper function to generate RapidIO maintenance 10948618fb4SAlexandre Bounine * transactions using designated Tsi721 DMA channel. 11048618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 11148618fb4SAlexandre Bounine * @sys_size: RapdiIO transport system size 11248618fb4SAlexandre Bounine * @destid: Destination ID of transaction 11348618fb4SAlexandre Bounine * @hopcount: Number of hops to target device 11448618fb4SAlexandre Bounine * @offset: Offset into configuration space 11548618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction 11648618fb4SAlexandre Bounine * @data: Location to be read from or write into 11748618fb4SAlexandre Bounine * @do_wr: Operation flag (1 == MAINT_WR) 11848618fb4SAlexandre Bounine * 11948618fb4SAlexandre Bounine * Generates a RapidIO maintenance transaction (Read or Write). 12048618fb4SAlexandre Bounine * Returns %0 on success and %-EINVAL or %-EFAULT on failure. 12148618fb4SAlexandre Bounine */ 12248618fb4SAlexandre Bounine static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size, 12348618fb4SAlexandre Bounine u16 destid, u8 hopcount, u32 offset, int len, 12448618fb4SAlexandre Bounine u32 *data, int do_wr) 12548618fb4SAlexandre Bounine { 1269eaa3d9bSAlexandre Bounine void __iomem *regs = priv->regs + TSI721_DMAC_BASE(priv->mdma.ch_id); 12748618fb4SAlexandre Bounine struct tsi721_dma_desc *bd_ptr; 12848618fb4SAlexandre Bounine u32 rd_count, swr_ptr, ch_stat; 129*31d1e130SIoan Nicu unsigned long flags; 13048618fb4SAlexandre Bounine int i, err = 0; 13148618fb4SAlexandre Bounine u32 op = do_wr ? MAINT_WR : MAINT_RD; 13248618fb4SAlexandre Bounine 13348618fb4SAlexandre Bounine if (offset > (RIO_MAINT_SPACE_SZ - len) || (len != sizeof(u32))) 13448618fb4SAlexandre Bounine return -EINVAL; 13548618fb4SAlexandre Bounine 136*31d1e130SIoan Nicu spin_lock_irqsave(&tsi721_maint_lock, flags); 137*31d1e130SIoan Nicu 1389eaa3d9bSAlexandre Bounine bd_ptr = priv->mdma.bd_base; 13948618fb4SAlexandre Bounine 1409eaa3d9bSAlexandre Bounine rd_count = ioread32(regs + TSI721_DMAC_DRDCNT); 14148618fb4SAlexandre Bounine 14248618fb4SAlexandre Bounine /* Initialize DMA descriptor */ 14348618fb4SAlexandre Bounine bd_ptr[0].type_id = cpu_to_le32((DTYPE2 << 29) | (op << 19) | destid); 14448618fb4SAlexandre Bounine bd_ptr[0].bcount = cpu_to_le32((sys_size << 26) | 0x04); 14548618fb4SAlexandre Bounine bd_ptr[0].raddr_lo = cpu_to_le32((hopcount << 24) | offset); 14648618fb4SAlexandre Bounine bd_ptr[0].raddr_hi = 0; 14748618fb4SAlexandre Bounine if (do_wr) 14848618fb4SAlexandre Bounine bd_ptr[0].data[0] = cpu_to_be32p(data); 14948618fb4SAlexandre Bounine else 15048618fb4SAlexandre Bounine bd_ptr[0].data[0] = 0xffffffff; 15148618fb4SAlexandre Bounine 15248618fb4SAlexandre Bounine mb(); 15348618fb4SAlexandre Bounine 15448618fb4SAlexandre Bounine /* Start DMA operation */ 1559eaa3d9bSAlexandre Bounine iowrite32(rd_count + 2, regs + TSI721_DMAC_DWRCNT); 1569eaa3d9bSAlexandre Bounine ioread32(regs + TSI721_DMAC_DWRCNT); 15748618fb4SAlexandre Bounine i = 0; 15848618fb4SAlexandre Bounine 15948618fb4SAlexandre Bounine /* Wait until DMA transfer is finished */ 1609eaa3d9bSAlexandre Bounine while ((ch_stat = ioread32(regs + TSI721_DMAC_STS)) 1619eaa3d9bSAlexandre Bounine & TSI721_DMAC_STS_RUN) { 16248618fb4SAlexandre Bounine udelay(1); 16348618fb4SAlexandre Bounine if (++i >= 5000000) { 16472d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev, 16572d8a0d2SAlexandre Bounine "DMA[%d] read timeout ch_status=%x", 16672d8a0d2SAlexandre Bounine priv->mdma.ch_id, ch_stat); 16748618fb4SAlexandre Bounine if (!do_wr) 16848618fb4SAlexandre Bounine *data = 0xffffffff; 16948618fb4SAlexandre Bounine err = -EIO; 17048618fb4SAlexandre Bounine goto err_out; 17148618fb4SAlexandre Bounine } 17248618fb4SAlexandre Bounine } 17348618fb4SAlexandre Bounine 17448618fb4SAlexandre Bounine if (ch_stat & TSI721_DMAC_STS_ABORT) { 17548618fb4SAlexandre Bounine /* If DMA operation aborted due to error, 17648618fb4SAlexandre Bounine * reinitialize DMA channel 17748618fb4SAlexandre Bounine */ 17872d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev, "DMA ABORT ch_stat=%x", 17972d8a0d2SAlexandre Bounine ch_stat); 18072d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev, 18172d8a0d2SAlexandre Bounine "OP=%d : destid=%x hc=%x off=%x", 18272d8a0d2SAlexandre Bounine do_wr ? MAINT_WR : MAINT_RD, 18372d8a0d2SAlexandre Bounine destid, hopcount, offset); 1849eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_INT_ALL, regs + TSI721_DMAC_INT); 1859eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL); 18648618fb4SAlexandre Bounine udelay(10); 1879eaa3d9bSAlexandre Bounine iowrite32(0, regs + TSI721_DMAC_DWRCNT); 18848618fb4SAlexandre Bounine udelay(1); 18948618fb4SAlexandre Bounine if (!do_wr) 19048618fb4SAlexandre Bounine *data = 0xffffffff; 19148618fb4SAlexandre Bounine err = -EIO; 19248618fb4SAlexandre Bounine goto err_out; 19348618fb4SAlexandre Bounine } 19448618fb4SAlexandre Bounine 19548618fb4SAlexandre Bounine if (!do_wr) 19648618fb4SAlexandre Bounine *data = be32_to_cpu(bd_ptr[0].data[0]); 19748618fb4SAlexandre Bounine 19848618fb4SAlexandre Bounine /* 19948618fb4SAlexandre Bounine * Update descriptor status FIFO RD pointer. 20048618fb4SAlexandre Bounine * NOTE: Skipping check and clear FIFO entries because we are waiting 20148618fb4SAlexandre Bounine * for transfer to be completed. 20248618fb4SAlexandre Bounine */ 2039eaa3d9bSAlexandre Bounine swr_ptr = ioread32(regs + TSI721_DMAC_DSWP); 2049eaa3d9bSAlexandre Bounine iowrite32(swr_ptr, regs + TSI721_DMAC_DSRP); 205*31d1e130SIoan Nicu 20648618fb4SAlexandre Bounine err_out: 207*31d1e130SIoan Nicu spin_unlock_irqrestore(&tsi721_maint_lock, flags); 20848618fb4SAlexandre Bounine 20948618fb4SAlexandre Bounine return err; 21048618fb4SAlexandre Bounine } 21148618fb4SAlexandre Bounine 21248618fb4SAlexandre Bounine /** 21348618fb4SAlexandre Bounine * tsi721_cread_dma - Generate a RapidIO maintenance read transaction 21448618fb4SAlexandre Bounine * using Tsi721 BDMA engine. 21548618fb4SAlexandre Bounine * @mport: RapidIO master port control structure 21648618fb4SAlexandre Bounine * @index: ID of RapdiIO interface 21748618fb4SAlexandre Bounine * @destid: Destination ID of transaction 21848618fb4SAlexandre Bounine * @hopcount: Number of hops to target device 21948618fb4SAlexandre Bounine * @offset: Offset into configuration space 22048618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction 22148618fb4SAlexandre Bounine * @val: Location to be read into 22248618fb4SAlexandre Bounine * 22348618fb4SAlexandre Bounine * Generates a RapidIO maintenance read transaction. 22448618fb4SAlexandre Bounine * Returns %0 on success and %-EINVAL or %-EFAULT on failure. 22548618fb4SAlexandre Bounine */ 22648618fb4SAlexandre Bounine static int tsi721_cread_dma(struct rio_mport *mport, int index, u16 destid, 22748618fb4SAlexandre Bounine u8 hopcount, u32 offset, int len, u32 *data) 22848618fb4SAlexandre Bounine { 22948618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 23048618fb4SAlexandre Bounine 23148618fb4SAlexandre Bounine return tsi721_maint_dma(priv, mport->sys_size, destid, hopcount, 23248618fb4SAlexandre Bounine offset, len, data, 0); 23348618fb4SAlexandre Bounine } 23448618fb4SAlexandre Bounine 23548618fb4SAlexandre Bounine /** 23648618fb4SAlexandre Bounine * tsi721_cwrite_dma - Generate a RapidIO maintenance write transaction 23748618fb4SAlexandre Bounine * using Tsi721 BDMA engine 23848618fb4SAlexandre Bounine * @mport: RapidIO master port control structure 23948618fb4SAlexandre Bounine * @index: ID of RapdiIO interface 24048618fb4SAlexandre Bounine * @destid: Destination ID of transaction 24148618fb4SAlexandre Bounine * @hopcount: Number of hops to target device 24248618fb4SAlexandre Bounine * @offset: Offset into configuration space 24348618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction 24448618fb4SAlexandre Bounine * @val: Value to be written 24548618fb4SAlexandre Bounine * 24648618fb4SAlexandre Bounine * Generates a RapidIO maintenance write transaction. 24748618fb4SAlexandre Bounine * Returns %0 on success and %-EINVAL or %-EFAULT on failure. 24848618fb4SAlexandre Bounine */ 24948618fb4SAlexandre Bounine static int tsi721_cwrite_dma(struct rio_mport *mport, int index, u16 destid, 25048618fb4SAlexandre Bounine u8 hopcount, u32 offset, int len, u32 data) 25148618fb4SAlexandre Bounine { 25248618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 25348618fb4SAlexandre Bounine u32 temp = data; 25448618fb4SAlexandre Bounine 25548618fb4SAlexandre Bounine return tsi721_maint_dma(priv, mport->sys_size, destid, hopcount, 25648618fb4SAlexandre Bounine offset, len, &temp, 1); 25748618fb4SAlexandre Bounine } 25848618fb4SAlexandre Bounine 25948618fb4SAlexandre Bounine /** 26048618fb4SAlexandre Bounine * tsi721_pw_handler - Tsi721 inbound port-write interrupt handler 261748353ccSAlexandre Bounine * @priv: tsi721 device private structure 26248618fb4SAlexandre Bounine * 26348618fb4SAlexandre Bounine * Handles inbound port-write interrupts. Copies PW message from an internal 26448618fb4SAlexandre Bounine * buffer into PW message FIFO and schedules deferred routine to process 26548618fb4SAlexandre Bounine * queued messages. 26648618fb4SAlexandre Bounine */ 26748618fb4SAlexandre Bounine static int 268748353ccSAlexandre Bounine tsi721_pw_handler(struct tsi721_device *priv) 26948618fb4SAlexandre Bounine { 27048618fb4SAlexandre Bounine u32 pw_stat; 27148618fb4SAlexandre Bounine u32 pw_buf[TSI721_RIO_PW_MSG_SIZE/sizeof(u32)]; 27248618fb4SAlexandre Bounine 27348618fb4SAlexandre Bounine 27448618fb4SAlexandre Bounine pw_stat = ioread32(priv->regs + TSI721_RIO_PW_RX_STAT); 27548618fb4SAlexandre Bounine 27648618fb4SAlexandre Bounine if (pw_stat & TSI721_RIO_PW_RX_STAT_PW_VAL) { 27748618fb4SAlexandre Bounine pw_buf[0] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(0)); 27848618fb4SAlexandre Bounine pw_buf[1] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(1)); 27948618fb4SAlexandre Bounine pw_buf[2] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(2)); 28048618fb4SAlexandre Bounine pw_buf[3] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(3)); 28148618fb4SAlexandre Bounine 28248618fb4SAlexandre Bounine /* Queue PW message (if there is room in FIFO), 28348618fb4SAlexandre Bounine * otherwise discard it. 28448618fb4SAlexandre Bounine */ 28548618fb4SAlexandre Bounine spin_lock(&priv->pw_fifo_lock); 28648618fb4SAlexandre Bounine if (kfifo_avail(&priv->pw_fifo) >= TSI721_RIO_PW_MSG_SIZE) 28748618fb4SAlexandre Bounine kfifo_in(&priv->pw_fifo, pw_buf, 28848618fb4SAlexandre Bounine TSI721_RIO_PW_MSG_SIZE); 28948618fb4SAlexandre Bounine else 29048618fb4SAlexandre Bounine priv->pw_discard_count++; 29148618fb4SAlexandre Bounine spin_unlock(&priv->pw_fifo_lock); 29248618fb4SAlexandre Bounine } 29348618fb4SAlexandre Bounine 29448618fb4SAlexandre Bounine /* Clear pending PW interrupts */ 29548618fb4SAlexandre Bounine iowrite32(TSI721_RIO_PW_RX_STAT_PW_DISC | TSI721_RIO_PW_RX_STAT_PW_VAL, 29648618fb4SAlexandre Bounine priv->regs + TSI721_RIO_PW_RX_STAT); 29748618fb4SAlexandre Bounine 29848618fb4SAlexandre Bounine schedule_work(&priv->pw_work); 29948618fb4SAlexandre Bounine 30048618fb4SAlexandre Bounine return 0; 30148618fb4SAlexandre Bounine } 30248618fb4SAlexandre Bounine 30348618fb4SAlexandre Bounine static void tsi721_pw_dpc(struct work_struct *work) 30448618fb4SAlexandre Bounine { 30548618fb4SAlexandre Bounine struct tsi721_device *priv = container_of(work, struct tsi721_device, 30648618fb4SAlexandre Bounine pw_work); 3079a0b0627SAlexandre Bounine union rio_pw_msg pwmsg; 30848618fb4SAlexandre Bounine 30948618fb4SAlexandre Bounine /* 31048618fb4SAlexandre Bounine * Process port-write messages 31148618fb4SAlexandre Bounine */ 3129a0b0627SAlexandre Bounine while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)&pwmsg, 31348618fb4SAlexandre Bounine TSI721_RIO_PW_MSG_SIZE, &priv->pw_fifo_lock)) { 31448618fb4SAlexandre Bounine /* Pass the port-write message to RIO core for processing */ 3159a0b0627SAlexandre Bounine rio_inb_pwrite_handler(&priv->mport, &pwmsg); 31648618fb4SAlexandre Bounine } 31748618fb4SAlexandre Bounine } 31848618fb4SAlexandre Bounine 31948618fb4SAlexandre Bounine /** 32048618fb4SAlexandre Bounine * tsi721_pw_enable - enable/disable port-write interface init 32148618fb4SAlexandre Bounine * @mport: Master port implementing the port write unit 32248618fb4SAlexandre Bounine * @enable: 1=enable; 0=disable port-write message handling 32348618fb4SAlexandre Bounine */ 32448618fb4SAlexandre Bounine static int tsi721_pw_enable(struct rio_mport *mport, int enable) 32548618fb4SAlexandre Bounine { 32648618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 32748618fb4SAlexandre Bounine u32 rval; 32848618fb4SAlexandre Bounine 32948618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_RIO_EM_INT_ENABLE); 33048618fb4SAlexandre Bounine 33148618fb4SAlexandre Bounine if (enable) 33248618fb4SAlexandre Bounine rval |= TSI721_RIO_EM_INT_ENABLE_PW_RX; 33348618fb4SAlexandre Bounine else 33448618fb4SAlexandre Bounine rval &= ~TSI721_RIO_EM_INT_ENABLE_PW_RX; 33548618fb4SAlexandre Bounine 33648618fb4SAlexandre Bounine /* Clear pending PW interrupts */ 33748618fb4SAlexandre Bounine iowrite32(TSI721_RIO_PW_RX_STAT_PW_DISC | TSI721_RIO_PW_RX_STAT_PW_VAL, 33848618fb4SAlexandre Bounine priv->regs + TSI721_RIO_PW_RX_STAT); 33948618fb4SAlexandre Bounine /* Update enable bits */ 34048618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_RIO_EM_INT_ENABLE); 34148618fb4SAlexandre Bounine 34248618fb4SAlexandre Bounine return 0; 34348618fb4SAlexandre Bounine } 34448618fb4SAlexandre Bounine 34548618fb4SAlexandre Bounine /** 34648618fb4SAlexandre Bounine * tsi721_dsend - Send a RapidIO doorbell 34748618fb4SAlexandre Bounine * @mport: RapidIO master port info 34848618fb4SAlexandre Bounine * @index: ID of RapidIO interface 34948618fb4SAlexandre Bounine * @destid: Destination ID of target device 35048618fb4SAlexandre Bounine * @data: 16-bit info field of RapidIO doorbell 35148618fb4SAlexandre Bounine * 35248618fb4SAlexandre Bounine * Sends a RapidIO doorbell message. Always returns %0. 35348618fb4SAlexandre Bounine */ 35448618fb4SAlexandre Bounine static int tsi721_dsend(struct rio_mport *mport, int index, 35548618fb4SAlexandre Bounine u16 destid, u16 data) 35648618fb4SAlexandre Bounine { 35748618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 35848618fb4SAlexandre Bounine u32 offset; 35948618fb4SAlexandre Bounine 36048618fb4SAlexandre Bounine offset = (((mport->sys_size) ? RIO_TT_CODE_16 : RIO_TT_CODE_8) << 18) | 36148618fb4SAlexandre Bounine (destid << 2); 36248618fb4SAlexandre Bounine 36372d8a0d2SAlexandre Bounine tsi_debug(DBELL, &priv->pdev->dev, 36472d8a0d2SAlexandre Bounine "Send Doorbell 0x%04x to destID 0x%x", data, destid); 36548618fb4SAlexandre Bounine iowrite16be(data, priv->odb_base + offset); 36648618fb4SAlexandre Bounine 36748618fb4SAlexandre Bounine return 0; 36848618fb4SAlexandre Bounine } 36948618fb4SAlexandre Bounine 37048618fb4SAlexandre Bounine /** 37148618fb4SAlexandre Bounine * tsi721_dbell_handler - Tsi721 doorbell interrupt handler 372748353ccSAlexandre Bounine * @priv: tsi721 device-specific data structure 37348618fb4SAlexandre Bounine * 37448618fb4SAlexandre Bounine * Handles inbound doorbell interrupts. Copies doorbell entry from an internal 37548618fb4SAlexandre Bounine * buffer into DB message FIFO and schedules deferred routine to process 37648618fb4SAlexandre Bounine * queued DBs. 37748618fb4SAlexandre Bounine */ 37848618fb4SAlexandre Bounine static int 379748353ccSAlexandre Bounine tsi721_dbell_handler(struct tsi721_device *priv) 38048618fb4SAlexandre Bounine { 38148618fb4SAlexandre Bounine u32 regval; 38248618fb4SAlexandre Bounine 38348618fb4SAlexandre Bounine /* Disable IDB interrupts */ 38448618fb4SAlexandre Bounine regval = ioread32(priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); 38548618fb4SAlexandre Bounine regval &= ~TSI721_SR_CHINT_IDBQRCV; 38648618fb4SAlexandre Bounine iowrite32(regval, 38748618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); 38848618fb4SAlexandre Bounine 38948618fb4SAlexandre Bounine schedule_work(&priv->idb_work); 39048618fb4SAlexandre Bounine 39148618fb4SAlexandre Bounine return 0; 39248618fb4SAlexandre Bounine } 39348618fb4SAlexandre Bounine 39448618fb4SAlexandre Bounine static void tsi721_db_dpc(struct work_struct *work) 39548618fb4SAlexandre Bounine { 39648618fb4SAlexandre Bounine struct tsi721_device *priv = container_of(work, struct tsi721_device, 39748618fb4SAlexandre Bounine idb_work); 39848618fb4SAlexandre Bounine struct rio_mport *mport; 39948618fb4SAlexandre Bounine struct rio_dbell *dbell; 40048618fb4SAlexandre Bounine int found = 0; 40148618fb4SAlexandre Bounine u32 wr_ptr, rd_ptr; 40248618fb4SAlexandre Bounine u64 *idb_entry; 40348618fb4SAlexandre Bounine u32 regval; 40448618fb4SAlexandre Bounine union { 40548618fb4SAlexandre Bounine u64 msg; 40648618fb4SAlexandre Bounine u8 bytes[8]; 40748618fb4SAlexandre Bounine } idb; 40848618fb4SAlexandre Bounine 40948618fb4SAlexandre Bounine /* 41048618fb4SAlexandre Bounine * Process queued inbound doorbells 41148618fb4SAlexandre Bounine */ 412748353ccSAlexandre Bounine mport = &priv->mport; 41348618fb4SAlexandre Bounine 414b24823e6SAlexandre Bounine wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE; 415b24823e6SAlexandre Bounine rd_ptr = ioread32(priv->regs + TSI721_IDQ_RP(IDB_QUEUE)) % IDB_QSIZE; 41648618fb4SAlexandre Bounine 41748618fb4SAlexandre Bounine while (wr_ptr != rd_ptr) { 41848618fb4SAlexandre Bounine idb_entry = (u64 *)(priv->idb_base + 41948618fb4SAlexandre Bounine (TSI721_IDB_ENTRY_SIZE * rd_ptr)); 42048618fb4SAlexandre Bounine rd_ptr++; 421b24823e6SAlexandre Bounine rd_ptr %= IDB_QSIZE; 42248618fb4SAlexandre Bounine idb.msg = *idb_entry; 42348618fb4SAlexandre Bounine *idb_entry = 0; 42448618fb4SAlexandre Bounine 42548618fb4SAlexandre Bounine /* Process one doorbell */ 42648618fb4SAlexandre Bounine list_for_each_entry(dbell, &mport->dbells, node) { 42748618fb4SAlexandre Bounine if ((dbell->res->start <= DBELL_INF(idb.bytes)) && 42848618fb4SAlexandre Bounine (dbell->res->end >= DBELL_INF(idb.bytes))) { 42948618fb4SAlexandre Bounine found = 1; 43048618fb4SAlexandre Bounine break; 43148618fb4SAlexandre Bounine } 43248618fb4SAlexandre Bounine } 43348618fb4SAlexandre Bounine 43448618fb4SAlexandre Bounine if (found) { 43548618fb4SAlexandre Bounine dbell->dinb(mport, dbell->dev_id, DBELL_SID(idb.bytes), 43648618fb4SAlexandre Bounine DBELL_TID(idb.bytes), DBELL_INF(idb.bytes)); 43748618fb4SAlexandre Bounine } else { 43872d8a0d2SAlexandre Bounine tsi_debug(DBELL, &priv->pdev->dev, 43972d8a0d2SAlexandre Bounine "spurious IDB sid %2.2x tid %2.2x info %4.4x", 44072d8a0d2SAlexandre Bounine DBELL_SID(idb.bytes), DBELL_TID(idb.bytes), 44172d8a0d2SAlexandre Bounine DBELL_INF(idb.bytes)); 44248618fb4SAlexandre Bounine } 4433670e7e1SAlexandre Bounine 4443670e7e1SAlexandre Bounine wr_ptr = ioread32(priv->regs + 4453670e7e1SAlexandre Bounine TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE; 44648618fb4SAlexandre Bounine } 44748618fb4SAlexandre Bounine 44848618fb4SAlexandre Bounine iowrite32(rd_ptr & (IDB_QSIZE - 1), 44948618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_RP(IDB_QUEUE)); 45048618fb4SAlexandre Bounine 45148618fb4SAlexandre Bounine /* Re-enable IDB interrupts */ 45248618fb4SAlexandre Bounine regval = ioread32(priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); 45348618fb4SAlexandre Bounine regval |= TSI721_SR_CHINT_IDBQRCV; 45448618fb4SAlexandre Bounine iowrite32(regval, 45548618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); 4563670e7e1SAlexandre Bounine 4573670e7e1SAlexandre Bounine wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE; 4583670e7e1SAlexandre Bounine if (wr_ptr != rd_ptr) 4593670e7e1SAlexandre Bounine schedule_work(&priv->idb_work); 46048618fb4SAlexandre Bounine } 46148618fb4SAlexandre Bounine 46248618fb4SAlexandre Bounine /** 46348618fb4SAlexandre Bounine * tsi721_irqhandler - Tsi721 interrupt handler 46448618fb4SAlexandre Bounine * @irq: Linux interrupt number 465748353ccSAlexandre Bounine * @ptr: Pointer to interrupt-specific data (tsi721_device structure) 46648618fb4SAlexandre Bounine * 46748618fb4SAlexandre Bounine * Handles Tsi721 interrupts signaled using MSI and INTA. Checks reported 46848618fb4SAlexandre Bounine * interrupt events and calls an event-specific handler(s). 46948618fb4SAlexandre Bounine */ 47048618fb4SAlexandre Bounine static irqreturn_t tsi721_irqhandler(int irq, void *ptr) 47148618fb4SAlexandre Bounine { 472748353ccSAlexandre Bounine struct tsi721_device *priv = (struct tsi721_device *)ptr; 47348618fb4SAlexandre Bounine u32 dev_int; 47448618fb4SAlexandre Bounine u32 dev_ch_int; 47548618fb4SAlexandre Bounine u32 intval; 47648618fb4SAlexandre Bounine u32 ch_inte; 47748618fb4SAlexandre Bounine 4781ccc819dSAlexandre Bounine /* For MSI mode disable all device-level interrupts */ 4791ccc819dSAlexandre Bounine if (priv->flags & TSI721_USING_MSI) 4801ccc819dSAlexandre Bounine iowrite32(0, priv->regs + TSI721_DEV_INTE); 4811ccc819dSAlexandre Bounine 48248618fb4SAlexandre Bounine dev_int = ioread32(priv->regs + TSI721_DEV_INT); 48348618fb4SAlexandre Bounine if (!dev_int) 48448618fb4SAlexandre Bounine return IRQ_NONE; 48548618fb4SAlexandre Bounine 48648618fb4SAlexandre Bounine dev_ch_int = ioread32(priv->regs + TSI721_DEV_CHAN_INT); 48748618fb4SAlexandre Bounine 48848618fb4SAlexandre Bounine if (dev_int & TSI721_DEV_INT_SR2PC_CH) { 48948618fb4SAlexandre Bounine /* Service SR2PC Channel interrupts */ 49048618fb4SAlexandre Bounine if (dev_ch_int & TSI721_INT_SR2PC_CHAN(IDB_QUEUE)) { 49148618fb4SAlexandre Bounine /* Service Inbound Doorbell interrupt */ 49248618fb4SAlexandre Bounine intval = ioread32(priv->regs + 49348618fb4SAlexandre Bounine TSI721_SR_CHINT(IDB_QUEUE)); 49448618fb4SAlexandre Bounine if (intval & TSI721_SR_CHINT_IDBQRCV) 495748353ccSAlexandre Bounine tsi721_dbell_handler(priv); 49648618fb4SAlexandre Bounine else 49772d8a0d2SAlexandre Bounine tsi_info(&priv->pdev->dev, 49872d8a0d2SAlexandre Bounine "Unsupported SR_CH_INT %x", intval); 49948618fb4SAlexandre Bounine 50048618fb4SAlexandre Bounine /* Clear interrupts */ 50148618fb4SAlexandre Bounine iowrite32(intval, 50248618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 50348618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 50448618fb4SAlexandre Bounine } 50548618fb4SAlexandre Bounine } 50648618fb4SAlexandre Bounine 50748618fb4SAlexandre Bounine if (dev_int & TSI721_DEV_INT_SMSG_CH) { 50848618fb4SAlexandre Bounine int ch; 50948618fb4SAlexandre Bounine 51048618fb4SAlexandre Bounine /* 51148618fb4SAlexandre Bounine * Service channel interrupts from Messaging Engine 51248618fb4SAlexandre Bounine */ 51348618fb4SAlexandre Bounine 51448618fb4SAlexandre Bounine if (dev_ch_int & TSI721_INT_IMSG_CHAN_M) { /* Inbound Msg */ 51548618fb4SAlexandre Bounine /* Disable signaled OB MSG Channel interrupts */ 51648618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 51748618fb4SAlexandre Bounine ch_inte &= ~(dev_ch_int & TSI721_INT_IMSG_CHAN_M); 51848618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE); 51948618fb4SAlexandre Bounine 52048618fb4SAlexandre Bounine /* 52148618fb4SAlexandre Bounine * Process Inbound Message interrupt for each MBOX 52248618fb4SAlexandre Bounine */ 52348618fb4SAlexandre Bounine for (ch = 4; ch < RIO_MAX_MBOX + 4; ch++) { 52448618fb4SAlexandre Bounine if (!(dev_ch_int & TSI721_INT_IMSG_CHAN(ch))) 52548618fb4SAlexandre Bounine continue; 52648618fb4SAlexandre Bounine tsi721_imsg_handler(priv, ch); 52748618fb4SAlexandre Bounine } 52848618fb4SAlexandre Bounine } 52948618fb4SAlexandre Bounine 53048618fb4SAlexandre Bounine if (dev_ch_int & TSI721_INT_OMSG_CHAN_M) { /* Outbound Msg */ 53148618fb4SAlexandre Bounine /* Disable signaled OB MSG Channel interrupts */ 53248618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 53348618fb4SAlexandre Bounine ch_inte &= ~(dev_ch_int & TSI721_INT_OMSG_CHAN_M); 53448618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE); 53548618fb4SAlexandre Bounine 53648618fb4SAlexandre Bounine /* 53748618fb4SAlexandre Bounine * Process Outbound Message interrupts for each MBOX 53848618fb4SAlexandre Bounine */ 53948618fb4SAlexandre Bounine 54048618fb4SAlexandre Bounine for (ch = 0; ch < RIO_MAX_MBOX; ch++) { 54148618fb4SAlexandre Bounine if (!(dev_ch_int & TSI721_INT_OMSG_CHAN(ch))) 54248618fb4SAlexandre Bounine continue; 54348618fb4SAlexandre Bounine tsi721_omsg_handler(priv, ch); 54448618fb4SAlexandre Bounine } 54548618fb4SAlexandre Bounine } 54648618fb4SAlexandre Bounine } 54748618fb4SAlexandre Bounine 54848618fb4SAlexandre Bounine if (dev_int & TSI721_DEV_INT_SRIO) { 54948618fb4SAlexandre Bounine /* Service SRIO MAC interrupts */ 55048618fb4SAlexandre Bounine intval = ioread32(priv->regs + TSI721_RIO_EM_INT_STAT); 55148618fb4SAlexandre Bounine if (intval & TSI721_RIO_EM_INT_STAT_PW_RX) 552748353ccSAlexandre Bounine tsi721_pw_handler(priv); 55348618fb4SAlexandre Bounine } 55448618fb4SAlexandre Bounine 5559eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 5569eaa3d9bSAlexandre Bounine if (dev_int & TSI721_DEV_INT_BDMA_CH) { 5579eaa3d9bSAlexandre Bounine int ch; 5589eaa3d9bSAlexandre Bounine 5599eaa3d9bSAlexandre Bounine if (dev_ch_int & TSI721_INT_BDMA_CHAN_M) { 56072d8a0d2SAlexandre Bounine tsi_debug(DMA, &priv->pdev->dev, 56172d8a0d2SAlexandre Bounine "IRQ from DMA channel 0x%08x", dev_ch_int); 5629eaa3d9bSAlexandre Bounine 5639eaa3d9bSAlexandre Bounine for (ch = 0; ch < TSI721_DMA_MAXCH; ch++) { 5649eaa3d9bSAlexandre Bounine if (!(dev_ch_int & TSI721_INT_BDMA_CHAN(ch))) 5659eaa3d9bSAlexandre Bounine continue; 5669eaa3d9bSAlexandre Bounine tsi721_bdma_handler(&priv->bdma[ch]); 5679eaa3d9bSAlexandre Bounine } 5689eaa3d9bSAlexandre Bounine } 5699eaa3d9bSAlexandre Bounine } 5709eaa3d9bSAlexandre Bounine #endif 5711ccc819dSAlexandre Bounine 5721ccc819dSAlexandre Bounine /* For MSI mode re-enable device-level interrupts */ 5731ccc819dSAlexandre Bounine if (priv->flags & TSI721_USING_MSI) { 5741ccc819dSAlexandre Bounine dev_int = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO | 5751ccc819dSAlexandre Bounine TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH; 5761ccc819dSAlexandre Bounine iowrite32(dev_int, priv->regs + TSI721_DEV_INTE); 5771ccc819dSAlexandre Bounine } 5781ccc819dSAlexandre Bounine 57948618fb4SAlexandre Bounine return IRQ_HANDLED; 58048618fb4SAlexandre Bounine } 58148618fb4SAlexandre Bounine 58248618fb4SAlexandre Bounine static void tsi721_interrupts_init(struct tsi721_device *priv) 58348618fb4SAlexandre Bounine { 58448618fb4SAlexandre Bounine u32 intr; 58548618fb4SAlexandre Bounine 58648618fb4SAlexandre Bounine /* Enable IDB interrupts */ 58748618fb4SAlexandre Bounine iowrite32(TSI721_SR_CHINT_ALL, 58848618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 58948618fb4SAlexandre Bounine iowrite32(TSI721_SR_CHINT_IDBQRCV, 59048618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); 59148618fb4SAlexandre Bounine 59248618fb4SAlexandre Bounine /* Enable SRIO MAC interrupts */ 59348618fb4SAlexandre Bounine iowrite32(TSI721_RIO_EM_DEV_INT_EN_INT, 59448618fb4SAlexandre Bounine priv->regs + TSI721_RIO_EM_DEV_INT_EN); 59548618fb4SAlexandre Bounine 5969eaa3d9bSAlexandre Bounine /* Enable interrupts from channels in use */ 5979eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 5989eaa3d9bSAlexandre Bounine intr = TSI721_INT_SR2PC_CHAN(IDB_QUEUE) | 5999eaa3d9bSAlexandre Bounine (TSI721_INT_BDMA_CHAN_M & 6009eaa3d9bSAlexandre Bounine ~TSI721_INT_BDMA_CHAN(TSI721_DMACH_MAINT)); 6019eaa3d9bSAlexandre Bounine #else 6029eaa3d9bSAlexandre Bounine intr = TSI721_INT_SR2PC_CHAN(IDB_QUEUE); 6039eaa3d9bSAlexandre Bounine #endif 6049eaa3d9bSAlexandre Bounine iowrite32(intr, priv->regs + TSI721_DEV_CHAN_INTE); 6059eaa3d9bSAlexandre Bounine 60648618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 60748618fb4SAlexandre Bounine intr = TSI721_DEV_INT_SRIO; 60848618fb4SAlexandre Bounine else 60948618fb4SAlexandre Bounine intr = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO | 6109eaa3d9bSAlexandre Bounine TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH; 61148618fb4SAlexandre Bounine 61248618fb4SAlexandre Bounine iowrite32(intr, priv->regs + TSI721_DEV_INTE); 61348618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_DEV_INTE); 61448618fb4SAlexandre Bounine } 61548618fb4SAlexandre Bounine 61648618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 61748618fb4SAlexandre Bounine /** 61848618fb4SAlexandre Bounine * tsi721_omsg_msix - MSI-X interrupt handler for outbound messaging 61948618fb4SAlexandre Bounine * @irq: Linux interrupt number 620748353ccSAlexandre Bounine * @ptr: Pointer to interrupt-specific data (tsi721_device structure) 62148618fb4SAlexandre Bounine * 62248618fb4SAlexandre Bounine * Handles outbound messaging interrupts signaled using MSI-X. 62348618fb4SAlexandre Bounine */ 62448618fb4SAlexandre Bounine static irqreturn_t tsi721_omsg_msix(int irq, void *ptr) 62548618fb4SAlexandre Bounine { 626748353ccSAlexandre Bounine struct tsi721_device *priv = (struct tsi721_device *)ptr; 62748618fb4SAlexandre Bounine int mbox; 62848618fb4SAlexandre Bounine 62948618fb4SAlexandre Bounine mbox = (irq - priv->msix[TSI721_VECT_OMB0_DONE].vector) % RIO_MAX_MBOX; 63048618fb4SAlexandre Bounine tsi721_omsg_handler(priv, mbox); 63148618fb4SAlexandre Bounine return IRQ_HANDLED; 63248618fb4SAlexandre Bounine } 63348618fb4SAlexandre Bounine 63448618fb4SAlexandre Bounine /** 63548618fb4SAlexandre Bounine * tsi721_imsg_msix - MSI-X interrupt handler for inbound messaging 63648618fb4SAlexandre Bounine * @irq: Linux interrupt number 637748353ccSAlexandre Bounine * @ptr: Pointer to interrupt-specific data (tsi721_device structure) 63848618fb4SAlexandre Bounine * 63948618fb4SAlexandre Bounine * Handles inbound messaging interrupts signaled using MSI-X. 64048618fb4SAlexandre Bounine */ 64148618fb4SAlexandre Bounine static irqreturn_t tsi721_imsg_msix(int irq, void *ptr) 64248618fb4SAlexandre Bounine { 643748353ccSAlexandre Bounine struct tsi721_device *priv = (struct tsi721_device *)ptr; 64448618fb4SAlexandre Bounine int mbox; 64548618fb4SAlexandre Bounine 64648618fb4SAlexandre Bounine mbox = (irq - priv->msix[TSI721_VECT_IMB0_RCV].vector) % RIO_MAX_MBOX; 64748618fb4SAlexandre Bounine tsi721_imsg_handler(priv, mbox + 4); 64848618fb4SAlexandre Bounine return IRQ_HANDLED; 64948618fb4SAlexandre Bounine } 65048618fb4SAlexandre Bounine 65148618fb4SAlexandre Bounine /** 65248618fb4SAlexandre Bounine * tsi721_srio_msix - Tsi721 MSI-X SRIO MAC interrupt handler 65348618fb4SAlexandre Bounine * @irq: Linux interrupt number 654748353ccSAlexandre Bounine * @ptr: Pointer to interrupt-specific data (tsi721_device structure) 65548618fb4SAlexandre Bounine * 65648618fb4SAlexandre Bounine * Handles Tsi721 interrupts from SRIO MAC. 65748618fb4SAlexandre Bounine */ 65848618fb4SAlexandre Bounine static irqreturn_t tsi721_srio_msix(int irq, void *ptr) 65948618fb4SAlexandre Bounine { 660748353ccSAlexandre Bounine struct tsi721_device *priv = (struct tsi721_device *)ptr; 66148618fb4SAlexandre Bounine u32 srio_int; 66248618fb4SAlexandre Bounine 66348618fb4SAlexandre Bounine /* Service SRIO MAC interrupts */ 66448618fb4SAlexandre Bounine srio_int = ioread32(priv->regs + TSI721_RIO_EM_INT_STAT); 66548618fb4SAlexandre Bounine if (srio_int & TSI721_RIO_EM_INT_STAT_PW_RX) 666748353ccSAlexandre Bounine tsi721_pw_handler(priv); 66748618fb4SAlexandre Bounine 66848618fb4SAlexandre Bounine return IRQ_HANDLED; 66948618fb4SAlexandre Bounine } 67048618fb4SAlexandre Bounine 67148618fb4SAlexandre Bounine /** 67248618fb4SAlexandre Bounine * tsi721_sr2pc_ch_msix - Tsi721 MSI-X SR2PC Channel interrupt handler 67348618fb4SAlexandre Bounine * @irq: Linux interrupt number 674748353ccSAlexandre Bounine * @ptr: Pointer to interrupt-specific data (tsi721_device structure) 67548618fb4SAlexandre Bounine * 67648618fb4SAlexandre Bounine * Handles Tsi721 interrupts from SR2PC Channel. 67748618fb4SAlexandre Bounine * NOTE: At this moment services only one SR2PC channel associated with inbound 67848618fb4SAlexandre Bounine * doorbells. 67948618fb4SAlexandre Bounine */ 68048618fb4SAlexandre Bounine static irqreturn_t tsi721_sr2pc_ch_msix(int irq, void *ptr) 68148618fb4SAlexandre Bounine { 682748353ccSAlexandre Bounine struct tsi721_device *priv = (struct tsi721_device *)ptr; 68348618fb4SAlexandre Bounine u32 sr_ch_int; 68448618fb4SAlexandre Bounine 68548618fb4SAlexandre Bounine /* Service Inbound DB interrupt from SR2PC channel */ 68648618fb4SAlexandre Bounine sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 68748618fb4SAlexandre Bounine if (sr_ch_int & TSI721_SR_CHINT_IDBQRCV) 688748353ccSAlexandre Bounine tsi721_dbell_handler(priv); 68948618fb4SAlexandre Bounine 69048618fb4SAlexandre Bounine /* Clear interrupts */ 69148618fb4SAlexandre Bounine iowrite32(sr_ch_int, priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 69248618fb4SAlexandre Bounine /* Read back to ensure that interrupt was cleared */ 69348618fb4SAlexandre Bounine sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 69448618fb4SAlexandre Bounine 69548618fb4SAlexandre Bounine return IRQ_HANDLED; 69648618fb4SAlexandre Bounine } 69748618fb4SAlexandre Bounine 69848618fb4SAlexandre Bounine /** 69948618fb4SAlexandre Bounine * tsi721_request_msix - register interrupt service for MSI-X mode. 700748353ccSAlexandre Bounine * @priv: tsi721 device-specific data structure 70148618fb4SAlexandre Bounine * 70248618fb4SAlexandre Bounine * Registers MSI-X interrupt service routines for interrupts that are active 70348618fb4SAlexandre Bounine * immediately after mport initialization. Messaging interrupt service routines 70448618fb4SAlexandre Bounine * should be registered during corresponding open requests. 70548618fb4SAlexandre Bounine */ 706748353ccSAlexandre Bounine static int tsi721_request_msix(struct tsi721_device *priv) 70748618fb4SAlexandre Bounine { 70848618fb4SAlexandre Bounine int err = 0; 70948618fb4SAlexandre Bounine 71048618fb4SAlexandre Bounine err = request_irq(priv->msix[TSI721_VECT_IDB].vector, 71148618fb4SAlexandre Bounine tsi721_sr2pc_ch_msix, 0, 712748353ccSAlexandre Bounine priv->msix[TSI721_VECT_IDB].irq_name, (void *)priv); 71348618fb4SAlexandre Bounine if (err) 714748353ccSAlexandre Bounine return err; 71548618fb4SAlexandre Bounine 71648618fb4SAlexandre Bounine err = request_irq(priv->msix[TSI721_VECT_PWRX].vector, 71748618fb4SAlexandre Bounine tsi721_srio_msix, 0, 718748353ccSAlexandre Bounine priv->msix[TSI721_VECT_PWRX].irq_name, (void *)priv); 719748353ccSAlexandre Bounine if (err) { 720748353ccSAlexandre Bounine free_irq(priv->msix[TSI721_VECT_IDB].vector, (void *)priv); 72148618fb4SAlexandre Bounine return err; 72248618fb4SAlexandre Bounine } 72348618fb4SAlexandre Bounine 724748353ccSAlexandre Bounine return 0; 725748353ccSAlexandre Bounine } 726748353ccSAlexandre Bounine 72748618fb4SAlexandre Bounine /** 72848618fb4SAlexandre Bounine * tsi721_enable_msix - Attempts to enable MSI-X support for Tsi721. 72948618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 73048618fb4SAlexandre Bounine * 73148618fb4SAlexandre Bounine * Configures MSI-X support for Tsi721. Supports only an exact number 73248618fb4SAlexandre Bounine * of requested vectors. 73348618fb4SAlexandre Bounine */ 73448618fb4SAlexandre Bounine static int tsi721_enable_msix(struct tsi721_device *priv) 73548618fb4SAlexandre Bounine { 73648618fb4SAlexandre Bounine struct msix_entry entries[TSI721_VECT_MAX]; 73748618fb4SAlexandre Bounine int err; 73848618fb4SAlexandre Bounine int i; 73948618fb4SAlexandre Bounine 74048618fb4SAlexandre Bounine entries[TSI721_VECT_IDB].entry = TSI721_MSIX_SR2PC_IDBQ_RCV(IDB_QUEUE); 74148618fb4SAlexandre Bounine entries[TSI721_VECT_PWRX].entry = TSI721_MSIX_SRIO_MAC_INT; 74248618fb4SAlexandre Bounine 74348618fb4SAlexandre Bounine /* 74448618fb4SAlexandre Bounine * Initialize MSI-X entries for Messaging Engine: 74548618fb4SAlexandre Bounine * this driver supports four RIO mailboxes (inbound and outbound) 74648618fb4SAlexandre Bounine * NOTE: Inbound message MBOX 0...4 use IB channels 4...7. Therefore 74748618fb4SAlexandre Bounine * offset +4 is added to IB MBOX number. 74848618fb4SAlexandre Bounine */ 74948618fb4SAlexandre Bounine for (i = 0; i < RIO_MAX_MBOX; i++) { 75048618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_RCV + i].entry = 75148618fb4SAlexandre Bounine TSI721_MSIX_IMSG_DQ_RCV(i + 4); 75248618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_INT + i].entry = 75348618fb4SAlexandre Bounine TSI721_MSIX_IMSG_INT(i + 4); 75448618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_DONE + i].entry = 75548618fb4SAlexandre Bounine TSI721_MSIX_OMSG_DONE(i); 75648618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_INT + i].entry = 75748618fb4SAlexandre Bounine TSI721_MSIX_OMSG_INT(i); 75848618fb4SAlexandre Bounine } 75948618fb4SAlexandre Bounine 7609eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 7619eaa3d9bSAlexandre Bounine /* 7629eaa3d9bSAlexandre Bounine * Initialize MSI-X entries for Block DMA Engine: 7639eaa3d9bSAlexandre Bounine * this driver supports XXX DMA channels 7649eaa3d9bSAlexandre Bounine * (one is reserved for SRIO maintenance transactions) 7659eaa3d9bSAlexandre Bounine */ 7669eaa3d9bSAlexandre Bounine for (i = 0; i < TSI721_DMA_CHNUM; i++) { 7679eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_DONE + i].entry = 7689eaa3d9bSAlexandre Bounine TSI721_MSIX_DMACH_DONE(i); 7699eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_INT + i].entry = 7709eaa3d9bSAlexandre Bounine TSI721_MSIX_DMACH_INT(i); 7719eaa3d9bSAlexandre Bounine } 7729eaa3d9bSAlexandre Bounine #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ 7739eaa3d9bSAlexandre Bounine 7741c92ab1eSAlexander Gordeev err = pci_enable_msix_exact(priv->pdev, entries, ARRAY_SIZE(entries)); 77548618fb4SAlexandre Bounine if (err) { 77672d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev, 77772d8a0d2SAlexandre Bounine "Failed to enable MSI-X (err=%d)", err); 77848618fb4SAlexandre Bounine return err; 77948618fb4SAlexandre Bounine } 78048618fb4SAlexandre Bounine 78148618fb4SAlexandre Bounine /* 78248618fb4SAlexandre Bounine * Copy MSI-X vector information into tsi721 private structure 78348618fb4SAlexandre Bounine */ 78448618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IDB].vector = entries[TSI721_VECT_IDB].vector; 78548618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_IDB].irq_name, IRQ_DEVICE_NAME_MAX, 78648618fb4SAlexandre Bounine DRV_NAME "-idb@pci:%s", pci_name(priv->pdev)); 78748618fb4SAlexandre Bounine priv->msix[TSI721_VECT_PWRX].vector = entries[TSI721_VECT_PWRX].vector; 78848618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_PWRX].irq_name, IRQ_DEVICE_NAME_MAX, 78948618fb4SAlexandre Bounine DRV_NAME "-pwrx@pci:%s", pci_name(priv->pdev)); 79048618fb4SAlexandre Bounine 79148618fb4SAlexandre Bounine for (i = 0; i < RIO_MAX_MBOX; i++) { 79248618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_RCV + i].vector = 79348618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_RCV + i].vector; 79448618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_IMB0_RCV + i].irq_name, 79548618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-imbr%d@pci:%s", 79648618fb4SAlexandre Bounine i, pci_name(priv->pdev)); 79748618fb4SAlexandre Bounine 79848618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_INT + i].vector = 79948618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_INT + i].vector; 80048618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_IMB0_INT + i].irq_name, 80148618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-imbi%d@pci:%s", 80248618fb4SAlexandre Bounine i, pci_name(priv->pdev)); 80348618fb4SAlexandre Bounine 80448618fb4SAlexandre Bounine priv->msix[TSI721_VECT_OMB0_DONE + i].vector = 80548618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_DONE + i].vector; 80648618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_OMB0_DONE + i].irq_name, 80748618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-ombd%d@pci:%s", 80848618fb4SAlexandre Bounine i, pci_name(priv->pdev)); 80948618fb4SAlexandre Bounine 81048618fb4SAlexandre Bounine priv->msix[TSI721_VECT_OMB0_INT + i].vector = 81148618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_INT + i].vector; 81248618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_OMB0_INT + i].irq_name, 81348618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-ombi%d@pci:%s", 81448618fb4SAlexandre Bounine i, pci_name(priv->pdev)); 81548618fb4SAlexandre Bounine } 81648618fb4SAlexandre Bounine 8179eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 8189eaa3d9bSAlexandre Bounine for (i = 0; i < TSI721_DMA_CHNUM; i++) { 8199eaa3d9bSAlexandre Bounine priv->msix[TSI721_VECT_DMA0_DONE + i].vector = 8209eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_DONE + i].vector; 8219eaa3d9bSAlexandre Bounine snprintf(priv->msix[TSI721_VECT_DMA0_DONE + i].irq_name, 8229eaa3d9bSAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-dmad%d@pci:%s", 8239eaa3d9bSAlexandre Bounine i, pci_name(priv->pdev)); 8249eaa3d9bSAlexandre Bounine 8259eaa3d9bSAlexandre Bounine priv->msix[TSI721_VECT_DMA0_INT + i].vector = 8269eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_INT + i].vector; 8279eaa3d9bSAlexandre Bounine snprintf(priv->msix[TSI721_VECT_DMA0_INT + i].irq_name, 8289eaa3d9bSAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-dmai%d@pci:%s", 8299eaa3d9bSAlexandre Bounine i, pci_name(priv->pdev)); 8309eaa3d9bSAlexandre Bounine } 8319eaa3d9bSAlexandre Bounine #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ 8329eaa3d9bSAlexandre Bounine 83348618fb4SAlexandre Bounine return 0; 83448618fb4SAlexandre Bounine } 83548618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 83648618fb4SAlexandre Bounine 837748353ccSAlexandre Bounine static int tsi721_request_irq(struct tsi721_device *priv) 83848618fb4SAlexandre Bounine { 83948618fb4SAlexandre Bounine int err; 84048618fb4SAlexandre Bounine 84148618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 84248618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 843748353ccSAlexandre Bounine err = tsi721_request_msix(priv); 84448618fb4SAlexandre Bounine else 84548618fb4SAlexandre Bounine #endif 84648618fb4SAlexandre Bounine err = request_irq(priv->pdev->irq, tsi721_irqhandler, 84748618fb4SAlexandre Bounine (priv->flags & TSI721_USING_MSI) ? 0 : IRQF_SHARED, 848748353ccSAlexandre Bounine DRV_NAME, (void *)priv); 84948618fb4SAlexandre Bounine 85048618fb4SAlexandre Bounine if (err) 85172d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev, 85272d8a0d2SAlexandre Bounine "Unable to allocate interrupt, err=%d", err); 85348618fb4SAlexandre Bounine 85448618fb4SAlexandre Bounine return err; 85548618fb4SAlexandre Bounine } 85648618fb4SAlexandre Bounine 857748353ccSAlexandre Bounine static void tsi721_free_irq(struct tsi721_device *priv) 858748353ccSAlexandre Bounine { 859748353ccSAlexandre Bounine #ifdef CONFIG_PCI_MSI 860748353ccSAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) { 861748353ccSAlexandre Bounine free_irq(priv->msix[TSI721_VECT_IDB].vector, (void *)priv); 862748353ccSAlexandre Bounine free_irq(priv->msix[TSI721_VECT_PWRX].vector, (void *)priv); 863748353ccSAlexandre Bounine } else 864748353ccSAlexandre Bounine #endif 865748353ccSAlexandre Bounine free_irq(priv->pdev->irq, (void *)priv); 866748353ccSAlexandre Bounine } 867748353ccSAlexandre Bounine 8681679e8daSAlexandre Bounine static int 8691679e8daSAlexandre Bounine tsi721_obw_alloc(struct tsi721_device *priv, struct tsi721_obw_bar *pbar, 8701679e8daSAlexandre Bounine u32 size, int *win_id) 8711679e8daSAlexandre Bounine { 8721679e8daSAlexandre Bounine u64 win_base; 8731679e8daSAlexandre Bounine u64 bar_base; 8741679e8daSAlexandre Bounine u64 bar_end; 8751679e8daSAlexandre Bounine u32 align; 8761679e8daSAlexandre Bounine struct tsi721_ob_win *win; 8771679e8daSAlexandre Bounine struct tsi721_ob_win *new_win = NULL; 8781679e8daSAlexandre Bounine int new_win_idx = -1; 8791679e8daSAlexandre Bounine int i = 0; 8801679e8daSAlexandre Bounine 8811679e8daSAlexandre Bounine bar_base = pbar->base; 8821679e8daSAlexandre Bounine bar_end = bar_base + pbar->size; 8831679e8daSAlexandre Bounine win_base = bar_base; 8841679e8daSAlexandre Bounine align = size/TSI721_PC2SR_ZONES; 8851679e8daSAlexandre Bounine 8861679e8daSAlexandre Bounine while (i < TSI721_IBWIN_NUM) { 8871679e8daSAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) { 8881679e8daSAlexandre Bounine if (!priv->ob_win[i].active) { 8891679e8daSAlexandre Bounine if (new_win == NULL) { 8901679e8daSAlexandre Bounine new_win = &priv->ob_win[i]; 8911679e8daSAlexandre Bounine new_win_idx = i; 8921679e8daSAlexandre Bounine } 8931679e8daSAlexandre Bounine continue; 8941679e8daSAlexandre Bounine } 8951679e8daSAlexandre Bounine 8961679e8daSAlexandre Bounine /* 8971679e8daSAlexandre Bounine * If this window belongs to the current BAR check it 8981679e8daSAlexandre Bounine * for overlap 8991679e8daSAlexandre Bounine */ 9001679e8daSAlexandre Bounine win = &priv->ob_win[i]; 9011679e8daSAlexandre Bounine 9021679e8daSAlexandre Bounine if (win->base >= bar_base && win->base < bar_end) { 9031679e8daSAlexandre Bounine if (win_base < (win->base + win->size) && 9041679e8daSAlexandre Bounine (win_base + size) > win->base) { 9051679e8daSAlexandre Bounine /* Overlap detected */ 9061679e8daSAlexandre Bounine win_base = win->base + win->size; 9071679e8daSAlexandre Bounine win_base = ALIGN(win_base, align); 9081679e8daSAlexandre Bounine break; 9091679e8daSAlexandre Bounine } 9101679e8daSAlexandre Bounine } 9111679e8daSAlexandre Bounine } 9121679e8daSAlexandre Bounine } 9131679e8daSAlexandre Bounine 9141679e8daSAlexandre Bounine if (win_base + size > bar_end) 9151679e8daSAlexandre Bounine return -ENOMEM; 9161679e8daSAlexandre Bounine 9171679e8daSAlexandre Bounine if (!new_win) { 91872d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev, "OBW count tracking failed"); 9191679e8daSAlexandre Bounine return -EIO; 9201679e8daSAlexandre Bounine } 9211679e8daSAlexandre Bounine 9221679e8daSAlexandre Bounine new_win->active = true; 9231679e8daSAlexandre Bounine new_win->base = win_base; 9241679e8daSAlexandre Bounine new_win->size = size; 9251679e8daSAlexandre Bounine new_win->pbar = pbar; 9261679e8daSAlexandre Bounine priv->obwin_cnt--; 9271679e8daSAlexandre Bounine pbar->free -= size; 9281679e8daSAlexandre Bounine *win_id = new_win_idx; 9291679e8daSAlexandre Bounine return 0; 9301679e8daSAlexandre Bounine } 9311679e8daSAlexandre Bounine 9321679e8daSAlexandre Bounine static int tsi721_map_outb_win(struct rio_mport *mport, u16 destid, u64 rstart, 9331679e8daSAlexandre Bounine u32 size, u32 flags, dma_addr_t *laddr) 9341679e8daSAlexandre Bounine { 9351679e8daSAlexandre Bounine struct tsi721_device *priv = mport->priv; 9361679e8daSAlexandre Bounine int i; 9371679e8daSAlexandre Bounine struct tsi721_obw_bar *pbar; 9381679e8daSAlexandre Bounine struct tsi721_ob_win *ob_win; 9391679e8daSAlexandre Bounine int obw = -1; 9401679e8daSAlexandre Bounine u32 rval; 9411679e8daSAlexandre Bounine u64 rio_addr; 9421679e8daSAlexandre Bounine u32 zsize; 9431679e8daSAlexandre Bounine int ret = -ENOMEM; 9441679e8daSAlexandre Bounine 94572d8a0d2SAlexandre Bounine tsi_debug(OBW, &priv->pdev->dev, 94672d8a0d2SAlexandre Bounine "did=%d ra=0x%llx sz=0x%x", destid, rstart, size); 94772d8a0d2SAlexandre Bounine 9481679e8daSAlexandre Bounine if (!is_power_of_2(size) || (size < 0x8000) || (rstart & (size - 1))) 9491679e8daSAlexandre Bounine return -EINVAL; 9501679e8daSAlexandre Bounine 9511679e8daSAlexandre Bounine if (priv->obwin_cnt == 0) 9521679e8daSAlexandre Bounine return -EBUSY; 9531679e8daSAlexandre Bounine 9541679e8daSAlexandre Bounine for (i = 0; i < 2; i++) { 9551679e8daSAlexandre Bounine if (priv->p2r_bar[i].free >= size) { 9561679e8daSAlexandre Bounine pbar = &priv->p2r_bar[i]; 9571679e8daSAlexandre Bounine ret = tsi721_obw_alloc(priv, pbar, size, &obw); 9581679e8daSAlexandre Bounine if (!ret) 9591679e8daSAlexandre Bounine break; 9601679e8daSAlexandre Bounine } 9611679e8daSAlexandre Bounine } 9621679e8daSAlexandre Bounine 9631679e8daSAlexandre Bounine if (ret) 9641679e8daSAlexandre Bounine return ret; 9651679e8daSAlexandre Bounine 9661679e8daSAlexandre Bounine WARN_ON(obw == -1); 9671679e8daSAlexandre Bounine ob_win = &priv->ob_win[obw]; 9681679e8daSAlexandre Bounine ob_win->destid = destid; 9691679e8daSAlexandre Bounine ob_win->rstart = rstart; 97072d8a0d2SAlexandre Bounine tsi_debug(OBW, &priv->pdev->dev, 97172d8a0d2SAlexandre Bounine "allocated OBW%d @%llx", obw, ob_win->base); 9721679e8daSAlexandre Bounine 9731679e8daSAlexandre Bounine /* 9741679e8daSAlexandre Bounine * Configure Outbound Window 9751679e8daSAlexandre Bounine */ 9761679e8daSAlexandre Bounine 9771679e8daSAlexandre Bounine zsize = size/TSI721_PC2SR_ZONES; 9781679e8daSAlexandre Bounine rio_addr = rstart; 9791679e8daSAlexandre Bounine 9801679e8daSAlexandre Bounine /* 9811679e8daSAlexandre Bounine * Program Address Translation Zones: 9821679e8daSAlexandre Bounine * This implementation uses all 8 zones associated wit window. 9831679e8daSAlexandre Bounine */ 9841679e8daSAlexandre Bounine for (i = 0; i < TSI721_PC2SR_ZONES; i++) { 9851679e8daSAlexandre Bounine 9861679e8daSAlexandre Bounine while (ioread32(priv->regs + TSI721_ZONE_SEL) & 9871679e8daSAlexandre Bounine TSI721_ZONE_SEL_GO) { 9881679e8daSAlexandre Bounine udelay(1); 9891679e8daSAlexandre Bounine } 9901679e8daSAlexandre Bounine 9911679e8daSAlexandre Bounine rval = (u32)(rio_addr & TSI721_LUT_DATA0_ADD) | 9921679e8daSAlexandre Bounine TSI721_LUT_DATA0_NREAD | TSI721_LUT_DATA0_NWR; 9931679e8daSAlexandre Bounine iowrite32(rval, priv->regs + TSI721_LUT_DATA0); 9941679e8daSAlexandre Bounine rval = (u32)(rio_addr >> 32); 9951679e8daSAlexandre Bounine iowrite32(rval, priv->regs + TSI721_LUT_DATA1); 9961679e8daSAlexandre Bounine rval = destid; 9971679e8daSAlexandre Bounine iowrite32(rval, priv->regs + TSI721_LUT_DATA2); 9981679e8daSAlexandre Bounine 9991679e8daSAlexandre Bounine rval = TSI721_ZONE_SEL_GO | (obw << 3) | i; 10001679e8daSAlexandre Bounine iowrite32(rval, priv->regs + TSI721_ZONE_SEL); 10011679e8daSAlexandre Bounine 10021679e8daSAlexandre Bounine rio_addr += zsize; 10031679e8daSAlexandre Bounine } 10041679e8daSAlexandre Bounine 10051679e8daSAlexandre Bounine iowrite32(TSI721_OBWIN_SIZE(size) << 8, 10061679e8daSAlexandre Bounine priv->regs + TSI721_OBWINSZ(obw)); 10071679e8daSAlexandre Bounine iowrite32((u32)(ob_win->base >> 32), priv->regs + TSI721_OBWINUB(obw)); 10081679e8daSAlexandre Bounine iowrite32((u32)(ob_win->base & TSI721_OBWINLB_BA) | TSI721_OBWINLB_WEN, 10091679e8daSAlexandre Bounine priv->regs + TSI721_OBWINLB(obw)); 10101679e8daSAlexandre Bounine 10111679e8daSAlexandre Bounine *laddr = ob_win->base; 10121679e8daSAlexandre Bounine return 0; 10131679e8daSAlexandre Bounine } 10141679e8daSAlexandre Bounine 10151679e8daSAlexandre Bounine static void tsi721_unmap_outb_win(struct rio_mport *mport, 10161679e8daSAlexandre Bounine u16 destid, u64 rstart) 10171679e8daSAlexandre Bounine { 10181679e8daSAlexandre Bounine struct tsi721_device *priv = mport->priv; 10191679e8daSAlexandre Bounine struct tsi721_ob_win *ob_win; 10201679e8daSAlexandre Bounine int i; 10211679e8daSAlexandre Bounine 102272d8a0d2SAlexandre Bounine tsi_debug(OBW, &priv->pdev->dev, "did=%d ra=0x%llx", destid, rstart); 102372d8a0d2SAlexandre Bounine 10241679e8daSAlexandre Bounine for (i = 0; i < TSI721_OBWIN_NUM; i++) { 10251679e8daSAlexandre Bounine ob_win = &priv->ob_win[i]; 10261679e8daSAlexandre Bounine 10271679e8daSAlexandre Bounine if (ob_win->active && 10281679e8daSAlexandre Bounine ob_win->destid == destid && ob_win->rstart == rstart) { 102972d8a0d2SAlexandre Bounine tsi_debug(OBW, &priv->pdev->dev, 103072d8a0d2SAlexandre Bounine "free OBW%d @%llx", i, ob_win->base); 10311679e8daSAlexandre Bounine ob_win->active = false; 10321679e8daSAlexandre Bounine iowrite32(0, priv->regs + TSI721_OBWINLB(i)); 10331679e8daSAlexandre Bounine ob_win->pbar->free += ob_win->size; 10341679e8daSAlexandre Bounine priv->obwin_cnt++; 10351679e8daSAlexandre Bounine break; 10361679e8daSAlexandre Bounine } 10371679e8daSAlexandre Bounine } 10381679e8daSAlexandre Bounine } 10391679e8daSAlexandre Bounine 104048618fb4SAlexandre Bounine /** 104148618fb4SAlexandre Bounine * tsi721_init_pc2sr_mapping - initializes outbound (PCIe->SRIO) 104248618fb4SAlexandre Bounine * translation regions. 104348618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 104448618fb4SAlexandre Bounine * 104548618fb4SAlexandre Bounine * Disables SREP translation regions. 104648618fb4SAlexandre Bounine */ 104748618fb4SAlexandre Bounine static void tsi721_init_pc2sr_mapping(struct tsi721_device *priv) 104848618fb4SAlexandre Bounine { 10491679e8daSAlexandre Bounine int i, z; 10501679e8daSAlexandre Bounine u32 rval; 105148618fb4SAlexandre Bounine 105248618fb4SAlexandre Bounine /* Disable all PC2SR translation windows */ 105348618fb4SAlexandre Bounine for (i = 0; i < TSI721_OBWIN_NUM; i++) 105448618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_OBWINLB(i)); 10551679e8daSAlexandre Bounine 10561679e8daSAlexandre Bounine /* Initialize zone lookup tables to avoid ECC errors on reads */ 10571679e8daSAlexandre Bounine iowrite32(0, priv->regs + TSI721_LUT_DATA0); 10581679e8daSAlexandre Bounine iowrite32(0, priv->regs + TSI721_LUT_DATA1); 10591679e8daSAlexandre Bounine iowrite32(0, priv->regs + TSI721_LUT_DATA2); 10601679e8daSAlexandre Bounine 10611679e8daSAlexandre Bounine for (i = 0; i < TSI721_OBWIN_NUM; i++) { 10621679e8daSAlexandre Bounine for (z = 0; z < TSI721_PC2SR_ZONES; z++) { 10631679e8daSAlexandre Bounine while (ioread32(priv->regs + TSI721_ZONE_SEL) & 10641679e8daSAlexandre Bounine TSI721_ZONE_SEL_GO) { 10651679e8daSAlexandre Bounine udelay(1); 10661679e8daSAlexandre Bounine } 10671679e8daSAlexandre Bounine rval = TSI721_ZONE_SEL_GO | (i << 3) | z; 10681679e8daSAlexandre Bounine iowrite32(rval, priv->regs + TSI721_ZONE_SEL); 10691679e8daSAlexandre Bounine } 10701679e8daSAlexandre Bounine } 10711679e8daSAlexandre Bounine 10721679e8daSAlexandre Bounine if (priv->p2r_bar[0].size == 0 && priv->p2r_bar[1].size == 0) { 10731679e8daSAlexandre Bounine priv->obwin_cnt = 0; 10741679e8daSAlexandre Bounine return; 10751679e8daSAlexandre Bounine } 10761679e8daSAlexandre Bounine 10771679e8daSAlexandre Bounine priv->p2r_bar[0].free = priv->p2r_bar[0].size; 10781679e8daSAlexandre Bounine priv->p2r_bar[1].free = priv->p2r_bar[1].size; 10791679e8daSAlexandre Bounine 10801679e8daSAlexandre Bounine for (i = 0; i < TSI721_OBWIN_NUM; i++) 10811679e8daSAlexandre Bounine priv->ob_win[i].active = false; 10821679e8daSAlexandre Bounine 10831679e8daSAlexandre Bounine priv->obwin_cnt = TSI721_OBWIN_NUM; 108448618fb4SAlexandre Bounine } 108548618fb4SAlexandre Bounine 108648618fb4SAlexandre Bounine /** 108771afe341SAlexandre Bounine * tsi721_rio_map_inb_mem -- Mapping inbound memory region. 108871afe341SAlexandre Bounine * @mport: RapidIO master port 108971afe341SAlexandre Bounine * @lstart: Local memory space start address. 109071afe341SAlexandre Bounine * @rstart: RapidIO space start address. 109171afe341SAlexandre Bounine * @size: The mapping region size. 109271afe341SAlexandre Bounine * @flags: Flags for mapping. 0 for using default flags. 109371afe341SAlexandre Bounine * 109471afe341SAlexandre Bounine * Return: 0 -- Success. 109571afe341SAlexandre Bounine * 109671afe341SAlexandre Bounine * This function will create the inbound mapping 109771afe341SAlexandre Bounine * from rstart to lstart. 109871afe341SAlexandre Bounine */ 109971afe341SAlexandre Bounine static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, 1100a057a52eSAlexandre Bounine u64 rstart, u64 size, u32 flags) 110171afe341SAlexandre Bounine { 110271afe341SAlexandre Bounine struct tsi721_device *priv = mport->priv; 1103ba5d141bSAlexandre Bounine int i, avail = -1; 110471afe341SAlexandre Bounine u32 regval; 1105ba5d141bSAlexandre Bounine struct tsi721_ib_win *ib_win; 11069673b883SAlexandre Bounine bool direct = (lstart == rstart); 11079673b883SAlexandre Bounine u64 ibw_size; 11089673b883SAlexandre Bounine dma_addr_t loc_start; 11099673b883SAlexandre Bounine u64 ibw_start; 11109673b883SAlexandre Bounine struct tsi721_ib_win_mapping *map = NULL; 1111ba5d141bSAlexandre Bounine int ret = -EBUSY; 111271afe341SAlexandre Bounine 1113a057a52eSAlexandre Bounine /* Max IBW size supported by HW is 16GB */ 1114a057a52eSAlexandre Bounine if (size > 0x400000000UL) 1115a057a52eSAlexandre Bounine return -EINVAL; 1116a057a52eSAlexandre Bounine 11179673b883SAlexandre Bounine if (direct) { 11189673b883SAlexandre Bounine /* Calculate minimal acceptable window size and base address */ 11199673b883SAlexandre Bounine 11209673b883SAlexandre Bounine ibw_size = roundup_pow_of_two(size); 11219673b883SAlexandre Bounine ibw_start = lstart & ~(ibw_size - 1); 11229673b883SAlexandre Bounine 112372d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev, 1124a057a52eSAlexandre Bounine "Direct (RIO_0x%llx -> PCIe_%pad), size=0x%llx, ibw_start = 0x%llx", 112572d8a0d2SAlexandre Bounine rstart, &lstart, size, ibw_start); 112672d8a0d2SAlexandre Bounine 11279673b883SAlexandre Bounine while ((lstart + size) > (ibw_start + ibw_size)) { 11289673b883SAlexandre Bounine ibw_size *= 2; 11299673b883SAlexandre Bounine ibw_start = lstart & ~(ibw_size - 1); 1130a057a52eSAlexandre Bounine /* Check for crossing IBW max size 16GB */ 1131a057a52eSAlexandre Bounine if (ibw_size > 0x400000000UL) 11329673b883SAlexandre Bounine return -EBUSY; 11339673b883SAlexandre Bounine } 11349673b883SAlexandre Bounine 11359673b883SAlexandre Bounine loc_start = ibw_start; 11369673b883SAlexandre Bounine 11379673b883SAlexandre Bounine map = kzalloc(sizeof(struct tsi721_ib_win_mapping), GFP_ATOMIC); 11389673b883SAlexandre Bounine if (map == NULL) 11399673b883SAlexandre Bounine return -ENOMEM; 11409673b883SAlexandre Bounine 11419673b883SAlexandre Bounine } else { 114272d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev, 1143a057a52eSAlexandre Bounine "Translated (RIO_0x%llx -> PCIe_%pad), size=0x%llx", 11449673b883SAlexandre Bounine rstart, &lstart, size); 11459673b883SAlexandre Bounine 114671afe341SAlexandre Bounine if (!is_power_of_2(size) || size < 0x1000 || 114771afe341SAlexandre Bounine ((u64)lstart & (size - 1)) || (rstart & (size - 1))) 114871afe341SAlexandre Bounine return -EINVAL; 11499673b883SAlexandre Bounine if (priv->ibwin_cnt == 0) 11509673b883SAlexandre Bounine return -EBUSY; 11519673b883SAlexandre Bounine ibw_start = rstart; 11529673b883SAlexandre Bounine ibw_size = size; 11539673b883SAlexandre Bounine loc_start = lstart; 11549673b883SAlexandre Bounine } 115571afe341SAlexandre Bounine 1156ba5d141bSAlexandre Bounine /* 1157ba5d141bSAlexandre Bounine * Scan for overlapping with active regions and mark the first available 1158ba5d141bSAlexandre Bounine * IB window at the same time. 1159ba5d141bSAlexandre Bounine */ 116071afe341SAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) { 1161ba5d141bSAlexandre Bounine ib_win = &priv->ib_win[i]; 11629673b883SAlexandre Bounine 1163ba5d141bSAlexandre Bounine if (!ib_win->active) { 1164ba5d141bSAlexandre Bounine if (avail == -1) { 1165ba5d141bSAlexandre Bounine avail = i; 1166ba5d141bSAlexandre Bounine ret = 0; 1167ba5d141bSAlexandre Bounine } 11689673b883SAlexandre Bounine } else if (ibw_start < (ib_win->rstart + ib_win->size) && 11699673b883SAlexandre Bounine (ibw_start + ibw_size) > ib_win->rstart) { 11709673b883SAlexandre Bounine /* Return error if address translation involved */ 1171b3006929SAlexandre Bounine if (!direct || ib_win->xlat) { 11729673b883SAlexandre Bounine ret = -EFAULT; 11739673b883SAlexandre Bounine break; 11749673b883SAlexandre Bounine } 11759673b883SAlexandre Bounine 11769673b883SAlexandre Bounine /* 11779673b883SAlexandre Bounine * Direct mappings usually are larger than originally 11789673b883SAlexandre Bounine * requested fragments - check if this new request fits 11799673b883SAlexandre Bounine * into it. 11809673b883SAlexandre Bounine */ 11819673b883SAlexandre Bounine if (rstart >= ib_win->rstart && 11829673b883SAlexandre Bounine (rstart + size) <= (ib_win->rstart + 11839673b883SAlexandre Bounine ib_win->size)) { 11849673b883SAlexandre Bounine /* We are in - no further mapping required */ 11859673b883SAlexandre Bounine map->lstart = lstart; 11869673b883SAlexandre Bounine list_add_tail(&map->node, &ib_win->mappings); 11879673b883SAlexandre Bounine return 0; 11889673b883SAlexandre Bounine } 11899673b883SAlexandre Bounine 1190ba5d141bSAlexandre Bounine ret = -EFAULT; 119171afe341SAlexandre Bounine break; 119271afe341SAlexandre Bounine } 119371afe341SAlexandre Bounine } 119471afe341SAlexandre Bounine 1195ba5d141bSAlexandre Bounine if (ret) 11969673b883SAlexandre Bounine goto out; 1197ba5d141bSAlexandre Bounine i = avail; 1198ba5d141bSAlexandre Bounine 1199ba5d141bSAlexandre Bounine /* Sanity check: available IB window must be disabled at this point */ 1200ba5d141bSAlexandre Bounine regval = ioread32(priv->regs + TSI721_IBWIN_LB(i)); 1201ba5d141bSAlexandre Bounine if (WARN_ON(regval & TSI721_IBWIN_LB_WEN)) { 1202ba5d141bSAlexandre Bounine ret = -EIO; 12039673b883SAlexandre Bounine goto out; 1204ba5d141bSAlexandre Bounine } 1205ba5d141bSAlexandre Bounine 1206ba5d141bSAlexandre Bounine ib_win = &priv->ib_win[i]; 1207ba5d141bSAlexandre Bounine ib_win->active = true; 12089673b883SAlexandre Bounine ib_win->rstart = ibw_start; 12099673b883SAlexandre Bounine ib_win->lstart = loc_start; 12109673b883SAlexandre Bounine ib_win->size = ibw_size; 12119673b883SAlexandre Bounine ib_win->xlat = (lstart != rstart); 12129673b883SAlexandre Bounine INIT_LIST_HEAD(&ib_win->mappings); 1213ba5d141bSAlexandre Bounine 12149673b883SAlexandre Bounine /* 12159673b883SAlexandre Bounine * When using direct IBW mapping and have larger than requested IBW size 12169673b883SAlexandre Bounine * we can have multiple local memory blocks mapped through the same IBW 12179673b883SAlexandre Bounine * To handle this situation we maintain list of "clients" for such IBWs. 12189673b883SAlexandre Bounine */ 12199673b883SAlexandre Bounine if (direct) { 12209673b883SAlexandre Bounine map->lstart = lstart; 12219673b883SAlexandre Bounine list_add_tail(&map->node, &ib_win->mappings); 12229673b883SAlexandre Bounine } 12239673b883SAlexandre Bounine 12249673b883SAlexandre Bounine iowrite32(TSI721_IBWIN_SIZE(ibw_size) << 8, 122571afe341SAlexandre Bounine priv->regs + TSI721_IBWIN_SZ(i)); 122671afe341SAlexandre Bounine 12279673b883SAlexandre Bounine iowrite32(((u64)loc_start >> 32), priv->regs + TSI721_IBWIN_TUA(i)); 12289673b883SAlexandre Bounine iowrite32(((u64)loc_start & TSI721_IBWIN_TLA_ADD), 122971afe341SAlexandre Bounine priv->regs + TSI721_IBWIN_TLA(i)); 123071afe341SAlexandre Bounine 12319673b883SAlexandre Bounine iowrite32(ibw_start >> 32, priv->regs + TSI721_IBWIN_UB(i)); 12329673b883SAlexandre Bounine iowrite32((ibw_start & TSI721_IBWIN_LB_BA) | TSI721_IBWIN_LB_WEN, 123371afe341SAlexandre Bounine priv->regs + TSI721_IBWIN_LB(i)); 12349673b883SAlexandre Bounine 12359673b883SAlexandre Bounine priv->ibwin_cnt--; 12369673b883SAlexandre Bounine 123772d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev, 1238ea87b8e1SJoe Perches "Configured IBWIN%d (RIO_0x%llx -> PCIe_%pad), size=0x%llx", 123972d8a0d2SAlexandre Bounine i, ibw_start, &loc_start, ibw_size); 124071afe341SAlexandre Bounine 124171afe341SAlexandre Bounine return 0; 12429673b883SAlexandre Bounine out: 12439673b883SAlexandre Bounine kfree(map); 1244ba5d141bSAlexandre Bounine return ret; 124571afe341SAlexandre Bounine } 124671afe341SAlexandre Bounine 124771afe341SAlexandre Bounine /** 12489673b883SAlexandre Bounine * tsi721_rio_unmap_inb_mem -- Unmapping inbound memory region. 124971afe341SAlexandre Bounine * @mport: RapidIO master port 125071afe341SAlexandre Bounine * @lstart: Local memory space start address. 125171afe341SAlexandre Bounine */ 125271afe341SAlexandre Bounine static void tsi721_rio_unmap_inb_mem(struct rio_mport *mport, 125371afe341SAlexandre Bounine dma_addr_t lstart) 125471afe341SAlexandre Bounine { 125571afe341SAlexandre Bounine struct tsi721_device *priv = mport->priv; 1256ba5d141bSAlexandre Bounine struct tsi721_ib_win *ib_win; 125771afe341SAlexandre Bounine int i; 125871afe341SAlexandre Bounine 125972d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev, 1260ea87b8e1SJoe Perches "Unmap IBW mapped to PCIe_%pad", &lstart); 12619673b883SAlexandre Bounine 126271afe341SAlexandre Bounine /* Search for matching active inbound translation window */ 126371afe341SAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) { 1264ba5d141bSAlexandre Bounine ib_win = &priv->ib_win[i]; 12659673b883SAlexandre Bounine 12669673b883SAlexandre Bounine /* Address translating IBWs must to be an exact march */ 12679673b883SAlexandre Bounine if (!ib_win->active || 12689673b883SAlexandre Bounine (ib_win->xlat && lstart != ib_win->lstart)) 12699673b883SAlexandre Bounine continue; 12709673b883SAlexandre Bounine 12719673b883SAlexandre Bounine if (lstart >= ib_win->lstart && 12729673b883SAlexandre Bounine lstart < (ib_win->lstart + ib_win->size)) { 12739673b883SAlexandre Bounine 12749673b883SAlexandre Bounine if (!ib_win->xlat) { 12759673b883SAlexandre Bounine struct tsi721_ib_win_mapping *map; 12769673b883SAlexandre Bounine int found = 0; 12779673b883SAlexandre Bounine 12789673b883SAlexandre Bounine list_for_each_entry(map, 12799673b883SAlexandre Bounine &ib_win->mappings, node) { 12809673b883SAlexandre Bounine if (map->lstart == lstart) { 12819673b883SAlexandre Bounine list_del(&map->node); 12829673b883SAlexandre Bounine kfree(map); 12839673b883SAlexandre Bounine found = 1; 128471afe341SAlexandre Bounine break; 128571afe341SAlexandre Bounine } 128671afe341SAlexandre Bounine } 12879673b883SAlexandre Bounine 12889673b883SAlexandre Bounine if (!found) 12899673b883SAlexandre Bounine continue; 12909673b883SAlexandre Bounine 12919673b883SAlexandre Bounine if (!list_empty(&ib_win->mappings)) 12929673b883SAlexandre Bounine break; 12939673b883SAlexandre Bounine } 12949673b883SAlexandre Bounine 129572d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev, "Disable IBWIN_%d", i); 12969673b883SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBWIN_LB(i)); 12979673b883SAlexandre Bounine ib_win->active = false; 12989673b883SAlexandre Bounine priv->ibwin_cnt++; 12999673b883SAlexandre Bounine break; 13009673b883SAlexandre Bounine } 13019673b883SAlexandre Bounine } 1302ba5d141bSAlexandre Bounine 1303ba5d141bSAlexandre Bounine if (i == TSI721_IBWIN_NUM) 130472d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev, 13059673b883SAlexandre Bounine "IB window mapped to %pad not found", &lstart); 130671afe341SAlexandre Bounine } 130771afe341SAlexandre Bounine 130871afe341SAlexandre Bounine /** 130948618fb4SAlexandre Bounine * tsi721_init_sr2pc_mapping - initializes inbound (SRIO->PCIe) 131048618fb4SAlexandre Bounine * translation regions. 131148618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 131248618fb4SAlexandre Bounine * 131348618fb4SAlexandre Bounine * Disables inbound windows. 131448618fb4SAlexandre Bounine */ 131548618fb4SAlexandre Bounine static void tsi721_init_sr2pc_mapping(struct tsi721_device *priv) 131648618fb4SAlexandre Bounine { 131748618fb4SAlexandre Bounine int i; 131848618fb4SAlexandre Bounine 131948618fb4SAlexandre Bounine /* Disable all SR2PC inbound windows */ 132048618fb4SAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) 132171afe341SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBWIN_LB(i)); 13229673b883SAlexandre Bounine priv->ibwin_cnt = TSI721_IBWIN_NUM; 132348618fb4SAlexandre Bounine } 132448618fb4SAlexandre Bounine 1325748353ccSAlexandre Bounine /* 1326748353ccSAlexandre Bounine * tsi721_close_sr2pc_mapping - closes all active inbound (SRIO->PCIe) 1327748353ccSAlexandre Bounine * translation regions. 1328748353ccSAlexandre Bounine * @priv: pointer to tsi721 device private data 1329748353ccSAlexandre Bounine */ 1330748353ccSAlexandre Bounine static void tsi721_close_sr2pc_mapping(struct tsi721_device *priv) 1331748353ccSAlexandre Bounine { 1332748353ccSAlexandre Bounine struct tsi721_ib_win *ib_win; 1333748353ccSAlexandre Bounine int i; 1334748353ccSAlexandre Bounine 1335748353ccSAlexandre Bounine /* Disable all active SR2PC inbound windows */ 1336748353ccSAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) { 1337748353ccSAlexandre Bounine ib_win = &priv->ib_win[i]; 1338748353ccSAlexandre Bounine if (ib_win->active) { 1339748353ccSAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBWIN_LB(i)); 1340748353ccSAlexandre Bounine ib_win->active = false; 1341748353ccSAlexandre Bounine } 1342748353ccSAlexandre Bounine } 1343748353ccSAlexandre Bounine } 1344748353ccSAlexandre Bounine 134548618fb4SAlexandre Bounine /** 134648618fb4SAlexandre Bounine * tsi721_port_write_init - Inbound port write interface init 134748618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 134848618fb4SAlexandre Bounine * 134948618fb4SAlexandre Bounine * Initializes inbound port write handler. 135048618fb4SAlexandre Bounine * Returns %0 on success or %-ENOMEM on failure. 135148618fb4SAlexandre Bounine */ 135248618fb4SAlexandre Bounine static int tsi721_port_write_init(struct tsi721_device *priv) 135348618fb4SAlexandre Bounine { 135448618fb4SAlexandre Bounine priv->pw_discard_count = 0; 135548618fb4SAlexandre Bounine INIT_WORK(&priv->pw_work, tsi721_pw_dpc); 135648618fb4SAlexandre Bounine spin_lock_init(&priv->pw_fifo_lock); 135748618fb4SAlexandre Bounine if (kfifo_alloc(&priv->pw_fifo, 135848618fb4SAlexandre Bounine TSI721_RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) { 135972d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev, "PW FIFO allocation failed"); 136048618fb4SAlexandre Bounine return -ENOMEM; 136148618fb4SAlexandre Bounine } 136248618fb4SAlexandre Bounine 136348618fb4SAlexandre Bounine /* Use reliable port-write capture mode */ 136448618fb4SAlexandre Bounine iowrite32(TSI721_RIO_PW_CTL_PWC_REL, priv->regs + TSI721_RIO_PW_CTL); 136548618fb4SAlexandre Bounine return 0; 136648618fb4SAlexandre Bounine } 136748618fb4SAlexandre Bounine 1368748353ccSAlexandre Bounine static void tsi721_port_write_free(struct tsi721_device *priv) 1369748353ccSAlexandre Bounine { 1370748353ccSAlexandre Bounine kfifo_free(&priv->pw_fifo); 1371748353ccSAlexandre Bounine } 1372748353ccSAlexandre Bounine 137348618fb4SAlexandre Bounine static int tsi721_doorbell_init(struct tsi721_device *priv) 137448618fb4SAlexandre Bounine { 137548618fb4SAlexandre Bounine /* Outbound Doorbells do not require any setup. 137648618fb4SAlexandre Bounine * Tsi721 uses dedicated PCI BAR1 to generate doorbells. 137748618fb4SAlexandre Bounine * That BAR1 was mapped during the probe routine. 137848618fb4SAlexandre Bounine */ 137948618fb4SAlexandre Bounine 138048618fb4SAlexandre Bounine /* Initialize Inbound Doorbell processing DPC and queue */ 138148618fb4SAlexandre Bounine priv->db_discard_count = 0; 138248618fb4SAlexandre Bounine INIT_WORK(&priv->idb_work, tsi721_db_dpc); 138348618fb4SAlexandre Bounine 138448618fb4SAlexandre Bounine /* Allocate buffer for inbound doorbells queue */ 1385ceb96398SAlexandre Bounine priv->idb_base = dma_zalloc_coherent(&priv->pdev->dev, 138648618fb4SAlexandre Bounine IDB_QSIZE * TSI721_IDB_ENTRY_SIZE, 138748618fb4SAlexandre Bounine &priv->idb_dma, GFP_KERNEL); 138848618fb4SAlexandre Bounine if (!priv->idb_base) 138948618fb4SAlexandre Bounine return -ENOMEM; 139048618fb4SAlexandre Bounine 139172d8a0d2SAlexandre Bounine tsi_debug(DBELL, &priv->pdev->dev, 139272d8a0d2SAlexandre Bounine "Allocated IDB buffer @ %p (phys = %pad)", 139372d8a0d2SAlexandre Bounine priv->idb_base, &priv->idb_dma); 139448618fb4SAlexandre Bounine 139548618fb4SAlexandre Bounine iowrite32(TSI721_IDQ_SIZE_VAL(IDB_QSIZE), 139648618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_SIZE(IDB_QUEUE)); 139748618fb4SAlexandre Bounine iowrite32(((u64)priv->idb_dma >> 32), 139848618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_BASEU(IDB_QUEUE)); 139948618fb4SAlexandre Bounine iowrite32(((u64)priv->idb_dma & TSI721_IDQ_BASEL_ADDR), 140048618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_BASEL(IDB_QUEUE)); 140148618fb4SAlexandre Bounine /* Enable accepting all inbound doorbells */ 140248618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IDQ_MASK(IDB_QUEUE)); 140348618fb4SAlexandre Bounine 140448618fb4SAlexandre Bounine iowrite32(TSI721_IDQ_INIT, priv->regs + TSI721_IDQ_CTL(IDB_QUEUE)); 140548618fb4SAlexandre Bounine 140648618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IDQ_RP(IDB_QUEUE)); 140748618fb4SAlexandre Bounine 140848618fb4SAlexandre Bounine return 0; 140948618fb4SAlexandre Bounine } 141048618fb4SAlexandre Bounine 141148618fb4SAlexandre Bounine static void tsi721_doorbell_free(struct tsi721_device *priv) 141248618fb4SAlexandre Bounine { 141348618fb4SAlexandre Bounine if (priv->idb_base == NULL) 141448618fb4SAlexandre Bounine return; 141548618fb4SAlexandre Bounine 141648618fb4SAlexandre Bounine /* Free buffer allocated for inbound doorbell queue */ 141748618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, IDB_QSIZE * TSI721_IDB_ENTRY_SIZE, 141848618fb4SAlexandre Bounine priv->idb_base, priv->idb_dma); 141948618fb4SAlexandre Bounine priv->idb_base = NULL; 142048618fb4SAlexandre Bounine } 142148618fb4SAlexandre Bounine 14229eaa3d9bSAlexandre Bounine /** 14239eaa3d9bSAlexandre Bounine * tsi721_bdma_maint_init - Initialize maintenance request BDMA channel. 14249eaa3d9bSAlexandre Bounine * @priv: pointer to tsi721 private data 14259eaa3d9bSAlexandre Bounine * 14269eaa3d9bSAlexandre Bounine * Initialize BDMA channel allocated for RapidIO maintenance read/write 14279eaa3d9bSAlexandre Bounine * request generation 14289eaa3d9bSAlexandre Bounine * Returns %0 on success or %-ENOMEM on failure. 14299eaa3d9bSAlexandre Bounine */ 14309eaa3d9bSAlexandre Bounine static int tsi721_bdma_maint_init(struct tsi721_device *priv) 143148618fb4SAlexandre Bounine { 143248618fb4SAlexandre Bounine struct tsi721_dma_desc *bd_ptr; 143348618fb4SAlexandre Bounine u64 *sts_ptr; 143448618fb4SAlexandre Bounine dma_addr_t bd_phys, sts_phys; 143548618fb4SAlexandre Bounine int sts_size; 14369eaa3d9bSAlexandre Bounine int bd_num = 2; 14379eaa3d9bSAlexandre Bounine void __iomem *regs; 143848618fb4SAlexandre Bounine 143972d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev, 144072d8a0d2SAlexandre Bounine "Init BDMA_%d Maintenance requests", TSI721_DMACH_MAINT); 144148618fb4SAlexandre Bounine 144248618fb4SAlexandre Bounine /* 144348618fb4SAlexandre Bounine * Initialize DMA channel for maintenance requests 144448618fb4SAlexandre Bounine */ 144548618fb4SAlexandre Bounine 14469eaa3d9bSAlexandre Bounine priv->mdma.ch_id = TSI721_DMACH_MAINT; 14479eaa3d9bSAlexandre Bounine regs = priv->regs + TSI721_DMAC_BASE(TSI721_DMACH_MAINT); 14489eaa3d9bSAlexandre Bounine 144948618fb4SAlexandre Bounine /* Allocate space for DMA descriptors */ 1450ceb96398SAlexandre Bounine bd_ptr = dma_zalloc_coherent(&priv->pdev->dev, 145148618fb4SAlexandre Bounine bd_num * sizeof(struct tsi721_dma_desc), 145248618fb4SAlexandre Bounine &bd_phys, GFP_KERNEL); 145348618fb4SAlexandre Bounine if (!bd_ptr) 145448618fb4SAlexandre Bounine return -ENOMEM; 145548618fb4SAlexandre Bounine 14569eaa3d9bSAlexandre Bounine priv->mdma.bd_num = bd_num; 14579eaa3d9bSAlexandre Bounine priv->mdma.bd_phys = bd_phys; 14589eaa3d9bSAlexandre Bounine priv->mdma.bd_base = bd_ptr; 145948618fb4SAlexandre Bounine 146072d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev, "DMA descriptors @ %p (phys = %pad)", 146172d8a0d2SAlexandre Bounine bd_ptr, &bd_phys); 146248618fb4SAlexandre Bounine 146348618fb4SAlexandre Bounine /* Allocate space for descriptor status FIFO */ 146448618fb4SAlexandre Bounine sts_size = (bd_num >= TSI721_DMA_MINSTSSZ) ? 146548618fb4SAlexandre Bounine bd_num : TSI721_DMA_MINSTSSZ; 146648618fb4SAlexandre Bounine sts_size = roundup_pow_of_two(sts_size); 1467ceb96398SAlexandre Bounine sts_ptr = dma_zalloc_coherent(&priv->pdev->dev, 146848618fb4SAlexandre Bounine sts_size * sizeof(struct tsi721_dma_sts), 146948618fb4SAlexandre Bounine &sts_phys, GFP_KERNEL); 147048618fb4SAlexandre Bounine if (!sts_ptr) { 147148618fb4SAlexandre Bounine /* Free space allocated for DMA descriptors */ 147248618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 147348618fb4SAlexandre Bounine bd_num * sizeof(struct tsi721_dma_desc), 147448618fb4SAlexandre Bounine bd_ptr, bd_phys); 14759eaa3d9bSAlexandre Bounine priv->mdma.bd_base = NULL; 147648618fb4SAlexandre Bounine return -ENOMEM; 147748618fb4SAlexandre Bounine } 147848618fb4SAlexandre Bounine 14799eaa3d9bSAlexandre Bounine priv->mdma.sts_phys = sts_phys; 14809eaa3d9bSAlexandre Bounine priv->mdma.sts_base = sts_ptr; 14819eaa3d9bSAlexandre Bounine priv->mdma.sts_size = sts_size; 148248618fb4SAlexandre Bounine 148372d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev, 148472d8a0d2SAlexandre Bounine "desc status FIFO @ %p (phys = %pad) size=0x%x", 148572d8a0d2SAlexandre Bounine sts_ptr, &sts_phys, sts_size); 148648618fb4SAlexandre Bounine 148748618fb4SAlexandre Bounine /* Initialize DMA descriptors ring */ 148848618fb4SAlexandre Bounine bd_ptr[bd_num - 1].type_id = cpu_to_le32(DTYPE3 << 29); 148948618fb4SAlexandre Bounine bd_ptr[bd_num - 1].next_lo = cpu_to_le32((u64)bd_phys & 149048618fb4SAlexandre Bounine TSI721_DMAC_DPTRL_MASK); 149148618fb4SAlexandre Bounine bd_ptr[bd_num - 1].next_hi = cpu_to_le32((u64)bd_phys >> 32); 149248618fb4SAlexandre Bounine 149348618fb4SAlexandre Bounine /* Setup DMA descriptor pointers */ 14949eaa3d9bSAlexandre Bounine iowrite32(((u64)bd_phys >> 32), regs + TSI721_DMAC_DPTRH); 149548618fb4SAlexandre Bounine iowrite32(((u64)bd_phys & TSI721_DMAC_DPTRL_MASK), 14969eaa3d9bSAlexandre Bounine regs + TSI721_DMAC_DPTRL); 149748618fb4SAlexandre Bounine 149848618fb4SAlexandre Bounine /* Setup descriptor status FIFO */ 14999eaa3d9bSAlexandre Bounine iowrite32(((u64)sts_phys >> 32), regs + TSI721_DMAC_DSBH); 150048618fb4SAlexandre Bounine iowrite32(((u64)sts_phys & TSI721_DMAC_DSBL_MASK), 15019eaa3d9bSAlexandre Bounine regs + TSI721_DMAC_DSBL); 150248618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(sts_size), 15039eaa3d9bSAlexandre Bounine regs + TSI721_DMAC_DSSZ); 150448618fb4SAlexandre Bounine 150548618fb4SAlexandre Bounine /* Clear interrupt bits */ 15069eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_INT_ALL, regs + TSI721_DMAC_INT); 150748618fb4SAlexandre Bounine 15089eaa3d9bSAlexandre Bounine ioread32(regs + TSI721_DMAC_INT); 150948618fb4SAlexandre Bounine 151048618fb4SAlexandre Bounine /* Toggle DMA channel initialization */ 15119eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL); 15129eaa3d9bSAlexandre Bounine ioread32(regs + TSI721_DMAC_CTL); 151348618fb4SAlexandre Bounine udelay(10); 151448618fb4SAlexandre Bounine 151548618fb4SAlexandre Bounine return 0; 151648618fb4SAlexandre Bounine } 151748618fb4SAlexandre Bounine 15189eaa3d9bSAlexandre Bounine static int tsi721_bdma_maint_free(struct tsi721_device *priv) 151948618fb4SAlexandre Bounine { 152048618fb4SAlexandre Bounine u32 ch_stat; 15219eaa3d9bSAlexandre Bounine struct tsi721_bdma_maint *mdma = &priv->mdma; 15229eaa3d9bSAlexandre Bounine void __iomem *regs = priv->regs + TSI721_DMAC_BASE(mdma->ch_id); 152348618fb4SAlexandre Bounine 15249eaa3d9bSAlexandre Bounine if (mdma->bd_base == NULL) 152548618fb4SAlexandre Bounine return 0; 152648618fb4SAlexandre Bounine 152748618fb4SAlexandre Bounine /* Check if DMA channel still running */ 15289eaa3d9bSAlexandre Bounine ch_stat = ioread32(regs + TSI721_DMAC_STS); 152948618fb4SAlexandre Bounine if (ch_stat & TSI721_DMAC_STS_RUN) 153048618fb4SAlexandre Bounine return -EFAULT; 153148618fb4SAlexandre Bounine 153248618fb4SAlexandre Bounine /* Put DMA channel into init state */ 15339eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL); 153448618fb4SAlexandre Bounine 153548618fb4SAlexandre Bounine /* Free space allocated for DMA descriptors */ 153648618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 15379eaa3d9bSAlexandre Bounine mdma->bd_num * sizeof(struct tsi721_dma_desc), 15389eaa3d9bSAlexandre Bounine mdma->bd_base, mdma->bd_phys); 15399eaa3d9bSAlexandre Bounine mdma->bd_base = NULL; 154048618fb4SAlexandre Bounine 154148618fb4SAlexandre Bounine /* Free space allocated for status FIFO */ 154248618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 15439eaa3d9bSAlexandre Bounine mdma->sts_size * sizeof(struct tsi721_dma_sts), 15449eaa3d9bSAlexandre Bounine mdma->sts_base, mdma->sts_phys); 15459eaa3d9bSAlexandre Bounine mdma->sts_base = NULL; 154648618fb4SAlexandre Bounine return 0; 154748618fb4SAlexandre Bounine } 154848618fb4SAlexandre Bounine 154948618fb4SAlexandre Bounine /* Enable Inbound Messaging Interrupts */ 155048618fb4SAlexandre Bounine static void 155148618fb4SAlexandre Bounine tsi721_imsg_interrupt_enable(struct tsi721_device *priv, int ch, 155248618fb4SAlexandre Bounine u32 inte_mask) 155348618fb4SAlexandre Bounine { 155448618fb4SAlexandre Bounine u32 rval; 155548618fb4SAlexandre Bounine 155648618fb4SAlexandre Bounine if (!inte_mask) 155748618fb4SAlexandre Bounine return; 155848618fb4SAlexandre Bounine 155948618fb4SAlexandre Bounine /* Clear pending Inbound Messaging interrupts */ 156048618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_IBDMAC_INT(ch)); 156148618fb4SAlexandre Bounine 156248618fb4SAlexandre Bounine /* Enable Inbound Messaging interrupts */ 156348618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_IBDMAC_INTE(ch)); 156448618fb4SAlexandre Bounine iowrite32(rval | inte_mask, priv->regs + TSI721_IBDMAC_INTE(ch)); 156548618fb4SAlexandre Bounine 156648618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 156748618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */ 156848618fb4SAlexandre Bounine 156948618fb4SAlexandre Bounine /* 157048618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to enable next levels 157148618fb4SAlexandre Bounine */ 157248618fb4SAlexandre Bounine 157348618fb4SAlexandre Bounine /* Enable Device Channel Interrupt */ 157448618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 157548618fb4SAlexandre Bounine iowrite32(rval | TSI721_INT_IMSG_CHAN(ch), 157648618fb4SAlexandre Bounine priv->regs + TSI721_DEV_CHAN_INTE); 157748618fb4SAlexandre Bounine } 157848618fb4SAlexandre Bounine 157948618fb4SAlexandre Bounine /* Disable Inbound Messaging Interrupts */ 158048618fb4SAlexandre Bounine static void 158148618fb4SAlexandre Bounine tsi721_imsg_interrupt_disable(struct tsi721_device *priv, int ch, 158248618fb4SAlexandre Bounine u32 inte_mask) 158348618fb4SAlexandre Bounine { 158448618fb4SAlexandre Bounine u32 rval; 158548618fb4SAlexandre Bounine 158648618fb4SAlexandre Bounine if (!inte_mask) 158748618fb4SAlexandre Bounine return; 158848618fb4SAlexandre Bounine 158948618fb4SAlexandre Bounine /* Clear pending Inbound Messaging interrupts */ 159048618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_IBDMAC_INT(ch)); 159148618fb4SAlexandre Bounine 159248618fb4SAlexandre Bounine /* Disable Inbound Messaging interrupts */ 159348618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_IBDMAC_INTE(ch)); 159448618fb4SAlexandre Bounine rval &= ~inte_mask; 159548618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_IBDMAC_INTE(ch)); 159648618fb4SAlexandre Bounine 159748618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 159848618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */ 159948618fb4SAlexandre Bounine 160048618fb4SAlexandre Bounine /* 160148618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to disable next levels 160248618fb4SAlexandre Bounine */ 160348618fb4SAlexandre Bounine 160448618fb4SAlexandre Bounine /* Disable Device Channel Interrupt */ 160548618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 160648618fb4SAlexandre Bounine rval &= ~TSI721_INT_IMSG_CHAN(ch); 160748618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_DEV_CHAN_INTE); 160848618fb4SAlexandre Bounine } 160948618fb4SAlexandre Bounine 161048618fb4SAlexandre Bounine /* Enable Outbound Messaging interrupts */ 161148618fb4SAlexandre Bounine static void 161248618fb4SAlexandre Bounine tsi721_omsg_interrupt_enable(struct tsi721_device *priv, int ch, 161348618fb4SAlexandre Bounine u32 inte_mask) 161448618fb4SAlexandre Bounine { 161548618fb4SAlexandre Bounine u32 rval; 161648618fb4SAlexandre Bounine 161748618fb4SAlexandre Bounine if (!inte_mask) 161848618fb4SAlexandre Bounine return; 161948618fb4SAlexandre Bounine 162048618fb4SAlexandre Bounine /* Clear pending Outbound Messaging interrupts */ 162148618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_OBDMAC_INT(ch)); 162248618fb4SAlexandre Bounine 162348618fb4SAlexandre Bounine /* Enable Outbound Messaging channel interrupts */ 162448618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_OBDMAC_INTE(ch)); 162548618fb4SAlexandre Bounine iowrite32(rval | inte_mask, priv->regs + TSI721_OBDMAC_INTE(ch)); 162648618fb4SAlexandre Bounine 162748618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 162848618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */ 162948618fb4SAlexandre Bounine 163048618fb4SAlexandre Bounine /* 163148618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to enable next levels 163248618fb4SAlexandre Bounine */ 163348618fb4SAlexandre Bounine 163448618fb4SAlexandre Bounine /* Enable Device Channel Interrupt */ 163548618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 163648618fb4SAlexandre Bounine iowrite32(rval | TSI721_INT_OMSG_CHAN(ch), 163748618fb4SAlexandre Bounine priv->regs + TSI721_DEV_CHAN_INTE); 163848618fb4SAlexandre Bounine } 163948618fb4SAlexandre Bounine 164048618fb4SAlexandre Bounine /* Disable Outbound Messaging interrupts */ 164148618fb4SAlexandre Bounine static void 164248618fb4SAlexandre Bounine tsi721_omsg_interrupt_disable(struct tsi721_device *priv, int ch, 164348618fb4SAlexandre Bounine u32 inte_mask) 164448618fb4SAlexandre Bounine { 164548618fb4SAlexandre Bounine u32 rval; 164648618fb4SAlexandre Bounine 164748618fb4SAlexandre Bounine if (!inte_mask) 164848618fb4SAlexandre Bounine return; 164948618fb4SAlexandre Bounine 165048618fb4SAlexandre Bounine /* Clear pending Outbound Messaging interrupts */ 165148618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_OBDMAC_INT(ch)); 165248618fb4SAlexandre Bounine 165348618fb4SAlexandre Bounine /* Disable Outbound Messaging interrupts */ 165448618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_OBDMAC_INTE(ch)); 165548618fb4SAlexandre Bounine rval &= ~inte_mask; 165648618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_OBDMAC_INTE(ch)); 165748618fb4SAlexandre Bounine 165848618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 165948618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */ 166048618fb4SAlexandre Bounine 166148618fb4SAlexandre Bounine /* 166248618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to disable next levels 166348618fb4SAlexandre Bounine */ 166448618fb4SAlexandre Bounine 166548618fb4SAlexandre Bounine /* Disable Device Channel Interrupt */ 166648618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 166748618fb4SAlexandre Bounine rval &= ~TSI721_INT_OMSG_CHAN(ch); 166848618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_DEV_CHAN_INTE); 166948618fb4SAlexandre Bounine } 167048618fb4SAlexandre Bounine 167148618fb4SAlexandre Bounine /** 167248618fb4SAlexandre Bounine * tsi721_add_outb_message - Add message to the Tsi721 outbound message queue 167348618fb4SAlexandre Bounine * @mport: Master port with outbound message queue 167448618fb4SAlexandre Bounine * @rdev: Target of outbound message 167548618fb4SAlexandre Bounine * @mbox: Outbound mailbox 167648618fb4SAlexandre Bounine * @buffer: Message to add to outbound queue 167748618fb4SAlexandre Bounine * @len: Length of message 167848618fb4SAlexandre Bounine */ 167948618fb4SAlexandre Bounine static int 168048618fb4SAlexandre Bounine tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, 168148618fb4SAlexandre Bounine void *buffer, size_t len) 168248618fb4SAlexandre Bounine { 168348618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 168448618fb4SAlexandre Bounine struct tsi721_omsg_desc *desc; 168548618fb4SAlexandre Bounine u32 tx_slot; 16862ece1cafSAlexandre Bounine unsigned long flags; 168748618fb4SAlexandre Bounine 168848618fb4SAlexandre Bounine if (!priv->omsg_init[mbox] || 168948618fb4SAlexandre Bounine len > TSI721_MSG_MAX_SIZE || len < 8) 169048618fb4SAlexandre Bounine return -EINVAL; 169148618fb4SAlexandre Bounine 16922ece1cafSAlexandre Bounine spin_lock_irqsave(&priv->omsg_ring[mbox].lock, flags); 16932ece1cafSAlexandre Bounine 169448618fb4SAlexandre Bounine tx_slot = priv->omsg_ring[mbox].tx_slot; 169548618fb4SAlexandre Bounine 169648618fb4SAlexandre Bounine /* Copy copy message into transfer buffer */ 169748618fb4SAlexandre Bounine memcpy(priv->omsg_ring[mbox].omq_base[tx_slot], buffer, len); 169848618fb4SAlexandre Bounine 169948618fb4SAlexandre Bounine if (len & 0x7) 170048618fb4SAlexandre Bounine len += 8; 170148618fb4SAlexandre Bounine 170248618fb4SAlexandre Bounine /* Build descriptor associated with buffer */ 170348618fb4SAlexandre Bounine desc = priv->omsg_ring[mbox].omd_base; 170448618fb4SAlexandre Bounine desc[tx_slot].type_id = cpu_to_le32((DTYPE4 << 29) | rdev->destid); 17052ece1cafSAlexandre Bounine #ifdef TSI721_OMSG_DESC_INT 17062ece1cafSAlexandre Bounine /* Request IOF_DONE interrupt generation for each N-th frame in queue */ 170748618fb4SAlexandre Bounine if (tx_slot % 4 == 0) 170848618fb4SAlexandre Bounine desc[tx_slot].type_id |= cpu_to_le32(TSI721_OMD_IOF); 17092ece1cafSAlexandre Bounine #endif 171048618fb4SAlexandre Bounine desc[tx_slot].msg_info = 171148618fb4SAlexandre Bounine cpu_to_le32((mport->sys_size << 26) | (mbox << 22) | 171248618fb4SAlexandre Bounine (0xe << 12) | (len & 0xff8)); 171348618fb4SAlexandre Bounine desc[tx_slot].bufptr_lo = 171448618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omq_phys[tx_slot] & 171548618fb4SAlexandre Bounine 0xffffffff); 171648618fb4SAlexandre Bounine desc[tx_slot].bufptr_hi = 171748618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omq_phys[tx_slot] >> 32); 171848618fb4SAlexandre Bounine 171948618fb4SAlexandre Bounine priv->omsg_ring[mbox].wr_count++; 172048618fb4SAlexandre Bounine 172148618fb4SAlexandre Bounine /* Go to next descriptor */ 172248618fb4SAlexandre Bounine if (++priv->omsg_ring[mbox].tx_slot == priv->omsg_ring[mbox].size) { 172348618fb4SAlexandre Bounine priv->omsg_ring[mbox].tx_slot = 0; 172448618fb4SAlexandre Bounine /* Move through the ring link descriptor at the end */ 172548618fb4SAlexandre Bounine priv->omsg_ring[mbox].wr_count++; 172648618fb4SAlexandre Bounine } 172748618fb4SAlexandre Bounine 172848618fb4SAlexandre Bounine mb(); 172948618fb4SAlexandre Bounine 173048618fb4SAlexandre Bounine /* Set new write count value */ 173148618fb4SAlexandre Bounine iowrite32(priv->omsg_ring[mbox].wr_count, 173248618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); 173348618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); 173448618fb4SAlexandre Bounine 17352ece1cafSAlexandre Bounine spin_unlock_irqrestore(&priv->omsg_ring[mbox].lock, flags); 17362ece1cafSAlexandre Bounine 173748618fb4SAlexandre Bounine return 0; 173848618fb4SAlexandre Bounine } 173948618fb4SAlexandre Bounine 174048618fb4SAlexandre Bounine /** 174148618fb4SAlexandre Bounine * tsi721_omsg_handler - Outbound Message Interrupt Handler 174248618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 174348618fb4SAlexandre Bounine * @ch: number of OB MSG channel to service 174448618fb4SAlexandre Bounine * 174548618fb4SAlexandre Bounine * Services channel interrupts from outbound messaging engine. 174648618fb4SAlexandre Bounine */ 174748618fb4SAlexandre Bounine static void tsi721_omsg_handler(struct tsi721_device *priv, int ch) 174848618fb4SAlexandre Bounine { 174948618fb4SAlexandre Bounine u32 omsg_int; 1750748353ccSAlexandre Bounine struct rio_mport *mport = &priv->mport; 17512ece1cafSAlexandre Bounine void *dev_id = NULL; 17522ece1cafSAlexandre Bounine u32 tx_slot = 0xffffffff; 17532ece1cafSAlexandre Bounine int do_callback = 0; 175448618fb4SAlexandre Bounine 175548618fb4SAlexandre Bounine spin_lock(&priv->omsg_ring[ch].lock); 175648618fb4SAlexandre Bounine 175748618fb4SAlexandre Bounine omsg_int = ioread32(priv->regs + TSI721_OBDMAC_INT(ch)); 175848618fb4SAlexandre Bounine 175948618fb4SAlexandre Bounine if (omsg_int & TSI721_OBDMAC_INT_ST_FULL) 176072d8a0d2SAlexandre Bounine tsi_info(&priv->pdev->dev, 176172d8a0d2SAlexandre Bounine "OB MBOX%d: Status FIFO is full", ch); 176248618fb4SAlexandre Bounine 176348618fb4SAlexandre Bounine if (omsg_int & (TSI721_OBDMAC_INT_DONE | TSI721_OBDMAC_INT_IOF_DONE)) { 176448618fb4SAlexandre Bounine u32 srd_ptr; 176548618fb4SAlexandre Bounine u64 *sts_ptr, last_ptr = 0, prev_ptr = 0; 176648618fb4SAlexandre Bounine int i, j; 176748618fb4SAlexandre Bounine 176848618fb4SAlexandre Bounine /* 176948618fb4SAlexandre Bounine * Find last successfully processed descriptor 177048618fb4SAlexandre Bounine */ 177148618fb4SAlexandre Bounine 177248618fb4SAlexandre Bounine /* Check and clear descriptor status FIFO entries */ 177348618fb4SAlexandre Bounine srd_ptr = priv->omsg_ring[ch].sts_rdptr; 177448618fb4SAlexandre Bounine sts_ptr = priv->omsg_ring[ch].sts_base; 177548618fb4SAlexandre Bounine j = srd_ptr * 8; 177648618fb4SAlexandre Bounine while (sts_ptr[j]) { 177748618fb4SAlexandre Bounine for (i = 0; i < 8 && sts_ptr[j]; i++, j++) { 177848618fb4SAlexandre Bounine prev_ptr = last_ptr; 177948618fb4SAlexandre Bounine last_ptr = le64_to_cpu(sts_ptr[j]); 178048618fb4SAlexandre Bounine sts_ptr[j] = 0; 178148618fb4SAlexandre Bounine } 178248618fb4SAlexandre Bounine 178348618fb4SAlexandre Bounine ++srd_ptr; 178448618fb4SAlexandre Bounine srd_ptr %= priv->omsg_ring[ch].sts_size; 178548618fb4SAlexandre Bounine j = srd_ptr * 8; 178648618fb4SAlexandre Bounine } 178748618fb4SAlexandre Bounine 178848618fb4SAlexandre Bounine if (last_ptr == 0) 178948618fb4SAlexandre Bounine goto no_sts_update; 179048618fb4SAlexandre Bounine 179148618fb4SAlexandre Bounine priv->omsg_ring[ch].sts_rdptr = srd_ptr; 179248618fb4SAlexandre Bounine iowrite32(srd_ptr, priv->regs + TSI721_OBDMAC_DSRP(ch)); 179348618fb4SAlexandre Bounine 1794748353ccSAlexandre Bounine if (!mport->outb_msg[ch].mcback) 179548618fb4SAlexandre Bounine goto no_sts_update; 179648618fb4SAlexandre Bounine 179748618fb4SAlexandre Bounine /* Inform upper layer about transfer completion */ 179848618fb4SAlexandre Bounine 179948618fb4SAlexandre Bounine tx_slot = (last_ptr - (u64)priv->omsg_ring[ch].omd_phys)/ 180048618fb4SAlexandre Bounine sizeof(struct tsi721_omsg_desc); 180148618fb4SAlexandre Bounine 180248618fb4SAlexandre Bounine /* 180348618fb4SAlexandre Bounine * Check if this is a Link Descriptor (LD). 180448618fb4SAlexandre Bounine * If yes, ignore LD and use descriptor processed 180548618fb4SAlexandre Bounine * before LD. 180648618fb4SAlexandre Bounine */ 180748618fb4SAlexandre Bounine if (tx_slot == priv->omsg_ring[ch].size) { 180848618fb4SAlexandre Bounine if (prev_ptr) 180948618fb4SAlexandre Bounine tx_slot = (prev_ptr - 181048618fb4SAlexandre Bounine (u64)priv->omsg_ring[ch].omd_phys)/ 181148618fb4SAlexandre Bounine sizeof(struct tsi721_omsg_desc); 181248618fb4SAlexandre Bounine else 181348618fb4SAlexandre Bounine goto no_sts_update; 181448618fb4SAlexandre Bounine } 181548618fb4SAlexandre Bounine 18162ece1cafSAlexandre Bounine if (tx_slot >= priv->omsg_ring[ch].size) 181772d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev, 18182ece1cafSAlexandre Bounine "OB_MSG tx_slot=%x > size=%x", 18192ece1cafSAlexandre Bounine tx_slot, priv->omsg_ring[ch].size); 18202ece1cafSAlexandre Bounine WARN_ON(tx_slot >= priv->omsg_ring[ch].size); 18212ece1cafSAlexandre Bounine 182248618fb4SAlexandre Bounine /* Move slot index to the next message to be sent */ 182348618fb4SAlexandre Bounine ++tx_slot; 182448618fb4SAlexandre Bounine if (tx_slot == priv->omsg_ring[ch].size) 182548618fb4SAlexandre Bounine tx_slot = 0; 18262ece1cafSAlexandre Bounine 18272ece1cafSAlexandre Bounine dev_id = priv->omsg_ring[ch].dev_id; 18282ece1cafSAlexandre Bounine do_callback = 1; 182948618fb4SAlexandre Bounine } 183048618fb4SAlexandre Bounine 183148618fb4SAlexandre Bounine no_sts_update: 183248618fb4SAlexandre Bounine 183348618fb4SAlexandre Bounine if (omsg_int & TSI721_OBDMAC_INT_ERROR) { 183448618fb4SAlexandre Bounine /* 183548618fb4SAlexandre Bounine * Outbound message operation aborted due to error, 183648618fb4SAlexandre Bounine * reinitialize OB MSG channel 183748618fb4SAlexandre Bounine */ 183848618fb4SAlexandre Bounine 183972d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev, "OB MSG ABORT ch_stat=%x", 184048618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_STS(ch))); 184148618fb4SAlexandre Bounine 184248618fb4SAlexandre Bounine iowrite32(TSI721_OBDMAC_INT_ERROR, 184348618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_INT(ch)); 18442ece1cafSAlexandre Bounine iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT, 184548618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_CTL(ch)); 184648618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_CTL(ch)); 184748618fb4SAlexandre Bounine 184848618fb4SAlexandre Bounine /* Inform upper level to clear all pending tx slots */ 18492ece1cafSAlexandre Bounine dev_id = priv->omsg_ring[ch].dev_id; 18502ece1cafSAlexandre Bounine tx_slot = priv->omsg_ring[ch].tx_slot; 18512ece1cafSAlexandre Bounine do_callback = 1; 18522ece1cafSAlexandre Bounine 185348618fb4SAlexandre Bounine /* Synch tx_slot tracking */ 185448618fb4SAlexandre Bounine iowrite32(priv->omsg_ring[ch].tx_slot, 185548618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DRDCNT(ch)); 185648618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_DRDCNT(ch)); 185748618fb4SAlexandre Bounine priv->omsg_ring[ch].wr_count = priv->omsg_ring[ch].tx_slot; 185848618fb4SAlexandre Bounine priv->omsg_ring[ch].sts_rdptr = 0; 185948618fb4SAlexandre Bounine } 186048618fb4SAlexandre Bounine 186148618fb4SAlexandre Bounine /* Clear channel interrupts */ 186248618fb4SAlexandre Bounine iowrite32(omsg_int, priv->regs + TSI721_OBDMAC_INT(ch)); 186348618fb4SAlexandre Bounine 186448618fb4SAlexandre Bounine if (!(priv->flags & TSI721_USING_MSIX)) { 186548618fb4SAlexandre Bounine u32 ch_inte; 186648618fb4SAlexandre Bounine 186748618fb4SAlexandre Bounine /* Re-enable channel interrupts */ 186848618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 186948618fb4SAlexandre Bounine ch_inte |= TSI721_INT_OMSG_CHAN(ch); 187048618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE); 187148618fb4SAlexandre Bounine } 187248618fb4SAlexandre Bounine 187348618fb4SAlexandre Bounine spin_unlock(&priv->omsg_ring[ch].lock); 18742ece1cafSAlexandre Bounine 18752ece1cafSAlexandre Bounine if (mport->outb_msg[ch].mcback && do_callback) 18762ece1cafSAlexandre Bounine mport->outb_msg[ch].mcback(mport, dev_id, ch, tx_slot); 187748618fb4SAlexandre Bounine } 187848618fb4SAlexandre Bounine 187948618fb4SAlexandre Bounine /** 188048618fb4SAlexandre Bounine * tsi721_open_outb_mbox - Initialize Tsi721 outbound mailbox 188148618fb4SAlexandre Bounine * @mport: Master port implementing Outbound Messaging Engine 188248618fb4SAlexandre Bounine * @dev_id: Device specific pointer to pass on event 188348618fb4SAlexandre Bounine * @mbox: Mailbox to open 188448618fb4SAlexandre Bounine * @entries: Number of entries in the outbound mailbox ring 188548618fb4SAlexandre Bounine */ 188648618fb4SAlexandre Bounine static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id, 188748618fb4SAlexandre Bounine int mbox, int entries) 188848618fb4SAlexandre Bounine { 188948618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 189048618fb4SAlexandre Bounine struct tsi721_omsg_desc *bd_ptr; 189148618fb4SAlexandre Bounine int i, rc = 0; 189248618fb4SAlexandre Bounine 189348618fb4SAlexandre Bounine if ((entries < TSI721_OMSGD_MIN_RING_SIZE) || 189448618fb4SAlexandre Bounine (entries > (TSI721_OMSGD_RING_SIZE)) || 189548618fb4SAlexandre Bounine (!is_power_of_2(entries)) || mbox >= RIO_MAX_MBOX) { 189648618fb4SAlexandre Bounine rc = -EINVAL; 189748618fb4SAlexandre Bounine goto out; 189848618fb4SAlexandre Bounine } 189948618fb4SAlexandre Bounine 1900e519685dSAlexandre Bounine if ((mbox_sel & (1 << mbox)) == 0) { 1901e519685dSAlexandre Bounine rc = -ENODEV; 1902e519685dSAlexandre Bounine goto out; 1903e519685dSAlexandre Bounine } 1904e519685dSAlexandre Bounine 190548618fb4SAlexandre Bounine priv->omsg_ring[mbox].dev_id = dev_id; 190648618fb4SAlexandre Bounine priv->omsg_ring[mbox].size = entries; 190748618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_rdptr = 0; 190848618fb4SAlexandre Bounine spin_lock_init(&priv->omsg_ring[mbox].lock); 190948618fb4SAlexandre Bounine 191048618fb4SAlexandre Bounine /* Outbound Msg Buffer allocation based on 191148618fb4SAlexandre Bounine the number of maximum descriptor entries */ 191248618fb4SAlexandre Bounine for (i = 0; i < entries; i++) { 191348618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i] = 191448618fb4SAlexandre Bounine dma_alloc_coherent( 191548618fb4SAlexandre Bounine &priv->pdev->dev, TSI721_MSG_BUFFER_SIZE, 191648618fb4SAlexandre Bounine &priv->omsg_ring[mbox].omq_phys[i], 191748618fb4SAlexandre Bounine GFP_KERNEL); 191848618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omq_base[i] == NULL) { 191972d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev, 192072d8a0d2SAlexandre Bounine "ENOMEM for OB_MSG_%d data buffer", mbox); 192148618fb4SAlexandre Bounine rc = -ENOMEM; 192248618fb4SAlexandre Bounine goto out_buf; 192348618fb4SAlexandre Bounine } 192448618fb4SAlexandre Bounine } 192548618fb4SAlexandre Bounine 192648618fb4SAlexandre Bounine /* Outbound message descriptor allocation */ 192748618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base = dma_alloc_coherent( 192848618fb4SAlexandre Bounine &priv->pdev->dev, 192948618fb4SAlexandre Bounine (entries + 1) * sizeof(struct tsi721_omsg_desc), 193048618fb4SAlexandre Bounine &priv->omsg_ring[mbox].omd_phys, GFP_KERNEL); 193148618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omd_base == NULL) { 193272d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev, 193372d8a0d2SAlexandre Bounine "ENOMEM for OB_MSG_%d descriptor memory", mbox); 193448618fb4SAlexandre Bounine rc = -ENOMEM; 193548618fb4SAlexandre Bounine goto out_buf; 193648618fb4SAlexandre Bounine } 193748618fb4SAlexandre Bounine 193848618fb4SAlexandre Bounine priv->omsg_ring[mbox].tx_slot = 0; 193948618fb4SAlexandre Bounine 194048618fb4SAlexandre Bounine /* Outbound message descriptor status FIFO allocation */ 194148618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size = roundup_pow_of_two(entries + 1); 1942ceb96398SAlexandre Bounine priv->omsg_ring[mbox].sts_base = dma_zalloc_coherent(&priv->pdev->dev, 194348618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size * 194448618fb4SAlexandre Bounine sizeof(struct tsi721_dma_sts), 194548618fb4SAlexandre Bounine &priv->omsg_ring[mbox].sts_phys, GFP_KERNEL); 194648618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].sts_base == NULL) { 194772d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev, 194872d8a0d2SAlexandre Bounine "ENOMEM for OB_MSG_%d status FIFO", mbox); 194948618fb4SAlexandre Bounine rc = -ENOMEM; 195048618fb4SAlexandre Bounine goto out_desc; 195148618fb4SAlexandre Bounine } 195248618fb4SAlexandre Bounine 195348618fb4SAlexandre Bounine /* 195448618fb4SAlexandre Bounine * Configure Outbound Messaging Engine 195548618fb4SAlexandre Bounine */ 195648618fb4SAlexandre Bounine 195748618fb4SAlexandre Bounine /* Setup Outbound Message descriptor pointer */ 195848618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].omd_phys >> 32), 195948618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DPTRH(mbox)); 196048618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].omd_phys & 196148618fb4SAlexandre Bounine TSI721_OBDMAC_DPTRL_MASK), 196248618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DPTRL(mbox)); 196348618fb4SAlexandre Bounine 196448618fb4SAlexandre Bounine /* Setup Outbound Message descriptor status FIFO */ 196548618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].sts_phys >> 32), 196648618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DSBH(mbox)); 196748618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].sts_phys & 196848618fb4SAlexandre Bounine TSI721_OBDMAC_DSBL_MASK), 196948618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DSBL(mbox)); 197048618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(priv->omsg_ring[mbox].sts_size), 197148618fb4SAlexandre Bounine priv->regs + (u32)TSI721_OBDMAC_DSSZ(mbox)); 197248618fb4SAlexandre Bounine 197348618fb4SAlexandre Bounine /* Enable interrupts */ 197448618fb4SAlexandre Bounine 197548618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 197648618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) { 1977748353ccSAlexandre Bounine int idx = TSI721_VECT_OMB0_DONE + mbox; 1978748353ccSAlexandre Bounine 197948618fb4SAlexandre Bounine /* Request interrupt service if we are in MSI-X mode */ 1980748353ccSAlexandre Bounine rc = request_irq(priv->msix[idx].vector, tsi721_omsg_msix, 0, 1981748353ccSAlexandre Bounine priv->msix[idx].irq_name, (void *)priv); 198248618fb4SAlexandre Bounine 198348618fb4SAlexandre Bounine if (rc) { 198472d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev, 198572d8a0d2SAlexandre Bounine "Unable to get MSI-X IRQ for OBOX%d-DONE", 198672d8a0d2SAlexandre Bounine mbox); 198748618fb4SAlexandre Bounine goto out_stat; 198848618fb4SAlexandre Bounine } 198948618fb4SAlexandre Bounine 1990748353ccSAlexandre Bounine idx = TSI721_VECT_OMB0_INT + mbox; 1991748353ccSAlexandre Bounine rc = request_irq(priv->msix[idx].vector, tsi721_omsg_msix, 0, 1992748353ccSAlexandre Bounine priv->msix[idx].irq_name, (void *)priv); 199348618fb4SAlexandre Bounine 199448618fb4SAlexandre Bounine if (rc) { 199572d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev, 199672d8a0d2SAlexandre Bounine "Unable to get MSI-X IRQ for MBOX%d-INT", mbox); 1997748353ccSAlexandre Bounine idx = TSI721_VECT_OMB0_DONE + mbox; 1998748353ccSAlexandre Bounine free_irq(priv->msix[idx].vector, (void *)priv); 199948618fb4SAlexandre Bounine goto out_stat; 200048618fb4SAlexandre Bounine } 200148618fb4SAlexandre Bounine } 200248618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 200348618fb4SAlexandre Bounine 200448618fb4SAlexandre Bounine tsi721_omsg_interrupt_enable(priv, mbox, TSI721_OBDMAC_INT_ALL); 200548618fb4SAlexandre Bounine 200648618fb4SAlexandre Bounine /* Initialize Outbound Message descriptors ring */ 200748618fb4SAlexandre Bounine bd_ptr = priv->omsg_ring[mbox].omd_base; 200848618fb4SAlexandre Bounine bd_ptr[entries].type_id = cpu_to_le32(DTYPE5 << 29); 200948618fb4SAlexandre Bounine bd_ptr[entries].msg_info = 0; 201048618fb4SAlexandre Bounine bd_ptr[entries].next_lo = 201148618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omd_phys & 201248618fb4SAlexandre Bounine TSI721_OBDMAC_DPTRL_MASK); 201348618fb4SAlexandre Bounine bd_ptr[entries].next_hi = 201448618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omd_phys >> 32); 201548618fb4SAlexandre Bounine priv->omsg_ring[mbox].wr_count = 0; 201648618fb4SAlexandre Bounine mb(); 201748618fb4SAlexandre Bounine 201848618fb4SAlexandre Bounine /* Initialize Outbound Message engine */ 20192ece1cafSAlexandre Bounine iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT, 20202ece1cafSAlexandre Bounine priv->regs + TSI721_OBDMAC_CTL(mbox)); 202148618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); 202248618fb4SAlexandre Bounine udelay(10); 202348618fb4SAlexandre Bounine 202448618fb4SAlexandre Bounine priv->omsg_init[mbox] = 1; 202548618fb4SAlexandre Bounine 202648618fb4SAlexandre Bounine return 0; 202748618fb4SAlexandre Bounine 202848618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 202948618fb4SAlexandre Bounine out_stat: 203048618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 203148618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts), 203248618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base, 203348618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_phys); 203448618fb4SAlexandre Bounine 203548618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base = NULL; 203648618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 203748618fb4SAlexandre Bounine 203848618fb4SAlexandre Bounine out_desc: 203948618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 204048618fb4SAlexandre Bounine (entries + 1) * sizeof(struct tsi721_omsg_desc), 204148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base, 204248618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_phys); 204348618fb4SAlexandre Bounine 204448618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base = NULL; 204548618fb4SAlexandre Bounine 204648618fb4SAlexandre Bounine out_buf: 204748618fb4SAlexandre Bounine for (i = 0; i < priv->omsg_ring[mbox].size; i++) { 204848618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omq_base[i]) { 204948618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 205048618fb4SAlexandre Bounine TSI721_MSG_BUFFER_SIZE, 205148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i], 205248618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_phys[i]); 205348618fb4SAlexandre Bounine 205448618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i] = NULL; 205548618fb4SAlexandre Bounine } 205648618fb4SAlexandre Bounine } 205748618fb4SAlexandre Bounine 205848618fb4SAlexandre Bounine out: 205948618fb4SAlexandre Bounine return rc; 206048618fb4SAlexandre Bounine } 206148618fb4SAlexandre Bounine 206248618fb4SAlexandre Bounine /** 206348618fb4SAlexandre Bounine * tsi721_close_outb_mbox - Close Tsi721 outbound mailbox 206448618fb4SAlexandre Bounine * @mport: Master port implementing the outbound message unit 206548618fb4SAlexandre Bounine * @mbox: Mailbox to close 206648618fb4SAlexandre Bounine */ 206748618fb4SAlexandre Bounine static void tsi721_close_outb_mbox(struct rio_mport *mport, int mbox) 206848618fb4SAlexandre Bounine { 206948618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 207048618fb4SAlexandre Bounine u32 i; 207148618fb4SAlexandre Bounine 207248618fb4SAlexandre Bounine if (!priv->omsg_init[mbox]) 207348618fb4SAlexandre Bounine return; 207448618fb4SAlexandre Bounine priv->omsg_init[mbox] = 0; 207548618fb4SAlexandre Bounine 207648618fb4SAlexandre Bounine /* Disable Interrupts */ 207748618fb4SAlexandre Bounine 207848618fb4SAlexandre Bounine tsi721_omsg_interrupt_disable(priv, mbox, TSI721_OBDMAC_INT_ALL); 207948618fb4SAlexandre Bounine 208048618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 208148618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) { 208248618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_OMB0_DONE + mbox].vector, 2083748353ccSAlexandre Bounine (void *)priv); 208448618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_OMB0_INT + mbox].vector, 2085748353ccSAlexandre Bounine (void *)priv); 208648618fb4SAlexandre Bounine } 208748618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 208848618fb4SAlexandre Bounine 208948618fb4SAlexandre Bounine /* Free OMSG Descriptor Status FIFO */ 209048618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 209148618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts), 209248618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base, 209348618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_phys); 209448618fb4SAlexandre Bounine 209548618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base = NULL; 209648618fb4SAlexandre Bounine 209748618fb4SAlexandre Bounine /* Free OMSG descriptors */ 209848618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 209948618fb4SAlexandre Bounine (priv->omsg_ring[mbox].size + 1) * 210048618fb4SAlexandre Bounine sizeof(struct tsi721_omsg_desc), 210148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base, 210248618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_phys); 210348618fb4SAlexandre Bounine 210448618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base = NULL; 210548618fb4SAlexandre Bounine 210648618fb4SAlexandre Bounine /* Free message buffers */ 210748618fb4SAlexandre Bounine for (i = 0; i < priv->omsg_ring[mbox].size; i++) { 210848618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omq_base[i]) { 210948618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 211048618fb4SAlexandre Bounine TSI721_MSG_BUFFER_SIZE, 211148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i], 211248618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_phys[i]); 211348618fb4SAlexandre Bounine 211448618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i] = NULL; 211548618fb4SAlexandre Bounine } 211648618fb4SAlexandre Bounine } 211748618fb4SAlexandre Bounine } 211848618fb4SAlexandre Bounine 211948618fb4SAlexandre Bounine /** 212048618fb4SAlexandre Bounine * tsi721_imsg_handler - Inbound Message Interrupt Handler 212148618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 212248618fb4SAlexandre Bounine * @ch: inbound message channel number to service 212348618fb4SAlexandre Bounine * 212448618fb4SAlexandre Bounine * Services channel interrupts from inbound messaging engine. 212548618fb4SAlexandre Bounine */ 212648618fb4SAlexandre Bounine static void tsi721_imsg_handler(struct tsi721_device *priv, int ch) 212748618fb4SAlexandre Bounine { 212848618fb4SAlexandre Bounine u32 mbox = ch - 4; 212948618fb4SAlexandre Bounine u32 imsg_int; 2130748353ccSAlexandre Bounine struct rio_mport *mport = &priv->mport; 213148618fb4SAlexandre Bounine 213248618fb4SAlexandre Bounine spin_lock(&priv->imsg_ring[mbox].lock); 213348618fb4SAlexandre Bounine 213448618fb4SAlexandre Bounine imsg_int = ioread32(priv->regs + TSI721_IBDMAC_INT(ch)); 213548618fb4SAlexandre Bounine 213648618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_SRTO) 213772d8a0d2SAlexandre Bounine tsi_info(&priv->pdev->dev, "IB MBOX%d SRIO timeout", mbox); 213848618fb4SAlexandre Bounine 213948618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_PC_ERROR) 214072d8a0d2SAlexandre Bounine tsi_info(&priv->pdev->dev, "IB MBOX%d PCIe error", mbox); 214148618fb4SAlexandre Bounine 214248618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_FQ_LOW) 214372d8a0d2SAlexandre Bounine tsi_info(&priv->pdev->dev, "IB MBOX%d IB free queue low", mbox); 214448618fb4SAlexandre Bounine 214548618fb4SAlexandre Bounine /* Clear IB channel interrupts */ 214648618fb4SAlexandre Bounine iowrite32(imsg_int, priv->regs + TSI721_IBDMAC_INT(ch)); 214748618fb4SAlexandre Bounine 214848618fb4SAlexandre Bounine /* If an IB Msg is received notify the upper layer */ 214948618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_DQ_RCV && 2150748353ccSAlexandre Bounine mport->inb_msg[mbox].mcback) 2151748353ccSAlexandre Bounine mport->inb_msg[mbox].mcback(mport, 215248618fb4SAlexandre Bounine priv->imsg_ring[mbox].dev_id, mbox, -1); 215348618fb4SAlexandre Bounine 215448618fb4SAlexandre Bounine if (!(priv->flags & TSI721_USING_MSIX)) { 215548618fb4SAlexandre Bounine u32 ch_inte; 215648618fb4SAlexandre Bounine 215748618fb4SAlexandre Bounine /* Re-enable channel interrupts */ 215848618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 215948618fb4SAlexandre Bounine ch_inte |= TSI721_INT_IMSG_CHAN(ch); 216048618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE); 216148618fb4SAlexandre Bounine } 216248618fb4SAlexandre Bounine 216348618fb4SAlexandre Bounine spin_unlock(&priv->imsg_ring[mbox].lock); 216448618fb4SAlexandre Bounine } 216548618fb4SAlexandre Bounine 216648618fb4SAlexandre Bounine /** 216748618fb4SAlexandre Bounine * tsi721_open_inb_mbox - Initialize Tsi721 inbound mailbox 216848618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine 216948618fb4SAlexandre Bounine * @dev_id: Device specific pointer to pass on event 217048618fb4SAlexandre Bounine * @mbox: Mailbox to open 217148618fb4SAlexandre Bounine * @entries: Number of entries in the inbound mailbox ring 217248618fb4SAlexandre Bounine */ 217348618fb4SAlexandre Bounine static int tsi721_open_inb_mbox(struct rio_mport *mport, void *dev_id, 217448618fb4SAlexandre Bounine int mbox, int entries) 217548618fb4SAlexandre Bounine { 217648618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 217748618fb4SAlexandre Bounine int ch = mbox + 4; 217848618fb4SAlexandre Bounine int i; 217948618fb4SAlexandre Bounine u64 *free_ptr; 218048618fb4SAlexandre Bounine int rc = 0; 218148618fb4SAlexandre Bounine 218248618fb4SAlexandre Bounine if ((entries < TSI721_IMSGD_MIN_RING_SIZE) || 218348618fb4SAlexandre Bounine (entries > TSI721_IMSGD_RING_SIZE) || 218448618fb4SAlexandre Bounine (!is_power_of_2(entries)) || mbox >= RIO_MAX_MBOX) { 218548618fb4SAlexandre Bounine rc = -EINVAL; 218648618fb4SAlexandre Bounine goto out; 218748618fb4SAlexandre Bounine } 218848618fb4SAlexandre Bounine 2189e519685dSAlexandre Bounine if ((mbox_sel & (1 << mbox)) == 0) { 2190e519685dSAlexandre Bounine rc = -ENODEV; 2191e519685dSAlexandre Bounine goto out; 2192e519685dSAlexandre Bounine } 2193e519685dSAlexandre Bounine 219448618fb4SAlexandre Bounine /* Initialize IB Messaging Ring */ 219548618fb4SAlexandre Bounine priv->imsg_ring[mbox].dev_id = dev_id; 219648618fb4SAlexandre Bounine priv->imsg_ring[mbox].size = entries; 219748618fb4SAlexandre Bounine priv->imsg_ring[mbox].rx_slot = 0; 219848618fb4SAlexandre Bounine priv->imsg_ring[mbox].desc_rdptr = 0; 219948618fb4SAlexandre Bounine priv->imsg_ring[mbox].fq_wrptr = 0; 220048618fb4SAlexandre Bounine for (i = 0; i < priv->imsg_ring[mbox].size; i++) 220148618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[i] = NULL; 220248618fb4SAlexandre Bounine spin_lock_init(&priv->imsg_ring[mbox].lock); 220348618fb4SAlexandre Bounine 220448618fb4SAlexandre Bounine /* Allocate buffers for incoming messages */ 220548618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base = 220648618fb4SAlexandre Bounine dma_alloc_coherent(&priv->pdev->dev, 220748618fb4SAlexandre Bounine entries * TSI721_MSG_BUFFER_SIZE, 220848618fb4SAlexandre Bounine &priv->imsg_ring[mbox].buf_phys, 220948618fb4SAlexandre Bounine GFP_KERNEL); 221048618fb4SAlexandre Bounine 221148618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].buf_base == NULL) { 221272d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev, 221372d8a0d2SAlexandre Bounine "Failed to allocate buffers for IB MBOX%d", mbox); 221448618fb4SAlexandre Bounine rc = -ENOMEM; 221548618fb4SAlexandre Bounine goto out; 221648618fb4SAlexandre Bounine } 221748618fb4SAlexandre Bounine 221848618fb4SAlexandre Bounine /* Allocate memory for circular free list */ 221948618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base = 222048618fb4SAlexandre Bounine dma_alloc_coherent(&priv->pdev->dev, 222148618fb4SAlexandre Bounine entries * 8, 222248618fb4SAlexandre Bounine &priv->imsg_ring[mbox].imfq_phys, 222348618fb4SAlexandre Bounine GFP_KERNEL); 222448618fb4SAlexandre Bounine 222548618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].imfq_base == NULL) { 222672d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev, 222772d8a0d2SAlexandre Bounine "Failed to allocate free queue for IB MBOX%d", mbox); 222848618fb4SAlexandre Bounine rc = -ENOMEM; 222948618fb4SAlexandre Bounine goto out_buf; 223048618fb4SAlexandre Bounine } 223148618fb4SAlexandre Bounine 223248618fb4SAlexandre Bounine /* Allocate memory for Inbound message descriptors */ 223348618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base = 223448618fb4SAlexandre Bounine dma_alloc_coherent(&priv->pdev->dev, 223548618fb4SAlexandre Bounine entries * sizeof(struct tsi721_imsg_desc), 223648618fb4SAlexandre Bounine &priv->imsg_ring[mbox].imd_phys, GFP_KERNEL); 223748618fb4SAlexandre Bounine 223848618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].imd_base == NULL) { 223972d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev, 224072d8a0d2SAlexandre Bounine "Failed to allocate descriptor memory for IB MBOX%d", 224148618fb4SAlexandre Bounine mbox); 224248618fb4SAlexandre Bounine rc = -ENOMEM; 224348618fb4SAlexandre Bounine goto out_dma; 224448618fb4SAlexandre Bounine } 224548618fb4SAlexandre Bounine 224648618fb4SAlexandre Bounine /* Fill free buffer pointer list */ 224748618fb4SAlexandre Bounine free_ptr = priv->imsg_ring[mbox].imfq_base; 224848618fb4SAlexandre Bounine for (i = 0; i < entries; i++) 224948618fb4SAlexandre Bounine free_ptr[i] = cpu_to_le64( 225048618fb4SAlexandre Bounine (u64)(priv->imsg_ring[mbox].buf_phys) + 225148618fb4SAlexandre Bounine i * 0x1000); 225248618fb4SAlexandre Bounine 225348618fb4SAlexandre Bounine mb(); 225448618fb4SAlexandre Bounine 225548618fb4SAlexandre Bounine /* 225648618fb4SAlexandre Bounine * For mapping of inbound SRIO Messages into appropriate queues we need 225748618fb4SAlexandre Bounine * to set Inbound Device ID register in the messaging engine. We do it 225848618fb4SAlexandre Bounine * once when first inbound mailbox is requested. 225948618fb4SAlexandre Bounine */ 226048618fb4SAlexandre Bounine if (!(priv->flags & TSI721_IMSGID_SET)) { 2261748353ccSAlexandre Bounine iowrite32((u32)priv->mport.host_deviceid, 226248618fb4SAlexandre Bounine priv->regs + TSI721_IB_DEVID); 226348618fb4SAlexandre Bounine priv->flags |= TSI721_IMSGID_SET; 226448618fb4SAlexandre Bounine } 226548618fb4SAlexandre Bounine 226648618fb4SAlexandre Bounine /* 226748618fb4SAlexandre Bounine * Configure Inbound Messaging channel (ch = mbox + 4) 226848618fb4SAlexandre Bounine */ 226948618fb4SAlexandre Bounine 227048618fb4SAlexandre Bounine /* Setup Inbound Message free queue */ 227148618fb4SAlexandre Bounine iowrite32(((u64)priv->imsg_ring[mbox].imfq_phys >> 32), 227248618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_FQBH(ch)); 227348618fb4SAlexandre Bounine iowrite32(((u64)priv->imsg_ring[mbox].imfq_phys & 227448618fb4SAlexandre Bounine TSI721_IBDMAC_FQBL_MASK), 227548618fb4SAlexandre Bounine priv->regs+TSI721_IBDMAC_FQBL(ch)); 227648618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(entries), 227748618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_FQSZ(ch)); 227848618fb4SAlexandre Bounine 227948618fb4SAlexandre Bounine /* Setup Inbound Message descriptor queue */ 228048618fb4SAlexandre Bounine iowrite32(((u64)priv->imsg_ring[mbox].imd_phys >> 32), 228148618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_DQBH(ch)); 228248618fb4SAlexandre Bounine iowrite32(((u32)priv->imsg_ring[mbox].imd_phys & 228348618fb4SAlexandre Bounine (u32)TSI721_IBDMAC_DQBL_MASK), 228448618fb4SAlexandre Bounine priv->regs+TSI721_IBDMAC_DQBL(ch)); 228548618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(entries), 228648618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_DQSZ(ch)); 228748618fb4SAlexandre Bounine 228848618fb4SAlexandre Bounine /* Enable interrupts */ 228948618fb4SAlexandre Bounine 229048618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 229148618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) { 2292748353ccSAlexandre Bounine int idx = TSI721_VECT_IMB0_RCV + mbox; 2293748353ccSAlexandre Bounine 229448618fb4SAlexandre Bounine /* Request interrupt service if we are in MSI-X mode */ 2295748353ccSAlexandre Bounine rc = request_irq(priv->msix[idx].vector, tsi721_imsg_msix, 0, 2296748353ccSAlexandre Bounine priv->msix[idx].irq_name, (void *)priv); 229748618fb4SAlexandre Bounine 229848618fb4SAlexandre Bounine if (rc) { 229972d8a0d2SAlexandre Bounine tsi_debug(IMSG, &priv->pdev->dev, 230072d8a0d2SAlexandre Bounine "Unable to get MSI-X IRQ for IBOX%d-DONE", 230172d8a0d2SAlexandre Bounine mbox); 230248618fb4SAlexandre Bounine goto out_desc; 230348618fb4SAlexandre Bounine } 230448618fb4SAlexandre Bounine 2305748353ccSAlexandre Bounine idx = TSI721_VECT_IMB0_INT + mbox; 2306748353ccSAlexandre Bounine rc = request_irq(priv->msix[idx].vector, tsi721_imsg_msix, 0, 2307748353ccSAlexandre Bounine priv->msix[idx].irq_name, (void *)priv); 230848618fb4SAlexandre Bounine 230948618fb4SAlexandre Bounine if (rc) { 231072d8a0d2SAlexandre Bounine tsi_debug(IMSG, &priv->pdev->dev, 231172d8a0d2SAlexandre Bounine "Unable to get MSI-X IRQ for IBOX%d-INT", mbox); 231248618fb4SAlexandre Bounine free_irq( 231348618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector, 2314748353ccSAlexandre Bounine (void *)priv); 231548618fb4SAlexandre Bounine goto out_desc; 231648618fb4SAlexandre Bounine } 231748618fb4SAlexandre Bounine } 231848618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 231948618fb4SAlexandre Bounine 232048618fb4SAlexandre Bounine tsi721_imsg_interrupt_enable(priv, ch, TSI721_IBDMAC_INT_ALL); 232148618fb4SAlexandre Bounine 232248618fb4SAlexandre Bounine /* Initialize Inbound Message Engine */ 232348618fb4SAlexandre Bounine iowrite32(TSI721_IBDMAC_CTL_INIT, priv->regs + TSI721_IBDMAC_CTL(ch)); 232448618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_IBDMAC_CTL(ch)); 232548618fb4SAlexandre Bounine udelay(10); 232648618fb4SAlexandre Bounine priv->imsg_ring[mbox].fq_wrptr = entries - 1; 232748618fb4SAlexandre Bounine iowrite32(entries - 1, priv->regs + TSI721_IBDMAC_FQWP(ch)); 232848618fb4SAlexandre Bounine 232948618fb4SAlexandre Bounine priv->imsg_init[mbox] = 1; 233048618fb4SAlexandre Bounine return 0; 233148618fb4SAlexandre Bounine 233248618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 233348618fb4SAlexandre Bounine out_desc: 233448618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 233548618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * sizeof(struct tsi721_imsg_desc), 233648618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base, 233748618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_phys); 233848618fb4SAlexandre Bounine 233948618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base = NULL; 234048618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 234148618fb4SAlexandre Bounine 234248618fb4SAlexandre Bounine out_dma: 234348618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 234448618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * 8, 234548618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base, 234648618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_phys); 234748618fb4SAlexandre Bounine 234848618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base = NULL; 234948618fb4SAlexandre Bounine 235048618fb4SAlexandre Bounine out_buf: 235148618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 235248618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * TSI721_MSG_BUFFER_SIZE, 235348618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base, 235448618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_phys); 235548618fb4SAlexandre Bounine 235648618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base = NULL; 235748618fb4SAlexandre Bounine 235848618fb4SAlexandre Bounine out: 235948618fb4SAlexandre Bounine return rc; 236048618fb4SAlexandre Bounine } 236148618fb4SAlexandre Bounine 236248618fb4SAlexandre Bounine /** 236348618fb4SAlexandre Bounine * tsi721_close_inb_mbox - Shut down Tsi721 inbound mailbox 236448618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine 236548618fb4SAlexandre Bounine * @mbox: Mailbox to close 236648618fb4SAlexandre Bounine */ 236748618fb4SAlexandre Bounine static void tsi721_close_inb_mbox(struct rio_mport *mport, int mbox) 236848618fb4SAlexandre Bounine { 236948618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 237048618fb4SAlexandre Bounine u32 rx_slot; 237148618fb4SAlexandre Bounine int ch = mbox + 4; 237248618fb4SAlexandre Bounine 237348618fb4SAlexandre Bounine if (!priv->imsg_init[mbox]) /* mbox isn't initialized yet */ 237448618fb4SAlexandre Bounine return; 237548618fb4SAlexandre Bounine priv->imsg_init[mbox] = 0; 237648618fb4SAlexandre Bounine 237748618fb4SAlexandre Bounine /* Disable Inbound Messaging Engine */ 237848618fb4SAlexandre Bounine 237948618fb4SAlexandre Bounine /* Disable Interrupts */ 238048618fb4SAlexandre Bounine tsi721_imsg_interrupt_disable(priv, ch, TSI721_OBDMAC_INT_MASK); 238148618fb4SAlexandre Bounine 238248618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 238348618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) { 238448618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector, 2385748353ccSAlexandre Bounine (void *)priv); 238648618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_IMB0_INT + mbox].vector, 2387748353ccSAlexandre Bounine (void *)priv); 238848618fb4SAlexandre Bounine } 238948618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 239048618fb4SAlexandre Bounine 239148618fb4SAlexandre Bounine /* Clear Inbound Buffer Queue */ 239248618fb4SAlexandre Bounine for (rx_slot = 0; rx_slot < priv->imsg_ring[mbox].size; rx_slot++) 239348618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[rx_slot] = NULL; 239448618fb4SAlexandre Bounine 239548618fb4SAlexandre Bounine /* Free memory allocated for message buffers */ 239648618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 239748618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * TSI721_MSG_BUFFER_SIZE, 239848618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base, 239948618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_phys); 240048618fb4SAlexandre Bounine 240148618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base = NULL; 240248618fb4SAlexandre Bounine 240348618fb4SAlexandre Bounine /* Free memory allocated for free pointr list */ 240448618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 240548618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * 8, 240648618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base, 240748618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_phys); 240848618fb4SAlexandre Bounine 240948618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base = NULL; 241048618fb4SAlexandre Bounine 241148618fb4SAlexandre Bounine /* Free memory allocated for RX descriptors */ 241248618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 241348618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * sizeof(struct tsi721_imsg_desc), 241448618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base, 241548618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_phys); 241648618fb4SAlexandre Bounine 241748618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base = NULL; 241848618fb4SAlexandre Bounine } 241948618fb4SAlexandre Bounine 242048618fb4SAlexandre Bounine /** 242148618fb4SAlexandre Bounine * tsi721_add_inb_buffer - Add buffer to the Tsi721 inbound message queue 242248618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine 242348618fb4SAlexandre Bounine * @mbox: Inbound mailbox number 242448618fb4SAlexandre Bounine * @buf: Buffer to add to inbound queue 242548618fb4SAlexandre Bounine */ 242648618fb4SAlexandre Bounine static int tsi721_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) 242748618fb4SAlexandre Bounine { 242848618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 242948618fb4SAlexandre Bounine u32 rx_slot; 243048618fb4SAlexandre Bounine int rc = 0; 243148618fb4SAlexandre Bounine 243248618fb4SAlexandre Bounine rx_slot = priv->imsg_ring[mbox].rx_slot; 243348618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].imq_base[rx_slot]) { 243472d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev, 243572d8a0d2SAlexandre Bounine "Error adding inbound buffer %d, buffer exists", 243648618fb4SAlexandre Bounine rx_slot); 243748618fb4SAlexandre Bounine rc = -EINVAL; 243848618fb4SAlexandre Bounine goto out; 243948618fb4SAlexandre Bounine } 244048618fb4SAlexandre Bounine 244148618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[rx_slot] = buf; 244248618fb4SAlexandre Bounine 244348618fb4SAlexandre Bounine if (++priv->imsg_ring[mbox].rx_slot == priv->imsg_ring[mbox].size) 244448618fb4SAlexandre Bounine priv->imsg_ring[mbox].rx_slot = 0; 244548618fb4SAlexandre Bounine 244648618fb4SAlexandre Bounine out: 244748618fb4SAlexandre Bounine return rc; 244848618fb4SAlexandre Bounine } 244948618fb4SAlexandre Bounine 245048618fb4SAlexandre Bounine /** 245148618fb4SAlexandre Bounine * tsi721_get_inb_message - Fetch inbound message from the Tsi721 MSG Queue 245248618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine 245348618fb4SAlexandre Bounine * @mbox: Inbound mailbox number 245448618fb4SAlexandre Bounine * 245548618fb4SAlexandre Bounine * Returns pointer to the message on success or NULL on failure. 245648618fb4SAlexandre Bounine */ 245748618fb4SAlexandre Bounine static void *tsi721_get_inb_message(struct rio_mport *mport, int mbox) 245848618fb4SAlexandre Bounine { 245948618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 246048618fb4SAlexandre Bounine struct tsi721_imsg_desc *desc; 246148618fb4SAlexandre Bounine u32 rx_slot; 246248618fb4SAlexandre Bounine void *rx_virt = NULL; 246348618fb4SAlexandre Bounine u64 rx_phys; 246448618fb4SAlexandre Bounine void *buf = NULL; 246548618fb4SAlexandre Bounine u64 *free_ptr; 246648618fb4SAlexandre Bounine int ch = mbox + 4; 246748618fb4SAlexandre Bounine int msg_size; 246848618fb4SAlexandre Bounine 246948618fb4SAlexandre Bounine if (!priv->imsg_init[mbox]) 247048618fb4SAlexandre Bounine return NULL; 247148618fb4SAlexandre Bounine 247248618fb4SAlexandre Bounine desc = priv->imsg_ring[mbox].imd_base; 247348618fb4SAlexandre Bounine desc += priv->imsg_ring[mbox].desc_rdptr; 247448618fb4SAlexandre Bounine 247548618fb4SAlexandre Bounine if (!(le32_to_cpu(desc->msg_info) & TSI721_IMD_HO)) 247648618fb4SAlexandre Bounine goto out; 247748618fb4SAlexandre Bounine 247848618fb4SAlexandre Bounine rx_slot = priv->imsg_ring[mbox].rx_slot; 247948618fb4SAlexandre Bounine while (priv->imsg_ring[mbox].imq_base[rx_slot] == NULL) { 248048618fb4SAlexandre Bounine if (++rx_slot == priv->imsg_ring[mbox].size) 248148618fb4SAlexandre Bounine rx_slot = 0; 248248618fb4SAlexandre Bounine } 248348618fb4SAlexandre Bounine 248448618fb4SAlexandre Bounine rx_phys = ((u64)le32_to_cpu(desc->bufptr_hi) << 32) | 248548618fb4SAlexandre Bounine le32_to_cpu(desc->bufptr_lo); 248648618fb4SAlexandre Bounine 248748618fb4SAlexandre Bounine rx_virt = priv->imsg_ring[mbox].buf_base + 248848618fb4SAlexandre Bounine (rx_phys - (u64)priv->imsg_ring[mbox].buf_phys); 248948618fb4SAlexandre Bounine 249048618fb4SAlexandre Bounine buf = priv->imsg_ring[mbox].imq_base[rx_slot]; 249148618fb4SAlexandre Bounine msg_size = le32_to_cpu(desc->msg_info) & TSI721_IMD_BCOUNT; 249248618fb4SAlexandre Bounine if (msg_size == 0) 249348618fb4SAlexandre Bounine msg_size = RIO_MAX_MSG_SIZE; 249448618fb4SAlexandre Bounine 249548618fb4SAlexandre Bounine memcpy(buf, rx_virt, msg_size); 249648618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[rx_slot] = NULL; 249748618fb4SAlexandre Bounine 249848618fb4SAlexandre Bounine desc->msg_info &= cpu_to_le32(~TSI721_IMD_HO); 249948618fb4SAlexandre Bounine if (++priv->imsg_ring[mbox].desc_rdptr == priv->imsg_ring[mbox].size) 250048618fb4SAlexandre Bounine priv->imsg_ring[mbox].desc_rdptr = 0; 250148618fb4SAlexandre Bounine 250248618fb4SAlexandre Bounine iowrite32(priv->imsg_ring[mbox].desc_rdptr, 250348618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_DQRP(ch)); 250448618fb4SAlexandre Bounine 250548618fb4SAlexandre Bounine /* Return free buffer into the pointer list */ 250648618fb4SAlexandre Bounine free_ptr = priv->imsg_ring[mbox].imfq_base; 250748618fb4SAlexandre Bounine free_ptr[priv->imsg_ring[mbox].fq_wrptr] = cpu_to_le64(rx_phys); 250848618fb4SAlexandre Bounine 250948618fb4SAlexandre Bounine if (++priv->imsg_ring[mbox].fq_wrptr == priv->imsg_ring[mbox].size) 251048618fb4SAlexandre Bounine priv->imsg_ring[mbox].fq_wrptr = 0; 251148618fb4SAlexandre Bounine 251248618fb4SAlexandre Bounine iowrite32(priv->imsg_ring[mbox].fq_wrptr, 251348618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_FQWP(ch)); 251448618fb4SAlexandre Bounine out: 251548618fb4SAlexandre Bounine return buf; 251648618fb4SAlexandre Bounine } 251748618fb4SAlexandre Bounine 251848618fb4SAlexandre Bounine /** 251948618fb4SAlexandre Bounine * tsi721_messages_init - Initialization of Messaging Engine 252048618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 252148618fb4SAlexandre Bounine * 252248618fb4SAlexandre Bounine * Configures Tsi721 messaging engine. 252348618fb4SAlexandre Bounine */ 252448618fb4SAlexandre Bounine static int tsi721_messages_init(struct tsi721_device *priv) 252548618fb4SAlexandre Bounine { 252648618fb4SAlexandre Bounine int ch; 252748618fb4SAlexandre Bounine 252848618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SMSG_ECC_LOG); 252948618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RETRY_GEN_CNT); 253048618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RETRY_RX_CNT); 253148618fb4SAlexandre Bounine 253248618fb4SAlexandre Bounine /* Set SRIO Message Request/Response Timeout */ 253348618fb4SAlexandre Bounine iowrite32(TSI721_RQRPTO_VAL, priv->regs + TSI721_RQRPTO); 253448618fb4SAlexandre Bounine 253548618fb4SAlexandre Bounine /* Initialize Inbound Messaging Engine Registers */ 253648618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_IMSG_CHNUM; ch++) { 253748618fb4SAlexandre Bounine /* Clear interrupt bits */ 253848618fb4SAlexandre Bounine iowrite32(TSI721_IBDMAC_INT_MASK, 253948618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_INT(ch)); 254048618fb4SAlexandre Bounine /* Clear Status */ 254148618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBDMAC_STS(ch)); 254248618fb4SAlexandre Bounine 254348618fb4SAlexandre Bounine iowrite32(TSI721_SMSG_ECC_COR_LOG_MASK, 254448618fb4SAlexandre Bounine priv->regs + TSI721_SMSG_ECC_COR_LOG(ch)); 254548618fb4SAlexandre Bounine iowrite32(TSI721_SMSG_ECC_NCOR_MASK, 254648618fb4SAlexandre Bounine priv->regs + TSI721_SMSG_ECC_NCOR(ch)); 254748618fb4SAlexandre Bounine } 254848618fb4SAlexandre Bounine 254948618fb4SAlexandre Bounine return 0; 255048618fb4SAlexandre Bounine } 255148618fb4SAlexandre Bounine 255248618fb4SAlexandre Bounine /** 2553dbe74afeSAlexandre Bounine * tsi721_query_mport - Fetch inbound message from the Tsi721 MSG Queue 2554dbe74afeSAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine 2555dbe74afeSAlexandre Bounine * @mbox: Inbound mailbox number 2556dbe74afeSAlexandre Bounine * 2557dbe74afeSAlexandre Bounine * Returns pointer to the message on success or NULL on failure. 2558dbe74afeSAlexandre Bounine */ 2559dbe74afeSAlexandre Bounine static int tsi721_query_mport(struct rio_mport *mport, 2560dbe74afeSAlexandre Bounine struct rio_mport_attr *attr) 2561dbe74afeSAlexandre Bounine { 2562dbe74afeSAlexandre Bounine struct tsi721_device *priv = mport->priv; 2563dbe74afeSAlexandre Bounine u32 rval; 2564dbe74afeSAlexandre Bounine 25651ae842deSAlexandre Bounine rval = ioread32(priv->regs + 0x100 + RIO_PORT_N_ERR_STS_CSR(0, 0)); 2566dbe74afeSAlexandre Bounine if (rval & RIO_PORT_N_ERR_STS_PORT_OK) { 25671ae842deSAlexandre Bounine rval = ioread32(priv->regs + 0x100 + RIO_PORT_N_CTL2_CSR(0, 0)); 2568dbe74afeSAlexandre Bounine attr->link_speed = (rval & RIO_PORT_N_CTL2_SEL_BAUD) >> 28; 25691ae842deSAlexandre Bounine rval = ioread32(priv->regs + 0x100 + RIO_PORT_N_CTL_CSR(0, 0)); 2570dbe74afeSAlexandre Bounine attr->link_width = (rval & RIO_PORT_N_CTL_IPW) >> 27; 2571dbe74afeSAlexandre Bounine } else 2572dbe74afeSAlexandre Bounine attr->link_speed = RIO_LINK_DOWN; 2573dbe74afeSAlexandre Bounine 2574dbe74afeSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 2575dbe74afeSAlexandre Bounine attr->flags = RIO_MPORT_DMA | RIO_MPORT_DMA_SG; 2576dbe74afeSAlexandre Bounine attr->dma_max_sge = 0; 2577dbe74afeSAlexandre Bounine attr->dma_max_size = TSI721_BDMA_MAX_BCOUNT; 2578dbe74afeSAlexandre Bounine attr->dma_align = 0; 2579dbe74afeSAlexandre Bounine #else 2580dbe74afeSAlexandre Bounine attr->flags = 0; 2581dbe74afeSAlexandre Bounine #endif 2582dbe74afeSAlexandre Bounine return 0; 2583dbe74afeSAlexandre Bounine } 2584dbe74afeSAlexandre Bounine 2585dbe74afeSAlexandre Bounine /** 258648618fb4SAlexandre Bounine * tsi721_disable_ints - disables all device interrupts 258748618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 258848618fb4SAlexandre Bounine */ 258948618fb4SAlexandre Bounine static void tsi721_disable_ints(struct tsi721_device *priv) 259048618fb4SAlexandre Bounine { 259148618fb4SAlexandre Bounine int ch; 259248618fb4SAlexandre Bounine 259348618fb4SAlexandre Bounine /* Disable all device level interrupts */ 259448618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_DEV_INTE); 259548618fb4SAlexandre Bounine 259648618fb4SAlexandre Bounine /* Disable all Device Channel interrupts */ 259748618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_DEV_CHAN_INTE); 259848618fb4SAlexandre Bounine 259948618fb4SAlexandre Bounine /* Disable all Inbound Msg Channel interrupts */ 260048618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_IMSG_CHNUM; ch++) 260148618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBDMAC_INTE(ch)); 260248618fb4SAlexandre Bounine 260348618fb4SAlexandre Bounine /* Disable all Outbound Msg Channel interrupts */ 260448618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_OMSG_CHNUM; ch++) 260548618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_OBDMAC_INTE(ch)); 260648618fb4SAlexandre Bounine 260748618fb4SAlexandre Bounine /* Disable all general messaging interrupts */ 260848618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SMSG_INTE); 260948618fb4SAlexandre Bounine 261048618fb4SAlexandre Bounine /* Disable all BDMA Channel interrupts */ 261148618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_DMA_MAXCH; ch++) 26129eaa3d9bSAlexandre Bounine iowrite32(0, 26139eaa3d9bSAlexandre Bounine priv->regs + TSI721_DMAC_BASE(ch) + TSI721_DMAC_INTE); 261448618fb4SAlexandre Bounine 261548618fb4SAlexandre Bounine /* Disable all general BDMA interrupts */ 261648618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_BDMA_INTE); 261748618fb4SAlexandre Bounine 261848618fb4SAlexandre Bounine /* Disable all SRIO Channel interrupts */ 261948618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_SRIO_MAXCH; ch++) 262048618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SR_CHINTE(ch)); 262148618fb4SAlexandre Bounine 262248618fb4SAlexandre Bounine /* Disable all general SR2PC interrupts */ 262348618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SR2PC_GEN_INTE); 262448618fb4SAlexandre Bounine 262548618fb4SAlexandre Bounine /* Disable all PC2SR interrupts */ 262648618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_PC2SR_INTE); 262748618fb4SAlexandre Bounine 262848618fb4SAlexandre Bounine /* Disable all I2C interrupts */ 262948618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_I2C_INT_ENABLE); 263048618fb4SAlexandre Bounine 263148618fb4SAlexandre Bounine /* Disable SRIO MAC interrupts */ 263248618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RIO_EM_INT_ENABLE); 263348618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RIO_EM_DEV_INT_EN); 263448618fb4SAlexandre Bounine } 263548618fb4SAlexandre Bounine 2636748353ccSAlexandre Bounine static struct rio_ops tsi721_rio_ops = { 2637748353ccSAlexandre Bounine .lcread = tsi721_lcread, 2638748353ccSAlexandre Bounine .lcwrite = tsi721_lcwrite, 2639748353ccSAlexandre Bounine .cread = tsi721_cread_dma, 2640748353ccSAlexandre Bounine .cwrite = tsi721_cwrite_dma, 2641748353ccSAlexandre Bounine .dsend = tsi721_dsend, 2642748353ccSAlexandre Bounine .open_inb_mbox = tsi721_open_inb_mbox, 2643748353ccSAlexandre Bounine .close_inb_mbox = tsi721_close_inb_mbox, 2644748353ccSAlexandre Bounine .open_outb_mbox = tsi721_open_outb_mbox, 2645748353ccSAlexandre Bounine .close_outb_mbox = tsi721_close_outb_mbox, 2646748353ccSAlexandre Bounine .add_outb_message = tsi721_add_outb_message, 2647748353ccSAlexandre Bounine .add_inb_buffer = tsi721_add_inb_buffer, 2648748353ccSAlexandre Bounine .get_inb_message = tsi721_get_inb_message, 2649748353ccSAlexandre Bounine .map_inb = tsi721_rio_map_inb_mem, 2650748353ccSAlexandre Bounine .unmap_inb = tsi721_rio_unmap_inb_mem, 2651748353ccSAlexandre Bounine .pwenable = tsi721_pw_enable, 2652748353ccSAlexandre Bounine .query_mport = tsi721_query_mport, 26531679e8daSAlexandre Bounine .map_outb = tsi721_map_outb_win, 26541679e8daSAlexandre Bounine .unmap_outb = tsi721_unmap_outb_win, 2655748353ccSAlexandre Bounine }; 2656748353ccSAlexandre Bounine 2657748353ccSAlexandre Bounine static void tsi721_mport_release(struct device *dev) 2658748353ccSAlexandre Bounine { 2659748353ccSAlexandre Bounine struct rio_mport *mport = to_rio_mport(dev); 2660748353ccSAlexandre Bounine 266172d8a0d2SAlexandre Bounine tsi_debug(EXIT, dev, "%s id=%d", mport->name, mport->id); 2662748353ccSAlexandre Bounine } 2663748353ccSAlexandre Bounine 266448618fb4SAlexandre Bounine /** 266548618fb4SAlexandre Bounine * tsi721_setup_mport - Setup Tsi721 as RapidIO subsystem master port 266648618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 266748618fb4SAlexandre Bounine * 266848618fb4SAlexandre Bounine * Configures Tsi721 as RapidIO master port. 266948618fb4SAlexandre Bounine */ 2670305c891eSBill Pemberton static int tsi721_setup_mport(struct tsi721_device *priv) 267148618fb4SAlexandre Bounine { 267248618fb4SAlexandre Bounine struct pci_dev *pdev = priv->pdev; 267348618fb4SAlexandre Bounine int err = 0; 2674748353ccSAlexandre Bounine struct rio_mport *mport = &priv->mport; 267548618fb4SAlexandre Bounine 2676748353ccSAlexandre Bounine err = rio_mport_initialize(mport); 2677748353ccSAlexandre Bounine if (err) 2678748353ccSAlexandre Bounine return err; 267948618fb4SAlexandre Bounine 2680748353ccSAlexandre Bounine mport->ops = &tsi721_rio_ops; 268148618fb4SAlexandre Bounine mport->index = 0; 268248618fb4SAlexandre Bounine mport->sys_size = 0; /* small system */ 268348618fb4SAlexandre Bounine mport->priv = (void *)priv; 268448618fb4SAlexandre Bounine mport->phys_efptr = 0x100; 26851ae842deSAlexandre Bounine mport->phys_rmap = 1; 26862aaf308bSAlexandre Bounine mport->dev.parent = &pdev->dev; 2687748353ccSAlexandre Bounine mport->dev.release = tsi721_mport_release; 268848618fb4SAlexandre Bounine 268948618fb4SAlexandre Bounine INIT_LIST_HEAD(&mport->dbells); 269048618fb4SAlexandre Bounine 269148618fb4SAlexandre Bounine rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); 2692b439e66fSAlexandre Bounine rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 3); 2693b439e66fSAlexandre Bounine rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 3); 2694ed43f44fSAlexandre Bounine snprintf(mport->name, RIO_MAX_MPORT_NAME, "%s(%s)", 2695ed43f44fSAlexandre Bounine dev_driver_string(&pdev->dev), dev_name(&pdev->dev)); 269648618fb4SAlexandre Bounine 269748618fb4SAlexandre Bounine /* Hook up interrupt handler */ 269848618fb4SAlexandre Bounine 269948618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 270048618fb4SAlexandre Bounine if (!tsi721_enable_msix(priv)) 270148618fb4SAlexandre Bounine priv->flags |= TSI721_USING_MSIX; 270248618fb4SAlexandre Bounine else if (!pci_enable_msi(pdev)) 270348618fb4SAlexandre Bounine priv->flags |= TSI721_USING_MSI; 270448618fb4SAlexandre Bounine else 270572d8a0d2SAlexandre Bounine tsi_debug(MPORT, &pdev->dev, 270672d8a0d2SAlexandre Bounine "MSI/MSI-X is not available. Using legacy INTx."); 270748618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 270848618fb4SAlexandre Bounine 2709748353ccSAlexandre Bounine err = tsi721_request_irq(priv); 271048618fb4SAlexandre Bounine 2711748353ccSAlexandre Bounine if (err) { 271272d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Unable to get PCI IRQ %02X (err=0x%x)", 271372d8a0d2SAlexandre Bounine pdev->irq, err); 2714748353ccSAlexandre Bounine return err; 27159eaa3d9bSAlexandre Bounine } 271648618fb4SAlexandre Bounine 27179eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 2718748353ccSAlexandre Bounine err = tsi721_register_dma(priv); 2719748353ccSAlexandre Bounine if (err) 2720748353ccSAlexandre Bounine goto err_exit; 27219eaa3d9bSAlexandre Bounine #endif 272248618fb4SAlexandre Bounine /* Enable SRIO link */ 272348618fb4SAlexandre Bounine iowrite32(ioread32(priv->regs + TSI721_DEVCTL) | 272448618fb4SAlexandre Bounine TSI721_DEVCTL_SRBOOT_CMPL, 272548618fb4SAlexandre Bounine priv->regs + TSI721_DEVCTL); 272648618fb4SAlexandre Bounine 272748618fb4SAlexandre Bounine if (mport->host_deviceid >= 0) 272848618fb4SAlexandre Bounine iowrite32(RIO_PORT_GEN_HOST | RIO_PORT_GEN_MASTER | 272948618fb4SAlexandre Bounine RIO_PORT_GEN_DISCOVERED, 273048618fb4SAlexandre Bounine priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR)); 273148618fb4SAlexandre Bounine else 273248618fb4SAlexandre Bounine iowrite32(0, priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR)); 273348618fb4SAlexandre Bounine 2734748353ccSAlexandre Bounine err = rio_register_mport(mport); 2735748353ccSAlexandre Bounine if (err) { 2736748353ccSAlexandre Bounine tsi721_unregister_dma(priv); 2737748353ccSAlexandre Bounine goto err_exit; 2738748353ccSAlexandre Bounine } 2739748353ccSAlexandre Bounine 274048618fb4SAlexandre Bounine return 0; 27419eaa3d9bSAlexandre Bounine 27429eaa3d9bSAlexandre Bounine err_exit: 2743748353ccSAlexandre Bounine tsi721_free_irq(priv); 27449eaa3d9bSAlexandre Bounine return err; 274548618fb4SAlexandre Bounine } 274648618fb4SAlexandre Bounine 2747305c891eSBill Pemberton static int tsi721_probe(struct pci_dev *pdev, 274848618fb4SAlexandre Bounine const struct pci_device_id *id) 274948618fb4SAlexandre Bounine { 275048618fb4SAlexandre Bounine struct tsi721_device *priv; 275148618fb4SAlexandre Bounine int err; 275248618fb4SAlexandre Bounine 275348618fb4SAlexandre Bounine priv = kzalloc(sizeof(struct tsi721_device), GFP_KERNEL); 275472d8a0d2SAlexandre Bounine if (!priv) { 275548618fb4SAlexandre Bounine err = -ENOMEM; 275648618fb4SAlexandre Bounine goto err_exit; 275748618fb4SAlexandre Bounine } 275848618fb4SAlexandre Bounine 275948618fb4SAlexandre Bounine err = pci_enable_device(pdev); 276048618fb4SAlexandre Bounine if (err) { 276172d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Failed to enable PCI device"); 276248618fb4SAlexandre Bounine goto err_clean; 276348618fb4SAlexandre Bounine } 276448618fb4SAlexandre Bounine 276548618fb4SAlexandre Bounine priv->pdev = pdev; 276648618fb4SAlexandre Bounine 276748618fb4SAlexandre Bounine #ifdef DEBUG 27689a9a9a7aSAlexandre Bounine { 27699a9a9a7aSAlexandre Bounine int i; 277072d8a0d2SAlexandre Bounine 277148618fb4SAlexandre Bounine for (i = 0; i <= PCI_STD_RESOURCE_END; i++) { 277272d8a0d2SAlexandre Bounine tsi_debug(INIT, &pdev->dev, "res%d %pR", 277372d8a0d2SAlexandre Bounine i, &pdev->resource[i]); 277448618fb4SAlexandre Bounine } 27759a9a9a7aSAlexandre Bounine } 277648618fb4SAlexandre Bounine #endif 277748618fb4SAlexandre Bounine /* 277848618fb4SAlexandre Bounine * Verify BAR configuration 277948618fb4SAlexandre Bounine */ 278048618fb4SAlexandre Bounine 278148618fb4SAlexandre Bounine /* BAR_0 (registers) must be 512KB+ in 32-bit address space */ 278248618fb4SAlexandre Bounine if (!(pci_resource_flags(pdev, BAR_0) & IORESOURCE_MEM) || 278348618fb4SAlexandre Bounine pci_resource_flags(pdev, BAR_0) & IORESOURCE_MEM_64 || 278448618fb4SAlexandre Bounine pci_resource_len(pdev, BAR_0) < TSI721_REG_SPACE_SIZE) { 278572d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Missing or misconfigured CSR BAR0"); 278648618fb4SAlexandre Bounine err = -ENODEV; 278748618fb4SAlexandre Bounine goto err_disable_pdev; 278848618fb4SAlexandre Bounine } 278948618fb4SAlexandre Bounine 279048618fb4SAlexandre Bounine /* BAR_1 (outbound doorbells) must be 16MB+ in 32-bit address space */ 279148618fb4SAlexandre Bounine if (!(pci_resource_flags(pdev, BAR_1) & IORESOURCE_MEM) || 279248618fb4SAlexandre Bounine pci_resource_flags(pdev, BAR_1) & IORESOURCE_MEM_64 || 279348618fb4SAlexandre Bounine pci_resource_len(pdev, BAR_1) < TSI721_DB_WIN_SIZE) { 279472d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Missing or misconfigured Doorbell BAR1"); 279548618fb4SAlexandre Bounine err = -ENODEV; 279648618fb4SAlexandre Bounine goto err_disable_pdev; 279748618fb4SAlexandre Bounine } 279848618fb4SAlexandre Bounine 279948618fb4SAlexandre Bounine /* 280048618fb4SAlexandre Bounine * BAR_2 and BAR_4 (outbound translation) must be in 64-bit PCIe address 280148618fb4SAlexandre Bounine * space. 280248618fb4SAlexandre Bounine * NOTE: BAR_2 and BAR_4 are not used by this version of driver. 280348618fb4SAlexandre Bounine * It may be a good idea to keep them disabled using HW configuration 280448618fb4SAlexandre Bounine * to save PCI memory space. 280548618fb4SAlexandre Bounine */ 28061679e8daSAlexandre Bounine 28071679e8daSAlexandre Bounine priv->p2r_bar[0].size = priv->p2r_bar[1].size = 0; 28081679e8daSAlexandre Bounine 28091679e8daSAlexandre Bounine if (pci_resource_flags(pdev, BAR_2) & IORESOURCE_MEM_64) { 28101679e8daSAlexandre Bounine if (pci_resource_flags(pdev, BAR_2) & IORESOURCE_PREFETCH) 281172d8a0d2SAlexandre Bounine tsi_debug(INIT, &pdev->dev, 281272d8a0d2SAlexandre Bounine "Prefetchable OBW BAR2 will not be used"); 28131679e8daSAlexandre Bounine else { 28141679e8daSAlexandre Bounine priv->p2r_bar[0].base = pci_resource_start(pdev, BAR_2); 28151679e8daSAlexandre Bounine priv->p2r_bar[0].size = pci_resource_len(pdev, BAR_2); 28161679e8daSAlexandre Bounine } 281748618fb4SAlexandre Bounine } 281848618fb4SAlexandre Bounine 28191679e8daSAlexandre Bounine if (pci_resource_flags(pdev, BAR_4) & IORESOURCE_MEM_64) { 28201679e8daSAlexandre Bounine if (pci_resource_flags(pdev, BAR_4) & IORESOURCE_PREFETCH) 282172d8a0d2SAlexandre Bounine tsi_debug(INIT, &pdev->dev, 282272d8a0d2SAlexandre Bounine "Prefetchable OBW BAR4 will not be used"); 28231679e8daSAlexandre Bounine else { 28241679e8daSAlexandre Bounine priv->p2r_bar[1].base = pci_resource_start(pdev, BAR_4); 28251679e8daSAlexandre Bounine priv->p2r_bar[1].size = pci_resource_len(pdev, BAR_4); 28261679e8daSAlexandre Bounine } 282748618fb4SAlexandre Bounine } 282848618fb4SAlexandre Bounine 282948618fb4SAlexandre Bounine err = pci_request_regions(pdev, DRV_NAME); 283048618fb4SAlexandre Bounine if (err) { 283172d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Unable to obtain PCI resources"); 283248618fb4SAlexandre Bounine goto err_disable_pdev; 283348618fb4SAlexandre Bounine } 283448618fb4SAlexandre Bounine 283548618fb4SAlexandre Bounine pci_set_master(pdev); 283648618fb4SAlexandre Bounine 283748618fb4SAlexandre Bounine priv->regs = pci_ioremap_bar(pdev, BAR_0); 283848618fb4SAlexandre Bounine if (!priv->regs) { 283972d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Unable to map device registers space"); 284048618fb4SAlexandre Bounine err = -ENOMEM; 284148618fb4SAlexandre Bounine goto err_free_res; 284248618fb4SAlexandre Bounine } 284348618fb4SAlexandre Bounine 284448618fb4SAlexandre Bounine priv->odb_base = pci_ioremap_bar(pdev, BAR_1); 284548618fb4SAlexandre Bounine if (!priv->odb_base) { 284672d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Unable to map outbound doorbells space"); 284748618fb4SAlexandre Bounine err = -ENOMEM; 284848618fb4SAlexandre Bounine goto err_unmap_bars; 284948618fb4SAlexandre Bounine } 285048618fb4SAlexandre Bounine 285148618fb4SAlexandre Bounine /* Configure DMA attributes. */ 285248618fb4SAlexandre Bounine if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { 285318f6287fSPeter Senna Tschudin err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 285418f6287fSPeter Senna Tschudin if (err) { 285572d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Unable to set DMA mask"); 285648618fb4SAlexandre Bounine goto err_unmap_bars; 285748618fb4SAlexandre Bounine } 285848618fb4SAlexandre Bounine 285948618fb4SAlexandre Bounine if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) 286072d8a0d2SAlexandre Bounine tsi_info(&pdev->dev, "Unable to set consistent DMA mask"); 286148618fb4SAlexandre Bounine } else { 286248618fb4SAlexandre Bounine err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); 286348618fb4SAlexandre Bounine if (err) 286472d8a0d2SAlexandre Bounine tsi_info(&pdev->dev, "Unable to set consistent DMA mask"); 286548618fb4SAlexandre Bounine } 286648618fb4SAlexandre Bounine 28675cdaaf8aSJiang Liu BUG_ON(!pci_is_pcie(pdev)); 28681cee22b7SAlexandre Bounine 2869174f1a71SAlexandre Bounine /* Clear "no snoop" and "relaxed ordering" bits. */ 28705cdaaf8aSJiang Liu pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL, 2871174f1a71SAlexandre Bounine PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN, 0); 28721cee22b7SAlexandre Bounine 2873cb782cddSAlexandre Bounine /* Override PCIe Maximum Read Request Size setting if requested */ 2874cb782cddSAlexandre Bounine if (pcie_mrrs >= 0) { 2875cb782cddSAlexandre Bounine if (pcie_mrrs <= 5) 2876cb782cddSAlexandre Bounine pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL, 2877cb782cddSAlexandre Bounine PCI_EXP_DEVCTL_READRQ, pcie_mrrs << 12); 2878cb782cddSAlexandre Bounine else 2879cb782cddSAlexandre Bounine tsi_info(&pdev->dev, 2880cb782cddSAlexandre Bounine "Invalid MRRS override value %d", pcie_mrrs); 2881cb782cddSAlexandre Bounine } 2882cb782cddSAlexandre Bounine 28831cee22b7SAlexandre Bounine /* Adjust PCIe completion timeout. */ 28845cdaaf8aSJiang Liu pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2, 0xf, 0x2); 288548618fb4SAlexandre Bounine 288648618fb4SAlexandre Bounine /* 288748618fb4SAlexandre Bounine * FIXUP: correct offsets of MSI-X tables in the MSI-X Capability Block 288848618fb4SAlexandre Bounine */ 288948618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_EPCTL, 0x01); 289048618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_MSIXTBL, 289148618fb4SAlexandre Bounine TSI721_MSIXTBL_OFFSET); 289248618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_MSIXPBA, 289348618fb4SAlexandre Bounine TSI721_MSIXPBA_OFFSET); 289448618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_EPCTL, 0); 289548618fb4SAlexandre Bounine /* End of FIXUP */ 289648618fb4SAlexandre Bounine 289748618fb4SAlexandre Bounine tsi721_disable_ints(priv); 289848618fb4SAlexandre Bounine 289948618fb4SAlexandre Bounine tsi721_init_pc2sr_mapping(priv); 290048618fb4SAlexandre Bounine tsi721_init_sr2pc_mapping(priv); 290148618fb4SAlexandre Bounine 29029eaa3d9bSAlexandre Bounine if (tsi721_bdma_maint_init(priv)) { 290372d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "BDMA initialization failed"); 290448618fb4SAlexandre Bounine err = -ENOMEM; 290548618fb4SAlexandre Bounine goto err_unmap_bars; 290648618fb4SAlexandre Bounine } 290748618fb4SAlexandre Bounine 290848618fb4SAlexandre Bounine err = tsi721_doorbell_init(priv); 290948618fb4SAlexandre Bounine if (err) 291048618fb4SAlexandre Bounine goto err_free_bdma; 291148618fb4SAlexandre Bounine 291248618fb4SAlexandre Bounine tsi721_port_write_init(priv); 291348618fb4SAlexandre Bounine 291448618fb4SAlexandre Bounine err = tsi721_messages_init(priv); 291548618fb4SAlexandre Bounine if (err) 291648618fb4SAlexandre Bounine goto err_free_consistent; 291748618fb4SAlexandre Bounine 291848618fb4SAlexandre Bounine err = tsi721_setup_mport(priv); 291948618fb4SAlexandre Bounine if (err) 292048618fb4SAlexandre Bounine goto err_free_consistent; 292148618fb4SAlexandre Bounine 2922e3dd8cd4SAlexandre Bounine pci_set_drvdata(pdev, priv); 2923748353ccSAlexandre Bounine tsi721_interrupts_init(priv); 2924e3dd8cd4SAlexandre Bounine 292548618fb4SAlexandre Bounine return 0; 292648618fb4SAlexandre Bounine 292748618fb4SAlexandre Bounine err_free_consistent: 2928748353ccSAlexandre Bounine tsi721_port_write_free(priv); 292948618fb4SAlexandre Bounine tsi721_doorbell_free(priv); 293048618fb4SAlexandre Bounine err_free_bdma: 29319eaa3d9bSAlexandre Bounine tsi721_bdma_maint_free(priv); 293248618fb4SAlexandre Bounine err_unmap_bars: 293348618fb4SAlexandre Bounine if (priv->regs) 293448618fb4SAlexandre Bounine iounmap(priv->regs); 293548618fb4SAlexandre Bounine if (priv->odb_base) 293648618fb4SAlexandre Bounine iounmap(priv->odb_base); 293748618fb4SAlexandre Bounine err_free_res: 293848618fb4SAlexandre Bounine pci_release_regions(pdev); 293948618fb4SAlexandre Bounine pci_clear_master(pdev); 294048618fb4SAlexandre Bounine err_disable_pdev: 294148618fb4SAlexandre Bounine pci_disable_device(pdev); 294248618fb4SAlexandre Bounine err_clean: 294348618fb4SAlexandre Bounine kfree(priv); 294448618fb4SAlexandre Bounine err_exit: 294548618fb4SAlexandre Bounine return err; 294648618fb4SAlexandre Bounine } 294748618fb4SAlexandre Bounine 2948748353ccSAlexandre Bounine static void tsi721_remove(struct pci_dev *pdev) 2949748353ccSAlexandre Bounine { 2950748353ccSAlexandre Bounine struct tsi721_device *priv = pci_get_drvdata(pdev); 2951748353ccSAlexandre Bounine 295272d8a0d2SAlexandre Bounine tsi_debug(EXIT, &pdev->dev, "enter"); 2953748353ccSAlexandre Bounine 2954748353ccSAlexandre Bounine tsi721_disable_ints(priv); 2955748353ccSAlexandre Bounine tsi721_free_irq(priv); 29569a0b0627SAlexandre Bounine flush_scheduled_work(); 2957748353ccSAlexandre Bounine rio_unregister_mport(&priv->mport); 2958748353ccSAlexandre Bounine 2959748353ccSAlexandre Bounine tsi721_unregister_dma(priv); 2960748353ccSAlexandre Bounine tsi721_bdma_maint_free(priv); 2961748353ccSAlexandre Bounine tsi721_doorbell_free(priv); 2962748353ccSAlexandre Bounine tsi721_port_write_free(priv); 2963748353ccSAlexandre Bounine tsi721_close_sr2pc_mapping(priv); 2964748353ccSAlexandre Bounine 2965748353ccSAlexandre Bounine if (priv->regs) 2966748353ccSAlexandre Bounine iounmap(priv->regs); 2967748353ccSAlexandre Bounine if (priv->odb_base) 2968748353ccSAlexandre Bounine iounmap(priv->odb_base); 2969748353ccSAlexandre Bounine #ifdef CONFIG_PCI_MSI 2970748353ccSAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 2971748353ccSAlexandre Bounine pci_disable_msix(priv->pdev); 2972748353ccSAlexandre Bounine else if (priv->flags & TSI721_USING_MSI) 2973748353ccSAlexandre Bounine pci_disable_msi(priv->pdev); 2974748353ccSAlexandre Bounine #endif 2975748353ccSAlexandre Bounine pci_release_regions(pdev); 2976748353ccSAlexandre Bounine pci_clear_master(pdev); 2977748353ccSAlexandre Bounine pci_disable_device(pdev); 2978748353ccSAlexandre Bounine pci_set_drvdata(pdev, NULL); 2979748353ccSAlexandre Bounine kfree(priv); 298072d8a0d2SAlexandre Bounine tsi_debug(EXIT, &pdev->dev, "exit"); 2981748353ccSAlexandre Bounine } 2982748353ccSAlexandre Bounine 2983e3dd8cd4SAlexandre Bounine static void tsi721_shutdown(struct pci_dev *pdev) 2984e3dd8cd4SAlexandre Bounine { 2985e3dd8cd4SAlexandre Bounine struct tsi721_device *priv = pci_get_drvdata(pdev); 2986e3dd8cd4SAlexandre Bounine 298772d8a0d2SAlexandre Bounine tsi_debug(EXIT, &pdev->dev, "enter"); 2988e3dd8cd4SAlexandre Bounine 2989e3dd8cd4SAlexandre Bounine tsi721_disable_ints(priv); 2990e3dd8cd4SAlexandre Bounine tsi721_dma_stop_all(priv); 2991e3dd8cd4SAlexandre Bounine pci_clear_master(pdev); 2992e3dd8cd4SAlexandre Bounine pci_disable_device(pdev); 2993e3dd8cd4SAlexandre Bounine } 2994e3dd8cd4SAlexandre Bounine 29959baa3c34SBenoit Taine static const struct pci_device_id tsi721_pci_tbl[] = { 299648618fb4SAlexandre Bounine { PCI_DEVICE(PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_TSI721) }, 299748618fb4SAlexandre Bounine { 0, } /* terminate list */ 299848618fb4SAlexandre Bounine }; 299948618fb4SAlexandre Bounine 300048618fb4SAlexandre Bounine MODULE_DEVICE_TABLE(pci, tsi721_pci_tbl); 300148618fb4SAlexandre Bounine 300248618fb4SAlexandre Bounine static struct pci_driver tsi721_driver = { 300348618fb4SAlexandre Bounine .name = "tsi721", 300448618fb4SAlexandre Bounine .id_table = tsi721_pci_tbl, 300548618fb4SAlexandre Bounine .probe = tsi721_probe, 3006748353ccSAlexandre Bounine .remove = tsi721_remove, 3007e3dd8cd4SAlexandre Bounine .shutdown = tsi721_shutdown, 300848618fb4SAlexandre Bounine }; 300948618fb4SAlexandre Bounine 3010748353ccSAlexandre Bounine module_pci_driver(tsi721_driver); 301194d9bd45SAlexandre Bounine 301294d9bd45SAlexandre Bounine MODULE_DESCRIPTION("IDT Tsi721 PCIExpress-to-SRIO bridge driver"); 301394d9bd45SAlexandre Bounine MODULE_AUTHOR("Integrated Device Technology, Inc."); 301494d9bd45SAlexandre Bounine MODULE_LICENSE("GPL"); 3015