/* Copyright 2009-2011 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 FSL_PME_H
#define FSL_PME_H

/* pme_fd_res_status() returns this enum */
enum pme_status {
	pme_status_ok = 0x00,
	pme_status_kes_ccl = 0x40, /* KES Confidence Collision Limit */
	pme_status_kes_cme = 0x41, /* KES Confidence Mask Error */
	pme_status_dxe_ire = 0x48, /* DXE Invalid Repeat Error */
	pme_status_dxe_tlse = 0x49, /* DXE Test Line Syntax Error */
	pme_status_dxe_ile = 0x4b, /* DXE Instruction Limit Error */
	pme_status_dxe_pdsrsore = 0x4c, /* DXE PDSR Space Out Range Error */
	pme_status_dxe_soe = 0x4d, /* DXE Stack Overflow Error */
	pme_status_dxe_alse = 0x4e, /* DXE Alternate Link Same Error */
	pme_status_dxe_slse = 0x4f, /* DXE Subsequent Link Same Error */
	pme_status_dxe_slre = 0x50, /* DXE Subsequent Link Reverse Error */
	pme_status_dxe_itlb = 0x51, /* DXE Invalid Test Line Branch */
	pme_status_dxe_cle = 0x52, /* DXE Compare Limit Exceeded */
	pme_status_dxe_mle = 0x53, /* DXE Match Limit Exceeded */
	pme_status_sre_irhbni = 0x59, /* SRE Invalid Reaction Head Block */
				      /* Number Instructions */
	pme_status_sre_rl = 0x5a, /* SRE Reaction Limit */
	pme_status_sre_pdsrsore = 0x5b, /* SRE PDSR Space Out Range Error */
	pme_status_sre_score = 0x5c, /* SRE Session Context Out Range Error */
	pme_status_sre_ctore = 0x5d, /* SRE Context Table Out Range Error */
	pme_status_sre_il = 0x5e, /* SRE Instruction Limit */
	pme_status_sre_iij = 0x5f, /* SRE Invalid Instruction Jump */
	pme_status_sre_ise = 0x60, /* SRE Instruction Syntax Error */
	pme_status_pmfa_pmtcce = 0x80, /* PMFA PCTCC Error */
	pme_status_pmfa_fcwe = 0x90, /* PMFA Flow Context Write Command Error */
	pme_status_pmfa_fcre = 0x91, /* PMFA Flow Context Read Command Error */
	pme_status_pmfa_ume = 0x93, /* PMFA Unrecognized Mode Error */
	pme_status_pmfa_uce = 0x94, /* PMFA Unrecognized Command Error */
	pme_status_pmfa_ufe = 0x95, /* PMFA Unrecognized Frame Error */
	pme_status_sre_csmre = 0xc0, /* SRE Context System Memory Read Error */
	pme_status_sre_ismre = 0xc1, /* SRE Instruction System Memory Read */
				     /* Error */
	pme_status_dxe_smre = 0xc2, /* DXE System Memory Read Error */
	pme_status_pmfa_pmtccsmre = 0xc4, /* PMFA PMTCC System Memory Read */
					  /* Error */
	pme_status_pmfa_csmre = 0xc5, /* PMFA Context System Memory Read */
				      /* Error */
	pme_status_pmfa_dsmre = 0xc6, /* PMFA Data System Memory Read Error */
	pme_status_kes_cmecce = 0xd2, /* KES Confidence Memory ECC Error */
	pme_status_kes_2btmecce = 0xd4, /*KES 2-Byte Trigger Memory ECC Error */
	pme_status_kes_vltmecce = 0xd5, /*KES Variable Length Trigger Memory */
					/* ECC Error */
	pme_status_pmfa_cmecce = 0xd7, /* PMFA Confidence Memory ECC Error */
	pme_status_pmfa_2btmecce = 0xd9, /* PMFA 2-Byte Trigger Memory ECC */
					 /* Error */
	pme_status_pmfa_vltmecce = 0xda, /* PMFA Variable Length Trigger */
					  /* Memory ECC Error */
	pme_status_dxe_iemce = 0xdb, /* DXE Internal Examination Memory */
				     /* Collision Error */
	pme_status_dxe_iemecce = 0xdc, /* DXE Internal Examination Memory */
				       /* ECC Error */
	pme_status_dxe_icmecce = 0xdd, /* DXE Internal Context Memory ECC */
				       /* Error */
	pme_status_sre_ctsmwe = 0xe0, /* SRE Context Table System Memory */
				      /* Write Error */
	pme_status_pmfa_pmtccsmwe = 0xe7, /* PMFA PMTCC System Memory Write */
					  /* Error */
	pme_status_pmfa_csmwe = 0xe8, /* PMFA Context System Memory Write */
				      /* Error */
	pme_status_pmfa_dsmwe = 0xe9, /* PMFA Data System Memory Write Error */
};

