bus/fslmc: add QBMAN driver to bus
QBMAN, is a hardware block which interfaces with the other accelerating hardware blocks (For e.g., WRIOP) on NXP's DPAA2 SoC for queue, buffer and packet scheduling. This patch introduces a userspace driver for interfacing with the QBMAN hw block. The qbman-portal component provides APIs to do the low level hardware bit twiddling for operations such as: -initializing Qman software portals -building and sending portal commands -portal interrupt configuration and processing This same/similar code is used in kernel and compat file is used to make it working in user space. Signed-off-by: Geoff Thorpe <geoff.thorpe@nxp.com> Signed-off-by: Roy Pledge <roy.pledge@nxp.com> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
This commit is contained in:
parent
7e7df6d0a4
commit
531b17a780
@ -49,6 +49,7 @@ CFLAGS += $(WERROR_FLAGS)
|
||||
endif
|
||||
|
||||
CFLAGS += -I$(RTE_SDK)/drivers/bus/fslmc
|
||||
CFLAGS += -I$(RTE_SDK)/drivers/bus/fslmc/qbman/include
|
||||
CFLAGS += -I$(RTE_SDK)/lib/librte_eal/linuxapp/eal
|
||||
|
||||
# versioning export map
|
||||
@ -57,6 +58,9 @@ EXPORT_MAP := rte_bus_fslmc_version.map
|
||||
# library version
|
||||
LIBABIVER := 1
|
||||
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += \
|
||||
qbman/qbman_portal.c
|
||||
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc_bus.c
|
||||
|
||||
include $(RTE_SDK)/mk/rte.lib.mk
|
||||
|
410
drivers/bus/fslmc/qbman/include/compat.h
Normal file
410
drivers/bus/fslmc/qbman/include/compat.h
Normal file
@ -0,0 +1,410 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) 2008-2016 Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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 HEADER_COMPAT_H
|
||||
#define HEADER_COMPAT_H
|
||||
|
||||
#include <sched.h>
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <malloc.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <inttypes.h>
|
||||
#include <error.h>
|
||||
#include <rte_atomic.h>
|
||||
|
||||
/* The following definitions are primarily to allow the single-source driver
|
||||
* interfaces to be included by arbitrary program code. Ie. for interfaces that
|
||||
* are also available in kernel-space, these definitions provide compatibility
|
||||
* with certain attributes and types used in those interfaces.
|
||||
*/
|
||||
|
||||
/* Required compiler attributes */
|
||||
#define __user
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#define ____cacheline_aligned __attribute__((aligned(L1_CACHE_BYTES)))
|
||||
#undef container_of
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
typeof(((type *)0)->member)(*__mptr) = (ptr); \
|
||||
(type *)((char *)__mptr - offsetof(type, member)); })
|
||||
#define __stringify_1(x) #x
|
||||
#define __stringify(x) __stringify_1(x)
|
||||
|
||||
#ifdef ARRAY_SIZE
|
||||
#undef ARRAY_SIZE
|
||||
#endif
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
/* Required types */
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef uint64_t dma_addr_t;
|
||||
typedef cpu_set_t cpumask_t;
|
||||
typedef u32 compat_uptr_t;
|
||||
|
||||
static inline void __user *compat_ptr(compat_uptr_t uptr)
|
||||
{
|
||||
return (void __user *)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
|
||||
{
|
||||
return (u32)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
/* I/O operations */
|
||||
static inline u32 in_be32(volatile void *__p)
|
||||
{
|
||||
volatile u32 *p = __p;
|
||||
return *p;
|
||||
}
|
||||
|
||||
static inline void out_be32(volatile void *__p, u32 val)
|
||||
{
|
||||
volatile u32 *p = __p;
|
||||
*p = val;
|
||||
}
|
||||
|
||||
/* Debugging */
|
||||
#define prflush(fmt, args...) \
|
||||
do { \
|
||||
printf(fmt, ##args); \
|
||||
fflush(stdout); \
|
||||
} while (0)
|
||||
#define pr_crit(fmt, args...) prflush("CRIT:" fmt, ##args)
|
||||
#define pr_err(fmt, args...) prflush("ERR:" fmt, ##args)
|
||||
#define pr_warn(fmt, args...) prflush("WARN:" fmt, ##args)
|
||||
#define pr_info(fmt, args...) prflush(fmt, ##args)
|
||||
|
||||
#ifdef pr_debug
|
||||
#undef pr_debug
|
||||
#endif
|
||||
#define pr_debug(fmt, args...) {}
|
||||
#define might_sleep_if(c) {}
|
||||
#define msleep(x) {}
|
||||
#define WARN_ON(c, str) \
|
||||
do { \
|
||||
static int warned_##__LINE__; \
|
||||
if ((c) && !warned_##__LINE__) { \
|
||||
pr_warn("%s\n", str); \
|
||||
pr_warn("(%s:%d)\n", __FILE__, __LINE__); \
|
||||
warned_##__LINE__ = 1; \
|
||||
} \
|
||||
} while (0)
|
||||
#ifdef CONFIG_BUGON
|
||||
#define QBMAN_BUG_ON(c) WARN_ON(c, "BUG")
|
||||
#else
|
||||
#define QBMAN_BUG_ON(c) {}
|
||||
#endif
|
||||
|
||||
#define ALIGN(x, a) (((x) + ((typeof(x))(a) - 1)) & ~((typeof(x))(a) - 1))
|
||||
|
||||
/****************/
|
||||
/* Linked-lists */
|
||||
/****************/
|
||||
|
||||
struct list_head {
|
||||
struct list_head *prev;
|
||||
struct list_head *next;
|
||||
};
|
||||
|
||||
#define LIST_HEAD(n) \
|
||||
struct list_head n = { \
|
||||
.prev = &n, \
|
||||
.next = &n \
|
||||
}
|
||||
|
||||
#define INIT_LIST_HEAD(p) \
|
||||
do { \
|
||||
struct list_head *__p298 = (p); \
|
||||
__p298->next = __p298; \
|
||||
__p298->prev = __p298->next; \
|
||||
} while (0)
|
||||
#define list_entry(node, type, member) \
|
||||
(type *)((void *)node - offsetof(type, member))
|
||||
#define list_empty(p) \
|
||||
({ \
|
||||
const struct list_head *__p298 = (p); \
|
||||
((__p298->next == __p298) && (__p298->prev == __p298)); \
|
||||
})
|
||||
#define list_add(p, l) \
|
||||
do { \
|
||||
struct list_head *__p298 = (p); \
|
||||
struct list_head *__l298 = (l); \
|
||||
__p298->next = __l298->next; \
|
||||
__p298->prev = __l298; \
|
||||
__l298->next->prev = __p298; \
|
||||
__l298->next = __p298; \
|
||||
} while (0)
|
||||
#define list_add_tail(p, l) \
|
||||
do { \
|
||||
struct list_head *__p298 = (p); \
|
||||
struct list_head *__l298 = (l); \
|
||||
__p298->prev = __l298->prev; \
|
||||
__p298->next = __l298; \
|
||||
__l298->prev->next = __p298; \
|
||||
__l298->prev = __p298; \
|
||||
} while (0)
|
||||
#define list_for_each(i, l) \
|
||||
for (i = (l)->next; i != (l); i = i->next)
|
||||
#define list_for_each_safe(i, j, l) \
|
||||
for (i = (l)->next, j = i->next; i != (l); \
|
||||
i = j, j = i->next)
|
||||
#define list_for_each_entry(i, l, name) \
|
||||
for (i = list_entry((l)->next, typeof(*i), name); &i->name != (l); \
|
||||
i = list_entry(i->name.next, typeof(*i), name))
|
||||
#define list_for_each_entry_safe(i, j, l, name) \
|
||||
for (i = list_entry((l)->next, typeof(*i), name), \
|
||||
j = list_entry(i->name.next, typeof(*j), name); \
|
||||
&i->name != (l); \
|
||||
i = j, j = list_entry(j->name.next, typeof(*j), name))
|
||||
#define list_del(i) \
|
||||
do { \
|
||||
(i)->next->prev = (i)->prev; \
|
||||
(i)->prev->next = (i)->next; \
|
||||
} while (0)
|
||||
|
||||
/* Other miscellaneous interfaces our APIs depend on; */
|
||||
|
||||
#define lower_32_bits(x) ((u32)(x))
|
||||
#define upper_32_bits(x) ((u32)(((x) >> 16) >> 16))
|
||||
|
||||
/* Compiler/type stuff */
|
||||
typedef unsigned int gfp_t;
|
||||
typedef uint32_t phandle;
|
||||
|
||||
#define __iomem
|
||||
#define EINTR 4
|
||||
#define ENODEV 19
|
||||
#define GFP_KERNEL 0
|
||||
#define __raw_readb(p) (*(const volatile unsigned char *)(p))
|
||||
#define __raw_readl(p) (*(const volatile unsigned int *)(p))
|
||||
#define __raw_writel(v, p) {*(volatile unsigned int *)(p) = (v); }
|
||||
|
||||
/* memcpy() stuff - when you know alignments in advance */
|
||||
#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;
|
||||
|
||||
QBMAN_BUG_ON((unsigned long)dest & 0x3);
|
||||
QBMAN_BUG_ON((unsigned long)src & 0x3);
|
||||
QBMAN_BUG_ON(sz & 0x3);
|
||||
while (__sz--)
|
||||
*(__dest++) = *(__src++);
|
||||
}
|
||||
|
||||
static inline void copy_shorts(void *dest, const void *src, size_t sz)
|
||||
{
|
||||
u16 *__dest = dest;
|
||||
const u16 *__src = src;
|
||||
size_t __sz = sz >> 1;
|
||||
|
||||
QBMAN_BUG_ON((unsigned long)dest & 0x1);
|
||||
QBMAN_BUG_ON((unsigned long)src & 0x1);
|
||||
QBMAN_BUG_ON(sz & 0x1);
|
||||
while (__sz--)
|
||||
*(__dest++) = *(__src++);
|
||||
}
|
||||
|
||||
static inline void copy_bytes(void *dest, const void *src, size_t sz)
|
||||
{
|
||||
u8 *__dest = dest;
|
||||
const u8 *__src = src;
|
||||
|
||||
while (sz--)
|
||||
*(__dest++) = *(__src++);
|
||||
}
|
||||
#else
|
||||
#define copy_words memcpy
|
||||
#define copy_shorts memcpy
|
||||
#define copy_bytes memcpy
|
||||
#endif
|
||||
|
||||
/* Completion stuff */
|
||||
#define DECLARE_COMPLETION(n) int n = 0
|
||||
#define complete(n) { *n = 1; }
|
||||
#define wait_for_completion(n) \
|
||||
do { \
|
||||
while (!*n) { \
|
||||
bman_poll(); \
|
||||
qman_poll(); \
|
||||
} \
|
||||
*n = 0; \
|
||||
} while (0)
|
||||
|
||||
/* Allocator stuff */
|
||||
#define kmalloc(sz, t) malloc(sz)
|
||||
#define vmalloc(sz) malloc(sz)
|
||||
#define kfree(p) { if (p) free(p); }
|
||||
static inline void *kzalloc(size_t sz, gfp_t __foo __rte_unused)
|
||||
{
|
||||
void *ptr = malloc(sz);
|
||||
|
||||
if (ptr)
|
||||
memset(ptr, 0, sz);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline unsigned long get_zeroed_page(gfp_t __foo __rte_unused)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (posix_memalign(&p, 4096, 4096))
|
||||
return 0;
|
||||
memset(p, 0, 4096);
|
||||
return (unsigned long)p;
|
||||
}
|
||||
|
||||
static inline void free_page(unsigned long p)
|
||||
{
|
||||
free((void *)p);
|
||||
}
|
||||
|
||||
/* Bitfield stuff. */
|
||||
#define BITS_PER_ULONG (sizeof(unsigned long) << 3)
|
||||
#define SHIFT_PER_ULONG (((1 << 5) == BITS_PER_ULONG) ? 5 : 6)
|
||||
#define BITS_MASK(idx) ((unsigned long)1 << ((idx) & (BITS_PER_ULONG - 1)))
|
||||
#define BITS_IDX(idx) ((idx) >> SHIFT_PER_ULONG)
|
||||
static inline unsigned long test_bits(unsigned long mask,
|
||||
volatile unsigned long *p)
|
||||
{
|
||||
return *p & mask;
|
||||
}
|
||||
|
||||
static inline int test_bit(int idx, volatile unsigned long *bits)
|
||||
{
|
||||
return test_bits(BITS_MASK(idx), bits + BITS_IDX(idx));
|
||||
}
|
||||
|
||||
static inline void set_bits(unsigned long mask, volatile unsigned long *p)
|
||||
{
|
||||
*p |= mask;
|
||||
}
|
||||
|
||||
static inline void set_bit(int idx, volatile unsigned long *bits)
|
||||
{
|
||||
set_bits(BITS_MASK(idx), bits + BITS_IDX(idx));
|
||||
}
|
||||
|
||||
static inline void clear_bits(unsigned long mask, volatile unsigned long *p)
|
||||
{
|
||||
*p &= ~mask;
|
||||
}
|
||||
|
||||
static inline void clear_bit(int idx, volatile unsigned long *bits)
|
||||
{
|
||||
clear_bits(BITS_MASK(idx), bits + BITS_IDX(idx));
|
||||
}
|
||||
|
||||
static inline unsigned long test_and_set_bits(unsigned long mask,
|
||||
volatile unsigned long *p)
|
||||
{
|
||||
unsigned long ret = test_bits(mask, p);
|
||||
|
||||
set_bits(mask, p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int test_and_set_bit(int idx, volatile unsigned long *bits)
|
||||
{
|
||||
int ret = test_bit(idx, bits);
|
||||
|
||||
set_bit(idx, bits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int test_and_clear_bit(int idx, volatile unsigned long *bits)
|
||||
{
|
||||
int ret = test_bit(idx, bits);
|
||||
|
||||
clear_bit(idx, bits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int find_next_zero_bit(unsigned long *bits, int limit, int idx)
|
||||
{
|
||||
while ((++idx < limit) && test_bit(idx, bits))
|
||||
;
|
||||
return idx;
|
||||
}
|
||||
|
||||
static inline int find_first_zero_bit(unsigned long *bits, int limit)
|
||||
{
|
||||
int idx = 0;
|
||||
|
||||
while (test_bit(idx, bits) && (++idx < limit))
|
||||
;
|
||||
return idx;
|
||||
}
|
||||
|
||||
static inline u64 div64_u64(u64 n, u64 d)
|
||||
{
|
||||
return n / d;
|
||||
}
|
||||
|
||||
#define atomic_t rte_atomic32_t
|
||||
#define atomic_read(v) rte_atomic32_read(v)
|
||||
#define atomic_set(v, i) rte_atomic32_set(v, i)
|
||||
|
||||
#define atomic_inc(v) rte_atomic32_add(v, 1)
|
||||
#define atomic_dec(v) rte_atomic32_sub(v, 1)
|
||||
|
||||
#define atomic_inc_and_test(v) rte_atomic32_inc_and_test(v)
|
||||
#define atomic_dec_and_test(v) rte_atomic32_dec_and_test(v)
|
||||
|
||||
#define atomic_inc_return(v) rte_atomic32_add_return(v, 1)
|
||||
#define atomic_dec_return(v) rte_atomic32_sub_return(v, 1)
|
||||
#define atomic_sub_and_test(i, v) (rte_atomic32_sub_return(v, i) == 0)
|
||||
|
||||
#endif /* HEADER_COMPAT_H */
|
160
drivers/bus/fslmc/qbman/include/fsl_qbman_base.h
Normal file
160
drivers/bus/fslmc/qbman/include/fsl_qbman_base.h
Normal file
@ -0,0 +1,160 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (C) 2014 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.
|
||||
*
|
||||
* 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 _FSL_QBMAN_BASE_H
|
||||
#define _FSL_QBMAN_BASE_H
|
||||
|
||||
typedef uint64_t dma_addr_t;
|
||||
|
||||
/**
|
||||
* DOC: QBMan basic structures
|
||||
*
|
||||
* The QBMan block descriptor, software portal descriptor and Frame descriptor
|
||||
* are defined here.
|
||||
*
|
||||
*/
|
||||
|
||||
#define QMAN_REV_4000 0x04000000
|
||||
#define QMAN_REV_4100 0x04010000
|
||||
#define QMAN_REV_4101 0x04010001
|
||||
|
||||
/**
|
||||
* struct qbman_block_desc - qbman block descriptor structure
|
||||
* @ccsr_reg_bar: CCSR register map.
|
||||
* @irq_rerr: Recoverable error interrupt line.
|
||||
* @irq_nrerr: Non-recoverable error interrupt line
|
||||
*
|
||||
* Descriptor for a QBMan instance on the SoC. On partitions/targets that do not
|
||||
* control this QBMan instance, these values may simply be place-holders. The
|
||||
* idea is simply that we be able to distinguish between them, eg. so that SWP
|
||||
* descriptors can identify which QBMan instance they belong to.
|
||||
*/
|
||||
struct qbman_block_desc {
|
||||
void *ccsr_reg_bar;
|
||||
int irq_rerr;
|
||||
int irq_nrerr;
|
||||
};
|
||||
|
||||
enum qbman_eqcr_mode {
|
||||
qman_eqcr_vb_ring = 2, /* Valid bit, with eqcr in ring mode */
|
||||
qman_eqcr_vb_array, /* Valid bit, with eqcr in array mode */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qbman_swp_desc - qbman software portal descriptor structure
|
||||
* @block: The QBMan instance.
|
||||
* @cena_bar: Cache-enabled portal register map.
|
||||
* @cinh_bar: Cache-inhibited portal register map.
|
||||
* @irq: -1 if unused (or unassigned)
|
||||
* @idx: SWPs within a QBMan are indexed. -1 if opaque to the user.
|
||||
* @qman_version: the qman version.
|
||||
* @eqcr_mode: Select the eqcr mode, currently only valid bit ring mode and
|
||||
* valid bit array mode are supported.
|
||||
*
|
||||
* Descriptor for a QBMan software portal, expressed in terms that make sense to
|
||||
* the user context. Ie. on MC, this information is likely to be true-physical,
|
||||
* and instantiated statically at compile-time. On GPP, this information is
|
||||
* likely to be obtained via "discovery" over a partition's "MC bus"
|
||||
* (ie. in response to a MC portal command), and would take into account any
|
||||
* virtualisation of the GPP user's address space and/or interrupt numbering.
|
||||
*/
|
||||
struct qbman_swp_desc {
|
||||
const struct qbman_block_desc *block;
|
||||
uint8_t *cena_bar;
|
||||
uint8_t *cinh_bar;
|
||||
int irq;
|
||||
int idx;
|
||||
uint32_t qman_version;
|
||||
enum qbman_eqcr_mode eqcr_mode;
|
||||
};
|
||||
|
||||
/* Driver object for managing a QBMan portal */
|
||||
struct qbman_swp;
|
||||
|
||||
/**
|
||||
* struct qbman_fd - basci structure for qbman frame descriptor
|
||||
* @words: for easier/faster copying the whole FD structure.
|
||||
* @addr_lo: the lower 32 bits of the address in FD.
|
||||
* @addr_hi: the upper 32 bits of the address in FD.
|
||||
* @len: the length field in FD.
|
||||
* @bpid_offset: represent the bpid and offset fields in FD. offset in
|
||||
* the MS 16 bits, BPID in the LS 16 bits.
|
||||
* @frc: frame context
|
||||
* @ctrl: the 32bit control bits including dd, sc,... va, err.
|
||||
* @flc_lo: the lower 32bit of flow context.
|
||||
* @flc_hi: the upper 32bits of flow context.
|
||||
*
|
||||
* Place-holder for FDs, we represent it via the simplest form that we need for
|
||||
* now. Different overlays may be needed to support different options, etc. (It
|
||||
* is impractical to define One True Struct, because the resulting encoding
|
||||
* routines (lots of read-modify-writes) would be worst-case performance whether
|
||||
* or not circumstances required them.)
|
||||
*
|
||||
* Note, as with all data-structures exchanged between software and hardware (be
|
||||
* they located in the portal register map or DMA'd to and from main-memory),
|
||||
* the driver ensures that the caller of the driver API sees the data-structures
|
||||
* in host-endianness. "struct qbman_fd" is no exception. The 32-bit words
|
||||
* contained within this structure are represented in host-endianness, even if
|
||||
* hardware always treats them as little-endian. As such, if any of these fields
|
||||
* are interpreted in a binary (rather than numerical) fashion by hardware
|
||||
* blocks (eg. accelerators), then the user should be careful. We illustrate
|
||||
* with an example;
|
||||
*
|
||||
* Suppose the desired behaviour of an accelerator is controlled by the "frc"
|
||||
* field of the FDs that are sent to it. Suppose also that the behaviour desired
|
||||
* by the user corresponds to an "frc" value which is expressed as the literal
|
||||
* sequence of bytes 0xfe, 0xed, 0xab, and 0xba. So "frc" should be the 32-bit
|
||||
* value in which 0xfe is the first byte and 0xba is the last byte, and as
|
||||
* hardware is little-endian, this amounts to a 32-bit "value" of 0xbaabedfe. If
|
||||
* the software is little-endian also, this can simply be achieved by setting
|
||||
* frc=0xbaabedfe. On the other hand, if software is big-endian, it should set
|
||||
* frc=0xfeedabba! The best away of avoiding trouble with this sort of thing is
|
||||
* to treat the 32-bit words as numerical values, in which the offset of a field
|
||||
* from the beginning of the first byte (as required or generated by hardware)
|
||||
* is numerically encoded by a left-shift (ie. by raising the field to a
|
||||
* corresponding power of 2). Ie. in the current example, software could set
|
||||
* "frc" in the following way, and it would work correctly on both little-endian
|
||||
* and big-endian operation;
|
||||
* fd.frc = (0xfe << 0) | (0xed << 8) | (0xab << 16) | (0xba << 24);
|
||||
*/
|
||||
struct qbman_fd {
|
||||
union {
|
||||
uint32_t words[8];
|
||||
struct qbman_fd_simple {
|
||||
uint32_t addr_lo;
|
||||
uint32_t addr_hi;
|
||||
uint32_t len;
|
||||
uint32_t bpid_offset;
|
||||
uint32_t frc;
|
||||
uint32_t ctrl;
|
||||
uint32_t flc_lo;
|
||||
uint32_t flc_hi;
|
||||
} simple;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* !_FSL_QBMAN_BASE_H */
|
1093
drivers/bus/fslmc/qbman/include/fsl_qbman_portal.h
Normal file
1093
drivers/bus/fslmc/qbman/include/fsl_qbman_portal.h
Normal file
File diff suppressed because it is too large
Load Diff
1496
drivers/bus/fslmc/qbman/qbman_portal.c
Normal file
1496
drivers/bus/fslmc/qbman/qbman_portal.c
Normal file
File diff suppressed because it is too large
Load Diff
277
drivers/bus/fslmc/qbman/qbman_portal.h
Normal file
277
drivers/bus/fslmc/qbman/qbman_portal.h
Normal file
@ -0,0 +1,277 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (C) 2014-2016 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "qbman_private.h"
|
||||
#include <fsl_qbman_portal.h>
|
||||
|
||||
/* All QBMan command and result structures use this "valid bit" encoding */
|
||||
#define QB_VALID_BIT ((uint32_t)0x80)
|
||||
|
||||
/* Management command result codes */
|
||||
#define QBMAN_MC_RSLT_OK 0xf0
|
||||
|
||||
/* QBMan DQRR size is set at runtime in qbman_portal.c */
|
||||
|
||||
#define QBMAN_EQCR_SIZE 8
|
||||
|
||||
static inline u8 qm_cyc_diff(u8 ringsize, u8 first, u8 last)
|
||||
{
|
||||
/* 'first' is included, 'last' is excluded */
|
||||
if (first <= last)
|
||||
return last - first;
|
||||
return (2 * ringsize) + last - first;
|
||||
}
|
||||
|
||||
/* --------------------- */
|
||||
/* portal data structure */
|
||||
/* --------------------- */
|
||||
|
||||
struct qbman_swp {
|
||||
struct qbman_swp_desc desc;
|
||||
/* The qbman_sys (ie. arch/OS-specific) support code can put anything it
|
||||
* needs in here.
|
||||
*/
|
||||
struct qbman_swp_sys sys;
|
||||
/* Management commands */
|
||||
struct {
|
||||
#ifdef QBMAN_CHECKING
|
||||
enum swp_mc_check {
|
||||
swp_mc_can_start, /* call __qbman_swp_mc_start() */
|
||||
swp_mc_can_submit, /* call __qbman_swp_mc_submit() */
|
||||
swp_mc_can_poll, /* call __qbman_swp_mc_result() */
|
||||
} check;
|
||||
#endif
|
||||
uint32_t valid_bit; /* 0x00 or 0x80 */
|
||||
} mc;
|
||||
/* Push dequeues */
|
||||
uint32_t sdq;
|
||||
/* Volatile dequeues */
|
||||
struct {
|
||||
/* VDQCR supports a "1 deep pipeline", meaning that if you know
|
||||
* the last-submitted command is already executing in the
|
||||
* hardware (as evidenced by at least 1 valid dequeue result),
|
||||
* you can write another dequeue command to the register, the
|
||||
* hardware will start executing it as soon as the
|
||||
* already-executing command terminates. (This minimises latency
|
||||
* and stalls.) With that in mind, this "busy" variable refers
|
||||
* to whether or not a command can be submitted, not whether or
|
||||
* not a previously-submitted command is still executing. In
|
||||
* other words, once proof is seen that the previously-submitted
|
||||
* command is executing, "vdq" is no longer "busy".
|
||||
*/
|
||||
atomic_t busy;
|
||||
uint32_t valid_bit; /* 0x00 or 0x80 */
|
||||
/* We need to determine when vdq is no longer busy. This depends
|
||||
* on whether the "busy" (last-submitted) dequeue command is
|
||||
* targeting DQRR or main-memory, and detected is based on the
|
||||
* presence of the dequeue command's "token" showing up in
|
||||
* dequeue entries in DQRR or main-memory (respectively).
|
||||
*/
|
||||
struct qbman_result *storage; /* NULL if DQRR */
|
||||
} vdq;
|
||||
/* DQRR */
|
||||
struct {
|
||||
uint32_t next_idx;
|
||||
uint32_t valid_bit;
|
||||
uint8_t dqrr_size;
|
||||
int reset_bug;
|
||||
} dqrr;
|
||||
struct {
|
||||
uint32_t pi;
|
||||
uint32_t pi_vb;
|
||||
uint32_t ci;
|
||||
int available;
|
||||
} eqcr;
|
||||
};
|
||||
|
||||
/* -------------------------- */
|
||||
/* portal management commands */
|
||||
/* -------------------------- */
|
||||
|
||||
/* Different management commands all use this common base layer of code to issue
|
||||
* commands and poll for results. The first function returns a pointer to where
|
||||
* the caller should fill in their MC command (though they should ignore the
|
||||
* verb byte), the second function commits merges in the caller-supplied command
|
||||
* verb (which should not include the valid-bit) and submits the command to
|
||||
* hardware, and the third function checks for a completed response (returns
|
||||
* non-NULL if only if the response is complete).
|
||||
*/
|
||||
void *qbman_swp_mc_start(struct qbman_swp *p);
|
||||
void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, uint32_t cmd_verb);
|
||||
void *qbman_swp_mc_result(struct qbman_swp *p);
|
||||
|
||||
/* Wraps up submit + poll-for-result */
|
||||
static inline void *qbman_swp_mc_complete(struct qbman_swp *swp, void *cmd,
|
||||
uint32_t cmd_verb)
|
||||
{
|
||||
int loopvar;
|
||||
|
||||
qbman_swp_mc_submit(swp, cmd, cmd_verb);
|
||||
DBG_POLL_START(loopvar);
|
||||
do {
|
||||
DBG_POLL_CHECK(loopvar);
|
||||
cmd = qbman_swp_mc_result(swp);
|
||||
} while (!cmd);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/* ------------ */
|
||||
/* qb_attr_code */
|
||||
/* ------------ */
|
||||
|
||||
/* This struct locates a sub-field within a QBMan portal (CENA) cacheline which
|
||||
* is either serving as a configuration command or a query result. The
|
||||
* representation is inherently little-endian, as the indexing of the words is
|
||||
* itself little-endian in nature and DPAA2 QBMan is little endian for anything
|
||||
* that crosses a word boundary too (64-bit fields are the obvious examples).
|
||||
*/
|
||||
struct qb_attr_code {
|
||||
unsigned int word; /* which uint32_t[] array member encodes the field */
|
||||
unsigned int lsoffset; /* encoding offset from ls-bit */
|
||||
unsigned int width; /* encoding width. (bool must be 1.) */
|
||||
};
|
||||
|
||||
/* Some pre-defined codes */
|
||||
extern struct qb_attr_code code_generic_verb;
|
||||
extern struct qb_attr_code code_generic_rslt;
|
||||
|
||||
/* Macros to define codes */
|
||||
#define QB_CODE(a, b, c) { a, b, c}
|
||||
#define QB_CODE_NULL \
|
||||
QB_CODE((unsigned int)-1, (unsigned int)-1, (unsigned int)-1)
|
||||
|
||||
/* Rotate a code "ms", meaning that it moves from less-significant bytes to
|
||||
* more-significant, from less-significant words to more-significant, etc. The
|
||||
* "ls" version does the inverse, from more-significant towards
|
||||
* less-significant.
|
||||
*/
|
||||
static inline void qb_attr_code_rotate_ms(struct qb_attr_code *code,
|
||||
unsigned int bits)
|
||||
{
|
||||
code->lsoffset += bits;
|
||||
while (code->lsoffset > 31) {
|
||||
code->word++;
|
||||
code->lsoffset -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void qb_attr_code_rotate_ls(struct qb_attr_code *code,
|
||||
unsigned int bits)
|
||||
{
|
||||
/* Don't be fooled, this trick should work because the types are
|
||||
* unsigned. So the case that interests the while loop (the rotate has
|
||||
* gone too far and the word count needs to compensate for it), is
|
||||
* manifested when lsoffset is negative. But that equates to a really
|
||||
* large unsigned value, starting with lots of "F"s. As such, we can
|
||||
* continue adding 32 back to it until it wraps back round above zero,
|
||||
* to a value of 31 or less...
|
||||
*/
|
||||
code->lsoffset -= bits;
|
||||
while (code->lsoffset > 31) {
|
||||
code->word--;
|
||||
code->lsoffset += 32;
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement a loop of code rotations until 'expr' evaluates to FALSE (0). */
|
||||
#define qb_attr_code_for_ms(code, bits, expr) \
|
||||
for (; expr; qb_attr_code_rotate_ms(code, bits))
|
||||
#define qb_attr_code_for_ls(code, bits, expr) \
|
||||
for (; expr; qb_attr_code_rotate_ls(code, bits))
|
||||
|
||||
/* decode a field from a cacheline */
|
||||
static inline uint32_t qb_attr_code_decode(const struct qb_attr_code *code,
|
||||
const uint32_t *cacheline)
|
||||
{
|
||||
return d32_uint32_t(code->lsoffset, code->width, cacheline[code->word]);
|
||||
}
|
||||
|
||||
static inline uint64_t qb_attr_code_decode_64(const struct qb_attr_code *code,
|
||||
const uint64_t *cacheline)
|
||||
{
|
||||
return cacheline[code->word / 2];
|
||||
}
|
||||
|
||||
/* encode a field to a cacheline */
|
||||
static inline void qb_attr_code_encode(const struct qb_attr_code *code,
|
||||
uint32_t *cacheline, uint32_t val)
|
||||
{
|
||||
cacheline[code->word] =
|
||||
r32_uint32_t(code->lsoffset, code->width, cacheline[code->word])
|
||||
| e32_uint32_t(code->lsoffset, code->width, val);
|
||||
}
|
||||
|
||||
static inline void qb_attr_code_encode_64(const struct qb_attr_code *code,
|
||||
uint64_t *cacheline, uint64_t val)
|
||||
{
|
||||
cacheline[code->word / 2] = val;
|
||||
}
|
||||
|
||||
/* Small-width signed values (two's-complement) will decode into medium-width
|
||||
* positives. (Eg. for an 8-bit signed field, which stores values from -128 to
|
||||
* +127, a setting of -7 would appear to decode to the 32-bit unsigned value
|
||||
* 249. Likewise -120 would decode as 136.) This function allows the caller to
|
||||
* "re-sign" such fields to 32-bit signed. (Eg. -7, which was 249 with an 8-bit
|
||||
* encoding, will become 0xfffffff9 if you cast the return value to uint32_t).
|
||||
*/
|
||||
static inline int32_t qb_attr_code_makesigned(const struct qb_attr_code *code,
|
||||
uint32_t val)
|
||||
{
|
||||
QBMAN_BUG_ON(val >= (1u << code->width));
|
||||
/* code->width should never exceed the width of val. If it does then a
|
||||
* different function with larger val size must be used to translate
|
||||
* from unsigned to signed
|
||||
*/
|
||||
QBMAN_BUG_ON(code->width > sizeof(val) * CHAR_BIT);
|
||||
/* If the high bit was set, it was encoding a negative */
|
||||
if (val >= 1u << (code->width - 1))
|
||||
return (int32_t)0 - (int32_t)(((uint32_t)1 << code->width) -
|
||||
val);
|
||||
/* Otherwise, it was encoding a positive */
|
||||
return (int32_t)val;
|
||||
}
|
||||
|
||||
/* ---------------------- */
|
||||
/* Descriptors/cachelines */
|
||||
/* ---------------------- */
|
||||
|
||||
/* To avoid needless dynamic allocation, the driver API often gives the caller
|
||||
* a "descriptor" type that the caller can instantiate however they like.
|
||||
* Ultimately though, it is just a cacheline of binary storage (or something
|
||||
* smaller when it is known that the descriptor doesn't need all 64 bytes) for
|
||||
* holding pre-formatted pieces of hardware commands. The performance-critical
|
||||
* code can then copy these descriptors directly into hardware command
|
||||
* registers more efficiently than trying to construct/format commands
|
||||
* on-the-fly. The API user sees the descriptor as an array of 32-bit words in
|
||||
* order for the compiler to know its size, but the internal details are not
|
||||
* exposed. The following macro is used within the driver for converting *any*
|
||||
* descriptor pointer to a usable array pointer. The use of a macro (instead of
|
||||
* an inline) is necessary to work with different descriptor types and to work
|
||||
* correctly with const and non-const inputs (and similarly-qualified outputs).
|
||||
*/
|
||||
#define qb_cl(d) (&(d)->dont_manipulate_directly[0])
|
174
drivers/bus/fslmc/qbman/qbman_private.h
Normal file
174
drivers/bus/fslmc/qbman/qbman_private.h
Normal file
@ -0,0 +1,174 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (C) 2014-2016 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Perform extra checking */
|
||||
#define QBMAN_CHECKING
|
||||
|
||||
/* To maximise the amount of logic that is common between the Linux driver and
|
||||
* other targets (such as the embedded MC firmware), we pivot here between the
|
||||
* inclusion of two platform-specific headers.
|
||||
*
|
||||
* The first, qbman_sys_decl.h, includes any and all required system headers as
|
||||
* well as providing any definitions for the purposes of compatibility. The
|
||||
* second, qbman_sys.h, is where platform-specific routines go.
|
||||
*
|
||||
* The point of the split is that the platform-independent code (including this
|
||||
* header) may depend on platform-specific declarations, yet other
|
||||
* platform-specific routines may depend on platform-independent definitions.
|
||||
*/
|
||||
|
||||
#include "qbman_sys_decl.h"
|
||||
|
||||
/* When things go wrong, it is a convenient trick to insert a few FOO()
|
||||
* statements in the code to trace progress. TODO: remove this once we are
|
||||
* hacking the code less actively.
|
||||
*/
|
||||
#define FOO() fsl_os_print("FOO: %s:%d\n", __FILE__, __LINE__)
|
||||
|
||||
/* Any time there is a register interface which we poll on, this provides a
|
||||
* "break after x iterations" scheme for it. It's handy for debugging, eg.
|
||||
* where you don't want millions of lines of log output from a polling loop
|
||||
* that won't, because such things tend to drown out the earlier log output
|
||||
* that might explain what caused the problem. (NB: put ";" after each macro!)
|
||||
* TODO: we should probably remove this once we're done sanitising the
|
||||
* simulator...
|
||||
*/
|
||||
#define DBG_POLL_START(loopvar) (loopvar = 10)
|
||||
#define DBG_POLL_CHECK(loopvar) \
|
||||
do { \
|
||||
if (!(loopvar--)) \
|
||||
QBMAN_BUG_ON(NULL == "DBG_POLL_CHECK"); \
|
||||
} while (0)
|
||||
|
||||
/* For CCSR or portal-CINH registers that contain fields at arbitrary offsets
|
||||
* and widths, these macro-generated encode/decode/isolate/remove inlines can
|
||||
* be used.
|
||||
*
|
||||
* Eg. to "d"ecode a 14-bit field out of a register (into a "uint16_t" type),
|
||||
* where the field is located 3 bits "up" from the least-significant bit of the
|
||||
* register (ie. the field location within the 32-bit register corresponds to a
|
||||
* mask of 0x0001fff8), you would do;
|
||||
* uint16_t field = d32_uint16_t(3, 14, reg_value);
|
||||
*
|
||||
* Or to "e"ncode a 1-bit boolean value (input type is "int", zero is FALSE,
|
||||
* non-zero is TRUE, so must convert all non-zero inputs to 1, hence the "!!"
|
||||
* operator) into a register at bit location 0x00080000 (19 bits "in" from the
|
||||
* LS bit), do;
|
||||
* reg_value |= e32_int(19, 1, !!field);
|
||||
*
|
||||
* If you wish to read-modify-write a register, such that you leave the 14-bit
|
||||
* field as-is but have all other fields set to zero, then "i"solate the 14-bit
|
||||
* value using;
|
||||
* reg_value = i32_uint16_t(3, 14, reg_value);
|
||||
*
|
||||
* Alternatively, you could "r"emove the 1-bit boolean field (setting it to
|
||||
* zero) but leaving all other fields as-is;
|
||||
* reg_val = r32_int(19, 1, reg_value);
|
||||
*
|
||||
*/
|
||||
#ifdef __LP64__
|
||||
#define MAKE_MASK32(width) ((uint32_t)(( 1ULL << width) - 1))
|
||||
#else
|
||||
#define MAKE_MASK32(width) (width == 32 ? 0xffffffff : \
|
||||
(uint32_t)((1 << width) - 1))
|
||||
#endif
|
||||
#define DECLARE_CODEC32(t) \
|
||||
static inline uint32_t e32_##t(uint32_t lsoffset, uint32_t width, t val) \
|
||||
{ \
|
||||
QBMAN_BUG_ON(width > (sizeof(t) * 8)); \
|
||||
return ((uint32_t)val & MAKE_MASK32(width)) << lsoffset; \
|
||||
} \
|
||||
static inline t d32_##t(uint32_t lsoffset, uint32_t width, uint32_t val) \
|
||||
{ \
|
||||
QBMAN_BUG_ON(width > (sizeof(t) * 8)); \
|
||||
return (t)((val >> lsoffset) & MAKE_MASK32(width)); \
|
||||
} \
|
||||
static inline uint32_t i32_##t(uint32_t lsoffset, uint32_t width, \
|
||||
uint32_t val) \
|
||||
{ \
|
||||
QBMAN_BUG_ON(width > (sizeof(t) * 8)); \
|
||||
return e32_##t(lsoffset, width, d32_##t(lsoffset, width, val)); \
|
||||
} \
|
||||
static inline uint32_t r32_##t(uint32_t lsoffset, uint32_t width, \
|
||||
uint32_t val) \
|
||||
{ \
|
||||
QBMAN_BUG_ON(width > (sizeof(t) * 8)); \
|
||||
return ~(MAKE_MASK32(width) << lsoffset) & val; \
|
||||
}
|
||||
DECLARE_CODEC32(uint32_t)
|
||||
DECLARE_CODEC32(uint16_t)
|
||||
DECLARE_CODEC32(uint8_t)
|
||||
DECLARE_CODEC32(int)
|
||||
|
||||
/*********************/
|
||||
/* Debugging assists */
|
||||
/*********************/
|
||||
|
||||
static inline void __hexdump(unsigned long start, unsigned long end,
|
||||
unsigned long p, size_t sz, const unsigned char *c)
|
||||
{
|
||||
while (start < end) {
|
||||
unsigned int pos = 0;
|
||||
char buf[64];
|
||||
int nl = 0;
|
||||
|
||||
pos += sprintf(buf + pos, "%08lx: ", start);
|
||||
do {
|
||||
if ((start < p) || (start >= (p + sz)))
|
||||
pos += sprintf(buf + pos, "..");
|
||||
else
|
||||
pos += sprintf(buf + pos, "%02x", *(c++));
|
||||
if (!(++start & 15)) {
|
||||
buf[pos++] = '\n';
|
||||
nl = 1;
|
||||
} else {
|
||||
nl = 0;
|
||||
if (!(start & 1))
|
||||
buf[pos++] = ' ';
|
||||
if (!(start & 3))
|
||||
buf[pos++] = ' ';
|
||||
}
|
||||
} while (start & 15);
|
||||
if (!nl)
|
||||
buf[pos++] = '\n';
|
||||
buf[pos] = '\0';
|
||||
pr_info("%s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hexdump(const void *ptr, size_t sz)
|
||||
{
|
||||
unsigned long p = (unsigned long)ptr;
|
||||
unsigned long start = p & ~(unsigned long)15;
|
||||
unsigned long end = (p + sz + 15) & ~(unsigned long)15;
|
||||
const unsigned char *c = ptr;
|
||||
|
||||
__hexdump(start, end, p, sz, c);
|
||||
}
|
||||
|
||||
#include "qbman_sys.h"
|
385
drivers/bus/fslmc/qbman/qbman_sys.h
Normal file
385
drivers/bus/fslmc/qbman/qbman_sys.h
Normal file
@ -0,0 +1,385 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (C) 2014-2016 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/* qbman_sys_decl.h and qbman_sys.h are the two platform-specific files in the
|
||||
* driver. They are only included via qbman_private.h, which is itself a
|
||||
* platform-independent file and is included by all the other driver source.
|
||||
*
|
||||
* qbman_sys_decl.h is included prior to all other declarations and logic, and
|
||||
* it exists to provide compatibility with any linux interfaces our
|
||||
* single-source driver code is dependent on (eg. kmalloc). Ie. this file
|
||||
* provides linux compatibility.
|
||||
*
|
||||
* This qbman_sys.h header, on the other hand, is included *after* any common
|
||||
* and platform-neutral declarations and logic in qbman_private.h, and exists to
|
||||
* implement any platform-specific logic of the qbman driver itself. Ie. it is
|
||||
* *not* to provide linux compatibility.
|
||||
*/
|
||||
|
||||
/* Trace the 3 different classes of read/write access to QBMan. #undef as
|
||||
* required.
|
||||
*/
|
||||
#undef QBMAN_CCSR_TRACE
|
||||
#undef QBMAN_CINH_TRACE
|
||||
#undef QBMAN_CENA_TRACE
|
||||
|
||||
static inline void word_copy(void *d, const void *s, unsigned int cnt)
|
||||
{
|
||||
uint32_t *dd = d;
|
||||
const uint32_t *ss = s;
|
||||
|
||||
while (cnt--)
|
||||
*(dd++) = *(ss++);
|
||||
}
|
||||
|
||||
/* Currently, the CENA support code expects each 32-bit word to be written in
|
||||
* host order, and these are converted to hardware (little-endian) order on
|
||||
* command submission. However, 64-bit quantities are must be written (and read)
|
||||
* as two 32-bit words with the least-significant word first, irrespective of
|
||||
* host endianness.
|
||||
*/
|
||||
static inline void u64_to_le32_copy(void *d, const uint64_t *s,
|
||||
unsigned int cnt)
|
||||
{
|
||||
uint32_t *dd = d;
|
||||
const uint32_t *ss = (const uint32_t *)s;
|
||||
|
||||
while (cnt--) {
|
||||
/* TBD: the toolchain was choking on the use of 64-bit types up
|
||||
* until recently so this works entirely with 32-bit variables.
|
||||
* When 64-bit types become usable again, investigate better
|
||||
* ways of doing this.
|
||||
*/
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
*(dd++) = ss[1];
|
||||
*(dd++) = ss[0];
|
||||
ss += 2;
|
||||
#else
|
||||
*(dd++) = *(ss++);
|
||||
*(dd++) = *(ss++);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline void u64_from_le32_copy(uint64_t *d, const void *s,
|
||||
unsigned int cnt)
|
||||
{
|
||||
const uint32_t *ss = s;
|
||||
uint32_t *dd = (uint32_t *)d;
|
||||
|
||||
while (cnt--) {
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
dd[1] = *(ss++);
|
||||
dd[0] = *(ss++);
|
||||
dd += 2;
|
||||
#else
|
||||
*(dd++) = *(ss++);
|
||||
*(dd++) = *(ss++);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a host-native 32bit value into little endian */
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
static inline uint32_t make_le32(uint32_t val)
|
||||
{
|
||||
return ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
|
||||
((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24);
|
||||
}
|
||||
|
||||
static inline uint32_t make_le24(uint32_t val)
|
||||
{
|
||||
return (((val & 0xff) << 16) | (val & 0xff00) |
|
||||
((val & 0xff0000) >> 16));
|
||||
}
|
||||
|
||||
static inline void make_le32_n(uint32_t *val, unsigned int num)
|
||||
{
|
||||
while (num--) {
|
||||
*val = make_le32(*val);
|
||||
val++;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#define make_le32(val) (val)
|
||||
#define make_le24(val) (val)
|
||||
#define make_le32_n(val, len) do {} while (0)
|
||||
#endif
|
||||
|
||||
/******************/
|
||||
/* Portal access */
|
||||
/******************/
|
||||
struct qbman_swp_sys {
|
||||
/* On GPP, the sys support for qbman_swp is here. The CENA region isi
|
||||
* not an mmap() of the real portal registers, but an allocated
|
||||
* place-holder, because the actual writes/reads to/from the portal are
|
||||
* marshalled from these allocated areas using QBMan's "MC access
|
||||
* registers". CINH accesses are atomic so there's no need for a
|
||||
* place-holder.
|
||||
*/
|
||||
uint8_t *cena;
|
||||
uint8_t __iomem *addr_cena;
|
||||
uint8_t __iomem *addr_cinh;
|
||||
uint32_t idx;
|
||||
enum qbman_eqcr_mode eqcr_mode;
|
||||
};
|
||||
|
||||
/* P_OFFSET is (ACCESS_CMD,0,12) - offset within the portal
|
||||
* C is (ACCESS_CMD,12,1) - is inhibited? (0==CENA, 1==CINH)
|
||||
* SWP_IDX is (ACCESS_CMD,16,10) - Software portal index
|
||||
* P is (ACCESS_CMD,28,1) - (0==special portal, 1==any portal)
|
||||
* T is (ACCESS_CMD,29,1) - Command type (0==READ, 1==WRITE)
|
||||
* E is (ACCESS_CMD,31,1) - Command execute (1 to issue, poll for 0==complete)
|
||||
*/
|
||||
|
||||
static inline void qbman_cinh_write(struct qbman_swp_sys *s, uint32_t offset,
|
||||
uint32_t val)
|
||||
{
|
||||
__raw_writel(val, s->addr_cinh + offset);
|
||||
#ifdef QBMAN_CINH_TRACE
|
||||
pr_info("qbman_cinh_write(%p:%d:0x%03x) 0x%08x\n",
|
||||
s->addr_cinh, s->idx, offset, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t qbman_cinh_read(struct qbman_swp_sys *s, uint32_t offset)
|
||||
{
|
||||
uint32_t reg = __raw_readl(s->addr_cinh + offset);
|
||||
#ifdef QBMAN_CINH_TRACE
|
||||
pr_info("qbman_cinh_read(%p:%d:0x%03x) 0x%08x\n",
|
||||
s->addr_cinh, s->idx, offset, reg);
|
||||
#endif
|
||||
return reg;
|
||||
}
|
||||
|
||||
static inline void *qbman_cena_write_start(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
void *shadow = s->cena + offset;
|
||||
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
pr_info("qbman_cena_write_start(%p:%d:0x%03x) %p\n",
|
||||
s->addr_cena, s->idx, offset, shadow);
|
||||
#endif
|
||||
QBMAN_BUG_ON(offset & 63);
|
||||
dcbz(shadow);
|
||||
return shadow;
|
||||
}
|
||||
|
||||
static inline void *qbman_cena_write_start_wo_shadow(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
pr_info("qbman_cena_write_start(%p:%d:0x%03x)\n",
|
||||
s->addr_cena, s->idx, offset);
|
||||
#endif
|
||||
QBMAN_BUG_ON(offset & 63);
|
||||
return (s->addr_cena + offset);
|
||||
}
|
||||
|
||||
static inline void qbman_cena_write_complete(struct qbman_swp_sys *s,
|
||||
uint32_t offset, void *cmd)
|
||||
{
|
||||
const uint32_t *shadow = cmd;
|
||||
int loop;
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
pr_info("qbman_cena_write_complete(%p:%d:0x%03x) %p\n",
|
||||
s->addr_cena, s->idx, offset, shadow);
|
||||
hexdump(cmd, 64);
|
||||
#endif
|
||||
for (loop = 15; loop >= 1; loop--)
|
||||
__raw_writel(shadow[loop], s->addr_cena +
|
||||
offset + loop * 4);
|
||||
lwsync();
|
||||
__raw_writel(shadow[0], s->addr_cena + offset);
|
||||
dcbf(s->addr_cena + offset);
|
||||
}
|
||||
|
||||
static inline void qbman_cena_write_complete_wo_shadow(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
pr_info("qbman_cena_write_complete(%p:%d:0x%03x)\n",
|
||||
s->addr_cena, s->idx, offset);
|
||||
hexdump(cmd, 64);
|
||||
#endif
|
||||
dcbf(s->addr_cena + offset);
|
||||
}
|
||||
|
||||
static inline uint32_t qbman_cena_read_reg(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
return __raw_readl(s->addr_cena + offset);
|
||||
}
|
||||
|
||||
static inline void *qbman_cena_read(struct qbman_swp_sys *s, uint32_t offset)
|
||||
{
|
||||
uint32_t *shadow = (uint32_t *)(s->cena + offset);
|
||||
unsigned int loop;
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
pr_info("qbman_cena_read(%p:%d:0x%03x) %p\n",
|
||||
s->addr_cena, s->idx, offset, shadow);
|
||||
#endif
|
||||
|
||||
for (loop = 0; loop < 16; loop++)
|
||||
shadow[loop] = __raw_readl(s->addr_cena + offset
|
||||
+ loop * 4);
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
hexdump(shadow, 64);
|
||||
#endif
|
||||
return shadow;
|
||||
}
|
||||
|
||||
static inline void *qbman_cena_read_wo_shadow(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
pr_info("qbman_cena_read(%p:%d:0x%03x) %p\n",
|
||||
s->addr_cena, s->idx, offset, shadow);
|
||||
#endif
|
||||
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
hexdump(shadow, 64);
|
||||
#endif
|
||||
return s->addr_cena + offset;
|
||||
}
|
||||
|
||||
static inline void qbman_cena_invalidate(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
dccivac(s->addr_cena + offset);
|
||||
}
|
||||
|
||||
static inline void qbman_cena_invalidate_prefetch(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
dccivac(s->addr_cena + offset);
|
||||
prefetch_for_load(s->addr_cena + offset);
|
||||
}
|
||||
|
||||
static inline void qbman_cena_prefetch(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
prefetch_for_load(s->addr_cena + offset);
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* Portal support */
|
||||
/******************/
|
||||
|
||||
/* The SWP_CFG portal register is special, in that it is used by the
|
||||
* platform-specific code rather than the platform-independent code in
|
||||
* qbman_portal.c. So use of it is declared locally here.
|
||||
*/
|
||||
#define QBMAN_CINH_SWP_CFG 0xd00
|
||||
|
||||
/* For MC portal use, we always configure with
|
||||
* DQRR_MF is (SWP_CFG,20,3) - DQRR max fill (<- 0x4)
|
||||
* EST is (SWP_CFG,16,3) - EQCR_CI stashing threshold (<- 0x2)
|
||||
* RPM is (SWP_CFG,12,2) - RCR production notification mode (<- 0x3)
|
||||
* DCM is (SWP_CFG,10,2) - DQRR consumption notification mode (<- 0x2)
|
||||
* EPM is (SWP_CFG,8,2) - EQCR production notification mode (<- 0x2)
|
||||
* SD is (SWP_CFG,5,1) - memory stashing drop enable (<- TRUE)
|
||||
* SP is (SWP_CFG,4,1) - memory stashing priority (<- TRUE)
|
||||
* SE is (SWP_CFG,3,1) - memory stashing enable (<- TRUE)
|
||||
* DP is (SWP_CFG,2,1) - dequeue stashing priority (<- TRUE)
|
||||
* DE is (SWP_CFG,1,1) - dequeue stashing enable (<- TRUE)
|
||||
* EP is (SWP_CFG,0,1) - EQCR_CI stashing priority (<- TRUE)
|
||||
*/
|
||||
static inline uint32_t qbman_set_swp_cfg(uint8_t max_fill, uint8_t wn,
|
||||
uint8_t est, uint8_t rpm, uint8_t dcm,
|
||||
uint8_t epm, int sd, int sp, int se,
|
||||
int dp, int de, int ep)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = e32_uint8_t(20, (uint32_t)(3 + (max_fill >> 3)), max_fill) |
|
||||
e32_uint8_t(16, 3, est) |
|
||||
e32_uint8_t(12, 2, rpm) | e32_uint8_t(10, 2, dcm) |
|
||||
e32_uint8_t(8, 2, epm) | e32_int(5, 1, sd) |
|
||||
e32_int(4, 1, sp) | e32_int(3, 1, se) | e32_int(2, 1, dp) |
|
||||
e32_int(1, 1, de) | e32_int(0, 1, ep) | e32_uint8_t(14, 1, wn);
|
||||
return reg;
|
||||
}
|
||||
|
||||
static inline int qbman_swp_sys_init(struct qbman_swp_sys *s,
|
||||
const struct qbman_swp_desc *d,
|
||||
uint8_t dqrr_size)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
s->addr_cena = d->cena_bar;
|
||||
s->addr_cinh = d->cinh_bar;
|
||||
s->idx = (uint32_t)d->idx;
|
||||
s->cena = (void *)get_zeroed_page(GFP_KERNEL);
|
||||
if (!s->cena) {
|
||||
pr_err("Could not allocate page for cena shadow\n");
|
||||
return -1;
|
||||
}
|
||||
s->eqcr_mode = d->eqcr_mode;
|
||||
QBMAN_BUG_ON(d->idx < 0);
|
||||
#ifdef QBMAN_CHECKING
|
||||
/* We should never be asked to initialise for a portal that isn't in
|
||||
* the power-on state. (Ie. don't forget to reset portals when they are
|
||||
* decommissioned!)
|
||||
*/
|
||||
reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG);
|
||||
QBMAN_BUG_ON(reg);
|
||||
#endif
|
||||
if (s->eqcr_mode == qman_eqcr_vb_array)
|
||||
reg = qbman_set_swp_cfg(dqrr_size, 0, 0, 3, 2, 3, 1, 1, 1, 1,
|
||||
1, 1);
|
||||
else
|
||||
reg = qbman_set_swp_cfg(dqrr_size, 0, 2, 3, 2, 2, 1, 1, 1, 1,
|
||||
1, 1);
|
||||
qbman_cinh_write(s, QBMAN_CINH_SWP_CFG, reg);
|
||||
reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG);
|
||||
if (!reg) {
|
||||
pr_err("The portal %d is not enabled!\n", s->idx);
|
||||
kfree(s->cena);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void qbman_swp_sys_finish(struct qbman_swp_sys *s)
|
||||
{
|
||||
free_page((unsigned long)s->cena);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
qbman_cena_write_start_wo_shadow_fast(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
pr_info("qbman_cena_write_start(%p:%d:0x%03x)\n",
|
||||
s->addr_cena, s->idx, offset);
|
||||
#endif
|
||||
QBMAN_BUG_ON(offset & 63);
|
||||
return (s->addr_cena + offset);
|
||||
}
|
73
drivers/bus/fslmc/qbman/qbman_sys_decl.h
Normal file
73
drivers/bus/fslmc/qbman/qbman_sys_decl.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (C) 2014-2016 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <compat.h>
|
||||
#include <fsl_qbman_base.h>
|
||||
|
||||
/* Sanity check */
|
||||
#if (__BYTE_ORDER__ != __ORDER_BIG_ENDIAN__) && \
|
||||
(__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__)
|
||||
#error "Unknown endianness!"
|
||||
#endif
|
||||
|
||||
/* The platform-independent code shouldn't need endianness, except for
|
||||
* weird/fast-path cases like qbman_result_has_token(), which needs to
|
||||
* perform a passive and endianness-specific test on a read-only data structure
|
||||
* very quickly. It's an exception, and this symbol is used for that case.
|
||||
*/
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define DQRR_TOK_OFFSET 0
|
||||
#define QBMAN_RESULT_VERB_OFFSET_IN_MEM 24
|
||||
#define SCN_STATE_OFFSET_IN_MEM 8
|
||||
#define SCN_RID_OFFSET_IN_MEM 8
|
||||
#else
|
||||
#define DQRR_TOK_OFFSET 24
|
||||
#define QBMAN_RESULT_VERB_OFFSET_IN_MEM 0
|
||||
#define SCN_STATE_OFFSET_IN_MEM 16
|
||||
#define SCN_RID_OFFSET_IN_MEM 0
|
||||
#endif
|
||||
|
||||
/* Similarly-named functions */
|
||||
#define upper32(a) upper_32_bits(a)
|
||||
#define lower32(a) lower_32_bits(a)
|
||||
|
||||
/****************/
|
||||
/* arch assists */
|
||||
/****************/
|
||||
#define dcbz(p) { asm volatile("dc zva, %0" : : "r" (p) : "memory"); }
|
||||
#define lwsync() { asm volatile("dmb st" : : : "memory"); }
|
||||
#define dcbf(p) { asm volatile("dc cvac, %0" : : "r"(p) : "memory"); }
|
||||
#define dccivac(p) { asm volatile("dc civac, %0" : : "r"(p) : "memory"); }
|
||||
static inline void prefetch_for_load(void *p)
|
||||
{
|
||||
asm volatile("prfm pldl1keep, [%0, #64]" : : "r" (p));
|
||||
}
|
||||
|
||||
static inline void prefetch_for_store(void *p)
|
||||
{
|
||||
asm volatile("prfm pstl1keep, [%0, #64]" : : "r" (p));
|
||||
}
|
@ -1,6 +1,25 @@
|
||||
DPDK_17.05 {
|
||||
global:
|
||||
|
||||
qbman_check_command_complete;
|
||||
qbman_eq_desc_clear;
|
||||
qbman_eq_desc_set_no_orp;
|
||||
qbman_eq_desc_set_qd;
|
||||
qbman_eq_desc_set_response;
|
||||
qbman_get_version;
|
||||
qbman_pull_desc_clear;
|
||||
qbman_pull_desc_set_fq;
|
||||
qbman_pull_desc_set_numframes;
|
||||
qbman_pull_desc_set_storage;
|
||||
qbman_release_desc_clear;
|
||||
qbman_release_desc_set_bpid;
|
||||
qbman_result_DQ_fd;
|
||||
qbman_result_DQ_flags;
|
||||
qbman_result_has_new_result;
|
||||
qbman_swp_acquire;
|
||||
qbman_swp_pull;
|
||||
qbman_swp_release;
|
||||
qbman_swp_send_multiple;
|
||||
rte_fslmc_driver_register;
|
||||
rte_fslmc_driver_unregister;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user