// 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"
#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_LOW | 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 *