/* pme_fd_res_flags() returns these flags */
#define PME_STATUS_UNRELIABLE	0x80
#define PME_STATUS_TRUNCATED	0x10
#define PME_STATUS_MASK		0x90

/**************/
/* USER SPACE */
/**************/

#define PME_IOCTL_MAGIC 'p'

/* Wrapper for a pointer and size. */
struct pme_buffer {
	void __user *data;
	size_t size;
};

/***************/
/* SCAN DEVICE */
/***************/
/*
 * The /dev/pme_scan device creates a file-descriptor that uses scheduled FQs
 * serviced by PME's datapath portal. This can only be used for scanning.
 */
#define PME_DEV_SCAN_NODE	"pme_scan"
#define PME_DEV_SCAN_PATH	"/dev/" PME_DEV_SCAN_NODE

/* ioctls for 'scan' device */
#define PMEIO_SETSCAN	_IOW(PME_IOCTL_MAGIC, 0x06, struct pme_scan_params)
#define PMEIO_GETSCAN	_IOR(PME_IOCTL_MAGIC, 0x07, struct pme_scan_params)
#define PMEIO_RESETSEQ	_IO(PME_IOCTL_MAGIC, 0x08)
#define PMEIO_RESETRES	_IO(PME_IOCTL_MAGIC, 0x09)
#define PMEIO_SCAN_W1	_IOW(PME_IOCTL_MAGIC, 0x0a, struct pme_scan_cmd)
#define PMEIO_SCAN_Wn	_IOWR(PME_IOCTL_MAGIC, 0x0b, struct pme_scan_cmds)
#define PMEIO_SCAN_R1	_IOR(PME_IOCTL_MAGIC, 0x0c, struct pme_scan_result)
#define PMEIO_SCAN_Rn	_IOWR(PME_IOCTL_MAGIC, 0x0d, struct pme_scan_results)
#define PMEIO_SCAN	_IOWR(PME_IOCTL_MAGIC, 0x0e, struct pme_scan)
/* The release_bufs ioctl takes as parameter a (void *) */
#define PMEIO_RELEASE_BUFS _IOW(PME_IOCTL_MAGIC, 0x0f, void *)

/*
 * Parameters for PMEIO_SETSCAN and PMEIO_GETSCAN ioctl()s. This doesn't cover
 * "sequence" fields ('soc' and 'seqnum'), they can only be influenced by flags
 * passed to scan operations, or by PMEIO_RESETSEQ ioctl()s.
 */
struct pme_scan_params {
	__u32 flags; /* PME_SCAN_PARAMS_*** bitmask */
	struct pme_scan_params_residue {
		__u8 enable; /* boolean, residue enable */
		__u8 length; /* read-only for GETSCAN, ignored for SETSCAN */
	} residue;
	struct pme_scan_params_sre {
		__u32 sessionid; /* 27-bit */
		__u8 verbose; /* 0-3 */
		__u8 esee; /* boolean, End Of Sui Event Enable */
	} sre;
	struct pme_scan_params_dxe {
		__u16 clim; /* compare limit */
		__u16 mlim; /* match limit */
	} dxe;
	struct pme_scan_params_pattern {
		__u8 set;
		__u16 subset;
	} pattern;
};
#define PME_SCAN_PARAMS_RESIDUE	0x00000001
#define PME_SCAN_PARAMS_SRE	0x00000002
#define PME_SCAN_PARAMS_DXE	0x00000004
#define PME_SCAN_PARAMS_PATTERN	0x00000008

/* argument to PMEIO_SCAN_W1 ioctl */
struct pme_scan_cmd {
	__u32 flags; /* PME_SCAN_CMD_*** bitmask */
	void *opaque; /* value carried through in the pme_scan_result */
	struct pme_buffer input;
	struct pme_buffer output; /* ignored for 'RES_BMAN' output */
};

#define PME_SCAN_CMD_RES_BMAN	0x00000001 /* use Bman for output */
#define PME_SCAN_CMD_STARTRESET	0x00000002
#define PME_SCAN_CMD_END	0x00000004

/* argument to PMEIO_SCAN_Wn ioctl
 * 'num' indicates how many 'cmds' are present on input and is updated on the
 * response to indicate how many were sent. */
struct pme_scan_cmds {
	unsigned num;
	struct pme_scan_cmd __user *cmds;
};

/*
 * argument to PMEIO_SCAN_R1 ioctl. The ioctl doesn't read any of these
 * fields, they are only written to. If the output comes from BMAN buffer
 * then 'flags' will have PME_SCAN_RESULT_BMAN set.
 */
