blob: 85098f8973a9c2e3022512318ee14188da9219a7 [file] [log] [blame]
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001/*
2 * RapidIO mport driver for Tsi721 PCIExpress-to-SRIO bridge
3 *
4 * Copyright 2011 Integrated Device Technology, Inc.
5 * Alexandre Bounine <alexandre.bounine@idt.com>
6 * Chul Kim <chul.kim@idt.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc., 59
20 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23#include <linux/io.h>
24#include <linux/errno.h>
25#include <linux/init.h>
26#include <linux/ioport.h>
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/pci.h>
30#include <linux/rio.h>
31#include <linux/rio_drv.h>
32#include <linux/dma-mapping.h>
33#include <linux/interrupt.h>
34#include <linux/kfifo.h>
35#include <linux/delay.h>
36
37#include "tsi721.h"
38
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -070039#ifdef DEBUG
Alexandre Bouninecb782cd2016-08-02 14:06:40 -070040u32 dbg_level;
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -070041module_param(dbg_level, uint, S_IWUSR | S_IRUGO);
42MODULE_PARM_DESC(dbg_level, "Debugging output level (default 0 = none)");
43#endif
44
Alexandre Bouninecb782cd2016-08-02 14:06:40 -070045static int pcie_mrrs = -1;
46module_param(pcie_mrrs, int, S_IRUGO);
47MODULE_PARM_DESC(pcie_mrrs, "PCIe MRRS override value (0...5)");
48
Alexandre Bounine48618fb2011-11-02 13:39:09 -070049static void tsi721_omsg_handler(struct tsi721_device *priv, int ch);
50static void tsi721_imsg_handler(struct tsi721_device *priv, int ch);
51
52/**
53 * tsi721_lcread - read from local SREP config space
54 * @mport: RapidIO master port info
55 * @index: ID of RapdiIO interface
56 * @offset: Offset into configuration space
57 * @len: Length (in bytes) of the maintenance transaction
58 * @data: Value to be read into
59 *
60 * Generates a local SREP space read. Returns %0 on
61 * success or %-EINVAL on failure.
62 */
63static int tsi721_lcread(struct rio_mport *mport, int index, u32 offset,
64 int len, u32 *data)
65{
66 struct tsi721_device *priv = mport->priv;
67
68 if (len != sizeof(u32))
69 return -EINVAL; /* only 32-bit access is supported */
70
71 *data = ioread32(priv->regs + offset);
72
73 return 0;
74}
75
76/**
77 * tsi721_lcwrite - write into local SREP config space
78 * @mport: RapidIO master port info
79 * @index: ID of RapdiIO interface
80 * @offset: Offset into configuration space
81 * @len: Length (in bytes) of the maintenance transaction
82 * @data: Value to be written
83 *
84 * Generates a local write into SREP configuration space. Returns %0 on
85 * success or %-EINVAL on failure.
86 */
87static int tsi721_lcwrite(struct rio_mport *mport, int index, u32 offset,
88 int len, u32 data)
89{
90 struct tsi721_device *priv = mport->priv;
91
92 if (len != sizeof(u32))
93 return -EINVAL; /* only 32-bit access is supported */
94
95 iowrite32(data, priv->regs + offset);
96
97 return 0;
98}
99
100/**
101 * tsi721_maint_dma - Helper function to generate RapidIO maintenance
102 * transactions using designated Tsi721 DMA channel.
103 * @priv: pointer to tsi721 private data
104 * @sys_size: RapdiIO transport system size
105 * @destid: Destination ID of transaction
106 * @hopcount: Number of hops to target device
107 * @offset: Offset into configuration space
108 * @len: Length (in bytes) of the maintenance transaction
109 * @data: Location to be read from or write into
110 * @do_wr: Operation flag (1 == MAINT_WR)
111 *
112 * Generates a RapidIO maintenance transaction (Read or Write).
113 * Returns %0 on success and %-EINVAL or %-EFAULT on failure.
114 */
115static int tsi721_maint_dma(struct tsi721_device *priv, u32 sys_size,
116 u16 destid, u8 hopcount, u32 offset, int len,
117 u32 *data, int do_wr)
118{
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700119 void __iomem *regs = priv->regs + TSI721_DMAC_BASE(priv->mdma.ch_id);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700120 struct tsi721_dma_desc *bd_ptr;
121 u32 rd_count, swr_ptr, ch_stat;
122 int i, err = 0;
123 u32 op = do_wr ? MAINT_WR : MAINT_RD;
124
125 if (offset > (RIO_MAINT_SPACE_SZ - len) || (len != sizeof(u32)))
126 return -EINVAL;
127
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700128 bd_ptr = priv->mdma.bd_base;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700129
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700130 rd_count = ioread32(regs + TSI721_DMAC_DRDCNT);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700131
132 /* Initialize DMA descriptor */
133 bd_ptr[0].type_id = cpu_to_le32((DTYPE2 << 29) | (op << 19) | destid);
134 bd_ptr[0].bcount = cpu_to_le32((sys_size << 26) | 0x04);
135 bd_ptr[0].raddr_lo = cpu_to_le32((hopcount << 24) | offset);
136 bd_ptr[0].raddr_hi = 0;
137 if (do_wr)
138 bd_ptr[0].data[0] = cpu_to_be32p(data);
139 else
140 bd_ptr[0].data[0] = 0xffffffff;
141
142 mb();
143
144 /* Start DMA operation */
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700145 iowrite32(rd_count + 2, regs + TSI721_DMAC_DWRCNT);
146 ioread32(regs + TSI721_DMAC_DWRCNT);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700147 i = 0;
148
149 /* Wait until DMA transfer is finished */
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700150 while ((ch_stat = ioread32(regs + TSI721_DMAC_STS))
151 & TSI721_DMAC_STS_RUN) {
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700152 udelay(1);
153 if (++i >= 5000000) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700154 tsi_debug(MAINT, &priv->pdev->dev,
155 "DMA[%d] read timeout ch_status=%x",
156 priv->mdma.ch_id, ch_stat);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700157 if (!do_wr)
158 *data = 0xffffffff;
159 err = -EIO;
160 goto err_out;
161 }
162 }
163
164 if (ch_stat & TSI721_DMAC_STS_ABORT) {
165 /* If DMA operation aborted due to error,
166 * reinitialize DMA channel
167 */
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700168 tsi_debug(MAINT, &priv->pdev->dev, "DMA ABORT ch_stat=%x",
169 ch_stat);
170 tsi_debug(MAINT, &priv->pdev->dev,
171 "OP=%d : destid=%x hc=%x off=%x",
172 do_wr ? MAINT_WR : MAINT_RD,
173 destid, hopcount, offset);
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700174 iowrite32(TSI721_DMAC_INT_ALL, regs + TSI721_DMAC_INT);
175 iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700176 udelay(10);
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700177 iowrite32(0, regs + TSI721_DMAC_DWRCNT);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700178 udelay(1);
179 if (!do_wr)
180 *data = 0xffffffff;
181 err = -EIO;
182 goto err_out;
183 }
184
185 if (!do_wr)
186 *data = be32_to_cpu(bd_ptr[0].data[0]);
187
188 /*
189 * Update descriptor status FIFO RD pointer.
190 * NOTE: Skipping check and clear FIFO entries because we are waiting
191 * for transfer to be completed.
192 */
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700193 swr_ptr = ioread32(regs + TSI721_DMAC_DSWP);
194 iowrite32(swr_ptr, regs + TSI721_DMAC_DSRP);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700195err_out:
196
197 return err;
198}
199
200/**
201 * tsi721_cread_dma - Generate a RapidIO maintenance read transaction
202 * using Tsi721 BDMA engine.
203 * @mport: RapidIO master port control structure
204 * @index: ID of RapdiIO interface
205 * @destid: Destination ID of transaction
206 * @hopcount: Number of hops to target device
207 * @offset: Offset into configuration space
208 * @len: Length (in bytes) of the maintenance transaction
209 * @val: Location to be read into
210 *
211 * Generates a RapidIO maintenance read transaction.
212 * Returns %0 on success and %-EINVAL or %-EFAULT on failure.
213 */
214static int tsi721_cread_dma(struct rio_mport *mport, int index, u16 destid,
215 u8 hopcount, u32 offset, int len, u32 *data)
216{
217 struct tsi721_device *priv = mport->priv;
218
219 return tsi721_maint_dma(priv, mport->sys_size, destid, hopcount,
220 offset, len, data, 0);
221}
222
223/**
224 * tsi721_cwrite_dma - Generate a RapidIO maintenance write transaction
225 * using Tsi721 BDMA engine
226 * @mport: RapidIO master port control structure
227 * @index: ID of RapdiIO interface
228 * @destid: Destination ID of transaction
229 * @hopcount: Number of hops to target device
230 * @offset: Offset into configuration space
231 * @len: Length (in bytes) of the maintenance transaction
232 * @val: Value to be written
233 *
234 * Generates a RapidIO maintenance write transaction.
235 * Returns %0 on success and %-EINVAL or %-EFAULT on failure.
236 */
237static int tsi721_cwrite_dma(struct rio_mport *mport, int index, u16 destid,
238 u8 hopcount, u32 offset, int len, u32 data)
239{
240 struct tsi721_device *priv = mport->priv;
241 u32 temp = data;
242
243 return tsi721_maint_dma(priv, mport->sys_size, destid, hopcount,
244 offset, len, &temp, 1);
245}
246
247/**
248 * tsi721_pw_handler - Tsi721 inbound port-write interrupt handler
Alexandre Bounine748353c2016-03-22 14:26:23 -0700249 * @priv: tsi721 device private structure
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700250 *
251 * Handles inbound port-write interrupts. Copies PW message from an internal
252 * buffer into PW message FIFO and schedules deferred routine to process
253 * queued messages.
254 */
255static int
Alexandre Bounine748353c2016-03-22 14:26:23 -0700256tsi721_pw_handler(struct tsi721_device *priv)
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700257{
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700258 u32 pw_stat;
259 u32 pw_buf[TSI721_RIO_PW_MSG_SIZE/sizeof(u32)];
260
261
262 pw_stat = ioread32(priv->regs + TSI721_RIO_PW_RX_STAT);
263
264 if (pw_stat & TSI721_RIO_PW_RX_STAT_PW_VAL) {
265 pw_buf[0] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(0));
266 pw_buf[1] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(1));
267 pw_buf[2] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(2));
268 pw_buf[3] = ioread32(priv->regs + TSI721_RIO_PW_RX_CAPT(3));
269
270 /* Queue PW message (if there is room in FIFO),
271 * otherwise discard it.
272 */
273 spin_lock(&priv->pw_fifo_lock);
274 if (kfifo_avail(&priv->pw_fifo) >= TSI721_RIO_PW_MSG_SIZE)
275 kfifo_in(&priv->pw_fifo, pw_buf,
276 TSI721_RIO_PW_MSG_SIZE);
277 else
278 priv->pw_discard_count++;
279 spin_unlock(&priv->pw_fifo_lock);
280 }
281
282 /* Clear pending PW interrupts */
283 iowrite32(TSI721_RIO_PW_RX_STAT_PW_DISC | TSI721_RIO_PW_RX_STAT_PW_VAL,
284 priv->regs + TSI721_RIO_PW_RX_STAT);
285
286 schedule_work(&priv->pw_work);
287
288 return 0;
289}
290
291static void tsi721_pw_dpc(struct work_struct *work)
292{
293 struct tsi721_device *priv = container_of(work, struct tsi721_device,
294 pw_work);
Alexandre Bounine9a0b0622016-03-22 14:26:44 -0700295 union rio_pw_msg pwmsg;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700296
297 /*
298 * Process port-write messages
299 */
Alexandre Bounine9a0b0622016-03-22 14:26:44 -0700300 while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)&pwmsg,
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700301 TSI721_RIO_PW_MSG_SIZE, &priv->pw_fifo_lock)) {
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700302 /* Pass the port-write message to RIO core for processing */
Alexandre Bounine9a0b0622016-03-22 14:26:44 -0700303 rio_inb_pwrite_handler(&priv->mport, &pwmsg);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700304 }
305}
306
307/**
308 * tsi721_pw_enable - enable/disable port-write interface init
309 * @mport: Master port implementing the port write unit
310 * @enable: 1=enable; 0=disable port-write message handling
311 */
312static int tsi721_pw_enable(struct rio_mport *mport, int enable)
313{
314 struct tsi721_device *priv = mport->priv;
315 u32 rval;
316
317 rval = ioread32(priv->regs + TSI721_RIO_EM_INT_ENABLE);
318
319 if (enable)
320 rval |= TSI721_RIO_EM_INT_ENABLE_PW_RX;
321 else
322 rval &= ~TSI721_RIO_EM_INT_ENABLE_PW_RX;
323
324 /* Clear pending PW interrupts */
325 iowrite32(TSI721_RIO_PW_RX_STAT_PW_DISC | TSI721_RIO_PW_RX_STAT_PW_VAL,
326 priv->regs + TSI721_RIO_PW_RX_STAT);
327 /* Update enable bits */
328 iowrite32(rval, priv->regs + TSI721_RIO_EM_INT_ENABLE);
329
330 return 0;
331}
332
333/**
334 * tsi721_dsend - Send a RapidIO doorbell
335 * @mport: RapidIO master port info
336 * @index: ID of RapidIO interface
337 * @destid: Destination ID of target device
338 * @data: 16-bit info field of RapidIO doorbell
339 *
340 * Sends a RapidIO doorbell message. Always returns %0.
341 */
342static int tsi721_dsend(struct rio_mport *mport, int index,
343 u16 destid, u16 data)
344{
345 struct tsi721_device *priv = mport->priv;
346 u32 offset;
347
348 offset = (((mport->sys_size) ? RIO_TT_CODE_16 : RIO_TT_CODE_8) << 18) |
349 (destid << 2);
350
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700351 tsi_debug(DBELL, &priv->pdev->dev,
352 "Send Doorbell 0x%04x to destID 0x%x", data, destid);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700353 iowrite16be(data, priv->odb_base + offset);
354
355 return 0;
356}
357
358/**
359 * tsi721_dbell_handler - Tsi721 doorbell interrupt handler
Alexandre Bounine748353c2016-03-22 14:26:23 -0700360 * @priv: tsi721 device-specific data structure
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700361 *
362 * Handles inbound doorbell interrupts. Copies doorbell entry from an internal
363 * buffer into DB message FIFO and schedules deferred routine to process
364 * queued DBs.
365 */
366static int
Alexandre Bounine748353c2016-03-22 14:26:23 -0700367tsi721_dbell_handler(struct tsi721_device *priv)
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700368{
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700369 u32 regval;
370
371 /* Disable IDB interrupts */
372 regval = ioread32(priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
373 regval &= ~TSI721_SR_CHINT_IDBQRCV;
374 iowrite32(regval,
375 priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
376
377 schedule_work(&priv->idb_work);
378
379 return 0;
380}
381
382static void tsi721_db_dpc(struct work_struct *work)
383{
384 struct tsi721_device *priv = container_of(work, struct tsi721_device,
385 idb_work);
386 struct rio_mport *mport;
387 struct rio_dbell *dbell;
388 int found = 0;
389 u32 wr_ptr, rd_ptr;
390 u64 *idb_entry;
391 u32 regval;
392 union {
393 u64 msg;
394 u8 bytes[8];
395 } idb;
396
397 /*
398 * Process queued inbound doorbells
399 */
Alexandre Bounine748353c2016-03-22 14:26:23 -0700400 mport = &priv->mport;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700401
Alexandre Bounineb24823e2012-03-05 14:59:21 -0800402 wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE;
403 rd_ptr = ioread32(priv->regs + TSI721_IDQ_RP(IDB_QUEUE)) % IDB_QSIZE;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700404
405 while (wr_ptr != rd_ptr) {
406 idb_entry = (u64 *)(priv->idb_base +
407 (TSI721_IDB_ENTRY_SIZE * rd_ptr));
408 rd_ptr++;
Alexandre Bounineb24823e2012-03-05 14:59:21 -0800409 rd_ptr %= IDB_QSIZE;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700410 idb.msg = *idb_entry;
411 *idb_entry = 0;
412
413 /* Process one doorbell */
414 list_for_each_entry(dbell, &mport->dbells, node) {
415 if ((dbell->res->start <= DBELL_INF(idb.bytes)) &&
416 (dbell->res->end >= DBELL_INF(idb.bytes))) {
417 found = 1;
418 break;
419 }
420 }
421
422 if (found) {
423 dbell->dinb(mport, dbell->dev_id, DBELL_SID(idb.bytes),
424 DBELL_TID(idb.bytes), DBELL_INF(idb.bytes));
425 } else {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700426 tsi_debug(DBELL, &priv->pdev->dev,
427 "spurious IDB sid %2.2x tid %2.2x info %4.4x",
428 DBELL_SID(idb.bytes), DBELL_TID(idb.bytes),
429 DBELL_INF(idb.bytes));
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700430 }
Alexandre Bounine3670e7e2012-08-21 16:16:11 -0700431
432 wr_ptr = ioread32(priv->regs +
433 TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700434 }
435
436 iowrite32(rd_ptr & (IDB_QSIZE - 1),
437 priv->regs + TSI721_IDQ_RP(IDB_QUEUE));
438
439 /* Re-enable IDB interrupts */
440 regval = ioread32(priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
441 regval |= TSI721_SR_CHINT_IDBQRCV;
442 iowrite32(regval,
443 priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
Alexandre Bounine3670e7e2012-08-21 16:16:11 -0700444
445 wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE;
446 if (wr_ptr != rd_ptr)
447 schedule_work(&priv->idb_work);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700448}
449
450/**
451 * tsi721_irqhandler - Tsi721 interrupt handler
452 * @irq: Linux interrupt number
Alexandre Bounine748353c2016-03-22 14:26:23 -0700453 * @ptr: Pointer to interrupt-specific data (tsi721_device structure)
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700454 *
455 * Handles Tsi721 interrupts signaled using MSI and INTA. Checks reported
456 * interrupt events and calls an event-specific handler(s).
457 */
458static irqreturn_t tsi721_irqhandler(int irq, void *ptr)
459{
Alexandre Bounine748353c2016-03-22 14:26:23 -0700460 struct tsi721_device *priv = (struct tsi721_device *)ptr;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700461 u32 dev_int;
462 u32 dev_ch_int;
463 u32 intval;
464 u32 ch_inte;
465
Alexandre Bounine1ccc8192013-05-24 15:55:17 -0700466 /* For MSI mode disable all device-level interrupts */
467 if (priv->flags & TSI721_USING_MSI)
468 iowrite32(0, priv->regs + TSI721_DEV_INTE);
469
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700470 dev_int = ioread32(priv->regs + TSI721_DEV_INT);
471 if (!dev_int)
472 return IRQ_NONE;
473
474 dev_ch_int = ioread32(priv->regs + TSI721_DEV_CHAN_INT);
475
476 if (dev_int & TSI721_DEV_INT_SR2PC_CH) {
477 /* Service SR2PC Channel interrupts */
478 if (dev_ch_int & TSI721_INT_SR2PC_CHAN(IDB_QUEUE)) {
479 /* Service Inbound Doorbell interrupt */
480 intval = ioread32(priv->regs +
481 TSI721_SR_CHINT(IDB_QUEUE));
482 if (intval & TSI721_SR_CHINT_IDBQRCV)
Alexandre Bounine748353c2016-03-22 14:26:23 -0700483 tsi721_dbell_handler(priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700484 else
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700485 tsi_info(&priv->pdev->dev,
486 "Unsupported SR_CH_INT %x", intval);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700487
488 /* Clear interrupts */
489 iowrite32(intval,
490 priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
491 ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
492 }
493 }
494
495 if (dev_int & TSI721_DEV_INT_SMSG_CH) {
496 int ch;
497
498 /*
499 * Service channel interrupts from Messaging Engine
500 */
501
502 if (dev_ch_int & TSI721_INT_IMSG_CHAN_M) { /* Inbound Msg */
503 /* Disable signaled OB MSG Channel interrupts */
504 ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
505 ch_inte &= ~(dev_ch_int & TSI721_INT_IMSG_CHAN_M);
506 iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE);
507
508 /*
509 * Process Inbound Message interrupt for each MBOX
510 */
511 for (ch = 4; ch < RIO_MAX_MBOX + 4; ch++) {
512 if (!(dev_ch_int & TSI721_INT_IMSG_CHAN(ch)))
513 continue;
514 tsi721_imsg_handler(priv, ch);
515 }
516 }
517
518 if (dev_ch_int & TSI721_INT_OMSG_CHAN_M) { /* Outbound Msg */
519 /* Disable signaled OB MSG Channel interrupts */
520 ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
521 ch_inte &= ~(dev_ch_int & TSI721_INT_OMSG_CHAN_M);
522 iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE);
523
524 /*
525 * Process Outbound Message interrupts for each MBOX
526 */
527
528 for (ch = 0; ch < RIO_MAX_MBOX; ch++) {
529 if (!(dev_ch_int & TSI721_INT_OMSG_CHAN(ch)))
530 continue;
531 tsi721_omsg_handler(priv, ch);
532 }
533 }
534 }
535
536 if (dev_int & TSI721_DEV_INT_SRIO) {
537 /* Service SRIO MAC interrupts */
538 intval = ioread32(priv->regs + TSI721_RIO_EM_INT_STAT);
539 if (intval & TSI721_RIO_EM_INT_STAT_PW_RX)
Alexandre Bounine748353c2016-03-22 14:26:23 -0700540 tsi721_pw_handler(priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700541 }
542
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700543#ifdef CONFIG_RAPIDIO_DMA_ENGINE
544 if (dev_int & TSI721_DEV_INT_BDMA_CH) {
545 int ch;
546
547 if (dev_ch_int & TSI721_INT_BDMA_CHAN_M) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700548 tsi_debug(DMA, &priv->pdev->dev,
549 "IRQ from DMA channel 0x%08x", dev_ch_int);
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700550
551 for (ch = 0; ch < TSI721_DMA_MAXCH; ch++) {
552 if (!(dev_ch_int & TSI721_INT_BDMA_CHAN(ch)))
553 continue;
554 tsi721_bdma_handler(&priv->bdma[ch]);
555 }
556 }
557 }
558#endif
Alexandre Bounine1ccc8192013-05-24 15:55:17 -0700559
560 /* For MSI mode re-enable device-level interrupts */
561 if (priv->flags & TSI721_USING_MSI) {
562 dev_int = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO |
563 TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH;
564 iowrite32(dev_int, priv->regs + TSI721_DEV_INTE);
565 }
566
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700567 return IRQ_HANDLED;
568}
569
570static void tsi721_interrupts_init(struct tsi721_device *priv)
571{
572 u32 intr;
573
574 /* Enable IDB interrupts */
575 iowrite32(TSI721_SR_CHINT_ALL,
576 priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
577 iowrite32(TSI721_SR_CHINT_IDBQRCV,
578 priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700579
580 /* Enable SRIO MAC interrupts */
581 iowrite32(TSI721_RIO_EM_DEV_INT_EN_INT,
582 priv->regs + TSI721_RIO_EM_DEV_INT_EN);
583
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700584 /* Enable interrupts from channels in use */
585#ifdef CONFIG_RAPIDIO_DMA_ENGINE
586 intr = TSI721_INT_SR2PC_CHAN(IDB_QUEUE) |
587 (TSI721_INT_BDMA_CHAN_M &
588 ~TSI721_INT_BDMA_CHAN(TSI721_DMACH_MAINT));
589#else
590 intr = TSI721_INT_SR2PC_CHAN(IDB_QUEUE);
591#endif
592 iowrite32(intr, priv->regs + TSI721_DEV_CHAN_INTE);
593
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700594 if (priv->flags & TSI721_USING_MSIX)
595 intr = TSI721_DEV_INT_SRIO;
596 else
597 intr = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO |
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700598 TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700599
600 iowrite32(intr, priv->regs + TSI721_DEV_INTE);
601 ioread32(priv->regs + TSI721_DEV_INTE);
602}
603
604#ifdef CONFIG_PCI_MSI
605/**
606 * tsi721_omsg_msix - MSI-X interrupt handler for outbound messaging
607 * @irq: Linux interrupt number
Alexandre Bounine748353c2016-03-22 14:26:23 -0700608 * @ptr: Pointer to interrupt-specific data (tsi721_device structure)
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700609 *
610 * Handles outbound messaging interrupts signaled using MSI-X.
611 */
612static irqreturn_t tsi721_omsg_msix(int irq, void *ptr)
613{
Alexandre Bounine748353c2016-03-22 14:26:23 -0700614 struct tsi721_device *priv = (struct tsi721_device *)ptr;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700615 int mbox;
616
617 mbox = (irq - priv->msix[TSI721_VECT_OMB0_DONE].vector) % RIO_MAX_MBOX;
618 tsi721_omsg_handler(priv, mbox);
619 return IRQ_HANDLED;
620}
621
622/**
623 * tsi721_imsg_msix - MSI-X interrupt handler for inbound messaging
624 * @irq: Linux interrupt number
Alexandre Bounine748353c2016-03-22 14:26:23 -0700625 * @ptr: Pointer to interrupt-specific data (tsi721_device structure)
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700626 *
627 * Handles inbound messaging interrupts signaled using MSI-X.
628 */
629static irqreturn_t tsi721_imsg_msix(int irq, void *ptr)
630{
Alexandre Bounine748353c2016-03-22 14:26:23 -0700631 struct tsi721_device *priv = (struct tsi721_device *)ptr;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700632 int mbox;
633
634 mbox = (irq - priv->msix[TSI721_VECT_IMB0_RCV].vector) % RIO_MAX_MBOX;
635 tsi721_imsg_handler(priv, mbox + 4);
636 return IRQ_HANDLED;
637}
638
639/**
640 * tsi721_srio_msix - Tsi721 MSI-X SRIO MAC interrupt handler
641 * @irq: Linux interrupt number
Alexandre Bounine748353c2016-03-22 14:26:23 -0700642 * @ptr: Pointer to interrupt-specific data (tsi721_device structure)
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700643 *
644 * Handles Tsi721 interrupts from SRIO MAC.
645 */
646static irqreturn_t tsi721_srio_msix(int irq, void *ptr)
647{
Alexandre Bounine748353c2016-03-22 14:26:23 -0700648 struct tsi721_device *priv = (struct tsi721_device *)ptr;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700649 u32 srio_int;
650
651 /* Service SRIO MAC interrupts */
652 srio_int = ioread32(priv->regs + TSI721_RIO_EM_INT_STAT);
653 if (srio_int & TSI721_RIO_EM_INT_STAT_PW_RX)
Alexandre Bounine748353c2016-03-22 14:26:23 -0700654 tsi721_pw_handler(priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700655
656 return IRQ_HANDLED;
657}
658
659/**
660 * tsi721_sr2pc_ch_msix - Tsi721 MSI-X SR2PC Channel interrupt handler
661 * @irq: Linux interrupt number
Alexandre Bounine748353c2016-03-22 14:26:23 -0700662 * @ptr: Pointer to interrupt-specific data (tsi721_device structure)
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700663 *
664 * Handles Tsi721 interrupts from SR2PC Channel.
665 * NOTE: At this moment services only one SR2PC channel associated with inbound
666 * doorbells.
667 */
668static irqreturn_t tsi721_sr2pc_ch_msix(int irq, void *ptr)
669{
Alexandre Bounine748353c2016-03-22 14:26:23 -0700670 struct tsi721_device *priv = (struct tsi721_device *)ptr;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700671 u32 sr_ch_int;
672
673 /* Service Inbound DB interrupt from SR2PC channel */
674 sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
675 if (sr_ch_int & TSI721_SR_CHINT_IDBQRCV)
Alexandre Bounine748353c2016-03-22 14:26:23 -0700676 tsi721_dbell_handler(priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700677
678 /* Clear interrupts */
679 iowrite32(sr_ch_int, priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
680 /* Read back to ensure that interrupt was cleared */
681 sr_ch_int = ioread32(priv->regs + TSI721_SR_CHINT(IDB_QUEUE));
682
683 return IRQ_HANDLED;
684}
685
686/**
687 * tsi721_request_msix - register interrupt service for MSI-X mode.
Alexandre Bounine748353c2016-03-22 14:26:23 -0700688 * @priv: tsi721 device-specific data structure
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700689 *
690 * Registers MSI-X interrupt service routines for interrupts that are active
691 * immediately after mport initialization. Messaging interrupt service routines
692 * should be registered during corresponding open requests.
693 */
Alexandre Bounine748353c2016-03-22 14:26:23 -0700694static int tsi721_request_msix(struct tsi721_device *priv)
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700695{
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700696 int err = 0;
697
698 err = request_irq(priv->msix[TSI721_VECT_IDB].vector,
699 tsi721_sr2pc_ch_msix, 0,
Alexandre Bounine748353c2016-03-22 14:26:23 -0700700 priv->msix[TSI721_VECT_IDB].irq_name, (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700701 if (err)
Alexandre Bounine748353c2016-03-22 14:26:23 -0700702 return err;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700703
704 err = request_irq(priv->msix[TSI721_VECT_PWRX].vector,
705 tsi721_srio_msix, 0,
Alexandre Bounine748353c2016-03-22 14:26:23 -0700706 priv->msix[TSI721_VECT_PWRX].irq_name, (void *)priv);
707 if (err) {
708 free_irq(priv->msix[TSI721_VECT_IDB].vector, (void *)priv);
709 return err;
710 }
711
712 return 0;
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700713}
714
715/**
716 * tsi721_enable_msix - Attempts to enable MSI-X support for Tsi721.
717 * @priv: pointer to tsi721 private data
718 *
719 * Configures MSI-X support for Tsi721. Supports only an exact number
720 * of requested vectors.
721 */
722static int tsi721_enable_msix(struct tsi721_device *priv)
723{
724 struct msix_entry entries[TSI721_VECT_MAX];
725 int err;
726 int i;
727
728 entries[TSI721_VECT_IDB].entry = TSI721_MSIX_SR2PC_IDBQ_RCV(IDB_QUEUE);
729 entries[TSI721_VECT_PWRX].entry = TSI721_MSIX_SRIO_MAC_INT;
730
731 /*
732 * Initialize MSI-X entries for Messaging Engine:
733 * this driver supports four RIO mailboxes (inbound and outbound)
734 * NOTE: Inbound message MBOX 0...4 use IB channels 4...7. Therefore
735 * offset +4 is added to IB MBOX number.
736 */
737 for (i = 0; i < RIO_MAX_MBOX; i++) {
738 entries[TSI721_VECT_IMB0_RCV + i].entry =
739 TSI721_MSIX_IMSG_DQ_RCV(i + 4);
740 entries[TSI721_VECT_IMB0_INT + i].entry =
741 TSI721_MSIX_IMSG_INT(i + 4);
742 entries[TSI721_VECT_OMB0_DONE + i].entry =
743 TSI721_MSIX_OMSG_DONE(i);
744 entries[TSI721_VECT_OMB0_INT + i].entry =
745 TSI721_MSIX_OMSG_INT(i);
746 }
747
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700748#ifdef CONFIG_RAPIDIO_DMA_ENGINE
749 /*
750 * Initialize MSI-X entries for Block DMA Engine:
751 * this driver supports XXX DMA channels
752 * (one is reserved for SRIO maintenance transactions)
753 */
754 for (i = 0; i < TSI721_DMA_CHNUM; i++) {
755 entries[TSI721_VECT_DMA0_DONE + i].entry =
756 TSI721_MSIX_DMACH_DONE(i);
757 entries[TSI721_VECT_DMA0_INT + i].entry =
758 TSI721_MSIX_DMACH_INT(i);
759 }
760#endif /* CONFIG_RAPIDIO_DMA_ENGINE */
761
Alexander Gordeev1c92ab12014-06-06 14:37:16 -0700762 err = pci_enable_msix_exact(priv->pdev, entries, ARRAY_SIZE(entries));
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700763 if (err) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700764 tsi_err(&priv->pdev->dev,
765 "Failed to enable MSI-X (err=%d)", err);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700766 return err;
767 }
768
769 /*
770 * Copy MSI-X vector information into tsi721 private structure
771 */
772 priv->msix[TSI721_VECT_IDB].vector = entries[TSI721_VECT_IDB].vector;
773 snprintf(priv->msix[TSI721_VECT_IDB].irq_name, IRQ_DEVICE_NAME_MAX,
774 DRV_NAME "-idb@pci:%s", pci_name(priv->pdev));
775 priv->msix[TSI721_VECT_PWRX].vector = entries[TSI721_VECT_PWRX].vector;
776 snprintf(priv->msix[TSI721_VECT_PWRX].irq_name, IRQ_DEVICE_NAME_MAX,
777 DRV_NAME "-pwrx@pci:%s", pci_name(priv->pdev));
778
779 for (i = 0; i < RIO_MAX_MBOX; i++) {
780 priv->msix[TSI721_VECT_IMB0_RCV + i].vector =
781 entries[TSI721_VECT_IMB0_RCV + i].vector;
782 snprintf(priv->msix[TSI721_VECT_IMB0_RCV + i].irq_name,
783 IRQ_DEVICE_NAME_MAX, DRV_NAME "-imbr%d@pci:%s",
784 i, pci_name(priv->pdev));
785
786 priv->msix[TSI721_VECT_IMB0_INT + i].vector =
787 entries[TSI721_VECT_IMB0_INT + i].vector;
788 snprintf(priv->msix[TSI721_VECT_IMB0_INT + i].irq_name,
789 IRQ_DEVICE_NAME_MAX, DRV_NAME "-imbi%d@pci:%s",
790 i, pci_name(priv->pdev));
791
792 priv->msix[TSI721_VECT_OMB0_DONE + i].vector =
793 entries[TSI721_VECT_OMB0_DONE + i].vector;
794 snprintf(priv->msix[TSI721_VECT_OMB0_DONE + i].irq_name,
795 IRQ_DEVICE_NAME_MAX, DRV_NAME "-ombd%d@pci:%s",
796 i, pci_name(priv->pdev));
797
798 priv->msix[TSI721_VECT_OMB0_INT + i].vector =
799 entries[TSI721_VECT_OMB0_INT + i].vector;
800 snprintf(priv->msix[TSI721_VECT_OMB0_INT + i].irq_name,
801 IRQ_DEVICE_NAME_MAX, DRV_NAME "-ombi%d@pci:%s",
802 i, pci_name(priv->pdev));
803 }
804
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -0700805#ifdef CONFIG_RAPIDIO_DMA_ENGINE
806 for (i = 0; i < TSI721_DMA_CHNUM; i++) {
807 priv->msix[TSI721_VECT_DMA0_DONE + i].vector =
808 entries[TSI721_VECT_DMA0_DONE + i].vector;
809 snprintf(priv->msix[TSI721_VECT_DMA0_DONE + i].irq_name,
810 IRQ_DEVICE_NAME_MAX, DRV_NAME "-dmad%d@pci:%s",
811 i, pci_name(priv->pdev));
812
813 priv->msix[TSI721_VECT_DMA0_INT + i].vector =
814 entries[TSI721_VECT_DMA0_INT + i].vector;
815 snprintf(priv->msix[TSI721_VECT_DMA0_INT + i].irq_name,
816 IRQ_DEVICE_NAME_MAX, DRV_NAME "-dmai%d@pci:%s",
817 i, pci_name(priv->pdev));
818 }
819#endif /* CONFIG_RAPIDIO_DMA_ENGINE */
820
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700821 return 0;
822}
823#endif /* CONFIG_PCI_MSI */
824
Alexandre Bounine748353c2016-03-22 14:26:23 -0700825static int tsi721_request_irq(struct tsi721_device *priv)
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700826{
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700827 int err;
828
829#ifdef CONFIG_PCI_MSI
830 if (priv->flags & TSI721_USING_MSIX)
Alexandre Bounine748353c2016-03-22 14:26:23 -0700831 err = tsi721_request_msix(priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700832 else
833#endif
834 err = request_irq(priv->pdev->irq, tsi721_irqhandler,
835 (priv->flags & TSI721_USING_MSI) ? 0 : IRQF_SHARED,
Alexandre Bounine748353c2016-03-22 14:26:23 -0700836 DRV_NAME, (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700837
838 if (err)
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700839 tsi_err(&priv->pdev->dev,
840 "Unable to allocate interrupt, err=%d", err);
Alexandre Bounine48618fb2011-11-02 13:39:09 -0700841
842 return err;
843}
844
Alexandre Bounine748353c2016-03-22 14:26:23 -0700845static void tsi721_free_irq(struct tsi721_device *priv)
846{
847#ifdef CONFIG_PCI_MSI
848 if (priv->flags & TSI721_USING_MSIX) {
849 free_irq(priv->msix[TSI721_VECT_IDB].vector, (void *)priv);
850 free_irq(priv->msix[TSI721_VECT_PWRX].vector, (void *)priv);
851 } else
852#endif
853 free_irq(priv->pdev->irq, (void *)priv);
854}
855
Alexandre Bounine1679e8d2016-03-22 14:26:53 -0700856static int
857tsi721_obw_alloc(struct tsi721_device *priv, struct tsi721_obw_bar *pbar,
858 u32 size, int *win_id)
859{
860 u64 win_base;
861 u64 bar_base;
862 u64 bar_end;
863 u32 align;
864 struct tsi721_ob_win *win;
865 struct tsi721_ob_win *new_win = NULL;
866 int new_win_idx = -1;
867 int i = 0;
868
869 bar_base = pbar->base;
870 bar_end = bar_base + pbar->size;
871 win_base = bar_base;
872 align = size/TSI721_PC2SR_ZONES;
873
874 while (i < TSI721_IBWIN_NUM) {
875 for (i = 0; i < TSI721_IBWIN_NUM; i++) {
876 if (!priv->ob_win[i].active) {
877 if (new_win == NULL) {
878 new_win = &priv->ob_win[i];
879 new_win_idx = i;
880 }
881 continue;
882 }
883
884 /*
885 * If this window belongs to the current BAR check it
886 * for overlap
887 */
888 win = &priv->ob_win[i];
889
890 if (win->base >= bar_base && win->base < bar_end) {
891 if (win_base < (win->base + win->size) &&
892 (win_base + size) > win->base) {
893 /* Overlap detected */
894 win_base = win->base + win->size;
895 win_base = ALIGN(win_base, align);
896 break;
897 }
898 }
899 }
900 }
901
902 if (win_base + size > bar_end)
903 return -ENOMEM;
904
905 if (!new_win) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700906 tsi_err(&priv->pdev->dev, "OBW count tracking failed");
Alexandre Bounine1679e8d2016-03-22 14:26:53 -0700907 return -EIO;
908 }
909
910 new_win->active = true;
911 new_win->base = win_base;
912 new_win->size = size;
913 new_win->pbar = pbar;
914 priv->obwin_cnt--;
915 pbar->free -= size;
916 *win_id = new_win_idx;
917 return 0;
918}
919
920static int tsi721_map_outb_win(struct rio_mport *mport, u16 destid, u64 rstart,
921 u32 size, u32 flags, dma_addr_t *laddr)
922{
923 struct tsi721_device *priv = mport->priv;
924 int i;
925 struct tsi721_obw_bar *pbar;
926 struct tsi721_ob_win *ob_win;
927 int obw = -1;
928 u32 rval;
929 u64 rio_addr;
930 u32 zsize;
931 int ret = -ENOMEM;
932
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700933 tsi_debug(OBW, &priv->pdev->dev,
934 "did=%d ra=0x%llx sz=0x%x", destid, rstart, size);
935
Alexandre Bounine1679e8d2016-03-22 14:26:53 -0700936 if (!is_power_of_2(size) || (size < 0x8000) || (rstart & (size - 1)))
937 return -EINVAL;
938
939 if (priv->obwin_cnt == 0)
940 return -EBUSY;
941
942 for (i = 0; i < 2; i++) {
943 if (priv->p2r_bar[i].free >= size) {
944 pbar = &priv->p2r_bar[i];
945 ret = tsi721_obw_alloc(priv, pbar, size, &obw);
946 if (!ret)
947 break;
948 }
949 }
950
951 if (ret)
952 return ret;
953
954 WARN_ON(obw == -1);
955 ob_win = &priv->ob_win[obw];
956 ob_win->destid = destid;
957 ob_win->rstart = rstart;
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -0700958 tsi_debug(OBW, &priv->pdev->dev,
959 "allocated OBW%d @%llx", obw, ob_win->base);
Alexandre Bounine1679e8d2016-03-22 14:26:53 -0700960
961 /*
962 * Configure Outbound Window
963 */
964
965 zsize = size/TSI721_PC2SR_ZONES;
966 rio_addr = rstart;
967
968 /*
969 * Program Address Translation Zones:
970 * This implementation uses all 8 zones associated wit window.
971 */
972 for (i = 0; i < TSI721_PC2SR_ZONES; i++) {
973
974 while (ioread32(priv->regs + TSI721_ZONE_SEL) &
975 TSI721_ZONE_SEL_GO) {
976 udelay(1);
977 }
978
979 rval = (u32)(rio_addr & TSI721_LUT_DATA0_ADD) |
980 TSI721_LUT_DATA0_NREAD | TSI721_LUT_DATA0_NWR;
981 iowrite32(rval, priv->regs + TSI721_LUT_DATA0);
982 rval = (u32)(rio_addr >> 32);
983 iowrite32(rval, priv->regs + TSI721_LUT_DATA1);
984 rval = destid;
985 iowrite32(rval, priv->regs + TSI721_LUT_DATA2);
986
987 rval = TSI721_ZONE_SEL_GO | (obw << 3) | i;
988 iowrite32(rval, priv->regs + TSI721_ZONE_SEL);
989
990 rio_addr += zsize;
991 }
992
993 iowrite32(TSI721_OBWIN_SIZE(size) << 8,
994 priv->regs + TSI721_OBWINSZ(obw));
995 iowrite32((u32)(ob_win->base >> 32), priv->regs + TSI721_OBWINUB(obw));
996 iowrite32((u32)(ob_win->base & TSI721_OBWINLB_BA) | TSI721_OBWINLB_WEN,
997 priv->regs + TSI721_OBWINLB(obw));
998
999 *laddr = ob_win->base;
1000 return 0;
1001}
1002
1003static void tsi721_unmap_outb_win(struct rio_mport *mport,
1004 u16 destid, u64 rstart)
1005{
1006 struct tsi721_device *priv = mport->priv;
1007 struct tsi721_ob_win *ob_win;
1008 int i;
1009
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001010 tsi_debug(OBW, &priv->pdev->dev, "did=%d ra=0x%llx", destid, rstart);
1011
Alexandre Bounine1679e8d2016-03-22 14:26:53 -07001012 for (i = 0; i < TSI721_OBWIN_NUM; i++) {
1013 ob_win = &priv->ob_win[i];
1014
1015 if (ob_win->active &&
1016 ob_win->destid == destid && ob_win->rstart == rstart) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001017 tsi_debug(OBW, &priv->pdev->dev,
1018 "free OBW%d @%llx", i, ob_win->base);
Alexandre Bounine1679e8d2016-03-22 14:26:53 -07001019 ob_win->active = false;
1020 iowrite32(0, priv->regs + TSI721_OBWINLB(i));
1021 ob_win->pbar->free += ob_win->size;
1022 priv->obwin_cnt++;
1023 break;
1024 }
1025 }
1026}
1027
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001028/**
1029 * tsi721_init_pc2sr_mapping - initializes outbound (PCIe->SRIO)
1030 * translation regions.
1031 * @priv: pointer to tsi721 private data
1032 *
1033 * Disables SREP translation regions.
1034 */
1035static void tsi721_init_pc2sr_mapping(struct tsi721_device *priv)
1036{
Alexandre Bounine1679e8d2016-03-22 14:26:53 -07001037 int i, z;
1038 u32 rval;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001039
1040 /* Disable all PC2SR translation windows */
1041 for (i = 0; i < TSI721_OBWIN_NUM; i++)
1042 iowrite32(0, priv->regs + TSI721_OBWINLB(i));
Alexandre Bounine1679e8d2016-03-22 14:26:53 -07001043
1044 /* Initialize zone lookup tables to avoid ECC errors on reads */
1045 iowrite32(0, priv->regs + TSI721_LUT_DATA0);
1046 iowrite32(0, priv->regs + TSI721_LUT_DATA1);
1047 iowrite32(0, priv->regs + TSI721_LUT_DATA2);
1048
1049 for (i = 0; i < TSI721_OBWIN_NUM; i++) {
1050 for (z = 0; z < TSI721_PC2SR_ZONES; z++) {
1051 while (ioread32(priv->regs + TSI721_ZONE_SEL) &
1052 TSI721_ZONE_SEL_GO) {
1053 udelay(1);
1054 }
1055 rval = TSI721_ZONE_SEL_GO | (i << 3) | z;
1056 iowrite32(rval, priv->regs + TSI721_ZONE_SEL);
1057 }
1058 }
1059
1060 if (priv->p2r_bar[0].size == 0 && priv->p2r_bar[1].size == 0) {
1061 priv->obwin_cnt = 0;
1062 return;
1063 }
1064
1065 priv->p2r_bar[0].free = priv->p2r_bar[0].size;
1066 priv->p2r_bar[1].free = priv->p2r_bar[1].size;
1067
1068 for (i = 0; i < TSI721_OBWIN_NUM; i++)
1069 priv->ob_win[i].active = false;
1070
1071 priv->obwin_cnt = TSI721_OBWIN_NUM;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001072}
1073
1074/**
Alexandre Bounine71afe342012-10-04 17:16:00 -07001075 * tsi721_rio_map_inb_mem -- Mapping inbound memory region.
1076 * @mport: RapidIO master port
1077 * @lstart: Local memory space start address.
1078 * @rstart: RapidIO space start address.
1079 * @size: The mapping region size.
1080 * @flags: Flags for mapping. 0 for using default flags.
1081 *
1082 * Return: 0 -- Success.
1083 *
1084 * This function will create the inbound mapping
1085 * from rstart to lstart.
1086 */
1087static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
1088 u64 rstart, u32 size, u32 flags)
1089{
1090 struct tsi721_device *priv = mport->priv;
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001091 int i, avail = -1;
Alexandre Bounine71afe342012-10-04 17:16:00 -07001092 u32 regval;
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001093 struct tsi721_ib_win *ib_win;
Alexandre Bounine9673b882016-03-22 14:25:54 -07001094 bool direct = (lstart == rstart);
1095 u64 ibw_size;
1096 dma_addr_t loc_start;
1097 u64 ibw_start;
1098 struct tsi721_ib_win_mapping *map = NULL;
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001099 int ret = -EBUSY;
Alexandre Bounine71afe342012-10-04 17:16:00 -07001100
Alexandre Bounine9673b882016-03-22 14:25:54 -07001101 if (direct) {
Alexandre Bounine9673b882016-03-22 14:25:54 -07001102 /* Calculate minimal acceptable window size and base address */
1103
1104 ibw_size = roundup_pow_of_two(size);
1105 ibw_start = lstart & ~(ibw_size - 1);
1106
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001107 tsi_debug(IBW, &priv->pdev->dev,
Joe Perchesea87b8e2016-08-02 14:06:28 -07001108 "Direct (RIO_0x%llx -> PCIe_%pad), size=0x%x, ibw_start = 0x%llx",
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001109 rstart, &lstart, size, ibw_start);
1110
Alexandre Bounine9673b882016-03-22 14:25:54 -07001111 while ((lstart + size) > (ibw_start + ibw_size)) {
1112 ibw_size *= 2;
1113 ibw_start = lstart & ~(ibw_size - 1);
1114 if (ibw_size > 0x80000000) { /* Limit max size to 2GB */
1115 return -EBUSY;
1116 }
1117 }
1118
1119 loc_start = ibw_start;
1120
1121 map = kzalloc(sizeof(struct tsi721_ib_win_mapping), GFP_ATOMIC);
1122 if (map == NULL)
1123 return -ENOMEM;
1124
1125 } else {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001126 tsi_debug(IBW, &priv->pdev->dev,
Joe Perchesea87b8e2016-08-02 14:06:28 -07001127 "Translated (RIO_0x%llx -> PCIe_%pad), size=0x%x",
Alexandre Bounine9673b882016-03-22 14:25:54 -07001128 rstart, &lstart, size);
1129
1130 if (!is_power_of_2(size) || size < 0x1000 ||
1131 ((u64)lstart & (size - 1)) || (rstart & (size - 1)))
1132 return -EINVAL;
1133 if (priv->ibwin_cnt == 0)
1134 return -EBUSY;
1135 ibw_start = rstart;
1136 ibw_size = size;
1137 loc_start = lstart;
1138 }
1139
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001140 /*
1141 * Scan for overlapping with active regions and mark the first available
1142 * IB window at the same time.
1143 */
Alexandre Bounine71afe342012-10-04 17:16:00 -07001144 for (i = 0; i < TSI721_IBWIN_NUM; i++) {
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001145 ib_win = &priv->ib_win[i];
Alexandre Bounine9673b882016-03-22 14:25:54 -07001146
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001147 if (!ib_win->active) {
1148 if (avail == -1) {
1149 avail = i;
1150 ret = 0;
1151 }
Alexandre Bounine9673b882016-03-22 14:25:54 -07001152 } else if (ibw_start < (ib_win->rstart + ib_win->size) &&
1153 (ibw_start + ibw_size) > ib_win->rstart) {
1154 /* Return error if address translation involved */
1155 if (direct && ib_win->xlat) {
1156 ret = -EFAULT;
1157 break;
1158 }
1159
1160 /*
1161 * Direct mappings usually are larger than originally
1162 * requested fragments - check if this new request fits
1163 * into it.
1164 */
1165 if (rstart >= ib_win->rstart &&
1166 (rstart + size) <= (ib_win->rstart +
1167 ib_win->size)) {
1168 /* We are in - no further mapping required */
1169 map->lstart = lstart;
1170 list_add_tail(&map->node, &ib_win->mappings);
1171 return 0;
1172 }
1173
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001174 ret = -EFAULT;
Alexandre Bounine71afe342012-10-04 17:16:00 -07001175 break;
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001176 }
Alexandre Bounine71afe342012-10-04 17:16:00 -07001177 }
1178
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001179 if (ret)
Alexandre Bounine9673b882016-03-22 14:25:54 -07001180 goto out;
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001181 i = avail;
1182
1183 /* Sanity check: available IB window must be disabled at this point */
1184 regval = ioread32(priv->regs + TSI721_IBWIN_LB(i));
1185 if (WARN_ON(regval & TSI721_IBWIN_LB_WEN)) {
1186 ret = -EIO;
Alexandre Bounine9673b882016-03-22 14:25:54 -07001187 goto out;
Alexandre Bounine71afe342012-10-04 17:16:00 -07001188 }
1189
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001190 ib_win = &priv->ib_win[i];
1191 ib_win->active = true;
Alexandre Bounine9673b882016-03-22 14:25:54 -07001192 ib_win->rstart = ibw_start;
1193 ib_win->lstart = loc_start;
1194 ib_win->size = ibw_size;
1195 ib_win->xlat = (lstart != rstart);
1196 INIT_LIST_HEAD(&ib_win->mappings);
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001197
Alexandre Bounine9673b882016-03-22 14:25:54 -07001198 /*
1199 * When using direct IBW mapping and have larger than requested IBW size
1200 * we can have multiple local memory blocks mapped through the same IBW
1201 * To handle this situation we maintain list of "clients" for such IBWs.
1202 */
1203 if (direct) {
1204 map->lstart = lstart;
1205 list_add_tail(&map->node, &ib_win->mappings);
1206 }
1207
1208 iowrite32(TSI721_IBWIN_SIZE(ibw_size) << 8,
Alexandre Bounine71afe342012-10-04 17:16:00 -07001209 priv->regs + TSI721_IBWIN_SZ(i));
1210
Alexandre Bounine9673b882016-03-22 14:25:54 -07001211 iowrite32(((u64)loc_start >> 32), priv->regs + TSI721_IBWIN_TUA(i));
1212 iowrite32(((u64)loc_start & TSI721_IBWIN_TLA_ADD),
Alexandre Bounine71afe342012-10-04 17:16:00 -07001213 priv->regs + TSI721_IBWIN_TLA(i));
1214
Alexandre Bounine9673b882016-03-22 14:25:54 -07001215 iowrite32(ibw_start >> 32, priv->regs + TSI721_IBWIN_UB(i));
1216 iowrite32((ibw_start & TSI721_IBWIN_LB_BA) | TSI721_IBWIN_LB_WEN,
Alexandre Bounine71afe342012-10-04 17:16:00 -07001217 priv->regs + TSI721_IBWIN_LB(i));
Alexandre Bounine9673b882016-03-22 14:25:54 -07001218
1219 priv->ibwin_cnt--;
1220
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001221 tsi_debug(IBW, &priv->pdev->dev,
Joe Perchesea87b8e2016-08-02 14:06:28 -07001222 "Configured IBWIN%d (RIO_0x%llx -> PCIe_%pad), size=0x%llx",
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001223 i, ibw_start, &loc_start, ibw_size);
Alexandre Bounine71afe342012-10-04 17:16:00 -07001224
1225 return 0;
Alexandre Bounine9673b882016-03-22 14:25:54 -07001226out:
1227 kfree(map);
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001228 return ret;
Alexandre Bounine71afe342012-10-04 17:16:00 -07001229}
1230
1231/**
Alexandre Bounine9673b882016-03-22 14:25:54 -07001232 * tsi721_rio_unmap_inb_mem -- Unmapping inbound memory region.
Alexandre Bounine71afe342012-10-04 17:16:00 -07001233 * @mport: RapidIO master port
1234 * @lstart: Local memory space start address.
1235 */
1236static void tsi721_rio_unmap_inb_mem(struct rio_mport *mport,
1237 dma_addr_t lstart)
1238{
1239 struct tsi721_device *priv = mport->priv;
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001240 struct tsi721_ib_win *ib_win;
Alexandre Bounine71afe342012-10-04 17:16:00 -07001241 int i;
Alexandre Bounine71afe342012-10-04 17:16:00 -07001242
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001243 tsi_debug(IBW, &priv->pdev->dev,
Joe Perchesea87b8e2016-08-02 14:06:28 -07001244 "Unmap IBW mapped to PCIe_%pad", &lstart);
Alexandre Bounine9673b882016-03-22 14:25:54 -07001245
Alexandre Bounine71afe342012-10-04 17:16:00 -07001246 /* Search for matching active inbound translation window */
1247 for (i = 0; i < TSI721_IBWIN_NUM; i++) {
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001248 ib_win = &priv->ib_win[i];
Alexandre Bounine9673b882016-03-22 14:25:54 -07001249
1250 /* Address translating IBWs must to be an exact march */
1251 if (!ib_win->active ||
1252 (ib_win->xlat && lstart != ib_win->lstart))
1253 continue;
1254
1255 if (lstart >= ib_win->lstart &&
1256 lstart < (ib_win->lstart + ib_win->size)) {
1257
1258 if (!ib_win->xlat) {
1259 struct tsi721_ib_win_mapping *map;
1260 int found = 0;
1261
1262 list_for_each_entry(map,
1263 &ib_win->mappings, node) {
1264 if (map->lstart == lstart) {
1265 list_del(&map->node);
1266 kfree(map);
1267 found = 1;
1268 break;
1269 }
1270 }
1271
1272 if (!found)
1273 continue;
1274
1275 if (!list_empty(&ib_win->mappings))
1276 break;
1277 }
1278
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001279 tsi_debug(IBW, &priv->pdev->dev, "Disable IBWIN_%d", i);
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001280 iowrite32(0, priv->regs + TSI721_IBWIN_LB(i));
1281 ib_win->active = false;
Alexandre Bounine9673b882016-03-22 14:25:54 -07001282 priv->ibwin_cnt++;
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001283 break;
Alexandre Bounine71afe342012-10-04 17:16:00 -07001284 }
1285 }
Alexandre Bounineba5d1412016-03-22 14:25:51 -07001286
1287 if (i == TSI721_IBWIN_NUM)
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001288 tsi_debug(IBW, &priv->pdev->dev,
Alexandre Bounine9673b882016-03-22 14:25:54 -07001289 "IB window mapped to %pad not found", &lstart);
Alexandre Bounine71afe342012-10-04 17:16:00 -07001290}
1291
1292/**
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001293 * tsi721_init_sr2pc_mapping - initializes inbound (SRIO->PCIe)
1294 * translation regions.
1295 * @priv: pointer to tsi721 private data
1296 *
1297 * Disables inbound windows.
1298 */
1299static void tsi721_init_sr2pc_mapping(struct tsi721_device *priv)
1300{
1301 int i;
1302
1303 /* Disable all SR2PC inbound windows */
1304 for (i = 0; i < TSI721_IBWIN_NUM; i++)
Alexandre Bounine71afe342012-10-04 17:16:00 -07001305 iowrite32(0, priv->regs + TSI721_IBWIN_LB(i));
Alexandre Bounine9673b882016-03-22 14:25:54 -07001306 priv->ibwin_cnt = TSI721_IBWIN_NUM;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001307}
1308
Alexandre Bounine748353c2016-03-22 14:26:23 -07001309/*
1310 * tsi721_close_sr2pc_mapping - closes all active inbound (SRIO->PCIe)
1311 * translation regions.
1312 * @priv: pointer to tsi721 device private data
1313 */
1314static void tsi721_close_sr2pc_mapping(struct tsi721_device *priv)
1315{
1316 struct tsi721_ib_win *ib_win;
1317 int i;
1318
1319 /* Disable all active SR2PC inbound windows */
1320 for (i = 0; i < TSI721_IBWIN_NUM; i++) {
1321 ib_win = &priv->ib_win[i];
1322 if (ib_win->active) {
1323 iowrite32(0, priv->regs + TSI721_IBWIN_LB(i));
1324 ib_win->active = false;
1325 }
1326 }
1327}
1328
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001329/**
1330 * tsi721_port_write_init - Inbound port write interface init
1331 * @priv: pointer to tsi721 private data
1332 *
1333 * Initializes inbound port write handler.
1334 * Returns %0 on success or %-ENOMEM on failure.
1335 */
1336static int tsi721_port_write_init(struct tsi721_device *priv)
1337{
1338 priv->pw_discard_count = 0;
1339 INIT_WORK(&priv->pw_work, tsi721_pw_dpc);
1340 spin_lock_init(&priv->pw_fifo_lock);
1341 if (kfifo_alloc(&priv->pw_fifo,
1342 TSI721_RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001343 tsi_err(&priv->pdev->dev, "PW FIFO allocation failed");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001344 return -ENOMEM;
1345 }
1346
1347 /* Use reliable port-write capture mode */
1348 iowrite32(TSI721_RIO_PW_CTL_PWC_REL, priv->regs + TSI721_RIO_PW_CTL);
1349 return 0;
1350}
1351
Alexandre Bounine748353c2016-03-22 14:26:23 -07001352static void tsi721_port_write_free(struct tsi721_device *priv)
1353{
1354 kfifo_free(&priv->pw_fifo);
1355}
1356
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001357static int tsi721_doorbell_init(struct tsi721_device *priv)
1358{
1359 /* Outbound Doorbells do not require any setup.
1360 * Tsi721 uses dedicated PCI BAR1 to generate doorbells.
1361 * That BAR1 was mapped during the probe routine.
1362 */
1363
1364 /* Initialize Inbound Doorbell processing DPC and queue */
1365 priv->db_discard_count = 0;
1366 INIT_WORK(&priv->idb_work, tsi721_db_dpc);
1367
1368 /* Allocate buffer for inbound doorbells queue */
Alexandre Bounineceb96392011-12-08 14:34:35 -08001369 priv->idb_base = dma_zalloc_coherent(&priv->pdev->dev,
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001370 IDB_QSIZE * TSI721_IDB_ENTRY_SIZE,
1371 &priv->idb_dma, GFP_KERNEL);
1372 if (!priv->idb_base)
1373 return -ENOMEM;
1374
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001375 tsi_debug(DBELL, &priv->pdev->dev,
1376 "Allocated IDB buffer @ %p (phys = %pad)",
1377 priv->idb_base, &priv->idb_dma);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001378
1379 iowrite32(TSI721_IDQ_SIZE_VAL(IDB_QSIZE),
1380 priv->regs + TSI721_IDQ_SIZE(IDB_QUEUE));
1381 iowrite32(((u64)priv->idb_dma >> 32),
1382 priv->regs + TSI721_IDQ_BASEU(IDB_QUEUE));
1383 iowrite32(((u64)priv->idb_dma & TSI721_IDQ_BASEL_ADDR),
1384 priv->regs + TSI721_IDQ_BASEL(IDB_QUEUE));
1385 /* Enable accepting all inbound doorbells */
1386 iowrite32(0, priv->regs + TSI721_IDQ_MASK(IDB_QUEUE));
1387
1388 iowrite32(TSI721_IDQ_INIT, priv->regs + TSI721_IDQ_CTL(IDB_QUEUE));
1389
1390 iowrite32(0, priv->regs + TSI721_IDQ_RP(IDB_QUEUE));
1391
1392 return 0;
1393}
1394
1395static void tsi721_doorbell_free(struct tsi721_device *priv)
1396{
1397 if (priv->idb_base == NULL)
1398 return;
1399
1400 /* Free buffer allocated for inbound doorbell queue */
1401 dma_free_coherent(&priv->pdev->dev, IDB_QSIZE * TSI721_IDB_ENTRY_SIZE,
1402 priv->idb_base, priv->idb_dma);
1403 priv->idb_base = NULL;
1404}
1405
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001406/**
1407 * tsi721_bdma_maint_init - Initialize maintenance request BDMA channel.
1408 * @priv: pointer to tsi721 private data
1409 *
1410 * Initialize BDMA channel allocated for RapidIO maintenance read/write
1411 * request generation
1412 * Returns %0 on success or %-ENOMEM on failure.
1413 */
1414static int tsi721_bdma_maint_init(struct tsi721_device *priv)
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001415{
1416 struct tsi721_dma_desc *bd_ptr;
1417 u64 *sts_ptr;
1418 dma_addr_t bd_phys, sts_phys;
1419 int sts_size;
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001420 int bd_num = 2;
1421 void __iomem *regs;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001422
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001423 tsi_debug(MAINT, &priv->pdev->dev,
1424 "Init BDMA_%d Maintenance requests", TSI721_DMACH_MAINT);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001425
1426 /*
1427 * Initialize DMA channel for maintenance requests
1428 */
1429
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001430 priv->mdma.ch_id = TSI721_DMACH_MAINT;
1431 regs = priv->regs + TSI721_DMAC_BASE(TSI721_DMACH_MAINT);
1432
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001433 /* Allocate space for DMA descriptors */
Alexandre Bounineceb96392011-12-08 14:34:35 -08001434 bd_ptr = dma_zalloc_coherent(&priv->pdev->dev,
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001435 bd_num * sizeof(struct tsi721_dma_desc),
1436 &bd_phys, GFP_KERNEL);
1437 if (!bd_ptr)
1438 return -ENOMEM;
1439
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001440 priv->mdma.bd_num = bd_num;
1441 priv->mdma.bd_phys = bd_phys;
1442 priv->mdma.bd_base = bd_ptr;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001443
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001444 tsi_debug(MAINT, &priv->pdev->dev, "DMA descriptors @ %p (phys = %pad)",
1445 bd_ptr, &bd_phys);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001446
1447 /* Allocate space for descriptor status FIFO */
1448 sts_size = (bd_num >= TSI721_DMA_MINSTSSZ) ?
1449 bd_num : TSI721_DMA_MINSTSSZ;
1450 sts_size = roundup_pow_of_two(sts_size);
Alexandre Bounineceb96392011-12-08 14:34:35 -08001451 sts_ptr = dma_zalloc_coherent(&priv->pdev->dev,
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001452 sts_size * sizeof(struct tsi721_dma_sts),
1453 &sts_phys, GFP_KERNEL);
1454 if (!sts_ptr) {
1455 /* Free space allocated for DMA descriptors */
1456 dma_free_coherent(&priv->pdev->dev,
1457 bd_num * sizeof(struct tsi721_dma_desc),
1458 bd_ptr, bd_phys);
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001459 priv->mdma.bd_base = NULL;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001460 return -ENOMEM;
1461 }
1462
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001463 priv->mdma.sts_phys = sts_phys;
1464 priv->mdma.sts_base = sts_ptr;
1465 priv->mdma.sts_size = sts_size;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001466
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001467 tsi_debug(MAINT, &priv->pdev->dev,
1468 "desc status FIFO @ %p (phys = %pad) size=0x%x",
1469 sts_ptr, &sts_phys, sts_size);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001470
1471 /* Initialize DMA descriptors ring */
1472 bd_ptr[bd_num - 1].type_id = cpu_to_le32(DTYPE3 << 29);
1473 bd_ptr[bd_num - 1].next_lo = cpu_to_le32((u64)bd_phys &
1474 TSI721_DMAC_DPTRL_MASK);
1475 bd_ptr[bd_num - 1].next_hi = cpu_to_le32((u64)bd_phys >> 32);
1476
1477 /* Setup DMA descriptor pointers */
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001478 iowrite32(((u64)bd_phys >> 32), regs + TSI721_DMAC_DPTRH);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001479 iowrite32(((u64)bd_phys & TSI721_DMAC_DPTRL_MASK),
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001480 regs + TSI721_DMAC_DPTRL);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001481
1482 /* Setup descriptor status FIFO */
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001483 iowrite32(((u64)sts_phys >> 32), regs + TSI721_DMAC_DSBH);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001484 iowrite32(((u64)sts_phys & TSI721_DMAC_DSBL_MASK),
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001485 regs + TSI721_DMAC_DSBL);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001486 iowrite32(TSI721_DMAC_DSSZ_SIZE(sts_size),
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001487 regs + TSI721_DMAC_DSSZ);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001488
1489 /* Clear interrupt bits */
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001490 iowrite32(TSI721_DMAC_INT_ALL, regs + TSI721_DMAC_INT);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001491
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001492 ioread32(regs + TSI721_DMAC_INT);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001493
1494 /* Toggle DMA channel initialization */
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001495 iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL);
1496 ioread32(regs + TSI721_DMAC_CTL);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001497 udelay(10);
1498
1499 return 0;
1500}
1501
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001502static int tsi721_bdma_maint_free(struct tsi721_device *priv)
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001503{
1504 u32 ch_stat;
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001505 struct tsi721_bdma_maint *mdma = &priv->mdma;
1506 void __iomem *regs = priv->regs + TSI721_DMAC_BASE(mdma->ch_id);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001507
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001508 if (mdma->bd_base == NULL)
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001509 return 0;
1510
1511 /* Check if DMA channel still running */
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001512 ch_stat = ioread32(regs + TSI721_DMAC_STS);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001513 if (ch_stat & TSI721_DMAC_STS_RUN)
1514 return -EFAULT;
1515
1516 /* Put DMA channel into init state */
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001517 iowrite32(TSI721_DMAC_CTL_INIT, regs + TSI721_DMAC_CTL);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001518
1519 /* Free space allocated for DMA descriptors */
1520 dma_free_coherent(&priv->pdev->dev,
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001521 mdma->bd_num * sizeof(struct tsi721_dma_desc),
1522 mdma->bd_base, mdma->bd_phys);
1523 mdma->bd_base = NULL;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001524
1525 /* Free space allocated for status FIFO */
1526 dma_free_coherent(&priv->pdev->dev,
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07001527 mdma->sts_size * sizeof(struct tsi721_dma_sts),
1528 mdma->sts_base, mdma->sts_phys);
1529 mdma->sts_base = NULL;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001530 return 0;
1531}
1532
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001533/* Enable Inbound Messaging Interrupts */
1534static void
1535tsi721_imsg_interrupt_enable(struct tsi721_device *priv, int ch,
1536 u32 inte_mask)
1537{
1538 u32 rval;
1539
1540 if (!inte_mask)
1541 return;
1542
1543 /* Clear pending Inbound Messaging interrupts */
1544 iowrite32(inte_mask, priv->regs + TSI721_IBDMAC_INT(ch));
1545
1546 /* Enable Inbound Messaging interrupts */
1547 rval = ioread32(priv->regs + TSI721_IBDMAC_INTE(ch));
1548 iowrite32(rval | inte_mask, priv->regs + TSI721_IBDMAC_INTE(ch));
1549
1550 if (priv->flags & TSI721_USING_MSIX)
1551 return; /* Finished if we are in MSI-X mode */
1552
1553 /*
1554 * For MSI and INTA interrupt signalling we need to enable next levels
1555 */
1556
1557 /* Enable Device Channel Interrupt */
1558 rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
1559 iowrite32(rval | TSI721_INT_IMSG_CHAN(ch),
1560 priv->regs + TSI721_DEV_CHAN_INTE);
1561}
1562
1563/* Disable Inbound Messaging Interrupts */
1564static void
1565tsi721_imsg_interrupt_disable(struct tsi721_device *priv, int ch,
1566 u32 inte_mask)
1567{
1568 u32 rval;
1569
1570 if (!inte_mask)
1571 return;
1572
1573 /* Clear pending Inbound Messaging interrupts */
1574 iowrite32(inte_mask, priv->regs + TSI721_IBDMAC_INT(ch));
1575
1576 /* Disable Inbound Messaging interrupts */
1577 rval = ioread32(priv->regs + TSI721_IBDMAC_INTE(ch));
1578 rval &= ~inte_mask;
1579 iowrite32(rval, priv->regs + TSI721_IBDMAC_INTE(ch));
1580
1581 if (priv->flags & TSI721_USING_MSIX)
1582 return; /* Finished if we are in MSI-X mode */
1583
1584 /*
1585 * For MSI and INTA interrupt signalling we need to disable next levels
1586 */
1587
1588 /* Disable Device Channel Interrupt */
1589 rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
1590 rval &= ~TSI721_INT_IMSG_CHAN(ch);
1591 iowrite32(rval, priv->regs + TSI721_DEV_CHAN_INTE);
1592}
1593
1594/* Enable Outbound Messaging interrupts */
1595static void
1596tsi721_omsg_interrupt_enable(struct tsi721_device *priv, int ch,
1597 u32 inte_mask)
1598{
1599 u32 rval;
1600
1601 if (!inte_mask)
1602 return;
1603
1604 /* Clear pending Outbound Messaging interrupts */
1605 iowrite32(inte_mask, priv->regs + TSI721_OBDMAC_INT(ch));
1606
1607 /* Enable Outbound Messaging channel interrupts */
1608 rval = ioread32(priv->regs + TSI721_OBDMAC_INTE(ch));
1609 iowrite32(rval | inte_mask, priv->regs + TSI721_OBDMAC_INTE(ch));
1610
1611 if (priv->flags & TSI721_USING_MSIX)
1612 return; /* Finished if we are in MSI-X mode */
1613
1614 /*
1615 * For MSI and INTA interrupt signalling we need to enable next levels
1616 */
1617
1618 /* Enable Device Channel Interrupt */
1619 rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
1620 iowrite32(rval | TSI721_INT_OMSG_CHAN(ch),
1621 priv->regs + TSI721_DEV_CHAN_INTE);
1622}
1623
1624/* Disable Outbound Messaging interrupts */
1625static void
1626tsi721_omsg_interrupt_disable(struct tsi721_device *priv, int ch,
1627 u32 inte_mask)
1628{
1629 u32 rval;
1630
1631 if (!inte_mask)
1632 return;
1633
1634 /* Clear pending Outbound Messaging interrupts */
1635 iowrite32(inte_mask, priv->regs + TSI721_OBDMAC_INT(ch));
1636
1637 /* Disable Outbound Messaging interrupts */
1638 rval = ioread32(priv->regs + TSI721_OBDMAC_INTE(ch));
1639 rval &= ~inte_mask;
1640 iowrite32(rval, priv->regs + TSI721_OBDMAC_INTE(ch));
1641
1642 if (priv->flags & TSI721_USING_MSIX)
1643 return; /* Finished if we are in MSI-X mode */
1644
1645 /*
1646 * For MSI and INTA interrupt signalling we need to disable next levels
1647 */
1648
1649 /* Disable Device Channel Interrupt */
1650 rval = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
1651 rval &= ~TSI721_INT_OMSG_CHAN(ch);
1652 iowrite32(rval, priv->regs + TSI721_DEV_CHAN_INTE);
1653}
1654
1655/**
1656 * tsi721_add_outb_message - Add message to the Tsi721 outbound message queue
1657 * @mport: Master port with outbound message queue
1658 * @rdev: Target of outbound message
1659 * @mbox: Outbound mailbox
1660 * @buffer: Message to add to outbound queue
1661 * @len: Length of message
1662 */
1663static int
1664tsi721_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
1665 void *buffer, size_t len)
1666{
1667 struct tsi721_device *priv = mport->priv;
1668 struct tsi721_omsg_desc *desc;
1669 u32 tx_slot;
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001670 unsigned long flags;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001671
1672 if (!priv->omsg_init[mbox] ||
1673 len > TSI721_MSG_MAX_SIZE || len < 8)
1674 return -EINVAL;
1675
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001676 spin_lock_irqsave(&priv->omsg_ring[mbox].lock, flags);
1677
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001678 tx_slot = priv->omsg_ring[mbox].tx_slot;
1679
1680 /* Copy copy message into transfer buffer */
1681 memcpy(priv->omsg_ring[mbox].omq_base[tx_slot], buffer, len);
1682
1683 if (len & 0x7)
1684 len += 8;
1685
1686 /* Build descriptor associated with buffer */
1687 desc = priv->omsg_ring[mbox].omd_base;
1688 desc[tx_slot].type_id = cpu_to_le32((DTYPE4 << 29) | rdev->destid);
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001689#ifdef TSI721_OMSG_DESC_INT
1690 /* Request IOF_DONE interrupt generation for each N-th frame in queue */
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001691 if (tx_slot % 4 == 0)
1692 desc[tx_slot].type_id |= cpu_to_le32(TSI721_OMD_IOF);
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001693#endif
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001694 desc[tx_slot].msg_info =
1695 cpu_to_le32((mport->sys_size << 26) | (mbox << 22) |
1696 (0xe << 12) | (len & 0xff8));
1697 desc[tx_slot].bufptr_lo =
1698 cpu_to_le32((u64)priv->omsg_ring[mbox].omq_phys[tx_slot] &
1699 0xffffffff);
1700 desc[tx_slot].bufptr_hi =
1701 cpu_to_le32((u64)priv->omsg_ring[mbox].omq_phys[tx_slot] >> 32);
1702
1703 priv->omsg_ring[mbox].wr_count++;
1704
1705 /* Go to next descriptor */
1706 if (++priv->omsg_ring[mbox].tx_slot == priv->omsg_ring[mbox].size) {
1707 priv->omsg_ring[mbox].tx_slot = 0;
1708 /* Move through the ring link descriptor at the end */
1709 priv->omsg_ring[mbox].wr_count++;
1710 }
1711
1712 mb();
1713
1714 /* Set new write count value */
1715 iowrite32(priv->omsg_ring[mbox].wr_count,
1716 priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
1717 ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
1718
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001719 spin_unlock_irqrestore(&priv->omsg_ring[mbox].lock, flags);
1720
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001721 return 0;
1722}
1723
1724/**
1725 * tsi721_omsg_handler - Outbound Message Interrupt Handler
1726 * @priv: pointer to tsi721 private data
1727 * @ch: number of OB MSG channel to service
1728 *
1729 * Services channel interrupts from outbound messaging engine.
1730 */
1731static void tsi721_omsg_handler(struct tsi721_device *priv, int ch)
1732{
1733 u32 omsg_int;
Alexandre Bounine748353c2016-03-22 14:26:23 -07001734 struct rio_mport *mport = &priv->mport;
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001735 void *dev_id = NULL;
1736 u32 tx_slot = 0xffffffff;
1737 int do_callback = 0;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001738
1739 spin_lock(&priv->omsg_ring[ch].lock);
1740
1741 omsg_int = ioread32(priv->regs + TSI721_OBDMAC_INT(ch));
1742
1743 if (omsg_int & TSI721_OBDMAC_INT_ST_FULL)
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001744 tsi_info(&priv->pdev->dev,
1745 "OB MBOX%d: Status FIFO is full", ch);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001746
1747 if (omsg_int & (TSI721_OBDMAC_INT_DONE | TSI721_OBDMAC_INT_IOF_DONE)) {
1748 u32 srd_ptr;
1749 u64 *sts_ptr, last_ptr = 0, prev_ptr = 0;
1750 int i, j;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001751
1752 /*
1753 * Find last successfully processed descriptor
1754 */
1755
1756 /* Check and clear descriptor status FIFO entries */
1757 srd_ptr = priv->omsg_ring[ch].sts_rdptr;
1758 sts_ptr = priv->omsg_ring[ch].sts_base;
1759 j = srd_ptr * 8;
1760 while (sts_ptr[j]) {
1761 for (i = 0; i < 8 && sts_ptr[j]; i++, j++) {
1762 prev_ptr = last_ptr;
1763 last_ptr = le64_to_cpu(sts_ptr[j]);
1764 sts_ptr[j] = 0;
1765 }
1766
1767 ++srd_ptr;
1768 srd_ptr %= priv->omsg_ring[ch].sts_size;
1769 j = srd_ptr * 8;
1770 }
1771
1772 if (last_ptr == 0)
1773 goto no_sts_update;
1774
1775 priv->omsg_ring[ch].sts_rdptr = srd_ptr;
1776 iowrite32(srd_ptr, priv->regs + TSI721_OBDMAC_DSRP(ch));
1777
Alexandre Bounine748353c2016-03-22 14:26:23 -07001778 if (!mport->outb_msg[ch].mcback)
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001779 goto no_sts_update;
1780
1781 /* Inform upper layer about transfer completion */
1782
1783 tx_slot = (last_ptr - (u64)priv->omsg_ring[ch].omd_phys)/
1784 sizeof(struct tsi721_omsg_desc);
1785
1786 /*
1787 * Check if this is a Link Descriptor (LD).
1788 * If yes, ignore LD and use descriptor processed
1789 * before LD.
1790 */
1791 if (tx_slot == priv->omsg_ring[ch].size) {
1792 if (prev_ptr)
1793 tx_slot = (prev_ptr -
1794 (u64)priv->omsg_ring[ch].omd_phys)/
1795 sizeof(struct tsi721_omsg_desc);
1796 else
1797 goto no_sts_update;
1798 }
1799
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001800 if (tx_slot >= priv->omsg_ring[ch].size)
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001801 tsi_debug(OMSG, &priv->pdev->dev,
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001802 "OB_MSG tx_slot=%x > size=%x",
1803 tx_slot, priv->omsg_ring[ch].size);
1804 WARN_ON(tx_slot >= priv->omsg_ring[ch].size);
1805
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001806 /* Move slot index to the next message to be sent */
1807 ++tx_slot;
1808 if (tx_slot == priv->omsg_ring[ch].size)
1809 tx_slot = 0;
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001810
1811 dev_id = priv->omsg_ring[ch].dev_id;
1812 do_callback = 1;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001813 }
1814
1815no_sts_update:
1816
1817 if (omsg_int & TSI721_OBDMAC_INT_ERROR) {
1818 /*
1819 * Outbound message operation aborted due to error,
1820 * reinitialize OB MSG channel
1821 */
1822
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001823 tsi_debug(OMSG, &priv->pdev->dev, "OB MSG ABORT ch_stat=%x",
1824 ioread32(priv->regs + TSI721_OBDMAC_STS(ch)));
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001825
1826 iowrite32(TSI721_OBDMAC_INT_ERROR,
1827 priv->regs + TSI721_OBDMAC_INT(ch));
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001828 iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT,
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001829 priv->regs + TSI721_OBDMAC_CTL(ch));
1830 ioread32(priv->regs + TSI721_OBDMAC_CTL(ch));
1831
1832 /* Inform upper level to clear all pending tx slots */
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001833 dev_id = priv->omsg_ring[ch].dev_id;
1834 tx_slot = priv->omsg_ring[ch].tx_slot;
1835 do_callback = 1;
1836
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001837 /* Synch tx_slot tracking */
1838 iowrite32(priv->omsg_ring[ch].tx_slot,
1839 priv->regs + TSI721_OBDMAC_DRDCNT(ch));
1840 ioread32(priv->regs + TSI721_OBDMAC_DRDCNT(ch));
1841 priv->omsg_ring[ch].wr_count = priv->omsg_ring[ch].tx_slot;
1842 priv->omsg_ring[ch].sts_rdptr = 0;
1843 }
1844
1845 /* Clear channel interrupts */
1846 iowrite32(omsg_int, priv->regs + TSI721_OBDMAC_INT(ch));
1847
1848 if (!(priv->flags & TSI721_USING_MSIX)) {
1849 u32 ch_inte;
1850
1851 /* Re-enable channel interrupts */
1852 ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
1853 ch_inte |= TSI721_INT_OMSG_CHAN(ch);
1854 iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE);
1855 }
1856
1857 spin_unlock(&priv->omsg_ring[ch].lock);
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001858
1859 if (mport->outb_msg[ch].mcback && do_callback)
1860 mport->outb_msg[ch].mcback(mport, dev_id, ch, tx_slot);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001861}
1862
1863/**
1864 * tsi721_open_outb_mbox - Initialize Tsi721 outbound mailbox
1865 * @mport: Master port implementing Outbound Messaging Engine
1866 * @dev_id: Device specific pointer to pass on event
1867 * @mbox: Mailbox to open
1868 * @entries: Number of entries in the outbound mailbox ring
1869 */
1870static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id,
1871 int mbox, int entries)
1872{
1873 struct tsi721_device *priv = mport->priv;
1874 struct tsi721_omsg_desc *bd_ptr;
1875 int i, rc = 0;
1876
1877 if ((entries < TSI721_OMSGD_MIN_RING_SIZE) ||
1878 (entries > (TSI721_OMSGD_RING_SIZE)) ||
1879 (!is_power_of_2(entries)) || mbox >= RIO_MAX_MBOX) {
1880 rc = -EINVAL;
1881 goto out;
1882 }
1883
1884 priv->omsg_ring[mbox].dev_id = dev_id;
1885 priv->omsg_ring[mbox].size = entries;
1886 priv->omsg_ring[mbox].sts_rdptr = 0;
1887 spin_lock_init(&priv->omsg_ring[mbox].lock);
1888
1889 /* Outbound Msg Buffer allocation based on
1890 the number of maximum descriptor entries */
1891 for (i = 0; i < entries; i++) {
1892 priv->omsg_ring[mbox].omq_base[i] =
1893 dma_alloc_coherent(
1894 &priv->pdev->dev, TSI721_MSG_BUFFER_SIZE,
1895 &priv->omsg_ring[mbox].omq_phys[i],
1896 GFP_KERNEL);
1897 if (priv->omsg_ring[mbox].omq_base[i] == NULL) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001898 tsi_debug(OMSG, &priv->pdev->dev,
1899 "ENOMEM for OB_MSG_%d data buffer", mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001900 rc = -ENOMEM;
1901 goto out_buf;
1902 }
1903 }
1904
1905 /* Outbound message descriptor allocation */
1906 priv->omsg_ring[mbox].omd_base = dma_alloc_coherent(
1907 &priv->pdev->dev,
1908 (entries + 1) * sizeof(struct tsi721_omsg_desc),
1909 &priv->omsg_ring[mbox].omd_phys, GFP_KERNEL);
1910 if (priv->omsg_ring[mbox].omd_base == NULL) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001911 tsi_debug(OMSG, &priv->pdev->dev,
1912 "ENOMEM for OB_MSG_%d descriptor memory", mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001913 rc = -ENOMEM;
1914 goto out_buf;
1915 }
1916
1917 priv->omsg_ring[mbox].tx_slot = 0;
1918
1919 /* Outbound message descriptor status FIFO allocation */
1920 priv->omsg_ring[mbox].sts_size = roundup_pow_of_two(entries + 1);
Alexandre Bounineceb96392011-12-08 14:34:35 -08001921 priv->omsg_ring[mbox].sts_base = dma_zalloc_coherent(&priv->pdev->dev,
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001922 priv->omsg_ring[mbox].sts_size *
1923 sizeof(struct tsi721_dma_sts),
1924 &priv->omsg_ring[mbox].sts_phys, GFP_KERNEL);
1925 if (priv->omsg_ring[mbox].sts_base == NULL) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001926 tsi_debug(OMSG, &priv->pdev->dev,
1927 "ENOMEM for OB_MSG_%d status FIFO", mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001928 rc = -ENOMEM;
1929 goto out_desc;
1930 }
1931
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001932 /*
1933 * Configure Outbound Messaging Engine
1934 */
1935
1936 /* Setup Outbound Message descriptor pointer */
1937 iowrite32(((u64)priv->omsg_ring[mbox].omd_phys >> 32),
1938 priv->regs + TSI721_OBDMAC_DPTRH(mbox));
1939 iowrite32(((u64)priv->omsg_ring[mbox].omd_phys &
1940 TSI721_OBDMAC_DPTRL_MASK),
1941 priv->regs + TSI721_OBDMAC_DPTRL(mbox));
1942
1943 /* Setup Outbound Message descriptor status FIFO */
1944 iowrite32(((u64)priv->omsg_ring[mbox].sts_phys >> 32),
1945 priv->regs + TSI721_OBDMAC_DSBH(mbox));
1946 iowrite32(((u64)priv->omsg_ring[mbox].sts_phys &
1947 TSI721_OBDMAC_DSBL_MASK),
1948 priv->regs + TSI721_OBDMAC_DSBL(mbox));
1949 iowrite32(TSI721_DMAC_DSSZ_SIZE(priv->omsg_ring[mbox].sts_size),
1950 priv->regs + (u32)TSI721_OBDMAC_DSSZ(mbox));
1951
1952 /* Enable interrupts */
1953
1954#ifdef CONFIG_PCI_MSI
1955 if (priv->flags & TSI721_USING_MSIX) {
Alexandre Bounine748353c2016-03-22 14:26:23 -07001956 int idx = TSI721_VECT_OMB0_DONE + mbox;
1957
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001958 /* Request interrupt service if we are in MSI-X mode */
Alexandre Bounine748353c2016-03-22 14:26:23 -07001959 rc = request_irq(priv->msix[idx].vector, tsi721_omsg_msix, 0,
1960 priv->msix[idx].irq_name, (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001961
1962 if (rc) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001963 tsi_debug(OMSG, &priv->pdev->dev,
1964 "Unable to get MSI-X IRQ for OBOX%d-DONE",
1965 mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001966 goto out_stat;
1967 }
1968
Alexandre Bounine748353c2016-03-22 14:26:23 -07001969 idx = TSI721_VECT_OMB0_INT + mbox;
1970 rc = request_irq(priv->msix[idx].vector, tsi721_omsg_msix, 0,
1971 priv->msix[idx].irq_name, (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001972
1973 if (rc) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07001974 tsi_debug(OMSG, &priv->pdev->dev,
1975 "Unable to get MSI-X IRQ for MBOX%d-INT", mbox);
Alexandre Bounine748353c2016-03-22 14:26:23 -07001976 idx = TSI721_VECT_OMB0_DONE + mbox;
1977 free_irq(priv->msix[idx].vector, (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07001978 goto out_stat;
1979 }
1980 }
1981#endif /* CONFIG_PCI_MSI */
1982
1983 tsi721_omsg_interrupt_enable(priv, mbox, TSI721_OBDMAC_INT_ALL);
1984
1985 /* Initialize Outbound Message descriptors ring */
1986 bd_ptr = priv->omsg_ring[mbox].omd_base;
1987 bd_ptr[entries].type_id = cpu_to_le32(DTYPE5 << 29);
1988 bd_ptr[entries].msg_info = 0;
1989 bd_ptr[entries].next_lo =
1990 cpu_to_le32((u64)priv->omsg_ring[mbox].omd_phys &
1991 TSI721_OBDMAC_DPTRL_MASK);
1992 bd_ptr[entries].next_hi =
1993 cpu_to_le32((u64)priv->omsg_ring[mbox].omd_phys >> 32);
1994 priv->omsg_ring[mbox].wr_count = 0;
1995 mb();
1996
1997 /* Initialize Outbound Message engine */
Alexandre Bounine2ece1ca2016-03-22 14:26:47 -07001998 iowrite32(TSI721_OBDMAC_CTL_RETRY_THR | TSI721_OBDMAC_CTL_INIT,
1999 priv->regs + TSI721_OBDMAC_CTL(mbox));
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002000 ioread32(priv->regs + TSI721_OBDMAC_DWRCNT(mbox));
2001 udelay(10);
2002
2003 priv->omsg_init[mbox] = 1;
2004
2005 return 0;
2006
2007#ifdef CONFIG_PCI_MSI
2008out_stat:
2009 dma_free_coherent(&priv->pdev->dev,
2010 priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts),
2011 priv->omsg_ring[mbox].sts_base,
2012 priv->omsg_ring[mbox].sts_phys);
2013
2014 priv->omsg_ring[mbox].sts_base = NULL;
2015#endif /* CONFIG_PCI_MSI */
2016
2017out_desc:
2018 dma_free_coherent(&priv->pdev->dev,
2019 (entries + 1) * sizeof(struct tsi721_omsg_desc),
2020 priv->omsg_ring[mbox].omd_base,
2021 priv->omsg_ring[mbox].omd_phys);
2022
2023 priv->omsg_ring[mbox].omd_base = NULL;
2024
2025out_buf:
2026 for (i = 0; i < priv->omsg_ring[mbox].size; i++) {
2027 if (priv->omsg_ring[mbox].omq_base[i]) {
2028 dma_free_coherent(&priv->pdev->dev,
2029 TSI721_MSG_BUFFER_SIZE,
2030 priv->omsg_ring[mbox].omq_base[i],
2031 priv->omsg_ring[mbox].omq_phys[i]);
2032
2033 priv->omsg_ring[mbox].omq_base[i] = NULL;
2034 }
2035 }
2036
2037out:
2038 return rc;
2039}
2040
2041/**
2042 * tsi721_close_outb_mbox - Close Tsi721 outbound mailbox
2043 * @mport: Master port implementing the outbound message unit
2044 * @mbox: Mailbox to close
2045 */
2046static void tsi721_close_outb_mbox(struct rio_mport *mport, int mbox)
2047{
2048 struct tsi721_device *priv = mport->priv;
2049 u32 i;
2050
2051 if (!priv->omsg_init[mbox])
2052 return;
2053 priv->omsg_init[mbox] = 0;
2054
2055 /* Disable Interrupts */
2056
2057 tsi721_omsg_interrupt_disable(priv, mbox, TSI721_OBDMAC_INT_ALL);
2058
2059#ifdef CONFIG_PCI_MSI
2060 if (priv->flags & TSI721_USING_MSIX) {
2061 free_irq(priv->msix[TSI721_VECT_OMB0_DONE + mbox].vector,
Alexandre Bounine748353c2016-03-22 14:26:23 -07002062 (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002063 free_irq(priv->msix[TSI721_VECT_OMB0_INT + mbox].vector,
Alexandre Bounine748353c2016-03-22 14:26:23 -07002064 (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002065 }
2066#endif /* CONFIG_PCI_MSI */
2067
2068 /* Free OMSG Descriptor Status FIFO */
2069 dma_free_coherent(&priv->pdev->dev,
2070 priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts),
2071 priv->omsg_ring[mbox].sts_base,
2072 priv->omsg_ring[mbox].sts_phys);
2073
2074 priv->omsg_ring[mbox].sts_base = NULL;
2075
2076 /* Free OMSG descriptors */
2077 dma_free_coherent(&priv->pdev->dev,
2078 (priv->omsg_ring[mbox].size + 1) *
2079 sizeof(struct tsi721_omsg_desc),
2080 priv->omsg_ring[mbox].omd_base,
2081 priv->omsg_ring[mbox].omd_phys);
2082
2083 priv->omsg_ring[mbox].omd_base = NULL;
2084
2085 /* Free message buffers */
2086 for (i = 0; i < priv->omsg_ring[mbox].size; i++) {
2087 if (priv->omsg_ring[mbox].omq_base[i]) {
2088 dma_free_coherent(&priv->pdev->dev,
2089 TSI721_MSG_BUFFER_SIZE,
2090 priv->omsg_ring[mbox].omq_base[i],
2091 priv->omsg_ring[mbox].omq_phys[i]);
2092
2093 priv->omsg_ring[mbox].omq_base[i] = NULL;
2094 }
2095 }
2096}
2097
2098/**
2099 * tsi721_imsg_handler - Inbound Message Interrupt Handler
2100 * @priv: pointer to tsi721 private data
2101 * @ch: inbound message channel number to service
2102 *
2103 * Services channel interrupts from inbound messaging engine.
2104 */
2105static void tsi721_imsg_handler(struct tsi721_device *priv, int ch)
2106{
2107 u32 mbox = ch - 4;
2108 u32 imsg_int;
Alexandre Bounine748353c2016-03-22 14:26:23 -07002109 struct rio_mport *mport = &priv->mport;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002110
2111 spin_lock(&priv->imsg_ring[mbox].lock);
2112
2113 imsg_int = ioread32(priv->regs + TSI721_IBDMAC_INT(ch));
2114
2115 if (imsg_int & TSI721_IBDMAC_INT_SRTO)
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002116 tsi_info(&priv->pdev->dev, "IB MBOX%d SRIO timeout", mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002117
2118 if (imsg_int & TSI721_IBDMAC_INT_PC_ERROR)
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002119 tsi_info(&priv->pdev->dev, "IB MBOX%d PCIe error", mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002120
2121 if (imsg_int & TSI721_IBDMAC_INT_FQ_LOW)
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002122 tsi_info(&priv->pdev->dev, "IB MBOX%d IB free queue low", mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002123
2124 /* Clear IB channel interrupts */
2125 iowrite32(imsg_int, priv->regs + TSI721_IBDMAC_INT(ch));
2126
2127 /* If an IB Msg is received notify the upper layer */
2128 if (imsg_int & TSI721_IBDMAC_INT_DQ_RCV &&
Alexandre Bounine748353c2016-03-22 14:26:23 -07002129 mport->inb_msg[mbox].mcback)
2130 mport->inb_msg[mbox].mcback(mport,
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002131 priv->imsg_ring[mbox].dev_id, mbox, -1);
2132
2133 if (!(priv->flags & TSI721_USING_MSIX)) {
2134 u32 ch_inte;
2135
2136 /* Re-enable channel interrupts */
2137 ch_inte = ioread32(priv->regs + TSI721_DEV_CHAN_INTE);
2138 ch_inte |= TSI721_INT_IMSG_CHAN(ch);
2139 iowrite32(ch_inte, priv->regs + TSI721_DEV_CHAN_INTE);
2140 }
2141
2142 spin_unlock(&priv->imsg_ring[mbox].lock);
2143}
2144
2145/**
2146 * tsi721_open_inb_mbox - Initialize Tsi721 inbound mailbox
2147 * @mport: Master port implementing the Inbound Messaging Engine
2148 * @dev_id: Device specific pointer to pass on event
2149 * @mbox: Mailbox to open
2150 * @entries: Number of entries in the inbound mailbox ring
2151 */
2152static int tsi721_open_inb_mbox(struct rio_mport *mport, void *dev_id,
2153 int mbox, int entries)
2154{
2155 struct tsi721_device *priv = mport->priv;
2156 int ch = mbox + 4;
2157 int i;
2158 u64 *free_ptr;
2159 int rc = 0;
2160
2161 if ((entries < TSI721_IMSGD_MIN_RING_SIZE) ||
2162 (entries > TSI721_IMSGD_RING_SIZE) ||
2163 (!is_power_of_2(entries)) || mbox >= RIO_MAX_MBOX) {
2164 rc = -EINVAL;
2165 goto out;
2166 }
2167
2168 /* Initialize IB Messaging Ring */
2169 priv->imsg_ring[mbox].dev_id = dev_id;
2170 priv->imsg_ring[mbox].size = entries;
2171 priv->imsg_ring[mbox].rx_slot = 0;
2172 priv->imsg_ring[mbox].desc_rdptr = 0;
2173 priv->imsg_ring[mbox].fq_wrptr = 0;
2174 for (i = 0; i < priv->imsg_ring[mbox].size; i++)
2175 priv->imsg_ring[mbox].imq_base[i] = NULL;
2176 spin_lock_init(&priv->imsg_ring[mbox].lock);
2177
2178 /* Allocate buffers for incoming messages */
2179 priv->imsg_ring[mbox].buf_base =
2180 dma_alloc_coherent(&priv->pdev->dev,
2181 entries * TSI721_MSG_BUFFER_SIZE,
2182 &priv->imsg_ring[mbox].buf_phys,
2183 GFP_KERNEL);
2184
2185 if (priv->imsg_ring[mbox].buf_base == NULL) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002186 tsi_err(&priv->pdev->dev,
2187 "Failed to allocate buffers for IB MBOX%d", mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002188 rc = -ENOMEM;
2189 goto out;
2190 }
2191
2192 /* Allocate memory for circular free list */
2193 priv->imsg_ring[mbox].imfq_base =
2194 dma_alloc_coherent(&priv->pdev->dev,
2195 entries * 8,
2196 &priv->imsg_ring[mbox].imfq_phys,
2197 GFP_KERNEL);
2198
2199 if (priv->imsg_ring[mbox].imfq_base == NULL) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002200 tsi_err(&priv->pdev->dev,
2201 "Failed to allocate free queue for IB MBOX%d", mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002202 rc = -ENOMEM;
2203 goto out_buf;
2204 }
2205
2206 /* Allocate memory for Inbound message descriptors */
2207 priv->imsg_ring[mbox].imd_base =
2208 dma_alloc_coherent(&priv->pdev->dev,
2209 entries * sizeof(struct tsi721_imsg_desc),
2210 &priv->imsg_ring[mbox].imd_phys, GFP_KERNEL);
2211
2212 if (priv->imsg_ring[mbox].imd_base == NULL) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002213 tsi_err(&priv->pdev->dev,
2214 "Failed to allocate descriptor memory for IB MBOX%d",
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002215 mbox);
2216 rc = -ENOMEM;
2217 goto out_dma;
2218 }
2219
2220 /* Fill free buffer pointer list */
2221 free_ptr = priv->imsg_ring[mbox].imfq_base;
2222 for (i = 0; i < entries; i++)
2223 free_ptr[i] = cpu_to_le64(
2224 (u64)(priv->imsg_ring[mbox].buf_phys) +
2225 i * 0x1000);
2226
2227 mb();
2228
2229 /*
2230 * For mapping of inbound SRIO Messages into appropriate queues we need
2231 * to set Inbound Device ID register in the messaging engine. We do it
2232 * once when first inbound mailbox is requested.
2233 */
2234 if (!(priv->flags & TSI721_IMSGID_SET)) {
Alexandre Bounine748353c2016-03-22 14:26:23 -07002235 iowrite32((u32)priv->mport.host_deviceid,
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002236 priv->regs + TSI721_IB_DEVID);
2237 priv->flags |= TSI721_IMSGID_SET;
2238 }
2239
2240 /*
2241 * Configure Inbound Messaging channel (ch = mbox + 4)
2242 */
2243
2244 /* Setup Inbound Message free queue */
2245 iowrite32(((u64)priv->imsg_ring[mbox].imfq_phys >> 32),
2246 priv->regs + TSI721_IBDMAC_FQBH(ch));
2247 iowrite32(((u64)priv->imsg_ring[mbox].imfq_phys &
2248 TSI721_IBDMAC_FQBL_MASK),
2249 priv->regs+TSI721_IBDMAC_FQBL(ch));
2250 iowrite32(TSI721_DMAC_DSSZ_SIZE(entries),
2251 priv->regs + TSI721_IBDMAC_FQSZ(ch));
2252
2253 /* Setup Inbound Message descriptor queue */
2254 iowrite32(((u64)priv->imsg_ring[mbox].imd_phys >> 32),
2255 priv->regs + TSI721_IBDMAC_DQBH(ch));
2256 iowrite32(((u32)priv->imsg_ring[mbox].imd_phys &
2257 (u32)TSI721_IBDMAC_DQBL_MASK),
2258 priv->regs+TSI721_IBDMAC_DQBL(ch));
2259 iowrite32(TSI721_DMAC_DSSZ_SIZE(entries),
2260 priv->regs + TSI721_IBDMAC_DQSZ(ch));
2261
2262 /* Enable interrupts */
2263
2264#ifdef CONFIG_PCI_MSI
2265 if (priv->flags & TSI721_USING_MSIX) {
Alexandre Bounine748353c2016-03-22 14:26:23 -07002266 int idx = TSI721_VECT_IMB0_RCV + mbox;
2267
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002268 /* Request interrupt service if we are in MSI-X mode */
Alexandre Bounine748353c2016-03-22 14:26:23 -07002269 rc = request_irq(priv->msix[idx].vector, tsi721_imsg_msix, 0,
2270 priv->msix[idx].irq_name, (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002271
2272 if (rc) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002273 tsi_debug(IMSG, &priv->pdev->dev,
2274 "Unable to get MSI-X IRQ for IBOX%d-DONE",
2275 mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002276 goto out_desc;
2277 }
2278
Alexandre Bounine748353c2016-03-22 14:26:23 -07002279 idx = TSI721_VECT_IMB0_INT + mbox;
2280 rc = request_irq(priv->msix[idx].vector, tsi721_imsg_msix, 0,
2281 priv->msix[idx].irq_name, (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002282
2283 if (rc) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002284 tsi_debug(IMSG, &priv->pdev->dev,
2285 "Unable to get MSI-X IRQ for IBOX%d-INT", mbox);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002286 free_irq(
2287 priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector,
Alexandre Bounine748353c2016-03-22 14:26:23 -07002288 (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002289 goto out_desc;
2290 }
2291 }
2292#endif /* CONFIG_PCI_MSI */
2293
2294 tsi721_imsg_interrupt_enable(priv, ch, TSI721_IBDMAC_INT_ALL);
2295
2296 /* Initialize Inbound Message Engine */
2297 iowrite32(TSI721_IBDMAC_CTL_INIT, priv->regs + TSI721_IBDMAC_CTL(ch));
2298 ioread32(priv->regs + TSI721_IBDMAC_CTL(ch));
2299 udelay(10);
2300 priv->imsg_ring[mbox].fq_wrptr = entries - 1;
2301 iowrite32(entries - 1, priv->regs + TSI721_IBDMAC_FQWP(ch));
2302
2303 priv->imsg_init[mbox] = 1;
2304 return 0;
2305
2306#ifdef CONFIG_PCI_MSI
2307out_desc:
2308 dma_free_coherent(&priv->pdev->dev,
2309 priv->imsg_ring[mbox].size * sizeof(struct tsi721_imsg_desc),
2310 priv->imsg_ring[mbox].imd_base,
2311 priv->imsg_ring[mbox].imd_phys);
2312
2313 priv->imsg_ring[mbox].imd_base = NULL;
2314#endif /* CONFIG_PCI_MSI */
2315
2316out_dma:
2317 dma_free_coherent(&priv->pdev->dev,
2318 priv->imsg_ring[mbox].size * 8,
2319 priv->imsg_ring[mbox].imfq_base,
2320 priv->imsg_ring[mbox].imfq_phys);
2321
2322 priv->imsg_ring[mbox].imfq_base = NULL;
2323
2324out_buf:
2325 dma_free_coherent(&priv->pdev->dev,
2326 priv->imsg_ring[mbox].size * TSI721_MSG_BUFFER_SIZE,
2327 priv->imsg_ring[mbox].buf_base,
2328 priv->imsg_ring[mbox].buf_phys);
2329
2330 priv->imsg_ring[mbox].buf_base = NULL;
2331
2332out:
2333 return rc;
2334}
2335
2336/**
2337 * tsi721_close_inb_mbox - Shut down Tsi721 inbound mailbox
2338 * @mport: Master port implementing the Inbound Messaging Engine
2339 * @mbox: Mailbox to close
2340 */
2341static void tsi721_close_inb_mbox(struct rio_mport *mport, int mbox)
2342{
2343 struct tsi721_device *priv = mport->priv;
2344 u32 rx_slot;
2345 int ch = mbox + 4;
2346
2347 if (!priv->imsg_init[mbox]) /* mbox isn't initialized yet */
2348 return;
2349 priv->imsg_init[mbox] = 0;
2350
2351 /* Disable Inbound Messaging Engine */
2352
2353 /* Disable Interrupts */
2354 tsi721_imsg_interrupt_disable(priv, ch, TSI721_OBDMAC_INT_MASK);
2355
2356#ifdef CONFIG_PCI_MSI
2357 if (priv->flags & TSI721_USING_MSIX) {
2358 free_irq(priv->msix[TSI721_VECT_IMB0_RCV + mbox].vector,
Alexandre Bounine748353c2016-03-22 14:26:23 -07002359 (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002360 free_irq(priv->msix[TSI721_VECT_IMB0_INT + mbox].vector,
Alexandre Bounine748353c2016-03-22 14:26:23 -07002361 (void *)priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002362 }
2363#endif /* CONFIG_PCI_MSI */
2364
2365 /* Clear Inbound Buffer Queue */
2366 for (rx_slot = 0; rx_slot < priv->imsg_ring[mbox].size; rx_slot++)
2367 priv->imsg_ring[mbox].imq_base[rx_slot] = NULL;
2368
2369 /* Free memory allocated for message buffers */
2370 dma_free_coherent(&priv->pdev->dev,
2371 priv->imsg_ring[mbox].size * TSI721_MSG_BUFFER_SIZE,
2372 priv->imsg_ring[mbox].buf_base,
2373 priv->imsg_ring[mbox].buf_phys);
2374
2375 priv->imsg_ring[mbox].buf_base = NULL;
2376
2377 /* Free memory allocated for free pointr list */
2378 dma_free_coherent(&priv->pdev->dev,
2379 priv->imsg_ring[mbox].size * 8,
2380 priv->imsg_ring[mbox].imfq_base,
2381 priv->imsg_ring[mbox].imfq_phys);
2382
2383 priv->imsg_ring[mbox].imfq_base = NULL;
2384
2385 /* Free memory allocated for RX descriptors */
2386 dma_free_coherent(&priv->pdev->dev,
2387 priv->imsg_ring[mbox].size * sizeof(struct tsi721_imsg_desc),
2388 priv->imsg_ring[mbox].imd_base,
2389 priv->imsg_ring[mbox].imd_phys);
2390
2391 priv->imsg_ring[mbox].imd_base = NULL;
2392}
2393
2394/**
2395 * tsi721_add_inb_buffer - Add buffer to the Tsi721 inbound message queue
2396 * @mport: Master port implementing the Inbound Messaging Engine
2397 * @mbox: Inbound mailbox number
2398 * @buf: Buffer to add to inbound queue
2399 */
2400static int tsi721_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
2401{
2402 struct tsi721_device *priv = mport->priv;
2403 u32 rx_slot;
2404 int rc = 0;
2405
2406 rx_slot = priv->imsg_ring[mbox].rx_slot;
2407 if (priv->imsg_ring[mbox].imq_base[rx_slot]) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002408 tsi_err(&priv->pdev->dev,
2409 "Error adding inbound buffer %d, buffer exists",
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002410 rx_slot);
2411 rc = -EINVAL;
2412 goto out;
2413 }
2414
2415 priv->imsg_ring[mbox].imq_base[rx_slot] = buf;
2416
2417 if (++priv->imsg_ring[mbox].rx_slot == priv->imsg_ring[mbox].size)
2418 priv->imsg_ring[mbox].rx_slot = 0;
2419
2420out:
2421 return rc;
2422}
2423
2424/**
2425 * tsi721_get_inb_message - Fetch inbound message from the Tsi721 MSG Queue
2426 * @mport: Master port implementing the Inbound Messaging Engine
2427 * @mbox: Inbound mailbox number
2428 *
2429 * Returns pointer to the message on success or NULL on failure.
2430 */
2431static void *tsi721_get_inb_message(struct rio_mport *mport, int mbox)
2432{
2433 struct tsi721_device *priv = mport->priv;
2434 struct tsi721_imsg_desc *desc;
2435 u32 rx_slot;
2436 void *rx_virt = NULL;
2437 u64 rx_phys;
2438 void *buf = NULL;
2439 u64 *free_ptr;
2440 int ch = mbox + 4;
2441 int msg_size;
2442
2443 if (!priv->imsg_init[mbox])
2444 return NULL;
2445
2446 desc = priv->imsg_ring[mbox].imd_base;
2447 desc += priv->imsg_ring[mbox].desc_rdptr;
2448
2449 if (!(le32_to_cpu(desc->msg_info) & TSI721_IMD_HO))
2450 goto out;
2451
2452 rx_slot = priv->imsg_ring[mbox].rx_slot;
2453 while (priv->imsg_ring[mbox].imq_base[rx_slot] == NULL) {
2454 if (++rx_slot == priv->imsg_ring[mbox].size)
2455 rx_slot = 0;
2456 }
2457
2458 rx_phys = ((u64)le32_to_cpu(desc->bufptr_hi) << 32) |
2459 le32_to_cpu(desc->bufptr_lo);
2460
2461 rx_virt = priv->imsg_ring[mbox].buf_base +
2462 (rx_phys - (u64)priv->imsg_ring[mbox].buf_phys);
2463
2464 buf = priv->imsg_ring[mbox].imq_base[rx_slot];
2465 msg_size = le32_to_cpu(desc->msg_info) & TSI721_IMD_BCOUNT;
2466 if (msg_size == 0)
2467 msg_size = RIO_MAX_MSG_SIZE;
2468
2469 memcpy(buf, rx_virt, msg_size);
2470 priv->imsg_ring[mbox].imq_base[rx_slot] = NULL;
2471
2472 desc->msg_info &= cpu_to_le32(~TSI721_IMD_HO);
2473 if (++priv->imsg_ring[mbox].desc_rdptr == priv->imsg_ring[mbox].size)
2474 priv->imsg_ring[mbox].desc_rdptr = 0;
2475
2476 iowrite32(priv->imsg_ring[mbox].desc_rdptr,
2477 priv->regs + TSI721_IBDMAC_DQRP(ch));
2478
2479 /* Return free buffer into the pointer list */
2480 free_ptr = priv->imsg_ring[mbox].imfq_base;
2481 free_ptr[priv->imsg_ring[mbox].fq_wrptr] = cpu_to_le64(rx_phys);
2482
2483 if (++priv->imsg_ring[mbox].fq_wrptr == priv->imsg_ring[mbox].size)
2484 priv->imsg_ring[mbox].fq_wrptr = 0;
2485
2486 iowrite32(priv->imsg_ring[mbox].fq_wrptr,
2487 priv->regs + TSI721_IBDMAC_FQWP(ch));
2488out:
2489 return buf;
2490}
2491
2492/**
2493 * tsi721_messages_init - Initialization of Messaging Engine
2494 * @priv: pointer to tsi721 private data
2495 *
2496 * Configures Tsi721 messaging engine.
2497 */
2498static int tsi721_messages_init(struct tsi721_device *priv)
2499{
2500 int ch;
2501
2502 iowrite32(0, priv->regs + TSI721_SMSG_ECC_LOG);
2503 iowrite32(0, priv->regs + TSI721_RETRY_GEN_CNT);
2504 iowrite32(0, priv->regs + TSI721_RETRY_RX_CNT);
2505
2506 /* Set SRIO Message Request/Response Timeout */
2507 iowrite32(TSI721_RQRPTO_VAL, priv->regs + TSI721_RQRPTO);
2508
2509 /* Initialize Inbound Messaging Engine Registers */
2510 for (ch = 0; ch < TSI721_IMSG_CHNUM; ch++) {
2511 /* Clear interrupt bits */
2512 iowrite32(TSI721_IBDMAC_INT_MASK,
2513 priv->regs + TSI721_IBDMAC_INT(ch));
2514 /* Clear Status */
2515 iowrite32(0, priv->regs + TSI721_IBDMAC_STS(ch));
2516
2517 iowrite32(TSI721_SMSG_ECC_COR_LOG_MASK,
2518 priv->regs + TSI721_SMSG_ECC_COR_LOG(ch));
2519 iowrite32(TSI721_SMSG_ECC_NCOR_MASK,
2520 priv->regs + TSI721_SMSG_ECC_NCOR(ch));
2521 }
2522
2523 return 0;
2524}
2525
2526/**
Alexandre Bouninedbe74af2016-03-22 14:26:02 -07002527 * tsi721_query_mport - Fetch inbound message from the Tsi721 MSG Queue
2528 * @mport: Master port implementing the Inbound Messaging Engine
2529 * @mbox: Inbound mailbox number
2530 *
2531 * Returns pointer to the message on success or NULL on failure.
2532 */
2533static int tsi721_query_mport(struct rio_mport *mport,
2534 struct rio_mport_attr *attr)
2535{
2536 struct tsi721_device *priv = mport->priv;
2537 u32 rval;
2538
2539 rval = ioread32(priv->regs + (0x100 + RIO_PORT_N_ERR_STS_CSR(0)));
2540 if (rval & RIO_PORT_N_ERR_STS_PORT_OK) {
2541 rval = ioread32(priv->regs + (0x100 + RIO_PORT_N_CTL2_CSR(0)));
2542 attr->link_speed = (rval & RIO_PORT_N_CTL2_SEL_BAUD) >> 28;
2543 rval = ioread32(priv->regs + (0x100 + RIO_PORT_N_CTL_CSR(0)));
2544 attr->link_width = (rval & RIO_PORT_N_CTL_IPW) >> 27;
2545 } else
2546 attr->link_speed = RIO_LINK_DOWN;
2547
2548#ifdef CONFIG_RAPIDIO_DMA_ENGINE
2549 attr->flags = RIO_MPORT_DMA | RIO_MPORT_DMA_SG;
2550 attr->dma_max_sge = 0;
2551 attr->dma_max_size = TSI721_BDMA_MAX_BCOUNT;
2552 attr->dma_align = 0;
2553#else
2554 attr->flags = 0;
2555#endif
2556 return 0;
2557}
2558
2559/**
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002560 * tsi721_disable_ints - disables all device interrupts
2561 * @priv: pointer to tsi721 private data
2562 */
2563static void tsi721_disable_ints(struct tsi721_device *priv)
2564{
2565 int ch;
2566
2567 /* Disable all device level interrupts */
2568 iowrite32(0, priv->regs + TSI721_DEV_INTE);
2569
2570 /* Disable all Device Channel interrupts */
2571 iowrite32(0, priv->regs + TSI721_DEV_CHAN_INTE);
2572
2573 /* Disable all Inbound Msg Channel interrupts */
2574 for (ch = 0; ch < TSI721_IMSG_CHNUM; ch++)
2575 iowrite32(0, priv->regs + TSI721_IBDMAC_INTE(ch));
2576
2577 /* Disable all Outbound Msg Channel interrupts */
2578 for (ch = 0; ch < TSI721_OMSG_CHNUM; ch++)
2579 iowrite32(0, priv->regs + TSI721_OBDMAC_INTE(ch));
2580
2581 /* Disable all general messaging interrupts */
2582 iowrite32(0, priv->regs + TSI721_SMSG_INTE);
2583
2584 /* Disable all BDMA Channel interrupts */
2585 for (ch = 0; ch < TSI721_DMA_MAXCH; ch++)
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07002586 iowrite32(0,
2587 priv->regs + TSI721_DMAC_BASE(ch) + TSI721_DMAC_INTE);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002588
2589 /* Disable all general BDMA interrupts */
2590 iowrite32(0, priv->regs + TSI721_BDMA_INTE);
2591
2592 /* Disable all SRIO Channel interrupts */
2593 for (ch = 0; ch < TSI721_SRIO_MAXCH; ch++)
2594 iowrite32(0, priv->regs + TSI721_SR_CHINTE(ch));
2595
2596 /* Disable all general SR2PC interrupts */
2597 iowrite32(0, priv->regs + TSI721_SR2PC_GEN_INTE);
2598
2599 /* Disable all PC2SR interrupts */
2600 iowrite32(0, priv->regs + TSI721_PC2SR_INTE);
2601
2602 /* Disable all I2C interrupts */
2603 iowrite32(0, priv->regs + TSI721_I2C_INT_ENABLE);
2604
2605 /* Disable SRIO MAC interrupts */
2606 iowrite32(0, priv->regs + TSI721_RIO_EM_INT_ENABLE);
2607 iowrite32(0, priv->regs + TSI721_RIO_EM_DEV_INT_EN);
2608}
2609
Alexandre Bounine748353c2016-03-22 14:26:23 -07002610static struct rio_ops tsi721_rio_ops = {
2611 .lcread = tsi721_lcread,
2612 .lcwrite = tsi721_lcwrite,
2613 .cread = tsi721_cread_dma,
2614 .cwrite = tsi721_cwrite_dma,
2615 .dsend = tsi721_dsend,
2616 .open_inb_mbox = tsi721_open_inb_mbox,
2617 .close_inb_mbox = tsi721_close_inb_mbox,
2618 .open_outb_mbox = tsi721_open_outb_mbox,
2619 .close_outb_mbox = tsi721_close_outb_mbox,
2620 .add_outb_message = tsi721_add_outb_message,
2621 .add_inb_buffer = tsi721_add_inb_buffer,
2622 .get_inb_message = tsi721_get_inb_message,
2623 .map_inb = tsi721_rio_map_inb_mem,
2624 .unmap_inb = tsi721_rio_unmap_inb_mem,
2625 .pwenable = tsi721_pw_enable,
2626 .query_mport = tsi721_query_mport,
Alexandre Bounine1679e8d2016-03-22 14:26:53 -07002627 .map_outb = tsi721_map_outb_win,
2628 .unmap_outb = tsi721_unmap_outb_win,
Alexandre Bounine748353c2016-03-22 14:26:23 -07002629};
2630
2631static void tsi721_mport_release(struct device *dev)
2632{
2633 struct rio_mport *mport = to_rio_mport(dev);
2634
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002635 tsi_debug(EXIT, dev, "%s id=%d", mport->name, mport->id);
Alexandre Bounine748353c2016-03-22 14:26:23 -07002636}
2637
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002638/**
2639 * tsi721_setup_mport - Setup Tsi721 as RapidIO subsystem master port
2640 * @priv: pointer to tsi721 private data
2641 *
2642 * Configures Tsi721 as RapidIO master port.
2643 */
Bill Pemberton305c8912012-11-19 13:23:25 -05002644static int tsi721_setup_mport(struct tsi721_device *priv)
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002645{
2646 struct pci_dev *pdev = priv->pdev;
2647 int err = 0;
Alexandre Bounine748353c2016-03-22 14:26:23 -07002648 struct rio_mport *mport = &priv->mport;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002649
Alexandre Bounine748353c2016-03-22 14:26:23 -07002650 err = rio_mport_initialize(mport);
2651 if (err)
2652 return err;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002653
Alexandre Bounine748353c2016-03-22 14:26:23 -07002654 mport->ops = &tsi721_rio_ops;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002655 mport->index = 0;
2656 mport->sys_size = 0; /* small system */
2657 mport->phy_type = RIO_PHY_SERIAL;
2658 mport->priv = (void *)priv;
2659 mport->phys_efptr = 0x100;
Alexandre Bounine2aaf3082014-04-07 15:38:56 -07002660 mport->dev.parent = &pdev->dev;
Alexandre Bounine748353c2016-03-22 14:26:23 -07002661 mport->dev.release = tsi721_mport_release;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002662
2663 INIT_LIST_HEAD(&mport->dbells);
2664
2665 rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
Alexandre Bounineb439e662011-12-08 14:34:36 -08002666 rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 3);
2667 rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 3);
Alexandre Bounineed43f442012-10-04 17:15:51 -07002668 snprintf(mport->name, RIO_MAX_MPORT_NAME, "%s(%s)",
2669 dev_driver_string(&pdev->dev), dev_name(&pdev->dev));
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002670
2671 /* Hook up interrupt handler */
2672
2673#ifdef CONFIG_PCI_MSI
2674 if (!tsi721_enable_msix(priv))
2675 priv->flags |= TSI721_USING_MSIX;
2676 else if (!pci_enable_msi(pdev))
2677 priv->flags |= TSI721_USING_MSI;
2678 else
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002679 tsi_debug(MPORT, &pdev->dev,
2680 "MSI/MSI-X is not available. Using legacy INTx.");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002681#endif /* CONFIG_PCI_MSI */
2682
Alexandre Bounine748353c2016-03-22 14:26:23 -07002683 err = tsi721_request_irq(priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002684
Alexandre Bounine748353c2016-03-22 14:26:23 -07002685 if (err) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002686 tsi_err(&pdev->dev, "Unable to get PCI IRQ %02X (err=0x%x)",
2687 pdev->irq, err);
Alexandre Bounine748353c2016-03-22 14:26:23 -07002688 return err;
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07002689 }
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002690
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07002691#ifdef CONFIG_RAPIDIO_DMA_ENGINE
Alexandre Bounine748353c2016-03-22 14:26:23 -07002692 err = tsi721_register_dma(priv);
2693 if (err)
2694 goto err_exit;
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07002695#endif
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002696 /* Enable SRIO link */
2697 iowrite32(ioread32(priv->regs + TSI721_DEVCTL) |
2698 TSI721_DEVCTL_SRBOOT_CMPL,
2699 priv->regs + TSI721_DEVCTL);
2700
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002701 if (mport->host_deviceid >= 0)
2702 iowrite32(RIO_PORT_GEN_HOST | RIO_PORT_GEN_MASTER |
2703 RIO_PORT_GEN_DISCOVERED,
2704 priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR));
2705 else
2706 iowrite32(0, priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR));
2707
Alexandre Bounine748353c2016-03-22 14:26:23 -07002708 err = rio_register_mport(mport);
2709 if (err) {
2710 tsi721_unregister_dma(priv);
2711 goto err_exit;
2712 }
2713
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002714 return 0;
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07002715
2716err_exit:
Alexandre Bounine748353c2016-03-22 14:26:23 -07002717 tsi721_free_irq(priv);
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07002718 return err;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002719}
2720
Bill Pemberton305c8912012-11-19 13:23:25 -05002721static int tsi721_probe(struct pci_dev *pdev,
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002722 const struct pci_device_id *id)
2723{
2724 struct tsi721_device *priv;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002725 int err;
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002726
2727 priv = kzalloc(sizeof(struct tsi721_device), GFP_KERNEL);
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002728 if (!priv) {
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002729 err = -ENOMEM;
2730 goto err_exit;
2731 }
2732
2733 err = pci_enable_device(pdev);
2734 if (err) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002735 tsi_err(&pdev->dev, "Failed to enable PCI device");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002736 goto err_clean;
2737 }
2738
2739 priv->pdev = pdev;
2740
2741#ifdef DEBUG
Alexandre Bounine9a9a9a72012-08-21 16:16:12 -07002742 {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002743 int i;
2744
2745 for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
2746 tsi_debug(INIT, &pdev->dev, "res%d %pR",
2747 i, &pdev->resource[i]);
2748 }
Alexandre Bounine9a9a9a72012-08-21 16:16:12 -07002749 }
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002750#endif
2751 /*
2752 * Verify BAR configuration
2753 */
2754
2755 /* BAR_0 (registers) must be 512KB+ in 32-bit address space */
2756 if (!(pci_resource_flags(pdev, BAR_0) & IORESOURCE_MEM) ||
2757 pci_resource_flags(pdev, BAR_0) & IORESOURCE_MEM_64 ||
2758 pci_resource_len(pdev, BAR_0) < TSI721_REG_SPACE_SIZE) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002759 tsi_err(&pdev->dev, "Missing or misconfigured CSR BAR0");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002760 err = -ENODEV;
2761 goto err_disable_pdev;
2762 }
2763
2764 /* BAR_1 (outbound doorbells) must be 16MB+ in 32-bit address space */
2765 if (!(pci_resource_flags(pdev, BAR_1) & IORESOURCE_MEM) ||
2766 pci_resource_flags(pdev, BAR_1) & IORESOURCE_MEM_64 ||
2767 pci_resource_len(pdev, BAR_1) < TSI721_DB_WIN_SIZE) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002768 tsi_err(&pdev->dev, "Missing or misconfigured Doorbell BAR1");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002769 err = -ENODEV;
2770 goto err_disable_pdev;
2771 }
2772
2773 /*
2774 * BAR_2 and BAR_4 (outbound translation) must be in 64-bit PCIe address
2775 * space.
2776 * NOTE: BAR_2 and BAR_4 are not used by this version of driver.
2777 * It may be a good idea to keep them disabled using HW configuration
2778 * to save PCI memory space.
2779 */
Alexandre Bounine1679e8d2016-03-22 14:26:53 -07002780
2781 priv->p2r_bar[0].size = priv->p2r_bar[1].size = 0;
2782
2783 if (pci_resource_flags(pdev, BAR_2) & IORESOURCE_MEM_64) {
2784 if (pci_resource_flags(pdev, BAR_2) & IORESOURCE_PREFETCH)
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002785 tsi_debug(INIT, &pdev->dev,
2786 "Prefetchable OBW BAR2 will not be used");
Alexandre Bounine1679e8d2016-03-22 14:26:53 -07002787 else {
2788 priv->p2r_bar[0].base = pci_resource_start(pdev, BAR_2);
2789 priv->p2r_bar[0].size = pci_resource_len(pdev, BAR_2);
2790 }
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002791 }
2792
Alexandre Bounine1679e8d2016-03-22 14:26:53 -07002793 if (pci_resource_flags(pdev, BAR_4) & IORESOURCE_MEM_64) {
2794 if (pci_resource_flags(pdev, BAR_4) & IORESOURCE_PREFETCH)
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002795 tsi_debug(INIT, &pdev->dev,
2796 "Prefetchable OBW BAR4 will not be used");
Alexandre Bounine1679e8d2016-03-22 14:26:53 -07002797 else {
2798 priv->p2r_bar[1].base = pci_resource_start(pdev, BAR_4);
2799 priv->p2r_bar[1].size = pci_resource_len(pdev, BAR_4);
2800 }
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002801 }
2802
2803 err = pci_request_regions(pdev, DRV_NAME);
2804 if (err) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002805 tsi_err(&pdev->dev, "Unable to obtain PCI resources");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002806 goto err_disable_pdev;
2807 }
2808
2809 pci_set_master(pdev);
2810
2811 priv->regs = pci_ioremap_bar(pdev, BAR_0);
2812 if (!priv->regs) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002813 tsi_err(&pdev->dev, "Unable to map device registers space");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002814 err = -ENOMEM;
2815 goto err_free_res;
2816 }
2817
2818 priv->odb_base = pci_ioremap_bar(pdev, BAR_1);
2819 if (!priv->odb_base) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002820 tsi_err(&pdev->dev, "Unable to map outbound doorbells space");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002821 err = -ENOMEM;
2822 goto err_unmap_bars;
2823 }
2824
2825 /* Configure DMA attributes. */
2826 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
Peter Senna Tschudin18f62872012-10-04 17:15:55 -07002827 err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
2828 if (err) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002829 tsi_err(&pdev->dev, "Unable to set DMA mask");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002830 goto err_unmap_bars;
2831 }
2832
2833 if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002834 tsi_info(&pdev->dev, "Unable to set consistent DMA mask");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002835 } else {
2836 err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
2837 if (err)
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002838 tsi_info(&pdev->dev, "Unable to set consistent DMA mask");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002839 }
2840
Jiang Liu5cdaaf82012-07-24 17:20:31 +08002841 BUG_ON(!pci_is_pcie(pdev));
Alexandre Bounine1cee22b2011-12-08 14:34:42 -08002842
Alexandre Bounine174f1a72016-03-22 14:25:48 -07002843 /* Clear "no snoop" and "relaxed ordering" bits. */
Jiang Liu5cdaaf82012-07-24 17:20:31 +08002844 pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
Alexandre Bounine174f1a72016-03-22 14:25:48 -07002845 PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN, 0);
Alexandre Bounine1cee22b2011-12-08 14:34:42 -08002846
Alexandre Bouninecb782cd2016-08-02 14:06:40 -07002847 /* Override PCIe Maximum Read Request Size setting if requested */
2848 if (pcie_mrrs >= 0) {
2849 if (pcie_mrrs <= 5)
2850 pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
2851 PCI_EXP_DEVCTL_READRQ, pcie_mrrs << 12);
2852 else
2853 tsi_info(&pdev->dev,
2854 "Invalid MRRS override value %d", pcie_mrrs);
2855 }
2856
Alexandre Bounine1cee22b2011-12-08 14:34:42 -08002857 /* Adjust PCIe completion timeout. */
Jiang Liu5cdaaf82012-07-24 17:20:31 +08002858 pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2, 0xf, 0x2);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002859
2860 /*
2861 * FIXUP: correct offsets of MSI-X tables in the MSI-X Capability Block
2862 */
2863 pci_write_config_dword(pdev, TSI721_PCIECFG_EPCTL, 0x01);
2864 pci_write_config_dword(pdev, TSI721_PCIECFG_MSIXTBL,
2865 TSI721_MSIXTBL_OFFSET);
2866 pci_write_config_dword(pdev, TSI721_PCIECFG_MSIXPBA,
2867 TSI721_MSIXPBA_OFFSET);
2868 pci_write_config_dword(pdev, TSI721_PCIECFG_EPCTL, 0);
2869 /* End of FIXUP */
2870
2871 tsi721_disable_ints(priv);
2872
2873 tsi721_init_pc2sr_mapping(priv);
2874 tsi721_init_sr2pc_mapping(priv);
2875
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07002876 if (tsi721_bdma_maint_init(priv)) {
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002877 tsi_err(&pdev->dev, "BDMA initialization failed");
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002878 err = -ENOMEM;
2879 goto err_unmap_bars;
2880 }
2881
2882 err = tsi721_doorbell_init(priv);
2883 if (err)
2884 goto err_free_bdma;
2885
2886 tsi721_port_write_init(priv);
2887
2888 err = tsi721_messages_init(priv);
2889 if (err)
2890 goto err_free_consistent;
2891
2892 err = tsi721_setup_mport(priv);
2893 if (err)
2894 goto err_free_consistent;
2895
Alexandre Bouninee3dd8cd2016-03-22 14:26:08 -07002896 pci_set_drvdata(pdev, priv);
Alexandre Bounine748353c2016-03-22 14:26:23 -07002897 tsi721_interrupts_init(priv);
Alexandre Bouninee3dd8cd2016-03-22 14:26:08 -07002898
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002899 return 0;
2900
2901err_free_consistent:
Alexandre Bounine748353c2016-03-22 14:26:23 -07002902 tsi721_port_write_free(priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002903 tsi721_doorbell_free(priv);
2904err_free_bdma:
Alexandre Bounine9eaa3d92012-05-31 16:26:39 -07002905 tsi721_bdma_maint_free(priv);
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002906err_unmap_bars:
2907 if (priv->regs)
2908 iounmap(priv->regs);
2909 if (priv->odb_base)
2910 iounmap(priv->odb_base);
2911err_free_res:
2912 pci_release_regions(pdev);
2913 pci_clear_master(pdev);
2914err_disable_pdev:
2915 pci_disable_device(pdev);
2916err_clean:
2917 kfree(priv);
2918err_exit:
2919 return err;
2920}
2921
Alexandre Bounine748353c2016-03-22 14:26:23 -07002922static void tsi721_remove(struct pci_dev *pdev)
2923{
2924 struct tsi721_device *priv = pci_get_drvdata(pdev);
2925
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002926 tsi_debug(EXIT, &pdev->dev, "enter");
Alexandre Bounine748353c2016-03-22 14:26:23 -07002927
2928 tsi721_disable_ints(priv);
2929 tsi721_free_irq(priv);
Alexandre Bounine9a0b0622016-03-22 14:26:44 -07002930 flush_scheduled_work();
Alexandre Bounine748353c2016-03-22 14:26:23 -07002931 rio_unregister_mport(&priv->mport);
2932
2933 tsi721_unregister_dma(priv);
2934 tsi721_bdma_maint_free(priv);
2935 tsi721_doorbell_free(priv);
2936 tsi721_port_write_free(priv);
2937 tsi721_close_sr2pc_mapping(priv);
2938
2939 if (priv->regs)
2940 iounmap(priv->regs);
2941 if (priv->odb_base)
2942 iounmap(priv->odb_base);
2943#ifdef CONFIG_PCI_MSI
2944 if (priv->flags & TSI721_USING_MSIX)
2945 pci_disable_msix(priv->pdev);
2946 else if (priv->flags & TSI721_USING_MSI)
2947 pci_disable_msi(priv->pdev);
2948#endif
2949 pci_release_regions(pdev);
2950 pci_clear_master(pdev);
2951 pci_disable_device(pdev);
2952 pci_set_drvdata(pdev, NULL);
2953 kfree(priv);
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002954 tsi_debug(EXIT, &pdev->dev, "exit");
Alexandre Bounine748353c2016-03-22 14:26:23 -07002955}
2956
Alexandre Bouninee3dd8cd2016-03-22 14:26:08 -07002957static void tsi721_shutdown(struct pci_dev *pdev)
2958{
2959 struct tsi721_device *priv = pci_get_drvdata(pdev);
2960
Alexandre Bounine72d8a0d2016-03-22 14:26:56 -07002961 tsi_debug(EXIT, &pdev->dev, "enter");
Alexandre Bouninee3dd8cd2016-03-22 14:26:08 -07002962
2963 tsi721_disable_ints(priv);
2964 tsi721_dma_stop_all(priv);
2965 pci_clear_master(pdev);
2966 pci_disable_device(pdev);
2967}
2968
Benoit Taine9baa3c32014-08-08 15:56:03 +02002969static const struct pci_device_id tsi721_pci_tbl[] = {
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002970 { PCI_DEVICE(PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_TSI721) },
2971 { 0, } /* terminate list */
2972};
2973
2974MODULE_DEVICE_TABLE(pci, tsi721_pci_tbl);
2975
2976static struct pci_driver tsi721_driver = {
2977 .name = "tsi721",
2978 .id_table = tsi721_pci_tbl,
2979 .probe = tsi721_probe,
Alexandre Bounine748353c2016-03-22 14:26:23 -07002980 .remove = tsi721_remove,
Alexandre Bouninee3dd8cd2016-03-22 14:26:08 -07002981 .shutdown = tsi721_shutdown,
Alexandre Bounine48618fb2011-11-02 13:39:09 -07002982};
2983
Alexandre Bounine748353c2016-03-22 14:26:23 -07002984module_pci_driver(tsi721_driver);
Alexandre Bounine94d9bd42013-07-03 15:08:55 -07002985
2986MODULE_DESCRIPTION("IDT Tsi721 PCIExpress-to-SRIO bridge driver");
2987MODULE_AUTHOR("Integrated Device Technology, Inc.");
2988MODULE_LICENSE("GPL");