1584 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.4 * All rights reserved.5 */6 7#include <linux/if_ether.h>8#include <linux/ip.h>9#include <net/dsfield.h>10#include "cfg80211.h"11#include "wlan_cfg.h"12 13#define WAKE_UP_TRIAL_RETRY 1000014 15static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire)16{17 mutex_lock(&wilc->hif_cs);18 if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode)19 chip_wakeup(wilc);20}21 22static inline void release_bus(struct wilc *wilc, enum bus_release release)23{24 if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode)25 chip_allow_sleep(wilc);26 mutex_unlock(&wilc->hif_cs);27}28 29static void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num,30 struct txq_entry_t *tqe)31{32 list_del(&tqe->list);33 wilc->txq_entries -= 1;34 wilc->txq[q_num].count--;35}36 37static struct txq_entry_t *38wilc_wlan_txq_remove_from_head(struct wilc *wilc, u8 q_num)39{40 struct txq_entry_t *tqe = NULL;41 unsigned long flags;42 43 spin_lock_irqsave(&wilc->txq_spinlock, flags);44 45 if (!list_empty(&wilc->txq[q_num].txq_head.list)) {46 tqe = list_first_entry(&wilc->txq[q_num].txq_head.list,47 struct txq_entry_t, list);48 list_del(&tqe->list);49 wilc->txq_entries -= 1;50 wilc->txq[q_num].count--;51 }52 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);53 return tqe;54}55 56static void wilc_wlan_txq_add_to_tail(struct net_device *dev, u8 q_num,57 struct txq_entry_t *tqe)58{59 unsigned long flags;60 struct wilc_vif *vif = netdev_priv(dev);61 struct wilc *wilc = vif->wilc;62 63 spin_lock_irqsave(&wilc->txq_spinlock, flags);64 65 list_add_tail(&tqe->list, &wilc->txq[q_num].txq_head.list);66 wilc->txq_entries += 1;67 wilc->txq[q_num].count++;68 69 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);70 71 complete(&wilc->txq_event);72}73 74static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, u8 q_num,75 struct txq_entry_t *tqe)76{77 unsigned long flags;78 struct wilc *wilc = vif->wilc;79 80 mutex_lock(&wilc->txq_add_to_head_cs);81 82 spin_lock_irqsave(&wilc->txq_spinlock, flags);83 84 list_add(&tqe->list, &wilc->txq[q_num].txq_head.list);85 wilc->txq_entries += 1;86 wilc->txq[q_num].count++;87 88 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);89 mutex_unlock(&wilc->txq_add_to_head_cs);90 complete(&wilc->txq_event);91}92 93#define NOT_TCP_ACK (-1)94 95static inline void add_tcp_session(struct wilc_vif *vif, u32 src_prt,96 u32 dst_prt, u32 seq)97{98 struct tcp_ack_filter *f = &vif->ack_filter;99 100 if (f->tcp_session < 2 * MAX_TCP_SESSION) {101 f->ack_session_info[f->tcp_session].seq_num = seq;102 f->ack_session_info[f->tcp_session].bigger_ack_num = 0;103 f->ack_session_info[f->tcp_session].src_port = src_prt;104 f->ack_session_info[f->tcp_session].dst_port = dst_prt;105 f->tcp_session++;106 }107}108 109static inline void update_tcp_session(struct wilc_vif *vif, u32 index, u32 ack)110{111 struct tcp_ack_filter *f = &vif->ack_filter;112 113 if (index < 2 * MAX_TCP_SESSION &&114 ack > f->ack_session_info[index].bigger_ack_num)115 f->ack_session_info[index].bigger_ack_num = ack;116}117 118static inline void add_tcp_pending_ack(struct wilc_vif *vif, u32 ack,119 u32 session_index,120 struct txq_entry_t *txqe)121{122 struct tcp_ack_filter *f = &vif->ack_filter;123 u32 i = f->pending_base + f->pending_acks_idx;124 125 if (i < MAX_PENDING_ACKS) {126 f->pending_acks[i].ack_num = ack;127 f->pending_acks[i].txqe = txqe;128 f->pending_acks[i].session_index = session_index;129 txqe->ack_idx = i;130 f->pending_acks_idx++;131 }132}133 134static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)135{136 void *buffer = tqe->buffer;137 const struct ethhdr *eth_hdr_ptr = buffer;138 int i;139 unsigned long flags;140 struct wilc_vif *vif = netdev_priv(dev);141 struct wilc *wilc = vif->wilc;142 struct tcp_ack_filter *f = &vif->ack_filter;143 const struct iphdr *ip_hdr_ptr;144 const struct tcphdr *tcp_hdr_ptr;145 u32 ihl, total_length, data_offset;146 147 spin_lock_irqsave(&wilc->txq_spinlock, flags);148 149 if (eth_hdr_ptr->h_proto != htons(ETH_P_IP))150 goto out;151 152 ip_hdr_ptr = buffer + ETH_HLEN;153 154 if (ip_hdr_ptr->protocol != IPPROTO_TCP)155 goto out;156 157 ihl = ip_hdr_ptr->ihl << 2;158 tcp_hdr_ptr = buffer + ETH_HLEN + ihl;159 total_length = ntohs(ip_hdr_ptr->tot_len);160 161 data_offset = tcp_hdr_ptr->doff << 2;162 if (total_length == (ihl + data_offset)) {163 u32 seq_no, ack_no;164 165 seq_no = ntohl(tcp_hdr_ptr->seq);166 ack_no = ntohl(tcp_hdr_ptr->ack_seq);167 for (i = 0; i < f->tcp_session; i++) {168 u32 j = f->ack_session_info[i].seq_num;169 170 if (i < 2 * MAX_TCP_SESSION &&171 j == seq_no) {172 update_tcp_session(vif, i, ack_no);173 break;174 }175 }176 if (i == f->tcp_session)177 add_tcp_session(vif, 0, 0, seq_no);178 179 add_tcp_pending_ack(vif, ack_no, i, tqe);180 }181 182out:183 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);184}185 186static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)187{188 struct wilc_vif *vif = netdev_priv(dev);189 struct wilc *wilc = vif->wilc;190 struct tcp_ack_filter *f = &vif->ack_filter;191 u32 i = 0;192 u32 dropped = 0;193 unsigned long flags;194 195 spin_lock_irqsave(&wilc->txq_spinlock, flags);196 for (i = f->pending_base;197 i < (f->pending_base + f->pending_acks_idx); i++) {198 u32 index;199 u32 bigger_ack_num;200 201 if (i >= MAX_PENDING_ACKS)202 break;203 204 index = f->pending_acks[i].session_index;205 206 if (index >= 2 * MAX_TCP_SESSION)207 break;208 209 bigger_ack_num = f->ack_session_info[index].bigger_ack_num;210 211 if (f->pending_acks[i].ack_num < bigger_ack_num) {212 struct txq_entry_t *tqe;213 214 tqe = f->pending_acks[i].txqe;215 if (tqe) {216 wilc_wlan_txq_remove(wilc, tqe->q_num, tqe);217 tqe->status = 1;218 if (tqe->tx_complete_func)219 tqe->tx_complete_func(tqe->priv,220 tqe->status);221 kfree(tqe);222 dropped++;223 }224 }225 }226 f->pending_acks_idx = 0;227 f->tcp_session = 0;228 229 if (f->pending_base == 0)230 f->pending_base = MAX_TCP_SESSION;231 else232 f->pending_base = 0;233 234 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);235 236 while (dropped > 0) {237 wait_for_completion_timeout(&wilc->txq_event,238 msecs_to_jiffies(1));239 dropped--;240 }241}242 243void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value)244{245 vif->ack_filter.enabled = value;246}247 248static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer,249 u32 buffer_size)250{251 struct txq_entry_t *tqe;252 struct wilc *wilc = vif->wilc;253 254 netdev_dbg(vif->ndev, "Adding config packet ...\n");255 if (wilc->quit) {256 netdev_dbg(vif->ndev, "Return due to clear function\n");257 complete(&wilc->cfg_event);258 return 0;259 }260 261 tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);262 if (!tqe) {263 complete(&wilc->cfg_event);264 return 0;265 }266 267 tqe->type = WILC_CFG_PKT;268 tqe->buffer = buffer;269 tqe->buffer_size = buffer_size;270 tqe->tx_complete_func = NULL;271 tqe->priv = NULL;272 tqe->q_num = AC_VO_Q;273 tqe->ack_idx = NOT_TCP_ACK;274 tqe->vif = vif;275 276 wilc_wlan_txq_add_to_head(vif, AC_VO_Q, tqe);277 278 return 1;279}280 281static bool is_ac_q_limit(struct wilc *wl, u8 q_num)282{283 u8 factors[NQUEUES] = {1, 1, 1, 1};284 u16 i;285 unsigned long flags;286 struct wilc_tx_queue_status *q = &wl->tx_q_limit;287 u8 end_index;288 u8 q_limit;289 bool ret = false;290 291 spin_lock_irqsave(&wl->txq_spinlock, flags);292 if (!q->initialized) {293 for (i = 0; i < AC_BUFFER_SIZE; i++)294 q->buffer[i] = i % NQUEUES;295 296 for (i = 0; i < NQUEUES; i++) {297 q->cnt[i] = AC_BUFFER_SIZE * factors[i] / NQUEUES;298 q->sum += q->cnt[i];299 }300 q->end_index = AC_BUFFER_SIZE - 1;301 q->initialized = 1;302 }303 304 end_index = q->end_index;305 q->cnt[q->buffer[end_index]] -= factors[q->buffer[end_index]];306 q->cnt[q_num] += factors[q_num];307 q->sum += (factors[q_num] - factors[q->buffer[end_index]]);308 309 q->buffer[end_index] = q_num;310 if (end_index > 0)311 q->end_index--;312 else313 q->end_index = AC_BUFFER_SIZE - 1;314 315 if (!q->sum)316 q_limit = 1;317 else318 q_limit = (q->cnt[q_num] * FLOW_CONTROL_UPPER_THRESHOLD / q->sum) + 1;319 320 if (wl->txq[q_num].count <= q_limit)321 ret = true;322 323 spin_unlock_irqrestore(&wl->txq_spinlock, flags);324 325 return ret;326}327 328static inline u8 ac_classify(struct wilc *wilc, struct sk_buff *skb)329{330 u8 q_num = AC_BE_Q;331 u8 dscp;332 333 switch (skb->protocol) {334 case htons(ETH_P_IP):335 dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc;336 break;337 case htons(ETH_P_IPV6):338 dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc;339 break;340 default:341 return q_num;342 }343 344 switch (dscp) {345 case 0x08:346 case 0x20:347 case 0x40:348 q_num = AC_BK_Q;349 break;350 case 0x80:351 case 0xA0:352 case 0x28:353 q_num = AC_VI_Q;354 break;355 case 0xC0:356 case 0xD0:357 case 0xE0:358 case 0x88:359 case 0xB8:360 q_num = AC_VO_Q;361 break;362 }363 364 return q_num;365}366 367static inline int ac_balance(struct wilc *wl, u8 *ratio)368{369 u8 i, max_count = 0;370 371 if (!ratio)372 return -EINVAL;373 374 for (i = 0; i < NQUEUES; i++)375 if (wl->txq[i].fw.count > max_count)376 max_count = wl->txq[i].fw.count;377 378 for (i = 0; i < NQUEUES; i++)379 ratio[i] = max_count - wl->txq[i].fw.count;380 381 return 0;382}383 384static inline void ac_update_fw_ac_pkt_info(struct wilc *wl, u32 reg)385{386 wl->txq[AC_BK_Q].fw.count = FIELD_GET(BK_AC_COUNT_FIELD, reg);387 wl->txq[AC_BE_Q].fw.count = FIELD_GET(BE_AC_COUNT_FIELD, reg);388 wl->txq[AC_VI_Q].fw.count = FIELD_GET(VI_AC_COUNT_FIELD, reg);389 wl->txq[AC_VO_Q].fw.count = FIELD_GET(VO_AC_COUNT_FIELD, reg);390 391 wl->txq[AC_BK_Q].fw.acm = FIELD_GET(BK_AC_ACM_STAT_FIELD, reg);392 wl->txq[AC_BE_Q].fw.acm = FIELD_GET(BE_AC_ACM_STAT_FIELD, reg);393 wl->txq[AC_VI_Q].fw.acm = FIELD_GET(VI_AC_ACM_STAT_FIELD, reg);394 wl->txq[AC_VO_Q].fw.acm = FIELD_GET(VO_AC_ACM_STAT_FIELD, reg);395}396 397static inline u8 ac_change(struct wilc *wilc, u8 *ac)398{399 do {400 if (wilc->txq[*ac].fw.acm == 0)401 return 0;402 (*ac)++;403 } while (*ac < NQUEUES);404 405 return 1;406}407 408int wilc_wlan_txq_add_net_pkt(struct net_device *dev,409 struct tx_complete_data *tx_data, u8 *buffer,410 u32 buffer_size,411 void (*tx_complete_fn)(void *, int))412{413 struct txq_entry_t *tqe;414 struct wilc_vif *vif = netdev_priv(dev);415 struct wilc *wilc;416 u8 q_num;417 418 wilc = vif->wilc;419 420 if (wilc->quit) {421 tx_complete_fn(tx_data, 0);422 return 0;423 }424 425 if (!wilc->initialized) {426 tx_complete_fn(tx_data, 0);427 return 0;428 }429 430 tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);431 432 if (!tqe) {433 tx_complete_fn(tx_data, 0);434 return 0;435 }436 tqe->type = WILC_NET_PKT;437 tqe->buffer = buffer;438 tqe->buffer_size = buffer_size;439 tqe->tx_complete_func = tx_complete_fn;440 tqe->priv = tx_data;441 tqe->vif = vif;442 443 q_num = ac_classify(wilc, tx_data->skb);444 tqe->q_num = q_num;445 if (ac_change(wilc, &q_num)) {446 tx_complete_fn(tx_data, 0);447 kfree(tqe);448 return 0;449 }450 451 if (is_ac_q_limit(wilc, q_num)) {452 tqe->ack_idx = NOT_TCP_ACK;453 if (vif->ack_filter.enabled)454 tcp_process(dev, tqe);455 wilc_wlan_txq_add_to_tail(dev, q_num, tqe);456 } else {457 tx_complete_fn(tx_data, 0);458 kfree(tqe);459 }460 461 return wilc->txq_entries;462}463 464int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,465 u32 buffer_size,466 void (*tx_complete_fn)(void *, int))467{468 struct txq_entry_t *tqe;469 struct wilc_vif *vif = netdev_priv(dev);470 struct wilc *wilc;471 472 wilc = vif->wilc;473 474 if (wilc->quit) {475 tx_complete_fn(priv, 0);476 return 0;477 }478 479 if (!wilc->initialized) {480 tx_complete_fn(priv, 0);481 return 0;482 }483 tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);484 485 if (!tqe) {486 tx_complete_fn(priv, 0);487 return 0;488 }489 tqe->type = WILC_MGMT_PKT;490 tqe->buffer = buffer;491 tqe->buffer_size = buffer_size;492 tqe->tx_complete_func = tx_complete_fn;493 tqe->priv = priv;494 tqe->q_num = AC_BE_Q;495 tqe->ack_idx = NOT_TCP_ACK;496 tqe->vif = vif;497 wilc_wlan_txq_add_to_tail(dev, AC_VO_Q, tqe);498 return 1;499}500 501static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc, u8 q_num)502{503 struct txq_entry_t *tqe = NULL;504 unsigned long flags;505 506 spin_lock_irqsave(&wilc->txq_spinlock, flags);507 508 if (!list_empty(&wilc->txq[q_num].txq_head.list))509 tqe = list_first_entry(&wilc->txq[q_num].txq_head.list,510 struct txq_entry_t, list);511 512 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);513 514 return tqe;515}516 517static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,518 struct txq_entry_t *tqe,519 u8 q_num)520{521 unsigned long flags;522 523 spin_lock_irqsave(&wilc->txq_spinlock, flags);524 525 if (!list_is_last(&tqe->list, &wilc->txq[q_num].txq_head.list))526 tqe = list_next_entry(tqe, list);527 else528 tqe = NULL;529 spin_unlock_irqrestore(&wilc->txq_spinlock, flags);530 531 return tqe;532}533 534static void wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe)535{536 if (wilc->quit)537 return;538 539 mutex_lock(&wilc->rxq_cs);540 list_add_tail(&rqe->list, &wilc->rxq_head.list);541 mutex_unlock(&wilc->rxq_cs);542}543 544static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)545{546 struct rxq_entry_t *rqe = NULL;547 548 mutex_lock(&wilc->rxq_cs);549 if (!list_empty(&wilc->rxq_head.list)) {550 rqe = list_first_entry(&wilc->rxq_head.list, struct rxq_entry_t,551 list);552 list_del(&rqe->list);553 }554 mutex_unlock(&wilc->rxq_cs);555 return rqe;556}557 558void chip_allow_sleep(struct wilc *wilc)559{560 u32 reg = 0;561 const struct wilc_hif_func *hif_func = wilc->hif_func;562 u32 wakeup_reg, wakeup_bit;563 u32 to_host_from_fw_reg, to_host_from_fw_bit;564 u32 from_host_to_fw_reg, from_host_to_fw_bit;565 u32 trials = 100;566 int ret;567 568 if (wilc->io_type == WILC_HIF_SDIO) {569 wakeup_reg = WILC_SDIO_WAKEUP_REG;570 wakeup_bit = WILC_SDIO_WAKEUP_BIT;571 from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG;572 from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT;573 to_host_from_fw_reg = WILC_SDIO_FW_TO_HOST_REG;574 to_host_from_fw_bit = WILC_SDIO_FW_TO_HOST_BIT;575 } else {576 wakeup_reg = WILC_SPI_WAKEUP_REG;577 wakeup_bit = WILC_SPI_WAKEUP_BIT;578 from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG;579 from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT;580 to_host_from_fw_reg = WILC_SPI_FW_TO_HOST_REG;581 to_host_from_fw_bit = WILC_SPI_FW_TO_HOST_BIT;582 }583 584 while (--trials) {585 ret = hif_func->hif_read_reg(wilc, to_host_from_fw_reg, ®);586 if (ret)587 return;588 if ((reg & to_host_from_fw_bit) == 0)589 break;590 }591 if (!trials)592 pr_warn("FW not responding\n");593 594 /* Clear bit 1 */595 ret = hif_func->hif_read_reg(wilc, wakeup_reg, ®);596 if (ret)597 return;598 if (reg & wakeup_bit) {599 reg &= ~wakeup_bit;600 ret = hif_func->hif_write_reg(wilc, wakeup_reg, reg);601 if (ret)602 return;603 }604 605 ret = hif_func->hif_read_reg(wilc, from_host_to_fw_reg, ®);606 if (ret)607 return;608 if (reg & from_host_to_fw_bit) {609 reg &= ~from_host_to_fw_bit;610 ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, reg);611 if (ret)612 return;613 614 }615}616EXPORT_SYMBOL_GPL(chip_allow_sleep);617 618void chip_wakeup(struct wilc *wilc)619{620 u32 ret = 0;621 u32 clk_status_val = 0, trials = 0;622 u32 wakeup_reg, wakeup_bit;623 u32 clk_status_reg, clk_status_bit;624 u32 from_host_to_fw_reg, from_host_to_fw_bit;625 const struct wilc_hif_func *hif_func = wilc->hif_func;626 627 if (wilc->io_type == WILC_HIF_SDIO) {628 wakeup_reg = WILC_SDIO_WAKEUP_REG;629 wakeup_bit = WILC_SDIO_WAKEUP_BIT;630 clk_status_reg = WILC_SDIO_CLK_STATUS_REG;631 clk_status_bit = WILC_SDIO_CLK_STATUS_BIT;632 from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG;633 from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT;634 } else {635 wakeup_reg = WILC_SPI_WAKEUP_REG;636 wakeup_bit = WILC_SPI_WAKEUP_BIT;637 clk_status_reg = WILC_SPI_CLK_STATUS_REG;638 clk_status_bit = WILC_SPI_CLK_STATUS_BIT;639 from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG;640 from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT;641 }642 643 /* indicate host wakeup */644 ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg,645 from_host_to_fw_bit);646 if (ret)647 return;648 649 /* Set wake-up bit */650 ret = hif_func->hif_write_reg(wilc, wakeup_reg,651 wakeup_bit);652 if (ret)653 return;654 655 while (trials < WAKE_UP_TRIAL_RETRY) {656 ret = hif_func->hif_read_reg(wilc, clk_status_reg,657 &clk_status_val);658 if (ret) {659 pr_err("Bus error %d %x\n", ret, clk_status_val);660 return;661 }662 if (clk_status_val & clk_status_bit)663 break;664 665 trials++;666 }667 if (trials >= WAKE_UP_TRIAL_RETRY) {668 pr_err("Failed to wake-up the chip\n");669 return;670 }671 /* Sometimes spi fail to read clock regs after reading672 * writing clockless registers673 */674 if (wilc->io_type == WILC_HIF_SPI)675 wilc->hif_func->hif_reset(wilc);676}677EXPORT_SYMBOL_GPL(chip_wakeup);678 679void host_wakeup_notify(struct wilc *wilc)680{681 acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);682 wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_2, 1);683 release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);684}685EXPORT_SYMBOL_GPL(host_wakeup_notify);686 687void host_sleep_notify(struct wilc *wilc)688{689 acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);690 wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_1, 1);691 release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);692}693EXPORT_SYMBOL_GPL(host_sleep_notify);694 695int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)696{697 int i, entries = 0;698 u8 k, ac;699 u32 sum;700 u32 reg;701 u8 ac_desired_ratio[NQUEUES] = {0, 0, 0, 0};702 u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1};703 u8 *num_pkts_to_add;704 u8 vmm_entries_ac[WILC_VMM_TBL_SIZE];705 u32 offset = 0;706 bool max_size_over = 0, ac_exist = 0;707 int vmm_sz = 0;708 struct txq_entry_t *tqe_q[NQUEUES];709 int ret = 0;710 int counter;711 int timeout;712 u32 *vmm_table = wilc->vmm_table;713 u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0};714 const struct wilc_hif_func *func;715 int srcu_idx;716 u8 *txb = wilc->tx_buffer;717 struct wilc_vif *vif;718 719 if (wilc->quit)720 goto out_update_cnt;721 722 if (ac_balance(wilc, ac_desired_ratio))723 return -EINVAL;724 725 mutex_lock(&wilc->txq_add_to_head_cs);726 727 srcu_idx = srcu_read_lock(&wilc->srcu);728 wilc_for_each_vif(wilc, vif)729 wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev);730 srcu_read_unlock(&wilc->srcu, srcu_idx);731 732 for (ac = 0; ac < NQUEUES; ac++)733 tqe_q[ac] = wilc_wlan_txq_get_first(wilc, ac);734 735 i = 0;736 sum = 0;737 max_size_over = 0;738 num_pkts_to_add = ac_desired_ratio;739 do {740 ac_exist = 0;741 for (ac = 0; (ac < NQUEUES) && (!max_size_over); ac++) {742 if (!tqe_q[ac])743 continue;744 745 ac_exist = 1;746 for (k = 0; (k < num_pkts_to_add[ac]) &&747 (!max_size_over) && tqe_q[ac]; k++) {748 if (i >= (WILC_VMM_TBL_SIZE - 1)) {749 max_size_over = 1;750 break;751 }752 753 if (tqe_q[ac]->type == WILC_CFG_PKT)754 vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;755 else if (tqe_q[ac]->type == WILC_NET_PKT)756 vmm_sz = ETH_ETHERNET_HDR_OFFSET;757 else758 vmm_sz = HOST_HDR_OFFSET;759 760 vmm_sz += tqe_q[ac]->buffer_size;761 vmm_sz = ALIGN(vmm_sz, 4);762 763 if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE) {764 max_size_over = 1;765 break;766 }767 vmm_table[i] = vmm_sz / 4;768 if (tqe_q[ac]->type == WILC_CFG_PKT)769 vmm_table[i] |= BIT(10);770 771 cpu_to_le32s(&vmm_table[i]);772 vmm_entries_ac[i] = ac;773 774 i++;775 sum += vmm_sz;776 tqe_q[ac] = wilc_wlan_txq_get_next(wilc,777 tqe_q[ac],778 ac);779 }780 }781 num_pkts_to_add = ac_preserve_ratio;782 } while (!max_size_over && ac_exist);783 784 if (i == 0)785 goto out_unlock;786 vmm_table[i] = 0x0;787 788 acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);789 counter = 0;790 func = wilc->hif_func;791 do {792 ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®);793 if (ret)794 break;795 796 if ((reg & 0x1) == 0) {797 ac_update_fw_ac_pkt_info(wilc, reg);798 break;799 }800 801 counter++;802 if (counter > 200) {803 counter = 0;804 ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0);805 break;806 }807 } while (!wilc->quit);808 809 if (ret)810 goto out_release_bus;811 812 timeout = 200;813 do {814 ret = func->hif_block_tx(wilc,815 WILC_VMM_TBL_RX_SHADOW_BASE,816 (u8 *)vmm_table,817 ((i + 1) * 4));818 if (ret)819 break;820 821 ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2);822 if (ret)823 break;824 825 do {826 ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®);827 if (ret)828 break;829 if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) {830 entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg);831 break;832 }833 } while (--timeout);834 if (timeout <= 0) {835 ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);836 break;837 }838 839 if (ret)840 break;841 842 if (entries == 0) {843 ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®);844 if (ret)845 break;846 reg &= ~BIT(0);847 ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);848 }849 } while (0);850 851 if (ret)852 goto out_release_bus;853 854 if (entries == 0) {855 /*856 * No VMM space available in firmware so retry to transmit857 * the packet from tx queue.858 */859 ret = WILC_VMM_ENTRY_FULL_RETRY;860 goto out_release_bus;861 }862 863 release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);864 865 offset = 0;866 i = 0;867 do {868 struct txq_entry_t *tqe;869 u32 header, buffer_offset;870 char *bssid;871 u8 mgmt_ptk = 0;872 873 if (vmm_table[i] == 0 || vmm_entries_ac[i] >= NQUEUES)874 break;875 876 tqe = wilc_wlan_txq_remove_from_head(wilc, vmm_entries_ac[i]);877 if (!tqe)878 break;879 880 ac_pkt_num_to_chip[vmm_entries_ac[i]]++;881 vif = tqe->vif;882 883 le32_to_cpus(&vmm_table[i]);884 vmm_sz = FIELD_GET(WILC_VMM_BUFFER_SIZE, vmm_table[i]);885 vmm_sz *= 4;886 887 if (tqe->type == WILC_MGMT_PKT)888 mgmt_ptk = 1;889 890 header = (FIELD_PREP(WILC_VMM_HDR_TYPE, tqe->type) |891 FIELD_PREP(WILC_VMM_HDR_MGMT_FIELD, mgmt_ptk) |892 FIELD_PREP(WILC_VMM_HDR_PKT_SIZE, tqe->buffer_size) |893 FIELD_PREP(WILC_VMM_HDR_BUFF_SIZE, vmm_sz));894 895 cpu_to_le32s(&header);896 memcpy(&txb[offset], &header, 4);897 if (tqe->type == WILC_CFG_PKT) {898 buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;899 } else if (tqe->type == WILC_NET_PKT) {900 int prio = tqe->q_num;901 902 bssid = tqe->vif->bssid;903 buffer_offset = ETH_ETHERNET_HDR_OFFSET;904 memcpy(&txb[offset + 4], &prio, sizeof(prio));905 memcpy(&txb[offset + 8], bssid, 6);906 } else {907 buffer_offset = HOST_HDR_OFFSET;908 }909 910 memcpy(&txb[offset + buffer_offset],911 tqe->buffer, tqe->buffer_size);912 offset += vmm_sz;913 i++;914 tqe->status = 1;915 if (tqe->tx_complete_func)916 tqe->tx_complete_func(tqe->priv, tqe->status);917 if (tqe->ack_idx != NOT_TCP_ACK &&918 tqe->ack_idx < MAX_PENDING_ACKS)919 vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL;920 kfree(tqe);921 } while (--entries);922 for (i = 0; i < NQUEUES; i++)923 wilc->txq[i].fw.count += ac_pkt_num_to_chip[i];924 925 acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);926 927 ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);928 if (ret)929 goto out_release_bus;930 931 ret = func->hif_block_tx_ext(wilc, 0, txb, offset);932 933out_release_bus:934 release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);935 936out_unlock:937 mutex_unlock(&wilc->txq_add_to_head_cs);938 939out_update_cnt:940 *txq_count = wilc->txq_entries;941 return ret;942}943 944static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)945{946 int offset = 0;947 u32 header;948 u32 pkt_len, pkt_offset, tp_len;949 int is_cfg_packet;950 u8 *buff_ptr;951 952 do {953 buff_ptr = buffer + offset;954 header = get_unaligned_le32(buff_ptr);955 956 is_cfg_packet = FIELD_GET(WILC_PKT_HDR_CONFIG_FIELD, header);957 pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header);958 tp_len = FIELD_GET(WILC_PKT_HDR_TOTAL_LEN_FIELD, header);959 pkt_len = FIELD_GET(WILC_PKT_HDR_LEN_FIELD, header);960 961 if (pkt_len == 0 || tp_len == 0)962 break;963 964 if (pkt_offset & IS_MANAGMEMENT) {965 buff_ptr += HOST_HDR_OFFSET;966 wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len,967 pkt_offset & IS_MGMT_AUTH_PKT);968 } else {969 if (!is_cfg_packet) {970 wilc_frmw_to_host(wilc, buff_ptr, pkt_len,971 pkt_offset);972 } else {973 struct wilc_cfg_rsp rsp;974 975 buff_ptr += pkt_offset;976 977 wilc_wlan_cfg_indicate_rx(wilc, buff_ptr,978 pkt_len,979 &rsp);980 if (rsp.type == WILC_CFG_RSP) {981 if (wilc->cfg_seq_no == rsp.seq_no)982 complete(&wilc->cfg_event);983 } else if (rsp.type == WILC_CFG_RSP_STATUS) {984 wilc_mac_indicate(wilc);985 }986 }987 }988 offset += tp_len;989 } while (offset < size);990}991 992static void wilc_wlan_handle_rxq(struct wilc *wilc)993{994 int size;995 u8 *buffer;996 struct rxq_entry_t *rqe;997 998 while (!wilc->quit) {999 rqe = wilc_wlan_rxq_remove(wilc);1000 if (!rqe)1001 break;1002 1003 buffer = rqe->buffer;1004 size = rqe->buffer_size;1005 wilc_wlan_handle_rx_buff(wilc, buffer, size);1006 1007 kfree(rqe);1008 }1009 if (wilc->quit)1010 complete(&wilc->cfg_event);1011}1012 1013static void wilc_unknown_isr_ext(struct wilc *wilc)1014{1015 wilc->hif_func->hif_clear_int_ext(wilc, 0);1016}1017 1018static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)1019{1020 u32 offset = wilc->rx_buffer_offset;1021 u8 *buffer = NULL;1022 u32 size;1023 u32 retries = 0;1024 int ret = 0;1025 struct rxq_entry_t *rqe;1026 1027 size = FIELD_GET(WILC_INTERRUPT_DATA_SIZE, int_status) << 2;1028 1029 while (!size && retries < 10) {1030 wilc->hif_func->hif_read_size(wilc, &size);1031 size = FIELD_GET(WILC_INTERRUPT_DATA_SIZE, size) << 2;1032 retries++;1033 }1034 1035 if (size <= 0)1036 return;1037 1038 if (WILC_RX_BUFF_SIZE - offset < size)1039 offset = 0;1040 1041 buffer = &wilc->rx_buffer[offset];1042 1043 wilc->hif_func->hif_clear_int_ext(wilc, DATA_INT_CLR | ENABLE_RX_VMM);1044 ret = wilc->hif_func->hif_block_rx_ext(wilc, 0, buffer, size);1045 if (ret)1046 return;1047 1048 offset += size;1049 wilc->rx_buffer_offset = offset;1050 rqe = kmalloc(sizeof(*rqe), GFP_KERNEL);1051 if (!rqe)1052 return;1053 1054 rqe->buffer = buffer;1055 rqe->buffer_size = size;1056 wilc_wlan_rxq_add(wilc, rqe);1057 wilc_wlan_handle_rxq(wilc);1058}1059 1060void wilc_handle_isr(struct wilc *wilc)1061{1062 u32 int_status;1063 1064 acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);1065 wilc->hif_func->hif_read_int(wilc, &int_status);1066 1067 if (int_status & DATA_INT_EXT)1068 wilc_wlan_handle_isr_ext(wilc, int_status);1069 1070 if (!(int_status & (ALL_INT_EXT)))1071 wilc_unknown_isr_ext(wilc);1072 1073 release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);1074}1075EXPORT_SYMBOL_GPL(wilc_handle_isr);1076 1077int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,1078 u32 buffer_size)1079{1080 u32 offset;1081 u32 addr, size, size2, blksz;1082 u8 *dma_buffer;1083 int ret = 0;1084 u32 reg = 0;1085 1086 blksz = BIT(12);1087 1088 dma_buffer = kmalloc(blksz, GFP_KERNEL);1089 if (!dma_buffer)1090 return -EIO;1091 1092 offset = 0;1093 pr_debug("%s: Downloading firmware size = %d\n", __func__, buffer_size);1094 1095 acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);1096 1097 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);1098 reg &= ~BIT(10);1099 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);1100 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);1101 if (reg & BIT(10))1102 pr_err("%s: Failed to reset\n", __func__);1103 1104 release_bus(wilc, WILC_BUS_RELEASE_ONLY);1105 do {1106 addr = get_unaligned_le32(&buffer[offset]);1107 size = get_unaligned_le32(&buffer[offset + 4]);1108 acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);1109 offset += 8;1110 while (((int)size) && (offset < buffer_size)) {1111 if (size <= blksz)1112 size2 = size;1113 else1114 size2 = blksz;1115 1116 memcpy(dma_buffer, &buffer[offset], size2);1117 ret = wilc->hif_func->hif_block_tx(wilc, addr,1118 dma_buffer, size2);1119 if (ret)1120 break;1121 1122 addr += size2;1123 offset += size2;1124 size -= size2;1125 }1126 release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);1127 1128 if (ret) {1129 pr_err("%s Bus error\n", __func__);1130 goto fail;1131 }1132 pr_debug("%s Offset = %d\n", __func__, offset);1133 } while (offset < buffer_size);1134 1135fail:1136 1137 kfree(dma_buffer);1138 1139 return ret;1140}1141 1142int wilc_wlan_start(struct wilc *wilc)1143{1144 u32 reg = 0;1145 int ret;1146 u32 chipid;1147 1148 if (wilc->io_type == WILC_HIF_SDIO) {1149 reg = 0;1150 reg |= BIT(3);1151 } else if (wilc->io_type == WILC_HIF_SPI) {1152 reg = 1;1153 }1154 acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);1155 ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg);1156 if (ret)1157 goto release;1158 1159 reg = 0;1160 if (wilc->io_type == WILC_HIF_SDIO && wilc->dev_irq_num)1161 reg |= WILC_HAVE_SDIO_IRQ_GPIO;1162 1163 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg);1164 if (ret)1165 goto release;1166 1167 wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT);1168 1169 ret = wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid);1170 if (ret)1171 goto release;1172 1173 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);1174 if ((reg & BIT(10)) == BIT(10)) {1175 reg &= ~BIT(10);1176 wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);1177 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);1178 }1179 1180 reg |= BIT(10);1181 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg);1182 wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®);1183 1184release:1185 release_bus(wilc, WILC_BUS_RELEASE_ONLY);1186 return ret;1187}1188 1189int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)1190{1191 u32 reg = 0;1192 int ret;1193 1194 acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);1195 1196 ret = wilc->hif_func->hif_read_reg(wilc, GLOBAL_MODE_CONTROL, ®);1197 if (ret)1198 goto release;1199 1200 reg &= ~WILC_GLOBAL_MODE_ENABLE_WIFI;1201 ret = wilc->hif_func->hif_write_reg(wilc, GLOBAL_MODE_CONTROL, reg);1202 if (ret)1203 goto release;1204 1205 ret = wilc->hif_func->hif_read_reg(wilc, PWR_SEQ_MISC_CTRL, ®);1206 if (ret)1207 goto release;1208 1209 reg &= ~WILC_PWR_SEQ_ENABLE_WIFI_SLEEP;1210 ret = wilc->hif_func->hif_write_reg(wilc, PWR_SEQ_MISC_CTRL, reg);1211 if (ret)1212 goto release;1213 1214 ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®);1215 if (ret) {1216 netdev_err(vif->ndev, "Error while reading reg\n");1217 goto release;1218 }1219 1220 ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0,1221 (reg | WILC_ABORT_REQ_BIT));1222 if (ret) {1223 netdev_err(vif->ndev, "Error while writing reg\n");1224 goto release;1225 }1226 1227 ret = 0;1228release:1229 /* host comm is disabled - we can't issue sleep command anymore: */1230 release_bus(wilc, WILC_BUS_RELEASE_ONLY);1231 1232 return ret;1233}1234 1235void wilc_wlan_cleanup(struct net_device *dev)1236{1237 struct txq_entry_t *tqe;1238 struct rxq_entry_t *rqe;1239 u8 ac;1240 struct wilc_vif *vif = netdev_priv(dev);1241 struct wilc *wilc = vif->wilc;1242 1243 wilc->quit = 1;1244 for (ac = 0; ac < NQUEUES; ac++) {1245 while ((tqe = wilc_wlan_txq_remove_from_head(wilc, ac))) {1246 if (tqe->tx_complete_func)1247 tqe->tx_complete_func(tqe->priv, 0);1248 kfree(tqe);1249 }1250 }1251 1252 while ((rqe = wilc_wlan_rxq_remove(wilc)))1253 kfree(rqe);1254 1255 kfree(wilc->vmm_table);1256 wilc->vmm_table = NULL;1257 kfree(wilc->rx_buffer);1258 wilc->rx_buffer = NULL;1259 kfree(wilc->tx_buffer);1260 wilc->tx_buffer = NULL;1261 wilc->hif_func->hif_deinit(wilc);1262}1263 1264static int wilc_wlan_cfg_commit(struct wilc_vif *vif, int type,1265 u32 drv_handler)1266{1267 struct wilc *wilc = vif->wilc;1268 struct wilc_cfg_frame *cfg = &wilc->cfg_frame;1269 int t_len = wilc->cfg_frame_offset + sizeof(struct wilc_cfg_cmd_hdr);1270 1271 if (type == WILC_CFG_SET)1272 cfg->hdr.cmd_type = 'W';1273 else1274 cfg->hdr.cmd_type = 'Q';1275 1276 cfg->hdr.seq_no = wilc->cfg_seq_no % 256;1277 cfg->hdr.total_len = cpu_to_le16(t_len);1278 cfg->hdr.driver_handler = cpu_to_le32(drv_handler);1279 wilc->cfg_seq_no = cfg->hdr.seq_no;1280 1281 if (!wilc_wlan_txq_add_cfg_pkt(vif, (u8 *)&cfg->hdr, t_len))1282 return -1;1283 1284 return 0;1285}1286 1287int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,1288 u32 buffer_size, int commit, u32 drv_handler)1289{1290 u32 offset;1291 int ret_size;1292 struct wilc *wilc = vif->wilc;1293 1294 mutex_lock(&wilc->cfg_cmd_lock);1295 1296 if (start)1297 wilc->cfg_frame_offset = 0;1298 1299 offset = wilc->cfg_frame_offset;1300 ret_size = wilc_wlan_cfg_set_wid(wilc->cfg_frame.frame, offset,1301 wid, buffer, buffer_size);1302 offset += ret_size;1303 wilc->cfg_frame_offset = offset;1304 1305 if (!commit) {1306 mutex_unlock(&wilc->cfg_cmd_lock);1307 return ret_size;1308 }1309 1310 netdev_dbg(vif->ndev, "%s: seqno[%d]\n", __func__, wilc->cfg_seq_no);1311 1312 if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler))1313 ret_size = 0;1314 1315 if (!wait_for_completion_timeout(&wilc->cfg_event,1316 WILC_CFG_PKTS_TIMEOUT)) {1317 netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__);1318 ret_size = 0;1319 }1320 1321 wilc->cfg_frame_offset = 0;1322 wilc->cfg_seq_no += 1;1323 mutex_unlock(&wilc->cfg_cmd_lock);1324 1325 return ret_size;1326}1327 1328int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,1329 u32 drv_handler)1330{1331 u32 offset;1332 int ret_size;1333 struct wilc *wilc = vif->wilc;1334 1335 mutex_lock(&wilc->cfg_cmd_lock);1336 1337 if (start)1338 wilc->cfg_frame_offset = 0;1339 1340 offset = wilc->cfg_frame_offset;1341 ret_size = wilc_wlan_cfg_get_wid(wilc->cfg_frame.frame, offset, wid);1342 offset += ret_size;1343 wilc->cfg_frame_offset = offset;1344 1345 if (!commit) {1346 mutex_unlock(&wilc->cfg_cmd_lock);1347 return ret_size;1348 }1349 1350 if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler))1351 ret_size = 0;1352 1353 if (!wait_for_completion_timeout(&wilc->cfg_event,1354 WILC_CFG_PKTS_TIMEOUT)) {1355 netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__);1356 ret_size = 0;1357 }1358 wilc->cfg_frame_offset = 0;1359 wilc->cfg_seq_no += 1;1360 mutex_unlock(&wilc->cfg_cmd_lock);1361 1362 return ret_size;1363}1364 1365int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,1366 u32 count)1367{1368 int i;1369 int ret = 0;1370 u32 drv = wilc_get_vif_idx(vif);1371 1372 if (mode == WILC_GET_CFG) {1373 for (i = 0; i < count; i++) {1374 if (!wilc_wlan_cfg_get(vif, !i,1375 wids[i].id,1376 (i == count - 1),1377 drv)) {1378 ret = -ETIMEDOUT;1379 break;1380 }1381 }1382 for (i = 0; i < count; i++) {1383 wids[i].size = wilc_wlan_cfg_get_val(vif->wilc,1384 wids[i].id,1385 wids[i].val,1386 wids[i].size);1387 }1388 } else if (mode == WILC_SET_CFG) {1389 for (i = 0; i < count; i++) {1390 if (!wilc_wlan_cfg_set(vif, !i,1391 wids[i].id,1392 wids[i].val,1393 wids[i].size,1394 (i == count - 1),1395 drv)) {1396 ret = -ETIMEDOUT;1397 break;1398 }1399 }1400 }1401 1402 return ret;1403}1404 1405static int init_chip(struct net_device *dev)1406{1407 u32 chipid;1408 u32 reg;1409 int ret = 0;1410 struct wilc_vif *vif = netdev_priv(dev);1411 struct wilc *wilc = vif->wilc;1412 1413 acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);1414 1415 chipid = wilc_get_chipid(wilc, true);1416 1417 if ((chipid & 0xfff) != 0xa0) {1418 ret = wilc->hif_func->hif_read_reg(wilc,1419 WILC_CORTUS_RESET_MUX_SEL,1420 ®);1421 if (ret) {1422 netdev_err(dev, "fail read reg 0x1118\n");1423 goto release;1424 }1425 reg |= BIT(0);1426 ret = wilc->hif_func->hif_write_reg(wilc,1427 WILC_CORTUS_RESET_MUX_SEL,1428 reg);1429 if (ret) {1430 netdev_err(dev, "fail write reg 0x1118\n");1431 goto release;1432 }1433 ret = wilc->hif_func->hif_write_reg(wilc,1434 WILC_CORTUS_BOOT_REGISTER,1435 WILC_CORTUS_BOOT_FROM_IRAM);1436 if (ret) {1437 netdev_err(dev, "fail write reg 0xc0000\n");1438 goto release;1439 }1440 }1441 1442release:1443 release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);1444 1445 return ret;1446}1447 1448u32 wilc_get_chipid(struct wilc *wilc, bool update)1449{1450 u32 chipid = 0;1451 u32 rfrevid = 0;1452 1453 if (wilc->chipid == 0 || update) {1454 wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid);1455 wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID,1456 &rfrevid);1457 if (!is_wilc1000(chipid)) {1458 wilc->chipid = 0;1459 return wilc->chipid;1460 }1461 if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */1462 if (rfrevid != 0x1)1463 chipid = WILC_1000_BASE_ID_2A_REV1;1464 } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */1465 if (rfrevid == 0x4)1466 chipid = WILC_1000_BASE_ID_2B_REV1;1467 else if (rfrevid != 0x3)1468 chipid = WILC_1000_BASE_ID_2B_REV2;1469 }1470 1471 wilc->chipid = chipid;1472 }1473 return wilc->chipid;1474}1475 1476int wilc_load_mac_from_nv(struct wilc *wl)1477{1478 int ret = -EINVAL;1479 unsigned int i;1480 1481 acquire_bus(wl, WILC_BUS_ACQUIRE_AND_WAKEUP);1482 1483 for (i = 0; i < WILC_NVMEM_MAX_NUM_BANK; i++) {1484 int bank_offset = get_bank_offset_from_bank_index(i);1485 u32 reg1, reg2;1486 u8 invalid;1487 u8 used;1488 1489 ret = wl->hif_func->hif_read_reg(wl,1490 WILC_NVMEM_BANK_BASE + bank_offset,1491 ®1);1492 if (ret) {1493 pr_err("Can not read address %d lower part", i);1494 break;1495 }1496 ret = wl->hif_func->hif_read_reg(wl,1497 WILC_NVMEM_BANK_BASE + bank_offset + 4,1498 ®2);1499 if (ret) {1500 pr_err("Can not read address %d upper part", i);1501 break;1502 }1503 1504 used = FIELD_GET(WILC_NVMEM_IS_BANK_USED, reg1);1505 invalid = FIELD_GET(WILC_NVMEM_IS_BANK_INVALID, reg1);1506 if (!used || invalid)1507 continue;1508 1509 wl->nv_mac_address[0] = FIELD_GET(GENMASK(23, 16), reg1);1510 wl->nv_mac_address[1] = FIELD_GET(GENMASK(15, 8), reg1);1511 wl->nv_mac_address[2] = FIELD_GET(GENMASK(7, 0), reg1);1512 wl->nv_mac_address[3] = FIELD_GET(GENMASK(31, 24), reg2);1513 wl->nv_mac_address[4] = FIELD_GET(GENMASK(23, 16), reg2);1514 wl->nv_mac_address[5] = FIELD_GET(GENMASK(15, 8), reg2);1515 1516 ret = 0;1517 break;1518 }1519 1520 release_bus(wl, WILC_BUS_RELEASE_ALLOW_SLEEP);1521 return ret;1522}1523EXPORT_SYMBOL_GPL(wilc_load_mac_from_nv);1524 1525int wilc_wlan_init(struct net_device *dev)1526{1527 int ret = 0;1528 struct wilc_vif *vif = netdev_priv(dev);1529 struct wilc *wilc;1530 1531 wilc = vif->wilc;1532 1533 wilc->quit = 0;1534 1535 if (!wilc->hif_func->hif_is_init(wilc)) {1536 acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);1537 ret = wilc->hif_func->hif_init(wilc, false);1538 release_bus(wilc, WILC_BUS_RELEASE_ONLY);1539 if (ret)1540 goto fail;1541 }1542 1543 if (!wilc->vmm_table)1544 wilc->vmm_table = kcalloc(WILC_VMM_TBL_SIZE, sizeof(u32), GFP_KERNEL);1545 1546 if (!wilc->vmm_table) {1547 ret = -ENOBUFS;1548 goto fail;1549 }1550 1551 if (!wilc->tx_buffer)1552 wilc->tx_buffer = kmalloc(WILC_TX_BUFF_SIZE, GFP_KERNEL);1553 1554 if (!wilc->tx_buffer) {1555 ret = -ENOBUFS;1556 goto fail;1557 }1558 1559 if (!wilc->rx_buffer)1560 wilc->rx_buffer = kmalloc(WILC_RX_BUFF_SIZE, GFP_KERNEL);1561 1562 if (!wilc->rx_buffer) {1563 ret = -ENOBUFS;1564 goto fail;1565 }1566 1567 if (init_chip(dev)) {1568 ret = -EIO;1569 goto fail;1570 }1571 1572 return 0;1573 1574fail:1575 kfree(wilc->vmm_table);1576 wilc->vmm_table = NULL;1577 kfree(wilc->rx_buffer);1578 wilc->rx_buffer = NULL;1579 kfree(wilc->tx_buffer);1580 wilc->tx_buffer = NULL;1581 1582 return ret;1583}1584