struct pme_scan_result {
	__u8 flags; /* PME_SCAN_RESULT_*** bitmask */
	enum pme_status status;
	struct pme_buffer output;
	void *opaque; /* value carried from the pme_scan_cmd */
};
#define PME_SCAN_RESULT_UNRELIABLE	PME_STATUS_UNRELIABLE
#define PME_SCAN_RESULT_TRUNCATED	PME_STATUS_TRUNCATED
#define PME_SCAN_RESULT_BMAN		0x01

/*
 * argument to PMEIO_SCAN_Rn ioctl.
 * 'num' indicates how many 'cmds' are present on input and is updated on the
 * response to indicate how many were retrieved.
 */
struct pme_scan_results {
	unsigned num;
	struct pme_scan_result *results;
};

/* argument to PMEIO_SCANWR ioctl. */
struct pme_scan {
	struct pme_scan_cmd cmd;
	struct pme_scan_result result;
};

/*************/
/* DB DEVICE */
/*************/
/*
 * The /dev/pme_db device creates a file-descriptor that uses parked FQs
 * serviced by the PME's EFQC (Exclusive Frame Queue Control) mechanism. This is
 * usually for PMTCC commands for programming the database, though can also be
 * used for high-priority scanning. This device would typically require root
 * perms. The EFQC exclusivity is reference-counted, so by default is asserted
 * on-demand and released when processing quiesces for the context, but
 * exclusivity can be maintained across inter-frame gaps using the INC and DEC
 * ioctls, which provide supplementary increments and decrements of the
 * reference count.
 */
#define PME_DEV_DB_NODE	"pme_db"
#define PME_DEV_DB_PATH	"/dev/" PME_DEV_DB_NODE

/* ioctls for 'db' device */
#define PMEIO_EXL_INC	_IO(PME_IOCTL_MAGIC, 0x00)
#define PMEIO_EXL_DEC	_IO(PME_IOCTL_MAGIC, 0x01)
#define PMEIO_EXL_GET	_IOR(PME_IOCTL_MAGIC, 0x02, int)
#define PMEIO_PMTCC	_IOWR(PME_IOCTL_MAGIC, 0x03, struct pme_db)
#define PMEIO_SRE_RESET	_IOR(PME_IOCTL_MAGIC, 0x04, struct pme_db_sre_reset)
#define PMEIO_NOP	_IO(PME_IOCTL_MAGIC, 0x05)

/* Database structures */
#define PME_DB_RESULT_UNRELIABLE	PME_STATUS_UNRELIABLE
#define PME_DB_RESULT_TRUNCATED		PME_STATUS_TRUNCATED

struct pme_db {
	struct pme_buffer input;
	struct pme_buffer output;
	__u8 flags; /* PME_DB_RESULT_*** bitmask */
	enum pme_status status;
};

/* This is related to the sre_reset ioctl */
#define PME_SRE_RULE_VECTOR_SIZE  8
struct pme_db_sre_reset {
	__u32 rule_vector[PME_SRE_RULE_VECTOR_SIZE];
	__u32 rule_index;
	__u16 rule_increment;
	__u32 rule_repetitions;
	__u16 rule_reset_interval;
	__u8 rule_reset_priority;
};

/****************/
/* KERNEL SPACE */
/****************/

#ifdef __KERNEL__

#include <linux/fsl_qman.h>
#include <linux/fsl_bman.h>

/*
 * "struct pme_hw_flow" represents a flow-context resource for h/w, whereas
 * "struct pme_flow" (below) is the s/w type used to provide (and receive)
 * parameters to(/from) the h/w resource.
 */
struct pme_hw_flow;

/* "struct pme_hw_residue" represents a residue resource for h/w. */
struct pme_hw_residue;

/*
 * This is the pme_flow structure type, used for querying or updating a PME flow
 * context
 */
struct pme_flow {
	u8 sos:1;
	u8 __reserved1:1;
	u8 srvm:2;
	u8 esee:1;
	u8 __reserved2:3;
	u8 ren:1;
	u8 rlen:7;
	/* Sequence Number (48-bit) */
	u16 seqnum_hi;
	u32 seqnum_lo;
	u32 __reserved3;
	u32 sessionid:27;
	u32 __reserved4:5;
	u16 __reserved5;
	/* Residue pointer (48-bit), ignored if ren==0 */
	u16 rptr_hi;
	u32 rptr_lo;
	u16 clim;
	u16 mlim;
	u32 __reserved6;
} __packed;
static inline u64 pme_flow_seqnum_get64(const struct pme_flow *p)
{
	return ((u64)p->seqnum_hi << 32) | (u64)p->seqnum_lo;
}
static inline u64 pme_flow_rptr_get64(const struct pme_flow *p)
{
	return ((u64)p->rptr_hi << 32) | (u64)p->rptr_lo;
}
/* Macro, so we compile better if 'v' isn't always 64-bit */
#define pme_flow_seqnum_set64(p, v) \
	do { \
		struct pme_flow *__p931 = (p); \
		__p931->seqnum_hi = upper_32_bits(v); \
		__p931->seqnum_lo = lower_32_bits(v); \
	} while (0)
