BigW Consortium Gitlab

Commit ef9fced2 by David Clark

MT7697 Queues and WiFi drivers - work in progress

parent c2df0ce0
/*
* This file is part of mt7697
*
* Copyright (C) 2017 Sierra Wireless Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __MT7697_BIT_OPS_H__
#define __MT7697_BIT_OPS_H__
// Clears a bitfield from _value_
#define BF_CLEAR(v, o, w) ((v) & ~GENMASK((o) + (w), (o)))
/* Extracts a bitfield from a value */
#define BF_GET(v, o, w) (((v) >> (o)) & GENMASK((w), 0))
/* Compose a value with the given bitfield set to v */
#define BF_DEFINE(v, o, w) (((v) & GENMASK((w), 0)) << (o))
/* Replace the given bitfield with the value in b */
#define BF_SET(v, b, o, w) (BF_CLEAR(v, o, w) | BF_DEFINE(b, o, w))
#endif
/*
* Copyright (c) 2017 Sierra Wireless Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/device.h>
#include <linux/interrupt.h>
#include "interrupt.h"
#include "queue.h"
#include "io.h"
/*
static void mt7697_flush_deferred_work(struct mt7697_data *wl)
{
struct sk_buff *skb;
*/
/* Pass all received frames to the network stack */
/* while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
ieee80211_rx_ni(wl->hw, skb);
*/
/* Return sent skbs to the network stack */
/* while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
ieee80211_tx_status_ni(wl->hw, skb);
}
*/
/*
static int mt7697_irq_locked(struct mt7697_data *wl)
{
int ret = 0;
int loopcount = MT7697_IRQ_MAX_LOOPS;
bool done = false;
unsigned int defer_count;
unsigned long flags;
if (unlikely(wl->state != MT7697_STATE_ON))
goto out;
while (!done && loopcount--) {
clear_bit(MT7697_FLAG_IRQ_RUNNING, &wl->flags);
ret = mt7697_rx(wl);
if (ret < 0) {
dev_err(wl->dev, "%s(): mt7697_rx() failed(%d)\n", __func__, ret);
goto out;
}
*/
/* Check if any tx blocks were freed */
/* spin_lock_irqsave(&wl->lock, flags);
if (!test_bit(MT7697_FLAG_FW_TX_BUSY, &wl->flags) &&
mt7697_tx_total_queue_count(wl) > 0) {
spin_unlock_irqrestore(&wl->lock, flags);*/
/*
* In order to avoid starvation of the TX path,
* call the work function directly.
*/
/* ret = mt7697_tx_work_locked(wl);
if (ret < 0) {
dev_err(wl->dev, "%s(): mt7697_tx_work_locked() failed(%d)\n", __func__, ret);
goto out;
}
} else {
spin_unlock_irqrestore(&wl->lock, flags);
}
*/
/* check for tx results */
// ret = mt7697_hw_tx_delayed_compl(wl);
/* if (ret < 0) {
dev_err(wl->dev, "%s(): mt7697_hw_tx_delayed_compl() failed(%d)\n", __func__, ret);
goto out;
}
*/
/* Make sure the deferred queues don't get too long */
/* defer_count = skb_queue_len(&wl->deferred_tx_queue) +
skb_queue_len(&wl->deferred_rx_queue);
if (defer_count > MT7697_DEFERRED_QUEUE_LIMIT)
mt7697_flush_deferred_work(wl);
}
out:
return ret;
}*/
/*
irqreturn_t mt7697_irq(int irq, void *cookie)
{
struct mt7697_data *wl = cookie;
int ret;
unsigned long flags;
spin_lock_irqsave(&wl->lock, flags);
if (test_bit(MT7697_FLAG_SUSPENDED, &wl->flags)) {*/
/* don't enqueue a work right now. mark it as pending */
/* set_bit(MT7697_FLAG_PENDING_WORK, &wl->flags);
dev_info(wl->dev, "should not enqueue work\n");
// disable_irq_nosync(wl->irq);
// pm_wakeup_event(wl->dev, 0);
spin_unlock_irqrestore(&wl->lock, flags);
return IRQ_HANDLED;
}
spin_unlock_irqrestore(&wl->lock, flags);
*/
/* TX might be handled here, avoid redundant work */
/* set_bit(MT7697_FLAG_TX_PENDING, &wl->flags);
cancel_work_sync(&wl->tx_work);
mutex_lock(&wl->mutex);
ret = mt7697_irq_locked(wl);
if (ret) {
dev_warn(wl->dev, "%s(): mt7697_irq_locked() failed(%d)\n", __func__, ret);
// mt7697_queue_recovery_work(wl);
}
spin_lock_irqsave(&wl->lock, flags);*/
/* In case TX was not handled here, queue TX work */
/* clear_bit(MT7697_FLAG_TX_PENDING, &wl->flags);
if (!test_bit(MT7697_FLAG_FW_TX_BUSY, &wl->flags) &&
mt7697_tx_total_queue_count(wl) > 0)
ieee80211_queue_work(wl->hw, &wl->tx_work);
spin_unlock_irqrestore(&wl->lock, flags);
mutex_unlock(&wl->mutex);
return IRQ_HANDLED;
}*/
void mt7697_irq_work(struct work_struct *irq_work)
{
struct mt7697q_info *qinfo = container_of(irq_work,
struct mt7697q_info, irq_work);
int ch;
int ret;
mutex_lock(&qinfo->mutex);
ret = mt7697io_rd_s2m_mbx(qinfo);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_rd_s2m_mbx() failed(%d)\n", __func__, ret);
goto cleanup;
}
if (!qinfo->s2m_mbox)
goto cleanup;
ret = mt7697io_clr_s2m_mbx(qinfo);
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): mt7697io_clr_s2m_mbx() failed(%d)\n", __func__, ret);
goto cleanup;
}
for (ch = 0; ch < MT7697_NUM_QUEUES; ch++) {
if (qinfo->s2m_mbox & (0x01 << ch)) {
struct mt7697q_spec *qs = &qinfo->queues[ch];
u32 in_use = mt7697q_flags_get_in_use(qs->data.flags);
u32 dir = mt7697q_flags_get_dir(qs->data.flags);
if (in_use &&
(dir == MT7697_QUEUE_DIR_SLAVE_TO_MASTER)) {
WARN_ON(!qs->rx_fcn);
ret = qs->rx_fcn(qs->priv);
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): rx_fcn() failed(%d)\n",
__func__, ret);
}
}
else if (!in_use) {
dev_warn(qinfo->dev,
"%s(): unused channel(%d)\n", __func__, ch);
}
}
}
cleanup:
ret = queue_delayed_work(qinfo->irq_workq, &qinfo->irq_work,
msecs_to_jiffies(1000));
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): queue_delayed_work() failed(%d)\n", __func__, ret);
}
mutex_unlock(&qinfo->mutex);
}
irqreturn_t mt7697_irq(int irq, void *cookie)
{
/* struct mt7697q_info *qinfo = cookie;
int err = queue_work(qinfo->irq_workq, &qinfo->irq_work);
if (err < 0) {
dev_err(qinfo->dev, "queue_work() failed(%d)\n", err);
}*/
return IRQ_HANDLED;
}
/*
* Copyright (c) 2017 Sierra Wireless Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _MT7697_INTERRUPT_H_
#define _MT7697_INTERRUPT_H_
#include <linux/interrupt.h>
#define MT7697_USBHUB_IRQ_PIN 6
#define MT7697_IRQ_MAX_LOOPS 256
irqreturn_t mt7697_irq(int, void*);
void mt7697_irq_work(struct work_struct*);
#endif
/*
* Copyright (c) 2017 Sierra Wireless Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/device.h>
#include <linux/delay.h>
#include "bits.h"
#include "queue.h"
#include "io.h"
#include "spi.h"
static int mt7697io_write16(struct mt7697q_info *qinfo, u8 reg, u16 value)
{
int ret;
WARN_ON(reg % sizeof(u16));
qinfo->txBuffer[0] = MT7697_IO_CMD_WRITE;
qinfo->txBuffer[1] = reg;
qinfo->txBuffer[2] = ((value >> 8) & 0xFF);
qinfo->txBuffer[3] = value & 0xFF;
ret = qinfo->hw_ops->write(qinfo->hw_priv, qinfo->txBuffer,
sizeof(qinfo->txBuffer));
if (ret < 0) {
dev_err(qinfo->dev, "%s(): write() failed(%d)\n",
__func__, ret);
goto cleanup;
}
cleanup:
return ret;
}
static int mt7697io_write32(struct mt7697q_info *qinfo, u8 reg, u32 value)
{
int ret;
WARN_ON(reg % sizeof(u32));
ret = mt7697io_write16(qinfo, reg, BF_GET(value, 0, 16));
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_write16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
ret = mt7697io_write16(qinfo, reg + 2, BF_GET(value, 16, 16));
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_write16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
cleanup:
return ret;
}
static int mt7697io_read16(struct mt7697q_info *qinfo, u8 reg, u16 *value)
{
int ret;
WARN_ON(reg % sizeof(u16));
qinfo->txBuffer[0] = MT7697_IO_CMD_READ;
qinfo->txBuffer[1] = reg;
ret = qinfo->hw_ops->write_then_read(qinfo->hw_priv,
qinfo->txBuffer, sizeof(u16),
qinfo->rxBuffer, sizeof(qinfo->rxBuffer));
if (ret < 0) {
dev_err(qinfo->dev, "%s(): write_then_read() failed(%d)\n",
__func__, ret);
goto cleanup;
}
*value = ((qinfo->rxBuffer[0] << 8) | qinfo->rxBuffer[1]);
cleanup:
return ret;
}
static int mt7697io_read32(struct mt7697q_info *qinfo, u8 reg, u32 *value)
{
int ret;
u16 low;
u16 high;
WARN_ON(reg % sizeof(u32));
ret = mt7697io_read16(qinfo, reg, &low);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_read16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
ret = mt7697io_read16(qinfo, reg + sizeof(u16), &high);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_read16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
*value = (low | (high << 16));
cleanup:
return ret;
}
static int mt7697io_chk_slave_busy(struct mt7697q_info *qinfo)
{
int ret;
u16 value;
ret = mt7697io_read16(qinfo, MT7697_IO_SLAVE_REG_STATUS, &value);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_read16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
qinfo->slave_busy = mt7697q_busy(value) == MT7697_IO_STATUS_REG_BUSY_VAL_BUSY;
cleanup:
return ret;
}
static int mt7697io_slave_wait(struct mt7697q_info *qinfo)
{
int ret;
qinfo->slave_busy = true;
while (qinfo->slave_busy) {
ret = mt7697io_chk_slave_busy(qinfo);
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): mt7697io_chk_slave_busy() failed(%d)\n",
__func__, ret);
goto cleanup;
}
udelay(1);
};
cleanup:
return ret;
}
static __inline u8 mt7697io_get_s2m_mbox(u16 value)
{
return BF_GET(value,
MT7697_IO_S2M_MAILBOX_REG_MAILBOX_OFFSET,
MT7697_IO_S2M_MAILBOX_REG_MAILBOX_WIDTH);
}
static __inline u16 mt7697io_set_s2m_mbox(u8 value)
{
return BF_DEFINE(value,
MT7697_IO_S2M_MAILBOX_REG_MAILBOX_OFFSET,
MT7697_IO_S2M_MAILBOX_REG_MAILBOX_WIDTH);
}
int mt7697io_wr_m2s_mbx(struct mt7697q_info *qinfo, u8 bits)
{
int ret;
const u16 value = BF_DEFINE(bits,
MT7697_IO_M2S_MAILBOX_REG_MAILBOX_OFFSET,
MT7697_IO_M2S_MAILBOX_REG_MAILBOX_WIDTH);
dev_dbg(qinfo->dev, "%s(): m2s mbx(0x%02x)\n", __func__, bits);
WARN_ON((GENMASK(MT7697_IO_M2S_MAILBOX_REG_MAILBOX_WIDTH, 0) & bits) != bits);
ret = mt7697io_write16(qinfo, MT7697_IO_SLAVE_REG_MAILBOX_M2S, value);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_write16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
cleanup:
return ret;
}
int mt7697io_rd_s2m_mbx(struct mt7697q_info *qinfo)
{
int ret;
u16 value;
ret = mt7697io_read16(qinfo, MT7697_IO_SLAVE_REG_MAILBOX_S2M, &value);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_read16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
dev_dbg(qinfo->dev, "%s(): s2m mbx(0x%02x)\n",
__func__, qinfo->s2m_mbox);
cleanup:
return ret;
}
int mt7697io_clr_s2m_mbx(struct mt7697q_info *qinfo)
{
const u16 value = mt7697io_set_s2m_mbox(qinfo->s2m_mbox);
int ret;
ret = mt7697io_write16(qinfo, MT7697_IO_SLAVE_REG_MAILBOX_S2M, value);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_write16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
cleanup:
return ret;
}
int mt7697io_wr(struct mt7697q_info *qinfo, u32 addr, const u32 *data, size_t num)
{
size_t i;
int ret;
WARN_ON(num == 0);
ret = mt7697io_slave_wait(qinfo);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_slave_wait() failed(%d)\n",
__func__, ret);
goto cleanup;
}
ret = mt7697io_write32(qinfo, MT7697_IO_SLAVE_REG_BUS_ADDR_LOW, addr);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_write32() failed(%d)\n",
__func__, ret);
goto cleanup;
}
for (i = 0; i < num; i++) {
ret = mt7697io_write32(qinfo, MT7697_IO_SLAVE_REG_WRITE_DATA_LOW, data[i]);
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): mt7697io_write32() failed(%d)\n",
__func__, ret);
goto cleanup;
}
ret = mt7697io_write16(qinfo, MT7697_IO_SLAVE_REG_COMMAND, (
BF_DEFINE(MT7697_IO_COMMAND_REG_BUS_SIZE_VAL_WORD,
MT7697_IO_COMMAND_REG_BUS_SIZE_OFFSET,
MT7697_IO_COMMAND_REG_BUS_SIZE_WIDTH) |
BF_DEFINE(MT7697_IO_COMMAND_REG_RW_VAL_WRITE,
MT7697_IO_COMMAND_REG_RW_OFFSET,
MT7697_IO_COMMAND_REG_RW_WIDTH)));
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): mt7697io_write16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
ret = mt7697io_slave_wait(qinfo);
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): mt7697io_slave_wait() failed(%d)\n",
__func__, ret);
goto cleanup;
}
}
cleanup:
return ret;
}
int mt7697io_rd(struct mt7697q_info *qinfo, u32 addr, u32 *data, size_t num)
{
size_t i;
int ret;
WARN_ON(num == 0);
ret = mt7697io_slave_wait(qinfo);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_slave_wait() failed(%d)\n",
__func__, ret);
goto cleanup;
}
ret = mt7697io_write32(qinfo, MT7697_IO_SLAVE_REG_BUS_ADDR_LOW, addr);
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_write32() failed(%d)\n",
__func__, ret);
goto cleanup;
}
for (i = 0; i < num; i++) {
ret = mt7697io_write16(qinfo, MT7697_IO_SLAVE_REG_COMMAND, (
BF_DEFINE(MT7697_IO_COMMAND_REG_BUS_SIZE_VAL_WORD,
MT7697_IO_COMMAND_REG_BUS_SIZE_OFFSET,
MT7697_IO_COMMAND_REG_BUS_SIZE_WIDTH) |
BF_DEFINE(MT7697_IO_COMMAND_REG_RW_VAL_READ,
MT7697_IO_COMMAND_REG_RW_OFFSET,
MT7697_IO_COMMAND_REG_RW_WIDTH)));
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): mt7697io_write16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
ret = mt7697io_slave_wait(qinfo);
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): mt7697io_slave_wait() failed(%d)\n",
__func__, ret);
goto cleanup;
}
ret = mt7697io_read32(qinfo, MT7697_IO_SLAVE_REG_READ_DATA_LOW, &data[i]);
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): mt7697io_read32() failed(%d)\n",
__func__, ret);
goto cleanup;
}
}
cleanup:
return ret;
}
int mt7697io_trigger_intr(struct mt7697q_info *qinfo)
{
int ret;
ret = mt7697io_write16(qinfo, MT7697_IO_SLAVE_REG_IRQ,
BF_DEFINE(MT7697_IO_IRQ_REG_IRQ_STATUS_VAL_ACTIVE,
MT7697_IO_IRQ_REG_IRQ_STATUS_OFFSET,
MT7697_IO_IRQ_REG_IRQ_STATUS_WIDTH));
if (ret < 0) {
dev_err(qinfo->dev, "%s(): mt7697io_write16() failed(%d)\n",
__func__, ret);
goto cleanup;
}
cleanup:
return ret;
}
/*
* This file is part of mt7697
*
* Copyright (C) 2017 Sierra Wireless Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __MT7697_IO_H__
#define __MT7697_IO_H__
#include <linux/types.h>
/* Address is based on linker script used to build mt7697 code */
#define MT7697_IO_SLAVE_BUFFER_ADDRESS 0x20000200
/* The first byte of every SPI write is always a Read/Write indicator */
#define MT7697_IO_CMD_WRITE 0x80
#define MT7697_IO_CMD_READ 0x00
/*
* MediaTek MT7697 SPI slave registers
*/
/* Reg0 */
#define MT7697_IO_SLAVE_REG_READ_DATA_LOW 0x00
#define MT7697_IO_SLAVE_REG_READ_DATA_HIGH 0x02
/* Reg1 */
#define MT7697_IO_SLAVE_REG_WRITE_DATA_LOW 0x04
#define MT7697_IO_SLAVE_REG_WRITE_DATA_HIGH 0x06
/* Reg2 */
#define MT7697_IO_SLAVE_REG_BUS_ADDR_LOW 0x08
#define MT7697_IO_SLAVE_REG_BUS_ADDR_HIGH 0x0A
/* Reg3 */
#define MT7697_IO_SLAVE_REG_COMMAND 0x0C
/* Reg4 */
#define MT7697_IO_SLAVE_REG_STATUS 0x10
/* Reg5 */
#define MT7697_IO_SLAVE_REG_IRQ 0x14
/* Reg6 */
#define MT7697_IO_SLAVE_REG_MAILBOX_S2M 0x18
/* Reg7 */
#define MT7697_IO_SLAVE_REG_MAILBOX_M2S 0x1C
/* Register fields */
#define MT7697_IO_COMMAND_REG_BUS_SIZE_OFFSET 1
#define MT7697_IO_COMMAND_REG_BUS_SIZE_WIDTH 2
#define MT7697_IO_COMMAND_REG_BUS_SIZE_VAL_WORD 0x2
#define MT7697_IO_COMMAND_REG_RW_OFFSET 0
#define MT7697_IO_COMMAND_REG_RW_WIDTH 1
#define MT7697_IO_COMMAND_REG_RW_VAL_READ 0
#define MT7697_IO_COMMAND_REG_RW_VAL_WRITE 1
#define MT7697_IO_STATUS_REG_BUSY_OFFSET 0
#define MT7697_IO_STATUS_REG_BUSY_WIDTH 1
#define MT7697_IO_STATUS_REG_BUSY_VAL_IDLE 0
#define MT7697_IO_STATUS_REG_BUSY_VAL_BUSY 1
#define MT7697_IO_IRQ_REG_IRQ_STATUS_OFFSET 0
#define MT7697_IO_IRQ_REG_IRQ_STATUS_WIDTH 1
#define MT7697_IO_IRQ_REG_IRQ_STATUS_VAL_INACTIVE 0
#define MT7697_IO_IRQ_REG_IRQ_STATUS_VAL_ACTIVE 1
#define MT7697_IO_S2M_MAILBOX_REG_MAILBOX_OFFSET 0
#define MT7697_IO_S2M_MAILBOX_REG_MAILBOX_WIDTH 7
#define MT7697_IO_M2S_MAILBOX_REG_MAILBOX_OFFSET 0
#define MT7697_IO_M2S_MAILBOX_REG_MAILBOX_WIDTH 7
struct mt7697q_info;
int mt7697io_wr_m2s_mbx(struct mt7697q_info*, u8);
int mt7697io_rd_s2m_mbx(struct mt7697q_info*);
int mt7697io_clr_s2m_mbx(struct mt7697q_info*);
int mt7697io_wr(struct mt7697q_info*, u32, const u32*, size_t);
int mt7697io_rd(struct mt7697q_info*, u32, u32*, size_t);
int mt7697io_trigger_intr(struct mt7697q_info*);
#endif
sources:
{
io.c
interrupt.c
queue.c
spi.c
}
cflags:
{
-DDEBUG
}
/*
* Copyright (c) 2017 Sierra Wireless Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _MT7697_QUEUE_H_
#define _MT7697_QUEUE_H_
#include <linux/types.h>
#include "queue_i.h"
#define MT7697_NUM_QUEUES 7
#define MT7697_QUEUE_FLAGS_IN_USE_OFFSET 0
#define MT7697_QUEUE_FLAGS_IN_USE_WIDTH 1
#define MT7697_QUEUE_FLAGS_DIR_OFFSET 1
#define MT7697_QUEUE_FLAGS_DIR_WIDTH 1
#define MT7697_QUEUE_FLAGS_NUM_WORDS_OFFSET 16
#define MT7697_QUEUE_FLAGS_NUM_WORDS_WIDTH 16
#define MT7697_QUEUE_DEBUG_DUMP_LIMIT 1024
typedef int (*rx_hndlr)(void*);
struct mt7697q_data {
u32 flags;
u32 base_addr;
u32 rd_offset;
u32 wr_offset;
} __attribute__((packed));
struct mt7697q_spec {
struct mt7697q_data data;
struct mt7697q_info *qinfo;
void *priv;
rx_hndlr rx_fcn;
u8 ch;
};
struct mt7697q_info {
struct mt7697q_spec queues[MT7697_NUM_QUEUES];
u8 txBuffer[sizeof(u32)];
u8 rxBuffer[sizeof(u16)];
struct device *dev;
void *hw_priv;
const struct mt7697spi_hw_ops *hw_ops;
struct mutex mutex;
struct workqueue_struct *irq_workq;
// struct work_struct irq_work;
struct delayed_work irq_work;
int irq;
u8 s2m_mbox;
bool slave_busy;
};
u8 mt7697q_busy(u16);
u8 mt7697q_get_s2m_mbox(u16);
u16 mt7697q_set_s2m_mbox(u8);
u8 mt7697q_get_m2s_mbox(u16);
u32 mt7697q_flags_get_in_use(u32);
u32 mt7697q_flags_get_dir(u32);
void* mt7697q_init(u8, void*, rx_hndlr);
size_t mt7697q_read(void*, u32*, size_t);
size_t mt7697q_write(void*, const u32*, size_t);
int mt7697q_pull_rd_ptr(void*);
int mt7697q_pull_wr_ptr(void*);
size_t mt7697q_get_capacity(const void*);
size_t mt7697q_get_num_words(const void*);
size_t mt7697q_get_free_words(const void*);
#endif
/*
* Copyright (c) 2017 Sierra Wireless Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _MT7697_QUEUE_I_H_
#define _MT7697_QUEUE_I_H_
#define MT7697_QUEUE_LEN_TO_WORD(x) ((x) / sizeof(u32) + \
((x) % sizeof(u32) ? 1:0))
enum mt7697q_dir
{
MT7697_QUEUE_DIR_MASTER_TO_SLAVE = 0,
MT7697_QUEUE_DIR_SLAVE_TO_MASTER,
};
typedef int (*rx_hndlr)(void*);
struct mt7697q_if_ops {
void* (*init)(u8, void*, rx_hndlr);
size_t (*read)(void*, u32*, size_t);
size_t (*write)(void*, const u32*, size_t);
int (*pull_rd_ptr)(void*);
int (*pull_wr_ptr)(void*);
size_t (*capacity)(const void*);
size_t (*num_wr)(const void*);
size_t (*num_rd)(const void*);
void (*reset)(void*);
void (*enable_irq)(void*);
void (*disable_irq)(void*);
};
u8 mt7697q_busy(u16);
u8 mt7697q_get_s2m_mbox(u16);
u16 mt7697q_set_s2m_mbox(u8);
u8 mt7697q_get_m2s_mbox(u16);
u16 mt7697q_set_m2s_mbox(u8);
u32 mt7697q_flags_get_in_use(u32);
u32 mt7697q_flags_get_dir(u32);
void* mt7697q_init(u8, void*, rx_hndlr);
size_t mt7697q_read(void*, u32*, size_t);
size_t mt7697q_write(void*, const u32*, size_t);
int mt7697q_pull_rd_ptr(void*);
int mt7697q_pull_wr_ptr(void*);
size_t mt7697q_get_capacity(const void*);
size_t mt7697q_get_num_words(const void*);
size_t mt7697q_get_free_words(const void*);
#endif
/*
* This file is part of mt7697
*
* Copyright (C) 2017 Sierra Wireless Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/usb.h>
#include "interrupt.h"
#include "queue.h"
#include "spi.h"
static void mt7697spi_reset(struct spi_device *spi)
{
}
static void mt7697spi_enable_irq(struct spi_device *spi)
{
enable_irq(spi->irq);
}
static void mt7697spi_disable_irq(struct spi_device *spi)
{
disable_irq(spi->irq);
}
static const struct mt7697spi_hw_ops hw_ops =
{
.write = spi_write,
.read = spi_read,
.write_then_read = spi_write_then_read,
.reset = mt7697spi_reset,
.enable_irq = mt7697spi_enable_irq,
.disable_irq = mt7697spi_disable_irq,
};
static int mt7697spi_probe(struct spi_device *spi)
{
struct mt7697q_info *qinfo;
int ret = 0;
pr_info(DRVNAME" init dev('%s') mode(%d) max speed(%d) "
"CS(%d) GPIO(%d) bits/word(%d)\n",
spi->modalias, spi->mode, spi->max_speed_hz, spi->chip_select,
spi->cs_gpio, spi->bits_per_word);
qinfo = kzalloc(sizeof(struct mt7697q_info), GFP_KERNEL);
if (!qinfo) {
pr_err(DRVNAME" create queue info failed\n");
ret = -ENOMEM;
goto cleanup;
}
memset(qinfo, 0, sizeof(struct mt7697q_info));
qinfo->dev = &spi->dev;
qinfo->hw_priv = spi;
qinfo->hw_ops = &hw_ops;
mutex_init(&qinfo->mutex);
qinfo->irq_workq = create_workqueue(DRVNAME);
if (!qinfo) {
pr_err(DRVNAME" create_workqueue() failed\n");
ret = -ENOMEM;
goto cleanup;
}
INIT_DELAYED_WORK(&qinfo->irq_work, mt7697_irq_work);
// INIT_WORK(&qinfo->irq_work, mt7697_irq_work);
qinfo->irq = spi->irq;
dev_info(qinfo->dev, "%s(): '%s' request irq(%d)\n",
__func__, spi->modalias, spi->irq);
/* ret = request_irq(spi->irq, mt7697_irq,
IRQF_SHARED| IRQF_NO_SUSPEND, spi->modalias, qinfo);
if (ret < 0) {
pr_err(DRVNAME" request_irq() failed(%d)", ret);
goto failed_irq;
}
*/
spi_set_drvdata(spi, qinfo);
ret = queue_delayed_work(qinfo->irq_workq, &qinfo->irq_work,
msecs_to_jiffies(1000));
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): queue_delayed_work() failed(%d)\n",
__func__, ret);
}
return 0;
/*failed_irq:
destroy_workqueue(qinfo->irq_workq);
free_irq(spi->irq, qinfo);*/
cleanup:
kfree(qinfo);
return ret;
}
static int mt7697spi_remove(struct spi_device *spi)
{
struct mt7697q_info *qinfo = spi_get_drvdata(spi);
if (qinfo) {
dev_info(qinfo->dev, "%s(): remove\n", __func__);
free_irq(spi->irq, qinfo);
kfree(qinfo);
}
return 0;
}
static const struct of_device_id dt_ids[] = {
{ .compatible = "MediaTek,mt7697" },
{},
};
MODULE_DEVICE_TABLE(of, dt_ids);
static struct spi_driver mt7697spi_driver = {
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(dt_ids),
},
.probe = mt7697spi_probe,
.remove = mt7697spi_remove,
};
module_spi_driver(mt7697spi_driver)
MODULE_AUTHOR( "Sierra Wireless Corporation" );
MODULE_LICENSE( "GPL" );
MODULE_DESCRIPTION( "MediaTek7697 SPI master" );
/*
* This file is part of mt7697
*
* Copyright (C) 2017 Sierra Wireless Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __MT7697_SPI_H__
#define __MT7697_SPI_H__
#include <linux/spi/spi.h>
#define DRVNAME "mt7697"
#define MT7697_SPI_BUS_NUM 32766
#define MT7697_SPI_CS 0
struct mt7697spi_hw_ops {
int (*write)(struct spi_device*, const void*, size_t);
int (*read)(struct spi_device*, void*, size_t);
int (*write_then_read)(struct spi_device*, const void*, unsigned,
void*, unsigned);
void (*reset)(struct spi_device*);
void (*enable_irq)(struct spi_device*);
void (*disable_irq)(struct spi_device*);
};
#endif /* __MT7697_SPI_H__ */
master.mk
\ No newline at end of file
ln -sf master.mk Makefile
make clean ; make
if [ $? -ne 0 ] ; then exit 1 ; fi
#ln -sf spi.mk Makefile
#make
#Sif [ $? -ne 0 ] ; then exit 1 ; fi
/*
* Copyright (c) 2017 Sierra Wireless Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _MT7697_WL_CFG80211_H_
#define _MT7697_WL_CFG80211_H_
#define MT7697_DEFAULT_BG_SCAN_PERIOD 60
struct mt7697_cfg80211_info;
struct mt7697_vif;
int mt7697_cfg80211_connect_event(struct mt7697_vif*, const u8*, u32);
struct mt7697_cfg80211_info *mt7697_cfg80211_create(void);
void mt7697_cfg80211_stop(struct mt7697_vif *vif);
int mt7697_cfg80211_init(struct mt7697_cfg80211_info*);
void mt7697_cfg80211_cleanup(struct mt7697_cfg80211_info*);
void mt7697_cfg80211_destroy(struct mt7697_cfg80211_info*);
#endif
/*
* Copyright (c) 2017 Sierra Wireless Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _MT7697_CORE_H_
#define _MT7697_CORE_H_
#include <net/cfg80211.h>
#include "wifi_api.h"
#include "wmi.h"
#define DRVNAME "mt7697core"
#define MT7697_MAC80211_QUEUE_TX 0
#define MT7697_MAC80211_QUEUE_RX 1
#define MT7697_CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */
#define MT7697_CH_MIN_5G_CHANNEL 34
#define MT7697_SCAN_MAX_ITEMS 16
#define MT7697_IFACE_MAX_CNT 2
#define MT7697_MAX_MC_FILTERS_PER_LIST 7
#define MT7697_MAX_COOKIE_NUM 180
#define MT7697_TX_TIMEOUT 10
#define MT7697_DISCON_TIMER_INTVAL 10000 /* in msec */
#define MT7697_KEY_SEQ_LEN 8
#define MT7697_MAX_KEY_INDEX 3
enum mt7697_dev_state {
WMI_ENABLED,
WMI_READY,
WMI_CTRL_EP_FULL,
TESTMODE,
DESTROY_IN_PROGRESS,
SKIP_SCAN,
ROAM_TBL_PEND,
FIRST_BOOT,
RECOVERY_CLEANUP,
};
enum mt7697_sme_state {
SME_DISCONNECTED,
SME_CONNECTING,
SME_CONNECTED
};
enum mt7697_vif_state {
CONNECTED,
CONNECT_PEND,
WMM_ENABLED,
NETQ_STOPPED,
DTIM_EXPIRED,
CLEAR_BSSFILTER_ON_BEACON,
DTIM_PERIOD_AVAIL,
WLAN_ENABLED,
STATS_UPDATE_PEND,
HOST_SLEEP_MODE_CMD_PROCESSED,
NETDEV_MCAST_ALL_ON,
NETDEV_MCAST_ALL_OFF,
SCHED_SCANNING,
};
struct mt7697_cookie {
struct sk_buff *skb;
struct mt7697_cookie *arc_list_next;
};
struct mt7697_cfg80211_info {
struct device *dev;
struct wiphy *wiphy;
struct semaphore sem;
struct platform_device *hif_priv;
const struct mt7697q_if_ops *hif_ops;
void* txq_hdl;
void* rxq_hdl;
struct work_struct init_work;
struct mt7697_cookie *cookie_list;
u32 cookie_count;
struct mt7697_cookie cookie_mem[MT7697_MAX_COOKIE_NUM];
struct work_struct tx_work;
u8 tx_data[IEEE80211_MAX_DATA_LEN];
u8 rx_data[IEEE80211_MAX_DATA_LEN];
u8 probe_data[IEEE80211_MAX_DATA_LEN];
struct mt7697_rsp_hdr rsp;
enum mt7697_radio_state radio_state;
enum mt7697_wifi_phy_mode_t wireless_mode;
struct mac_address mac_addr;
struct mt7697_wifi_config_t wifi_config;
int listen_interval;
enum mt7697_wifi_rx_filter_t rx_filter;
u8 pmkid[MT7697_WIFI_LENGTH_PMK];
struct list_head vif_list;
spinlock_t vif_list_lock;
u8 num_vif;
unsigned int vif_max;
u8 max_norm_iface;
u8 avail_idx_map;
bool wiphy_registered;
bool ibss_if_active;
u32 connect_ctrl_flags;
unsigned long flag;
};
struct mt7697_key {
u8 key[WLAN_MAX_KEY_LEN];
u8 key_len;
u8 seq[MT7697_KEY_SEQ_LEN];
u8 seq_len;
u32 cipher;
};
struct mt7697_vif {
struct list_head list;
struct wireless_dev wdev;
struct net_device *ndev;
struct mt7697_cfg80211_info *cfg;
/* Lock to protect vif specific net_stats and flags */
spinlock_t if_lock;
u8 fw_vif_idx;
unsigned long flags;
int ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 bssid[ETH_ALEN];
u8 req_bssid[ETH_ALEN];
u16 ch_hint;
struct work_struct disconnect_work;
struct timer_list disconnect_timer;
enum mt7697_wifi_auth_mode_t auth_mode;
u8 auto_connect;
enum mt7697_wifi_encrypt_type_t prwise_crypto;
u8 prwise_crypto_len;
enum mt7697_wifi_encrypt_type_t grp_crypto;
u8 grp_crypto_len;
u8 def_txkey_index;
struct mt7697_key keys[MT7697_MAX_KEY_INDEX + 1];
struct cfg80211_scan_request *scan_req;
bool probe_req_report;
enum mt7697_sme_state sme_state;
int reconnect_flag;
u8 listen_intvl_t;
};
static inline struct wiphy *cfg_to_wiphy(struct mt7697_cfg80211_info *cfg)
{
return cfg->wiphy;
}
static inline struct mt7697_cfg80211_info *wiphy_to_cfg(struct wiphy *w)
{
return (struct mt7697_cfg80211_info *)(wiphy_priv(w));
}
static inline struct mt7697_cfg80211_info *mt7697_priv(struct net_device *ndev)
{
return ((struct mt7697_vif*)netdev_priv(ndev))->cfg;
}
static inline struct mt7697_vif *mt7697_vif_from_wdev(struct wireless_dev *wdev)
{
return container_of(wdev, struct mt7697_vif, wdev);
}
void mt7697_init_netdev(struct net_device*);
struct wireless_dev *mt7697_interface_add(struct mt7697_cfg80211_info*,
const char*, enum nl80211_iftype, u8 fw_vif_idx);
void mt7697_tx_work(struct work_struct *);
int mt7697_data_tx(struct sk_buff*, struct net_device*);
void mt7697_disconnect_timer_hndlr(unsigned long);
int mt7697_disconnect(struct mt7697_vif*);
struct mt7697_cookie *mt7697_alloc_cookie(struct mt7697_cfg80211_info*);
void mt7697_free_cookie(struct mt7697_cfg80211_info*, struct mt7697_cookie*);
#endif
#
#*******************************************************************************
# Name: Makefile.master
#
# Notes: Makefile for mt7697 kernel module. Include files for this module must
# point to WL18xx includes from TIs kernel driver tree.
#===============================================================================
#
# Dragan Marinkovic (dragan@marisol-sys.com)
#
#*******************************************************************************
#
# Driver version
DRV_VERSION=1.0.0
#
# Note that we could have used KCFLAGS instead of CC_OPTS, and put KCFLAGS on
# make line.
#
# Make sure that arm-poky-linux-gnueabi-gcc is on you path. THe default location is:
# /opt/swi/y17-ext/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi
# The location of the kernel build directory, should be some kind of environment
# variable
KDIR := /home/david/kernel
# Root of TI driver module driver sources
TI_DRIVER_ROOT := /home/david/yocto-1.7/build_bin/tmp/work/swi_mdm9x15-poky-linux-gnueabi/ti-compat-wireless/1.0-r0/ti-compat-wireless/src/compat_wireless
# Root of MT7697 SPI queue module driver sources
MT7697_QUEUES_ROOT := /home/david/mangOH/legato/drivers/mangoh/mt7697q
# Pass version information to module
EXTRA_CFLAGS += -DVERSION=\"$(DRV_VERSION)\" -DDEBUG
EXTRA_CFLAGS += -DCPTCFG_NL80211_TESTMODE -DCPTCFG_CFG80211_DEFAULT_PS -DCPTCFG_CFG80211_DEBUGFS -DCPTCFG_CFG80211_WEXT
EXTRA_CFLAGS += -DCPTCFG_WEXT_CORE -DCPTCFG_WEXT_PROC -DCPTCFG_WEXT_SPY -DCPTCFG_WEXT_PRIV
# Kernel tree comes with some "defined but not used funnctions" warnings and
# we are going to supress it here.
EXTRA_CFLAGS += -Wno-unused-function
# It is good idea to make sure that there are no warnings
# EXTRA_CFLAGS += -Werror
# Add some missing include paths
# EXTRA_CFLAGS += -Idrivers/net/wireless/ti -I$(MODROOT)/wl12xx -I$(MODROOT) -I$(MODROOT)/drivers/net/wireless/ti
EXTRA_CFLAGS += -I$(TI_DRIVER_ROOT) -I$(MT7697_QUEUES_ROOT)
EXTRA_CFLAGS += -I$(TI_DRIVER_ROOT)/include -I$(TI_DRIVER_ROOT)/include/uapi
# Make kernel build verbose
VERBOSE += 1
TARGET := mt7697wifi_core
PWD := $(shell pwd)
ARCH := arm
CROSS_COMPILE := arm-poky-linux-gnueabi-
CC := $(CROSS_COMPILE)gcc
CC_OPTS := -O3 -Wall $(EXTRA_CFLAGS)
STRIP := $(CROSS_COMPILE)strip
MAKE := make
# Add all object files we need to make *.ko module file. Multiple lines using
# obj-m += ... would work as well.
$(TARGET)-objs := wmi.o cfg80211.o main.o txrx.o
obj-m := $(TARGET).o
all: modules
modules:
$(MAKE) -C $(KDIR) KBUILD_VERBOSE=$(VERBOSE) SUBDIRS=$(PWD) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
dist-clean: clean
@rm -f *~
clean:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) M=$(PWD) ARCH=$(ARCH) \
CROSS_COMPILE=$(CROSS_COMPILE) clean
@rm -f $(TARGET).o
@rm -f $(TARGET).mod.c
@rm -f $(TARGET).mod.o
@rm -f $(TARGET).ko
@rm -f .*.cmd
@rm -f Module.symvers
@rm -rf .tmp_versions
.PHONY: modules clean dist-clean
sources:
{
wmi.c
cfg80211.c
main.c
txrx.c
}
cflags:
{
-DDEBUG
-I$MANGOH_ROOT/linux_kernel_modules/mt7697q
}
# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8)
# The loopback interface
auto lo
iface lo inet loopback
# Wired or wireless interfaces
auto eth0
iface eth0 inet dhcp
# Wireless interfaces
#iface wlan0 inet manual
# pre-up /etc/init.d/tiwifi start
# post-down /etc/init.d/tiwifi stop
iface wlan0 inet manual
# wpa-ssid SWI-MOBILE
# wpa-psk 13811swi
pre-up /etc/init.d/mtwifi start
post-down /etc/init.d/mtwifi stop
#!/bin/sh
# Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.
#
# MediaTek wireless 7697 specific applications start or stop here
# MediaTek WIFI IoT board is managed by SPI bus.
#export PATH=$PATH:/usr/bin:/bin:/usr/sbin:/sbin
#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/tmp
mt_wifi_start() {
lsmod | grep spi-cp2130 >/dev/null
if [ $? -eq 1 ]; then
insmod /tmp/spi-cp2130.ko || exit 127
for f in `ls -d /sys/class/gpio/gpiochip*`; do echo $f `cat $f/label $f/base $f/ngpio` ; done
echo -n 0,2,6,0,0,1,2,0,0,0,0,mt7697 > /sys/devices/platform/msm_hsic_host/usb1/1-1/1-1.3/1-1.3:1.0/channel_config
fi
lsmod | grep cfg80211 >/dev/null
if [ $? -eq 1 ]; then
# modprobe cfg80211 || exit 127
insmod /tmp/cfg80211.ko || exit 127
fi
lsmod | grep cfg80211 >/dev/null
if [ $? -eq 1 ]; then
# modprobe mac80211 || exit 127
insmod /tmp/mac80211.ko || exit 127
fi
lsmod | grep mt7697q >/dev/null
if [ $? -eq 1 ]; then
insmod /tmp/mt7697q.ko || exit 127
echo "Initialized MT7697 queues"; exit 127
fi
lsmod | grep mt7697wifi_core >/dev/null
if [ $? -eq 1 ]; then
insmod /tmp/mt7697wifi_core.ko || exit 127
echo "Initialized MT7697 80211 core"; exit 127
sleep 2
fi
ifconfig -a | grep wlan0 >/dev/null
if [ $? -ne 0 ] ; then
echo "Failed to init MT7697 80211 core"; exit 127
fi
ifconfig wlan0 up >/dev/null
if [ $? -ne 0 ] ; then
echo "Failed to start MT7697 80211 core"; exit 127
fi
}
mt_wifi_stop() {
ifconfig | grep wlan0 >/dev/null
if [ $? -eq 0 ]; then
ifconfig wlan0 down
fi
lsmod | grep mt7697wifi_core >/dev/null
if [ $? -eq 0 ]; then
rmmod mt7697wifi_core || exit 127
echo "Removed MT7697 80211 core"; exit 127
fi
}
case "$1" in
start)
mt_wifi_start
;;
stop)
mt_wifi_stop
;;
restart)
mt_wifi_stop
mt_wifi_start
;;
*)
exit 1
;;
esac
exit 0
/*
* Copyright (c) 2017 Sierra Wireless Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "core.h"
int mt7697_data_tx(struct sk_buff *skb, struct net_device *ndev)
{
struct mt7697_cfg80211_info *cfg = mt7697_priv(ndev);
struct mt7697_vif *vif = netdev_priv(ndev);
struct mt7697_cookie *cookie;
int ret;
dev_dbg(cfg->dev, "%s: tx cookie cnt(%u) skb(0x%p), data(0x%p), len(%u)\n",
__func__, cfg->cookie_count, skb, skb->data, skb->len);
if (!test_bit(CONNECTED, &vif->flags)) {
dev_warn(cfg->dev, "%s: interface not associated\n", __func__);
ret = -EAGAIN;
goto fail_tx;
}
cookie = mt7697_alloc_cookie(cfg);
if (cookie == NULL) {
ret = -ENOMEM;
goto fail_tx;
}
dev_dbg(cfg->dev, "%s: tx cookie/cnt(0x%p/%u)\n",
__func__, cookie, cfg->cookie_count);
cookie->skb = skb;
schedule_work(&cfg->tx_work);
return 0;
fail_tx:
dev_kfree_skb(skb);
return ret;
}
void mt7697_tx_work(struct work_struct *work)
{
struct mt7697_cfg80211_info *cfg = container_of(work,
struct mt7697_cfg80211_info, tx_work);
struct mt7697_cookie *cookie = &cfg->cookie_mem[cfg->cookie_count];
int ret;
dev_dbg(cfg->dev, "%s: tx work cookie/cnt(0x%p/%u)\n",
__func__, cookie, cfg->cookie_count);
while (cfg->cookie_count < MT7697_MAX_COOKIE_NUM) {
print_hex_dump(KERN_DEBUG, DRVNAME" <-- Tx ", DUMP_PREFIX_OFFSET,
16, 1, cookie->skb->data, cookie->skb->len, 0);
ret = mt7697_send_tx_raw_packet(cfg, cookie->skb->data,
cookie->skb->len);
if (ret < 0) {
dev_err(cfg->dev,
"%s: mt7697_send_tx_raw_packet() failed(%d)\n",
__func__, ret);
goto cleanup;
}
dev_kfree_skb(cookie->skb);
mt7697_free_cookie(cfg, cookie);
dev_dbg(cfg->dev, "%s: tx cookie cnt(%u)\n",
__func__, cfg->cookie_count);
if (cfg->cookie_count < MT7697_MAX_COOKIE_NUM)
cookie = &cfg->cookie_mem[cfg->cookie_count];
}
cleanup:
return;
}
/*
* Copyright (c) 2017 Sierra Wireless Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _MT7697_CMD_H_
#define _MT7697_CMD_H_
#include <linux/ieee80211.h>
#include <linux/if_ether.h>
#include "wifi_api.h"
#define MT7697_LEN32_ALIGNED(x) (((x) / sizeof(u32) + \
((x) % sizeof(u32) ? 1:0)) * sizeof(u32))
#define MT7697_WOW_MAX_FILTERS_PER_LIST 4
#define MT7697_WOW_PATTERN_SIZE 64
#define mt7697_cfg_req mt7697_cmd_hdr
#define mt7697_get_radio_state_req mt7697_cmd_hdr
#define mt7697_get_rx_filter_req mt7697_cmd_hdr
#define mt7697_get_listen_interval_req mt7697_cmd_hdr
#define mt7697_scan_stop mt7697_cmd_hdr
#define mt7697_set_radio_state_rsp mt7697_rsp_hdr
#define mt7697_set_op_mode_rsp mt7697_rsp_hdr
#define mt7697_set_rx_filter_rsp mt7697_rsp_hdr
#define mt7697_set_listen_interval_rsp mt7697_rsp_hdr
#define mt7697_set_pmk_rsp mt7697_rsp_hdr
#define mt7697_set_security_mode_rsp mt7697_rsp_hdr
#define mt7697_scan_stop_rsp mt7697_rsp_hdr
enum mt7697_connect_ctrl_flags_bits {
MT7697_CONNECT_ASSOC_POLICY_USER = 0x0001,
MT7697_CONNECT_SEND_REASSOC = 0x0002,
MT7697_CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004,
MT7697_CONNECT_PROFILE_MATCH_DONE = 0x0008,
MT7697_CONNECT_IGNORE_AAC_BEACON = 0x0010,
MT7697_CONNECT_CSA_FOLLOW_BSS = 0x0020,
MT7697_CONNECT_DO_WPA_OFFLOAD = 0x0040,
MT7697_CONNECT_DO_NOT_DEAUTH = 0x0080,
MT7697_CONNECT_WPS_FLAG = 0x0100,
};
enum mt7697_cmd_grp {
MT7697_CMD_GRP_QUEUE = 0,
MT7697_CMD_GRP_80211,
MT7697_CMD_GRP_BT,
};
enum mt7697_queue_cmd_types {
MT7697_CMD_INIT = 0,
MT7697_CMD_RESET,
};
enum mt7697_wifi_cmd_types {
MT7697_CMD_MAC_ADDR_REQ = 0,
MT7697_CMD_MAC_ADDR_RSP,
MT7697_CMD_GET_CFG_REQ,
MT7697_CMD_GET_CFG_RSP,
MT7697_CMD_GET_WIRELESS_MODE_REQ,
MT7697_CMD_GET_WIRELESS_MODE_RSP,
MT7697_CMD_SET_OP_MODE_REQ,
MT7697_CMD_SET_OP_MODE_RSP,
MT7697_CMD_GET_RADIO_STATE_REQ,
MT7697_CMD_GET_RADIO_STATE_RSP,
MT7697_CMD_SET_RADIO_STATE_REQ,
MT7697_CMD_SET_RADIO_STATE_RSP,
MT7697_CMD_GET_RX_FILTER_REQ,
MT7697_CMD_GET_RX_FILTER_RSP,
MT7697_CMD_SET_RX_FILTER_REQ,
MT7697_CMD_SET_RX_FILTER_RSP,
MT7697_CMD_GET_LISTEN_INTERVAL_REQ,
MT7697_CMD_GET_LISTEN_INTERVAL_RSP,
MT7697_CMD_SET_LISTEN_INTERVAL_REQ,
MT7697_CMD_SET_LISTEN_INTERVAL_RSP,
MT7697_CMD_SET_SECURITY_MODE_REQ,
MT7697_CMD_SET_SECURITY_MODE_RSP,
MT7697_CMD_GET_SECURITY_MODE_REQ,
MT7697_CMD_GET_SECURITY_MODE_RSP,
MT7697_CMD_SCAN_REQ,
MT7697_CMD_SCAN_RSP,
MT7697_CMD_SCAN_COMPLETE,
MT7697_CMD_SCAN_STOP,
MT7697_CMD_SCAN_STOP_RSP,
MT7697_CMD_GET_PMK_REQ,
MT7697_CMD_GET_PMK_RSP,
MT7697_CMD_SET_PMK_REQ,
MT7697_CMD_SET_PMK_RSP,
MT7697_CMD_CONNECT_REQ,
MT7697_CMD_CONNECT_RSP,
MT7697_CMD_DISCONNECT_REQ,
MT7697_CMD_DISCONNECT_RSP,
MT7697_CMD_TX_RAW,
MT7697_CMD_RX_RAW,
};
struct mt7697_cfg80211_info;
struct cfg80211_scan_request;
struct mt7697_cmd_hdr {
__be16 len;
u8 grp;
u8 type;
} __attribute__((__packed__, aligned(4)));
struct mt7697_rsp_hdr {
struct mt7697_cmd_hdr cmd;
__be32 result;
} __attribute__((__packed__, aligned(4)));
struct mt7697_mac_addr_req {
struct mt7697_cmd_hdr cmd;
__be32 port;
} __attribute__((packed, aligned(4)));
struct mt7697_mac_addr {
__be16 len;
u8 data[ETH_ALEN];
} __attribute__((packed, aligned(4)));
struct mt7697_mac_addr_rsp {
struct mt7697_rsp_hdr rsp;
struct mt7697_mac_addr addr;
} __attribute__((packed, aligned(4)));
struct mt7697_get_wireless_mode_req {
struct mt7697_cmd_hdr cmd;
__be32 port;
} __attribute__((packed, aligned(4)));
struct mt7697_get_wireless_mode_rsp {
struct mt7697_rsp_hdr rsp;
__be32 mode;
} __attribute__((packed, aligned(4)));
struct mt7697_cfg_rsp {
struct mt7697_rsp_hdr rsp;
struct mt7697_wifi_config_t cfg;
} __attribute__((packed, aligned(4)));
struct mt7697_set_op_mode_req {
struct mt7697_cmd_hdr cmd;
__be32 opmode;
} __attribute__((packed, aligned(4)));
struct mt7697_get_radio_state_rsp {
struct mt7697_rsp_hdr rsp;
__be32 state;
} __attribute__((packed, aligned(4)));
struct mt7697_set_radio_state_req {
struct mt7697_cmd_hdr cmd;
__be32 state;
} __attribute__((packed, aligned(4)));
struct mt7697_get_rx_filter_rsp {
struct mt7697_rsp_hdr rsp;
__be32 rx_filter;
} __attribute__((packed, aligned(4)));
struct mt7697_set_rx_filter_req {
struct mt7697_cmd_hdr cmd;
__be32 rx_filter;
} __attribute__((packed, aligned(4)));
struct mt7697_get_listen_interval_rsp {
struct mt7697_rsp_hdr rsp;
__be32 interval;
} __attribute__((packed, aligned(4)));
struct mt7697_set_listen_interval_req {
struct mt7697_cmd_hdr cmd;
__be32 interval;
} __attribute__((packed, aligned(4)));
struct mt7697_scan_req {
struct mt7697_cmd_hdr cmd;
__be32 if_idx;
u8 mode;
u8 option;
u8 ssid_len;
u8 bssid_len;
u8 ssid_bssid[ETH_ALEN + IEEE80211_MAX_SSID_LEN];
} __attribute__((packed, aligned(4)));
struct mt7697_scan_rsp {
struct mt7697_rsp_hdr rsp;
__be32 rssi;
__be32 channel;
__be32 probe_rsp_len;
u8 probe_rsp[];
} __attribute__((packed, aligned(4)));
struct mt7697_scan_complete_rsp {
struct mt7697_rsp_hdr rsp;
__be32 if_idx;
} __attribute__((packed, aligned(4)));
struct mt7697_get_pmk_req {
struct mt7697_cmd_hdr cmd;
__be32 port;
} __attribute__((packed, aligned(4)));
struct mt7697_get_pmk_rsp {
struct mt7697_rsp_hdr rsp;
u8 pmk[MT7697_WIFI_LENGTH_PMK];
} __attribute__((packed, aligned(4)));
struct mt7697_set_pmk_req {
struct mt7697_cmd_hdr cmd;
__be32 port;
u8 pmk[MT7697_WIFI_LENGTH_PMK];
} __attribute__((packed, aligned(4)));
struct mt7697_set_security_mode_req {
struct mt7697_cmd_hdr cmd;
__be32 port;
__be32 auth_mode;
__be32 encrypt_type;
} __attribute__((packed, aligned(4)));
struct mt7697_get_security_mode_req {
struct mt7697_cmd_hdr cmd;
__be32 if_idx;
__be32 port;
} __attribute__((packed, aligned(4)));
struct mt7697_get_security_mode_rsp {
struct mt7697_rsp_hdr rsp;
__be32 if_idx;
__be32 auth_mode;
__be32 encrypt_type;
} __attribute__((packed, aligned(4)));
struct mt7697_connect_req {
struct mt7697_cmd_hdr cmd;
__be32 if_idx;
__be32 port;
__be32 channel;
__be32 bssid_len;
__be32 ssid_len;
u8 bssid_ssid[];
} __attribute__((packed, aligned(4)));
struct mt7697_connect_rsp {
struct mt7697_rsp_hdr rsp;
__be32 if_idx;
__be32 channel;
u8 bssid[ETH_ALEN];
} __attribute__((packed, aligned(4)));
struct mt7697_disconnect_req {
struct mt7697_cmd_hdr cmd;
__be32 if_idx;
__be32 addr_len;
u8 addr[];
} __attribute__((packed, aligned(4)));
struct mt7697_disconnect_rsp {
struct mt7697_rsp_hdr rsp;
__be32 if_idx;
u8 bssid[ETH_ALEN];
} __attribute__((packed, aligned(4)));
struct mt7697_tx_raw_packet {
struct mt7697_cmd_hdr cmd;
__be32 len;
u8 data[];
} __attribute__((packed, aligned(4)));
struct mt7697_rx_raw_packet {
struct mt7697_cmd_hdr cmd;
__be32 len;
u8 data[];
} __attribute__((packed, aligned(4)));
int mt7697_send_init(struct mt7697_cfg80211_info*);
int mt7697_send_reset(struct mt7697_cfg80211_info*);
int mt7697_send_get_wireless_mode_req(struct mt7697_cfg80211_info*, u8);
int mt7697_send_get_pmk_req(struct mt7697_cfg80211_info*, u8);
int mt7697_send_set_pmk_req(struct mt7697_cfg80211_info*, u8, const u8[]);
int mt7697_send_mac_addr_req(struct mt7697_cfg80211_info*, u8);
int mt7697_send_cfg_req(struct mt7697_cfg80211_info*);
int mt7697_send_set_op_mode_req(struct mt7697_cfg80211_info*, u8);
int mt7697_send_get_radio_state_req(struct mt7697_cfg80211_info*);
int mt7697_send_set_radio_state_req(struct mt7697_cfg80211_info*, u8);
int mt7697_send_get_rx_filter_req(struct mt7697_cfg80211_info*);
int mt7697_send_set_rx_filter_req(struct mt7697_cfg80211_info*, u32);
int mt7697_send_get_listen_interval_req(struct mt7697_cfg80211_info*);
int mt7697_send_set_listen_interval_req(struct mt7697_cfg80211_info*, u32);
int mt7697_send_scan_req(struct mt7697_cfg80211_info*, u32,
const struct cfg80211_scan_request*);
int mt7697_send_set_security_mode_req(struct mt7697_cfg80211_info*, u8, u8, u8);
int mt7697_send_get_security_mode_req(struct mt7697_cfg80211_info*, u32, u8);
int mt7697_send_scan_stop_req(struct mt7697_cfg80211_info*);
int mt7697_send_connect_req(struct mt7697_cfg80211_info*,
u8, u32, const u8*, const u8*, u32, u32);
int mt7697_send_disconnect_req(struct mt7697_cfg80211_info*, u32, const u8*);
int mt7697_send_tx_raw_packet(struct mt7697_cfg80211_info*, const u8*, u32);
int mt7697_proc_data(void*);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment