18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. 48c2ecf20Sopenharmony_ci * All rights reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 88c2ecf20Sopenharmony_ci#include <linux/ip.h> 98c2ecf20Sopenharmony_ci#include "cfg80211.h" 108c2ecf20Sopenharmony_ci#include "wlan_cfg.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic inline bool is_wilc1000(u32 id) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID; 158c2ecf20Sopenharmony_ci} 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci mutex_lock(&wilc->hif_cs); 208c2ecf20Sopenharmony_ci if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP) 218c2ecf20Sopenharmony_ci chip_wakeup(wilc); 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic inline void release_bus(struct wilc *wilc, enum bus_release release) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci if (release == WILC_BUS_RELEASE_ALLOW_SLEEP) 278c2ecf20Sopenharmony_ci chip_allow_sleep(wilc); 288c2ecf20Sopenharmony_ci mutex_unlock(&wilc->hif_cs); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void wilc_wlan_txq_remove(struct wilc *wilc, struct txq_entry_t *tqe) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci list_del(&tqe->list); 348c2ecf20Sopenharmony_ci wilc->txq_entries -= 1; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic struct txq_entry_t * 388c2ecf20Sopenharmony_ciwilc_wlan_txq_remove_from_head(struct net_device *dev) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct txq_entry_t *tqe = NULL; 418c2ecf20Sopenharmony_ci unsigned long flags; 428c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 438c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci spin_lock_irqsave(&wilc->txq_spinlock, flags); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (!list_empty(&wilc->txq_head.list)) { 488c2ecf20Sopenharmony_ci tqe = list_first_entry(&wilc->txq_head.list, struct txq_entry_t, 498c2ecf20Sopenharmony_ci list); 508c2ecf20Sopenharmony_ci list_del(&tqe->list); 518c2ecf20Sopenharmony_ci wilc->txq_entries -= 1; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wilc->txq_spinlock, flags); 548c2ecf20Sopenharmony_ci return tqe; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void wilc_wlan_txq_add_to_tail(struct net_device *dev, 588c2ecf20Sopenharmony_ci struct txq_entry_t *tqe) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci unsigned long flags; 618c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 628c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci spin_lock_irqsave(&wilc->txq_spinlock, flags); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci list_add_tail(&tqe->list, &wilc->txq_head.list); 678c2ecf20Sopenharmony_ci wilc->txq_entries += 1; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wilc->txq_spinlock, flags); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci complete(&wilc->txq_event); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, 758c2ecf20Sopenharmony_ci struct txq_entry_t *tqe) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci unsigned long flags; 788c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci mutex_lock(&wilc->txq_add_to_head_cs); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci spin_lock_irqsave(&wilc->txq_spinlock, flags); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci list_add(&tqe->list, &wilc->txq_head.list); 858c2ecf20Sopenharmony_ci wilc->txq_entries += 1; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wilc->txq_spinlock, flags); 888c2ecf20Sopenharmony_ci mutex_unlock(&wilc->txq_add_to_head_cs); 898c2ecf20Sopenharmony_ci complete(&wilc->txq_event); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define NOT_TCP_ACK (-1) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic inline void add_tcp_session(struct wilc_vif *vif, u32 src_prt, 958c2ecf20Sopenharmony_ci u32 dst_prt, u32 seq) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct tcp_ack_filter *f = &vif->ack_filter; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (f->tcp_session < 2 * MAX_TCP_SESSION) { 1008c2ecf20Sopenharmony_ci f->ack_session_info[f->tcp_session].seq_num = seq; 1018c2ecf20Sopenharmony_ci f->ack_session_info[f->tcp_session].bigger_ack_num = 0; 1028c2ecf20Sopenharmony_ci f->ack_session_info[f->tcp_session].src_port = src_prt; 1038c2ecf20Sopenharmony_ci f->ack_session_info[f->tcp_session].dst_port = dst_prt; 1048c2ecf20Sopenharmony_ci f->tcp_session++; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic inline void update_tcp_session(struct wilc_vif *vif, u32 index, u32 ack) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct tcp_ack_filter *f = &vif->ack_filter; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (index < 2 * MAX_TCP_SESSION && 1138c2ecf20Sopenharmony_ci ack > f->ack_session_info[index].bigger_ack_num) 1148c2ecf20Sopenharmony_ci f->ack_session_info[index].bigger_ack_num = ack; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic inline void add_tcp_pending_ack(struct wilc_vif *vif, u32 ack, 1188c2ecf20Sopenharmony_ci u32 session_index, 1198c2ecf20Sopenharmony_ci struct txq_entry_t *txqe) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct tcp_ack_filter *f = &vif->ack_filter; 1228c2ecf20Sopenharmony_ci u32 i = f->pending_base + f->pending_acks_idx; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (i < MAX_PENDING_ACKS) { 1258c2ecf20Sopenharmony_ci f->pending_acks[i].ack_num = ack; 1268c2ecf20Sopenharmony_ci f->pending_acks[i].txqe = txqe; 1278c2ecf20Sopenharmony_ci f->pending_acks[i].session_index = session_index; 1288c2ecf20Sopenharmony_ci txqe->ack_idx = i; 1298c2ecf20Sopenharmony_ci f->pending_acks_idx++; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci void *buffer = tqe->buffer; 1368c2ecf20Sopenharmony_ci const struct ethhdr *eth_hdr_ptr = buffer; 1378c2ecf20Sopenharmony_ci int i; 1388c2ecf20Sopenharmony_ci unsigned long flags; 1398c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 1408c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 1418c2ecf20Sopenharmony_ci struct tcp_ack_filter *f = &vif->ack_filter; 1428c2ecf20Sopenharmony_ci const struct iphdr *ip_hdr_ptr; 1438c2ecf20Sopenharmony_ci const struct tcphdr *tcp_hdr_ptr; 1448c2ecf20Sopenharmony_ci u32 ihl, total_length, data_offset; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci spin_lock_irqsave(&wilc->txq_spinlock, flags); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (eth_hdr_ptr->h_proto != htons(ETH_P_IP)) 1498c2ecf20Sopenharmony_ci goto out; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci ip_hdr_ptr = buffer + ETH_HLEN; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (ip_hdr_ptr->protocol != IPPROTO_TCP) 1548c2ecf20Sopenharmony_ci goto out; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ihl = ip_hdr_ptr->ihl << 2; 1578c2ecf20Sopenharmony_ci tcp_hdr_ptr = buffer + ETH_HLEN + ihl; 1588c2ecf20Sopenharmony_ci total_length = ntohs(ip_hdr_ptr->tot_len); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci data_offset = tcp_hdr_ptr->doff << 2; 1618c2ecf20Sopenharmony_ci if (total_length == (ihl + data_offset)) { 1628c2ecf20Sopenharmony_ci u32 seq_no, ack_no; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci seq_no = ntohl(tcp_hdr_ptr->seq); 1658c2ecf20Sopenharmony_ci ack_no = ntohl(tcp_hdr_ptr->ack_seq); 1668c2ecf20Sopenharmony_ci for (i = 0; i < f->tcp_session; i++) { 1678c2ecf20Sopenharmony_ci u32 j = f->ack_session_info[i].seq_num; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (i < 2 * MAX_TCP_SESSION && 1708c2ecf20Sopenharmony_ci j == seq_no) { 1718c2ecf20Sopenharmony_ci update_tcp_session(vif, i, ack_no); 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci if (i == f->tcp_session) 1768c2ecf20Sopenharmony_ci add_tcp_session(vif, 0, 0, seq_no); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci add_tcp_pending_ack(vif, ack_no, i, tqe); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ciout: 1828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wilc->txq_spinlock, flags); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 1888c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 1898c2ecf20Sopenharmony_ci struct tcp_ack_filter *f = &vif->ack_filter; 1908c2ecf20Sopenharmony_ci u32 i = 0; 1918c2ecf20Sopenharmony_ci u32 dropped = 0; 1928c2ecf20Sopenharmony_ci unsigned long flags; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci spin_lock_irqsave(&wilc->txq_spinlock, flags); 1958c2ecf20Sopenharmony_ci for (i = f->pending_base; 1968c2ecf20Sopenharmony_ci i < (f->pending_base + f->pending_acks_idx); i++) { 1978c2ecf20Sopenharmony_ci u32 index; 1988c2ecf20Sopenharmony_ci u32 bigger_ack_num; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (i >= MAX_PENDING_ACKS) 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci index = f->pending_acks[i].session_index; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (index >= 2 * MAX_TCP_SESSION) 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci bigger_ack_num = f->ack_session_info[index].bigger_ack_num; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (f->pending_acks[i].ack_num < bigger_ack_num) { 2118c2ecf20Sopenharmony_ci struct txq_entry_t *tqe; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci tqe = f->pending_acks[i].txqe; 2148c2ecf20Sopenharmony_ci if (tqe) { 2158c2ecf20Sopenharmony_ci wilc_wlan_txq_remove(wilc, tqe); 2168c2ecf20Sopenharmony_ci tqe->status = 1; 2178c2ecf20Sopenharmony_ci if (tqe->tx_complete_func) 2188c2ecf20Sopenharmony_ci tqe->tx_complete_func(tqe->priv, 2198c2ecf20Sopenharmony_ci tqe->status); 2208c2ecf20Sopenharmony_ci kfree(tqe); 2218c2ecf20Sopenharmony_ci dropped++; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci f->pending_acks_idx = 0; 2268c2ecf20Sopenharmony_ci f->tcp_session = 0; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (f->pending_base == 0) 2298c2ecf20Sopenharmony_ci f->pending_base = MAX_TCP_SESSION; 2308c2ecf20Sopenharmony_ci else 2318c2ecf20Sopenharmony_ci f->pending_base = 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wilc->txq_spinlock, flags); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci while (dropped > 0) { 2368c2ecf20Sopenharmony_ci wait_for_completion_timeout(&wilc->txq_event, 2378c2ecf20Sopenharmony_ci msecs_to_jiffies(1)); 2388c2ecf20Sopenharmony_ci dropped--; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_civoid wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci vif->ack_filter.enabled = value; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer, 2488c2ecf20Sopenharmony_ci u32 buffer_size) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct txq_entry_t *tqe; 2518c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci netdev_dbg(vif->ndev, "Adding config packet ...\n"); 2548c2ecf20Sopenharmony_ci if (wilc->quit) { 2558c2ecf20Sopenharmony_ci netdev_dbg(vif->ndev, "Return due to clear function\n"); 2568c2ecf20Sopenharmony_ci complete(&wilc->cfg_event); 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC); 2618c2ecf20Sopenharmony_ci if (!tqe) 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci tqe->type = WILC_CFG_PKT; 2658c2ecf20Sopenharmony_ci tqe->buffer = buffer; 2668c2ecf20Sopenharmony_ci tqe->buffer_size = buffer_size; 2678c2ecf20Sopenharmony_ci tqe->tx_complete_func = NULL; 2688c2ecf20Sopenharmony_ci tqe->priv = NULL; 2698c2ecf20Sopenharmony_ci tqe->ack_idx = NOT_TCP_ACK; 2708c2ecf20Sopenharmony_ci tqe->vif = vif; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci wilc_wlan_txq_add_to_head(vif, tqe); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return 1; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ciint wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, 2788c2ecf20Sopenharmony_ci u32 buffer_size, 2798c2ecf20Sopenharmony_ci void (*tx_complete_fn)(void *, int)) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct txq_entry_t *tqe; 2828c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 2838c2ecf20Sopenharmony_ci struct wilc *wilc; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci wilc = vif->wilc; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (wilc->quit) 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (!tqe) 2938c2ecf20Sopenharmony_ci return 0; 2948c2ecf20Sopenharmony_ci tqe->type = WILC_NET_PKT; 2958c2ecf20Sopenharmony_ci tqe->buffer = buffer; 2968c2ecf20Sopenharmony_ci tqe->buffer_size = buffer_size; 2978c2ecf20Sopenharmony_ci tqe->tx_complete_func = tx_complete_fn; 2988c2ecf20Sopenharmony_ci tqe->priv = priv; 2998c2ecf20Sopenharmony_ci tqe->vif = vif; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci tqe->ack_idx = NOT_TCP_ACK; 3028c2ecf20Sopenharmony_ci if (vif->ack_filter.enabled) 3038c2ecf20Sopenharmony_ci tcp_process(dev, tqe); 3048c2ecf20Sopenharmony_ci wilc_wlan_txq_add_to_tail(dev, tqe); 3058c2ecf20Sopenharmony_ci return wilc->txq_entries; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ciint wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer, 3098c2ecf20Sopenharmony_ci u32 buffer_size, 3108c2ecf20Sopenharmony_ci void (*tx_complete_fn)(void *, int)) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct txq_entry_t *tqe; 3138c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 3148c2ecf20Sopenharmony_ci struct wilc *wilc; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci wilc = vif->wilc; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (wilc->quit) 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (!tqe) 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci tqe->type = WILC_MGMT_PKT; 3268c2ecf20Sopenharmony_ci tqe->buffer = buffer; 3278c2ecf20Sopenharmony_ci tqe->buffer_size = buffer_size; 3288c2ecf20Sopenharmony_ci tqe->tx_complete_func = tx_complete_fn; 3298c2ecf20Sopenharmony_ci tqe->priv = priv; 3308c2ecf20Sopenharmony_ci tqe->ack_idx = NOT_TCP_ACK; 3318c2ecf20Sopenharmony_ci tqe->vif = vif; 3328c2ecf20Sopenharmony_ci wilc_wlan_txq_add_to_tail(dev, tqe); 3338c2ecf20Sopenharmony_ci return 1; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct txq_entry_t *tqe = NULL; 3398c2ecf20Sopenharmony_ci unsigned long flags; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci spin_lock_irqsave(&wilc->txq_spinlock, flags); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (!list_empty(&wilc->txq_head.list)) 3448c2ecf20Sopenharmony_ci tqe = list_first_entry(&wilc->txq_head.list, struct txq_entry_t, 3458c2ecf20Sopenharmony_ci list); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wilc->txq_spinlock, flags); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return tqe; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc, 3538c2ecf20Sopenharmony_ci struct txq_entry_t *tqe) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci unsigned long flags; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci spin_lock_irqsave(&wilc->txq_spinlock, flags); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (!list_is_last(&tqe->list, &wilc->txq_head.list)) 3608c2ecf20Sopenharmony_ci tqe = list_next_entry(tqe, list); 3618c2ecf20Sopenharmony_ci else 3628c2ecf20Sopenharmony_ci tqe = NULL; 3638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wilc->txq_spinlock, flags); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return tqe; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci if (wilc->quit) 3718c2ecf20Sopenharmony_ci return; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci mutex_lock(&wilc->rxq_cs); 3748c2ecf20Sopenharmony_ci list_add_tail(&rqe->list, &wilc->rxq_head.list); 3758c2ecf20Sopenharmony_ci mutex_unlock(&wilc->rxq_cs); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct rxq_entry_t *rqe = NULL; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci mutex_lock(&wilc->rxq_cs); 3838c2ecf20Sopenharmony_ci if (!list_empty(&wilc->rxq_head.list)) { 3848c2ecf20Sopenharmony_ci rqe = list_first_entry(&wilc->rxq_head.list, struct rxq_entry_t, 3858c2ecf20Sopenharmony_ci list); 3868c2ecf20Sopenharmony_ci list_del(&rqe->list); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci mutex_unlock(&wilc->rxq_cs); 3898c2ecf20Sopenharmony_ci return rqe; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_civoid chip_allow_sleep(struct wilc *wilc) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci u32 reg = 0; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci wilc->hif_func->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, ®); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci wilc->hif_func->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG, 3998c2ecf20Sopenharmony_ci reg & ~WILC_SDIO_WAKEUP_BIT); 4008c2ecf20Sopenharmony_ci wilc->hif_func->hif_write_reg(wilc, WILC_SDIO_HOST_TO_FW_REG, 0); 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(chip_allow_sleep); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_civoid chip_wakeup(struct wilc *wilc) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci u32 reg, clk_status_reg; 4078c2ecf20Sopenharmony_ci const struct wilc_hif_func *h = wilc->hif_func; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (wilc->io_type == WILC_HIF_SPI) { 4108c2ecf20Sopenharmony_ci do { 4118c2ecf20Sopenharmony_ci h->hif_read_reg(wilc, WILC_SPI_WAKEUP_REG, ®); 4128c2ecf20Sopenharmony_ci h->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG, 4138c2ecf20Sopenharmony_ci reg | WILC_SPI_WAKEUP_BIT); 4148c2ecf20Sopenharmony_ci h->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG, 4158c2ecf20Sopenharmony_ci reg & ~WILC_SPI_WAKEUP_BIT); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci do { 4188c2ecf20Sopenharmony_ci usleep_range(2000, 2500); 4198c2ecf20Sopenharmony_ci wilc_get_chipid(wilc, true); 4208c2ecf20Sopenharmony_ci } while (wilc_get_chipid(wilc, true) == 0); 4218c2ecf20Sopenharmony_ci } while (wilc_get_chipid(wilc, true) == 0); 4228c2ecf20Sopenharmony_ci } else if (wilc->io_type == WILC_HIF_SDIO) { 4238c2ecf20Sopenharmony_ci h->hif_write_reg(wilc, WILC_SDIO_HOST_TO_FW_REG, 4248c2ecf20Sopenharmony_ci WILC_SDIO_HOST_TO_FW_BIT); 4258c2ecf20Sopenharmony_ci usleep_range(200, 400); 4268c2ecf20Sopenharmony_ci h->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, ®); 4278c2ecf20Sopenharmony_ci do { 4288c2ecf20Sopenharmony_ci h->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG, 4298c2ecf20Sopenharmony_ci reg | WILC_SDIO_WAKEUP_BIT); 4308c2ecf20Sopenharmony_ci h->hif_read_reg(wilc, WILC_SDIO_CLK_STATUS_REG, 4318c2ecf20Sopenharmony_ci &clk_status_reg); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci while (!(clk_status_reg & WILC_SDIO_CLK_STATUS_BIT)) { 4348c2ecf20Sopenharmony_ci usleep_range(2000, 2500); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci h->hif_read_reg(wilc, WILC_SDIO_CLK_STATUS_REG, 4378c2ecf20Sopenharmony_ci &clk_status_reg); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci if (!(clk_status_reg & WILC_SDIO_CLK_STATUS_BIT)) { 4408c2ecf20Sopenharmony_ci h->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG, 4418c2ecf20Sopenharmony_ci reg & ~WILC_SDIO_WAKEUP_BIT); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci } while (!(clk_status_reg & WILC_SDIO_CLK_STATUS_BIT)); 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (wilc->chip_ps_state == WILC_CHIP_SLEEPING_MANUAL) { 4478c2ecf20Sopenharmony_ci if (wilc_get_chipid(wilc, false) < WILC_1000_BASE_ID_2B) { 4488c2ecf20Sopenharmony_ci u32 val32; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci h->hif_read_reg(wilc, WILC_REG_4_TO_1_RX, &val32); 4518c2ecf20Sopenharmony_ci val32 |= BIT(6); 4528c2ecf20Sopenharmony_ci h->hif_write_reg(wilc, WILC_REG_4_TO_1_RX, val32); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci h->hif_read_reg(wilc, WILC_REG_4_TO_1_TX_BANK0, &val32); 4558c2ecf20Sopenharmony_ci val32 |= BIT(6); 4568c2ecf20Sopenharmony_ci h->hif_write_reg(wilc, WILC_REG_4_TO_1_TX_BANK0, val32); 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci wilc->chip_ps_state = WILC_CHIP_WAKEDUP; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(chip_wakeup); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_civoid host_wakeup_notify(struct wilc *wilc) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); 4668c2ecf20Sopenharmony_ci wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_2, 1); 4678c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ONLY); 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(host_wakeup_notify); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_civoid host_sleep_notify(struct wilc *wilc) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); 4748c2ecf20Sopenharmony_ci wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_1, 1); 4758c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ONLY); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(host_sleep_notify); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ciint wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci int i, entries = 0; 4828c2ecf20Sopenharmony_ci u32 sum; 4838c2ecf20Sopenharmony_ci u32 reg; 4848c2ecf20Sopenharmony_ci u32 offset = 0; 4858c2ecf20Sopenharmony_ci int vmm_sz = 0; 4868c2ecf20Sopenharmony_ci struct txq_entry_t *tqe; 4878c2ecf20Sopenharmony_ci int ret = 0; 4888c2ecf20Sopenharmony_ci int counter; 4898c2ecf20Sopenharmony_ci int timeout; 4908c2ecf20Sopenharmony_ci u32 vmm_table[WILC_VMM_TBL_SIZE]; 4918c2ecf20Sopenharmony_ci const struct wilc_hif_func *func; 4928c2ecf20Sopenharmony_ci u8 *txb = wilc->tx_buffer; 4938c2ecf20Sopenharmony_ci struct net_device *dev; 4948c2ecf20Sopenharmony_ci struct wilc_vif *vif; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (wilc->quit) 4978c2ecf20Sopenharmony_ci goto out_update_cnt; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci mutex_lock(&wilc->txq_add_to_head_cs); 5008c2ecf20Sopenharmony_ci tqe = wilc_wlan_txq_get_first(wilc); 5018c2ecf20Sopenharmony_ci if (!tqe) 5028c2ecf20Sopenharmony_ci goto out_unlock; 5038c2ecf20Sopenharmony_ci dev = tqe->vif->ndev; 5048c2ecf20Sopenharmony_ci wilc_wlan_txq_filter_dup_tcp_ack(dev); 5058c2ecf20Sopenharmony_ci i = 0; 5068c2ecf20Sopenharmony_ci sum = 0; 5078c2ecf20Sopenharmony_ci while (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) { 5088c2ecf20Sopenharmony_ci if (tqe->type == WILC_CFG_PKT) 5098c2ecf20Sopenharmony_ci vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET; 5108c2ecf20Sopenharmony_ci else if (tqe->type == WILC_NET_PKT) 5118c2ecf20Sopenharmony_ci vmm_sz = ETH_ETHERNET_HDR_OFFSET; 5128c2ecf20Sopenharmony_ci else 5138c2ecf20Sopenharmony_ci vmm_sz = HOST_HDR_OFFSET; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci vmm_sz += tqe->buffer_size; 5168c2ecf20Sopenharmony_ci vmm_sz = ALIGN(vmm_sz, 4); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE) 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci vmm_table[i] = vmm_sz / 4; 5228c2ecf20Sopenharmony_ci if (tqe->type == WILC_CFG_PKT) 5238c2ecf20Sopenharmony_ci vmm_table[i] |= BIT(10); 5248c2ecf20Sopenharmony_ci cpu_to_le32s(&vmm_table[i]); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci i++; 5278c2ecf20Sopenharmony_ci sum += vmm_sz; 5288c2ecf20Sopenharmony_ci tqe = wilc_wlan_txq_get_next(wilc, tqe); 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (i == 0) 5328c2ecf20Sopenharmony_ci goto out_unlock; 5338c2ecf20Sopenharmony_ci vmm_table[i] = 0x0; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); 5368c2ecf20Sopenharmony_ci counter = 0; 5378c2ecf20Sopenharmony_ci func = wilc->hif_func; 5388c2ecf20Sopenharmony_ci do { 5398c2ecf20Sopenharmony_ci ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®); 5408c2ecf20Sopenharmony_ci if (ret) 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if ((reg & 0x1) == 0) 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci counter++; 5478c2ecf20Sopenharmony_ci if (counter > 200) { 5488c2ecf20Sopenharmony_ci counter = 0; 5498c2ecf20Sopenharmony_ci ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0); 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci } while (!wilc->quit); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (ret) 5558c2ecf20Sopenharmony_ci goto out_release_bus; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci timeout = 200; 5588c2ecf20Sopenharmony_ci do { 5598c2ecf20Sopenharmony_ci ret = func->hif_block_tx(wilc, 5608c2ecf20Sopenharmony_ci WILC_VMM_TBL_RX_SHADOW_BASE, 5618c2ecf20Sopenharmony_ci (u8 *)vmm_table, 5628c2ecf20Sopenharmony_ci ((i + 1) * 4)); 5638c2ecf20Sopenharmony_ci if (ret) 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2); 5678c2ecf20Sopenharmony_ci if (ret) 5688c2ecf20Sopenharmony_ci break; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci do { 5718c2ecf20Sopenharmony_ci ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); 5728c2ecf20Sopenharmony_ci if (ret) 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) { 5758c2ecf20Sopenharmony_ci entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); 5768c2ecf20Sopenharmony_ci break; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci } while (--timeout); 5798c2ecf20Sopenharmony_ci if (timeout <= 0) { 5808c2ecf20Sopenharmony_ci ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0); 5818c2ecf20Sopenharmony_ci break; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (ret) 5858c2ecf20Sopenharmony_ci break; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (entries == 0) { 5888c2ecf20Sopenharmony_ci ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®); 5898c2ecf20Sopenharmony_ci if (ret) 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci reg &= ~BIT(0); 5928c2ecf20Sopenharmony_ci ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci } while (0); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (ret) 5978c2ecf20Sopenharmony_ci goto out_release_bus; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (entries == 0) { 6008c2ecf20Sopenharmony_ci /* 6018c2ecf20Sopenharmony_ci * No VMM space available in firmware so retry to transmit 6028c2ecf20Sopenharmony_ci * the packet from tx queue. 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_ci ret = WILC_VMM_ENTRY_FULL_RETRY; 6058c2ecf20Sopenharmony_ci goto out_release_bus; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci offset = 0; 6118c2ecf20Sopenharmony_ci i = 0; 6128c2ecf20Sopenharmony_ci do { 6138c2ecf20Sopenharmony_ci u32 header, buffer_offset; 6148c2ecf20Sopenharmony_ci char *bssid; 6158c2ecf20Sopenharmony_ci u8 mgmt_ptk = 0; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci tqe = wilc_wlan_txq_remove_from_head(dev); 6188c2ecf20Sopenharmony_ci if (!tqe) 6198c2ecf20Sopenharmony_ci break; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci vif = tqe->vif; 6228c2ecf20Sopenharmony_ci if (vmm_table[i] == 0) 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci le32_to_cpus(&vmm_table[i]); 6268c2ecf20Sopenharmony_ci vmm_sz = FIELD_GET(WILC_VMM_BUFFER_SIZE, vmm_table[i]); 6278c2ecf20Sopenharmony_ci vmm_sz *= 4; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (tqe->type == WILC_MGMT_PKT) 6308c2ecf20Sopenharmony_ci mgmt_ptk = 1; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci header = (FIELD_PREP(WILC_VMM_HDR_TYPE, tqe->type) | 6338c2ecf20Sopenharmony_ci FIELD_PREP(WILC_VMM_HDR_MGMT_FIELD, mgmt_ptk) | 6348c2ecf20Sopenharmony_ci FIELD_PREP(WILC_VMM_HDR_PKT_SIZE, tqe->buffer_size) | 6358c2ecf20Sopenharmony_ci FIELD_PREP(WILC_VMM_HDR_BUFF_SIZE, vmm_sz)); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci cpu_to_le32s(&header); 6388c2ecf20Sopenharmony_ci memcpy(&txb[offset], &header, 4); 6398c2ecf20Sopenharmony_ci if (tqe->type == WILC_CFG_PKT) { 6408c2ecf20Sopenharmony_ci buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET; 6418c2ecf20Sopenharmony_ci } else if (tqe->type == WILC_NET_PKT) { 6428c2ecf20Sopenharmony_ci bssid = tqe->vif->bssid; 6438c2ecf20Sopenharmony_ci buffer_offset = ETH_ETHERNET_HDR_OFFSET; 6448c2ecf20Sopenharmony_ci memcpy(&txb[offset + 8], bssid, 6); 6458c2ecf20Sopenharmony_ci } else { 6468c2ecf20Sopenharmony_ci buffer_offset = HOST_HDR_OFFSET; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci memcpy(&txb[offset + buffer_offset], 6508c2ecf20Sopenharmony_ci tqe->buffer, tqe->buffer_size); 6518c2ecf20Sopenharmony_ci offset += vmm_sz; 6528c2ecf20Sopenharmony_ci i++; 6538c2ecf20Sopenharmony_ci tqe->status = 1; 6548c2ecf20Sopenharmony_ci if (tqe->tx_complete_func) 6558c2ecf20Sopenharmony_ci tqe->tx_complete_func(tqe->priv, tqe->status); 6568c2ecf20Sopenharmony_ci if (tqe->ack_idx != NOT_TCP_ACK && 6578c2ecf20Sopenharmony_ci tqe->ack_idx < MAX_PENDING_ACKS) 6588c2ecf20Sopenharmony_ci vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL; 6598c2ecf20Sopenharmony_ci kfree(tqe); 6608c2ecf20Sopenharmony_ci } while (--entries); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM); 6658c2ecf20Sopenharmony_ci if (ret) 6668c2ecf20Sopenharmony_ci goto out_release_bus; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci ret = func->hif_block_tx_ext(wilc, 0, txb, offset); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ciout_release_bus: 6718c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ciout_unlock: 6748c2ecf20Sopenharmony_ci mutex_unlock(&wilc->txq_add_to_head_cs); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ciout_update_cnt: 6778c2ecf20Sopenharmony_ci *txq_count = wilc->txq_entries; 6788c2ecf20Sopenharmony_ci return ret; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci int offset = 0; 6848c2ecf20Sopenharmony_ci u32 header; 6858c2ecf20Sopenharmony_ci u32 pkt_len, pkt_offset, tp_len; 6868c2ecf20Sopenharmony_ci int is_cfg_packet; 6878c2ecf20Sopenharmony_ci u8 *buff_ptr; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci do { 6908c2ecf20Sopenharmony_ci buff_ptr = buffer + offset; 6918c2ecf20Sopenharmony_ci header = get_unaligned_le32(buff_ptr); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci is_cfg_packet = FIELD_GET(WILC_PKT_HDR_CONFIG_FIELD, header); 6948c2ecf20Sopenharmony_ci pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header); 6958c2ecf20Sopenharmony_ci tp_len = FIELD_GET(WILC_PKT_HDR_TOTAL_LEN_FIELD, header); 6968c2ecf20Sopenharmony_ci pkt_len = FIELD_GET(WILC_PKT_HDR_LEN_FIELD, header); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (pkt_len == 0 || tp_len == 0) 6998c2ecf20Sopenharmony_ci break; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (pkt_offset & IS_MANAGMEMENT) { 7028c2ecf20Sopenharmony_ci buff_ptr += HOST_HDR_OFFSET; 7038c2ecf20Sopenharmony_ci wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len); 7048c2ecf20Sopenharmony_ci } else { 7058c2ecf20Sopenharmony_ci if (!is_cfg_packet) { 7068c2ecf20Sopenharmony_ci wilc_frmw_to_host(wilc, buff_ptr, pkt_len, 7078c2ecf20Sopenharmony_ci pkt_offset); 7088c2ecf20Sopenharmony_ci } else { 7098c2ecf20Sopenharmony_ci struct wilc_cfg_rsp rsp; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci buff_ptr += pkt_offset; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci wilc_wlan_cfg_indicate_rx(wilc, buff_ptr, 7148c2ecf20Sopenharmony_ci pkt_len, 7158c2ecf20Sopenharmony_ci &rsp); 7168c2ecf20Sopenharmony_ci if (rsp.type == WILC_CFG_RSP) { 7178c2ecf20Sopenharmony_ci if (wilc->cfg_seq_no == rsp.seq_no) 7188c2ecf20Sopenharmony_ci complete(&wilc->cfg_event); 7198c2ecf20Sopenharmony_ci } else if (rsp.type == WILC_CFG_RSP_STATUS) { 7208c2ecf20Sopenharmony_ci wilc_mac_indicate(wilc); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci offset += tp_len; 7258c2ecf20Sopenharmony_ci } while (offset < size); 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic void wilc_wlan_handle_rxq(struct wilc *wilc) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci int size; 7318c2ecf20Sopenharmony_ci u8 *buffer; 7328c2ecf20Sopenharmony_ci struct rxq_entry_t *rqe; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci while (!wilc->quit) { 7358c2ecf20Sopenharmony_ci rqe = wilc_wlan_rxq_remove(wilc); 7368c2ecf20Sopenharmony_ci if (!rqe) 7378c2ecf20Sopenharmony_ci break; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci buffer = rqe->buffer; 7408c2ecf20Sopenharmony_ci size = rqe->buffer_size; 7418c2ecf20Sopenharmony_ci wilc_wlan_handle_rx_buff(wilc, buffer, size); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci kfree(rqe); 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci if (wilc->quit) 7468c2ecf20Sopenharmony_ci complete(&wilc->cfg_event); 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic void wilc_unknown_isr_ext(struct wilc *wilc) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci wilc->hif_func->hif_clear_int_ext(wilc, 0); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci u32 offset = wilc->rx_buffer_offset; 7578c2ecf20Sopenharmony_ci u8 *buffer = NULL; 7588c2ecf20Sopenharmony_ci u32 size; 7598c2ecf20Sopenharmony_ci u32 retries = 0; 7608c2ecf20Sopenharmony_ci int ret = 0; 7618c2ecf20Sopenharmony_ci struct rxq_entry_t *rqe; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci size = FIELD_GET(WILC_INTERRUPT_DATA_SIZE, int_status) << 2; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci while (!size && retries < 10) { 7668c2ecf20Sopenharmony_ci wilc->hif_func->hif_read_size(wilc, &size); 7678c2ecf20Sopenharmony_ci size = FIELD_GET(WILC_INTERRUPT_DATA_SIZE, size) << 2; 7688c2ecf20Sopenharmony_ci retries++; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (size <= 0) 7728c2ecf20Sopenharmony_ci return; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (WILC_RX_BUFF_SIZE - offset < size) 7758c2ecf20Sopenharmony_ci offset = 0; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci buffer = &wilc->rx_buffer[offset]; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci wilc->hif_func->hif_clear_int_ext(wilc, DATA_INT_CLR | ENABLE_RX_VMM); 7808c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_block_rx_ext(wilc, 0, buffer, size); 7818c2ecf20Sopenharmony_ci if (ret) 7828c2ecf20Sopenharmony_ci return; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci offset += size; 7858c2ecf20Sopenharmony_ci wilc->rx_buffer_offset = offset; 7868c2ecf20Sopenharmony_ci rqe = kmalloc(sizeof(*rqe), GFP_KERNEL); 7878c2ecf20Sopenharmony_ci if (!rqe) 7888c2ecf20Sopenharmony_ci return; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci rqe->buffer = buffer; 7918c2ecf20Sopenharmony_ci rqe->buffer_size = size; 7928c2ecf20Sopenharmony_ci wilc_wlan_rxq_add(wilc, rqe); 7938c2ecf20Sopenharmony_ci wilc_wlan_handle_rxq(wilc); 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_civoid wilc_handle_isr(struct wilc *wilc) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci u32 int_status; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); 8018c2ecf20Sopenharmony_ci wilc->hif_func->hif_read_int(wilc, &int_status); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (int_status & DATA_INT_EXT) 8048c2ecf20Sopenharmony_ci wilc_wlan_handle_isr_ext(wilc, int_status); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (!(int_status & (ALL_INT_EXT))) 8078c2ecf20Sopenharmony_ci wilc_unknown_isr_ext(wilc); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wilc_handle_isr); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ciint wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, 8148c2ecf20Sopenharmony_ci u32 buffer_size) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci u32 offset; 8178c2ecf20Sopenharmony_ci u32 addr, size, size2, blksz; 8188c2ecf20Sopenharmony_ci u8 *dma_buffer; 8198c2ecf20Sopenharmony_ci int ret = 0; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci blksz = BIT(12); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci dma_buffer = kmalloc(blksz, GFP_KERNEL); 8248c2ecf20Sopenharmony_ci if (!dma_buffer) 8258c2ecf20Sopenharmony_ci return -EIO; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci offset = 0; 8288c2ecf20Sopenharmony_ci do { 8298c2ecf20Sopenharmony_ci addr = get_unaligned_le32(&buffer[offset]); 8308c2ecf20Sopenharmony_ci size = get_unaligned_le32(&buffer[offset + 4]); 8318c2ecf20Sopenharmony_ci acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); 8328c2ecf20Sopenharmony_ci offset += 8; 8338c2ecf20Sopenharmony_ci while (((int)size) && (offset < buffer_size)) { 8348c2ecf20Sopenharmony_ci if (size <= blksz) 8358c2ecf20Sopenharmony_ci size2 = size; 8368c2ecf20Sopenharmony_ci else 8378c2ecf20Sopenharmony_ci size2 = blksz; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci memcpy(dma_buffer, &buffer[offset], size2); 8408c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_block_tx(wilc, addr, 8418c2ecf20Sopenharmony_ci dma_buffer, size2); 8428c2ecf20Sopenharmony_ci if (ret) 8438c2ecf20Sopenharmony_ci break; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci addr += size2; 8468c2ecf20Sopenharmony_ci offset += size2; 8478c2ecf20Sopenharmony_ci size -= size2; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ONLY); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (ret) 8528c2ecf20Sopenharmony_ci goto fail; 8538c2ecf20Sopenharmony_ci } while (offset < buffer_size); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cifail: 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci kfree(dma_buffer); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci return ret; 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ciint wilc_wlan_start(struct wilc *wilc) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci u32 reg = 0; 8658c2ecf20Sopenharmony_ci int ret; 8668c2ecf20Sopenharmony_ci u32 chipid; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (wilc->io_type == WILC_HIF_SDIO) { 8698c2ecf20Sopenharmony_ci reg = 0; 8708c2ecf20Sopenharmony_ci reg |= BIT(3); 8718c2ecf20Sopenharmony_ci } else if (wilc->io_type == WILC_HIF_SPI) { 8728c2ecf20Sopenharmony_ci reg = 1; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); 8758c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg); 8768c2ecf20Sopenharmony_ci if (ret) { 8778c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ONLY); 8788c2ecf20Sopenharmony_ci return ret; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci reg = 0; 8818c2ecf20Sopenharmony_ci if (wilc->io_type == WILC_HIF_SDIO && wilc->dev_irq_num) 8828c2ecf20Sopenharmony_ci reg |= WILC_HAVE_SDIO_IRQ_GPIO; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg); 8858c2ecf20Sopenharmony_ci if (ret) { 8868c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ONLY); 8878c2ecf20Sopenharmony_ci return ret; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid); 8938c2ecf20Sopenharmony_ci if (ret) { 8948c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ONLY); 8958c2ecf20Sopenharmony_ci return ret; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); 8998c2ecf20Sopenharmony_ci if ((reg & BIT(10)) == BIT(10)) { 9008c2ecf20Sopenharmony_ci reg &= ~BIT(10); 9018c2ecf20Sopenharmony_ci wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); 9028c2ecf20Sopenharmony_ci wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci reg |= BIT(10); 9068c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); 9078c2ecf20Sopenharmony_ci wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); 9088c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ONLY); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci return ret; 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ciint wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci u32 reg = 0; 9168c2ecf20Sopenharmony_ci int ret; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®); 9218c2ecf20Sopenharmony_ci if (ret) { 9228c2ecf20Sopenharmony_ci netdev_err(vif->ndev, "Error while reading reg\n"); 9238c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); 9248c2ecf20Sopenharmony_ci return ret; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0, 9288c2ecf20Sopenharmony_ci (reg | WILC_ABORT_REQ_BIT)); 9298c2ecf20Sopenharmony_ci if (ret) { 9308c2ecf20Sopenharmony_ci netdev_err(vif->ndev, "Error while writing reg\n"); 9318c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); 9328c2ecf20Sopenharmony_ci return ret; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, ®); 9368c2ecf20Sopenharmony_ci if (ret) { 9378c2ecf20Sopenharmony_ci netdev_err(vif->ndev, "Error while reading reg\n"); 9388c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); 9398c2ecf20Sopenharmony_ci return ret; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci reg = BIT(0); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg); 9448c2ecf20Sopenharmony_ci if (ret) { 9458c2ecf20Sopenharmony_ci netdev_err(vif->ndev, "Error while writing reg\n"); 9468c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); 9478c2ecf20Sopenharmony_ci return ret; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci return 0; 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_civoid wilc_wlan_cleanup(struct net_device *dev) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci struct txq_entry_t *tqe; 9588c2ecf20Sopenharmony_ci struct rxq_entry_t *rqe; 9598c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 9608c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci wilc->quit = 1; 9638c2ecf20Sopenharmony_ci while ((tqe = wilc_wlan_txq_remove_from_head(dev))) { 9648c2ecf20Sopenharmony_ci if (tqe->tx_complete_func) 9658c2ecf20Sopenharmony_ci tqe->tx_complete_func(tqe->priv, 0); 9668c2ecf20Sopenharmony_ci kfree(tqe); 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci while ((rqe = wilc_wlan_rxq_remove(wilc))) 9708c2ecf20Sopenharmony_ci kfree(rqe); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci kfree(wilc->rx_buffer); 9738c2ecf20Sopenharmony_ci wilc->rx_buffer = NULL; 9748c2ecf20Sopenharmony_ci kfree(wilc->tx_buffer); 9758c2ecf20Sopenharmony_ci wilc->tx_buffer = NULL; 9768c2ecf20Sopenharmony_ci wilc->hif_func->hif_deinit(NULL); 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic int wilc_wlan_cfg_commit(struct wilc_vif *vif, int type, 9808c2ecf20Sopenharmony_ci u32 drv_handler) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 9838c2ecf20Sopenharmony_ci struct wilc_cfg_frame *cfg = &wilc->cfg_frame; 9848c2ecf20Sopenharmony_ci int t_len = wilc->cfg_frame_offset + sizeof(struct wilc_cfg_cmd_hdr); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (type == WILC_CFG_SET) 9878c2ecf20Sopenharmony_ci cfg->hdr.cmd_type = 'W'; 9888c2ecf20Sopenharmony_ci else 9898c2ecf20Sopenharmony_ci cfg->hdr.cmd_type = 'Q'; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci cfg->hdr.seq_no = wilc->cfg_seq_no % 256; 9928c2ecf20Sopenharmony_ci cfg->hdr.total_len = cpu_to_le16(t_len); 9938c2ecf20Sopenharmony_ci cfg->hdr.driver_handler = cpu_to_le32(drv_handler); 9948c2ecf20Sopenharmony_ci wilc->cfg_seq_no = cfg->hdr.seq_no; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (!wilc_wlan_txq_add_cfg_pkt(vif, (u8 *)&cfg->hdr, t_len)) 9978c2ecf20Sopenharmony_ci return -1; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci return 0; 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ciint wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer, 10038c2ecf20Sopenharmony_ci u32 buffer_size, int commit, u32 drv_handler) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci u32 offset; 10068c2ecf20Sopenharmony_ci int ret_size; 10078c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci mutex_lock(&wilc->cfg_cmd_lock); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (start) 10128c2ecf20Sopenharmony_ci wilc->cfg_frame_offset = 0; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci offset = wilc->cfg_frame_offset; 10158c2ecf20Sopenharmony_ci ret_size = wilc_wlan_cfg_set_wid(wilc->cfg_frame.frame, offset, 10168c2ecf20Sopenharmony_ci wid, buffer, buffer_size); 10178c2ecf20Sopenharmony_ci offset += ret_size; 10188c2ecf20Sopenharmony_ci wilc->cfg_frame_offset = offset; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (!commit) { 10218c2ecf20Sopenharmony_ci mutex_unlock(&wilc->cfg_cmd_lock); 10228c2ecf20Sopenharmony_ci return ret_size; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci netdev_dbg(vif->ndev, "%s: seqno[%d]\n", __func__, wilc->cfg_seq_no); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler)) 10288c2ecf20Sopenharmony_ci ret_size = 0; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&wilc->cfg_event, 10318c2ecf20Sopenharmony_ci WILC_CFG_PKTS_TIMEOUT)) { 10328c2ecf20Sopenharmony_ci netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__); 10338c2ecf20Sopenharmony_ci ret_size = 0; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci wilc->cfg_frame_offset = 0; 10378c2ecf20Sopenharmony_ci wilc->cfg_seq_no += 1; 10388c2ecf20Sopenharmony_ci mutex_unlock(&wilc->cfg_cmd_lock); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci return ret_size; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ciint wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit, 10448c2ecf20Sopenharmony_ci u32 drv_handler) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci u32 offset; 10478c2ecf20Sopenharmony_ci int ret_size; 10488c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci mutex_lock(&wilc->cfg_cmd_lock); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (start) 10538c2ecf20Sopenharmony_ci wilc->cfg_frame_offset = 0; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci offset = wilc->cfg_frame_offset; 10568c2ecf20Sopenharmony_ci ret_size = wilc_wlan_cfg_get_wid(wilc->cfg_frame.frame, offset, wid); 10578c2ecf20Sopenharmony_ci offset += ret_size; 10588c2ecf20Sopenharmony_ci wilc->cfg_frame_offset = offset; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (!commit) { 10618c2ecf20Sopenharmony_ci mutex_unlock(&wilc->cfg_cmd_lock); 10628c2ecf20Sopenharmony_ci return ret_size; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler)) 10668c2ecf20Sopenharmony_ci ret_size = 0; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&wilc->cfg_event, 10698c2ecf20Sopenharmony_ci WILC_CFG_PKTS_TIMEOUT)) { 10708c2ecf20Sopenharmony_ci netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__); 10718c2ecf20Sopenharmony_ci ret_size = 0; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci wilc->cfg_frame_offset = 0; 10748c2ecf20Sopenharmony_ci wilc->cfg_seq_no += 1; 10758c2ecf20Sopenharmony_ci mutex_unlock(&wilc->cfg_cmd_lock); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return ret_size; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ciint wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, 10818c2ecf20Sopenharmony_ci u32 count) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci int i; 10848c2ecf20Sopenharmony_ci int ret = 0; 10858c2ecf20Sopenharmony_ci u32 drv = wilc_get_vif_idx(vif); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (mode == WILC_GET_CFG) { 10888c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 10898c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_get(vif, !i, 10908c2ecf20Sopenharmony_ci wids[i].id, 10918c2ecf20Sopenharmony_ci (i == count - 1), 10928c2ecf20Sopenharmony_ci drv)) { 10938c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 10948c2ecf20Sopenharmony_ci break; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 10988c2ecf20Sopenharmony_ci wids[i].size = wilc_wlan_cfg_get_val(vif->wilc, 10998c2ecf20Sopenharmony_ci wids[i].id, 11008c2ecf20Sopenharmony_ci wids[i].val, 11018c2ecf20Sopenharmony_ci wids[i].size); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci } else if (mode == WILC_SET_CFG) { 11048c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 11058c2ecf20Sopenharmony_ci if (!wilc_wlan_cfg_set(vif, !i, 11068c2ecf20Sopenharmony_ci wids[i].id, 11078c2ecf20Sopenharmony_ci wids[i].val, 11088c2ecf20Sopenharmony_ci wids[i].size, 11098c2ecf20Sopenharmony_ci (i == count - 1), 11108c2ecf20Sopenharmony_ci drv)) { 11118c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 11128c2ecf20Sopenharmony_ci break; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci return ret; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic int init_chip(struct net_device *dev) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci u32 chipid; 11238c2ecf20Sopenharmony_ci u32 reg; 11248c2ecf20Sopenharmony_ci int ret = 0; 11258c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 11268c2ecf20Sopenharmony_ci struct wilc *wilc = vif->wilc; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci chipid = wilc_get_chipid(wilc, true); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if ((chipid & 0xfff) != 0xa0) { 11338c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_read_reg(wilc, 11348c2ecf20Sopenharmony_ci WILC_CORTUS_RESET_MUX_SEL, 11358c2ecf20Sopenharmony_ci ®); 11368c2ecf20Sopenharmony_ci if (ret) { 11378c2ecf20Sopenharmony_ci netdev_err(dev, "fail read reg 0x1118\n"); 11388c2ecf20Sopenharmony_ci goto release; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci reg |= BIT(0); 11418c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_write_reg(wilc, 11428c2ecf20Sopenharmony_ci WILC_CORTUS_RESET_MUX_SEL, 11438c2ecf20Sopenharmony_ci reg); 11448c2ecf20Sopenharmony_ci if (ret) { 11458c2ecf20Sopenharmony_ci netdev_err(dev, "fail write reg 0x1118\n"); 11468c2ecf20Sopenharmony_ci goto release; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci ret = wilc->hif_func->hif_write_reg(wilc, 11498c2ecf20Sopenharmony_ci WILC_CORTUS_BOOT_REGISTER, 11508c2ecf20Sopenharmony_ci WILC_CORTUS_BOOT_FROM_IRAM); 11518c2ecf20Sopenharmony_ci if (ret) { 11528c2ecf20Sopenharmony_ci netdev_err(dev, "fail write reg 0xc0000\n"); 11538c2ecf20Sopenharmony_ci goto release; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_cirelease: 11588c2ecf20Sopenharmony_ci release_bus(wilc, WILC_BUS_RELEASE_ONLY); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci return ret; 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ciu32 wilc_get_chipid(struct wilc *wilc, bool update) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci static u32 chipid; 11668c2ecf20Sopenharmony_ci u32 tempchipid = 0; 11678c2ecf20Sopenharmony_ci u32 rfrevid = 0; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (chipid == 0 || update) { 11708c2ecf20Sopenharmony_ci wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &tempchipid); 11718c2ecf20Sopenharmony_ci wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID, 11728c2ecf20Sopenharmony_ci &rfrevid); 11738c2ecf20Sopenharmony_ci if (!is_wilc1000(tempchipid)) { 11748c2ecf20Sopenharmony_ci chipid = 0; 11758c2ecf20Sopenharmony_ci return chipid; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci if (tempchipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */ 11788c2ecf20Sopenharmony_ci if (rfrevid != 0x1) 11798c2ecf20Sopenharmony_ci tempchipid = WILC_1000_BASE_ID_2A_REV1; 11808c2ecf20Sopenharmony_ci } else if (tempchipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */ 11818c2ecf20Sopenharmony_ci if (rfrevid == 0x4) 11828c2ecf20Sopenharmony_ci tempchipid = WILC_1000_BASE_ID_2B_REV1; 11838c2ecf20Sopenharmony_ci else if (rfrevid != 0x3) 11848c2ecf20Sopenharmony_ci tempchipid = WILC_1000_BASE_ID_2B_REV2; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci chipid = tempchipid; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci return chipid; 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ciint wilc_wlan_init(struct net_device *dev) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci int ret = 0; 11958c2ecf20Sopenharmony_ci struct wilc_vif *vif = netdev_priv(dev); 11968c2ecf20Sopenharmony_ci struct wilc *wilc; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci wilc = vif->wilc; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci wilc->quit = 0; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (wilc->hif_func->hif_init(wilc, false)) { 12038c2ecf20Sopenharmony_ci ret = -EIO; 12048c2ecf20Sopenharmony_ci goto fail; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (!wilc->tx_buffer) 12088c2ecf20Sopenharmony_ci wilc->tx_buffer = kmalloc(WILC_TX_BUFF_SIZE, GFP_KERNEL); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (!wilc->tx_buffer) { 12118c2ecf20Sopenharmony_ci ret = -ENOBUFS; 12128c2ecf20Sopenharmony_ci goto fail; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (!wilc->rx_buffer) 12168c2ecf20Sopenharmony_ci wilc->rx_buffer = kmalloc(WILC_RX_BUFF_SIZE, GFP_KERNEL); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (!wilc->rx_buffer) { 12198c2ecf20Sopenharmony_ci ret = -ENOBUFS; 12208c2ecf20Sopenharmony_ci goto fail; 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci if (init_chip(dev)) { 12248c2ecf20Sopenharmony_ci ret = -EIO; 12258c2ecf20Sopenharmony_ci goto fail; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci return 0; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cifail: 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci kfree(wilc->rx_buffer); 12338c2ecf20Sopenharmony_ci wilc->rx_buffer = NULL; 12348c2ecf20Sopenharmony_ci kfree(wilc->tx_buffer); 12358c2ecf20Sopenharmony_ci wilc->tx_buffer = NULL; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci return ret; 12388c2ecf20Sopenharmony_ci} 1239