#define pme_flow_rptr_set64(p, v) \
	do { \
		struct pme_flow *__p931 = (p); \
		__p931->rptr_hi = upper_32_bits(v); \
		__p931->rptr_lo = lower_32_bits(v); \
	} while (0)

/*
 * pme_ctx_ctrl_update_flow(), pme_fd_cmd_fcw() and pme_scan_params::flags
 * use these;
 */
#define PME_CMD_FCW_RES	0x80	/* "Residue": ren, rlen */
#define PME_CMD_FCW_SEQ	0x40	/* "Sequence": sos, sequnum */
#define PME_CMD_FCW_SRE	0x20	/* "Stateful Rule": srvm, esee, sessionid */
#define PME_CMD_FCW_DXE	0x10	/* "Data Examination": clim, mlim */
#define PME_CMD_FCW_ALL 0xf0

/* pme_ctx_scan() and pme_fd_cmd_scan() use these; */
#define PME_CMD_SCAN_SRVM(n) ((n) << 3) /* n in [0..3] */
#define PME_CMD_SCAN_FLUSH 0x04
#define PME_CMD_SCAN_SR    0x02 /* aka "Start of Flow or Reset */
#define PME_CMD_SCAN_E     0x01 /* aka "End of Flow */

/***********************/
/* low-level functions */
/***********************/

/* (De)Allocate PME hardware resources */
struct pme_hw_residue *pme_hw_residue_new(void);
void pme_hw_residue_free(struct pme_hw_residue *);
struct pme_hw_flow *pme_hw_flow_new(void);
void pme_hw_flow_free(struct pme_hw_flow *);

/* Initialise a flow context to known default values */
void pme_sw_flow_init(struct pme_flow *);

/*
 * Fill in an "Initialise FQ" management command for a PME input FQ. NB, the
 * caller is responsible for setting the following fields, they will not be set
 * by the API;
 *   - initfq->fqid, the frame queue to be initialised
 *   - initfq->count, should most likely be zero. A count of 0 initialises 1 FQ,
 *			a count of 1 initialises 2 FQs, etc/
 * The 'qos' parameter indicates which workqueue in the PME channel the
 * FQ should schedule to for regular scanning (0..7). If 'flow' is non-NULL the
 * FQ is configured for Flow Mode, otherwise it is configured for Direct Action
 * Mode. 'bpid' is the buffer pool ID to use when Bman-based output is
 * produced, and 'rfqid' is the frame queue ID to enqueue output frames to.
 * Following this api, when calling qm_mc_commit(), use QM_MCC_VERB_INITFQ_SCHED
 * for regular PMEscanning or QM_MCC_VERB_INITFQ_PARK for exclusive PME
 * processing (usually PMTCC).
 */
void pme_initfq(struct qm_mcc_initfq *initfq, struct pme_hw_flow *flow, u8 qos,
		u8 rbpid, u32 rfqid);

/* Given a dequeued frame from PME, return status/flags */
static inline enum pme_status pme_fd_res_status(const struct qm_fd *fd)
{
	return (enum pme_status)(fd->status >> 24);
}
static inline u8 pme_fd_res_flags(const struct qm_fd *fd)
{
	return (fd->status >> 16) & PME_STATUS_MASK;
}

/* Fill in a frame descriptor for a NOP command. */
void pme_fd_cmd_nop(struct qm_fd *fd);

/*
 * Fill in a frame descriptor for a Flow Context Write command. NB, the caller
 * is responsible for setting all the relevant fields in 'flow', only the
 * following fields are set by the API;
 *   - flow->rptr_hi
 *   - flow->rptr_lo
 * The fields in 'flow' are divided into 4 groups, 'flags' indicates which of
 * them should be written to the h/w flow context using PME_CMD_FCW_*** defines.
 * 'residue' should be non-NULL iff flow->ren is non-zero and PME_CMD_FCW_RES is
 * set.
 */
void pme_fd_cmd_fcw(struct qm_fd *fd, u8 flags, struct pme_flow *flow,
		struct pme_hw_residue *residue);

/* Fill in a frame descriptor for a Flow Context Read command. */
void pme_fd_cmd_fcr(struct qm_fd *fd, struct pme_flow *flow);

