blob: 19a580939dfc09d0f122a3fe8515f4d172542176 [file] [log] [blame]
Binoy Jayanb27a6d52016-06-15 11:00:34 +05301#include <linux/completion.h>
Johnny Kimc5c77ba2015-05-11 14:30:56 +09002#include "wilc_wlan_if.h"
Arnd Bergmann491880e2015-11-16 15:04:55 +01003#include "wilc_wlan.h"
Tony Cho60bd1002015-10-12 16:56:04 +09004#include "wilc_wfi_netdevice.h"
Glen Lee17e8f162015-10-02 14:22:07 +09005#include "wilc_wlan_cfg.h"
Johnny Kimc5c77ba2015-05-11 14:30:56 +09006
Leo Kimb7d1e182015-11-06 11:12:30 +09007static CHIP_PS_STATE_T chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09008
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01009static inline void acquire_bus(struct wilc *wilc, BUS_ACQUIRE_T acquire)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090010{
Arnd Bergmann562ed3f2015-11-16 15:05:10 +010011 mutex_lock(&wilc->hif_cs);
Glen Lee33c64972016-01-25 16:35:06 +090012 if (acquire == ACQUIRE_AND_WAKEUP)
13 chip_wakeup(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090014}
Leo Kim2d6973e2015-11-06 11:12:28 +090015
Arnd Bergmann562ed3f2015-11-16 15:05:10 +010016static inline void release_bus(struct wilc *wilc, BUS_RELEASE_T release)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090017{
Johnny Kimc5c77ba2015-05-11 14:30:56 +090018 if (release == RELEASE_ALLOW_SLEEP)
Glen Lee00215dd2015-11-18 15:11:25 +090019 chip_allow_sleep(wilc);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +010020 mutex_unlock(&wilc->hif_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090021}
Johnny Kimc5c77ba2015-05-11 14:30:56 +090022
Glen Leee9576e92016-02-04 18:15:23 +090023static void wilc_wlan_txq_remove(struct wilc *wilc, struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090024{
Glen Lee67e2a072015-12-21 14:18:12 +090025 if (tqe == wilc->txq_head) {
26 wilc->txq_head = tqe->next;
27 if (wilc->txq_head)
28 wilc->txq_head->prev = NULL;
29 } else if (tqe == wilc->txq_tail) {
30 wilc->txq_tail = (tqe->prev);
31 if (wilc->txq_tail)
32 wilc->txq_tail->next = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090033 } else {
34 tqe->prev->next = tqe->next;
35 tqe->next->prev = tqe->prev;
36 }
Glen Lee67e2a072015-12-21 14:18:12 +090037 wilc->txq_entries -= 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090038}
39
Glen Lee718fc2c2015-10-29 12:18:43 +090040static struct txq_entry_t *
41wilc_wlan_txq_remove_from_head(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090042{
43 struct txq_entry_t *tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090044 unsigned long flags;
Glen Leea4cac482015-12-21 14:18:36 +090045 struct wilc_vif *vif;
Glen Lee718fc2c2015-10-29 12:18:43 +090046 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +090047
Glen Leea4cac482015-12-21 14:18:36 +090048 vif = netdev_priv(dev);
49 wilc = vif->wilc;
Glen Lee718fc2c2015-10-29 12:18:43 +090050
51 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Glen Lee67e2a072015-12-21 14:18:12 +090052 if (wilc->txq_head) {
53 tqe = wilc->txq_head;
54 wilc->txq_head = tqe->next;
55 if (wilc->txq_head)
56 wilc->txq_head->prev = NULL;
Alison Schofield39823a52015-10-08 21:18:03 -070057
Glen Lee67e2a072015-12-21 14:18:12 +090058 wilc->txq_entries -= 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090059 } else {
60 tqe = NULL;
61 }
Glen Lee718fc2c2015-10-29 12:18:43 +090062 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090063 return tqe;
64}
65
Glen Lee32f03322015-10-29 12:18:45 +090066static void wilc_wlan_txq_add_to_tail(struct net_device *dev,
67 struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090068{
Johnny Kimc5c77ba2015-05-11 14:30:56 +090069 unsigned long flags;
Glen Leea4cac482015-12-21 14:18:36 +090070 struct wilc_vif *vif;
Glen Lee32f03322015-10-29 12:18:45 +090071 struct wilc *wilc;
72
Glen Leea4cac482015-12-21 14:18:36 +090073 vif = netdev_priv(dev);
74 wilc = vif->wilc;
Glen Lee32f03322015-10-29 12:18:45 +090075
76 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090077
Glen Lee67e2a072015-12-21 14:18:12 +090078 if (!wilc->txq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +090079 tqe->next = NULL;
80 tqe->prev = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +090081 wilc->txq_head = tqe;
82 wilc->txq_tail = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090083 } else {
84 tqe->next = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +090085 tqe->prev = wilc->txq_tail;
86 wilc->txq_tail->next = tqe;
87 wilc->txq_tail = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090088 }
Glen Lee67e2a072015-12-21 14:18:12 +090089 wilc->txq_entries += 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +090090
Glen Lee32f03322015-10-29 12:18:45 +090091 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090092
Binoy Jayanb27a6d52016-06-15 11:00:34 +053093 complete(&wilc->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +090094}
95
Chris Park4d38a562016-02-04 18:15:49 +090096static int wilc_wlan_txq_add_to_head(struct wilc_vif *vif,
97 struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +090098{
Johnny Kimc5c77ba2015-05-11 14:30:56 +090099 unsigned long flags;
Glen Lee79df6a42016-02-04 18:15:31 +0900100 struct wilc *wilc = vif->wilc;
101
Binoy Jayan334bed02016-06-15 11:00:35 +0530102 mutex_lock(&wilc->txq_add_to_head_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900103
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100104 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900105
Glen Lee67e2a072015-12-21 14:18:12 +0900106 if (!wilc->txq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900107 tqe->next = NULL;
108 tqe->prev = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +0900109 wilc->txq_head = tqe;
110 wilc->txq_tail = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900111 } else {
Glen Lee67e2a072015-12-21 14:18:12 +0900112 tqe->next = wilc->txq_head;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900113 tqe->prev = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +0900114 wilc->txq_head->prev = tqe;
115 wilc->txq_head = tqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900116 }
Glen Lee67e2a072015-12-21 14:18:12 +0900117 wilc->txq_entries += 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900118
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100119 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Binoy Jayan334bed02016-06-15 11:00:35 +0530120 mutex_unlock(&wilc->txq_add_to_head_cs);
Binoy Jayanb27a6d52016-06-15 11:00:34 +0530121 complete(&wilc->txq_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900122
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900123 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900124}
125
Leo Kim130a41f2015-11-06 11:12:34 +0900126struct ack_session_info;
127struct ack_session_info {
Leo Kimd06b6cb2015-11-06 11:12:35 +0900128 u32 seq_num;
Leo Kim9d54d3d2015-11-06 11:12:36 +0900129 u32 bigger_ack_num;
Chaehyun Limec53adf2015-09-15 14:06:15 +0900130 u16 src_port;
131 u16 dst_port;
132 u16 status;
Shraddha Barkeeeb1c062015-08-05 01:29:22 +0530133};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900134
Leo Kim08b90b12015-11-06 11:12:37 +0900135struct pending_acks_info {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900136 u32 ack_num;
Leo Kim84136972015-11-06 11:12:38 +0900137 u32 session_index;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900138 struct txq_entry_t *txqe;
Leo Kim08b90b12015-11-06 11:12:37 +0900139};
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900140
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900141#define NOT_TCP_ACK (-1)
142
143#define MAX_TCP_SESSION 25
144#define MAX_PENDING_ACKS 256
Arnd Bergmann1608c402015-11-16 15:04:53 +0100145static struct ack_session_info ack_session_info[2 * MAX_TCP_SESSION];
146static struct pending_acks_info pending_acks_info[MAX_PENDING_ACKS];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900147
Arnd Bergmann1608c402015-11-16 15:04:53 +0100148static u32 pending_base;
149static u32 tcp_session;
150static u32 pending_acks;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900151
Leo Kim67620782015-11-06 11:12:45 +0900152static inline int add_tcp_session(u32 src_prt, u32 dst_prt, u32 seq)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900153{
Glen Lee4fd62292016-02-04 18:15:24 +0900154 if (tcp_session < 2 * MAX_TCP_SESSION) {
155 ack_session_info[tcp_session].seq_num = seq;
156 ack_session_info[tcp_session].bigger_ack_num = 0;
157 ack_session_info[tcp_session].src_port = src_prt;
158 ack_session_info[tcp_session].dst_port = dst_prt;
159 tcp_session++;
160 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900161 return 0;
162}
163
Leo Kimb801a962015-11-06 11:12:48 +0900164static inline int update_tcp_session(u32 index, u32 ack)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900165{
Glen Lee4fd62292016-02-04 18:15:24 +0900166 if (index < 2 * MAX_TCP_SESSION &&
167 ack > ack_session_info[index].bigger_ack_num)
Leo Kimb801a962015-11-06 11:12:48 +0900168 ack_session_info[index].bigger_ack_num = ack;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900169 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900170}
Leo Kim2d6973e2015-11-06 11:12:28 +0900171
Leo Kimea03f572015-11-06 11:12:49 +0900172static inline int add_tcp_pending_ack(u32 ack, u32 session_index,
Leo Kim66a43a92015-11-06 11:19:50 +0900173 struct txq_entry_t *txqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900174{
Glen Lee4fd62292016-02-04 18:15:24 +0900175 if (pending_base + pending_acks < MAX_PENDING_ACKS) {
Leo Kimb801a962015-11-06 11:12:48 +0900176 pending_acks_info[pending_base + pending_acks].ack_num = ack;
Leo Kimd12ac7e2015-11-06 11:12:43 +0900177 pending_acks_info[pending_base + pending_acks].txqe = txqe;
Leo Kimea03f572015-11-06 11:12:49 +0900178 pending_acks_info[pending_base + pending_acks].session_index = session_index;
Glen Leeb7193022015-12-21 14:18:07 +0900179 txqe->tcp_pending_ack_idx = pending_base + pending_acks;
Leo Kimd12ac7e2015-11-06 11:12:43 +0900180 pending_acks++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900181 }
182 return 0;
183}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900184
Janani Ravichandranaae96202016-02-16 14:07:00 -0500185static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900186{
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900187 u8 *eth_hdr_ptr;
188 u8 *buffer = tqe->buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900189 unsigned short h_proto;
190 int i;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900191 unsigned long flags;
Glen Leea4cac482015-12-21 14:18:36 +0900192 struct wilc_vif *vif;
Glen Lee82bb18e2015-10-27 18:28:03 +0900193 struct wilc *wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900194
Glen Leea4cac482015-12-21 14:18:36 +0900195 vif = netdev_priv(dev);
196 wilc = vif->wilc;
Glen Lee82bb18e2015-10-27 18:28:03 +0900197
Glen Leec6866cc2016-02-04 18:15:22 +0900198 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900199
200 eth_hdr_ptr = &buffer[0];
201 h_proto = ntohs(*((unsigned short *)&eth_hdr_ptr[12]));
Hari Prasath Gujulan Elangoa0456182015-12-22 11:44:43 +0000202 if (h_proto == ETH_P_IP) {
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900203 u8 *ip_hdr_ptr;
204 u8 protocol;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900205
206 ip_hdr_ptr = &buffer[ETHERNET_HDR_LEN];
207 protocol = ip_hdr_ptr[9];
208
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900209 if (protocol == 0x06) {
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900210 u8 *tcp_hdr_ptr;
Leo Kim51bffa92015-11-06 11:12:52 +0900211 u32 IHL, total_length, data_offset;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900212
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900213 tcp_hdr_ptr = &ip_hdr_ptr[IP_HDR_LEN];
214 IHL = (ip_hdr_ptr[0] & 0xf) << 2;
Leo Kim24e2dac2015-11-06 11:12:51 +0900215 total_length = ((u32)ip_hdr_ptr[2] << 8) +
216 (u32)ip_hdr_ptr[3];
Leo Kim51bffa92015-11-06 11:12:52 +0900217 data_offset = ((u32)tcp_hdr_ptr[12] & 0xf0) >> 2;
218 if (total_length == (IHL + data_offset)) {
Leo Kimf91c5d72015-11-06 11:12:53 +0900219 u32 seq_no, ack_no;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900220
Leo Kim4478c622015-11-06 11:12:54 +0900221 seq_no = ((u32)tcp_hdr_ptr[4] << 24) +
222 ((u32)tcp_hdr_ptr[5] << 16) +
223 ((u32)tcp_hdr_ptr[6] << 8) +
224 (u32)tcp_hdr_ptr[7];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900225
Leo Kimf91c5d72015-11-06 11:12:53 +0900226 ack_no = ((u32)tcp_hdr_ptr[8] << 24) +
227 ((u32)tcp_hdr_ptr[9] << 16) +
228 ((u32)tcp_hdr_ptr[10] << 8) +
229 (u32)tcp_hdr_ptr[11];
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900230
Leo Kim3056ec32015-11-06 11:12:42 +0900231 for (i = 0; i < tcp_session; i++) {
Glen Lee4fd62292016-02-04 18:15:24 +0900232 if (i < 2 * MAX_TCP_SESSION &&
233 ack_session_info[i].seq_num == seq_no) {
Leo Kimf91c5d72015-11-06 11:12:53 +0900234 update_tcp_session(i, ack_no);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900235 break;
236 }
237 }
Leo Kim3056ec32015-11-06 11:12:42 +0900238 if (i == tcp_session)
Leo Kim67620782015-11-06 11:12:45 +0900239 add_tcp_session(0, 0, seq_no);
Alison Schofield39823a52015-10-08 21:18:03 -0700240
Leo Kimf91c5d72015-11-06 11:12:53 +0900241 add_tcp_pending_ack(ack_no, i, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900242 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900243 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900244 }
Glen Lee82bb18e2015-10-27 18:28:03 +0900245 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900246}
247
Glen Leec029e992015-10-27 18:27:48 +0900248static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900249{
Glen Leea4cac482015-12-21 14:18:36 +0900250 struct wilc_vif *vif;
Glen Leec029e992015-10-27 18:27:48 +0900251 struct wilc *wilc;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900252 u32 i = 0;
Leo Kim442eda42015-11-06 11:12:55 +0900253 u32 dropped = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900254
Glen Leea4cac482015-12-21 14:18:36 +0900255 vif = netdev_priv(dev);
256 wilc = vif->wilc;
Glen Leec029e992015-10-27 18:27:48 +0900257
Glen Lee67e2a072015-12-21 14:18:12 +0900258 spin_lock_irqsave(&wilc->txq_spinlock, wilc->txq_spinlock_flags);
Leo Kimd12ac7e2015-11-06 11:12:43 +0900259 for (i = pending_base; i < (pending_base + pending_acks); i++) {
Glen Lee4fd62292016-02-04 18:15:24 +0900260 if (i >= MAX_PENDING_ACKS ||
261 pending_acks_info[i].session_index >= 2 * MAX_TCP_SESSION)
262 break;
Leo Kim2bb17082015-11-06 11:12:40 +0900263 if (pending_acks_info[i].ack_num < ack_session_info[pending_acks_info[i].session_index].bigger_ack_num) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900264 struct txq_entry_t *tqe;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900265
Leo Kim2bb17082015-11-06 11:12:40 +0900266 tqe = pending_acks_info[i].txqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900267 if (tqe) {
Glen Leee9576e92016-02-04 18:15:23 +0900268 wilc_wlan_txq_remove(wilc, tqe);
Leo Kimac087c82015-11-06 11:12:25 +0900269 tqe->status = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900270 if (tqe->tx_complete_func)
Leo Kimab12d8c2015-11-06 11:19:54 +0900271 tqe->tx_complete_func(tqe->priv,
272 tqe->status);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700273 kfree(tqe);
Leo Kim442eda42015-11-06 11:12:55 +0900274 dropped++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900275 }
276 }
277 }
Leo Kimd12ac7e2015-11-06 11:12:43 +0900278 pending_acks = 0;
Leo Kim3056ec32015-11-06 11:12:42 +0900279 tcp_session = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900280
Leo Kim2ae91ed2015-11-06 11:12:41 +0900281 if (pending_base == 0)
282 pending_base = MAX_TCP_SESSION;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530283 else
Leo Kim2ae91ed2015-11-06 11:12:41 +0900284 pending_base = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900285
Glen Lee67e2a072015-12-21 14:18:12 +0900286 spin_unlock_irqrestore(&wilc->txq_spinlock, wilc->txq_spinlock_flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900287
Leo Kim442eda42015-11-06 11:12:55 +0900288 while (dropped > 0) {
Binoy Jayanb27a6d52016-06-15 11:00:34 +0530289 wait_for_completion_timeout(&wilc->txq_event,
290 msecs_to_jiffies(1));
Leo Kim442eda42015-11-06 11:12:55 +0900291 dropped--;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900292 }
293
294 return 1;
295}
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900296
Eva Rachel Retuyad38f5ba2016-02-15 13:34:17 +0800297static bool enabled;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900298
Arnd Bergmann0e1af732015-11-16 15:04:54 +0100299void wilc_enable_tcp_ack_filter(bool value)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900300{
Leo Kim7c4bafe2015-11-06 11:12:56 +0900301 enabled = value;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900302}
303
Glen Lee79df6a42016-02-04 18:15:31 +0900304static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer,
305 u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900306{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900307 struct txq_entry_t *tqe;
Glen Lee79df6a42016-02-04 18:15:31 +0900308 struct wilc *wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900309
Glen Lee79df6a42016-02-04 18:15:31 +0900310 netdev_dbg(vif->ndev, "Adding config packet ...\n");
Glen Lee67e2a072015-12-21 14:18:12 +0900311 if (wilc->quit) {
Glen Lee79df6a42016-02-04 18:15:31 +0900312 netdev_dbg(vif->ndev, "Return due to clear function\n");
Binoy Jayanfa659692016-06-15 11:00:36 +0530313 complete(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900314 return 0;
315 }
316
Leo Kim1d401a42015-11-06 11:12:59 +0900317 tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
Anchal Jaine27604e2016-03-11 19:49:50 +0530318 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900319 return 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900320
321 tqe->type = WILC_CFG_PKT;
322 tqe->buffer = buffer;
323 tqe->buffer_size = buffer_size;
324 tqe->tx_complete_func = NULL;
325 tqe->priv = NULL;
Glen Leeb7193022015-12-21 14:18:07 +0900326 tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900327
Claudiu Beznea245b4312016-04-25 02:07:18 +0300328 if (wilc_wlan_txq_add_to_head(vif, tqe)) {
329 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900330 return 0;
Claudiu Beznea245b4312016-04-25 02:07:18 +0300331 }
332
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900333 return 1;
334}
335
Glen Lee691bbd42015-10-27 18:28:02 +0900336int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
337 u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900338{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900339 struct txq_entry_t *tqe;
Glen Leea4cac482015-12-21 14:18:36 +0900340 struct wilc_vif *vif = netdev_priv(dev);
Glen Lee67e2a072015-12-21 14:18:12 +0900341 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900342
Glen Leea4cac482015-12-21 14:18:36 +0900343 wilc = vif->wilc;
Glen Lee67e2a072015-12-21 14:18:12 +0900344
345 if (wilc->quit)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900346 return 0;
347
Leo Kim1d401a42015-11-06 11:12:59 +0900348 tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900349
Leo Kima4b17192015-11-06 11:12:31 +0900350 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900351 return 0;
352 tqe->type = WILC_NET_PKT;
353 tqe->buffer = buffer;
354 tqe->buffer_size = buffer_size;
355 tqe->tx_complete_func = func;
356 tqe->priv = priv;
357
Glen Leeb7193022015-12-21 14:18:07 +0900358 tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
Amitoj Kaur Chawla5a9ff742016-02-29 19:23:44 +0530359 if (enabled)
Glen Lee82bb18e2015-10-27 18:28:03 +0900360 tcp_process(dev, tqe);
Glen Lee32f03322015-10-29 12:18:45 +0900361 wilc_wlan_txq_add_to_tail(dev, tqe);
Glen Lee67e2a072015-12-21 14:18:12 +0900362 return wilc->txq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900363}
Glen Leefcc6ef92015-09-16 18:53:21 +0900364
Glen Lee829c4772015-10-29 12:18:44 +0900365int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
366 u32 buffer_size, wilc_tx_complete_func_t func)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900367{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900368 struct txq_entry_t *tqe;
Glen Leea4cac482015-12-21 14:18:36 +0900369 struct wilc_vif *vif = netdev_priv(dev);
Glen Lee67e2a072015-12-21 14:18:12 +0900370 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900371
Glen Leea4cac482015-12-21 14:18:36 +0900372 wilc = vif->wilc;
Glen Lee67e2a072015-12-21 14:18:12 +0900373
374 if (wilc->quit)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900375 return 0;
376
Leo Kim1d401a42015-11-06 11:12:59 +0900377 tqe = kmalloc(sizeof(*tqe), GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900378
Leo Kima4b17192015-11-06 11:12:31 +0900379 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900380 return 0;
381 tqe->type = WILC_MGMT_PKT;
382 tqe->buffer = buffer;
383 tqe->buffer_size = buffer_size;
384 tqe->tx_complete_func = func;
385 tqe->priv = priv;
Glen Leeb7193022015-12-21 14:18:07 +0900386 tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
Glen Lee32f03322015-10-29 12:18:45 +0900387 wilc_wlan_txq_add_to_tail(dev, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900388 return 1;
389}
Glen Leefcc6ef92015-09-16 18:53:21 +0900390
Glen Lee7af05222015-10-29 12:18:41 +0900391static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900392{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900393 struct txq_entry_t *tqe;
394 unsigned long flags;
395
Glen Lee7af05222015-10-29 12:18:41 +0900396 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900397
Glen Lee67e2a072015-12-21 14:18:12 +0900398 tqe = wilc->txq_head;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900399
Glen Lee7af05222015-10-29 12:18:41 +0900400 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900401
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900402 return tqe;
403}
404
Glen Lee50a0b3b2015-10-27 18:28:00 +0900405static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,
406 struct txq_entry_t *tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900407{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900408 unsigned long flags;
Leo Kim8739eeb2015-11-06 11:12:29 +0900409
Glen Lee50a0b3b2015-10-27 18:28:00 +0900410 spin_lock_irqsave(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900411
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900412 tqe = tqe->next;
Glen Lee50a0b3b2015-10-27 18:28:00 +0900413 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900414
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900415 return tqe;
416}
417
Glen Leed06f3622015-10-27 18:27:59 +0900418static int wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900419{
Glen Lee67e2a072015-12-21 14:18:12 +0900420 if (wilc->quit)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900421 return 0;
422
Glen Leed06f3622015-10-27 18:27:59 +0900423 mutex_lock(&wilc->rxq_cs);
Glen Lee67e2a072015-12-21 14:18:12 +0900424 if (!wilc->rxq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900425 rqe->next = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +0900426 wilc->rxq_head = rqe;
427 wilc->rxq_tail = rqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900428 } else {
Glen Lee67e2a072015-12-21 14:18:12 +0900429 wilc->rxq_tail->next = rqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900430 rqe->next = NULL;
Glen Lee67e2a072015-12-21 14:18:12 +0900431 wilc->rxq_tail = rqe;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900432 }
Glen Lee67e2a072015-12-21 14:18:12 +0900433 wilc->rxq_entries += 1;
Glen Leed06f3622015-10-27 18:27:59 +0900434 mutex_unlock(&wilc->rxq_cs);
Glen Lee67e2a072015-12-21 14:18:12 +0900435 return wilc->rxq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900436}
437
Glen Leedb387632015-10-27 18:27:55 +0900438static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900439{
Glen Lee67e2a072015-12-21 14:18:12 +0900440 if (wilc->rxq_head) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900441 struct rxq_entry_t *rqe;
442
Glen Leedb387632015-10-27 18:27:55 +0900443 mutex_lock(&wilc->rxq_cs);
Glen Lee67e2a072015-12-21 14:18:12 +0900444 rqe = wilc->rxq_head;
445 wilc->rxq_head = wilc->rxq_head->next;
446 wilc->rxq_entries -= 1;
Glen Leedb387632015-10-27 18:27:55 +0900447 mutex_unlock(&wilc->rxq_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900448 return rqe;
449 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900450 return NULL;
451}
452
Glen Lee76855ba2016-01-25 16:35:08 +0900453void chip_allow_sleep(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900454{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900455 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900456
Glen Leeaf9ae092015-12-21 14:18:09 +0900457 wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900458
Glen Leeaf9ae092015-12-21 14:18:09 +0900459 wilc->hif_func->hif_write_reg(wilc, 0xf0, reg & ~BIT(0));
Glen Leefdc2ac12016-01-25 16:35:07 +0900460 wilc->hif_func->hif_write_reg(wilc, 0xfa, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900461}
Glen Lee76855ba2016-01-25 16:35:08 +0900462EXPORT_SYMBOL_GPL(chip_allow_sleep);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900463
Glen Lee76855ba2016-01-25 16:35:08 +0900464void chip_wakeup(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900465{
Leo Kimeed9e542016-02-23 21:10:53 +0900466 u32 reg, clk_status_reg;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900467
Glen Leea3629a92015-12-21 14:18:10 +0900468 if ((wilc->io_type & 0x1) == HIF_SPI) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900469 do {
Glen Leeaf9ae092015-12-21 14:18:09 +0900470 wilc->hif_func->hif_read_reg(wilc, 1, &reg);
471 wilc->hif_func->hif_write_reg(wilc, 1, reg | BIT(1));
472 wilc->hif_func->hif_write_reg(wilc, 1, reg & ~BIT(1));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900473
474 do {
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700475 usleep_range(2 * 1000, 2 * 1000);
Leo Kim7242eee2016-02-22 13:41:13 +0900476 wilc_get_chipid(wilc, true);
Leo Kimeed9e542016-02-23 21:10:53 +0900477 } while (wilc_get_chipid(wilc, true) == 0);
Glen Lee00215dd2015-11-18 15:11:25 +0900478 } while (wilc_get_chipid(wilc, true) == 0);
Glen Leea3629a92015-12-21 14:18:10 +0900479 } else if ((wilc->io_type & 0x1) == HIF_SDIO) {
Glen Leefdc2ac12016-01-25 16:35:07 +0900480 wilc->hif_func->hif_write_reg(wilc, 0xfa, 1);
481 udelay(200);
Glen Leeaf9ae092015-12-21 14:18:09 +0900482 wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900483 do {
Glen Leeaf9ae092015-12-21 14:18:09 +0900484 wilc->hif_func->hif_write_reg(wilc, 0xf0,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900485 reg | BIT(0));
Glen Leeaf9ae092015-12-21 14:18:09 +0900486 wilc->hif_func->hif_read_reg(wilc, 0xf1,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900487 &clk_status_reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900488
Leo Kimeed9e542016-02-23 21:10:53 +0900489 while ((clk_status_reg & 0x1) == 0) {
Greg Kroah-Hartman80e29c72015-08-14 19:42:23 -0700490 usleep_range(2 * 1000, 2 * 1000);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900491
Glen Leeaf9ae092015-12-21 14:18:09 +0900492 wilc->hif_func->hif_read_reg(wilc, 0xf1,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900493 &clk_status_reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900494 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900495 if ((clk_status_reg & 0x1) == 0) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900496 wilc->hif_func->hif_write_reg(wilc, 0xf0,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900497 reg & (~BIT(0)));
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900498 }
499 } while ((clk_status_reg & 0x1) == 0);
500 }
501
Leo Kimb7d1e182015-11-06 11:12:30 +0900502 if (chip_ps_state == CHIP_SLEEPING_MANUAL) {
Glen Leefdc2ac12016-01-25 16:35:07 +0900503 if (wilc_get_chipid(wilc, false) < 0x1002b0) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900504 u32 val32;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900505
Glen Leeaf9ae092015-12-21 14:18:09 +0900506 wilc->hif_func->hif_read_reg(wilc, 0x1e1c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700507 val32 |= BIT(6);
Glen Leeaf9ae092015-12-21 14:18:09 +0900508 wilc->hif_func->hif_write_reg(wilc, 0x1e1c, val32);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900509
Glen Leeaf9ae092015-12-21 14:18:09 +0900510 wilc->hif_func->hif_read_reg(wilc, 0x1e9c, &val32);
Anish Bhattffda2032015-09-29 12:15:49 -0700511 val32 |= BIT(6);
Glen Leeaf9ae092015-12-21 14:18:09 +0900512 wilc->hif_func->hif_write_reg(wilc, 0x1e9c, val32);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900513 }
514 }
Leo Kimb7d1e182015-11-06 11:12:30 +0900515 chip_ps_state = CHIP_WAKEDUP;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900516}
Glen Lee76855ba2016-01-25 16:35:08 +0900517EXPORT_SYMBOL_GPL(chip_wakeup);
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900518
Glen Lee00215dd2015-11-18 15:11:25 +0900519void wilc_chip_sleep_manually(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900520{
Leo Kimb7d1e182015-11-06 11:12:30 +0900521 if (chip_ps_state != CHIP_WAKEDUP)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900522 return;
Glen Lee00215dd2015-11-18 15:11:25 +0900523 acquire_bus(wilc, ACQUIRE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900524
Glen Lee00215dd2015-11-18 15:11:25 +0900525 chip_allow_sleep(wilc);
Glen Leeaf9ae092015-12-21 14:18:09 +0900526 wilc->hif_func->hif_write_reg(wilc, 0x10a8, 1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900527
Leo Kimb7d1e182015-11-06 11:12:30 +0900528 chip_ps_state = CHIP_SLEEPING_MANUAL;
Glen Lee00215dd2015-11-18 15:11:25 +0900529 release_bus(wilc, RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900530}
Glen Lee76855ba2016-01-25 16:35:08 +0900531EXPORT_SYMBOL_GPL(wilc_chip_sleep_manually);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900532
Glen Leefdc2ac12016-01-25 16:35:07 +0900533void host_wakeup_notify(struct wilc *wilc)
534{
535 acquire_bus(wilc, ACQUIRE_ONLY);
536 wilc->hif_func->hif_write_reg(wilc, 0x10b0, 1);
537 release_bus(wilc, RELEASE_ONLY);
538}
Glen Lee76855ba2016-01-25 16:35:08 +0900539EXPORT_SYMBOL_GPL(host_wakeup_notify);
Glen Leefdc2ac12016-01-25 16:35:07 +0900540
541void host_sleep_notify(struct wilc *wilc)
542{
543 acquire_bus(wilc, ACQUIRE_ONLY);
544 wilc->hif_func->hif_write_reg(wilc, 0x10ac, 1);
545 release_bus(wilc, RELEASE_ONLY);
546}
Glen Lee76855ba2016-01-25 16:35:08 +0900547EXPORT_SYMBOL_GPL(host_sleep_notify);
Glen Leefdc2ac12016-01-25 16:35:07 +0900548
Leo Kimb1d19292015-11-06 11:13:01 +0900549int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900550{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900551 int i, entries = 0;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900552 u32 sum;
553 u32 reg;
Glen Lee67e2a072015-12-21 14:18:12 +0900554 u8 *txb;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900555 u32 offset = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900556 int vmm_sz = 0;
557 struct txq_entry_t *tqe;
558 int ret = 0;
559 int counter;
560 int timeout;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900561 u32 vmm_table[WILC_VMM_TBL_SIZE];
Glen Leea4cac482015-12-21 14:18:36 +0900562 struct wilc_vif *vif;
Glen Leea1332ca2015-10-27 18:27:47 +0900563 struct wilc *wilc;
564
Glen Leea4cac482015-12-21 14:18:36 +0900565 vif = netdev_priv(dev);
566 wilc = vif->wilc;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900567
Glen Lee67e2a072015-12-21 14:18:12 +0900568 txb = wilc->tx_buffer;
569 wilc->txq_exit = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900570 do {
Glen Lee67e2a072015-12-21 14:18:12 +0900571 if (wilc->quit)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900572 break;
573
Binoy Jayan334bed02016-06-15 11:00:35 +0530574 mutex_lock(&wilc->txq_add_to_head_cs);
Glen Leec029e992015-10-27 18:27:48 +0900575 wilc_wlan_txq_filter_dup_tcp_ack(dev);
Glen Lee7af05222015-10-29 12:18:41 +0900576 tqe = wilc_wlan_txq_get_first(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900577 i = 0;
578 sum = 0;
579 do {
Leo Kima4b17192015-11-06 11:12:31 +0900580 if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) {
Alison Schofield39823a52015-10-08 21:18:03 -0700581 if (tqe->type == WILC_CFG_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900582 vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700583
584 else if (tqe->type == WILC_NET_PKT)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900585 vmm_sz = ETH_ETHERNET_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700586
587 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900588 vmm_sz = HOST_HDR_OFFSET;
Alison Schofield39823a52015-10-08 21:18:03 -0700589
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900590 vmm_sz += tqe->buffer_size;
Chris Park133b22d62016-02-04 18:15:50 +0900591
Leo Kimac087c82015-11-06 11:12:25 +0900592 if (vmm_sz & 0x3)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900593 vmm_sz = (vmm_sz + 4) & ~0x3;
Leo Kimac087c82015-11-06 11:12:25 +0900594
Alison Schofield39823a52015-10-08 21:18:03 -0700595 if ((sum + vmm_sz) > LINUX_TX_SIZE)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900596 break;
Alison Schofield39823a52015-10-08 21:18:03 -0700597
Leo Kimac087c82015-11-06 11:12:25 +0900598 vmm_table[i] = vmm_sz / 4;
Chris Park133b22d62016-02-04 18:15:50 +0900599 if (tqe->type == WILC_CFG_PKT)
Anish Bhattffda2032015-09-29 12:15:49 -0700600 vmm_table[i] |= BIT(10);
Glen Lee9e6627a2015-12-21 14:18:08 +0900601 vmm_table[i] = cpu_to_le32(vmm_table[i]);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900602
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900603 i++;
604 sum += vmm_sz;
Glen Lee50a0b3b2015-10-27 18:28:00 +0900605 tqe = wilc_wlan_txq_get_next(wilc, tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900606 } else {
607 break;
608 }
609 } while (1);
610
Chris Parka4104792016-02-04 18:24:05 +0900611 if (i == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900612 break;
Rehas Sachdeva6e4d1a82016-02-26 18:17:45 +0530613 vmm_table[i] = 0x0;
Chris Parka4104792016-02-04 18:24:05 +0900614
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100615 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900616 counter = 0;
617 do {
Chris Park4d38a562016-02-04 18:15:49 +0900618 ret = wilc->hif_func->hif_read_reg(wilc,
619 WILC_HOST_TX_CTRL,
620 &reg);
Chris Park133b22d62016-02-04 18:15:50 +0900621 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900622 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900623
624 if ((reg & 0x1) == 0) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900625 break;
Anchal Jaina5c3f8d2016-03-13 15:14:38 +0530626 }
627 counter++;
628 if (counter > 200) {
629 counter = 0;
630 ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0);
631 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900632 }
Glen Lee67e2a072015-12-21 14:18:12 +0900633 } while (!wilc->quit);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900634
Alison Schofield39823a52015-10-08 21:18:03 -0700635 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900636 goto _end_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900637
638 timeout = 200;
639 do {
Glen Leeaf9ae092015-12-21 14:18:09 +0900640 ret = wilc->hif_func->hif_block_tx(wilc, WILC_VMM_TBL_RX_SHADOW_BASE, (u8 *)vmm_table, ((i + 1) * 4));
Chris Park133b22d62016-02-04 18:15:50 +0900641 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900642 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900643
Chris Park4d38a562016-02-04 18:15:49 +0900644 ret = wilc->hif_func->hif_write_reg(wilc,
645 WILC_HOST_VMM_CTL,
646 0x2);
Chris Park133b22d62016-02-04 18:15:50 +0900647 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900648 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900649
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900650 do {
Glen Leeaf9ae092015-12-21 14:18:09 +0900651 ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
Chris Park133b22d62016-02-04 18:15:50 +0900652 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900653 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900654 if ((reg >> 2) & 0x1) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900655 entries = ((reg >> 3) & 0x3f);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900656 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900657 }
Anchal Jaina5c3f8d2016-03-13 15:14:38 +0530658 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900659 } while (--timeout);
660 if (timeout <= 0) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900661 ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900662 break;
663 }
664
Alison Schofield39823a52015-10-08 21:18:03 -0700665 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900666 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900667
668 if (entries == 0) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900669 ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
Chris Park133b22d62016-02-04 18:15:50 +0900670 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900671 break;
Anish Bhattffda2032015-09-29 12:15:49 -0700672 reg &= ~BIT(0);
Glen Leeaf9ae092015-12-21 14:18:09 +0900673 ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);
Chris Park133b22d62016-02-04 18:15:50 +0900674 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900675 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900676 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900677 }
Anchal Jaina5c3f8d2016-03-13 15:14:38 +0530678 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900679 } while (1);
680
Alison Schofield39823a52015-10-08 21:18:03 -0700681 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900682 goto _end_;
Alison Schofield39823a52015-10-08 21:18:03 -0700683
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900684 if (entries == 0) {
685 ret = WILC_TX_ERR_NO_BUF;
686 goto _end_;
687 }
688
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100689 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900690
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900691 offset = 0;
692 i = 0;
693 do {
Glen Lee718fc2c2015-10-29 12:18:43 +0900694 tqe = wilc_wlan_txq_remove_from_head(dev);
Leo Kima4b17192015-11-06 11:12:31 +0900695 if (tqe && (vmm_table[i] != 0)) {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900696 u32 header, buffer_offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900697
Glen Lee9e6627a2015-12-21 14:18:08 +0900698 vmm_table[i] = cpu_to_le32(vmm_table[i]);
Leo Kimac087c82015-11-06 11:12:25 +0900699 vmm_sz = (vmm_table[i] & 0x3ff);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900700 vmm_sz *= 4;
Leo Kimab12d8c2015-11-06 11:19:54 +0900701 header = (tqe->type << 31) |
702 (tqe->buffer_size << 15) |
703 vmm_sz;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530704 if (tqe->type == WILC_MGMT_PKT)
Anish Bhattffda2032015-09-29 12:15:49 -0700705 header |= BIT(30);
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530706 else
Anish Bhattffda2032015-09-29 12:15:49 -0700707 header &= ~BIT(30);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900708
Glen Lee9e6627a2015-12-21 14:18:08 +0900709 header = cpu_to_le32(header);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900710 memcpy(&txb[offset], &header, 4);
711 if (tqe->type == WILC_CFG_PKT) {
712 buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
Leo Kim590c0a32015-11-06 11:13:02 +0900713 } else if (tqe->type == WILC_NET_PKT) {
Leo Kim5b9f5262016-02-04 18:15:34 +0900714 char *bssid = ((struct tx_complete_data *)(tqe->priv))->bssid;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900715
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900716 buffer_offset = ETH_ETHERNET_HDR_OFFSET;
Leo Kim2f7c31f2015-11-06 11:13:03 +0900717 memcpy(&txb[offset + 4], bssid, 6);
Leo Kim590c0a32015-11-06 11:13:02 +0900718 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900719 buffer_offset = HOST_HDR_OFFSET;
720 }
721
Leo Kimab12d8c2015-11-06 11:19:54 +0900722 memcpy(&txb[offset + buffer_offset],
723 tqe->buffer, tqe->buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900724 offset += vmm_sz;
725 i++;
Leo Kimac087c82015-11-06 11:12:25 +0900726 tqe->status = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900727 if (tqe->tx_complete_func)
Leo Kimab12d8c2015-11-06 11:19:54 +0900728 tqe->tx_complete_func(tqe->priv,
729 tqe->status);
Glen Lee4fd62292016-02-04 18:15:24 +0900730 if (tqe->tcp_pending_ack_idx != NOT_TCP_ACK &&
731 tqe->tcp_pending_ack_idx < MAX_PENDING_ACKS)
Glen Leeb7193022015-12-21 14:18:07 +0900732 pending_acks_info[tqe->tcp_pending_ack_idx].txqe = NULL;
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700733 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900734 } else {
735 break;
736 }
737 } while (--entries);
738
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100739 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900740
Glen Leeaf9ae092015-12-21 14:18:09 +0900741 ret = wilc->hif_func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
Chris Park133b22d62016-02-04 18:15:50 +0900742 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900743 goto _end_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900744
Glen Leeaf9ae092015-12-21 14:18:09 +0900745 ret = wilc->hif_func->hif_block_tx_ext(wilc, 0, txb, offset);
Chris Park133b22d62016-02-04 18:15:50 +0900746 if (!ret)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900747 goto _end_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900748
749_end_:
750
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100751 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900752 if (ret != 1)
753 break;
754 } while (0);
Binoy Jayan334bed02016-06-15 11:00:35 +0530755 mutex_unlock(&wilc->txq_add_to_head_cs);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900756
Glen Lee67e2a072015-12-21 14:18:12 +0900757 wilc->txq_exit = 1;
Glen Lee67e2a072015-12-21 14:18:12 +0900758 *txq_count = wilc->txq_entries;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900759 return ret;
760}
761
Glen Lee39ce4d32015-10-27 18:27:42 +0900762static void wilc_wlan_handle_rxq(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900763{
Chris Park5b3b7442016-02-04 18:24:27 +0900764 int offset = 0, size;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900765 u8 *buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900766 struct rxq_entry_t *rqe;
767
Glen Lee67e2a072015-12-21 14:18:12 +0900768 wilc->rxq_exit = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900769
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900770 do {
Glen Lee67e2a072015-12-21 14:18:12 +0900771 if (wilc->quit) {
Binoy Jayanfa659692016-06-15 11:00:36 +0530772 complete(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900773 break;
774 }
Glen Leedb387632015-10-27 18:27:55 +0900775 rqe = wilc_wlan_rxq_remove(wilc);
Chris Park133b22d62016-02-04 18:15:50 +0900776 if (!rqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900777 break;
Chris Park133b22d62016-02-04 18:15:50 +0900778
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900779 buffer = rqe->buffer;
780 size = rqe->buffer_size;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900781 offset = 0;
782
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900783 do {
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900784 u32 header;
785 u32 pkt_len, pkt_offset, tp_len;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900786 int is_cfg_packet;
Chaehyun Lim8dfaafd2015-08-18 23:18:11 +0900787
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900788 memcpy(&header, &buffer[offset], 4);
Glen Lee9e6627a2015-12-21 14:18:08 +0900789 header = cpu_to_le32(header);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900790
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900791 is_cfg_packet = (header >> 31) & 0x1;
792 pkt_offset = (header >> 22) & 0x1ff;
793 tp_len = (header >> 11) & 0x7ff;
794 pkt_len = header & 0x7ff;
795
Chris Park133b22d62016-02-04 18:15:50 +0900796 if (pkt_len == 0 || tp_len == 0)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900797 break;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900798
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900799 #define IS_MANAGMEMENT 0x100
800 #define IS_MANAGMEMENT_CALLBACK 0x080
801 #define IS_MGMT_STATUS_SUCCES 0x040
802
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900803 if (pkt_offset & IS_MANAGMEMENT) {
Leo Kimab12d8c2015-11-06 11:19:54 +0900804 pkt_offset &= ~(IS_MANAGMEMENT |
805 IS_MANAGMEMENT_CALLBACK |
806 IS_MGMT_STATUS_SUCCES);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900807
Glen Lee11f4b2e2015-10-27 18:27:51 +0900808 WILC_WFI_mgmt_rx(wilc, &buffer[offset + HOST_HDR_OFFSET], pkt_len);
Leo Kim590c0a32015-11-06 11:13:02 +0900809 } else {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900810 if (!is_cfg_packet) {
Glen Lee63611672015-09-24 18:14:52 +0900811 if (pkt_len > 0) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100812 wilc_frmw_to_linux(wilc,
Glen Leecb1991a2015-10-27 18:27:56 +0900813 &buffer[offset],
Glen Lee63611672015-09-24 18:14:52 +0900814 pkt_len,
815 pkt_offset);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900816 }
817 } else {
Leo Kimbcddd482015-11-06 11:20:01 +0900818 struct wilc_cfg_rsp rsp;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900819
Glen Leecd04d222015-12-21 14:18:42 +0900820 wilc_wlan_cfg_indicate_rx(wilc, &buffer[pkt_offset + offset], pkt_len, &rsp);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900821 if (rsp.type == WILC_CFG_RSP) {
Glen Lee67e2a072015-12-21 14:18:12 +0900822 if (wilc->cfg_seq_no == rsp.seq_no)
Binoy Jayanfa659692016-06-15 11:00:36 +0530823 complete(&wilc->cfg_event);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900824 } else if (rsp.type == WILC_CFG_RSP_STATUS) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100825 wilc_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900826
827 } else if (rsp.type == WILC_CFG_RSP_SCAN) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100828 wilc_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900829 }
830 }
831 }
832 offset += tp_len;
833 if (offset >= size)
834 break;
835 } while (1);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700836 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900837 } while (1);
838
Glen Lee67e2a072015-12-21 14:18:12 +0900839 wilc->rxq_exit = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900840}
841
Glen Lee00215dd2015-11-18 15:11:25 +0900842static void wilc_unknown_isr_ext(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900843{
Glen Leeaf9ae092015-12-21 14:18:09 +0900844 wilc->hif_func->hif_clear_int_ext(wilc, 0);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900845}
Leo Kim2d6973e2015-11-06 11:12:28 +0900846
Glen Lee00215dd2015-11-18 15:11:25 +0900847static void wilc_pllupdate_isr_ext(struct wilc *wilc, u32 int_stats)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900848{
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900849 int trials = 10;
850
Glen Leeaf9ae092015-12-21 14:18:09 +0900851 wilc->hif_func->hif_clear_int_ext(wilc, PLL_INT_CLR);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900852
Glen Leea3629a92015-12-21 14:18:10 +0900853 if (wilc->io_type == HIF_SDIO)
Arnd Bergmanne28e84d2015-11-16 15:05:07 +0100854 mdelay(WILC_PLL_TO_SDIO);
855 else
856 mdelay(WILC_PLL_TO_SPI);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900857
Chris Park133b22d62016-02-04 18:15:50 +0900858 while (!(ISWILC1000(wilc_get_chipid(wilc, true)) && --trials))
Greg Kroah-Hartmanc2e4c0f2015-09-03 19:09:50 -0700859 mdelay(1);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900860}
861
Glen Lee00215dd2015-11-18 15:11:25 +0900862static void wilc_sleeptimer_isr_ext(struct wilc *wilc, u32 int_stats1)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900863{
Glen Leeaf9ae092015-12-21 14:18:09 +0900864 wilc->hif_func->hif_clear_int_ext(wilc, SLEEP_INT_CLR);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900865}
866
Glen Lee3bcd45b2015-10-27 18:27:41 +0900867static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900868{
Glen Lee67e2a072015-12-21 14:18:12 +0900869 u32 offset = wilc->rx_buffer_offset;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900870 u8 *buffer = NULL;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900871 u32 size;
872 u32 retries = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900873 int ret = 0;
874 struct rxq_entry_t *rqe;
875
Alison Schofielde682e912016-02-10 21:34:41 -0800876 size = (int_status & 0x7fff) << 2;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900877
878 while (!size && retries < 10) {
Glen Leeaf9ae092015-12-21 14:18:09 +0900879 wilc->hif_func->hif_read_size(wilc, &size);
Alison Schofielde682e912016-02-10 21:34:41 -0800880 size = (size & 0x7fff) << 2;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900881 retries++;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900882 }
883
884 if (size > 0) {
Glen Lee03eb7262015-09-24 18:15:03 +0900885 if (LINUX_RX_SIZE - offset < size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900886 offset = 0;
887
Chris Park133b22d62016-02-04 18:15:50 +0900888 if (wilc->rx_buffer)
Glen Lee67e2a072015-12-21 14:18:12 +0900889 buffer = &wilc->rx_buffer[offset];
Chris Park133b22d62016-02-04 18:15:50 +0900890 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900891 goto _end_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900892
Glen Leeaf9ae092015-12-21 14:18:09 +0900893 wilc->hif_func->hif_clear_int_ext(wilc,
Glen Lee49dcd0d2015-11-18 15:11:26 +0900894 DATA_INT_CLR | ENABLE_RX_VMM);
Glen Leeaf9ae092015-12-21 14:18:09 +0900895 ret = wilc->hif_func->hif_block_rx_ext(wilc, 0, buffer, size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900896
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900897_end_:
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900898 if (ret) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900899 offset += size;
Glen Lee67e2a072015-12-21 14:18:12 +0900900 wilc->rx_buffer_offset = offset;
Leo Kim13b01e42015-11-06 11:13:04 +0900901 rqe = kmalloc(sizeof(*rqe), GFP_KERNEL);
Leo Kima4b17192015-11-06 11:12:31 +0900902 if (rqe) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900903 rqe->buffer = buffer;
904 rqe->buffer_size = size;
Glen Leed06f3622015-10-27 18:27:59 +0900905 wilc_wlan_rxq_add(wilc, rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900906 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900907 }
908 }
Glen Lee39ce4d32015-10-27 18:27:42 +0900909 wilc_wlan_handle_rxq(wilc);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900910}
911
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100912void wilc_handle_isr(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900913{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900914 u32 int_status;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900915
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100916 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Glen Leeaf9ae092015-12-21 14:18:09 +0900917 wilc->hif_func->hif_read_int(wilc, &int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900918
Alison Schofield39823a52015-10-08 21:18:03 -0700919 if (int_status & PLL_INT_EXT)
Glen Lee00215dd2015-11-18 15:11:25 +0900920 wilc_pllupdate_isr_ext(wilc, int_status);
Alison Schofield39823a52015-10-08 21:18:03 -0700921
Chris Parkf06b9ba2016-02-04 18:15:52 +0900922 if (int_status & DATA_INT_EXT)
Glen Lee3bcd45b2015-10-27 18:27:41 +0900923 wilc_wlan_handle_isr_ext(wilc, int_status);
Chris Parkf06b9ba2016-02-04 18:15:52 +0900924
Alison Schofield39823a52015-10-08 21:18:03 -0700925 if (int_status & SLEEP_INT_EXT)
Glen Lee00215dd2015-11-18 15:11:25 +0900926 wilc_sleeptimer_isr_ext(wilc, int_status);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900927
Chris Parkf06b9ba2016-02-04 18:15:52 +0900928 if (!(int_status & (ALL_INT_EXT)))
Glen Lee00215dd2015-11-18 15:11:25 +0900929 wilc_unknown_isr_ext(wilc);
Chris Parkf06b9ba2016-02-04 18:15:52 +0900930
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100931 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900932}
Arnd Bergmann750ffe92015-11-16 15:05:08 +0100933EXPORT_SYMBOL_GPL(wilc_handle_isr);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900934
Chris Park4d38a562016-02-04 18:15:49 +0900935int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
936 u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900937{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900938 u32 offset;
939 u32 addr, size, size2, blksz;
Chaehyun Lim51e825f2015-09-15 14:06:14 +0900940 u8 *dma_buffer;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900941 int ret = 0;
942
Anish Bhattffda2032015-09-29 12:15:49 -0700943 blksz = BIT(12);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900944
Greg Kroah-Hartmanf019b9d2015-09-03 18:50:27 -0700945 dma_buffer = kmalloc(blksz, GFP_KERNEL);
Leo Kim5c6021d2016-03-15 18:48:13 +0900946 if (!dma_buffer)
947 return -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900948
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900949 offset = 0;
950 do {
951 memcpy(&addr, &buffer[offset], 4);
952 memcpy(&size, &buffer[offset + 4], 4);
Glen Lee9e6627a2015-12-21 14:18:08 +0900953 addr = cpu_to_le32(addr);
954 size = cpu_to_le32(size);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100955 acquire_bus(wilc, ACQUIRE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900956 offset += 8;
957 while (((int)size) && (offset < buffer_size)) {
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530958 if (size <= blksz)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900959 size2 = size;
Chandra S Gorentla78174ad2015-08-08 17:41:36 +0530960 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900961 size2 = blksz;
Leo Kimac087c82015-11-06 11:12:25 +0900962
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900963 memcpy(dma_buffer, &buffer[offset], size2);
Chris Park4d38a562016-02-04 18:15:49 +0900964 ret = wilc->hif_func->hif_block_tx(wilc, addr,
965 dma_buffer, size2);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900966 if (!ret)
967 break;
968
969 addr += size2;
970 offset += size2;
971 size -= size2;
972 }
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100973 release_bus(wilc, RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900974
975 if (!ret) {
Leo Kim92e7d182015-11-06 11:19:55 +0900976 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900977 goto _fail_;
978 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900979 } while (offset < buffer_size);
980
981_fail_:
982
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -0700983 kfree(dma_buffer);
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900984
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900985 return (ret < 0) ? ret : 0;
986}
987
Arnd Bergmann562ed3f2015-11-16 15:05:10 +0100988int wilc_wlan_start(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900989{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900990 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900991 int ret;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +0900992 u32 chipid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900993
Glen Leea3629a92015-12-21 14:18:10 +0900994 if (wilc->io_type == HIF_SDIO) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900995 reg = 0;
Leo Kimac087c82015-11-06 11:12:25 +0900996 reg |= BIT(3);
Glen Leea3629a92015-12-21 14:18:10 +0900997 } else if (wilc->io_type == HIF_SPI) {
Johnny Kimc5c77ba2015-05-11 14:30:56 +0900998 reg = 1;
999 }
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001000 acquire_bus(wilc, ACQUIRE_ONLY);
Glen Leeaf9ae092015-12-21 14:18:09 +09001001 ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001002 if (!ret) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001003 release_bus(wilc, RELEASE_ONLY);
Leo Kim92e7d182015-11-06 11:19:55 +09001004 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001005 return ret;
1006 }
1007 reg = 0;
Glen Leea3629a92015-12-21 14:18:10 +09001008 if (wilc->io_type == HIF_SDIO && wilc->dev_irq_num)
Arnd Bergmannc4d139c2015-11-16 15:05:04 +01001009 reg |= WILC_HAVE_SDIO_IRQ_GPIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001010
1011#ifdef WILC_DISABLE_PMU
1012#else
1013 reg |= WILC_HAVE_USE_PMU;
1014#endif
1015
1016#ifdef WILC_SLEEP_CLK_SRC_XO
1017 reg |= WILC_HAVE_SLEEP_CLK_SRC_XO;
1018#elif defined WILC_SLEEP_CLK_SRC_RTC
1019 reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC;
1020#endif
1021
1022#ifdef WILC_EXT_PA_INV_TX_RX
1023 reg |= WILC_HAVE_EXT_PA_INV_TX_RX;
1024#endif
Glen Leefdc2ac12016-01-25 16:35:07 +09001025 reg |= WILC_HAVE_USE_IRQ_AS_HOST_WAKE;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001026 reg |= WILC_HAVE_LEGACY_RF_SETTINGS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001027#ifdef XTAL_24
1028 reg |= WILC_HAVE_XTAL_24;
1029#endif
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001030#ifdef DISABLE_WILC_UART
1031 reg |= WILC_HAVE_DISABLE_WILC_UART;
1032#endif
1033
Glen Leeaf9ae092015-12-21 14:18:09 +09001034 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001035 if (!ret) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001036 release_bus(wilc, RELEASE_ONLY);
Leo Kim92e7d182015-11-06 11:19:55 +09001037 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001038 return ret;
1039 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001040
Glen Leeaf9ae092015-12-21 14:18:09 +09001041 wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001042
Glen Leeaf9ae092015-12-21 14:18:09 +09001043 ret = wilc->hif_func->hif_read_reg(wilc, 0x1000, &chipid);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001044 if (!ret) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001045 release_bus(wilc, RELEASE_ONLY);
Leo Kim92e7d182015-11-06 11:19:55 +09001046 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001047 return ret;
1048 }
1049
Glen Leeaf9ae092015-12-21 14:18:09 +09001050 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
Anish Bhattffda2032015-09-29 12:15:49 -07001051 if ((reg & BIT(10)) == BIT(10)) {
1052 reg &= ~BIT(10);
Glen Leeaf9ae092015-12-21 14:18:09 +09001053 wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
1054 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001055 }
1056
Anish Bhattffda2032015-09-29 12:15:49 -07001057 reg |= BIT(10);
Glen Leeaf9ae092015-12-21 14:18:09 +09001058 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
1059 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001060 release_bus(wilc, RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001061
1062 return (ret < 0) ? ret : 0;
1063}
1064
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001065int wilc_wlan_stop(struct wilc *wilc)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001066{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001067 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001068 int ret;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001069 u8 timeout = 10;
Chris Park20f4e712016-02-04 18:15:53 +09001070
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001071 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001072
Glen Leeaf9ae092015-12-21 14:18:09 +09001073 ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001074 if (!ret) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001075 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001076 return ret;
1077 }
1078
Anish Bhattffda2032015-09-29 12:15:49 -07001079 reg &= ~BIT(10);
Glen Leeaf9ae092015-12-21 14:18:09 +09001080 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001081 if (!ret) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001082 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001083 return ret;
1084 }
1085
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001086 do {
Chris Park4d38a562016-02-04 18:15:49 +09001087 ret = wilc->hif_func->hif_read_reg(wilc,
1088 WILC_GLB_RESET_0, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001089 if (!ret) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001090 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001091 return ret;
1092 }
Leo Kimac087c82015-11-06 11:12:25 +09001093
Anish Bhattffda2032015-09-29 12:15:49 -07001094 if ((reg & BIT(10))) {
Anish Bhattffda2032015-09-29 12:15:49 -07001095 reg &= ~BIT(10);
Chris Park4d38a562016-02-04 18:15:49 +09001096 ret = wilc->hif_func->hif_write_reg(wilc,
1097 WILC_GLB_RESET_0,
1098 reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001099 timeout--;
1100 } else {
Chris Park4d38a562016-02-04 18:15:49 +09001101 ret = wilc->hif_func->hif_read_reg(wilc,
1102 WILC_GLB_RESET_0,
1103 &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001104 if (!ret) {
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001105 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001106 return ret;
1107 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001108 break;
1109 }
1110
1111 } while (timeout);
Anish Bhattffda2032015-09-29 12:15:49 -07001112 reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | BIT(26) |
1113 BIT(29) | BIT(30) | BIT(31));
Anish Bhatt65ead4e2015-09-29 12:15:48 -07001114
Glen Leeaf9ae092015-12-21 14:18:09 +09001115 wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
Anish Bhattffda2032015-09-29 12:15:49 -07001116 reg = (u32)~BIT(10);
Anish Bhatt65ead4e2015-09-29 12:15:48 -07001117
Glen Leeaf9ae092015-12-21 14:18:09 +09001118 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001119
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001120 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001121
1122 return ret;
1123}
1124
Glen Lee2de7cbe2015-10-27 18:27:54 +09001125void wilc_wlan_cleanup(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001126{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001127 struct txq_entry_t *tqe;
1128 struct rxq_entry_t *rqe;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001129 u32 reg = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001130 int ret;
Glen Leea4cac482015-12-21 14:18:36 +09001131 struct wilc_vif *vif;
Glen Leedb387632015-10-27 18:27:55 +09001132 struct wilc *wilc;
1133
Glen Leea4cac482015-12-21 14:18:36 +09001134 vif = netdev_priv(dev);
1135 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001136
Glen Lee67e2a072015-12-21 14:18:12 +09001137 wilc->quit = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001138 do {
Glen Lee718fc2c2015-10-29 12:18:43 +09001139 tqe = wilc_wlan_txq_remove_from_head(dev);
Leo Kima4b17192015-11-06 11:12:31 +09001140 if (!tqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001141 break;
1142 if (tqe->tx_complete_func)
1143 tqe->tx_complete_func(tqe->priv, 0);
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001144 kfree(tqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001145 } while (1);
1146
1147 do {
Glen Leedb387632015-10-27 18:27:55 +09001148 rqe = wilc_wlan_rxq_remove(wilc);
Leo Kima4b17192015-11-06 11:12:31 +09001149 if (!rqe)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001150 break;
Greg Kroah-Hartmana18dd632015-09-03 19:04:19 -07001151 kfree(rqe);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001152 } while (1);
1153
Glen Lee67e2a072015-12-21 14:18:12 +09001154 kfree(wilc->rx_buffer);
1155 wilc->rx_buffer = NULL;
1156 kfree(wilc->tx_buffer);
Glen Lee608b0512015-12-21 14:18:50 +09001157 wilc->tx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001158
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001159 acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001160
Glen Leeaf9ae092015-12-21 14:18:09 +09001161 ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, &reg);
Chris Park133b22d62016-02-04 18:15:50 +09001162 if (!ret)
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001163 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Chris Park133b22d62016-02-04 18:15:50 +09001164
Glen Leeaf9ae092015-12-21 14:18:09 +09001165 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,
Glen Lee49dcd0d2015-11-18 15:11:26 +09001166 (reg | ABORT_INT));
Chris Park133b22d62016-02-04 18:15:50 +09001167 if (!ret)
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001168 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Chris Park133b22d62016-02-04 18:15:50 +09001169
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001170 release_bus(wilc, RELEASE_ALLOW_SLEEP);
Glen Leeaf9ae092015-12-21 14:18:09 +09001171 wilc->hif_func->hif_deinit(NULL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001172}
1173
Glen Lee79df6a42016-02-04 18:15:31 +09001174static int wilc_wlan_cfg_commit(struct wilc_vif *vif, int type,
1175 u32 drv_handler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001176{
Glen Lee79df6a42016-02-04 18:15:31 +09001177 struct wilc *wilc = vif->wilc;
Glen Lee67e2a072015-12-21 14:18:12 +09001178 struct wilc_cfg_frame *cfg = &wilc->cfg_frame;
1179 int total_len = wilc->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE;
1180 int seq_no = wilc->cfg_seq_no % 256;
Leo Kim48641672015-11-06 11:13:08 +09001181 int driver_handler = (u32)drv_handler;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001182
Leo Kim076ef652015-11-06 11:13:07 +09001183 if (type == WILC_CFG_SET)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001184 cfg->wid_header[0] = 'W';
Leo Kim076ef652015-11-06 11:13:07 +09001185 else
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001186 cfg->wid_header[0] = 'Q';
Leo Kimac087c82015-11-06 11:12:25 +09001187 cfg->wid_header[1] = seq_no;
Chaehyun Lim51e825f2015-09-15 14:06:14 +09001188 cfg->wid_header[2] = (u8)total_len;
1189 cfg->wid_header[3] = (u8)(total_len >> 8);
1190 cfg->wid_header[4] = (u8)driver_handler;
1191 cfg->wid_header[5] = (u8)(driver_handler >> 8);
1192 cfg->wid_header[6] = (u8)(driver_handler >> 16);
1193 cfg->wid_header[7] = (u8)(driver_handler >> 24);
Glen Lee67e2a072015-12-21 14:18:12 +09001194 wilc->cfg_seq_no = seq_no;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001195
Glen Lee79df6a42016-02-04 18:15:31 +09001196 if (!wilc_wlan_txq_add_cfg_pkt(vif, &cfg->wid_header[0], total_len))
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001197 return -1;
1198
1199 return 0;
1200}
1201
Chaehyun Lim70011f52016-03-28 13:55:56 +09001202int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,
Glen Lee89758e12015-11-18 15:11:34 +09001203 u32 buffer_size, int commit, u32 drv_handler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001204{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001205 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001206 int ret_size;
Glen Lee79df6a42016-02-04 18:15:31 +09001207 struct wilc *wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001208
Glen Lee67e2a072015-12-21 14:18:12 +09001209 if (wilc->cfg_frame_in_use)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001210 return 0;
1211
1212 if (start)
Glen Lee67e2a072015-12-21 14:18:12 +09001213 wilc->cfg_frame_offset = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001214
Glen Lee67e2a072015-12-21 14:18:12 +09001215 offset = wilc->cfg_frame_offset;
1216 ret_size = wilc_wlan_cfg_set_wid(wilc->cfg_frame.frame, offset,
Chaehyun Lim70011f52016-03-28 13:55:56 +09001217 wid, buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001218 offset += ret_size;
Glen Lee67e2a072015-12-21 14:18:12 +09001219 wilc->cfg_frame_offset = offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001220
1221 if (commit) {
Glen Lee79df6a42016-02-04 18:15:31 +09001222 netdev_dbg(vif->ndev,
1223 "[WILC]PACKET Commit with sequence number %d\n",
1224 wilc->cfg_seq_no);
1225 netdev_dbg(vif->ndev, "Processing cfg_set()\n");
Glen Lee67e2a072015-12-21 14:18:12 +09001226 wilc->cfg_frame_in_use = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001227
Glen Lee79df6a42016-02-04 18:15:31 +09001228 if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001229 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001230
Binoy Jayanfa659692016-06-15 11:00:36 +05301231 if (!wait_for_completion_timeout(&wilc->cfg_event,
1232 msecs_to_jiffies(CFG_PKTS_TIMEOUT))) {
Glen Lee79df6a42016-02-04 18:15:31 +09001233 netdev_dbg(vif->ndev, "Set Timed Out\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001234 ret_size = 0;
1235 }
Binoy Jayanfa659692016-06-15 11:00:36 +05301236
Glen Lee67e2a072015-12-21 14:18:12 +09001237 wilc->cfg_frame_in_use = 0;
1238 wilc->cfg_frame_offset = 0;
1239 wilc->cfg_seq_no += 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001240 }
1241
1242 return ret_size;
1243}
Leo Kim2d6973e2015-11-06 11:12:28 +09001244
Chaehyun Lim7db699d2016-03-28 13:55:57 +09001245int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,
Glen Leed40c99c2015-11-18 15:11:35 +09001246 u32 drv_handler)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001247{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001248 u32 offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001249 int ret_size;
Glen Lee79df6a42016-02-04 18:15:31 +09001250 struct wilc *wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001251
Glen Lee67e2a072015-12-21 14:18:12 +09001252 if (wilc->cfg_frame_in_use)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001253 return 0;
1254
1255 if (start)
Glen Lee67e2a072015-12-21 14:18:12 +09001256 wilc->cfg_frame_offset = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001257
Glen Lee67e2a072015-12-21 14:18:12 +09001258 offset = wilc->cfg_frame_offset;
Chaehyun Lim7db699d2016-03-28 13:55:57 +09001259 ret_size = wilc_wlan_cfg_get_wid(wilc->cfg_frame.frame, offset, wid);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001260 offset += ret_size;
Glen Lee67e2a072015-12-21 14:18:12 +09001261 wilc->cfg_frame_offset = offset;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001262
1263 if (commit) {
Glen Lee67e2a072015-12-21 14:18:12 +09001264 wilc->cfg_frame_in_use = 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001265
Glen Lee79df6a42016-02-04 18:15:31 +09001266 if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler))
Chaehyun Lim5af6b852015-09-17 16:48:48 +09001267 ret_size = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001268
Binoy Jayanfa659692016-06-15 11:00:36 +05301269 if (!wait_for_completion_timeout(&wilc->cfg_event,
1270 msecs_to_jiffies(CFG_PKTS_TIMEOUT))) {
Glen Lee79df6a42016-02-04 18:15:31 +09001271 netdev_dbg(vif->ndev, "Get Timed Out\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001272 ret_size = 0;
1273 }
Glen Lee67e2a072015-12-21 14:18:12 +09001274 wilc->cfg_frame_in_use = 0;
1275 wilc->cfg_frame_offset = 0;
1276 wilc->cfg_seq_no += 1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001277 }
1278
1279 return ret_size;
1280}
1281
Chaehyun Limc975f9d2016-03-28 13:55:58 +09001282int wilc_wlan_cfg_get_val(u16 wid, u8 *buffer, u32 buffer_size)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001283{
Chaehyun Limc975f9d2016-03-28 13:55:58 +09001284 return wilc_wlan_cfg_get_wid_value(wid, buffer, buffer_size);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001285}
1286
Chaehyun Lim6e944452016-02-11 13:46:22 +09001287int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
Glen Leeef7e0122016-02-04 18:15:30 +09001288 u32 count, u32 drv)
1289{
Chaehyun Limb3306362016-02-11 13:46:25 +09001290 int i;
Chaehyun Lim6e944452016-02-11 13:46:22 +09001291 int ret = 0;
Glen Leeef7e0122016-02-04 18:15:30 +09001292
1293 if (mode == GET_CFG) {
Chaehyun Limb3306362016-02-11 13:46:25 +09001294 for (i = 0; i < count; i++) {
1295 if (!wilc_wlan_cfg_get(vif, !i,
1296 wids[i].id,
1297 (i == count - 1),
Glen Leeef7e0122016-02-04 18:15:30 +09001298 drv)) {
1299 ret = -ETIMEDOUT;
1300 break;
1301 }
1302 }
Chaehyun Limb3306362016-02-11 13:46:25 +09001303 for (i = 0; i < count; i++) {
1304 wids[i].size = wilc_wlan_cfg_get_val(wids[i].id,
1305 wids[i].val,
1306 wids[i].size);
Glen Leeef7e0122016-02-04 18:15:30 +09001307 }
1308 } else if (mode == SET_CFG) {
Chaehyun Limb3306362016-02-11 13:46:25 +09001309 for (i = 0; i < count; i++) {
1310 if (!wilc_wlan_cfg_set(vif, !i,
1311 wids[i].id,
1312 wids[i].val,
1313 wids[i].size,
1314 (i == count - 1),
Glen Leeef7e0122016-02-04 18:15:30 +09001315 drv)) {
1316 ret = -ETIMEDOUT;
1317 break;
1318 }
1319 }
1320 }
1321
1322 return ret;
1323}
1324
Arnd Bergmann1608c402015-11-16 15:04:53 +01001325static u32 init_chip(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001326{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001327 u32 chipid;
1328 u32 reg, ret = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001329 struct wilc_vif *vif;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001330 struct wilc *wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001331
Glen Leea4cac482015-12-21 14:18:36 +09001332 vif = netdev_priv(dev);
1333 wilc = vif->wilc;
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001334
1335 acquire_bus(wilc, ACQUIRE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001336
Glen Lee00215dd2015-11-18 15:11:25 +09001337 chipid = wilc_get_chipid(wilc, true);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001338
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001339 if ((chipid & 0xfff) != 0xa0) {
Glen Leeaf9ae092015-12-21 14:18:09 +09001340 ret = wilc->hif_func->hif_read_reg(wilc, 0x1118, &reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001341 if (!ret) {
Leo Kime974b532016-02-22 13:41:11 +09001342 netdev_err(dev, "fail read reg 0x1118\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001343 return ret;
1344 }
Anish Bhattffda2032015-09-29 12:15:49 -07001345 reg |= BIT(0);
Glen Leeaf9ae092015-12-21 14:18:09 +09001346 ret = wilc->hif_func->hif_write_reg(wilc, 0x1118, reg);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001347 if (!ret) {
Leo Kime974b532016-02-22 13:41:11 +09001348 netdev_err(dev, "fail write reg 0x1118\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001349 return ret;
1350 }
Glen Leeaf9ae092015-12-21 14:18:09 +09001351 ret = wilc->hif_func->hif_write_reg(wilc, 0xc0000, 0x71);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001352 if (!ret) {
Leo Kime974b532016-02-22 13:41:11 +09001353 netdev_err(dev, "fail write reg 0xc0000\n");
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001354 return ret;
1355 }
1356 }
1357
Arnd Bergmann562ed3f2015-11-16 15:05:10 +01001358 release_bus(wilc, RELEASE_ONLY);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001359
1360 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001361}
1362
Chris Park65c3f002016-02-04 18:15:54 +09001363u32 wilc_get_chipid(struct wilc *wilc, bool update)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001364{
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001365 static u32 chipid;
Chaehyun Limfbc2fe12015-09-15 14:06:16 +09001366 u32 tempchipid = 0;
Chris Park65c3f002016-02-04 18:15:54 +09001367 u32 rfrevid = 0;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001368
Chris Park65c3f002016-02-04 18:15:54 +09001369 if (chipid == 0 || update) {
Glen Leeaf9ae092015-12-21 14:18:09 +09001370 wilc->hif_func->hif_read_reg(wilc, 0x1000, &tempchipid);
1371 wilc->hif_func->hif_read_reg(wilc, 0x13f4, &rfrevid);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001372 if (!ISWILC1000(tempchipid)) {
1373 chipid = 0;
Chris Park65c3f002016-02-04 18:15:54 +09001374 return chipid;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001375 }
1376 if (tempchipid == 0x1002a0) {
Chris Park65c3f002016-02-04 18:15:54 +09001377 if (rfrevid != 0x1)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001378 tempchipid = 0x1002a1;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001379 } else if (tempchipid == 0x1002b0) {
Chris Park65c3f002016-02-04 18:15:54 +09001380 if (rfrevid == 0x4)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001381 tempchipid = 0x1002b1;
Chris Park65c3f002016-02-04 18:15:54 +09001382 else if (rfrevid != 0x3)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001383 tempchipid = 0x1002b2;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001384 }
1385
1386 chipid = tempchipid;
1387 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001388 return chipid;
1389}
1390
Arnd Bergmann4bd7baf2015-11-16 15:04:59 +01001391int wilc_wlan_init(struct net_device *dev)
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001392{
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001393 int ret = 0;
Glen Leea4cac482015-12-21 14:18:36 +09001394 struct wilc_vif *vif = netdev_priv(dev);
Glen Lee9c800322015-11-06 18:40:22 +09001395 struct wilc *wilc;
1396
Glen Leea4cac482015-12-21 14:18:36 +09001397 wilc = vif->wilc;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001398
Glen Lee0c94df02016-01-25 16:35:05 +09001399 wilc->quit = 0;
1400
Glen Lee5397cbc2016-01-25 16:35:09 +09001401 if (!wilc->hif_func->hif_init(wilc, false)) {
Glen Leecdb99232015-11-06 18:39:58 +09001402 ret = -EIO;
1403 goto _fail_;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001404 }
1405
Leo Kimbda2b2f2016-02-22 13:41:15 +09001406 if (!wilc_wlan_cfg_init()) {
Leo Kim92e7d182015-11-06 11:19:55 +09001407 ret = -ENOBUFS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001408 goto _fail_;
1409 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001410
Glen Lee67e2a072015-12-21 14:18:12 +09001411 if (!wilc->tx_buffer)
1412 wilc->tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL);
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001413
Glen Lee67e2a072015-12-21 14:18:12 +09001414 if (!wilc->tx_buffer) {
Leo Kim92e7d182015-11-06 11:19:55 +09001415 ret = -ENOBUFS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001416 goto _fail_;
1417 }
1418
Glen Lee67e2a072015-12-21 14:18:12 +09001419 if (!wilc->rx_buffer)
1420 wilc->rx_buffer = kmalloc(LINUX_RX_SIZE, GFP_KERNEL);
Chris Park133b22d62016-02-04 18:15:50 +09001421
Glen Lee67e2a072015-12-21 14:18:12 +09001422 if (!wilc->rx_buffer) {
Leo Kim92e7d182015-11-06 11:19:55 +09001423 ret = -ENOBUFS;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001424 goto _fail_;
1425 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001426
Glen Leeae6f7722015-10-29 12:18:48 +09001427 if (!init_chip(dev)) {
Leo Kim92e7d182015-11-06 11:19:55 +09001428 ret = -EIO;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001429 goto _fail_;
1430 }
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001431
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001432 return 1;
1433
1434_fail_:
1435
Glen Lee67e2a072015-12-21 14:18:12 +09001436 kfree(wilc->rx_buffer);
1437 wilc->rx_buffer = NULL;
1438 kfree(wilc->tx_buffer);
1439 wilc->tx_buffer = NULL;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001440
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001441 return ret;
Johnny Kimc5c77ba2015-05-11 14:30:56 +09001442}