Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e6a546fd authored by Martijn de Gouw's avatar Martijn de Gouw Committed by Scott Wood
Browse files

powerpc/fsl-rio: add support for mapping inbound windows



Add support for mapping and unmapping of inbound rapidio windows.  This
allows for drivers to open up a part of local memory on the rapidio
network.  Also applications can use this and tranfer blocks of data
over the network.

Signed-off-by: default avatarMartijn de Gouw <martijn.de.gouw@prodrive-technologies.com>
[scottwood@freescale.com: updated commit message based on review]
Signed-off-by: default avatarScott Wood <scottwood@freescale.com>
parent e327fff4
Loading
Loading
Loading
Loading
+104 −0
Original line number Diff line number Diff line
@@ -58,6 +58,19 @@
#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

#define __fsl_read_rio_config(x, addr, err, op)		\
	__asm__ __volatile__(				\
		"1:	"op" %1,0(%2)\n"		\
@@ -266,6 +279,89 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
	return 0;
}

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);
}

int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
	u64 rstart, u32 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)
		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;
}

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 */
@@ -389,6 +485,8 @@ int fsl_rio_setup(struct platform_device *dev)
	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) {
@@ -602,6 +700,11 @@ int fsl_rio_setup(struct platform_device *dev)
			RIO_ATMU_REGS_PORT2_OFFSET));

		priv->maint_atmu_regs = priv->atmu_regs + 1;
		priv->inb_atmu_regs = (struct rio_inb_atmu_regs __iomem *)
			(priv->regs_win +
			((i == 0) ? RIO_INB_ATMU_REGS_PORT1_OFFSET :
			RIO_INB_ATMU_REGS_PORT2_OFFSET));


		/* Set to receive any dist ID for serial RapidIO controller. */
		if (port->phy_type == RIO_PHY_SERIAL)
@@ -620,6 +723,7 @@ int fsl_rio_setup(struct platform_device *dev)
		rio_law_start = range_start;

		fsl_rio_setup_rmu(port, rmu_np[i]);
		fsl_rio_inbound_mem_init(priv);

		dbell->mport[i] = port;

+13 −0
Original line number Diff line number Diff line
@@ -50,9 +50,12 @@
#define RIO_S_DBELL_REGS_OFFSET	0x13400
#define RIO_S_PW_REGS_OFFSET	0x134e0
#define RIO_ATMU_REGS_DBELL_OFFSET	0x10C40
#define RIO_INB_ATMU_REGS_PORT1_OFFSET 0x10d60
#define RIO_INB_ATMU_REGS_PORT2_OFFSET 0x10f60

#define MAX_MSG_UNIT_NUM	2
#define MAX_PORT_NUM		4
#define RIO_INB_ATMU_COUNT	4

struct rio_atmu_regs {
	 u32 rowtar;
@@ -63,6 +66,15 @@ struct rio_atmu_regs {
	 u32 pad2[3];
};

struct rio_inb_atmu_regs {
	u32 riwtar;
	u32 pad1;
	u32 riwbar;
	u32 pad2;
	u32 riwar;
	u32 pad3[3];
};

struct rio_dbell_ring {
	void *virt;
	dma_addr_t phys;
@@ -99,6 +111,7 @@ struct rio_priv {
	void __iomem *regs_win;
	struct rio_atmu_regs __iomem *atmu_regs;
	struct rio_atmu_regs __iomem *maint_atmu_regs;
	struct rio_inb_atmu_regs __iomem *inb_atmu_regs;
	void __iomem *maint_win;
	void *rmm_handle; /* RapidIO message manager(unit) Handle */
};