/* Modify a frame descriptor for a PMTCC command (only modifies 'cmd' field) */
void pme_fd_cmd_pmtcc(struct qm_fd *fd);

/*
 * Modify a frame descriptor for a Scan command (only modifies 'cmd' field).
 * 'flags' are chosen from PME_CMD_SCAN_*** symbols. NB, the use of the
 * intermediary representation (and PME_SCAN_ARGS) improves performance - ie.
 * if the scan params are essentially constant, this compacts them for storage
 * into the same format used in the interface to h/w. So it reduces parameter
 * passing, stack-use, and encoding time.
 */
#define PME_SCAN_ARGS(flags, set, subset) \
({ \
	u8 __flags461 = (flags); \
	u8 __set461 = (set); \
	u16 __subset461 = (subset); \
	u32 __res461 = ((u32)__flags461 << 24) | \
			((u32)__set461 << 16) | \
			(u32)__subset461; \
	__res461; \
})
void pme_fd_cmd_scan(struct qm_fd *fd, u32 args);

/* convert pointer to physical address for use by PME */
dma_addr_t pme_map(void *ptr);
int pme_map_error(dma_addr_t dma_addr);

enum pme_cmd_type {
	pme_cmd_nop = 0x7,
	pme_cmd_flow_read = 0x5,	/* aka FCR */
	pme_cmd_flow_write = 0x4,	/* aka FCW */
	pme_cmd_pmtcc = 0x1,
	pme_cmd_scan = 0
};

/************************/
/* high-level functions */
/************************/

/* predeclaration of a private structure" */
struct pme_ctx;
struct pme_nostash;

/*
 * Calls to pme_ctx_scan() and pme_ctx_pmtcc() provide these, and they are
 * provided back in the completion callback. You can embed this within a larger
 * structure in order to maintain per-command data of your own. The fields are
 * owned by the driver until the callback is invoked, so for example do not link
 * this token into a list while the command is in-flight!
 */
struct pme_ctx_token {
	u32 blob[4];
	struct list_head node;
	enum pme_cmd_type cmd_type:8;
	u8 is_disable_flush;
};

struct pme_ctx_ctrl_token {
	void (*cb)(struct pme_ctx *, const struct qm_fd *,
			struct pme_ctx_ctrl_token *);
	void (*ern_cb)(struct pme_ctx *, const struct qm_mr_entry *,
			struct pme_ctx_ctrl_token *);
	/* don't touch the rest */
	struct pme_hw_flow *internal_flow_ptr;
	struct pme_flow *usr_flow_ptr;
	struct pme_ctx_token base_token;
};

/* Scan results invoke a user-provided callback of this type */
typedef void (*pme_scan_cb)(struct pme_ctx *, const struct qm_fd *,
				struct pme_ctx_token *);
/*
 * Enqueue rejections may happen before order-restoration or after (eg. if due
 * to congestion or tail-drop). Use * 'rc' code of the 'mr_entry' to
 * determine.
 */
typedef void (*pme_scan_ern_cb)(struct pme_ctx *, const struct qm_mr_entry *,
				struct pme_ctx_token *);

/*
 * PME "association" - ie. connects two frame-queues, with or without a PME flow
 * (if not, direct action mode), and manages mux/demux of scans and flow-context
 * updates. To allow state used by your callback to be stashed, as well as
 * optimising the PME driver and the Qman driver beneath it, embed this
 * structure as the first field in your own context structure.
 */
struct pme_ctx {
	struct qman_fq fq;
	/*
	 * IMPORTANT: Set (only) these two fields prior to calling
	 * pme_ctx_init(). 'ern_cb' can be NULL if you know you will not
	 * receive enqueue rejections.
	 */
	pme_scan_cb cb;
	pme_scan_ern_cb ern_cb;
	/*
	 * These fields should not be manipulated directly. Also the structure
	 * may change and/or grow, so avoid making any alignment or size
	 * assumptions.
	 */
	atomic_t refs;
	volatile u32 flags;
	spinlock_t lock;
	wait_queue_head_t queue;
	struct list_head tokens;
	/*
	 * TODO: the following "slow-path" values should be bundled into a
	 * secondary structure so that sizeof(struct pme_ctx) is minimised (for
	 * stashing of caller-side fast-path state).
	 */
	struct pme_hw_flow *hw_flow;
	struct pme_hw_residue *hw_residue;
	struct qm_fqd_stashing stashing;
	struct qm_fd update_fd;
	struct pme_nostash *us_data;
	u32 pme_rev1;
	u32 pme_rev2;
	int max_scan_size;
};

