BigW Consortium Gitlab

Commit 82174f7c by David Clark

Updates after getting WiFi Tx and Rx working (except not both at the same time)

parent 3b911ff1
...@@ -15,197 +15,106 @@ ...@@ -15,197 +15,106 @@
*/ */
#include <linux/device.h> #include <linux/device.h>
#include <linux/gpio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include "interrupt.h" #include "interrupt.h"
#include "queue.h" #include "queue.h"
#include "io.h" #include "io.h"
/* #include "spi.h"
static void mt7697_flush_deferred_work(struct mt7697_data *wl)
{ int mt7697_irq_run(struct mt7697q_info *qinfo)
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 ret;
int loopcount = MT7697_IRQ_MAX_LOOPS; u8 ch;
bool done = false; u8 s2m_mbox;
unsigned int defer_count;
unsigned long flags;
if (unlikely(wl->state != MT7697_STATE_ON)) ret = mt7697q_get_s2m_mbx(qinfo, &s2m_mbox);
goto out; if (ret < 0) {
dev_err(qinfo->dev,
"%s(): mt7697q_get_s2m_mbx() failed(%d)\n",
__func__, ret);
goto cleanup;
}
while (!done && loopcount--) { if (s2m_mbox) {
clear_bit(MT7697_FLAG_IRQ_RUNNING, &wl->flags); if (!queue_delayed_work(qinfo->irq_workq,
&qinfo->irq_delayed_work, usecs_to_jiffies(100))) {
dev_err(qinfo->dev,
"%s(): queue_delayed_work() failed\n",
__func__);
ret = -EINVAL;
}
}
else
enable_irq(qinfo->irq);
ret = mt7697_rx(wl); for (ch = 0; ch < MT7697_NUM_QUEUES; ch++) {
if (ret < 0) { struct mt7697q_spec *qs = &qinfo->queues[ch];
dev_err(wl->dev, "%s(): mt7697_rx() failed(%d)\n", __func__, ret); u32 in_use = mt7697q_flags_get_in_use(qs->data.flags);
goto out; u32 dir = mt7697q_flags_get_dir(qs->data.flags);
}
*/ if (in_use &&
/* Check if any tx blocks were freed */ (s2m_mbox & (0x01 << ch)) &&
/* spin_lock_irqsave(&wl->lock, flags); (dir == MT7697_QUEUE_DIR_S2M)) {
if (!test_bit(MT7697_FLAG_FW_TX_BUSY, &wl->flags) && ret = mt7697q_proc_data(qs);
mt7697_tx_total_queue_count(wl) > 0) { if (ret < 0) {
spin_unlock_irqrestore(&wl->lock, flags);*/ dev_err(qinfo->dev,
/* "%s(): mt7697q_proc_data() failed(%d)\n",
* In order to avoid starvation of the TX path, __func__, ret);
* call the work function directly. goto cleanup;
*/ }
/* 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: cleanup:
return ret; return ret;
}*/ }
/*
irqreturn_t mt7697_irq(int irq, void *cookie) void mt7697_irq_delayed_work(struct work_struct *irq_delayed_work)
{ {
struct mt7697_data *wl = cookie; struct mt7697q_info *qinfo = container_of(irq_delayed_work,
struct mt7697q_info, irq_delayed_work.work);
int ret; int ret;
unsigned long flags;
dev_dbg(qinfo->dev, "%s(): process work\n", __func__);
spin_lock_irqsave(&wl->lock, flags); ret = mt7697_irq_run(qinfo);
if (ret < 0) {
if (test_bit(MT7697_FLAG_SUSPENDED, &wl->flags)) {*/ dev_err(qinfo->dev, "%s(): mt7697_irq_run() failed(%d)\n",
/* don't enqueue a work right now. mark it as pending */ __func__, ret);
/* set_bit(MT7697_FLAG_PENDING_WORK, &wl->flags); goto cleanup;
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);*/ cleanup:
/* In case TX was not handled here, queue TX work */ return;
/* 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) void mt7697_irq_work(struct work_struct *irq_work)
{ {
struct mt7697q_info *qinfo = container_of(irq_work, struct mt7697q_info *qinfo = container_of(irq_work,
struct mt7697q_info, irq_work); struct mt7697q_info, irq_work);
int ch;
int ret; int ret;
mutex_lock(&qinfo->mutex); dev_dbg(qinfo->dev, "%s(): process work\n", __func__);
ret = mt7697_irq_run(qinfo);
ret = mt7697io_rd_s2m_mbx(qinfo); if (ret < 0) {
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, dev_err(qinfo->dev,
"%s(): mt7697io_clr_s2m_mbx() failed(%d)\n", "%s(): mt7697_irq_run() failed(%d)\n",
__func__, ret); __func__, ret);
goto cleanup; 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);
mutex_unlock(&qinfo->mutex);
ret = qs->rx_fcn(qs->priv);
if (ret < 0) {
dev_err(qinfo->dev,
"%s(): rx_fcn() failed(%d)\n",
__func__, ret);
}
mutex_lock(&qinfo->mutex);
}
else if (!in_use) {
dev_warn(qinfo->dev,
"%s(): unused channel(%d)\n",
__func__, ch);
}
}
}
cleanup: cleanup:
ret = queue_delayed_work(qinfo->irq_workq, &qinfo->irq_work, return;
msecs_to_jiffies(100));
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) irqreturn_t mt7697_isr(int irq, void *cookie)
{ {
/* struct mt7697q_info *qinfo = cookie; struct mt7697q_info *qinfo = cookie;
int err = queue_work(qinfo->irq_workq, &qinfo->irq_work);
if (err < 0) { disable_irq_nosync(qinfo->irq);
dev_err(qinfo->dev, "queue_work() failed(%d)\n", err); if (!queue_work(qinfo->irq_workq, &qinfo->irq_work)) {
}*/ dev_err(qinfo->dev, "%s(): queue_work() failed\n", __func__);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -19,10 +19,7 @@ ...@@ -19,10 +19,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#define MT7697_USBHUB_IRQ_PIN 6 irqreturn_t mt7697_isr(int, void*);
#define MT7697_IRQ_MAX_LOOPS 256
irqreturn_t mt7697_irq(int, void*);
void mt7697_irq_work(struct work_struct*); void mt7697_irq_work(struct work_struct*);
#endif #endif
...@@ -21,6 +21,12 @@ ...@@ -21,6 +21,12 @@
#include "io.h" #include "io.h"
#include "spi.h" #include "spi.h"
static __inline u8 mt7697io_busy(u16 value)
{
return BF_GET(value, MT7697_IO_STATUS_REG_BUSY_OFFSET,
MT7697_IO_STATUS_REG_BUSY_WIDTH);
}
static int mt7697io_write16(struct mt7697q_info *qinfo, u8 reg, u16 value) static int mt7697io_write16(struct mt7697q_info *qinfo, u8 reg, u16 value)
{ {
int ret; int ret;
...@@ -131,7 +137,7 @@ static int mt7697io_chk_slave_busy(struct mt7697q_info *qinfo) ...@@ -131,7 +137,7 @@ static int mt7697io_chk_slave_busy(struct mt7697q_info *qinfo)
goto cleanup; goto cleanup;
} }
qinfo->slave_busy = mt7697q_busy(value) == MT7697_IO_STATUS_REG_BUSY_VAL_BUSY; qinfo->slave_busy = mt7697io_busy(value) == MT7697_IO_STATUS_REG_BUSY_VAL_BUSY;
cleanup: cleanup:
return ret; return ret;
...@@ -206,7 +212,7 @@ int mt7697io_rd_s2m_mbx(struct mt7697q_info *qinfo) ...@@ -206,7 +212,7 @@ int mt7697io_rd_s2m_mbx(struct mt7697q_info *qinfo)
} }
qinfo->s2m_mbox = mt7697io_get_s2m_mbox(value); qinfo->s2m_mbox = mt7697io_get_s2m_mbox(value);
dev_dbg(qinfo->dev, "%s(): s2m mbx(0x%04x)\n", dev_dbg(qinfo->dev, "%s(): s2m mbx(0x%02x)\n",
__func__, qinfo->s2m_mbox); __func__, qinfo->s2m_mbox);
cleanup: cleanup:
...@@ -346,9 +352,7 @@ cleanup: ...@@ -346,9 +352,7 @@ cleanup:
int mt7697io_trigger_intr(struct mt7697q_info *qinfo) int mt7697io_trigger_intr(struct mt7697q_info *qinfo)
{ {
int ret; int ret = mt7697io_write16(qinfo, MT7697_IO_SLAVE_REG_IRQ,
ret = mt7697io_write16(qinfo, MT7697_IO_SLAVE_REG_IRQ,
BF_DEFINE(MT7697_IO_IRQ_REG_IRQ_STATUS_VAL_ACTIVE, BF_DEFINE(MT7697_IO_IRQ_REG_IRQ_STATUS_VAL_ACTIVE,
MT7697_IO_IRQ_REG_IRQ_STATUS_OFFSET, MT7697_IO_IRQ_REG_IRQ_STATUS_OFFSET,
MT7697_IO_IRQ_REG_IRQ_STATUS_WIDTH)); MT7697_IO_IRQ_REG_IRQ_STATUS_WIDTH));
......
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
#define MT7697_IO_IRQ_REG_IRQ_STATUS_VAL_ACTIVE 1 #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_OFFSET 0
#define MT7697_IO_S2M_MAILBOX_REG_MAILBOX_WIDTH 7 #define MT7697_IO_S2M_MAILBOX_REG_MAILBOX_WIDTH 6
#define MT7697_IO_M2S_MAILBOX_REG_MAILBOX_OFFSET 0 #define MT7697_IO_M2S_MAILBOX_REG_MAILBOX_OFFSET 0
#define MT7697_IO_M2S_MAILBOX_REG_MAILBOX_WIDTH 7 #define MT7697_IO_M2S_MAILBOX_REG_MAILBOX_WIDTH 7
......
...@@ -18,9 +18,10 @@ ...@@ -18,9 +18,10 @@
#define _MT7697_QUEUE_H_ #define _MT7697_QUEUE_H_
#include <linux/types.h> #include <linux/types.h>
#include <linux/interrupt.h>
#include "queue_i.h" #include "queue_i.h"
#define MT7697_NUM_QUEUES 7 #define MT7697_NUM_QUEUES 6
#define MT7697_QUEUE_FLAGS_IN_USE_OFFSET 0 #define MT7697_QUEUE_FLAGS_IN_USE_OFFSET 0
#define MT7697_QUEUE_FLAGS_IN_USE_WIDTH 1 #define MT7697_QUEUE_FLAGS_IN_USE_WIDTH 1
...@@ -33,14 +34,14 @@ ...@@ -33,14 +34,14 @@
#define MT7697_QUEUE_DEBUG_DUMP_LIMIT 1024 #define MT7697_QUEUE_DEBUG_DUMP_LIMIT 1024
typedef int (*rx_hndlr)(void*);
struct mt7697q_data { struct mt7697q_data {
u32 flags; u32 flags;
u32 base_addr; u32 base_addr;
u32 rd_offset; u16 rd_offset;
u32 wr_offset; u16 reserved1;
} __attribute__((packed)); u16 wr_offset;
u16 reserved2;
};
struct mt7697q_spec { struct mt7697q_spec {
struct mt7697q_data data; struct mt7697q_data data;
...@@ -52,6 +53,7 @@ struct mt7697q_spec { ...@@ -52,6 +53,7 @@ struct mt7697q_spec {
struct mt7697q_info { struct mt7697q_info {
struct mt7697q_spec queues[MT7697_NUM_QUEUES]; struct mt7697q_spec queues[MT7697_NUM_QUEUES];
struct mt7697q_rsp_hdr rsp;
u8 txBuffer[sizeof(u32)]; u8 txBuffer[sizeof(u32)];
u8 rxBuffer[sizeof(u16)]; u8 rxBuffer[sizeof(u16)];
...@@ -62,30 +64,18 @@ struct mt7697q_info { ...@@ -62,30 +64,18 @@ struct mt7697q_info {
struct mutex mutex; struct mutex mutex;
struct workqueue_struct *irq_workq; struct workqueue_struct *irq_workq;
// struct work_struct irq_work; struct work_struct irq_work;
struct delayed_work irq_work; struct delayed_work irq_delayed_work;
int irq; int irq;
u8 s2m_mbox; u8 s2m_mbox;
bool slave_busy; bool slave_busy;
}; };
u8 mt7697q_busy(u16); void mt7697_irq_delayed_work(struct work_struct*);
u8 mt7697q_get_s2m_mbox(u16); void mt7697_irq_work(struct work_struct*);
u16 mt7697q_set_s2m_mbox(u8); irqreturn_t mt7697_isr(int, void*);
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*); int mt7697q_proc_data(struct mt7697q_spec*);
size_t mt7697q_get_num_words(const void*); int mt7697q_get_s2m_mbx(struct mt7697q_info*, u8*);
size_t mt7697q_get_free_words(const void*);
#endif #endif
...@@ -17,49 +17,83 @@ ...@@ -17,49 +17,83 @@
#ifndef _MT7697_QUEUE_I_H_ #ifndef _MT7697_QUEUE_I_H_
#define _MT7697_QUEUE_I_H_ #define _MT7697_QUEUE_I_H_
#define MT7697_QUEUE_LEN_TO_WORD(x) ((x) / sizeof(u32) + \ #define LEN32_ALIGNED(x) (((x) / sizeof(u32) + \
((x) % sizeof(u32) ? 1:0)) ((x) % sizeof(u32) ? 1:0)) * sizeof(u32))
#define LEN_TO_WORD(x) ((x) / sizeof(u32) + \
((x) % sizeof(u32) ? 1:0))
#define mt7697_queue_init_rsp mt7697q_rsp_hdr
#define mt7697_queue_unused_rsp mt7697q_rsp_hdr
#define mt7697_queue_reset_rsp mt7697q_rsp_hdr
enum mt7697q_dir enum mt7697q_dir
{ {
MT7697_QUEUE_DIR_MASTER_TO_SLAVE = 0, MT7697_QUEUE_DIR_M2S = 0,
MT7697_QUEUE_DIR_SLAVE_TO_MASTER, MT7697_QUEUE_DIR_S2M,
};
enum mt7697q_cmd_grp {
MT7697_CMD_GRP_QUEUE = 0,
MT7697_CMD_GRP_80211,
MT7697_CMD_GRP_BT,
}; };
typedef int (*rx_hndlr)(void*); enum mt7697q_cmd_types {
MT7697_CMD_QUEUE_INIT = 0,
MT7697_CMD_QUEUE_INIT_RSP,
MT7697_CMD_QUEUE_UNUSED,
MT7697_CMD_QUEUE_UNUSED_RSP,
MT7697_CMD_QUEUE_RESET,
MT7697_CMD_QUEUE_RESET_RSP,
};
struct mt7697q_cmd_hdr {
__be16 len;
u8 grp;
u8 type;
} __attribute__((__packed__, aligned(4)));
struct mt7697q_rsp_hdr {
struct mt7697q_cmd_hdr cmd;
__be32 result;
} __attribute__((__packed__, aligned(4)));
struct mt7697_queue_init_req {
struct mt7697q_cmd_hdr cmd;
__be32 m2s_ch;
__be32 s2m_ch;
} __attribute__((packed, aligned(4)));
struct mt7697_queue_unused_req {
struct mt7697q_cmd_hdr cmd;
__be32 m2s_ch;
__be32 s2m_ch;
} __attribute__((packed, aligned(4)));
struct mt7697_queue_reset_req {
struct mt7697q_cmd_hdr cmd;
__be32 m2s_ch;
__be32 s2m_ch;
} __attribute__((packed, aligned(4)));
typedef int (*rx_hndlr)(const struct mt7697q_rsp_hdr*, void*);
struct mt7697q_if_ops { struct mt7697q_if_ops {
void* (*init)(u8, void*, rx_hndlr); int (*init)(u8, u8, void*, rx_hndlr, void**, void**);
size_t (*read)(void*, u32*, size_t); size_t (*read)(void*, u32*, size_t);
size_t (*write)(void*, const 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 (*reset)(void*);
void (*enable_irq)(void*); void (*enable_irq)(void*);
void (*disable_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_in_use(u32);
u32 mt7697q_flags_get_dir(u32); u32 mt7697q_flags_get_dir(u32);
void* mt7697q_init(u8, void*, rx_hndlr); int mt7697q_init(u8, u8, void*, rx_hndlr, void**, void**);
size_t mt7697q_read(void*, u32*, size_t); size_t mt7697q_read(void*, u32*, size_t);
size_t mt7697q_write(void*, const u32*, size_t); size_t mt7697q_write(void*, const u32*, size_t);
int mt7697q_pull_rd_ptr(void*); int mt7697q_send_reset(void*, 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 #endif
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/gpio.h>
#include "interrupt.h" #include "interrupt.h"
#include "queue.h" #include "queue.h"
#include "spi.h" #include "spi.h"
...@@ -35,12 +36,16 @@ static void mt7697spi_reset(struct spi_device *spi) ...@@ -35,12 +36,16 @@ static void mt7697spi_reset(struct spi_device *spi)
static void mt7697spi_enable_irq(struct spi_device *spi) static void mt7697spi_enable_irq(struct spi_device *spi)
{ {
enable_irq(spi->irq); struct mt7697q_info *qinfo = spi_get_drvdata(spi);
WARN_ON(!qinfo);
enable_irq(qinfo->irq);
} }
static void mt7697spi_disable_irq(struct spi_device *spi) static void mt7697spi_disable_irq(struct spi_device *spi)
{ {
disable_irq(spi->irq); struct mt7697q_info *qinfo = spi_get_drvdata(spi);
WARN_ON(!qinfo);
disable_irq(qinfo->irq);
} }
static const struct mt7697spi_hw_ops hw_ops = static const struct mt7697spi_hw_ops hw_ops =
...@@ -62,6 +67,10 @@ static int __init mt7697spi_init(void) ...@@ -62,6 +67,10 @@ static int __init mt7697spi_init(void)
struct mt7697q_info *qinfo; struct mt7697q_info *qinfo;
int ret = 0; int ret = 0;
pr_info(DRVNAME" %s(): '%s' initialize\n", __func__, DRVNAME);
pr_info(DRVNAME" %s(): get SPI master bus(%u)\n",
__func__, MT7697_SPI_BUS_NUM);
master = spi_busnum_to_master(MT7697_SPI_BUS_NUM); master = spi_busnum_to_master(MT7697_SPI_BUS_NUM);
if (!master) { if (!master) {
pr_err(DRVNAME" spi_busnum_to_master(%d) failed\n", pr_err(DRVNAME" spi_busnum_to_master(%d) failed\n",
...@@ -70,27 +79,31 @@ static int __init mt7697spi_init(void) ...@@ -70,27 +79,31 @@ static int __init mt7697spi_init(void)
} }
snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), MT7697_SPI_CS); snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), MT7697_SPI_CS);
pr_info(DRVNAME" find SPI device('%s')\n", str); dev_info(&master->dev, "%s(): find SPI device('%s')\n", __func__, str);
dev = bus_find_device_by_name(&spi_bus_type, NULL, str); dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
if (!dev) { if (!dev) {
pr_err(DRVNAME" '%s' bus_find_device_by_name() failed\n", str); dev_err(&master->dev,
"%s(): '%s' bus_find_device_by_name() failed\n",
__func__, str);
goto cleanup; goto cleanup;
} }
spi = container_of(dev, struct spi_device, dev); spi = container_of(dev, struct spi_device, dev);
if (!spi) { if (!spi) {
pr_err(DRVNAME" get SPI device failed\n"); dev_err(&master->dev, "%s(): get SPI device failed\n",
__func__);
goto cleanup; goto cleanup;
} }
pr_info(DRVNAME" init dev('%s') mode(%d) max speed(%d) " dev_info(&master->dev, "%s(): init dev('%s') mode(%d) max speed(%d) "
"CS(%d) GPIO(%d) bits/word(%d)\n", "CS(%d) GPIO(%d) bits/word(%d)\n",
spi->modalias, spi->mode, spi->max_speed_hz, spi->chip_select, __func__, spi->modalias, spi->mode, spi->max_speed_hz,
spi->cs_gpio, spi->bits_per_word); spi->chip_select, spi->cs_gpio, spi->bits_per_word);
qinfo = kzalloc(sizeof(struct mt7697q_info), GFP_KERNEL); qinfo = kzalloc(sizeof(struct mt7697q_info), GFP_KERNEL);
if (!qinfo) { if (!qinfo) {
pr_err(DRVNAME" create queue info failed\n"); dev_err(&master->dev, "%s(): create queue info failed\n",
__func__);
ret = -ENOMEM; ret = -ENOMEM;
goto cleanup; goto cleanup;
} }
...@@ -102,40 +115,47 @@ static int __init mt7697spi_init(void) ...@@ -102,40 +115,47 @@ static int __init mt7697spi_init(void)
qinfo->hw_ops = &hw_ops; qinfo->hw_ops = &hw_ops;
mutex_init(&qinfo->mutex); mutex_init(&qinfo->mutex);
INIT_DELAYED_WORK(&qinfo->irq_delayed_work, mt7697_irq_delayed_work);
INIT_WORK(&qinfo->irq_work, mt7697_irq_work);
qinfo->irq_workq = create_workqueue(DRVNAME); qinfo->irq_workq = create_workqueue(DRVNAME"wq");
if (!qinfo) { if (!qinfo->irq_workq) {
pr_err(DRVNAME" create_workqueue() failed\n"); dev_err(qinfo->dev, "%s(): create_workqueue() failed\n",
__func__);
ret = -ENOMEM; ret = -ENOMEM;
goto cleanup; goto cleanup;
} }
/* TODO: revove after CP2130 working */ ret = gpio_request(MT7697_SPI_INTR_GPIO_PIN, MT7697_GPIO_IRQ_NAME);
INIT_DELAYED_WORK(&qinfo->irq_work, mt7697_irq_work); if (ret < 0) {
// INIT_WORK(&qinfo->irq_work, mt7697_irq_work); dev_err(qinfo->dev, "%s(): gpio_request() failed(%d)",
qinfo->irq = spi->irq; __func__, ret);
dev_info(qinfo->dev, "'%s' request irq(%d)\n", spi->modalias, spi->irq); goto failed_workqueue;
/* ret = request_irq(spi->irq, mt7697_irq, }
IRQF_SHARED| IRQF_NO_SUSPEND, spi->modalias, qinfo);
gpio_direction_input(MT7697_SPI_INTR_GPIO_PIN);
qinfo->irq = gpio_to_irq(MT7697_SPI_INTR_GPIO_PIN);
dev_info(qinfo->dev, "%s(): request irq(%d)\n", __func__, qinfo->irq);
ret = request_irq(qinfo->irq, mt7697_isr, 0, DRVNAME, qinfo);
if (ret < 0) { if (ret < 0) {
pr_err(DRVNAME" request_irq() failed(%d)", ret); dev_err(qinfo->dev, "%s(): request_irq() failed(%d)",
goto failed_irq; __func__, ret);
goto failed_gpio_req;
} }
*/
irq_set_irq_type(qinfo->irq, IRQ_TYPE_EDGE_BOTH);
spi_set_drvdata(spi, qinfo); spi_set_drvdata(spi, qinfo);
/* TODO: revove after CP2130 working */ dev_info(qinfo->dev, "%s(): '%s' initialized\n", __func__, DRVNAME);
ret = queue_delayed_work(qinfo->irq_workq, &qinfo->irq_work,
msecs_to_jiffies(1000));
if (ret < 0) {
dev_err(qinfo->dev,
"queue_delayed_work() failed(%d)\n", ret);
}
return 0; return 0;
/*failed_irq: failed_workqueue:
destroy_workqueue(qinfo->irq_workq); destroy_workqueue(qinfo->irq_workq);
free_irq(spi->irq, qinfo);*/
failed_gpio_req:
gpio_free(MT7697_SPI_INTR_GPIO_PIN);
cleanup: cleanup:
kfree(qinfo); kfree(qinfo);
return ret; return ret;
...@@ -149,36 +169,49 @@ static void __exit mt7697spi_exit(void) ...@@ -149,36 +169,49 @@ static void __exit mt7697spi_exit(void)
struct spi_device *spi; struct spi_device *spi;
struct mt7697q_info *qinfo; struct mt7697q_info *qinfo;
pr_info(DRVNAME" %s(): get SPI master bus(%u)\n",
__func__, MT7697_SPI_BUS_NUM);
master = spi_busnum_to_master(MT7697_SPI_BUS_NUM); master = spi_busnum_to_master(MT7697_SPI_BUS_NUM);
if (!master) { if (!master) {
pr_err(DRVNAME" spi_busnum_to_master(%d) failed\n", pr_err(DRVNAME" %s(): spi_busnum_to_master(%d) failed\n",
MT7697_SPI_BUS_NUM); __func__, MT7697_SPI_BUS_NUM);
goto cleanup; goto cleanup;
} }
snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), MT7697_SPI_CS); snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), MT7697_SPI_CS);
pr_info(DRVNAME" find SPI device('%s')\n", str); dev_info(&master->dev, "%s(): find SPI device('%s')\n", __func__, str);
dev = bus_find_device_by_name(&spi_bus_type, NULL, str); dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
if (!dev) { if (!dev) {
pr_err(DRVNAME" '%s' bus_find_device_by_name() failed\n", str); dev_err(&master->dev,
"%s(): '%s' bus_find_device_by_name() failed\n",
__func__, str);
goto cleanup; goto cleanup;
} }
spi = container_of(dev, struct spi_device, dev); spi = container_of(dev, struct spi_device, dev);
if (!spi) { if (!spi) {
pr_err(DRVNAME" get SPI device failed\n"); dev_err(dev, "%s(): get SPI device failed\n",
__func__);
goto cleanup; goto cleanup;
} }
qinfo = spi_get_drvdata(spi); qinfo = spi_get_drvdata(spi);
if (qinfo) { if (!qinfo) {
dev_info(qinfo->dev, "remove\n"); dev_err(dev, "%s(): SPI device no queue info\n",
flush_workqueue(qinfo->irq_workq); __func__);
destroy_workqueue(qinfo->irq_workq); goto cleanup;
// free_irq(spi->irq, qinfo);
kfree(qinfo);
} }
dev_info(qinfo->dev, "%s(): remove '%s'\n", __func__, DRVNAME);
cancel_delayed_work_sync(&qinfo->irq_delayed_work);
cancel_work_sync(&qinfo->irq_work);
flush_workqueue(qinfo->irq_workq);
destroy_workqueue(qinfo->irq_workq);
free_irq(qinfo->irq, qinfo);
gpio_free(MT7697_SPI_INTR_GPIO_PIN);
kfree(qinfo);
cleanup: cleanup:
return; return;
} }
......
...@@ -24,9 +24,12 @@ ...@@ -24,9 +24,12 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#define DRVNAME "mt7697q" #define DRVNAME "mt7697q"
#define MT7697_SPI_BUS_NUM 32766 #define MT7697_GPIO_IRQ_NAME "mt7697q irq"
#define MT7697_SPI_CS 0
#define MT7697_SPI_INTR_GPIO_PIN 50//21
#define MT7697_SPI_BUS_NUM 32766
#define MT7697_SPI_CS 0
struct mt7697spi_hw_ops { struct mt7697spi_hw_ops {
int (*write)(struct spi_device*, const void*, size_t); int (*write)(struct spi_device*, const void*, size_t);
......
- use variable length fields
- use msg to set if idx for each mode (STA, AP)
- connect/scan/connect failed - need to notify cfg of disconnect
- master to slave rd offset corrupted
- use memory pool for MT7697 SPI messages
/*
* 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_COMMON_H_
#define _MT7697_COMMON_H_
struct mt7697_llc_snap_hdr {
u8 dsap;
u8 ssap;
u8 cntl;
u8 org_code[3];
__be16 eth_type;
} __packed;
#endif
...@@ -100,10 +100,8 @@ struct mt7697_cfg80211_info { ...@@ -100,10 +100,8 @@ struct mt7697_cfg80211_info {
struct work_struct tx_work; struct work_struct tx_work;
struct mt7697_tx_raw_packet tx_req; struct mt7697_tx_raw_packet tx_req;
u8 rx_data[MT7697_LEN32_ALIGNED(IEEE80211_MAX_FRAME_LEN)]; u8 rx_data[LEN32_ALIGNED(IEEE80211_MAX_FRAME_LEN)];
u8 probe_data[MT7697_LEN32_ALIGNED(IEEE80211_MAX_DATA_LEN)]; u8 probe_data[LEN32_ALIGNED(IEEE80211_MAX_DATA_LEN)];
struct mt7697_rsp_hdr rsp;
enum mt7697_radio_state radio_state; enum mt7697_radio_state radio_state;
enum mt7697_wifi_phy_mode_t wireless_mode; enum mt7697_wifi_phy_mode_t wireless_mode;
...@@ -113,6 +111,7 @@ struct mt7697_cfg80211_info { ...@@ -113,6 +111,7 @@ struct mt7697_cfg80211_info {
int listen_interval; int listen_interval;
enum mt7697_wifi_rx_filter_t rx_filter; enum mt7697_wifi_rx_filter_t rx_filter;
u8 smart_conn_filter; u8 smart_conn_filter;
u8 reg_rx_hndlr;
u8 psk[MT7697_PASSPHRASE_LEN]; u8 psk[MT7697_PASSPHRASE_LEN];
struct list_head vif_list; struct list_head vif_list;
...@@ -171,6 +170,8 @@ struct mt7697_vif { ...@@ -171,6 +170,8 @@ struct mt7697_vif {
enum mt7697_sme_state sme_state; enum mt7697_sme_state sme_state;
int reconnect_flag; int reconnect_flag;
u8 listen_intvl_t; u8 listen_intvl_t;
struct net_device_stats net_stats;
}; };
static inline struct wiphy *cfg_to_wiphy(struct mt7697_cfg80211_info *cfg) static inline struct wiphy *cfg_to_wiphy(struct mt7697_cfg80211_info *cfg)
...@@ -200,7 +201,8 @@ struct wireless_dev *mt7697_interface_add(struct mt7697_cfg80211_info*, ...@@ -200,7 +201,8 @@ struct wireless_dev *mt7697_interface_add(struct mt7697_cfg80211_info*,
const char*, enum nl80211_iftype, u8 fw_vif_idx); const char*, enum nl80211_iftype, u8 fw_vif_idx);
void mt7697_tx_work(struct work_struct *); void mt7697_tx_work(struct work_struct *);
int mt7697_data_tx(struct sk_buff*, struct net_device*); int mt7697_data_tx(struct sk_buff*, struct net_device*);
int mt7697_rx_data(struct mt7697_cfg80211_info*, u32); int mt7697_rx_data(struct mt7697_cfg80211_info*, u32, u32);
int mt7697_proc_80211cmd(const struct mt7697q_rsp_hdr*, void*);
void mt7697_disconnect_timer_hndlr(unsigned long); void mt7697_disconnect_timer_hndlr(unsigned long);
int mt7697_disconnect(struct mt7697_vif*); int mt7697_disconnect(struct mt7697_vif*);
......
...@@ -13,7 +13,7 @@ mt_wifi_start() { ...@@ -13,7 +13,7 @@ mt_wifi_start() {
if [ $? -eq 1 ]; then if [ $? -eq 1 ]; then
insmod /tmp/spi-cp2130.ko || exit 127 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 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.1/1-1.1:1.0/channel_config echo -n 0,2,-1,0,0,1,0,0,0,0,0,mt7697 > /sys/devices/platform/msm_hsic_host/usb1/1-1/1-1.1/1-1.1:1.0/channel_config
fi fi
lsmod | grep cfg80211 >/dev/null lsmod | grep cfg80211 >/dev/null
......
...@@ -15,37 +15,172 @@ ...@@ -15,37 +15,172 @@
*/ */
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include "common.h"
#include "core.h" #include "core.h"
static int mt7697_80211_to_ethernet(struct sk_buff *skb,
struct net_device *ndev)
{
struct mt7697_cfg80211_info *cfg = mt7697_priv(ndev);
struct mt7697_vif *vif = netdev_priv(ndev);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr*) skb->data;
struct ethhdr *ehdr;
u8 *payload;
u16 hdrlen, ethertype;
__be16 len;
u8 dst[ETH_ALEN];
u8 src[ETH_ALEN] __aligned(2);
int ret = 0;
print_hex_dump(KERN_DEBUG, DRVNAME" --> Rx 802.11 Frame",
DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, 0);
if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
dev_warn(cfg->dev, "%s(): no data present\n", __func__);
ret = -EINVAL;
goto cleanup;
}
hdrlen = ieee80211_hdrlen(hdr->frame_control);
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
* header
* IEEE 802.11 address fields:
* ToDS FromDS Addr1 Addr2 Addr3 Addr4
* 0 0 DA SA BSSID n/a
* 0 1 DA BSSID SA n/a
* 1 0 BSSID SA DA n/a
* 1 1 RA TA DA SA
*/
memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
if (!pskb_may_pull(skb, hdrlen + 8)) {
dev_warn(cfg->dev, "%s(): pskb_may_pull() failed\n", __func__);
ret = -EINVAL;
goto cleanup;
}
payload = skb->data + hdrlen;
ethertype = (payload[6] << 8) | payload[7];
skb_pull(skb, hdrlen);
len = htons(skb->len);
ehdr = (struct ethhdr*)skb_push(skb, sizeof(struct ethhdr));
memcpy(ehdr->h_dest, dst, ETH_ALEN);
memcpy(ehdr->h_source, src, ETH_ALEN);
ehdr->h_proto = len;
print_hex_dump(KERN_DEBUG, DRVNAME" Rx 802.3 Frame ",
DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, 0);
if (!is_broadcast_ether_addr(ehdr->h_dest))
vif->net_stats.multicast++;
cleanup:
return ret;
}
static void mt7697_ethernet_to_80211(struct sk_buff *skb,
struct net_device *ndev)
{
struct ieee80211_hdr hdr;
struct mt7697_cfg80211_info *cfg = mt7697_priv(ndev);
struct mt7697_vif *vif = netdev_priv(ndev);
struct ethhdr *eth_hdr = (struct ethhdr*)skb->data;
struct mt7697_llc_snap_hdr *llc_hdr;
u8 *datap;
__be16 type = eth_hdr->h_proto;
__le16 fc;
u16 hdrlen;
dev_dbg(cfg->dev, "%s(): Tx 802.3 Frame len(%u)\n", __func__, skb->len);
print_hex_dump(KERN_DEBUG, DRVNAME" 802.3 Frame ", DUMP_PREFIX_OFFSET,
16, 1, skb->data, skb->len, 0);
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
// fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
/* DA BSSID SA */
hdr.frame_control = fc;
hdr.duration_id = 0;
// memcpy(hdr.addr1, eth_hdr->h_dest, ETH_ALEN);
// memcpy(hdr.addr2, vif->bssid, ETH_ALEN);
// memcpy(hdr.addr3, eth_hdr->h_source, ETH_ALEN);
memcpy(hdr.addr1, vif->bssid, ETH_ALEN);
memcpy(hdr.addr2, eth_hdr->h_source, ETH_ALEN);
memcpy(hdr.addr3, eth_hdr->h_dest, ETH_ALEN);
hdr.seq_ctrl = 0;
hdrlen = sizeof(struct ieee80211_hdr_3addr);
datap = skb_push(skb, hdrlen + sizeof(struct mt7697_llc_snap_hdr) - sizeof(struct ethhdr));
memcpy(datap, &hdr, hdrlen);
llc_hdr = (struct mt7697_llc_snap_hdr*)(datap + hdrlen);
llc_hdr->dsap = 0xAA;
llc_hdr->ssap = 0xAA;
llc_hdr->cntl = 0x03;
llc_hdr->org_code[0] = 0x0;
llc_hdr->org_code[1] = 0x0;
llc_hdr->org_code[2] = 0x0;
llc_hdr->eth_type = type;
dev_dbg(cfg->dev, "%s(): Tx 802.11 Frame len(%u)\n",
__func__, skb->len);
print_hex_dump(KERN_DEBUG, DRVNAME" <-- Tx 802.11 Frame ", DUMP_PREFIX_OFFSET,
16, 1, skb->data, skb->len, 0);
}
int mt7697_data_tx(struct sk_buff *skb, struct net_device *ndev) int mt7697_data_tx(struct sk_buff *skb, struct net_device *ndev)
{ {
struct mt7697_cfg80211_info *cfg = mt7697_priv(ndev); struct mt7697_cfg80211_info *cfg = mt7697_priv(ndev);
struct mt7697_vif *vif = netdev_priv(ndev); struct mt7697_vif *vif = netdev_priv(ndev);
struct mt7697_cookie *cookie; struct mt7697_cookie *cookie;
int ret; int ret = 0;
dev_dbg(cfg->dev, "%s: tx cookie cnt(%u) skb(0x%p), data(0x%p), len(%u)\n", 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); __func__, cfg->cookie_count, skb, skb->data, skb->len);
if (!test_bit(CONNECTED, &vif->flags)) { if (!test_bit(CONNECTED, &vif->flags)) {
dev_warn(cfg->dev, "%s: interface not associated\n", __func__); dev_warn(cfg->dev, "%s(): interface not associated\n",
__func__);
ret = -EAGAIN; ret = -EAGAIN;
goto fail_tx; goto cleanup;
} }
dev_dbg(cfg->dev, "%s(): headroom skb/needed(%u/%u)\n",
__func__, skb_headroom(skb), ndev->needed_headroom);
if (skb_headroom(skb) < ndev->needed_headroom) {
struct sk_buff *tmp_skb = skb;
skb = skb_realloc_headroom(skb, ndev->needed_headroom);
kfree_skb(tmp_skb);
if (skb == NULL) {
dev_dbg(cfg->dev, "%s(): tx dropped\n", __func__);
goto cleanup;
}
}
mt7697_ethernet_to_80211(skb, ndev);
cookie = mt7697_alloc_cookie(cfg); cookie = mt7697_alloc_cookie(cfg);
if (cookie == NULL) { if (cookie == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto fail_tx; goto cleanup;
} }
dev_dbg(cfg->dev, "%s: tx cookie/cnt(0x%p/%u)\n", dev_dbg(cfg->dev, "%s(): tx cookie/cnt(0x%p/%u)\n",
__func__, cookie, cfg->cookie_count); __func__, cookie, cfg->cookie_count);
cookie->skb = skb; cookie->skb = skb;
schedule_work(&cfg->tx_work); schedule_work(&cfg->tx_work);
return 0;
fail_tx: return NETDEV_TX_OK;
cleanup:
vif->net_stats.tx_dropped++;
vif->net_stats.tx_aborted_errors++;
dev_kfree_skb(skb); dev_kfree_skb(skb);
return ret; return ret;
} }
...@@ -54,76 +189,121 @@ void mt7697_tx_work(struct work_struct *work) ...@@ -54,76 +189,121 @@ void mt7697_tx_work(struct work_struct *work)
{ {
struct mt7697_cfg80211_info *cfg = container_of(work, struct mt7697_cfg80211_info *cfg = container_of(work,
struct mt7697_cfg80211_info, tx_work); struct mt7697_cfg80211_info, tx_work);
struct mt7697_cookie *cookie = &cfg->cookie_mem[cfg->cookie_count]; struct sk_buff_head skb_queue;
struct ieee80211_hdr *hdr;
int ret; int ret;
dev_dbg(cfg->dev, "%s: tx work cookie/cnt(0x%p/%u)\n", skb_queue_head_init(&skb_queue);
__func__, cookie, cfg->cookie_count);
dev_dbg(cfg->dev, "%s(): tx cookie cnt(%u)\n",
__func__, cfg->cookie_count);
while (cfg->cookie_count < MT7697_MAX_COOKIE_NUM) { while (cfg->cookie_count < MT7697_MAX_COOKIE_NUM) {
print_hex_dump(KERN_DEBUG, DRVNAME" <-- Tx ", DUMP_PREFIX_OFFSET, struct mt7697_vif *vif;
16, 1, cookie->skb->data, cookie->skb->len, 0); struct mt7697_cookie *cookie = &cfg->cookie_mem[cfg->cookie_count];
if (!cookie->skb)
break;
vif = netdev_priv(cookie->skb->dev);
WARN_ON(!vif);
/* validate length for ether packet */
if (cookie->skb->len < sizeof(*hdr)) {
dev_err(cfg->dev, "%s(): invalid skb len(%u < %u)\n",
__func__, cookie->skb->len, sizeof(*hdr));
vif->net_stats.tx_errors++;
ret = -EINVAL;
goto cleanup;
}
ret = mt7697_send_tx_raw_packet(cfg, cookie->skb->data, ret = mt7697_wr_tx_raw_packet(cfg, cookie->skb->data,
cookie->skb->len); cookie->skb->len);
if (ret < 0) { if (ret < 0) {
dev_err(cfg->dev, dev_err(cfg->dev,
"%s: mt7697_send_tx_raw_packet() failed(%d)\n", "%s(): mt7697_wr_tx_raw_packet() failed(%d)\n",
__func__, ret); __func__, ret);
vif->net_stats.tx_errors++;
goto cleanup; goto cleanup;
} }
dev_kfree_skb(cookie->skb); vif->net_stats.tx_packets++;
vif->net_stats.tx_bytes += cookie->skb->len;
__skb_queue_tail(&skb_queue, cookie->skb);
mt7697_free_cookie(cfg, cookie); mt7697_free_cookie(cfg, cookie);
dev_dbg(cfg->dev, "%s: tx cookie cnt(%u)\n",
dev_dbg(cfg->dev, "%s(): tx cookie cnt(%u)\n",
__func__, cfg->cookie_count); __func__, cfg->cookie_count);
if (cfg->cookie_count < MT7697_MAX_COOKIE_NUM) if (cfg->cookie_count < MT7697_MAX_COOKIE_NUM)
cookie = &cfg->cookie_mem[cfg->cookie_count]; cookie = &cfg->cookie_mem[cfg->cookie_count];
} }
__skb_queue_purge(&skb_queue);
cleanup: cleanup:
return; return;
} }
int mt7697_rx_data(struct mt7697_cfg80211_info *cfg, u32 if_idx) int mt7697_rx_data(struct mt7697_cfg80211_info *cfg, u32 len, u32 if_idx)
{ {
struct mt7697_vif *vif; struct mt7697_vif *vif;
struct sk_buff *skb; struct sk_buff *skb = NULL;
struct ieee80211_hdr *hdr;
int ret = 0; int ret = 0;
skb = alloc_skb(cfg->rsp.result, GFP_KERNEL); vif = mt7697_get_vif_by_idx(cfg, if_idx);
if (!skb) { if (!vif) {
dev_err(cfg->dev, "%s: alloc_skb() failed\n", __func__); dev_err(cfg->dev, "%s(): mt7697_get_vif_by_idx(%u) failed\n",
ret = -ENOMEM; __func__, if_idx);
ret = -EINVAL;
goto cleanup; goto cleanup;
} }
skb_put(skb, cfg->rsp.result); dev_dbg(cfg->dev, "%s(): vif(%u)\n", __func__, vif->fw_vif_idx);
memcpy(skb->data, cfg->rx_data, cfg->rsp.result); if (!(vif->ndev->flags & IFF_UP)) {
dev_warn(cfg->dev, "%s(): net device NOT up\n", __func__);
ret = -EINVAL;
goto cleanup;
}
vif = mt7697_get_vif_by_idx(cfg, if_idx); if ((len < sizeof(*hdr)) || (len > IEEE80211_MAX_FRAME_LEN)) {
if (!vif) { dev_warn(cfg->dev, "%s(): invalid Rx frame size(%u)\n",
dev_err(cfg->dev, "%s: mt7697_get_vif_by_idx(%u) failed\n", __func__, len);
__func__, if_idx); vif->net_stats.rx_length_errors++;
ret = -EINVAL; ret = -EINVAL;
goto cleanup; goto cleanup;
} }
dev_dbg(cfg->dev, "%s: vif(%u)\n", __func__, vif->fw_vif_idx); skb = alloc_skb(len, GFP_KERNEL);
if (!skb) {
dev_err(cfg->dev, "%s(): alloc_skb() failed\n", __func__);
ret = -ENOMEM;
goto cleanup;
}
skb_put(skb, len);
memcpy(skb->data, cfg->rx_data, len);
skb->dev = vif->ndev; skb->dev = vif->ndev;
if (!(skb->dev->flags & IFF_UP)) { ret = mt7697_80211_to_ethernet(skb, vif->ndev);
dev_warn(cfg->dev, "%s: net device NOT up\n", __func__); if (ret < 0) {
ret = -EINVAL; dev_err(cfg->dev,
"%s(): mt7697_80211_to_ethernet() failed(%d)\n",
__func__, ret);
goto cleanup; goto cleanup;
} }
skb->protocol = eth_type_trans(skb, skb->dev); vif->net_stats.rx_packets++;
dev_dbg(cfg->dev, "%s: protocol(%u)\n", __func__, skb->protocol); vif->net_stats.rx_bytes += len;
netif_rx_ni(skb); netif_rx_ni(skb);
cleanup: cleanup:
if (ret && skb) dev_kfree_skb(skb); if (ret < 0) {
vif->net_stats.tx_errors++;
if (skb) dev_kfree_skb(skb);
}
return ret; return ret;
} }
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