11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
248618fb4SAlexandre Bounine /*
348618fb4SAlexandre Bounine * RapidIO mport driver for Tsi721 PCIExpress-to-SRIO bridge
448618fb4SAlexandre Bounine *
548618fb4SAlexandre Bounine * Copyright 2011 Integrated Device Technology, Inc.
648618fb4SAlexandre Bounine * Alexandre Bounine <alexandre.bounine@idt.com>
748618fb4SAlexandre Bounine * Chul Kim <chul.kim@idt.com>
848618fb4SAlexandre Bounine */
948618fb4SAlexandre Bounine
1048618fb4SAlexandre Bounine #include <linux/io.h>
1148618fb4SAlexandre Bounine #include <linux/errno.h>
1248618fb4SAlexandre Bounine #include <linux/init.h>
1348618fb4SAlexandre Bounine #include <linux/ioport.h>
1448618fb4SAlexandre Bounine #include <linux/kernel.h>
1548618fb4SAlexandre Bounine #include <linux/module.h>
1648618fb4SAlexandre Bounine #include <linux/pci.h>
1748618fb4SAlexandre Bounine #include <linux/rio.h>
1848618fb4SAlexandre Bounine #include <linux/rio_drv.h>
1948618fb4SAlexandre Bounine #include <linux/dma-mapping.h>
2048618fb4SAlexandre Bounine #include <linux/interrupt.h>
2148618fb4SAlexandre Bounine #include <linux/kfifo.h>
2248618fb4SAlexandre Bounine #include <linux/delay.h>
2348618fb4SAlexandre Bounine
2448618fb4SAlexandre Bounine #include "tsi721.h"
2548618fb4SAlexandre Bounine
2672d8a0d2SAlexandre Bounine #ifdef DEBUG
274785603bSRandy Dunlap u32 tsi_dbg_level;
284785603bSRandy Dunlap module_param_named(dbg_level, tsi_dbg_level, uint, S_IWUSR | S_IRUGO);
2972d8a0d2SAlexandre Bounine MODULE_PARM_DESC(dbg_level, "Debugging output level (default 0 = none)");
3072d8a0d2SAlexandre Bounine #endif
3172d8a0d2SAlexandre Bounine
32cb782cddSAlexandre Bounine static int pcie_mrrs = -1;
33cb782cddSAlexandre Bounine module_param(pcie_mrrs, int, S_IRUGO);
34cb782cddSAlexandre Bounine MODULE_PARM_DESC(pcie_mrrs, "PCIe MRRS override value (0...5)");
35cb782cddSAlexandre Bounine
36e519685dSAlexandre Bounine static u8 mbox_sel = 0x0f;
37e519685dSAlexandre Bounine module_param(mbox_sel, byte, S_IRUGO);
38e519685dSAlexandre Bounine MODULE_PARM_DESC(mbox_sel,
39e519685dSAlexandre Bounine "RIO Messaging MBOX Selection Mask (default: 0x0f = all)");
40e519685dSAlexandre Bounine
4131d1e130SIoan Nicu static DEFINE_SPINLOCK(tsi721_maint_lock);
4231d1e130SIoan Nicu
4348618fb4SAlexandre Bounine static void tsi721_omsg_handler(struct tsi721_device *priv, int ch);
4448618fb4SAlexandre Bounine static void tsi721_imsg_handler(struct tsi721_device *priv, int ch);
4548618fb4SAlexandre Bounine
4648618fb4SAlexandre Bounine /**
4748618fb4SAlexandre Bounine * tsi721_lcread - read from local SREP config space
4848618fb4SAlexandre Bounine * @mport: RapidIO master port info
4948618fb4SAlexandre Bounine * @index: ID of RapdiIO interface
5048618fb4SAlexandre Bounine * @offset: Offset into configuration space
5148618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction
5248618fb4SAlexandre Bounine * @data: Value to be read into
5348618fb4SAlexandre Bounine *
5448618fb4SAlexandre Bounine * Generates a local SREP space read. Returns %0 on
5548618fb4SAlexandre Bounine * success or %-EINVAL on failure.
5648618fb4SAlexandre Bounine */
tsi721_lcread(struct rio_mport * mport,int index,u32 offset,int len,u32 * data)5748618fb4SAlexandre Bounine static int tsi721_lcread(struct rio_mport *mport, int index, u32 offset,
5848618fb4SAlexandre Bounine int len, u32 *data)
5948618fb4SAlexandre Bounine {
6048618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
6148618fb4SAlexandre Bounine
6248618fb4SAlexandre Bounine if (len != sizeof(u32))
6348618fb4SAlexandre Bounine return -EINVAL; /* only 32-bit access is supported */
6448618fb4SAlexandre Bounine
6548618fb4SAlexandre Bounine *data = ioread32(priv->regs + offset);
6648618fb4SAlexandre Bounine
6748618fb4SAlexandre Bounine return 0;
6848618fb4SAlexandre Bounine }
6948618fb4SAlexandre Bounine
7048618fb4SAlexandre Bounine /**
7148618fb4SAlexandre Bounine * tsi721_lcwrite - write into local SREP config space
7248618fb4SAlexandre Bounine * @mport: RapidIO master port info
7348618fb4SAlexandre Bounine * @index: ID of RapdiIO interface
7448618fb4SAlexandre Bounine * @offset: Offset into configuration space
7548618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction
7648618fb4SAlexandre Bounine * @data: Value to be written
7748618fb4SAlexandre Bounine *
7848618fb4SAlexandre Bounine * Generates a local write into SREP configuration space. Returns %0 on
7948618fb4SAlexandre Bounine * success or %-EINVAL on failure.
8048618fb4SAlexandre Bounine */
tsi721_lcwrite(struct rio_mport * mport,int index,u32 offset,int len,u32 data)8148618fb4SAlexandre Bounine static int tsi721_lcwrite(struct rio_mport *mport, int index, u32 offset,
8248618fb4SAlexandre Bounine int len, u32 data)
8348618fb4SAlexandre Bounine {
8448618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
8548618fb4SAlexandre Bounine
8648618fb4SAlexandre Bounine if (len != sizeof(u32))
8748618fb4SAlexandre Bounine return -EINVAL; /* only 32-bit access is supported */
8848618fb4SAlexandre Bounine
8948618fb4SAlexandre Bounine iowrite32(data, priv->regs + offset);
9048618fb4SAlexandre Bounine
9148618fb4SAlexandre Bounine return 0;
9248618fb4SAlexandre Bounine }
9348618fb4SAlexandre Bounine
9448618fb4SAlexandre Bounine /**
9548618fb4SAlexandre Bounine * tsi721_maint_dma - Helper function to generate RapidIO maintenance
9648618fb4SAlexandre Bounine * transactions using designated Tsi721 DMA channel.
9748618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data
9848618fb4SAlexandre Bounine * @sys_size: RapdiIO transport system size
9948618fb4SAlexandre Bounine * @destid: Destination ID of transaction
10048618fb4SAlexandre Bounine * @hopcount: Number of hops to target device
10148618fb4SAlexandre Bounine * @offset: Offset into configuration space
10248618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction
10348618fb4SAlexandre Bounine * @data: Location to be read from or write into
10448618fb4SAlexandre Bounine * @do_wr: Operation flag (1 == MAINT_WR)
10548618fb4SAlexandre Bounine *
10648618fb4SAlexandre Bounine * Generates a RapidIO maintenance transaction (Read or Write).
10748618fb4SAlexandre Bounine * Returns %0 on success and %-EINVAL or %-EFAULT on failure.
10848618fb4SAlexandre Bounine */
tsi721_maint_dma(struct tsi721_device * priv,u32 sys_size,u16 destid,u8 hopcount,u32 offset,int len,u32 * data,int do_wr)10948618fb4SAlexandre Bounine static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size,
11048618fb4SAlexandre Bounine u16 destid, u8 hopcount, u32 offset, int len,
11148618fb4SAlexandre Bounine u32 *data, int do_wr)
11248618fb4SAlexandre Bounine {
1139eaa3d9bSAlexandre Bounine void __iomem *regs = priv->regs + TSI721_DMAC_BASE(priv->mdma.ch_id);
11448618fb4SAlexandre Bounine struct tsi721_dma_desc *bd_ptr;
11548618fb4SAlexandre Bounine u32 rd_count, swr_ptr, ch_stat;
11631d1e130SIoan Nicu unsigned long flags;
11748618fb4SAlexandre Bounine int i, err = 0;
11848618fb4SAlexandre Bounine u32 op = do_wr ? MAINT_WR : MAINT_RD;
11948618fb4SAlexandre Bounine
12048618fb4SAlexandre Bounine if (offset > (RIO_MAINT_SPACE_SZ - len) || (len != sizeof(u32)))
12148618fb4SAlexandre Bounine return -EINVAL;
12248618fb4SAlexandre Bounine
12331d1e130SIoan Nicu spin_lock_irqsave(&tsi721_maint_lock, flags);
12431d1e130SIoan Nicu
1259eaa3d9bSAlexandre Bounine bd_ptr = priv->mdma.bd_base;
12648618fb4SAlexandre Bounine
1279eaa3d9bSAlexandre Bounine rd_count = ioread32(regs + TSI721_DMAC_DRDCNT);
12848618fb4SAlexandre Bounine
12948618fb4SAlexandre Bounine /* Initialize DMA descriptor */
13048618fb4SAlexandre Bounine bd_ptr[0].type_id = cpu_to_le32((DTYPE2 << 29) | (op << 19) | destid);
13148618fb4SAlexandre Bounine bd_ptr[0].bcount = cpu_to_le32((sys_size << 26) | 0x04);
13248618fb4SAlexandre Bounine bd_ptr[0].raddr_lo = cpu_to_le32((hopcount << 24) | offset);
13348618fb4SAlexandre Bounine bd_ptr[0].raddr_hi = 0;
13448618fb4SAlexandre Bounine if (do_wr)
13548618fb4SAlexandre Bounine bd_ptr[0].data[0] = cpu_to_be32p(data);
13648618fb4SAlexandre Bounine else
13748618fb4SAlexandre Bounine bd_ptr[0].data[0] = 0xffffffff;
13848618fb4SAlexandre Bounine
13948618fb4SAlexandre Bounine mb();
14048618fb4SAlexandre Bounine
14148618fb4SAlexandre Bounine /* Start DMA operation */
1429eaa3d9bSAlexandre Bounine iowrite32(rd_count + 2, regs + TSI721_DMAC_DWRCNT);
1439eaa3d9bSAlexandre Bounine ioread32(regs + TSI721_DMAC_DWRCNT);
14448618fb4SAlexandre Bounine i = 0;
14548618fb4SAlexandre Bounine
14648618fb4SAlexandre Bounine /* Wait until DMA transfer is finished */
1479eaa3d9bSAlexandre Bounine while ((ch_stat = ioread32(regs + TSI721_DMAC_STS))
1489eaa3d9bSAlexandre Bounine & TSI721_DMAC_STS_RUN) {
14948618fb4SAlexandre Bounine udelay(1);
15048618fb4SAlexandre Bounine if (++i >= 5000000) {
15172d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev,
15272d8a0d2SAlexandre Bounine "DMA[%d] read timeout ch_status=%x",
15372d8a0d2SAlexandre Bounine priv->mdma.ch_id, ch_stat);
15448618fb4SAlexandre Bounine if (!do_wr)
15548618fb4SAlexandre Bounine *data = 0xffffffff;
15648618fb4SAlexandre Bounine err = -EIO;
15748618fb4SAlexandre Bounine goto err_out;
15848618fb4SAlexandre Bounine }
15948618fb4SAlexandre Bounine }
16048618fb4SAlexandre Bounine
16148618fb4SAlexandre Bounine if (ch_stat & TSI721_DMAC_STS_ABORT) {
16248618fb4SAlexandre Bounine /* If DMA operation aborted due to error,
16348618fb4SAlexandre Bounine * reinitialize DMA channel
16448618fb4SAlexandre Bounine */
16572d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev, "DMA ABORT ch_stat=%x",
16672d8a0d2SAlexandre Bounine ch_stat);
16772d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev,
16872d8a0d2SAlexandre Bounine "OP=%d : destid=%x hc=%x off=%x",
16972d8a0d2SAlexandre Bounine do_wr ? MAINT_WR : MAINT_RD,
17072d8a0d2SAlexandre Bounine destid, hopcount, offset);
1719eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_INT_ALL, regs + TSI721_DMAC_INT);
1729eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL);
17348618fb4SAlexandre Bounine udelay(10);
1749eaa3d9bSAlexandre Bounine iowrite32(0, regs + TSI721_DMAC_DWRCNT);
17548618fb4SAlexandre Bounine udelay(1);
17648618fb4SAlexandre Bounine if (!do_wr)
17748618fb4SAlexandre Bounine *data = 0xffffffff;
17848618fb4SAlexandre Bounine err = -EIO;
17948618fb4SAlexandre Bounine goto err_out;
18048618fb4SAlexandre Bounine }
18148618fb4SAlexandre Bounine
18248618fb4SAlexandre Bounine if (!do_wr)
18348618fb4SAlexandre Bounine *data = be32_to_cpu(bd_ptr[0].data[0]);
18448618fb4SAlexandre Bounine
18548618fb4SAlexandre Bounine /*
18648618fb4SAlexandre Bounine * Update descriptor status FIFO RD pointer.
18748618fb4SAlexandre Bounine * NOTE: Skipping check and clear FIFO entries because we are waiting
18848618fb4SAlexandre Bounine * for transfer to be completed.
18948618fb4SAlexandre Bounine */
1909eaa3d9bSAlexandre Bounine swr_ptr = ioread32(regs + TSI721_DMAC_DSWP);
1919eaa3d9bSAlexandre Bounine iowrite32(swr_ptr, regs + TSI721_DMAC_DSRP);
19231d1e130SIoan Nicu
19348618fb4SAlexandre Bounine err_out:
19431d1e130SIoan Nicu spin_unlock_irqrestore(&tsi721_maint_lock, flags);
19548618fb4SAlexandre Bounine
19648618fb4SAlexandre Bounine return err;
19748618fb4SAlexandre Bounine }
19848618fb4SAlexandre Bounine
19948618fb4SAlexandre Bounine /**
20048618fb4SAlexandre Bounine * tsi721_cread_dma - Generate a RapidIO maintenance read transaction
20148618fb4SAlexandre Bounine * using Tsi721 BDMA engine.
20248618fb4SAlexandre Bounine * @mport: RapidIO master port control structure
20348618fb4SAlexandre Bounine * @index: ID of RapdiIO interface
20448618fb4SAlexandre Bounine * @destid: Destination ID of transaction
20548618fb4SAlexandre Bounine * @hopcount: Number of hops to target device
20648618fb4SAlexandre Bounine * @offset: Offset into configuration space
20748618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction
20848618fb4SAlexandre Bounine * @val: Location to be read into
20948618fb4SAlexandre Bounine *
21048618fb4SAlexandre Bounine * Generates a RapidIO maintenance read transaction.
21148618fb4SAlexandre Bounine * Returns %0 on success and %-EINVAL or %-EFAULT on failure.
21248618fb4SAlexandre Bounine */
tsi721_cread_dma(struct rio_mport * mport,int index,u16 destid,u8 hopcount,u32 offset,int len,u32 * data)21348618fb4SAlexandre Bounine static int tsi721_cread_dma(struct rio_mport *mport, int index, u16 destid,
21448618fb4SAlexandre Bounine u8 hopcount, u32 offset, int len, u32 *data)
21548618fb4SAlexandre Bounine {
21648618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
21748618fb4SAlexandre Bounine
21848618fb4SAlexandre Bounine return tsi721_maint_dma(priv, mport->sys_size, destid, hopcount,
21948618fb4SAlexandre Bounine offset, len, data, 0);
22048618fb4SAlexandre Bounine }
22148618fb4SAlexandre Bounine
22248618fb4SAlexandre Bounine /**
22348618fb4SAlexandre Bounine * tsi721_cwrite_dma - Generate a RapidIO maintenance write transaction
22448618fb4SAlexandre Bounine * using Tsi721 BDMA engine
22548618fb4SAlexandre Bounine * @mport: RapidIO master port control structure
22648618fb4SAlexandre Bounine * @index: ID of RapdiIO interface
22748618fb4SAlexandre Bounine * @destid: Destination ID of transaction
22848618fb4SAlexandre Bounine * @hopcount: Number of hops to target device
22948618fb4SAlexandre Bounine * @offset: Offset into configuration space
23048618fb4SAlexandre Bounine * @len: Length (in bytes) of the maintenance transaction
23148618fb4SAlexandre Bounine * @val: Value to be written
23248618fb4SAlexandre Bounine *
23348618fb4SAlexandre Bounine * Generates a RapidIO maintenance write transaction.
23448618fb4SAlexandre Bounine * Returns %0 on success and %-EINVAL or %-EFAULT on failure.
23548618fb4SAlexandre Bounine */
tsi721_cwrite_dma(struct rio_mport * mport,int index,u16 destid,u8 hopcount,u32 offset,int len,u32 data)23648618fb4SAlexandre Bounine static int tsi721_cwrite_dma(struct rio_mport *mport, int index, u16 destid,
23748618fb4SAlexandre Bounine u8 hopcount, u32 offset, int len, u32 data)
23848618fb4SAlexandre Bounine {
23948618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
24048618fb4SAlexandre Bounine u32 temp = data;
24148618fb4SAlexandre Bounine
24248618fb4SAlexandre Bounine return tsi721_maint_dma(priv, mport->sys_size, destid, hopcount,
24348618fb4SAlexandre Bounine offset, len, &temp, 1);
24448618fb4SAlexandre Bounine }
24548618fb4SAlexandre Bounine
24648618fb4SAlexandre Bounine /**
24748618fb4SAlexandre Bounine * tsi721_pw_handler - Tsi721 inbound port-write interrupt handler
248748353ccSAlexandre Bounine * @priv: tsi721 device private structure
24948618fb4SAlexandre Bounine *
25048618fb4SAlexandre Bounine * Handles inbound port-write interrupts. Copies PW message from an internal
25148618fb4SAlexandre Bounine * buffer into PW message FIFO and schedules deferred routine to process
25248618fb4SAlexandre Bounine * queued messages.
25348618fb4SAlexandre Bounine */
25448618fb4SAlexandre Bounine static int
tsi721_pw_handler(struct tsi721_device * priv)255748353ccSAlexandre Bounine tsi721_pw_handler(struct tsi721_device *priv)
25648618fb4SAlexandre Bounine {
25748618fb4SAlexandre Bounine u32 pw_stat;
25848618fb4SAlexandre Bounine u32 pw_buf[TSI721_RIO_PW_MSG_SIZE/sizeof(u32)];
25948618fb4SAlexandre Bounine
26048618fb4SAlexandre Bounine
26148618fb4SAlexandre Bounine pw_stat = ioread32(priv->regs + TSI721_RIO_PW_RX_STAT);
26248618fb4SAlexandre Bounine
26348618fb4SAlexandre Bounine if (pw_stat & TSI721_RIO_PW_RX_STAT_PW_VAL) {
26448618fb4SAlexandre Bounine pw_buf[0] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(0));
26548618fb4SAlexandre Bounine pw_buf[1] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(1));
26648618fb4SAlexandre Bounine pw_buf[2] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(2));
26748618fb4SAlexandre Bounine pw_buf[3] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(3));
26848618fb4SAlexandre Bounine
26948618fb4SAlexandre Bounine /* Queue PW message (if there is room in FIFO),
27048618fb4SAlexandre Bounine * otherwise discard it.
27148618fb4SAlexandre Bounine */
27248618fb4SAlexandre Bounine spin_lock(&priv->pw_fifo_lock);
27348618fb4SAlexandre Bounine if (kfifo_avail(&priv->pw_fifo) >= TSI721_RIO_PW_MSG_SIZE)
27448618fb4SAlexandre Bounine kfifo_in(&priv->pw_fifo, pw_buf,
27548618fb4SAlexandre Bounine TSI721_RIO_PW_MSG_SIZE);
27648618fb4SAlexandre Bounine else
27748618fb4SAlexandre Bounine priv->pw_discard_count++;
27848618fb4SAlexandre Bounine spin_unlock(&priv->pw_fifo_lock);
27948618fb4SAlexandre Bounine }
28048618fb4SAlexandre Bounine
28148618fb4SAlexandre Bounine /* Clear pending PW interrupts */
28248618fb4SAlexandre Bounine iowrite32(TSI721_RIO_PW_RX_STAT_PW_DISC | TSI721_RIO_PW_RX_STAT_PW_VAL,
28348618fb4SAlexandre Bounine priv->regs + TSI721_RIO_PW_RX_STAT);
28448618fb4SAlexandre Bounine
28548618fb4SAlexandre Bounine schedule_work(&priv->pw_work);
28648618fb4SAlexandre Bounine
28748618fb4SAlexandre Bounine return 0;
28848618fb4SAlexandre Bounine }
28948618fb4SAlexandre Bounine
tsi721_pw_dpc(struct work_struct * work)29048618fb4SAlexandre Bounine static void tsi721_pw_dpc(struct work_struct *work)
29148618fb4SAlexandre Bounine {
29248618fb4SAlexandre Bounine struct tsi721_device *priv = container_of(work, struct tsi721_device,
29348618fb4SAlexandre Bounine pw_work);
2949a0b0627SAlexandre Bounine union rio_pw_msg pwmsg;
29548618fb4SAlexandre Bounine
29648618fb4SAlexandre Bounine /*
29748618fb4SAlexandre Bounine * Process port-write messages
29848618fb4SAlexandre Bounine */
2999a0b0627SAlexandre Bounine while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)&pwmsg,
30048618fb4SAlexandre Bounine TSI721_RIO_PW_MSG_SIZE, &priv->pw_fifo_lock)) {
30148618fb4SAlexandre Bounine /* Pass the port-write message to RIO core for processing */
3029a0b0627SAlexandre Bounine rio_inb_pwrite_handler(&priv->mport, &pwmsg);
30348618fb4SAlexandre Bounine }
30448618fb4SAlexandre Bounine }
30548618fb4SAlexandre Bounine
30648618fb4SAlexandre Bounine /**
30748618fb4SAlexandre Bounine * tsi721_pw_enable - enable/disable port-write interface init
30848618fb4SAlexandre Bounine * @mport: Master port implementing the port write unit
30948618fb4SAlexandre Bounine * @enable: 1=enable; 0=disable port-write message handling
31048618fb4SAlexandre Bounine */
tsi721_pw_enable(struct rio_mport * mport,int enable)31148618fb4SAlexandre Bounine static int tsi721_pw_enable(struct rio_mport *mport, int enable)
31248618fb4SAlexandre Bounine {
31348618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
31448618fb4SAlexandre Bounine u32 rval;
31548618fb4SAlexandre Bounine
31648618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_RIO_EM_INT_ENABLE);
31748618fb4SAlexandre Bounine
31848618fb4SAlexandre Bounine if (enable)
31948618fb4SAlexandre Bounine rval |= TSI721_RIO_EM_INT_ENABLE_PW_RX;
32048618fb4SAlexandre Bounine else
32148618fb4SAlexandre Bounine rval &= ~TSI721_RIO_EM_INT_ENABLE_PW_RX;
32248618fb4SAlexandre Bounine
32348618fb4SAlexandre Bounine /* Clear pending PW interrupts */
32448618fb4SAlexandre Bounine iowrite32(TSI721_RIO_PW_RX_STAT_PW_DISC | TSI721_RIO_PW_RX_STAT_PW_VAL,
32548618fb4SAlexandre Bounine priv->regs + TSI721_RIO_PW_RX_STAT);
32648618fb4SAlexandre Bounine /* Update enable bits */
32748618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_RIO_EM_INT_ENABLE);
32848618fb4SAlexandre Bounine
32948618fb4SAlexandre Bounine return 0;
33048618fb4SAlexandre Bounine }
33148618fb4SAlexandre Bounine
33248618fb4SAlexandre Bounine /**
33348618fb4SAlexandre Bounine * tsi721_dsend - Send a RapidIO doorbell
33448618fb4SAlexandre Bounine * @mport: RapidIO master port info
33548618fb4SAlexandre Bounine * @index: ID of RapidIO interface
33648618fb4SAlexandre Bounine * @destid: Destination ID of target device
33748618fb4SAlexandre Bounine * @data: 16-bit info field of RapidIO doorbell
33848618fb4SAlexandre Bounine *
33948618fb4SAlexandre Bounine * Sends a RapidIO doorbell message. Always returns %0.
34048618fb4SAlexandre Bounine */
tsi721_dsend(struct rio_mport * mport,int index,u16 destid,u16 data)34148618fb4SAlexandre Bounine static int tsi721_dsend(struct rio_mport *mport, int index,
34248618fb4SAlexandre Bounine u16 destid, u16 data)
34348618fb4SAlexandre Bounine {
34448618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
34548618fb4SAlexandre Bounine u32 offset;
34648618fb4SAlexandre Bounine
34748618fb4SAlexandre Bounine offset = (((mport->sys_size) ? RIO_TT_CODE_16 : RIO_TT_CODE_8) << 18) |
34848618fb4SAlexandre Bounine (destid << 2);
34948618fb4SAlexandre Bounine
35072d8a0d2SAlexandre Bounine tsi_debug(DBELL, &priv->pdev->dev,
35172d8a0d2SAlexandre Bounine "Send Doorbell 0x%04x to destID 0x%x", data, destid);
35248618fb4SAlexandre Bounine iowrite16be(data, priv->odb_base + offset);
35348618fb4SAlexandre Bounine
35448618fb4SAlexandre Bounine return 0;
35548618fb4SAlexandre Bounine }
35648618fb4SAlexandre Bounine
35748618fb4SAlexandre Bounine /**
35848618fb4SAlexandre Bounine * tsi721_dbell_handler - Tsi721 doorbell interrupt handler
359748353ccSAlexandre Bounine * @priv: tsi721 device-specific data structure
36048618fb4SAlexandre Bounine *
36148618fb4SAlexandre Bounine * Handles inbound doorbell interrupts. Copies doorbell entry from an internal
36248618fb4SAlexandre Bounine * buffer into DB message FIFO and schedules deferred routine to process
36348618fb4SAlexandre Bounine * queued DBs.
36448618fb4SAlexandre Bounine */
36548618fb4SAlexandre Bounine static int
tsi721_dbell_handler(struct tsi721_device * priv)366748353ccSAlexandre Bounine tsi721_dbell_handler(struct tsi721_device *priv)
36748618fb4SAlexandre Bounine {
36848618fb4SAlexandre Bounine u32 regval;
36948618fb4SAlexandre Bounine
37048618fb4SAlexandre Bounine /* Disable IDB interrupts */
37148618fb4SAlexandre Bounine regval = ioread32(priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
37248618fb4SAlexandre Bounine regval &= ~TSI721_SR_CHINT_IDBQRCV;
37348618fb4SAlexandre Bounine iowrite32(regval,
37448618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
37548618fb4SAlexandre Bounine
37648618fb4SAlexandre Bounine schedule_work(&priv->idb_work);
37748618fb4SAlexandre Bounine
37848618fb4SAlexandre Bounine return 0;
37948618fb4SAlexandre Bounine }
38048618fb4SAlexandre Bounine
tsi721_db_dpc(struct work_struct * work)38148618fb4SAlexandre Bounine static void tsi721_db_dpc(struct work_struct *work)
38248618fb4SAlexandre Bounine {
38348618fb4SAlexandre Bounine struct tsi721_device *priv = container_of(work, struct tsi721_device,
38448618fb4SAlexandre Bounine idb_work);
38548618fb4SAlexandre Bounine struct rio_mport *mport;
38648618fb4SAlexandre Bounine struct rio_dbell *dbell;
38748618fb4SAlexandre Bounine int found = 0;
38848618fb4SAlexandre Bounine u32 wr_ptr, rd_ptr;
38948618fb4SAlexandre Bounine u64 *idb_entry;
39048618fb4SAlexandre Bounine u32 regval;
39148618fb4SAlexandre Bounine union {
39248618fb4SAlexandre Bounine u64 msg;
39348618fb4SAlexandre Bounine u8 bytes[8];
39448618fb4SAlexandre Bounine } idb;
39548618fb4SAlexandre Bounine
39648618fb4SAlexandre Bounine /*
39748618fb4SAlexandre Bounine * Process queued inbound doorbells
39848618fb4SAlexandre Bounine */
399748353ccSAlexandre Bounine mport = &priv->mport;
40048618fb4SAlexandre Bounine
401b24823e6SAlexandre Bounine wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE;
402b24823e6SAlexandre Bounine rd_ptr = ioread32(priv->regs + TSI721_IDQ_RP(IDB_QUEUE)) % IDB_QSIZE;
40348618fb4SAlexandre Bounine
40448618fb4SAlexandre Bounine while (wr_ptr != rd_ptr) {
40548618fb4SAlexandre Bounine idb_entry = (u64 *)(priv->idb_base +
40648618fb4SAlexandre Bounine (TSI721_IDB_ENTRY_SIZE * rd_ptr));
40748618fb4SAlexandre Bounine rd_ptr++;
408b24823e6SAlexandre Bounine rd_ptr %= IDB_QSIZE;
40948618fb4SAlexandre Bounine idb.msg = *idb_entry;
41048618fb4SAlexandre Bounine *idb_entry = 0;
41148618fb4SAlexandre Bounine
41248618fb4SAlexandre Bounine /* Process one doorbell */
41348618fb4SAlexandre Bounine list_for_each_entry(dbell, &mport->dbells, node) {
41448618fb4SAlexandre Bounine if ((dbell->res->start <= DBELL_INF(idb.bytes)) &&
41548618fb4SAlexandre Bounine (dbell->res->end >= DBELL_INF(idb.bytes))) {
41648618fb4SAlexandre Bounine found = 1;
41748618fb4SAlexandre Bounine break;
41848618fb4SAlexandre Bounine }
41948618fb4SAlexandre Bounine }
42048618fb4SAlexandre Bounine
42148618fb4SAlexandre Bounine if (found) {
42248618fb4SAlexandre Bounine dbell->dinb(mport, dbell->dev_id, DBELL_SID(idb.bytes),
42348618fb4SAlexandre Bounine DBELL_TID(idb.bytes), DBELL_INF(idb.bytes));
42448618fb4SAlexandre Bounine } else {
42572d8a0d2SAlexandre Bounine tsi_debug(DBELL, &priv->pdev->dev,
42672d8a0d2SAlexandre Bounine "spurious IDB sid %2.2x tid %2.2x info %4.4x",
42772d8a0d2SAlexandre Bounine DBELL_SID(idb.bytes), DBELL_TID(idb.bytes),
42872d8a0d2SAlexandre Bounine DBELL_INF(idb.bytes));
42948618fb4SAlexandre Bounine }
4303670e7e1SAlexandre Bounine
4313670e7e1SAlexandre Bounine wr_ptr = ioread32(priv->regs +
4323670e7e1SAlexandre Bounine TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE;
43348618fb4SAlexandre Bounine }
43448618fb4SAlexandre Bounine
43548618fb4SAlexandre Bounine iowrite32(rd_ptr & (IDB_QSIZE - 1),
43648618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_RP(IDB_QUEUE));
43748618fb4SAlexandre Bounine
43848618fb4SAlexandre Bounine /* Re-enable IDB interrupts */
43948618fb4SAlexandre Bounine regval = ioread32(priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
44048618fb4SAlexandre Bounine regval |= TSI721_SR_CHINT_IDBQRCV;
44148618fb4SAlexandre Bounine iowrite32(regval,
44248618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
4433670e7e1SAlexandre Bounine
4443670e7e1SAlexandre Bounine wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE;
4453670e7e1SAlexandre Bounine if (wr_ptr != rd_ptr)
4463670e7e1SAlexandre Bounine schedule_work(&priv->idb_work);
44748618fb4SAlexandre Bounine }
44848618fb4SAlexandre Bounine
44948618fb4SAlexandre Bounine /**
45048618fb4SAlexandre Bounine * tsi721_irqhandler - Tsi721 interrupt handler
45148618fb4SAlexandre Bounine * @irq: Linux interrupt number
452748353ccSAlexandre Bounine * @ptr: Pointer to interrupt-specific data (tsi721_device structure)
45348618fb4SAlexandre Bounine *
45448618fb4SAlexandre Bounine * Handles Tsi721 interrupts signaled using MSI and INTA. Checks reported
45548618fb4SAlexandre Bounine * interrupt events and calls an event-specific handler(s).
45648618fb4SAlexandre Bounine */
tsi721_irqhandler(int irq,void * ptr)45748618fb4SAlexandre Bounine static irqreturn_t tsi721_irqhandler(int irq, void *ptr)
45848618fb4SAlexandre Bounine {
459748353ccSAlexandre Bounine struct tsi721_device *priv = (struct tsi721_device *)ptr;
46048618fb4SAlexandre Bounine u32 dev_int;
46148618fb4SAlexandre Bounine u32 dev_ch_int;
46248618fb4SAlexandre Bounine u32 intval;
46348618fb4SAlexandre Bounine u32 ch_inte;
46448618fb4SAlexandre Bounine
4651ccc819dSAlexandre Bounine /* For MSI mode disable all device-level interrupts */
4661ccc819dSAlexandre Bounine if (priv->flags & TSI721_USING_MSI)
4671ccc819dSAlexandre Bounine iowrite32(0, priv->regs + TSI721_DEV_INTE);
4681ccc819dSAlexandre Bounine
46948618fb4SAlexandre Bounine dev_int = ioread32(priv->regs + TSI721_DEV_INT);
47048618fb4SAlexandre Bounine if (!dev_int)
47148618fb4SAlexandre Bounine return IRQ_NONE;
47248618fb4SAlexandre Bounine
47348618fb4SAlexandre Bounine dev_ch_int = ioread32(priv->regs + TSI721_DEV_CHAN_INT);
47448618fb4SAlexandre Bounine
47548618fb4SAlexandre Bounine if (dev_int & TSI721_DEV_INT_SR2PC_CH) {
47648618fb4SAlexandre Bounine /* Service SR2PC Channel interrupts */
47748618fb4SAlexandre Bounine if (dev_ch_int & TSI721_INT_SR2PC_CHAN(IDB_QUEUE)) {
47848618fb4SAlexandre Bounine /* Service Inbound Doorbell interrupt */
47948618fb4SAlexandre Bounine intval = ioread32(priv->regs +
48048618fb4SAlexandre Bounine TSI721_SR_CHINT(IDB_QUEUE));
48148618fb4SAlexandre Bounine if (intval & TSI721_SR_CHINT_IDBQRCV)
482748353ccSAlexandre Bounine tsi721_dbell_handler(priv);
48348618fb4SAlexandre Bounine else
48472d8a0d2SAlexandre Bounine tsi_info(&priv->pdev->dev,
48572d8a0d2SAlexandre Bounine "Unsupported SR_CH_INT %x", intval);
48648618fb4SAlexandre Bounine
48748618fb4SAlexandre Bounine /* Clear interrupts */
48848618fb4SAlexandre Bounine iowrite32(intval,
48948618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
49048618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
49148618fb4SAlexandre Bounine }
49248618fb4SAlexandre Bounine }
49348618fb4SAlexandre Bounine
49448618fb4SAlexandre Bounine if (dev_int & TSI721_DEV_INT_SMSG_CH) {
49548618fb4SAlexandre Bounine int ch;
49648618fb4SAlexandre Bounine
49748618fb4SAlexandre Bounine /*
49848618fb4SAlexandre Bounine * Service channel interrupts from Messaging Engine
49948618fb4SAlexandre Bounine */
50048618fb4SAlexandre Bounine
50148618fb4SAlexandre Bounine if (dev_ch_int & TSI721_INT_IMSG_CHAN_M) { /* Inbound Msg */
50248618fb4SAlexandre Bounine /* Disable signaled OB MSG Channel interrupts */
50348618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
50448618fb4SAlexandre Bounine ch_inte &= ~(dev_ch_int & TSI721_INT_IMSG_CHAN_M);
50548618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE);
50648618fb4SAlexandre Bounine
50748618fb4SAlexandre Bounine /*
50848618fb4SAlexandre Bounine * Process Inbound Message interrupt for each MBOX
50948618fb4SAlexandre Bounine */
51048618fb4SAlexandre Bounine for (ch = 4; ch < RIO_MAX_MBOX + 4; ch++) {
51148618fb4SAlexandre Bounine if (!(dev_ch_int & TSI721_INT_IMSG_CHAN(ch)))
51248618fb4SAlexandre Bounine continue;
51348618fb4SAlexandre Bounine tsi721_imsg_handler(priv, ch);
51448618fb4SAlexandre Bounine }
51548618fb4SAlexandre Bounine }
51648618fb4SAlexandre Bounine
51748618fb4SAlexandre Bounine if (dev_ch_int & TSI721_INT_OMSG_CHAN_M) { /* Outbound Msg */
51848618fb4SAlexandre Bounine /* Disable signaled OB MSG Channel interrupts */
51948618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
52048618fb4SAlexandre Bounine ch_inte &= ~(dev_ch_int & TSI721_INT_OMSG_CHAN_M);
52148618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE);
52248618fb4SAlexandre Bounine
52348618fb4SAlexandre Bounine /*
52448618fb4SAlexandre Bounine * Process Outbound Message interrupts for each MBOX
52548618fb4SAlexandre Bounine */
52648618fb4SAlexandre Bounine
52748618fb4SAlexandre Bounine for (ch = 0; ch < RIO_MAX_MBOX; ch++) {
52848618fb4SAlexandre Bounine if (!(dev_ch_int & TSI721_INT_OMSG_CHAN(ch)))
52948618fb4SAlexandre Bounine continue;
53048618fb4SAlexandre Bounine tsi721_omsg_handler(priv, ch);
53148618fb4SAlexandre Bounine }
53248618fb4SAlexandre Bounine }
53348618fb4SAlexandre Bounine }
53448618fb4SAlexandre Bounine
53548618fb4SAlexandre Bounine if (dev_int & TSI721_DEV_INT_SRIO) {
53648618fb4SAlexandre Bounine /* Service SRIO MAC interrupts */
53748618fb4SAlexandre Bounine intval = ioread32(priv->regs + TSI721_RIO_EM_INT_STAT);
53848618fb4SAlexandre Bounine if (intval & TSI721_RIO_EM_INT_STAT_PW_RX)
539748353ccSAlexandre Bounine tsi721_pw_handler(priv);
54048618fb4SAlexandre Bounine }
54148618fb4SAlexandre Bounine
5429eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE
5439eaa3d9bSAlexandre Bounine if (dev_int & TSI721_DEV_INT_BDMA_CH) {
5449eaa3d9bSAlexandre Bounine int ch;
5459eaa3d9bSAlexandre Bounine
5469eaa3d9bSAlexandre Bounine if (dev_ch_int & TSI721_INT_BDMA_CHAN_M) {
54772d8a0d2SAlexandre Bounine tsi_debug(DMA, &priv->pdev->dev,
54872d8a0d2SAlexandre Bounine "IRQ from DMA channel 0x%08x", dev_ch_int);
5499eaa3d9bSAlexandre Bounine
5509eaa3d9bSAlexandre Bounine for (ch = 0; ch < TSI721_DMA_MAXCH; ch++) {
5519eaa3d9bSAlexandre Bounine if (!(dev_ch_int & TSI721_INT_BDMA_CHAN(ch)))
5529eaa3d9bSAlexandre Bounine continue;
5539eaa3d9bSAlexandre Bounine tsi721_bdma_handler(&priv->bdma[ch]);
5549eaa3d9bSAlexandre Bounine }
5559eaa3d9bSAlexandre Bounine }
5569eaa3d9bSAlexandre Bounine }
5579eaa3d9bSAlexandre Bounine #endif
5581ccc819dSAlexandre Bounine
5591ccc819dSAlexandre Bounine /* For MSI mode re-enable device-level interrupts */
5601ccc819dSAlexandre Bounine if (priv->flags & TSI721_USING_MSI) {
5611ccc819dSAlexandre Bounine dev_int = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO |
5621ccc819dSAlexandre Bounine TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH;
5631ccc819dSAlexandre Bounine iowrite32(dev_int, priv->regs + TSI721_DEV_INTE);
5641ccc819dSAlexandre Bounine }
5651ccc819dSAlexandre Bounine
56648618fb4SAlexandre Bounine return IRQ_HANDLED;
56748618fb4SAlexandre Bounine }
56848618fb4SAlexandre Bounine
tsi721_interrupts_init(struct tsi721_device * priv)56948618fb4SAlexandre Bounine static void tsi721_interrupts_init(struct tsi721_device *priv)
57048618fb4SAlexandre Bounine {
57148618fb4SAlexandre Bounine u32 intr;
57248618fb4SAlexandre Bounine
57348618fb4SAlexandre Bounine /* Enable IDB interrupts */
57448618fb4SAlexandre Bounine iowrite32(TSI721_SR_CHINT_ALL,
57548618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
57648618fb4SAlexandre Bounine iowrite32(TSI721_SR_CHINT_IDBQRCV,
57748618fb4SAlexandre Bounine priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
57848618fb4SAlexandre Bounine
57948618fb4SAlexandre Bounine /* Enable SRIO MAC interrupts */
58048618fb4SAlexandre Bounine iowrite32(TSI721_RIO_EM_DEV_INT_EN_INT,
58148618fb4SAlexandre Bounine priv->regs + TSI721_RIO_EM_DEV_INT_EN);
58248618fb4SAlexandre Bounine
5839eaa3d9bSAlexandre Bounine /* Enable interrupts from channels in use */
5849eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE
5859eaa3d9bSAlexandre Bounine intr = TSI721_INT_SR2PC_CHAN(IDB_QUEUE) |
5869eaa3d9bSAlexandre Bounine (TSI721_INT_BDMA_CHAN_M &
5879eaa3d9bSAlexandre Bounine ~TSI721_INT_BDMA_CHAN(TSI721_DMACH_MAINT));
5889eaa3d9bSAlexandre Bounine #else
5899eaa3d9bSAlexandre Bounine intr = TSI721_INT_SR2PC_CHAN(IDB_QUEUE);
5909eaa3d9bSAlexandre Bounine #endif
5919eaa3d9bSAlexandre Bounine iowrite32(intr, priv->regs + TSI721_DEV_CHAN_INTE);
5929eaa3d9bSAlexandre Bounine
59348618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX)
59448618fb4SAlexandre Bounine intr = TSI721_DEV_INT_SRIO;
59548618fb4SAlexandre Bounine else
59648618fb4SAlexandre Bounine intr = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO |
5979eaa3d9bSAlexandre Bounine TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH;
59848618fb4SAlexandre Bounine
59948618fb4SAlexandre Bounine iowrite32(intr, priv->regs + TSI721_DEV_INTE);
60048618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_DEV_INTE);
60148618fb4SAlexandre Bounine }
60248618fb4SAlexandre Bounine
60348618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI
60448618fb4SAlexandre Bounine /**
60548618fb4SAlexandre Bounine * tsi721_omsg_msix - MSI-X interrupt handler for outbound messaging
60648618fb4SAlexandre Bounine * @irq: Linux interrupt number
607748353ccSAlexandre Bounine * @ptr: Pointer to interrupt-specific data (tsi721_device structure)
60848618fb4SAlexandre Bounine *
60948618fb4SAlexandre Bounine * Handles outbound messaging interrupts signaled using MSI-X.
61048618fb4SAlexandre Bounine */
tsi721_omsg_msix(int irq,void * ptr)61148618fb4SAlexandre Bounine static irqreturn_t tsi721_omsg_msix(int irq, void *ptr)
61248618fb4SAlexandre Bounine {
613748353ccSAlexandre Bounine struct tsi721_device *priv = (struct tsi721_device *)ptr;
61448618fb4SAlexandre Bounine int mbox;
61548618fb4SAlexandre Bounine
61648618fb4SAlexandre Bounine mbox = (irq - priv->msix[TSI721_VECT_OMB0_DONE].vector) % RIO_MAX_MBOX;
61748618fb4SAlexandre Bounine tsi721_omsg_handler(priv, mbox);
61848618fb4SAlexandre Bounine return IRQ_HANDLED;
61948618fb4SAlexandre Bounine }
62048618fb4SAlexandre Bounine
62148618fb4SAlexandre Bounine /**
62248618fb4SAlexandre Bounine * tsi721_imsg_msix - MSI-X interrupt handler for inbound messaging
62348618fb4SAlexandre Bounine * @irq: Linux interrupt number
624748353ccSAlexandre Bounine * @ptr: Pointer to interrupt-specific data (tsi721_device structure)
62548618fb4SAlexandre Bounine *
62648618fb4SAlexandre Bounine * Handles inbound messaging interrupts signaled using MSI-X.
62748618fb4SAlexandre Bounine */
tsi721_imsg_msix(int irq,void * ptr)62848618fb4SAlexandre Bounine static irqreturn_t tsi721_imsg_msix(int irq, void *ptr)
62948618fb4SAlexandre Bounine {
630748353ccSAlexandre Bounine struct tsi721_device *priv = (struct tsi721_device *)ptr;
63148618fb4SAlexandre Bounine int mbox;
63248618fb4SAlexandre Bounine
63348618fb4SAlexandre Bounine mbox = (irq - priv->msix[TSI721_VECT_IMB0_RCV].vector) % RIO_MAX_MBOX;
63448618fb4SAlexandre Bounine tsi721_imsg_handler(priv, mbox + 4);
63548618fb4SAlexandre Bounine return IRQ_HANDLED;
63648618fb4SAlexandre Bounine }
63748618fb4SAlexandre Bounine
63848618fb4SAlexandre Bounine /**
63948618fb4SAlexandre Bounine * tsi721_srio_msix - Tsi721 MSI-X SRIO MAC interrupt handler
64048618fb4SAlexandre Bounine * @irq: Linux interrupt number
641748353ccSAlexandre Bounine * @ptr: Pointer to interrupt-specific data (tsi721_device structure)
64248618fb4SAlexandre Bounine *
64348618fb4SAlexandre Bounine * Handles Tsi721 interrupts from SRIO MAC.
64448618fb4SAlexandre Bounine */
tsi721_srio_msix(int irq,void * ptr)64548618fb4SAlexandre Bounine static irqreturn_t tsi721_srio_msix(int irq, void *ptr)
64648618fb4SAlexandre Bounine {
647748353ccSAlexandre Bounine struct tsi721_device *priv = (struct tsi721_device *)ptr;
64848618fb4SAlexandre Bounine u32 srio_int;
64948618fb4SAlexandre Bounine
65048618fb4SAlexandre Bounine /* Service SRIO MAC interrupts */
65148618fb4SAlexandre Bounine srio_int = ioread32(priv->regs + TSI721_RIO_EM_INT_STAT);
65248618fb4SAlexandre Bounine if (srio_int & TSI721_RIO_EM_INT_STAT_PW_RX)
653748353ccSAlexandre Bounine tsi721_pw_handler(priv);
65448618fb4SAlexandre Bounine
65548618fb4SAlexandre Bounine return IRQ_HANDLED;
65648618fb4SAlexandre Bounine }
65748618fb4SAlexandre Bounine
65848618fb4SAlexandre Bounine /**
65948618fb4SAlexandre Bounine * tsi721_sr2pc_ch_msix - Tsi721 MSI-X SR2PC Channel interrupt handler
66048618fb4SAlexandre Bounine * @irq: Linux interrupt number
661748353ccSAlexandre Bounine * @ptr: Pointer to interrupt-specific data (tsi721_device structure)
66248618fb4SAlexandre Bounine *
66348618fb4SAlexandre Bounine * Handles Tsi721 interrupts from SR2PC Channel.
66448618fb4SAlexandre Bounine * NOTE: At this moment services only one SR2PC channel associated with inbound
66548618fb4SAlexandre Bounine * doorbells.
66648618fb4SAlexandre Bounine */
tsi721_sr2pc_ch_msix(int irq,void * ptr)66748618fb4SAlexandre Bounine static irqreturn_t tsi721_sr2pc_ch_msix(int irq, void *ptr)
66848618fb4SAlexandre Bounine {
669748353ccSAlexandre Bounine struct tsi721_device *priv = (struct tsi721_device *)ptr;
67048618fb4SAlexandre Bounine u32 sr_ch_int;
67148618fb4SAlexandre Bounine
67248618fb4SAlexandre Bounine /* Service Inbound DB interrupt from SR2PC channel */
67348618fb4SAlexandre Bounine sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
67448618fb4SAlexandre Bounine if (sr_ch_int & TSI721_SR_CHINT_IDBQRCV)
675748353ccSAlexandre Bounine tsi721_dbell_handler(priv);
67648618fb4SAlexandre Bounine
67748618fb4SAlexandre Bounine /* Clear interrupts */
67848618fb4SAlexandre Bounine iowrite32(sr_ch_int, priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
67948618fb4SAlexandre Bounine /* Read back to ensure that interrupt was cleared */
68048618fb4SAlexandre Bounine sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
68148618fb4SAlexandre Bounine
68248618fb4SAlexandre Bounine return IRQ_HANDLED;
68348618fb4SAlexandre Bounine }
68448618fb4SAlexandre Bounine
68548618fb4SAlexandre Bounine /**
68648618fb4SAlexandre Bounine * tsi721_request_msix - register interrupt service for MSI-X mode.
687748353ccSAlexandre Bounine * @priv: tsi721 device-specific data structure
68848618fb4SAlexandre Bounine *
68948618fb4SAlexandre Bounine * Registers MSI-X interrupt service routines for interrupts that are active
69048618fb4SAlexandre Bounine * immediately after mport initialization. Messaging interrupt service routines
69148618fb4SAlexandre Bounine * should be registered during corresponding open requests.
69248618fb4SAlexandre Bounine */
tsi721_request_msix(struct tsi721_device * priv)693748353ccSAlexandre Bounine static int tsi721_request_msix(struct tsi721_device *priv)
69448618fb4SAlexandre Bounine {
69548618fb4SAlexandre Bounine int err = 0;
69648618fb4SAlexandre Bounine
69748618fb4SAlexandre Bounine err = request_irq(priv->msix[TSI721_VECT_IDB].vector,
69848618fb4SAlexandre Bounine tsi721_sr2pc_ch_msix, 0,
699748353ccSAlexandre Bounine priv->msix[TSI721_VECT_IDB].irq_name, (void *)priv);
70048618fb4SAlexandre Bounine if (err)
701748353ccSAlexandre Bounine return err;
70248618fb4SAlexandre Bounine
70348618fb4SAlexandre Bounine err = request_irq(priv->msix[TSI721_VECT_PWRX].vector,
70448618fb4SAlexandre Bounine tsi721_srio_msix, 0,
705748353ccSAlexandre Bounine priv->msix[TSI721_VECT_PWRX].irq_name, (void *)priv);
706748353ccSAlexandre Bounine if (err) {
707748353ccSAlexandre Bounine free_irq(priv->msix[TSI721_VECT_IDB].vector, (void *)priv);
70848618fb4SAlexandre Bounine return err;
70948618fb4SAlexandre Bounine }
71048618fb4SAlexandre Bounine
711748353ccSAlexandre Bounine return 0;
712748353ccSAlexandre Bounine }
713748353ccSAlexandre Bounine
71448618fb4SAlexandre Bounine /**
71548618fb4SAlexandre Bounine * tsi721_enable_msix - Attempts to enable MSI-X support for Tsi721.
71648618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data
71748618fb4SAlexandre Bounine *
71848618fb4SAlexandre Bounine * Configures MSI-X support for Tsi721. Supports only an exact number
71948618fb4SAlexandre Bounine * of requested vectors.
72048618fb4SAlexandre Bounine */
tsi721_enable_msix(struct tsi721_device * priv)72148618fb4SAlexandre Bounine static int tsi721_enable_msix(struct tsi721_device *priv)
72248618fb4SAlexandre Bounine {
72348618fb4SAlexandre Bounine struct msix_entry entries[TSI721_VECT_MAX];
72448618fb4SAlexandre Bounine int err;
72548618fb4SAlexandre Bounine int i;
72648618fb4SAlexandre Bounine
72748618fb4SAlexandre Bounine entries[TSI721_VECT_IDB].entry = TSI721_MSIX_SR2PC_IDBQ_RCV(IDB_QUEUE);
72848618fb4SAlexandre Bounine entries[TSI721_VECT_PWRX].entry = TSI721_MSIX_SRIO_MAC_INT;
72948618fb4SAlexandre Bounine
73048618fb4SAlexandre Bounine /*
73148618fb4SAlexandre Bounine * Initialize MSI-X entries for Messaging Engine:
73248618fb4SAlexandre Bounine * this driver supports four RIO mailboxes (inbound and outbound)
73348618fb4SAlexandre Bounine * NOTE: Inbound message MBOX 0...4 use IB channels 4...7. Therefore
73448618fb4SAlexandre Bounine * offset +4 is added to IB MBOX number.
73548618fb4SAlexandre Bounine */
73648618fb4SAlexandre Bounine for (i = 0; i < RIO_MAX_MBOX; i++) {
73748618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_RCV + i].entry =
73848618fb4SAlexandre Bounine TSI721_MSIX_IMSG_DQ_RCV(i + 4);
73948618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_INT + i].entry =
74048618fb4SAlexandre Bounine TSI721_MSIX_IMSG_INT(i + 4);
74148618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_DONE + i].entry =
74248618fb4SAlexandre Bounine TSI721_MSIX_OMSG_DONE(i);
74348618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_INT + i].entry =
74448618fb4SAlexandre Bounine TSI721_MSIX_OMSG_INT(i);
74548618fb4SAlexandre Bounine }
74648618fb4SAlexandre Bounine
7479eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE
7489eaa3d9bSAlexandre Bounine /*
7499eaa3d9bSAlexandre Bounine * Initialize MSI-X entries for Block DMA Engine:
7509eaa3d9bSAlexandre Bounine * this driver supports XXX DMA channels
7519eaa3d9bSAlexandre Bounine * (one is reserved for SRIO maintenance transactions)
7529eaa3d9bSAlexandre Bounine */
7539eaa3d9bSAlexandre Bounine for (i = 0; i < TSI721_DMA_CHNUM; i++) {
7549eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_DONE + i].entry =
7559eaa3d9bSAlexandre Bounine TSI721_MSIX_DMACH_DONE(i);
7569eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_INT + i].entry =
7579eaa3d9bSAlexandre Bounine TSI721_MSIX_DMACH_INT(i);
7589eaa3d9bSAlexandre Bounine }
7599eaa3d9bSAlexandre Bounine #endif /* CONFIG_RAPIDIO_DMA_ENGINE */
7609eaa3d9bSAlexandre Bounine
7611c92ab1eSAlexander Gordeev err = pci_enable_msix_exact(priv->pdev, entries, ARRAY_SIZE(entries));
76248618fb4SAlexandre Bounine if (err) {
76372d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev,
76472d8a0d2SAlexandre Bounine "Failed to enable MSI-X (err=%d)", err);
76548618fb4SAlexandre Bounine return err;
76648618fb4SAlexandre Bounine }
76748618fb4SAlexandre Bounine
76848618fb4SAlexandre Bounine /*
76948618fb4SAlexandre Bounine * Copy MSI-X vector information into tsi721 private structure
77048618fb4SAlexandre Bounine */
77148618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IDB].vector = entries[TSI721_VECT_IDB].vector;
77248618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_IDB].irq_name, IRQ_DEVICE_NAME_MAX,
77348618fb4SAlexandre Bounine DRV_NAME "-idb@pci:%s", pci_name(priv->pdev));
77448618fb4SAlexandre Bounine priv->msix[TSI721_VECT_PWRX].vector = entries[TSI721_VECT_PWRX].vector;
77548618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_PWRX].irq_name, IRQ_DEVICE_NAME_MAX,
77648618fb4SAlexandre Bounine DRV_NAME "-pwrx@pci:%s", pci_name(priv->pdev));
77748618fb4SAlexandre Bounine
77848618fb4SAlexandre Bounine for (i = 0; i < RIO_MAX_MBOX; i++) {
77948618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_RCV + i].vector =
78048618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_RCV + i].vector;
78148618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_IMB0_RCV + i].irq_name,
78248618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-imbr%d@pci:%s",
78348618fb4SAlexandre Bounine i, pci_name(priv->pdev));
78448618fb4SAlexandre Bounine
78548618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_INT + i].vector =
78648618fb4SAlexandre Bounine entries[TSI721_VECT_IMB0_INT + i].vector;
78748618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_IMB0_INT + i].irq_name,
78848618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-imbi%d@pci:%s",
78948618fb4SAlexandre Bounine i, pci_name(priv->pdev));
79048618fb4SAlexandre Bounine
79148618fb4SAlexandre Bounine priv->msix[TSI721_VECT_OMB0_DONE + i].vector =
79248618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_DONE + i].vector;
79348618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_OMB0_DONE + i].irq_name,
79448618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-ombd%d@pci:%s",
79548618fb4SAlexandre Bounine i, pci_name(priv->pdev));
79648618fb4SAlexandre Bounine
79748618fb4SAlexandre Bounine priv->msix[TSI721_VECT_OMB0_INT + i].vector =
79848618fb4SAlexandre Bounine entries[TSI721_VECT_OMB0_INT + i].vector;
79948618fb4SAlexandre Bounine snprintf(priv->msix[TSI721_VECT_OMB0_INT + i].irq_name,
80048618fb4SAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-ombi%d@pci:%s",
80148618fb4SAlexandre Bounine i, pci_name(priv->pdev));
80248618fb4SAlexandre Bounine }
80348618fb4SAlexandre Bounine
8049eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE
8059eaa3d9bSAlexandre Bounine for (i = 0; i < TSI721_DMA_CHNUM; i++) {
8069eaa3d9bSAlexandre Bounine priv->msix[TSI721_VECT_DMA0_DONE + i].vector =
8079eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_DONE + i].vector;
8089eaa3d9bSAlexandre Bounine snprintf(priv->msix[TSI721_VECT_DMA0_DONE + i].irq_name,
8099eaa3d9bSAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-dmad%d@pci:%s",
8109eaa3d9bSAlexandre Bounine i, pci_name(priv->pdev));
8119eaa3d9bSAlexandre Bounine
8129eaa3d9bSAlexandre Bounine priv->msix[TSI721_VECT_DMA0_INT + i].vector =
8139eaa3d9bSAlexandre Bounine entries[TSI721_VECT_DMA0_INT + i].vector;
8149eaa3d9bSAlexandre Bounine snprintf(priv->msix[TSI721_VECT_DMA0_INT + i].irq_name,
8159eaa3d9bSAlexandre Bounine IRQ_DEVICE_NAME_MAX, DRV_NAME "-dmai%d@pci:%s",
8169eaa3d9bSAlexandre Bounine i, pci_name(priv->pdev));
8179eaa3d9bSAlexandre Bounine }
8189eaa3d9bSAlexandre Bounine #endif /* CONFIG_RAPIDIO_DMA_ENGINE */
8199eaa3d9bSAlexandre Bounine
82048618fb4SAlexandre Bounine return 0;
82148618fb4SAlexandre Bounine }
82248618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */
82348618fb4SAlexandre Bounine
tsi721_request_irq(struct tsi721_device * priv)824748353ccSAlexandre Bounine static int tsi721_request_irq(struct tsi721_device *priv)
82548618fb4SAlexandre Bounine {
82648618fb4SAlexandre Bounine int err;
82748618fb4SAlexandre Bounine
82848618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI
82948618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX)
830748353ccSAlexandre Bounine err = tsi721_request_msix(priv);
83148618fb4SAlexandre Bounine else
83248618fb4SAlexandre Bounine #endif
83348618fb4SAlexandre Bounine err = request_irq(priv->pdev->irq, tsi721_irqhandler,
83448618fb4SAlexandre Bounine (priv->flags & TSI721_USING_MSI) ? 0 : IRQF_SHARED,
835748353ccSAlexandre Bounine DRV_NAME, (void *)priv);
83648618fb4SAlexandre Bounine
83748618fb4SAlexandre Bounine if (err)
83872d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev,
83972d8a0d2SAlexandre Bounine "Unable to allocate interrupt, err=%d", err);
84048618fb4SAlexandre Bounine
84148618fb4SAlexandre Bounine return err;
84248618fb4SAlexandre Bounine }
84348618fb4SAlexandre Bounine
tsi721_free_irq(struct tsi721_device * priv)844748353ccSAlexandre Bounine static void tsi721_free_irq(struct tsi721_device *priv)
845748353ccSAlexandre Bounine {
846748353ccSAlexandre Bounine #ifdef CONFIG_PCI_MSI
847748353ccSAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) {
848748353ccSAlexandre Bounine free_irq(priv->msix[TSI721_VECT_IDB].vector, (void *)priv);
849748353ccSAlexandre Bounine free_irq(priv->msix[TSI721_VECT_PWRX].vector, (void *)priv);
850748353ccSAlexandre Bounine } else
851748353ccSAlexandre Bounine #endif
852748353ccSAlexandre Bounine free_irq(priv->pdev->irq, (void *)priv);
853748353ccSAlexandre Bounine }
854748353ccSAlexandre Bounine
8551679e8daSAlexandre Bounine static int
tsi721_obw_alloc(struct tsi721_device * priv,struct tsi721_obw_bar * pbar,u32 size,int * win_id)8561679e8daSAlexandre Bounine tsi721_obw_alloc(struct tsi721_device *priv, struct tsi721_obw_bar *pbar,
8571679e8daSAlexandre Bounine u32 size, int *win_id)
8581679e8daSAlexandre Bounine {
8591679e8daSAlexandre Bounine u64 win_base;
8601679e8daSAlexandre Bounine u64 bar_base;
8611679e8daSAlexandre Bounine u64 bar_end;
8621679e8daSAlexandre Bounine u32 align;
8631679e8daSAlexandre Bounine struct tsi721_ob_win *win;
8641679e8daSAlexandre Bounine struct tsi721_ob_win *new_win = NULL;
8651679e8daSAlexandre Bounine int new_win_idx = -1;
8661679e8daSAlexandre Bounine int i = 0;
8671679e8daSAlexandre Bounine
8681679e8daSAlexandre Bounine bar_base = pbar->base;
8691679e8daSAlexandre Bounine bar_end = bar_base + pbar->size;
8701679e8daSAlexandre Bounine win_base = bar_base;
8711679e8daSAlexandre Bounine align = size/TSI721_PC2SR_ZONES;
8721679e8daSAlexandre Bounine
8731679e8daSAlexandre Bounine while (i < TSI721_IBWIN_NUM) {
8741679e8daSAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) {
8751679e8daSAlexandre Bounine if (!priv->ob_win[i].active) {
8761679e8daSAlexandre Bounine if (new_win == NULL) {
8771679e8daSAlexandre Bounine new_win = &priv->ob_win[i];
8781679e8daSAlexandre Bounine new_win_idx = i;
8791679e8daSAlexandre Bounine }
8801679e8daSAlexandre Bounine continue;
8811679e8daSAlexandre Bounine }
8821679e8daSAlexandre Bounine
8831679e8daSAlexandre Bounine /*
8841679e8daSAlexandre Bounine * If this window belongs to the current BAR check it
8851679e8daSAlexandre Bounine * for overlap
8861679e8daSAlexandre Bounine */
8871679e8daSAlexandre Bounine win = &priv->ob_win[i];
8881679e8daSAlexandre Bounine
8891679e8daSAlexandre Bounine if (win->base >= bar_base && win->base < bar_end) {
8901679e8daSAlexandre Bounine if (win_base < (win->base + win->size) &&
8911679e8daSAlexandre Bounine (win_base + size) > win->base) {
8921679e8daSAlexandre Bounine /* Overlap detected */
8931679e8daSAlexandre Bounine win_base = win->base + win->size;
8941679e8daSAlexandre Bounine win_base = ALIGN(win_base, align);
8951679e8daSAlexandre Bounine break;
8961679e8daSAlexandre Bounine }
8971679e8daSAlexandre Bounine }
8981679e8daSAlexandre Bounine }
8991679e8daSAlexandre Bounine }
9001679e8daSAlexandre Bounine
9011679e8daSAlexandre Bounine if (win_base + size > bar_end)
9021679e8daSAlexandre Bounine return -ENOMEM;
9031679e8daSAlexandre Bounine
9041679e8daSAlexandre Bounine if (!new_win) {
90572d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev, "OBW count tracking failed");
9061679e8daSAlexandre Bounine return -EIO;
9071679e8daSAlexandre Bounine }
9081679e8daSAlexandre Bounine
9091679e8daSAlexandre Bounine new_win->active = true;
9101679e8daSAlexandre Bounine new_win->base = win_base;
9111679e8daSAlexandre Bounine new_win->size = size;
9121679e8daSAlexandre Bounine new_win->pbar = pbar;
9131679e8daSAlexandre Bounine priv->obwin_cnt--;
9141679e8daSAlexandre Bounine pbar->free -= size;
9151679e8daSAlexandre Bounine *win_id = new_win_idx;
9161679e8daSAlexandre Bounine return 0;
9171679e8daSAlexandre Bounine }
9181679e8daSAlexandre Bounine
tsi721_map_outb_win(struct rio_mport * mport,u16 destid,u64 rstart,u32 size,u32 flags,dma_addr_t * laddr)9191679e8daSAlexandre Bounine static int tsi721_map_outb_win(struct rio_mport *mport, u16 destid, u64 rstart,
9201679e8daSAlexandre Bounine u32 size, u32 flags, dma_addr_t *laddr)
9211679e8daSAlexandre Bounine {
9221679e8daSAlexandre Bounine struct tsi721_device *priv = mport->priv;
9231679e8daSAlexandre Bounine int i;
9241679e8daSAlexandre Bounine struct tsi721_obw_bar *pbar;
9251679e8daSAlexandre Bounine struct tsi721_ob_win *ob_win;
9261679e8daSAlexandre Bounine int obw = -1;
9271679e8daSAlexandre Bounine u32 rval;
9281679e8daSAlexandre Bounine u64 rio_addr;
9291679e8daSAlexandre Bounine u32 zsize;
9301679e8daSAlexandre Bounine int ret = -ENOMEM;
9311679e8daSAlexandre Bounine
93272d8a0d2SAlexandre Bounine tsi_debug(OBW, &priv->pdev->dev,
93372d8a0d2SAlexandre Bounine "did=%d ra=0x%llx sz=0x%x", destid, rstart, size);
93472d8a0d2SAlexandre Bounine
9351679e8daSAlexandre Bounine if (!is_power_of_2(size) || (size < 0x8000) || (rstart & (size - 1)))
9361679e8daSAlexandre Bounine return -EINVAL;
9371679e8daSAlexandre Bounine
9381679e8daSAlexandre Bounine if (priv->obwin_cnt == 0)
9391679e8daSAlexandre Bounine return -EBUSY;
9401679e8daSAlexandre Bounine
9411679e8daSAlexandre Bounine for (i = 0; i < 2; i++) {
9421679e8daSAlexandre Bounine if (priv->p2r_bar[i].free >= size) {
9431679e8daSAlexandre Bounine pbar = &priv->p2r_bar[i];
9441679e8daSAlexandre Bounine ret = tsi721_obw_alloc(priv, pbar, size, &obw);
9451679e8daSAlexandre Bounine if (!ret)
9461679e8daSAlexandre Bounine break;
9471679e8daSAlexandre Bounine }
9481679e8daSAlexandre Bounine }
9491679e8daSAlexandre Bounine
9501679e8daSAlexandre Bounine if (ret)
9511679e8daSAlexandre Bounine return ret;
9521679e8daSAlexandre Bounine
9531679e8daSAlexandre Bounine WARN_ON(obw == -1);
9541679e8daSAlexandre Bounine ob_win = &priv->ob_win[obw];
9551679e8daSAlexandre Bounine ob_win->destid = destid;
9561679e8daSAlexandre Bounine ob_win->rstart = rstart;
95772d8a0d2SAlexandre Bounine tsi_debug(OBW, &priv->pdev->dev,
95872d8a0d2SAlexandre Bounine "allocated OBW%d @%llx", obw, ob_win->base);
9591679e8daSAlexandre Bounine
9601679e8daSAlexandre Bounine /*
9611679e8daSAlexandre Bounine * Configure Outbound Window
9621679e8daSAlexandre Bounine */
9631679e8daSAlexandre Bounine
9641679e8daSAlexandre Bounine zsize = size/TSI721_PC2SR_ZONES;
9651679e8daSAlexandre Bounine rio_addr = rstart;
9661679e8daSAlexandre Bounine
9671679e8daSAlexandre Bounine /*
9681679e8daSAlexandre Bounine * Program Address Translation Zones:
9691679e8daSAlexandre Bounine * This implementation uses all 8 zones associated wit window.
9701679e8daSAlexandre Bounine */
9711679e8daSAlexandre Bounine for (i = 0; i < TSI721_PC2SR_ZONES; i++) {
9721679e8daSAlexandre Bounine
9731679e8daSAlexandre Bounine while (ioread32(priv->regs + TSI721_ZONE_SEL) &
9741679e8daSAlexandre Bounine TSI721_ZONE_SEL_GO) {
9751679e8daSAlexandre Bounine udelay(1);
9761679e8daSAlexandre Bounine }
9771679e8daSAlexandre Bounine
9781679e8daSAlexandre Bounine rval = (u32)(rio_addr & TSI721_LUT_DATA0_ADD) |
9791679e8daSAlexandre Bounine TSI721_LUT_DATA0_NREAD | TSI721_LUT_DATA0_NWR;
9801679e8daSAlexandre Bounine iowrite32(rval, priv->regs + TSI721_LUT_DATA0);
9811679e8daSAlexandre Bounine rval = (u32)(rio_addr >> 32);
9821679e8daSAlexandre Bounine iowrite32(rval, priv->regs + TSI721_LUT_DATA1);
9831679e8daSAlexandre Bounine rval = destid;
9841679e8daSAlexandre Bounine iowrite32(rval, priv->regs + TSI721_LUT_DATA2);
9851679e8daSAlexandre Bounine
9861679e8daSAlexandre Bounine rval = TSI721_ZONE_SEL_GO | (obw << 3) | i;
9871679e8daSAlexandre Bounine iowrite32(rval, priv->regs + TSI721_ZONE_SEL);
9881679e8daSAlexandre Bounine
9891679e8daSAlexandre Bounine rio_addr += zsize;
9901679e8daSAlexandre Bounine }
9911679e8daSAlexandre Bounine
9921679e8daSAlexandre Bounine iowrite32(TSI721_OBWIN_SIZE(size) << 8,
9931679e8daSAlexandre Bounine priv->regs + TSI721_OBWINSZ(obw));
9941679e8daSAlexandre Bounine iowrite32((u32)(ob_win->base >> 32), priv->regs + TSI721_OBWINUB(obw));
9951679e8daSAlexandre Bounine iowrite32((u32)(ob_win->base & TSI721_OBWINLB_BA) | TSI721_OBWINLB_WEN,
9961679e8daSAlexandre Bounine priv->regs + TSI721_OBWINLB(obw));
9971679e8daSAlexandre Bounine
9981679e8daSAlexandre Bounine *laddr = ob_win->base;
9991679e8daSAlexandre Bounine return 0;
10001679e8daSAlexandre Bounine }
10011679e8daSAlexandre Bounine
tsi721_unmap_outb_win(struct rio_mport * mport,u16 destid,u64 rstart)10021679e8daSAlexandre Bounine static void tsi721_unmap_outb_win(struct rio_mport *mport,
10031679e8daSAlexandre Bounine u16 destid, u64 rstart)
10041679e8daSAlexandre Bounine {
10051679e8daSAlexandre Bounine struct tsi721_device *priv = mport->priv;
10061679e8daSAlexandre Bounine struct tsi721_ob_win *ob_win;
10071679e8daSAlexandre Bounine int i;
10081679e8daSAlexandre Bounine
100972d8a0d2SAlexandre Bounine tsi_debug(OBW, &priv->pdev->dev, "did=%d ra=0x%llx", destid, rstart);
101072d8a0d2SAlexandre Bounine
10111679e8daSAlexandre Bounine for (i = 0; i < TSI721_OBWIN_NUM; i++) {
10121679e8daSAlexandre Bounine ob_win = &priv->ob_win[i];
10131679e8daSAlexandre Bounine
10141679e8daSAlexandre Bounine if (ob_win->active &&
10151679e8daSAlexandre Bounine ob_win->destid == destid && ob_win->rstart == rstart) {
101672d8a0d2SAlexandre Bounine tsi_debug(OBW, &priv->pdev->dev,
101772d8a0d2SAlexandre Bounine "free OBW%d @%llx", i, ob_win->base);
10181679e8daSAlexandre Bounine ob_win->active = false;
10191679e8daSAlexandre Bounine iowrite32(0, priv->regs + TSI721_OBWINLB(i));
10201679e8daSAlexandre Bounine ob_win->pbar->free += ob_win->size;
10211679e8daSAlexandre Bounine priv->obwin_cnt++;
10221679e8daSAlexandre Bounine break;
10231679e8daSAlexandre Bounine }
10241679e8daSAlexandre Bounine }
10251679e8daSAlexandre Bounine }
10261679e8daSAlexandre Bounine
102748618fb4SAlexandre Bounine /**
102848618fb4SAlexandre Bounine * tsi721_init_pc2sr_mapping - initializes outbound (PCIe->SRIO)
102948618fb4SAlexandre Bounine * translation regions.
103048618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data
103148618fb4SAlexandre Bounine *
103248618fb4SAlexandre Bounine * Disables SREP translation regions.
103348618fb4SAlexandre Bounine */
tsi721_init_pc2sr_mapping(struct tsi721_device * priv)103448618fb4SAlexandre Bounine static void tsi721_init_pc2sr_mapping(struct tsi721_device *priv)
103548618fb4SAlexandre Bounine {
10361679e8daSAlexandre Bounine int i, z;
10371679e8daSAlexandre Bounine u32 rval;
103848618fb4SAlexandre Bounine
103948618fb4SAlexandre Bounine /* Disable all PC2SR translation windows */
104048618fb4SAlexandre Bounine for (i = 0; i < TSI721_OBWIN_NUM; i++)
104148618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_OBWINLB(i));
10421679e8daSAlexandre Bounine
10431679e8daSAlexandre Bounine /* Initialize zone lookup tables to avoid ECC errors on reads */
10441679e8daSAlexandre Bounine iowrite32(0, priv->regs + TSI721_LUT_DATA0);
10451679e8daSAlexandre Bounine iowrite32(0, priv->regs + TSI721_LUT_DATA1);
10461679e8daSAlexandre Bounine iowrite32(0, priv->regs + TSI721_LUT_DATA2);
10471679e8daSAlexandre Bounine
10481679e8daSAlexandre Bounine for (i = 0; i < TSI721_OBWIN_NUM; i++) {
10491679e8daSAlexandre Bounine for (z = 0; z < TSI721_PC2SR_ZONES; z++) {
10501679e8daSAlexandre Bounine while (ioread32(priv->regs + TSI721_ZONE_SEL) &
10511679e8daSAlexandre Bounine TSI721_ZONE_SEL_GO) {
10521679e8daSAlexandre Bounine udelay(1);
10531679e8daSAlexandre Bounine }
10541679e8daSAlexandre Bounine rval = TSI721_ZONE_SEL_GO | (i << 3) | z;
10551679e8daSAlexandre Bounine iowrite32(rval, priv->regs + TSI721_ZONE_SEL);
10561679e8daSAlexandre Bounine }
10571679e8daSAlexandre Bounine }
10581679e8daSAlexandre Bounine
10591679e8daSAlexandre Bounine if (priv->p2r_bar[0].size == 0 && priv->p2r_bar[1].size == 0) {
10601679e8daSAlexandre Bounine priv->obwin_cnt = 0;
10611679e8daSAlexandre Bounine return;
10621679e8daSAlexandre Bounine }
10631679e8daSAlexandre Bounine
10641679e8daSAlexandre Bounine priv->p2r_bar[0].free = priv->p2r_bar[0].size;
10651679e8daSAlexandre Bounine priv->p2r_bar[1].free = priv->p2r_bar[1].size;
10661679e8daSAlexandre Bounine
10671679e8daSAlexandre Bounine for (i = 0; i < TSI721_OBWIN_NUM; i++)
10681679e8daSAlexandre Bounine priv->ob_win[i].active = false;
10691679e8daSAlexandre Bounine
10701679e8daSAlexandre Bounine priv->obwin_cnt = TSI721_OBWIN_NUM;
107148618fb4SAlexandre Bounine }
107248618fb4SAlexandre Bounine
107348618fb4SAlexandre Bounine /**
107471afe341SAlexandre Bounine * tsi721_rio_map_inb_mem -- Mapping inbound memory region.
107571afe341SAlexandre Bounine * @mport: RapidIO master port
107671afe341SAlexandre Bounine * @lstart: Local memory space start address.
107771afe341SAlexandre Bounine * @rstart: RapidIO space start address.
107871afe341SAlexandre Bounine * @size: The mapping region size.
107971afe341SAlexandre Bounine * @flags: Flags for mapping. 0 for using default flags.
108071afe341SAlexandre Bounine *
108171afe341SAlexandre Bounine * Return: 0 -- Success.
108271afe341SAlexandre Bounine *
108371afe341SAlexandre Bounine * This function will create the inbound mapping
108471afe341SAlexandre Bounine * from rstart to lstart.
108571afe341SAlexandre Bounine */
tsi721_rio_map_inb_mem(struct rio_mport * mport,dma_addr_t lstart,u64 rstart,u64 size,u32 flags)108671afe341SAlexandre Bounine static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
1087a057a52eSAlexandre Bounine u64 rstart, u64 size, u32 flags)
108871afe341SAlexandre Bounine {
108971afe341SAlexandre Bounine struct tsi721_device *priv = mport->priv;
1090ba5d141bSAlexandre Bounine int i, avail = -1;
109171afe341SAlexandre Bounine u32 regval;
1092ba5d141bSAlexandre Bounine struct tsi721_ib_win *ib_win;
10939673b883SAlexandre Bounine bool direct = (lstart == rstart);
10949673b883SAlexandre Bounine u64 ibw_size;
10959673b883SAlexandre Bounine dma_addr_t loc_start;
10969673b883SAlexandre Bounine u64 ibw_start;
10979673b883SAlexandre Bounine struct tsi721_ib_win_mapping *map = NULL;
1098ba5d141bSAlexandre Bounine int ret = -EBUSY;
109971afe341SAlexandre Bounine
1100a057a52eSAlexandre Bounine /* Max IBW size supported by HW is 16GB */
1101a057a52eSAlexandre Bounine if (size > 0x400000000UL)
1102a057a52eSAlexandre Bounine return -EINVAL;
1103a057a52eSAlexandre Bounine
11049673b883SAlexandre Bounine if (direct) {
11059673b883SAlexandre Bounine /* Calculate minimal acceptable window size and base address */
11069673b883SAlexandre Bounine
11079673b883SAlexandre Bounine ibw_size = roundup_pow_of_two(size);
11089673b883SAlexandre Bounine ibw_start = lstart & ~(ibw_size - 1);
11099673b883SAlexandre Bounine
111072d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev,
1111a057a52eSAlexandre Bounine "Direct (RIO_0x%llx -> PCIe_%pad), size=0x%llx, ibw_start = 0x%llx",
111272d8a0d2SAlexandre Bounine rstart, &lstart, size, ibw_start);
111372d8a0d2SAlexandre Bounine
11149673b883SAlexandre Bounine while ((lstart + size) > (ibw_start + ibw_size)) {
11159673b883SAlexandre Bounine ibw_size *= 2;
11169673b883SAlexandre Bounine ibw_start = lstart & ~(ibw_size - 1);
1117a057a52eSAlexandre Bounine /* Check for crossing IBW max size 16GB */
1118a057a52eSAlexandre Bounine if (ibw_size > 0x400000000UL)
11199673b883SAlexandre Bounine return -EBUSY;
11209673b883SAlexandre Bounine }
11219673b883SAlexandre Bounine
11229673b883SAlexandre Bounine loc_start = ibw_start;
11239673b883SAlexandre Bounine
11249673b883SAlexandre Bounine map = kzalloc(sizeof(struct tsi721_ib_win_mapping), GFP_ATOMIC);
11259673b883SAlexandre Bounine if (map == NULL)
11269673b883SAlexandre Bounine return -ENOMEM;
11279673b883SAlexandre Bounine
11289673b883SAlexandre Bounine } else {
112972d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev,
1130a057a52eSAlexandre Bounine "Translated (RIO_0x%llx -> PCIe_%pad), size=0x%llx",
11319673b883SAlexandre Bounine rstart, &lstart, size);
11329673b883SAlexandre Bounine
113371afe341SAlexandre Bounine if (!is_power_of_2(size) || size < 0x1000 ||
113471afe341SAlexandre Bounine ((u64)lstart & (size - 1)) || (rstart & (size - 1)))
113571afe341SAlexandre Bounine return -EINVAL;
11369673b883SAlexandre Bounine if (priv->ibwin_cnt == 0)
11379673b883SAlexandre Bounine return -EBUSY;
11389673b883SAlexandre Bounine ibw_start = rstart;
11399673b883SAlexandre Bounine ibw_size = size;
11409673b883SAlexandre Bounine loc_start = lstart;
11419673b883SAlexandre Bounine }
114271afe341SAlexandre Bounine
1143ba5d141bSAlexandre Bounine /*
1144ba5d141bSAlexandre Bounine * Scan for overlapping with active regions and mark the first available
1145ba5d141bSAlexandre Bounine * IB window at the same time.
1146ba5d141bSAlexandre Bounine */
114771afe341SAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) {
1148ba5d141bSAlexandre Bounine ib_win = &priv->ib_win[i];
11499673b883SAlexandre Bounine
1150ba5d141bSAlexandre Bounine if (!ib_win->active) {
1151ba5d141bSAlexandre Bounine if (avail == -1) {
1152ba5d141bSAlexandre Bounine avail = i;
1153ba5d141bSAlexandre Bounine ret = 0;
1154ba5d141bSAlexandre Bounine }
11559673b883SAlexandre Bounine } else if (ibw_start < (ib_win->rstart + ib_win->size) &&
11569673b883SAlexandre Bounine (ibw_start + ibw_size) > ib_win->rstart) {
11579673b883SAlexandre Bounine /* Return error if address translation involved */
1158b3006929SAlexandre Bounine if (!direct || ib_win->xlat) {
11599673b883SAlexandre Bounine ret = -EFAULT;
11609673b883SAlexandre Bounine break;
11619673b883SAlexandre Bounine }
11629673b883SAlexandre Bounine
11639673b883SAlexandre Bounine /*
11649673b883SAlexandre Bounine * Direct mappings usually are larger than originally
11659673b883SAlexandre Bounine * requested fragments - check if this new request fits
11669673b883SAlexandre Bounine * into it.
11679673b883SAlexandre Bounine */
11689673b883SAlexandre Bounine if (rstart >= ib_win->rstart &&
11699673b883SAlexandre Bounine (rstart + size) <= (ib_win->rstart +
11709673b883SAlexandre Bounine ib_win->size)) {
11719673b883SAlexandre Bounine /* We are in - no further mapping required */
11729673b883SAlexandre Bounine map->lstart = lstart;
11739673b883SAlexandre Bounine list_add_tail(&map->node, &ib_win->mappings);
11749673b883SAlexandre Bounine return 0;
11759673b883SAlexandre Bounine }
11769673b883SAlexandre Bounine
1177ba5d141bSAlexandre Bounine ret = -EFAULT;
117871afe341SAlexandre Bounine break;
117971afe341SAlexandre Bounine }
118071afe341SAlexandre Bounine }
118171afe341SAlexandre Bounine
1182ba5d141bSAlexandre Bounine if (ret)
11839673b883SAlexandre Bounine goto out;
1184ba5d141bSAlexandre Bounine i = avail;
1185ba5d141bSAlexandre Bounine
1186ba5d141bSAlexandre Bounine /* Sanity check: available IB window must be disabled at this point */
1187ba5d141bSAlexandre Bounine regval = ioread32(priv->regs + TSI721_IBWIN_LB(i));
1188ba5d141bSAlexandre Bounine if (WARN_ON(regval & TSI721_IBWIN_LB_WEN)) {
1189ba5d141bSAlexandre Bounine ret = -EIO;
11909673b883SAlexandre Bounine goto out;
1191ba5d141bSAlexandre Bounine }
1192ba5d141bSAlexandre Bounine
1193ba5d141bSAlexandre Bounine ib_win = &priv->ib_win[i];
1194ba5d141bSAlexandre Bounine ib_win->active = true;
11959673b883SAlexandre Bounine ib_win->rstart = ibw_start;
11969673b883SAlexandre Bounine ib_win->lstart = loc_start;
11979673b883SAlexandre Bounine ib_win->size = ibw_size;
11989673b883SAlexandre Bounine ib_win->xlat = (lstart != rstart);
11999673b883SAlexandre Bounine INIT_LIST_HEAD(&ib_win->mappings);
1200ba5d141bSAlexandre Bounine
12019673b883SAlexandre Bounine /*
12029673b883SAlexandre Bounine * When using direct IBW mapping and have larger than requested IBW size
12039673b883SAlexandre Bounine * we can have multiple local memory blocks mapped through the same IBW
12049673b883SAlexandre Bounine * To handle this situation we maintain list of "clients" for such IBWs.
12059673b883SAlexandre Bounine */
12069673b883SAlexandre Bounine if (direct) {
12079673b883SAlexandre Bounine map->lstart = lstart;
12089673b883SAlexandre Bounine list_add_tail(&map->node, &ib_win->mappings);
12099673b883SAlexandre Bounine }
12109673b883SAlexandre Bounine
12119673b883SAlexandre Bounine iowrite32(TSI721_IBWIN_SIZE(ibw_size) << 8,
121271afe341SAlexandre Bounine priv->regs + TSI721_IBWIN_SZ(i));
121371afe341SAlexandre Bounine
12149673b883SAlexandre Bounine iowrite32(((u64)loc_start >> 32), priv->regs + TSI721_IBWIN_TUA(i));
12159673b883SAlexandre Bounine iowrite32(((u64)loc_start & TSI721_IBWIN_TLA_ADD),
121671afe341SAlexandre Bounine priv->regs + TSI721_IBWIN_TLA(i));
121771afe341SAlexandre Bounine
12189673b883SAlexandre Bounine iowrite32(ibw_start >> 32, priv->regs + TSI721_IBWIN_UB(i));
12199673b883SAlexandre Bounine iowrite32((ibw_start & TSI721_IBWIN_LB_BA) | TSI721_IBWIN_LB_WEN,
122071afe341SAlexandre Bounine priv->regs + TSI721_IBWIN_LB(i));
12219673b883SAlexandre Bounine
12229673b883SAlexandre Bounine priv->ibwin_cnt--;
12239673b883SAlexandre Bounine
122472d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev,
1225ea87b8e1SJoe Perches "Configured IBWIN%d (RIO_0x%llx -> PCIe_%pad), size=0x%llx",
122672d8a0d2SAlexandre Bounine i, ibw_start, &loc_start, ibw_size);
122771afe341SAlexandre Bounine
122871afe341SAlexandre Bounine return 0;
12299673b883SAlexandre Bounine out:
12309673b883SAlexandre Bounine kfree(map);
1231ba5d141bSAlexandre Bounine return ret;
123271afe341SAlexandre Bounine }
123371afe341SAlexandre Bounine
123471afe341SAlexandre Bounine /**
12359673b883SAlexandre Bounine * tsi721_rio_unmap_inb_mem -- Unmapping inbound memory region.
123671afe341SAlexandre Bounine * @mport: RapidIO master port
123771afe341SAlexandre Bounine * @lstart: Local memory space start address.
123871afe341SAlexandre Bounine */
tsi721_rio_unmap_inb_mem(struct rio_mport * mport,dma_addr_t lstart)123971afe341SAlexandre Bounine static void tsi721_rio_unmap_inb_mem(struct rio_mport *mport,
124071afe341SAlexandre Bounine dma_addr_t lstart)
124171afe341SAlexandre Bounine {
124271afe341SAlexandre Bounine struct tsi721_device *priv = mport->priv;
1243ba5d141bSAlexandre Bounine struct tsi721_ib_win *ib_win;
124471afe341SAlexandre Bounine int i;
124571afe341SAlexandre Bounine
124672d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev,
1247ea87b8e1SJoe Perches "Unmap IBW mapped to PCIe_%pad", &lstart);
12489673b883SAlexandre Bounine
124971afe341SAlexandre Bounine /* Search for matching active inbound translation window */
125071afe341SAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) {
1251ba5d141bSAlexandre Bounine ib_win = &priv->ib_win[i];
12529673b883SAlexandre Bounine
12539673b883SAlexandre Bounine /* Address translating IBWs must to be an exact march */
12549673b883SAlexandre Bounine if (!ib_win->active ||
12559673b883SAlexandre Bounine (ib_win->xlat && lstart != ib_win->lstart))
12569673b883SAlexandre Bounine continue;
12579673b883SAlexandre Bounine
12589673b883SAlexandre Bounine if (lstart >= ib_win->lstart &&
12599673b883SAlexandre Bounine lstart < (ib_win->lstart + ib_win->size)) {
12609673b883SAlexandre Bounine
12619673b883SAlexandre Bounine if (!ib_win->xlat) {
12629673b883SAlexandre Bounine struct tsi721_ib_win_mapping *map;
12639673b883SAlexandre Bounine int found = 0;
12649673b883SAlexandre Bounine
12659673b883SAlexandre Bounine list_for_each_entry(map,
12669673b883SAlexandre Bounine &ib_win->mappings, node) {
12679673b883SAlexandre Bounine if (map->lstart == lstart) {
12689673b883SAlexandre Bounine list_del(&map->node);
12699673b883SAlexandre Bounine kfree(map);
12709673b883SAlexandre Bounine found = 1;
127171afe341SAlexandre Bounine break;
127271afe341SAlexandre Bounine }
127371afe341SAlexandre Bounine }
12749673b883SAlexandre Bounine
12759673b883SAlexandre Bounine if (!found)
12769673b883SAlexandre Bounine continue;
12779673b883SAlexandre Bounine
12789673b883SAlexandre Bounine if (!list_empty(&ib_win->mappings))
12799673b883SAlexandre Bounine break;
12809673b883SAlexandre Bounine }
12819673b883SAlexandre Bounine
128272d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev, "Disable IBWIN_%d", i);
12839673b883SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBWIN_LB(i));
12849673b883SAlexandre Bounine ib_win->active = false;
12859673b883SAlexandre Bounine priv->ibwin_cnt++;
12869673b883SAlexandre Bounine break;
12879673b883SAlexandre Bounine }
12889673b883SAlexandre Bounine }
1289ba5d141bSAlexandre Bounine
1290ba5d141bSAlexandre Bounine if (i == TSI721_IBWIN_NUM)
129172d8a0d2SAlexandre Bounine tsi_debug(IBW, &priv->pdev->dev,
12929673b883SAlexandre Bounine "IB window mapped to %pad not found", &lstart);
129371afe341SAlexandre Bounine }
129471afe341SAlexandre Bounine
129571afe341SAlexandre Bounine /**
129648618fb4SAlexandre Bounine * tsi721_init_sr2pc_mapping - initializes inbound (SRIO->PCIe)
129748618fb4SAlexandre Bounine * translation regions.
129848618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data
129948618fb4SAlexandre Bounine *
130048618fb4SAlexandre Bounine * Disables inbound windows.
130148618fb4SAlexandre Bounine */
tsi721_init_sr2pc_mapping(struct tsi721_device * priv)130248618fb4SAlexandre Bounine static void tsi721_init_sr2pc_mapping(struct tsi721_device *priv)
130348618fb4SAlexandre Bounine {
130448618fb4SAlexandre Bounine int i;
130548618fb4SAlexandre Bounine
130648618fb4SAlexandre Bounine /* Disable all SR2PC inbound windows */
130748618fb4SAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++)
130871afe341SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBWIN_LB(i));
13099673b883SAlexandre Bounine priv->ibwin_cnt = TSI721_IBWIN_NUM;
131048618fb4SAlexandre Bounine }
131148618fb4SAlexandre Bounine
1312748353ccSAlexandre Bounine /*
1313748353ccSAlexandre Bounine * tsi721_close_sr2pc_mapping - closes all active inbound (SRIO->PCIe)
1314748353ccSAlexandre Bounine * translation regions.
1315748353ccSAlexandre Bounine * @priv: pointer to tsi721 device private data
1316748353ccSAlexandre Bounine */
tsi721_close_sr2pc_mapping(struct tsi721_device * priv)1317748353ccSAlexandre Bounine static void tsi721_close_sr2pc_mapping(struct tsi721_device *priv)
1318748353ccSAlexandre Bounine {
1319748353ccSAlexandre Bounine struct tsi721_ib_win *ib_win;
1320748353ccSAlexandre Bounine int i;
1321748353ccSAlexandre Bounine
1322748353ccSAlexandre Bounine /* Disable all active SR2PC inbound windows */
1323748353ccSAlexandre Bounine for (i = 0; i < TSI721_IBWIN_NUM; i++) {
1324748353ccSAlexandre Bounine ib_win = &priv->ib_win[i];
1325748353ccSAlexandre Bounine if (ib_win->active) {
1326748353ccSAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBWIN_LB(i));
1327748353ccSAlexandre Bounine ib_win->active = false;
1328748353ccSAlexandre Bounine }
1329748353ccSAlexandre Bounine }
1330748353ccSAlexandre Bounine }
1331748353ccSAlexandre Bounine
133248618fb4SAlexandre Bounine /**
133348618fb4SAlexandre Bounine * tsi721_port_write_init - Inbound port write interface init
133448618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data
133548618fb4SAlexandre Bounine *
133648618fb4SAlexandre Bounine * Initializes inbound port write handler.
133748618fb4SAlexandre Bounine * Returns %0 on success or %-ENOMEM on failure.
133848618fb4SAlexandre Bounine */
tsi721_port_write_init(struct tsi721_device * priv)133948618fb4SAlexandre Bounine static int tsi721_port_write_init(struct tsi721_device *priv)
134048618fb4SAlexandre Bounine {
134148618fb4SAlexandre Bounine priv->pw_discard_count = 0;
134248618fb4SAlexandre Bounine INIT_WORK(&priv->pw_work, tsi721_pw_dpc);
134348618fb4SAlexandre Bounine spin_lock_init(&priv->pw_fifo_lock);
134448618fb4SAlexandre Bounine if (kfifo_alloc(&priv->pw_fifo,
134548618fb4SAlexandre Bounine TSI721_RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
134672d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev, "PW FIFO allocation failed");
134748618fb4SAlexandre Bounine return -ENOMEM;
134848618fb4SAlexandre Bounine }
134948618fb4SAlexandre Bounine
135048618fb4SAlexandre Bounine /* Use reliable port-write capture mode */
135148618fb4SAlexandre Bounine iowrite32(TSI721_RIO_PW_CTL_PWC_REL, priv->regs + TSI721_RIO_PW_CTL);
135248618fb4SAlexandre Bounine return 0;
135348618fb4SAlexandre Bounine }
135448618fb4SAlexandre Bounine
tsi721_port_write_free(struct tsi721_device * priv)1355748353ccSAlexandre Bounine static void tsi721_port_write_free(struct tsi721_device *priv)
1356748353ccSAlexandre Bounine {
1357748353ccSAlexandre Bounine kfifo_free(&priv->pw_fifo);
1358748353ccSAlexandre Bounine }
1359748353ccSAlexandre Bounine
tsi721_doorbell_init(struct tsi721_device * priv)136048618fb4SAlexandre Bounine static int tsi721_doorbell_init(struct tsi721_device *priv)
136148618fb4SAlexandre Bounine {
136248618fb4SAlexandre Bounine /* Outbound Doorbells do not require any setup.
136348618fb4SAlexandre Bounine * Tsi721 uses dedicated PCI BAR1 to generate doorbells.
136448618fb4SAlexandre Bounine * That BAR1 was mapped during the probe routine.
136548618fb4SAlexandre Bounine */
136648618fb4SAlexandre Bounine
136748618fb4SAlexandre Bounine /* Initialize Inbound Doorbell processing DPC and queue */
136848618fb4SAlexandre Bounine priv->db_discard_count = 0;
136948618fb4SAlexandre Bounine INIT_WORK(&priv->idb_work, tsi721_db_dpc);
137048618fb4SAlexandre Bounine
137148618fb4SAlexandre Bounine /* Allocate buffer for inbound doorbells queue */
1372750afb08SLuis Chamberlain priv->idb_base = dma_alloc_coherent(&priv->pdev->dev,
137348618fb4SAlexandre Bounine IDB_QSIZE * TSI721_IDB_ENTRY_SIZE,
137448618fb4SAlexandre Bounine &priv->idb_dma, GFP_KERNEL);
137548618fb4SAlexandre Bounine if (!priv->idb_base)
137648618fb4SAlexandre Bounine return -ENOMEM;
137748618fb4SAlexandre Bounine
137872d8a0d2SAlexandre Bounine tsi_debug(DBELL, &priv->pdev->dev,
137972d8a0d2SAlexandre Bounine "Allocated IDB buffer @ %p (phys = %pad)",
138072d8a0d2SAlexandre Bounine priv->idb_base, &priv->idb_dma);
138148618fb4SAlexandre Bounine
138248618fb4SAlexandre Bounine iowrite32(TSI721_IDQ_SIZE_VAL(IDB_QSIZE),
138348618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_SIZE(IDB_QUEUE));
138448618fb4SAlexandre Bounine iowrite32(((u64)priv->idb_dma >> 32),
138548618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_BASEU(IDB_QUEUE));
138648618fb4SAlexandre Bounine iowrite32(((u64)priv->idb_dma & TSI721_IDQ_BASEL_ADDR),
138748618fb4SAlexandre Bounine priv->regs + TSI721_IDQ_BASEL(IDB_QUEUE));
138848618fb4SAlexandre Bounine /* Enable accepting all inbound doorbells */
138948618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IDQ_MASK(IDB_QUEUE));
139048618fb4SAlexandre Bounine
139148618fb4SAlexandre Bounine iowrite32(TSI721_IDQ_INIT, priv->regs + TSI721_IDQ_CTL(IDB_QUEUE));
139248618fb4SAlexandre Bounine
139348618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IDQ_RP(IDB_QUEUE));
139448618fb4SAlexandre Bounine
139548618fb4SAlexandre Bounine return 0;
139648618fb4SAlexandre Bounine }
139748618fb4SAlexandre Bounine
tsi721_doorbell_free(struct tsi721_device * priv)139848618fb4SAlexandre Bounine static void tsi721_doorbell_free(struct tsi721_device *priv)
139948618fb4SAlexandre Bounine {
140048618fb4SAlexandre Bounine if (priv->idb_base == NULL)
140148618fb4SAlexandre Bounine return;
140248618fb4SAlexandre Bounine
140348618fb4SAlexandre Bounine /* Free buffer allocated for inbound doorbell queue */
140448618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev, IDB_QSIZE * TSI721_IDB_ENTRY_SIZE,
140548618fb4SAlexandre Bounine priv->idb_base, priv->idb_dma);
140648618fb4SAlexandre Bounine priv->idb_base = NULL;
140748618fb4SAlexandre Bounine }
140848618fb4SAlexandre Bounine
14099eaa3d9bSAlexandre Bounine /**
14109eaa3d9bSAlexandre Bounine * tsi721_bdma_maint_init - Initialize maintenance request BDMA channel.
14119eaa3d9bSAlexandre Bounine * @priv: pointer to tsi721 private data
14129eaa3d9bSAlexandre Bounine *
14139eaa3d9bSAlexandre Bounine * Initialize BDMA channel allocated for RapidIO maintenance read/write
14149eaa3d9bSAlexandre Bounine * request generation
14159eaa3d9bSAlexandre Bounine * Returns %0 on success or %-ENOMEM on failure.
14169eaa3d9bSAlexandre Bounine */
tsi721_bdma_maint_init(struct tsi721_device * priv)14179eaa3d9bSAlexandre Bounine static int tsi721_bdma_maint_init(struct tsi721_device *priv)
141848618fb4SAlexandre Bounine {
141948618fb4SAlexandre Bounine struct tsi721_dma_desc *bd_ptr;
142048618fb4SAlexandre Bounine u64 *sts_ptr;
142148618fb4SAlexandre Bounine dma_addr_t bd_phys, sts_phys;
142248618fb4SAlexandre Bounine int sts_size;
14239eaa3d9bSAlexandre Bounine int bd_num = 2;
14249eaa3d9bSAlexandre Bounine void __iomem *regs;
142548618fb4SAlexandre Bounine
142672d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev,
142772d8a0d2SAlexandre Bounine "Init BDMA_%d Maintenance requests", TSI721_DMACH_MAINT);
142848618fb4SAlexandre Bounine
142948618fb4SAlexandre Bounine /*
143048618fb4SAlexandre Bounine * Initialize DMA channel for maintenance requests
143148618fb4SAlexandre Bounine */
143248618fb4SAlexandre Bounine
14339eaa3d9bSAlexandre Bounine priv->mdma.ch_id = TSI721_DMACH_MAINT;
14349eaa3d9bSAlexandre Bounine regs = priv->regs + TSI721_DMAC_BASE(TSI721_DMACH_MAINT);
14359eaa3d9bSAlexandre Bounine
143648618fb4SAlexandre Bounine /* Allocate space for DMA descriptors */
1437750afb08SLuis Chamberlain bd_ptr = dma_alloc_coherent(&priv->pdev->dev,
143848618fb4SAlexandre Bounine bd_num * sizeof(struct tsi721_dma_desc),
143948618fb4SAlexandre Bounine &bd_phys, GFP_KERNEL);
144048618fb4SAlexandre Bounine if (!bd_ptr)
144148618fb4SAlexandre Bounine return -ENOMEM;
144248618fb4SAlexandre Bounine
14439eaa3d9bSAlexandre Bounine priv->mdma.bd_num = bd_num;
14449eaa3d9bSAlexandre Bounine priv->mdma.bd_phys = bd_phys;
14459eaa3d9bSAlexandre Bounine priv->mdma.bd_base = bd_ptr;
144648618fb4SAlexandre Bounine
144772d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev, "DMA descriptors @ %p (phys = %pad)",
144872d8a0d2SAlexandre Bounine bd_ptr, &bd_phys);
144948618fb4SAlexandre Bounine
145048618fb4SAlexandre Bounine /* Allocate space for descriptor status FIFO */
145148618fb4SAlexandre Bounine sts_size = (bd_num >= TSI721_DMA_MINSTSSZ) ?
145248618fb4SAlexandre Bounine bd_num : TSI721_DMA_MINSTSSZ;
145348618fb4SAlexandre Bounine sts_size = roundup_pow_of_two(sts_size);
1454750afb08SLuis Chamberlain sts_ptr = dma_alloc_coherent(&priv->pdev->dev,
145548618fb4SAlexandre Bounine sts_size * sizeof(struct tsi721_dma_sts),
145648618fb4SAlexandre Bounine &sts_phys, GFP_KERNEL);
145748618fb4SAlexandre Bounine if (!sts_ptr) {
145848618fb4SAlexandre Bounine /* Free space allocated for DMA descriptors */
145948618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
146048618fb4SAlexandre Bounine bd_num * sizeof(struct tsi721_dma_desc),
146148618fb4SAlexandre Bounine bd_ptr, bd_phys);
14629eaa3d9bSAlexandre Bounine priv->mdma.bd_base = NULL;
146348618fb4SAlexandre Bounine return -ENOMEM;
146448618fb4SAlexandre Bounine }
146548618fb4SAlexandre Bounine
14669eaa3d9bSAlexandre Bounine priv->mdma.sts_phys = sts_phys;
14679eaa3d9bSAlexandre Bounine priv->mdma.sts_base = sts_ptr;
14689eaa3d9bSAlexandre Bounine priv->mdma.sts_size = sts_size;
146948618fb4SAlexandre Bounine
147072d8a0d2SAlexandre Bounine tsi_debug(MAINT, &priv->pdev->dev,
147172d8a0d2SAlexandre Bounine "desc status FIFO @ %p (phys = %pad) size=0x%x",
147272d8a0d2SAlexandre Bounine sts_ptr, &sts_phys, sts_size);
147348618fb4SAlexandre Bounine
147448618fb4SAlexandre Bounine /* Initialize DMA descriptors ring */
147548618fb4SAlexandre Bounine bd_ptr[bd_num - 1].type_id = cpu_to_le32(DTYPE3 << 29);
147648618fb4SAlexandre Bounine bd_ptr[bd_num - 1].next_lo = cpu_to_le32((u64)bd_phys &
147748618fb4SAlexandre Bounine TSI721_DMAC_DPTRL_MASK);
147848618fb4SAlexandre Bounine bd_ptr[bd_num - 1].next_hi = cpu_to_le32((u64)bd_phys >> 32);
147948618fb4SAlexandre Bounine
148048618fb4SAlexandre Bounine /* Setup DMA descriptor pointers */
14819eaa3d9bSAlexandre Bounine iowrite32(((u64)bd_phys >> 32), regs + TSI721_DMAC_DPTRH);
148248618fb4SAlexandre Bounine iowrite32(((u64)bd_phys & TSI721_DMAC_DPTRL_MASK),
14839eaa3d9bSAlexandre Bounine regs + TSI721_DMAC_DPTRL);
148448618fb4SAlexandre Bounine
148548618fb4SAlexandre Bounine /* Setup descriptor status FIFO */
14869eaa3d9bSAlexandre Bounine iowrite32(((u64)sts_phys >> 32), regs + TSI721_DMAC_DSBH);
148748618fb4SAlexandre Bounine iowrite32(((u64)sts_phys & TSI721_DMAC_DSBL_MASK),
14889eaa3d9bSAlexandre Bounine regs + TSI721_DMAC_DSBL);
148948618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(sts_size),
14909eaa3d9bSAlexandre Bounine regs + TSI721_DMAC_DSSZ);
149148618fb4SAlexandre Bounine
149248618fb4SAlexandre Bounine /* Clear interrupt bits */
14939eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_INT_ALL, regs + TSI721_DMAC_INT);
149448618fb4SAlexandre Bounine
14959eaa3d9bSAlexandre Bounine ioread32(regs + TSI721_DMAC_INT);
149648618fb4SAlexandre Bounine
149748618fb4SAlexandre Bounine /* Toggle DMA channel initialization */
14989eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL);
14999eaa3d9bSAlexandre Bounine ioread32(regs + TSI721_DMAC_CTL);
150048618fb4SAlexandre Bounine udelay(10);
150148618fb4SAlexandre Bounine
150248618fb4SAlexandre Bounine return 0;
150348618fb4SAlexandre Bounine }
150448618fb4SAlexandre Bounine
tsi721_bdma_maint_free(struct tsi721_device * priv)15059eaa3d9bSAlexandre Bounine static int tsi721_bdma_maint_free(struct tsi721_device *priv)
150648618fb4SAlexandre Bounine {
150748618fb4SAlexandre Bounine u32 ch_stat;
15089eaa3d9bSAlexandre Bounine struct tsi721_bdma_maint *mdma = &priv->mdma;
15099eaa3d9bSAlexandre Bounine void __iomem *regs = priv->regs + TSI721_DMAC_BASE(mdma->ch_id);
151048618fb4SAlexandre Bounine
15119eaa3d9bSAlexandre Bounine if (mdma->bd_base == NULL)
151248618fb4SAlexandre Bounine return 0;
151348618fb4SAlexandre Bounine
151448618fb4SAlexandre Bounine /* Check if DMA channel still running */
15159eaa3d9bSAlexandre Bounine ch_stat = ioread32(regs + TSI721_DMAC_STS);
151648618fb4SAlexandre Bounine if (ch_stat & TSI721_DMAC_STS_RUN)
151748618fb4SAlexandre Bounine return -EFAULT;
151848618fb4SAlexandre Bounine
151948618fb4SAlexandre Bounine /* Put DMA channel into init state */
15209eaa3d9bSAlexandre Bounine iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL);
152148618fb4SAlexandre Bounine
152248618fb4SAlexandre Bounine /* Free space allocated for DMA descriptors */
152348618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
15249eaa3d9bSAlexandre Bounine mdma->bd_num * sizeof(struct tsi721_dma_desc),
15259eaa3d9bSAlexandre Bounine mdma->bd_base, mdma->bd_phys);
15269eaa3d9bSAlexandre Bounine mdma->bd_base = NULL;
152748618fb4SAlexandre Bounine
152848618fb4SAlexandre Bounine /* Free space allocated for status FIFO */
152948618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
15309eaa3d9bSAlexandre Bounine mdma->sts_size * sizeof(struct tsi721_dma_sts),
15319eaa3d9bSAlexandre Bounine mdma->sts_base, mdma->sts_phys);
15329eaa3d9bSAlexandre Bounine mdma->sts_base = NULL;
153348618fb4SAlexandre Bounine return 0;
153448618fb4SAlexandre Bounine }
153548618fb4SAlexandre Bounine
153648618fb4SAlexandre Bounine /* Enable Inbound Messaging Interrupts */
153748618fb4SAlexandre Bounine static void
tsi721_imsg_interrupt_enable(struct tsi721_device * priv,int ch,u32 inte_mask)153848618fb4SAlexandre Bounine tsi721_imsg_interrupt_enable(struct tsi721_device *priv, int ch,
153948618fb4SAlexandre Bounine u32 inte_mask)
154048618fb4SAlexandre Bounine {
154148618fb4SAlexandre Bounine u32 rval;
154248618fb4SAlexandre Bounine
154348618fb4SAlexandre Bounine if (!inte_mask)
154448618fb4SAlexandre Bounine return;
154548618fb4SAlexandre Bounine
154648618fb4SAlexandre Bounine /* Clear pending Inbound Messaging interrupts */
154748618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_IBDMAC_INT(ch));
154848618fb4SAlexandre Bounine
154948618fb4SAlexandre Bounine /* Enable Inbound Messaging interrupts */
155048618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_IBDMAC_INTE(ch));
155148618fb4SAlexandre Bounine iowrite32(rval | inte_mask, priv->regs + TSI721_IBDMAC_INTE(ch));
155248618fb4SAlexandre Bounine
155348618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX)
155448618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */
155548618fb4SAlexandre Bounine
155648618fb4SAlexandre Bounine /*
155748618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to enable next levels
155848618fb4SAlexandre Bounine */
155948618fb4SAlexandre Bounine
156048618fb4SAlexandre Bounine /* Enable Device Channel Interrupt */
156148618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
156248618fb4SAlexandre Bounine iowrite32(rval | TSI721_INT_IMSG_CHAN(ch),
156348618fb4SAlexandre Bounine priv->regs + TSI721_DEV_CHAN_INTE);
156448618fb4SAlexandre Bounine }
156548618fb4SAlexandre Bounine
156648618fb4SAlexandre Bounine /* Disable Inbound Messaging Interrupts */
156748618fb4SAlexandre Bounine static void
tsi721_imsg_interrupt_disable(struct tsi721_device * priv,int ch,u32 inte_mask)156848618fb4SAlexandre Bounine tsi721_imsg_interrupt_disable(struct tsi721_device *priv, int ch,
156948618fb4SAlexandre Bounine u32 inte_mask)
157048618fb4SAlexandre Bounine {
157148618fb4SAlexandre Bounine u32 rval;
157248618fb4SAlexandre Bounine
157348618fb4SAlexandre Bounine if (!inte_mask)
157448618fb4SAlexandre Bounine return;
157548618fb4SAlexandre Bounine
157648618fb4SAlexandre Bounine /* Clear pending Inbound Messaging interrupts */
157748618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_IBDMAC_INT(ch));
157848618fb4SAlexandre Bounine
157948618fb4SAlexandre Bounine /* Disable Inbound Messaging interrupts */
158048618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_IBDMAC_INTE(ch));
158148618fb4SAlexandre Bounine rval &= ~inte_mask;
158248618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_IBDMAC_INTE(ch));
158348618fb4SAlexandre Bounine
158448618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX)
158548618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */
158648618fb4SAlexandre Bounine
158748618fb4SAlexandre Bounine /*
158848618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to disable next levels
158948618fb4SAlexandre Bounine */
159048618fb4SAlexandre Bounine
159148618fb4SAlexandre Bounine /* Disable Device Channel Interrupt */
159248618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
159348618fb4SAlexandre Bounine rval &= ~TSI721_INT_IMSG_CHAN(ch);
159448618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_DEV_CHAN_INTE);
159548618fb4SAlexandre Bounine }
159648618fb4SAlexandre Bounine
159748618fb4SAlexandre Bounine /* Enable Outbound Messaging interrupts */
159848618fb4SAlexandre Bounine static void
tsi721_omsg_interrupt_enable(struct tsi721_device * priv,int ch,u32 inte_mask)159948618fb4SAlexandre Bounine tsi721_omsg_interrupt_enable(struct tsi721_device *priv, int ch,
160048618fb4SAlexandre Bounine u32 inte_mask)
160148618fb4SAlexandre Bounine {
160248618fb4SAlexandre Bounine u32 rval;
160348618fb4SAlexandre Bounine
160448618fb4SAlexandre Bounine if (!inte_mask)
160548618fb4SAlexandre Bounine return;
160648618fb4SAlexandre Bounine
160748618fb4SAlexandre Bounine /* Clear pending Outbound Messaging interrupts */
160848618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_OBDMAC_INT(ch));
160948618fb4SAlexandre Bounine
161048618fb4SAlexandre Bounine /* Enable Outbound Messaging channel interrupts */
161148618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_OBDMAC_INTE(ch));
161248618fb4SAlexandre Bounine iowrite32(rval | inte_mask, priv->regs + TSI721_OBDMAC_INTE(ch));
161348618fb4SAlexandre Bounine
161448618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX)
161548618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */
161648618fb4SAlexandre Bounine
161748618fb4SAlexandre Bounine /*
161848618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to enable next levels
161948618fb4SAlexandre Bounine */
162048618fb4SAlexandre Bounine
162148618fb4SAlexandre Bounine /* Enable Device Channel Interrupt */
162248618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
162348618fb4SAlexandre Bounine iowrite32(rval | TSI721_INT_OMSG_CHAN(ch),
162448618fb4SAlexandre Bounine priv->regs + TSI721_DEV_CHAN_INTE);
162548618fb4SAlexandre Bounine }
162648618fb4SAlexandre Bounine
162748618fb4SAlexandre Bounine /* Disable Outbound Messaging interrupts */
162848618fb4SAlexandre Bounine static void
tsi721_omsg_interrupt_disable(struct tsi721_device * priv,int ch,u32 inte_mask)162948618fb4SAlexandre Bounine tsi721_omsg_interrupt_disable(struct tsi721_device *priv, int ch,
163048618fb4SAlexandre Bounine u32 inte_mask)
163148618fb4SAlexandre Bounine {
163248618fb4SAlexandre Bounine u32 rval;
163348618fb4SAlexandre Bounine
163448618fb4SAlexandre Bounine if (!inte_mask)
163548618fb4SAlexandre Bounine return;
163648618fb4SAlexandre Bounine
163748618fb4SAlexandre Bounine /* Clear pending Outbound Messaging interrupts */
163848618fb4SAlexandre Bounine iowrite32(inte_mask, priv->regs + TSI721_OBDMAC_INT(ch));
163948618fb4SAlexandre Bounine
164048618fb4SAlexandre Bounine /* Disable Outbound Messaging interrupts */
164148618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_OBDMAC_INTE(ch));
164248618fb4SAlexandre Bounine rval &= ~inte_mask;
164348618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_OBDMAC_INTE(ch));
164448618fb4SAlexandre Bounine
164548618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX)
164648618fb4SAlexandre Bounine return; /* Finished if we are in MSI-X mode */
164748618fb4SAlexandre Bounine
164848618fb4SAlexandre Bounine /*
164948618fb4SAlexandre Bounine * For MSI and INTA interrupt signalling we need to disable next levels
165048618fb4SAlexandre Bounine */
165148618fb4SAlexandre Bounine
165248618fb4SAlexandre Bounine /* Disable Device Channel Interrupt */
165348618fb4SAlexandre Bounine rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
165448618fb4SAlexandre Bounine rval &= ~TSI721_INT_OMSG_CHAN(ch);
165548618fb4SAlexandre Bounine iowrite32(rval, priv->regs + TSI721_DEV_CHAN_INTE);
165648618fb4SAlexandre Bounine }
165748618fb4SAlexandre Bounine
165848618fb4SAlexandre Bounine /**
165948618fb4SAlexandre Bounine * tsi721_add_outb_message - Add message to the Tsi721 outbound message queue
166048618fb4SAlexandre Bounine * @mport: Master port with outbound message queue
166148618fb4SAlexandre Bounine * @rdev: Target of outbound message
166248618fb4SAlexandre Bounine * @mbox: Outbound mailbox
166348618fb4SAlexandre Bounine * @buffer: Message to add to outbound queue
166448618fb4SAlexandre Bounine * @len: Length of message
166548618fb4SAlexandre Bounine */
166648618fb4SAlexandre Bounine static int
tsi721_add_outb_message(struct rio_mport * mport,struct rio_dev * rdev,int mbox,void * buffer,size_t len)166748618fb4SAlexandre Bounine tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
166848618fb4SAlexandre Bounine void *buffer, size_t len)
166948618fb4SAlexandre Bounine {
167048618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
167148618fb4SAlexandre Bounine struct tsi721_omsg_desc *desc;
167248618fb4SAlexandre Bounine u32 tx_slot;
16732ece1cafSAlexandre Bounine unsigned long flags;
167448618fb4SAlexandre Bounine
167548618fb4SAlexandre Bounine if (!priv->omsg_init[mbox] ||
167648618fb4SAlexandre Bounine len > TSI721_MSG_MAX_SIZE || len < 8)
167748618fb4SAlexandre Bounine return -EINVAL;
167848618fb4SAlexandre Bounine
16792ece1cafSAlexandre Bounine spin_lock_irqsave(&priv->omsg_ring[mbox].lock, flags);
16802ece1cafSAlexandre Bounine
168148618fb4SAlexandre Bounine tx_slot = priv->omsg_ring[mbox].tx_slot;
168248618fb4SAlexandre Bounine
168348618fb4SAlexandre Bounine /* Copy copy message into transfer buffer */
168448618fb4SAlexandre Bounine memcpy(priv->omsg_ring[mbox].omq_base[tx_slot], buffer, len);
168548618fb4SAlexandre Bounine
168648618fb4SAlexandre Bounine if (len & 0x7)
168748618fb4SAlexandre Bounine len += 8;
168848618fb4SAlexandre Bounine
168948618fb4SAlexandre Bounine /* Build descriptor associated with buffer */
169048618fb4SAlexandre Bounine desc = priv->omsg_ring[mbox].omd_base;
169148618fb4SAlexandre Bounine desc[tx_slot].type_id = cpu_to_le32((DTYPE4 << 29) | rdev->destid);
16922ece1cafSAlexandre Bounine #ifdef TSI721_OMSG_DESC_INT
16932ece1cafSAlexandre Bounine /* Request IOF_DONE interrupt generation for each N-th frame in queue */
169448618fb4SAlexandre Bounine if (tx_slot % 4 == 0)
169548618fb4SAlexandre Bounine desc[tx_slot].type_id |= cpu_to_le32(TSI721_OMD_IOF);
16962ece1cafSAlexandre Bounine #endif
169748618fb4SAlexandre Bounine desc[tx_slot].msg_info =
169848618fb4SAlexandre Bounine cpu_to_le32((mport->sys_size << 26) | (mbox << 22) |
169948618fb4SAlexandre Bounine (0xe << 12) | (len & 0xff8));
170048618fb4SAlexandre Bounine desc[tx_slot].bufptr_lo =
170148618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omq_phys[tx_slot] &
170248618fb4SAlexandre Bounine 0xffffffff);
170348618fb4SAlexandre Bounine desc[tx_slot].bufptr_hi =
170448618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omq_phys[tx_slot] >> 32);
170548618fb4SAlexandre Bounine
170648618fb4SAlexandre Bounine priv->omsg_ring[mbox].wr_count++;
170748618fb4SAlexandre Bounine
170848618fb4SAlexandre Bounine /* Go to next descriptor */
170948618fb4SAlexandre Bounine if (++priv->omsg_ring[mbox].tx_slot == priv->omsg_ring[mbox].size) {
171048618fb4SAlexandre Bounine priv->omsg_ring[mbox].tx_slot = 0;
171148618fb4SAlexandre Bounine /* Move through the ring link descriptor at the end */
171248618fb4SAlexandre Bounine priv->omsg_ring[mbox].wr_count++;
171348618fb4SAlexandre Bounine }
171448618fb4SAlexandre Bounine
171548618fb4SAlexandre Bounine mb();
171648618fb4SAlexandre Bounine
171748618fb4SAlexandre Bounine /* Set new write count value */
171848618fb4SAlexandre Bounine iowrite32(priv->omsg_ring[mbox].wr_count,
171948618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
172048618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
172148618fb4SAlexandre Bounine
17222ece1cafSAlexandre Bounine spin_unlock_irqrestore(&priv->omsg_ring[mbox].lock, flags);
17232ece1cafSAlexandre Bounine
172448618fb4SAlexandre Bounine return 0;
172548618fb4SAlexandre Bounine }
172648618fb4SAlexandre Bounine
172748618fb4SAlexandre Bounine /**
172848618fb4SAlexandre Bounine * tsi721_omsg_handler - Outbound Message Interrupt Handler
172948618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data
173048618fb4SAlexandre Bounine * @ch: number of OB MSG channel to service
173148618fb4SAlexandre Bounine *
173248618fb4SAlexandre Bounine * Services channel interrupts from outbound messaging engine.
173348618fb4SAlexandre Bounine */
tsi721_omsg_handler(struct tsi721_device * priv,int ch)173448618fb4SAlexandre Bounine static void tsi721_omsg_handler(struct tsi721_device *priv, int ch)
173548618fb4SAlexandre Bounine {
173648618fb4SAlexandre Bounine u32 omsg_int;
1737748353ccSAlexandre Bounine struct rio_mport *mport = &priv->mport;
17382ece1cafSAlexandre Bounine void *dev_id = NULL;
17392ece1cafSAlexandre Bounine u32 tx_slot = 0xffffffff;
17402ece1cafSAlexandre Bounine int do_callback = 0;
174148618fb4SAlexandre Bounine
174248618fb4SAlexandre Bounine spin_lock(&priv->omsg_ring[ch].lock);
174348618fb4SAlexandre Bounine
174448618fb4SAlexandre Bounine omsg_int = ioread32(priv->regs + TSI721_OBDMAC_INT(ch));
174548618fb4SAlexandre Bounine
174648618fb4SAlexandre Bounine if (omsg_int & TSI721_OBDMAC_INT_ST_FULL)
174772d8a0d2SAlexandre Bounine tsi_info(&priv->pdev->dev,
174872d8a0d2SAlexandre Bounine "OB MBOX%d: Status FIFO is full", ch);
174948618fb4SAlexandre Bounine
175048618fb4SAlexandre Bounine if (omsg_int & (TSI721_OBDMAC_INT_DONE | TSI721_OBDMAC_INT_IOF_DONE)) {
175148618fb4SAlexandre Bounine u32 srd_ptr;
175248618fb4SAlexandre Bounine u64 *sts_ptr, last_ptr = 0, prev_ptr = 0;
175348618fb4SAlexandre Bounine int i, j;
175448618fb4SAlexandre Bounine
175548618fb4SAlexandre Bounine /*
175648618fb4SAlexandre Bounine * Find last successfully processed descriptor
175748618fb4SAlexandre Bounine */
175848618fb4SAlexandre Bounine
175948618fb4SAlexandre Bounine /* Check and clear descriptor status FIFO entries */
176048618fb4SAlexandre Bounine srd_ptr = priv->omsg_ring[ch].sts_rdptr;
176148618fb4SAlexandre Bounine sts_ptr = priv->omsg_ring[ch].sts_base;
176248618fb4SAlexandre Bounine j = srd_ptr * 8;
176348618fb4SAlexandre Bounine while (sts_ptr[j]) {
176448618fb4SAlexandre Bounine for (i = 0; i < 8 && sts_ptr[j]; i++, j++) {
176548618fb4SAlexandre Bounine prev_ptr = last_ptr;
176648618fb4SAlexandre Bounine last_ptr = le64_to_cpu(sts_ptr[j]);
176748618fb4SAlexandre Bounine sts_ptr[j] = 0;
176848618fb4SAlexandre Bounine }
176948618fb4SAlexandre Bounine
177048618fb4SAlexandre Bounine ++srd_ptr;
177148618fb4SAlexandre Bounine srd_ptr %= priv->omsg_ring[ch].sts_size;
177248618fb4SAlexandre Bounine j = srd_ptr * 8;
177348618fb4SAlexandre Bounine }
177448618fb4SAlexandre Bounine
177548618fb4SAlexandre Bounine if (last_ptr == 0)
177648618fb4SAlexandre Bounine goto no_sts_update;
177748618fb4SAlexandre Bounine
177848618fb4SAlexandre Bounine priv->omsg_ring[ch].sts_rdptr = srd_ptr;
177948618fb4SAlexandre Bounine iowrite32(srd_ptr, priv->regs + TSI721_OBDMAC_DSRP(ch));
178048618fb4SAlexandre Bounine
1781748353ccSAlexandre Bounine if (!mport->outb_msg[ch].mcback)
178248618fb4SAlexandre Bounine goto no_sts_update;
178348618fb4SAlexandre Bounine
178448618fb4SAlexandre Bounine /* Inform upper layer about transfer completion */
178548618fb4SAlexandre Bounine
178648618fb4SAlexandre Bounine tx_slot = (last_ptr - (u64)priv->omsg_ring[ch].omd_phys)/
178748618fb4SAlexandre Bounine sizeof(struct tsi721_omsg_desc);
178848618fb4SAlexandre Bounine
178948618fb4SAlexandre Bounine /*
179048618fb4SAlexandre Bounine * Check if this is a Link Descriptor (LD).
179148618fb4SAlexandre Bounine * If yes, ignore LD and use descriptor processed
179248618fb4SAlexandre Bounine * before LD.
179348618fb4SAlexandre Bounine */
179448618fb4SAlexandre Bounine if (tx_slot == priv->omsg_ring[ch].size) {
179548618fb4SAlexandre Bounine if (prev_ptr)
179648618fb4SAlexandre Bounine tx_slot = (prev_ptr -
179748618fb4SAlexandre Bounine (u64)priv->omsg_ring[ch].omd_phys)/
179848618fb4SAlexandre Bounine sizeof(struct tsi721_omsg_desc);
179948618fb4SAlexandre Bounine else
180048618fb4SAlexandre Bounine goto no_sts_update;
180148618fb4SAlexandre Bounine }
180248618fb4SAlexandre Bounine
18032ece1cafSAlexandre Bounine if (tx_slot >= priv->omsg_ring[ch].size)
180472d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev,
18052ece1cafSAlexandre Bounine "OB_MSG tx_slot=%x > size=%x",
18062ece1cafSAlexandre Bounine tx_slot, priv->omsg_ring[ch].size);
18072ece1cafSAlexandre Bounine WARN_ON(tx_slot >= priv->omsg_ring[ch].size);
18082ece1cafSAlexandre Bounine
180948618fb4SAlexandre Bounine /* Move slot index to the next message to be sent */
181048618fb4SAlexandre Bounine ++tx_slot;
181148618fb4SAlexandre Bounine if (tx_slot == priv->omsg_ring[ch].size)
181248618fb4SAlexandre Bounine tx_slot = 0;
18132ece1cafSAlexandre Bounine
18142ece1cafSAlexandre Bounine dev_id = priv->omsg_ring[ch].dev_id;
18152ece1cafSAlexandre Bounine do_callback = 1;
181648618fb4SAlexandre Bounine }
181748618fb4SAlexandre Bounine
181848618fb4SAlexandre Bounine no_sts_update:
181948618fb4SAlexandre Bounine
182048618fb4SAlexandre Bounine if (omsg_int & TSI721_OBDMAC_INT_ERROR) {
182148618fb4SAlexandre Bounine /*
182248618fb4SAlexandre Bounine * Outbound message operation aborted due to error,
182348618fb4SAlexandre Bounine * reinitialize OB MSG channel
182448618fb4SAlexandre Bounine */
182548618fb4SAlexandre Bounine
182672d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev, "OB MSG ABORT ch_stat=%x",
182748618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_STS(ch)));
182848618fb4SAlexandre Bounine
182948618fb4SAlexandre Bounine iowrite32(TSI721_OBDMAC_INT_ERROR,
183048618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_INT(ch));
18312ece1cafSAlexandre Bounine iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT,
183248618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_CTL(ch));
183348618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_CTL(ch));
183448618fb4SAlexandre Bounine
183548618fb4SAlexandre Bounine /* Inform upper level to clear all pending tx slots */
18362ece1cafSAlexandre Bounine dev_id = priv->omsg_ring[ch].dev_id;
18372ece1cafSAlexandre Bounine tx_slot = priv->omsg_ring[ch].tx_slot;
18382ece1cafSAlexandre Bounine do_callback = 1;
18392ece1cafSAlexandre Bounine
184048618fb4SAlexandre Bounine /* Synch tx_slot tracking */
184148618fb4SAlexandre Bounine iowrite32(priv->omsg_ring[ch].tx_slot,
184248618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DRDCNT(ch));
184348618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_DRDCNT(ch));
184448618fb4SAlexandre Bounine priv->omsg_ring[ch].wr_count = priv->omsg_ring[ch].tx_slot;
184548618fb4SAlexandre Bounine priv->omsg_ring[ch].sts_rdptr = 0;
184648618fb4SAlexandre Bounine }
184748618fb4SAlexandre Bounine
184848618fb4SAlexandre Bounine /* Clear channel interrupts */
184948618fb4SAlexandre Bounine iowrite32(omsg_int, priv->regs + TSI721_OBDMAC_INT(ch));
185048618fb4SAlexandre Bounine
185148618fb4SAlexandre Bounine if (!(priv->flags & TSI721_USING_MSIX)) {
185248618fb4SAlexandre Bounine u32 ch_inte;
185348618fb4SAlexandre Bounine
185448618fb4SAlexandre Bounine /* Re-enable channel interrupts */
185548618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
185648618fb4SAlexandre Bounine ch_inte |= TSI721_INT_OMSG_CHAN(ch);
185748618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE);
185848618fb4SAlexandre Bounine }
185948618fb4SAlexandre Bounine
186048618fb4SAlexandre Bounine spin_unlock(&priv->omsg_ring[ch].lock);
18612ece1cafSAlexandre Bounine
18622ece1cafSAlexandre Bounine if (mport->outb_msg[ch].mcback && do_callback)
18632ece1cafSAlexandre Bounine mport->outb_msg[ch].mcback(mport, dev_id, ch, tx_slot);
186448618fb4SAlexandre Bounine }
186548618fb4SAlexandre Bounine
186648618fb4SAlexandre Bounine /**
186748618fb4SAlexandre Bounine * tsi721_open_outb_mbox - Initialize Tsi721 outbound mailbox
186848618fb4SAlexandre Bounine * @mport: Master port implementing Outbound Messaging Engine
186948618fb4SAlexandre Bounine * @dev_id: Device specific pointer to pass on event
187048618fb4SAlexandre Bounine * @mbox: Mailbox to open
187148618fb4SAlexandre Bounine * @entries: Number of entries in the outbound mailbox ring
187248618fb4SAlexandre Bounine */
tsi721_open_outb_mbox(struct rio_mport * mport,void * dev_id,int mbox,int entries)187348618fb4SAlexandre Bounine static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id,
187448618fb4SAlexandre Bounine int mbox, int entries)
187548618fb4SAlexandre Bounine {
187648618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
187748618fb4SAlexandre Bounine struct tsi721_omsg_desc *bd_ptr;
187848618fb4SAlexandre Bounine int i, rc = 0;
187948618fb4SAlexandre Bounine
188048618fb4SAlexandre Bounine if ((entries < TSI721_OMSGD_MIN_RING_SIZE) ||
188148618fb4SAlexandre Bounine (entries > (TSI721_OMSGD_RING_SIZE)) ||
188248618fb4SAlexandre Bounine (!is_power_of_2(entries)) || mbox >= RIO_MAX_MBOX) {
188348618fb4SAlexandre Bounine rc = -EINVAL;
188448618fb4SAlexandre Bounine goto out;
188548618fb4SAlexandre Bounine }
188648618fb4SAlexandre Bounine
1887e519685dSAlexandre Bounine if ((mbox_sel & (1 << mbox)) == 0) {
1888e519685dSAlexandre Bounine rc = -ENODEV;
1889e519685dSAlexandre Bounine goto out;
1890e519685dSAlexandre Bounine }
1891e519685dSAlexandre Bounine
189248618fb4SAlexandre Bounine priv->omsg_ring[mbox].dev_id = dev_id;
189348618fb4SAlexandre Bounine priv->omsg_ring[mbox].size = entries;
189448618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_rdptr = 0;
189548618fb4SAlexandre Bounine spin_lock_init(&priv->omsg_ring[mbox].lock);
189648618fb4SAlexandre Bounine
189748618fb4SAlexandre Bounine /* Outbound Msg Buffer allocation based on
189848618fb4SAlexandre Bounine the number of maximum descriptor entries */
189948618fb4SAlexandre Bounine for (i = 0; i < entries; i++) {
190048618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i] =
190148618fb4SAlexandre Bounine dma_alloc_coherent(
190248618fb4SAlexandre Bounine &priv->pdev->dev, TSI721_MSG_BUFFER_SIZE,
190348618fb4SAlexandre Bounine &priv->omsg_ring[mbox].omq_phys[i],
190448618fb4SAlexandre Bounine GFP_KERNEL);
190548618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omq_base[i] == NULL) {
190672d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev,
190772d8a0d2SAlexandre Bounine "ENOMEM for OB_MSG_%d data buffer", mbox);
190848618fb4SAlexandre Bounine rc = -ENOMEM;
190948618fb4SAlexandre Bounine goto out_buf;
191048618fb4SAlexandre Bounine }
191148618fb4SAlexandre Bounine }
191248618fb4SAlexandre Bounine
191348618fb4SAlexandre Bounine /* Outbound message descriptor allocation */
191448618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base = dma_alloc_coherent(
191548618fb4SAlexandre Bounine &priv->pdev->dev,
191648618fb4SAlexandre Bounine (entries + 1) * sizeof(struct tsi721_omsg_desc),
191748618fb4SAlexandre Bounine &priv->omsg_ring[mbox].omd_phys, GFP_KERNEL);
191848618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omd_base == NULL) {
191972d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev,
192072d8a0d2SAlexandre Bounine "ENOMEM for OB_MSG_%d descriptor memory", mbox);
192148618fb4SAlexandre Bounine rc = -ENOMEM;
192248618fb4SAlexandre Bounine goto out_buf;
192348618fb4SAlexandre Bounine }
192448618fb4SAlexandre Bounine
192548618fb4SAlexandre Bounine priv->omsg_ring[mbox].tx_slot = 0;
192648618fb4SAlexandre Bounine
192748618fb4SAlexandre Bounine /* Outbound message descriptor status FIFO allocation */
192848618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size = roundup_pow_of_two(entries + 1);
1929750afb08SLuis Chamberlain priv->omsg_ring[mbox].sts_base = dma_alloc_coherent(&priv->pdev->dev,
1930750afb08SLuis Chamberlain priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts),
1931750afb08SLuis Chamberlain &priv->omsg_ring[mbox].sts_phys,
1932750afb08SLuis Chamberlain GFP_KERNEL);
193348618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].sts_base == NULL) {
193472d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev,
193572d8a0d2SAlexandre Bounine "ENOMEM for OB_MSG_%d status FIFO", mbox);
193648618fb4SAlexandre Bounine rc = -ENOMEM;
193748618fb4SAlexandre Bounine goto out_desc;
193848618fb4SAlexandre Bounine }
193948618fb4SAlexandre Bounine
194048618fb4SAlexandre Bounine /*
194148618fb4SAlexandre Bounine * Configure Outbound Messaging Engine
194248618fb4SAlexandre Bounine */
194348618fb4SAlexandre Bounine
194448618fb4SAlexandre Bounine /* Setup Outbound Message descriptor pointer */
194548618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].omd_phys >> 32),
194648618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DPTRH(mbox));
194748618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].omd_phys &
194848618fb4SAlexandre Bounine TSI721_OBDMAC_DPTRL_MASK),
194948618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DPTRL(mbox));
195048618fb4SAlexandre Bounine
195148618fb4SAlexandre Bounine /* Setup Outbound Message descriptor status FIFO */
195248618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].sts_phys >> 32),
195348618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DSBH(mbox));
195448618fb4SAlexandre Bounine iowrite32(((u64)priv->omsg_ring[mbox].sts_phys &
195548618fb4SAlexandre Bounine TSI721_OBDMAC_DSBL_MASK),
195648618fb4SAlexandre Bounine priv->regs + TSI721_OBDMAC_DSBL(mbox));
195748618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(priv->omsg_ring[mbox].sts_size),
195848618fb4SAlexandre Bounine priv->regs + (u32)TSI721_OBDMAC_DSSZ(mbox));
195948618fb4SAlexandre Bounine
196048618fb4SAlexandre Bounine /* Enable interrupts */
196148618fb4SAlexandre Bounine
196248618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI
196348618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) {
1964748353ccSAlexandre Bounine int idx = TSI721_VECT_OMB0_DONE + mbox;
1965748353ccSAlexandre Bounine
196648618fb4SAlexandre Bounine /* Request interrupt service if we are in MSI-X mode */
1967748353ccSAlexandre Bounine rc = request_irq(priv->msix[idx].vector, tsi721_omsg_msix, 0,
1968748353ccSAlexandre Bounine priv->msix[idx].irq_name, (void *)priv);
196948618fb4SAlexandre Bounine
197048618fb4SAlexandre Bounine if (rc) {
197172d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev,
197272d8a0d2SAlexandre Bounine "Unable to get MSI-X IRQ for OBOX%d-DONE",
197372d8a0d2SAlexandre Bounine mbox);
197448618fb4SAlexandre Bounine goto out_stat;
197548618fb4SAlexandre Bounine }
197648618fb4SAlexandre Bounine
1977748353ccSAlexandre Bounine idx = TSI721_VECT_OMB0_INT + mbox;
1978748353ccSAlexandre Bounine rc = request_irq(priv->msix[idx].vector, tsi721_omsg_msix, 0,
1979748353ccSAlexandre Bounine priv->msix[idx].irq_name, (void *)priv);
198048618fb4SAlexandre Bounine
198148618fb4SAlexandre Bounine if (rc) {
198272d8a0d2SAlexandre Bounine tsi_debug(OMSG, &priv->pdev->dev,
198372d8a0d2SAlexandre Bounine "Unable to get MSI-X IRQ for MBOX%d-INT", mbox);
1984748353ccSAlexandre Bounine idx = TSI721_VECT_OMB0_DONE + mbox;
1985748353ccSAlexandre Bounine free_irq(priv->msix[idx].vector, (void *)priv);
198648618fb4SAlexandre Bounine goto out_stat;
198748618fb4SAlexandre Bounine }
198848618fb4SAlexandre Bounine }
198948618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */
199048618fb4SAlexandre Bounine
199148618fb4SAlexandre Bounine tsi721_omsg_interrupt_enable(priv, mbox, TSI721_OBDMAC_INT_ALL);
199248618fb4SAlexandre Bounine
199348618fb4SAlexandre Bounine /* Initialize Outbound Message descriptors ring */
199448618fb4SAlexandre Bounine bd_ptr = priv->omsg_ring[mbox].omd_base;
199548618fb4SAlexandre Bounine bd_ptr[entries].type_id = cpu_to_le32(DTYPE5 << 29);
199648618fb4SAlexandre Bounine bd_ptr[entries].msg_info = 0;
199748618fb4SAlexandre Bounine bd_ptr[entries].next_lo =
199848618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omd_phys &
199948618fb4SAlexandre Bounine TSI721_OBDMAC_DPTRL_MASK);
200048618fb4SAlexandre Bounine bd_ptr[entries].next_hi =
200148618fb4SAlexandre Bounine cpu_to_le32((u64)priv->omsg_ring[mbox].omd_phys >> 32);
200248618fb4SAlexandre Bounine priv->omsg_ring[mbox].wr_count = 0;
200348618fb4SAlexandre Bounine mb();
200448618fb4SAlexandre Bounine
200548618fb4SAlexandre Bounine /* Initialize Outbound Message engine */
20062ece1cafSAlexandre Bounine iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT,
20072ece1cafSAlexandre Bounine priv->regs + TSI721_OBDMAC_CTL(mbox));
200848618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
200948618fb4SAlexandre Bounine udelay(10);
201048618fb4SAlexandre Bounine
201148618fb4SAlexandre Bounine priv->omsg_init[mbox] = 1;
201248618fb4SAlexandre Bounine
201348618fb4SAlexandre Bounine return 0;
201448618fb4SAlexandre Bounine
201548618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI
201648618fb4SAlexandre Bounine out_stat:
201748618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
201848618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts),
201948618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base,
202048618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_phys);
202148618fb4SAlexandre Bounine
202248618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base = NULL;
202348618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */
202448618fb4SAlexandre Bounine
202548618fb4SAlexandre Bounine out_desc:
202648618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
202748618fb4SAlexandre Bounine (entries + 1) * sizeof(struct tsi721_omsg_desc),
202848618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base,
202948618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_phys);
203048618fb4SAlexandre Bounine
203148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base = NULL;
203248618fb4SAlexandre Bounine
203348618fb4SAlexandre Bounine out_buf:
203448618fb4SAlexandre Bounine for (i = 0; i < priv->omsg_ring[mbox].size; i++) {
203548618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omq_base[i]) {
203648618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
203748618fb4SAlexandre Bounine TSI721_MSG_BUFFER_SIZE,
203848618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i],
203948618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_phys[i]);
204048618fb4SAlexandre Bounine
204148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i] = NULL;
204248618fb4SAlexandre Bounine }
204348618fb4SAlexandre Bounine }
204448618fb4SAlexandre Bounine
204548618fb4SAlexandre Bounine out:
204648618fb4SAlexandre Bounine return rc;
204748618fb4SAlexandre Bounine }
204848618fb4SAlexandre Bounine
204948618fb4SAlexandre Bounine /**
205048618fb4SAlexandre Bounine * tsi721_close_outb_mbox - Close Tsi721 outbound mailbox
205148618fb4SAlexandre Bounine * @mport: Master port implementing the outbound message unit
205248618fb4SAlexandre Bounine * @mbox: Mailbox to close
205348618fb4SAlexandre Bounine */
tsi721_close_outb_mbox(struct rio_mport * mport,int mbox)205448618fb4SAlexandre Bounine static void tsi721_close_outb_mbox(struct rio_mport *mport, int mbox)
205548618fb4SAlexandre Bounine {
205648618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
205748618fb4SAlexandre Bounine u32 i;
205848618fb4SAlexandre Bounine
205948618fb4SAlexandre Bounine if (!priv->omsg_init[mbox])
206048618fb4SAlexandre Bounine return;
206148618fb4SAlexandre Bounine priv->omsg_init[mbox] = 0;
206248618fb4SAlexandre Bounine
206348618fb4SAlexandre Bounine /* Disable Interrupts */
206448618fb4SAlexandre Bounine
206548618fb4SAlexandre Bounine tsi721_omsg_interrupt_disable(priv, mbox, TSI721_OBDMAC_INT_ALL);
206648618fb4SAlexandre Bounine
206748618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI
206848618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) {
206948618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_OMB0_DONE + mbox].vector,
2070748353ccSAlexandre Bounine (void *)priv);
207148618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_OMB0_INT + mbox].vector,
2072748353ccSAlexandre Bounine (void *)priv);
207348618fb4SAlexandre Bounine }
207448618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */
207548618fb4SAlexandre Bounine
207648618fb4SAlexandre Bounine /* Free OMSG Descriptor Status FIFO */
207748618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
207848618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts),
207948618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base,
208048618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_phys);
208148618fb4SAlexandre Bounine
208248618fb4SAlexandre Bounine priv->omsg_ring[mbox].sts_base = NULL;
208348618fb4SAlexandre Bounine
208448618fb4SAlexandre Bounine /* Free OMSG descriptors */
208548618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
208648618fb4SAlexandre Bounine (priv->omsg_ring[mbox].size + 1) *
208748618fb4SAlexandre Bounine sizeof(struct tsi721_omsg_desc),
208848618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base,
208948618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_phys);
209048618fb4SAlexandre Bounine
209148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omd_base = NULL;
209248618fb4SAlexandre Bounine
209348618fb4SAlexandre Bounine /* Free message buffers */
209448618fb4SAlexandre Bounine for (i = 0; i < priv->omsg_ring[mbox].size; i++) {
209548618fb4SAlexandre Bounine if (priv->omsg_ring[mbox].omq_base[i]) {
209648618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
209748618fb4SAlexandre Bounine TSI721_MSG_BUFFER_SIZE,
209848618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i],
209948618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_phys[i]);
210048618fb4SAlexandre Bounine
210148618fb4SAlexandre Bounine priv->omsg_ring[mbox].omq_base[i] = NULL;
210248618fb4SAlexandre Bounine }
210348618fb4SAlexandre Bounine }
210448618fb4SAlexandre Bounine }
210548618fb4SAlexandre Bounine
210648618fb4SAlexandre Bounine /**
210748618fb4SAlexandre Bounine * tsi721_imsg_handler - Inbound Message Interrupt Handler
210848618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data
210948618fb4SAlexandre Bounine * @ch: inbound message channel number to service
211048618fb4SAlexandre Bounine *
211148618fb4SAlexandre Bounine * Services channel interrupts from inbound messaging engine.
211248618fb4SAlexandre Bounine */
tsi721_imsg_handler(struct tsi721_device * priv,int ch)211348618fb4SAlexandre Bounine static void tsi721_imsg_handler(struct tsi721_device *priv, int ch)
211448618fb4SAlexandre Bounine {
211548618fb4SAlexandre Bounine u32 mbox = ch - 4;
211648618fb4SAlexandre Bounine u32 imsg_int;
2117748353ccSAlexandre Bounine struct rio_mport *mport = &priv->mport;
211848618fb4SAlexandre Bounine
211948618fb4SAlexandre Bounine spin_lock(&priv->imsg_ring[mbox].lock);
212048618fb4SAlexandre Bounine
212148618fb4SAlexandre Bounine imsg_int = ioread32(priv->regs + TSI721_IBDMAC_INT(ch));
212248618fb4SAlexandre Bounine
212348618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_SRTO)
212472d8a0d2SAlexandre Bounine tsi_info(&priv->pdev->dev, "IB MBOX%d SRIO timeout", mbox);
212548618fb4SAlexandre Bounine
212648618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_PC_ERROR)
212772d8a0d2SAlexandre Bounine tsi_info(&priv->pdev->dev, "IB MBOX%d PCIe error", mbox);
212848618fb4SAlexandre Bounine
212948618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_FQ_LOW)
213072d8a0d2SAlexandre Bounine tsi_info(&priv->pdev->dev, "IB MBOX%d IB free queue low", mbox);
213148618fb4SAlexandre Bounine
213248618fb4SAlexandre Bounine /* Clear IB channel interrupts */
213348618fb4SAlexandre Bounine iowrite32(imsg_int, priv->regs + TSI721_IBDMAC_INT(ch));
213448618fb4SAlexandre Bounine
213548618fb4SAlexandre Bounine /* If an IB Msg is received notify the upper layer */
213648618fb4SAlexandre Bounine if (imsg_int & TSI721_IBDMAC_INT_DQ_RCV &&
2137748353ccSAlexandre Bounine mport->inb_msg[mbox].mcback)
2138748353ccSAlexandre Bounine mport->inb_msg[mbox].mcback(mport,
213948618fb4SAlexandre Bounine priv->imsg_ring[mbox].dev_id, mbox, -1);
214048618fb4SAlexandre Bounine
214148618fb4SAlexandre Bounine if (!(priv->flags & TSI721_USING_MSIX)) {
214248618fb4SAlexandre Bounine u32 ch_inte;
214348618fb4SAlexandre Bounine
214448618fb4SAlexandre Bounine /* Re-enable channel interrupts */
214548618fb4SAlexandre Bounine ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
214648618fb4SAlexandre Bounine ch_inte |= TSI721_INT_IMSG_CHAN(ch);
214748618fb4SAlexandre Bounine iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE);
214848618fb4SAlexandre Bounine }
214948618fb4SAlexandre Bounine
215048618fb4SAlexandre Bounine spin_unlock(&priv->imsg_ring[mbox].lock);
215148618fb4SAlexandre Bounine }
215248618fb4SAlexandre Bounine
215348618fb4SAlexandre Bounine /**
215448618fb4SAlexandre Bounine * tsi721_open_inb_mbox - Initialize Tsi721 inbound mailbox
215548618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine
215648618fb4SAlexandre Bounine * @dev_id: Device specific pointer to pass on event
215748618fb4SAlexandre Bounine * @mbox: Mailbox to open
215848618fb4SAlexandre Bounine * @entries: Number of entries in the inbound mailbox ring
215948618fb4SAlexandre Bounine */
tsi721_open_inb_mbox(struct rio_mport * mport,void * dev_id,int mbox,int entries)216048618fb4SAlexandre Bounine static int tsi721_open_inb_mbox(struct rio_mport *mport, void *dev_id,
216148618fb4SAlexandre Bounine int mbox, int entries)
216248618fb4SAlexandre Bounine {
216348618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
216448618fb4SAlexandre Bounine int ch = mbox + 4;
216548618fb4SAlexandre Bounine int i;
216648618fb4SAlexandre Bounine u64 *free_ptr;
216748618fb4SAlexandre Bounine int rc = 0;
216848618fb4SAlexandre Bounine
216948618fb4SAlexandre Bounine if ((entries < TSI721_IMSGD_MIN_RING_SIZE) ||
217048618fb4SAlexandre Bounine (entries > TSI721_IMSGD_RING_SIZE) ||
217148618fb4SAlexandre Bounine (!is_power_of_2(entries)) || mbox >= RIO_MAX_MBOX) {
217248618fb4SAlexandre Bounine rc = -EINVAL;
217348618fb4SAlexandre Bounine goto out;
217448618fb4SAlexandre Bounine }
217548618fb4SAlexandre Bounine
2176e519685dSAlexandre Bounine if ((mbox_sel & (1 << mbox)) == 0) {
2177e519685dSAlexandre Bounine rc = -ENODEV;
2178e519685dSAlexandre Bounine goto out;
2179e519685dSAlexandre Bounine }
2180e519685dSAlexandre Bounine
218148618fb4SAlexandre Bounine /* Initialize IB Messaging Ring */
218248618fb4SAlexandre Bounine priv->imsg_ring[mbox].dev_id = dev_id;
218348618fb4SAlexandre Bounine priv->imsg_ring[mbox].size = entries;
218448618fb4SAlexandre Bounine priv->imsg_ring[mbox].rx_slot = 0;
218548618fb4SAlexandre Bounine priv->imsg_ring[mbox].desc_rdptr = 0;
218648618fb4SAlexandre Bounine priv->imsg_ring[mbox].fq_wrptr = 0;
218748618fb4SAlexandre Bounine for (i = 0; i < priv->imsg_ring[mbox].size; i++)
218848618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[i] = NULL;
218948618fb4SAlexandre Bounine spin_lock_init(&priv->imsg_ring[mbox].lock);
219048618fb4SAlexandre Bounine
219148618fb4SAlexandre Bounine /* Allocate buffers for incoming messages */
219248618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base =
219348618fb4SAlexandre Bounine dma_alloc_coherent(&priv->pdev->dev,
219448618fb4SAlexandre Bounine entries * TSI721_MSG_BUFFER_SIZE,
219548618fb4SAlexandre Bounine &priv->imsg_ring[mbox].buf_phys,
219648618fb4SAlexandre Bounine GFP_KERNEL);
219748618fb4SAlexandre Bounine
219848618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].buf_base == NULL) {
219972d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev,
220072d8a0d2SAlexandre Bounine "Failed to allocate buffers for IB MBOX%d", mbox);
220148618fb4SAlexandre Bounine rc = -ENOMEM;
220248618fb4SAlexandre Bounine goto out;
220348618fb4SAlexandre Bounine }
220448618fb4SAlexandre Bounine
220548618fb4SAlexandre Bounine /* Allocate memory for circular free list */
220648618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base =
220748618fb4SAlexandre Bounine dma_alloc_coherent(&priv->pdev->dev,
220848618fb4SAlexandre Bounine entries * 8,
220948618fb4SAlexandre Bounine &priv->imsg_ring[mbox].imfq_phys,
221048618fb4SAlexandre Bounine GFP_KERNEL);
221148618fb4SAlexandre Bounine
221248618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].imfq_base == NULL) {
221372d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev,
221472d8a0d2SAlexandre Bounine "Failed to allocate free queue for IB MBOX%d", mbox);
221548618fb4SAlexandre Bounine rc = -ENOMEM;
221648618fb4SAlexandre Bounine goto out_buf;
221748618fb4SAlexandre Bounine }
221848618fb4SAlexandre Bounine
221948618fb4SAlexandre Bounine /* Allocate memory for Inbound message descriptors */
222048618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base =
222148618fb4SAlexandre Bounine dma_alloc_coherent(&priv->pdev->dev,
222248618fb4SAlexandre Bounine entries * sizeof(struct tsi721_imsg_desc),
222348618fb4SAlexandre Bounine &priv->imsg_ring[mbox].imd_phys, GFP_KERNEL);
222448618fb4SAlexandre Bounine
222548618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].imd_base == NULL) {
222672d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev,
222772d8a0d2SAlexandre Bounine "Failed to allocate descriptor memory for IB MBOX%d",
222848618fb4SAlexandre Bounine mbox);
222948618fb4SAlexandre Bounine rc = -ENOMEM;
223048618fb4SAlexandre Bounine goto out_dma;
223148618fb4SAlexandre Bounine }
223248618fb4SAlexandre Bounine
223348618fb4SAlexandre Bounine /* Fill free buffer pointer list */
223448618fb4SAlexandre Bounine free_ptr = priv->imsg_ring[mbox].imfq_base;
223548618fb4SAlexandre Bounine for (i = 0; i < entries; i++)
223648618fb4SAlexandre Bounine free_ptr[i] = cpu_to_le64(
223748618fb4SAlexandre Bounine (u64)(priv->imsg_ring[mbox].buf_phys) +
223848618fb4SAlexandre Bounine i * 0x1000);
223948618fb4SAlexandre Bounine
224048618fb4SAlexandre Bounine mb();
224148618fb4SAlexandre Bounine
224248618fb4SAlexandre Bounine /*
224348618fb4SAlexandre Bounine * For mapping of inbound SRIO Messages into appropriate queues we need
224448618fb4SAlexandre Bounine * to set Inbound Device ID register in the messaging engine. We do it
224548618fb4SAlexandre Bounine * once when first inbound mailbox is requested.
224648618fb4SAlexandre Bounine */
224748618fb4SAlexandre Bounine if (!(priv->flags & TSI721_IMSGID_SET)) {
2248748353ccSAlexandre Bounine iowrite32((u32)priv->mport.host_deviceid,
224948618fb4SAlexandre Bounine priv->regs + TSI721_IB_DEVID);
225048618fb4SAlexandre Bounine priv->flags |= TSI721_IMSGID_SET;
225148618fb4SAlexandre Bounine }
225248618fb4SAlexandre Bounine
225348618fb4SAlexandre Bounine /*
225448618fb4SAlexandre Bounine * Configure Inbound Messaging channel (ch = mbox + 4)
225548618fb4SAlexandre Bounine */
225648618fb4SAlexandre Bounine
225748618fb4SAlexandre Bounine /* Setup Inbound Message free queue */
225848618fb4SAlexandre Bounine iowrite32(((u64)priv->imsg_ring[mbox].imfq_phys >> 32),
225948618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_FQBH(ch));
226048618fb4SAlexandre Bounine iowrite32(((u64)priv->imsg_ring[mbox].imfq_phys &
226148618fb4SAlexandre Bounine TSI721_IBDMAC_FQBL_MASK),
226248618fb4SAlexandre Bounine priv->regs+TSI721_IBDMAC_FQBL(ch));
226348618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(entries),
226448618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_FQSZ(ch));
226548618fb4SAlexandre Bounine
226648618fb4SAlexandre Bounine /* Setup Inbound Message descriptor queue */
226748618fb4SAlexandre Bounine iowrite32(((u64)priv->imsg_ring[mbox].imd_phys >> 32),
226848618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_DQBH(ch));
226948618fb4SAlexandre Bounine iowrite32(((u32)priv->imsg_ring[mbox].imd_phys &
227048618fb4SAlexandre Bounine (u32)TSI721_IBDMAC_DQBL_MASK),
227148618fb4SAlexandre Bounine priv->regs+TSI721_IBDMAC_DQBL(ch));
227248618fb4SAlexandre Bounine iowrite32(TSI721_DMAC_DSSZ_SIZE(entries),
227348618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_DQSZ(ch));
227448618fb4SAlexandre Bounine
227548618fb4SAlexandre Bounine /* Enable interrupts */
227648618fb4SAlexandre Bounine
227748618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI
227848618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) {
2279748353ccSAlexandre Bounine int idx = TSI721_VECT_IMB0_RCV + mbox;
2280748353ccSAlexandre Bounine
228148618fb4SAlexandre Bounine /* Request interrupt service if we are in MSI-X mode */
2282748353ccSAlexandre Bounine rc = request_irq(priv->msix[idx].vector, tsi721_imsg_msix, 0,
2283748353ccSAlexandre Bounine priv->msix[idx].irq_name, (void *)priv);
228448618fb4SAlexandre Bounine
228548618fb4SAlexandre Bounine if (rc) {
228672d8a0d2SAlexandre Bounine tsi_debug(IMSG, &priv->pdev->dev,
228772d8a0d2SAlexandre Bounine "Unable to get MSI-X IRQ for IBOX%d-DONE",
228872d8a0d2SAlexandre Bounine mbox);
228948618fb4SAlexandre Bounine goto out_desc;
229048618fb4SAlexandre Bounine }
229148618fb4SAlexandre Bounine
2292748353ccSAlexandre Bounine idx = TSI721_VECT_IMB0_INT + mbox;
2293748353ccSAlexandre Bounine rc = request_irq(priv->msix[idx].vector, tsi721_imsg_msix, 0,
2294748353ccSAlexandre Bounine priv->msix[idx].irq_name, (void *)priv);
229548618fb4SAlexandre Bounine
229648618fb4SAlexandre Bounine if (rc) {
229772d8a0d2SAlexandre Bounine tsi_debug(IMSG, &priv->pdev->dev,
229872d8a0d2SAlexandre Bounine "Unable to get MSI-X IRQ for IBOX%d-INT", mbox);
229948618fb4SAlexandre Bounine free_irq(
230048618fb4SAlexandre Bounine priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector,
2301748353ccSAlexandre Bounine (void *)priv);
230248618fb4SAlexandre Bounine goto out_desc;
230348618fb4SAlexandre Bounine }
230448618fb4SAlexandre Bounine }
230548618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */
230648618fb4SAlexandre Bounine
230748618fb4SAlexandre Bounine tsi721_imsg_interrupt_enable(priv, ch, TSI721_IBDMAC_INT_ALL);
230848618fb4SAlexandre Bounine
230948618fb4SAlexandre Bounine /* Initialize Inbound Message Engine */
231048618fb4SAlexandre Bounine iowrite32(TSI721_IBDMAC_CTL_INIT, priv->regs + TSI721_IBDMAC_CTL(ch));
231148618fb4SAlexandre Bounine ioread32(priv->regs + TSI721_IBDMAC_CTL(ch));
231248618fb4SAlexandre Bounine udelay(10);
231348618fb4SAlexandre Bounine priv->imsg_ring[mbox].fq_wrptr = entries - 1;
231448618fb4SAlexandre Bounine iowrite32(entries - 1, priv->regs + TSI721_IBDMAC_FQWP(ch));
231548618fb4SAlexandre Bounine
231648618fb4SAlexandre Bounine priv->imsg_init[mbox] = 1;
231748618fb4SAlexandre Bounine return 0;
231848618fb4SAlexandre Bounine
231948618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI
232048618fb4SAlexandre Bounine out_desc:
232148618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
232248618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * sizeof(struct tsi721_imsg_desc),
232348618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base,
232448618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_phys);
232548618fb4SAlexandre Bounine
232648618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base = NULL;
232748618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */
232848618fb4SAlexandre Bounine
232948618fb4SAlexandre Bounine out_dma:
233048618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
233148618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * 8,
233248618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base,
233348618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_phys);
233448618fb4SAlexandre Bounine
233548618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base = NULL;
233648618fb4SAlexandre Bounine
233748618fb4SAlexandre Bounine out_buf:
233848618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
233948618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * TSI721_MSG_BUFFER_SIZE,
234048618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base,
234148618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_phys);
234248618fb4SAlexandre Bounine
234348618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base = NULL;
234448618fb4SAlexandre Bounine
234548618fb4SAlexandre Bounine out:
234648618fb4SAlexandre Bounine return rc;
234748618fb4SAlexandre Bounine }
234848618fb4SAlexandre Bounine
234948618fb4SAlexandre Bounine /**
235048618fb4SAlexandre Bounine * tsi721_close_inb_mbox - Shut down Tsi721 inbound mailbox
235148618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine
235248618fb4SAlexandre Bounine * @mbox: Mailbox to close
235348618fb4SAlexandre Bounine */
tsi721_close_inb_mbox(struct rio_mport * mport,int mbox)235448618fb4SAlexandre Bounine static void tsi721_close_inb_mbox(struct rio_mport *mport, int mbox)
235548618fb4SAlexandre Bounine {
235648618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
235748618fb4SAlexandre Bounine u32 rx_slot;
235848618fb4SAlexandre Bounine int ch = mbox + 4;
235948618fb4SAlexandre Bounine
236048618fb4SAlexandre Bounine if (!priv->imsg_init[mbox]) /* mbox isn't initialized yet */
236148618fb4SAlexandre Bounine return;
236248618fb4SAlexandre Bounine priv->imsg_init[mbox] = 0;
236348618fb4SAlexandre Bounine
236448618fb4SAlexandre Bounine /* Disable Inbound Messaging Engine */
236548618fb4SAlexandre Bounine
236648618fb4SAlexandre Bounine /* Disable Interrupts */
236748618fb4SAlexandre Bounine tsi721_imsg_interrupt_disable(priv, ch, TSI721_OBDMAC_INT_MASK);
236848618fb4SAlexandre Bounine
236948618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI
237048618fb4SAlexandre Bounine if (priv->flags & TSI721_USING_MSIX) {
237148618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector,
2372748353ccSAlexandre Bounine (void *)priv);
237348618fb4SAlexandre Bounine free_irq(priv->msix[TSI721_VECT_IMB0_INT + mbox].vector,
2374748353ccSAlexandre Bounine (void *)priv);
237548618fb4SAlexandre Bounine }
237648618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */
237748618fb4SAlexandre Bounine
237848618fb4SAlexandre Bounine /* Clear Inbound Buffer Queue */
237948618fb4SAlexandre Bounine for (rx_slot = 0; rx_slot < priv->imsg_ring[mbox].size; rx_slot++)
238048618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[rx_slot] = NULL;
238148618fb4SAlexandre Bounine
238248618fb4SAlexandre Bounine /* Free memory allocated for message buffers */
238348618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
238448618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * TSI721_MSG_BUFFER_SIZE,
238548618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base,
238648618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_phys);
238748618fb4SAlexandre Bounine
238848618fb4SAlexandre Bounine priv->imsg_ring[mbox].buf_base = NULL;
238948618fb4SAlexandre Bounine
239048618fb4SAlexandre Bounine /* Free memory allocated for free pointr list */
239148618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
239248618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * 8,
239348618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base,
239448618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_phys);
239548618fb4SAlexandre Bounine
239648618fb4SAlexandre Bounine priv->imsg_ring[mbox].imfq_base = NULL;
239748618fb4SAlexandre Bounine
239848618fb4SAlexandre Bounine /* Free memory allocated for RX descriptors */
239948618fb4SAlexandre Bounine dma_free_coherent(&priv->pdev->dev,
240048618fb4SAlexandre Bounine priv->imsg_ring[mbox].size * sizeof(struct tsi721_imsg_desc),
240148618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base,
240248618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_phys);
240348618fb4SAlexandre Bounine
240448618fb4SAlexandre Bounine priv->imsg_ring[mbox].imd_base = NULL;
240548618fb4SAlexandre Bounine }
240648618fb4SAlexandre Bounine
240748618fb4SAlexandre Bounine /**
240848618fb4SAlexandre Bounine * tsi721_add_inb_buffer - Add buffer to the Tsi721 inbound message queue
240948618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine
241048618fb4SAlexandre Bounine * @mbox: Inbound mailbox number
241148618fb4SAlexandre Bounine * @buf: Buffer to add to inbound queue
241248618fb4SAlexandre Bounine */
tsi721_add_inb_buffer(struct rio_mport * mport,int mbox,void * buf)241348618fb4SAlexandre Bounine static int tsi721_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
241448618fb4SAlexandre Bounine {
241548618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
241648618fb4SAlexandre Bounine u32 rx_slot;
241748618fb4SAlexandre Bounine int rc = 0;
241848618fb4SAlexandre Bounine
241948618fb4SAlexandre Bounine rx_slot = priv->imsg_ring[mbox].rx_slot;
242048618fb4SAlexandre Bounine if (priv->imsg_ring[mbox].imq_base[rx_slot]) {
242172d8a0d2SAlexandre Bounine tsi_err(&priv->pdev->dev,
242272d8a0d2SAlexandre Bounine "Error adding inbound buffer %d, buffer exists",
242348618fb4SAlexandre Bounine rx_slot);
242448618fb4SAlexandre Bounine rc = -EINVAL;
242548618fb4SAlexandre Bounine goto out;
242648618fb4SAlexandre Bounine }
242748618fb4SAlexandre Bounine
242848618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[rx_slot] = buf;
242948618fb4SAlexandre Bounine
243048618fb4SAlexandre Bounine if (++priv->imsg_ring[mbox].rx_slot == priv->imsg_ring[mbox].size)
243148618fb4SAlexandre Bounine priv->imsg_ring[mbox].rx_slot = 0;
243248618fb4SAlexandre Bounine
243348618fb4SAlexandre Bounine out:
243448618fb4SAlexandre Bounine return rc;
243548618fb4SAlexandre Bounine }
243648618fb4SAlexandre Bounine
243748618fb4SAlexandre Bounine /**
243848618fb4SAlexandre Bounine * tsi721_get_inb_message - Fetch inbound message from the Tsi721 MSG Queue
243948618fb4SAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine
244048618fb4SAlexandre Bounine * @mbox: Inbound mailbox number
244148618fb4SAlexandre Bounine *
244248618fb4SAlexandre Bounine * Returns pointer to the message on success or NULL on failure.
244348618fb4SAlexandre Bounine */
tsi721_get_inb_message(struct rio_mport * mport,int mbox)244448618fb4SAlexandre Bounine static void *tsi721_get_inb_message(struct rio_mport *mport, int mbox)
244548618fb4SAlexandre Bounine {
244648618fb4SAlexandre Bounine struct tsi721_device *priv = mport->priv;
244748618fb4SAlexandre Bounine struct tsi721_imsg_desc *desc;
244848618fb4SAlexandre Bounine u32 rx_slot;
244948618fb4SAlexandre Bounine void *rx_virt = NULL;
245048618fb4SAlexandre Bounine u64 rx_phys;
245148618fb4SAlexandre Bounine void *buf = NULL;
245248618fb4SAlexandre Bounine u64 *free_ptr;
245348618fb4SAlexandre Bounine int ch = mbox + 4;
245448618fb4SAlexandre Bounine int msg_size;
245548618fb4SAlexandre Bounine
245648618fb4SAlexandre Bounine if (!priv->imsg_init[mbox])
245748618fb4SAlexandre Bounine return NULL;
245848618fb4SAlexandre Bounine
245948618fb4SAlexandre Bounine desc = priv->imsg_ring[mbox].imd_base;
246048618fb4SAlexandre Bounine desc += priv->imsg_ring[mbox].desc_rdptr;
246148618fb4SAlexandre Bounine
246248618fb4SAlexandre Bounine if (!(le32_to_cpu(desc->msg_info) & TSI721_IMD_HO))
246348618fb4SAlexandre Bounine goto out;
246448618fb4SAlexandre Bounine
246548618fb4SAlexandre Bounine rx_slot = priv->imsg_ring[mbox].rx_slot;
246648618fb4SAlexandre Bounine while (priv->imsg_ring[mbox].imq_base[rx_slot] == NULL) {
246748618fb4SAlexandre Bounine if (++rx_slot == priv->imsg_ring[mbox].size)
246848618fb4SAlexandre Bounine rx_slot = 0;
246948618fb4SAlexandre Bounine }
247048618fb4SAlexandre Bounine
247148618fb4SAlexandre Bounine rx_phys = ((u64)le32_to_cpu(desc->bufptr_hi) << 32) |
247248618fb4SAlexandre Bounine le32_to_cpu(desc->bufptr_lo);
247348618fb4SAlexandre Bounine
247448618fb4SAlexandre Bounine rx_virt = priv->imsg_ring[mbox].buf_base +
247548618fb4SAlexandre Bounine (rx_phys - (u64)priv->imsg_ring[mbox].buf_phys);
247648618fb4SAlexandre Bounine
247748618fb4SAlexandre Bounine buf = priv->imsg_ring[mbox].imq_base[rx_slot];
247848618fb4SAlexandre Bounine msg_size = le32_to_cpu(desc->msg_info) & TSI721_IMD_BCOUNT;
247948618fb4SAlexandre Bounine if (msg_size == 0)
248048618fb4SAlexandre Bounine msg_size = RIO_MAX_MSG_SIZE;
248148618fb4SAlexandre Bounine
248248618fb4SAlexandre Bounine memcpy(buf, rx_virt, msg_size);
248348618fb4SAlexandre Bounine priv->imsg_ring[mbox].imq_base[rx_slot] = NULL;
248448618fb4SAlexandre Bounine
248548618fb4SAlexandre Bounine desc->msg_info &= cpu_to_le32(~TSI721_IMD_HO);
248648618fb4SAlexandre Bounine if (++priv->imsg_ring[mbox].desc_rdptr == priv->imsg_ring[mbox].size)
248748618fb4SAlexandre Bounine priv->imsg_ring[mbox].desc_rdptr = 0;
248848618fb4SAlexandre Bounine
248948618fb4SAlexandre Bounine iowrite32(priv->imsg_ring[mbox].desc_rdptr,
249048618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_DQRP(ch));
249148618fb4SAlexandre Bounine
249248618fb4SAlexandre Bounine /* Return free buffer into the pointer list */
249348618fb4SAlexandre Bounine free_ptr = priv->imsg_ring[mbox].imfq_base;
249448618fb4SAlexandre Bounine free_ptr[priv->imsg_ring[mbox].fq_wrptr] = cpu_to_le64(rx_phys);
249548618fb4SAlexandre Bounine
249648618fb4SAlexandre Bounine if (++priv->imsg_ring[mbox].fq_wrptr == priv->imsg_ring[mbox].size)
249748618fb4SAlexandre Bounine priv->imsg_ring[mbox].fq_wrptr = 0;
249848618fb4SAlexandre Bounine
249948618fb4SAlexandre Bounine iowrite32(priv->imsg_ring[mbox].fq_wrptr,
250048618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_FQWP(ch));
250148618fb4SAlexandre Bounine out:
250248618fb4SAlexandre Bounine return buf;
250348618fb4SAlexandre Bounine }
250448618fb4SAlexandre Bounine
250548618fb4SAlexandre Bounine /**
250648618fb4SAlexandre Bounine * tsi721_messages_init - Initialization of Messaging Engine
250748618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data
250848618fb4SAlexandre Bounine *
250948618fb4SAlexandre Bounine * Configures Tsi721 messaging engine.
251048618fb4SAlexandre Bounine */
tsi721_messages_init(struct tsi721_device * priv)251148618fb4SAlexandre Bounine static int tsi721_messages_init(struct tsi721_device *priv)
251248618fb4SAlexandre Bounine {
251348618fb4SAlexandre Bounine int ch;
251448618fb4SAlexandre Bounine
251548618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SMSG_ECC_LOG);
251648618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RETRY_GEN_CNT);
251748618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RETRY_RX_CNT);
251848618fb4SAlexandre Bounine
251948618fb4SAlexandre Bounine /* Set SRIO Message Request/Response Timeout */
252048618fb4SAlexandre Bounine iowrite32(TSI721_RQRPTO_VAL, priv->regs + TSI721_RQRPTO);
252148618fb4SAlexandre Bounine
252248618fb4SAlexandre Bounine /* Initialize Inbound Messaging Engine Registers */
252348618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_IMSG_CHNUM; ch++) {
252448618fb4SAlexandre Bounine /* Clear interrupt bits */
252548618fb4SAlexandre Bounine iowrite32(TSI721_IBDMAC_INT_MASK,
252648618fb4SAlexandre Bounine priv->regs + TSI721_IBDMAC_INT(ch));
252748618fb4SAlexandre Bounine /* Clear Status */
252848618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBDMAC_STS(ch));
252948618fb4SAlexandre Bounine
253048618fb4SAlexandre Bounine iowrite32(TSI721_SMSG_ECC_COR_LOG_MASK,
253148618fb4SAlexandre Bounine priv->regs + TSI721_SMSG_ECC_COR_LOG(ch));
253248618fb4SAlexandre Bounine iowrite32(TSI721_SMSG_ECC_NCOR_MASK,
253348618fb4SAlexandre Bounine priv->regs + TSI721_SMSG_ECC_NCOR(ch));
253448618fb4SAlexandre Bounine }
253548618fb4SAlexandre Bounine
253648618fb4SAlexandre Bounine return 0;
253748618fb4SAlexandre Bounine }
253848618fb4SAlexandre Bounine
253948618fb4SAlexandre Bounine /**
2540dbe74afeSAlexandre Bounine * tsi721_query_mport - Fetch inbound message from the Tsi721 MSG Queue
2541dbe74afeSAlexandre Bounine * @mport: Master port implementing the Inbound Messaging Engine
2542dbe74afeSAlexandre Bounine * @mbox: Inbound mailbox number
2543dbe74afeSAlexandre Bounine *
2544dbe74afeSAlexandre Bounine * Returns pointer to the message on success or NULL on failure.
2545dbe74afeSAlexandre Bounine */
tsi721_query_mport(struct rio_mport * mport,struct rio_mport_attr * attr)2546dbe74afeSAlexandre Bounine static int tsi721_query_mport(struct rio_mport *mport,
2547dbe74afeSAlexandre Bounine struct rio_mport_attr *attr)
2548dbe74afeSAlexandre Bounine {
2549dbe74afeSAlexandre Bounine struct tsi721_device *priv = mport->priv;
2550dbe74afeSAlexandre Bounine u32 rval;
2551dbe74afeSAlexandre Bounine
25521ae842deSAlexandre Bounine rval = ioread32(priv->regs + 0x100 + RIO_PORT_N_ERR_STS_CSR(0, 0));
2553dbe74afeSAlexandre Bounine if (rval & RIO_PORT_N_ERR_STS_PORT_OK) {
25541ae842deSAlexandre Bounine rval = ioread32(priv->regs + 0x100 + RIO_PORT_N_CTL2_CSR(0, 0));
2555dbe74afeSAlexandre Bounine attr->link_speed = (rval & RIO_PORT_N_CTL2_SEL_BAUD) >> 28;
25561ae842deSAlexandre Bounine rval = ioread32(priv->regs + 0x100 + RIO_PORT_N_CTL_CSR(0, 0));
2557dbe74afeSAlexandre Bounine attr->link_width = (rval & RIO_PORT_N_CTL_IPW) >> 27;
2558dbe74afeSAlexandre Bounine } else
2559dbe74afeSAlexandre Bounine attr->link_speed = RIO_LINK_DOWN;
2560dbe74afeSAlexandre Bounine
2561dbe74afeSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE
2562dbe74afeSAlexandre Bounine attr->flags = RIO_MPORT_DMA | RIO_MPORT_DMA_SG;
2563dbe74afeSAlexandre Bounine attr->dma_max_sge = 0;
2564dbe74afeSAlexandre Bounine attr->dma_max_size = TSI721_BDMA_MAX_BCOUNT;
2565dbe74afeSAlexandre Bounine attr->dma_align = 0;
2566dbe74afeSAlexandre Bounine #else
2567dbe74afeSAlexandre Bounine attr->flags = 0;
2568dbe74afeSAlexandre Bounine #endif
2569dbe74afeSAlexandre Bounine return 0;
2570dbe74afeSAlexandre Bounine }
2571dbe74afeSAlexandre Bounine
2572dbe74afeSAlexandre Bounine /**
257348618fb4SAlexandre Bounine * tsi721_disable_ints - disables all device interrupts
257448618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data
257548618fb4SAlexandre Bounine */
tsi721_disable_ints(struct tsi721_device * priv)257648618fb4SAlexandre Bounine static void tsi721_disable_ints(struct tsi721_device *priv)
257748618fb4SAlexandre Bounine {
257848618fb4SAlexandre Bounine int ch;
257948618fb4SAlexandre Bounine
258048618fb4SAlexandre Bounine /* Disable all device level interrupts */
258148618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_DEV_INTE);
258248618fb4SAlexandre Bounine
258348618fb4SAlexandre Bounine /* Disable all Device Channel interrupts */
258448618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_DEV_CHAN_INTE);
258548618fb4SAlexandre Bounine
258648618fb4SAlexandre Bounine /* Disable all Inbound Msg Channel interrupts */
258748618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_IMSG_CHNUM; ch++)
258848618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_IBDMAC_INTE(ch));
258948618fb4SAlexandre Bounine
259048618fb4SAlexandre Bounine /* Disable all Outbound Msg Channel interrupts */
259148618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_OMSG_CHNUM; ch++)
259248618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_OBDMAC_INTE(ch));
259348618fb4SAlexandre Bounine
259448618fb4SAlexandre Bounine /* Disable all general messaging interrupts */
259548618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SMSG_INTE);
259648618fb4SAlexandre Bounine
259748618fb4SAlexandre Bounine /* Disable all BDMA Channel interrupts */
259848618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_DMA_MAXCH; ch++)
25999eaa3d9bSAlexandre Bounine iowrite32(0,
26009eaa3d9bSAlexandre Bounine priv->regs + TSI721_DMAC_BASE(ch) + TSI721_DMAC_INTE);
260148618fb4SAlexandre Bounine
260248618fb4SAlexandre Bounine /* Disable all general BDMA interrupts */
260348618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_BDMA_INTE);
260448618fb4SAlexandre Bounine
260548618fb4SAlexandre Bounine /* Disable all SRIO Channel interrupts */
260648618fb4SAlexandre Bounine for (ch = 0; ch < TSI721_SRIO_MAXCH; ch++)
260748618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SR_CHINTE(ch));
260848618fb4SAlexandre Bounine
260948618fb4SAlexandre Bounine /* Disable all general SR2PC interrupts */
261048618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_SR2PC_GEN_INTE);
261148618fb4SAlexandre Bounine
261248618fb4SAlexandre Bounine /* Disable all PC2SR interrupts */
261348618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_PC2SR_INTE);
261448618fb4SAlexandre Bounine
261548618fb4SAlexandre Bounine /* Disable all I2C interrupts */
261648618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_I2C_INT_ENABLE);
261748618fb4SAlexandre Bounine
261848618fb4SAlexandre Bounine /* Disable SRIO MAC interrupts */
261948618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RIO_EM_INT_ENABLE);
262048618fb4SAlexandre Bounine iowrite32(0, priv->regs + TSI721_RIO_EM_DEV_INT_EN);
262148618fb4SAlexandre Bounine }
262248618fb4SAlexandre Bounine
2623748353ccSAlexandre Bounine static struct rio_ops tsi721_rio_ops = {
2624748353ccSAlexandre Bounine .lcread = tsi721_lcread,
2625748353ccSAlexandre Bounine .lcwrite = tsi721_lcwrite,
2626748353ccSAlexandre Bounine .cread = tsi721_cread_dma,
2627748353ccSAlexandre Bounine .cwrite = tsi721_cwrite_dma,
2628748353ccSAlexandre Bounine .dsend = tsi721_dsend,
2629748353ccSAlexandre Bounine .open_inb_mbox = tsi721_open_inb_mbox,
2630748353ccSAlexandre Bounine .close_inb_mbox = tsi721_close_inb_mbox,
2631748353ccSAlexandre Bounine .open_outb_mbox = tsi721_open_outb_mbox,
2632748353ccSAlexandre Bounine .close_outb_mbox = tsi721_close_outb_mbox,
2633748353ccSAlexandre Bounine .add_outb_message = tsi721_add_outb_message,
2634748353ccSAlexandre Bounine .add_inb_buffer = tsi721_add_inb_buffer,
2635748353ccSAlexandre Bounine .get_inb_message = tsi721_get_inb_message,
2636748353ccSAlexandre Bounine .map_inb = tsi721_rio_map_inb_mem,
2637748353ccSAlexandre Bounine .unmap_inb = tsi721_rio_unmap_inb_mem,
2638748353ccSAlexandre Bounine .pwenable = tsi721_pw_enable,
2639748353ccSAlexandre Bounine .query_mport = tsi721_query_mport,
26401679e8daSAlexandre Bounine .map_outb = tsi721_map_outb_win,
26411679e8daSAlexandre Bounine .unmap_outb = tsi721_unmap_outb_win,
2642748353ccSAlexandre Bounine };
2643748353ccSAlexandre Bounine
tsi721_mport_release(struct device * dev)2644748353ccSAlexandre Bounine static void tsi721_mport_release(struct device *dev)
2645748353ccSAlexandre Bounine {
2646748353ccSAlexandre Bounine struct rio_mport *mport = to_rio_mport(dev);
2647748353ccSAlexandre Bounine
264872d8a0d2SAlexandre Bounine tsi_debug(EXIT, dev, "%s id=%d", mport->name, mport->id);
2649748353ccSAlexandre Bounine }
2650748353ccSAlexandre Bounine
265148618fb4SAlexandre Bounine /**
265248618fb4SAlexandre Bounine * tsi721_setup_mport - Setup Tsi721 as RapidIO subsystem master port
265348618fb4SAlexandre Bounine * @priv: pointer to tsi721 private data
265448618fb4SAlexandre Bounine *
265548618fb4SAlexandre Bounine * Configures Tsi721 as RapidIO master port.
265648618fb4SAlexandre Bounine */
tsi721_setup_mport(struct tsi721_device * priv)2657305c891eSBill Pemberton static int tsi721_setup_mport(struct tsi721_device *priv)
265848618fb4SAlexandre Bounine {
265948618fb4SAlexandre Bounine struct pci_dev *pdev = priv->pdev;
266048618fb4SAlexandre Bounine int err = 0;
2661748353ccSAlexandre Bounine struct rio_mport *mport = &priv->mport;
266248618fb4SAlexandre Bounine
2663748353ccSAlexandre Bounine err = rio_mport_initialize(mport);
2664748353ccSAlexandre Bounine if (err)
2665748353ccSAlexandre Bounine return err;
266648618fb4SAlexandre Bounine
2667748353ccSAlexandre Bounine mport->ops = &tsi721_rio_ops;
266848618fb4SAlexandre Bounine mport->index = 0;
266948618fb4SAlexandre Bounine mport->sys_size = 0; /* small system */
267048618fb4SAlexandre Bounine mport->priv = (void *)priv;
267148618fb4SAlexandre Bounine mport->phys_efptr = 0x100;
26721ae842deSAlexandre Bounine mport->phys_rmap = 1;
26732aaf308bSAlexandre Bounine mport->dev.parent = &pdev->dev;
2674748353ccSAlexandre Bounine mport->dev.release = tsi721_mport_release;
267548618fb4SAlexandre Bounine
267648618fb4SAlexandre Bounine INIT_LIST_HEAD(&mport->dbells);
267748618fb4SAlexandre Bounine
267848618fb4SAlexandre Bounine rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
2679b439e66fSAlexandre Bounine rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 3);
2680b439e66fSAlexandre Bounine rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 3);
2681ed43f44fSAlexandre Bounine snprintf(mport->name, RIO_MAX_MPORT_NAME, "%s(%s)",
2682ed43f44fSAlexandre Bounine dev_driver_string(&pdev->dev), dev_name(&pdev->dev));
268348618fb4SAlexandre Bounine
268448618fb4SAlexandre Bounine /* Hook up interrupt handler */
268548618fb4SAlexandre Bounine
268648618fb4SAlexandre Bounine #ifdef CONFIG_PCI_MSI
268748618fb4SAlexandre Bounine if (!tsi721_enable_msix(priv))
268848618fb4SAlexandre Bounine priv->flags |= TSI721_USING_MSIX;
268948618fb4SAlexandre Bounine else if (!pci_enable_msi(pdev))
269048618fb4SAlexandre Bounine priv->flags |= TSI721_USING_MSI;
269148618fb4SAlexandre Bounine else
269272d8a0d2SAlexandre Bounine tsi_debug(MPORT, &pdev->dev,
269372d8a0d2SAlexandre Bounine "MSI/MSI-X is not available. Using legacy INTx.");
269448618fb4SAlexandre Bounine #endif /* CONFIG_PCI_MSI */
269548618fb4SAlexandre Bounine
2696748353ccSAlexandre Bounine err = tsi721_request_irq(priv);
269748618fb4SAlexandre Bounine
2698748353ccSAlexandre Bounine if (err) {
269972d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Unable to get PCI IRQ %02X (err=0x%x)",
270072d8a0d2SAlexandre Bounine pdev->irq, err);
2701748353ccSAlexandre Bounine return err;
27029eaa3d9bSAlexandre Bounine }
270348618fb4SAlexandre Bounine
27049eaa3d9bSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE
2705748353ccSAlexandre Bounine err = tsi721_register_dma(priv);
2706748353ccSAlexandre Bounine if (err)
2707748353ccSAlexandre Bounine goto err_exit;
27089eaa3d9bSAlexandre Bounine #endif
270948618fb4SAlexandre Bounine /* Enable SRIO link */
271048618fb4SAlexandre Bounine iowrite32(ioread32(priv->regs + TSI721_DEVCTL) |
271148618fb4SAlexandre Bounine TSI721_DEVCTL_SRBOOT_CMPL,
271248618fb4SAlexandre Bounine priv->regs + TSI721_DEVCTL);
271348618fb4SAlexandre Bounine
271448618fb4SAlexandre Bounine if (mport->host_deviceid >= 0)
271548618fb4SAlexandre Bounine iowrite32(RIO_PORT_GEN_HOST | RIO_PORT_GEN_MASTER |
271648618fb4SAlexandre Bounine RIO_PORT_GEN_DISCOVERED,
271748618fb4SAlexandre Bounine priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR));
271848618fb4SAlexandre Bounine else
271948618fb4SAlexandre Bounine iowrite32(0, priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR));
272048618fb4SAlexandre Bounine
2721748353ccSAlexandre Bounine err = rio_register_mport(mport);
2722748353ccSAlexandre Bounine if (err) {
2723748353ccSAlexandre Bounine tsi721_unregister_dma(priv);
2724748353ccSAlexandre Bounine goto err_exit;
2725748353ccSAlexandre Bounine }
2726748353ccSAlexandre Bounine
272748618fb4SAlexandre Bounine return 0;
27289eaa3d9bSAlexandre Bounine
27299eaa3d9bSAlexandre Bounine err_exit:
2730748353ccSAlexandre Bounine tsi721_free_irq(priv);
27319eaa3d9bSAlexandre Bounine return err;
273248618fb4SAlexandre Bounine }
273348618fb4SAlexandre Bounine
tsi721_probe(struct pci_dev * pdev,const struct pci_device_id * id)2734305c891eSBill Pemberton static int tsi721_probe(struct pci_dev *pdev,
273548618fb4SAlexandre Bounine const struct pci_device_id *id)
273648618fb4SAlexandre Bounine {
273748618fb4SAlexandre Bounine struct tsi721_device *priv;
273848618fb4SAlexandre Bounine int err;
273948618fb4SAlexandre Bounine
274048618fb4SAlexandre Bounine priv = kzalloc(sizeof(struct tsi721_device), GFP_KERNEL);
274172d8a0d2SAlexandre Bounine if (!priv) {
274248618fb4SAlexandre Bounine err = -ENOMEM;
274348618fb4SAlexandre Bounine goto err_exit;
274448618fb4SAlexandre Bounine }
274548618fb4SAlexandre Bounine
274648618fb4SAlexandre Bounine err = pci_enable_device(pdev);
274748618fb4SAlexandre Bounine if (err) {
274872d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Failed to enable PCI device");
274948618fb4SAlexandre Bounine goto err_clean;
275048618fb4SAlexandre Bounine }
275148618fb4SAlexandre Bounine
275248618fb4SAlexandre Bounine priv->pdev = pdev;
275348618fb4SAlexandre Bounine
275448618fb4SAlexandre Bounine #ifdef DEBUG
27559a9a9a7aSAlexandre Bounine {
27569a9a9a7aSAlexandre Bounine int i;
275772d8a0d2SAlexandre Bounine
2758c9c13ba4SDenis Efremov for (i = 0; i < PCI_STD_NUM_BARS; i++) {
275972d8a0d2SAlexandre Bounine tsi_debug(INIT, &pdev->dev, "res%d %pR",
276072d8a0d2SAlexandre Bounine i, &pdev->resource[i]);
276148618fb4SAlexandre Bounine }
27629a9a9a7aSAlexandre Bounine }
276348618fb4SAlexandre Bounine #endif
276448618fb4SAlexandre Bounine /*
276548618fb4SAlexandre Bounine * Verify BAR configuration
276648618fb4SAlexandre Bounine */
276748618fb4SAlexandre Bounine
276848618fb4SAlexandre Bounine /* BAR_0 (registers) must be 512KB+ in 32-bit address space */
276948618fb4SAlexandre Bounine if (!(pci_resource_flags(pdev, BAR_0) & IORESOURCE_MEM) ||
277048618fb4SAlexandre Bounine pci_resource_flags(pdev, BAR_0) & IORESOURCE_MEM_64 ||
277148618fb4SAlexandre Bounine pci_resource_len(pdev, BAR_0) < TSI721_REG_SPACE_SIZE) {
277272d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Missing or misconfigured CSR BAR0");
277348618fb4SAlexandre Bounine err = -ENODEV;
277448618fb4SAlexandre Bounine goto err_disable_pdev;
277548618fb4SAlexandre Bounine }
277648618fb4SAlexandre Bounine
277748618fb4SAlexandre Bounine /* BAR_1 (outbound doorbells) must be 16MB+ in 32-bit address space */
277848618fb4SAlexandre Bounine if (!(pci_resource_flags(pdev, BAR_1) & IORESOURCE_MEM) ||
277948618fb4SAlexandre Bounine pci_resource_flags(pdev, BAR_1) & IORESOURCE_MEM_64 ||
278048618fb4SAlexandre Bounine pci_resource_len(pdev, BAR_1) < TSI721_DB_WIN_SIZE) {
278172d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Missing or misconfigured Doorbell BAR1");
278248618fb4SAlexandre Bounine err = -ENODEV;
278348618fb4SAlexandre Bounine goto err_disable_pdev;
278448618fb4SAlexandre Bounine }
278548618fb4SAlexandre Bounine
278648618fb4SAlexandre Bounine /*
278748618fb4SAlexandre Bounine * BAR_2 and BAR_4 (outbound translation) must be in 64-bit PCIe address
278848618fb4SAlexandre Bounine * space.
278948618fb4SAlexandre Bounine * NOTE: BAR_2 and BAR_4 are not used by this version of driver.
279048618fb4SAlexandre Bounine * It may be a good idea to keep them disabled using HW configuration
279148618fb4SAlexandre Bounine * to save PCI memory space.
279248618fb4SAlexandre Bounine */
27931679e8daSAlexandre Bounine
27941679e8daSAlexandre Bounine priv->p2r_bar[0].size = priv->p2r_bar[1].size = 0;
27951679e8daSAlexandre Bounine
27961679e8daSAlexandre Bounine if (pci_resource_flags(pdev, BAR_2) & IORESOURCE_MEM_64) {
27971679e8daSAlexandre Bounine if (pci_resource_flags(pdev, BAR_2) & IORESOURCE_PREFETCH)
279872d8a0d2SAlexandre Bounine tsi_debug(INIT, &pdev->dev,
279972d8a0d2SAlexandre Bounine "Prefetchable OBW BAR2 will not be used");
28001679e8daSAlexandre Bounine else {
28011679e8daSAlexandre Bounine priv->p2r_bar[0].base = pci_resource_start(pdev, BAR_2);
28021679e8daSAlexandre Bounine priv->p2r_bar[0].size = pci_resource_len(pdev, BAR_2);
28031679e8daSAlexandre Bounine }
280448618fb4SAlexandre Bounine }
280548618fb4SAlexandre Bounine
28061679e8daSAlexandre Bounine if (pci_resource_flags(pdev, BAR_4) & IORESOURCE_MEM_64) {
28071679e8daSAlexandre Bounine if (pci_resource_flags(pdev, BAR_4) & IORESOURCE_PREFETCH)
280872d8a0d2SAlexandre Bounine tsi_debug(INIT, &pdev->dev,
280972d8a0d2SAlexandre Bounine "Prefetchable OBW BAR4 will not be used");
28101679e8daSAlexandre Bounine else {
28111679e8daSAlexandre Bounine priv->p2r_bar[1].base = pci_resource_start(pdev, BAR_4);
28121679e8daSAlexandre Bounine priv->p2r_bar[1].size = pci_resource_len(pdev, BAR_4);
28131679e8daSAlexandre Bounine }
281448618fb4SAlexandre Bounine }
281548618fb4SAlexandre Bounine
281648618fb4SAlexandre Bounine err = pci_request_regions(pdev, DRV_NAME);
281748618fb4SAlexandre Bounine if (err) {
281872d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Unable to obtain PCI resources");
281948618fb4SAlexandre Bounine goto err_disable_pdev;
282048618fb4SAlexandre Bounine }
282148618fb4SAlexandre Bounine
282248618fb4SAlexandre Bounine pci_set_master(pdev);
282348618fb4SAlexandre Bounine
282448618fb4SAlexandre Bounine priv->regs = pci_ioremap_bar(pdev, BAR_0);
282548618fb4SAlexandre Bounine if (!priv->regs) {
282672d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Unable to map device registers space");
282748618fb4SAlexandre Bounine err = -ENOMEM;
282848618fb4SAlexandre Bounine goto err_free_res;
282948618fb4SAlexandre Bounine }
283048618fb4SAlexandre Bounine
283148618fb4SAlexandre Bounine priv->odb_base = pci_ioremap_bar(pdev, BAR_1);
283248618fb4SAlexandre Bounine if (!priv->odb_base) {
283372d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Unable to map outbound doorbells space");
283448618fb4SAlexandre Bounine err = -ENOMEM;
283548618fb4SAlexandre Bounine goto err_unmap_bars;
283648618fb4SAlexandre Bounine }
283748618fb4SAlexandre Bounine
283848618fb4SAlexandre Bounine /* Configure DMA attributes. */
28398c155674SChristophe JAILLET if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
28408c155674SChristophe JAILLET err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
284118f6287fSPeter Senna Tschudin if (err) {
284272d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "Unable to set DMA mask");
284348618fb4SAlexandre Bounine goto err_unmap_bars;
284448618fb4SAlexandre Bounine }
284548618fb4SAlexandre Bounine
28468c155674SChristophe JAILLET if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)))
284772d8a0d2SAlexandre Bounine tsi_info(&pdev->dev, "Unable to set consistent DMA mask");
284848618fb4SAlexandre Bounine } else {
28498c155674SChristophe JAILLET err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
285048618fb4SAlexandre Bounine if (err)
285172d8a0d2SAlexandre Bounine tsi_info(&pdev->dev, "Unable to set consistent DMA mask");
285248618fb4SAlexandre Bounine }
285348618fb4SAlexandre Bounine
28545cdaaf8aSJiang Liu BUG_ON(!pci_is_pcie(pdev));
28551cee22b7SAlexandre Bounine
2856174f1a71SAlexandre Bounine /* Clear "no snoop" and "relaxed ordering" bits. */
28575cdaaf8aSJiang Liu pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
2858174f1a71SAlexandre Bounine PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN, 0);
28591cee22b7SAlexandre Bounine
2860cb782cddSAlexandre Bounine /* Override PCIe Maximum Read Request Size setting if requested */
2861cb782cddSAlexandre Bounine if (pcie_mrrs >= 0) {
2862cb782cddSAlexandre Bounine if (pcie_mrrs <= 5)
2863cb782cddSAlexandre Bounine pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
2864cb782cddSAlexandre Bounine PCI_EXP_DEVCTL_READRQ, pcie_mrrs << 12);
2865cb782cddSAlexandre Bounine else
2866cb782cddSAlexandre Bounine tsi_info(&pdev->dev,
2867cb782cddSAlexandre Bounine "Invalid MRRS override value %d", pcie_mrrs);
2868cb782cddSAlexandre Bounine }
2869cb782cddSAlexandre Bounine
28707babfa5bSBjorn Helgaas /* Set PCIe completion timeout to 1-10ms */
28717babfa5bSBjorn Helgaas pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2,
28727babfa5bSBjorn Helgaas PCI_EXP_DEVCTL2_COMP_TIMEOUT, 0x2);
287348618fb4SAlexandre Bounine
287448618fb4SAlexandre Bounine /*
287548618fb4SAlexandre Bounine * FIXUP: correct offsets of MSI-X tables in the MSI-X Capability Block
287648618fb4SAlexandre Bounine */
287748618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_EPCTL, 0x01);
287848618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_MSIXTBL,
287948618fb4SAlexandre Bounine TSI721_MSIXTBL_OFFSET);
288048618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_MSIXPBA,
288148618fb4SAlexandre Bounine TSI721_MSIXPBA_OFFSET);
288248618fb4SAlexandre Bounine pci_write_config_dword(pdev, TSI721_PCIECFG_EPCTL, 0);
288348618fb4SAlexandre Bounine /* End of FIXUP */
288448618fb4SAlexandre Bounine
288548618fb4SAlexandre Bounine tsi721_disable_ints(priv);
288648618fb4SAlexandre Bounine
288748618fb4SAlexandre Bounine tsi721_init_pc2sr_mapping(priv);
288848618fb4SAlexandre Bounine tsi721_init_sr2pc_mapping(priv);
288948618fb4SAlexandre Bounine
28909eaa3d9bSAlexandre Bounine if (tsi721_bdma_maint_init(priv)) {
289172d8a0d2SAlexandre Bounine tsi_err(&pdev->dev, "BDMA initialization failed");
289248618fb4SAlexandre Bounine err = -ENOMEM;
289348618fb4SAlexandre Bounine goto err_unmap_bars;
289448618fb4SAlexandre Bounine }
289548618fb4SAlexandre Bounine
289648618fb4SAlexandre Bounine err = tsi721_doorbell_init(priv);
289748618fb4SAlexandre Bounine if (err)
289848618fb4SAlexandre Bounine goto err_free_bdma;
289948618fb4SAlexandre Bounine
290048618fb4SAlexandre Bounine tsi721_port_write_init(priv);
290148618fb4SAlexandre Bounine
290248618fb4SAlexandre Bounine err = tsi721_messages_init(priv);
290348618fb4SAlexandre Bounine if (err)
290448618fb4SAlexandre Bounine goto err_free_consistent;
290548618fb4SAlexandre Bounine
290648618fb4SAlexandre Bounine err = tsi721_setup_mport(priv);
290748618fb4SAlexandre Bounine if (err)
290848618fb4SAlexandre Bounine goto err_free_consistent;
290948618fb4SAlexandre Bounine
2910e3dd8cd4SAlexandre Bounine pci_set_drvdata(pdev, priv);
2911748353ccSAlexandre Bounine tsi721_interrupts_init(priv);
2912e3dd8cd4SAlexandre Bounine
291348618fb4SAlexandre Bounine return 0;
291448618fb4SAlexandre Bounine
291548618fb4SAlexandre Bounine err_free_consistent:
2916748353ccSAlexandre Bounine tsi721_port_write_free(priv);
291748618fb4SAlexandre Bounine tsi721_doorbell_free(priv);
291848618fb4SAlexandre Bounine err_free_bdma:
29199eaa3d9bSAlexandre Bounine tsi721_bdma_maint_free(priv);
292048618fb4SAlexandre Bounine err_unmap_bars:
292148618fb4SAlexandre Bounine if (priv->regs)
292248618fb4SAlexandre Bounine iounmap(priv->regs);
292348618fb4SAlexandre Bounine if (priv->odb_base)
292448618fb4SAlexandre Bounine iounmap(priv->odb_base);
292548618fb4SAlexandre Bounine err_free_res:
292648618fb4SAlexandre Bounine pci_release_regions(pdev);
292748618fb4SAlexandre Bounine err_disable_pdev:
292848618fb4SAlexandre Bounine pci_disable_device(pdev);
292948618fb4SAlexandre Bounine err_clean:
293048618fb4SAlexandre Bounine kfree(priv);
293148618fb4SAlexandre Bounine err_exit:
293248618fb4SAlexandre Bounine return err;
293348618fb4SAlexandre Bounine }
293448618fb4SAlexandre Bounine
tsi721_remove(struct pci_dev * pdev)2935748353ccSAlexandre Bounine static void tsi721_remove(struct pci_dev *pdev)
2936748353ccSAlexandre Bounine {
2937748353ccSAlexandre Bounine struct tsi721_device *priv = pci_get_drvdata(pdev);
2938748353ccSAlexandre Bounine
293972d8a0d2SAlexandre Bounine tsi_debug(EXIT, &pdev->dev, "enter");
2940748353ccSAlexandre Bounine
2941748353ccSAlexandre Bounine tsi721_disable_ints(priv);
2942748353ccSAlexandre Bounine tsi721_free_irq(priv);
2943*7960546cSTetsuo Handa flush_work(&priv->idb_work);
2944*7960546cSTetsuo Handa flush_work(&priv->pw_work);
2945748353ccSAlexandre Bounine rio_unregister_mport(&priv->mport);
2946748353ccSAlexandre Bounine
2947748353ccSAlexandre Bounine tsi721_unregister_dma(priv);
2948748353ccSAlexandre Bounine tsi721_bdma_maint_free(priv);
2949748353ccSAlexandre Bounine tsi721_doorbell_free(priv);
2950748353ccSAlexandre Bounine tsi721_port_write_free(priv);
2951748353ccSAlexandre Bounine tsi721_close_sr2pc_mapping(priv);
2952748353ccSAlexandre Bounine
2953748353ccSAlexandre Bounine if (priv->regs)
2954748353ccSAlexandre Bounine iounmap(priv->regs);
2955748353ccSAlexandre Bounine if (priv->odb_base)
2956748353ccSAlexandre Bounine iounmap(priv->odb_base);
2957748353ccSAlexandre Bounine #ifdef CONFIG_PCI_MSI
2958748353ccSAlexandre Bounine if (priv->flags & TSI721_USING_MSIX)
2959748353ccSAlexandre Bounine pci_disable_msix(priv->pdev);
2960748353ccSAlexandre Bounine else if (priv->flags & TSI721_USING_MSI)
2961748353ccSAlexandre Bounine pci_disable_msi(priv->pdev);
2962748353ccSAlexandre Bounine #endif
2963748353ccSAlexandre Bounine pci_release_regions(pdev);
2964748353ccSAlexandre Bounine pci_disable_device(pdev);
2965748353ccSAlexandre Bounine pci_set_drvdata(pdev, NULL);
2966748353ccSAlexandre Bounine kfree(priv);
296772d8a0d2SAlexandre Bounine tsi_debug(EXIT, &pdev->dev, "exit");
2968748353ccSAlexandre Bounine }
2969748353ccSAlexandre Bounine
tsi721_shutdown(struct pci_dev * pdev)2970e3dd8cd4SAlexandre Bounine static void tsi721_shutdown(struct pci_dev *pdev)
2971e3dd8cd4SAlexandre Bounine {
2972e3dd8cd4SAlexandre Bounine struct tsi721_device *priv = pci_get_drvdata(pdev);
2973e3dd8cd4SAlexandre Bounine
297472d8a0d2SAlexandre Bounine tsi_debug(EXIT, &pdev->dev, "enter");
2975e3dd8cd4SAlexandre Bounine
2976e3dd8cd4SAlexandre Bounine tsi721_disable_ints(priv);
2977e3dd8cd4SAlexandre Bounine tsi721_dma_stop_all(priv);
2978e3dd8cd4SAlexandre Bounine pci_disable_device(pdev);
2979e3dd8cd4SAlexandre Bounine }
2980e3dd8cd4SAlexandre Bounine
29819baa3c34SBenoit Taine static const struct pci_device_id tsi721_pci_tbl[] = {
298248618fb4SAlexandre Bounine { PCI_DEVICE(PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_TSI721) },
298348618fb4SAlexandre Bounine { 0, } /* terminate list */
298448618fb4SAlexandre Bounine };
298548618fb4SAlexandre Bounine
298648618fb4SAlexandre Bounine MODULE_DEVICE_TABLE(pci, tsi721_pci_tbl);
298748618fb4SAlexandre Bounine
298848618fb4SAlexandre Bounine static struct pci_driver tsi721_driver = {
298948618fb4SAlexandre Bounine .name = "tsi721",
299048618fb4SAlexandre Bounine .id_table = tsi721_pci_tbl,
299148618fb4SAlexandre Bounine .probe = tsi721_probe,
2992748353ccSAlexandre Bounine .remove = tsi721_remove,
2993e3dd8cd4SAlexandre Bounine .shutdown = tsi721_shutdown,
299448618fb4SAlexandre Bounine };
299548618fb4SAlexandre Bounine
2996748353ccSAlexandre Bounine module_pci_driver(tsi721_driver);
299794d9bd45SAlexandre Bounine
299894d9bd45SAlexandre Bounine MODULE_DESCRIPTION("IDT Tsi721 PCIExpress-to-SRIO bridge driver");
299994d9bd45SAlexandre Bounine MODULE_AUTHOR("Integrated Device Technology, Inc.");
300094d9bd45SAlexandre Bounine MODULE_LICENSE("GPL");
3001