/* Flags for pme_ctx_init() */
#define PME_CTX_FLAG_LOCKED      0x00000001 /* use QMAN_FQ_FLAG_LOCKED */
#define PME_CTX_FLAG_EXCLUSIVE   0x00000002 /* unscheduled, exclusive mode */
#define PME_CTX_FLAG_PMTCC       0x00000004 /* PMTCC rather than scanning */
#define PME_CTX_FLAG_DIRECT      0x00000008 /* Direct Action mode (not Flow) */
#define PME_CTX_FLAG_LOCAL       0x00000020 /* Ignore dest, use cpu portal */

/* Flags for operations */
#ifdef CONFIG_FSL_DPA_CAN_WAIT
#define PME_CTX_OP_WAIT          QMAN_ENQUEUE_FLAG_WAIT
#define PME_CTX_OP_WAIT_INT      QMAN_ENQUEUE_FLAG_WAIT_INT
#endif
#define PME_CTX_OP_RESETRESLEN   0x00000001 /* no en/disable, just set len */
/*
 * Note that pme_ctx_ctrl_update_flow() also uses PME_CMD_FCW flags, so they
 * mustn't conflict with PME_CTX_OP_***.
 * Also, the above are defined to match QMAN_ENQUEUE values for optimisation
 * purposes (ie. fast-path operations that don't _WAIT will not incur PME->QMAN
 * flag conversion overheads).
 */

/**
 * pme_ctx_init - Initialise a PME context
 * @ctx: the context structure to initialise
 * @flags: bit-mask of PME_CTX_FLAG_*** options
 * @bpid: buffer pool ID used for any Bman-generated output
 * @qosin: workqueue priority on the PME channel (0-7)
 * @qosout: workqueue priority on the result channel (0-7)
 * @dest: channel to receive results from PME
 * @stashing: desired dequeue stashing behaviour
 *
 * This creates and initialises a PME context, composed of two FQs, an optional
 * flow-context, and scheduling parameters for the datapath. The ctx->cb and
 * ctx->pool fields must have been initialised prior to calling this api. The
 * initialised context is left 'disabled', meaning that the FQ towards PME is
 * Parked and no operations are possible. If PME_CTX_INIT_EXCLUSIVE is specified
 * in @flags, then the input FQ is not scheduled, otherwise enabling the context
 * will schedule the FQ to PME. Exclusive access is only available if the driver
 * is built with control functionality and if the operating system has access to
 * PME's CCSR map. @qosin applies if EXCLUSIVE is not set, and indicates which
 * of the PME's 8 prioritised workqueues the FQ should schedule to. @dest
 * indicates the channel that should receive results from PME, unless
 * PME_CTX_FLAG_LOCAL is set in which case this parameter is ignored and the
 * dedicated portal channel for the current cpu will be used instead. @qosout
 * indicates which of the 8 prioritised workqueus the FQ should schedule to on
 * the s/w portal. @stashing configures whether FQ context, frame data, and/or
 * frame annotation should be stashed into cpu cache when dequeuing output, and
 * if so, how many cachelines.  For the FQ context part, set the number of
 * cachelines to cover; 1. sizeof(struct qman_fq_base), to accelerate only Qman
 * driver processing, 2. sizeof(struct pme_ctx), to accelerate Qman and PME
 * driver processing, or 3. sizeof(<user-struct>), where <user-struct> is the
 * caller's structure of which the pme_ctx is the first member - this will allow
 * callbacks to operate on state which has a high probability of already being
 * in-cache.
 * Returns 0 on success.
 */
int pme_ctx_init(struct pme_ctx *ctx, u32 flags, u32 bpid, u8 qosin,
			u8 qosout, u16 dest,
			const struct qm_fqd_stashing *stashing);

/* Cleanup allocated resources */
void pme_ctx_finish(struct pme_ctx *ctx);

/* enable a context */
int pme_ctx_enable(struct pme_ctx *ctx);

/*
 * disable a context
 * If it returns zero, the context is disabled.
 * If it returns +1, the context is disabling and the token's completion
 * callback will be invoked when disabling is complete.
 * Returns -EBUSY on error, in which case the context remains enabled.
 * If the PME_CTX_OP_WAIT flag is specified, it should only fail if
 * PME_CTX_OP_WAIT_INT is also specified and a signal is pending.
 */
int pme_ctx_disable(struct pme_ctx *ctx, u32 flags,
		struct pme_ctx_ctrl_token *token);

/* query whether a context is disabled. Returns > 0 if the ctx is disabled. */
int pme_ctx_is_disabled(struct pme_ctx *ctx);

/* query whether a context is in an error state. */
int pme_ctx_is_dead(struct pme_ctx *ctx);

/*
 * A pre-condition for the following APIs is the ctx must be disabled
 * dest maybe ignored if the flags parameter indicated LOCAL during the
 * corresponding pme_ctx_init.
 */
