#ifndef _INTELXLVF_H
#define _INTELXLVF_H

/** @file
 *
 * Intel 40 Gigabit Ethernet virtual function network card driver
 *
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
FILE_SECBOOT ( PERMITTED );

#include "intelxl.h"

/** BAR size */
#define INTELXLVF_BAR_SIZE 0x10000

/** MSI-X vector
 *
 * The 100 Gigabit physical function driver requires a virtual
 * function driver to request that transmit and receive queues are
 * mapped to MSI-X vector 1 or higher.
 */
#define INTELXLVF_MSIX_VECTOR 1

/** Transmit Queue Tail Register */
#define INTELXLVF_QTX_TAIL 0x00000

/** Receive Queue Tail Register */
#define INTELXLVF_QRX_TAIL 0x02000

/** VF Interrupt N Dynamic Control Register */
#define INTELXLVF_VFINT_DYN_CTLN( x ) ( 0x3800 + ( 0x4 * ( (x) - 1  ) ) )

/** VF Interrupt Zero Dynamic Control Register */
#define INTELXLVF_VFINT_DYN_CTL0 0x5c00

/** VF Admin Queue register block */
#define INTELXLVF_ADMIN 0x6000

/** Admin Command Queue Base Address Low Register (offset) */
#define INTELXLVF_ADMIN_CMD_BAL 0x1c00

/** Admin Command Queue Base Address High Register (offset) */
#define INTELXLVF_ADMIN_CMD_BAH 0x1800

/** Admin Command Queue Length Register (offset) */
#define INTELXLVF_ADMIN_CMD_LEN 0x0800

/** Admin Command Queue Head Register (offset) */
#define INTELXLVF_ADMIN_CMD_HEAD 0x0400

/** Admin Command Queue Tail Register (offset) */
#define INTELXLVF_ADMIN_CMD_TAIL 0x2400

/** Admin Event Queue Base Address Low Register (offset) */
#define INTELXLVF_ADMIN_EVT_BAL 0x0c00

/** Admin Event Queue Base Address High Register (offset) */
#define INTELXLVF_ADMIN_EVT_BAH 0x0000

/** Admin Event Queue Length Register (offset) */
#define INTELXLVF_ADMIN_EVT_LEN 0x2000

/** Admin Event Queue Head Register (offset) */
#define INTELXLVF_ADMIN_EVT_HEAD 0x1400

/** Admin Event Queue Tail Register (offset) */
#define INTELXLVF_ADMIN_EVT_TAIL 0x1000

/** Maximum time to wait for a VF admin request to complete */
#define INTELXLVF_ADMIN_MAX_WAIT_MS 2000

/** Admin queue Send Message to PF command */
#define INTELXLVF_ADMIN_SEND_TO_PF 0x0801

/** Admin queue Send Message to VF command */
#define INTELXLVF_ADMIN_SEND_TO_VF 0x0802

/** Admin Queue VF Version opcode */
#define INTELXLVF_ADMIN_VERSION 0x00000001

/** Admin Queue VF Version data buffer */
struct intelxlvf_admin_version_buffer {
	/** Major version */
	uint32_t major;
	/** Minor version */
	uint32_t minor;
} __attribute__ (( packed ));

/** Admin queue VF API major version */
#define INTELXLVF_ADMIN_API_MAJOR 1

/** Admin queue VF API minor version */
#define INTELXLVF_ADMIN_API_MINOR 1

/** Admin Queue VF Reset opcode */
#define INTELXLVF_ADMIN_RESET 0x00000002

/** Admin Queue VF Get Resources opcode */
#define INTELXLVF_ADMIN_GET_RESOURCES 0x00000003

/** Admin Queue VF Capabilities data buffer */
struct intelxlvf_admin_capabilities_buffer {
	/** Capabilities */
	uint32_t caps;
} __attribute__ (( packed ));

/** Admin Queue VF Get Resources data buffer */
struct intelxlvf_admin_get_resources_buffer {
	/** Number of VSIs */
	uint16_t vsis;
	/** Number of queue pairs */
	uint16_t qps;
	/** Number of MSI-X vectors */
	uint16_t vectors;
	/** Maximum MTU */
	uint16_t mtu;
	/** Capabilities */
	uint32_t caps;
	/** Reserved */
	uint8_t reserved_a[8];
	/** VSI switching element ID */
	uint16_t vsi;
	/** Reserved */
	uint8_t reserved_b[8];
	/** MAC address */
	uint8_t mac[ETH_ALEN];
} __attribute__ (( packed ));

/** Layer 2 capabilities (add/remove MAC, configure promiscuous mode) */
#define INTELXLVF_ADMIN_CAP_L2 0x00000001

/** Request Queues capabilities */
#define INTELXLVF_ADMIN_CAP_RQPS 0x00000040

