/* 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 #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_HOTPLUG_CPU #include #endif #include #ifdef __rtems__ #include #include #include #include #include #include #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 */