int pme_ctx_reconfigure_tx(struct pme_ctx *ctx, u32 bpid, u8 qosin);
int pme_ctx_reconfigure_rx(struct pme_ctx *ctx, u8 qosout,
		u16 dest, const struct qm_fqd_stashing *stashing);

/*
 * Precondition: pme_ctx must be enabled
 * if PME_CTX_OP_WAIT is specified, it'll wait (if it has to) to start the ctrl
 * command but never waits for it to complete. The callback serves that purpose.
 * NB: 'params' may be modified by this call. For instance if
 * PME_CTX_OP_RESETRESLEN was specified and residue is enabled, then the
 * params->ren will be set to 1 (in order not to disabled residue).
 * NB: _update() will overwrite the 'params->rptr_[hi/low]' fields since the
 * residue resource is managed by this layer.
 */
int pme_ctx_ctrl_update_flow(struct pme_ctx *ctx, u32 flags,
		struct pme_flow *params, struct pme_ctx_ctrl_token *token);
int pme_ctx_ctrl_read_flow(struct pme_ctx *ctx, u32 flags,
		struct pme_flow *params, struct pme_ctx_ctrl_token *token);
int pme_ctx_ctrl_nop(struct pme_ctx *ctx, u32 flags,
		struct pme_ctx_ctrl_token *token);

/*
 * if PME_CTX_OP_WAIT is specified, it'll wait (if it has to) to start the scan
 * but never waits for it to complete. The scan callback serves that purpose.
 * 'fd' is modified by both these calls, but only the 'cmd' field. The 'args'
 * parameters is produced by the PME_SCAN_ARGS() inline function.
 */
int pme_ctx_scan(struct pme_ctx *ctx, u32 flags, struct qm_fd *fd, u32 args,
		struct pme_ctx_token *token);
int pme_ctx_pmtcc(struct pme_ctx *ctx, u32 flags, struct qm_fd *fd,
		struct pme_ctx_token *token);

/*
 * This is extends pme_ctx_scan() to provide ORP support. 'orp_fq' represents
 * the FQD that is used as the ORP and 'seqnum' is the sequence number to use
 * for order restoration, these are usually the FQ the frame was dequeued from
 * and the sequence number of that dequeued frame (respectively).
 */
int pme_ctx_scan_orp(struct pme_ctx *ctx, u32 flags, struct qm_fd *fd, u32 args,
	       struct pme_ctx_token *token, struct qman_fq *orp_fq, u16 seqnum);

/* Precondition: must be PME_CTX_FLAG_EXCLUSIVE */
int pme_ctx_exclusive_inc(struct pme_ctx *ctx, u32 flags);
void pme_ctx_exclusive_dec(struct pme_ctx *ctx);

/* Does pme have access to ccsr */
int pme2_have_control(void);

/**************************/
/* control-plane only API */
/**************************/
#ifdef CONFIG_FSL_PME2_CTRL

