blob: cb955c5092dace72eb7fc8ab1eb2e257955b6ce4 [file] [log] [blame]
/**
Copyright (c) 2008 - 2013 Quantenna Communications Inc
All Rights Reserved
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef AUTOCONF_INCLUDED
#include <linux/config.h>
#endif
#include <linux/version.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <asm/hardware.h>
#include "qdrv_features.h"
#include "qdrv_debug.h"
#include "qdrv_mac.h"
#include "qdrv_soc.h"
#include "qdrv_comm.h"
#include "qdrv_wlan.h"
static void qdrv_scan_irq(void *arg1, void *arg2)
{
struct qdrv_wlan *qw = (struct qdrv_wlan *) arg1;
unsigned long flags;
spin_lock_irqsave(&qw->lock, flags);
schedule_work(&qw->scan_task);
spin_unlock_irqrestore(&qw->lock, flags);
}
static void qdrv_scan_work(struct work_struct *work)
{
struct qdrv_wlan *qw = container_of(work, struct qdrv_wlan, scan_task);
struct host_scandesc *scan_desc;
u32* sd;
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "-->Enter\n");
/* Protect the scan fifo contention between MuC & Linux using hw sem */
if(!sem_take(qw->host_sem, qw->scan_if.scan_sem_bit))
{
DBGPRINTF_E("Unable to get semaphore - rescedule.\n");
schedule_work(&qw->scan_task);
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "<--Exit\n");
return;
}
scan_desc = (struct host_scandesc *)
IO_ADDRESS((u32)*(qw->scan_if.sc_req_mbox));
sd = (u32 *) (*qw->scan_if.sc_req_mbox);
if (sd == NULL) {
sem_give(qw->host_sem, qw->scan_if.scan_sem_bit);
DBGPRINTF_E("sd NULL\n");
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "<--Exit\n");
return;
}
writel_wmb(0, qw->scan_if.sc_req_mbox);
sem_give(qw->host_sem, qw->scan_if.scan_sem_bit);
/* MATS FIX this. What is it supposed to do */
/* Call Baseband driver with dev, chan and req_type */
/* Fake for now. Old wlan_host_scan_process() */
scan_desc->status = 1;
if (sem_take(qw->host_sem, qw->scan_if.scan_sem_bit))
{
writel_wmb(sd, qw->scan_if.sc_res_mbox);
sem_give(qw->host_sem, qw->scan_if.scan_sem_bit);
}
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "<--Exit\n");
return;
}
int qdrv_scan_start(struct qdrv_mac *mac)
{
struct qdrv_wlan *qw = (struct qdrv_wlan *) mac->data;
struct int_handler int_handler;
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "-->Enter\n");
INIT_WORK(&qw->scan_task, qdrv_scan_work);
int_handler.handler = qdrv_scan_irq;
int_handler.arg1 = (void *) qw;
int_handler.arg2 = NULL;
if(qdrv_mac_set_handler(mac, qw->scanirq, &int_handler) != 0)
{
DBGPRINTF_E("Failed to register IRQ handler for %d\n",
qw->scanirq);
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "<--Exit\n");
return(-1);
}
qdrv_mac_enable_irq(mac, qw->scanirq);
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "<--Exit\n");
return(0);
}
int qdrv_scan_stop(struct qdrv_mac *mac)
{
struct qdrv_wlan *qw = (struct qdrv_wlan *) mac->data;
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "-->Enter\n");
qdrv_mac_disable_irq(mac, qw->scanirq);
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "<--Exit\n");
return(0);
}
int qdrv_scan_init(struct qdrv_wlan *qw, struct host_ioctl_hifinfo *hifinfo)
{
struct host_scanfifo *scan;
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "-->Enter\n");
/*
hal_range_check_sram_addr(hifinfo->hi_scanfifo)
*/
scan = ioremap_nocache(muc_to_lhost(hifinfo->hi_scanfifo), sizeof(*scan));
KASSERT(scan != NULL, (DBGEFMT "Unable to ioremap tx done memory area - reboot\n", DBGARG));
qw->scan_fifo = scan;
qw->scan_if.sc_res_mbox = (volatile u32 *) &(scan->sf_res);
qw->scan_if.sc_req_mbox = (volatile u32 *) &(scan->sf_req);
qw->scanirq = hifinfo->hi_scanirq & IOCTL_DEVATTACH_IRQNUM;
qw->scan_if.scan_sem_bit = scan->sf_sem;
qw->scan_if.tx_sem_bit = scan->tx_sem;
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "<--Exit\n");
return(0);
}
int qdrv_scan_exit(struct qdrv_wlan *qw)
{
iounmap(qw->scan_fifo);
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "-->Enter\n");
DBGPRINTF(DBG_LL_ALL, QDRV_LF_TRACE, "<--Exit\n");
return(0);
}