linux-stable/drivers/staging/wilc1000/wilc_netdev.c
Ajay Singh 9a4c56be67 staging: wilc1000: avoid twice IRQ handler execution for each single interrupt
The IRQ handler(isr_bh_routine()) was called twice for each interrupt
from firmware. The data was read completely during the first call and
the second call was doing nothing.
Now changed the IRQ flag from ‘level’ to ‘edge’ trigger i.e
IRQF_TRIGGER_LOW to IRQF_TRIGGER_FALLING to avoid extra interrupt
trigger.

Signed-off-by: Ajay Singh <ajay.kathat@microchip.com>
Link: https://lore.kernel.org/r/20190910074514.3073-2-ajay.kathat@microchip.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-09-12 10:37:26 +01:00

931 lines
20 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
* All rights reserved.
*/
#include <linux/irq.h>
#include <linux/kthread.h>
#include <linux/firmware.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include "wilc_wfi_cfgoperations.h"
#include "wilc_wlan_cfg.h"
#define WILC_MULTICAST_TABLE_SIZE 8
static irqreturn_t isr_uh_routine(int irq, void *user_data)
{
struct net_device *dev = user_data;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
if (wilc->close) {
netdev_err(dev, "Can't handle UH interrupt\n");
return IRQ_HANDLED;
}
return IRQ_WAKE_THREAD;
}
static irqreturn_t isr_bh_routine(int irq, void *userdata)
{
struct net_device *dev = userdata;
struct wilc_vif *vif = netdev_priv(userdata);
struct wilc *wilc = vif->wilc;
if (wilc->close) {
netdev_err(dev, "Can't handle BH interrupt\n");
return IRQ_HANDLED;
}
wilc_handle_isr(wilc);
return IRQ_HANDLED;
}
static int init_irq(struct net_device *dev)
{
int ret = 0;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wl = vif->wilc;
ret = gpiod_direction_input(wl->gpio_irq);
if (ret) {
netdev_err(dev, "could not obtain gpio for WILC_INTR\n");
return ret;
}
wl->dev_irq_num = gpiod_to_irq(wl->gpio_irq);
ret = request_threaded_irq(wl->dev_irq_num, isr_uh_routine,
isr_bh_routine,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"WILC_IRQ", dev);
if (ret < 0)
netdev_err(dev, "Failed to request IRQ\n");
else
netdev_dbg(dev, "IRQ request succeeded IRQ-NUM= %d\n",
wl->dev_irq_num);
return ret;
}
static void deinit_irq(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
/* Deinitialize IRQ */
if (wilc->dev_irq_num)
free_irq(wilc->dev_irq_num, wilc);
}
void wilc_mac_indicate(struct wilc *wilc)
{
s8 status;
wilc_wlan_cfg_get_val(wilc, WID_STATUS, &status, 1);
if (wilc->mac_status == WILC_MAC_STATUS_INIT) {
wilc->mac_status = status;
complete(&wilc->sync_event);
} else {
wilc->mac_status = status;
}
}
static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
{
u8 *bssid, *bssid1;
int i = 0;
struct net_device *ndev = NULL;
bssid = mac_header + 10;
bssid1 = mac_header + 4;
mutex_lock(&wilc->vif_mutex);
for (i = 0; i < wilc->vif_num; i++) {
if (wilc->vif[i]->mode == WILC_STATION_MODE)
if (ether_addr_equal_unaligned(bssid,
wilc->vif[i]->bssid)) {
ndev = wilc->vif[i]->ndev;
goto out;
}
if (wilc->vif[i]->mode == WILC_AP_MODE)
if (ether_addr_equal_unaligned(bssid1,
wilc->vif[i]->bssid)) {
ndev = wilc->vif[i]->ndev;
goto out;
}
}
out:
mutex_unlock(&wilc->vif_mutex);
return ndev;
}
void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
{
struct wilc_vif *vif = netdev_priv(wilc_netdev);
if (bssid)
ether_addr_copy(vif->bssid, bssid);
else
eth_zero_addr(vif->bssid);
vif->mode = mode;
}
int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
{
u8 i = 0;
u8 ret_val = 0;
for (i = 0; i < wilc->vif_num; i++)
if (!is_zero_ether_addr(wilc->vif[i]->bssid))
ret_val++;
return ret_val;
}
static int wilc_txq_task(void *vp)
{
int ret;
u32 txq_count;
struct wilc *wl = vp;
complete(&wl->txq_thread_started);
while (1) {
wait_for_completion(&wl->txq_event);
if (wl->close) {
complete(&wl->txq_thread_started);
while (!kthread_should_stop())
schedule();
break;
}
do {
ret = wilc_wlan_handle_txq(wl, &txq_count);
if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) {
int i;
struct wilc_vif *ifc;
mutex_lock(&wl->vif_mutex);
for (i = 0; i < wl->vif_num; i++) {
ifc = wl->vif[i];
if (ifc->mac_opened && ifc->ndev)
netif_wake_queue(ifc->ndev);
}
mutex_unlock(&wl->vif_mutex);
}
} while (ret == -ENOBUFS && !wl->close);
}
return 0;
}
static int wilc_wlan_get_firmware(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
int chip_id, ret = 0;
const struct firmware *wilc_firmware;
char *firmware;
chip_id = wilc_get_chipid(wilc, false);
if (chip_id < 0x1003a0)
firmware = FIRMWARE_1002;
else
firmware = FIRMWARE_1003;
netdev_info(dev, "loading firmware %s\n", firmware);
if (request_firmware(&wilc_firmware, firmware, wilc->dev) != 0) {
netdev_err(dev, "%s - firmware not available\n", firmware);
ret = -1;
goto fail;
}
wilc->firmware = wilc_firmware;
fail:
return ret;
}
static int wilc_start_firmware(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
int ret = 0;
ret = wilc_wlan_start(wilc);
if (ret < 0)
return ret;
if (!wait_for_completion_timeout(&wilc->sync_event,
msecs_to_jiffies(5000)))
return -ETIME;
return 0;
}
static int wilc1000_firmware_download(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
int ret = 0;
if (!wilc->firmware) {
netdev_err(dev, "Firmware buffer is NULL\n");
return -ENOBUFS;
}
ret = wilc_wlan_firmware_download(wilc, wilc->firmware->data,
wilc->firmware->size);
if (ret < 0)
return ret;
release_firmware(wilc->firmware);
wilc->firmware = NULL;
netdev_dbg(dev, "Download Succeeded\n");
return 0;
}
static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif)
{
struct wilc_priv *priv = &vif->priv;
struct host_if_drv *hif_drv;
u8 b;
u16 hw;
u32 w;
netdev_dbg(dev, "Start configuring Firmware\n");
hif_drv = (struct host_if_drv *)priv->hif_drv;
netdev_dbg(dev, "Host = %p\n", hif_drv);
w = vif->iftype;
cpu_to_le32s(&w);
if (!wilc_wlan_cfg_set(vif, 1, WID_SET_OPERATION_MODE, (u8 *)&w, 4,
0, 0))
goto fail;
b = WILC_FW_BSS_TYPE_INFRA;
if (!wilc_wlan_cfg_set(vif, 0, WID_BSS_TYPE, &b, 1, 0, 0))
goto fail;
b = WILC_FW_TX_RATE_AUTO;
if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_TX_RATE, &b, 1, 0, 0))
goto fail;
b = WILC_FW_OPER_MODE_G_MIXED_11B_2;
if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, &b, 1, 0, 0))
goto fail;
b = WILC_FW_PREAMBLE_SHORT;
if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, &b, 1, 0, 0))
goto fail;
b = WILC_FW_11N_PROT_AUTO;
if (!wilc_wlan_cfg_set(vif, 0, WID_11N_PROT_MECH, &b, 1, 0, 0))
goto fail;
b = WILC_FW_ACTIVE_SCAN;
if (!wilc_wlan_cfg_set(vif, 0, WID_SCAN_TYPE, &b, 1, 0, 0))
goto fail;
b = WILC_FW_SITE_SURVEY_OFF;
if (!wilc_wlan_cfg_set(vif, 0, WID_SITE_SURVEY, &b, 1, 0, 0))
goto fail;
hw = 0xffff;
cpu_to_le16s(&hw);
if (!wilc_wlan_cfg_set(vif, 0, WID_RTS_THRESHOLD, (u8 *)&hw, 2, 0, 0))
goto fail;
hw = 2346;
cpu_to_le16s(&hw);
if (!wilc_wlan_cfg_set(vif, 0, WID_FRAG_THRESHOLD, (u8 *)&hw, 2, 0, 0))
goto fail;
b = 0;
if (!wilc_wlan_cfg_set(vif, 0, WID_BCAST_SSID, &b, 1, 0, 0))
goto fail;
b = 1;
if (!wilc_wlan_cfg_set(vif, 0, WID_QOS_ENABLE, &b, 1, 0, 0))
goto fail;
b = WILC_FW_NO_POWERSAVE;
if (!wilc_wlan_cfg_set(vif, 0, WID_POWER_MANAGEMENT, &b, 1, 0, 0))
goto fail;
b = WILC_FW_SEC_NO;
if (!wilc_wlan_cfg_set(vif, 0, WID_11I_MODE, &b, 1, 0, 0))
goto fail;
b = WILC_FW_AUTH_OPEN_SYSTEM;
if (!wilc_wlan_cfg_set(vif, 0, WID_AUTH_TYPE, &b, 1, 0, 0))
goto fail;
b = 3;
if (!wilc_wlan_cfg_set(vif, 0, WID_LISTEN_INTERVAL, &b, 1, 0, 0))
goto fail;
b = 3;
if (!wilc_wlan_cfg_set(vif, 0, WID_DTIM_PERIOD, &b, 1, 0, 0))
goto fail;
b = WILC_FW_ACK_POLICY_NORMAL;
if (!wilc_wlan_cfg_set(vif, 0, WID_ACK_POLICY, &b, 1, 0, 0))
goto fail;
b = 0;
if (!wilc_wlan_cfg_set(vif, 0, WID_USER_CONTROL_ON_TX_POWER, &b, 1,
0, 0))
goto fail;
b = 48;
if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11A, &b, 1, 0, 0))
goto fail;
b = 28;
if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11B, &b, 1, 0, 0))
goto fail;
hw = 100;
cpu_to_le16s(&hw);
if (!wilc_wlan_cfg_set(vif, 0, WID_BEACON_INTERVAL, (u8 *)&hw, 2, 0, 0))
goto fail;
b = WILC_FW_REKEY_POLICY_DISABLE;
if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_POLICY, &b, 1, 0, 0))
goto fail;
w = 84600;
cpu_to_le32s(&w);
if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PERIOD, (u8 *)&w, 4, 0, 0))
goto fail;
w = 500;
cpu_to_le32s(&w);
if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PACKET_COUNT, (u8 *)&w, 4, 0,
0))
goto fail;
b = 1;
if (!wilc_wlan_cfg_set(vif, 0, WID_SHORT_SLOT_ALLOWED, &b, 1, 0,
0))
goto fail;
b = WILC_FW_ERP_PROT_SELF_CTS;
if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ERP_PROT_TYPE, &b, 1, 0, 0))
goto fail;
b = 1;
if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ENABLE, &b, 1, 0, 0))
goto fail;
b = WILC_FW_11N_OP_MODE_HT_MIXED;
if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OPERATING_MODE, &b, 1, 0, 0))
goto fail;
b = 1;
if (!wilc_wlan_cfg_set(vif, 0, WID_11N_TXOP_PROT_DISABLE, &b, 1, 0, 0))
goto fail;
b = WILC_FW_OBBS_NONHT_DETECT_PROTECT_REPORT;
if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OBSS_NONHT_DETECTION, &b, 1,
0, 0))
goto fail;
b = WILC_FW_HT_PROT_RTS_CTS_NONHT;
if (!wilc_wlan_cfg_set(vif, 0, WID_11N_HT_PROT_TYPE, &b, 1, 0, 0))
goto fail;
b = 0;
if (!wilc_wlan_cfg_set(vif, 0, WID_11N_RIFS_PROT_ENABLE, &b, 1, 0,
0))
goto fail;
b = 7;
if (!wilc_wlan_cfg_set(vif, 0, WID_11N_CURRENT_TX_MCS, &b, 1, 0, 0))
goto fail;
b = 1;
if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, &b, 1,
1, 1))
goto fail;
return 0;
fail:
return -1;
}
static void wlan_deinit_locks(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
mutex_destroy(&wilc->hif_cs);
mutex_destroy(&wilc->rxq_cs);
mutex_destroy(&wilc->cfg_cmd_lock);
mutex_destroy(&wilc->txq_add_to_head_cs);
mutex_destroy(&wilc->vif_mutex);
}
static void wlan_deinitialize_threads(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wl = vif->wilc;
wl->close = 1;
complete(&wl->txq_event);
if (wl->txq_thread) {
kthread_stop(wl->txq_thread);
wl->txq_thread = NULL;
}
}
static void wilc_wlan_deinitialize(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wl = vif->wilc;
if (!wl) {
netdev_err(dev, "wl is NULL\n");
return;
}
if (wl->initialized) {
netdev_info(dev, "Deinitializing wilc1000...\n");
if (!wl->dev_irq_num &&
wl->hif_func->disable_interrupt) {
mutex_lock(&wl->hif_cs);
wl->hif_func->disable_interrupt(wl);
mutex_unlock(&wl->hif_cs);
}
complete(&wl->txq_event);
wlan_deinitialize_threads(dev);
deinit_irq(dev);
wilc_wlan_stop(wl, vif);
wilc_wlan_cleanup(dev);
wlan_deinit_locks(dev);
wl->initialized = false;
netdev_dbg(dev, "wilc1000 deinitialization Done\n");
} else {
netdev_dbg(dev, "wilc1000 is not initialized\n");
}
}
static int wlan_initialize_threads(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
wilc->txq_thread = kthread_run(wilc_txq_task, (void *)wilc,
"K_TXQ_TASK");
if (IS_ERR(wilc->txq_thread)) {
netdev_err(dev, "couldn't create TXQ thread\n");
wilc->close = 0;
return PTR_ERR(wilc->txq_thread);
}
wait_for_completion(&wilc->txq_thread_started);
return 0;
}
static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
{
int ret = 0;
struct wilc *wl = vif->wilc;
if (!wl->initialized) {
wl->mac_status = WILC_MAC_STATUS_INIT;
wl->close = 0;
ret = wilc_wlan_init(dev);
if (ret < 0)
return -EIO;
ret = wlan_initialize_threads(dev);
if (ret < 0) {
ret = -EIO;
goto fail_wilc_wlan;
}
if (wl->gpio_irq && init_irq(dev)) {
ret = -EIO;
goto fail_threads;
}
if (!wl->dev_irq_num &&
wl->hif_func->enable_interrupt &&
wl->hif_func->enable_interrupt(wl)) {
ret = -EIO;
goto fail_irq_init;
}
if (wilc_wlan_get_firmware(dev)) {
ret = -EIO;
goto fail_irq_enable;
}
ret = wilc1000_firmware_download(dev);
if (ret < 0) {
ret = -EIO;
goto fail_irq_enable;
}
ret = wilc_start_firmware(dev);
if (ret < 0) {
ret = -EIO;
goto fail_irq_enable;
}
if (wilc_wlan_cfg_get(vif, 1, WID_FIRMWARE_VERSION, 1, 0)) {
int size;
char firmware_ver[20];
size = wilc_wlan_cfg_get_val(wl, WID_FIRMWARE_VERSION,
firmware_ver,
sizeof(firmware_ver));
firmware_ver[size] = '\0';
netdev_dbg(dev, "Firmware Ver = %s\n", firmware_ver);
}
ret = wilc_init_fw_config(dev, vif);
if (ret < 0) {
netdev_err(dev, "Failed to configure firmware\n");
ret = -EIO;
goto fail_fw_start;
}
wl->initialized = true;
return 0;
fail_fw_start:
wilc_wlan_stop(wl, vif);
fail_irq_enable:
if (!wl->dev_irq_num &&
wl->hif_func->disable_interrupt)
wl->hif_func->disable_interrupt(wl);
fail_irq_init:
if (wl->dev_irq_num)
deinit_irq(dev);
fail_threads:
wlan_deinitialize_threads(dev);
fail_wilc_wlan:
wilc_wlan_cleanup(dev);
netdev_err(dev, "WLAN initialization FAILED\n");
} else {
netdev_dbg(dev, "wilc1000 already initialized\n");
}
return ret;
}
static int mac_init_fn(struct net_device *ndev)
{
netif_start_queue(ndev);
netif_stop_queue(ndev);
return 0;
}
static int wilc_mac_open(struct net_device *ndev)
{
struct wilc_vif *vif = netdev_priv(ndev);
struct wilc *wl = vif->wilc;
struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
unsigned char mac_add[ETH_ALEN] = {0};
int ret = 0;
if (!wl || !wl->dev) {
netdev_err(ndev, "device not ready\n");
return -ENODEV;
}
netdev_dbg(ndev, "MAC OPEN[%p]\n", ndev);
ret = wilc_init_host_int(ndev);
if (ret < 0)
return ret;
ret = wilc_wlan_initialize(ndev, vif);
if (ret < 0) {
wilc_deinit_host_int(ndev);
return ret;
}
wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype,
vif->idx);
wilc_get_mac_address(vif, mac_add);
netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
ether_addr_copy(ndev->dev_addr, mac_add);
if (!is_valid_ether_addr(ndev->dev_addr)) {
netdev_err(ndev, "Wrong MAC address\n");
wilc_deinit_host_int(ndev);
wilc_wlan_deinitialize(ndev);
return -EINVAL;
}
wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
vif->ndev->ieee80211_ptr,
vif->frame_reg[0].type,
vif->frame_reg[0].reg);
wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
vif->ndev->ieee80211_ptr,
vif->frame_reg[1].type,
vif->frame_reg[1].reg);
netif_wake_queue(ndev);
wl->open_ifcs++;
priv->p2p.local_random = 0x01;
vif->mac_opened = 1;
return 0;
}
static struct net_device_stats *mac_stats(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
return &vif->netstats;
}
static void wilc_set_multicast_list(struct net_device *dev)
{
struct netdev_hw_addr *ha;
struct wilc_vif *vif = netdev_priv(dev);
int i;
u8 *mc_list;
u8 *cur_mc;
if (dev->flags & IFF_PROMISC)
return;
if (dev->flags & IFF_ALLMULTI ||
dev->mc.count > WILC_MULTICAST_TABLE_SIZE) {
wilc_setup_multicast_filter(vif, 0, 0, NULL);
return;
}
if (dev->mc.count == 0) {
wilc_setup_multicast_filter(vif, 1, 0, NULL);
return;
}
mc_list = kmalloc_array(dev->mc.count, ETH_ALEN, GFP_ATOMIC);
if (!mc_list)
return;
cur_mc = mc_list;
i = 0;
netdev_for_each_mc_addr(ha, dev) {
memcpy(cur_mc, ha->addr, ETH_ALEN);
netdev_dbg(dev, "Entry[%d]: %pM\n", i, cur_mc);
i++;
cur_mc += ETH_ALEN;
}
if (wilc_setup_multicast_filter(vif, 1, dev->mc.count, mc_list))
kfree(mc_list);
}
static void wilc_tx_complete(void *priv, int status)
{
struct tx_complete_data *pv_data = priv;
dev_kfree_skb(pv_data->skb);
kfree(pv_data);
}
netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wilc_vif *vif = netdev_priv(ndev);
struct wilc *wilc = vif->wilc;
struct tx_complete_data *tx_data = NULL;
int queue_count;
if (skb->dev != ndev) {
netdev_err(ndev, "Packet not destined to this device\n");
return 0;
}
tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
if (!tx_data) {
dev_kfree_skb(skb);
netif_wake_queue(ndev);
return 0;
}
tx_data->buff = skb->data;
tx_data->size = skb->len;
tx_data->skb = skb;
vif->netstats.tx_packets++;
vif->netstats.tx_bytes += tx_data->size;
queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data,
tx_data->buff, tx_data->size,
wilc_tx_complete);
if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
int i;
mutex_lock(&wilc->vif_mutex);
for (i = 0; i < wilc->vif_num; i++) {
if (wilc->vif[i]->mac_opened)
netif_stop_queue(wilc->vif[i]->ndev);
}
mutex_unlock(&wilc->vif_mutex);
}
return 0;
}
static int wilc_mac_close(struct net_device *ndev)
{
struct wilc_vif *vif = netdev_priv(ndev);
struct wilc *wl = vif->wilc;
netdev_dbg(ndev, "Mac close\n");
if (wl->open_ifcs > 0)
wl->open_ifcs--;
else
return 0;
if (vif->ndev) {
netif_stop_queue(vif->ndev);
wilc_deinit_host_int(vif->ndev);
}
if (wl->open_ifcs == 0) {
netdev_dbg(ndev, "Deinitializing wilc1000\n");
wl->close = 1;
wilc_wlan_deinitialize(ndev);
}
vif->mac_opened = 0;
return 0;
}
void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size,
u32 pkt_offset)
{
unsigned int frame_len = 0;
int stats;
unsigned char *buff_to_send = NULL;
struct sk_buff *skb;
struct net_device *wilc_netdev;
struct wilc_vif *vif;
if (!wilc)
return;
wilc_netdev = get_if_handler(wilc, buff);
if (!wilc_netdev)
return;
buff += pkt_offset;
vif = netdev_priv(wilc_netdev);
if (size > 0) {
frame_len = size;
buff_to_send = buff;
skb = dev_alloc_skb(frame_len);
if (!skb)
return;
skb->dev = wilc_netdev;
skb_put_data(skb, buff_to_send, frame_len);
skb->protocol = eth_type_trans(skb, wilc_netdev);
vif->netstats.rx_packets++;
vif->netstats.rx_bytes += frame_len;
skb->ip_summed = CHECKSUM_UNNECESSARY;
stats = netif_rx(skb);
netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats);
}
}
void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
{
int i = 0;
struct wilc_vif *vif;
mutex_lock(&wilc->vif_mutex);
for (i = 0; i < wilc->vif_num; i++) {
u16 type = le16_to_cpup((__le16 *)buff);
vif = netdev_priv(wilc->vif[i]->ndev);
if ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
(type == vif->frame_reg[1].type && vif->frame_reg[1].reg)) {
wilc_wfi_p2p_rx(vif, buff, size);
break;
}
if (vif->monitor_flag) {
wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size);
break;
}
}
mutex_unlock(&wilc->vif_mutex);
}
static const struct net_device_ops wilc_netdev_ops = {
.ndo_init = mac_init_fn,
.ndo_open = wilc_mac_open,
.ndo_stop = wilc_mac_close,
.ndo_start_xmit = wilc_mac_xmit,
.ndo_get_stats = mac_stats,
.ndo_set_rx_mode = wilc_set_multicast_list,
};
void wilc_netdev_cleanup(struct wilc *wilc)
{
int i;
if (!wilc)
return;
if (wilc->firmware) {
release_firmware(wilc->firmware);
wilc->firmware = NULL;
}
for (i = 0; i < wilc->vif_num; i++) {
if (wilc->vif[i] && wilc->vif[i]->ndev)
unregister_netdev(wilc->vif[i]->ndev);
}
wilc_wfi_deinit_mon_interface(wilc, false);
flush_workqueue(wilc->hif_workqueue);
destroy_workqueue(wilc->hif_workqueue);
wilc_wlan_cfg_deinit(wilc);
kfree(wilc->bus_data);
wiphy_unregister(wilc->wiphy);
wiphy_free(wilc->wiphy);
}
EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
int vif_type, enum nl80211_iftype type,
bool rtnl_locked)
{
struct net_device *ndev;
struct wilc_vif *vif;
int ret;
ndev = alloc_etherdev(sizeof(*vif));
if (!ndev)
return ERR_PTR(-ENOMEM);
vif = netdev_priv(ndev);
ndev->ieee80211_ptr = &vif->priv.wdev;
strcpy(ndev->name, name);
vif->wilc = wl;
vif->ndev = ndev;
ndev->ml_priv = vif;
ndev->netdev_ops = &wilc_netdev_ops;
SET_NETDEV_DEV(ndev, wiphy_dev(wl->wiphy));
vif->priv.wdev.wiphy = wl->wiphy;
vif->priv.wdev.netdev = ndev;
vif->priv.wdev.iftype = type;
vif->priv.dev = ndev;
if (rtnl_locked)
ret = register_netdevice(ndev);
else
ret = register_netdev(ndev);
if (ret) {
free_netdev(ndev);
return ERR_PTR(-EFAULT);
}
ndev->needs_free_netdev = true;
vif->iftype = vif_type;
vif->wilc->vif[wl->vif_num] = vif;
vif->idx = wl->vif_num;
wl->vif_num += 1;
vif->mac_opened = 0;
return vif;
}
MODULE_LICENSE("GPL");