/** Admin Queue VF Status Change Event opcode */
#define INTELXLVF_ADMIN_STATUS 0x00000011

/** Link status change event type */
#define INTELXLVF_ADMIN_STATUS_LINK 0x00000001

/** Link status change event data */
struct intelxlvf_admin_status_link {
	/** Link speed */
	uint32_t speed;
	/** Link status */
	uint8_t status;
	/** Reserved */
	uint8_t reserved[3];
} __attribute__ (( packed ));

/** Admin Queue VF Status Change Event data buffer */
struct intelxlvf_admin_status_buffer {
	/** Event type */
	uint32_t event;
	/** Event data */
	union {
		/** Link change event data */
		struct intelxlvf_admin_status_link link;
	} data;
	/** Reserved */
	uint8_t reserved[4];
} __attribute__ (( packed ));

/** Admin Queue VF Configure Queues opcode */
#define INTELXLVF_ADMIN_CONFIGURE 0x00000006

/** Admin Queue VF Configure Queues data buffer */
struct intelxlvf_admin_configure_buffer {
	/** VSI switching element ID */
	uint16_t vsi;
	/** Number of queue pairs */
	uint16_t count;
	/** Reserved */
	uint8_t reserved_a[4];
	/** Transmit queue */
	struct {
		/** VSI switching element ID */
		uint16_t vsi;
		/** Queue ID */
		uint16_t id;
		/** Queue count */
		uint16_t count;
		/** Reserved */
		uint8_t reserved_a[2];
		/** Base address */
		uint64_t base;
		/** Reserved */
		uint8_t reserved_b[8];
	} __attribute__ (( packed )) tx;
	/** Receive queue */
	struct {
		/** VSI switching element ID */
		uint16_t vsi;
		/** Queue ID */
		uint16_t id;
		/** Queue count */
		uint32_t count;
		/** Reserved */
		uint8_t reserved_a[4];
		/** Data buffer length */
		uint32_t len;
		/** Maximum frame size */
		uint32_t mfs;
		/** Reserved */
		uint8_t reserved_b[4];
		/** Base address */
		uint64_t base;
		/** Reserved */
		uint8_t reserved_c[8];
	} __attribute__ (( packed )) rx;
	/** Reserved
	 *
	 * This field exists only due to a bug in the PF driver's
	 * message validation logic, which causes it to miscalculate
	 * the expected message length.
	 */
	uint8_t reserved_b[64];
} __attribute__ (( packed ));

/** Admin Queue VF IRQ Map opcode */
#define INTELXLVF_ADMIN_IRQ_MAP 0x00000007

/** Admin Queue VF IRQ Map data buffer */
struct intelxlvf_admin_irq_map_buffer {
	/** Number of interrupt vectors */
	uint16_t count;
	/** VSI switching element ID */
	uint16_t vsi;
	/** Interrupt vector ID */
	uint16_t vec;
	/** Receive queue bitmap */
	uint16_t rxmap;
	/** Transmit queue bitmap */
	uint16_t txmap;
	/** Receive interrupt throttling index */
	uint16_t rxitr;
	/** Transmit interrupt throttling index */
	uint16_t txitr;
	/** Reserved
	 *
	 * This field exists only due to a bug in the PF driver's
	 * message validation logic, which causes it to miscalculate
	 * the expected message length.
	 */
	uint8_t reserved[12];
} __attribute__ (( packed ));

/** Admin Queue VF Enable Queues opcode */
#define INTELXLVF_ADMIN_ENABLE 0x00000008

/** Admin Queue VF Disable Queues opcode */
#define INTELXLVF_ADMIN_DISABLE 0x00000009

/** Admin Queue VF Enable/Disable Queues data buffer */
struct intelxlvf_admin_queues_buffer {
	/** VSI switching element ID */
	uint16_t vsi;
	/** Reserved */
	uint8_t reserved[2];
	/** Receive queue bitmask */
	uint32_t rx;
	/** Transmit queue bitmask */
	uint32_t tx;
} __attribute__ (( packed ));

/** Admin Queue VF Configure Promiscuous Mode opcode */
#define INTELXLVF_ADMIN_PROMISC 0x0000000e

/** Admin Queue VF Configure Promiscuous Mode data buffer */
struct intelxlvf_admin_promisc_buffer {
	/** VSI switching element ID */
	uint16_t vsi;
	/** Flags */
	uint16_t flags;
} __attribute__ (( packed ));

/** Admin Queue VF Get Statistics opcode */
#define INTELXLVF_ADMIN_GET_STATS 0x0000000f

/** VF statistics */
struct intelxlvf_admin_stats {
	/** Bytes */
	uint64_t bytes;
	/** Unicast packets */
	uint64_t unicasts;
	/** Multicast packets */
	uint64_t multicasts;
	/** Broadcast packets */
	uint64_t broadcasts;
	/** Discarded packets */
	uint64_t discards;
	/** Errors */
	uint64_t errors;
} __attribute__ (( packed ));

