162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Freescale MPC85xx/MPC86xx RapidIO RMU support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2009 Sysgo AG 662306a36Sopenharmony_ci * Thomas Moll <thomas.moll@sysgo.com> 762306a36Sopenharmony_ci * - fixed maintenance access routines, check for aligned access 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright 2009 Integrated Device Technology, Inc. 1062306a36Sopenharmony_ci * Alex Bounine <alexandre.bounine@idt.com> 1162306a36Sopenharmony_ci * - Added Port-Write message handling 1262306a36Sopenharmony_ci * - Added Machine Check exception handling 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc. 1562306a36Sopenharmony_ci * Zhang Wei <wei.zhang@freescale.com> 1662306a36Sopenharmony_ci * Lian Minghuan-B31939 <Minghuan.Lian@freescale.com> 1762306a36Sopenharmony_ci * Liu Gang <Gang.Liu@freescale.com> 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Copyright 2005 MontaVista Software, Inc. 2062306a36Sopenharmony_ci * Matt Porter <mporter@kernel.crashing.org> 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/types.h> 2462306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2562306a36Sopenharmony_ci#include <linux/interrupt.h> 2662306a36Sopenharmony_ci#include <linux/of_address.h> 2762306a36Sopenharmony_ci#include <linux/of_irq.h> 2862306a36Sopenharmony_ci#include <linux/slab.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "fsl_rio.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define GET_RMM_HANDLE(mport) \ 3362306a36Sopenharmony_ci (((struct rio_priv *)(mport->priv))->rmm_handle) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* RapidIO definition irq, which read from OF-tree */ 3662306a36Sopenharmony_ci#define IRQ_RIO_PW(m) (((struct fsl_rio_pw *)(m))->pwirq) 3762306a36Sopenharmony_ci#define IRQ_RIO_BELL(m) (((struct fsl_rio_dbell *)(m))->bellirq) 3862306a36Sopenharmony_ci#define IRQ_RIO_TX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->txirq) 3962306a36Sopenharmony_ci#define IRQ_RIO_RX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->rxirq) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define RIO_MIN_TX_RING_SIZE 2 4262306a36Sopenharmony_ci#define RIO_MAX_TX_RING_SIZE 2048 4362306a36Sopenharmony_ci#define RIO_MIN_RX_RING_SIZE 2 4462306a36Sopenharmony_ci#define RIO_MAX_RX_RING_SIZE 2048 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define RIO_IPWMR_SEN 0x00100000 4762306a36Sopenharmony_ci#define RIO_IPWMR_QFIE 0x00000100 4862306a36Sopenharmony_ci#define RIO_IPWMR_EIE 0x00000020 4962306a36Sopenharmony_ci#define RIO_IPWMR_CQ 0x00000002 5062306a36Sopenharmony_ci#define RIO_IPWMR_PWE 0x00000001 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define RIO_IPWSR_QF 0x00100000 5362306a36Sopenharmony_ci#define RIO_IPWSR_TE 0x00000080 5462306a36Sopenharmony_ci#define RIO_IPWSR_QFI 0x00000010 5562306a36Sopenharmony_ci#define RIO_IPWSR_PWD 0x00000008 5662306a36Sopenharmony_ci#define RIO_IPWSR_PWB 0x00000004 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define RIO_EPWISR 0x10010 5962306a36Sopenharmony_ci/* EPWISR Error match value */ 6062306a36Sopenharmony_ci#define RIO_EPWISR_PINT1 0x80000000 6162306a36Sopenharmony_ci#define RIO_EPWISR_PINT2 0x40000000 6262306a36Sopenharmony_ci#define RIO_EPWISR_MU 0x00000002 6362306a36Sopenharmony_ci#define RIO_EPWISR_PW 0x00000001 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define IPWSR_CLEAR 0x98 6662306a36Sopenharmony_ci#define OMSR_CLEAR 0x1cb3 6762306a36Sopenharmony_ci#define IMSR_CLEAR 0x491 6862306a36Sopenharmony_ci#define IDSR_CLEAR 0x91 6962306a36Sopenharmony_ci#define ODSR_CLEAR 0x1c00 7062306a36Sopenharmony_ci#define LTLEECSR_ENABLE_ALL 0xFFC000FC 7162306a36Sopenharmony_ci#define RIO_LTLEECSR 0x060c 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define RIO_IM0SR 0x64 7462306a36Sopenharmony_ci#define RIO_IM1SR 0x164 7562306a36Sopenharmony_ci#define RIO_OM0SR 0x4 7662306a36Sopenharmony_ci#define RIO_OM1SR 0x104 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define RIO_DBELL_WIN_SIZE 0x1000 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define RIO_MSG_OMR_MUI 0x00000002 8162306a36Sopenharmony_ci#define RIO_MSG_OSR_TE 0x00000080 8262306a36Sopenharmony_ci#define RIO_MSG_OSR_QOI 0x00000020 8362306a36Sopenharmony_ci#define RIO_MSG_OSR_QFI 0x00000010 8462306a36Sopenharmony_ci#define RIO_MSG_OSR_MUB 0x00000004 8562306a36Sopenharmony_ci#define RIO_MSG_OSR_EOMI 0x00000002 8662306a36Sopenharmony_ci#define RIO_MSG_OSR_QEI 0x00000001 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define RIO_MSG_IMR_MI 0x00000002 8962306a36Sopenharmony_ci#define RIO_MSG_ISR_TE 0x00000080 9062306a36Sopenharmony_ci#define RIO_MSG_ISR_QFI 0x00000010 9162306a36Sopenharmony_ci#define RIO_MSG_ISR_DIQI 0x00000001 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define RIO_MSG_DESC_SIZE 32 9462306a36Sopenharmony_ci#define RIO_MSG_BUFFER_SIZE 4096 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define DOORBELL_DMR_DI 0x00000002 9762306a36Sopenharmony_ci#define DOORBELL_DSR_TE 0x00000080 9862306a36Sopenharmony_ci#define DOORBELL_DSR_QFI 0x00000010 9962306a36Sopenharmony_ci#define DOORBELL_DSR_DIQI 0x00000001 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define DOORBELL_MESSAGE_SIZE 0x08 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic DEFINE_SPINLOCK(fsl_rio_doorbell_lock); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistruct rio_msg_regs { 10662306a36Sopenharmony_ci u32 omr; 10762306a36Sopenharmony_ci u32 osr; 10862306a36Sopenharmony_ci u32 pad1; 10962306a36Sopenharmony_ci u32 odqdpar; 11062306a36Sopenharmony_ci u32 pad2; 11162306a36Sopenharmony_ci u32 osar; 11262306a36Sopenharmony_ci u32 odpr; 11362306a36Sopenharmony_ci u32 odatr; 11462306a36Sopenharmony_ci u32 odcr; 11562306a36Sopenharmony_ci u32 pad3; 11662306a36Sopenharmony_ci u32 odqepar; 11762306a36Sopenharmony_ci u32 pad4[13]; 11862306a36Sopenharmony_ci u32 imr; 11962306a36Sopenharmony_ci u32 isr; 12062306a36Sopenharmony_ci u32 pad5; 12162306a36Sopenharmony_ci u32 ifqdpar; 12262306a36Sopenharmony_ci u32 pad6; 12362306a36Sopenharmony_ci u32 ifqepar; 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistruct rio_dbell_regs { 12762306a36Sopenharmony_ci u32 odmr; 12862306a36Sopenharmony_ci u32 odsr; 12962306a36Sopenharmony_ci u32 pad1[4]; 13062306a36Sopenharmony_ci u32 oddpr; 13162306a36Sopenharmony_ci u32 oddatr; 13262306a36Sopenharmony_ci u32 pad2[3]; 13362306a36Sopenharmony_ci u32 odretcr; 13462306a36Sopenharmony_ci u32 pad3[12]; 13562306a36Sopenharmony_ci u32 dmr; 13662306a36Sopenharmony_ci u32 dsr; 13762306a36Sopenharmony_ci u32 pad4; 13862306a36Sopenharmony_ci u32 dqdpar; 13962306a36Sopenharmony_ci u32 pad5; 14062306a36Sopenharmony_ci u32 dqepar; 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistruct rio_pw_regs { 14462306a36Sopenharmony_ci u32 pwmr; 14562306a36Sopenharmony_ci u32 pwsr; 14662306a36Sopenharmony_ci u32 epwqbar; 14762306a36Sopenharmony_ci u32 pwqbar; 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistruct rio_tx_desc { 15262306a36Sopenharmony_ci u32 pad1; 15362306a36Sopenharmony_ci u32 saddr; 15462306a36Sopenharmony_ci u32 dport; 15562306a36Sopenharmony_ci u32 dattr; 15662306a36Sopenharmony_ci u32 pad2; 15762306a36Sopenharmony_ci u32 pad3; 15862306a36Sopenharmony_ci u32 dwcnt; 15962306a36Sopenharmony_ci u32 pad4; 16062306a36Sopenharmony_ci}; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistruct rio_msg_tx_ring { 16362306a36Sopenharmony_ci void *virt; 16462306a36Sopenharmony_ci dma_addr_t phys; 16562306a36Sopenharmony_ci void *virt_buffer[RIO_MAX_TX_RING_SIZE]; 16662306a36Sopenharmony_ci dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE]; 16762306a36Sopenharmony_ci int tx_slot; 16862306a36Sopenharmony_ci int size; 16962306a36Sopenharmony_ci void *dev_id; 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistruct rio_msg_rx_ring { 17362306a36Sopenharmony_ci void *virt; 17462306a36Sopenharmony_ci dma_addr_t phys; 17562306a36Sopenharmony_ci void *virt_buffer[RIO_MAX_RX_RING_SIZE]; 17662306a36Sopenharmony_ci int rx_slot; 17762306a36Sopenharmony_ci int size; 17862306a36Sopenharmony_ci void *dev_id; 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistruct fsl_rmu { 18262306a36Sopenharmony_ci struct rio_msg_regs __iomem *msg_regs; 18362306a36Sopenharmony_ci struct rio_msg_tx_ring msg_tx_ring; 18462306a36Sopenharmony_ci struct rio_msg_rx_ring msg_rx_ring; 18562306a36Sopenharmony_ci int txirq; 18662306a36Sopenharmony_ci int rxirq; 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistruct rio_dbell_msg { 19062306a36Sopenharmony_ci u16 pad1; 19162306a36Sopenharmony_ci u16 tid; 19262306a36Sopenharmony_ci u16 sid; 19362306a36Sopenharmony_ci u16 info; 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/** 19762306a36Sopenharmony_ci * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler 19862306a36Sopenharmony_ci * @irq: Linux interrupt number 19962306a36Sopenharmony_ci * @dev_instance: Pointer to interrupt-specific data 20062306a36Sopenharmony_ci * 20162306a36Sopenharmony_ci * Handles outbound message interrupts. Executes a register outbound 20262306a36Sopenharmony_ci * mailbox event handler and acks the interrupt occurrence. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_cistatic irqreturn_t 20562306a36Sopenharmony_cifsl_rio_tx_handler(int irq, void *dev_instance) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci int osr; 20862306a36Sopenharmony_ci struct rio_mport *port = (struct rio_mport *)dev_instance; 20962306a36Sopenharmony_ci struct fsl_rmu *rmu = GET_RMM_HANDLE(port); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci osr = in_be32(&rmu->msg_regs->osr); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (osr & RIO_MSG_OSR_TE) { 21462306a36Sopenharmony_ci pr_info("RIO: outbound message transmission error\n"); 21562306a36Sopenharmony_ci out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_TE); 21662306a36Sopenharmony_ci goto out; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (osr & RIO_MSG_OSR_QOI) { 22062306a36Sopenharmony_ci pr_info("RIO: outbound message queue overflow\n"); 22162306a36Sopenharmony_ci out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_QOI); 22262306a36Sopenharmony_ci goto out; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (osr & RIO_MSG_OSR_EOMI) { 22662306a36Sopenharmony_ci u32 dqp = in_be32(&rmu->msg_regs->odqdpar); 22762306a36Sopenharmony_ci int slot = (dqp - rmu->msg_tx_ring.phys) >> 5; 22862306a36Sopenharmony_ci if (port->outb_msg[0].mcback != NULL) { 22962306a36Sopenharmony_ci port->outb_msg[0].mcback(port, rmu->msg_tx_ring.dev_id, 23062306a36Sopenharmony_ci -1, 23162306a36Sopenharmony_ci slot); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci /* Ack the end-of-message interrupt */ 23462306a36Sopenharmony_ci out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_EOMI); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciout: 23862306a36Sopenharmony_ci return IRQ_HANDLED; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/** 24262306a36Sopenharmony_ci * fsl_rio_rx_handler - MPC85xx inbound message interrupt handler 24362306a36Sopenharmony_ci * @irq: Linux interrupt number 24462306a36Sopenharmony_ci * @dev_instance: Pointer to interrupt-specific data 24562306a36Sopenharmony_ci * 24662306a36Sopenharmony_ci * Handles inbound message interrupts. Executes a registered inbound 24762306a36Sopenharmony_ci * mailbox event handler and acks the interrupt occurrence. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_cistatic irqreturn_t 25062306a36Sopenharmony_cifsl_rio_rx_handler(int irq, void *dev_instance) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci int isr; 25362306a36Sopenharmony_ci struct rio_mport *port = (struct rio_mport *)dev_instance; 25462306a36Sopenharmony_ci struct fsl_rmu *rmu = GET_RMM_HANDLE(port); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci isr = in_be32(&rmu->msg_regs->isr); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (isr & RIO_MSG_ISR_TE) { 25962306a36Sopenharmony_ci pr_info("RIO: inbound message reception error\n"); 26062306a36Sopenharmony_ci out_be32((void *)&rmu->msg_regs->isr, RIO_MSG_ISR_TE); 26162306a36Sopenharmony_ci goto out; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* XXX Need to check/dispatch until queue empty */ 26562306a36Sopenharmony_ci if (isr & RIO_MSG_ISR_DIQI) { 26662306a36Sopenharmony_ci /* 26762306a36Sopenharmony_ci * Can receive messages for any mailbox/letter to that 26862306a36Sopenharmony_ci * mailbox destination. So, make the callback with an 26962306a36Sopenharmony_ci * unknown/invalid mailbox number argument. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci if (port->inb_msg[0].mcback != NULL) 27262306a36Sopenharmony_ci port->inb_msg[0].mcback(port, rmu->msg_rx_ring.dev_id, 27362306a36Sopenharmony_ci -1, 27462306a36Sopenharmony_ci -1); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* Ack the queueing interrupt */ 27762306a36Sopenharmony_ci out_be32(&rmu->msg_regs->isr, RIO_MSG_ISR_DIQI); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ciout: 28162306a36Sopenharmony_ci return IRQ_HANDLED; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler 28662306a36Sopenharmony_ci * @irq: Linux interrupt number 28762306a36Sopenharmony_ci * @dev_instance: Pointer to interrupt-specific data 28862306a36Sopenharmony_ci * 28962306a36Sopenharmony_ci * Handles doorbell interrupts. Parses a list of registered 29062306a36Sopenharmony_ci * doorbell event handlers and executes a matching event handler. 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_cistatic irqreturn_t 29362306a36Sopenharmony_cifsl_rio_dbell_handler(int irq, void *dev_instance) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci int dsr; 29662306a36Sopenharmony_ci struct fsl_rio_dbell *fsl_dbell = (struct fsl_rio_dbell *)dev_instance; 29762306a36Sopenharmony_ci int i; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci dsr = in_be32(&fsl_dbell->dbell_regs->dsr); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (dsr & DOORBELL_DSR_TE) { 30262306a36Sopenharmony_ci pr_info("RIO: doorbell reception error\n"); 30362306a36Sopenharmony_ci out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_TE); 30462306a36Sopenharmony_ci goto out; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (dsr & DOORBELL_DSR_QFI) { 30862306a36Sopenharmony_ci pr_info("RIO: doorbell queue full\n"); 30962306a36Sopenharmony_ci out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_QFI); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* XXX Need to check/dispatch until queue empty */ 31362306a36Sopenharmony_ci if (dsr & DOORBELL_DSR_DIQI) { 31462306a36Sopenharmony_ci struct rio_dbell_msg *dmsg = 31562306a36Sopenharmony_ci fsl_dbell->dbell_ring.virt + 31662306a36Sopenharmony_ci (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff); 31762306a36Sopenharmony_ci struct rio_dbell *dbell; 31862306a36Sopenharmony_ci int found = 0; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci pr_debug 32162306a36Sopenharmony_ci ("RIO: processing doorbell," 32262306a36Sopenharmony_ci " sid %2.2x tid %2.2x info %4.4x\n", 32362306a36Sopenharmony_ci dmsg->sid, dmsg->tid, dmsg->info); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci for (i = 0; i < MAX_PORT_NUM; i++) { 32662306a36Sopenharmony_ci if (fsl_dbell->mport[i]) { 32762306a36Sopenharmony_ci list_for_each_entry(dbell, 32862306a36Sopenharmony_ci &fsl_dbell->mport[i]->dbells, node) { 32962306a36Sopenharmony_ci if ((dbell->res->start 33062306a36Sopenharmony_ci <= dmsg->info) 33162306a36Sopenharmony_ci && (dbell->res->end 33262306a36Sopenharmony_ci >= dmsg->info)) { 33362306a36Sopenharmony_ci found = 1; 33462306a36Sopenharmony_ci break; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci if (found && dbell->dinb) { 33862306a36Sopenharmony_ci dbell->dinb(fsl_dbell->mport[i], 33962306a36Sopenharmony_ci dbell->dev_id, dmsg->sid, 34062306a36Sopenharmony_ci dmsg->tid, 34162306a36Sopenharmony_ci dmsg->info); 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (!found) { 34862306a36Sopenharmony_ci pr_debug 34962306a36Sopenharmony_ci ("RIO: spurious doorbell," 35062306a36Sopenharmony_ci " sid %2.2x tid %2.2x info %4.4x\n", 35162306a36Sopenharmony_ci dmsg->sid, dmsg->tid, 35262306a36Sopenharmony_ci dmsg->info); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI); 35562306a36Sopenharmony_ci out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ciout: 35962306a36Sopenharmony_ci return IRQ_HANDLED; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void msg_unit_error_handler(void) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /*XXX: Error recovery is not implemented, we just clear errors */ 36662306a36Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci out_be32((u32 *)(rmu_regs_win + RIO_IM0SR), IMSR_CLEAR); 36962306a36Sopenharmony_ci out_be32((u32 *)(rmu_regs_win + RIO_IM1SR), IMSR_CLEAR); 37062306a36Sopenharmony_ci out_be32((u32 *)(rmu_regs_win + RIO_OM0SR), OMSR_CLEAR); 37162306a36Sopenharmony_ci out_be32((u32 *)(rmu_regs_win + RIO_OM1SR), OMSR_CLEAR); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->odsr, ODSR_CLEAR); 37462306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->dsr, IDSR_CLEAR); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwsr, IPWSR_CLEAR); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/** 38062306a36Sopenharmony_ci * fsl_rio_port_write_handler - MPC85xx port write interrupt handler 38162306a36Sopenharmony_ci * @irq: Linux interrupt number 38262306a36Sopenharmony_ci * @dev_instance: Pointer to interrupt-specific data 38362306a36Sopenharmony_ci * 38462306a36Sopenharmony_ci * Handles port write interrupts. Parses a list of registered 38562306a36Sopenharmony_ci * port write event handlers and executes a matching event handler. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_cistatic irqreturn_t 38862306a36Sopenharmony_cifsl_rio_port_write_handler(int irq, void *dev_instance) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci u32 ipwmr, ipwsr; 39162306a36Sopenharmony_ci struct fsl_rio_pw *pw = (struct fsl_rio_pw *)dev_instance; 39262306a36Sopenharmony_ci u32 epwisr, tmp; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci epwisr = in_be32(rio_regs_win + RIO_EPWISR); 39562306a36Sopenharmony_ci if (!(epwisr & RIO_EPWISR_PW)) 39662306a36Sopenharmony_ci goto pw_done; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ipwmr = in_be32(&pw->pw_regs->pwmr); 39962306a36Sopenharmony_ci ipwsr = in_be32(&pw->pw_regs->pwsr); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci#ifdef DEBUG_PW 40262306a36Sopenharmony_ci pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr); 40362306a36Sopenharmony_ci if (ipwsr & RIO_IPWSR_QF) 40462306a36Sopenharmony_ci pr_debug(" QF"); 40562306a36Sopenharmony_ci if (ipwsr & RIO_IPWSR_TE) 40662306a36Sopenharmony_ci pr_debug(" TE"); 40762306a36Sopenharmony_ci if (ipwsr & RIO_IPWSR_QFI) 40862306a36Sopenharmony_ci pr_debug(" QFI"); 40962306a36Sopenharmony_ci if (ipwsr & RIO_IPWSR_PWD) 41062306a36Sopenharmony_ci pr_debug(" PWD"); 41162306a36Sopenharmony_ci if (ipwsr & RIO_IPWSR_PWB) 41262306a36Sopenharmony_ci pr_debug(" PWB"); 41362306a36Sopenharmony_ci pr_debug(" )\n"); 41462306a36Sopenharmony_ci#endif 41562306a36Sopenharmony_ci /* Schedule deferred processing if PW was received */ 41662306a36Sopenharmony_ci if (ipwsr & RIO_IPWSR_QFI) { 41762306a36Sopenharmony_ci /* Save PW message (if there is room in FIFO), 41862306a36Sopenharmony_ci * otherwise discard it. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci if (kfifo_avail(&pw->pw_fifo) >= RIO_PW_MSG_SIZE) { 42162306a36Sopenharmony_ci pw->port_write_msg.msg_count++; 42262306a36Sopenharmony_ci kfifo_in(&pw->pw_fifo, pw->port_write_msg.virt, 42362306a36Sopenharmony_ci RIO_PW_MSG_SIZE); 42462306a36Sopenharmony_ci } else { 42562306a36Sopenharmony_ci pw->port_write_msg.discard_count++; 42662306a36Sopenharmony_ci pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n", 42762306a36Sopenharmony_ci pw->port_write_msg.discard_count); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci /* Clear interrupt and issue Clear Queue command. This allows 43062306a36Sopenharmony_ci * another port-write to be received. 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_QFI); 43362306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwmr, ipwmr | RIO_IPWMR_CQ); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci schedule_work(&pw->pw_work); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) { 43962306a36Sopenharmony_ci pw->port_write_msg.err_count++; 44062306a36Sopenharmony_ci pr_debug("RIO: Port-Write Transaction Err (%d)\n", 44162306a36Sopenharmony_ci pw->port_write_msg.err_count); 44262306a36Sopenharmony_ci /* Clear Transaction Error: port-write controller should be 44362306a36Sopenharmony_ci * disabled when clearing this error 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE); 44662306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_TE); 44762306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwmr, ipwmr); 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (ipwsr & RIO_IPWSR_PWD) { 45162306a36Sopenharmony_ci pw->port_write_msg.discard_count++; 45262306a36Sopenharmony_ci pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n", 45362306a36Sopenharmony_ci pw->port_write_msg.discard_count); 45462306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_PWD); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cipw_done: 45862306a36Sopenharmony_ci if (epwisr & RIO_EPWISR_PINT1) { 45962306a36Sopenharmony_ci tmp = in_be32(rio_regs_win + RIO_LTLEDCSR); 46062306a36Sopenharmony_ci pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); 46162306a36Sopenharmony_ci fsl_rio_port_error_handler(0); 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (epwisr & RIO_EPWISR_PINT2) { 46562306a36Sopenharmony_ci tmp = in_be32(rio_regs_win + RIO_LTLEDCSR); 46662306a36Sopenharmony_ci pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); 46762306a36Sopenharmony_ci fsl_rio_port_error_handler(1); 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (epwisr & RIO_EPWISR_MU) { 47162306a36Sopenharmony_ci tmp = in_be32(rio_regs_win + RIO_LTLEDCSR); 47262306a36Sopenharmony_ci pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); 47362306a36Sopenharmony_ci msg_unit_error_handler(); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return IRQ_HANDLED; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic void fsl_pw_dpc(struct work_struct *work) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct fsl_rio_pw *pw = container_of(work, struct fsl_rio_pw, pw_work); 48262306a36Sopenharmony_ci union rio_pw_msg msg_buffer; 48362306a36Sopenharmony_ci int i; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* 48662306a36Sopenharmony_ci * Process port-write messages 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_ci while (kfifo_out_spinlocked(&pw->pw_fifo, (unsigned char *)&msg_buffer, 48962306a36Sopenharmony_ci RIO_PW_MSG_SIZE, &pw->pw_fifo_lock)) { 49062306a36Sopenharmony_ci#ifdef DEBUG_PW 49162306a36Sopenharmony_ci { 49262306a36Sopenharmony_ci u32 i; 49362306a36Sopenharmony_ci pr_debug("%s : Port-Write Message:", __func__); 49462306a36Sopenharmony_ci for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) { 49562306a36Sopenharmony_ci if ((i%4) == 0) 49662306a36Sopenharmony_ci pr_debug("\n0x%02x: 0x%08x", i*4, 49762306a36Sopenharmony_ci msg_buffer.raw[i]); 49862306a36Sopenharmony_ci else 49962306a36Sopenharmony_ci pr_debug(" 0x%08x", msg_buffer.raw[i]); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci pr_debug("\n"); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci#endif 50462306a36Sopenharmony_ci /* Pass the port-write message to RIO core for processing */ 50562306a36Sopenharmony_ci for (i = 0; i < MAX_PORT_NUM; i++) { 50662306a36Sopenharmony_ci if (pw->mport[i]) 50762306a36Sopenharmony_ci rio_inb_pwrite_handler(pw->mport[i], 50862306a36Sopenharmony_ci &msg_buffer); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci/** 51462306a36Sopenharmony_ci * fsl_rio_pw_enable - enable/disable port-write interface init 51562306a36Sopenharmony_ci * @mport: Master port implementing the port write unit 51662306a36Sopenharmony_ci * @enable: 1=enable; 0=disable port-write message handling 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_ciint fsl_rio_pw_enable(struct rio_mport *mport, int enable) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci u32 rval; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci rval = in_be32(&pw->pw_regs->pwmr); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (enable) 52562306a36Sopenharmony_ci rval |= RIO_IPWMR_PWE; 52662306a36Sopenharmony_ci else 52762306a36Sopenharmony_ci rval &= ~RIO_IPWMR_PWE; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwmr, rval); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/** 53562306a36Sopenharmony_ci * fsl_rio_port_write_init - MPC85xx port write interface init 53662306a36Sopenharmony_ci * @mport: Master port implementing the port write unit 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci * Initializes port write unit hardware and DMA buffer 53962306a36Sopenharmony_ci * ring. Called from fsl_rio_setup(). Returns %0 on success 54062306a36Sopenharmony_ci * or %-ENOMEM on failure. 54162306a36Sopenharmony_ci */ 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ciint fsl_rio_port_write_init(struct fsl_rio_pw *pw) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci int rc = 0; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Following configurations require a disabled port write controller */ 54862306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwmr, 54962306a36Sopenharmony_ci in_be32(&pw->pw_regs->pwmr) & ~RIO_IPWMR_PWE); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* Initialize port write */ 55262306a36Sopenharmony_ci pw->port_write_msg.virt = dma_alloc_coherent(pw->dev, 55362306a36Sopenharmony_ci RIO_PW_MSG_SIZE, 55462306a36Sopenharmony_ci &pw->port_write_msg.phys, GFP_KERNEL); 55562306a36Sopenharmony_ci if (!pw->port_write_msg.virt) { 55662306a36Sopenharmony_ci pr_err("RIO: unable allocate port write queue\n"); 55762306a36Sopenharmony_ci return -ENOMEM; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci pw->port_write_msg.err_count = 0; 56162306a36Sopenharmony_ci pw->port_write_msg.discard_count = 0; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* Point dequeue/enqueue pointers at first entry */ 56462306a36Sopenharmony_ci out_be32(&pw->pw_regs->epwqbar, 0); 56562306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwqbar, (u32) pw->port_write_msg.phys); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n", 56862306a36Sopenharmony_ci in_be32(&pw->pw_regs->epwqbar), 56962306a36Sopenharmony_ci in_be32(&pw->pw_regs->pwqbar)); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* Clear interrupt status IPWSR */ 57262306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwsr, 57362306a36Sopenharmony_ci (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD)); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Configure port write controller for snooping enable all reporting, 57662306a36Sopenharmony_ci clear queue full */ 57762306a36Sopenharmony_ci out_be32(&pw->pw_regs->pwmr, 57862306a36Sopenharmony_ci RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* Hook up port-write handler */ 58262306a36Sopenharmony_ci rc = request_irq(IRQ_RIO_PW(pw), fsl_rio_port_write_handler, 58362306a36Sopenharmony_ci IRQF_SHARED, "port-write", (void *)pw); 58462306a36Sopenharmony_ci if (rc < 0) { 58562306a36Sopenharmony_ci pr_err("MPC85xx RIO: unable to request inbound doorbell irq"); 58662306a36Sopenharmony_ci goto err_out; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci /* Enable Error Interrupt */ 58962306a36Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci INIT_WORK(&pw->pw_work, fsl_pw_dpc); 59262306a36Sopenharmony_ci spin_lock_init(&pw->pw_fifo_lock); 59362306a36Sopenharmony_ci if (kfifo_alloc(&pw->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) { 59462306a36Sopenharmony_ci pr_err("FIFO allocation failed\n"); 59562306a36Sopenharmony_ci rc = -ENOMEM; 59662306a36Sopenharmony_ci goto err_out_irq; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n", 60062306a36Sopenharmony_ci in_be32(&pw->pw_regs->pwmr), 60162306a36Sopenharmony_ci in_be32(&pw->pw_regs->pwsr)); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return rc; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cierr_out_irq: 60662306a36Sopenharmony_ci free_irq(IRQ_RIO_PW(pw), (void *)pw); 60762306a36Sopenharmony_cierr_out: 60862306a36Sopenharmony_ci dma_free_coherent(pw->dev, RIO_PW_MSG_SIZE, 60962306a36Sopenharmony_ci pw->port_write_msg.virt, 61062306a36Sopenharmony_ci pw->port_write_msg.phys); 61162306a36Sopenharmony_ci return rc; 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/** 61562306a36Sopenharmony_ci * fsl_rio_doorbell_send - Send a MPC85xx doorbell message 61662306a36Sopenharmony_ci * @mport: RapidIO master port info 61762306a36Sopenharmony_ci * @index: ID of RapidIO interface 61862306a36Sopenharmony_ci * @destid: Destination ID of target device 61962306a36Sopenharmony_ci * @data: 16-bit info field of RapidIO doorbell message 62062306a36Sopenharmony_ci * 62162306a36Sopenharmony_ci * Sends a MPC85xx doorbell message. Returns %0 on success or 62262306a36Sopenharmony_ci * %-EINVAL on failure. 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ciint fsl_rio_doorbell_send(struct rio_mport *mport, 62562306a36Sopenharmony_ci int index, u16 destid, u16 data) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci unsigned long flags; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n", 63062306a36Sopenharmony_ci index, destid, data); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci spin_lock_irqsave(&fsl_rio_doorbell_lock, flags); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* In the serial version silicons, such as MPC8548, MPC8641, 63562306a36Sopenharmony_ci * below operations is must be. 63662306a36Sopenharmony_ci */ 63762306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->odmr, 0x00000000); 63862306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->odretcr, 0x00000004); 63962306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->oddpr, destid << 16); 64062306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->oddatr, (index << 20) | data); 64162306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->odmr, 0x00000001); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci spin_unlock_irqrestore(&fsl_rio_doorbell_lock, flags); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci return 0; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci/** 64962306a36Sopenharmony_ci * fsl_add_outb_message - Add message to the MPC85xx outbound message queue 65062306a36Sopenharmony_ci * @mport: Master port with outbound message queue 65162306a36Sopenharmony_ci * @rdev: Target of outbound message 65262306a36Sopenharmony_ci * @mbox: Outbound mailbox 65362306a36Sopenharmony_ci * @buffer: Message to add to outbound queue 65462306a36Sopenharmony_ci * @len: Length of message 65562306a36Sopenharmony_ci * 65662306a36Sopenharmony_ci * Adds the @buffer message to the MPC85xx outbound message queue. Returns 65762306a36Sopenharmony_ci * %0 on success or %-EINVAL on failure. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_ciint 66062306a36Sopenharmony_cifsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, 66162306a36Sopenharmony_ci void *buffer, size_t len) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); 66462306a36Sopenharmony_ci u32 omr; 66562306a36Sopenharmony_ci struct rio_tx_desc *desc = (struct rio_tx_desc *)rmu->msg_tx_ring.virt 66662306a36Sopenharmony_ci + rmu->msg_tx_ring.tx_slot; 66762306a36Sopenharmony_ci int ret = 0; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \ 67062306a36Sopenharmony_ci "%p len %8.8zx\n", rdev->destid, mbox, buffer, len); 67162306a36Sopenharmony_ci if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { 67262306a36Sopenharmony_ci ret = -EINVAL; 67362306a36Sopenharmony_ci goto out; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* Copy and clear rest of buffer */ 67762306a36Sopenharmony_ci memcpy(rmu->msg_tx_ring.virt_buffer[rmu->msg_tx_ring.tx_slot], buffer, 67862306a36Sopenharmony_ci len); 67962306a36Sopenharmony_ci if (len < (RIO_MAX_MSG_SIZE - 4)) 68062306a36Sopenharmony_ci memset(rmu->msg_tx_ring.virt_buffer[rmu->msg_tx_ring.tx_slot] 68162306a36Sopenharmony_ci + len, 0, RIO_MAX_MSG_SIZE - len); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* Set mbox field for message, and set destid */ 68462306a36Sopenharmony_ci desc->dport = (rdev->destid << 16) | (mbox & 0x3); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Enable EOMI interrupt and priority */ 68762306a36Sopenharmony_ci desc->dattr = 0x28000000 | ((mport->index) << 20); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* Set transfer size aligned to next power of 2 (in double words) */ 69062306a36Sopenharmony_ci desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* Set snooping and source buffer address */ 69362306a36Sopenharmony_ci desc->saddr = 0x00000004 69462306a36Sopenharmony_ci | rmu->msg_tx_ring.phys_buffer[rmu->msg_tx_ring.tx_slot]; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* Increment enqueue pointer */ 69762306a36Sopenharmony_ci omr = in_be32(&rmu->msg_regs->omr); 69862306a36Sopenharmony_ci out_be32(&rmu->msg_regs->omr, omr | RIO_MSG_OMR_MUI); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* Go to next descriptor */ 70162306a36Sopenharmony_ci if (++rmu->msg_tx_ring.tx_slot == rmu->msg_tx_ring.size) 70262306a36Sopenharmony_ci rmu->msg_tx_ring.tx_slot = 0; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ciout: 70562306a36Sopenharmony_ci return ret; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci/** 70962306a36Sopenharmony_ci * fsl_open_outb_mbox - Initialize MPC85xx outbound mailbox 71062306a36Sopenharmony_ci * @mport: Master port implementing the outbound message unit 71162306a36Sopenharmony_ci * @dev_id: Device specific pointer to pass on event 71262306a36Sopenharmony_ci * @mbox: Mailbox to open 71362306a36Sopenharmony_ci * @entries: Number of entries in the outbound mailbox ring 71462306a36Sopenharmony_ci * 71562306a36Sopenharmony_ci * Initializes buffer ring, request the outbound message interrupt, 71662306a36Sopenharmony_ci * and enables the outbound message unit. Returns %0 on success and 71762306a36Sopenharmony_ci * %-EINVAL or %-ENOMEM on failure. 71862306a36Sopenharmony_ci */ 71962306a36Sopenharmony_ciint 72062306a36Sopenharmony_cifsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci int i, j, rc = 0; 72362306a36Sopenharmony_ci struct rio_priv *priv = mport->priv; 72462306a36Sopenharmony_ci struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if ((entries < RIO_MIN_TX_RING_SIZE) || 72762306a36Sopenharmony_ci (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) { 72862306a36Sopenharmony_ci rc = -EINVAL; 72962306a36Sopenharmony_ci goto out; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* Initialize shadow copy ring */ 73362306a36Sopenharmony_ci rmu->msg_tx_ring.dev_id = dev_id; 73462306a36Sopenharmony_ci rmu->msg_tx_ring.size = entries; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci for (i = 0; i < rmu->msg_tx_ring.size; i++) { 73762306a36Sopenharmony_ci rmu->msg_tx_ring.virt_buffer[i] = 73862306a36Sopenharmony_ci dma_alloc_coherent(priv->dev, RIO_MSG_BUFFER_SIZE, 73962306a36Sopenharmony_ci &rmu->msg_tx_ring.phys_buffer[i], GFP_KERNEL); 74062306a36Sopenharmony_ci if (!rmu->msg_tx_ring.virt_buffer[i]) { 74162306a36Sopenharmony_ci rc = -ENOMEM; 74262306a36Sopenharmony_ci for (j = 0; j < rmu->msg_tx_ring.size; j++) 74362306a36Sopenharmony_ci if (rmu->msg_tx_ring.virt_buffer[j]) 74462306a36Sopenharmony_ci dma_free_coherent(priv->dev, 74562306a36Sopenharmony_ci RIO_MSG_BUFFER_SIZE, 74662306a36Sopenharmony_ci rmu->msg_tx_ring. 74762306a36Sopenharmony_ci virt_buffer[j], 74862306a36Sopenharmony_ci rmu->msg_tx_ring. 74962306a36Sopenharmony_ci phys_buffer[j]); 75062306a36Sopenharmony_ci goto out; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* Initialize outbound message descriptor ring */ 75562306a36Sopenharmony_ci rmu->msg_tx_ring.virt = dma_alloc_coherent(priv->dev, 75662306a36Sopenharmony_ci rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE, 75762306a36Sopenharmony_ci &rmu->msg_tx_ring.phys, 75862306a36Sopenharmony_ci GFP_KERNEL); 75962306a36Sopenharmony_ci if (!rmu->msg_tx_ring.virt) { 76062306a36Sopenharmony_ci rc = -ENOMEM; 76162306a36Sopenharmony_ci goto out_dma; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci rmu->msg_tx_ring.tx_slot = 0; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* Point dequeue/enqueue pointers at first entry in ring */ 76662306a36Sopenharmony_ci out_be32(&rmu->msg_regs->odqdpar, rmu->msg_tx_ring.phys); 76762306a36Sopenharmony_ci out_be32(&rmu->msg_regs->odqepar, rmu->msg_tx_ring.phys); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* Configure for snooping */ 77062306a36Sopenharmony_ci out_be32(&rmu->msg_regs->osar, 0x00000004); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* Clear interrupt status */ 77362306a36Sopenharmony_ci out_be32(&rmu->msg_regs->osr, 0x000000b3); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* Hook up outbound message handler */ 77662306a36Sopenharmony_ci rc = request_irq(IRQ_RIO_TX(mport), fsl_rio_tx_handler, 0, 77762306a36Sopenharmony_ci "msg_tx", (void *)mport); 77862306a36Sopenharmony_ci if (rc < 0) 77962306a36Sopenharmony_ci goto out_irq; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci /* 78262306a36Sopenharmony_ci * Configure outbound message unit 78362306a36Sopenharmony_ci * Snooping 78462306a36Sopenharmony_ci * Interrupts (all enabled, except QEIE) 78562306a36Sopenharmony_ci * Chaining mode 78662306a36Sopenharmony_ci * Disable 78762306a36Sopenharmony_ci */ 78862306a36Sopenharmony_ci out_be32(&rmu->msg_regs->omr, 0x00100220); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* Set number of entries */ 79162306a36Sopenharmony_ci out_be32(&rmu->msg_regs->omr, 79262306a36Sopenharmony_ci in_be32(&rmu->msg_regs->omr) | 79362306a36Sopenharmony_ci ((get_bitmask_order(entries) - 2) << 12)); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci /* Now enable the unit */ 79662306a36Sopenharmony_ci out_be32(&rmu->msg_regs->omr, in_be32(&rmu->msg_regs->omr) | 0x1); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ciout: 79962306a36Sopenharmony_ci return rc; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ciout_irq: 80262306a36Sopenharmony_ci dma_free_coherent(priv->dev, 80362306a36Sopenharmony_ci rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE, 80462306a36Sopenharmony_ci rmu->msg_tx_ring.virt, rmu->msg_tx_ring.phys); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ciout_dma: 80762306a36Sopenharmony_ci for (i = 0; i < rmu->msg_tx_ring.size; i++) 80862306a36Sopenharmony_ci dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE, 80962306a36Sopenharmony_ci rmu->msg_tx_ring.virt_buffer[i], 81062306a36Sopenharmony_ci rmu->msg_tx_ring.phys_buffer[i]); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return rc; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci/** 81662306a36Sopenharmony_ci * fsl_close_outb_mbox - Shut down MPC85xx outbound mailbox 81762306a36Sopenharmony_ci * @mport: Master port implementing the outbound message unit 81862306a36Sopenharmony_ci * @mbox: Mailbox to close 81962306a36Sopenharmony_ci * 82062306a36Sopenharmony_ci * Disables the outbound message unit, free all buffers, and 82162306a36Sopenharmony_ci * frees the outbound message interrupt. 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_civoid fsl_close_outb_mbox(struct rio_mport *mport, int mbox) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct rio_priv *priv = mport->priv; 82662306a36Sopenharmony_ci struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* Disable inbound message unit */ 82962306a36Sopenharmony_ci out_be32(&rmu->msg_regs->omr, 0); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* Free ring */ 83262306a36Sopenharmony_ci dma_free_coherent(priv->dev, 83362306a36Sopenharmony_ci rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE, 83462306a36Sopenharmony_ci rmu->msg_tx_ring.virt, rmu->msg_tx_ring.phys); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Free interrupt */ 83762306a36Sopenharmony_ci free_irq(IRQ_RIO_TX(mport), (void *)mport); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci/** 84162306a36Sopenharmony_ci * fsl_open_inb_mbox - Initialize MPC85xx inbound mailbox 84262306a36Sopenharmony_ci * @mport: Master port implementing the inbound message unit 84362306a36Sopenharmony_ci * @dev_id: Device specific pointer to pass on event 84462306a36Sopenharmony_ci * @mbox: Mailbox to open 84562306a36Sopenharmony_ci * @entries: Number of entries in the inbound mailbox ring 84662306a36Sopenharmony_ci * 84762306a36Sopenharmony_ci * Initializes buffer ring, request the inbound message interrupt, 84862306a36Sopenharmony_ci * and enables the inbound message unit. Returns %0 on success 84962306a36Sopenharmony_ci * and %-EINVAL or %-ENOMEM on failure. 85062306a36Sopenharmony_ci */ 85162306a36Sopenharmony_ciint 85262306a36Sopenharmony_cifsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci int i, rc = 0; 85562306a36Sopenharmony_ci struct rio_priv *priv = mport->priv; 85662306a36Sopenharmony_ci struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci if ((entries < RIO_MIN_RX_RING_SIZE) || 85962306a36Sopenharmony_ci (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) { 86062306a36Sopenharmony_ci rc = -EINVAL; 86162306a36Sopenharmony_ci goto out; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* Initialize client buffer ring */ 86562306a36Sopenharmony_ci rmu->msg_rx_ring.dev_id = dev_id; 86662306a36Sopenharmony_ci rmu->msg_rx_ring.size = entries; 86762306a36Sopenharmony_ci rmu->msg_rx_ring.rx_slot = 0; 86862306a36Sopenharmony_ci for (i = 0; i < rmu->msg_rx_ring.size; i++) 86962306a36Sopenharmony_ci rmu->msg_rx_ring.virt_buffer[i] = NULL; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* Initialize inbound message ring */ 87262306a36Sopenharmony_ci rmu->msg_rx_ring.virt = dma_alloc_coherent(priv->dev, 87362306a36Sopenharmony_ci rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE, 87462306a36Sopenharmony_ci &rmu->msg_rx_ring.phys, GFP_KERNEL); 87562306a36Sopenharmony_ci if (!rmu->msg_rx_ring.virt) { 87662306a36Sopenharmony_ci rc = -ENOMEM; 87762306a36Sopenharmony_ci goto out; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* Point dequeue/enqueue pointers at first entry in ring */ 88162306a36Sopenharmony_ci out_be32(&rmu->msg_regs->ifqdpar, (u32) rmu->msg_rx_ring.phys); 88262306a36Sopenharmony_ci out_be32(&rmu->msg_regs->ifqepar, (u32) rmu->msg_rx_ring.phys); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* Clear interrupt status */ 88562306a36Sopenharmony_ci out_be32(&rmu->msg_regs->isr, 0x00000091); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* Hook up inbound message handler */ 88862306a36Sopenharmony_ci rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0, 88962306a36Sopenharmony_ci "msg_rx", (void *)mport); 89062306a36Sopenharmony_ci if (rc < 0) { 89162306a36Sopenharmony_ci dma_free_coherent(priv->dev, 89262306a36Sopenharmony_ci rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE, 89362306a36Sopenharmony_ci rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys); 89462306a36Sopenharmony_ci goto out; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* 89862306a36Sopenharmony_ci * Configure inbound message unit: 89962306a36Sopenharmony_ci * Snooping 90062306a36Sopenharmony_ci * 4KB max message size 90162306a36Sopenharmony_ci * Unmask all interrupt sources 90262306a36Sopenharmony_ci * Disable 90362306a36Sopenharmony_ci */ 90462306a36Sopenharmony_ci out_be32(&rmu->msg_regs->imr, 0x001b0060); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci /* Set number of queue entries */ 90762306a36Sopenharmony_ci setbits32(&rmu->msg_regs->imr, (get_bitmask_order(entries) - 2) << 12); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci /* Now enable the unit */ 91062306a36Sopenharmony_ci setbits32(&rmu->msg_regs->imr, 0x1); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ciout: 91362306a36Sopenharmony_ci return rc; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci/** 91762306a36Sopenharmony_ci * fsl_close_inb_mbox - Shut down MPC85xx inbound mailbox 91862306a36Sopenharmony_ci * @mport: Master port implementing the inbound message unit 91962306a36Sopenharmony_ci * @mbox: Mailbox to close 92062306a36Sopenharmony_ci * 92162306a36Sopenharmony_ci * Disables the inbound message unit, free all buffers, and 92262306a36Sopenharmony_ci * frees the inbound message interrupt. 92362306a36Sopenharmony_ci */ 92462306a36Sopenharmony_civoid fsl_close_inb_mbox(struct rio_mport *mport, int mbox) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci struct rio_priv *priv = mport->priv; 92762306a36Sopenharmony_ci struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* Disable inbound message unit */ 93062306a36Sopenharmony_ci out_be32(&rmu->msg_regs->imr, 0); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci /* Free ring */ 93362306a36Sopenharmony_ci dma_free_coherent(priv->dev, rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE, 93462306a36Sopenharmony_ci rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Free interrupt */ 93762306a36Sopenharmony_ci free_irq(IRQ_RIO_RX(mport), (void *)mport); 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci/** 94162306a36Sopenharmony_ci * fsl_add_inb_buffer - Add buffer to the MPC85xx inbound message queue 94262306a36Sopenharmony_ci * @mport: Master port implementing the inbound message unit 94362306a36Sopenharmony_ci * @mbox: Inbound mailbox number 94462306a36Sopenharmony_ci * @buf: Buffer to add to inbound queue 94562306a36Sopenharmony_ci * 94662306a36Sopenharmony_ci * Adds the @buf buffer to the MPC85xx inbound message queue. Returns 94762306a36Sopenharmony_ci * %0 on success or %-EINVAL on failure. 94862306a36Sopenharmony_ci */ 94962306a36Sopenharmony_ciint fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci int rc = 0; 95262306a36Sopenharmony_ci struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci pr_debug("RIO: fsl_add_inb_buffer(), msg_rx_ring.rx_slot %d\n", 95562306a36Sopenharmony_ci rmu->msg_rx_ring.rx_slot); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (rmu->msg_rx_ring.virt_buffer[rmu->msg_rx_ring.rx_slot]) { 95862306a36Sopenharmony_ci printk(KERN_ERR 95962306a36Sopenharmony_ci "RIO: error adding inbound buffer %d, buffer exists\n", 96062306a36Sopenharmony_ci rmu->msg_rx_ring.rx_slot); 96162306a36Sopenharmony_ci rc = -EINVAL; 96262306a36Sopenharmony_ci goto out; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci rmu->msg_rx_ring.virt_buffer[rmu->msg_rx_ring.rx_slot] = buf; 96662306a36Sopenharmony_ci if (++rmu->msg_rx_ring.rx_slot == rmu->msg_rx_ring.size) 96762306a36Sopenharmony_ci rmu->msg_rx_ring.rx_slot = 0; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ciout: 97062306a36Sopenharmony_ci return rc; 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci/** 97462306a36Sopenharmony_ci * fsl_get_inb_message - Fetch inbound message from the MPC85xx message unit 97562306a36Sopenharmony_ci * @mport: Master port implementing the inbound message unit 97662306a36Sopenharmony_ci * @mbox: Inbound mailbox number 97762306a36Sopenharmony_ci * 97862306a36Sopenharmony_ci * Gets the next available inbound message from the inbound message queue. 97962306a36Sopenharmony_ci * A pointer to the message is returned on success or NULL on failure. 98062306a36Sopenharmony_ci */ 98162306a36Sopenharmony_civoid *fsl_get_inb_message(struct rio_mport *mport, int mbox) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); 98462306a36Sopenharmony_ci u32 phys_buf; 98562306a36Sopenharmony_ci void *virt_buf; 98662306a36Sopenharmony_ci void *buf = NULL; 98762306a36Sopenharmony_ci int buf_idx; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci phys_buf = in_be32(&rmu->msg_regs->ifqdpar); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci /* If no more messages, then bail out */ 99262306a36Sopenharmony_ci if (phys_buf == in_be32(&rmu->msg_regs->ifqepar)) 99362306a36Sopenharmony_ci goto out2; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci virt_buf = rmu->msg_rx_ring.virt + (phys_buf 99662306a36Sopenharmony_ci - rmu->msg_rx_ring.phys); 99762306a36Sopenharmony_ci buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; 99862306a36Sopenharmony_ci buf = rmu->msg_rx_ring.virt_buffer[buf_idx]; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (!buf) { 100162306a36Sopenharmony_ci printk(KERN_ERR 100262306a36Sopenharmony_ci "RIO: inbound message copy failed, no buffers\n"); 100362306a36Sopenharmony_ci goto out1; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci /* Copy max message size, caller is expected to allocate that big */ 100762306a36Sopenharmony_ci memcpy(buf, virt_buf, RIO_MAX_MSG_SIZE); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* Clear the available buffer */ 101062306a36Sopenharmony_ci rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ciout1: 101362306a36Sopenharmony_ci setbits32(&rmu->msg_regs->imr, RIO_MSG_IMR_MI); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ciout2: 101662306a36Sopenharmony_ci return buf; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci/** 102062306a36Sopenharmony_ci * fsl_rio_doorbell_init - MPC85xx doorbell interface init 102162306a36Sopenharmony_ci * @mport: Master port implementing the inbound doorbell unit 102262306a36Sopenharmony_ci * 102362306a36Sopenharmony_ci * Initializes doorbell unit hardware and inbound DMA buffer 102462306a36Sopenharmony_ci * ring. Called from fsl_rio_setup(). Returns %0 on success 102562306a36Sopenharmony_ci * or %-ENOMEM on failure. 102662306a36Sopenharmony_ci */ 102762306a36Sopenharmony_ciint fsl_rio_doorbell_init(struct fsl_rio_dbell *dbell) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci int rc = 0; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci /* Initialize inbound doorbells */ 103262306a36Sopenharmony_ci dbell->dbell_ring.virt = dma_alloc_coherent(dbell->dev, 512 * 103362306a36Sopenharmony_ci DOORBELL_MESSAGE_SIZE, &dbell->dbell_ring.phys, GFP_KERNEL); 103462306a36Sopenharmony_ci if (!dbell->dbell_ring.virt) { 103562306a36Sopenharmony_ci printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n"); 103662306a36Sopenharmony_ci rc = -ENOMEM; 103762306a36Sopenharmony_ci goto out; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* Point dequeue/enqueue pointers at first entry in ring */ 104162306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->dqdpar, (u32) dbell->dbell_ring.phys); 104262306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->dqepar, (u32) dbell->dbell_ring.phys); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* Clear interrupt status */ 104562306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->dsr, 0x00000091); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci /* Hook up doorbell handler */ 104862306a36Sopenharmony_ci rc = request_irq(IRQ_RIO_BELL(dbell), fsl_rio_dbell_handler, 0, 104962306a36Sopenharmony_ci "dbell_rx", (void *)dbell); 105062306a36Sopenharmony_ci if (rc < 0) { 105162306a36Sopenharmony_ci dma_free_coherent(dbell->dev, 512 * DOORBELL_MESSAGE_SIZE, 105262306a36Sopenharmony_ci dbell->dbell_ring.virt, dbell->dbell_ring.phys); 105362306a36Sopenharmony_ci printk(KERN_ERR 105462306a36Sopenharmony_ci "MPC85xx RIO: unable to request inbound doorbell irq"); 105562306a36Sopenharmony_ci goto out; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* Configure doorbells for snooping, 512 entries, and enable */ 105962306a36Sopenharmony_ci out_be32(&dbell->dbell_regs->dmr, 0x00108161); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ciout: 106262306a36Sopenharmony_ci return rc; 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ciint fsl_rio_setup_rmu(struct rio_mport *mport, struct device_node *node) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci struct rio_priv *priv; 106862306a36Sopenharmony_ci struct fsl_rmu *rmu; 106962306a36Sopenharmony_ci u64 msg_start; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci if (!mport || !mport->priv) 107262306a36Sopenharmony_ci return -EINVAL; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci priv = mport->priv; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (!node) { 107762306a36Sopenharmony_ci dev_warn(priv->dev, "Can't get %pOF property 'fsl,rmu'\n", 107862306a36Sopenharmony_ci priv->dev->of_node); 107962306a36Sopenharmony_ci return -EINVAL; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci rmu = kzalloc(sizeof(struct fsl_rmu), GFP_KERNEL); 108362306a36Sopenharmony_ci if (!rmu) 108462306a36Sopenharmony_ci return -ENOMEM; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (of_property_read_reg(node, 0, &msg_start, NULL)) { 108762306a36Sopenharmony_ci pr_err("%pOF: unable to find 'reg' property of message-unit\n", 108862306a36Sopenharmony_ci node); 108962306a36Sopenharmony_ci kfree(rmu); 109062306a36Sopenharmony_ci return -ENOMEM; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci rmu->msg_regs = (struct rio_msg_regs *) 109362306a36Sopenharmony_ci (rmu_regs_win + (u32)msg_start); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci rmu->txirq = irq_of_parse_and_map(node, 0); 109662306a36Sopenharmony_ci rmu->rxirq = irq_of_parse_and_map(node, 1); 109762306a36Sopenharmony_ci printk(KERN_INFO "%pOF: txirq: %d, rxirq %d\n", 109862306a36Sopenharmony_ci node, rmu->txirq, rmu->rxirq); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci priv->rmm_handle = rmu; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); 110362306a36Sopenharmony_ci rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 0); 110462306a36Sopenharmony_ci rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci return 0; 110762306a36Sopenharmony_ci} 1108