/* Attributes for pme_reg_[set|get]() */
enum pme_attr {
	pme_attr_efqc_int,
	pme_attr_sw_db,
	pme_attr_dmcr,
	pme_attr_smcr,
	pme_attr_famcr,
	pme_attr_kvlts,
	pme_attr_max_chain_length,
	pme_attr_pattern_range_counter_idx,
	pme_attr_pattern_range_counter_mask,
	pme_attr_max_allowed_test_line_per_pattern,
	pme_attr_max_pdsr_index,
	pme_attr_max_pattern_matches_per_sui,
	pme_attr_max_pattern_evaluations_per_sui,
	pme_attr_report_length_limit,
	pme_attr_end_of_simple_sui_report,
	pme_attr_aim,
	pme_attr_sre_context_size,
	pme_attr_sre_rule_num,
	pme_attr_sre_session_ctx_num,
	pme_attr_end_of_sui_reaction_ptr,
	pme_attr_sre_pscl,
	pme_attr_sre_max_block_num,
	pme_attr_sre_max_instruction_limit,
	pme_attr_sre_max_index_size,
	pme_attr_sre_max_offset_ctrl,
	pme_attr_src_id,
	pme_attr_liodnr,
	pme_attr_rev1,
	pme_attr_rev2,
	pme_attr_srrv0,
	pme_attr_srrv1,
	pme_attr_srrv2,
	pme_attr_srrv3,
	pme_attr_srrv4,
	pme_attr_srrv5,
	pme_attr_srrv6,
	pme_attr_srrv7,
	pme_attr_srrfi,
	pme_attr_srri,
	pme_attr_srrwc,
	pme_attr_srrr,
	pme_attr_trunci,
	pme_attr_rbc,
	pme_attr_tbt0ecc1ec,
	pme_attr_tbt1ecc1ec,
	pme_attr_vlt0ecc1ec,
	pme_attr_vlt1ecc1ec,
	pme_attr_cmecc1ec,
	pme_attr_dxcmecc1ec,
	pme_attr_dxemecc1ec,
	pme_attr_stnib,
	pme_attr_stnis,
	pme_attr_stnth1,
	pme_attr_stnth2,
	pme_attr_stnthv,
	pme_attr_stnths,
	pme_attr_stnch,
	pme_attr_stnpm,
	pme_attr_stns1m,
	pme_attr_stnpmr,
	pme_attr_stndsr,
	pme_attr_stnesr,
	pme_attr_stns1r,
	pme_attr_stnob,
	pme_attr_mia_byc,
	pme_attr_mia_blc,
	pme_attr_isr,
	pme_attr_tbt0ecc1th,
	pme_attr_tbt1ecc1th,
	pme_attr_vlt0ecc1th,
	pme_attr_vlt1ecc1th,
	pme_attr_cmecc1th,
	pme_attr_dxcmecc1th,
	pme_attr_dxemecc1th,
	pme_attr_esr,
	pme_attr_ecr0,
	pme_attr_ecr1,
	pme_attr_pmstat,
	pme_attr_pmtr,
	pme_attr_pehd,
	pme_attr_ecc1bes,
	pme_attr_ecc2bes,
	pme_attr_eccaddr,
	pme_attr_ecccode,
	pme_attr_miace,
	pme_attr_miacr,
	pme_attr_cdcr,
	pme_attr_faconf,
	pme_attr_ier,
	pme_attr_isdr,
	pme_attr_iir,
	pme_attr_pdsrbah,
	pme_attr_pdsrbal,
	pme_attr_scbarh,
	pme_attr_scbarl,
	pme_attr_bsc_first, /* create 64-wide space for bsc */
	pme_attr_bsc_last = pme_attr_bsc_first + 63,
	pme_attr_faconf_rst,
	pme_attr_faconf_en,
	pme_attr_efqc
};

#define pme_attr_bsc(n) (pme_attr_bsc_first + (n))
/* Get/set driver attributes */
int pme_attr_set(enum pme_attr attr, u32 val);
int pme_attr_get(enum pme_attr attr, u32 *val);
int pme_stat_get(enum pme_attr stat, u64 *value, int reset);
#endif /* defined(CONFIG_FSL_PME2_CTRL) */

#ifdef CONFIG_COMPAT
#include <linux/compat.h>

struct compat_pme_buffer {
	compat_uptr_t data;
	compat_size_t size;
};

struct compat_pme_scan_cmd {
	__u32 flags; /* PME_SCAN_CMD_*** bitmask */
	compat_uptr_t opaque;
	struct compat_pme_buffer input;
	struct compat_pme_buffer output;
};
#define PMEIO_SCAN_W132	_IOW(PME_IOCTL_MAGIC, 0x0a, struct compat_pme_scan_cmd)

struct compat_pme_scan_cmds {
	compat_uint_t num;
	compat_uptr_t cmds;
};
#define PMEIO_SCAN_Wn32	_IOWR(PME_IOCTL_MAGIC, 0x0b, \
				struct compat_pme_scan_cmds)


struct compat_pme_scan_result {
	__u8 flags; /* PME_SCAN_RESULT_*** bitmask */
	enum pme_status status;
	struct compat_pme_buffer output;
	compat_uptr_t opaque;  /* value carried from the pme_scan_cmd */
};
#define PMEIO_SCAN_R132	_IOR(PME_IOCTL_MAGIC, 0x0c, \
				struct compat_pme_scan_result)


struct compat_pme_scan_results {
	compat_uint_t num;
	compat_uptr_t results;
};
#define PMEIO_SCAN_Rn32	_IOWR(PME_IOCTL_MAGIC, 0x0d, \
				struct compat_pme_scan_results)


struct compat_pme_scan {
	struct compat_pme_scan_cmd cmd;
	struct compat_pme_scan_result result;
};
#define PMEIO_SCAN32	_IOWR(PME_IOCTL_MAGIC, 0x0e, struct compat_pme_scan)

struct compat_pme_db {
	struct compat_pme_buffer input;
	struct compat_pme_buffer output;
	__u8 flags; /* PME_DB_RESULT_*** bitmask */
	enum pme_status status;
};
#define PMEIO_PMTCC32	_IOWR(PME_IOCTL_MAGIC, 0x03, struct compat_pme_db)

#endif /* CONFIG_COMPAT */

#endif /* __KERNEL__ */

#endif /* FSL_PME_H */