/** Admin Queue VF Get Statistics data buffer */
struct intelxlvf_admin_stats_buffer {
	/** Receive statistics */
	struct intelxlvf_admin_stats rx;
	/** Transmit statistics */
	struct intelxlvf_admin_stats tx;
} __attribute__ (( packed ));

/** Admin Queue VF Request Queues opcode */
#define INTELXLVF_ADMIN_REQUEST_QPS 0x0000001d

/** Admin Queue VF Request Queues data buffer */
struct intelxlvf_admin_request_qps_buffer {
	/** Number of queue pairs */
	uint16_t count;
} __attribute__ (( packed ));

/** Admin queue data buffer */
union intelxlvf_admin_buffer {
	/** Original 40 Gigabit Ethernet data buffer */
	union intelxl_admin_buffer xl;
	/** VF Version data buffer */
	struct intelxlvf_admin_version_buffer ver;
	/** VF Capabilities data buffer */
	struct intelxlvf_admin_capabilities_buffer caps;
	/** VF Get Resources data buffer */
	struct intelxlvf_admin_get_resources_buffer res;
	/** VF Status Change Event data buffer */
	struct intelxlvf_admin_status_buffer stat;
	/** VF Configure Queues data buffer */
	struct intelxlvf_admin_configure_buffer cfg;
	/** VF Enable/Disable Queues data buffer */
	struct intelxlvf_admin_queues_buffer queues;
	/** VF Configure Promiscuous Mode data buffer */
	struct intelxlvf_admin_promisc_buffer promisc;
	/** VF IRQ Map data buffer */
	struct intelxlvf_admin_irq_map_buffer irq;
	/** VF Get Statistics data buffer */
	struct intelxlvf_admin_stats_buffer stats;
	/** VF Request Queues data buffer */
	struct intelxlvf_admin_request_qps_buffer rqps;
} __attribute__ (( packed ));

/** Admin queue descriptor */
struct intelxlvf_admin_descriptor {
	/** Transparent union */
	union {
		/** Original 40 Gigabit Ethernet descriptor */
		struct intelxl_admin_descriptor xl;
		/** Transparent struct */
		struct {
			/** Flags */
			uint16_t flags;
			/** Opcode */
			uint16_t opcode;
			/** Data length */
			uint16_t len;
			/** Return value */
			uint16_t ret;
			/** VF opcode */
			uint32_t vopcode;
			/** VF return value */
			int32_t vret;
			/** Parameters */
			union intelxl_admin_params params;
		} __attribute__ (( packed ));
	} __attribute__ (( packed ));
} __attribute__ (( packed ));

/**
 * Get next admin command queue descriptor
 *
 * @v intelxl		Intel device
 * @ret cmd		Command descriptor
 */
struct intelxlvf_admin_descriptor *
intelxlvf_admin_command_descriptor ( struct intelxl_nic *intelxl ) {
	struct intelxl_admin_descriptor *xlcmd =
		intelxl_admin_command_descriptor ( intelxl );

	return container_of ( xlcmd, struct intelxlvf_admin_descriptor, xl );
}

/**
 * Get next admin command queue data buffer
 *
 * @v intelxl		Intel device
 * @ret buf		Data buffer
 */
static inline __attribute__ (( always_inline )) union intelxlvf_admin_buffer *
intelxlvf_admin_command_buffer ( struct intelxl_nic *intelxl ) {
	union intelxl_admin_buffer *xlbuf =
		intelxl_admin_command_buffer ( intelxl );

	return container_of ( xlbuf, union intelxlvf_admin_buffer, xl );
}

/** VF Reset Status Register */
#define INTELXLVF_VFGEN_RSTAT 0x8800
#define INTELXLVF_VFGEN_RSTAT_VFR_STATE(x) ( (x) & 0x3 )
#define INTELXLVF_VFGEN_RSTAT_VFR_STATE_ACTIVE 0x2

/** Minimum time to wait for reset to complete */
#define INTELXLVF_RESET_DELAY_MS 100

/** Maximum time to wait for reset to complete */
#define INTELXLVF_RESET_MAX_WAIT_MS 1000

/**
 * Initialise descriptor ring
 *
 * @v ring		Descriptor ring
 * @v count		Number of descriptors
 * @v len		Length of a single descriptor
 * @v tail		Tail register offset
 */
static inline __attribute__ (( always_inline)) void
intelxlvf_init_ring ( struct intelxl_ring *ring, unsigned int count,
		      size_t len, unsigned int tail ) {

	ring->len = ( count * len );
	ring->tail = tail;
}

#endif /* _INTELXLVF_H */
