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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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 ®); 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