16ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/*
26ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Freescale MPC85xx/MPC86xx RapidIO RMU support
36ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
46ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Copyright 2009 Sysgo AG
56ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Thomas Moll <thomas.moll@sysgo.com>
66ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * - fixed maintenance access routines, check for aligned access
76ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
86ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Copyright 2009 Integrated Device Technology, Inc.
96ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Alex Bounine <alexandre.bounine@idt.com>
106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * - Added Port-Write message handling
116ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * - Added Machine Check exception handling
126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
136ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc.
146ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Zhang Wei <wei.zhang@freescale.com>
156ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Lian Minghuan-B31939 <Minghuan.Lian@freescale.com>
166ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Liu Gang <Gang.Liu@freescale.com>
176ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
186ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Copyright 2005 MontaVista Software, Inc.
196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Matt Porter <mporter@kernel.crashing.org>
206ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
216ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * This program is free software; you can redistribute  it and/or modify it
226ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * under  the terms of  the GNU General  Public License as published by the
236ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Free Software Foundation;  either version 2 of the  License, or (at your
246ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * option) any later version.
256ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
266ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
276ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#include <linux/types.h>
286ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#include <linux/dma-mapping.h>
296ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#include <linux/interrupt.h>
3026a2056eb21fff26caf99d19ad5448e9403db55dRob Herring#include <linux/of_irq.h>
316ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#include <linux/of_platform.h>
326ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#include <linux/slab.h>
336ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
346ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#include "fsl_rio.h"
356ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
366ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define GET_RMM_HANDLE(mport) \
376ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		(((struct rio_priv *)(mport->priv))->rmm_handle)
386ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
396ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/* RapidIO definition irq, which read from OF-tree */
40abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang#define IRQ_RIO_PW(m)		(((struct fsl_rio_pw *)(m))->pwirq)
41abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang#define IRQ_RIO_BELL(m) (((struct fsl_rio_dbell *)(m))->bellirq)
426ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define IRQ_RIO_TX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->txirq)
436ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define IRQ_RIO_RX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->rxirq)
446ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
456ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MIN_TX_RING_SIZE	2
466ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MAX_TX_RING_SIZE	2048
476ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MIN_RX_RING_SIZE	2
486ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MAX_RX_RING_SIZE	2048
496ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
506ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_IPWMR_SEN		0x00100000
516ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_IPWMR_QFIE		0x00000100
526ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_IPWMR_EIE		0x00000020
536ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_IPWMR_CQ		0x00000002
546ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_IPWMR_PWE		0x00000001
556ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
566ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_IPWSR_QF		0x00100000
576ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_IPWSR_TE		0x00000080
586ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_IPWSR_QFI		0x00000010
596ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_IPWSR_PWD		0x00000008
606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_IPWSR_PWB		0x00000004
616ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
626ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_EPWISR		0x10010
636ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/* EPWISR Error match value */
646ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_EPWISR_PINT1	0x80000000
656ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_EPWISR_PINT2	0x40000000
666ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_EPWISR_MU		0x00000002
676ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_EPWISR_PW		0x00000001
686ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
696ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define IPWSR_CLEAR		0x98
706ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define OMSR_CLEAR		0x1cb3
716ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define IMSR_CLEAR		0x491
726ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define IDSR_CLEAR		0x91
736ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define ODSR_CLEAR		0x1c00
746ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define LTLEECSR_ENABLE_ALL	0xFFC000FC
756ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_LTLEECSR		0x060c
766ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
77abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang#define RIO_IM0SR		0x64
78abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang#define RIO_IM1SR		0x164
79abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang#define RIO_OM0SR		0x4
80abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang#define RIO_OM1SR		0x104
816ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
826ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_DBELL_WIN_SIZE	0x1000
836ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
846ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_OMR_MUI		0x00000002
856ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_OSR_TE		0x00000080
866ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_OSR_QOI		0x00000020
876ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_OSR_QFI		0x00000010
886ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_OSR_MUB		0x00000004
896ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_OSR_EOMI	0x00000002
906ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_OSR_QEI		0x00000001
916ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
926ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_IMR_MI		0x00000002
936ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_ISR_TE		0x00000080
946ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_ISR_QFI		0x00000010
956ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_ISR_DIQI	0x00000001
966ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
976ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_DESC_SIZE	32
986ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define RIO_MSG_BUFFER_SIZE	4096
996ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
1006ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define DOORBELL_DMR_DI		0x00000002
1016ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define DOORBELL_DSR_TE		0x00000080
1026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define DOORBELL_DSR_QFI	0x00000010
1036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define DOORBELL_DSR_DIQI	0x00000001
1046ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
1056ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#define DOORBELL_MESSAGE_SIZE	0x08
1066ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
1076ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangstruct rio_msg_regs {
108abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 omr;
109abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 osr;
1106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 pad1;
111abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 odqdpar;
1126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 pad2;
113abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 osar;
114abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 odpr;
115abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 odatr;
116abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 odcr;
1176ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 pad3;
118abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 odqepar;
1196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 pad4[13];
120abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 imr;
121abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 isr;
1226ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 pad5;
123abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 ifqdpar;
1246ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 pad6;
125abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 ifqepar;
126abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang};
127abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
128abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangstruct rio_dbell_regs {
129abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 odmr;
130abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 odsr;
131abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pad1[4];
132abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 oddpr;
133abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 oddatr;
134abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pad2[3];
135abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 odretcr;
136abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pad3[12];
137abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 dmr;
138abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 dsr;
139abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pad4;
140abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 dqdpar;
141abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pad5;
142abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 dqepar;
143abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang};
144abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
145abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangstruct rio_pw_regs {
146abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pwmr;
147abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pwsr;
148abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 epwqbar;
149abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pwqbar;
1506ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang};
1516ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
152abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
1536ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangstruct rio_tx_desc {
154abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pad1;
1556ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 saddr;
1566ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 dport;
1576ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 dattr;
158abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pad2;
159abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pad3;
1606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 dwcnt;
161abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u32 pad4;
1626ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang};
1636ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
1646ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangstruct rio_msg_tx_ring {
1656ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	void *virt;
1666ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	dma_addr_t phys;
1676ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	void *virt_buffer[RIO_MAX_TX_RING_SIZE];
1686ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE];
1696ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int tx_slot;
1706ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int size;
1716ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	void *dev_id;
1726ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang};
1736ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
1746ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangstruct rio_msg_rx_ring {
1756ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	void *virt;
1766ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	dma_addr_t phys;
1776ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	void *virt_buffer[RIO_MAX_RX_RING_SIZE];
1786ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int rx_slot;
1796ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int size;
1806ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	void *dev_id;
1816ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang};
1826ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
1836ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangstruct fsl_rmu {
1846ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_msg_regs __iomem *msg_regs;
1856ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_msg_tx_ring msg_tx_ring;
1866ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_msg_rx_ring msg_rx_ring;
1876ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int txirq;
1886ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int rxirq;
1896ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang};
1906ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
1912a2383dab097823d68accce65da043402bdeb57bLiu Gangstruct rio_dbell_msg {
1922a2383dab097823d68accce65da043402bdeb57bLiu Gang	u16 pad1;
1932a2383dab097823d68accce65da043402bdeb57bLiu Gang	u16 tid;
1942a2383dab097823d68accce65da043402bdeb57bLiu Gang	u16 sid;
1952a2383dab097823d68accce65da043402bdeb57bLiu Gang	u16 info;
1962a2383dab097823d68accce65da043402bdeb57bLiu Gang};
1972a2383dab097823d68accce65da043402bdeb57bLiu Gang
1986ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
1996ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler
2006ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @irq: Linux interrupt number
2016ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @dev_instance: Pointer to interrupt-specific data
2026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
2036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Handles outbound message interrupts. Executes a register outbound
2046ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * mailbox event handler and acks the interrupt occurrence.
2056ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
2066ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangstatic irqreturn_t
2076ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangfsl_rio_tx_handler(int irq, void *dev_instance)
2086ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
2096ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int osr;
2106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_mport *port = (struct rio_mport *)dev_instance;
2116ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
2126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2136ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	osr = in_be32(&rmu->msg_regs->osr);
2146ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2156ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (osr & RIO_MSG_OSR_TE) {
2166ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_info("RIO: outbound message transmission error\n");
2176ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_TE);
2186ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
2196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
2206ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2216ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (osr & RIO_MSG_OSR_QOI) {
2226ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_info("RIO: outbound message queue overflow\n");
2236ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_QOI);
2246ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
2256ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
2266ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2276ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (osr & RIO_MSG_OSR_EOMI) {
2286ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		u32 dqp = in_be32(&rmu->msg_regs->odqdpar);
2296ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		int slot = (dqp - rmu->msg_tx_ring.phys) >> 5;
230abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		if (port->outb_msg[0].mcback != NULL) {
231abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			port->outb_msg[0].mcback(port, rmu->msg_tx_ring.dev_id,
232abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang					-1,
233abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang					slot);
234abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		}
2356ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		/* Ack the end-of-message interrupt */
2366ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_EOMI);
2376ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
2386ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2396ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout:
2406ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return IRQ_HANDLED;
2416ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
2426ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2436ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
2446ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_rio_rx_handler - MPC85xx inbound message interrupt handler
2456ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @irq: Linux interrupt number
2466ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @dev_instance: Pointer to interrupt-specific data
2476ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
2486ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Handles inbound message interrupts. Executes a registered inbound
2496ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * mailbox event handler and acks the interrupt occurrence.
2506ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
2516ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangstatic irqreturn_t
2526ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangfsl_rio_rx_handler(int irq, void *dev_instance)
2536ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
2546ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int isr;
2556ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_mport *port = (struct rio_mport *)dev_instance;
2566ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
2576ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2586ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	isr = in_be32(&rmu->msg_regs->isr);
2596ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (isr & RIO_MSG_ISR_TE) {
2616ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_info("RIO: inbound message reception error\n");
2626ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		out_be32((void *)&rmu->msg_regs->isr, RIO_MSG_ISR_TE);
2636ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
2646ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
2656ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2666ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* XXX Need to check/dispatch until queue empty */
2676ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (isr & RIO_MSG_ISR_DIQI) {
2686ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		/*
269abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		* Can receive messages for any mailbox/letter to that
270abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		* mailbox destination. So, make the callback with an
271abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		* unknown/invalid mailbox number argument.
272abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		*/
273abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		if (port->inb_msg[0].mcback != NULL)
274abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			port->inb_msg[0].mcback(port, rmu->msg_rx_ring.dev_id,
275abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang				-1,
276abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang				-1);
2776ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2786ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		/* Ack the queueing interrupt */
2796ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		out_be32(&rmu->msg_regs->isr, RIO_MSG_ISR_DIQI);
2806ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
2816ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2826ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout:
2836ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return IRQ_HANDLED;
2846ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
2856ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
2866ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
2876ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler
2886ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @irq: Linux interrupt number
2896ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @dev_instance: Pointer to interrupt-specific data
2906ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
2916ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Handles doorbell interrupts. Parses a list of registered
2926ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * doorbell event handlers and executes a matching event handler.
2936ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
2946ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangstatic irqreturn_t
2956ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangfsl_rio_dbell_handler(int irq, void *dev_instance)
2966ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
2976ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int dsr;
298abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	struct fsl_rio_dbell *fsl_dbell = (struct fsl_rio_dbell *)dev_instance;
299abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	int i;
3006ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
301abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	dsr = in_be32(&fsl_dbell->dbell_regs->dsr);
3026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
3036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (dsr & DOORBELL_DSR_TE) {
3046ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_info("RIO: doorbell reception error\n");
305abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_TE);
3066ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
3076ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
3086ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
3096ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (dsr & DOORBELL_DSR_QFI) {
3106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_info("RIO: doorbell queue full\n");
311abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_QFI);
3126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
3136ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
3146ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* XXX Need to check/dispatch until queue empty */
3156ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (dsr & DOORBELL_DSR_DIQI) {
3162a2383dab097823d68accce65da043402bdeb57bLiu Gang		struct rio_dbell_msg *dmsg =
3172a2383dab097823d68accce65da043402bdeb57bLiu Gang			fsl_dbell->dbell_ring.virt +
318abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			(in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff);
3196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		struct rio_dbell *dbell;
3206ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		int found = 0;
3216ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
3226ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug
3236ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			("RIO: processing doorbell,"
3246ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			" sid %2.2x tid %2.2x info %4.4x\n",
3252a2383dab097823d68accce65da043402bdeb57bLiu Gang			dmsg->sid, dmsg->tid, dmsg->info);
3266ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
327abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		for (i = 0; i < MAX_PORT_NUM; i++) {
328abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			if (fsl_dbell->mport[i]) {
329abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang				list_for_each_entry(dbell,
330abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang					&fsl_dbell->mport[i]->dbells, node) {
331abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang					if ((dbell->res->start
3322a2383dab097823d68accce65da043402bdeb57bLiu Gang						<= dmsg->info)
333abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang						&& (dbell->res->end
3342a2383dab097823d68accce65da043402bdeb57bLiu Gang						>= dmsg->info)) {
335abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang						found = 1;
336abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang						break;
337abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang					}
338abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang				}
339abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang				if (found && dbell->dinb) {
340abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang					dbell->dinb(fsl_dbell->mport[i],
3412a2383dab097823d68accce65da043402bdeb57bLiu Gang						dbell->dev_id, dmsg->sid,
3422a2383dab097823d68accce65da043402bdeb57bLiu Gang						dmsg->tid,
3432a2383dab097823d68accce65da043402bdeb57bLiu Gang						dmsg->info);
344abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang					break;
345abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang				}
3466ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			}
3476ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		}
348abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
349abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		if (!found) {
3506ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			pr_debug
3516ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				("RIO: spurious doorbell,"
3526ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				" sid %2.2x tid %2.2x info %4.4x\n",
3532a2383dab097823d68accce65da043402bdeb57bLiu Gang				dmsg->sid, dmsg->tid,
3542a2383dab097823d68accce65da043402bdeb57bLiu Gang				dmsg->info);
3556ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		}
356abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI);
357abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI);
3586ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
3596ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
3606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout:
3616ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return IRQ_HANDLED;
3626ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
3636ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
364abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangvoid msg_unit_error_handler(void)
3656ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
3666ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
3676ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/*XXX: Error recovery is not implemented, we just clear errors */
3686ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
3696ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
370abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32((u32 *)(rmu_regs_win + RIO_IM0SR), IMSR_CLEAR);
371abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32((u32 *)(rmu_regs_win + RIO_IM1SR), IMSR_CLEAR);
372abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32((u32 *)(rmu_regs_win + RIO_OM0SR), OMSR_CLEAR);
373abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32((u32 *)(rmu_regs_win + RIO_OM1SR), OMSR_CLEAR);
3746ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
375abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->odsr, ODSR_CLEAR);
376abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->dsr, IDSR_CLEAR);
3776ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
378abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&pw->pw_regs->pwsr, IPWSR_CLEAR);
3796ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
3806ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
3816ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
3826ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_rio_port_write_handler - MPC85xx port write interrupt handler
3836ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @irq: Linux interrupt number
3846ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @dev_instance: Pointer to interrupt-specific data
3856ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
3866ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Handles port write interrupts. Parses a list of registered
3876ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * port write event handlers and executes a matching event handler.
3886ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
3896ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangstatic irqreturn_t
3906ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangfsl_rio_port_write_handler(int irq, void *dev_instance)
3916ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
3926ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 ipwmr, ipwsr;
393abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	struct fsl_rio_pw *pw = (struct fsl_rio_pw *)dev_instance;
3946ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 epwisr, tmp;
3956ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
396abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	epwisr = in_be32(rio_regs_win + RIO_EPWISR);
3976ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (!(epwisr & RIO_EPWISR_PW))
3986ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto pw_done;
3996ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
400abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	ipwmr = in_be32(&pw->pw_regs->pwmr);
401abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	ipwsr = in_be32(&pw->pw_regs->pwsr);
4026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
4036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#ifdef DEBUG_PW
4046ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
4056ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (ipwsr & RIO_IPWSR_QF)
4066ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug(" QF");
4076ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (ipwsr & RIO_IPWSR_TE)
4086ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug(" TE");
4096ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (ipwsr & RIO_IPWSR_QFI)
4106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug(" QFI");
4116ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (ipwsr & RIO_IPWSR_PWD)
4126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug(" PWD");
4136ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (ipwsr & RIO_IPWSR_PWB)
4146ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug(" PWB");
4156ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	pr_debug(" )\n");
4166ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#endif
4176ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Schedule deferred processing if PW was received */
4186ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (ipwsr & RIO_IPWSR_QFI) {
4196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		/* Save PW message (if there is room in FIFO),
4206ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 * otherwise discard it.
4216ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 */
422abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		if (kfifo_avail(&pw->pw_fifo) >= RIO_PW_MSG_SIZE) {
423abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			pw->port_write_msg.msg_count++;
424abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			kfifo_in(&pw->pw_fifo, pw->port_write_msg.virt,
4256ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				 RIO_PW_MSG_SIZE);
4266ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		} else {
427abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			pw->port_write_msg.discard_count++;
4286ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
429abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang				 pw->port_write_msg.discard_count);
4306ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		}
4316ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		/* Clear interrupt and issue Clear Queue command. This allows
4326ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 * another port-write to be received.
4336ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 */
434abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		out_be32(&pw->pw_regs->pwsr,	RIO_IPWSR_QFI);
435abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		out_be32(&pw->pw_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
4366ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
437abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		schedule_work(&pw->pw_work);
4386ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
4396ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
4406ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
441abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		pw->port_write_msg.err_count++;
4426ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug("RIO: Port-Write Transaction Err (%d)\n",
443abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			 pw->port_write_msg.err_count);
4446ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		/* Clear Transaction Error: port-write controller should be
4456ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 * disabled when clearing this error
4466ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 */
447abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		out_be32(&pw->pw_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE);
448abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		out_be32(&pw->pw_regs->pwsr,	RIO_IPWSR_TE);
449abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		out_be32(&pw->pw_regs->pwmr, ipwmr);
4506ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
4516ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
4526ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (ipwsr & RIO_IPWSR_PWD) {
453abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		pw->port_write_msg.discard_count++;
4546ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
455abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			 pw->port_write_msg.discard_count);
456abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_PWD);
4576ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
4586ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
4596ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangpw_done:
4606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (epwisr & RIO_EPWISR_PINT1) {
461abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		tmp = in_be32(rio_regs_win + RIO_LTLEDCSR);
4626ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
463abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		fsl_rio_port_error_handler(0);
4646ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
4656ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
4666ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (epwisr & RIO_EPWISR_PINT2) {
467abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		tmp = in_be32(rio_regs_win + RIO_LTLEDCSR);
4686ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
469abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		fsl_rio_port_error_handler(1);
4706ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
4716ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
4726ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (epwisr & RIO_EPWISR_MU) {
473abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		tmp = in_be32(rio_regs_win + RIO_LTLEDCSR);
4746ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
475abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		msg_unit_error_handler();
4766ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
4776ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
4786ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return IRQ_HANDLED;
4796ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
4806ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
4816ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangstatic void fsl_pw_dpc(struct work_struct *work)
4826ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
483abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	struct fsl_rio_pw *pw = container_of(work, struct fsl_rio_pw, pw_work);
4846ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
4856ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
4866ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/*
4876ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 * Process port-write messages
4886ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 */
489abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	while (kfifo_out_spinlocked(&pw->pw_fifo, (unsigned char *)msg_buffer,
490abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			 RIO_PW_MSG_SIZE, &pw->pw_fifo_lock)) {
4916ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		/* Process one message */
4926ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#ifdef DEBUG_PW
4936ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		{
4946ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		u32 i;
4956ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug("%s : Port-Write Message:", __func__);
4966ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
4976ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			if ((i%4) == 0)
4986ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				pr_debug("\n0x%02x: 0x%08x", i*4,
4996ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang					 msg_buffer[i]);
5006ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			else
5016ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				pr_debug(" 0x%08x", msg_buffer[i]);
5026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		}
5036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_debug("\n");
5046ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		}
5056ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang#endif
5066ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		/* Pass the port-write message to RIO core for processing */
5076ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
5086ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
5096ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
5106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5116ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
5126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_rio_pw_enable - enable/disable port-write interface init
5136ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: Master port implementing the port write unit
514abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang * @enable:    1=enable; 0=disable port-write message handling
5156ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
5166ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangint fsl_rio_pw_enable(struct rio_mport *mport, int enable)
5176ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
5186ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 rval;
5196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
520abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	rval = in_be32(&pw->pw_regs->pwmr);
5216ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5226ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (enable)
5236ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rval |= RIO_IPWMR_PWE;
5246ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	else
5256ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rval &= ~RIO_IPWMR_PWE;
5266ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
527abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&pw->pw_regs->pwmr, rval);
5286ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5296ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return 0;
5306ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
5316ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5326ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
5336ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_rio_port_write_init - MPC85xx port write interface init
5346ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: Master port implementing the port write unit
5356ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
5366ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Initializes port write unit hardware and DMA buffer
5376ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * ring. Called from fsl_rio_setup(). Returns %0 on success
5386ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * or %-ENOMEM on failure.
5396ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
5406ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
541abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangint fsl_rio_port_write_init(struct fsl_rio_pw *pw)
5426ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
5436ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int rc = 0;
5446ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5456ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Following configurations require a disabled port write controller */
546abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&pw->pw_regs->pwmr,
547abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		 in_be32(&pw->pw_regs->pwmr) & ~RIO_IPWMR_PWE);
5486ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5496ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Initialize port write */
550abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	pw->port_write_msg.virt = dma_alloc_coherent(pw->dev,
5516ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang					RIO_PW_MSG_SIZE,
552abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang					&pw->port_write_msg.phys, GFP_KERNEL);
553abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	if (!pw->port_write_msg.virt) {
5546ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_err("RIO: unable allocate port write queue\n");
5556ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		return -ENOMEM;
5566ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
5576ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
558abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	pw->port_write_msg.err_count = 0;
559abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	pw->port_write_msg.discard_count = 0;
5606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5616ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Point dequeue/enqueue pointers at first entry */
562abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&pw->pw_regs->epwqbar, 0);
563abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&pw->pw_regs->pwqbar, (u32) pw->port_write_msg.phys);
5646ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5656ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n",
566abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		 in_be32(&pw->pw_regs->epwqbar),
567abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		 in_be32(&pw->pw_regs->pwqbar));
5686ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5696ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Clear interrupt status IPWSR */
570abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&pw->pw_regs->pwsr,
5716ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
5726ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5736ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Configure port write contoller for snooping enable all reporting,
5746ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	   clear queue full */
575abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&pw->pw_regs->pwmr,
5766ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ);
5776ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5786ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5796ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Hook up port-write handler */
580abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	rc = request_irq(IRQ_RIO_PW(pw), fsl_rio_port_write_handler,
581abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			IRQF_SHARED, "port-write", (void *)pw);
5826ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (rc < 0) {
5836ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
5846ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto err_out;
5856ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
5866ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Enable Error Interrupt */
5876ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL);
5886ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
589abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	INIT_WORK(&pw->pw_work, fsl_pw_dpc);
590abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	spin_lock_init(&pw->pw_fifo_lock);
591abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	if (kfifo_alloc(&pw->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
5926ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		pr_err("FIFO allocation failed\n");
5936ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rc = -ENOMEM;
5946ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto err_out_irq;
5956ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
5966ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
5976ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n",
598abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		 in_be32(&pw->pw_regs->pwmr),
599abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		 in_be32(&pw->pw_regs->pwsr));
6006ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6016ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return rc;
6026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangerr_out_irq:
604abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	free_irq(IRQ_RIO_PW(pw), (void *)pw);
6056ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangerr_out:
606abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	dma_free_coherent(pw->dev, RIO_PW_MSG_SIZE,
607abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		pw->port_write_msg.virt,
608abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		pw->port_write_msg.phys);
6096ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return rc;
6106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
6116ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
6136ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_rio_doorbell_send - Send a MPC85xx doorbell message
6146ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: RapidIO master port info
6156ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @index: ID of RapidIO interface
6166ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @destid: Destination ID of target device
6176ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @data: 16-bit info field of RapidIO doorbell message
6186ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
6196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Sends a MPC85xx doorbell message. Returns %0 on success or
6206ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * %-EINVAL on failure.
6216ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
622abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangint fsl_rio_doorbell_send(struct rio_mport *mport,
6236ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				int index, u16 destid, u16 data)
6246ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
6256ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n",
6266ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 index, destid, data);
627abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
628abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	/* In the serial version silicons, such as MPC8548, MPC8641,
629abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	 * below operations is must be.
630abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	 */
631abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->odmr, 0x00000000);
632abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->odretcr, 0x00000004);
633abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->oddpr, destid << 16);
634abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->oddatr, (index << 20) | data);
635abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->odmr, 0x00000001);
6366ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6376ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return 0;
6386ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
6396ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6406ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
6416ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_add_outb_message - Add message to the MPC85xx outbound message queue
6426ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: Master port with outbound message queue
6436ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @rdev: Target of outbound message
6446ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mbox: Outbound mailbox
6456ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @buffer: Message to add to outbound queue
6466ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @len: Length of message
6476ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
6486ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Adds the @buffer message to the MPC85xx outbound message queue. Returns
6496ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * %0 on success or %-EINVAL on failure.
6506ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
651abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangint
6526ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangfsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
6536ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			void *buffer, size_t len)
6546ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
6556ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
6566ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	u32 omr;
6576ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_tx_desc *desc = (struct rio_tx_desc *)rmu->msg_tx_ring.virt
6586ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang					+ rmu->msg_tx_ring.tx_slot;
6596ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int ret = 0;
6606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6616ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \
6622a2383dab097823d68accce65da043402bdeb57bLiu Gang		 "%p len %8.8zx\n", rdev->destid, mbox, buffer, len);
6636ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
6646ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		ret = -EINVAL;
6656ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
6666ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
6676ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6686ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Copy and clear rest of buffer */
6696ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	memcpy(rmu->msg_tx_ring.virt_buffer[rmu->msg_tx_ring.tx_slot], buffer,
6706ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			len);
6716ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (len < (RIO_MAX_MSG_SIZE - 4))
6726ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		memset(rmu->msg_tx_ring.virt_buffer[rmu->msg_tx_ring.tx_slot]
6736ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				+ len, 0, RIO_MAX_MSG_SIZE - len);
6746ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
675abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	/* Set mbox field for message, and set destid */
676abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	desc->dport = (rdev->destid << 16) | (mbox & 0x3);
677abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
678abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	/* Enable EOMI interrupt and priority */
679abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	desc->dattr = 0x28000000 | ((mport->index) << 20);
6806ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6816ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Set transfer size aligned to next power of 2 (in double words) */
6826ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
6836ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6846ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Set snooping and source buffer address */
6856ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	desc->saddr = 0x00000004
6866ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		| rmu->msg_tx_ring.phys_buffer[rmu->msg_tx_ring.tx_slot];
6876ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6886ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Increment enqueue pointer */
6896ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	omr = in_be32(&rmu->msg_regs->omr);
6906ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->omr, omr | RIO_MSG_OMR_MUI);
6916ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6926ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Go to next descriptor */
6936ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (++rmu->msg_tx_ring.tx_slot == rmu->msg_tx_ring.size)
6946ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rmu->msg_tx_ring.tx_slot = 0;
6956ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
6966ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout:
6976ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return ret;
6986ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
6996ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7006ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
7016ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_open_outb_mbox - Initialize MPC85xx outbound mailbox
7026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: Master port implementing the outbound message unit
7036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @dev_id: Device specific pointer to pass on event
7046ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mbox: Mailbox to open
7056ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @entries: Number of entries in the outbound mailbox ring
7066ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
7076ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Initializes buffer ring, request the outbound message interrupt,
7086ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * and enables the outbound message unit. Returns %0 on success and
7096ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * %-EINVAL or %-ENOMEM on failure.
7106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
711abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangint
7126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangfsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
7136ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
7146ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int i, j, rc = 0;
7156ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_priv *priv = mport->priv;
7166ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
7176ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7186ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if ((entries < RIO_MIN_TX_RING_SIZE) ||
7196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		(entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) {
7206ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rc = -EINVAL;
7216ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
7226ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
7236ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7246ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Initialize shadow copy ring */
7256ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_tx_ring.dev_id = dev_id;
7266ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_tx_ring.size = entries;
7276ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7286ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	for (i = 0; i < rmu->msg_tx_ring.size; i++) {
7296ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rmu->msg_tx_ring.virt_buffer[i] =
7306ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			dma_alloc_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
7316ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				&rmu->msg_tx_ring.phys_buffer[i], GFP_KERNEL);
7326ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		if (!rmu->msg_tx_ring.virt_buffer[i]) {
7336ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			rc = -ENOMEM;
7346ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			for (j = 0; j < rmu->msg_tx_ring.size; j++)
7356ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				if (rmu->msg_tx_ring.virt_buffer[j])
7366ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang					dma_free_coherent(priv->dev,
7376ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang							RIO_MSG_BUFFER_SIZE,
7386ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang							rmu->msg_tx_ring.
7396ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang							virt_buffer[j],
7406ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang							rmu->msg_tx_ring.
7416ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang							phys_buffer[j]);
7426ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			goto out;
7436ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		}
7446ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
7456ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7466ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Initialize outbound message descriptor ring */
7476ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_tx_ring.virt = dma_alloc_coherent(priv->dev,
7486ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
7496ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				&rmu->msg_tx_ring.phys, GFP_KERNEL);
7506ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (!rmu->msg_tx_ring.virt) {
7516ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rc = -ENOMEM;
7526ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out_dma;
7536ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
7546ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	memset(rmu->msg_tx_ring.virt, 0,
7556ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE);
7566ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_tx_ring.tx_slot = 0;
7576ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7586ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Point dequeue/enqueue pointers at first entry in ring */
7596ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->odqdpar, rmu->msg_tx_ring.phys);
7606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->odqepar, rmu->msg_tx_ring.phys);
7616ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7626ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Configure for snooping */
7636ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->osar, 0x00000004);
7646ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7656ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Clear interrupt status */
7666ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->osr, 0x000000b3);
7676ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7686ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Hook up outbound message handler */
7696ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rc = request_irq(IRQ_RIO_TX(mport), fsl_rio_tx_handler, 0,
7706ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			 "msg_tx", (void *)mport);
7716ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (rc < 0)
7726ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out_irq;
7736ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7746ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/*
7756ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 * Configure outbound message unit
7766ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 *      Snooping
7776ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 *      Interrupts (all enabled, except QEIE)
7786ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 *      Chaining mode
7796ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 *      Disable
7806ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 */
7816ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->omr, 0x00100220);
7826ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7836ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Set number of entries */
7846ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->omr,
7856ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 in_be32(&rmu->msg_regs->omr) |
7866ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 ((get_bitmask_order(entries) - 2) << 12));
7876ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7886ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Now enable the unit */
7896ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->omr, in_be32(&rmu->msg_regs->omr) | 0x1);
7906ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7916ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout:
7926ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return rc;
7936ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7946ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout_irq:
7956ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	dma_free_coherent(priv->dev,
7966ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
7976ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rmu->msg_tx_ring.virt, rmu->msg_tx_ring.phys);
7986ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
7996ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout_dma:
8006ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	for (i = 0; i < rmu->msg_tx_ring.size; i++)
8016ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
8026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rmu->msg_tx_ring.virt_buffer[i],
8036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rmu->msg_tx_ring.phys_buffer[i]);
8046ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8056ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return rc;
8066ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
8076ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8086ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
8096ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_close_outb_mbox - Shut down MPC85xx outbound mailbox
8106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: Master port implementing the outbound message unit
8116ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mbox: Mailbox to close
8126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
8136ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Disables the outbound message unit, free all buffers, and
8146ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * frees the outbound message interrupt.
8156ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
816abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangvoid fsl_close_outb_mbox(struct rio_mport *mport, int mbox)
8176ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
8186ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_priv *priv = mport->priv;
8196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
8206ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8216ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Disable inbound message unit */
8226ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->omr, 0);
8236ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8246ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Free ring */
8256ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	dma_free_coherent(priv->dev,
8266ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
8276ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_tx_ring.virt, rmu->msg_tx_ring.phys);
8286ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8296ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Free interrupt */
8306ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	free_irq(IRQ_RIO_TX(mport), (void *)mport);
8316ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
8326ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8336ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
8346ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_open_inb_mbox - Initialize MPC85xx inbound mailbox
8356ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: Master port implementing the inbound message unit
8366ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @dev_id: Device specific pointer to pass on event
8376ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mbox: Mailbox to open
8386ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @entries: Number of entries in the inbound mailbox ring
8396ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
8406ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Initializes buffer ring, request the inbound message interrupt,
8416ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * and enables the inbound message unit. Returns %0 on success
8426ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * and %-EINVAL or %-ENOMEM on failure.
8436ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
844abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangint
8456ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangfsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
8466ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
8476ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int i, rc = 0;
8486ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_priv *priv = mport->priv;
8496ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
8506ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8516ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if ((entries < RIO_MIN_RX_RING_SIZE) ||
8526ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		(entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {
8536ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rc = -EINVAL;
8546ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
8556ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
8566ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8576ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Initialize client buffer ring */
8586ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_rx_ring.dev_id = dev_id;
8596ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_rx_ring.size = entries;
8606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_rx_ring.rx_slot = 0;
8616ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	for (i = 0; i < rmu->msg_rx_ring.size; i++)
8626ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rmu->msg_rx_ring.virt_buffer[i] = NULL;
8636ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8646ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Initialize inbound message ring */
8656ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_rx_ring.virt = dma_alloc_coherent(priv->dev,
8666ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
8676ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang				&rmu->msg_rx_ring.phys, GFP_KERNEL);
8686ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (!rmu->msg_rx_ring.virt) {
8696ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rc = -ENOMEM;
8706ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
8716ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
8726ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8736ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Point dequeue/enqueue pointers at first entry in ring */
8746ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->ifqdpar, (u32) rmu->msg_rx_ring.phys);
8756ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->ifqepar, (u32) rmu->msg_rx_ring.phys);
8766ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8776ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Clear interrupt status */
8786ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->isr, 0x00000091);
8796ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8806ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Hook up inbound message handler */
8816ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0,
8826ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			 "msg_rx", (void *)mport);
8836ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (rc < 0) {
8841c075f95504b77e80d6e491fef8f89a001164dedLiu Gang		dma_free_coherent(priv->dev,
8851c075f95504b77e80d6e491fef8f89a001164dedLiu Gang			rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
8861c075f95504b77e80d6e491fef8f89a001164dedLiu Gang			rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys);
8876ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
8886ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
8896ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8906ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/*
8916ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 * Configure inbound message unit:
8926ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 *      Snooping
8936ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 *      4KB max message size
8946ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 *      Unmask all interrupt sources
8956ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 *      Disable
8966ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	 */
8976ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->imr, 0x001b0060);
8986ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
8996ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Set number of queue entries */
9006ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	setbits32(&rmu->msg_regs->imr, (get_bitmask_order(entries) - 2) << 12);
9016ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Now enable the unit */
9036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	setbits32(&rmu->msg_regs->imr, 0x1);
9046ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9056ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout:
9066ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return rc;
9076ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
9086ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9096ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
9106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_close_inb_mbox - Shut down MPC85xx inbound mailbox
9116ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: Master port implementing the inbound message unit
9126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mbox: Mailbox to close
9136ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
9146ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Disables the inbound message unit, free all buffers, and
9156ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * frees the inbound message interrupt.
9166ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
917abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangvoid fsl_close_inb_mbox(struct rio_mport *mport, int mbox)
9186ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
9196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_priv *priv = mport->priv;
9206ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
9216ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9226ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Disable inbound message unit */
9236ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	out_be32(&rmu->msg_regs->imr, 0);
9246ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9256ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Free ring */
9266ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	dma_free_coherent(priv->dev, rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
927abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys);
9286ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9296ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Free interrupt */
9306ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	free_irq(IRQ_RIO_RX(mport), (void *)mport);
9316ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
9326ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9336ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
9346ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_add_inb_buffer - Add buffer to the MPC85xx inbound message queue
9356ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: Master port implementing the inbound message unit
9366ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mbox: Inbound mailbox number
9376ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @buf: Buffer to add to inbound queue
9386ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
9396ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Adds the @buf buffer to the MPC85xx inbound message queue. Returns
9406ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * %0 on success or %-EINVAL on failure.
9416ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
942abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangint fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
9436ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
9446ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int rc = 0;
9456ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
9466ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9476ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	pr_debug("RIO: fsl_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
9486ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		 rmu->msg_rx_ring.rx_slot);
9496ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9506ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (rmu->msg_rx_ring.virt_buffer[rmu->msg_rx_ring.rx_slot]) {
9516ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		printk(KERN_ERR
9526ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			"RIO: error adding inbound buffer %d, buffer exists\n",
9536ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			rmu->msg_rx_ring.rx_slot);
9546ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rc = -EINVAL;
9556ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
9566ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
9576ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9586ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_rx_ring.virt_buffer[rmu->msg_rx_ring.rx_slot] = buf;
9596ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (++rmu->msg_rx_ring.rx_slot == rmu->msg_rx_ring.size)
9606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rmu->msg_rx_ring.rx_slot = 0;
9616ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9626ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout:
9636ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return rc;
9646ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
9656ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9666ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
9676ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_get_inb_message - Fetch inbound message from the MPC85xx message unit
9686ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: Master port implementing the inbound message unit
9696ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mbox: Inbound mailbox number
9706ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
9716ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Gets the next available inbound message from the inbound message queue.
9726ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * A pointer to the message is returned on success or NULL on failure.
9736ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
974abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangvoid *fsl_get_inb_message(struct rio_mport *mport, int mbox)
9756ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
9766ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
9772a2383dab097823d68accce65da043402bdeb57bLiu Gang	u32 phys_buf;
9782a2383dab097823d68accce65da043402bdeb57bLiu Gang	void *virt_buf;
9796ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	void *buf = NULL;
9806ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int buf_idx;
9816ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9826ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	phys_buf = in_be32(&rmu->msg_regs->ifqdpar);
9836ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9846ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* If no more messages, then bail out */
9856ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (phys_buf == in_be32(&rmu->msg_regs->ifqepar))
9866ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out2;
9876ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9882a2383dab097823d68accce65da043402bdeb57bLiu Gang	virt_buf = rmu->msg_rx_ring.virt + (phys_buf
9896ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang						- rmu->msg_rx_ring.phys);
9906ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
9916ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	buf = rmu->msg_rx_ring.virt_buffer[buf_idx];
9926ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9936ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (!buf) {
9946ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		printk(KERN_ERR
9956ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			"RIO: inbound message copy failed, no buffers\n");
9966ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out1;
9976ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
9986ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
9996ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Copy max message size, caller is expected to allocate that big */
10002a2383dab097823d68accce65da043402bdeb57bLiu Gang	memcpy(buf, virt_buf, RIO_MAX_MSG_SIZE);
10016ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Clear the available buffer */
10036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL;
10046ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10056ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout1:
10066ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	setbits32(&rmu->msg_regs->imr, RIO_MSG_IMR_MI);
10076ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10086ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout2:
10096ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return buf;
10106ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
10116ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10126ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang/**
10136ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * fsl_rio_doorbell_init - MPC85xx doorbell interface init
10146ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * @mport: Master port implementing the inbound doorbell unit
10156ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang *
10166ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * Initializes doorbell unit hardware and inbound DMA buffer
10176ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * ring. Called from fsl_rio_setup(). Returns %0 on success
10186ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang * or %-ENOMEM on failure.
10196ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang */
1020abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gangint fsl_rio_doorbell_init(struct fsl_rio_dbell *dbell)
10216ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
10226ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	int rc = 0;
10236ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10246ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Initialize inbound doorbells */
1025abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	dbell->dbell_ring.virt = dma_alloc_coherent(dbell->dev, 512 *
1026abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		DOORBELL_MESSAGE_SIZE, &dbell->dbell_ring.phys, GFP_KERNEL);
1027abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	if (!dbell->dbell_ring.virt) {
10286ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n");
10296ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		rc = -ENOMEM;
10306ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
10316ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
10326ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10336ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Point dequeue/enqueue pointers at first entry in ring */
1034abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->dqdpar, (u32) dbell->dbell_ring.phys);
1035abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->dqepar, (u32) dbell->dbell_ring.phys);
10366ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10376ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Clear interrupt status */
1038abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->dsr, 0x00000091);
10396ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10406ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Hook up doorbell handler */
1041abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	rc = request_irq(IRQ_RIO_BELL(dbell), fsl_rio_dbell_handler, 0,
1042abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			 "dbell_rx", (void *)dbell);
10436ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (rc < 0) {
1044abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		dma_free_coherent(dbell->dev, 512 * DOORBELL_MESSAGE_SIZE,
1045abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			 dbell->dbell_ring.virt, dbell->dbell_ring.phys);
10466ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		printk(KERN_ERR
10476ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang			"MPC85xx RIO: unable to request inbound doorbell irq");
10486ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		goto out;
10496ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	}
10506ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10516ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	/* Configure doorbells for snooping, 512 entries, and enable */
1052abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	out_be32(&dbell->dbell_regs->dmr, 0x00108161);
10536ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10546ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangout:
10556ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return rc;
10566ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
10576ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10586ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gangint fsl_rio_setup_rmu(struct rio_mport *mport, struct device_node *node)
10596ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang{
10606ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct rio_priv *priv;
10616ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	struct fsl_rmu *rmu;
1062abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	u64 msg_start;
1063abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	const u32 *msg_addr;
1064abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	int mlen;
1065abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	int aw;
10666ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
1067abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	if (!mport || !mport->priv)
1068abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		return -EINVAL;
1069abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
1070abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	priv = mport->priv;
1071abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
1072abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	if (!node) {
1073abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		dev_warn(priv->dev, "Can't get %s property 'fsl,rmu'\n",
1074abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			priv->dev->of_node->full_name);
1075abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		return -EINVAL;
1076abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	}
10776ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
10786ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rmu = kzalloc(sizeof(struct fsl_rmu), GFP_KERNEL);
10796ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	if (!rmu)
10806ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang		return -ENOMEM;
10816ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
1082abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	aw = of_n_addr_cells(node);
1083abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	msg_addr = of_get_property(node, "reg", &mlen);
1084abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	if (!msg_addr) {
1085abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		pr_err("%s: unable to find 'reg' property of message-unit\n",
1086abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			node->full_name);
1087c6ca52ad32cb9a4b9b331a60966ffa4d00ce3f37Julia Lawall		kfree(rmu);
1088abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		return -ENOMEM;
1089abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	}
1090abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	msg_start = of_read_number(msg_addr, aw);
1091abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
1092abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	rmu->msg_regs = (struct rio_msg_regs *)
1093abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang			(rmu_regs_win + (u32)msg_start);
1094abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
1095abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	rmu->txirq = irq_of_parse_and_map(node, 0);
1096abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	rmu->rxirq = irq_of_parse_and_map(node, 1);
1097abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang	printk(KERN_INFO "%s: txirq: %d, rxirq %d\n",
1098abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang		node->full_name, rmu->txirq, rmu->rxirq);
1099abc3aeae3aaa5c319d02f12649e17ea5929999aaLiu Gang
11006ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	priv->rmm_handle = rmu;
11016ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
11026ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
11036ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
11046ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
11056ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang
11066ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang	return 0;
11076ec4bedbf153a8ef71aeba99a40efef556b57798Liu Gang}
1108