summaryrefslogblamecommitdiffstats
path: root/linux/drivers/soc/fsl/qbman/dpaa_sys.h
blob: 85f87800610cbb329db38f25fa8193e60460dd91 (plain) (tree)



































































































































































































































































































                                                                                
/* Copyright 2008 - 2015 Freescale Semiconductor, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *	 notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *	 notice, this list of conditions and the following disclaimer in the
 *	 documentation and/or other materials provided with the distribution.
 *     * Neither the name of Freescale Semiconductor nor the
 *	 names of its contributors may be used to endorse or promote products
 *	 derived from this software without specific prior written permission.
 *
 * ALTERNATIVELY, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") as published by the Free Software
 * Foundation, either version 2 of that License or (at your option) any
 * later version.
 *
 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __DPAA_SYS_H
#define __DPAA_SYS_H

#include <linux/slab.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_reserved_mem.h>
#include <linux/kthread.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/vmalloc.h>
#include <linux/platform_device.h>
#include <linux/ctype.h>
#ifdef CONFIG_HOTPLUG_CPU
#include <linux/cpu.h>
#endif

#include <asm/pgtable.h>
#ifdef __rtems__
#include <asm/cache.h>
#include <asm/mpc85xx.h>
#include <linux/completion.h>
#include <linux/io.h>
#include <linux/rbtree.h>
#include <bsp/linker-symbols.h>
#define	DPAA_NOCACHENOLOAD_ALIGNED_REGION(designator, size) \
    BSP_NOCACHENOLOAD_SUBSECTION(designator) __aligned(size) \
    uint8_t designator[size]
#endif /* __rtems__ */

struct dpaa_resource {
	struct list_head free;
	spinlock_t lock;
	struct list_head used;
};

#define DECLARE_DPAA_RESOURCE(name)			\
struct dpaa_resource name = {				\
	.free = {					\
		.prev = &name.free,			\
		.next = &name.free			\
	},						\
	.lock = __SPIN_LOCK_UNLOCKED(name.lock),	\
	.used = {					\
		 .prev = &name.used,			\
		 .next = &name.used			\
	}						\
}

int dpaa_resource_new(struct dpaa_resource *alloc, u32 *result,
		      u32 count, u32 align, int partial);
u32 dpaa_resource_release(struct dpaa_resource *alloc,
			  u32 id, u32 count, int (*is_valid)(u32 id));
void dpaa_resource_seed(struct dpaa_resource *alloc, u32 base_id, u32 count);
int dpaa_resource_reserve(struct dpaa_resource *alloc, u32 base, u32 num);

/* When copying aligned words or shorts, try to avoid memcpy() */
#define CONFIG_TRY_BETTER_MEMCPY

/* For 2-element tables related to cache-inhibited and cache-enabled mappings */
#define DPA_PORTAL_CE 0
#define DPA_PORTAL_CI 1

/* Misc inline assists */

/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler
 * barriers and that dcb*() won't fall victim to compiler or execution
 * reordering with respect to other code/instructions that manipulate the same
 * cacheline. */
#define hwsync() __asm__ __volatile__ ("sync" : : : "memory")
#ifndef __rtems__
#define lwsync() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : : "memory")
#else /* __rtems__ */
  #ifdef __PPC_CPU_E6500__
    #define lwsync() ppc_light_weight_synchronize()
  #else
    #define lwsync() ppc_synchronize_data()
  #endif
#endif /* __rtems__ */
#define dcbf(p) __asm__ __volatile__ ("dcbf 0,%0" : : "r" (p) : "memory")
#define dcbt_ro(p) __asm__ __volatile__ ("dcbt 0,%0" : : "r" (p))
#define dcbt_rw(p) __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (p))
#define dcbi(p) dcbf(p)
#ifdef CONFIG_PPC_E500MC
#define dcbzl(p) __asm__ __volatile__ ("dcbzl 0,%0" : : "r" (p))
#define dcbz_64(p) dcbzl(p)
#define dcbf_64(p) dcbf(p)
/* Commonly used combo */
#define dcbit_ro(p) \
	do { \
		dcbi(p); \
		dcbt_ro(p); \
	} while (0)
#else
#define dcbz(p) __asm__ __volatile__ ("dcbz 0,%0" : : "r" (p))
#define dcbz_64(p) \
	do { \
		dcbz((u32)p + 32);	\
		dcbz(p);	\
	} while (0)
#define dcbf_64(p) \
	do { \
		dcbf((u32)p + 32); \
		dcbf(p); \
	} while (0)
/* Commonly used combo */
#define dcbit_ro(p) \
	do { \
		dcbi(p); \
		dcbi((u32)p + 32); \
		dcbt_ro(p); \
		dcbt_ro((u32)p + 32); \
	} while (0)
