763 lines · 19.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * Freescale MPC85xx/MPC86xx RapidIO support * * Copyright 2009 Sysgo AG * Thomas Moll <thomas.moll@sysgo.com> * - fixed maintenance access routines, check for aligned access * * Copyright 2009 Integrated Device Technology, Inc. * Alex Bounine <alexandre.bounine@idt.com> * - Added Port-Write message handling * - Added Machine Check exception handling * * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc. * Zhang Wei <wei.zhang@freescale.com> * * Copyright 2005 MontaVista Software, Inc. * Matt Porter <mporter@kernel.crashing.org> */ #include <linux/init.h>#include <linux/extable.h>#include <linux/types.h>#include <linux/dma-mapping.h>#include <linux/interrupt.h>#include <linux/of.h>#include <linux/of_address.h>#include <linux/of_irq.h>#include <linux/platform_device.h>#include <linux/delay.h>#include <linux/slab.h> #include <linux/io.h>#include <linux/uaccess.h>#include <asm/machdep.h>#include <asm/rio.h> #include "fsl_rio.h" #undef DEBUG_PW	/* Port-Write debugging */ #define RIO_PORT1_EDCSR		0x0640#define RIO_PORT2_EDCSR		0x0680#define RIO_PORT1_IECSR		0x10130#define RIO_PORT2_IECSR		0x101B0 #define RIO_GCCSR		0x13c#define RIO_ESCSR		0x158#define ESCSR_CLEAR		0x07120204#define RIO_PORT2_ESCSR		0x178#define RIO_CCSR		0x15c#define RIO_LTLEDCSR_IER	0x80000000#define RIO_LTLEDCSR_PRT	0x01000000#define IECSR_CLEAR		0x80000000#define RIO_ISR_AACR		0x10120#define RIO_ISR_AACR_AA		0x1	/* Accept All ID */ #define RIWTAR_TRAD_VAL_SHIFT	12#define RIWTAR_TRAD_MASK	0x00FFFFFF#define RIWBAR_BADD_VAL_SHIFT	12#define RIWBAR_BADD_MASK	0x003FFFFF#define RIWAR_ENABLE		0x80000000#define RIWAR_TGINT_LOCAL	0x00F00000#define RIWAR_RDTYP_NO_SNOOP	0x00040000#define RIWAR_RDTYP_SNOOP	0x00050000#define RIWAR_WRTYP_NO_SNOOP	0x00004000#define RIWAR_WRTYP_SNOOP	0x00005000#define RIWAR_WRTYP_ALLOC	0x00006000#define RIWAR_SIZE_MASK		0x0000003F static DEFINE_SPINLOCK(fsl_rio_config_lock); #define ___fsl_read_rio_config(x, addr, err, op, barrier)	\	__asm__ __volatile__(				\		"1:	"op" %1,0(%2)\n"		\		"	"barrier"\n"			\		"2:\n"					\		".section .fixup,\"ax\"\n"		\		"3:	li %1,-1\n"			\		"	li %0,%3\n"			\		"	b 2b\n"				\		".previous\n"				\		EX_TABLE(1b, 3b)			\		: "=r" (err), "=r" (x)			\		: "b" (addr), "i" (-EFAULT), "0" (err)) #ifdef CONFIG_BOOKE#define __fsl_read_rio_config(x, addr, err, op)	\	___fsl_read_rio_config(x, addr, err, op, "mbar")#else#define __fsl_read_rio_config(x, addr, err, op)	\	___fsl_read_rio_config(x, addr, err, op, "eieio")#endif void __iomem *rio_regs_win;void __iomem *rmu_regs_win;resource_size_t rio_law_start; struct fsl_rio_dbell *dbell;struct fsl_rio_pw *pw; #ifdef CONFIG_PPC_E500int fsl_rio_mcheck_exception(struct pt_regs *regs){	const struct exception_table_entry *entry;	unsigned long reason; 	if (!rio_regs_win)		return 0; 	reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR));	if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) {		/* Check if we are prepared to handle this fault */		entry = search_exception_tables(regs->nip);		if (entry) {			pr_debug("RIO: %s - MC Exception handled\n",				 __func__);			out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),				 0);			regs_set_recoverable(regs);			regs_set_return_ip(regs, extable_fixup(entry));			return 1;		}	} 	return 0;}EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception);#endif /** * fsl_local_config_read - Generate a MPC85xx local config space read * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Value to be read into * * Generates a MPC85xx local configuration space read. Returns %0 on * success or %-EINVAL on failure. */static int fsl_local_config_read(struct rio_mport *mport,				int index, u32 offset, int len, u32 *data){	struct rio_priv *priv = mport->priv;	pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index,		 offset);	*data = in_be32(priv->regs_win + offset); 	return 0;} /** * fsl_local_config_write - Generate a MPC85xx local config space write * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Value to be written * * Generates a MPC85xx local configuration space write. Returns %0 on * success or %-EINVAL on failure. */static int fsl_local_config_write(struct rio_mport *mport,				int index, u32 offset, int len, u32 data){	struct rio_priv *priv = mport->priv;	pr_debug		("fsl_local_config_write: index %d offset %8.8x data %8.8x\n",		index, offset, data);	out_be32(priv->regs_win + offset, data); 	return 0;} /** * fsl_rio_config_read - Generate a MPC85xx read maintenance transaction * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @destid: Destination ID of transaction * @hopcount: Number of hops to target device * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @val: Location to be read into * * Generates a MPC85xx read maintenance transaction. Returns %0 on * success or %-EINVAL on failure. */static intfsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,			u8 hopcount, u32 offset, int len, u32 *val){	struct rio_priv *priv = mport->priv;	unsigned long flags;	u8 *data;	u32 rval, err = 0; 	pr_debug		("fsl_rio_config_read:"		" index %d destid %d hopcount %d offset %8.8x len %d\n",		index, destid, hopcount, offset, len); 	/* 16MB maintenance window possible */	/* allow only aligned access to maintenance registers */	if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len))		return -EINVAL; 	spin_lock_irqsave(&fsl_rio_config_lock, flags); 	out_be32(&priv->maint_atmu_regs->rowtar,		 (destid << 22) | (hopcount << 12) | (offset >> 12));	out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); 	data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1));	switch (len) {	case 1:		__fsl_read_rio_config(rval, data, err, "lbz");		break;	case 2:		__fsl_read_rio_config(rval, data, err, "lhz");		break;	case 4:		__fsl_read_rio_config(rval, data, err, "lwz");		break;	default:		spin_unlock_irqrestore(&fsl_rio_config_lock, flags);		return -EINVAL;	} 	if (err) {		pr_debug("RIO: cfg_read error %d for %x:%x:%x\n",			 err, destid, hopcount, offset);	} 	spin_unlock_irqrestore(&fsl_rio_config_lock, flags);	*val = rval; 	return err;} /** * fsl_rio_config_write - Generate a MPC85xx write maintenance transaction * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @destid: Destination ID of transaction * @hopcount: Number of hops to target device * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @val: Value to be written * * Generates an MPC85xx write maintenance transaction. Returns %0 on * success or %-EINVAL on failure. */static intfsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,			u8 hopcount, u32 offset, int len, u32 val){	struct rio_priv *priv = mport->priv;	unsigned long flags;	u8 *data;	int ret = 0; 	pr_debug		("fsl_rio_config_write:"		" index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",		index, destid, hopcount, offset, len, val); 	/* 16MB maintenance windows possible */	/* allow only aligned access to maintenance registers */	if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len))		return -EINVAL; 	spin_lock_irqsave(&fsl_rio_config_lock, flags); 	out_be32(&priv->maint_atmu_regs->rowtar,		 (destid << 22) | (hopcount << 12) | (offset >> 12));	out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); 	data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1));	switch (len) {	case 1:		out_8((u8 *) data, val);		break;	case 2:		out_be16((u16 *) data, val);		break;	case 4:		out_be32((u32 *) data, val);		break;	default:		ret = -EINVAL;	}	spin_unlock_irqrestore(&fsl_rio_config_lock, flags); 	return ret;} static void fsl_rio_inbound_mem_init(struct rio_priv *priv){	int i; 	/* close inbound windows */	for (i = 0; i < RIO_INB_ATMU_COUNT; i++)		out_be32(&priv->inb_atmu_regs[i].riwar, 0);} static int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,			   u64 rstart, u64 size, u32 flags){	struct rio_priv *priv = mport->priv;	u32 base_size;	unsigned int base_size_log;	u64 win_start, win_end;	u32 riwar;	int i; 	if ((size & (size - 1)) != 0 || size > 0x400000000ULL)		return -EINVAL; 	base_size_log = ilog2(size);	base_size = 1 << base_size_log; 	/* check if addresses are aligned with the window size */	if (lstart & (base_size - 1))		return -EINVAL;	if (rstart & (base_size - 1))		return -EINVAL; 	/* check for conflicting ranges */	for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {		riwar = in_be32(&priv->inb_atmu_regs[i].riwar);		if ((riwar & RIWAR_ENABLE) == 0)			continue;		win_start = ((u64)(in_be32(&priv->inb_atmu_regs[i].riwbar) & RIWBAR_BADD_MASK))			<< RIWBAR_BADD_VAL_SHIFT;		win_end = win_start + ((1 << ((riwar & RIWAR_SIZE_MASK) + 1)) - 1);		if (rstart < win_end && (rstart + size) > win_start)			return -EINVAL;	} 	/* find unused atmu */	for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {		riwar = in_be32(&priv->inb_atmu_regs[i].riwar);		if ((riwar & RIWAR_ENABLE) == 0)			break;	}	if (i >= RIO_INB_ATMU_COUNT)		return -ENOMEM; 	out_be32(&priv->inb_atmu_regs[i].riwtar, lstart >> RIWTAR_TRAD_VAL_SHIFT);	out_be32(&priv->inb_atmu_regs[i].riwbar, rstart >> RIWBAR_BADD_VAL_SHIFT);	out_be32(&priv->inb_atmu_regs[i].riwar, RIWAR_ENABLE | RIWAR_TGINT_LOCAL |		RIWAR_RDTYP_SNOOP | RIWAR_WRTYP_SNOOP | (base_size_log - 1)); 	return 0;} static void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart){	u32 win_start_shift, base_start_shift;	struct rio_priv *priv = mport->priv;	u32 riwar, riwtar;	int i; 	/* skip default window */	base_start_shift = lstart >> RIWTAR_TRAD_VAL_SHIFT;	for (i = 0; i < RIO_INB_ATMU_COUNT; i++) {		riwar = in_be32(&priv->inb_atmu_regs[i].riwar);		if ((riwar & RIWAR_ENABLE) == 0)			continue; 		riwtar = in_be32(&priv->inb_atmu_regs[i].riwtar);		win_start_shift = riwtar & RIWTAR_TRAD_MASK;		if (win_start_shift == base_start_shift) {			out_be32(&priv->inb_atmu_regs[i].riwar, riwar & ~RIWAR_ENABLE);			return;		}	}} void fsl_rio_port_error_handler(int offset){	/*XXX: Error recovery is not implemented, we just clear errors */	out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); 	if (offset == 0) {		out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0);		out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR);		out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR);	} else {		out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0);		out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR);		out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR);	}}static inline void fsl_rio_info(struct device *dev, u32 ccsr){	const char *str;	if (ccsr & 1) {		/* Serial phy */		switch (ccsr >> 30) {		case 0:			str = "1";			break;		case 1:			str = "4";			break;		default:			str = "Unknown";			break;		}		dev_info(dev, "Hardware port width: %s\n", str); 		switch ((ccsr >> 27) & 7) {		case 0:			str = "Single-lane 0";			break;		case 1:			str = "Single-lane 2";			break;		case 2:			str = "Four-lane";			break;		default:			str = "Unknown";			break;		}		dev_info(dev, "Training connection status: %s\n", str);	} else {		/* Parallel phy */		if (!(ccsr & 0x80000000))			dev_info(dev, "Output port operating in 8-bit mode\n");		if (!(ccsr & 0x08000000))			dev_info(dev, "Input port operating in 8-bit mode\n");	}} /** * fsl_rio_setup - Setup Freescale PowerPC RapidIO interface * @dev: platform_device pointer * * Initializes MPC85xx RapidIO hardware interface, configures * master port with system-specific info, and registers the * master port with the RapidIO subsystem. */static int fsl_rio_setup(struct platform_device *dev){	struct rio_ops *ops;	struct rio_mport *port;	struct rio_priv *priv;	int rc = 0;	const u32 *port_index;	u32 active_ports = 0;	struct device_node *np, *rmu_node;	u32 ccsr;	u64 range_start;	u32 i;	static int tmp;	struct device_node *rmu_np[MAX_MSG_UNIT_NUM] = {NULL}; 	if (!dev->dev.of_node) {		dev_err(&dev->dev, "Device OF-Node is NULL");		return -ENODEV;	} 	rio_regs_win = of_iomap(dev->dev.of_node, 0);	if (!rio_regs_win) {		dev_err(&dev->dev, "Unable to map rio register window\n");		rc = -ENOMEM;		goto err_rio_regs;	} 	ops = kzalloc_obj(struct rio_ops);	if (!ops) {		rc = -ENOMEM;		goto err_ops;	}	ops->lcread = fsl_local_config_read;	ops->lcwrite = fsl_local_config_write;	ops->cread = fsl_rio_config_read;	ops->cwrite = fsl_rio_config_write;	ops->dsend = fsl_rio_doorbell_send;	ops->pwenable = fsl_rio_pw_enable;	ops->open_outb_mbox = fsl_open_outb_mbox;	ops->open_inb_mbox = fsl_open_inb_mbox;	ops->close_outb_mbox = fsl_close_outb_mbox;	ops->close_inb_mbox = fsl_close_inb_mbox;	ops->add_outb_message = fsl_add_outb_message;	ops->add_inb_buffer = fsl_add_inb_buffer;	ops->get_inb_message = fsl_get_inb_message;	ops->map_inb = fsl_map_inb_mem;	ops->unmap_inb = fsl_unmap_inb_mem; 	rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0);	if (!rmu_node) {		dev_err(&dev->dev, "No valid fsl,srio-rmu-handle property\n");		rc = -ENOENT;		goto err_rmu;	}	rmu_regs_win = of_iomap(rmu_node, 0);

Lines 1–500 of 763.