/* * Copyright (C) 2015 Spreadtrum Communications Inc. * * Authors : * Keguang Zhang * Jingxiang Li * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifndef __SPRDWL_MSG_H__ #define __SPRDWL_MSG_H__ #include #include #include #include #include /* 0 for cmd, 1 for event, 2 for data, 3 for mh data */ enum sprdwl_head_type { SPRDWL_TYPE_CMD, SPRDWL_TYPE_EVENT, SPRDWL_TYPE_DATA, SPRDWL_TYPE_DATA_SPECIAL, SPRDWL_TYPE_DATA_PCIE_ADDR, SPRDWL_TYPE_PKT_LOG, }; enum sprdwl_head_rsp { /* cmd no rsp */ SPRDWL_HEAD_NORSP, /* cmd need rsp */ SPRDWL_HEAD_RSP, }; /* bit[7][6][5] ctx_id: context id * bit[4] rsp: sprdwl_head_rsp * bit[3] reserv * bit[2][1][0] type: sprdwl_head_type */ struct sprdwl_common_hdr { #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 type:3; __u8 reserv:1; __u8 rsp:1; __u8 ctx_id:3; #elif defined(__BIG_ENDIAN_BITFIELD) __u8 ctx_id:3; __u8 rsp:1; __u8 reserv:1; __u8 type:3; #else #error "check defines" #endif }; #define SPRDWL_CMD_STATUS_OK 0 #define SPRDWL_CMD_STATUS_ARG_ERROR -1 #define SPRDWL_CMD_STATUS_GET_RESULT_ERROR -2 #define SPRDWL_CMD_STATUS_EXEC_ERROR -3 #define SPRDWL_CMD_STATUS_MALLOC_ERROR -4 #define SPRDWL_CMD_STATUS_WIFIMODE_ERROR -5 #define SPRDWL_CMD_STATUS_ERROR -6 #define SPRDWL_CMD_STATUS_CONNOT_EXEC_ERROR -7 #define SPRDWL_CMD_STATUS_NOT_SUPPORT_ERROR -8 #define SPRDWL_CMD_STATUS_CRC_ERROR -9 #define SPRDWL_CMD_STATUS_INI_INDEX_ERROR -10 #define SPRDWL_CMD_STATUS_LENGTH_ERROR -11 #define SPRDWL_CMD_STATUS_OTHER_ERROR -127 #define SPRDWL_HEAD_GET_TYPE(common) \ (((struct sprdwl_common_hdr *)(common))->type) #define SPRDWL_HEAD_GET_CTX_ID(common) \ (((struct sprdwl_common_hdr *)(common))->ctx_id) #define SPRD_HEAD_GET_RESUME_BIT(common) \ (((struct sprdwl_common_hdr *)(common))->reserv) struct sprdwl_cmd_hdr { struct sprdwl_common_hdr common; u8 cmd_id; /* the payload len include the size of this struct */ __le16 plen; __le32 mstime; s8 status; u8 rsp_cnt; u8 reserv[2]; u8 paydata[0]; } __packed; struct sprdwl_addr_hdr { struct sprdwl_common_hdr common; u8 paydata[0]; } __packed; #define SPRDWL_GET_CMD_PAYDATA(msg) \ (((struct sprdwl_cmd_hdr *)((msg)->skb->data))->paydata) struct sprdwl_data_hdr { struct sprdwl_common_hdr common; #define WAPI_PN_SIZE 16 #define SPRDWL_DATA_OFFSET 2 u8 info1; /*no used in marlin3*/ /* the payload len include the size of this struct */ __le16 plen; /* the flow contrl shared by sta and p2p */ u8 flow0; /* the sta flow contrl */ u8 flow1; /* the p2p flow contrl */ u8 flow2; /* flow3 0: share, 1: self */ u8 flow3; } __packed; struct sprdwl_pktlog_hdr { struct sprdwl_common_hdr common; u8 rsvd; /* the payload len include the size of this struct */ __le16 plen; } __packed; struct sprdwl_msg_list { struct list_head freelist; struct list_head busylist; /*cmd to be free list*/ struct list_head cmd_to_free; int maxnum; /* freelist lock */ spinlock_t freelock; /* busylist lock */ spinlock_t busylock; /*cmd_to_free lock*/ spinlock_t complock; atomic_t ref; /* data flow contrl */ atomic_t flow; }; struct sprdwl_xmit_msg_list { /*merge qos queues to this list*/ struct list_head to_send_list; /*data list sending by HIF, will be freed later*/ struct list_head to_free_list; spinlock_t send_lock; spinlock_t free_lock; u8 mode; unsigned long failcount; }; struct sprdwl_msg_buf { struct list_head list; struct sk_buff *skb; /* data just tx cmd use,not include the head */ void *data; void *tran_data; u8 type; u8 mode; u16 len; unsigned long timeout; /* marlin 2 */ unsigned int fifo_id; struct sprdwl_msg_list *msglist; /* marlin 3 */ unsigned char buffer_type; struct peer_list *data_list; struct sprdwl_xmit_msg_list *xmit_msg_list; unsigned char msg_type; #if defined(MORE_DEBUG) unsigned long tx_start_time; #endif }; static inline void sprdwl_fill_msg(struct sprdwl_msg_buf *msg, struct sk_buff *skb, void *data, u16 len) { msg->skb = skb; msg->tran_data = data; msg->len = len; } static inline int sprdwl_msg_ref(struct sprdwl_msg_list *msglist) { return atomic_read(&msglist->ref); } static inline int sprdwl_msg_tx_pended(struct sprdwl_msg_list *msglist) { return !list_empty(&msglist->busylist); } #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) #define list_last_entry(ptr, type, member) \ list_entry((ptr)->prev, type, member) #endif int sprdwl_msg_init(int num, struct sprdwl_msg_list *list); void sprdwl_msg_deinit(struct sprdwl_msg_list *list); struct sprdwl_msg_buf *sprdwl_alloc_msg_buf(struct sprdwl_msg_list *list); void sprdwl_free_msg_buf(struct sprdwl_msg_buf *msg_buf, struct sprdwl_msg_list *list); void sprdwl_queue_msg_buf(struct sprdwl_msg_buf *msg_buf, struct sprdwl_msg_list *list); struct sprdwl_msg_buf *sprdwl_peek_msg_buf(struct sprdwl_msg_list *list); void sprdwl_dequeue_msg_buf(struct sprdwl_msg_buf *msg_buf, struct sprdwl_msg_list *list); struct sprdwl_msg_buf *sprdwl_get_msgbuf_by_data(void *data, struct sprdwl_msg_list *list); #if defined(UWE5621_FTR) struct sprdwl_msg_buf *sprdwl_get_tail_msg_buf(struct sprdwl_msg_list *list); #endif #endif