162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Freescale MPC85xx/MPC86xx RapidIO 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 * 1762306a36Sopenharmony_ci * Copyright 2005 MontaVista Software, Inc. 1862306a36Sopenharmony_ci * Matt Porter <mporter@kernel.crashing.org> 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/extable.h> 2362306a36Sopenharmony_ci#include <linux/types.h> 2462306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2562306a36Sopenharmony_ci#include <linux/interrupt.h> 2662306a36Sopenharmony_ci#include <linux/of.h> 2762306a36Sopenharmony_ci#include <linux/of_address.h> 2862306a36Sopenharmony_ci#include <linux/of_irq.h> 2962306a36Sopenharmony_ci#include <linux/platform_device.h> 3062306a36Sopenharmony_ci#include <linux/delay.h> 3162306a36Sopenharmony_ci#include <linux/slab.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/io.h> 3462306a36Sopenharmony_ci#include <linux/uaccess.h> 3562306a36Sopenharmony_ci#include <asm/machdep.h> 3662306a36Sopenharmony_ci#include <asm/rio.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "fsl_rio.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#undef DEBUG_PW /* Port-Write debugging */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define RIO_PORT1_EDCSR 0x0640 4362306a36Sopenharmony_ci#define RIO_PORT2_EDCSR 0x0680 4462306a36Sopenharmony_ci#define RIO_PORT1_IECSR 0x10130 4562306a36Sopenharmony_ci#define RIO_PORT2_IECSR 0x101B0 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define RIO_GCCSR 0x13c 4862306a36Sopenharmony_ci#define RIO_ESCSR 0x158 4962306a36Sopenharmony_ci#define ESCSR_CLEAR 0x07120204 5062306a36Sopenharmony_ci#define RIO_PORT2_ESCSR 0x178 5162306a36Sopenharmony_ci#define RIO_CCSR 0x15c 5262306a36Sopenharmony_ci#define RIO_LTLEDCSR_IER 0x80000000 5362306a36Sopenharmony_ci#define RIO_LTLEDCSR_PRT 0x01000000 5462306a36Sopenharmony_ci#define IECSR_CLEAR 0x80000000 5562306a36Sopenharmony_ci#define RIO_ISR_AACR 0x10120 5662306a36Sopenharmony_ci#define RIO_ISR_AACR_AA 0x1 /* Accept All ID */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define RIWTAR_TRAD_VAL_SHIFT 12 5962306a36Sopenharmony_ci#define RIWTAR_TRAD_MASK 0x00FFFFFF 6062306a36Sopenharmony_ci#define RIWBAR_BADD_VAL_SHIFT 12 6162306a36Sopenharmony_ci#define RIWBAR_BADD_MASK 0x003FFFFF 6262306a36Sopenharmony_ci#define RIWAR_ENABLE 0x80000000 6362306a36Sopenharmony_ci#define RIWAR_TGINT_LOCAL 0x00F00000 6462306a36Sopenharmony_ci#define RIWAR_RDTYP_NO_SNOOP 0x00040000 6562306a36Sopenharmony_ci#define RIWAR_RDTYP_SNOOP 0x00050000 6662306a36Sopenharmony_ci#define RIWAR_WRTYP_NO_SNOOP 0x00004000 6762306a36Sopenharmony_ci#define RIWAR_WRTYP_SNOOP 0x00005000 6862306a36Sopenharmony_ci#define RIWAR_WRTYP_ALLOC 0x00006000 6962306a36Sopenharmony_ci#define RIWAR_SIZE_MASK 0x0000003F 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic DEFINE_SPINLOCK(fsl_rio_config_lock); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define ___fsl_read_rio_config(x, addr, err, op, barrier) \ 7462306a36Sopenharmony_ci __asm__ __volatile__( \ 7562306a36Sopenharmony_ci "1: "op" %1,0(%2)\n" \ 7662306a36Sopenharmony_ci " "barrier"\n" \ 7762306a36Sopenharmony_ci "2:\n" \ 7862306a36Sopenharmony_ci ".section .fixup,\"ax\"\n" \ 7962306a36Sopenharmony_ci "3: li %1,-1\n" \ 8062306a36Sopenharmony_ci " li %0,%3\n" \ 8162306a36Sopenharmony_ci " b 2b\n" \ 8262306a36Sopenharmony_ci ".previous\n" \ 8362306a36Sopenharmony_ci EX_TABLE(1b, 3b) \ 8462306a36Sopenharmony_ci : "=r" (err), "=r" (x) \ 8562306a36Sopenharmony_ci : "b" (addr), "i" (-EFAULT), "0" (err)) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#ifdef CONFIG_BOOKE 8862306a36Sopenharmony_ci#define __fsl_read_rio_config(x, addr, err, op) \ 8962306a36Sopenharmony_ci ___fsl_read_rio_config(x, addr, err, op, "mbar") 9062306a36Sopenharmony_ci#else 9162306a36Sopenharmony_ci#define __fsl_read_rio_config(x, addr, err, op) \ 9262306a36Sopenharmony_ci ___fsl_read_rio_config(x, addr, err, op, "eieio") 9362306a36Sopenharmony_ci#endif 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_civoid __iomem *rio_regs_win; 9662306a36Sopenharmony_civoid __iomem *rmu_regs_win; 9762306a36Sopenharmony_ciresource_size_t rio_law_start; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistruct fsl_rio_dbell *dbell; 10062306a36Sopenharmony_cistruct fsl_rio_pw *pw; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci#ifdef CONFIG_PPC_E500 10362306a36Sopenharmony_ciint fsl_rio_mcheck_exception(struct pt_regs *regs) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci const struct exception_table_entry *entry; 10662306a36Sopenharmony_ci unsigned long reason; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (!rio_regs_win) 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR)); 11262306a36Sopenharmony_ci if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) { 11362306a36Sopenharmony_ci /* Check if we are prepared to handle this fault */ 11462306a36Sopenharmony_ci entry = search_exception_tables(regs->nip); 11562306a36Sopenharmony_ci if (entry) { 11662306a36Sopenharmony_ci pr_debug("RIO: %s - MC Exception handled\n", 11762306a36Sopenharmony_ci __func__); 11862306a36Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 11962306a36Sopenharmony_ci 0); 12062306a36Sopenharmony_ci regs_set_recoverable(regs); 12162306a36Sopenharmony_ci regs_set_return_ip(regs, extable_fixup(entry)); 12262306a36Sopenharmony_ci return 1; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return 0; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception); 12962306a36Sopenharmony_ci#endif 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/** 13262306a36Sopenharmony_ci * fsl_local_config_read - Generate a MPC85xx local config space read 13362306a36Sopenharmony_ci * @mport: RapidIO master port info 13462306a36Sopenharmony_ci * @index: ID of RapdiIO interface 13562306a36Sopenharmony_ci * @offset: Offset into configuration space 13662306a36Sopenharmony_ci * @len: Length (in bytes) of the maintenance transaction 13762306a36Sopenharmony_ci * @data: Value to be read into 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * Generates a MPC85xx local configuration space read. Returns %0 on 14062306a36Sopenharmony_ci * success or %-EINVAL on failure. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_cistatic int fsl_local_config_read(struct rio_mport *mport, 14362306a36Sopenharmony_ci int index, u32 offset, int len, u32 *data) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct rio_priv *priv = mport->priv; 14662306a36Sopenharmony_ci pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index, 14762306a36Sopenharmony_ci offset); 14862306a36Sopenharmony_ci *data = in_be32(priv->regs_win + offset); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/** 15462306a36Sopenharmony_ci * fsl_local_config_write - Generate a MPC85xx local config space write 15562306a36Sopenharmony_ci * @mport: RapidIO master port info 15662306a36Sopenharmony_ci * @index: ID of RapdiIO interface 15762306a36Sopenharmony_ci * @offset: Offset into configuration space 15862306a36Sopenharmony_ci * @len: Length (in bytes) of the maintenance transaction 15962306a36Sopenharmony_ci * @data: Value to be written 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * Generates a MPC85xx local configuration space write. Returns %0 on 16262306a36Sopenharmony_ci * success or %-EINVAL on failure. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_cistatic int fsl_local_config_write(struct rio_mport *mport, 16562306a36Sopenharmony_ci int index, u32 offset, int len, u32 data) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct rio_priv *priv = mport->priv; 16862306a36Sopenharmony_ci pr_debug 16962306a36Sopenharmony_ci ("fsl_local_config_write: index %d offset %8.8x data %8.8x\n", 17062306a36Sopenharmony_ci index, offset, data); 17162306a36Sopenharmony_ci out_be32(priv->regs_win + offset, data); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/** 17762306a36Sopenharmony_ci * fsl_rio_config_read - Generate a MPC85xx read maintenance transaction 17862306a36Sopenharmony_ci * @mport: RapidIO master port info 17962306a36Sopenharmony_ci * @index: ID of RapdiIO interface 18062306a36Sopenharmony_ci * @destid: Destination ID of transaction 18162306a36Sopenharmony_ci * @hopcount: Number of hops to target device 18262306a36Sopenharmony_ci * @offset: Offset into configuration space 18362306a36Sopenharmony_ci * @len: Length (in bytes) of the maintenance transaction 18462306a36Sopenharmony_ci * @val: Location to be read into 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * Generates a MPC85xx read maintenance transaction. Returns %0 on 18762306a36Sopenharmony_ci * success or %-EINVAL on failure. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_cistatic int 19062306a36Sopenharmony_cifsl_rio_config_read(struct rio_mport *mport, int index, u16 destid, 19162306a36Sopenharmony_ci u8 hopcount, u32 offset, int len, u32 *val) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct rio_priv *priv = mport->priv; 19462306a36Sopenharmony_ci unsigned long flags; 19562306a36Sopenharmony_ci u8 *data; 19662306a36Sopenharmony_ci u32 rval, err = 0; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci pr_debug 19962306a36Sopenharmony_ci ("fsl_rio_config_read:" 20062306a36Sopenharmony_ci " index %d destid %d hopcount %d offset %8.8x len %d\n", 20162306a36Sopenharmony_ci index, destid, hopcount, offset, len); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* 16MB maintenance window possible */ 20462306a36Sopenharmony_ci /* allow only aligned access to maintenance registers */ 20562306a36Sopenharmony_ci if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) 20662306a36Sopenharmony_ci return -EINVAL; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci spin_lock_irqsave(&fsl_rio_config_lock, flags); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowtar, 21162306a36Sopenharmony_ci (destid << 22) | (hopcount << 12) | (offset >> 12)); 21262306a36Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); 21562306a36Sopenharmony_ci switch (len) { 21662306a36Sopenharmony_ci case 1: 21762306a36Sopenharmony_ci __fsl_read_rio_config(rval, data, err, "lbz"); 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci case 2: 22062306a36Sopenharmony_ci __fsl_read_rio_config(rval, data, err, "lhz"); 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci case 4: 22362306a36Sopenharmony_ci __fsl_read_rio_config(rval, data, err, "lwz"); 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci default: 22662306a36Sopenharmony_ci spin_unlock_irqrestore(&fsl_rio_config_lock, flags); 22762306a36Sopenharmony_ci return -EINVAL; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (err) { 23162306a36Sopenharmony_ci pr_debug("RIO: cfg_read error %d for %x:%x:%x\n", 23262306a36Sopenharmony_ci err, destid, hopcount, offset); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci spin_unlock_irqrestore(&fsl_rio_config_lock, flags); 23662306a36Sopenharmony_ci *val = rval; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return err; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/** 24262306a36Sopenharmony_ci * fsl_rio_config_write - Generate a MPC85xx write maintenance transaction 24362306a36Sopenharmony_ci * @mport: RapidIO master port info 24462306a36Sopenharmony_ci * @index: ID of RapdiIO interface 24562306a36Sopenharmony_ci * @destid: Destination ID of transaction 24662306a36Sopenharmony_ci * @hopcount: Number of hops to target device 24762306a36Sopenharmony_ci * @offset: Offset into configuration space 24862306a36Sopenharmony_ci * @len: Length (in bytes) of the maintenance transaction 24962306a36Sopenharmony_ci * @val: Value to be written 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * Generates an MPC85xx write maintenance transaction. Returns %0 on 25262306a36Sopenharmony_ci * success or %-EINVAL on failure. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_cistatic int 25562306a36Sopenharmony_cifsl_rio_config_write(struct rio_mport *mport, int index, u16 destid, 25662306a36Sopenharmony_ci u8 hopcount, u32 offset, int len, u32 val) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct rio_priv *priv = mport->priv; 25962306a36Sopenharmony_ci unsigned long flags; 26062306a36Sopenharmony_ci u8 *data; 26162306a36Sopenharmony_ci int ret = 0; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci pr_debug 26462306a36Sopenharmony_ci ("fsl_rio_config_write:" 26562306a36Sopenharmony_ci " index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", 26662306a36Sopenharmony_ci index, destid, hopcount, offset, len, val); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* 16MB maintenance windows possible */ 26962306a36Sopenharmony_ci /* allow only aligned access to maintenance registers */ 27062306a36Sopenharmony_ci if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) 27162306a36Sopenharmony_ci return -EINVAL; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci spin_lock_irqsave(&fsl_rio_config_lock, flags); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowtar, 27662306a36Sopenharmony_ci (destid << 22) | (hopcount << 12) | (offset >> 12)); 27762306a36Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); 28062306a36Sopenharmony_ci switch (len) { 28162306a36Sopenharmony_ci case 1: 28262306a36Sopenharmony_ci out_8((u8 *) data, val); 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci case 2: 28562306a36Sopenharmony_ci out_be16((u16 *) data, val); 28662306a36Sopenharmony_ci break; 28762306a36Sopenharmony_ci case 4: 28862306a36Sopenharmony_ci out_be32((u32 *) data, val); 28962306a36Sopenharmony_ci break; 29062306a36Sopenharmony_ci default: 29162306a36Sopenharmony_ci ret = -EINVAL; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci spin_unlock_irqrestore(&fsl_rio_config_lock, flags); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return ret; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic void fsl_rio_inbound_mem_init(struct rio_priv *priv) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci int i; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* close inbound windows */ 30362306a36Sopenharmony_ci for (i = 0; i < RIO_INB_ATMU_COUNT; i++) 30462306a36Sopenharmony_ci out_be32(&priv->inb_atmu_regs[i].riwar, 0); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, 30862306a36Sopenharmony_ci u64 rstart, u64 size, u32 flags) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct rio_priv *priv = mport->priv; 31162306a36Sopenharmony_ci u32 base_size; 31262306a36Sopenharmony_ci unsigned int base_size_log; 31362306a36Sopenharmony_ci u64 win_start, win_end; 31462306a36Sopenharmony_ci u32 riwar; 31562306a36Sopenharmony_ci int i; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if ((size & (size - 1)) != 0 || size > 0x400000000ULL) 31862306a36Sopenharmony_ci return -EINVAL; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci base_size_log = ilog2(size); 32162306a36Sopenharmony_ci base_size = 1 << base_size_log; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* check if addresses are aligned with the window size */ 32462306a36Sopenharmony_ci if (lstart & (base_size - 1)) 32562306a36Sopenharmony_ci return -EINVAL; 32662306a36Sopenharmony_ci if (rstart & (base_size - 1)) 32762306a36Sopenharmony_ci return -EINVAL; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* check for conflicting ranges */ 33062306a36Sopenharmony_ci for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { 33162306a36Sopenharmony_ci riwar = in_be32(&priv->inb_atmu_regs[i].riwar); 33262306a36Sopenharmony_ci if ((riwar & RIWAR_ENABLE) == 0) 33362306a36Sopenharmony_ci continue; 33462306a36Sopenharmony_ci win_start = ((u64)(in_be32(&priv->inb_atmu_regs[i].riwbar) & RIWBAR_BADD_MASK)) 33562306a36Sopenharmony_ci << RIWBAR_BADD_VAL_SHIFT; 33662306a36Sopenharmony_ci win_end = win_start + ((1 << ((riwar & RIWAR_SIZE_MASK) + 1)) - 1); 33762306a36Sopenharmony_ci if (rstart < win_end && (rstart + size) > win_start) 33862306a36Sopenharmony_ci return -EINVAL; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* find unused atmu */ 34262306a36Sopenharmony_ci for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { 34362306a36Sopenharmony_ci riwar = in_be32(&priv->inb_atmu_regs[i].riwar); 34462306a36Sopenharmony_ci if ((riwar & RIWAR_ENABLE) == 0) 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci if (i >= RIO_INB_ATMU_COUNT) 34862306a36Sopenharmony_ci return -ENOMEM; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci out_be32(&priv->inb_atmu_regs[i].riwtar, lstart >> RIWTAR_TRAD_VAL_SHIFT); 35162306a36Sopenharmony_ci out_be32(&priv->inb_atmu_regs[i].riwbar, rstart >> RIWBAR_BADD_VAL_SHIFT); 35262306a36Sopenharmony_ci out_be32(&priv->inb_atmu_regs[i].riwar, RIWAR_ENABLE | RIWAR_TGINT_LOCAL | 35362306a36Sopenharmony_ci RIWAR_RDTYP_SNOOP | RIWAR_WRTYP_SNOOP | (base_size_log - 1)); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci u32 win_start_shift, base_start_shift; 36162306a36Sopenharmony_ci struct rio_priv *priv = mport->priv; 36262306a36Sopenharmony_ci u32 riwar, riwtar; 36362306a36Sopenharmony_ci int i; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* skip default window */ 36662306a36Sopenharmony_ci base_start_shift = lstart >> RIWTAR_TRAD_VAL_SHIFT; 36762306a36Sopenharmony_ci for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { 36862306a36Sopenharmony_ci riwar = in_be32(&priv->inb_atmu_regs[i].riwar); 36962306a36Sopenharmony_ci if ((riwar & RIWAR_ENABLE) == 0) 37062306a36Sopenharmony_ci continue; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci riwtar = in_be32(&priv->inb_atmu_regs[i].riwtar); 37362306a36Sopenharmony_ci win_start_shift = riwtar & RIWTAR_TRAD_MASK; 37462306a36Sopenharmony_ci if (win_start_shift == base_start_shift) { 37562306a36Sopenharmony_ci out_be32(&priv->inb_atmu_regs[i].riwar, riwar & ~RIWAR_ENABLE); 37662306a36Sopenharmony_ci return; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_civoid fsl_rio_port_error_handler(int offset) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci /*XXX: Error recovery is not implemented, we just clear errors */ 38462306a36Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (offset == 0) { 38762306a36Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0); 38862306a36Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR); 38962306a36Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR); 39062306a36Sopenharmony_ci } else { 39162306a36Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0); 39262306a36Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR); 39362306a36Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR); 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_cistatic inline void fsl_rio_info(struct device *dev, u32 ccsr) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci const char *str; 39962306a36Sopenharmony_ci if (ccsr & 1) { 40062306a36Sopenharmony_ci /* Serial phy */ 40162306a36Sopenharmony_ci switch (ccsr >> 30) { 40262306a36Sopenharmony_ci case 0: 40362306a36Sopenharmony_ci str = "1"; 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci case 1: 40662306a36Sopenharmony_ci str = "4"; 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci default: 40962306a36Sopenharmony_ci str = "Unknown"; 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci dev_info(dev, "Hardware port width: %s\n", str); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci switch ((ccsr >> 27) & 7) { 41562306a36Sopenharmony_ci case 0: 41662306a36Sopenharmony_ci str = "Single-lane 0"; 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci case 1: 41962306a36Sopenharmony_ci str = "Single-lane 2"; 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci case 2: 42262306a36Sopenharmony_ci str = "Four-lane"; 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci default: 42562306a36Sopenharmony_ci str = "Unknown"; 42662306a36Sopenharmony_ci break; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci dev_info(dev, "Training connection status: %s\n", str); 42962306a36Sopenharmony_ci } else { 43062306a36Sopenharmony_ci /* Parallel phy */ 43162306a36Sopenharmony_ci if (!(ccsr & 0x80000000)) 43262306a36Sopenharmony_ci dev_info(dev, "Output port operating in 8-bit mode\n"); 43362306a36Sopenharmony_ci if (!(ccsr & 0x08000000)) 43462306a36Sopenharmony_ci dev_info(dev, "Input port operating in 8-bit mode\n"); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci/** 43962306a36Sopenharmony_ci * fsl_rio_setup - Setup Freescale PowerPC RapidIO interface 44062306a36Sopenharmony_ci * @dev: platform_device pointer 44162306a36Sopenharmony_ci * 44262306a36Sopenharmony_ci * Initializes MPC85xx RapidIO hardware interface, configures 44362306a36Sopenharmony_ci * master port with system-specific info, and registers the 44462306a36Sopenharmony_ci * master port with the RapidIO subsystem. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_cistatic int fsl_rio_setup(struct platform_device *dev) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct rio_ops *ops; 44962306a36Sopenharmony_ci struct rio_mport *port; 45062306a36Sopenharmony_ci struct rio_priv *priv; 45162306a36Sopenharmony_ci int rc = 0; 45262306a36Sopenharmony_ci const u32 *port_index; 45362306a36Sopenharmony_ci u32 active_ports = 0; 45462306a36Sopenharmony_ci struct device_node *np, *rmu_node; 45562306a36Sopenharmony_ci u32 ccsr; 45662306a36Sopenharmony_ci u64 range_start; 45762306a36Sopenharmony_ci u32 i; 45862306a36Sopenharmony_ci static int tmp; 45962306a36Sopenharmony_ci struct device_node *rmu_np[MAX_MSG_UNIT_NUM] = {NULL}; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (!dev->dev.of_node) { 46262306a36Sopenharmony_ci dev_err(&dev->dev, "Device OF-Node is NULL"); 46362306a36Sopenharmony_ci return -ENODEV; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci rio_regs_win = of_iomap(dev->dev.of_node, 0); 46762306a36Sopenharmony_ci if (!rio_regs_win) { 46862306a36Sopenharmony_ci dev_err(&dev->dev, "Unable to map rio register window\n"); 46962306a36Sopenharmony_ci rc = -ENOMEM; 47062306a36Sopenharmony_ci goto err_rio_regs; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci ops = kzalloc(sizeof(struct rio_ops), GFP_KERNEL); 47462306a36Sopenharmony_ci if (!ops) { 47562306a36Sopenharmony_ci rc = -ENOMEM; 47662306a36Sopenharmony_ci goto err_ops; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci ops->lcread = fsl_local_config_read; 47962306a36Sopenharmony_ci ops->lcwrite = fsl_local_config_write; 48062306a36Sopenharmony_ci ops->cread = fsl_rio_config_read; 48162306a36Sopenharmony_ci ops->cwrite = fsl_rio_config_write; 48262306a36Sopenharmony_ci ops->dsend = fsl_rio_doorbell_send; 48362306a36Sopenharmony_ci ops->pwenable = fsl_rio_pw_enable; 48462306a36Sopenharmony_ci ops->open_outb_mbox = fsl_open_outb_mbox; 48562306a36Sopenharmony_ci ops->open_inb_mbox = fsl_open_inb_mbox; 48662306a36Sopenharmony_ci ops->close_outb_mbox = fsl_close_outb_mbox; 48762306a36Sopenharmony_ci ops->close_inb_mbox = fsl_close_inb_mbox; 48862306a36Sopenharmony_ci ops->add_outb_message = fsl_add_outb_message; 48962306a36Sopenharmony_ci ops->add_inb_buffer = fsl_add_inb_buffer; 49062306a36Sopenharmony_ci ops->get_inb_message = fsl_get_inb_message; 49162306a36Sopenharmony_ci ops->map_inb = fsl_map_inb_mem; 49262306a36Sopenharmony_ci ops->unmap_inb = fsl_unmap_inb_mem; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0); 49562306a36Sopenharmony_ci if (!rmu_node) { 49662306a36Sopenharmony_ci dev_err(&dev->dev, "No valid fsl,srio-rmu-handle property\n"); 49762306a36Sopenharmony_ci rc = -ENOENT; 49862306a36Sopenharmony_ci goto err_rmu; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci rmu_regs_win = of_iomap(rmu_node, 0); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci of_node_put(rmu_node); 50362306a36Sopenharmony_ci if (!rmu_regs_win) { 50462306a36Sopenharmony_ci dev_err(&dev->dev, "Unable to map rmu register window\n"); 50562306a36Sopenharmony_ci rc = -ENOMEM; 50662306a36Sopenharmony_ci goto err_rmu; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci for_each_compatible_node(np, NULL, "fsl,srio-msg-unit") { 50962306a36Sopenharmony_ci rmu_np[tmp] = np; 51062306a36Sopenharmony_ci tmp++; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /*set up doobell node*/ 51462306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,srio-dbell-unit"); 51562306a36Sopenharmony_ci if (!np) { 51662306a36Sopenharmony_ci dev_err(&dev->dev, "No fsl,srio-dbell-unit node\n"); 51762306a36Sopenharmony_ci rc = -ENODEV; 51862306a36Sopenharmony_ci goto err_dbell; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci dbell = kzalloc(sizeof(struct fsl_rio_dbell), GFP_KERNEL); 52162306a36Sopenharmony_ci if (!(dbell)) { 52262306a36Sopenharmony_ci dev_err(&dev->dev, "Can't alloc memory for 'fsl_rio_dbell'\n"); 52362306a36Sopenharmony_ci rc = -ENOMEM; 52462306a36Sopenharmony_ci goto err_dbell; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci dbell->dev = &dev->dev; 52762306a36Sopenharmony_ci dbell->bellirq = irq_of_parse_and_map(np, 1); 52862306a36Sopenharmony_ci dev_info(&dev->dev, "bellirq: %d\n", dbell->bellirq); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (of_property_read_reg(np, 0, &range_start, NULL)) { 53162306a36Sopenharmony_ci pr_err("%pOF: unable to find 'reg' property\n", 53262306a36Sopenharmony_ci np); 53362306a36Sopenharmony_ci rc = -ENOMEM; 53462306a36Sopenharmony_ci goto err_pw; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci dbell->dbell_regs = (struct rio_dbell_regs *)(rmu_regs_win + 53762306a36Sopenharmony_ci (u32)range_start); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /*set up port write node*/ 54062306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,srio-port-write-unit"); 54162306a36Sopenharmony_ci if (!np) { 54262306a36Sopenharmony_ci dev_err(&dev->dev, "No fsl,srio-port-write-unit node\n"); 54362306a36Sopenharmony_ci rc = -ENODEV; 54462306a36Sopenharmony_ci goto err_pw; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci pw = kzalloc(sizeof(struct fsl_rio_pw), GFP_KERNEL); 54762306a36Sopenharmony_ci if (!(pw)) { 54862306a36Sopenharmony_ci dev_err(&dev->dev, "Can't alloc memory for 'fsl_rio_pw'\n"); 54962306a36Sopenharmony_ci rc = -ENOMEM; 55062306a36Sopenharmony_ci goto err_pw; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci pw->dev = &dev->dev; 55362306a36Sopenharmony_ci pw->pwirq = irq_of_parse_and_map(np, 0); 55462306a36Sopenharmony_ci dev_info(&dev->dev, "pwirq: %d\n", pw->pwirq); 55562306a36Sopenharmony_ci if (of_property_read_reg(np, 0, &range_start, NULL)) { 55662306a36Sopenharmony_ci pr_err("%pOF: unable to find 'reg' property\n", 55762306a36Sopenharmony_ci np); 55862306a36Sopenharmony_ci rc = -ENOMEM; 55962306a36Sopenharmony_ci goto err; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci pw->pw_regs = (struct rio_pw_regs *)(rmu_regs_win + (u32)range_start); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /*set up ports node*/ 56462306a36Sopenharmony_ci for_each_child_of_node(dev->dev.of_node, np) { 56562306a36Sopenharmony_ci struct resource res; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci port_index = of_get_property(np, "cell-index", NULL); 56862306a36Sopenharmony_ci if (!port_index) { 56962306a36Sopenharmony_ci dev_err(&dev->dev, "Can't get %pOF property 'cell-index'\n", 57062306a36Sopenharmony_ci np); 57162306a36Sopenharmony_ci continue; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (of_range_to_resource(np, 0, &res)) { 57562306a36Sopenharmony_ci dev_err(&dev->dev, "Can't get %pOF property 'ranges'\n", 57662306a36Sopenharmony_ci np); 57762306a36Sopenharmony_ci continue; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci dev_info(&dev->dev, "%pOF: LAW %pR\n", 58162306a36Sopenharmony_ci np, &res); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL); 58462306a36Sopenharmony_ci if (!port) 58562306a36Sopenharmony_ci continue; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci rc = rio_mport_initialize(port); 58862306a36Sopenharmony_ci if (rc) { 58962306a36Sopenharmony_ci kfree(port); 59062306a36Sopenharmony_ci continue; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci i = *port_index - 1; 59462306a36Sopenharmony_ci port->index = (unsigned char)i; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL); 59762306a36Sopenharmony_ci if (!priv) { 59862306a36Sopenharmony_ci dev_err(&dev->dev, "Can't alloc memory for 'priv'\n"); 59962306a36Sopenharmony_ci kfree(port); 60062306a36Sopenharmony_ci continue; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci INIT_LIST_HEAD(&port->dbells); 60462306a36Sopenharmony_ci port->iores = res; /* struct copy */ 60562306a36Sopenharmony_ci port->iores.name = "rio_io_win"; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (request_resource(&iomem_resource, &port->iores) < 0) { 60862306a36Sopenharmony_ci dev_err(&dev->dev, "RIO: Error requesting master port region" 60962306a36Sopenharmony_ci " 0x%016llx-0x%016llx\n", 61062306a36Sopenharmony_ci (u64)port->iores.start, (u64)port->iores.end); 61162306a36Sopenharmony_ci kfree(priv); 61262306a36Sopenharmony_ci kfree(port); 61362306a36Sopenharmony_ci continue; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci sprintf(port->name, "RIO mport %d", i); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci priv->dev = &dev->dev; 61862306a36Sopenharmony_ci port->dev.parent = &dev->dev; 61962306a36Sopenharmony_ci port->ops = ops; 62062306a36Sopenharmony_ci port->priv = priv; 62162306a36Sopenharmony_ci port->phys_efptr = 0x100; 62262306a36Sopenharmony_ci port->phys_rmap = 1; 62362306a36Sopenharmony_ci priv->regs_win = rio_regs_win; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci ccsr = in_be32(priv->regs_win + RIO_CCSR + i*0x20); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* Checking the port training status */ 62862306a36Sopenharmony_ci if (in_be32((priv->regs_win + RIO_ESCSR + i*0x20)) & 1) { 62962306a36Sopenharmony_ci dev_err(&dev->dev, "Port %d is not ready. " 63062306a36Sopenharmony_ci "Try to restart connection...\n", i); 63162306a36Sopenharmony_ci /* Disable ports */ 63262306a36Sopenharmony_ci out_be32(priv->regs_win 63362306a36Sopenharmony_ci + RIO_CCSR + i*0x20, 0); 63462306a36Sopenharmony_ci /* Set 1x lane */ 63562306a36Sopenharmony_ci setbits32(priv->regs_win 63662306a36Sopenharmony_ci + RIO_CCSR + i*0x20, 0x02000000); 63762306a36Sopenharmony_ci /* Enable ports */ 63862306a36Sopenharmony_ci setbits32(priv->regs_win 63962306a36Sopenharmony_ci + RIO_CCSR + i*0x20, 0x00600000); 64062306a36Sopenharmony_ci msleep(100); 64162306a36Sopenharmony_ci if (in_be32((priv->regs_win 64262306a36Sopenharmony_ci + RIO_ESCSR + i*0x20)) & 1) { 64362306a36Sopenharmony_ci dev_err(&dev->dev, 64462306a36Sopenharmony_ci "Port %d restart failed.\n", i); 64562306a36Sopenharmony_ci release_resource(&port->iores); 64662306a36Sopenharmony_ci kfree(priv); 64762306a36Sopenharmony_ci kfree(port); 64862306a36Sopenharmony_ci continue; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci dev_info(&dev->dev, "Port %d restart success!\n", i); 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci fsl_rio_info(&dev->dev, ccsr); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci port->sys_size = (in_be32((priv->regs_win + RIO_PEF_CAR)) 65562306a36Sopenharmony_ci & RIO_PEF_CTLS) >> 4; 65662306a36Sopenharmony_ci dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n", 65762306a36Sopenharmony_ci port->sys_size ? 65536 : 256); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (port->host_deviceid >= 0) 66062306a36Sopenharmony_ci out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST | 66162306a36Sopenharmony_ci RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED); 66262306a36Sopenharmony_ci else 66362306a36Sopenharmony_ci out_be32(priv->regs_win + RIO_GCCSR, 66462306a36Sopenharmony_ci RIO_PORT_GEN_MASTER); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win 66762306a36Sopenharmony_ci + ((i == 0) ? RIO_ATMU_REGS_PORT1_OFFSET : 66862306a36Sopenharmony_ci RIO_ATMU_REGS_PORT2_OFFSET)); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci priv->maint_atmu_regs = priv->atmu_regs + 1; 67162306a36Sopenharmony_ci priv->inb_atmu_regs = (struct rio_inb_atmu_regs __iomem *) 67262306a36Sopenharmony_ci (priv->regs_win + 67362306a36Sopenharmony_ci ((i == 0) ? RIO_INB_ATMU_REGS_PORT1_OFFSET : 67462306a36Sopenharmony_ci RIO_INB_ATMU_REGS_PORT2_OFFSET)); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* Set to receive packets with any dest ID */ 67762306a36Sopenharmony_ci out_be32((priv->regs_win + RIO_ISR_AACR + i*0x80), 67862306a36Sopenharmony_ci RIO_ISR_AACR_AA); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci /* Configure maintenance transaction window */ 68162306a36Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowbar, 68262306a36Sopenharmony_ci port->iores.start >> 12); 68362306a36Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowar, 68462306a36Sopenharmony_ci 0x80077000 | (ilog2(RIO_MAINT_WIN_SIZE) - 1)); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci priv->maint_win = ioremap(port->iores.start, 68762306a36Sopenharmony_ci RIO_MAINT_WIN_SIZE); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci rio_law_start = range_start; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci fsl_rio_setup_rmu(port, rmu_np[i]); 69262306a36Sopenharmony_ci fsl_rio_inbound_mem_init(priv); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci dbell->mport[i] = port; 69562306a36Sopenharmony_ci pw->mport[i] = port; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (rio_register_mport(port)) { 69862306a36Sopenharmony_ci release_resource(&port->iores); 69962306a36Sopenharmony_ci kfree(priv); 70062306a36Sopenharmony_ci kfree(port); 70162306a36Sopenharmony_ci continue; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci active_ports++; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (!active_ports) { 70762306a36Sopenharmony_ci rc = -ENOLINK; 70862306a36Sopenharmony_ci goto err; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci fsl_rio_doorbell_init(dbell); 71262306a36Sopenharmony_ci fsl_rio_port_write_init(pw); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci return 0; 71562306a36Sopenharmony_cierr: 71662306a36Sopenharmony_ci kfree(pw); 71762306a36Sopenharmony_ci pw = NULL; 71862306a36Sopenharmony_cierr_pw: 71962306a36Sopenharmony_ci kfree(dbell); 72062306a36Sopenharmony_ci dbell = NULL; 72162306a36Sopenharmony_cierr_dbell: 72262306a36Sopenharmony_ci iounmap(rmu_regs_win); 72362306a36Sopenharmony_ci rmu_regs_win = NULL; 72462306a36Sopenharmony_cierr_rmu: 72562306a36Sopenharmony_ci kfree(ops); 72662306a36Sopenharmony_cierr_ops: 72762306a36Sopenharmony_ci iounmap(rio_regs_win); 72862306a36Sopenharmony_ci rio_regs_win = NULL; 72962306a36Sopenharmony_cierr_rio_regs: 73062306a36Sopenharmony_ci return rc; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci/* The probe function for RapidIO peer-to-peer network. 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_cistatic int fsl_of_rio_rpn_probe(struct platform_device *dev) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci printk(KERN_INFO "Setting up RapidIO peer-to-peer network %pOF\n", 73862306a36Sopenharmony_ci dev->dev.of_node); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return fsl_rio_setup(dev); 74162306a36Sopenharmony_ci}; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic const struct of_device_id fsl_of_rio_rpn_ids[] = { 74462306a36Sopenharmony_ci { 74562306a36Sopenharmony_ci .compatible = "fsl,srio", 74662306a36Sopenharmony_ci }, 74762306a36Sopenharmony_ci {}, 74862306a36Sopenharmony_ci}; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic struct platform_driver fsl_of_rio_rpn_driver = { 75162306a36Sopenharmony_ci .driver = { 75262306a36Sopenharmony_ci .name = "fsl-of-rio", 75362306a36Sopenharmony_ci .of_match_table = fsl_of_rio_rpn_ids, 75462306a36Sopenharmony_ci }, 75562306a36Sopenharmony_ci .probe = fsl_of_rio_rpn_probe, 75662306a36Sopenharmony_ci}; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cistatic __init int fsl_of_rio_rpn_init(void) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci return platform_driver_register(&fsl_of_rio_rpn_driver); 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cisubsys_initcall(fsl_of_rio_rpn_init); 764