#endif /* CONFIG_PPC_E500MC */

static inline u64 mfatb(void)
{
	u32 hi, lo, chk;

	do {
		hi = mfspr(SPRN_ATBU);
		lo = mfspr(SPRN_ATBL);
		chk = mfspr(SPRN_ATBU);
	} while (unlikely(hi != chk));
	return ((u64)hi << 32) | (u64)lo;
}

#ifdef CONFIG_FSL_DPA_CHECKING
#define DPA_ASSERT(x) WARN_ON(!(x))
#else
#define DPA_ASSERT(x)
#endif

#ifdef CONFIG_TRY_BETTER_MEMCPY
static inline void copy_words(void *dest, const void *src, size_t sz)
{
	u32 *__dest = dest;
	const u32 *__src = src;
	size_t __sz = sz >> 2;

	BUG_ON((unsigned long)dest & 0x3);
	BUG_ON((unsigned long)src & 0x3);
	BUG_ON(sz & 0x3);
	while (__sz--)
		*(__dest++) = *(__src++);
}
#else
#define copy_words memcpy
#endif

/* RB-trees */

/* We encapsulate RB-trees so that its easier to use non-linux forms in
 * non-linux systems. This also encapsulates the extra plumbing that linux code
 * usually provides when using RB-trees. This encapsulation assumes that the
 * data type held by the tree is u32. */

struct dpa_rbtree {
	struct rb_root root;
};
#define DPA_RBTREE { .root = RB_ROOT }

static inline void dpa_rbtree_init(struct dpa_rbtree *tree)
{
	tree->root = RB_ROOT;
}

#define IMPLEMENT_DPA_RBTREE(name, type, node_field, val_field) \
static inline int name##_push(struct dpa_rbtree *tree, type *obj) \
{ \
	struct rb_node *parent = NULL, **p = &tree->root.rb_node; \
	while (*p) { \
		u32 item; \
		parent = *p; \
		item = rb_entry(parent, type, node_field)->val_field; \
		if (obj->val_field < item) \
			p = &parent->rb_left; \
		else if (obj->val_field > item) \
			p = &parent->rb_right; \
		else \
			return -EBUSY; \
	} \
	rb_link_node(&obj->node_field, parent, p); \
	rb_insert_color(&obj->node_field, &tree->root); \
	return 0; \
} \
static inline void name##_del(struct dpa_rbtree *tree, type *obj) \
{ \
	rb_erase(&obj->node_field, &tree->root); \
} \
static inline type *name##_find(struct dpa_rbtree *tree, u32 val) \
{ \
	type *ret; \
	struct rb_node *p = tree->root.rb_node; \
	while (p) { \
		ret = rb_entry(p, type, node_field); \
		if (val < ret->val_field) \
			p = p->rb_left; \
		else if (val > ret->val_field) \
			p = p->rb_right; \
		else \
			return ret; \
	} \
	return NULL; \
}

#ifndef __rtems__
/* Bootargs */

/* QMan has "qportals=" and BMan has "bportals=", they use the same syntax
 * though; a comma-separated list of items, each item being a cpu index and/or a
 * range of cpu indices, and each item optionally be prefixed by "s" to indicate
 * that the portal associated with that cpu should be shared. See bman_driver.c
 * for more specifics. */
static int __parse_portals_cpu(const char **s, unsigned int *cpu)
{
	*cpu = 0;
	if (!isdigit(**s))
		return -EINVAL;
	while (isdigit(**s))
		*cpu = *cpu * 10 + (*((*s)++) - '0');
	return 0;
}
static inline int parse_portals_bootarg(char *str, struct cpumask *want_shared,
					struct cpumask *want_unshared,
					const char *argname)
{
	const char *s = str;
	unsigned int shared, cpu1, cpu2, loop;

keep_going:
	if (*s == 's') {
		shared = 1;
		s++;
	} else
		shared = 0;
	if (__parse_portals_cpu(&s, &cpu1))
		goto err;
	if (*s == '-') {
		s++;
		if (__parse_portals_cpu(&s, &cpu2))
			goto err;
		if (cpu2 < cpu1)
			goto err;
	} else
		cpu2 = cpu1;
	for (loop = cpu1; loop <= cpu2; loop++)
		cpumask_set_cpu(loop, shared ? want_shared : want_unshared);
	if (*s == ',') {
		s++;
		goto keep_going;
	} else if ((*s == '\0') || isspace(*s))
		return 0;
err:
	pr_crit("Malformed %s argument: %s, offset: %lu\n", argname, str,
		(unsigned long)s - (unsigned long)str);
	return -EINVAL;
}
#endif /* __rtems__ */
#endif	/* __DPAA_SYS_H */