1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Freescale MPC85xx/MPC86xx RapidIO RMU support
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright 2009 Sysgo AG
6*4882a593Smuzhiyun * Thomas Moll <thomas.moll@sysgo.com>
7*4882a593Smuzhiyun * - fixed maintenance access routines, check for aligned access
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Copyright 2009 Integrated Device Technology, Inc.
10*4882a593Smuzhiyun * Alex Bounine <alexandre.bounine@idt.com>
11*4882a593Smuzhiyun * - Added Port-Write message handling
12*4882a593Smuzhiyun * - Added Machine Check exception handling
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc.
15*4882a593Smuzhiyun * Zhang Wei <wei.zhang@freescale.com>
16*4882a593Smuzhiyun * Lian Minghuan-B31939 <Minghuan.Lian@freescale.com>
17*4882a593Smuzhiyun * Liu Gang <Gang.Liu@freescale.com>
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * Copyright 2005 MontaVista Software, Inc.
20*4882a593Smuzhiyun * Matt Porter <mporter@kernel.crashing.org>
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include <linux/types.h>
24*4882a593Smuzhiyun #include <linux/dma-mapping.h>
25*4882a593Smuzhiyun #include <linux/interrupt.h>
26*4882a593Smuzhiyun #include <linux/of_irq.h>
27*4882a593Smuzhiyun #include <linux/of_platform.h>
28*4882a593Smuzhiyun #include <linux/slab.h>
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include "fsl_rio.h"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define GET_RMM_HANDLE(mport) \
33*4882a593Smuzhiyun (((struct rio_priv *)(mport->priv))->rmm_handle)
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* RapidIO definition irq, which read from OF-tree */
36*4882a593Smuzhiyun #define IRQ_RIO_PW(m) (((struct fsl_rio_pw *)(m))->pwirq)
37*4882a593Smuzhiyun #define IRQ_RIO_BELL(m) (((struct fsl_rio_dbell *)(m))->bellirq)
38*4882a593Smuzhiyun #define IRQ_RIO_TX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->txirq)
39*4882a593Smuzhiyun #define IRQ_RIO_RX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->rxirq)
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define RIO_MIN_TX_RING_SIZE 2
42*4882a593Smuzhiyun #define RIO_MAX_TX_RING_SIZE 2048
43*4882a593Smuzhiyun #define RIO_MIN_RX_RING_SIZE 2
44*4882a593Smuzhiyun #define RIO_MAX_RX_RING_SIZE 2048
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun #define RIO_IPWMR_SEN 0x00100000
47*4882a593Smuzhiyun #define RIO_IPWMR_QFIE 0x00000100
48*4882a593Smuzhiyun #define RIO_IPWMR_EIE 0x00000020
49*4882a593Smuzhiyun #define RIO_IPWMR_CQ 0x00000002
50*4882a593Smuzhiyun #define RIO_IPWMR_PWE 0x00000001
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define RIO_IPWSR_QF 0x00100000
53*4882a593Smuzhiyun #define RIO_IPWSR_TE 0x00000080
54*4882a593Smuzhiyun #define RIO_IPWSR_QFI 0x00000010
55*4882a593Smuzhiyun #define RIO_IPWSR_PWD 0x00000008
56*4882a593Smuzhiyun #define RIO_IPWSR_PWB 0x00000004
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun #define RIO_EPWISR 0x10010
59*4882a593Smuzhiyun /* EPWISR Error match value */
60*4882a593Smuzhiyun #define RIO_EPWISR_PINT1 0x80000000
61*4882a593Smuzhiyun #define RIO_EPWISR_PINT2 0x40000000
62*4882a593Smuzhiyun #define RIO_EPWISR_MU 0x00000002
63*4882a593Smuzhiyun #define RIO_EPWISR_PW 0x00000001
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun #define IPWSR_CLEAR 0x98
66*4882a593Smuzhiyun #define OMSR_CLEAR 0x1cb3
67*4882a593Smuzhiyun #define IMSR_CLEAR 0x491
68*4882a593Smuzhiyun #define IDSR_CLEAR 0x91
69*4882a593Smuzhiyun #define ODSR_CLEAR 0x1c00
70*4882a593Smuzhiyun #define LTLEECSR_ENABLE_ALL 0xFFC000FC
71*4882a593Smuzhiyun #define RIO_LTLEECSR 0x060c
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun #define RIO_IM0SR 0x64
74*4882a593Smuzhiyun #define RIO_IM1SR 0x164
75*4882a593Smuzhiyun #define RIO_OM0SR 0x4
76*4882a593Smuzhiyun #define RIO_OM1SR 0x104
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun #define RIO_DBELL_WIN_SIZE 0x1000
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun #define RIO_MSG_OMR_MUI 0x00000002
81*4882a593Smuzhiyun #define RIO_MSG_OSR_TE 0x00000080
82*4882a593Smuzhiyun #define RIO_MSG_OSR_QOI 0x00000020
83*4882a593Smuzhiyun #define RIO_MSG_OSR_QFI 0x00000010
84*4882a593Smuzhiyun #define RIO_MSG_OSR_MUB 0x00000004
85*4882a593Smuzhiyun #define RIO_MSG_OSR_EOMI 0x00000002
86*4882a593Smuzhiyun #define RIO_MSG_OSR_QEI 0x00000001
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun #define RIO_MSG_IMR_MI 0x00000002
89*4882a593Smuzhiyun #define RIO_MSG_ISR_TE 0x00000080
90*4882a593Smuzhiyun #define RIO_MSG_ISR_QFI 0x00000010
91*4882a593Smuzhiyun #define RIO_MSG_ISR_DIQI 0x00000001
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #define RIO_MSG_DESC_SIZE 32
94*4882a593Smuzhiyun #define RIO_MSG_BUFFER_SIZE 4096
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun #define DOORBELL_DMR_DI 0x00000002
97*4882a593Smuzhiyun #define DOORBELL_DSR_TE 0x00000080
98*4882a593Smuzhiyun #define DOORBELL_DSR_QFI 0x00000010
99*4882a593Smuzhiyun #define DOORBELL_DSR_DIQI 0x00000001
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun #define DOORBELL_MESSAGE_SIZE 0x08
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun static DEFINE_SPINLOCK(fsl_rio_doorbell_lock);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun struct rio_msg_regs {
106*4882a593Smuzhiyun u32 omr;
107*4882a593Smuzhiyun u32 osr;
108*4882a593Smuzhiyun u32 pad1;
109*4882a593Smuzhiyun u32 odqdpar;
110*4882a593Smuzhiyun u32 pad2;
111*4882a593Smuzhiyun u32 osar;
112*4882a593Smuzhiyun u32 odpr;
113*4882a593Smuzhiyun u32 odatr;
114*4882a593Smuzhiyun u32 odcr;
115*4882a593Smuzhiyun u32 pad3;
116*4882a593Smuzhiyun u32 odqepar;
117*4882a593Smuzhiyun u32 pad4[13];
118*4882a593Smuzhiyun u32 imr;
119*4882a593Smuzhiyun u32 isr;
120*4882a593Smuzhiyun u32 pad5;
121*4882a593Smuzhiyun u32 ifqdpar;
122*4882a593Smuzhiyun u32 pad6;
123*4882a593Smuzhiyun u32 ifqepar;
124*4882a593Smuzhiyun };
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun struct rio_dbell_regs {
127*4882a593Smuzhiyun u32 odmr;
128*4882a593Smuzhiyun u32 odsr;
129*4882a593Smuzhiyun u32 pad1[4];
130*4882a593Smuzhiyun u32 oddpr;
131*4882a593Smuzhiyun u32 oddatr;
132*4882a593Smuzhiyun u32 pad2[3];
133*4882a593Smuzhiyun u32 odretcr;
134*4882a593Smuzhiyun u32 pad3[12];
135*4882a593Smuzhiyun u32 dmr;
136*4882a593Smuzhiyun u32 dsr;
137*4882a593Smuzhiyun u32 pad4;
138*4882a593Smuzhiyun u32 dqdpar;
139*4882a593Smuzhiyun u32 pad5;
140*4882a593Smuzhiyun u32 dqepar;
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun struct rio_pw_regs {
144*4882a593Smuzhiyun u32 pwmr;
145*4882a593Smuzhiyun u32 pwsr;
146*4882a593Smuzhiyun u32 epwqbar;
147*4882a593Smuzhiyun u32 pwqbar;
148*4882a593Smuzhiyun };
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun struct rio_tx_desc {
152*4882a593Smuzhiyun u32 pad1;
153*4882a593Smuzhiyun u32 saddr;
154*4882a593Smuzhiyun u32 dport;
155*4882a593Smuzhiyun u32 dattr;
156*4882a593Smuzhiyun u32 pad2;
157*4882a593Smuzhiyun u32 pad3;
158*4882a593Smuzhiyun u32 dwcnt;
159*4882a593Smuzhiyun u32 pad4;
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun struct rio_msg_tx_ring {
163*4882a593Smuzhiyun void *virt;
164*4882a593Smuzhiyun dma_addr_t phys;
165*4882a593Smuzhiyun void *virt_buffer[RIO_MAX_TX_RING_SIZE];
166*4882a593Smuzhiyun dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE];
167*4882a593Smuzhiyun int tx_slot;
168*4882a593Smuzhiyun int size;
169*4882a593Smuzhiyun void *dev_id;
170*4882a593Smuzhiyun };
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun struct rio_msg_rx_ring {
173*4882a593Smuzhiyun void *virt;
174*4882a593Smuzhiyun dma_addr_t phys;
175*4882a593Smuzhiyun void *virt_buffer[RIO_MAX_RX_RING_SIZE];
176*4882a593Smuzhiyun int rx_slot;
177*4882a593Smuzhiyun int size;
178*4882a593Smuzhiyun void *dev_id;
179*4882a593Smuzhiyun };
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun struct fsl_rmu {
182*4882a593Smuzhiyun struct rio_msg_regs __iomem *msg_regs;
183*4882a593Smuzhiyun struct rio_msg_tx_ring msg_tx_ring;
184*4882a593Smuzhiyun struct rio_msg_rx_ring msg_rx_ring;
185*4882a593Smuzhiyun int txirq;
186*4882a593Smuzhiyun int rxirq;
187*4882a593Smuzhiyun };
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun struct rio_dbell_msg {
190*4882a593Smuzhiyun u16 pad1;
191*4882a593Smuzhiyun u16 tid;
192*4882a593Smuzhiyun u16 sid;
193*4882a593Smuzhiyun u16 info;
194*4882a593Smuzhiyun };
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /**
197*4882a593Smuzhiyun * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler
198*4882a593Smuzhiyun * @irq: Linux interrupt number
199*4882a593Smuzhiyun * @dev_instance: Pointer to interrupt-specific data
200*4882a593Smuzhiyun *
201*4882a593Smuzhiyun * Handles outbound message interrupts. Executes a register outbound
202*4882a593Smuzhiyun * mailbox event handler and acks the interrupt occurrence.
203*4882a593Smuzhiyun */
204*4882a593Smuzhiyun static irqreturn_t
fsl_rio_tx_handler(int irq,void * dev_instance)205*4882a593Smuzhiyun fsl_rio_tx_handler(int irq, void *dev_instance)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun int osr;
208*4882a593Smuzhiyun struct rio_mport *port = (struct rio_mport *)dev_instance;
209*4882a593Smuzhiyun struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun osr = in_be32(&rmu->msg_regs->osr);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (osr & RIO_MSG_OSR_TE) {
214*4882a593Smuzhiyun pr_info("RIO: outbound message transmission error\n");
215*4882a593Smuzhiyun out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_TE);
216*4882a593Smuzhiyun goto out;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun if (osr & RIO_MSG_OSR_QOI) {
220*4882a593Smuzhiyun pr_info("RIO: outbound message queue overflow\n");
221*4882a593Smuzhiyun out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_QOI);
222*4882a593Smuzhiyun goto out;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun if (osr & RIO_MSG_OSR_EOMI) {
226*4882a593Smuzhiyun u32 dqp = in_be32(&rmu->msg_regs->odqdpar);
227*4882a593Smuzhiyun int slot = (dqp - rmu->msg_tx_ring.phys) >> 5;
228*4882a593Smuzhiyun if (port->outb_msg[0].mcback != NULL) {
229*4882a593Smuzhiyun port->outb_msg[0].mcback(port, rmu->msg_tx_ring.dev_id,
230*4882a593Smuzhiyun -1,
231*4882a593Smuzhiyun slot);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun /* Ack the end-of-message interrupt */
234*4882a593Smuzhiyun out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_EOMI);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun out:
238*4882a593Smuzhiyun return IRQ_HANDLED;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun /**
242*4882a593Smuzhiyun * fsl_rio_rx_handler - MPC85xx inbound message interrupt handler
243*4882a593Smuzhiyun * @irq: Linux interrupt number
244*4882a593Smuzhiyun * @dev_instance: Pointer to interrupt-specific data
245*4882a593Smuzhiyun *
246*4882a593Smuzhiyun * Handles inbound message interrupts. Executes a registered inbound
247*4882a593Smuzhiyun * mailbox event handler and acks the interrupt occurrence.
248*4882a593Smuzhiyun */
249*4882a593Smuzhiyun static irqreturn_t
fsl_rio_rx_handler(int irq,void * dev_instance)250*4882a593Smuzhiyun fsl_rio_rx_handler(int irq, void *dev_instance)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun int isr;
253*4882a593Smuzhiyun struct rio_mport *port = (struct rio_mport *)dev_instance;
254*4882a593Smuzhiyun struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun isr = in_be32(&rmu->msg_regs->isr);
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun if (isr & RIO_MSG_ISR_TE) {
259*4882a593Smuzhiyun pr_info("RIO: inbound message reception error\n");
260*4882a593Smuzhiyun out_be32((void *)&rmu->msg_regs->isr, RIO_MSG_ISR_TE);
261*4882a593Smuzhiyun goto out;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /* XXX Need to check/dispatch until queue empty */
265*4882a593Smuzhiyun if (isr & RIO_MSG_ISR_DIQI) {
266*4882a593Smuzhiyun /*
267*4882a593Smuzhiyun * Can receive messages for any mailbox/letter to that
268*4882a593Smuzhiyun * mailbox destination. So, make the callback with an
269*4882a593Smuzhiyun * unknown/invalid mailbox number argument.
270*4882a593Smuzhiyun */
271*4882a593Smuzhiyun if (port->inb_msg[0].mcback != NULL)
272*4882a593Smuzhiyun port->inb_msg[0].mcback(port, rmu->msg_rx_ring.dev_id,
273*4882a593Smuzhiyun -1,
274*4882a593Smuzhiyun -1);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /* Ack the queueing interrupt */
277*4882a593Smuzhiyun out_be32(&rmu->msg_regs->isr, RIO_MSG_ISR_DIQI);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun out:
281*4882a593Smuzhiyun return IRQ_HANDLED;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /**
285*4882a593Smuzhiyun * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler
286*4882a593Smuzhiyun * @irq: Linux interrupt number
287*4882a593Smuzhiyun * @dev_instance: Pointer to interrupt-specific data
288*4882a593Smuzhiyun *
289*4882a593Smuzhiyun * Handles doorbell interrupts. Parses a list of registered
290*4882a593Smuzhiyun * doorbell event handlers and executes a matching event handler.
291*4882a593Smuzhiyun */
292*4882a593Smuzhiyun static irqreturn_t
fsl_rio_dbell_handler(int irq,void * dev_instance)293*4882a593Smuzhiyun fsl_rio_dbell_handler(int irq, void *dev_instance)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun int dsr;
296*4882a593Smuzhiyun struct fsl_rio_dbell *fsl_dbell = (struct fsl_rio_dbell *)dev_instance;
297*4882a593Smuzhiyun int i;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun dsr = in_be32(&fsl_dbell->dbell_regs->dsr);
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (dsr & DOORBELL_DSR_TE) {
302*4882a593Smuzhiyun pr_info("RIO: doorbell reception error\n");
303*4882a593Smuzhiyun out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_TE);
304*4882a593Smuzhiyun goto out;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (dsr & DOORBELL_DSR_QFI) {
308*4882a593Smuzhiyun pr_info("RIO: doorbell queue full\n");
309*4882a593Smuzhiyun out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_QFI);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun /* XXX Need to check/dispatch until queue empty */
313*4882a593Smuzhiyun if (dsr & DOORBELL_DSR_DIQI) {
314*4882a593Smuzhiyun struct rio_dbell_msg *dmsg =
315*4882a593Smuzhiyun fsl_dbell->dbell_ring.virt +
316*4882a593Smuzhiyun (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff);
317*4882a593Smuzhiyun struct rio_dbell *dbell;
318*4882a593Smuzhiyun int found = 0;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun pr_debug
321*4882a593Smuzhiyun ("RIO: processing doorbell,"
322*4882a593Smuzhiyun " sid %2.2x tid %2.2x info %4.4x\n",
323*4882a593Smuzhiyun dmsg->sid, dmsg->tid, dmsg->info);
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun for (i = 0; i < MAX_PORT_NUM; i++) {
326*4882a593Smuzhiyun if (fsl_dbell->mport[i]) {
327*4882a593Smuzhiyun list_for_each_entry(dbell,
328*4882a593Smuzhiyun &fsl_dbell->mport[i]->dbells, node) {
329*4882a593Smuzhiyun if ((dbell->res->start
330*4882a593Smuzhiyun <= dmsg->info)
331*4882a593Smuzhiyun && (dbell->res->end
332*4882a593Smuzhiyun >= dmsg->info)) {
333*4882a593Smuzhiyun found = 1;
334*4882a593Smuzhiyun break;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun if (found && dbell->dinb) {
338*4882a593Smuzhiyun dbell->dinb(fsl_dbell->mport[i],
339*4882a593Smuzhiyun dbell->dev_id, dmsg->sid,
340*4882a593Smuzhiyun dmsg->tid,
341*4882a593Smuzhiyun dmsg->info);
342*4882a593Smuzhiyun break;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (!found) {
348*4882a593Smuzhiyun pr_debug
349*4882a593Smuzhiyun ("RIO: spurious doorbell,"
350*4882a593Smuzhiyun " sid %2.2x tid %2.2x info %4.4x\n",
351*4882a593Smuzhiyun dmsg->sid, dmsg->tid,
352*4882a593Smuzhiyun dmsg->info);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI);
355*4882a593Smuzhiyun out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI);
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun out:
359*4882a593Smuzhiyun return IRQ_HANDLED;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
msg_unit_error_handler(void)362*4882a593Smuzhiyun void msg_unit_error_handler(void)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun /*XXX: Error recovery is not implemented, we just clear errors */
366*4882a593Smuzhiyun out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun out_be32((u32 *)(rmu_regs_win + RIO_IM0SR), IMSR_CLEAR);
369*4882a593Smuzhiyun out_be32((u32 *)(rmu_regs_win + RIO_IM1SR), IMSR_CLEAR);
370*4882a593Smuzhiyun out_be32((u32 *)(rmu_regs_win + RIO_OM0SR), OMSR_CLEAR);
371*4882a593Smuzhiyun out_be32((u32 *)(rmu_regs_win + RIO_OM1SR), OMSR_CLEAR);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->odsr, ODSR_CLEAR);
374*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->dsr, IDSR_CLEAR);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwsr, IPWSR_CLEAR);
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /**
380*4882a593Smuzhiyun * fsl_rio_port_write_handler - MPC85xx port write interrupt handler
381*4882a593Smuzhiyun * @irq: Linux interrupt number
382*4882a593Smuzhiyun * @dev_instance: Pointer to interrupt-specific data
383*4882a593Smuzhiyun *
384*4882a593Smuzhiyun * Handles port write interrupts. Parses a list of registered
385*4882a593Smuzhiyun * port write event handlers and executes a matching event handler.
386*4882a593Smuzhiyun */
387*4882a593Smuzhiyun static irqreturn_t
fsl_rio_port_write_handler(int irq,void * dev_instance)388*4882a593Smuzhiyun fsl_rio_port_write_handler(int irq, void *dev_instance)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun u32 ipwmr, ipwsr;
391*4882a593Smuzhiyun struct fsl_rio_pw *pw = (struct fsl_rio_pw *)dev_instance;
392*4882a593Smuzhiyun u32 epwisr, tmp;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun epwisr = in_be32(rio_regs_win + RIO_EPWISR);
395*4882a593Smuzhiyun if (!(epwisr & RIO_EPWISR_PW))
396*4882a593Smuzhiyun goto pw_done;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun ipwmr = in_be32(&pw->pw_regs->pwmr);
399*4882a593Smuzhiyun ipwsr = in_be32(&pw->pw_regs->pwsr);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun #ifdef DEBUG_PW
402*4882a593Smuzhiyun pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
403*4882a593Smuzhiyun if (ipwsr & RIO_IPWSR_QF)
404*4882a593Smuzhiyun pr_debug(" QF");
405*4882a593Smuzhiyun if (ipwsr & RIO_IPWSR_TE)
406*4882a593Smuzhiyun pr_debug(" TE");
407*4882a593Smuzhiyun if (ipwsr & RIO_IPWSR_QFI)
408*4882a593Smuzhiyun pr_debug(" QFI");
409*4882a593Smuzhiyun if (ipwsr & RIO_IPWSR_PWD)
410*4882a593Smuzhiyun pr_debug(" PWD");
411*4882a593Smuzhiyun if (ipwsr & RIO_IPWSR_PWB)
412*4882a593Smuzhiyun pr_debug(" PWB");
413*4882a593Smuzhiyun pr_debug(" )\n");
414*4882a593Smuzhiyun #endif
415*4882a593Smuzhiyun /* Schedule deferred processing if PW was received */
416*4882a593Smuzhiyun if (ipwsr & RIO_IPWSR_QFI) {
417*4882a593Smuzhiyun /* Save PW message (if there is room in FIFO),
418*4882a593Smuzhiyun * otherwise discard it.
419*4882a593Smuzhiyun */
420*4882a593Smuzhiyun if (kfifo_avail(&pw->pw_fifo) >= RIO_PW_MSG_SIZE) {
421*4882a593Smuzhiyun pw->port_write_msg.msg_count++;
422*4882a593Smuzhiyun kfifo_in(&pw->pw_fifo, pw->port_write_msg.virt,
423*4882a593Smuzhiyun RIO_PW_MSG_SIZE);
424*4882a593Smuzhiyun } else {
425*4882a593Smuzhiyun pw->port_write_msg.discard_count++;
426*4882a593Smuzhiyun pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
427*4882a593Smuzhiyun pw->port_write_msg.discard_count);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun /* Clear interrupt and issue Clear Queue command. This allows
430*4882a593Smuzhiyun * another port-write to be received.
431*4882a593Smuzhiyun */
432*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_QFI);
433*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun schedule_work(&pw->pw_work);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
439*4882a593Smuzhiyun pw->port_write_msg.err_count++;
440*4882a593Smuzhiyun pr_debug("RIO: Port-Write Transaction Err (%d)\n",
441*4882a593Smuzhiyun pw->port_write_msg.err_count);
442*4882a593Smuzhiyun /* Clear Transaction Error: port-write controller should be
443*4882a593Smuzhiyun * disabled when clearing this error
444*4882a593Smuzhiyun */
445*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE);
446*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_TE);
447*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwmr, ipwmr);
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun if (ipwsr & RIO_IPWSR_PWD) {
451*4882a593Smuzhiyun pw->port_write_msg.discard_count++;
452*4882a593Smuzhiyun pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
453*4882a593Smuzhiyun pw->port_write_msg.discard_count);
454*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_PWD);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun pw_done:
458*4882a593Smuzhiyun if (epwisr & RIO_EPWISR_PINT1) {
459*4882a593Smuzhiyun tmp = in_be32(rio_regs_win + RIO_LTLEDCSR);
460*4882a593Smuzhiyun pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
461*4882a593Smuzhiyun fsl_rio_port_error_handler(0);
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if (epwisr & RIO_EPWISR_PINT2) {
465*4882a593Smuzhiyun tmp = in_be32(rio_regs_win + RIO_LTLEDCSR);
466*4882a593Smuzhiyun pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
467*4882a593Smuzhiyun fsl_rio_port_error_handler(1);
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (epwisr & RIO_EPWISR_MU) {
471*4882a593Smuzhiyun tmp = in_be32(rio_regs_win + RIO_LTLEDCSR);
472*4882a593Smuzhiyun pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
473*4882a593Smuzhiyun msg_unit_error_handler();
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun return IRQ_HANDLED;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
fsl_pw_dpc(struct work_struct * work)479*4882a593Smuzhiyun static void fsl_pw_dpc(struct work_struct *work)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun struct fsl_rio_pw *pw = container_of(work, struct fsl_rio_pw, pw_work);
482*4882a593Smuzhiyun union rio_pw_msg msg_buffer;
483*4882a593Smuzhiyun int i;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /*
486*4882a593Smuzhiyun * Process port-write messages
487*4882a593Smuzhiyun */
488*4882a593Smuzhiyun while (kfifo_out_spinlocked(&pw->pw_fifo, (unsigned char *)&msg_buffer,
489*4882a593Smuzhiyun RIO_PW_MSG_SIZE, &pw->pw_fifo_lock)) {
490*4882a593Smuzhiyun #ifdef DEBUG_PW
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun u32 i;
493*4882a593Smuzhiyun pr_debug("%s : Port-Write Message:", __func__);
494*4882a593Smuzhiyun for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
495*4882a593Smuzhiyun if ((i%4) == 0)
496*4882a593Smuzhiyun pr_debug("\n0x%02x: 0x%08x", i*4,
497*4882a593Smuzhiyun msg_buffer.raw[i]);
498*4882a593Smuzhiyun else
499*4882a593Smuzhiyun pr_debug(" 0x%08x", msg_buffer.raw[i]);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun pr_debug("\n");
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun #endif
504*4882a593Smuzhiyun /* Pass the port-write message to RIO core for processing */
505*4882a593Smuzhiyun for (i = 0; i < MAX_PORT_NUM; i++) {
506*4882a593Smuzhiyun if (pw->mport[i])
507*4882a593Smuzhiyun rio_inb_pwrite_handler(pw->mport[i],
508*4882a593Smuzhiyun &msg_buffer);
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun /**
514*4882a593Smuzhiyun * fsl_rio_pw_enable - enable/disable port-write interface init
515*4882a593Smuzhiyun * @mport: Master port implementing the port write unit
516*4882a593Smuzhiyun * @enable: 1=enable; 0=disable port-write message handling
517*4882a593Smuzhiyun */
fsl_rio_pw_enable(struct rio_mport * mport,int enable)518*4882a593Smuzhiyun int fsl_rio_pw_enable(struct rio_mport *mport, int enable)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun u32 rval;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun rval = in_be32(&pw->pw_regs->pwmr);
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun if (enable)
525*4882a593Smuzhiyun rval |= RIO_IPWMR_PWE;
526*4882a593Smuzhiyun else
527*4882a593Smuzhiyun rval &= ~RIO_IPWMR_PWE;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwmr, rval);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun return 0;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun /**
535*4882a593Smuzhiyun * fsl_rio_port_write_init - MPC85xx port write interface init
536*4882a593Smuzhiyun * @mport: Master port implementing the port write unit
537*4882a593Smuzhiyun *
538*4882a593Smuzhiyun * Initializes port write unit hardware and DMA buffer
539*4882a593Smuzhiyun * ring. Called from fsl_rio_setup(). Returns %0 on success
540*4882a593Smuzhiyun * or %-ENOMEM on failure.
541*4882a593Smuzhiyun */
542*4882a593Smuzhiyun
fsl_rio_port_write_init(struct fsl_rio_pw * pw)543*4882a593Smuzhiyun int fsl_rio_port_write_init(struct fsl_rio_pw *pw)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun int rc = 0;
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun /* Following configurations require a disabled port write controller */
548*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwmr,
549*4882a593Smuzhiyun in_be32(&pw->pw_regs->pwmr) & ~RIO_IPWMR_PWE);
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun /* Initialize port write */
552*4882a593Smuzhiyun pw->port_write_msg.virt = dma_alloc_coherent(pw->dev,
553*4882a593Smuzhiyun RIO_PW_MSG_SIZE,
554*4882a593Smuzhiyun &pw->port_write_msg.phys, GFP_KERNEL);
555*4882a593Smuzhiyun if (!pw->port_write_msg.virt) {
556*4882a593Smuzhiyun pr_err("RIO: unable allocate port write queue\n");
557*4882a593Smuzhiyun return -ENOMEM;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun pw->port_write_msg.err_count = 0;
561*4882a593Smuzhiyun pw->port_write_msg.discard_count = 0;
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun /* Point dequeue/enqueue pointers at first entry */
564*4882a593Smuzhiyun out_be32(&pw->pw_regs->epwqbar, 0);
565*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwqbar, (u32) pw->port_write_msg.phys);
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n",
568*4882a593Smuzhiyun in_be32(&pw->pw_regs->epwqbar),
569*4882a593Smuzhiyun in_be32(&pw->pw_regs->pwqbar));
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun /* Clear interrupt status IPWSR */
572*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwsr,
573*4882a593Smuzhiyun (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /* Configure port write controller for snooping enable all reporting,
576*4882a593Smuzhiyun clear queue full */
577*4882a593Smuzhiyun out_be32(&pw->pw_regs->pwmr,
578*4882a593Smuzhiyun RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ);
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun /* Hook up port-write handler */
582*4882a593Smuzhiyun rc = request_irq(IRQ_RIO_PW(pw), fsl_rio_port_write_handler,
583*4882a593Smuzhiyun IRQF_SHARED, "port-write", (void *)pw);
584*4882a593Smuzhiyun if (rc < 0) {
585*4882a593Smuzhiyun pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
586*4882a593Smuzhiyun goto err_out;
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun /* Enable Error Interrupt */
589*4882a593Smuzhiyun out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL);
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun INIT_WORK(&pw->pw_work, fsl_pw_dpc);
592*4882a593Smuzhiyun spin_lock_init(&pw->pw_fifo_lock);
593*4882a593Smuzhiyun if (kfifo_alloc(&pw->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
594*4882a593Smuzhiyun pr_err("FIFO allocation failed\n");
595*4882a593Smuzhiyun rc = -ENOMEM;
596*4882a593Smuzhiyun goto err_out_irq;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n",
600*4882a593Smuzhiyun in_be32(&pw->pw_regs->pwmr),
601*4882a593Smuzhiyun in_be32(&pw->pw_regs->pwsr));
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun return rc;
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun err_out_irq:
606*4882a593Smuzhiyun free_irq(IRQ_RIO_PW(pw), (void *)pw);
607*4882a593Smuzhiyun err_out:
608*4882a593Smuzhiyun dma_free_coherent(pw->dev, RIO_PW_MSG_SIZE,
609*4882a593Smuzhiyun pw->port_write_msg.virt,
610*4882a593Smuzhiyun pw->port_write_msg.phys);
611*4882a593Smuzhiyun return rc;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun /**
615*4882a593Smuzhiyun * fsl_rio_doorbell_send - Send a MPC85xx doorbell message
616*4882a593Smuzhiyun * @mport: RapidIO master port info
617*4882a593Smuzhiyun * @index: ID of RapidIO interface
618*4882a593Smuzhiyun * @destid: Destination ID of target device
619*4882a593Smuzhiyun * @data: 16-bit info field of RapidIO doorbell message
620*4882a593Smuzhiyun *
621*4882a593Smuzhiyun * Sends a MPC85xx doorbell message. Returns %0 on success or
622*4882a593Smuzhiyun * %-EINVAL on failure.
623*4882a593Smuzhiyun */
fsl_rio_doorbell_send(struct rio_mport * mport,int index,u16 destid,u16 data)624*4882a593Smuzhiyun int fsl_rio_doorbell_send(struct rio_mport *mport,
625*4882a593Smuzhiyun int index, u16 destid, u16 data)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun unsigned long flags;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n",
630*4882a593Smuzhiyun index, destid, data);
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun spin_lock_irqsave(&fsl_rio_doorbell_lock, flags);
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun /* In the serial version silicons, such as MPC8548, MPC8641,
635*4882a593Smuzhiyun * below operations is must be.
636*4882a593Smuzhiyun */
637*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->odmr, 0x00000000);
638*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->odretcr, 0x00000004);
639*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->oddpr, destid << 16);
640*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->oddatr, (index << 20) | data);
641*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->odmr, 0x00000001);
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun spin_unlock_irqrestore(&fsl_rio_doorbell_lock, flags);
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun return 0;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun /**
649*4882a593Smuzhiyun * fsl_add_outb_message - Add message to the MPC85xx outbound message queue
650*4882a593Smuzhiyun * @mport: Master port with outbound message queue
651*4882a593Smuzhiyun * @rdev: Target of outbound message
652*4882a593Smuzhiyun * @mbox: Outbound mailbox
653*4882a593Smuzhiyun * @buffer: Message to add to outbound queue
654*4882a593Smuzhiyun * @len: Length of message
655*4882a593Smuzhiyun *
656*4882a593Smuzhiyun * Adds the @buffer message to the MPC85xx outbound message queue. Returns
657*4882a593Smuzhiyun * %0 on success or %-EINVAL on failure.
658*4882a593Smuzhiyun */
659*4882a593Smuzhiyun int
fsl_add_outb_message(struct rio_mport * mport,struct rio_dev * rdev,int mbox,void * buffer,size_t len)660*4882a593Smuzhiyun fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
661*4882a593Smuzhiyun void *buffer, size_t len)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
664*4882a593Smuzhiyun u32 omr;
665*4882a593Smuzhiyun struct rio_tx_desc *desc = (struct rio_tx_desc *)rmu->msg_tx_ring.virt
666*4882a593Smuzhiyun + rmu->msg_tx_ring.tx_slot;
667*4882a593Smuzhiyun int ret = 0;
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \
670*4882a593Smuzhiyun "%p len %8.8zx\n", rdev->destid, mbox, buffer, len);
671*4882a593Smuzhiyun if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
672*4882a593Smuzhiyun ret = -EINVAL;
673*4882a593Smuzhiyun goto out;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun /* Copy and clear rest of buffer */
677*4882a593Smuzhiyun memcpy(rmu->msg_tx_ring.virt_buffer[rmu->msg_tx_ring.tx_slot], buffer,
678*4882a593Smuzhiyun len);
679*4882a593Smuzhiyun if (len < (RIO_MAX_MSG_SIZE - 4))
680*4882a593Smuzhiyun memset(rmu->msg_tx_ring.virt_buffer[rmu->msg_tx_ring.tx_slot]
681*4882a593Smuzhiyun + len, 0, RIO_MAX_MSG_SIZE - len);
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun /* Set mbox field for message, and set destid */
684*4882a593Smuzhiyun desc->dport = (rdev->destid << 16) | (mbox & 0x3);
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun /* Enable EOMI interrupt and priority */
687*4882a593Smuzhiyun desc->dattr = 0x28000000 | ((mport->index) << 20);
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun /* Set transfer size aligned to next power of 2 (in double words) */
690*4882a593Smuzhiyun desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun /* Set snooping and source buffer address */
693*4882a593Smuzhiyun desc->saddr = 0x00000004
694*4882a593Smuzhiyun | rmu->msg_tx_ring.phys_buffer[rmu->msg_tx_ring.tx_slot];
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun /* Increment enqueue pointer */
697*4882a593Smuzhiyun omr = in_be32(&rmu->msg_regs->omr);
698*4882a593Smuzhiyun out_be32(&rmu->msg_regs->omr, omr | RIO_MSG_OMR_MUI);
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun /* Go to next descriptor */
701*4882a593Smuzhiyun if (++rmu->msg_tx_ring.tx_slot == rmu->msg_tx_ring.size)
702*4882a593Smuzhiyun rmu->msg_tx_ring.tx_slot = 0;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun out:
705*4882a593Smuzhiyun return ret;
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun /**
709*4882a593Smuzhiyun * fsl_open_outb_mbox - Initialize MPC85xx outbound mailbox
710*4882a593Smuzhiyun * @mport: Master port implementing the outbound message unit
711*4882a593Smuzhiyun * @dev_id: Device specific pointer to pass on event
712*4882a593Smuzhiyun * @mbox: Mailbox to open
713*4882a593Smuzhiyun * @entries: Number of entries in the outbound mailbox ring
714*4882a593Smuzhiyun *
715*4882a593Smuzhiyun * Initializes buffer ring, request the outbound message interrupt,
716*4882a593Smuzhiyun * and enables the outbound message unit. Returns %0 on success and
717*4882a593Smuzhiyun * %-EINVAL or %-ENOMEM on failure.
718*4882a593Smuzhiyun */
719*4882a593Smuzhiyun int
fsl_open_outb_mbox(struct rio_mport * mport,void * dev_id,int mbox,int entries)720*4882a593Smuzhiyun fsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun int i, j, rc = 0;
723*4882a593Smuzhiyun struct rio_priv *priv = mport->priv;
724*4882a593Smuzhiyun struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun if ((entries < RIO_MIN_TX_RING_SIZE) ||
727*4882a593Smuzhiyun (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) {
728*4882a593Smuzhiyun rc = -EINVAL;
729*4882a593Smuzhiyun goto out;
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun /* Initialize shadow copy ring */
733*4882a593Smuzhiyun rmu->msg_tx_ring.dev_id = dev_id;
734*4882a593Smuzhiyun rmu->msg_tx_ring.size = entries;
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun for (i = 0; i < rmu->msg_tx_ring.size; i++) {
737*4882a593Smuzhiyun rmu->msg_tx_ring.virt_buffer[i] =
738*4882a593Smuzhiyun dma_alloc_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
739*4882a593Smuzhiyun &rmu->msg_tx_ring.phys_buffer[i], GFP_KERNEL);
740*4882a593Smuzhiyun if (!rmu->msg_tx_ring.virt_buffer[i]) {
741*4882a593Smuzhiyun rc = -ENOMEM;
742*4882a593Smuzhiyun for (j = 0; j < rmu->msg_tx_ring.size; j++)
743*4882a593Smuzhiyun if (rmu->msg_tx_ring.virt_buffer[j])
744*4882a593Smuzhiyun dma_free_coherent(priv->dev,
745*4882a593Smuzhiyun RIO_MSG_BUFFER_SIZE,
746*4882a593Smuzhiyun rmu->msg_tx_ring.
747*4882a593Smuzhiyun virt_buffer[j],
748*4882a593Smuzhiyun rmu->msg_tx_ring.
749*4882a593Smuzhiyun phys_buffer[j]);
750*4882a593Smuzhiyun goto out;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun /* Initialize outbound message descriptor ring */
755*4882a593Smuzhiyun rmu->msg_tx_ring.virt = dma_alloc_coherent(priv->dev,
756*4882a593Smuzhiyun rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
757*4882a593Smuzhiyun &rmu->msg_tx_ring.phys,
758*4882a593Smuzhiyun GFP_KERNEL);
759*4882a593Smuzhiyun if (!rmu->msg_tx_ring.virt) {
760*4882a593Smuzhiyun rc = -ENOMEM;
761*4882a593Smuzhiyun goto out_dma;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun rmu->msg_tx_ring.tx_slot = 0;
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun /* Point dequeue/enqueue pointers at first entry in ring */
766*4882a593Smuzhiyun out_be32(&rmu->msg_regs->odqdpar, rmu->msg_tx_ring.phys);
767*4882a593Smuzhiyun out_be32(&rmu->msg_regs->odqepar, rmu->msg_tx_ring.phys);
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun /* Configure for snooping */
770*4882a593Smuzhiyun out_be32(&rmu->msg_regs->osar, 0x00000004);
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun /* Clear interrupt status */
773*4882a593Smuzhiyun out_be32(&rmu->msg_regs->osr, 0x000000b3);
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun /* Hook up outbound message handler */
776*4882a593Smuzhiyun rc = request_irq(IRQ_RIO_TX(mport), fsl_rio_tx_handler, 0,
777*4882a593Smuzhiyun "msg_tx", (void *)mport);
778*4882a593Smuzhiyun if (rc < 0)
779*4882a593Smuzhiyun goto out_irq;
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun /*
782*4882a593Smuzhiyun * Configure outbound message unit
783*4882a593Smuzhiyun * Snooping
784*4882a593Smuzhiyun * Interrupts (all enabled, except QEIE)
785*4882a593Smuzhiyun * Chaining mode
786*4882a593Smuzhiyun * Disable
787*4882a593Smuzhiyun */
788*4882a593Smuzhiyun out_be32(&rmu->msg_regs->omr, 0x00100220);
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun /* Set number of entries */
791*4882a593Smuzhiyun out_be32(&rmu->msg_regs->omr,
792*4882a593Smuzhiyun in_be32(&rmu->msg_regs->omr) |
793*4882a593Smuzhiyun ((get_bitmask_order(entries) - 2) << 12));
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun /* Now enable the unit */
796*4882a593Smuzhiyun out_be32(&rmu->msg_regs->omr, in_be32(&rmu->msg_regs->omr) | 0x1);
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun out:
799*4882a593Smuzhiyun return rc;
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun out_irq:
802*4882a593Smuzhiyun dma_free_coherent(priv->dev,
803*4882a593Smuzhiyun rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
804*4882a593Smuzhiyun rmu->msg_tx_ring.virt, rmu->msg_tx_ring.phys);
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun out_dma:
807*4882a593Smuzhiyun for (i = 0; i < rmu->msg_tx_ring.size; i++)
808*4882a593Smuzhiyun dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
809*4882a593Smuzhiyun rmu->msg_tx_ring.virt_buffer[i],
810*4882a593Smuzhiyun rmu->msg_tx_ring.phys_buffer[i]);
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun return rc;
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun /**
816*4882a593Smuzhiyun * fsl_close_outb_mbox - Shut down MPC85xx outbound mailbox
817*4882a593Smuzhiyun * @mport: Master port implementing the outbound message unit
818*4882a593Smuzhiyun * @mbox: Mailbox to close
819*4882a593Smuzhiyun *
820*4882a593Smuzhiyun * Disables the outbound message unit, free all buffers, and
821*4882a593Smuzhiyun * frees the outbound message interrupt.
822*4882a593Smuzhiyun */
fsl_close_outb_mbox(struct rio_mport * mport,int mbox)823*4882a593Smuzhiyun void fsl_close_outb_mbox(struct rio_mport *mport, int mbox)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun struct rio_priv *priv = mport->priv;
826*4882a593Smuzhiyun struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun /* Disable inbound message unit */
829*4882a593Smuzhiyun out_be32(&rmu->msg_regs->omr, 0);
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun /* Free ring */
832*4882a593Smuzhiyun dma_free_coherent(priv->dev,
833*4882a593Smuzhiyun rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
834*4882a593Smuzhiyun rmu->msg_tx_ring.virt, rmu->msg_tx_ring.phys);
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun /* Free interrupt */
837*4882a593Smuzhiyun free_irq(IRQ_RIO_TX(mport), (void *)mport);
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun /**
841*4882a593Smuzhiyun * fsl_open_inb_mbox - Initialize MPC85xx inbound mailbox
842*4882a593Smuzhiyun * @mport: Master port implementing the inbound message unit
843*4882a593Smuzhiyun * @dev_id: Device specific pointer to pass on event
844*4882a593Smuzhiyun * @mbox: Mailbox to open
845*4882a593Smuzhiyun * @entries: Number of entries in the inbound mailbox ring
846*4882a593Smuzhiyun *
847*4882a593Smuzhiyun * Initializes buffer ring, request the inbound message interrupt,
848*4882a593Smuzhiyun * and enables the inbound message unit. Returns %0 on success
849*4882a593Smuzhiyun * and %-EINVAL or %-ENOMEM on failure.
850*4882a593Smuzhiyun */
851*4882a593Smuzhiyun int
fsl_open_inb_mbox(struct rio_mport * mport,void * dev_id,int mbox,int entries)852*4882a593Smuzhiyun fsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
853*4882a593Smuzhiyun {
854*4882a593Smuzhiyun int i, rc = 0;
855*4882a593Smuzhiyun struct rio_priv *priv = mport->priv;
856*4882a593Smuzhiyun struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun if ((entries < RIO_MIN_RX_RING_SIZE) ||
859*4882a593Smuzhiyun (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {
860*4882a593Smuzhiyun rc = -EINVAL;
861*4882a593Smuzhiyun goto out;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun /* Initialize client buffer ring */
865*4882a593Smuzhiyun rmu->msg_rx_ring.dev_id = dev_id;
866*4882a593Smuzhiyun rmu->msg_rx_ring.size = entries;
867*4882a593Smuzhiyun rmu->msg_rx_ring.rx_slot = 0;
868*4882a593Smuzhiyun for (i = 0; i < rmu->msg_rx_ring.size; i++)
869*4882a593Smuzhiyun rmu->msg_rx_ring.virt_buffer[i] = NULL;
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun /* Initialize inbound message ring */
872*4882a593Smuzhiyun rmu->msg_rx_ring.virt = dma_alloc_coherent(priv->dev,
873*4882a593Smuzhiyun rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
874*4882a593Smuzhiyun &rmu->msg_rx_ring.phys, GFP_KERNEL);
875*4882a593Smuzhiyun if (!rmu->msg_rx_ring.virt) {
876*4882a593Smuzhiyun rc = -ENOMEM;
877*4882a593Smuzhiyun goto out;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun /* Point dequeue/enqueue pointers at first entry in ring */
881*4882a593Smuzhiyun out_be32(&rmu->msg_regs->ifqdpar, (u32) rmu->msg_rx_ring.phys);
882*4882a593Smuzhiyun out_be32(&rmu->msg_regs->ifqepar, (u32) rmu->msg_rx_ring.phys);
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun /* Clear interrupt status */
885*4882a593Smuzhiyun out_be32(&rmu->msg_regs->isr, 0x00000091);
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun /* Hook up inbound message handler */
888*4882a593Smuzhiyun rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0,
889*4882a593Smuzhiyun "msg_rx", (void *)mport);
890*4882a593Smuzhiyun if (rc < 0) {
891*4882a593Smuzhiyun dma_free_coherent(priv->dev,
892*4882a593Smuzhiyun rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
893*4882a593Smuzhiyun rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys);
894*4882a593Smuzhiyun goto out;
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun /*
898*4882a593Smuzhiyun * Configure inbound message unit:
899*4882a593Smuzhiyun * Snooping
900*4882a593Smuzhiyun * 4KB max message size
901*4882a593Smuzhiyun * Unmask all interrupt sources
902*4882a593Smuzhiyun * Disable
903*4882a593Smuzhiyun */
904*4882a593Smuzhiyun out_be32(&rmu->msg_regs->imr, 0x001b0060);
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun /* Set number of queue entries */
907*4882a593Smuzhiyun setbits32(&rmu->msg_regs->imr, (get_bitmask_order(entries) - 2) << 12);
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun /* Now enable the unit */
910*4882a593Smuzhiyun setbits32(&rmu->msg_regs->imr, 0x1);
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun out:
913*4882a593Smuzhiyun return rc;
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun /**
917*4882a593Smuzhiyun * fsl_close_inb_mbox - Shut down MPC85xx inbound mailbox
918*4882a593Smuzhiyun * @mport: Master port implementing the inbound message unit
919*4882a593Smuzhiyun * @mbox: Mailbox to close
920*4882a593Smuzhiyun *
921*4882a593Smuzhiyun * Disables the inbound message unit, free all buffers, and
922*4882a593Smuzhiyun * frees the inbound message interrupt.
923*4882a593Smuzhiyun */
fsl_close_inb_mbox(struct rio_mport * mport,int mbox)924*4882a593Smuzhiyun void fsl_close_inb_mbox(struct rio_mport *mport, int mbox)
925*4882a593Smuzhiyun {
926*4882a593Smuzhiyun struct rio_priv *priv = mport->priv;
927*4882a593Smuzhiyun struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun /* Disable inbound message unit */
930*4882a593Smuzhiyun out_be32(&rmu->msg_regs->imr, 0);
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun /* Free ring */
933*4882a593Smuzhiyun dma_free_coherent(priv->dev, rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
934*4882a593Smuzhiyun rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys);
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun /* Free interrupt */
937*4882a593Smuzhiyun free_irq(IRQ_RIO_RX(mport), (void *)mport);
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun
940*4882a593Smuzhiyun /**
941*4882a593Smuzhiyun * fsl_add_inb_buffer - Add buffer to the MPC85xx inbound message queue
942*4882a593Smuzhiyun * @mport: Master port implementing the inbound message unit
943*4882a593Smuzhiyun * @mbox: Inbound mailbox number
944*4882a593Smuzhiyun * @buf: Buffer to add to inbound queue
945*4882a593Smuzhiyun *
946*4882a593Smuzhiyun * Adds the @buf buffer to the MPC85xx inbound message queue. Returns
947*4882a593Smuzhiyun * %0 on success or %-EINVAL on failure.
948*4882a593Smuzhiyun */
fsl_add_inb_buffer(struct rio_mport * mport,int mbox,void * buf)949*4882a593Smuzhiyun int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
950*4882a593Smuzhiyun {
951*4882a593Smuzhiyun int rc = 0;
952*4882a593Smuzhiyun struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun pr_debug("RIO: fsl_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
955*4882a593Smuzhiyun rmu->msg_rx_ring.rx_slot);
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun if (rmu->msg_rx_ring.virt_buffer[rmu->msg_rx_ring.rx_slot]) {
958*4882a593Smuzhiyun printk(KERN_ERR
959*4882a593Smuzhiyun "RIO: error adding inbound buffer %d, buffer exists\n",
960*4882a593Smuzhiyun rmu->msg_rx_ring.rx_slot);
961*4882a593Smuzhiyun rc = -EINVAL;
962*4882a593Smuzhiyun goto out;
963*4882a593Smuzhiyun }
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun rmu->msg_rx_ring.virt_buffer[rmu->msg_rx_ring.rx_slot] = buf;
966*4882a593Smuzhiyun if (++rmu->msg_rx_ring.rx_slot == rmu->msg_rx_ring.size)
967*4882a593Smuzhiyun rmu->msg_rx_ring.rx_slot = 0;
968*4882a593Smuzhiyun
969*4882a593Smuzhiyun out:
970*4882a593Smuzhiyun return rc;
971*4882a593Smuzhiyun }
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun /**
974*4882a593Smuzhiyun * fsl_get_inb_message - Fetch inbound message from the MPC85xx message unit
975*4882a593Smuzhiyun * @mport: Master port implementing the inbound message unit
976*4882a593Smuzhiyun * @mbox: Inbound mailbox number
977*4882a593Smuzhiyun *
978*4882a593Smuzhiyun * Gets the next available inbound message from the inbound message queue.
979*4882a593Smuzhiyun * A pointer to the message is returned on success or NULL on failure.
980*4882a593Smuzhiyun */
fsl_get_inb_message(struct rio_mport * mport,int mbox)981*4882a593Smuzhiyun void *fsl_get_inb_message(struct rio_mport *mport, int mbox)
982*4882a593Smuzhiyun {
983*4882a593Smuzhiyun struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
984*4882a593Smuzhiyun u32 phys_buf;
985*4882a593Smuzhiyun void *virt_buf;
986*4882a593Smuzhiyun void *buf = NULL;
987*4882a593Smuzhiyun int buf_idx;
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun phys_buf = in_be32(&rmu->msg_regs->ifqdpar);
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun /* If no more messages, then bail out */
992*4882a593Smuzhiyun if (phys_buf == in_be32(&rmu->msg_regs->ifqepar))
993*4882a593Smuzhiyun goto out2;
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun virt_buf = rmu->msg_rx_ring.virt + (phys_buf
996*4882a593Smuzhiyun - rmu->msg_rx_ring.phys);
997*4882a593Smuzhiyun buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
998*4882a593Smuzhiyun buf = rmu->msg_rx_ring.virt_buffer[buf_idx];
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun if (!buf) {
1001*4882a593Smuzhiyun printk(KERN_ERR
1002*4882a593Smuzhiyun "RIO: inbound message copy failed, no buffers\n");
1003*4882a593Smuzhiyun goto out1;
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun /* Copy max message size, caller is expected to allocate that big */
1007*4882a593Smuzhiyun memcpy(buf, virt_buf, RIO_MAX_MSG_SIZE);
1008*4882a593Smuzhiyun
1009*4882a593Smuzhiyun /* Clear the available buffer */
1010*4882a593Smuzhiyun rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL;
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun out1:
1013*4882a593Smuzhiyun setbits32(&rmu->msg_regs->imr, RIO_MSG_IMR_MI);
1014*4882a593Smuzhiyun
1015*4882a593Smuzhiyun out2:
1016*4882a593Smuzhiyun return buf;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun /**
1020*4882a593Smuzhiyun * fsl_rio_doorbell_init - MPC85xx doorbell interface init
1021*4882a593Smuzhiyun * @mport: Master port implementing the inbound doorbell unit
1022*4882a593Smuzhiyun *
1023*4882a593Smuzhiyun * Initializes doorbell unit hardware and inbound DMA buffer
1024*4882a593Smuzhiyun * ring. Called from fsl_rio_setup(). Returns %0 on success
1025*4882a593Smuzhiyun * or %-ENOMEM on failure.
1026*4882a593Smuzhiyun */
fsl_rio_doorbell_init(struct fsl_rio_dbell * dbell)1027*4882a593Smuzhiyun int fsl_rio_doorbell_init(struct fsl_rio_dbell *dbell)
1028*4882a593Smuzhiyun {
1029*4882a593Smuzhiyun int rc = 0;
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun /* Initialize inbound doorbells */
1032*4882a593Smuzhiyun dbell->dbell_ring.virt = dma_alloc_coherent(dbell->dev, 512 *
1033*4882a593Smuzhiyun DOORBELL_MESSAGE_SIZE, &dbell->dbell_ring.phys, GFP_KERNEL);
1034*4882a593Smuzhiyun if (!dbell->dbell_ring.virt) {
1035*4882a593Smuzhiyun printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n");
1036*4882a593Smuzhiyun rc = -ENOMEM;
1037*4882a593Smuzhiyun goto out;
1038*4882a593Smuzhiyun }
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun /* Point dequeue/enqueue pointers at first entry in ring */
1041*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->dqdpar, (u32) dbell->dbell_ring.phys);
1042*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->dqepar, (u32) dbell->dbell_ring.phys);
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun /* Clear interrupt status */
1045*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->dsr, 0x00000091);
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun /* Hook up doorbell handler */
1048*4882a593Smuzhiyun rc = request_irq(IRQ_RIO_BELL(dbell), fsl_rio_dbell_handler, 0,
1049*4882a593Smuzhiyun "dbell_rx", (void *)dbell);
1050*4882a593Smuzhiyun if (rc < 0) {
1051*4882a593Smuzhiyun dma_free_coherent(dbell->dev, 512 * DOORBELL_MESSAGE_SIZE,
1052*4882a593Smuzhiyun dbell->dbell_ring.virt, dbell->dbell_ring.phys);
1053*4882a593Smuzhiyun printk(KERN_ERR
1054*4882a593Smuzhiyun "MPC85xx RIO: unable to request inbound doorbell irq");
1055*4882a593Smuzhiyun goto out;
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun /* Configure doorbells for snooping, 512 entries, and enable */
1059*4882a593Smuzhiyun out_be32(&dbell->dbell_regs->dmr, 0x00108161);
1060*4882a593Smuzhiyun
1061*4882a593Smuzhiyun out:
1062*4882a593Smuzhiyun return rc;
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun
fsl_rio_setup_rmu(struct rio_mport * mport,struct device_node * node)1065*4882a593Smuzhiyun int fsl_rio_setup_rmu(struct rio_mport *mport, struct device_node *node)
1066*4882a593Smuzhiyun {
1067*4882a593Smuzhiyun struct rio_priv *priv;
1068*4882a593Smuzhiyun struct fsl_rmu *rmu;
1069*4882a593Smuzhiyun u64 msg_start;
1070*4882a593Smuzhiyun const u32 *msg_addr;
1071*4882a593Smuzhiyun int mlen;
1072*4882a593Smuzhiyun int aw;
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun if (!mport || !mport->priv)
1075*4882a593Smuzhiyun return -EINVAL;
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun priv = mport->priv;
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun if (!node) {
1080*4882a593Smuzhiyun dev_warn(priv->dev, "Can't get %pOF property 'fsl,rmu'\n",
1081*4882a593Smuzhiyun priv->dev->of_node);
1082*4882a593Smuzhiyun return -EINVAL;
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun rmu = kzalloc(sizeof(struct fsl_rmu), GFP_KERNEL);
1086*4882a593Smuzhiyun if (!rmu)
1087*4882a593Smuzhiyun return -ENOMEM;
1088*4882a593Smuzhiyun
1089*4882a593Smuzhiyun aw = of_n_addr_cells(node);
1090*4882a593Smuzhiyun msg_addr = of_get_property(node, "reg", &mlen);
1091*4882a593Smuzhiyun if (!msg_addr) {
1092*4882a593Smuzhiyun pr_err("%pOF: unable to find 'reg' property of message-unit\n",
1093*4882a593Smuzhiyun node);
1094*4882a593Smuzhiyun kfree(rmu);
1095*4882a593Smuzhiyun return -ENOMEM;
1096*4882a593Smuzhiyun }
1097*4882a593Smuzhiyun msg_start = of_read_number(msg_addr, aw);
1098*4882a593Smuzhiyun
1099*4882a593Smuzhiyun rmu->msg_regs = (struct rio_msg_regs *)
1100*4882a593Smuzhiyun (rmu_regs_win + (u32)msg_start);
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun rmu->txirq = irq_of_parse_and_map(node, 0);
1103*4882a593Smuzhiyun rmu->rxirq = irq_of_parse_and_map(node, 1);
1104*4882a593Smuzhiyun printk(KERN_INFO "%pOF: txirq: %d, rxirq %d\n",
1105*4882a593Smuzhiyun node, rmu->txirq, rmu->rxirq);
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun priv->rmm_handle = rmu;
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
1110*4882a593Smuzhiyun rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
1111*4882a593Smuzhiyun rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun return 0;
1114*4882a593Smuzhiyun }
1115