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 3948618fb4SAlexandre Bounine #define DEBUG_PW /* Inbound Port-Write debugging */ 4048618fb4SAlexandre Bounine 4148618fb4SAlexandre Bounine static void tsi721_omsg_handler(struct tsi721_device *priv, int ch); 4248618fb4SAlexandre Bounine static void tsi721_imsg_handler(struct tsi721_device *priv, int ch); 4348618fb4SAlexandre Bounine 4448618fb4SAlexandre Bounine /** 4548618fb4SAlexandre Bounine * tsi721_lcread - read from local SREP config space 4648618fb4SAlexandre Bounine * @mport: RapidIO master port info 4748618fb4SAlexandre Bounine * @index: ID of RapdiIO interface 4848618fb4SAlexandre Bounine * @offset: Offset into configuration space 4948618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction 5048618fb4SAlexandre Bounine * @data: Value to be read into 5148618fb4SAlexandre Bounine * 5248618fb4SAlexandre Bounine * Generates a local SREP space read. Returns %0 on 5348618fb4SAlexandre Bounine * success or %-EINVAL on failure. 5448618fb4SAlexandre Bounine */ 5548618fb4SAlexandre Bounine static int tsi721_lcread(struct rio_mport *mport, int index, u32 offset, 5648618fb4SAlexandre Bounine int len, u32 *data) 5748618fb4SAlexandre Bounine { 5848618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 5948618fb4SAlexandre Bounine 6048618fb4SAlexandre Bounine if (len != sizeof(u32)) 6148618fb4SAlexandre Bounine return -EINVAL; /* only 32-bit access is supported */ 6248618fb4SAlexandre Bounine 6348618fb4SAlexandre Bounine *data = ioread32(priv->regs + offset); 6448618fb4SAlexandre Bounine 6548618fb4SAlexandre Bounine return 0; 6648618fb4SAlexandre Bounine } 6748618fb4SAlexandre Bounine 6848618fb4SAlexandre Bounine /** 6948618fb4SAlexandre Bounine * tsi721_lcwrite - write into local SREP config space 7048618fb4SAlexandre Bounine * @mport: RapidIO master port info 7148618fb4SAlexandre Bounine * @index: ID of RapdiIO interface 7248618fb4SAlexandre Bounine * @offset: Offset into configuration space 7348618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction 7448618fb4SAlexandre Bounine * @data: Value to be written 7548618fb4SAlexandre Bounine * 7648618fb4SAlexandre Bounine * Generates a local write into SREP configuration space. Returns %0 on 7748618fb4SAlexandre Bounine * success or %-EINVAL on failure. 7848618fb4SAlexandre Bounine */ 7948618fb4SAlexandre Bounine static int tsi721_lcwrite(struct rio_mport *mport, int index, u32 offset, 8048618fb4SAlexandre Bounine int len, u32 data) 8148618fb4SAlexandre Bounine { 8248618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 8348618fb4SAlexandre Bounine 8448618fb4SAlexandre Bounine if (len != sizeof(u32)) 8548618fb4SAlexandre Bounine return -EINVAL; /* only 32-bit access is supported */ 8648618fb4SAlexandre Bounine 8748618fb4SAlexandre Bounine iowrite32(data, priv->regs + offset); 8848618fb4SAlexandre Bounine 8948618fb4SAlexandre Bounine return 0; 9048618fb4SAlexandre Bounine } 9148618fb4SAlexandre Bounine 9248618fb4SAlexandre Bounine /** 9348618fb4SAlexandre Bounine * tsi721_maint_dma - Helper function to generate RapidIO maintenance 9448618fb4SAlexandre Bounine * transactions using designated Tsi721 DMA channel. 9548618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 9648618fb4SAlexandre Bounine * @sys_size: RapdiIO transport system size 9748618fb4SAlexandre Bounine * @destid: Destination ID of transaction 9848618fb4SAlexandre Bounine * @hopcount: Number of hops to target device 9948618fb4SAlexandre Bounine * @offset: Offset into configuration space 10048618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction 10148618fb4SAlexandre Bounine * @data: Location to be read from or write into 10248618fb4SAlexandre Bounine * @do_wr: Operation flag (1 == MAINT_WR) 10348618fb4SAlexandre Bounine * 10448618fb4SAlexandre Bounine * Generates a RapidIO maintenance transaction (Read or Write). 10548618fb4SAlexandre Bounine * Returns %0 on success and %-EINVAL or %-EFAULT on failure. 10648618fb4SAlexandre Bounine */ 10748618fb4SAlexandre Bounine static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size, 10848618fb4SAlexandre Bounine u16 destid, u8 hopcount, u32 offset, int len, 10948618fb4SAlexandre Bounine u32 *data, int do_wr) 11048618fb4SAlexandre Bounine { 1119eaa3d9bSAlexandre Bounine void __iomem *regs = priv->regs + TSI721_DMAC_BASE(priv->mdma.ch_id); 11248618fb4SAlexandre Bounine struct tsi721_dma_desc *bd_ptr; 11348618fb4SAlexandre Bounine u32 rd_count, swr_ptr, ch_stat; 11448618fb4SAlexandre Bounine int i, err = 0; 11548618fb4SAlexandre Bounine u32 op = do_wr ? MAINT_WR : MAINT_RD; 11648618fb4SAlexandre Bounine 11748618fb4SAlexandre Bounine if (offset > (RIO_MAINT_SPACE_SZ - len) || (len != sizeof(u32))) 11848618fb4SAlexandre Bounine return -EINVAL; 11948618fb4SAlexandre Bounine 1209eaa3d9bSAlexandre Bounine bd_ptr = priv->mdma.bd_base; 12148618fb4SAlexandre Bounine 1229eaa3d9bSAlexandre Bounine rd_count = ioread32(regs + TSI721_DMAC_DRDCNT); 12348618fb4SAlexandre Bounine 12448618fb4SAlexandre Bounine /* Initialize DMA descriptor */ 12548618fb4SAlexandre Bounine bd_ptr[0].type_id = cpu_to_le32((DTYPE2 << 29) | (op << 19) | destid); 12648618fb4SAlexandre Bounine bd_ptr[0].bcount = cpu_to_le32((sys_size << 26) | 0x04); 12748618fb4SAlexandre Bounine bd_ptr[0].raddr_lo = cpu_to_le32((hopcount << 24) | offset); 12848618fb4SAlexandre Bounine bd_ptr[0].raddr_hi = 0; 12948618fb4SAlexandre Bounine if (do_wr) 13048618fb4SAlexandre Bounine bd_ptr[0].data[0] = cpu_to_be32p(data); 13148618fb4SAlexandre Bounine else 13248618fb4SAlexandre Bounine bd_ptr[0].data[0] = 0xffffffff; 13348618fb4SAlexandre Bounine 13448618fb4SAlexandre Bounine mb(); 13548618fb4SAlexandre Bounine 13648618fb4SAlexandre Bounine /* Start DMA operation */ 1379eaa3d9bSAlexandre Bounine iowrite32(rd_count + 2, regs + TSI721_DMAC_DWRCNT); 1389eaa3d9bSAlexandre Bounine ioread32(regs + TSI721_DMAC_DWRCNT); 13948618fb4SAlexandre Bounine i = 0; 14048618fb4SAlexandre Bounine 14148618fb4SAlexandre Bounine /* Wait until DMA transfer is finished */ 1429eaa3d9bSAlexandre Bounine while ((ch_stat = ioread32(regs + TSI721_DMAC_STS)) 1439eaa3d9bSAlexandre Bounine & TSI721_DMAC_STS_RUN) { 14448618fb4SAlexandre Bounine udelay(1); 14548618fb4SAlexandre Bounine if (++i >= 5000000) { 14648618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 14748618fb4SAlexandre Bounine "%s : DMA[%d] read timeout ch_status=%x\n", 1489eaa3d9bSAlexandre Bounine __func__, priv->mdma.ch_id, ch_stat); 14948618fb4SAlexandre Bounine if (!do_wr) 15048618fb4SAlexandre Bounine *data = 0xffffffff; 15148618fb4SAlexandre Bounine err = -EIO; 15248618fb4SAlexandre Bounine goto err_out; 15348618fb4SAlexandre Bounine } 15448618fb4SAlexandre Bounine } 15548618fb4SAlexandre Bounine 15648618fb4SAlexandre Bounine if (ch_stat & TSI721_DMAC_STS_ABORT) { 15748618fb4SAlexandre Bounine /* If DMA operation aborted due to error, 15848618fb4SAlexandre Bounine * reinitialize DMA channel 15948618fb4SAlexandre Bounine */ 16048618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, "%s : DMA ABORT ch_stat=%x\n", 16148618fb4SAlexandre Bounine __func__, ch_stat); 16248618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, "OP=%d : destid=%x hc=%x off=%x\n", 16348618fb4SAlexandre Bounine do_wr ? MAINT_WR : MAINT_RD, destid, hopcount, offset); 1649eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_INT_ALL, regs + TSI721_DMAC_INT); 1659eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL); 16648618fb4SAlexandre Bounine udelay(10); 1679eaa3d9bSAlexandre Bounine iowrite32(0, regs + TSI721_DMAC_DWRCNT); 16848618fb4SAlexandre Bounine udelay(1); 16948618fb4SAlexandre Bounine if (!do_wr) 17048618fb4SAlexandre Bounine *data = 0xffffffff; 17148618fb4SAlexandre Bounine err = -EIO; 17248618fb4SAlexandre Bounine goto err_out; 17348618fb4SAlexandre Bounine } 17448618fb4SAlexandre Bounine 17548618fb4SAlexandre Bounine if (!do_wr) 17648618fb4SAlexandre Bounine *data = be32_to_cpu(bd_ptr[0].data[0]); 17748618fb4SAlexandre Bounine 17848618fb4SAlexandre Bounine /* 17948618fb4SAlexandre Bounine * Update descriptor status FIFO RD pointer. 18048618fb4SAlexandre Bounine * NOTE: Skipping check and clear FIFO entries because we are waiting 18148618fb4SAlexandre Bounine * for transfer to be completed. 18248618fb4SAlexandre Bounine */ 1839eaa3d9bSAlexandre Bounine swr_ptr = ioread32(regs + TSI721_DMAC_DSWP); 1849eaa3d9bSAlexandre Bounine iowrite32(swr_ptr, regs + TSI721_DMAC_DSRP); 18548618fb4SAlexandre Bounine err_out: 18648618fb4SAlexandre Bounine 18748618fb4SAlexandre Bounine return err; 18848618fb4SAlexandre Bounine } 18948618fb4SAlexandre Bounine 19048618fb4SAlexandre Bounine /** 19148618fb4SAlexandre Bounine * tsi721_cread_dma - Generate a RapidIO maintenance read transaction 19248618fb4SAlexandre Bounine * using Tsi721 BDMA engine. 19348618fb4SAlexandre Bounine * @mport: RapidIO master port control structure 19448618fb4SAlexandre Bounine * @index: ID of RapdiIO interface 19548618fb4SAlexandre Bounine * @destid: Destination ID of transaction 19648618fb4SAlexandre Bounine * @hopcount: Number of hops to target device 19748618fb4SAlexandre Bounine * @offset: Offset into configuration space 19848618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction 19948618fb4SAlexandre Bounine * @val: Location to be read into 20048618fb4SAlexandre Bounine * 20148618fb4SAlexandre Bounine * Generates a RapidIO maintenance read transaction. 20248618fb4SAlexandre Bounine * Returns %0 on success and %-EINVAL or %-EFAULT on failure. 20348618fb4SAlexandre Bounine */ 20448618fb4SAlexandre Bounine static int tsi721_cread_dma(struct rio_mport *mport, int index, u16 destid, 20548618fb4SAlexandre Bounine u8 hopcount, u32 offset, int len, u32 *data) 20648618fb4SAlexandre Bounine { 20748618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 20848618fb4SAlexandre Bounine 20948618fb4SAlexandre Bounine return tsi721_maint_dma(priv, mport->sys_size, destid, hopcount, 21048618fb4SAlexandre Bounine offset, len, data, 0); 21148618fb4SAlexandre Bounine } 21248618fb4SAlexandre Bounine 21348618fb4SAlexandre Bounine /** 21448618fb4SAlexandre Bounine * tsi721_cwrite_dma - Generate a RapidIO maintenance write transaction 21548618fb4SAlexandre Bounine * using Tsi721 BDMA engine 21648618fb4SAlexandre Bounine * @mport: RapidIO master port control structure 21748618fb4SAlexandre Bounine * @index: ID of RapdiIO interface 21848618fb4SAlexandre Bounine * @destid: Destination ID of transaction 21948618fb4SAlexandre Bounine * @hopcount: Number of hops to target device 22048618fb4SAlexandre Bounine * @offset: Offset into configuration space 22148618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction 22248618fb4SAlexandre Bounine * @val: Value to be written 22348618fb4SAlexandre Bounine * 22448618fb4SAlexandre Bounine * Generates a RapidIO maintenance write transaction. 22548618fb4SAlexandre Bounine * Returns %0 on success and %-EINVAL or %-EFAULT on failure. 22648618fb4SAlexandre Bounine */ 22748618fb4SAlexandre Bounine static int tsi721_cwrite_dma(struct rio_mport *mport, int index, u16 destid, 22848618fb4SAlexandre Bounine u8 hopcount, u32 offset, int len, u32 data) 22948618fb4SAlexandre Bounine { 23048618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 23148618fb4SAlexandre Bounine u32 temp = data; 23248618fb4SAlexandre Bounine 23348618fb4SAlexandre Bounine return tsi721_maint_dma(priv, mport->sys_size, destid, hopcount, 23448618fb4SAlexandre Bounine offset, len, &temp, 1); 23548618fb4SAlexandre Bounine } 23648618fb4SAlexandre Bounine 23748618fb4SAlexandre Bounine /** 23848618fb4SAlexandre Bounine * tsi721_pw_handler - Tsi721 inbound port-write interrupt handler 23948618fb4SAlexandre Bounine * @mport: RapidIO master port structure 24048618fb4SAlexandre Bounine * 24148618fb4SAlexandre Bounine * Handles inbound port-write interrupts. Copies PW message from an internal 24248618fb4SAlexandre Bounine * buffer into PW message FIFO and schedules deferred routine to process 24348618fb4SAlexandre Bounine * queued messages. 24448618fb4SAlexandre Bounine */ 24548618fb4SAlexandre Bounine static int 24648618fb4SAlexandre Bounine tsi721_pw_handler(struct rio_mport *mport) 24748618fb4SAlexandre Bounine { 24848618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 24948618fb4SAlexandre Bounine u32 pw_stat; 25048618fb4SAlexandre Bounine u32 pw_buf[TSI721_RIO_PW_MSG_SIZE/sizeof(u32)]; 25148618fb4SAlexandre Bounine 25248618fb4SAlexandre Bounine 25348618fb4SAlexandre Bounine pw_stat = ioread32(priv->regs + TSI721_RIO_PW_RX_STAT); 25448618fb4SAlexandre Bounine 25548618fb4SAlexandre Bounine if (pw_stat & TSI721_RIO_PW_RX_STAT_PW_VAL) { 25648618fb4SAlexandre Bounine pw_buf[0] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(0)); 25748618fb4SAlexandre Bounine pw_buf[1] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(1)); 25848618fb4SAlexandre Bounine pw_buf[2] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(2)); 25948618fb4SAlexandre Bounine pw_buf[3] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(3)); 26048618fb4SAlexandre Bounine 26148618fb4SAlexandre Bounine /* Queue PW message (if there is room in FIFO), 26248618fb4SAlexandre Bounine * otherwise discard it. 26348618fb4SAlexandre Bounine */ 26448618fb4SAlexandre Bounine spin_lock(&priv->pw_fifo_lock); 26548618fb4SAlexandre Bounine if (kfifo_avail(&priv->pw_fifo) >= TSI721_RIO_PW_MSG_SIZE) 26648618fb4SAlexandre Bounine kfifo_in(&priv->pw_fifo, pw_buf, 26748618fb4SAlexandre Bounine TSI721_RIO_PW_MSG_SIZE); 26848618fb4SAlexandre Bounine else 26948618fb4SAlexandre Bounine priv->pw_discard_count++; 27048618fb4SAlexandre Bounine spin_unlock(&priv->pw_fifo_lock); 27148618fb4SAlexandre Bounine } 27248618fb4SAlexandre Bounine 27348618fb4SAlexandre Bounine /* Clear pending PW interrupts */ 27448618fb4SAlexandre Bounine iowrite32(TSI721_RIO_PW_RX_STAT_PW_DISC | TSI721_RIO_PW_RX_STAT_PW_VAL, 27548618fb4SAlexandre Bounine priv->regs + TSI721_RIO_PW_RX_STAT); 27648618fb4SAlexandre Bounine 27748618fb4SAlexandre Bounine schedule_work(&priv->pw_work); 27848618fb4SAlexandre Bounine 27948618fb4SAlexandre Bounine return 0; 28048618fb4SAlexandre Bounine } 28148618fb4SAlexandre Bounine 28248618fb4SAlexandre Bounine static void tsi721_pw_dpc(struct work_struct *work) 28348618fb4SAlexandre Bounine { 28448618fb4SAlexandre Bounine struct tsi721_device *priv = container_of(work, struct tsi721_device, 28548618fb4SAlexandre Bounine pw_work); 28648618fb4SAlexandre Bounine u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)]; /* Use full size PW message 28748618fb4SAlexandre Bounine buffer for RIO layer */ 28848618fb4SAlexandre Bounine 28948618fb4SAlexandre Bounine /* 29048618fb4SAlexandre Bounine * Process port-write messages 29148618fb4SAlexandre Bounine */ 29248618fb4SAlexandre Bounine while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)msg_buffer, 29348618fb4SAlexandre Bounine TSI721_RIO_PW_MSG_SIZE, &priv->pw_fifo_lock)) { 29448618fb4SAlexandre Bounine /* Process one message */ 29548618fb4SAlexandre Bounine #ifdef DEBUG_PW 29648618fb4SAlexandre Bounine { 29748618fb4SAlexandre Bounine u32 i; 29848618fb4SAlexandre Bounine pr_debug("%s : Port-Write Message:", __func__); 29948618fb4SAlexandre Bounine for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); ) { 30048618fb4SAlexandre Bounine pr_debug("0x%02x: %08x %08x %08x %08x", i*4, 30148618fb4SAlexandre Bounine msg_buffer[i], msg_buffer[i + 1], 30248618fb4SAlexandre Bounine msg_buffer[i + 2], msg_buffer[i + 3]); 30348618fb4SAlexandre Bounine i += 4; 30448618fb4SAlexandre Bounine } 30548618fb4SAlexandre Bounine pr_debug("\n"); 30648618fb4SAlexandre Bounine } 30748618fb4SAlexandre Bounine #endif 30848618fb4SAlexandre Bounine /* Pass the port-write message to RIO core for processing */ 30948618fb4SAlexandre Bounine rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer); 31048618fb4SAlexandre Bounine } 31148618fb4SAlexandre Bounine } 31248618fb4SAlexandre Bounine 31348618fb4SAlexandre Bounine /** 31448618fb4SAlexandre Bounine * tsi721_pw_enable - enable/disable port-write interface init 31548618fb4SAlexandre Bounine * @mport: Master port implementing the port write unit 31648618fb4SAlexandre Bounine * @enable: 1=enable; 0=disable port-write message handling 31748618fb4SAlexandre Bounine */ 31848618fb4SAlexandre Bounine static int tsi721_pw_enable(struct rio_mport *mport, int enable) 31948618fb4SAlexandre Bounine { 32048618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 32148618fb4SAlexandre Bounine u32 rval; 32248618fb4SAlexandre Bounine 32348618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_RIO_EM_INT_ENABLE); 32448618fb4SAlexandre Bounine 32548618fb4SAlexandre Bounine if (enable) 32648618fb4SAlexandre Bounine rval |= TSI721_RIO_EM_INT_ENABLE_PW_RX; 32748618fb4SAlexandre Bounine else 32848618fb4SAlexandre Bounine rval &= ~TSI721_RIO_EM_INT_ENABLE_PW_RX; 32948618fb4SAlexandre Bounine 33048618fb4SAlexandre Bounine /* Clear pending PW interrupts */ 33148618fb4SAlexandre Bounine iowrite32(TSI721_RIO_PW_RX_STAT_PW_DISC | TSI721_RIO_PW_RX_STAT_PW_VAL, 33248618fb4SAlexandre Bounine priv->regs + TSI721_RIO_PW_RX_STAT); 33348618fb4SAlexandre Bounine /* Update enable bits */ 33448618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_RIO_EM_INT_ENABLE); 33548618fb4SAlexandre Bounine 33648618fb4SAlexandre Bounine return 0; 33748618fb4SAlexandre Bounine } 33848618fb4SAlexandre Bounine 33948618fb4SAlexandre Bounine /** 34048618fb4SAlexandre Bounine * tsi721_dsend - Send a RapidIO doorbell 34148618fb4SAlexandre Bounine * @mport: RapidIO master port info 34248618fb4SAlexandre Bounine * @index: ID of RapidIO interface 34348618fb4SAlexandre Bounine * @destid: Destination ID of target device 34448618fb4SAlexandre Bounine * @data: 16-bit info field of RapidIO doorbell 34548618fb4SAlexandre Bounine * 34648618fb4SAlexandre Bounine * Sends a RapidIO doorbell message. Always returns %0. 34748618fb4SAlexandre Bounine */ 34848618fb4SAlexandre Bounine static int tsi721_dsend(struct rio_mport *mport, int index, 34948618fb4SAlexandre Bounine u16 destid, u16 data) 35048618fb4SAlexandre Bounine { 35148618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 35248618fb4SAlexandre Bounine u32 offset; 35348618fb4SAlexandre Bounine 35448618fb4SAlexandre Bounine offset = (((mport->sys_size) ? RIO_TT_CODE_16 : RIO_TT_CODE_8) << 18) | 35548618fb4SAlexandre Bounine (destid << 2); 35648618fb4SAlexandre Bounine 35748618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 35848618fb4SAlexandre Bounine "Send Doorbell 0x%04x to destID 0x%x\n", data, destid); 35948618fb4SAlexandre Bounine iowrite16be(data, priv->odb_base + offset); 36048618fb4SAlexandre Bounine 36148618fb4SAlexandre Bounine return 0; 36248618fb4SAlexandre Bounine } 36348618fb4SAlexandre Bounine 36448618fb4SAlexandre Bounine /** 36548618fb4SAlexandre Bounine * tsi721_dbell_handler - Tsi721 doorbell interrupt handler 36648618fb4SAlexandre Bounine * @mport: RapidIO master port structure 36748618fb4SAlexandre Bounine * 36848618fb4SAlexandre Bounine * Handles inbound doorbell interrupts. Copies doorbell entry from an internal 36948618fb4SAlexandre Bounine * buffer into DB message FIFO and schedules deferred routine to process 37048618fb4SAlexandre Bounine * queued DBs. 37148618fb4SAlexandre Bounine */ 37248618fb4SAlexandre Bounine static int 37348618fb4SAlexandre Bounine tsi721_dbell_handler(struct rio_mport *mport) 37448618fb4SAlexandre Bounine { 37548618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 37648618fb4SAlexandre Bounine u32 regval; 37748618fb4SAlexandre Bounine 37848618fb4SAlexandre Bounine /* Disable IDB interrupts */ 37948618fb4SAlexandre Bounine regval = ioread32(priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); 38048618fb4SAlexandre Bounine regval &= ~TSI721_SR_CHINT_IDBQRCV; 38148618fb4SAlexandre Bounine iowrite32(regval, 38248618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); 38348618fb4SAlexandre Bounine 38448618fb4SAlexandre Bounine schedule_work(&priv->idb_work); 38548618fb4SAlexandre Bounine 38648618fb4SAlexandre Bounine return 0; 38748618fb4SAlexandre Bounine } 38848618fb4SAlexandre Bounine 38948618fb4SAlexandre Bounine static void tsi721_db_dpc(struct work_struct *work) 39048618fb4SAlexandre Bounine { 39148618fb4SAlexandre Bounine struct tsi721_device *priv = container_of(work, struct tsi721_device, 39248618fb4SAlexandre Bounine idb_work); 39348618fb4SAlexandre Bounine struct rio_mport *mport; 39448618fb4SAlexandre Bounine struct rio_dbell *dbell; 39548618fb4SAlexandre Bounine int found = 0; 39648618fb4SAlexandre Bounine u32 wr_ptr, rd_ptr; 39748618fb4SAlexandre Bounine u64 *idb_entry; 39848618fb4SAlexandre Bounine u32 regval; 39948618fb4SAlexandre Bounine union { 40048618fb4SAlexandre Bounine u64 msg; 40148618fb4SAlexandre Bounine u8 bytes[8]; 40248618fb4SAlexandre Bounine } idb; 40348618fb4SAlexandre Bounine 40448618fb4SAlexandre Bounine /* 40548618fb4SAlexandre Bounine * Process queued inbound doorbells 40648618fb4SAlexandre Bounine */ 40748618fb4SAlexandre Bounine mport = priv->mport; 40848618fb4SAlexandre Bounine 409b24823e6SAlexandre Bounine wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE; 410b24823e6SAlexandre Bounine rd_ptr = ioread32(priv->regs + TSI721_IDQ_RP(IDB_QUEUE)) % IDB_QSIZE; 41148618fb4SAlexandre Bounine 41248618fb4SAlexandre Bounine while (wr_ptr != rd_ptr) { 41348618fb4SAlexandre Bounine idb_entry = (u64 *)(priv->idb_base + 41448618fb4SAlexandre Bounine (TSI721_IDB_ENTRY_SIZE * rd_ptr)); 41548618fb4SAlexandre Bounine rd_ptr++; 416b24823e6SAlexandre Bounine rd_ptr %= IDB_QSIZE; 41748618fb4SAlexandre Bounine idb.msg = *idb_entry; 41848618fb4SAlexandre Bounine *idb_entry = 0; 41948618fb4SAlexandre Bounine 42048618fb4SAlexandre Bounine /* Process one doorbell */ 42148618fb4SAlexandre Bounine list_for_each_entry(dbell, &mport->dbells, node) { 42248618fb4SAlexandre Bounine if ((dbell->res->start <= DBELL_INF(idb.bytes)) && 42348618fb4SAlexandre Bounine (dbell->res->end >= DBELL_INF(idb.bytes))) { 42448618fb4SAlexandre Bounine found = 1; 42548618fb4SAlexandre Bounine break; 42648618fb4SAlexandre Bounine } 42748618fb4SAlexandre Bounine } 42848618fb4SAlexandre Bounine 42948618fb4SAlexandre Bounine if (found) { 43048618fb4SAlexandre Bounine dbell->dinb(mport, dbell->dev_id, DBELL_SID(idb.bytes), 43148618fb4SAlexandre Bounine DBELL_TID(idb.bytes), DBELL_INF(idb.bytes)); 43248618fb4SAlexandre Bounine } else { 43348618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 43448618fb4SAlexandre Bounine "spurious inb doorbell, sid %2.2x tid %2.2x" 43548618fb4SAlexandre Bounine " info %4.4x\n", DBELL_SID(idb.bytes), 43648618fb4SAlexandre Bounine DBELL_TID(idb.bytes), DBELL_INF(idb.bytes)); 43748618fb4SAlexandre Bounine } 4383670e7e1SAlexandre Bounine 4393670e7e1SAlexandre Bounine wr_ptr = ioread32(priv->regs + 4403670e7e1SAlexandre Bounine TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE; 44148618fb4SAlexandre Bounine } 44248618fb4SAlexandre Bounine 44348618fb4SAlexandre Bounine iowrite32(rd_ptr & (IDB_QSIZE - 1), 44448618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_RP(IDB_QUEUE)); 44548618fb4SAlexandre Bounine 44648618fb4SAlexandre Bounine /* Re-enable IDB interrupts */ 44748618fb4SAlexandre Bounine regval = ioread32(priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); 44848618fb4SAlexandre Bounine regval |= TSI721_SR_CHINT_IDBQRCV; 44948618fb4SAlexandre Bounine iowrite32(regval, 45048618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); 4513670e7e1SAlexandre Bounine 4523670e7e1SAlexandre Bounine wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE; 4533670e7e1SAlexandre Bounine if (wr_ptr != rd_ptr) 4543670e7e1SAlexandre Bounine schedule_work(&priv->idb_work); 45548618fb4SAlexandre Bounine } 45648618fb4SAlexandre Bounine 45748618fb4SAlexandre Bounine /** 45848618fb4SAlexandre Bounine * tsi721_irqhandler - Tsi721 interrupt handler 45948618fb4SAlexandre Bounine * @irq: Linux interrupt number 46048618fb4SAlexandre Bounine * @ptr: Pointer to interrupt-specific data (mport structure) 46148618fb4SAlexandre Bounine * 46248618fb4SAlexandre Bounine * Handles Tsi721 interrupts signaled using MSI and INTA. Checks reported 46348618fb4SAlexandre Bounine * interrupt events and calls an event-specific handler(s). 46448618fb4SAlexandre Bounine */ 46548618fb4SAlexandre Bounine static irqreturn_t tsi721_irqhandler(int irq, void *ptr) 46648618fb4SAlexandre Bounine { 46748618fb4SAlexandre Bounine struct rio_mport *mport = (struct rio_mport *)ptr; 46848618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 46948618fb4SAlexandre Bounine u32 dev_int; 47048618fb4SAlexandre Bounine u32 dev_ch_int; 47148618fb4SAlexandre Bounine u32 intval; 47248618fb4SAlexandre Bounine u32 ch_inte; 47348618fb4SAlexandre Bounine 4741ccc819dSAlexandre Bounine /* For MSI mode disable all device-level interrupts */ 4751ccc819dSAlexandre Bounine if (priv->flags & TSI721_USING_MSI) 4761ccc819dSAlexandre Bounine iowrite32(0, priv->regs + TSI721_DEV_INTE); 4771ccc819dSAlexandre Bounine 47848618fb4SAlexandre Bounine dev_int = ioread32(priv->regs + TSI721_DEV_INT); 47948618fb4SAlexandre Bounine if (!dev_int) 48048618fb4SAlexandre Bounine return IRQ_NONE; 48148618fb4SAlexandre Bounine 48248618fb4SAlexandre Bounine dev_ch_int = ioread32(priv->regs + TSI721_DEV_CHAN_INT); 48348618fb4SAlexandre Bounine 48448618fb4SAlexandre Bounine if (dev_int & TSI721_DEV_INT_SR2PC_CH) { 48548618fb4SAlexandre Bounine /* Service SR2PC Channel interrupts */ 48648618fb4SAlexandre Bounine if (dev_ch_int & TSI721_INT_SR2PC_CHAN(IDB_QUEUE)) { 48748618fb4SAlexandre Bounine /* Service Inbound Doorbell interrupt */ 48848618fb4SAlexandre Bounine intval = ioread32(priv->regs + 48948618fb4SAlexandre Bounine TSI721_SR_CHINT(IDB_QUEUE)); 49048618fb4SAlexandre Bounine if (intval & TSI721_SR_CHINT_IDBQRCV) 49148618fb4SAlexandre Bounine tsi721_dbell_handler(mport); 49248618fb4SAlexandre Bounine else 49348618fb4SAlexandre Bounine dev_info(&priv->pdev->dev, 49448618fb4SAlexandre Bounine "Unsupported SR_CH_INT %x\n", intval); 49548618fb4SAlexandre Bounine 49648618fb4SAlexandre Bounine /* Clear interrupts */ 49748618fb4SAlexandre Bounine iowrite32(intval, 49848618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 49948618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 50048618fb4SAlexandre Bounine } 50148618fb4SAlexandre Bounine } 50248618fb4SAlexandre Bounine 50348618fb4SAlexandre Bounine if (dev_int & TSI721_DEV_INT_SMSG_CH) { 50448618fb4SAlexandre Bounine int ch; 50548618fb4SAlexandre Bounine 50648618fb4SAlexandre Bounine /* 50748618fb4SAlexandre Bounine * Service channel interrupts from Messaging Engine 50848618fb4SAlexandre Bounine */ 50948618fb4SAlexandre Bounine 51048618fb4SAlexandre Bounine if (dev_ch_int & TSI721_INT_IMSG_CHAN_M) { /* Inbound Msg */ 51148618fb4SAlexandre Bounine /* Disable signaled OB MSG Channel interrupts */ 51248618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 51348618fb4SAlexandre Bounine ch_inte &= ~(dev_ch_int & TSI721_INT_IMSG_CHAN_M); 51448618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE); 51548618fb4SAlexandre Bounine 51648618fb4SAlexandre Bounine /* 51748618fb4SAlexandre Bounine * Process Inbound Message interrupt for each MBOX 51848618fb4SAlexandre Bounine */ 51948618fb4SAlexandre Bounine for (ch = 4; ch < RIO_MAX_MBOX + 4; ch++) { 52048618fb4SAlexandre Bounine if (!(dev_ch_int & TSI721_INT_IMSG_CHAN(ch))) 52148618fb4SAlexandre Bounine continue; 52248618fb4SAlexandre Bounine tsi721_imsg_handler(priv, ch); 52348618fb4SAlexandre Bounine } 52448618fb4SAlexandre Bounine } 52548618fb4SAlexandre Bounine 52648618fb4SAlexandre Bounine if (dev_ch_int & TSI721_INT_OMSG_CHAN_M) { /* Outbound Msg */ 52748618fb4SAlexandre Bounine /* Disable signaled OB MSG Channel interrupts */ 52848618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 52948618fb4SAlexandre Bounine ch_inte &= ~(dev_ch_int & TSI721_INT_OMSG_CHAN_M); 53048618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE); 53148618fb4SAlexandre Bounine 53248618fb4SAlexandre Bounine /* 53348618fb4SAlexandre Bounine * Process Outbound Message interrupts for each MBOX 53448618fb4SAlexandre Bounine */ 53548618fb4SAlexandre Bounine 53648618fb4SAlexandre Bounine for (ch = 0; ch < RIO_MAX_MBOX; ch++) { 53748618fb4SAlexandre Bounine if (!(dev_ch_int & TSI721_INT_OMSG_CHAN(ch))) 53848618fb4SAlexandre Bounine continue; 53948618fb4SAlexandre Bounine tsi721_omsg_handler(priv, ch); 54048618fb4SAlexandre Bounine } 54148618fb4SAlexandre Bounine } 54248618fb4SAlexandre Bounine } 54348618fb4SAlexandre Bounine 54448618fb4SAlexandre Bounine if (dev_int & TSI721_DEV_INT_SRIO) { 54548618fb4SAlexandre Bounine /* Service SRIO MAC interrupts */ 54648618fb4SAlexandre Bounine intval = ioread32(priv->regs + TSI721_RIO_EM_INT_STAT); 54748618fb4SAlexandre Bounine if (intval & TSI721_RIO_EM_INT_STAT_PW_RX) 54848618fb4SAlexandre Bounine tsi721_pw_handler(mport); 54948618fb4SAlexandre Bounine } 55048618fb4SAlexandre Bounine 5519eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 5529eaa3d9bSAlexandre Bounine if (dev_int & TSI721_DEV_INT_BDMA_CH) { 5539eaa3d9bSAlexandre Bounine int ch; 5549eaa3d9bSAlexandre Bounine 5559eaa3d9bSAlexandre Bounine if (dev_ch_int & TSI721_INT_BDMA_CHAN_M) { 5569eaa3d9bSAlexandre Bounine dev_dbg(&priv->pdev->dev, 5579eaa3d9bSAlexandre Bounine "IRQ from DMA channel 0x%08x\n", dev_ch_int); 5589eaa3d9bSAlexandre Bounine 5599eaa3d9bSAlexandre Bounine for (ch = 0; ch < TSI721_DMA_MAXCH; ch++) { 5609eaa3d9bSAlexandre Bounine if (!(dev_ch_int & TSI721_INT_BDMA_CHAN(ch))) 5619eaa3d9bSAlexandre Bounine continue; 5629eaa3d9bSAlexandre Bounine tsi721_bdma_handler(&priv->bdma[ch]); 5639eaa3d9bSAlexandre Bounine } 5649eaa3d9bSAlexandre Bounine } 5659eaa3d9bSAlexandre Bounine } 5669eaa3d9bSAlexandre Bounine #endif 5671ccc819dSAlexandre Bounine 5681ccc819dSAlexandre Bounine /* For MSI mode re-enable device-level interrupts */ 5691ccc819dSAlexandre Bounine if (priv->flags & TSI721_USING_MSI) { 5701ccc819dSAlexandre Bounine dev_int = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO | 5711ccc819dSAlexandre Bounine TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH; 5721ccc819dSAlexandre Bounine iowrite32(dev_int, priv->regs + TSI721_DEV_INTE); 5731ccc819dSAlexandre Bounine } 5741ccc819dSAlexandre Bounine 57548618fb4SAlexandre Bounine return IRQ_HANDLED; 57648618fb4SAlexandre Bounine } 57748618fb4SAlexandre Bounine 57848618fb4SAlexandre Bounine static void tsi721_interrupts_init(struct tsi721_device *priv) 57948618fb4SAlexandre Bounine { 58048618fb4SAlexandre Bounine u32 intr; 58148618fb4SAlexandre Bounine 58248618fb4SAlexandre Bounine /* Enable IDB interrupts */ 58348618fb4SAlexandre Bounine iowrite32(TSI721_SR_CHINT_ALL, 58448618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 58548618fb4SAlexandre Bounine iowrite32(TSI721_SR_CHINT_IDBQRCV, 58648618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINTE(IDB_QUEUE)); 58748618fb4SAlexandre Bounine 58848618fb4SAlexandre Bounine /* Enable SRIO MAC interrupts */ 58948618fb4SAlexandre Bounine iowrite32(TSI721_RIO_EM_DEV_INT_EN_INT, 59048618fb4SAlexandre Bounine priv->regs + TSI721_RIO_EM_DEV_INT_EN); 59148618fb4SAlexandre Bounine 5929eaa3d9bSAlexandre Bounine /* Enable interrupts from channels in use */ 5939eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 5949eaa3d9bSAlexandre Bounine intr = TSI721_INT_SR2PC_CHAN(IDB_QUEUE) | 5959eaa3d9bSAlexandre Bounine (TSI721_INT_BDMA_CHAN_M & 5969eaa3d9bSAlexandre Bounine ~TSI721_INT_BDMA_CHAN(TSI721_DMACH_MAINT)); 5979eaa3d9bSAlexandre Bounine #else 5989eaa3d9bSAlexandre Bounine intr = TSI721_INT_SR2PC_CHAN(IDB_QUEUE); 5999eaa3d9bSAlexandre Bounine #endif 6009eaa3d9bSAlexandre Bounine iowrite32(intr, priv->regs + TSI721_DEV_CHAN_INTE); 6019eaa3d9bSAlexandre Bounine 60248618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 60348618fb4SAlexandre Bounine intr = TSI721_DEV_INT_SRIO; 60448618fb4SAlexandre Bounine else 60548618fb4SAlexandre Bounine intr = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO | 6069eaa3d9bSAlexandre Bounine TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH; 60748618fb4SAlexandre Bounine 60848618fb4SAlexandre Bounine iowrite32(intr, priv->regs + TSI721_DEV_INTE); 60948618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_DEV_INTE); 61048618fb4SAlexandre Bounine } 61148618fb4SAlexandre Bounine 61248618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 61348618fb4SAlexandre Bounine /** 61448618fb4SAlexandre Bounine * tsi721_omsg_msix - MSI-X interrupt handler for outbound messaging 61548618fb4SAlexandre Bounine * @irq: Linux interrupt number 61648618fb4SAlexandre Bounine * @ptr: Pointer to interrupt-specific data (mport structure) 61748618fb4SAlexandre Bounine * 61848618fb4SAlexandre Bounine * Handles outbound messaging interrupts signaled using MSI-X. 61948618fb4SAlexandre Bounine */ 62048618fb4SAlexandre Bounine static irqreturn_t tsi721_omsg_msix(int irq, void *ptr) 62148618fb4SAlexandre Bounine { 62248618fb4SAlexandre Bounine struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv; 62348618fb4SAlexandre Bounine int mbox; 62448618fb4SAlexandre Bounine 62548618fb4SAlexandre Bounine mbox = (irq - priv->msix[TSI721_VECT_OMB0_DONE].vector) % RIO_MAX_MBOX; 62648618fb4SAlexandre Bounine tsi721_omsg_handler(priv, mbox); 62748618fb4SAlexandre Bounine return IRQ_HANDLED; 62848618fb4SAlexandre Bounine } 62948618fb4SAlexandre Bounine 63048618fb4SAlexandre Bounine /** 63148618fb4SAlexandre Bounine * tsi721_imsg_msix - MSI-X interrupt handler for inbound messaging 63248618fb4SAlexandre Bounine * @irq: Linux interrupt number 63348618fb4SAlexandre Bounine * @ptr: Pointer to interrupt-specific data (mport structure) 63448618fb4SAlexandre Bounine * 63548618fb4SAlexandre Bounine * Handles inbound messaging interrupts signaled using MSI-X. 63648618fb4SAlexandre Bounine */ 63748618fb4SAlexandre Bounine static irqreturn_t tsi721_imsg_msix(int irq, void *ptr) 63848618fb4SAlexandre Bounine { 63948618fb4SAlexandre Bounine struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv; 64048618fb4SAlexandre Bounine int mbox; 64148618fb4SAlexandre Bounine 64248618fb4SAlexandre Bounine mbox = (irq - priv->msix[TSI721_VECT_IMB0_RCV].vector) % RIO_MAX_MBOX; 64348618fb4SAlexandre Bounine tsi721_imsg_handler(priv, mbox + 4); 64448618fb4SAlexandre Bounine return IRQ_HANDLED; 64548618fb4SAlexandre Bounine } 64648618fb4SAlexandre Bounine 64748618fb4SAlexandre Bounine /** 64848618fb4SAlexandre Bounine * tsi721_srio_msix - Tsi721 MSI-X SRIO MAC interrupt handler 64948618fb4SAlexandre Bounine * @irq: Linux interrupt number 65048618fb4SAlexandre Bounine * @ptr: Pointer to interrupt-specific data (mport structure) 65148618fb4SAlexandre Bounine * 65248618fb4SAlexandre Bounine * Handles Tsi721 interrupts from SRIO MAC. 65348618fb4SAlexandre Bounine */ 65448618fb4SAlexandre Bounine static irqreturn_t tsi721_srio_msix(int irq, void *ptr) 65548618fb4SAlexandre Bounine { 65648618fb4SAlexandre Bounine struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv; 65748618fb4SAlexandre Bounine u32 srio_int; 65848618fb4SAlexandre Bounine 65948618fb4SAlexandre Bounine /* Service SRIO MAC interrupts */ 66048618fb4SAlexandre Bounine srio_int = ioread32(priv->regs + TSI721_RIO_EM_INT_STAT); 66148618fb4SAlexandre Bounine if (srio_int & TSI721_RIO_EM_INT_STAT_PW_RX) 66248618fb4SAlexandre Bounine tsi721_pw_handler((struct rio_mport *)ptr); 66348618fb4SAlexandre Bounine 66448618fb4SAlexandre Bounine return IRQ_HANDLED; 66548618fb4SAlexandre Bounine } 66648618fb4SAlexandre Bounine 66748618fb4SAlexandre Bounine /** 66848618fb4SAlexandre Bounine * tsi721_sr2pc_ch_msix - Tsi721 MSI-X SR2PC Channel interrupt handler 66948618fb4SAlexandre Bounine * @irq: Linux interrupt number 67048618fb4SAlexandre Bounine * @ptr: Pointer to interrupt-specific data (mport structure) 67148618fb4SAlexandre Bounine * 67248618fb4SAlexandre Bounine * Handles Tsi721 interrupts from SR2PC Channel. 67348618fb4SAlexandre Bounine * NOTE: At this moment services only one SR2PC channel associated with inbound 67448618fb4SAlexandre Bounine * doorbells. 67548618fb4SAlexandre Bounine */ 67648618fb4SAlexandre Bounine static irqreturn_t tsi721_sr2pc_ch_msix(int irq, void *ptr) 67748618fb4SAlexandre Bounine { 67848618fb4SAlexandre Bounine struct tsi721_device *priv = ((struct rio_mport *)ptr)->priv; 67948618fb4SAlexandre Bounine u32 sr_ch_int; 68048618fb4SAlexandre Bounine 68148618fb4SAlexandre Bounine /* Service Inbound DB interrupt from SR2PC channel */ 68248618fb4SAlexandre Bounine sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 68348618fb4SAlexandre Bounine if (sr_ch_int & TSI721_SR_CHINT_IDBQRCV) 68448618fb4SAlexandre Bounine tsi721_dbell_handler((struct rio_mport *)ptr); 68548618fb4SAlexandre Bounine 68648618fb4SAlexandre Bounine /* Clear interrupts */ 68748618fb4SAlexandre Bounine iowrite32(sr_ch_int, priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 68848618fb4SAlexandre Bounine /* Read back to ensure that interrupt was cleared */ 68948618fb4SAlexandre Bounine sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE)); 69048618fb4SAlexandre Bounine 69148618fb4SAlexandre Bounine return IRQ_HANDLED; 69248618fb4SAlexandre Bounine } 69348618fb4SAlexandre Bounine 69448618fb4SAlexandre Bounine /** 69548618fb4SAlexandre Bounine * tsi721_request_msix - register interrupt service for MSI-X mode. 69648618fb4SAlexandre Bounine * @mport: RapidIO master port structure 69748618fb4SAlexandre Bounine * 69848618fb4SAlexandre Bounine * Registers MSI-X interrupt service routines for interrupts that are active 69948618fb4SAlexandre Bounine * immediately after mport initialization. Messaging interrupt service routines 70048618fb4SAlexandre Bounine * should be registered during corresponding open requests. 70148618fb4SAlexandre Bounine */ 70248618fb4SAlexandre Bounine static int tsi721_request_msix(struct rio_mport *mport) 70348618fb4SAlexandre Bounine { 70448618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 70548618fb4SAlexandre Bounine int err = 0; 70648618fb4SAlexandre Bounine 70748618fb4SAlexandre Bounine err = request_irq(priv->msix[TSI721_VECT_IDB].vector, 70848618fb4SAlexandre Bounine tsi721_sr2pc_ch_msix, 0, 70948618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IDB].irq_name, (void *)mport); 71048618fb4SAlexandre Bounine if (err) 71148618fb4SAlexandre Bounine goto out; 71248618fb4SAlexandre Bounine 71348618fb4SAlexandre Bounine err = request_irq(priv->msix[TSI721_VECT_PWRX].vector, 71448618fb4SAlexandre Bounine tsi721_srio_msix, 0, 71548618fb4SAlexandre Bounine priv->msix[TSI721_VECT_PWRX].irq_name, (void *)mport); 71648618fb4SAlexandre Bounine if (err) 71748618fb4SAlexandre Bounine free_irq( 71848618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IDB].vector, 71948618fb4SAlexandre Bounine (void *)mport); 72048618fb4SAlexandre Bounine out: 72148618fb4SAlexandre Bounine return err; 72248618fb4SAlexandre Bounine } 72348618fb4SAlexandre Bounine 72448618fb4SAlexandre Bounine /** 72548618fb4SAlexandre Bounine * tsi721_enable_msix - Attempts to enable MSI-X support for Tsi721. 72648618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 72748618fb4SAlexandre Bounine * 72848618fb4SAlexandre Bounine * Configures MSI-X support for Tsi721. Supports only an exact number 72948618fb4SAlexandre Bounine * of requested vectors. 73048618fb4SAlexandre Bounine */ 73148618fb4SAlexandre Bounine static int tsi721_enable_msix(struct tsi721_device *priv) 73248618fb4SAlexandre Bounine { 73348618fb4SAlexandre Bounine struct msix_entry entries[TSI721_VECT_MAX]; 73448618fb4SAlexandre Bounine int err; 73548618fb4SAlexandre Bounine int i; 73648618fb4SAlexandre Bounine 73748618fb4SAlexandre Bounine entries[TSI721_VECT_IDB].entry = TSI721_MSIX_SR2PC_IDBQ_RCV(IDB_QUEUE); 73848618fb4SAlexandre Bounine entries[TSI721_VECT_PWRX].entry = TSI721_MSIX_SRIO_MAC_INT; 73948618fb4SAlexandre Bounine 74048618fb4SAlexandre Bounine /* 74148618fb4SAlexandre Bounine * Initialize MSI-X entries for Messaging Engine: 74248618fb4SAlexandre Bounine * this driver supports four RIO mailboxes (inbound and outbound) 74348618fb4SAlexandre Bounine * NOTE: Inbound message MBOX 0...4 use IB channels 4...7. Therefore 74448618fb4SAlexandre Bounine * offset +4 is added to IB MBOX number. 74548618fb4SAlexandre Bounine */ 74648618fb4SAlexandre Bounine for (i = 0; i < RIO_MAX_MBOX; i++) { 74748618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_RCV + i].entry = 74848618fb4SAlexandre Bounine TSI721_MSIX_IMSG_DQ_RCV(i + 4); 74948618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_INT + i].entry = 75048618fb4SAlexandre Bounine TSI721_MSIX_IMSG_INT(i + 4); 75148618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_DONE + i].entry = 75248618fb4SAlexandre Bounine TSI721_MSIX_OMSG_DONE(i); 75348618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_INT + i].entry = 75448618fb4SAlexandre Bounine TSI721_MSIX_OMSG_INT(i); 75548618fb4SAlexandre Bounine } 75648618fb4SAlexandre Bounine 7579eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 7589eaa3d9bSAlexandre Bounine /* 7599eaa3d9bSAlexandre Bounine * Initialize MSI-X entries for Block DMA Engine: 7609eaa3d9bSAlexandre Bounine * this driver supports XXX DMA channels 7619eaa3d9bSAlexandre Bounine * (one is reserved for SRIO maintenance transactions) 7629eaa3d9bSAlexandre Bounine */ 7639eaa3d9bSAlexandre Bounine for (i = 0; i < TSI721_DMA_CHNUM; i++) { 7649eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_DONE + i].entry = 7659eaa3d9bSAlexandre Bounine TSI721_MSIX_DMACH_DONE(i); 7669eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_INT + i].entry = 7679eaa3d9bSAlexandre Bounine TSI721_MSIX_DMACH_INT(i); 7689eaa3d9bSAlexandre Bounine } 7699eaa3d9bSAlexandre Bounine #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ 7709eaa3d9bSAlexandre Bounine 7711c92ab1eSAlexander Gordeev err = pci_enable_msix_exact(priv->pdev, entries, ARRAY_SIZE(entries)); 77248618fb4SAlexandre Bounine if (err) { 7739eaa3d9bSAlexandre Bounine dev_err(&priv->pdev->dev, 7749eaa3d9bSAlexandre Bounine "Failed to enable MSI-X (err=%d)\n", err); 77548618fb4SAlexandre Bounine return err; 77648618fb4SAlexandre Bounine } 77748618fb4SAlexandre Bounine 77848618fb4SAlexandre Bounine /* 77948618fb4SAlexandre Bounine * Copy MSI-X vector information into tsi721 private structure 78048618fb4SAlexandre Bounine */ 78148618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IDB].vector = entries[TSI721_VECT_IDB].vector; 78248618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_IDB].irq_name, IRQ_DEVICE_NAME_MAX, 78348618fb4SAlexandre Bounine DRV_NAME "-idb@pci:%s", pci_name(priv->pdev)); 78448618fb4SAlexandre Bounine priv->msix[TSI721_VECT_PWRX].vector = entries[TSI721_VECT_PWRX].vector; 78548618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_PWRX].irq_name, IRQ_DEVICE_NAME_MAX, 78648618fb4SAlexandre Bounine DRV_NAME "-pwrx@pci:%s", pci_name(priv->pdev)); 78748618fb4SAlexandre Bounine 78848618fb4SAlexandre Bounine for (i = 0; i < RIO_MAX_MBOX; i++) { 78948618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_RCV + i].vector = 79048618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_RCV + i].vector; 79148618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_IMB0_RCV + i].irq_name, 79248618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-imbr%d@pci:%s", 79348618fb4SAlexandre Bounine i, pci_name(priv->pdev)); 79448618fb4SAlexandre Bounine 79548618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_INT + i].vector = 79648618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_INT + i].vector; 79748618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_IMB0_INT + i].irq_name, 79848618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-imbi%d@pci:%s", 79948618fb4SAlexandre Bounine i, pci_name(priv->pdev)); 80048618fb4SAlexandre Bounine 80148618fb4SAlexandre Bounine priv->msix[TSI721_VECT_OMB0_DONE + i].vector = 80248618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_DONE + i].vector; 80348618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_OMB0_DONE + i].irq_name, 80448618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-ombd%d@pci:%s", 80548618fb4SAlexandre Bounine i, pci_name(priv->pdev)); 80648618fb4SAlexandre Bounine 80748618fb4SAlexandre Bounine priv->msix[TSI721_VECT_OMB0_INT + i].vector = 80848618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_INT + i].vector; 80948618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_OMB0_INT + i].irq_name, 81048618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-ombi%d@pci:%s", 81148618fb4SAlexandre Bounine i, pci_name(priv->pdev)); 81248618fb4SAlexandre Bounine } 81348618fb4SAlexandre Bounine 8149eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 8159eaa3d9bSAlexandre Bounine for (i = 0; i < TSI721_DMA_CHNUM; i++) { 8169eaa3d9bSAlexandre Bounine priv->msix[TSI721_VECT_DMA0_DONE + i].vector = 8179eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_DONE + i].vector; 8189eaa3d9bSAlexandre Bounine snprintf(priv->msix[TSI721_VECT_DMA0_DONE + i].irq_name, 8199eaa3d9bSAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-dmad%d@pci:%s", 8209eaa3d9bSAlexandre Bounine i, pci_name(priv->pdev)); 8219eaa3d9bSAlexandre Bounine 8229eaa3d9bSAlexandre Bounine priv->msix[TSI721_VECT_DMA0_INT + i].vector = 8239eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_INT + i].vector; 8249eaa3d9bSAlexandre Bounine snprintf(priv->msix[TSI721_VECT_DMA0_INT + i].irq_name, 8259eaa3d9bSAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-dmai%d@pci:%s", 8269eaa3d9bSAlexandre Bounine i, pci_name(priv->pdev)); 8279eaa3d9bSAlexandre Bounine } 8289eaa3d9bSAlexandre Bounine #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ 8299eaa3d9bSAlexandre Bounine 83048618fb4SAlexandre Bounine return 0; 83148618fb4SAlexandre Bounine } 83248618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 83348618fb4SAlexandre Bounine 83448618fb4SAlexandre Bounine static int tsi721_request_irq(struct rio_mport *mport) 83548618fb4SAlexandre Bounine { 83648618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 83748618fb4SAlexandre Bounine int err; 83848618fb4SAlexandre Bounine 83948618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 84048618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 84148618fb4SAlexandre Bounine err = tsi721_request_msix(mport); 84248618fb4SAlexandre Bounine else 84348618fb4SAlexandre Bounine #endif 84448618fb4SAlexandre Bounine err = request_irq(priv->pdev->irq, tsi721_irqhandler, 84548618fb4SAlexandre Bounine (priv->flags & TSI721_USING_MSI) ? 0 : IRQF_SHARED, 84648618fb4SAlexandre Bounine DRV_NAME, (void *)mport); 84748618fb4SAlexandre Bounine 84848618fb4SAlexandre Bounine if (err) 84948618fb4SAlexandre Bounine dev_err(&priv->pdev->dev, 85048618fb4SAlexandre Bounine "Unable to allocate interrupt, Error: %d\n", err); 85148618fb4SAlexandre Bounine 85248618fb4SAlexandre Bounine return err; 85348618fb4SAlexandre Bounine } 85448618fb4SAlexandre Bounine 85548618fb4SAlexandre Bounine /** 85648618fb4SAlexandre Bounine * tsi721_init_pc2sr_mapping - initializes outbound (PCIe->SRIO) 85748618fb4SAlexandre Bounine * translation regions. 85848618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 85948618fb4SAlexandre Bounine * 86048618fb4SAlexandre Bounine * Disables SREP translation regions. 86148618fb4SAlexandre Bounine */ 86248618fb4SAlexandre Bounine static void tsi721_init_pc2sr_mapping(struct tsi721_device *priv) 86348618fb4SAlexandre Bounine { 86448618fb4SAlexandre Bounine int i; 86548618fb4SAlexandre Bounine 86648618fb4SAlexandre Bounine /* Disable all PC2SR translation windows */ 86748618fb4SAlexandre Bounine for (i = 0; i < TSI721_OBWIN_NUM; i++) 86848618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_OBWINLB(i)); 86948618fb4SAlexandre Bounine } 87048618fb4SAlexandre Bounine 87148618fb4SAlexandre Bounine /** 87271afe341SAlexandre Bounine * tsi721_rio_map_inb_mem -- Mapping inbound memory region. 87371afe341SAlexandre Bounine * @mport: RapidIO master port 87471afe341SAlexandre Bounine * @lstart: Local memory space start address. 87571afe341SAlexandre Bounine * @rstart: RapidIO space start address. 87671afe341SAlexandre Bounine * @size: The mapping region size. 87771afe341SAlexandre Bounine * @flags: Flags for mapping. 0 for using default flags. 87871afe341SAlexandre Bounine * 87971afe341SAlexandre Bounine * Return: 0 -- Success. 88071afe341SAlexandre Bounine * 88171afe341SAlexandre Bounine * This function will create the inbound mapping 88271afe341SAlexandre Bounine * from rstart to lstart. 88371afe341SAlexandre Bounine */ 88471afe341SAlexandre Bounine static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, 88571afe341SAlexandre Bounine u64 rstart, u32 size, u32 flags) 88671afe341SAlexandre Bounine { 88771afe341SAlexandre Bounine struct tsi721_device *priv = mport->priv; 888ba5d141bSAlexandre Bounine int i, avail = -1; 88971afe341SAlexandre Bounine u32 regval; 890ba5d141bSAlexandre Bounine struct tsi721_ib_win *ib_win; 8919673b883SAlexandre Bounine bool direct = (lstart == rstart); 8929673b883SAlexandre Bounine u64 ibw_size; 8939673b883SAlexandre Bounine dma_addr_t loc_start; 8949673b883SAlexandre Bounine u64 ibw_start; 8959673b883SAlexandre Bounine struct tsi721_ib_win_mapping *map = NULL; 896ba5d141bSAlexandre Bounine int ret = -EBUSY; 89771afe341SAlexandre Bounine 8989673b883SAlexandre Bounine if (direct) { 8999673b883SAlexandre Bounine dev_dbg(&priv->pdev->dev, 9009673b883SAlexandre Bounine "Direct (RIO_0x%llx -> PCIe_0x%pad), size=0x%x", 9019673b883SAlexandre Bounine rstart, &lstart, size); 9029673b883SAlexandre Bounine 9039673b883SAlexandre Bounine /* Calculate minimal acceptable window size and base address */ 9049673b883SAlexandre Bounine 9059673b883SAlexandre Bounine ibw_size = roundup_pow_of_two(size); 9069673b883SAlexandre Bounine ibw_start = lstart & ~(ibw_size - 1); 9079673b883SAlexandre Bounine 9089673b883SAlexandre Bounine while ((lstart + size) > (ibw_start + ibw_size)) { 9099673b883SAlexandre Bounine ibw_size *= 2; 9109673b883SAlexandre Bounine ibw_start = lstart & ~(ibw_size - 1); 9119673b883SAlexandre Bounine if (ibw_size > 0x80000000) { /* Limit max size to 2GB */ 9129673b883SAlexandre Bounine return -EBUSY; 9139673b883SAlexandre Bounine } 9149673b883SAlexandre Bounine } 9159673b883SAlexandre Bounine 9169673b883SAlexandre Bounine loc_start = ibw_start; 9179673b883SAlexandre Bounine 9189673b883SAlexandre Bounine map = kzalloc(sizeof(struct tsi721_ib_win_mapping), GFP_ATOMIC); 9199673b883SAlexandre Bounine if (map == NULL) 9209673b883SAlexandre Bounine return -ENOMEM; 9219673b883SAlexandre Bounine 9229673b883SAlexandre Bounine } else { 9239673b883SAlexandre Bounine dev_dbg(&priv->pdev->dev, 9249673b883SAlexandre Bounine "Translated (RIO_0x%llx -> PCIe_0x%pad), size=0x%x", 9259673b883SAlexandre Bounine rstart, &lstart, size); 9269673b883SAlexandre Bounine 92771afe341SAlexandre Bounine if (!is_power_of_2(size) || size < 0x1000 || 92871afe341SAlexandre Bounine ((u64)lstart & (size - 1)) || (rstart & (size - 1))) 92971afe341SAlexandre Bounine return -EINVAL; 9309673b883SAlexandre Bounine if (priv->ibwin_cnt == 0) 9319673b883SAlexandre Bounine return -EBUSY; 9329673b883SAlexandre Bounine ibw_start = rstart; 9339673b883SAlexandre Bounine ibw_size = size; 9349673b883SAlexandre Bounine loc_start = lstart; 9359673b883SAlexandre Bounine } 93671afe341SAlexandre Bounine 937ba5d141bSAlexandre Bounine /* 938ba5d141bSAlexandre Bounine * Scan for overlapping with active regions and mark the first available 939ba5d141bSAlexandre Bounine * IB window at the same time. 940ba5d141bSAlexandre Bounine */ 94171afe341SAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) { 942ba5d141bSAlexandre Bounine ib_win = &priv->ib_win[i]; 9439673b883SAlexandre Bounine 944ba5d141bSAlexandre Bounine if (!ib_win->active) { 945ba5d141bSAlexandre Bounine if (avail == -1) { 946ba5d141bSAlexandre Bounine avail = i; 947ba5d141bSAlexandre Bounine ret = 0; 948ba5d141bSAlexandre Bounine } 9499673b883SAlexandre Bounine } else if (ibw_start < (ib_win->rstart + ib_win->size) && 9509673b883SAlexandre Bounine (ibw_start + ibw_size) > ib_win->rstart) { 9519673b883SAlexandre Bounine /* Return error if address translation involved */ 9529673b883SAlexandre Bounine if (direct && ib_win->xlat) { 9539673b883SAlexandre Bounine ret = -EFAULT; 9549673b883SAlexandre Bounine break; 9559673b883SAlexandre Bounine } 9569673b883SAlexandre Bounine 9579673b883SAlexandre Bounine /* 9589673b883SAlexandre Bounine * Direct mappings usually are larger than originally 9599673b883SAlexandre Bounine * requested fragments - check if this new request fits 9609673b883SAlexandre Bounine * into it. 9619673b883SAlexandre Bounine */ 9629673b883SAlexandre Bounine if (rstart >= ib_win->rstart && 9639673b883SAlexandre Bounine (rstart + size) <= (ib_win->rstart + 9649673b883SAlexandre Bounine ib_win->size)) { 9659673b883SAlexandre Bounine /* We are in - no further mapping required */ 9669673b883SAlexandre Bounine map->lstart = lstart; 9679673b883SAlexandre Bounine list_add_tail(&map->node, &ib_win->mappings); 9689673b883SAlexandre Bounine return 0; 9699673b883SAlexandre Bounine } 9709673b883SAlexandre Bounine 971ba5d141bSAlexandre Bounine ret = -EFAULT; 97271afe341SAlexandre Bounine break; 97371afe341SAlexandre Bounine } 97471afe341SAlexandre Bounine } 97571afe341SAlexandre Bounine 976ba5d141bSAlexandre Bounine if (ret) 9779673b883SAlexandre Bounine goto out; 978ba5d141bSAlexandre Bounine i = avail; 979ba5d141bSAlexandre Bounine 980ba5d141bSAlexandre Bounine /* Sanity check: available IB window must be disabled at this point */ 981ba5d141bSAlexandre Bounine regval = ioread32(priv->regs + TSI721_IBWIN_LB(i)); 982ba5d141bSAlexandre Bounine if (WARN_ON(regval & TSI721_IBWIN_LB_WEN)) { 983ba5d141bSAlexandre Bounine ret = -EIO; 9849673b883SAlexandre Bounine goto out; 985ba5d141bSAlexandre Bounine } 986ba5d141bSAlexandre Bounine 987ba5d141bSAlexandre Bounine ib_win = &priv->ib_win[i]; 988ba5d141bSAlexandre Bounine ib_win->active = true; 9899673b883SAlexandre Bounine ib_win->rstart = ibw_start; 9909673b883SAlexandre Bounine ib_win->lstart = loc_start; 9919673b883SAlexandre Bounine ib_win->size = ibw_size; 9929673b883SAlexandre Bounine ib_win->xlat = (lstart != rstart); 9939673b883SAlexandre Bounine INIT_LIST_HEAD(&ib_win->mappings); 994ba5d141bSAlexandre Bounine 9959673b883SAlexandre Bounine /* 9969673b883SAlexandre Bounine * When using direct IBW mapping and have larger than requested IBW size 9979673b883SAlexandre Bounine * we can have multiple local memory blocks mapped through the same IBW 9989673b883SAlexandre Bounine * To handle this situation we maintain list of "clients" for such IBWs. 9999673b883SAlexandre Bounine */ 10009673b883SAlexandre Bounine if (direct) { 10019673b883SAlexandre Bounine map->lstart = lstart; 10029673b883SAlexandre Bounine list_add_tail(&map->node, &ib_win->mappings); 10039673b883SAlexandre Bounine } 10049673b883SAlexandre Bounine 10059673b883SAlexandre Bounine iowrite32(TSI721_IBWIN_SIZE(ibw_size) << 8, 100671afe341SAlexandre Bounine priv->regs + TSI721_IBWIN_SZ(i)); 100771afe341SAlexandre Bounine 10089673b883SAlexandre Bounine iowrite32(((u64)loc_start >> 32), priv->regs + TSI721_IBWIN_TUA(i)); 10099673b883SAlexandre Bounine iowrite32(((u64)loc_start & TSI721_IBWIN_TLA_ADD), 101071afe341SAlexandre Bounine priv->regs + TSI721_IBWIN_TLA(i)); 101171afe341SAlexandre Bounine 10129673b883SAlexandre Bounine iowrite32(ibw_start >> 32, priv->regs + TSI721_IBWIN_UB(i)); 10139673b883SAlexandre Bounine iowrite32((ibw_start & TSI721_IBWIN_LB_BA) | TSI721_IBWIN_LB_WEN, 101471afe341SAlexandre Bounine priv->regs + TSI721_IBWIN_LB(i)); 10159673b883SAlexandre Bounine 10169673b883SAlexandre Bounine priv->ibwin_cnt--; 10179673b883SAlexandre Bounine 101871afe341SAlexandre Bounine dev_dbg(&priv->pdev->dev, 10199673b883SAlexandre Bounine "Configured IBWIN%d (RIO_0x%llx -> PCIe_0x%llx), size=0x%llx\n", 10209673b883SAlexandre Bounine i, ibw_start, (unsigned long long)loc_start, ibw_size); 102171afe341SAlexandre Bounine 102271afe341SAlexandre Bounine return 0; 10239673b883SAlexandre Bounine out: 10249673b883SAlexandre Bounine kfree(map); 1025ba5d141bSAlexandre Bounine return ret; 102671afe341SAlexandre Bounine } 102771afe341SAlexandre Bounine 102871afe341SAlexandre Bounine /** 10299673b883SAlexandre Bounine * tsi721_rio_unmap_inb_mem -- Unmapping inbound memory region. 103071afe341SAlexandre Bounine * @mport: RapidIO master port 103171afe341SAlexandre Bounine * @lstart: Local memory space start address. 103271afe341SAlexandre Bounine */ 103371afe341SAlexandre Bounine static void tsi721_rio_unmap_inb_mem(struct rio_mport *mport, 103471afe341SAlexandre Bounine dma_addr_t lstart) 103571afe341SAlexandre Bounine { 103671afe341SAlexandre Bounine struct tsi721_device *priv = mport->priv; 1037ba5d141bSAlexandre Bounine struct tsi721_ib_win *ib_win; 103871afe341SAlexandre Bounine int i; 103971afe341SAlexandre Bounine 10409673b883SAlexandre Bounine dev_dbg(&priv->pdev->dev, 10419673b883SAlexandre Bounine "Unmap IBW mapped to PCIe_0x%pad", &lstart); 10429673b883SAlexandre Bounine 104371afe341SAlexandre Bounine /* Search for matching active inbound translation window */ 104471afe341SAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) { 1045ba5d141bSAlexandre Bounine ib_win = &priv->ib_win[i]; 10469673b883SAlexandre Bounine 10479673b883SAlexandre Bounine /* Address translating IBWs must to be an exact march */ 10489673b883SAlexandre Bounine if (!ib_win->active || 10499673b883SAlexandre Bounine (ib_win->xlat && lstart != ib_win->lstart)) 10509673b883SAlexandre Bounine continue; 10519673b883SAlexandre Bounine 10529673b883SAlexandre Bounine if (lstart >= ib_win->lstart && 10539673b883SAlexandre Bounine lstart < (ib_win->lstart + ib_win->size)) { 10549673b883SAlexandre Bounine 10559673b883SAlexandre Bounine if (!ib_win->xlat) { 10569673b883SAlexandre Bounine struct tsi721_ib_win_mapping *map; 10579673b883SAlexandre Bounine int found = 0; 10589673b883SAlexandre Bounine 10599673b883SAlexandre Bounine list_for_each_entry(map, 10609673b883SAlexandre Bounine &ib_win->mappings, node) { 10619673b883SAlexandre Bounine if (map->lstart == lstart) { 10629673b883SAlexandre Bounine list_del(&map->node); 10639673b883SAlexandre Bounine kfree(map); 10649673b883SAlexandre Bounine found = 1; 106571afe341SAlexandre Bounine break; 106671afe341SAlexandre Bounine } 106771afe341SAlexandre Bounine } 10689673b883SAlexandre Bounine 10699673b883SAlexandre Bounine if (!found) 10709673b883SAlexandre Bounine continue; 10719673b883SAlexandre Bounine 10729673b883SAlexandre Bounine if (!list_empty(&ib_win->mappings)) 10739673b883SAlexandre Bounine break; 10749673b883SAlexandre Bounine } 10759673b883SAlexandre Bounine 10769673b883SAlexandre Bounine dev_dbg(&priv->pdev->dev, "Disable IBWIN_%d", i); 10779673b883SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBWIN_LB(i)); 10789673b883SAlexandre Bounine ib_win->active = false; 10799673b883SAlexandre Bounine priv->ibwin_cnt++; 10809673b883SAlexandre Bounine break; 10819673b883SAlexandre Bounine } 10829673b883SAlexandre Bounine } 1083ba5d141bSAlexandre Bounine 1084ba5d141bSAlexandre Bounine if (i == TSI721_IBWIN_NUM) 10859673b883SAlexandre Bounine dev_dbg(&priv->pdev->dev, 10869673b883SAlexandre Bounine "IB window mapped to %pad not found", &lstart); 108771afe341SAlexandre Bounine } 108871afe341SAlexandre Bounine 108971afe341SAlexandre Bounine /** 109048618fb4SAlexandre Bounine * tsi721_init_sr2pc_mapping - initializes inbound (SRIO->PCIe) 109148618fb4SAlexandre Bounine * translation regions. 109248618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 109348618fb4SAlexandre Bounine * 109448618fb4SAlexandre Bounine * Disables inbound windows. 109548618fb4SAlexandre Bounine */ 109648618fb4SAlexandre Bounine static void tsi721_init_sr2pc_mapping(struct tsi721_device *priv) 109748618fb4SAlexandre Bounine { 109848618fb4SAlexandre Bounine int i; 109948618fb4SAlexandre Bounine 110048618fb4SAlexandre Bounine /* Disable all SR2PC inbound windows */ 110148618fb4SAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) 110271afe341SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBWIN_LB(i)); 11039673b883SAlexandre Bounine priv->ibwin_cnt = TSI721_IBWIN_NUM; 110448618fb4SAlexandre Bounine } 110548618fb4SAlexandre Bounine 110648618fb4SAlexandre Bounine /** 110748618fb4SAlexandre Bounine * tsi721_port_write_init - Inbound port write interface init 110848618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 110948618fb4SAlexandre Bounine * 111048618fb4SAlexandre Bounine * Initializes inbound port write handler. 111148618fb4SAlexandre Bounine * Returns %0 on success or %-ENOMEM on failure. 111248618fb4SAlexandre Bounine */ 111348618fb4SAlexandre Bounine static int tsi721_port_write_init(struct tsi721_device *priv) 111448618fb4SAlexandre Bounine { 111548618fb4SAlexandre Bounine priv->pw_discard_count = 0; 111648618fb4SAlexandre Bounine INIT_WORK(&priv->pw_work, tsi721_pw_dpc); 111748618fb4SAlexandre Bounine spin_lock_init(&priv->pw_fifo_lock); 111848618fb4SAlexandre Bounine if (kfifo_alloc(&priv->pw_fifo, 111948618fb4SAlexandre Bounine TSI721_RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) { 112048618fb4SAlexandre Bounine dev_err(&priv->pdev->dev, "PW FIFO allocation failed\n"); 112148618fb4SAlexandre Bounine return -ENOMEM; 112248618fb4SAlexandre Bounine } 112348618fb4SAlexandre Bounine 112448618fb4SAlexandre Bounine /* Use reliable port-write capture mode */ 112548618fb4SAlexandre Bounine iowrite32(TSI721_RIO_PW_CTL_PWC_REL, priv->regs + TSI721_RIO_PW_CTL); 112648618fb4SAlexandre Bounine return 0; 112748618fb4SAlexandre Bounine } 112848618fb4SAlexandre Bounine 112948618fb4SAlexandre Bounine static int tsi721_doorbell_init(struct tsi721_device *priv) 113048618fb4SAlexandre Bounine { 113148618fb4SAlexandre Bounine /* Outbound Doorbells do not require any setup. 113248618fb4SAlexandre Bounine * Tsi721 uses dedicated PCI BAR1 to generate doorbells. 113348618fb4SAlexandre Bounine * That BAR1 was mapped during the probe routine. 113448618fb4SAlexandre Bounine */ 113548618fb4SAlexandre Bounine 113648618fb4SAlexandre Bounine /* Initialize Inbound Doorbell processing DPC and queue */ 113748618fb4SAlexandre Bounine priv->db_discard_count = 0; 113848618fb4SAlexandre Bounine INIT_WORK(&priv->idb_work, tsi721_db_dpc); 113948618fb4SAlexandre Bounine 114048618fb4SAlexandre Bounine /* Allocate buffer for inbound doorbells queue */ 1141ceb96398SAlexandre Bounine priv->idb_base = dma_zalloc_coherent(&priv->pdev->dev, 114248618fb4SAlexandre Bounine IDB_QSIZE * TSI721_IDB_ENTRY_SIZE, 114348618fb4SAlexandre Bounine &priv->idb_dma, GFP_KERNEL); 114448618fb4SAlexandre Bounine if (!priv->idb_base) 114548618fb4SAlexandre Bounine return -ENOMEM; 114648618fb4SAlexandre Bounine 114748618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, "Allocated IDB buffer @ %p (phys = %llx)\n", 114848618fb4SAlexandre Bounine priv->idb_base, (unsigned long long)priv->idb_dma); 114948618fb4SAlexandre Bounine 115048618fb4SAlexandre Bounine iowrite32(TSI721_IDQ_SIZE_VAL(IDB_QSIZE), 115148618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_SIZE(IDB_QUEUE)); 115248618fb4SAlexandre Bounine iowrite32(((u64)priv->idb_dma >> 32), 115348618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_BASEU(IDB_QUEUE)); 115448618fb4SAlexandre Bounine iowrite32(((u64)priv->idb_dma & TSI721_IDQ_BASEL_ADDR), 115548618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_BASEL(IDB_QUEUE)); 115648618fb4SAlexandre Bounine /* Enable accepting all inbound doorbells */ 115748618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IDQ_MASK(IDB_QUEUE)); 115848618fb4SAlexandre Bounine 115948618fb4SAlexandre Bounine iowrite32(TSI721_IDQ_INIT, priv->regs + TSI721_IDQ_CTL(IDB_QUEUE)); 116048618fb4SAlexandre Bounine 116148618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IDQ_RP(IDB_QUEUE)); 116248618fb4SAlexandre Bounine 116348618fb4SAlexandre Bounine return 0; 116448618fb4SAlexandre Bounine } 116548618fb4SAlexandre Bounine 116648618fb4SAlexandre Bounine static void tsi721_doorbell_free(struct tsi721_device *priv) 116748618fb4SAlexandre Bounine { 116848618fb4SAlexandre Bounine if (priv->idb_base == NULL) 116948618fb4SAlexandre Bounine return; 117048618fb4SAlexandre Bounine 117148618fb4SAlexandre Bounine /* Free buffer allocated for inbound doorbell queue */ 117248618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, IDB_QSIZE * TSI721_IDB_ENTRY_SIZE, 117348618fb4SAlexandre Bounine priv->idb_base, priv->idb_dma); 117448618fb4SAlexandre Bounine priv->idb_base = NULL; 117548618fb4SAlexandre Bounine } 117648618fb4SAlexandre Bounine 11779eaa3d9bSAlexandre Bounine /** 11789eaa3d9bSAlexandre Bounine * tsi721_bdma_maint_init - Initialize maintenance request BDMA channel. 11799eaa3d9bSAlexandre Bounine * @priv: pointer to tsi721 private data 11809eaa3d9bSAlexandre Bounine * 11819eaa3d9bSAlexandre Bounine * Initialize BDMA channel allocated for RapidIO maintenance read/write 11829eaa3d9bSAlexandre Bounine * request generation 11839eaa3d9bSAlexandre Bounine * Returns %0 on success or %-ENOMEM on failure. 11849eaa3d9bSAlexandre Bounine */ 11859eaa3d9bSAlexandre Bounine static int tsi721_bdma_maint_init(struct tsi721_device *priv) 118648618fb4SAlexandre Bounine { 118748618fb4SAlexandre Bounine struct tsi721_dma_desc *bd_ptr; 118848618fb4SAlexandre Bounine u64 *sts_ptr; 118948618fb4SAlexandre Bounine dma_addr_t bd_phys, sts_phys; 119048618fb4SAlexandre Bounine int sts_size; 11919eaa3d9bSAlexandre Bounine int bd_num = 2; 11929eaa3d9bSAlexandre Bounine void __iomem *regs; 119348618fb4SAlexandre Bounine 11949eaa3d9bSAlexandre Bounine dev_dbg(&priv->pdev->dev, 11959eaa3d9bSAlexandre Bounine "Init Block DMA Engine for Maintenance requests, CH%d\n", 11969eaa3d9bSAlexandre Bounine TSI721_DMACH_MAINT); 119748618fb4SAlexandre Bounine 119848618fb4SAlexandre Bounine /* 119948618fb4SAlexandre Bounine * Initialize DMA channel for maintenance requests 120048618fb4SAlexandre Bounine */ 120148618fb4SAlexandre Bounine 12029eaa3d9bSAlexandre Bounine priv->mdma.ch_id = TSI721_DMACH_MAINT; 12039eaa3d9bSAlexandre Bounine regs = priv->regs + TSI721_DMAC_BASE(TSI721_DMACH_MAINT); 12049eaa3d9bSAlexandre Bounine 120548618fb4SAlexandre Bounine /* Allocate space for DMA descriptors */ 1206ceb96398SAlexandre Bounine bd_ptr = dma_zalloc_coherent(&priv->pdev->dev, 120748618fb4SAlexandre Bounine bd_num * sizeof(struct tsi721_dma_desc), 120848618fb4SAlexandre Bounine &bd_phys, GFP_KERNEL); 120948618fb4SAlexandre Bounine if (!bd_ptr) 121048618fb4SAlexandre Bounine return -ENOMEM; 121148618fb4SAlexandre Bounine 12129eaa3d9bSAlexandre Bounine priv->mdma.bd_num = bd_num; 12139eaa3d9bSAlexandre Bounine priv->mdma.bd_phys = bd_phys; 12149eaa3d9bSAlexandre Bounine priv->mdma.bd_base = bd_ptr; 121548618fb4SAlexandre Bounine 121648618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, "DMA descriptors @ %p (phys = %llx)\n", 121748618fb4SAlexandre Bounine bd_ptr, (unsigned long long)bd_phys); 121848618fb4SAlexandre Bounine 121948618fb4SAlexandre Bounine /* Allocate space for descriptor status FIFO */ 122048618fb4SAlexandre Bounine sts_size = (bd_num >= TSI721_DMA_MINSTSSZ) ? 122148618fb4SAlexandre Bounine bd_num : TSI721_DMA_MINSTSSZ; 122248618fb4SAlexandre Bounine sts_size = roundup_pow_of_two(sts_size); 1223ceb96398SAlexandre Bounine sts_ptr = dma_zalloc_coherent(&priv->pdev->dev, 122448618fb4SAlexandre Bounine sts_size * sizeof(struct tsi721_dma_sts), 122548618fb4SAlexandre Bounine &sts_phys, GFP_KERNEL); 122648618fb4SAlexandre Bounine if (!sts_ptr) { 122748618fb4SAlexandre Bounine /* Free space allocated for DMA descriptors */ 122848618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 122948618fb4SAlexandre Bounine bd_num * sizeof(struct tsi721_dma_desc), 123048618fb4SAlexandre Bounine bd_ptr, bd_phys); 12319eaa3d9bSAlexandre Bounine priv->mdma.bd_base = NULL; 123248618fb4SAlexandre Bounine return -ENOMEM; 123348618fb4SAlexandre Bounine } 123448618fb4SAlexandre Bounine 12359eaa3d9bSAlexandre Bounine priv->mdma.sts_phys = sts_phys; 12369eaa3d9bSAlexandre Bounine priv->mdma.sts_base = sts_ptr; 12379eaa3d9bSAlexandre Bounine priv->mdma.sts_size = sts_size; 123848618fb4SAlexandre Bounine 123948618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 124048618fb4SAlexandre Bounine "desc status FIFO @ %p (phys = %llx) size=0x%x\n", 124148618fb4SAlexandre Bounine sts_ptr, (unsigned long long)sts_phys, sts_size); 124248618fb4SAlexandre Bounine 124348618fb4SAlexandre Bounine /* Initialize DMA descriptors ring */ 124448618fb4SAlexandre Bounine bd_ptr[bd_num - 1].type_id = cpu_to_le32(DTYPE3 << 29); 124548618fb4SAlexandre Bounine bd_ptr[bd_num - 1].next_lo = cpu_to_le32((u64)bd_phys & 124648618fb4SAlexandre Bounine TSI721_DMAC_DPTRL_MASK); 124748618fb4SAlexandre Bounine bd_ptr[bd_num - 1].next_hi = cpu_to_le32((u64)bd_phys >> 32); 124848618fb4SAlexandre Bounine 124948618fb4SAlexandre Bounine /* Setup DMA descriptor pointers */ 12509eaa3d9bSAlexandre Bounine iowrite32(((u64)bd_phys >> 32), regs + TSI721_DMAC_DPTRH); 125148618fb4SAlexandre Bounine iowrite32(((u64)bd_phys & TSI721_DMAC_DPTRL_MASK), 12529eaa3d9bSAlexandre Bounine regs + TSI721_DMAC_DPTRL); 125348618fb4SAlexandre Bounine 125448618fb4SAlexandre Bounine /* Setup descriptor status FIFO */ 12559eaa3d9bSAlexandre Bounine iowrite32(((u64)sts_phys >> 32), regs + TSI721_DMAC_DSBH); 125648618fb4SAlexandre Bounine iowrite32(((u64)sts_phys & TSI721_DMAC_DSBL_MASK), 12579eaa3d9bSAlexandre Bounine regs + TSI721_DMAC_DSBL); 125848618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(sts_size), 12599eaa3d9bSAlexandre Bounine regs + TSI721_DMAC_DSSZ); 126048618fb4SAlexandre Bounine 126148618fb4SAlexandre Bounine /* Clear interrupt bits */ 12629eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_INT_ALL, regs + TSI721_DMAC_INT); 126348618fb4SAlexandre Bounine 12649eaa3d9bSAlexandre Bounine ioread32(regs + TSI721_DMAC_INT); 126548618fb4SAlexandre Bounine 126648618fb4SAlexandre Bounine /* Toggle DMA channel initialization */ 12679eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL); 12689eaa3d9bSAlexandre Bounine ioread32(regs + TSI721_DMAC_CTL); 126948618fb4SAlexandre Bounine udelay(10); 127048618fb4SAlexandre Bounine 127148618fb4SAlexandre Bounine return 0; 127248618fb4SAlexandre Bounine } 127348618fb4SAlexandre Bounine 12749eaa3d9bSAlexandre Bounine static int tsi721_bdma_maint_free(struct tsi721_device *priv) 127548618fb4SAlexandre Bounine { 127648618fb4SAlexandre Bounine u32 ch_stat; 12779eaa3d9bSAlexandre Bounine struct tsi721_bdma_maint *mdma = &priv->mdma; 12789eaa3d9bSAlexandre Bounine void __iomem *regs = priv->regs + TSI721_DMAC_BASE(mdma->ch_id); 127948618fb4SAlexandre Bounine 12809eaa3d9bSAlexandre Bounine if (mdma->bd_base == NULL) 128148618fb4SAlexandre Bounine return 0; 128248618fb4SAlexandre Bounine 128348618fb4SAlexandre Bounine /* Check if DMA channel still running */ 12849eaa3d9bSAlexandre Bounine ch_stat = ioread32(regs + TSI721_DMAC_STS); 128548618fb4SAlexandre Bounine if (ch_stat & TSI721_DMAC_STS_RUN) 128648618fb4SAlexandre Bounine return -EFAULT; 128748618fb4SAlexandre Bounine 128848618fb4SAlexandre Bounine /* Put DMA channel into init state */ 12899eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL); 129048618fb4SAlexandre Bounine 129148618fb4SAlexandre Bounine /* Free space allocated for DMA descriptors */ 129248618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 12939eaa3d9bSAlexandre Bounine mdma->bd_num * sizeof(struct tsi721_dma_desc), 12949eaa3d9bSAlexandre Bounine mdma->bd_base, mdma->bd_phys); 12959eaa3d9bSAlexandre Bounine mdma->bd_base = NULL; 129648618fb4SAlexandre Bounine 129748618fb4SAlexandre Bounine /* Free space allocated for status FIFO */ 129848618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 12999eaa3d9bSAlexandre Bounine mdma->sts_size * sizeof(struct tsi721_dma_sts), 13009eaa3d9bSAlexandre Bounine mdma->sts_base, mdma->sts_phys); 13019eaa3d9bSAlexandre Bounine mdma->sts_base = NULL; 130248618fb4SAlexandre Bounine return 0; 130348618fb4SAlexandre Bounine } 130448618fb4SAlexandre Bounine 130548618fb4SAlexandre Bounine /* Enable Inbound Messaging Interrupts */ 130648618fb4SAlexandre Bounine static void 130748618fb4SAlexandre Bounine tsi721_imsg_interrupt_enable(struct tsi721_device *priv, int ch, 130848618fb4SAlexandre Bounine u32 inte_mask) 130948618fb4SAlexandre Bounine { 131048618fb4SAlexandre Bounine u32 rval; 131148618fb4SAlexandre Bounine 131248618fb4SAlexandre Bounine if (!inte_mask) 131348618fb4SAlexandre Bounine return; 131448618fb4SAlexandre Bounine 131548618fb4SAlexandre Bounine /* Clear pending Inbound Messaging interrupts */ 131648618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_IBDMAC_INT(ch)); 131748618fb4SAlexandre Bounine 131848618fb4SAlexandre Bounine /* Enable Inbound Messaging interrupts */ 131948618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_IBDMAC_INTE(ch)); 132048618fb4SAlexandre Bounine iowrite32(rval | inte_mask, priv->regs + TSI721_IBDMAC_INTE(ch)); 132148618fb4SAlexandre Bounine 132248618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 132348618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */ 132448618fb4SAlexandre Bounine 132548618fb4SAlexandre Bounine /* 132648618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to enable next levels 132748618fb4SAlexandre Bounine */ 132848618fb4SAlexandre Bounine 132948618fb4SAlexandre Bounine /* Enable Device Channel Interrupt */ 133048618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 133148618fb4SAlexandre Bounine iowrite32(rval | TSI721_INT_IMSG_CHAN(ch), 133248618fb4SAlexandre Bounine priv->regs + TSI721_DEV_CHAN_INTE); 133348618fb4SAlexandre Bounine } 133448618fb4SAlexandre Bounine 133548618fb4SAlexandre Bounine /* Disable Inbound Messaging Interrupts */ 133648618fb4SAlexandre Bounine static void 133748618fb4SAlexandre Bounine tsi721_imsg_interrupt_disable(struct tsi721_device *priv, int ch, 133848618fb4SAlexandre Bounine u32 inte_mask) 133948618fb4SAlexandre Bounine { 134048618fb4SAlexandre Bounine u32 rval; 134148618fb4SAlexandre Bounine 134248618fb4SAlexandre Bounine if (!inte_mask) 134348618fb4SAlexandre Bounine return; 134448618fb4SAlexandre Bounine 134548618fb4SAlexandre Bounine /* Clear pending Inbound Messaging interrupts */ 134648618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_IBDMAC_INT(ch)); 134748618fb4SAlexandre Bounine 134848618fb4SAlexandre Bounine /* Disable Inbound Messaging interrupts */ 134948618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_IBDMAC_INTE(ch)); 135048618fb4SAlexandre Bounine rval &= ~inte_mask; 135148618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_IBDMAC_INTE(ch)); 135248618fb4SAlexandre Bounine 135348618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 135448618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */ 135548618fb4SAlexandre Bounine 135648618fb4SAlexandre Bounine /* 135748618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to disable next levels 135848618fb4SAlexandre Bounine */ 135948618fb4SAlexandre Bounine 136048618fb4SAlexandre Bounine /* Disable Device Channel Interrupt */ 136148618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 136248618fb4SAlexandre Bounine rval &= ~TSI721_INT_IMSG_CHAN(ch); 136348618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_DEV_CHAN_INTE); 136448618fb4SAlexandre Bounine } 136548618fb4SAlexandre Bounine 136648618fb4SAlexandre Bounine /* Enable Outbound Messaging interrupts */ 136748618fb4SAlexandre Bounine static void 136848618fb4SAlexandre Bounine tsi721_omsg_interrupt_enable(struct tsi721_device *priv, int ch, 136948618fb4SAlexandre Bounine u32 inte_mask) 137048618fb4SAlexandre Bounine { 137148618fb4SAlexandre Bounine u32 rval; 137248618fb4SAlexandre Bounine 137348618fb4SAlexandre Bounine if (!inte_mask) 137448618fb4SAlexandre Bounine return; 137548618fb4SAlexandre Bounine 137648618fb4SAlexandre Bounine /* Clear pending Outbound Messaging interrupts */ 137748618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_OBDMAC_INT(ch)); 137848618fb4SAlexandre Bounine 137948618fb4SAlexandre Bounine /* Enable Outbound Messaging channel interrupts */ 138048618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_OBDMAC_INTE(ch)); 138148618fb4SAlexandre Bounine iowrite32(rval | inte_mask, priv->regs + TSI721_OBDMAC_INTE(ch)); 138248618fb4SAlexandre Bounine 138348618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 138448618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */ 138548618fb4SAlexandre Bounine 138648618fb4SAlexandre Bounine /* 138748618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to enable next levels 138848618fb4SAlexandre Bounine */ 138948618fb4SAlexandre Bounine 139048618fb4SAlexandre Bounine /* Enable Device Channel Interrupt */ 139148618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 139248618fb4SAlexandre Bounine iowrite32(rval | TSI721_INT_OMSG_CHAN(ch), 139348618fb4SAlexandre Bounine priv->regs + TSI721_DEV_CHAN_INTE); 139448618fb4SAlexandre Bounine } 139548618fb4SAlexandre Bounine 139648618fb4SAlexandre Bounine /* Disable Outbound Messaging interrupts */ 139748618fb4SAlexandre Bounine static void 139848618fb4SAlexandre Bounine tsi721_omsg_interrupt_disable(struct tsi721_device *priv, int ch, 139948618fb4SAlexandre Bounine u32 inte_mask) 140048618fb4SAlexandre Bounine { 140148618fb4SAlexandre Bounine u32 rval; 140248618fb4SAlexandre Bounine 140348618fb4SAlexandre Bounine if (!inte_mask) 140448618fb4SAlexandre Bounine return; 140548618fb4SAlexandre Bounine 140648618fb4SAlexandre Bounine /* Clear pending Outbound Messaging interrupts */ 140748618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_OBDMAC_INT(ch)); 140848618fb4SAlexandre Bounine 140948618fb4SAlexandre Bounine /* Disable Outbound Messaging interrupts */ 141048618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_OBDMAC_INTE(ch)); 141148618fb4SAlexandre Bounine rval &= ~inte_mask; 141248618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_OBDMAC_INTE(ch)); 141348618fb4SAlexandre Bounine 141448618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) 141548618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */ 141648618fb4SAlexandre Bounine 141748618fb4SAlexandre Bounine /* 141848618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to disable next levels 141948618fb4SAlexandre Bounine */ 142048618fb4SAlexandre Bounine 142148618fb4SAlexandre Bounine /* Disable Device Channel Interrupt */ 142248618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 142348618fb4SAlexandre Bounine rval &= ~TSI721_INT_OMSG_CHAN(ch); 142448618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_DEV_CHAN_INTE); 142548618fb4SAlexandre Bounine } 142648618fb4SAlexandre Bounine 142748618fb4SAlexandre Bounine /** 142848618fb4SAlexandre Bounine * tsi721_add_outb_message - Add message to the Tsi721 outbound message queue 142948618fb4SAlexandre Bounine * @mport: Master port with outbound message queue 143048618fb4SAlexandre Bounine * @rdev: Target of outbound message 143148618fb4SAlexandre Bounine * @mbox: Outbound mailbox 143248618fb4SAlexandre Bounine * @buffer: Message to add to outbound queue 143348618fb4SAlexandre Bounine * @len: Length of message 143448618fb4SAlexandre Bounine */ 143548618fb4SAlexandre Bounine static int 143648618fb4SAlexandre Bounine tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, 143748618fb4SAlexandre Bounine void *buffer, size_t len) 143848618fb4SAlexandre Bounine { 143948618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 144048618fb4SAlexandre Bounine struct tsi721_omsg_desc *desc; 144148618fb4SAlexandre Bounine u32 tx_slot; 144248618fb4SAlexandre Bounine 144348618fb4SAlexandre Bounine if (!priv->omsg_init[mbox] || 144448618fb4SAlexandre Bounine len > TSI721_MSG_MAX_SIZE || len < 8) 144548618fb4SAlexandre Bounine return -EINVAL; 144648618fb4SAlexandre Bounine 144748618fb4SAlexandre Bounine tx_slot = priv->omsg_ring[mbox].tx_slot; 144848618fb4SAlexandre Bounine 144948618fb4SAlexandre Bounine /* Copy copy message into transfer buffer */ 145048618fb4SAlexandre Bounine memcpy(priv->omsg_ring[mbox].omq_base[tx_slot], buffer, len); 145148618fb4SAlexandre Bounine 145248618fb4SAlexandre Bounine if (len & 0x7) 145348618fb4SAlexandre Bounine len += 8; 145448618fb4SAlexandre Bounine 145548618fb4SAlexandre Bounine /* Build descriptor associated with buffer */ 145648618fb4SAlexandre Bounine desc = priv->omsg_ring[mbox].omd_base; 145748618fb4SAlexandre Bounine desc[tx_slot].type_id = cpu_to_le32((DTYPE4 << 29) | rdev->destid); 145848618fb4SAlexandre Bounine if (tx_slot % 4 == 0) 145948618fb4SAlexandre Bounine desc[tx_slot].type_id |= cpu_to_le32(TSI721_OMD_IOF); 146048618fb4SAlexandre Bounine 146148618fb4SAlexandre Bounine desc[tx_slot].msg_info = 146248618fb4SAlexandre Bounine cpu_to_le32((mport->sys_size << 26) | (mbox << 22) | 146348618fb4SAlexandre Bounine (0xe << 12) | (len & 0xff8)); 146448618fb4SAlexandre Bounine desc[tx_slot].bufptr_lo = 146548618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omq_phys[tx_slot] & 146648618fb4SAlexandre Bounine 0xffffffff); 146748618fb4SAlexandre Bounine desc[tx_slot].bufptr_hi = 146848618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omq_phys[tx_slot] >> 32); 146948618fb4SAlexandre Bounine 147048618fb4SAlexandre Bounine priv->omsg_ring[mbox].wr_count++; 147148618fb4SAlexandre Bounine 147248618fb4SAlexandre Bounine /* Go to next descriptor */ 147348618fb4SAlexandre Bounine if (++priv->omsg_ring[mbox].tx_slot == priv->omsg_ring[mbox].size) { 147448618fb4SAlexandre Bounine priv->omsg_ring[mbox].tx_slot = 0; 147548618fb4SAlexandre Bounine /* Move through the ring link descriptor at the end */ 147648618fb4SAlexandre Bounine priv->omsg_ring[mbox].wr_count++; 147748618fb4SAlexandre Bounine } 147848618fb4SAlexandre Bounine 147948618fb4SAlexandre Bounine mb(); 148048618fb4SAlexandre Bounine 148148618fb4SAlexandre Bounine /* Set new write count value */ 148248618fb4SAlexandre Bounine iowrite32(priv->omsg_ring[mbox].wr_count, 148348618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); 148448618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); 148548618fb4SAlexandre Bounine 148648618fb4SAlexandre Bounine return 0; 148748618fb4SAlexandre Bounine } 148848618fb4SAlexandre Bounine 148948618fb4SAlexandre Bounine /** 149048618fb4SAlexandre Bounine * tsi721_omsg_handler - Outbound Message Interrupt Handler 149148618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 149248618fb4SAlexandre Bounine * @ch: number of OB MSG channel to service 149348618fb4SAlexandre Bounine * 149448618fb4SAlexandre Bounine * Services channel interrupts from outbound messaging engine. 149548618fb4SAlexandre Bounine */ 149648618fb4SAlexandre Bounine static void tsi721_omsg_handler(struct tsi721_device *priv, int ch) 149748618fb4SAlexandre Bounine { 149848618fb4SAlexandre Bounine u32 omsg_int; 149948618fb4SAlexandre Bounine 150048618fb4SAlexandre Bounine spin_lock(&priv->omsg_ring[ch].lock); 150148618fb4SAlexandre Bounine 150248618fb4SAlexandre Bounine omsg_int = ioread32(priv->regs + TSI721_OBDMAC_INT(ch)); 150348618fb4SAlexandre Bounine 150448618fb4SAlexandre Bounine if (omsg_int & TSI721_OBDMAC_INT_ST_FULL) 150548618fb4SAlexandre Bounine dev_info(&priv->pdev->dev, 150648618fb4SAlexandre Bounine "OB MBOX%d: Status FIFO is full\n", ch); 150748618fb4SAlexandre Bounine 150848618fb4SAlexandre Bounine if (omsg_int & (TSI721_OBDMAC_INT_DONE | TSI721_OBDMAC_INT_IOF_DONE)) { 150948618fb4SAlexandre Bounine u32 srd_ptr; 151048618fb4SAlexandre Bounine u64 *sts_ptr, last_ptr = 0, prev_ptr = 0; 151148618fb4SAlexandre Bounine int i, j; 151248618fb4SAlexandre Bounine u32 tx_slot; 151348618fb4SAlexandre Bounine 151448618fb4SAlexandre Bounine /* 151548618fb4SAlexandre Bounine * Find last successfully processed descriptor 151648618fb4SAlexandre Bounine */ 151748618fb4SAlexandre Bounine 151848618fb4SAlexandre Bounine /* Check and clear descriptor status FIFO entries */ 151948618fb4SAlexandre Bounine srd_ptr = priv->omsg_ring[ch].sts_rdptr; 152048618fb4SAlexandre Bounine sts_ptr = priv->omsg_ring[ch].sts_base; 152148618fb4SAlexandre Bounine j = srd_ptr * 8; 152248618fb4SAlexandre Bounine while (sts_ptr[j]) { 152348618fb4SAlexandre Bounine for (i = 0; i < 8 && sts_ptr[j]; i++, j++) { 152448618fb4SAlexandre Bounine prev_ptr = last_ptr; 152548618fb4SAlexandre Bounine last_ptr = le64_to_cpu(sts_ptr[j]); 152648618fb4SAlexandre Bounine sts_ptr[j] = 0; 152748618fb4SAlexandre Bounine } 152848618fb4SAlexandre Bounine 152948618fb4SAlexandre Bounine ++srd_ptr; 153048618fb4SAlexandre Bounine srd_ptr %= priv->omsg_ring[ch].sts_size; 153148618fb4SAlexandre Bounine j = srd_ptr * 8; 153248618fb4SAlexandre Bounine } 153348618fb4SAlexandre Bounine 153448618fb4SAlexandre Bounine if (last_ptr == 0) 153548618fb4SAlexandre Bounine goto no_sts_update; 153648618fb4SAlexandre Bounine 153748618fb4SAlexandre Bounine priv->omsg_ring[ch].sts_rdptr = srd_ptr; 153848618fb4SAlexandre Bounine iowrite32(srd_ptr, priv->regs + TSI721_OBDMAC_DSRP(ch)); 153948618fb4SAlexandre Bounine 154048618fb4SAlexandre Bounine if (!priv->mport->outb_msg[ch].mcback) 154148618fb4SAlexandre Bounine goto no_sts_update; 154248618fb4SAlexandre Bounine 154348618fb4SAlexandre Bounine /* Inform upper layer about transfer completion */ 154448618fb4SAlexandre Bounine 154548618fb4SAlexandre Bounine tx_slot = (last_ptr - (u64)priv->omsg_ring[ch].omd_phys)/ 154648618fb4SAlexandre Bounine sizeof(struct tsi721_omsg_desc); 154748618fb4SAlexandre Bounine 154848618fb4SAlexandre Bounine /* 154948618fb4SAlexandre Bounine * Check if this is a Link Descriptor (LD). 155048618fb4SAlexandre Bounine * If yes, ignore LD and use descriptor processed 155148618fb4SAlexandre Bounine * before LD. 155248618fb4SAlexandre Bounine */ 155348618fb4SAlexandre Bounine if (tx_slot == priv->omsg_ring[ch].size) { 155448618fb4SAlexandre Bounine if (prev_ptr) 155548618fb4SAlexandre Bounine tx_slot = (prev_ptr - 155648618fb4SAlexandre Bounine (u64)priv->omsg_ring[ch].omd_phys)/ 155748618fb4SAlexandre Bounine sizeof(struct tsi721_omsg_desc); 155848618fb4SAlexandre Bounine else 155948618fb4SAlexandre Bounine goto no_sts_update; 156048618fb4SAlexandre Bounine } 156148618fb4SAlexandre Bounine 156248618fb4SAlexandre Bounine /* Move slot index to the next message to be sent */ 156348618fb4SAlexandre Bounine ++tx_slot; 156448618fb4SAlexandre Bounine if (tx_slot == priv->omsg_ring[ch].size) 156548618fb4SAlexandre Bounine tx_slot = 0; 156648618fb4SAlexandre Bounine BUG_ON(tx_slot >= priv->omsg_ring[ch].size); 156748618fb4SAlexandre Bounine priv->mport->outb_msg[ch].mcback(priv->mport, 156848618fb4SAlexandre Bounine priv->omsg_ring[ch].dev_id, ch, 156948618fb4SAlexandre Bounine tx_slot); 157048618fb4SAlexandre Bounine } 157148618fb4SAlexandre Bounine 157248618fb4SAlexandre Bounine no_sts_update: 157348618fb4SAlexandre Bounine 157448618fb4SAlexandre Bounine if (omsg_int & TSI721_OBDMAC_INT_ERROR) { 157548618fb4SAlexandre Bounine /* 157648618fb4SAlexandre Bounine * Outbound message operation aborted due to error, 157748618fb4SAlexandre Bounine * reinitialize OB MSG channel 157848618fb4SAlexandre Bounine */ 157948618fb4SAlexandre Bounine 158048618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, "OB MSG ABORT ch_stat=%x\n", 158148618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_STS(ch))); 158248618fb4SAlexandre Bounine 158348618fb4SAlexandre Bounine iowrite32(TSI721_OBDMAC_INT_ERROR, 158448618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_INT(ch)); 158548618fb4SAlexandre Bounine iowrite32(TSI721_OBDMAC_CTL_INIT, 158648618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_CTL(ch)); 158748618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_CTL(ch)); 158848618fb4SAlexandre Bounine 158948618fb4SAlexandre Bounine /* Inform upper level to clear all pending tx slots */ 159048618fb4SAlexandre Bounine if (priv->mport->outb_msg[ch].mcback) 159148618fb4SAlexandre Bounine priv->mport->outb_msg[ch].mcback(priv->mport, 159248618fb4SAlexandre Bounine priv->omsg_ring[ch].dev_id, ch, 159348618fb4SAlexandre Bounine priv->omsg_ring[ch].tx_slot); 159448618fb4SAlexandre Bounine /* Synch tx_slot tracking */ 159548618fb4SAlexandre Bounine iowrite32(priv->omsg_ring[ch].tx_slot, 159648618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DRDCNT(ch)); 159748618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_DRDCNT(ch)); 159848618fb4SAlexandre Bounine priv->omsg_ring[ch].wr_count = priv->omsg_ring[ch].tx_slot; 159948618fb4SAlexandre Bounine priv->omsg_ring[ch].sts_rdptr = 0; 160048618fb4SAlexandre Bounine } 160148618fb4SAlexandre Bounine 160248618fb4SAlexandre Bounine /* Clear channel interrupts */ 160348618fb4SAlexandre Bounine iowrite32(omsg_int, priv->regs + TSI721_OBDMAC_INT(ch)); 160448618fb4SAlexandre Bounine 160548618fb4SAlexandre Bounine if (!(priv->flags & TSI721_USING_MSIX)) { 160648618fb4SAlexandre Bounine u32 ch_inte; 160748618fb4SAlexandre Bounine 160848618fb4SAlexandre Bounine /* Re-enable channel interrupts */ 160948618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 161048618fb4SAlexandre Bounine ch_inte |= TSI721_INT_OMSG_CHAN(ch); 161148618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE); 161248618fb4SAlexandre Bounine } 161348618fb4SAlexandre Bounine 161448618fb4SAlexandre Bounine spin_unlock(&priv->omsg_ring[ch].lock); 161548618fb4SAlexandre Bounine } 161648618fb4SAlexandre Bounine 161748618fb4SAlexandre Bounine /** 161848618fb4SAlexandre Bounine * tsi721_open_outb_mbox - Initialize Tsi721 outbound mailbox 161948618fb4SAlexandre Bounine * @mport: Master port implementing Outbound Messaging Engine 162048618fb4SAlexandre Bounine * @dev_id: Device specific pointer to pass on event 162148618fb4SAlexandre Bounine * @mbox: Mailbox to open 162248618fb4SAlexandre Bounine * @entries: Number of entries in the outbound mailbox ring 162348618fb4SAlexandre Bounine */ 162448618fb4SAlexandre Bounine static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id, 162548618fb4SAlexandre Bounine int mbox, int entries) 162648618fb4SAlexandre Bounine { 162748618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 162848618fb4SAlexandre Bounine struct tsi721_omsg_desc *bd_ptr; 162948618fb4SAlexandre Bounine int i, rc = 0; 163048618fb4SAlexandre Bounine 163148618fb4SAlexandre Bounine if ((entries < TSI721_OMSGD_MIN_RING_SIZE) || 163248618fb4SAlexandre Bounine (entries > (TSI721_OMSGD_RING_SIZE)) || 163348618fb4SAlexandre Bounine (!is_power_of_2(entries)) || mbox >= RIO_MAX_MBOX) { 163448618fb4SAlexandre Bounine rc = -EINVAL; 163548618fb4SAlexandre Bounine goto out; 163648618fb4SAlexandre Bounine } 163748618fb4SAlexandre Bounine 163848618fb4SAlexandre Bounine priv->omsg_ring[mbox].dev_id = dev_id; 163948618fb4SAlexandre Bounine priv->omsg_ring[mbox].size = entries; 164048618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_rdptr = 0; 164148618fb4SAlexandre Bounine spin_lock_init(&priv->omsg_ring[mbox].lock); 164248618fb4SAlexandre Bounine 164348618fb4SAlexandre Bounine /* Outbound Msg Buffer allocation based on 164448618fb4SAlexandre Bounine the number of maximum descriptor entries */ 164548618fb4SAlexandre Bounine for (i = 0; i < entries; i++) { 164648618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i] = 164748618fb4SAlexandre Bounine dma_alloc_coherent( 164848618fb4SAlexandre Bounine &priv->pdev->dev, TSI721_MSG_BUFFER_SIZE, 164948618fb4SAlexandre Bounine &priv->omsg_ring[mbox].omq_phys[i], 165048618fb4SAlexandre Bounine GFP_KERNEL); 165148618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omq_base[i] == NULL) { 165248618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 165348618fb4SAlexandre Bounine "Unable to allocate OB MSG data buffer for" 165448618fb4SAlexandre Bounine " MBOX%d\n", mbox); 165548618fb4SAlexandre Bounine rc = -ENOMEM; 165648618fb4SAlexandre Bounine goto out_buf; 165748618fb4SAlexandre Bounine } 165848618fb4SAlexandre Bounine } 165948618fb4SAlexandre Bounine 166048618fb4SAlexandre Bounine /* Outbound message descriptor allocation */ 166148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base = dma_alloc_coherent( 166248618fb4SAlexandre Bounine &priv->pdev->dev, 166348618fb4SAlexandre Bounine (entries + 1) * sizeof(struct tsi721_omsg_desc), 166448618fb4SAlexandre Bounine &priv->omsg_ring[mbox].omd_phys, GFP_KERNEL); 166548618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omd_base == NULL) { 166648618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 166748618fb4SAlexandre Bounine "Unable to allocate OB MSG descriptor memory " 166848618fb4SAlexandre Bounine "for MBOX%d\n", mbox); 166948618fb4SAlexandre Bounine rc = -ENOMEM; 167048618fb4SAlexandre Bounine goto out_buf; 167148618fb4SAlexandre Bounine } 167248618fb4SAlexandre Bounine 167348618fb4SAlexandre Bounine priv->omsg_ring[mbox].tx_slot = 0; 167448618fb4SAlexandre Bounine 167548618fb4SAlexandre Bounine /* Outbound message descriptor status FIFO allocation */ 167648618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size = roundup_pow_of_two(entries + 1); 1677ceb96398SAlexandre Bounine priv->omsg_ring[mbox].sts_base = dma_zalloc_coherent(&priv->pdev->dev, 167848618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size * 167948618fb4SAlexandre Bounine sizeof(struct tsi721_dma_sts), 168048618fb4SAlexandre Bounine &priv->omsg_ring[mbox].sts_phys, GFP_KERNEL); 168148618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].sts_base == NULL) { 168248618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 168348618fb4SAlexandre Bounine "Unable to allocate OB MSG descriptor status FIFO " 168448618fb4SAlexandre Bounine "for MBOX%d\n", mbox); 168548618fb4SAlexandre Bounine rc = -ENOMEM; 168648618fb4SAlexandre Bounine goto out_desc; 168748618fb4SAlexandre Bounine } 168848618fb4SAlexandre Bounine 168948618fb4SAlexandre Bounine /* 169048618fb4SAlexandre Bounine * Configure Outbound Messaging Engine 169148618fb4SAlexandre Bounine */ 169248618fb4SAlexandre Bounine 169348618fb4SAlexandre Bounine /* Setup Outbound Message descriptor pointer */ 169448618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].omd_phys >> 32), 169548618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DPTRH(mbox)); 169648618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].omd_phys & 169748618fb4SAlexandre Bounine TSI721_OBDMAC_DPTRL_MASK), 169848618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DPTRL(mbox)); 169948618fb4SAlexandre Bounine 170048618fb4SAlexandre Bounine /* Setup Outbound Message descriptor status FIFO */ 170148618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].sts_phys >> 32), 170248618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DSBH(mbox)); 170348618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].sts_phys & 170448618fb4SAlexandre Bounine TSI721_OBDMAC_DSBL_MASK), 170548618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DSBL(mbox)); 170648618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(priv->omsg_ring[mbox].sts_size), 170748618fb4SAlexandre Bounine priv->regs + (u32)TSI721_OBDMAC_DSSZ(mbox)); 170848618fb4SAlexandre Bounine 170948618fb4SAlexandre Bounine /* Enable interrupts */ 171048618fb4SAlexandre Bounine 171148618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 171248618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) { 171348618fb4SAlexandre Bounine /* Request interrupt service if we are in MSI-X mode */ 171448618fb4SAlexandre Bounine rc = request_irq( 171548618fb4SAlexandre Bounine priv->msix[TSI721_VECT_OMB0_DONE + mbox].vector, 171648618fb4SAlexandre Bounine tsi721_omsg_msix, 0, 171748618fb4SAlexandre Bounine priv->msix[TSI721_VECT_OMB0_DONE + mbox].irq_name, 171848618fb4SAlexandre Bounine (void *)mport); 171948618fb4SAlexandre Bounine 172048618fb4SAlexandre Bounine if (rc) { 172148618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 172248618fb4SAlexandre Bounine "Unable to allocate MSI-X interrupt for " 172348618fb4SAlexandre Bounine "OBOX%d-DONE\n", mbox); 172448618fb4SAlexandre Bounine goto out_stat; 172548618fb4SAlexandre Bounine } 172648618fb4SAlexandre Bounine 172748618fb4SAlexandre Bounine rc = request_irq(priv->msix[TSI721_VECT_OMB0_INT + mbox].vector, 172848618fb4SAlexandre Bounine tsi721_omsg_msix, 0, 172948618fb4SAlexandre Bounine priv->msix[TSI721_VECT_OMB0_INT + mbox].irq_name, 173048618fb4SAlexandre Bounine (void *)mport); 173148618fb4SAlexandre Bounine 173248618fb4SAlexandre Bounine if (rc) { 173348618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 173448618fb4SAlexandre Bounine "Unable to allocate MSI-X interrupt for " 173548618fb4SAlexandre Bounine "MBOX%d-INT\n", mbox); 173648618fb4SAlexandre Bounine free_irq( 173748618fb4SAlexandre Bounine priv->msix[TSI721_VECT_OMB0_DONE + mbox].vector, 173848618fb4SAlexandre Bounine (void *)mport); 173948618fb4SAlexandre Bounine goto out_stat; 174048618fb4SAlexandre Bounine } 174148618fb4SAlexandre Bounine } 174248618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 174348618fb4SAlexandre Bounine 174448618fb4SAlexandre Bounine tsi721_omsg_interrupt_enable(priv, mbox, TSI721_OBDMAC_INT_ALL); 174548618fb4SAlexandre Bounine 174648618fb4SAlexandre Bounine /* Initialize Outbound Message descriptors ring */ 174748618fb4SAlexandre Bounine bd_ptr = priv->omsg_ring[mbox].omd_base; 174848618fb4SAlexandre Bounine bd_ptr[entries].type_id = cpu_to_le32(DTYPE5 << 29); 174948618fb4SAlexandre Bounine bd_ptr[entries].msg_info = 0; 175048618fb4SAlexandre Bounine bd_ptr[entries].next_lo = 175148618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omd_phys & 175248618fb4SAlexandre Bounine TSI721_OBDMAC_DPTRL_MASK); 175348618fb4SAlexandre Bounine bd_ptr[entries].next_hi = 175448618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omd_phys >> 32); 175548618fb4SAlexandre Bounine priv->omsg_ring[mbox].wr_count = 0; 175648618fb4SAlexandre Bounine mb(); 175748618fb4SAlexandre Bounine 175848618fb4SAlexandre Bounine /* Initialize Outbound Message engine */ 175948618fb4SAlexandre Bounine iowrite32(TSI721_OBDMAC_CTL_INIT, priv->regs + TSI721_OBDMAC_CTL(mbox)); 176048618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox)); 176148618fb4SAlexandre Bounine udelay(10); 176248618fb4SAlexandre Bounine 176348618fb4SAlexandre Bounine priv->omsg_init[mbox] = 1; 176448618fb4SAlexandre Bounine 176548618fb4SAlexandre Bounine return 0; 176648618fb4SAlexandre Bounine 176748618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 176848618fb4SAlexandre Bounine out_stat: 176948618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 177048618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts), 177148618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base, 177248618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_phys); 177348618fb4SAlexandre Bounine 177448618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base = NULL; 177548618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 177648618fb4SAlexandre Bounine 177748618fb4SAlexandre Bounine out_desc: 177848618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 177948618fb4SAlexandre Bounine (entries + 1) * sizeof(struct tsi721_omsg_desc), 178048618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base, 178148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_phys); 178248618fb4SAlexandre Bounine 178348618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base = NULL; 178448618fb4SAlexandre Bounine 178548618fb4SAlexandre Bounine out_buf: 178648618fb4SAlexandre Bounine for (i = 0; i < priv->omsg_ring[mbox].size; i++) { 178748618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omq_base[i]) { 178848618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 178948618fb4SAlexandre Bounine TSI721_MSG_BUFFER_SIZE, 179048618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i], 179148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_phys[i]); 179248618fb4SAlexandre Bounine 179348618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i] = NULL; 179448618fb4SAlexandre Bounine } 179548618fb4SAlexandre Bounine } 179648618fb4SAlexandre Bounine 179748618fb4SAlexandre Bounine out: 179848618fb4SAlexandre Bounine return rc; 179948618fb4SAlexandre Bounine } 180048618fb4SAlexandre Bounine 180148618fb4SAlexandre Bounine /** 180248618fb4SAlexandre Bounine * tsi721_close_outb_mbox - Close Tsi721 outbound mailbox 180348618fb4SAlexandre Bounine * @mport: Master port implementing the outbound message unit 180448618fb4SAlexandre Bounine * @mbox: Mailbox to close 180548618fb4SAlexandre Bounine */ 180648618fb4SAlexandre Bounine static void tsi721_close_outb_mbox(struct rio_mport *mport, int mbox) 180748618fb4SAlexandre Bounine { 180848618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 180948618fb4SAlexandre Bounine u32 i; 181048618fb4SAlexandre Bounine 181148618fb4SAlexandre Bounine if (!priv->omsg_init[mbox]) 181248618fb4SAlexandre Bounine return; 181348618fb4SAlexandre Bounine priv->omsg_init[mbox] = 0; 181448618fb4SAlexandre Bounine 181548618fb4SAlexandre Bounine /* Disable Interrupts */ 181648618fb4SAlexandre Bounine 181748618fb4SAlexandre Bounine tsi721_omsg_interrupt_disable(priv, mbox, TSI721_OBDMAC_INT_ALL); 181848618fb4SAlexandre Bounine 181948618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 182048618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) { 182148618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_OMB0_DONE + mbox].vector, 182248618fb4SAlexandre Bounine (void *)mport); 182348618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_OMB0_INT + mbox].vector, 182448618fb4SAlexandre Bounine (void *)mport); 182548618fb4SAlexandre Bounine } 182648618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 182748618fb4SAlexandre Bounine 182848618fb4SAlexandre Bounine /* Free OMSG Descriptor Status FIFO */ 182948618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 183048618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts), 183148618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base, 183248618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_phys); 183348618fb4SAlexandre Bounine 183448618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base = NULL; 183548618fb4SAlexandre Bounine 183648618fb4SAlexandre Bounine /* Free OMSG descriptors */ 183748618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 183848618fb4SAlexandre Bounine (priv->omsg_ring[mbox].size + 1) * 183948618fb4SAlexandre Bounine sizeof(struct tsi721_omsg_desc), 184048618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base, 184148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_phys); 184248618fb4SAlexandre Bounine 184348618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base = NULL; 184448618fb4SAlexandre Bounine 184548618fb4SAlexandre Bounine /* Free message buffers */ 184648618fb4SAlexandre Bounine for (i = 0; i < priv->omsg_ring[mbox].size; i++) { 184748618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omq_base[i]) { 184848618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 184948618fb4SAlexandre Bounine TSI721_MSG_BUFFER_SIZE, 185048618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i], 185148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_phys[i]); 185248618fb4SAlexandre Bounine 185348618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i] = NULL; 185448618fb4SAlexandre Bounine } 185548618fb4SAlexandre Bounine } 185648618fb4SAlexandre Bounine } 185748618fb4SAlexandre Bounine 185848618fb4SAlexandre Bounine /** 185948618fb4SAlexandre Bounine * tsi721_imsg_handler - Inbound Message Interrupt Handler 186048618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 186148618fb4SAlexandre Bounine * @ch: inbound message channel number to service 186248618fb4SAlexandre Bounine * 186348618fb4SAlexandre Bounine * Services channel interrupts from inbound messaging engine. 186448618fb4SAlexandre Bounine */ 186548618fb4SAlexandre Bounine static void tsi721_imsg_handler(struct tsi721_device *priv, int ch) 186648618fb4SAlexandre Bounine { 186748618fb4SAlexandre Bounine u32 mbox = ch - 4; 186848618fb4SAlexandre Bounine u32 imsg_int; 186948618fb4SAlexandre Bounine 187048618fb4SAlexandre Bounine spin_lock(&priv->imsg_ring[mbox].lock); 187148618fb4SAlexandre Bounine 187248618fb4SAlexandre Bounine imsg_int = ioread32(priv->regs + TSI721_IBDMAC_INT(ch)); 187348618fb4SAlexandre Bounine 187448618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_SRTO) 187548618fb4SAlexandre Bounine dev_info(&priv->pdev->dev, "IB MBOX%d SRIO timeout\n", 187648618fb4SAlexandre Bounine mbox); 187748618fb4SAlexandre Bounine 187848618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_PC_ERROR) 187948618fb4SAlexandre Bounine dev_info(&priv->pdev->dev, "IB MBOX%d PCIe error\n", 188048618fb4SAlexandre Bounine mbox); 188148618fb4SAlexandre Bounine 188248618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_FQ_LOW) 188348618fb4SAlexandre Bounine dev_info(&priv->pdev->dev, 188448618fb4SAlexandre Bounine "IB MBOX%d IB free queue low\n", mbox); 188548618fb4SAlexandre Bounine 188648618fb4SAlexandre Bounine /* Clear IB channel interrupts */ 188748618fb4SAlexandre Bounine iowrite32(imsg_int, priv->regs + TSI721_IBDMAC_INT(ch)); 188848618fb4SAlexandre Bounine 188948618fb4SAlexandre Bounine /* If an IB Msg is received notify the upper layer */ 189048618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_DQ_RCV && 189148618fb4SAlexandre Bounine priv->mport->inb_msg[mbox].mcback) 189248618fb4SAlexandre Bounine priv->mport->inb_msg[mbox].mcback(priv->mport, 189348618fb4SAlexandre Bounine priv->imsg_ring[mbox].dev_id, mbox, -1); 189448618fb4SAlexandre Bounine 189548618fb4SAlexandre Bounine if (!(priv->flags & TSI721_USING_MSIX)) { 189648618fb4SAlexandre Bounine u32 ch_inte; 189748618fb4SAlexandre Bounine 189848618fb4SAlexandre Bounine /* Re-enable channel interrupts */ 189948618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE); 190048618fb4SAlexandre Bounine ch_inte |= TSI721_INT_IMSG_CHAN(ch); 190148618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE); 190248618fb4SAlexandre Bounine } 190348618fb4SAlexandre Bounine 190448618fb4SAlexandre Bounine spin_unlock(&priv->imsg_ring[mbox].lock); 190548618fb4SAlexandre Bounine } 190648618fb4SAlexandre Bounine 190748618fb4SAlexandre Bounine /** 190848618fb4SAlexandre Bounine * tsi721_open_inb_mbox - Initialize Tsi721 inbound mailbox 190948618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine 191048618fb4SAlexandre Bounine * @dev_id: Device specific pointer to pass on event 191148618fb4SAlexandre Bounine * @mbox: Mailbox to open 191248618fb4SAlexandre Bounine * @entries: Number of entries in the inbound mailbox ring 191348618fb4SAlexandre Bounine */ 191448618fb4SAlexandre Bounine static int tsi721_open_inb_mbox(struct rio_mport *mport, void *dev_id, 191548618fb4SAlexandre Bounine int mbox, int entries) 191648618fb4SAlexandre Bounine { 191748618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 191848618fb4SAlexandre Bounine int ch = mbox + 4; 191948618fb4SAlexandre Bounine int i; 192048618fb4SAlexandre Bounine u64 *free_ptr; 192148618fb4SAlexandre Bounine int rc = 0; 192248618fb4SAlexandre Bounine 192348618fb4SAlexandre Bounine if ((entries < TSI721_IMSGD_MIN_RING_SIZE) || 192448618fb4SAlexandre Bounine (entries > TSI721_IMSGD_RING_SIZE) || 192548618fb4SAlexandre Bounine (!is_power_of_2(entries)) || mbox >= RIO_MAX_MBOX) { 192648618fb4SAlexandre Bounine rc = -EINVAL; 192748618fb4SAlexandre Bounine goto out; 192848618fb4SAlexandre Bounine } 192948618fb4SAlexandre Bounine 193048618fb4SAlexandre Bounine /* Initialize IB Messaging Ring */ 193148618fb4SAlexandre Bounine priv->imsg_ring[mbox].dev_id = dev_id; 193248618fb4SAlexandre Bounine priv->imsg_ring[mbox].size = entries; 193348618fb4SAlexandre Bounine priv->imsg_ring[mbox].rx_slot = 0; 193448618fb4SAlexandre Bounine priv->imsg_ring[mbox].desc_rdptr = 0; 193548618fb4SAlexandre Bounine priv->imsg_ring[mbox].fq_wrptr = 0; 193648618fb4SAlexandre Bounine for (i = 0; i < priv->imsg_ring[mbox].size; i++) 193748618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[i] = NULL; 193848618fb4SAlexandre Bounine spin_lock_init(&priv->imsg_ring[mbox].lock); 193948618fb4SAlexandre Bounine 194048618fb4SAlexandre Bounine /* Allocate buffers for incoming messages */ 194148618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base = 194248618fb4SAlexandre Bounine dma_alloc_coherent(&priv->pdev->dev, 194348618fb4SAlexandre Bounine entries * TSI721_MSG_BUFFER_SIZE, 194448618fb4SAlexandre Bounine &priv->imsg_ring[mbox].buf_phys, 194548618fb4SAlexandre Bounine GFP_KERNEL); 194648618fb4SAlexandre Bounine 194748618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].buf_base == NULL) { 194848618fb4SAlexandre Bounine dev_err(&priv->pdev->dev, 194948618fb4SAlexandre Bounine "Failed to allocate buffers for IB MBOX%d\n", mbox); 195048618fb4SAlexandre Bounine rc = -ENOMEM; 195148618fb4SAlexandre Bounine goto out; 195248618fb4SAlexandre Bounine } 195348618fb4SAlexandre Bounine 195448618fb4SAlexandre Bounine /* Allocate memory for circular free list */ 195548618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base = 195648618fb4SAlexandre Bounine dma_alloc_coherent(&priv->pdev->dev, 195748618fb4SAlexandre Bounine entries * 8, 195848618fb4SAlexandre Bounine &priv->imsg_ring[mbox].imfq_phys, 195948618fb4SAlexandre Bounine GFP_KERNEL); 196048618fb4SAlexandre Bounine 196148618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].imfq_base == NULL) { 196248618fb4SAlexandre Bounine dev_err(&priv->pdev->dev, 196348618fb4SAlexandre Bounine "Failed to allocate free queue for IB MBOX%d\n", mbox); 196448618fb4SAlexandre Bounine rc = -ENOMEM; 196548618fb4SAlexandre Bounine goto out_buf; 196648618fb4SAlexandre Bounine } 196748618fb4SAlexandre Bounine 196848618fb4SAlexandre Bounine /* Allocate memory for Inbound message descriptors */ 196948618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base = 197048618fb4SAlexandre Bounine dma_alloc_coherent(&priv->pdev->dev, 197148618fb4SAlexandre Bounine entries * sizeof(struct tsi721_imsg_desc), 197248618fb4SAlexandre Bounine &priv->imsg_ring[mbox].imd_phys, GFP_KERNEL); 197348618fb4SAlexandre Bounine 197448618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].imd_base == NULL) { 197548618fb4SAlexandre Bounine dev_err(&priv->pdev->dev, 197648618fb4SAlexandre Bounine "Failed to allocate descriptor memory for IB MBOX%d\n", 197748618fb4SAlexandre Bounine mbox); 197848618fb4SAlexandre Bounine rc = -ENOMEM; 197948618fb4SAlexandre Bounine goto out_dma; 198048618fb4SAlexandre Bounine } 198148618fb4SAlexandre Bounine 198248618fb4SAlexandre Bounine /* Fill free buffer pointer list */ 198348618fb4SAlexandre Bounine free_ptr = priv->imsg_ring[mbox].imfq_base; 198448618fb4SAlexandre Bounine for (i = 0; i < entries; i++) 198548618fb4SAlexandre Bounine free_ptr[i] = cpu_to_le64( 198648618fb4SAlexandre Bounine (u64)(priv->imsg_ring[mbox].buf_phys) + 198748618fb4SAlexandre Bounine i * 0x1000); 198848618fb4SAlexandre Bounine 198948618fb4SAlexandre Bounine mb(); 199048618fb4SAlexandre Bounine 199148618fb4SAlexandre Bounine /* 199248618fb4SAlexandre Bounine * For mapping of inbound SRIO Messages into appropriate queues we need 199348618fb4SAlexandre Bounine * to set Inbound Device ID register in the messaging engine. We do it 199448618fb4SAlexandre Bounine * once when first inbound mailbox is requested. 199548618fb4SAlexandre Bounine */ 199648618fb4SAlexandre Bounine if (!(priv->flags & TSI721_IMSGID_SET)) { 199748618fb4SAlexandre Bounine iowrite32((u32)priv->mport->host_deviceid, 199848618fb4SAlexandre Bounine priv->regs + TSI721_IB_DEVID); 199948618fb4SAlexandre Bounine priv->flags |= TSI721_IMSGID_SET; 200048618fb4SAlexandre Bounine } 200148618fb4SAlexandre Bounine 200248618fb4SAlexandre Bounine /* 200348618fb4SAlexandre Bounine * Configure Inbound Messaging channel (ch = mbox + 4) 200448618fb4SAlexandre Bounine */ 200548618fb4SAlexandre Bounine 200648618fb4SAlexandre Bounine /* Setup Inbound Message free queue */ 200748618fb4SAlexandre Bounine iowrite32(((u64)priv->imsg_ring[mbox].imfq_phys >> 32), 200848618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_FQBH(ch)); 200948618fb4SAlexandre Bounine iowrite32(((u64)priv->imsg_ring[mbox].imfq_phys & 201048618fb4SAlexandre Bounine TSI721_IBDMAC_FQBL_MASK), 201148618fb4SAlexandre Bounine priv->regs+TSI721_IBDMAC_FQBL(ch)); 201248618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(entries), 201348618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_FQSZ(ch)); 201448618fb4SAlexandre Bounine 201548618fb4SAlexandre Bounine /* Setup Inbound Message descriptor queue */ 201648618fb4SAlexandre Bounine iowrite32(((u64)priv->imsg_ring[mbox].imd_phys >> 32), 201748618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_DQBH(ch)); 201848618fb4SAlexandre Bounine iowrite32(((u32)priv->imsg_ring[mbox].imd_phys & 201948618fb4SAlexandre Bounine (u32)TSI721_IBDMAC_DQBL_MASK), 202048618fb4SAlexandre Bounine priv->regs+TSI721_IBDMAC_DQBL(ch)); 202148618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(entries), 202248618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_DQSZ(ch)); 202348618fb4SAlexandre Bounine 202448618fb4SAlexandre Bounine /* Enable interrupts */ 202548618fb4SAlexandre Bounine 202648618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 202748618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) { 202848618fb4SAlexandre Bounine /* Request interrupt service if we are in MSI-X mode */ 202948618fb4SAlexandre Bounine rc = request_irq(priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector, 203048618fb4SAlexandre Bounine tsi721_imsg_msix, 0, 203148618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_RCV + mbox].irq_name, 203248618fb4SAlexandre Bounine (void *)mport); 203348618fb4SAlexandre Bounine 203448618fb4SAlexandre Bounine if (rc) { 203548618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 203648618fb4SAlexandre Bounine "Unable to allocate MSI-X interrupt for " 203748618fb4SAlexandre Bounine "IBOX%d-DONE\n", mbox); 203848618fb4SAlexandre Bounine goto out_desc; 203948618fb4SAlexandre Bounine } 204048618fb4SAlexandre Bounine 204148618fb4SAlexandre Bounine rc = request_irq(priv->msix[TSI721_VECT_IMB0_INT + mbox].vector, 204248618fb4SAlexandre Bounine tsi721_imsg_msix, 0, 204348618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_INT + mbox].irq_name, 204448618fb4SAlexandre Bounine (void *)mport); 204548618fb4SAlexandre Bounine 204648618fb4SAlexandre Bounine if (rc) { 204748618fb4SAlexandre Bounine dev_dbg(&priv->pdev->dev, 204848618fb4SAlexandre Bounine "Unable to allocate MSI-X interrupt for " 204948618fb4SAlexandre Bounine "IBOX%d-INT\n", mbox); 205048618fb4SAlexandre Bounine free_irq( 205148618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector, 205248618fb4SAlexandre Bounine (void *)mport); 205348618fb4SAlexandre Bounine goto out_desc; 205448618fb4SAlexandre Bounine } 205548618fb4SAlexandre Bounine } 205648618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 205748618fb4SAlexandre Bounine 205848618fb4SAlexandre Bounine tsi721_imsg_interrupt_enable(priv, ch, TSI721_IBDMAC_INT_ALL); 205948618fb4SAlexandre Bounine 206048618fb4SAlexandre Bounine /* Initialize Inbound Message Engine */ 206148618fb4SAlexandre Bounine iowrite32(TSI721_IBDMAC_CTL_INIT, priv->regs + TSI721_IBDMAC_CTL(ch)); 206248618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_IBDMAC_CTL(ch)); 206348618fb4SAlexandre Bounine udelay(10); 206448618fb4SAlexandre Bounine priv->imsg_ring[mbox].fq_wrptr = entries - 1; 206548618fb4SAlexandre Bounine iowrite32(entries - 1, priv->regs + TSI721_IBDMAC_FQWP(ch)); 206648618fb4SAlexandre Bounine 206748618fb4SAlexandre Bounine priv->imsg_init[mbox] = 1; 206848618fb4SAlexandre Bounine return 0; 206948618fb4SAlexandre Bounine 207048618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 207148618fb4SAlexandre Bounine out_desc: 207248618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 207348618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * sizeof(struct tsi721_imsg_desc), 207448618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base, 207548618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_phys); 207648618fb4SAlexandre Bounine 207748618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base = NULL; 207848618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 207948618fb4SAlexandre Bounine 208048618fb4SAlexandre Bounine out_dma: 208148618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 208248618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * 8, 208348618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base, 208448618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_phys); 208548618fb4SAlexandre Bounine 208648618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base = NULL; 208748618fb4SAlexandre Bounine 208848618fb4SAlexandre Bounine out_buf: 208948618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 209048618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * TSI721_MSG_BUFFER_SIZE, 209148618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base, 209248618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_phys); 209348618fb4SAlexandre Bounine 209448618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base = NULL; 209548618fb4SAlexandre Bounine 209648618fb4SAlexandre Bounine out: 209748618fb4SAlexandre Bounine return rc; 209848618fb4SAlexandre Bounine } 209948618fb4SAlexandre Bounine 210048618fb4SAlexandre Bounine /** 210148618fb4SAlexandre Bounine * tsi721_close_inb_mbox - Shut down Tsi721 inbound mailbox 210248618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine 210348618fb4SAlexandre Bounine * @mbox: Mailbox to close 210448618fb4SAlexandre Bounine */ 210548618fb4SAlexandre Bounine static void tsi721_close_inb_mbox(struct rio_mport *mport, int mbox) 210648618fb4SAlexandre Bounine { 210748618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 210848618fb4SAlexandre Bounine u32 rx_slot; 210948618fb4SAlexandre Bounine int ch = mbox + 4; 211048618fb4SAlexandre Bounine 211148618fb4SAlexandre Bounine if (!priv->imsg_init[mbox]) /* mbox isn't initialized yet */ 211248618fb4SAlexandre Bounine return; 211348618fb4SAlexandre Bounine priv->imsg_init[mbox] = 0; 211448618fb4SAlexandre Bounine 211548618fb4SAlexandre Bounine /* Disable Inbound Messaging Engine */ 211648618fb4SAlexandre Bounine 211748618fb4SAlexandre Bounine /* Disable Interrupts */ 211848618fb4SAlexandre Bounine tsi721_imsg_interrupt_disable(priv, ch, TSI721_OBDMAC_INT_MASK); 211948618fb4SAlexandre Bounine 212048618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 212148618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) { 212248618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector, 212348618fb4SAlexandre Bounine (void *)mport); 212448618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_IMB0_INT + mbox].vector, 212548618fb4SAlexandre Bounine (void *)mport); 212648618fb4SAlexandre Bounine } 212748618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 212848618fb4SAlexandre Bounine 212948618fb4SAlexandre Bounine /* Clear Inbound Buffer Queue */ 213048618fb4SAlexandre Bounine for (rx_slot = 0; rx_slot < priv->imsg_ring[mbox].size; rx_slot++) 213148618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[rx_slot] = NULL; 213248618fb4SAlexandre Bounine 213348618fb4SAlexandre Bounine /* Free memory allocated for message buffers */ 213448618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 213548618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * TSI721_MSG_BUFFER_SIZE, 213648618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base, 213748618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_phys); 213848618fb4SAlexandre Bounine 213948618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base = NULL; 214048618fb4SAlexandre Bounine 214148618fb4SAlexandre Bounine /* Free memory allocated for free pointr list */ 214248618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 214348618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * 8, 214448618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base, 214548618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_phys); 214648618fb4SAlexandre Bounine 214748618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base = NULL; 214848618fb4SAlexandre Bounine 214948618fb4SAlexandre Bounine /* Free memory allocated for RX descriptors */ 215048618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, 215148618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * sizeof(struct tsi721_imsg_desc), 215248618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base, 215348618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_phys); 215448618fb4SAlexandre Bounine 215548618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base = NULL; 215648618fb4SAlexandre Bounine } 215748618fb4SAlexandre Bounine 215848618fb4SAlexandre Bounine /** 215948618fb4SAlexandre Bounine * tsi721_add_inb_buffer - Add buffer to the Tsi721 inbound message queue 216048618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine 216148618fb4SAlexandre Bounine * @mbox: Inbound mailbox number 216248618fb4SAlexandre Bounine * @buf: Buffer to add to inbound queue 216348618fb4SAlexandre Bounine */ 216448618fb4SAlexandre Bounine static int tsi721_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) 216548618fb4SAlexandre Bounine { 216648618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 216748618fb4SAlexandre Bounine u32 rx_slot; 216848618fb4SAlexandre Bounine int rc = 0; 216948618fb4SAlexandre Bounine 217048618fb4SAlexandre Bounine rx_slot = priv->imsg_ring[mbox].rx_slot; 217148618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].imq_base[rx_slot]) { 217248618fb4SAlexandre Bounine dev_err(&priv->pdev->dev, 217348618fb4SAlexandre Bounine "Error adding inbound buffer %d, buffer exists\n", 217448618fb4SAlexandre Bounine rx_slot); 217548618fb4SAlexandre Bounine rc = -EINVAL; 217648618fb4SAlexandre Bounine goto out; 217748618fb4SAlexandre Bounine } 217848618fb4SAlexandre Bounine 217948618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[rx_slot] = buf; 218048618fb4SAlexandre Bounine 218148618fb4SAlexandre Bounine if (++priv->imsg_ring[mbox].rx_slot == priv->imsg_ring[mbox].size) 218248618fb4SAlexandre Bounine priv->imsg_ring[mbox].rx_slot = 0; 218348618fb4SAlexandre Bounine 218448618fb4SAlexandre Bounine out: 218548618fb4SAlexandre Bounine return rc; 218648618fb4SAlexandre Bounine } 218748618fb4SAlexandre Bounine 218848618fb4SAlexandre Bounine /** 218948618fb4SAlexandre Bounine * tsi721_get_inb_message - Fetch inbound message from the Tsi721 MSG Queue 219048618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine 219148618fb4SAlexandre Bounine * @mbox: Inbound mailbox number 219248618fb4SAlexandre Bounine * 219348618fb4SAlexandre Bounine * Returns pointer to the message on success or NULL on failure. 219448618fb4SAlexandre Bounine */ 219548618fb4SAlexandre Bounine static void *tsi721_get_inb_message(struct rio_mport *mport, int mbox) 219648618fb4SAlexandre Bounine { 219748618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv; 219848618fb4SAlexandre Bounine struct tsi721_imsg_desc *desc; 219948618fb4SAlexandre Bounine u32 rx_slot; 220048618fb4SAlexandre Bounine void *rx_virt = NULL; 220148618fb4SAlexandre Bounine u64 rx_phys; 220248618fb4SAlexandre Bounine void *buf = NULL; 220348618fb4SAlexandre Bounine u64 *free_ptr; 220448618fb4SAlexandre Bounine int ch = mbox + 4; 220548618fb4SAlexandre Bounine int msg_size; 220648618fb4SAlexandre Bounine 220748618fb4SAlexandre Bounine if (!priv->imsg_init[mbox]) 220848618fb4SAlexandre Bounine return NULL; 220948618fb4SAlexandre Bounine 221048618fb4SAlexandre Bounine desc = priv->imsg_ring[mbox].imd_base; 221148618fb4SAlexandre Bounine desc += priv->imsg_ring[mbox].desc_rdptr; 221248618fb4SAlexandre Bounine 221348618fb4SAlexandre Bounine if (!(le32_to_cpu(desc->msg_info) & TSI721_IMD_HO)) 221448618fb4SAlexandre Bounine goto out; 221548618fb4SAlexandre Bounine 221648618fb4SAlexandre Bounine rx_slot = priv->imsg_ring[mbox].rx_slot; 221748618fb4SAlexandre Bounine while (priv->imsg_ring[mbox].imq_base[rx_slot] == NULL) { 221848618fb4SAlexandre Bounine if (++rx_slot == priv->imsg_ring[mbox].size) 221948618fb4SAlexandre Bounine rx_slot = 0; 222048618fb4SAlexandre Bounine } 222148618fb4SAlexandre Bounine 222248618fb4SAlexandre Bounine rx_phys = ((u64)le32_to_cpu(desc->bufptr_hi) << 32) | 222348618fb4SAlexandre Bounine le32_to_cpu(desc->bufptr_lo); 222448618fb4SAlexandre Bounine 222548618fb4SAlexandre Bounine rx_virt = priv->imsg_ring[mbox].buf_base + 222648618fb4SAlexandre Bounine (rx_phys - (u64)priv->imsg_ring[mbox].buf_phys); 222748618fb4SAlexandre Bounine 222848618fb4SAlexandre Bounine buf = priv->imsg_ring[mbox].imq_base[rx_slot]; 222948618fb4SAlexandre Bounine msg_size = le32_to_cpu(desc->msg_info) & TSI721_IMD_BCOUNT; 223048618fb4SAlexandre Bounine if (msg_size == 0) 223148618fb4SAlexandre Bounine msg_size = RIO_MAX_MSG_SIZE; 223248618fb4SAlexandre Bounine 223348618fb4SAlexandre Bounine memcpy(buf, rx_virt, msg_size); 223448618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[rx_slot] = NULL; 223548618fb4SAlexandre Bounine 223648618fb4SAlexandre Bounine desc->msg_info &= cpu_to_le32(~TSI721_IMD_HO); 223748618fb4SAlexandre Bounine if (++priv->imsg_ring[mbox].desc_rdptr == priv->imsg_ring[mbox].size) 223848618fb4SAlexandre Bounine priv->imsg_ring[mbox].desc_rdptr = 0; 223948618fb4SAlexandre Bounine 224048618fb4SAlexandre Bounine iowrite32(priv->imsg_ring[mbox].desc_rdptr, 224148618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_DQRP(ch)); 224248618fb4SAlexandre Bounine 224348618fb4SAlexandre Bounine /* Return free buffer into the pointer list */ 224448618fb4SAlexandre Bounine free_ptr = priv->imsg_ring[mbox].imfq_base; 224548618fb4SAlexandre Bounine free_ptr[priv->imsg_ring[mbox].fq_wrptr] = cpu_to_le64(rx_phys); 224648618fb4SAlexandre Bounine 224748618fb4SAlexandre Bounine if (++priv->imsg_ring[mbox].fq_wrptr == priv->imsg_ring[mbox].size) 224848618fb4SAlexandre Bounine priv->imsg_ring[mbox].fq_wrptr = 0; 224948618fb4SAlexandre Bounine 225048618fb4SAlexandre Bounine iowrite32(priv->imsg_ring[mbox].fq_wrptr, 225148618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_FQWP(ch)); 225248618fb4SAlexandre Bounine out: 225348618fb4SAlexandre Bounine return buf; 225448618fb4SAlexandre Bounine } 225548618fb4SAlexandre Bounine 225648618fb4SAlexandre Bounine /** 225748618fb4SAlexandre Bounine * tsi721_messages_init - Initialization of Messaging Engine 225848618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 225948618fb4SAlexandre Bounine * 226048618fb4SAlexandre Bounine * Configures Tsi721 messaging engine. 226148618fb4SAlexandre Bounine */ 226248618fb4SAlexandre Bounine static int tsi721_messages_init(struct tsi721_device *priv) 226348618fb4SAlexandre Bounine { 226448618fb4SAlexandre Bounine int ch; 226548618fb4SAlexandre Bounine 226648618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SMSG_ECC_LOG); 226748618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RETRY_GEN_CNT); 226848618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RETRY_RX_CNT); 226948618fb4SAlexandre Bounine 227048618fb4SAlexandre Bounine /* Set SRIO Message Request/Response Timeout */ 227148618fb4SAlexandre Bounine iowrite32(TSI721_RQRPTO_VAL, priv->regs + TSI721_RQRPTO); 227248618fb4SAlexandre Bounine 227348618fb4SAlexandre Bounine /* Initialize Inbound Messaging Engine Registers */ 227448618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_IMSG_CHNUM; ch++) { 227548618fb4SAlexandre Bounine /* Clear interrupt bits */ 227648618fb4SAlexandre Bounine iowrite32(TSI721_IBDMAC_INT_MASK, 227748618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_INT(ch)); 227848618fb4SAlexandre Bounine /* Clear Status */ 227948618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBDMAC_STS(ch)); 228048618fb4SAlexandre Bounine 228148618fb4SAlexandre Bounine iowrite32(TSI721_SMSG_ECC_COR_LOG_MASK, 228248618fb4SAlexandre Bounine priv->regs + TSI721_SMSG_ECC_COR_LOG(ch)); 228348618fb4SAlexandre Bounine iowrite32(TSI721_SMSG_ECC_NCOR_MASK, 228448618fb4SAlexandre Bounine priv->regs + TSI721_SMSG_ECC_NCOR(ch)); 228548618fb4SAlexandre Bounine } 228648618fb4SAlexandre Bounine 228748618fb4SAlexandre Bounine return 0; 228848618fb4SAlexandre Bounine } 228948618fb4SAlexandre Bounine 229048618fb4SAlexandre Bounine /** 2291dbe74afeSAlexandre Bounine * tsi721_query_mport - Fetch inbound message from the Tsi721 MSG Queue 2292dbe74afeSAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine 2293dbe74afeSAlexandre Bounine * @mbox: Inbound mailbox number 2294dbe74afeSAlexandre Bounine * 2295dbe74afeSAlexandre Bounine * Returns pointer to the message on success or NULL on failure. 2296dbe74afeSAlexandre Bounine */ 2297dbe74afeSAlexandre Bounine static int tsi721_query_mport(struct rio_mport *mport, 2298dbe74afeSAlexandre Bounine struct rio_mport_attr *attr) 2299dbe74afeSAlexandre Bounine { 2300dbe74afeSAlexandre Bounine struct tsi721_device *priv = mport->priv; 2301dbe74afeSAlexandre Bounine u32 rval; 2302dbe74afeSAlexandre Bounine 2303dbe74afeSAlexandre Bounine rval = ioread32(priv->regs + (0x100 + RIO_PORT_N_ERR_STS_CSR(0))); 2304dbe74afeSAlexandre Bounine if (rval & RIO_PORT_N_ERR_STS_PORT_OK) { 2305dbe74afeSAlexandre Bounine rval = ioread32(priv->regs + (0x100 + RIO_PORT_N_CTL2_CSR(0))); 2306dbe74afeSAlexandre Bounine attr->link_speed = (rval & RIO_PORT_N_CTL2_SEL_BAUD) >> 28; 2307dbe74afeSAlexandre Bounine rval = ioread32(priv->regs + (0x100 + RIO_PORT_N_CTL_CSR(0))); 2308dbe74afeSAlexandre Bounine attr->link_width = (rval & RIO_PORT_N_CTL_IPW) >> 27; 2309dbe74afeSAlexandre Bounine } else 2310dbe74afeSAlexandre Bounine attr->link_speed = RIO_LINK_DOWN; 2311dbe74afeSAlexandre Bounine 2312dbe74afeSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 2313dbe74afeSAlexandre Bounine attr->flags = RIO_MPORT_DMA | RIO_MPORT_DMA_SG; 2314dbe74afeSAlexandre Bounine attr->dma_max_sge = 0; 2315dbe74afeSAlexandre Bounine attr->dma_max_size = TSI721_BDMA_MAX_BCOUNT; 2316dbe74afeSAlexandre Bounine attr->dma_align = 0; 2317dbe74afeSAlexandre Bounine #else 2318dbe74afeSAlexandre Bounine attr->flags = 0; 2319dbe74afeSAlexandre Bounine #endif 2320dbe74afeSAlexandre Bounine return 0; 2321dbe74afeSAlexandre Bounine } 2322dbe74afeSAlexandre Bounine 2323dbe74afeSAlexandre Bounine /** 232448618fb4SAlexandre Bounine * tsi721_disable_ints - disables all device interrupts 232548618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 232648618fb4SAlexandre Bounine */ 232748618fb4SAlexandre Bounine static void tsi721_disable_ints(struct tsi721_device *priv) 232848618fb4SAlexandre Bounine { 232948618fb4SAlexandre Bounine int ch; 233048618fb4SAlexandre Bounine 233148618fb4SAlexandre Bounine /* Disable all device level interrupts */ 233248618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_DEV_INTE); 233348618fb4SAlexandre Bounine 233448618fb4SAlexandre Bounine /* Disable all Device Channel interrupts */ 233548618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_DEV_CHAN_INTE); 233648618fb4SAlexandre Bounine 233748618fb4SAlexandre Bounine /* Disable all Inbound Msg Channel interrupts */ 233848618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_IMSG_CHNUM; ch++) 233948618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBDMAC_INTE(ch)); 234048618fb4SAlexandre Bounine 234148618fb4SAlexandre Bounine /* Disable all Outbound Msg Channel interrupts */ 234248618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_OMSG_CHNUM; ch++) 234348618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_OBDMAC_INTE(ch)); 234448618fb4SAlexandre Bounine 234548618fb4SAlexandre Bounine /* Disable all general messaging interrupts */ 234648618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SMSG_INTE); 234748618fb4SAlexandre Bounine 234848618fb4SAlexandre Bounine /* Disable all BDMA Channel interrupts */ 234948618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_DMA_MAXCH; ch++) 23509eaa3d9bSAlexandre Bounine iowrite32(0, 23519eaa3d9bSAlexandre Bounine priv->regs + TSI721_DMAC_BASE(ch) + TSI721_DMAC_INTE); 235248618fb4SAlexandre Bounine 235348618fb4SAlexandre Bounine /* Disable all general BDMA interrupts */ 235448618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_BDMA_INTE); 235548618fb4SAlexandre Bounine 235648618fb4SAlexandre Bounine /* Disable all SRIO Channel interrupts */ 235748618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_SRIO_MAXCH; ch++) 235848618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SR_CHINTE(ch)); 235948618fb4SAlexandre Bounine 236048618fb4SAlexandre Bounine /* Disable all general SR2PC interrupts */ 236148618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SR2PC_GEN_INTE); 236248618fb4SAlexandre Bounine 236348618fb4SAlexandre Bounine /* Disable all PC2SR interrupts */ 236448618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_PC2SR_INTE); 236548618fb4SAlexandre Bounine 236648618fb4SAlexandre Bounine /* Disable all I2C interrupts */ 236748618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_I2C_INT_ENABLE); 236848618fb4SAlexandre Bounine 236948618fb4SAlexandre Bounine /* Disable SRIO MAC interrupts */ 237048618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RIO_EM_INT_ENABLE); 237148618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RIO_EM_DEV_INT_EN); 237248618fb4SAlexandre Bounine } 237348618fb4SAlexandre Bounine 237448618fb4SAlexandre Bounine /** 237548618fb4SAlexandre Bounine * tsi721_setup_mport - Setup Tsi721 as RapidIO subsystem master port 237648618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data 237748618fb4SAlexandre Bounine * 237848618fb4SAlexandre Bounine * Configures Tsi721 as RapidIO master port. 237948618fb4SAlexandre Bounine */ 2380305c891eSBill Pemberton static int tsi721_setup_mport(struct tsi721_device *priv) 238148618fb4SAlexandre Bounine { 238248618fb4SAlexandre Bounine struct pci_dev *pdev = priv->pdev; 238348618fb4SAlexandre Bounine int err = 0; 238448618fb4SAlexandre Bounine struct rio_ops *ops; 238548618fb4SAlexandre Bounine 238648618fb4SAlexandre Bounine struct rio_mport *mport; 238748618fb4SAlexandre Bounine 238848618fb4SAlexandre Bounine ops = kzalloc(sizeof(struct rio_ops), GFP_KERNEL); 238948618fb4SAlexandre Bounine if (!ops) { 239048618fb4SAlexandre Bounine dev_dbg(&pdev->dev, "Unable to allocate memory for rio_ops\n"); 239148618fb4SAlexandre Bounine return -ENOMEM; 239248618fb4SAlexandre Bounine } 239348618fb4SAlexandre Bounine 239448618fb4SAlexandre Bounine ops->lcread = tsi721_lcread; 239548618fb4SAlexandre Bounine ops->lcwrite = tsi721_lcwrite; 239648618fb4SAlexandre Bounine ops->cread = tsi721_cread_dma; 239748618fb4SAlexandre Bounine ops->cwrite = tsi721_cwrite_dma; 239848618fb4SAlexandre Bounine ops->dsend = tsi721_dsend; 239948618fb4SAlexandre Bounine ops->open_inb_mbox = tsi721_open_inb_mbox; 240048618fb4SAlexandre Bounine ops->close_inb_mbox = tsi721_close_inb_mbox; 240148618fb4SAlexandre Bounine ops->open_outb_mbox = tsi721_open_outb_mbox; 240248618fb4SAlexandre Bounine ops->close_outb_mbox = tsi721_close_outb_mbox; 240348618fb4SAlexandre Bounine ops->add_outb_message = tsi721_add_outb_message; 240448618fb4SAlexandre Bounine ops->add_inb_buffer = tsi721_add_inb_buffer; 240548618fb4SAlexandre Bounine ops->get_inb_message = tsi721_get_inb_message; 240671afe341SAlexandre Bounine ops->map_inb = tsi721_rio_map_inb_mem; 240771afe341SAlexandre Bounine ops->unmap_inb = tsi721_rio_unmap_inb_mem; 2408dbe74afeSAlexandre Bounine ops->query_mport = tsi721_query_mport; 240948618fb4SAlexandre Bounine 241048618fb4SAlexandre Bounine mport = kzalloc(sizeof(struct rio_mport), GFP_KERNEL); 241148618fb4SAlexandre Bounine if (!mport) { 241248618fb4SAlexandre Bounine kfree(ops); 241348618fb4SAlexandre Bounine dev_dbg(&pdev->dev, "Unable to allocate memory for mport\n"); 241448618fb4SAlexandre Bounine return -ENOMEM; 241548618fb4SAlexandre Bounine } 241648618fb4SAlexandre Bounine 241748618fb4SAlexandre Bounine mport->ops = ops; 241848618fb4SAlexandre Bounine mport->index = 0; 241948618fb4SAlexandre Bounine mport->sys_size = 0; /* small system */ 242048618fb4SAlexandre Bounine mport->phy_type = RIO_PHY_SERIAL; 242148618fb4SAlexandre Bounine mport->priv = (void *)priv; 242248618fb4SAlexandre Bounine mport->phys_efptr = 0x100; 24232aaf308bSAlexandre Bounine mport->dev.parent = &pdev->dev; 24249eaa3d9bSAlexandre Bounine priv->mport = mport; 242548618fb4SAlexandre Bounine 242648618fb4SAlexandre Bounine INIT_LIST_HEAD(&mport->dbells); 242748618fb4SAlexandre Bounine 242848618fb4SAlexandre Bounine rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); 2429b439e66fSAlexandre Bounine rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 3); 2430b439e66fSAlexandre Bounine rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 3); 2431ed43f44fSAlexandre Bounine snprintf(mport->name, RIO_MAX_MPORT_NAME, "%s(%s)", 2432ed43f44fSAlexandre Bounine dev_driver_string(&pdev->dev), dev_name(&pdev->dev)); 243348618fb4SAlexandre Bounine 243448618fb4SAlexandre Bounine /* Hook up interrupt handler */ 243548618fb4SAlexandre Bounine 243648618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI 243748618fb4SAlexandre Bounine if (!tsi721_enable_msix(priv)) 243848618fb4SAlexandre Bounine priv->flags |= TSI721_USING_MSIX; 243948618fb4SAlexandre Bounine else if (!pci_enable_msi(pdev)) 244048618fb4SAlexandre Bounine priv->flags |= TSI721_USING_MSI; 244148618fb4SAlexandre Bounine else 244248618fb4SAlexandre Bounine dev_info(&pdev->dev, 244348618fb4SAlexandre Bounine "MSI/MSI-X is not available. Using legacy INTx.\n"); 244448618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */ 244548618fb4SAlexandre Bounine 244648618fb4SAlexandre Bounine err = tsi721_request_irq(mport); 244748618fb4SAlexandre Bounine 244848618fb4SAlexandre Bounine if (!err) { 244948618fb4SAlexandre Bounine tsi721_interrupts_init(priv); 245048618fb4SAlexandre Bounine ops->pwenable = tsi721_pw_enable; 24519eaa3d9bSAlexandre Bounine } else { 245248618fb4SAlexandre Bounine dev_err(&pdev->dev, "Unable to get assigned PCI IRQ " 245348618fb4SAlexandre Bounine "vector %02X err=0x%x\n", pdev->irq, err); 24549eaa3d9bSAlexandre Bounine goto err_exit; 24559eaa3d9bSAlexandre Bounine } 245648618fb4SAlexandre Bounine 24579eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 24589eaa3d9bSAlexandre Bounine tsi721_register_dma(priv); 24599eaa3d9bSAlexandre Bounine #endif 246048618fb4SAlexandre Bounine /* Enable SRIO link */ 246148618fb4SAlexandre Bounine iowrite32(ioread32(priv->regs + TSI721_DEVCTL) | 246248618fb4SAlexandre Bounine TSI721_DEVCTL_SRBOOT_CMPL, 246348618fb4SAlexandre Bounine priv->regs + TSI721_DEVCTL); 246448618fb4SAlexandre Bounine 246548618fb4SAlexandre Bounine rio_register_mport(mport); 246648618fb4SAlexandre Bounine 246748618fb4SAlexandre Bounine if (mport->host_deviceid >= 0) 246848618fb4SAlexandre Bounine iowrite32(RIO_PORT_GEN_HOST | RIO_PORT_GEN_MASTER | 246948618fb4SAlexandre Bounine RIO_PORT_GEN_DISCOVERED, 247048618fb4SAlexandre Bounine priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR)); 247148618fb4SAlexandre Bounine else 247248618fb4SAlexandre Bounine iowrite32(0, priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR)); 247348618fb4SAlexandre Bounine 247448618fb4SAlexandre Bounine return 0; 24759eaa3d9bSAlexandre Bounine 24769eaa3d9bSAlexandre Bounine err_exit: 24779eaa3d9bSAlexandre Bounine kfree(mport); 24789eaa3d9bSAlexandre Bounine kfree(ops); 24799eaa3d9bSAlexandre Bounine return err; 248048618fb4SAlexandre Bounine } 248148618fb4SAlexandre Bounine 2482305c891eSBill Pemberton static int tsi721_probe(struct pci_dev *pdev, 248348618fb4SAlexandre Bounine const struct pci_device_id *id) 248448618fb4SAlexandre Bounine { 248548618fb4SAlexandre Bounine struct tsi721_device *priv; 248648618fb4SAlexandre Bounine int err; 248748618fb4SAlexandre Bounine 248848618fb4SAlexandre Bounine priv = kzalloc(sizeof(struct tsi721_device), GFP_KERNEL); 248948618fb4SAlexandre Bounine if (priv == NULL) { 249048618fb4SAlexandre Bounine dev_err(&pdev->dev, "Failed to allocate memory for device\n"); 249148618fb4SAlexandre Bounine err = -ENOMEM; 249248618fb4SAlexandre Bounine goto err_exit; 249348618fb4SAlexandre Bounine } 249448618fb4SAlexandre Bounine 249548618fb4SAlexandre Bounine err = pci_enable_device(pdev); 249648618fb4SAlexandre Bounine if (err) { 249748618fb4SAlexandre Bounine dev_err(&pdev->dev, "Failed to enable PCI device\n"); 249848618fb4SAlexandre Bounine goto err_clean; 249948618fb4SAlexandre Bounine } 250048618fb4SAlexandre Bounine 250148618fb4SAlexandre Bounine priv->pdev = pdev; 250248618fb4SAlexandre Bounine 250348618fb4SAlexandre Bounine #ifdef DEBUG 25049a9a9a7aSAlexandre Bounine { 25059a9a9a7aSAlexandre Bounine int i; 250648618fb4SAlexandre Bounine for (i = 0; i <= PCI_STD_RESOURCE_END; i++) { 250748618fb4SAlexandre Bounine dev_dbg(&pdev->dev, "res[%d] @ 0x%llx (0x%lx, 0x%lx)\n", 250848618fb4SAlexandre Bounine i, (unsigned long long)pci_resource_start(pdev, i), 250948618fb4SAlexandre Bounine (unsigned long)pci_resource_len(pdev, i), 251048618fb4SAlexandre Bounine pci_resource_flags(pdev, i)); 251148618fb4SAlexandre Bounine } 25129a9a9a7aSAlexandre Bounine } 251348618fb4SAlexandre Bounine #endif 251448618fb4SAlexandre Bounine /* 251548618fb4SAlexandre Bounine * Verify BAR configuration 251648618fb4SAlexandre Bounine */ 251748618fb4SAlexandre Bounine 251848618fb4SAlexandre Bounine /* BAR_0 (registers) must be 512KB+ in 32-bit address space */ 251948618fb4SAlexandre Bounine if (!(pci_resource_flags(pdev, BAR_0) & IORESOURCE_MEM) || 252048618fb4SAlexandre Bounine pci_resource_flags(pdev, BAR_0) & IORESOURCE_MEM_64 || 252148618fb4SAlexandre Bounine pci_resource_len(pdev, BAR_0) < TSI721_REG_SPACE_SIZE) { 252248618fb4SAlexandre Bounine dev_err(&pdev->dev, 252348618fb4SAlexandre Bounine "Missing or misconfigured CSR BAR0, aborting.\n"); 252448618fb4SAlexandre Bounine err = -ENODEV; 252548618fb4SAlexandre Bounine goto err_disable_pdev; 252648618fb4SAlexandre Bounine } 252748618fb4SAlexandre Bounine 252848618fb4SAlexandre Bounine /* BAR_1 (outbound doorbells) must be 16MB+ in 32-bit address space */ 252948618fb4SAlexandre Bounine if (!(pci_resource_flags(pdev, BAR_1) & IORESOURCE_MEM) || 253048618fb4SAlexandre Bounine pci_resource_flags(pdev, BAR_1) & IORESOURCE_MEM_64 || 253148618fb4SAlexandre Bounine pci_resource_len(pdev, BAR_1) < TSI721_DB_WIN_SIZE) { 253248618fb4SAlexandre Bounine dev_err(&pdev->dev, 253348618fb4SAlexandre Bounine "Missing or misconfigured Doorbell BAR1, aborting.\n"); 253448618fb4SAlexandre Bounine err = -ENODEV; 253548618fb4SAlexandre Bounine goto err_disable_pdev; 253648618fb4SAlexandre Bounine } 253748618fb4SAlexandre Bounine 253848618fb4SAlexandre Bounine /* 253948618fb4SAlexandre Bounine * BAR_2 and BAR_4 (outbound translation) must be in 64-bit PCIe address 254048618fb4SAlexandre Bounine * space. 254148618fb4SAlexandre Bounine * NOTE: BAR_2 and BAR_4 are not used by this version of driver. 254248618fb4SAlexandre Bounine * It may be a good idea to keep them disabled using HW configuration 254348618fb4SAlexandre Bounine * to save PCI memory space. 254448618fb4SAlexandre Bounine */ 254548618fb4SAlexandre Bounine if ((pci_resource_flags(pdev, BAR_2) & IORESOURCE_MEM) && 254648618fb4SAlexandre Bounine (pci_resource_flags(pdev, BAR_2) & IORESOURCE_MEM_64)) { 254748618fb4SAlexandre Bounine dev_info(&pdev->dev, "Outbound BAR2 is not used but enabled.\n"); 254848618fb4SAlexandre Bounine } 254948618fb4SAlexandre Bounine 255048618fb4SAlexandre Bounine if ((pci_resource_flags(pdev, BAR_4) & IORESOURCE_MEM) && 255148618fb4SAlexandre Bounine (pci_resource_flags(pdev, BAR_4) & IORESOURCE_MEM_64)) { 255248618fb4SAlexandre Bounine dev_info(&pdev->dev, "Outbound BAR4 is not used but enabled.\n"); 255348618fb4SAlexandre Bounine } 255448618fb4SAlexandre Bounine 255548618fb4SAlexandre Bounine err = pci_request_regions(pdev, DRV_NAME); 255648618fb4SAlexandre Bounine if (err) { 255748618fb4SAlexandre Bounine dev_err(&pdev->dev, "Cannot obtain PCI resources, " 255848618fb4SAlexandre Bounine "aborting.\n"); 255948618fb4SAlexandre Bounine goto err_disable_pdev; 256048618fb4SAlexandre Bounine } 256148618fb4SAlexandre Bounine 256248618fb4SAlexandre Bounine pci_set_master(pdev); 256348618fb4SAlexandre Bounine 256448618fb4SAlexandre Bounine priv->regs = pci_ioremap_bar(pdev, BAR_0); 256548618fb4SAlexandre Bounine if (!priv->regs) { 256648618fb4SAlexandre Bounine dev_err(&pdev->dev, 256748618fb4SAlexandre Bounine "Unable to map device registers space, aborting\n"); 256848618fb4SAlexandre Bounine err = -ENOMEM; 256948618fb4SAlexandre Bounine goto err_free_res; 257048618fb4SAlexandre Bounine } 257148618fb4SAlexandre Bounine 257248618fb4SAlexandre Bounine priv->odb_base = pci_ioremap_bar(pdev, BAR_1); 257348618fb4SAlexandre Bounine if (!priv->odb_base) { 257448618fb4SAlexandre Bounine dev_err(&pdev->dev, 257548618fb4SAlexandre Bounine "Unable to map outbound doorbells space, aborting\n"); 257648618fb4SAlexandre Bounine err = -ENOMEM; 257748618fb4SAlexandre Bounine goto err_unmap_bars; 257848618fb4SAlexandre Bounine } 257948618fb4SAlexandre Bounine 258048618fb4SAlexandre Bounine /* Configure DMA attributes. */ 258148618fb4SAlexandre Bounine if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { 258218f6287fSPeter Senna Tschudin err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 258318f6287fSPeter Senna Tschudin if (err) { 258448618fb4SAlexandre Bounine dev_info(&pdev->dev, "Unable to set DMA mask\n"); 258548618fb4SAlexandre Bounine goto err_unmap_bars; 258648618fb4SAlexandre Bounine } 258748618fb4SAlexandre Bounine 258848618fb4SAlexandre Bounine if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) 258948618fb4SAlexandre Bounine dev_info(&pdev->dev, "Unable to set consistent DMA mask\n"); 259048618fb4SAlexandre Bounine } else { 259148618fb4SAlexandre Bounine err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); 259248618fb4SAlexandre Bounine if (err) 259348618fb4SAlexandre Bounine dev_info(&pdev->dev, "Unable to set consistent DMA mask\n"); 259448618fb4SAlexandre Bounine } 259548618fb4SAlexandre Bounine 25965cdaaf8aSJiang Liu BUG_ON(!pci_is_pcie(pdev)); 25971cee22b7SAlexandre Bounine 2598174f1a71SAlexandre Bounine /* Clear "no snoop" and "relaxed ordering" bits. */ 25995cdaaf8aSJiang Liu pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL, 2600174f1a71SAlexandre Bounine PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN, 0); 26011cee22b7SAlexandre Bounine 26021cee22b7SAlexandre Bounine /* Adjust PCIe completion timeout. */ 26035cdaaf8aSJiang Liu pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2, 0xf, 0x2); 260448618fb4SAlexandre Bounine 260548618fb4SAlexandre Bounine /* 260648618fb4SAlexandre Bounine * FIXUP: correct offsets of MSI-X tables in the MSI-X Capability Block 260748618fb4SAlexandre Bounine */ 260848618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_EPCTL, 0x01); 260948618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_MSIXTBL, 261048618fb4SAlexandre Bounine TSI721_MSIXTBL_OFFSET); 261148618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_MSIXPBA, 261248618fb4SAlexandre Bounine TSI721_MSIXPBA_OFFSET); 261348618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_EPCTL, 0); 261448618fb4SAlexandre Bounine /* End of FIXUP */ 261548618fb4SAlexandre Bounine 261648618fb4SAlexandre Bounine tsi721_disable_ints(priv); 261748618fb4SAlexandre Bounine 261848618fb4SAlexandre Bounine tsi721_init_pc2sr_mapping(priv); 261948618fb4SAlexandre Bounine tsi721_init_sr2pc_mapping(priv); 262048618fb4SAlexandre Bounine 26219eaa3d9bSAlexandre Bounine if (tsi721_bdma_maint_init(priv)) { 262248618fb4SAlexandre Bounine dev_err(&pdev->dev, "BDMA initialization failed, aborting\n"); 262348618fb4SAlexandre Bounine err = -ENOMEM; 262448618fb4SAlexandre Bounine goto err_unmap_bars; 262548618fb4SAlexandre Bounine } 262648618fb4SAlexandre Bounine 262748618fb4SAlexandre Bounine err = tsi721_doorbell_init(priv); 262848618fb4SAlexandre Bounine if (err) 262948618fb4SAlexandre Bounine goto err_free_bdma; 263048618fb4SAlexandre Bounine 263148618fb4SAlexandre Bounine tsi721_port_write_init(priv); 263248618fb4SAlexandre Bounine 263348618fb4SAlexandre Bounine err = tsi721_messages_init(priv); 263448618fb4SAlexandre Bounine if (err) 263548618fb4SAlexandre Bounine goto err_free_consistent; 263648618fb4SAlexandre Bounine 263748618fb4SAlexandre Bounine err = tsi721_setup_mport(priv); 263848618fb4SAlexandre Bounine if (err) 263948618fb4SAlexandre Bounine goto err_free_consistent; 264048618fb4SAlexandre Bounine 2641*e3dd8cd4SAlexandre Bounine pci_set_drvdata(pdev, priv); 2642*e3dd8cd4SAlexandre Bounine 264348618fb4SAlexandre Bounine return 0; 264448618fb4SAlexandre Bounine 264548618fb4SAlexandre Bounine err_free_consistent: 264648618fb4SAlexandre Bounine tsi721_doorbell_free(priv); 264748618fb4SAlexandre Bounine err_free_bdma: 26489eaa3d9bSAlexandre Bounine tsi721_bdma_maint_free(priv); 264948618fb4SAlexandre Bounine err_unmap_bars: 265048618fb4SAlexandre Bounine if (priv->regs) 265148618fb4SAlexandre Bounine iounmap(priv->regs); 265248618fb4SAlexandre Bounine if (priv->odb_base) 265348618fb4SAlexandre Bounine iounmap(priv->odb_base); 265448618fb4SAlexandre Bounine err_free_res: 265548618fb4SAlexandre Bounine pci_release_regions(pdev); 265648618fb4SAlexandre Bounine pci_clear_master(pdev); 265748618fb4SAlexandre Bounine err_disable_pdev: 265848618fb4SAlexandre Bounine pci_disable_device(pdev); 265948618fb4SAlexandre Bounine err_clean: 266048618fb4SAlexandre Bounine kfree(priv); 266148618fb4SAlexandre Bounine err_exit: 266248618fb4SAlexandre Bounine return err; 266348618fb4SAlexandre Bounine } 266448618fb4SAlexandre Bounine 2665*e3dd8cd4SAlexandre Bounine static void tsi721_shutdown(struct pci_dev *pdev) 2666*e3dd8cd4SAlexandre Bounine { 2667*e3dd8cd4SAlexandre Bounine struct tsi721_device *priv = pci_get_drvdata(pdev); 2668*e3dd8cd4SAlexandre Bounine 2669*e3dd8cd4SAlexandre Bounine dev_dbg(&pdev->dev, "RIO: %s\n", __func__); 2670*e3dd8cd4SAlexandre Bounine 2671*e3dd8cd4SAlexandre Bounine tsi721_disable_ints(priv); 2672*e3dd8cd4SAlexandre Bounine tsi721_dma_stop_all(priv); 2673*e3dd8cd4SAlexandre Bounine pci_clear_master(pdev); 2674*e3dd8cd4SAlexandre Bounine pci_disable_device(pdev); 2675*e3dd8cd4SAlexandre Bounine } 2676*e3dd8cd4SAlexandre Bounine 26779baa3c34SBenoit Taine static const struct pci_device_id tsi721_pci_tbl[] = { 267848618fb4SAlexandre Bounine { PCI_DEVICE(PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_TSI721) }, 267948618fb4SAlexandre Bounine { 0, } /* terminate list */ 268048618fb4SAlexandre Bounine }; 268148618fb4SAlexandre Bounine 268248618fb4SAlexandre Bounine MODULE_DEVICE_TABLE(pci, tsi721_pci_tbl); 268348618fb4SAlexandre Bounine 268448618fb4SAlexandre Bounine static struct pci_driver tsi721_driver = { 268548618fb4SAlexandre Bounine .name = "tsi721", 268648618fb4SAlexandre Bounine .id_table = tsi721_pci_tbl, 268748618fb4SAlexandre Bounine .probe = tsi721_probe, 2688*e3dd8cd4SAlexandre Bounine .shutdown = tsi721_shutdown, 268948618fb4SAlexandre Bounine }; 269048618fb4SAlexandre Bounine 269148618fb4SAlexandre Bounine static int __init tsi721_init(void) 269248618fb4SAlexandre Bounine { 269348618fb4SAlexandre Bounine return pci_register_driver(&tsi721_driver); 269448618fb4SAlexandre Bounine } 269548618fb4SAlexandre Bounine 269648618fb4SAlexandre Bounine device_initcall(tsi721_init); 269794d9bd45SAlexandre Bounine 269894d9bd45SAlexandre Bounine MODULE_DESCRIPTION("IDT Tsi721 PCIExpress-to-SRIO bridge driver"); 269994d9bd45SAlexandre Bounine MODULE_AUTHOR("Integrated Device Technology, Inc."); 270094d9bd45SAlexandre Bounine MODULE_LICENSE("GPL"); 2701