162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
462306a36Sopenharmony_ci * All rights reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/if_ether.h>
862306a36Sopenharmony_ci#include <linux/ip.h>
962306a36Sopenharmony_ci#include <net/dsfield.h>
1062306a36Sopenharmony_ci#include "cfg80211.h"
1162306a36Sopenharmony_ci#include "wlan_cfg.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define WAKE_UP_TRIAL_RETRY		10000
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic inline bool is_wilc1000(u32 id)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID;
1862306a36Sopenharmony_ci}
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	mutex_lock(&wilc->hif_cs);
2362306a36Sopenharmony_ci	if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode)
2462306a36Sopenharmony_ci		chip_wakeup(wilc);
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic inline void release_bus(struct wilc *wilc, enum bus_release release)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode)
3062306a36Sopenharmony_ci		chip_allow_sleep(wilc);
3162306a36Sopenharmony_ci	mutex_unlock(&wilc->hif_cs);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num,
3562306a36Sopenharmony_ci				 struct txq_entry_t *tqe)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	list_del(&tqe->list);
3862306a36Sopenharmony_ci	wilc->txq_entries -= 1;
3962306a36Sopenharmony_ci	wilc->txq[q_num].count--;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic struct txq_entry_t *
4362306a36Sopenharmony_ciwilc_wlan_txq_remove_from_head(struct wilc *wilc, u8 q_num)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	struct txq_entry_t *tqe = NULL;
4662306a36Sopenharmony_ci	unsigned long flags;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	spin_lock_irqsave(&wilc->txq_spinlock, flags);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (!list_empty(&wilc->txq[q_num].txq_head.list)) {
5162306a36Sopenharmony_ci		tqe = list_first_entry(&wilc->txq[q_num].txq_head.list,
5262306a36Sopenharmony_ci				       struct txq_entry_t, list);
5362306a36Sopenharmony_ci		list_del(&tqe->list);
5462306a36Sopenharmony_ci		wilc->txq_entries -= 1;
5562306a36Sopenharmony_ci		wilc->txq[q_num].count--;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci	spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
5862306a36Sopenharmony_ci	return tqe;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void wilc_wlan_txq_add_to_tail(struct net_device *dev, u8 q_num,
6262306a36Sopenharmony_ci				      struct txq_entry_t *tqe)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	unsigned long flags;
6562306a36Sopenharmony_ci	struct wilc_vif *vif = netdev_priv(dev);
6662306a36Sopenharmony_ci	struct wilc *wilc = vif->wilc;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	spin_lock_irqsave(&wilc->txq_spinlock, flags);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	list_add_tail(&tqe->list, &wilc->txq[q_num].txq_head.list);
7162306a36Sopenharmony_ci	wilc->txq_entries += 1;
7262306a36Sopenharmony_ci	wilc->txq[q_num].count++;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	complete(&wilc->txq_event);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, u8 q_num,
8062306a36Sopenharmony_ci				      struct txq_entry_t *tqe)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	unsigned long flags;
8362306a36Sopenharmony_ci	struct wilc *wilc = vif->wilc;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	mutex_lock(&wilc->txq_add_to_head_cs);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	spin_lock_irqsave(&wilc->txq_spinlock, flags);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	list_add(&tqe->list, &wilc->txq[q_num].txq_head.list);
9062306a36Sopenharmony_ci	wilc->txq_entries += 1;
9162306a36Sopenharmony_ci	wilc->txq[q_num].count++;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
9462306a36Sopenharmony_ci	mutex_unlock(&wilc->txq_add_to_head_cs);
9562306a36Sopenharmony_ci	complete(&wilc->txq_event);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define NOT_TCP_ACK			(-1)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic inline void add_tcp_session(struct wilc_vif *vif, u32 src_prt,
10162306a36Sopenharmony_ci				   u32 dst_prt, u32 seq)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct tcp_ack_filter *f = &vif->ack_filter;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (f->tcp_session < 2 * MAX_TCP_SESSION) {
10662306a36Sopenharmony_ci		f->ack_session_info[f->tcp_session].seq_num = seq;
10762306a36Sopenharmony_ci		f->ack_session_info[f->tcp_session].bigger_ack_num = 0;
10862306a36Sopenharmony_ci		f->ack_session_info[f->tcp_session].src_port = src_prt;
10962306a36Sopenharmony_ci		f->ack_session_info[f->tcp_session].dst_port = dst_prt;
11062306a36Sopenharmony_ci		f->tcp_session++;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic inline void update_tcp_session(struct wilc_vif *vif, u32 index, u32 ack)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct tcp_ack_filter *f = &vif->ack_filter;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	if (index < 2 * MAX_TCP_SESSION &&
11962306a36Sopenharmony_ci	    ack > f->ack_session_info[index].bigger_ack_num)
12062306a36Sopenharmony_ci		f->ack_session_info[index].bigger_ack_num = ack;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic inline void add_tcp_pending_ack(struct wilc_vif *vif, u32 ack,
12462306a36Sopenharmony_ci				       u32 session_index,
12562306a36Sopenharmony_ci				       struct txq_entry_t *txqe)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct tcp_ack_filter *f = &vif->ack_filter;
12862306a36Sopenharmony_ci	u32 i = f->pending_base + f->pending_acks_idx;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (i < MAX_PENDING_ACKS) {
13162306a36Sopenharmony_ci		f->pending_acks[i].ack_num = ack;
13262306a36Sopenharmony_ci		f->pending_acks[i].txqe = txqe;
13362306a36Sopenharmony_ci		f->pending_acks[i].session_index = session_index;
13462306a36Sopenharmony_ci		txqe->ack_idx = i;
13562306a36Sopenharmony_ci		f->pending_acks_idx++;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	void *buffer = tqe->buffer;
14262306a36Sopenharmony_ci	const struct ethhdr *eth_hdr_ptr = buffer;
14362306a36Sopenharmony_ci	int i;
14462306a36Sopenharmony_ci	unsigned long flags;
14562306a36Sopenharmony_ci	struct wilc_vif *vif = netdev_priv(dev);
14662306a36Sopenharmony_ci	struct wilc *wilc = vif->wilc;
14762306a36Sopenharmony_ci	struct tcp_ack_filter *f = &vif->ack_filter;
14862306a36Sopenharmony_ci	const struct iphdr *ip_hdr_ptr;
14962306a36Sopenharmony_ci	const struct tcphdr *tcp_hdr_ptr;
15062306a36Sopenharmony_ci	u32 ihl, total_length, data_offset;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	spin_lock_irqsave(&wilc->txq_spinlock, flags);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (eth_hdr_ptr->h_proto != htons(ETH_P_IP))
15562306a36Sopenharmony_ci		goto out;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	ip_hdr_ptr = buffer + ETH_HLEN;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (ip_hdr_ptr->protocol != IPPROTO_TCP)
16062306a36Sopenharmony_ci		goto out;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	ihl = ip_hdr_ptr->ihl << 2;
16362306a36Sopenharmony_ci	tcp_hdr_ptr = buffer + ETH_HLEN + ihl;
16462306a36Sopenharmony_ci	total_length = ntohs(ip_hdr_ptr->tot_len);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	data_offset = tcp_hdr_ptr->doff << 2;
16762306a36Sopenharmony_ci	if (total_length == (ihl + data_offset)) {
16862306a36Sopenharmony_ci		u32 seq_no, ack_no;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		seq_no = ntohl(tcp_hdr_ptr->seq);
17162306a36Sopenharmony_ci		ack_no = ntohl(tcp_hdr_ptr->ack_seq);
17262306a36Sopenharmony_ci		for (i = 0; i < f->tcp_session; i++) {
17362306a36Sopenharmony_ci			u32 j = f->ack_session_info[i].seq_num;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci			if (i < 2 * MAX_TCP_SESSION &&
17662306a36Sopenharmony_ci			    j == seq_no) {
17762306a36Sopenharmony_ci				update_tcp_session(vif, i, ack_no);
17862306a36Sopenharmony_ci				break;
17962306a36Sopenharmony_ci			}
18062306a36Sopenharmony_ci		}
18162306a36Sopenharmony_ci		if (i == f->tcp_session)
18262306a36Sopenharmony_ci			add_tcp_session(vif, 0, 0, seq_no);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci		add_tcp_pending_ack(vif, ack_no, i, tqe);
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ciout:
18862306a36Sopenharmony_ci	spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	struct wilc_vif *vif = netdev_priv(dev);
19462306a36Sopenharmony_ci	struct wilc *wilc = vif->wilc;
19562306a36Sopenharmony_ci	struct tcp_ack_filter *f = &vif->ack_filter;
19662306a36Sopenharmony_ci	u32 i = 0;
19762306a36Sopenharmony_ci	u32 dropped = 0;
19862306a36Sopenharmony_ci	unsigned long flags;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	spin_lock_irqsave(&wilc->txq_spinlock, flags);
20162306a36Sopenharmony_ci	for (i = f->pending_base;
20262306a36Sopenharmony_ci	     i < (f->pending_base + f->pending_acks_idx); i++) {
20362306a36Sopenharmony_ci		u32 index;
20462306a36Sopenharmony_ci		u32 bigger_ack_num;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		if (i >= MAX_PENDING_ACKS)
20762306a36Sopenharmony_ci			break;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		index = f->pending_acks[i].session_index;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		if (index >= 2 * MAX_TCP_SESSION)
21262306a36Sopenharmony_ci			break;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		bigger_ack_num = f->ack_session_info[index].bigger_ack_num;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		if (f->pending_acks[i].ack_num < bigger_ack_num) {
21762306a36Sopenharmony_ci			struct txq_entry_t *tqe;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci			tqe = f->pending_acks[i].txqe;
22062306a36Sopenharmony_ci			if (tqe) {
22162306a36Sopenharmony_ci				wilc_wlan_txq_remove(wilc, tqe->q_num, tqe);
22262306a36Sopenharmony_ci				tqe->status = 1;
22362306a36Sopenharmony_ci				if (tqe->tx_complete_func)
22462306a36Sopenharmony_ci					tqe->tx_complete_func(tqe->priv,
22562306a36Sopenharmony_ci							      tqe->status);
22662306a36Sopenharmony_ci				kfree(tqe);
22762306a36Sopenharmony_ci				dropped++;
22862306a36Sopenharmony_ci			}
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	f->pending_acks_idx = 0;
23262306a36Sopenharmony_ci	f->tcp_session = 0;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (f->pending_base == 0)
23562306a36Sopenharmony_ci		f->pending_base = MAX_TCP_SESSION;
23662306a36Sopenharmony_ci	else
23762306a36Sopenharmony_ci		f->pending_base = 0;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	while (dropped > 0) {
24262306a36Sopenharmony_ci		wait_for_completion_timeout(&wilc->txq_event,
24362306a36Sopenharmony_ci					    msecs_to_jiffies(1));
24462306a36Sopenharmony_ci		dropped--;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_civoid wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	vif->ack_filter.enabled = value;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer,
25462306a36Sopenharmony_ci				     u32 buffer_size)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct txq_entry_t *tqe;
25762306a36Sopenharmony_ci	struct wilc *wilc = vif->wilc;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	netdev_dbg(vif->ndev, "Adding config packet ...\n");
26062306a36Sopenharmony_ci	if (wilc->quit) {
26162306a36Sopenharmony_ci		netdev_dbg(vif->ndev, "Return due to clear function\n");
26262306a36Sopenharmony_ci		complete(&wilc->cfg_event);
26362306a36Sopenharmony_ci		return 0;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
26762306a36Sopenharmony_ci	if (!tqe) {
26862306a36Sopenharmony_ci		complete(&wilc->cfg_event);
26962306a36Sopenharmony_ci		return 0;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	tqe->type = WILC_CFG_PKT;
27362306a36Sopenharmony_ci	tqe->buffer = buffer;
27462306a36Sopenharmony_ci	tqe->buffer_size = buffer_size;
27562306a36Sopenharmony_ci	tqe->tx_complete_func = NULL;
27662306a36Sopenharmony_ci	tqe->priv = NULL;
27762306a36Sopenharmony_ci	tqe->q_num = AC_VO_Q;
27862306a36Sopenharmony_ci	tqe->ack_idx = NOT_TCP_ACK;
27962306a36Sopenharmony_ci	tqe->vif = vif;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	wilc_wlan_txq_add_to_head(vif, AC_VO_Q, tqe);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return 1;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic bool is_ac_q_limit(struct wilc *wl, u8 q_num)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	u8 factors[NQUEUES] = {1, 1, 1, 1};
28962306a36Sopenharmony_ci	u16 i;
29062306a36Sopenharmony_ci	unsigned long flags;
29162306a36Sopenharmony_ci	struct wilc_tx_queue_status *q = &wl->tx_q_limit;
29262306a36Sopenharmony_ci	u8 end_index;
29362306a36Sopenharmony_ci	u8 q_limit;
29462306a36Sopenharmony_ci	bool ret = false;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	spin_lock_irqsave(&wl->txq_spinlock, flags);
29762306a36Sopenharmony_ci	if (!q->initialized) {
29862306a36Sopenharmony_ci		for (i = 0; i < AC_BUFFER_SIZE; i++)
29962306a36Sopenharmony_ci			q->buffer[i] = i % NQUEUES;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		for (i = 0; i < NQUEUES; i++) {
30262306a36Sopenharmony_ci			q->cnt[i] = AC_BUFFER_SIZE * factors[i] / NQUEUES;
30362306a36Sopenharmony_ci			q->sum += q->cnt[i];
30462306a36Sopenharmony_ci		}
30562306a36Sopenharmony_ci		q->end_index = AC_BUFFER_SIZE - 1;
30662306a36Sopenharmony_ci		q->initialized = 1;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	end_index = q->end_index;
31062306a36Sopenharmony_ci	q->cnt[q->buffer[end_index]] -= factors[q->buffer[end_index]];
31162306a36Sopenharmony_ci	q->cnt[q_num] += factors[q_num];
31262306a36Sopenharmony_ci	q->sum += (factors[q_num] - factors[q->buffer[end_index]]);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	q->buffer[end_index] = q_num;
31562306a36Sopenharmony_ci	if (end_index > 0)
31662306a36Sopenharmony_ci		q->end_index--;
31762306a36Sopenharmony_ci	else
31862306a36Sopenharmony_ci		q->end_index = AC_BUFFER_SIZE - 1;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (!q->sum)
32162306a36Sopenharmony_ci		q_limit = 1;
32262306a36Sopenharmony_ci	else
32362306a36Sopenharmony_ci		q_limit = (q->cnt[q_num] * FLOW_CONTROL_UPPER_THRESHOLD / q->sum) + 1;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (wl->txq[q_num].count <= q_limit)
32662306a36Sopenharmony_ci		ret = true;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	spin_unlock_irqrestore(&wl->txq_spinlock, flags);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return ret;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic inline u8 ac_classify(struct wilc *wilc, struct sk_buff *skb)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	u8 q_num = AC_BE_Q;
33662306a36Sopenharmony_ci	u8 dscp;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	switch (skb->protocol) {
33962306a36Sopenharmony_ci	case htons(ETH_P_IP):
34062306a36Sopenharmony_ci		dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc;
34162306a36Sopenharmony_ci		break;
34262306a36Sopenharmony_ci	case htons(ETH_P_IPV6):
34362306a36Sopenharmony_ci		dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc;
34462306a36Sopenharmony_ci		break;
34562306a36Sopenharmony_ci	default:
34662306a36Sopenharmony_ci		return q_num;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	switch (dscp) {
35062306a36Sopenharmony_ci	case 0x08:
35162306a36Sopenharmony_ci	case 0x20:
35262306a36Sopenharmony_ci	case 0x40:
35362306a36Sopenharmony_ci		q_num = AC_BK_Q;
35462306a36Sopenharmony_ci		break;
35562306a36Sopenharmony_ci	case 0x80:
35662306a36Sopenharmony_ci	case 0xA0:
35762306a36Sopenharmony_ci	case 0x28:
35862306a36Sopenharmony_ci		q_num = AC_VI_Q;
35962306a36Sopenharmony_ci		break;
36062306a36Sopenharmony_ci	case 0xC0:
36162306a36Sopenharmony_ci	case 0xD0:
36262306a36Sopenharmony_ci	case 0xE0:
36362306a36Sopenharmony_ci	case 0x88:
36462306a36Sopenharmony_ci	case 0xB8:
36562306a36Sopenharmony_ci		q_num = AC_VO_Q;
36662306a36Sopenharmony_ci		break;
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	return q_num;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic inline int ac_balance(struct wilc *wl, u8 *ratio)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	u8 i, max_count = 0;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (!ratio)
37762306a36Sopenharmony_ci		return -EINVAL;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	for (i = 0; i < NQUEUES; i++)
38062306a36Sopenharmony_ci		if (wl->txq[i].fw.count > max_count)
38162306a36Sopenharmony_ci			max_count = wl->txq[i].fw.count;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	for (i = 0; i < NQUEUES; i++)
38462306a36Sopenharmony_ci		ratio[i] = max_count - wl->txq[i].fw.count;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	return 0;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic inline void ac_update_fw_ac_pkt_info(struct wilc *wl, u32 reg)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	wl->txq[AC_BK_Q].fw.count = FIELD_GET(BK_AC_COUNT_FIELD, reg);
39262306a36Sopenharmony_ci	wl->txq[AC_BE_Q].fw.count = FIELD_GET(BE_AC_COUNT_FIELD, reg);
39362306a36Sopenharmony_ci	wl->txq[AC_VI_Q].fw.count = FIELD_GET(VI_AC_COUNT_FIELD, reg);
39462306a36Sopenharmony_ci	wl->txq[AC_VO_Q].fw.count = FIELD_GET(VO_AC_COUNT_FIELD, reg);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	wl->txq[AC_BK_Q].fw.acm = FIELD_GET(BK_AC_ACM_STAT_FIELD, reg);
39762306a36Sopenharmony_ci	wl->txq[AC_BE_Q].fw.acm = FIELD_GET(BE_AC_ACM_STAT_FIELD, reg);
39862306a36Sopenharmony_ci	wl->txq[AC_VI_Q].fw.acm = FIELD_GET(VI_AC_ACM_STAT_FIELD, reg);
39962306a36Sopenharmony_ci	wl->txq[AC_VO_Q].fw.acm = FIELD_GET(VO_AC_ACM_STAT_FIELD, reg);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic inline u8 ac_change(struct wilc *wilc, u8 *ac)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	do {
40562306a36Sopenharmony_ci		if (wilc->txq[*ac].fw.acm == 0)
40662306a36Sopenharmony_ci			return 0;
40762306a36Sopenharmony_ci		(*ac)++;
40862306a36Sopenharmony_ci	} while (*ac < NQUEUES);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	return 1;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ciint wilc_wlan_txq_add_net_pkt(struct net_device *dev,
41462306a36Sopenharmony_ci			      struct tx_complete_data *tx_data, u8 *buffer,
41562306a36Sopenharmony_ci			      u32 buffer_size,
41662306a36Sopenharmony_ci			      void (*tx_complete_fn)(void *, int))
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	struct txq_entry_t *tqe;
41962306a36Sopenharmony_ci	struct wilc_vif *vif = netdev_priv(dev);
42062306a36Sopenharmony_ci	struct wilc *wilc;
42162306a36Sopenharmony_ci	u8 q_num;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	wilc = vif->wilc;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	if (wilc->quit) {
42662306a36Sopenharmony_ci		tx_complete_fn(tx_data, 0);
42762306a36Sopenharmony_ci		return 0;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if (!wilc->initialized) {
43162306a36Sopenharmony_ci		tx_complete_fn(tx_data, 0);
43262306a36Sopenharmony_ci		return 0;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	if (!tqe) {
43862306a36Sopenharmony_ci		tx_complete_fn(tx_data, 0);
43962306a36Sopenharmony_ci		return 0;
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci	tqe->type = WILC_NET_PKT;
44262306a36Sopenharmony_ci	tqe->buffer = buffer;
44362306a36Sopenharmony_ci	tqe->buffer_size = buffer_size;
44462306a36Sopenharmony_ci	tqe->tx_complete_func = tx_complete_fn;
44562306a36Sopenharmony_ci	tqe->priv = tx_data;
44662306a36Sopenharmony_ci	tqe->vif = vif;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	q_num = ac_classify(wilc, tx_data->skb);
44962306a36Sopenharmony_ci	tqe->q_num = q_num;
45062306a36Sopenharmony_ci	if (ac_change(wilc, &q_num)) {
45162306a36Sopenharmony_ci		tx_complete_fn(tx_data, 0);
45262306a36Sopenharmony_ci		kfree(tqe);
45362306a36Sopenharmony_ci		return 0;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (is_ac_q_limit(wilc, q_num)) {
45762306a36Sopenharmony_ci		tqe->ack_idx = NOT_TCP_ACK;
45862306a36Sopenharmony_ci		if (vif->ack_filter.enabled)
45962306a36Sopenharmony_ci			tcp_process(dev, tqe);
46062306a36Sopenharmony_ci		wilc_wlan_txq_add_to_tail(dev, q_num, tqe);
46162306a36Sopenharmony_ci	} else {
46262306a36Sopenharmony_ci		tx_complete_fn(tx_data, 0);
46362306a36Sopenharmony_ci		kfree(tqe);
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return wilc->txq_entries;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ciint wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
47062306a36Sopenharmony_ci			       u32 buffer_size,
47162306a36Sopenharmony_ci			       void (*tx_complete_fn)(void *, int))
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	struct txq_entry_t *tqe;
47462306a36Sopenharmony_ci	struct wilc_vif *vif = netdev_priv(dev);
47562306a36Sopenharmony_ci	struct wilc *wilc;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	wilc = vif->wilc;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (wilc->quit) {
48062306a36Sopenharmony_ci		tx_complete_fn(priv, 0);
48162306a36Sopenharmony_ci		return 0;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (!wilc->initialized) {
48562306a36Sopenharmony_ci		tx_complete_fn(priv, 0);
48662306a36Sopenharmony_ci		return 0;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci	tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (!tqe) {
49162306a36Sopenharmony_ci		tx_complete_fn(priv, 0);
49262306a36Sopenharmony_ci		return 0;
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci	tqe->type = WILC_MGMT_PKT;
49562306a36Sopenharmony_ci	tqe->buffer = buffer;
49662306a36Sopenharmony_ci	tqe->buffer_size = buffer_size;
49762306a36Sopenharmony_ci	tqe->tx_complete_func = tx_complete_fn;
49862306a36Sopenharmony_ci	tqe->priv = priv;
49962306a36Sopenharmony_ci	tqe->q_num = AC_BE_Q;
50062306a36Sopenharmony_ci	tqe->ack_idx = NOT_TCP_ACK;
50162306a36Sopenharmony_ci	tqe->vif = vif;
50262306a36Sopenharmony_ci	wilc_wlan_txq_add_to_tail(dev, AC_VO_Q, tqe);
50362306a36Sopenharmony_ci	return 1;
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc, u8 q_num)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct txq_entry_t *tqe = NULL;
50962306a36Sopenharmony_ci	unsigned long flags;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	spin_lock_irqsave(&wilc->txq_spinlock, flags);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (!list_empty(&wilc->txq[q_num].txq_head.list))
51462306a36Sopenharmony_ci		tqe = list_first_entry(&wilc->txq[q_num].txq_head.list,
51562306a36Sopenharmony_ci				       struct txq_entry_t, list);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return tqe;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,
52362306a36Sopenharmony_ci						  struct txq_entry_t *tqe,
52462306a36Sopenharmony_ci						  u8 q_num)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	unsigned long flags;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	spin_lock_irqsave(&wilc->txq_spinlock, flags);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (!list_is_last(&tqe->list, &wilc->txq[q_num].txq_head.list))
53162306a36Sopenharmony_ci		tqe = list_next_entry(tqe, list);
53262306a36Sopenharmony_ci	else
53362306a36Sopenharmony_ci		tqe = NULL;
53462306a36Sopenharmony_ci	spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	return tqe;
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic void wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	if (wilc->quit)
54262306a36Sopenharmony_ci		return;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	mutex_lock(&wilc->rxq_cs);
54562306a36Sopenharmony_ci	list_add_tail(&rqe->list, &wilc->rxq_head.list);
54662306a36Sopenharmony_ci	mutex_unlock(&wilc->rxq_cs);
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	struct rxq_entry_t *rqe = NULL;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	mutex_lock(&wilc->rxq_cs);
55462306a36Sopenharmony_ci	if (!list_empty(&wilc->rxq_head.list)) {
55562306a36Sopenharmony_ci		rqe = list_first_entry(&wilc->rxq_head.list, struct rxq_entry_t,
55662306a36Sopenharmony_ci				       list);
55762306a36Sopenharmony_ci		list_del(&rqe->list);
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci	mutex_unlock(&wilc->rxq_cs);
56062306a36Sopenharmony_ci	return rqe;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_civoid chip_allow_sleep(struct wilc *wilc)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	u32 reg = 0;
56662306a36Sopenharmony_ci	const struct wilc_hif_func *hif_func = wilc->hif_func;
56762306a36Sopenharmony_ci	u32 wakeup_reg, wakeup_bit;
56862306a36Sopenharmony_ci	u32 to_host_from_fw_reg, to_host_from_fw_bit;
56962306a36Sopenharmony_ci	u32 from_host_to_fw_reg, from_host_to_fw_bit;
57062306a36Sopenharmony_ci	u32 trials = 100;
57162306a36Sopenharmony_ci	int ret;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (wilc->io_type == WILC_HIF_SDIO) {
57462306a36Sopenharmony_ci		wakeup_reg = WILC_SDIO_WAKEUP_REG;
57562306a36Sopenharmony_ci		wakeup_bit = WILC_SDIO_WAKEUP_BIT;
57662306a36Sopenharmony_ci		from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG;
57762306a36Sopenharmony_ci		from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT;
57862306a36Sopenharmony_ci		to_host_from_fw_reg = WILC_SDIO_FW_TO_HOST_REG;
57962306a36Sopenharmony_ci		to_host_from_fw_bit = WILC_SDIO_FW_TO_HOST_BIT;
58062306a36Sopenharmony_ci	} else {
58162306a36Sopenharmony_ci		wakeup_reg = WILC_SPI_WAKEUP_REG;
58262306a36Sopenharmony_ci		wakeup_bit = WILC_SPI_WAKEUP_BIT;
58362306a36Sopenharmony_ci		from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG;
58462306a36Sopenharmony_ci		from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT;
58562306a36Sopenharmony_ci		to_host_from_fw_reg = WILC_SPI_FW_TO_HOST_REG;
58662306a36Sopenharmony_ci		to_host_from_fw_bit = WILC_SPI_FW_TO_HOST_BIT;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	while (--trials) {
59062306a36Sopenharmony_ci		ret = hif_func->hif_read_reg(wilc, to_host_from_fw_reg, &reg);
59162306a36Sopenharmony_ci		if (ret)
59262306a36Sopenharmony_ci			return;
59362306a36Sopenharmony_ci		if ((reg & to_host_from_fw_bit) == 0)
59462306a36Sopenharmony_ci			break;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci	if (!trials)
59762306a36Sopenharmony_ci		pr_warn("FW not responding\n");
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* Clear bit 1 */
60062306a36Sopenharmony_ci	ret = hif_func->hif_read_reg(wilc, wakeup_reg, &reg);
60162306a36Sopenharmony_ci	if (ret)
60262306a36Sopenharmony_ci		return;
60362306a36Sopenharmony_ci	if (reg & wakeup_bit) {
60462306a36Sopenharmony_ci		reg &= ~wakeup_bit;
60562306a36Sopenharmony_ci		ret = hif_func->hif_write_reg(wilc, wakeup_reg, reg);
60662306a36Sopenharmony_ci		if (ret)
60762306a36Sopenharmony_ci			return;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	ret = hif_func->hif_read_reg(wilc, from_host_to_fw_reg, &reg);
61162306a36Sopenharmony_ci	if (ret)
61262306a36Sopenharmony_ci		return;
61362306a36Sopenharmony_ci	if (reg & from_host_to_fw_bit) {
61462306a36Sopenharmony_ci		reg &= ~from_host_to_fw_bit;
61562306a36Sopenharmony_ci		ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, reg);
61662306a36Sopenharmony_ci		if (ret)
61762306a36Sopenharmony_ci			return;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(chip_allow_sleep);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_civoid chip_wakeup(struct wilc *wilc)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	u32 ret = 0;
62662306a36Sopenharmony_ci	u32 clk_status_val = 0, trials = 0;
62762306a36Sopenharmony_ci	u32 wakeup_reg, wakeup_bit;
62862306a36Sopenharmony_ci	u32 clk_status_reg, clk_status_bit;
62962306a36Sopenharmony_ci	u32 from_host_to_fw_reg, from_host_to_fw_bit;
63062306a36Sopenharmony_ci	const struct wilc_hif_func *hif_func = wilc->hif_func;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (wilc->io_type == WILC_HIF_SDIO) {
63362306a36Sopenharmony_ci		wakeup_reg = WILC_SDIO_WAKEUP_REG;
63462306a36Sopenharmony_ci		wakeup_bit = WILC_SDIO_WAKEUP_BIT;
63562306a36Sopenharmony_ci		clk_status_reg = WILC_SDIO_CLK_STATUS_REG;
63662306a36Sopenharmony_ci		clk_status_bit = WILC_SDIO_CLK_STATUS_BIT;
63762306a36Sopenharmony_ci		from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG;
63862306a36Sopenharmony_ci		from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT;
63962306a36Sopenharmony_ci	} else {
64062306a36Sopenharmony_ci		wakeup_reg = WILC_SPI_WAKEUP_REG;
64162306a36Sopenharmony_ci		wakeup_bit = WILC_SPI_WAKEUP_BIT;
64262306a36Sopenharmony_ci		clk_status_reg = WILC_SPI_CLK_STATUS_REG;
64362306a36Sopenharmony_ci		clk_status_bit = WILC_SPI_CLK_STATUS_BIT;
64462306a36Sopenharmony_ci		from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG;
64562306a36Sopenharmony_ci		from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT;
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/* indicate host wakeup */
64962306a36Sopenharmony_ci	ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg,
65062306a36Sopenharmony_ci				      from_host_to_fw_bit);
65162306a36Sopenharmony_ci	if (ret)
65262306a36Sopenharmony_ci		return;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	/* Set wake-up bit */
65562306a36Sopenharmony_ci	ret = hif_func->hif_write_reg(wilc, wakeup_reg,
65662306a36Sopenharmony_ci				      wakeup_bit);
65762306a36Sopenharmony_ci	if (ret)
65862306a36Sopenharmony_ci		return;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	while (trials < WAKE_UP_TRIAL_RETRY) {
66162306a36Sopenharmony_ci		ret = hif_func->hif_read_reg(wilc, clk_status_reg,
66262306a36Sopenharmony_ci					     &clk_status_val);
66362306a36Sopenharmony_ci		if (ret) {
66462306a36Sopenharmony_ci			pr_err("Bus error %d %x\n", ret, clk_status_val);
66562306a36Sopenharmony_ci			return;
66662306a36Sopenharmony_ci		}
66762306a36Sopenharmony_ci		if (clk_status_val & clk_status_bit)
66862306a36Sopenharmony_ci			break;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		trials++;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci	if (trials >= WAKE_UP_TRIAL_RETRY) {
67362306a36Sopenharmony_ci		pr_err("Failed to wake-up the chip\n");
67462306a36Sopenharmony_ci		return;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci	/* Sometimes spi fail to read clock regs after reading
67762306a36Sopenharmony_ci	 * writing clockless registers
67862306a36Sopenharmony_ci	 */
67962306a36Sopenharmony_ci	if (wilc->io_type == WILC_HIF_SPI)
68062306a36Sopenharmony_ci		wilc->hif_func->hif_reset(wilc);
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(chip_wakeup);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_civoid host_wakeup_notify(struct wilc *wilc)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
68762306a36Sopenharmony_ci	wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_2, 1);
68862306a36Sopenharmony_ci	release_bus(wilc, WILC_BUS_RELEASE_ONLY);
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(host_wakeup_notify);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_civoid host_sleep_notify(struct wilc *wilc)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
69562306a36Sopenharmony_ci	wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_1, 1);
69662306a36Sopenharmony_ci	release_bus(wilc, WILC_BUS_RELEASE_ONLY);
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(host_sleep_notify);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ciint wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	int i, entries = 0;
70362306a36Sopenharmony_ci	u8 k, ac;
70462306a36Sopenharmony_ci	u32 sum;
70562306a36Sopenharmony_ci	u32 reg;
70662306a36Sopenharmony_ci	u8 ac_desired_ratio[NQUEUES] = {0, 0, 0, 0};
70762306a36Sopenharmony_ci	u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1};
70862306a36Sopenharmony_ci	u8 *num_pkts_to_add;
70962306a36Sopenharmony_ci	u8 vmm_entries_ac[WILC_VMM_TBL_SIZE];
71062306a36Sopenharmony_ci	u32 offset = 0;
71162306a36Sopenharmony_ci	bool max_size_over = 0, ac_exist = 0;
71262306a36Sopenharmony_ci	int vmm_sz = 0;
71362306a36Sopenharmony_ci	struct txq_entry_t *tqe_q[NQUEUES];
71462306a36Sopenharmony_ci	int ret = 0;
71562306a36Sopenharmony_ci	int counter;
71662306a36Sopenharmony_ci	int timeout;
71762306a36Sopenharmony_ci	u32 *vmm_table = wilc->vmm_table;
71862306a36Sopenharmony_ci	u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0};
71962306a36Sopenharmony_ci	const struct wilc_hif_func *func;
72062306a36Sopenharmony_ci	int srcu_idx;
72162306a36Sopenharmony_ci	u8 *txb = wilc->tx_buffer;
72262306a36Sopenharmony_ci	struct wilc_vif *vif;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	if (wilc->quit)
72562306a36Sopenharmony_ci		goto out_update_cnt;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	if (ac_balance(wilc, ac_desired_ratio))
72862306a36Sopenharmony_ci		return -EINVAL;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	mutex_lock(&wilc->txq_add_to_head_cs);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	srcu_idx = srcu_read_lock(&wilc->srcu);
73362306a36Sopenharmony_ci	list_for_each_entry_rcu(vif, &wilc->vif_list, list)
73462306a36Sopenharmony_ci		wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev);
73562306a36Sopenharmony_ci	srcu_read_unlock(&wilc->srcu, srcu_idx);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	for (ac = 0; ac < NQUEUES; ac++)
73862306a36Sopenharmony_ci		tqe_q[ac] = wilc_wlan_txq_get_first(wilc, ac);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	i = 0;
74162306a36Sopenharmony_ci	sum = 0;
74262306a36Sopenharmony_ci	max_size_over = 0;
74362306a36Sopenharmony_ci	num_pkts_to_add = ac_desired_ratio;
74462306a36Sopenharmony_ci	do {
74562306a36Sopenharmony_ci		ac_exist = 0;
74662306a36Sopenharmony_ci		for (ac = 0; (ac < NQUEUES) && (!max_size_over); ac++) {
74762306a36Sopenharmony_ci			if (!tqe_q[ac])
74862306a36Sopenharmony_ci				continue;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci			ac_exist = 1;
75162306a36Sopenharmony_ci			for (k = 0; (k < num_pkts_to_add[ac]) &&
75262306a36Sopenharmony_ci			     (!max_size_over) && tqe_q[ac]; k++) {
75362306a36Sopenharmony_ci				if (i >= (WILC_VMM_TBL_SIZE - 1)) {
75462306a36Sopenharmony_ci					max_size_over = 1;
75562306a36Sopenharmony_ci					break;
75662306a36Sopenharmony_ci				}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci				if (tqe_q[ac]->type == WILC_CFG_PKT)
75962306a36Sopenharmony_ci					vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
76062306a36Sopenharmony_ci				else if (tqe_q[ac]->type == WILC_NET_PKT)
76162306a36Sopenharmony_ci					vmm_sz = ETH_ETHERNET_HDR_OFFSET;
76262306a36Sopenharmony_ci				else
76362306a36Sopenharmony_ci					vmm_sz = HOST_HDR_OFFSET;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci				vmm_sz += tqe_q[ac]->buffer_size;
76662306a36Sopenharmony_ci				vmm_sz = ALIGN(vmm_sz, 4);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci				if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE) {
76962306a36Sopenharmony_ci					max_size_over = 1;
77062306a36Sopenharmony_ci					break;
77162306a36Sopenharmony_ci				}
77262306a36Sopenharmony_ci				vmm_table[i] = vmm_sz / 4;
77362306a36Sopenharmony_ci				if (tqe_q[ac]->type == WILC_CFG_PKT)
77462306a36Sopenharmony_ci					vmm_table[i] |= BIT(10);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci				cpu_to_le32s(&vmm_table[i]);
77762306a36Sopenharmony_ci				vmm_entries_ac[i] = ac;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci				i++;
78062306a36Sopenharmony_ci				sum += vmm_sz;
78162306a36Sopenharmony_ci				tqe_q[ac] = wilc_wlan_txq_get_next(wilc,
78262306a36Sopenharmony_ci								   tqe_q[ac],
78362306a36Sopenharmony_ci								   ac);
78462306a36Sopenharmony_ci			}
78562306a36Sopenharmony_ci		}
78662306a36Sopenharmony_ci		num_pkts_to_add = ac_preserve_ratio;
78762306a36Sopenharmony_ci	} while (!max_size_over && ac_exist);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	if (i == 0)
79062306a36Sopenharmony_ci		goto out_unlock;
79162306a36Sopenharmony_ci	vmm_table[i] = 0x0;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
79462306a36Sopenharmony_ci	counter = 0;
79562306a36Sopenharmony_ci	func = wilc->hif_func;
79662306a36Sopenharmony_ci	do {
79762306a36Sopenharmony_ci		ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
79862306a36Sopenharmony_ci		if (ret)
79962306a36Sopenharmony_ci			break;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		if ((reg & 0x1) == 0) {
80262306a36Sopenharmony_ci			ac_update_fw_ac_pkt_info(wilc, reg);
80362306a36Sopenharmony_ci			break;
80462306a36Sopenharmony_ci		}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci		counter++;
80762306a36Sopenharmony_ci		if (counter > 200) {
80862306a36Sopenharmony_ci			counter = 0;
80962306a36Sopenharmony_ci			ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0);
81062306a36Sopenharmony_ci			break;
81162306a36Sopenharmony_ci		}
81262306a36Sopenharmony_ci	} while (!wilc->quit);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (ret)
81562306a36Sopenharmony_ci		goto out_release_bus;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	timeout = 200;
81862306a36Sopenharmony_ci	do {
81962306a36Sopenharmony_ci		ret = func->hif_block_tx(wilc,
82062306a36Sopenharmony_ci					 WILC_VMM_TBL_RX_SHADOW_BASE,
82162306a36Sopenharmony_ci					 (u8 *)vmm_table,
82262306a36Sopenharmony_ci					 ((i + 1) * 4));
82362306a36Sopenharmony_ci		if (ret)
82462306a36Sopenharmony_ci			break;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2);
82762306a36Sopenharmony_ci		if (ret)
82862306a36Sopenharmony_ci			break;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		do {
83162306a36Sopenharmony_ci			ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
83262306a36Sopenharmony_ci			if (ret)
83362306a36Sopenharmony_ci				break;
83462306a36Sopenharmony_ci			if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) {
83562306a36Sopenharmony_ci				entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg);
83662306a36Sopenharmony_ci				break;
83762306a36Sopenharmony_ci			}
83862306a36Sopenharmony_ci		} while (--timeout);
83962306a36Sopenharmony_ci		if (timeout <= 0) {
84062306a36Sopenharmony_ci			ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
84162306a36Sopenharmony_ci			break;
84262306a36Sopenharmony_ci		}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci		if (ret)
84562306a36Sopenharmony_ci			break;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci		if (entries == 0) {
84862306a36Sopenharmony_ci			ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
84962306a36Sopenharmony_ci			if (ret)
85062306a36Sopenharmony_ci				break;
85162306a36Sopenharmony_ci			reg &= ~BIT(0);
85262306a36Sopenharmony_ci			ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);
85362306a36Sopenharmony_ci		}
85462306a36Sopenharmony_ci	} while (0);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	if (ret)
85762306a36Sopenharmony_ci		goto out_release_bus;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	if (entries == 0) {
86062306a36Sopenharmony_ci		/*
86162306a36Sopenharmony_ci		 * No VMM space available in firmware so retry to transmit
86262306a36Sopenharmony_ci		 * the packet from tx queue.
86362306a36Sopenharmony_ci		 */
86462306a36Sopenharmony_ci		ret = WILC_VMM_ENTRY_FULL_RETRY;
86562306a36Sopenharmony_ci		goto out_release_bus;
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	offset = 0;
87162306a36Sopenharmony_ci	i = 0;
87262306a36Sopenharmony_ci	do {
87362306a36Sopenharmony_ci		struct txq_entry_t *tqe;
87462306a36Sopenharmony_ci		u32 header, buffer_offset;
87562306a36Sopenharmony_ci		char *bssid;
87662306a36Sopenharmony_ci		u8 mgmt_ptk = 0;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci		if (vmm_table[i] == 0 || vmm_entries_ac[i] >= NQUEUES)
87962306a36Sopenharmony_ci			break;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci		tqe = wilc_wlan_txq_remove_from_head(wilc, vmm_entries_ac[i]);
88262306a36Sopenharmony_ci		if (!tqe)
88362306a36Sopenharmony_ci			break;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci		ac_pkt_num_to_chip[vmm_entries_ac[i]]++;
88662306a36Sopenharmony_ci		vif = tqe->vif;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci		le32_to_cpus(&vmm_table[i]);
88962306a36Sopenharmony_ci		vmm_sz = FIELD_GET(WILC_VMM_BUFFER_SIZE, vmm_table[i]);
89062306a36Sopenharmony_ci		vmm_sz *= 4;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci		if (tqe->type == WILC_MGMT_PKT)
89362306a36Sopenharmony_ci			mgmt_ptk = 1;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		header = (FIELD_PREP(WILC_VMM_HDR_TYPE, tqe->type) |
89662306a36Sopenharmony_ci			  FIELD_PREP(WILC_VMM_HDR_MGMT_FIELD, mgmt_ptk) |
89762306a36Sopenharmony_ci			  FIELD_PREP(WILC_VMM_HDR_PKT_SIZE, tqe->buffer_size) |
89862306a36Sopenharmony_ci			  FIELD_PREP(WILC_VMM_HDR_BUFF_SIZE, vmm_sz));
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci		cpu_to_le32s(&header);
90162306a36Sopenharmony_ci		memcpy(&txb[offset], &header, 4);
90262306a36Sopenharmony_ci		if (tqe->type == WILC_CFG_PKT) {
90362306a36Sopenharmony_ci			buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
90462306a36Sopenharmony_ci		} else if (tqe->type == WILC_NET_PKT) {
90562306a36Sopenharmony_ci			int prio = tqe->q_num;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci			bssid = tqe->vif->bssid;
90862306a36Sopenharmony_ci			buffer_offset = ETH_ETHERNET_HDR_OFFSET;
90962306a36Sopenharmony_ci			memcpy(&txb[offset + 4], &prio, sizeof(prio));
91062306a36Sopenharmony_ci			memcpy(&txb[offset + 8], bssid, 6);
91162306a36Sopenharmony_ci		} else {
91262306a36Sopenharmony_ci			buffer_offset = HOST_HDR_OFFSET;
91362306a36Sopenharmony_ci		}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci		memcpy(&txb[offset + buffer_offset],
91662306a36Sopenharmony_ci		       tqe->buffer, tqe->buffer_size);
91762306a36Sopenharmony_ci		offset += vmm_sz;
91862306a36Sopenharmony_ci		i++;
91962306a36Sopenharmony_ci		tqe->status = 1;
92062306a36Sopenharmony_ci		if (tqe->tx_complete_func)
92162306a36Sopenharmony_ci			tqe->tx_complete_func(tqe->priv, tqe->status);
92262306a36Sopenharmony_ci		if (tqe->ack_idx != NOT_TCP_ACK &&
92362306a36Sopenharmony_ci		    tqe->ack_idx < MAX_PENDING_ACKS)
92462306a36Sopenharmony_ci			vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL;
92562306a36Sopenharmony_ci		kfree(tqe);
92662306a36Sopenharmony_ci	} while (--entries);
92762306a36Sopenharmony_ci	for (i = 0; i < NQUEUES; i++)
92862306a36Sopenharmony_ci		wilc->txq[i].fw.count += ac_pkt_num_to_chip[i];
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
93362306a36Sopenharmony_ci	if (ret)
93462306a36Sopenharmony_ci		goto out_release_bus;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	ret = func->hif_block_tx_ext(wilc, 0, txb, offset);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ciout_release_bus:
93962306a36Sopenharmony_ci	release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ciout_unlock:
94262306a36Sopenharmony_ci	mutex_unlock(&wilc->txq_add_to_head_cs);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ciout_update_cnt:
94562306a36Sopenharmony_ci	*txq_count = wilc->txq_entries;
94662306a36Sopenharmony_ci	return ret;
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
95062306a36Sopenharmony_ci{
95162306a36Sopenharmony_ci	int offset = 0;
95262306a36Sopenharmony_ci	u32 header;
95362306a36Sopenharmony_ci	u32 pkt_len, pkt_offset, tp_len;
95462306a36Sopenharmony_ci	int is_cfg_packet;
95562306a36Sopenharmony_ci	u8 *buff_ptr;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	do {
95862306a36Sopenharmony_ci		buff_ptr = buffer + offset;
95962306a36Sopenharmony_ci		header = get_unaligned_le32(buff_ptr);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci		is_cfg_packet = FIELD_GET(WILC_PKT_HDR_CONFIG_FIELD, header);
96262306a36Sopenharmony_ci		pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header);
96362306a36Sopenharmony_ci		tp_len = FIELD_GET(WILC_PKT_HDR_TOTAL_LEN_FIELD, header);
96462306a36Sopenharmony_ci		pkt_len = FIELD_GET(WILC_PKT_HDR_LEN_FIELD, header);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci		if (pkt_len == 0 || tp_len == 0)
96762306a36Sopenharmony_ci			break;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		if (pkt_offset & IS_MANAGMEMENT) {
97062306a36Sopenharmony_ci			buff_ptr += HOST_HDR_OFFSET;
97162306a36Sopenharmony_ci			wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len,
97262306a36Sopenharmony_ci					 pkt_offset & IS_MGMT_AUTH_PKT);
97362306a36Sopenharmony_ci		} else {
97462306a36Sopenharmony_ci			if (!is_cfg_packet) {
97562306a36Sopenharmony_ci				wilc_frmw_to_host(wilc, buff_ptr, pkt_len,
97662306a36Sopenharmony_ci						  pkt_offset);
97762306a36Sopenharmony_ci			} else {
97862306a36Sopenharmony_ci				struct wilc_cfg_rsp rsp;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci				buff_ptr += pkt_offset;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci				wilc_wlan_cfg_indicate_rx(wilc, buff_ptr,
98362306a36Sopenharmony_ci							  pkt_len,
98462306a36Sopenharmony_ci							  &rsp);
98562306a36Sopenharmony_ci				if (rsp.type == WILC_CFG_RSP) {
98662306a36Sopenharmony_ci					if (wilc->cfg_seq_no == rsp.seq_no)
98762306a36Sopenharmony_ci						complete(&wilc->cfg_event);
98862306a36Sopenharmony_ci				} else if (rsp.type == WILC_CFG_RSP_STATUS) {
98962306a36Sopenharmony_ci					wilc_mac_indicate(wilc);
99062306a36Sopenharmony_ci				}
99162306a36Sopenharmony_ci			}
99262306a36Sopenharmony_ci		}
99362306a36Sopenharmony_ci		offset += tp_len;
99462306a36Sopenharmony_ci	} while (offset < size);
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic void wilc_wlan_handle_rxq(struct wilc *wilc)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	int size;
100062306a36Sopenharmony_ci	u8 *buffer;
100162306a36Sopenharmony_ci	struct rxq_entry_t *rqe;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	while (!wilc->quit) {
100462306a36Sopenharmony_ci		rqe = wilc_wlan_rxq_remove(wilc);
100562306a36Sopenharmony_ci		if (!rqe)
100662306a36Sopenharmony_ci			break;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci		buffer = rqe->buffer;
100962306a36Sopenharmony_ci		size = rqe->buffer_size;
101062306a36Sopenharmony_ci		wilc_wlan_handle_rx_buff(wilc, buffer, size);
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci		kfree(rqe);
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci	if (wilc->quit)
101562306a36Sopenharmony_ci		complete(&wilc->cfg_event);
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cistatic void wilc_unknown_isr_ext(struct wilc *wilc)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci	wilc->hif_func->hif_clear_int_ext(wilc, 0);
102162306a36Sopenharmony_ci}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_cistatic void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci	u32 offset = wilc->rx_buffer_offset;
102662306a36Sopenharmony_ci	u8 *buffer = NULL;
102762306a36Sopenharmony_ci	u32 size;
102862306a36Sopenharmony_ci	u32 retries = 0;
102962306a36Sopenharmony_ci	int ret = 0;
103062306a36Sopenharmony_ci	struct rxq_entry_t *rqe;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	size = FIELD_GET(WILC_INTERRUPT_DATA_SIZE, int_status) << 2;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	while (!size && retries < 10) {
103562306a36Sopenharmony_ci		wilc->hif_func->hif_read_size(wilc, &size);
103662306a36Sopenharmony_ci		size = FIELD_GET(WILC_INTERRUPT_DATA_SIZE, size) << 2;
103762306a36Sopenharmony_ci		retries++;
103862306a36Sopenharmony_ci	}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if (size <= 0)
104162306a36Sopenharmony_ci		return;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (WILC_RX_BUFF_SIZE - offset < size)
104462306a36Sopenharmony_ci		offset = 0;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	buffer = &wilc->rx_buffer[offset];
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	wilc->hif_func->hif_clear_int_ext(wilc, DATA_INT_CLR | ENABLE_RX_VMM);
104962306a36Sopenharmony_ci	ret = wilc->hif_func->hif_block_rx_ext(wilc, 0, buffer, size);
105062306a36Sopenharmony_ci	if (ret)
105162306a36Sopenharmony_ci		return;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	offset += size;
105462306a36Sopenharmony_ci	wilc->rx_buffer_offset = offset;
105562306a36Sopenharmony_ci	rqe = kmalloc(sizeof(*rqe), GFP_KERNEL);
105662306a36Sopenharmony_ci	if (!rqe)
105762306a36Sopenharmony_ci		return;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	rqe->buffer = buffer;
106062306a36Sopenharmony_ci	rqe->buffer_size = size;
106162306a36Sopenharmony_ci	wilc_wlan_rxq_add(wilc, rqe);
106262306a36Sopenharmony_ci	wilc_wlan_handle_rxq(wilc);
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_civoid wilc_handle_isr(struct wilc *wilc)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	u32 int_status;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
107062306a36Sopenharmony_ci	wilc->hif_func->hif_read_int(wilc, &int_status);
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	if (int_status & DATA_INT_EXT)
107362306a36Sopenharmony_ci		wilc_wlan_handle_isr_ext(wilc, int_status);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	if (!(int_status & (ALL_INT_EXT)))
107662306a36Sopenharmony_ci		wilc_unknown_isr_ext(wilc);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
107962306a36Sopenharmony_ci}
108062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(wilc_handle_isr);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ciint wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
108362306a36Sopenharmony_ci				u32 buffer_size)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	u32 offset;
108662306a36Sopenharmony_ci	u32 addr, size, size2, blksz;
108762306a36Sopenharmony_ci	u8 *dma_buffer;
108862306a36Sopenharmony_ci	int ret = 0;
108962306a36Sopenharmony_ci	u32 reg = 0;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	blksz = BIT(12);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	dma_buffer = kmalloc(blksz, GFP_KERNEL);
109462306a36Sopenharmony_ci	if (!dma_buffer)
109562306a36Sopenharmony_ci		return -EIO;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	offset = 0;
109862306a36Sopenharmony_ci	pr_debug("%s: Downloading firmware size = %d\n", __func__, buffer_size);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
110362306a36Sopenharmony_ci	reg &= ~BIT(10);
110462306a36Sopenharmony_ci	ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
110562306a36Sopenharmony_ci	wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
110662306a36Sopenharmony_ci	if (reg & BIT(10))
110762306a36Sopenharmony_ci		pr_err("%s: Failed to reset\n", __func__);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	release_bus(wilc, WILC_BUS_RELEASE_ONLY);
111062306a36Sopenharmony_ci	do {
111162306a36Sopenharmony_ci		addr = get_unaligned_le32(&buffer[offset]);
111262306a36Sopenharmony_ci		size = get_unaligned_le32(&buffer[offset + 4]);
111362306a36Sopenharmony_ci		acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
111462306a36Sopenharmony_ci		offset += 8;
111562306a36Sopenharmony_ci		while (((int)size) && (offset < buffer_size)) {
111662306a36Sopenharmony_ci			if (size <= blksz)
111762306a36Sopenharmony_ci				size2 = size;
111862306a36Sopenharmony_ci			else
111962306a36Sopenharmony_ci				size2 = blksz;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci			memcpy(dma_buffer, &buffer[offset], size2);
112262306a36Sopenharmony_ci			ret = wilc->hif_func->hif_block_tx(wilc, addr,
112362306a36Sopenharmony_ci							   dma_buffer, size2);
112462306a36Sopenharmony_ci			if (ret)
112562306a36Sopenharmony_ci				break;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci			addr += size2;
112862306a36Sopenharmony_ci			offset += size2;
112962306a36Sopenharmony_ci			size -= size2;
113062306a36Sopenharmony_ci		}
113162306a36Sopenharmony_ci		release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci		if (ret) {
113462306a36Sopenharmony_ci			pr_err("%s Bus error\n", __func__);
113562306a36Sopenharmony_ci			goto fail;
113662306a36Sopenharmony_ci		}
113762306a36Sopenharmony_ci		pr_debug("%s Offset = %d\n", __func__, offset);
113862306a36Sopenharmony_ci	} while (offset < buffer_size);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cifail:
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	kfree(dma_buffer);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	return ret;
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ciint wilc_wlan_start(struct wilc *wilc)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	u32 reg = 0;
115062306a36Sopenharmony_ci	int ret;
115162306a36Sopenharmony_ci	u32 chipid;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (wilc->io_type == WILC_HIF_SDIO) {
115462306a36Sopenharmony_ci		reg = 0;
115562306a36Sopenharmony_ci		reg |= BIT(3);
115662306a36Sopenharmony_ci	} else if (wilc->io_type == WILC_HIF_SPI) {
115762306a36Sopenharmony_ci		reg = 1;
115862306a36Sopenharmony_ci	}
115962306a36Sopenharmony_ci	acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
116062306a36Sopenharmony_ci	ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg);
116162306a36Sopenharmony_ci	if (ret)
116262306a36Sopenharmony_ci		goto release;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	reg = 0;
116562306a36Sopenharmony_ci	if (wilc->io_type == WILC_HIF_SDIO && wilc->dev_irq_num)
116662306a36Sopenharmony_ci		reg |= WILC_HAVE_SDIO_IRQ_GPIO;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg);
116962306a36Sopenharmony_ci	if (ret)
117062306a36Sopenharmony_ci		goto release;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	ret = wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid);
117562306a36Sopenharmony_ci	if (ret)
117662306a36Sopenharmony_ci		goto release;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
117962306a36Sopenharmony_ci	if ((reg & BIT(10)) == BIT(10)) {
118062306a36Sopenharmony_ci		reg &= ~BIT(10);
118162306a36Sopenharmony_ci		wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
118262306a36Sopenharmony_ci		wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
118362306a36Sopenharmony_ci	}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	reg |= BIT(10);
118662306a36Sopenharmony_ci	ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);
118762306a36Sopenharmony_ci	wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_cirelease:
119062306a36Sopenharmony_ci	release_bus(wilc, WILC_BUS_RELEASE_ONLY);
119162306a36Sopenharmony_ci	return ret;
119262306a36Sopenharmony_ci}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ciint wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)
119562306a36Sopenharmony_ci{
119662306a36Sopenharmony_ci	u32 reg = 0;
119762306a36Sopenharmony_ci	int ret;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, &reg);
120262306a36Sopenharmony_ci	if (ret) {
120362306a36Sopenharmony_ci		netdev_err(vif->ndev, "Error while reading reg\n");
120462306a36Sopenharmony_ci		goto release;
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,
120862306a36Sopenharmony_ci					(reg | WILC_ABORT_REQ_BIT));
120962306a36Sopenharmony_ci	if (ret) {
121062306a36Sopenharmony_ci		netdev_err(vif->ndev, "Error while writing reg\n");
121162306a36Sopenharmony_ci		goto release;
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, &reg);
121562306a36Sopenharmony_ci	if (ret) {
121662306a36Sopenharmony_ci		netdev_err(vif->ndev, "Error while reading reg\n");
121762306a36Sopenharmony_ci		goto release;
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci	reg = BIT(0);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg);
122262306a36Sopenharmony_ci	if (ret) {
122362306a36Sopenharmony_ci		netdev_err(vif->ndev, "Error while writing reg\n");
122462306a36Sopenharmony_ci		goto release;
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	ret = 0;
122862306a36Sopenharmony_cirelease:
122962306a36Sopenharmony_ci	/* host comm is disabled - we can't issue sleep command anymore: */
123062306a36Sopenharmony_ci	release_bus(wilc, WILC_BUS_RELEASE_ONLY);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	return ret;
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_civoid wilc_wlan_cleanup(struct net_device *dev)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct txq_entry_t *tqe;
123862306a36Sopenharmony_ci	struct rxq_entry_t *rqe;
123962306a36Sopenharmony_ci	u8 ac;
124062306a36Sopenharmony_ci	struct wilc_vif *vif = netdev_priv(dev);
124162306a36Sopenharmony_ci	struct wilc *wilc = vif->wilc;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	wilc->quit = 1;
124462306a36Sopenharmony_ci	for (ac = 0; ac < NQUEUES; ac++) {
124562306a36Sopenharmony_ci		while ((tqe = wilc_wlan_txq_remove_from_head(wilc, ac))) {
124662306a36Sopenharmony_ci			if (tqe->tx_complete_func)
124762306a36Sopenharmony_ci				tqe->tx_complete_func(tqe->priv, 0);
124862306a36Sopenharmony_ci			kfree(tqe);
124962306a36Sopenharmony_ci		}
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	while ((rqe = wilc_wlan_rxq_remove(wilc)))
125362306a36Sopenharmony_ci		kfree(rqe);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	kfree(wilc->vmm_table);
125662306a36Sopenharmony_ci	wilc->vmm_table = NULL;
125762306a36Sopenharmony_ci	kfree(wilc->rx_buffer);
125862306a36Sopenharmony_ci	wilc->rx_buffer = NULL;
125962306a36Sopenharmony_ci	kfree(wilc->tx_buffer);
126062306a36Sopenharmony_ci	wilc->tx_buffer = NULL;
126162306a36Sopenharmony_ci	wilc->hif_func->hif_deinit(wilc);
126262306a36Sopenharmony_ci}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_cistatic int wilc_wlan_cfg_commit(struct wilc_vif *vif, int type,
126562306a36Sopenharmony_ci				u32 drv_handler)
126662306a36Sopenharmony_ci{
126762306a36Sopenharmony_ci	struct wilc *wilc = vif->wilc;
126862306a36Sopenharmony_ci	struct wilc_cfg_frame *cfg = &wilc->cfg_frame;
126962306a36Sopenharmony_ci	int t_len = wilc->cfg_frame_offset + sizeof(struct wilc_cfg_cmd_hdr);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	if (type == WILC_CFG_SET)
127262306a36Sopenharmony_ci		cfg->hdr.cmd_type = 'W';
127362306a36Sopenharmony_ci	else
127462306a36Sopenharmony_ci		cfg->hdr.cmd_type = 'Q';
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	cfg->hdr.seq_no = wilc->cfg_seq_no % 256;
127762306a36Sopenharmony_ci	cfg->hdr.total_len = cpu_to_le16(t_len);
127862306a36Sopenharmony_ci	cfg->hdr.driver_handler = cpu_to_le32(drv_handler);
127962306a36Sopenharmony_ci	wilc->cfg_seq_no = cfg->hdr.seq_no;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	if (!wilc_wlan_txq_add_cfg_pkt(vif, (u8 *)&cfg->hdr, t_len))
128262306a36Sopenharmony_ci		return -1;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	return 0;
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ciint wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,
128862306a36Sopenharmony_ci		      u32 buffer_size, int commit, u32 drv_handler)
128962306a36Sopenharmony_ci{
129062306a36Sopenharmony_ci	u32 offset;
129162306a36Sopenharmony_ci	int ret_size;
129262306a36Sopenharmony_ci	struct wilc *wilc = vif->wilc;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	mutex_lock(&wilc->cfg_cmd_lock);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	if (start)
129762306a36Sopenharmony_ci		wilc->cfg_frame_offset = 0;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	offset = wilc->cfg_frame_offset;
130062306a36Sopenharmony_ci	ret_size = wilc_wlan_cfg_set_wid(wilc->cfg_frame.frame, offset,
130162306a36Sopenharmony_ci					 wid, buffer, buffer_size);
130262306a36Sopenharmony_ci	offset += ret_size;
130362306a36Sopenharmony_ci	wilc->cfg_frame_offset = offset;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	if (!commit) {
130662306a36Sopenharmony_ci		mutex_unlock(&wilc->cfg_cmd_lock);
130762306a36Sopenharmony_ci		return ret_size;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	netdev_dbg(vif->ndev, "%s: seqno[%d]\n", __func__, wilc->cfg_seq_no);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler))
131362306a36Sopenharmony_ci		ret_size = 0;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&wilc->cfg_event,
131662306a36Sopenharmony_ci					 WILC_CFG_PKTS_TIMEOUT)) {
131762306a36Sopenharmony_ci		netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__);
131862306a36Sopenharmony_ci		ret_size = 0;
131962306a36Sopenharmony_ci	}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	wilc->cfg_frame_offset = 0;
132262306a36Sopenharmony_ci	wilc->cfg_seq_no += 1;
132362306a36Sopenharmony_ci	mutex_unlock(&wilc->cfg_cmd_lock);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	return ret_size;
132662306a36Sopenharmony_ci}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ciint wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,
132962306a36Sopenharmony_ci		      u32 drv_handler)
133062306a36Sopenharmony_ci{
133162306a36Sopenharmony_ci	u32 offset;
133262306a36Sopenharmony_ci	int ret_size;
133362306a36Sopenharmony_ci	struct wilc *wilc = vif->wilc;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	mutex_lock(&wilc->cfg_cmd_lock);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	if (start)
133862306a36Sopenharmony_ci		wilc->cfg_frame_offset = 0;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	offset = wilc->cfg_frame_offset;
134162306a36Sopenharmony_ci	ret_size = wilc_wlan_cfg_get_wid(wilc->cfg_frame.frame, offset, wid);
134262306a36Sopenharmony_ci	offset += ret_size;
134362306a36Sopenharmony_ci	wilc->cfg_frame_offset = offset;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	if (!commit) {
134662306a36Sopenharmony_ci		mutex_unlock(&wilc->cfg_cmd_lock);
134762306a36Sopenharmony_ci		return ret_size;
134862306a36Sopenharmony_ci	}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler))
135162306a36Sopenharmony_ci		ret_size = 0;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&wilc->cfg_event,
135462306a36Sopenharmony_ci					 WILC_CFG_PKTS_TIMEOUT)) {
135562306a36Sopenharmony_ci		netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__);
135662306a36Sopenharmony_ci		ret_size = 0;
135762306a36Sopenharmony_ci	}
135862306a36Sopenharmony_ci	wilc->cfg_frame_offset = 0;
135962306a36Sopenharmony_ci	wilc->cfg_seq_no += 1;
136062306a36Sopenharmony_ci	mutex_unlock(&wilc->cfg_cmd_lock);
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	return ret_size;
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ciint wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
136662306a36Sopenharmony_ci			 u32 count)
136762306a36Sopenharmony_ci{
136862306a36Sopenharmony_ci	int i;
136962306a36Sopenharmony_ci	int ret = 0;
137062306a36Sopenharmony_ci	u32 drv = wilc_get_vif_idx(vif);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	if (mode == WILC_GET_CFG) {
137362306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
137462306a36Sopenharmony_ci			if (!wilc_wlan_cfg_get(vif, !i,
137562306a36Sopenharmony_ci					       wids[i].id,
137662306a36Sopenharmony_ci					       (i == count - 1),
137762306a36Sopenharmony_ci					       drv)) {
137862306a36Sopenharmony_ci				ret = -ETIMEDOUT;
137962306a36Sopenharmony_ci				break;
138062306a36Sopenharmony_ci			}
138162306a36Sopenharmony_ci		}
138262306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
138362306a36Sopenharmony_ci			wids[i].size = wilc_wlan_cfg_get_val(vif->wilc,
138462306a36Sopenharmony_ci							     wids[i].id,
138562306a36Sopenharmony_ci							     wids[i].val,
138662306a36Sopenharmony_ci							     wids[i].size);
138762306a36Sopenharmony_ci		}
138862306a36Sopenharmony_ci	} else if (mode == WILC_SET_CFG) {
138962306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
139062306a36Sopenharmony_ci			if (!wilc_wlan_cfg_set(vif, !i,
139162306a36Sopenharmony_ci					       wids[i].id,
139262306a36Sopenharmony_ci					       wids[i].val,
139362306a36Sopenharmony_ci					       wids[i].size,
139462306a36Sopenharmony_ci					       (i == count - 1),
139562306a36Sopenharmony_ci					       drv)) {
139662306a36Sopenharmony_ci				ret = -ETIMEDOUT;
139762306a36Sopenharmony_ci				break;
139862306a36Sopenharmony_ci			}
139962306a36Sopenharmony_ci		}
140062306a36Sopenharmony_ci	}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	return ret;
140362306a36Sopenharmony_ci}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_cistatic int init_chip(struct net_device *dev)
140662306a36Sopenharmony_ci{
140762306a36Sopenharmony_ci	u32 chipid;
140862306a36Sopenharmony_ci	u32 reg;
140962306a36Sopenharmony_ci	int ret = 0;
141062306a36Sopenharmony_ci	struct wilc_vif *vif = netdev_priv(dev);
141162306a36Sopenharmony_ci	struct wilc *wilc = vif->wilc;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	chipid = wilc_get_chipid(wilc, true);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	if ((chipid & 0xfff) != 0xa0) {
141862306a36Sopenharmony_ci		ret = wilc->hif_func->hif_read_reg(wilc,
141962306a36Sopenharmony_ci						   WILC_CORTUS_RESET_MUX_SEL,
142062306a36Sopenharmony_ci						   &reg);
142162306a36Sopenharmony_ci		if (ret) {
142262306a36Sopenharmony_ci			netdev_err(dev, "fail read reg 0x1118\n");
142362306a36Sopenharmony_ci			goto release;
142462306a36Sopenharmony_ci		}
142562306a36Sopenharmony_ci		reg |= BIT(0);
142662306a36Sopenharmony_ci		ret = wilc->hif_func->hif_write_reg(wilc,
142762306a36Sopenharmony_ci						    WILC_CORTUS_RESET_MUX_SEL,
142862306a36Sopenharmony_ci						    reg);
142962306a36Sopenharmony_ci		if (ret) {
143062306a36Sopenharmony_ci			netdev_err(dev, "fail write reg 0x1118\n");
143162306a36Sopenharmony_ci			goto release;
143262306a36Sopenharmony_ci		}
143362306a36Sopenharmony_ci		ret = wilc->hif_func->hif_write_reg(wilc,
143462306a36Sopenharmony_ci						    WILC_CORTUS_BOOT_REGISTER,
143562306a36Sopenharmony_ci						    WILC_CORTUS_BOOT_FROM_IRAM);
143662306a36Sopenharmony_ci		if (ret) {
143762306a36Sopenharmony_ci			netdev_err(dev, "fail write reg 0xc0000\n");
143862306a36Sopenharmony_ci			goto release;
143962306a36Sopenharmony_ci		}
144062306a36Sopenharmony_ci	}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_cirelease:
144362306a36Sopenharmony_ci	release_bus(wilc, WILC_BUS_RELEASE_ONLY);
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	return ret;
144662306a36Sopenharmony_ci}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ciu32 wilc_get_chipid(struct wilc *wilc, bool update)
144962306a36Sopenharmony_ci{
145062306a36Sopenharmony_ci	u32 chipid = 0;
145162306a36Sopenharmony_ci	u32 rfrevid = 0;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	if (wilc->chipid == 0 || update) {
145462306a36Sopenharmony_ci		wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid);
145562306a36Sopenharmony_ci		wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID,
145662306a36Sopenharmony_ci					     &rfrevid);
145762306a36Sopenharmony_ci		if (!is_wilc1000(chipid)) {
145862306a36Sopenharmony_ci			wilc->chipid = 0;
145962306a36Sopenharmony_ci			return wilc->chipid;
146062306a36Sopenharmony_ci		}
146162306a36Sopenharmony_ci		if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */
146262306a36Sopenharmony_ci			if (rfrevid != 0x1)
146362306a36Sopenharmony_ci				chipid = WILC_1000_BASE_ID_2A_REV1;
146462306a36Sopenharmony_ci		} else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */
146562306a36Sopenharmony_ci			if (rfrevid == 0x4)
146662306a36Sopenharmony_ci				chipid = WILC_1000_BASE_ID_2B_REV1;
146762306a36Sopenharmony_ci			else if (rfrevid != 0x3)
146862306a36Sopenharmony_ci				chipid = WILC_1000_BASE_ID_2B_REV2;
146962306a36Sopenharmony_ci		}
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci		wilc->chipid = chipid;
147262306a36Sopenharmony_ci	}
147362306a36Sopenharmony_ci	return wilc->chipid;
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ciint wilc_wlan_init(struct net_device *dev)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci	int ret = 0;
147962306a36Sopenharmony_ci	struct wilc_vif *vif = netdev_priv(dev);
148062306a36Sopenharmony_ci	struct wilc *wilc;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	wilc = vif->wilc;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	wilc->quit = 0;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	if (!wilc->hif_func->hif_is_init(wilc)) {
148762306a36Sopenharmony_ci		acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
148862306a36Sopenharmony_ci		ret = wilc->hif_func->hif_init(wilc, false);
148962306a36Sopenharmony_ci		release_bus(wilc, WILC_BUS_RELEASE_ONLY);
149062306a36Sopenharmony_ci		if (ret)
149162306a36Sopenharmony_ci			goto fail;
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	if (!wilc->vmm_table)
149562306a36Sopenharmony_ci		wilc->vmm_table = kcalloc(WILC_VMM_TBL_SIZE, sizeof(u32), GFP_KERNEL);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	if (!wilc->vmm_table) {
149862306a36Sopenharmony_ci		ret = -ENOBUFS;
149962306a36Sopenharmony_ci		goto fail;
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	if (!wilc->tx_buffer)
150362306a36Sopenharmony_ci		wilc->tx_buffer = kmalloc(WILC_TX_BUFF_SIZE, GFP_KERNEL);
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	if (!wilc->tx_buffer) {
150662306a36Sopenharmony_ci		ret = -ENOBUFS;
150762306a36Sopenharmony_ci		goto fail;
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	if (!wilc->rx_buffer)
151162306a36Sopenharmony_ci		wilc->rx_buffer = kmalloc(WILC_RX_BUFF_SIZE, GFP_KERNEL);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	if (!wilc->rx_buffer) {
151462306a36Sopenharmony_ci		ret = -ENOBUFS;
151562306a36Sopenharmony_ci		goto fail;
151662306a36Sopenharmony_ci	}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	if (init_chip(dev)) {
151962306a36Sopenharmony_ci		ret = -EIO;
152062306a36Sopenharmony_ci		goto fail;
152162306a36Sopenharmony_ci	}
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	return 0;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_cifail:
152662306a36Sopenharmony_ci	kfree(wilc->vmm_table);
152762306a36Sopenharmony_ci	wilc->vmm_table = NULL;
152862306a36Sopenharmony_ci	kfree(wilc->rx_buffer);
152962306a36Sopenharmony_ci	wilc->rx_buffer = NULL;
153062306a36Sopenharmony_ci	kfree(wilc->tx_buffer);
153162306a36Sopenharmony_ci	wilc->tx_buffer = NULL;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	return ret;
153462306a36Sopenharmony_ci}
1535