Skip to content

Commit

Permalink
qtnfmac: send EAPOL frames via control path
Browse files Browse the repository at this point in the history
Use control path to send EAPOL frames to make sure they are
sent with higher priority with aggregation disabled.

Signed-off-by: Igor Mitsyanko <igor.mitsyanko.os@quantenna.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  • Loading branch information
Igor Mitsyanko authored and Kalle Valo committed Apr 4, 2019
1 parent 72b3270 commit bc70732
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 25 deletions.
1 change: 1 addition & 0 deletions drivers/net/wireless/quantenna/qtnfmac/bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct qtnf_bus {
struct napi_struct mux_napi;
struct net_device mux_dev;
struct workqueue_struct *workqueue;
struct workqueue_struct *hprio_workqueue;
struct work_struct fw_work;
struct work_struct event_work;
struct mutex bus_lock; /* lock during command/event processing */
Expand Down
17 changes: 11 additions & 6 deletions drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
{
struct net_device *netdev = wdev->netdev;
struct qtnf_vif *vif;
struct sk_buff *skb;

if (WARN_ON(!netdev))
return -EFAULT;
Expand All @@ -157,6 +158,11 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
if (netif_carrier_ok(netdev))
netif_carrier_off(netdev);

while ((skb = skb_dequeue(&vif->high_pri_tx_queue)))
dev_kfree_skb_any(skb);

cancel_work_sync(&vif->high_pri_tx_work);

if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdevice(netdev);

Expand Down Expand Up @@ -424,13 +430,13 @@ qtnf_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
*cookie = short_cookie;

if (params->offchan)
flags |= QLINK_MGMT_FRAME_TX_FLAG_OFFCHAN;
flags |= QLINK_FRAME_TX_FLAG_OFFCHAN;

if (params->no_cck)
flags |= QLINK_MGMT_FRAME_TX_FLAG_NO_CCK;
flags |= QLINK_FRAME_TX_FLAG_NO_CCK;

if (params->dont_wait_for_ack)
flags |= QLINK_MGMT_FRAME_TX_FLAG_ACK_NOWAIT;
flags |= QLINK_FRAME_TX_FLAG_ACK_NOWAIT;

/* If channel is not specified, pass "freq = 0" to tell device
* firmware to use current channel.
Expand All @@ -445,9 +451,8 @@ qtnf_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
le16_to_cpu(mgmt_frame->frame_control), mgmt_frame->da,
params->len, short_cookie, flags);

return qtnf_cmd_send_mgmt_frame(vif, short_cookie, flags,
freq,
params->buf, params->len);
return qtnf_cmd_send_frame(vif, short_cookie, flags,
freq, params->buf, params->len);
}

static int
Expand Down
10 changes: 5 additions & 5 deletions drivers/net/wireless/quantenna/qtnfmac/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,11 +381,11 @@ int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg)
return ret;
}

int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
u16 freq, const u8 *buf, size_t len)
int qtnf_cmd_send_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
u16 freq, const u8 *buf, size_t len)
{
struct sk_buff *cmd_skb;
struct qlink_cmd_mgmt_frame_tx *cmd;
struct qlink_cmd_frame_tx *cmd;
int ret;

if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) {
Expand All @@ -395,14 +395,14 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
}

cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_SEND_MGMT_FRAME,
QLINK_CMD_SEND_FRAME,
sizeof(*cmd));
if (!cmd_skb)
return -ENOMEM;

qtnf_bus_lock(vif->mac->bus);

cmd = (struct qlink_cmd_mgmt_frame_tx *)cmd_skb->data;
cmd = (struct qlink_cmd_frame_tx *)cmd_skb->data;
cmd->cookie = cpu_to_le32(cookie);
cmd->freq = cpu_to_le16(freq);
cmd->flags = cpu_to_le16(flags);
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/quantenna/qtnfmac/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
const struct cfg80211_ap_settings *s);
int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif);
int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg);
int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
u16 freq, const u8 *buf, size_t len);
int qtnf_cmd_send_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
u16 freq, const u8 *buf, size_t len);
int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,
const u8 *buf, size_t len);
int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,
Expand Down
45 changes: 42 additions & 3 deletions drivers/net/wireless/quantenna/qtnfmac/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,23 @@ static void qtnf_mac_scan_timeout(struct work_struct *work)
qtnf_mac_scan_finish(mac, true);
}

static void qtnf_vif_send_data_high_pri(struct work_struct *work)
{
struct qtnf_vif *vif =
container_of(work, struct qtnf_vif, high_pri_tx_work);
struct sk_buff *skb;

if (!vif->netdev ||
vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
return;

while ((skb = skb_dequeue(&vif->high_pri_tx_queue))) {
qtnf_cmd_send_frame(vif, 0, QLINK_FRAME_TX_FLAG_8023,
0, skb->data, skb->len);
dev_kfree_skb_any(skb);
}
}

static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
unsigned int macid)
{
Expand Down Expand Up @@ -395,7 +412,8 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
vif->mac = mac;
vif->vifid = i;
qtnf_sta_list_init(&vif->sta_list);

INIT_WORK(&vif->high_pri_tx_work, qtnf_vif_send_data_high_pri);
skb_queue_head_init(&vif->high_pri_tx_queue);
vif->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
if (!vif->stats64)
pr_warn("VIF%u.%u: per cpu stats allocation failed\n",
Expand Down Expand Up @@ -598,6 +616,13 @@ int qtnf_core_attach(struct qtnf_bus *bus)
goto error;
}

bus->hprio_workqueue = alloc_workqueue("QTNF_HPRI", WQ_HIGHPRI, 0);
if (!bus->hprio_workqueue) {
pr_err("failed to alloc high prio workqueue\n");
ret = -ENOMEM;
goto error;
}

INIT_WORK(&bus->event_work, qtnf_event_work_handler);

ret = qtnf_cmd_send_init_fw(bus);
Expand All @@ -607,7 +632,6 @@ int qtnf_core_attach(struct qtnf_bus *bus)
}

bus->fw_state = QTNF_FW_STATE_ACTIVE;

ret = qtnf_cmd_get_hw_info(bus);
if (ret) {
pr_err("failed to get HW info: %d\n", ret);
Expand Down Expand Up @@ -642,7 +666,6 @@ int qtnf_core_attach(struct qtnf_bus *bus)

error:
qtnf_core_detach(bus);

return ret;
}
EXPORT_SYMBOL_GPL(qtnf_core_attach);
Expand All @@ -664,6 +687,13 @@ void qtnf_core_detach(struct qtnf_bus *bus)
if (bus->workqueue) {
flush_workqueue(bus->workqueue);
destroy_workqueue(bus->workqueue);
bus->workqueue = NULL;
}

if (bus->hprio_workqueue) {
flush_workqueue(bus->hprio_workqueue);
destroy_workqueue(bus->hprio_workqueue);
bus->hprio_workqueue = NULL;
}

qtnf_trans_free(bus);
Expand Down Expand Up @@ -800,6 +830,15 @@ void qtnf_update_tx_stats(struct net_device *ndev, const struct sk_buff *skb)
}
EXPORT_SYMBOL_GPL(qtnf_update_tx_stats);

void qtnf_packet_send_hi_pri(struct sk_buff *skb)
{
struct qtnf_vif *vif = qtnf_netdev_get_priv(skb->dev);

skb_queue_tail(&vif->high_pri_tx_queue, skb);
queue_work(vif->mac->bus->hprio_workqueue, &vif->high_pri_tx_work);
}
EXPORT_SYMBOL_GPL(qtnf_packet_send_hi_pri);

MODULE_AUTHOR("Quantenna Communications");
MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver.");
MODULE_LICENSE("GPL");
3 changes: 3 additions & 0 deletions drivers/net/wireless/quantenna/qtnfmac/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ struct qtnf_vif {
struct qtnf_wmac *mac;

struct work_struct reset_work;
struct work_struct high_pri_tx_work;
struct sk_buff_head high_pri_tx_queue;
struct qtnf_sta_list sta_list;
unsigned long cons_tx_timeout_cnt;
int generation;
Expand Down Expand Up @@ -149,6 +151,7 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev);

void qtnf_netdev_updown(struct net_device *ndev, bool up);
void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted);
void qtnf_packet_send_hi_pri(struct sk_buff *skb);

static inline struct qtnf_vif *qtnf_netdev_get_priv(struct net_device *dev)
{
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pcie_priv->pcie_irq_count = 0;
pcie_priv->tx_reclaim_done = 0;
pcie_priv->tx_reclaim_req = 0;
pcie_priv->tx_eapol = 0;

pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PCIE");
if (!pcie_priv->workqueue) {
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct qtnf_pcie_bus_priv {
u32 tx_done_count;
u32 tx_reclaim_done;
u32 tx_reclaim_req;
u32 tx_eapol;

u8 msi_enabled;
u8 tx_stopped;
Expand Down
8 changes: 8 additions & 0 deletions drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,13 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)
int len;
int i;

if (unlikely(skb->protocol == htons(ETH_P_PAE))) {
qtnf_packet_send_hi_pri(skb);
qtnf_update_tx_stats(skb->dev, skb);
priv->tx_eapol++;
return NETDEV_TX_OK;
}

spin_lock_irqsave(&priv->tx_lock, flags);

if (!qtnf_tx_queue_ready(ts)) {
Expand Down Expand Up @@ -761,6 +768,7 @@ static int qtnf_dbg_pkt_stats(struct seq_file *s, void *data)
seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count);
seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done);
seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req);
seq_printf(s, "tx_eapol(%u)\n", priv->tx_eapol);

seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index);
seq_printf(s, "tx_done_index(%u)\n", tx_done_index);
Expand Down
24 changes: 15 additions & 9 deletions drivers/net/wireless/quantenna/qtnfmac/qlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ struct qlink_sta_info_state {
* execution status (one of &enum qlink_cmd_result). Reply message
* may also contain data payload specific to the command type.
*
* @QLINK_CMD_SEND_FRAME: send specified frame over the air; firmware will
* encapsulate 802.3 packet into 802.11 frame automatically.
* @QLINK_CMD_BAND_INFO_GET: for the specified MAC and specified band, get
* the band's description including number of operational channels and
* info on each channel, HT/VHT capabilities, supported rates etc.
Expand All @@ -220,7 +222,7 @@ enum qlink_cmd_type {
QLINK_CMD_FW_INIT = 0x0001,
QLINK_CMD_FW_DEINIT = 0x0002,
QLINK_CMD_REGISTER_MGMT = 0x0003,
QLINK_CMD_SEND_MGMT_FRAME = 0x0004,
QLINK_CMD_SEND_FRAME = 0x0004,
QLINK_CMD_MGMT_SET_APPIE = 0x0005,
QLINK_CMD_PHY_PARAMS_GET = 0x0011,
QLINK_CMD_PHY_PARAMS_SET = 0x0012,
Expand Down Expand Up @@ -321,22 +323,26 @@ struct qlink_cmd_mgmt_frame_register {
u8 do_register;
} __packed;

enum qlink_mgmt_frame_tx_flags {
QLINK_MGMT_FRAME_TX_FLAG_NONE = 0,
QLINK_MGMT_FRAME_TX_FLAG_OFFCHAN = BIT(0),
QLINK_MGMT_FRAME_TX_FLAG_NO_CCK = BIT(1),
QLINK_MGMT_FRAME_TX_FLAG_ACK_NOWAIT = BIT(2),
/**
* @QLINK_FRAME_TX_FLAG_8023: frame has a 802.3 header; if not set, frame
* is a 802.11 encapsulated.
*/
enum qlink_frame_tx_flags {
QLINK_FRAME_TX_FLAG_OFFCHAN = BIT(0),
QLINK_FRAME_TX_FLAG_NO_CCK = BIT(1),
QLINK_FRAME_TX_FLAG_ACK_NOWAIT = BIT(2),
QLINK_FRAME_TX_FLAG_8023 = BIT(3),
};

/**
* struct qlink_cmd_mgmt_frame_tx - data for QLINK_CMD_SEND_MGMT_FRAME command
* struct qlink_cmd_frame_tx - data for QLINK_CMD_SEND_FRAME command
*
* @cookie: opaque request identifier.
* @freq: Frequency to use for frame transmission.
* @flags: Transmission flags, one of &enum qlink_mgmt_frame_tx_flags.
* @flags: Transmission flags, one of &enum qlink_frame_tx_flags.
* @frame_data: frame to transmit.
*/
struct qlink_cmd_mgmt_frame_tx {
struct qlink_cmd_frame_tx {
struct qlink_cmd chdr;
__le32 cookie;
__le16 freq;
Expand Down

0 comments on commit bc70732

Please sign in to comment.