OK, so I'm nervous about such a large patch series, but it took a lot
of work to break things down into atomic changes. This should be it
for the transmit path as far as I'm concerned.
- v2:
- Fix 64-bit architecture compile breakage found by
kernel build daemon.
- Fix kernel-doc issues.
- All patches compie with "make W=1" now and pass scripts/checkpatch.pl
- Expand series to clean up some locking issues.
- Expand series to support zero-copy tx transfers for SPI.
- Rebase to latest wireless-drivers-next
Rework tx path to use sk_buffs throughout and optionally provide
zero-copy transmit.
Based on the earlier discussion (RFC: wilc1000: refactor TX path to
use sk_buff queue), here is the full patch series to clean up and
simplify the TX path.
The biggest patch is 0016, which is the one actually switching the
queue data type, but I worked hard to minimize it to only direct
changes due to the type changes.
There is no dramatic performance difference due to this patch. I'd
expect the new code to be slightly faster, but my WLAN
test-environment is not sufficiently controlled to be sure of that.
original iperf3 performance (duration 120 seconds):
TX [Mbps] RX [Mbps]
PSM off: 14.8 18.9
PSM on: 10.5 17.1
iperf3 performance with this patch-series applied:
TX [Mbps] RX [Mbps]
PSM off: 16.0 19.9
PSM on: 11.7 18.0
(PSM == power-save-mode; controlled by iw dev wlan0 set power_save on/off)
David Mosberger-Tang (50):
wilc1000: don't hold txq_spinlock while initializing AC queue limits
wilc1000: switch txq_event from completion to waitqueue
wilc1000: move receive-queue stats from txq to wilc structure
wilc1000: factor common code in wilc_wlan_cfg_set() and wilc_wlan_cfg_get()
wilc1000: add wilc_wlan_tx_packet_done() function
wilc1000: move tx packet drop code into its own function
wilc1000: increment tx_dropped stat counter on tx packet drop
wilc1000: fix management packet type inconsistency
wilc1000: prepare wilc_wlan_tx_packet_done() for sk_buff changes
wilc1000: factor initialization of tx queue-specific packet fields
wilc1000: convert tqx_entries from "int" to "atomic_t"
wilc1000: refactor wilc_wlan_cfg_commit() a bit
wilc1000: sanitize config packet sequence number management a bit
wilc1000: if there is no tx packet, don't increment packets-sent counter
wilc1000: add struct wilc_skb_tx_cb as an alias of struct txq_entry_t
wilc1000: switch tx queue to normal sk_buff entries
wilc1000: remove no longer used "vif" argument from init_txq_entry()
wilc1000: split huge tx handler into subfunctions
wilc1000: don't tell the chip to go to sleep while copying tx packets
wilc1000: eliminate "max_size_over" variable in fill_vmm_table
wilc1000: declare read-only ac_preserve_ratio as static and const
wilc1000: minor syntax cleanup
wilc1000: introduce symbolic names for two tx-related control bits
wilc1000: protect tx_q_limit with a mutex instead of a spinlock
wilc1000: replace txq_spinlock with ack_filter_lock mutex
wilc1000: reduce amount of time ack_filter_lock is held
wilc1000: simplify ac_balance() a bit
wilc1000: improve send_packets() a bit
wilc1000: factor header length calculation into a new function
wilc1000: use more descriptive variable names
wilc1000: eliminate another magic constant
wilc1000: introduce vmm_table_entry() helper function
wilc1000: move ac_desired_ratio calculation to where its needed
wilc1000: restructure wilc-wlan_handle_txq() for clarity
wilc1000: introduce copy_and_send_packets() helper function
wilc1000: introduce transmit path chip queue
wilc1000: introduce set_header() function
wilc1000: take advantage of chip queue
wilc1000: eliminate txq_add_to_head_cs mutex
wilc1000: introduce schedule_packets() function
wilc1000: use more descriptive variable name
wilc1000: simplify code by adding header/padding to skb
wilc1000: add support for zero-copy transmit of tx packets
wilc1000: don't allocate tx_buffer when zero-copy is available
wilc1000: move struct wilc_spi declaration
wilc1000: remove duplicate CRC calculation code
wilc1000: factor SPI DMA command initialization code into a function
wilc1000: introduce function to find and check DMA response
wilc1000: implement zero-copy transmit support for SPI
wilc1000: add module parameter "disable_zero_copy_tx" to SPI driver
.../wireless/microchip/wilc1000/cfg80211.c | 45 +-
drivers/net/wireless/microchip/wilc1000/mon.c | 36 +-
.../net/wireless/microchip/wilc1000/netdev.c | 46 +-
.../net/wireless/microchip/wilc1000/netdev.h | 41 +-
drivers/net/wireless/microchip/wilc1000/spi.c | 293 ++++-
.../net/wireless/microchip/wilc1000/wlan.c | 998 ++++++++++--------
.../net/wireless/microchip/wilc1000/wlan.h | 55 +-
7 files changed, 888 insertions(+), 626 deletions(-)
--
2.25.1
Always keep the config packet sequence number in the valid range from
0..255.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 2e3dc04120832..979615914d420 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -1275,10 +1275,9 @@ static int wilc_wlan_cfg_commit(struct wilc_vif *vif, int type,
hdr = &cfg->hdr;
hdr->cmd_type = (type == WILC_CFG_SET) ? 'W' : 'Q';
- hdr->seq_no = wilc->cfg_seq_no % 256;
+ hdr->seq_no = wilc->cfg_seq_no;
hdr->total_len = cpu_to_le16(t_len);
hdr->driver_handler = cpu_to_le32(drv_handler);
- wilc->cfg_seq_no = cfg->hdr.seq_no;
if (!wilc_wlan_txq_add_cfg_pkt(vif, (u8 *)&cfg->hdr, t_len))
return -1;
@@ -1347,7 +1346,7 @@ static int wilc_wlan_cfg_apply_wid(struct wilc_vif *vif, int start, u16 wid,
}
wilc->cfg_frame_offset = 0;
- wilc->cfg_seq_no += 1;
+ wilc->cfg_seq_no = (wilc->cfg_seq_no + 1) % 256;
mutex_unlock(&wilc->cfg_cmd_lock);
return ret_size;
--
2.25.1
Granted, this case is mostly theoretical as the queue should never be
empty in this place, and hence tqe should never be NULL, but it's
still wrong to count a packet that doesn't exist.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 979615914d420..7106e6be719c1 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -893,10 +893,10 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
u8 mgmt_ptk = 0;
tqe = wilc_wlan_txq_remove_from_head(wilc, vmm_entries_ac[i]);
- ac_pkt_num_to_chip[vmm_entries_ac[i]]++;
if (!tqe)
break;
+ ac_pkt_num_to_chip[vmm_entries_ac[i]]++;
vif = tqe->vif;
if (vmm_table[i] == 0)
break;
--
2.25.1
This is just to improve code clarity.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 7b7ee6ee9f849..e4342631aae93 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -200,6 +200,14 @@ static void wilc_wlan_tx_packet_done(struct txq_entry_t *tqe, int status)
kfree(tqe);
}
+static void wilc_wlan_txq_drop_net_pkt(struct txq_entry_t *tqe)
+{
+ struct wilc *wilc = tqe->vif->wilc;
+
+ wilc_wlan_txq_remove(wilc, tqe->q_num, tqe);
+ wilc_wlan_tx_packet_done(tqe, 1);
+}
+
static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
@@ -228,10 +236,8 @@ static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
struct txq_entry_t *tqe;
tqe = f->pending_acks[i].txqe;
- if (tqe) {
- wilc_wlan_txq_remove(wilc, tqe->q_num, tqe);
- wilc_wlan_tx_packet_done(tqe, 1);
- }
+ if (tqe)
+ wilc_wlan_txq_drop_net_pkt(tqe);
}
}
f->pending_acks_idx = 0;
--
2.25.1
Packet drops are important events so we should remember to count them.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index e4342631aae93..4e59d4c707ea5 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -202,7 +202,10 @@ static void wilc_wlan_tx_packet_done(struct txq_entry_t *tqe, int status)
static void wilc_wlan_txq_drop_net_pkt(struct txq_entry_t *tqe)
{
- struct wilc *wilc = tqe->vif->wilc;
+ struct wilc_vif *vif = tqe->vif;
+ struct wilc *wilc = vif->wilc;
+
+ vif->ndev->stats.tx_dropped++;
wilc_wlan_txq_remove(wilc, tqe->q_num, tqe);
wilc_wlan_tx_packet_done(tqe, 1);
--
2.25.1
Remove extraneous parentheses and braces.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index bdc31a4fd0f6a..27b1d317dc0c4 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -656,10 +656,9 @@ static int fill_vmm_table(const struct wilc *wilc,
continue;
ac_exist = 1;
- for (k = 0; (k < num_pkts_to_add[ac]) && tqe_q[ac]; k++) {
- if (i >= (WILC_VMM_TBL_SIZE - 1)) {
+ for (k = 0; k < num_pkts_to_add[ac] && tqe_q[ac]; k++) {
+ if (i >= WILC_VMM_TBL_SIZE - 1)
goto out;
- }
tx_cb = WILC_SKB_TX_CB(tqe_q[ac]);
if (tx_cb->type == WILC_CFG_PKT)
@@ -672,9 +671,8 @@ static int fill_vmm_table(const struct wilc *wilc,
vmm_sz += tqe_q[ac]->len;
vmm_sz = ALIGN(vmm_sz, 4);
- if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE) {
+ if (sum + vmm_sz > WILC_TX_BUFF_SIZE)
goto out;
- }
vmm_table[i] = vmm_sz / 4;
if (tx_cb->type == WILC_CFG_PKT)
vmm_table[i] |= BIT(10);
@@ -741,10 +739,8 @@ static int send_vmm_table(struct wilc *wilc, int i, const u32 *vmm_table)
timeout = 200;
do {
- ret = func->hif_block_tx(wilc,
- WILC_VMM_TBL_RX_SHADOW_BASE,
- (u8 *)vmm_table,
- ((i + 1) * 4));
+ ret = func->hif_block_tx(wilc, WILC_VMM_TBL_RX_SHADOW_BASE,
+ (u8 *)vmm_table, (i + 1) * 4);
if (ret)
break;
--
2.25.1
Access to tx_q_limit needs to be serialized among the possibly
multiple writers to the tx queue. A mutex will do fine for that.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/cfg80211.c | 2 ++
drivers/net/wireless/microchip/wilc1000/netdev.h | 2 ++
drivers/net/wireless/microchip/wilc1000/wlan.c | 5 ++---
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index d352b7dd03283..0fcc064254f1e 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -1672,6 +1672,7 @@ static void wlan_init_locks(struct wilc *wl)
spin_lock_init(&wl->txq_spinlock);
mutex_init(&wl->txq_add_to_head_cs);
+ mutex_init(&wl->tx_q_limit_lock);
init_waitqueue_head(&wl->txq_event);
init_completion(&wl->cfg_event);
@@ -1688,6 +1689,7 @@ void wlan_deinit_locks(struct wilc *wilc)
mutex_destroy(&wilc->txq_add_to_head_cs);
mutex_destroy(&wilc->vif_mutex);
mutex_destroy(&wilc->deinit_lock);
+ mutex_destroy(&wilc->tx_q_limit_lock);
cleanup_srcu_struct(&wilc->srcu);
}
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h
index 650b40961cf98..e247f92a409e0 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.h
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.h
@@ -257,6 +257,8 @@ struct wilc {
atomic_t txq_entries;
struct txq_fw_recv_queue_stat fw[NQUEUES];
+ /* protect tx_q_limit state */
+ struct mutex tx_q_limit_lock;
struct wilc_tx_queue_status tx_q_limit;
struct rxq_entry_t rxq_head;
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index f82857cebe35e..9b6605e9df296 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -279,13 +279,12 @@ static void init_q_limits(struct wilc *wl)
static bool is_ac_q_limit(struct wilc *wl, u8 q_num)
{
- unsigned long flags;
struct wilc_tx_queue_status *q = &wl->tx_q_limit;
u8 end_index;
u8 q_limit;
bool ret = false;
- spin_lock_irqsave(&wl->txq_spinlock, flags);
+ mutex_lock(&wl->tx_q_limit_lock);
end_index = q->end_index;
q->cnt[q->buffer[end_index]] -= factors[q->buffer[end_index]];
@@ -306,7 +305,7 @@ static bool is_ac_q_limit(struct wilc *wl, u8 q_num)
if (skb_queue_len(&wl->txq[q_num]) <= q_limit)
ret = true;
- spin_unlock_irqrestore(&wl->txq_spinlock, flags);
+ mutex_unlock(&wl->tx_q_limit_lock);
return ret;
}
--
2.25.1
I wish these registers were documented so I wouldn't have to guess at
their meanings and make up my own names.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 6 +++---
drivers/net/wireless/microchip/wilc1000/wlan.h | 2 ++
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 27b1d317dc0c4..f82857cebe35e 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -675,7 +675,7 @@ static int fill_vmm_table(const struct wilc *wilc,
goto out;
vmm_table[i] = vmm_sz / 4;
if (tx_cb->type == WILC_CFG_PKT)
- vmm_table[i] |= BIT(10);
+ vmm_table[i] |= WILC_VMM_CFG_PKT;
cpu_to_le32s(&vmm_table[i]);
vmm_entries_ac[i] = ac;
@@ -721,7 +721,7 @@ static int send_vmm_table(struct wilc *wilc, int i, const u32 *vmm_table)
if (ret)
break;
- if ((reg & 0x1) == 0) {
+ if ((reg & WILC_HOST_TX_CTRL_BUSY) == 0) {
ac_update_fw_ac_pkt_info(wilc, reg);
break;
}
@@ -769,7 +769,7 @@ static int send_vmm_table(struct wilc *wilc, int i, const u32 *vmm_table)
ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®);
if (ret)
break;
- reg &= ~BIT(0);
+ reg &= ~WILC_HOST_TX_CTRL_BUSY;
ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);
} else {
ret = entries;
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h
index 10618327133ce..f5d32ec93fdb9 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.h
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.h
@@ -224,6 +224,7 @@
#define BE_AC_ACM_STAT_FIELD BIT(8)
#define BK_AC_COUNT_FIELD GENMASK(7, 3)
#define BK_AC_ACM_STAT_FIELD BIT(1)
+#define WILC_HOST_TX_CTRL_BUSY BIT(0)
#define WILC_PKT_HDR_CONFIG_FIELD BIT(31)
#define WILC_PKT_HDR_OFFSET_FIELD GENMASK(30, 22)
@@ -233,6 +234,7 @@
#define WILC_INTERRUPT_DATA_SIZE GENMASK(14, 0)
#define WILC_VMM_BUFFER_SIZE GENMASK(9, 0)
+#define WILC_VMM_CFG_PKT BIT(10)
#define WILC_VMM_HDR_TYPE BIT(31)
#define WILC_VMM_HDR_MGMT_FIELD BIT(30)
--
2.25.1
Putting the chip to sleep and waking it up again is relatively slow,
so there is no point to put the chip to sleep for the short time it
takes to copy a couple of packets.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 24 +++++++++----------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 54dfb2b9f3524..a6064a85140b4 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -924,29 +924,27 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
ret = send_vmm_table(wilc, i, vmm_table);
+ if (ret <= 0) {
+ if (ret == 0)
+ /* No VMM space available in firmware. Inform
+ * caller to retry later.
+ */
+ ret = WILC_VMM_ENTRY_FULL_RETRY;
+ goto out_release_bus;
+ }
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
-
- if (ret < 0)
- goto out_unlock;
+ release_bus(wilc, WILC_BUS_RELEASE_ONLY);
entries = ret;
- if (entries == 0) {
- /* No VMM space available in firmware. Inform caller
- * to retry later.
- */
- ret = WILC_VMM_ENTRY_FULL_RETRY;
- goto out_unlock;
- }
-
len = copy_packets(wilc, entries, vmm_table, vmm_entries_ac);
if (len <= 0)
goto out_unlock;
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
ret = send_packets(wilc, len);
+out_release_bus:
release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
out_unlock:
--
2.25.1
Rename "i" to "vmm_table_len" to improve readability and update
kernel-doc for send_vmm_table() as well.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 21 ++++++++++---------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 1cd9a7761343a..a4523b0860878 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -712,9 +712,9 @@ static int fill_vmm_table(const struct wilc *wilc,
}
/**
- * send_vmm_table() - Send the VMM table to the chip
+ * send_vmm_table() - send the VMM table to the chip
* @wilc: Pointer to the wilc structure.
- * @i: The number of entries in the VMM table.
+ * @vmm_table_len: The number of entries in the VMM table.
* @vmm_table: The VMM table to send.
*
* Send the VMM table to the chip and get back the number of entries
@@ -723,10 +723,10 @@ static int fill_vmm_table(const struct wilc *wilc,
* Context: The bus must have been acquired before calling this
* function.
*
- * Return:
- * The number of VMM table entries the chip can accept.
+ * Return: The number of VMM table entries the chip can accept.
*/
-static int send_vmm_table(struct wilc *wilc, int i, const u32 *vmm_table)
+static int send_vmm_table(struct wilc *wilc,
+ int vmm_table_len, const u32 *vmm_table)
{
const struct wilc_hif_func *func;
int ret, counter, entries, timeout;
@@ -758,7 +758,8 @@ static int send_vmm_table(struct wilc *wilc, int i, const u32 *vmm_table)
timeout = 200;
do {
ret = func->hif_block_tx(wilc, WILC_VMM_TBL_RX_SHADOW_BASE,
- (u8 *)vmm_table, (i + 1) * 4);
+ (u8 *)vmm_table,
+ (vmm_table_len + 1) * 4);
if (ret)
break;
@@ -899,7 +900,7 @@ static int send_packets(struct wilc *wilc, int len)
int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
{
- int i, entries, len;
+ int vmm_table_len, entries, len;
u8 ac_desired_ratio[NQUEUES] = {0, 0, 0, 0};
u8 vmm_entries_ac[WILC_VMM_TBL_SIZE];
int ret = 0;
@@ -919,13 +920,13 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev);
srcu_read_unlock(&wilc->srcu, srcu_idx);
- i = fill_vmm_table(wilc, ac_desired_ratio, vmm_table, vmm_entries_ac);
- if (i == 0)
+ vmm_table_len = fill_vmm_table(wilc, ac_desired_ratio, vmm_table, vmm_entries_ac);
+ if (vmm_table_len == 0)
goto out_unlock;
acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
- ret = send_vmm_table(wilc, i, vmm_table);
+ ret = send_vmm_table(wilc, vmm_table_len, vmm_table);
if (ret <= 0) {
if (ret == 0)
/* No VMM space available in firmware. Inform
--
2.25.1
In tcp_process(), only hold the ack_filter_lock while accessing the
ack_filter state.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 81180b2f9f4e1..5ea9129b36925 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -130,15 +130,13 @@ static inline void tcp_process(struct net_device *dev, struct sk_buff *tqe)
const struct tcphdr *tcp_hdr_ptr;
u32 ihl, total_length, data_offset;
- mutex_lock(&vif->ack_filter_lock);
-
if (eth_hdr_ptr->h_proto != htons(ETH_P_IP))
- goto out;
+ return;
ip_hdr_ptr = buffer + ETH_HLEN;
if (ip_hdr_ptr->protocol != IPPROTO_TCP)
- goto out;
+ return;
ihl = ip_hdr_ptr->ihl << 2;
tcp_hdr_ptr = buffer + ETH_HLEN + ihl;
@@ -150,6 +148,9 @@ static inline void tcp_process(struct net_device *dev, struct sk_buff *tqe)
seq_no = ntohl(tcp_hdr_ptr->seq);
ack_no = ntohl(tcp_hdr_ptr->ack_seq);
+
+ mutex_lock(&vif->ack_filter_lock);
+
for (i = 0; i < f->tcp_session; i++) {
u32 j = f->ack_session_info[i].seq_num;
@@ -163,10 +164,9 @@ static inline void tcp_process(struct net_device *dev, struct sk_buff *tqe)
add_tcp_session(vif, 0, 0, seq_no);
add_tcp_pending_ack(vif, ack_no, i, tqe);
- }
-out:
- mutex_unlock(&vif->ack_filter_lock);
+ mutex_unlock(&vif->ack_filter_lock);
+ }
}
static void wilc_wlan_tx_packet_done(struct sk_buff *tqe, int status)
--
2.25.1
Continuing the quest of simplifying the txq handler, factor the code
to copy and send packets into its own function.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 23 ++++++++++++++-----
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 803d35b18d2e0..18b1e7fad4d71 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -906,6 +906,22 @@ static int send_packets(struct wilc *wilc, int len)
return func->hif_block_tx_ext(wilc, 0, wilc->tx_buffer, len);
}
+static int copy_and_send_packets(struct wilc *wilc, int entries,
+ u32 vmm_table[WILC_VMM_TBL_SIZE],
+ u8 vmm_entries_ac[WILC_VMM_TBL_SIZE])
+{
+ int len, ret;
+
+ len = copy_packets(wilc, entries, vmm_table, vmm_entries_ac);
+ if (len <= 0)
+ return len;
+
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ ret = send_packets(wilc, len);
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return ret;
+}
+
int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
{
int vmm_table_len, entries;
@@ -940,12 +956,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
if (entries <= 0) {
ret = entries;
} else {
- ret = copy_packets(wilc, entries, vmm_table, vmm_entries_ac);
- if (ret > 0) {
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
- ret = send_packets(wilc, ret);
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
- }
+ ret = copy_and_send_packets(wilc, entries, vmm_table, vmm_entries_ac);
}
if (ret >= 0 && entries < vmm_table_len)
ret = WILC_VMM_ENTRY_FULL_RETRY;
--
2.25.1
If a driver supports zero-copy transmit transfers, there is no need to
have a transmit buffer.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index d96a7e2a0bd59..d46d6e8122c8d 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -1604,12 +1604,12 @@ int wilc_wlan_init(struct net_device *dev)
init_q_limits(wilc);
- if (!wilc->tx_buffer)
+ if (!wilc->hif_func->hif_sk_buffs_tx && !wilc->tx_buffer) {
wilc->tx_buffer = kmalloc(WILC_TX_BUFF_SIZE, GFP_KERNEL);
-
- if (!wilc->tx_buffer) {
- ret = -ENOBUFS;
- goto fail;
+ if (!wilc->tx_buffer) {
+ ret = -ENOBUFS;
+ goto fail;
+ }
}
if (!wilc->rx_buffer)
--
2.25.1
Add the infrastructure to enable zero-copy transmits. This is
currently a no-op as the SPI or SDIO drivers will need to implement
hif_sk_buffs_tx to take advantage of this.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 43 ++++++++++++++++++-
.../net/wireless/microchip/wilc1000/wlan.h | 2 +
2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 08f3e96bf72cf..d96a7e2a0bd59 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -935,6 +935,44 @@ static int copy_and_send_packets(struct wilc *wilc, int entries)
return ret;
}
+/**
+ * zero_copy_send_packets() - send packets to the chip (copy-free).
+ * @wilc: Pointer to the wilc structure.
+ * @entries: The number of packets to send from the VMM table.
+ *
+ * Zero-copy version of sending the packets in the VMM table to the
+ * chip.
+ *
+ * Context: The wilc1000 bus must have been released but the chip
+ * must be awake.
+ *
+ * Return: Negative number on error, 0 on success.
+ */
+static int zero_copy_send_packets(struct wilc *wilc, int entries)
+{
+ const struct wilc_hif_func *func = wilc->hif_func;
+ struct wilc_skb_tx_cb *tx_cb;
+ struct sk_buff *tqe;
+ int ret, i = 0;
+
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+
+ ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
+ if (ret == 0)
+ ret = func->hif_sk_buffs_tx(wilc, 0, entries, &wilc->chipq);
+
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+
+ for (i = 0; i < entries; ++i) {
+ tqe = __skb_dequeue(&wilc->chipq);
+ tx_cb = WILC_SKB_TX_CB(tqe);
+ wilc->fw[tx_cb->q_num].count++;
+ wilc->chipq_bytes -= tqe->len;
+ wilc_wlan_tx_packet_done(tqe, ret == 0);
+ }
+ return ret;
+}
+
int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
{
int vmm_table_len, entries;
@@ -966,7 +1004,10 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
if (entries <= 0) {
ret = entries;
} else {
- ret = copy_and_send_packets(wilc, entries);
+ if (wilc->hif_func->hif_sk_buffs_tx)
+ ret = zero_copy_send_packets(wilc, entries);
+ else
+ ret = copy_and_send_packets(wilc, entries);
}
if (ret >= 0 && entries < vmm_table_len)
ret = WILC_VMM_ENTRY_FULL_RETRY;
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h
index 11a54320ffd05..bda31f0970bda 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.h
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.h
@@ -367,6 +367,8 @@ struct wilc_hif_func {
int (*hif_read_size)(struct wilc *wilc, u32 *size);
int (*hif_block_tx_ext)(struct wilc *wilc, u32 addr, u8 *buf, u32 size);
int (*hif_block_rx_ext)(struct wilc *wilc, u32 addr, u8 *buf, u32 size);
+ int (*hif_sk_buffs_tx)(struct wilc *wilc, u32 addr,
+ size_t num_skbs, struct sk_buff_head *skbs);
int (*hif_sync_ext)(struct wilc *wilc, int nint);
int (*enable_interrupt)(struct wilc *nic);
void (*disable_interrupt)(struct wilc *nic);
--
2.25.1
Now that the factoring is done, again rename "i" to "vmm_table_len" to
improve readability.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 31 +++++++++----------
1 file changed, 14 insertions(+), 17 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index f01f7bade6189..f89ea4839aa61 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -681,7 +681,7 @@ static void set_header(struct wilc *wilc, struct sk_buff *tqe,
* WILC_VMM_TBL_SIZE packets or up to WILC_TX_BUFF_SIZE bytes.
*/
static int schedule_packets(struct wilc *wilc,
- int i, u32 vmm_table[WILC_VMM_TBL_SIZE])
+ int vmm_table_len, u32 vmm_table[WILC_VMM_TBL_SIZE])
{
u8 k, ac;
static const u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1};
@@ -702,8 +702,8 @@ static int schedule_packets(struct wilc *wilc,
ac_exist = 1;
for (k = 0; k < num_pkts_to_add[ac]; k++) {
- if (i >= WILC_VMM_TBL_SIZE - 1)
- return i;
+ if (vmm_table_len >= WILC_VMM_TBL_SIZE - 1)
+ return vmm_table_len;
tqe = skb_dequeue(&wilc->txq[ac]);
if (!tqe)
@@ -717,21 +717,21 @@ static int schedule_packets(struct wilc *wilc,
if (wilc->chipq_bytes + vmm_sz > WILC_TX_BUFF_SIZE) {
/* return packet to its queue */
skb_queue_head(&wilc->txq[ac], tqe);
- return i;
+ return vmm_table_len;
}
atomic_dec(&wilc->txq_entries);
__skb_queue_tail(&wilc->chipq, tqe);
wilc->chipq_bytes += tqe->len;
- vmm_table[i] = vmm_table_entry(tqe, vmm_sz);
- i++;
+ vmm_table[vmm_table_len] = vmm_table_entry(tqe, vmm_sz);
+ vmm_table_len++;
}
}
num_pkts_to_add = ac_preserve_ratio;
} while (ac_exist);
- return i;
+ return vmm_table_len;
}
/**
@@ -747,13 +747,10 @@ static int schedule_packets(struct wilc *wilc,
*/
static int fill_vmm_table(struct wilc *wilc, u32 vmm_table[WILC_VMM_TBL_SIZE])
{
- int i;
- int vmm_sz = 0;
+ int vmm_table_len = 0, vmm_sz = 0;
struct sk_buff *tqe;
struct wilc_skb_tx_cb *tx_cb;
- i = 0;
-
if (unlikely(wilc->chipq_bytes > 0)) {
/* fill in packets that are already on the chipq: */
skb_queue_walk(&wilc->chipq, tqe) {
@@ -761,16 +758,16 @@ static int fill_vmm_table(struct wilc *wilc, u32 vmm_table[WILC_VMM_TBL_SIZE])
vmm_sz = tx_hdr_len(tx_cb->type);
vmm_sz += tqe->len;
vmm_sz = ALIGN(vmm_sz, 4);
- vmm_table[i++] = vmm_table_entry(tqe, vmm_sz);
+ vmm_table[vmm_table_len++] = vmm_table_entry(tqe, vmm_sz);
}
}
- i = schedule_packets(wilc, i, vmm_table);
- if (i > 0) {
- WARN_ON(i >= WILC_VMM_TBL_SIZE);
- vmm_table[i] = 0x0;
+ vmm_table_len = schedule_packets(wilc, vmm_table_len, vmm_table);
+ if (vmm_table_len > 0) {
+ WARN_ON(vmm_table_len >= WILC_VMM_TBL_SIZE);
+ vmm_table[vmm_table_len] = 0x0;
}
- return i;
+ return vmm_table_len;
}
/**
--
2.25.1
Improve the documentation and simplify the code a bit.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 287c0843ba152..033979cc85b43 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -858,29 +858,26 @@ static int copy_packets(struct wilc *wilc, int entries, u32 *vmm_table,
}
/**
- * send_packets() - Send packets to the chip
+ * send_packets() - send the transmit buffer to the chip
* @wilc: Pointer to the wilc structure.
- * @len: The length of the buffer containing the packets to be sent to
- * the chip.
+ * @len: The length of the buffer containing the packets to be to the chip.
*
- * Send the packets in the VMM table to the chip.
+ * Send the packets in the transmit buffer to the chip.
*
* Context: The bus must have been acquired.
*
- * Return:
- * Negative number on error, 0 on success.
+ * Return: Negative number on error, 0 on success.
*/
static int send_packets(struct wilc *wilc, int len)
{
const struct wilc_hif_func *func = wilc->hif_func;
int ret;
- u8 *txb = wilc->tx_buffer;
ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
if (ret)
return ret;
- return func->hif_block_tx_ext(wilc, 0, txb, len);
+ return func->hif_block_tx_ext(wilc, 0, wilc->tx_buffer, len);
}
int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
--
2.25.1
Add a module parameter to disable the zero-copy transmit path. This
is useful for testing and performance measurement, for example.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/spi.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index 8d94f111ffc49..588cec326a74b 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -31,6 +31,11 @@ MODULE_PARM_DESC(enable_crc16,
"\t\t\tData transfers can be large and the CPU-cycle cost\n"
"\t\t\tof enabling this may be substantial.");
+static bool disable_zero_copy_tx;
+module_param(disable_zero_copy_tx, bool, 0644);
+MODULE_PARM_DESC(disable_zero_copy_tx,
+ "Disable zero-copy when sending packets.");
+
/*
* For CMD_SINGLE_READ and CMD_INTERNAL_READ, WILC may insert one or
* more zero bytes between the command response and the DATA Start tag
@@ -41,7 +46,7 @@ MODULE_PARM_DESC(enable_crc16,
*/
#define WILC_SPI_RSP_HDR_EXTRA_DATA 8
-static const struct wilc_hif_func wilc_hif_spi;
+static struct wilc_hif_func wilc_hif_spi;
static int wilc_spi_reset(struct wilc *wilc);
static int wilc_spi_write_sk_buffs(struct wilc *wilc, u32 addr,
@@ -254,6 +259,9 @@ static int wilc_bus_probe(struct spi_device *spi)
if (!spi_priv)
return -ENOMEM;
+ if (!disable_zero_copy_tx)
+ wilc_hif_spi.hif_sk_buffs_tx = wilc_spi_write_sk_buffs;
+
ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi);
if (ret)
goto free;
@@ -1424,7 +1432,7 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
}
/* Global spi HIF function table */
-static const struct wilc_hif_func wilc_hif_spi = {
+static struct wilc_hif_func wilc_hif_spi = {
.hif_init = wilc_spi_init,
.hif_deinit = wilc_spi_deinit,
.hif_read_reg = wilc_spi_read_reg,
@@ -1436,7 +1444,6 @@ static const struct wilc_hif_func wilc_hif_spi = {
.hif_read_size = wilc_spi_read_size,
.hif_block_tx_ext = wilc_spi_write,
.hif_block_rx_ext = wilc_spi_read,
- .hif_sk_buffs_tx = wilc_spi_write_sk_buffs,
.hif_sync_ext = wilc_spi_sync_ext,
.hif_reset = wilc_spi_reset,
};
--
2.25.1
Refactor DMA response checking from spi_data_rsp() into its own
function spi_data_check_rsp() as that will come in handy later.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/spi.c | 52 +++++++++++--------
1 file changed, 30 insertions(+), 22 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index 3e2022b43ee70..8951202ed76e2 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -80,6 +80,18 @@ static int wilc_spi_reset(struct wilc *wilc);
#define PROTOCOL_REG_CRC16_MASK GENMASK(3, 3)
#define PROTOCOL_REG_CRC7_MASK GENMASK(2, 2)
+/* The response to data packets is two bytes long. For efficiency's
+ * sake, when DMAing data to WILC, we ignore the responses for all
+ * data packets except the final one. The downside of this
+ * optimization is that when the final data packet is short, we may
+ * receive (part of) the response to the second-to-last packet before
+ * the one for the final packet. To handle this, we always read 4
+ * bytes and then search for the last byte that contains the "Response
+ * Start" code (0xc in the top 4 bits). We then know that this byte
+ * is the first response byte of the final data packet.
+ */
+#define WILC_SPI_DATA_RSP_BYTES 4
+
/*
* The SPI data packet size may be any integer power of two in the
* range from 256 to 8192 bytes.
@@ -950,31 +962,13 @@ static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data)
return 0;
}
-static int spi_data_rsp(struct wilc *wilc, u8 cmd)
+static int spi_data_check_rsp(struct wilc *wilc,
+ u8 rsp[WILC_SPI_DATA_RSP_BYTES])
{
struct spi_device *spi = to_spi_device(wilc->dev);
- int result, i;
- u8 rsp[4];
-
- /*
- * The response to data packets is two bytes long. For
- * efficiency's sake, wilc_spi_write() wisely ignores the
- * responses for all packets but the final one. The downside
- * of that optimization is that when the final data packet is
- * short, we may receive (part of) the response to the
- * second-to-last packet before the one for the final packet.
- * To handle this, we always read 4 bytes and then search for
- * the last byte that contains the "Response Start" code (0xc
- * in the top 4 bits). We then know that this byte is the
- * first response byte of the final data packet.
- */
- result = wilc_spi_rx(wilc, rsp, sizeof(rsp));
- if (result) {
- dev_err(&spi->dev, "Failed bus error...\n");
- return result;
- }
+ int i;
- for (i = sizeof(rsp) - 2; i >= 0; --i)
+ for (i = WILC_SPI_DATA_RSP_BYTES - 2; i >= 0; --i)
if (FIELD_GET(RSP_START_FIELD, rsp[i]) == RSP_START_TAG)
break;
@@ -996,6 +990,20 @@ static int spi_data_rsp(struct wilc *wilc, u8 cmd)
return 0;
}
+static int spi_data_rsp(struct wilc *wilc, u8 cmd)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ u8 rsp[WILC_SPI_DATA_RSP_BYTES];
+ int result;
+
+ result = wilc_spi_rx(wilc, rsp, sizeof(rsp));
+ if (result) {
+ dev_err(&spi->dev, "Failed bus error...\n");
+ return result;
+ }
+ return spi_data_check_rsp(wilc, rsp);
+}
+
static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
{
struct spi_device *spi = to_spi_device(wilc->dev);
--
2.25.1
Factor common tx packet-done handling code into a function.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 31 +++++++++----------
1 file changed, 14 insertions(+), 17 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 97624f758cbe4..7b7ee6ee9f849 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -190,6 +190,16 @@ static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
}
+static void wilc_wlan_tx_packet_done(struct txq_entry_t *tqe, int status)
+{
+ tqe->status = status;
+ if (tqe->tx_complete_func)
+ tqe->tx_complete_func(tqe->priv, tqe->status);
+ if (tqe->ack_idx != NOT_TCP_ACK && tqe->ack_idx < MAX_PENDING_ACKS)
+ tqe->vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL;
+ kfree(tqe);
+}
+
static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
@@ -220,11 +230,7 @@ static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
tqe = f->pending_acks[i].txqe;
if (tqe) {
wilc_wlan_txq_remove(wilc, tqe->q_num, tqe);
- tqe->status = 1;
- if (tqe->tx_complete_func)
- tqe->tx_complete_func(tqe->priv,
- tqe->status);
- kfree(tqe);
+ wilc_wlan_tx_packet_done(tqe, 1);
}
}
}
@@ -911,13 +917,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
tqe->buffer, tqe->buffer_size);
offset += vmm_sz;
i++;
- tqe->status = 1;
- if (tqe->tx_complete_func)
- tqe->tx_complete_func(tqe->priv, tqe->status);
- if (tqe->ack_idx != NOT_TCP_ACK &&
- tqe->ack_idx < MAX_PENDING_ACKS)
- vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL;
- kfree(tqe);
+ wilc_wlan_tx_packet_done(tqe, 1);
} while (--entries);
for (i = 0; i < NQUEUES; i++)
wilc->fw[i].count += ac_pkt_num_to_chip[i];
@@ -1236,11 +1236,8 @@ void wilc_wlan_cleanup(struct net_device *dev)
wilc->quit = 1;
for (ac = 0; ac < NQUEUES; ac++) {
- while ((tqe = wilc_wlan_txq_remove_from_head(wilc, ac))) {
- if (tqe->tx_complete_func)
- tqe->tx_complete_func(tqe->priv, 0);
- kfree(tqe);
- }
+ while ((tqe = wilc_wlan_txq_remove_from_head(wilc, ac)))
+ wilc_wlan_tx_packet_done(tqe, 0);
}
while ((rqe = wilc_wlan_rxq_remove(wilc)))
--
2.25.1
Move the packet scheduling code in its own function for improved
readability.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 78 ++++++++++++-------
1 file changed, 50 insertions(+), 28 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 67f5293370d35..f01f7bade6189 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -669,22 +669,20 @@ static void set_header(struct wilc *wilc, struct sk_buff *tqe,
}
/**
- * fill_vmm_table() - fill VMM table with packets to be sent
+ * schedule_packets() - schedule packets for transmission
* @wilc: Pointer to the wilc structure.
+ * @vmm_table_len: Current length of the VMM table.
* @vmm_table: Pointer to the VMM table to fill.
*
- * Fill VMM table with packets waiting to be sent. The packets are
- * added based on access category (priority) but also balanced to
- * provide fairness.
- *
- * Return:
- * The number of VMM entries filled in. The table is 0-terminated
- * so the returned number is at most WILC_VMM_TBL_SIZE-1.
+ * Schedule packets from the access-category queues for transmission.
+ * The scheduling is primarily in order of priority, but also takes
+ * fairness into account. As many packets as possible are moved to
+ * the chip queue. The chip queue has space for up to
+ * WILC_VMM_TBL_SIZE packets or up to WILC_TX_BUFF_SIZE bytes.
*/
-static int fill_vmm_table(struct wilc *wilc,
- u32 vmm_table[WILC_VMM_TBL_SIZE])
+static int schedule_packets(struct wilc *wilc,
+ int i, u32 vmm_table[WILC_VMM_TBL_SIZE])
{
- int i;
u8 k, ac;
static const u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1};
u8 ac_desired_ratio[NQUEUES];
@@ -694,19 +692,6 @@ static int fill_vmm_table(struct wilc *wilc,
struct sk_buff *tqe;
struct wilc_skb_tx_cb *tx_cb;
- i = 0;
-
- if (unlikely(wilc->chipq_bytes > 0)) {
- /* fill in packets that are already on the chipq: */
- skb_queue_walk(&wilc->chipq, tqe) {
- tx_cb = WILC_SKB_TX_CB(tqe);
- vmm_sz = tx_hdr_len(tx_cb->type);
- vmm_sz += tqe->len;
- vmm_sz = ALIGN(vmm_sz, 4);
- vmm_table[i++] = vmm_table_entry(tqe, vmm_sz);
- }
- }
-
ac_balance(wilc, ac_desired_ratio);
num_pkts_to_add = ac_desired_ratio;
do {
@@ -718,7 +703,7 @@ static int fill_vmm_table(struct wilc *wilc,
ac_exist = 1;
for (k = 0; k < num_pkts_to_add[ac]; k++) {
if (i >= WILC_VMM_TBL_SIZE - 1)
- goto out;
+ return i;
tqe = skb_dequeue(&wilc->txq[ac]);
if (!tqe)
@@ -732,7 +717,7 @@ static int fill_vmm_table(struct wilc *wilc,
if (wilc->chipq_bytes + vmm_sz > WILC_TX_BUFF_SIZE) {
/* return packet to its queue */
skb_queue_head(&wilc->txq[ac], tqe);
- goto out;
+ return i;
}
atomic_dec(&wilc->txq_entries);
@@ -746,8 +731,45 @@ static int fill_vmm_table(struct wilc *wilc,
}
num_pkts_to_add = ac_preserve_ratio;
} while (ac_exist);
-out:
- vmm_table[i] = 0x0;
+ return i;
+}
+
+/**
+ * fill_vmm_table() - fill VMM table with packets to be sent
+ * @wilc: Pointer to the wilc structure.
+ * @vmm_table: Pointer to the VMM table to fill.
+ *
+ * Fill VMM table with packets waiting to be sent.
+ *
+ * Return: The number of VMM entries filled in. The table is
+ * 0-terminated so the returned number is at most
+ * WILC_VMM_TBL_SIZE-1.
+ */
+static int fill_vmm_table(struct wilc *wilc, u32 vmm_table[WILC_VMM_TBL_SIZE])
+{
+ int i;
+ int vmm_sz = 0;
+ struct sk_buff *tqe;
+ struct wilc_skb_tx_cb *tx_cb;
+
+ i = 0;
+
+ if (unlikely(wilc->chipq_bytes > 0)) {
+ /* fill in packets that are already on the chipq: */
+ skb_queue_walk(&wilc->chipq, tqe) {
+ tx_cb = WILC_SKB_TX_CB(tqe);
+ vmm_sz = tx_hdr_len(tx_cb->type);
+ vmm_sz += tqe->len;
+ vmm_sz = ALIGN(vmm_sz, 4);
+ vmm_table[i++] = vmm_table_entry(tqe, vmm_sz);
+ }
+ }
+
+ i = schedule_packets(wilc, i, vmm_table);
+ if (i > 0) {
+ WARN_ON(i >= WILC_VMM_TBL_SIZE);
+ vmm_table[i] = 0x0;
+ }
return i;
}
--
2.25.1
Since the tx queue handler is no longer peeking at the transmit
queues, we don't need this mutex anymore.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/cfg80211.c | 2 --
drivers/net/wireless/microchip/wilc1000/netdev.h | 3 ---
drivers/net/wireless/microchip/wilc1000/wlan.c | 13 +------------
3 files changed, 1 insertion(+), 17 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index 6d3635864569f..d87358ca71cf9 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -1670,7 +1670,6 @@ static void wlan_init_locks(struct wilc *wl)
mutex_init(&wl->vif_mutex);
mutex_init(&wl->deinit_lock);
- mutex_init(&wl->txq_add_to_head_cs);
mutex_init(&wl->tx_q_limit_lock);
init_waitqueue_head(&wl->txq_event);
@@ -1685,7 +1684,6 @@ void wlan_deinit_locks(struct wilc *wilc)
mutex_destroy(&wilc->hif_cs);
mutex_destroy(&wilc->rxq_cs);
mutex_destroy(&wilc->cfg_cmd_lock);
- mutex_destroy(&wilc->txq_add_to_head_cs);
mutex_destroy(&wilc->vif_mutex);
mutex_destroy(&wilc->deinit_lock);
mutex_destroy(&wilc->tx_q_limit_lock);
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h
index e168f8644c678..086b9273bb117 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.h
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.h
@@ -225,9 +225,6 @@ struct wilc {
struct srcu_struct srcu;
u8 open_ifcs;
- /* protect head of transmit queue */
- struct mutex txq_add_to_head_cs;
-
/* protect rxq_entry_t receiver queue */
struct mutex rxq_cs;
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index eefc0d18c1b5c..67f5293370d35 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -70,12 +70,9 @@ static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, u8 type, u8 q_num,
init_txq_entry(tqe, type, q_num);
- mutex_lock(&wilc->txq_add_to_head_cs);
-
skb_queue_head(&wilc->txq[q_num], tqe);
atomic_inc(&wilc->txq_entries);
- mutex_unlock(&wilc->txq_add_to_head_cs);
wake_up_interruptible(&wilc->txq_event);
}
@@ -848,9 +845,6 @@ static int send_vmm_table(struct wilc *wilc,
*
* Copy a number of packets to the transmit buffer.
*
- * Context: The txq_add_to_head_cs mutex must still be held when
- * calling this function.
- *
* Return: Number of bytes copied to the transmit buffer (always
* non-negative).
*/
@@ -940,8 +934,6 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
if (wilc->quit)
goto out_update_cnt;
- mutex_lock(&wilc->txq_add_to_head_cs);
-
srcu_idx = srcu_read_lock(&wilc->srcu);
list_for_each_entry_rcu(vif, &wilc->vif_list, list)
wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev);
@@ -949,7 +941,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
vmm_table_len = fill_vmm_table(wilc, vmm_table);
if (vmm_table_len == 0)
- goto out_unlock;
+ goto out_update_cnt;
acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
@@ -967,9 +959,6 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
if (ret >= 0 && entries < vmm_table_len)
ret = WILC_VMM_ENTRY_FULL_RETRY;
-out_unlock:
- mutex_unlock(&wilc->txq_add_to_head_cs);
-
out_update_cnt:
*txq_count = atomic_read(&wilc->txq_entries);
return ret;
--
2.25.1
Introduce wilc_spi_dma_init_cmd() as a helper function as this will
come in handy later.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/spi.c | 41 +++++++++++++------
1 file changed, 28 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index 189907580d921..3e2022b43ee70 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -650,21 +650,14 @@ static int wilc_spi_write_cmd(struct wilc *wilc, u8 cmd, u32 adr, u32 data,
return 0;
}
-static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz)
+static int wilc_spi_dma_init_cmd(struct wilc *wilc, struct wilc_spi_cmd *c,
+ u8 cmd, u32 adr, u32 sz)
{
struct spi_device *spi = to_spi_device(wilc->dev);
struct wilc_spi *spi_priv = wilc->bus_data;
- u16 crc_recv, crc_calc;
- u8 wb[32], rb[32];
- int cmd_len, resp_len;
- int retry, ix = 0;
- u8 crc[2], *crc7;
- struct wilc_spi_cmd *c;
- struct wilc_spi_rsp_data *r;
+ int cmd_len;
+ u8 *crc7;
- memset(wb, 0x0, sizeof(wb));
- memset(rb, 0x0, sizeof(rb));
- c = (struct wilc_spi_cmd *)wb;
c->cmd_type = cmd;
if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_READ) {
c->u.dma_cmd.addr[0] = adr >> 16;
@@ -687,10 +680,32 @@ static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz)
return -EINVAL;
}
if (spi_priv->crc7_enabled) {
- crc7 = wb + cmd_len;
- *crc7 = wilc_get_crc7(wb, cmd_len);
+ crc7 = (u8 *)c + cmd_len;
+ *crc7 = wilc_get_crc7((u8 *)c, cmd_len);
cmd_len += 1;
}
+ return cmd_len;
+}
+
+static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ u16 crc_recv, crc_calc;
+ u8 wb[32], rb[32];
+ int cmd_len, resp_len;
+ int retry, ix = 0;
+ u8 crc[2];
+ struct wilc_spi_cmd *c;
+ struct wilc_spi_rsp_data *r;
+
+ memset(wb, 0x0, sizeof(wb));
+ memset(rb, 0x0, sizeof(rb));
+ c = (struct wilc_spi_cmd *)wb;
+
+ cmd_len = wilc_spi_dma_init_cmd(wilc, c, cmd, adr, sz);
+ if (cmd_len < 0)
+ return -EINVAL;
resp_len = sizeof(*r);
--
2.25.1
This enables zero-copy transmits for the SPI driver. Maybe something
similar could be implemented for the SDIO driver, but I'm not really
familiar with it.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/spi.c | 162 ++++++++++++++++++
1 file changed, 162 insertions(+)
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index 8951202ed76e2..8d94f111ffc49 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -44,6 +44,8 @@ MODULE_PARM_DESC(enable_crc16,
static const struct wilc_hif_func wilc_hif_spi;
static int wilc_spi_reset(struct wilc *wilc);
+static int wilc_spi_write_sk_buffs(struct wilc *wilc, u32 addr,
+ size_t num_skbs, struct sk_buff_head *skbs);
/********************************************
*
@@ -107,9 +109,33 @@ static int wilc_spi_reset(struct wilc *wilc);
#define DATA_PKT_LOG_SZ DATA_PKT_LOG_SZ_MAX
#define DATA_PKT_SZ (1 << DATA_PKT_LOG_SZ)
+#define DATA_START_TAG 0xf0
+#define DATA_ORDER_FIRST 0x01
+#define DATA_ORDER_INNER 0x02
+#define DATA_ORDER_LAST 0x03
+
#define WILC_SPI_COMMAND_STAT_SUCCESS 0
#define WILC_GET_RESP_HDR_START(h) (((h) >> 4) & 0xf)
+/* wilc_spi_write_sk_buffs() needs the following max. number of SPI
+ * transfers:
+ *
+ * - 1 transfer to send the CMD_DMA_EXT_WRITE command
+ * - 1 transfer per sk_buff (at most WILC_VMM_TBL_SIZE of them)
+ * - for each data packet:
+ * + 1 transfer for the data start tag
+ * + 1 transfer for the current sk_buff (if it spans
+ * the boundary of a data packet)
+ * + 1 transfer for the optional CRC16
+ * - 1 transfer to read the DMA response bytes
+ */
+#define MAX_DATA_PKTS DIV_ROUND_UP(WILC_TX_BUFF_SIZE, DATA_PKT_SZ)
+#define MAX_SPI_XFERS \
+ (1 \
+ + WILC_VMM_TBL_SIZE \
+ + 3 * MAX_DATA_PKTS \
+ + 1)
+
struct wilc_spi {
bool isinit; /* true if SPI protocol has been configured */
bool probing_crc; /* true if we're probing chip's CRC config */
@@ -119,6 +145,11 @@ struct wilc_spi {
struct gpio_desc *enable; /* ENABLE GPIO or NULL */
struct gpio_desc *reset; /* RESET GPIO or NULL */
} gpios;
+ /* Scratch space used by wilc_spi_write_sk_buffs() for SPI
+ * transfers and the data packets' CRCs.
+ */
+ struct spi_transfer xfer[MAX_SPI_XFERS];
+ u8 crc[2 * MAX_DATA_PKTS];
};
struct wilc_spi_cmd {
@@ -1037,6 +1068,136 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
return spi_data_rsp(wilc, CMD_DMA_EXT_WRITE);
}
+static void wilc_spi_add_xfer(struct spi_message *msg,
+ struct spi_transfer **xferp,
+ size_t len, const void *tx_buf, void *rx_buf)
+{
+ struct spi_transfer *xfer = *xferp;
+
+ xfer->tx_buf = tx_buf;
+ xfer->rx_buf = rx_buf;
+ xfer->len = len;
+ spi_message_add_tail(xfer, msg);
+ *xferp = xfer + 1;
+}
+
+/**
+ * wilc_spi_write_sk_buffs() - Zero-copy write sk_buffs to the chip.
+ * @wilc: Pointer to the wilc structure.
+ * @addr: The WILC address to transfer the data to.
+ * @num_skbs: The length of the skbs array.
+ * @skbs: The queue containing the sk_buffs to transmit.
+ *
+ * Zero-copy transfer one or more sk_buffs to the WILC chip. At most
+ * WILC_VMM_TBL_SIZE sk_buffs may be transmitted and the total size of
+ * the data in the sk_buffs must not exceed WILC_VMM_TBL_SIZE.
+ *
+ * Context: The caller must hold ownership of the SPI bus through a
+ * call to acquire_bus().
+ *
+ * Return: Zero on success, negative number on error.
+ */
+static int wilc_spi_write_sk_buffs(struct wilc *wilc, u32 addr, size_t num_skbs,
+ struct sk_buff_head *skbs)
+{
+ static const u8 data_hdr_first = DATA_START_TAG | DATA_ORDER_FIRST;
+ static const u8 data_hdr_inner = DATA_START_TAG | DATA_ORDER_INNER;
+ static const u8 data_hdr_last = DATA_START_TAG | DATA_ORDER_LAST;
+ size_t num_data_packets = 0, total_bytes = 0, num_sent, n, space;
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
+ u8 rsp[WILC_SPI_DATA_RSP_BYTES], *crc;
+ int i, ret, cmd_len;
+ struct spi_transfer *xfer;
+ struct wilc_spi_cmd cmd;
+ struct spi_message msg;
+ struct sk_buff *skb;
+ const u8 *data_hdr;
+ u16 crc_calc;
+
+ /* setup the SPI message and transfers: */
+
+ spi_message_init(&msg);
+ msg.spi = spi;
+
+ skb = skb_peek(skbs);
+ for (i = 0; i < num_skbs; ++i) {
+ n = skb->len;
+ total_bytes += n;
+ skb = skb_peek_next(skb, skbs);
+ }
+
+ num_data_packets = DIV_ROUND_UP(total_bytes, DATA_PKT_SZ);
+ skb = skb_peek(skbs);
+ num_sent = 0;
+ xfer = spi_priv->xfer;
+ crc = spi_priv->crc;
+
+ cmd_len = wilc_spi_dma_init_cmd(wilc, &cmd, CMD_DMA_EXT_WRITE,
+ addr, total_bytes);
+ if (cmd_len < 0) {
+ dev_err(&spi->dev, "Failed to init DMA command.");
+ return -EINVAL;
+ }
+ wilc_spi_add_xfer(&msg, &xfer, cmd_len, &cmd, NULL);
+
+ for (i = 0; i < num_data_packets; ++i) {
+ space = DATA_PKT_SZ;
+ crc_calc = 0xffff;
+
+ /* write data packet's start header: */
+ if (i == num_data_packets - 1)
+ data_hdr = &data_hdr_last;
+ else if (i == 0)
+ data_hdr = &data_hdr_first;
+ else
+ data_hdr = &data_hdr_inner;
+ wilc_spi_add_xfer(&msg, &xfer, 1, data_hdr, NULL);
+
+ /* write packet data: */
+ do {
+ n = skb->len - num_sent;
+ if (n > space)
+ n = space;
+ wilc_spi_add_xfer(&msg, &xfer, n,
+ skb->data + num_sent, NULL);
+ if (spi_priv->crc16_enabled)
+ crc_calc = crc_itu_t(crc_calc,
+ skb->data + num_sent, n);
+ num_sent += n;
+ space -= n;
+
+ if (num_sent >= skb->len) {
+ skb = skb_peek_next(skb, skbs);
+ --num_skbs;
+ num_sent = 0;
+ }
+ } while (space > 0 && num_skbs > 0);
+
+ /* write optional CRC16 checksum: */
+ if (spi_priv->crc16_enabled) {
+ crc[0] = crc_calc >> 8;
+ crc[1] = crc_calc;
+ wilc_spi_add_xfer(&msg, &xfer, 2, crc, NULL);
+ crc += 2;
+ }
+ }
+ /* last transfer reads the response bytes: */
+ wilc_spi_add_xfer(&msg, &xfer, sizeof(rsp), NULL, rsp);
+
+ WARN_ON((u8 *)xfer - (u8 *)spi_priv->xfer > sizeof(spi_priv->xfer));
+ WARN_ON(crc - spi_priv->crc > sizeof(spi_priv->crc));
+
+ ret = spi_sync(spi, &msg);
+ if (ret < 0) {
+ dev_err(&spi->dev, "spi_sync() failed: ret=%d\n", ret);
+ return -EINVAL;
+ }
+
+ /* Check if the chip received the data correctly: */
+ return spi_data_check_rsp(wilc, rsp);
+}
+
/********************************************
*
* Bus interfaces
@@ -1275,6 +1436,7 @@ static const struct wilc_hif_func wilc_hif_spi = {
.hif_read_size = wilc_spi_read_size,
.hif_block_tx_ext = wilc_spi_write,
.hif_block_rx_ext = wilc_spi_read,
+ .hif_sk_buffs_tx = wilc_spi_write_sk_buffs,
.hif_sync_ext = wilc_spi_sync_ext,
.hif_reset = wilc_spi_reset,
};
--
2.25.1
This introduces a chip queue that will hold packets ready to be
transferred to the chip. A later patch will start using it.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/cfg80211.c | 3 +++
.../net/wireless/microchip/wilc1000/netdev.h | 18 ++++++++++++++++++
drivers/net/wireless/microchip/wilc1000/wlan.c | 5 +++++
3 files changed, 26 insertions(+)
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index 6f19dee813f2a..6d3635864569f 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -1716,6 +1716,9 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
for (i = 0; i < NQUEUES; i++)
skb_queue_head_init(&wl->txq[i]);
+ skb_queue_head_init(&wl->chipq);
+ wl->chipq_bytes = 0;
+
INIT_LIST_HEAD(&wl->rxq_head.list);
INIT_LIST_HEAD(&wl->vif_list);
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h
index 82f38a0e20214..e168f8644c678 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.h
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.h
@@ -261,6 +261,24 @@ struct wilc {
struct wilc_tx_queue_status tx_q_limit;
struct rxq_entry_t rxq_head;
+ /* The chip queue contains sk_buffs that are ready to be
+ * transferred to the wilc1000 chip. In particular, they
+ * already have the VMM and Ethernet headers (for net packets)
+ * and they are padded to a size that is an integer-multiple
+ * of 4 bytes.
+ *
+ * This queue is usually empty on return from
+ * wilc_wlan_handle_txq(). However, when the chip does fill
+ * up, the packets that didn't fit will be held until there is
+ * space again.
+ *
+ * This queue is only accessed by the txq handler thread, so
+ * no locking is required.
+ */
+ struct sk_buff_head chipq;
+ /* Total number of bytes queued on the chipq: */
+ int chipq_bytes;
+
const struct firmware *firmware;
struct device *dev;
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 18b1e7fad4d71..c3802a34defed 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -1263,6 +1263,11 @@ void wilc_wlan_cleanup(struct net_device *dev)
struct wilc *wilc = vif->wilc;
wilc->quit = 1;
+
+ while ((tqe = __skb_dequeue(&wilc->chipq)))
+ wilc_wlan_tx_packet_done(tqe, 0);
+ wilc->chipq_bytes = 0;
+
for (ac = 0; ac < NQUEUES; ac++) {
while ((tqe = skb_dequeue(&wilc->txq[ac])))
wilc_wlan_tx_packet_done(tqe, 0);
--
2.25.1
Refactor the transmit packet header initialization into its own
set_header() function.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 56 +++++++++++--------
1 file changed, 33 insertions(+), 23 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index c3802a34defed..86b945e5ee076 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -640,6 +640,37 @@ static u32 vmm_table_entry(struct sk_buff *tqe, u32 vmm_sz)
return cpu_to_le32(entry);
}
+/**
+ * set_header() - set WILC-specific header
+ * @wilc: Pointer to the wilc structure.
+ * @tqe: The packet to add to the chip queue.
+ * @vmm_sz: The final size of the packet, including VMM header and padding.
+ * @hdr: Pointer to the header to set
+ */
+static void set_header(struct wilc *wilc, struct sk_buff *tqe,
+ u32 vmm_sz, void *hdr)
+{
+ struct wilc_skb_tx_cb *tx_cb = WILC_SKB_TX_CB(tqe);
+ u32 mgmt_pkt = 0, vmm_hdr, prio, data_len = tqe->len;
+ struct wilc_vif *vif;
+
+ /* add the VMM header word: */
+ if (tx_cb->type == WILC_MGMT_PKT)
+ mgmt_pkt = FIELD_PREP(WILC_VMM_HDR_MGMT_FIELD, 1);
+ vmm_hdr = cpu_to_le32(mgmt_pkt |
+ FIELD_PREP(WILC_VMM_HDR_TYPE, tx_cb->type) |
+ FIELD_PREP(WILC_VMM_HDR_PKT_SIZE, data_len) |
+ FIELD_PREP(WILC_VMM_HDR_BUFF_SIZE, vmm_sz));
+ memcpy(hdr, &vmm_hdr, 4);
+
+ if (tx_cb->type == WILC_NET_PKT) {
+ vif = netdev_priv(tqe->dev);
+ prio = cpu_to_le32(tx_cb->q_num);
+ memcpy(hdr + 4, &prio, sizeof(prio));
+ memcpy(hdr + 8, vif->bssid, ETH_ALEN);
+ }
+}
+
/**
* fill_vmm_table() - Fill VMM table with packets to be sent
* @wilc: Pointer to the wilc structure.
@@ -827,7 +858,6 @@ static int copy_packets(struct wilc *wilc, int entries, u32 *vmm_table,
u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0};
struct wilc_skb_tx_cb *tx_cb;
u8 *txb = wilc->tx_buffer;
- struct wilc_vif *vif;
int i, vmm_sz;
u32 offset;
@@ -835,9 +865,7 @@ static int copy_packets(struct wilc *wilc, int entries, u32 *vmm_table,
i = 0;
do {
struct sk_buff *tqe;
- u32 header, buffer_offset;
- char *bssid;
- u8 mgmt_ptk = 0;
+ u32 buffer_offset;
tqe = skb_dequeue(&wilc->txq[vmm_entries_ac[i]]);
if (!tqe)
@@ -845,7 +873,6 @@ static int copy_packets(struct wilc *wilc, int entries, u32 *vmm_table,
atomic_dec(&wilc->txq_entries);
ac_pkt_num_to_chip[vmm_entries_ac[i]]++;
- vif = netdev_priv(tqe->dev);
tx_cb = WILC_SKB_TX_CB(tqe);
if (vmm_table[i] == 0)
break;
@@ -854,25 +881,8 @@ static int copy_packets(struct wilc *wilc, int entries, u32 *vmm_table,
vmm_sz = FIELD_GET(WILC_VMM_BUFFER_SIZE, vmm_table[i]);
vmm_sz *= 4;
- if (tx_cb->type == WILC_MGMT_PKT)
- mgmt_ptk = 1;
-
- header = (FIELD_PREP(WILC_VMM_HDR_TYPE, tx_cb->type) |
- FIELD_PREP(WILC_VMM_HDR_MGMT_FIELD, mgmt_ptk) |
- FIELD_PREP(WILC_VMM_HDR_PKT_SIZE, tqe->len) |
- FIELD_PREP(WILC_VMM_HDR_BUFF_SIZE, vmm_sz));
-
- cpu_to_le32s(&header);
- memcpy(&txb[offset], &header, 4);
buffer_offset = tx_hdr_len(tx_cb->type);
- if (tx_cb->type == WILC_NET_PKT) {
- int prio = tx_cb->q_num;
-
- bssid = vif->bssid;
- memcpy(&txb[offset + 4], &prio, sizeof(prio));
- memcpy(&txb[offset + 8], bssid, 6);
- }
-
+ set_header(wilc, tqe, vmm_sz, txb + offset);
memcpy(&txb[offset + buffer_offset], tqe->data, tqe->len);
offset += vmm_sz;
i++;
--
2.25.1
Completion structs are essentially counting semaphores: every
complete() call wakes up exactly one thread, either immediately (when
there are waiters queued) or in the future (when a waiter arrives).
This isn't really the appropriate synchronization structure for the
wilc1000 transmit queue handler (wilc_wlan_handle_txq) because it will
consume zero, one, or more packets on each call. Instead, use a
waitqueue as a condition variable: wake_up_interruptible() wakes up
the tx queue handler from a call to wait_event_interruptible()
whenever something interesting happens and it then takes the
appropriate action. This has a couple of benefits:
- Since the transmit queue handler often transfers multiple packets
to the chip on each call, repeated calls to wait_for_completion()
when there is no actual work to do are avoided.
- When the transmit queue handler cannot transfer any packets at all,
it'll simply give up the current time slice and then tries again.
Previously, the transmit would stall until a new packet showed up
(which potentially could cause extended stalls). It would be even
better to wait for a "tx queue not full" interrupt but, sadly, I'm
told the wilc1000 firmware doesn't provide that.
- There is no longer any need for wilc_wlan_txq_filter_dup_tcp_ack()
to adjust the completion structs wait count by calling
wait_for_completion_timeout() for each dropped packet.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/cfg80211.c | 2 +-
drivers/net/wireless/microchip/wilc1000/netdev.c | 13 +++++++++----
drivers/net/wireless/microchip/wilc1000/netdev.h | 2 +-
drivers/net/wireless/microchip/wilc1000/wlan.c | 12 ++----------
4 files changed, 13 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index 8d8378bafd9b0..be387a8abb6af 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -1692,7 +1692,7 @@ static void wlan_init_locks(struct wilc *wl)
spin_lock_init(&wl->txq_spinlock);
mutex_init(&wl->txq_add_to_head_cs);
- init_completion(&wl->txq_event);
+ init_waitqueue_head(&wl->txq_event);
init_completion(&wl->cfg_event);
init_completion(&wl->sync_event);
init_completion(&wl->txq_thread_started);
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c
index 643bddaae32ad..d5969f2e369c4 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.c
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.c
@@ -144,10 +144,12 @@ static int wilc_txq_task(void *vp)
int ret;
u32 txq_count;
struct wilc *wl = vp;
+ long timeout;
complete(&wl->txq_thread_started);
while (1) {
- wait_for_completion(&wl->txq_event);
+ wait_event_interruptible(wl->txq_event,
+ (wl->txq_entries > 0 || wl->close));
if (wl->close) {
complete(&wl->txq_thread_started);
@@ -170,6 +172,11 @@ static int wilc_txq_task(void *vp)
}
srcu_read_unlock(&wl->srcu, srcu_idx);
}
+ if (ret == WILC_VMM_ENTRY_FULL_RETRY) {
+ timeout = msecs_to_jiffies(1);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(timeout);
+ }
} while (ret == WILC_VMM_ENTRY_FULL_RETRY && !wl->close);
}
return 0;
@@ -419,12 +426,11 @@ static void wlan_deinitialize_threads(struct net_device *dev)
wl->close = 1;
- complete(&wl->txq_event);
-
if (wl->txq_thread) {
kthread_stop(wl->txq_thread);
wl->txq_thread = NULL;
}
+ wake_up_interruptible(&wl->txq_event);
}
static void wilc_wlan_deinitialize(struct net_device *dev)
@@ -446,7 +452,6 @@ static void wilc_wlan_deinitialize(struct net_device *dev)
wl->hif_func->disable_interrupt(wl);
mutex_unlock(&wl->hif_cs);
}
- complete(&wl->txq_event);
wlan_deinitialize_threads(dev);
deinit_irq(dev);
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h
index f4fc2cc392bd0..c07f58a86bc76 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.h
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.h
@@ -237,7 +237,7 @@ struct wilc {
struct completion cfg_event;
struct completion sync_event;
- struct completion txq_event;
+ wait_queue_head_t txq_event;
struct completion txq_thread_started;
struct task_struct *txq_thread;
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index c4da14147dd04..26fa7078acffd 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -75,7 +75,7 @@ static void wilc_wlan_txq_add_to_tail(struct net_device *dev, u8 q_num,
spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
- complete(&wilc->txq_event);
+ wake_up_interruptible(&wilc->txq_event);
}
static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, u8 q_num,
@@ -94,7 +94,7 @@ static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, u8 q_num,
spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
mutex_unlock(&wilc->txq_add_to_head_cs);
- complete(&wilc->txq_event);
+ wake_up_interruptible(&wilc->txq_event);
}
#define NOT_TCP_ACK (-1)
@@ -196,7 +196,6 @@ static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
struct wilc *wilc = vif->wilc;
struct tcp_ack_filter *f = &vif->ack_filter;
u32 i = 0;
- u32 dropped = 0;
unsigned long flags;
spin_lock_irqsave(&wilc->txq_spinlock, flags);
@@ -226,7 +225,6 @@ static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
tqe->tx_complete_func(tqe->priv,
tqe->status);
kfree(tqe);
- dropped++;
}
}
}
@@ -239,12 +237,6 @@ static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
f->pending_base = 0;
spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
-
- while (dropped > 0) {
- wait_for_completion_timeout(&wilc->txq_event,
- msecs_to_jiffies(1));
- dropped--;
- }
}
void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value)
--
2.25.1
Move ac_desired_ratio calculation to fill_vmm_table() since that's the
only place that needs it. Note that it is unnecessary to initialize
the array since ac_balance() is guaranteed to fill it in.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 5939ed5b2db68..64497754a36b1 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -643,8 +643,6 @@ static u32 vmm_table_entry(struct sk_buff *tqe, u32 vmm_sz)
/**
* fill_vmm_table() - Fill VMM table with packets to be sent
* @wilc: Pointer to the wilc structure.
- * @ac_desired_ratio: First-round limit on number of packets to add from the
- * respective queue.
* @vmm_table: Pointer to the VMM table to fill.
* @vmm_entries_ac: Pointer to the queue-number table to fill.
* For each packet added to the VMM table, this will be filled in
@@ -664,7 +662,6 @@ static u32 vmm_table_entry(struct sk_buff *tqe, u32 vmm_sz)
* so the returned number is at most WILC_VMM_TBL_SIZE-1.
*/
static int fill_vmm_table(const struct wilc *wilc,
- u8 ac_desired_ratio[NQUEUES],
u32 vmm_table[WILC_VMM_TBL_SIZE],
u8 vmm_entries_ac[WILC_VMM_TBL_SIZE])
{
@@ -672,6 +669,7 @@ static int fill_vmm_table(const struct wilc *wilc,
u8 k, ac;
u32 sum;
static const u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1};
+ u8 ac_desired_ratio[NQUEUES];
const u8 *num_pkts_to_add;
bool ac_exist = 0;
int vmm_sz = 0;
@@ -683,6 +681,8 @@ static int fill_vmm_table(const struct wilc *wilc,
i = 0;
sum = 0;
+
+ ac_balance(wilc, ac_desired_ratio);
num_pkts_to_add = ac_desired_ratio;
do {
ac_exist = 0;
@@ -909,7 +909,6 @@ static int send_packets(struct wilc *wilc, int len)
int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
{
int vmm_table_len, entries, len;
- u8 ac_desired_ratio[NQUEUES] = {0, 0, 0, 0};
u8 vmm_entries_ac[WILC_VMM_TBL_SIZE];
int ret = 0;
u32 vmm_table[WILC_VMM_TBL_SIZE];
@@ -919,8 +918,6 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
if (wilc->quit)
goto out_update_cnt;
- ac_balance(wilc, ac_desired_ratio);
-
mutex_lock(&wilc->txq_add_to_head_cs);
srcu_idx = srcu_read_lock(&wilc->srcu);
@@ -928,7 +925,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev);
srcu_read_unlock(&wilc->srcu, srcu_idx);
- vmm_table_len = fill_vmm_table(wilc, ac_desired_ratio, vmm_table, vmm_entries_ac);
+ vmm_table_len = fill_vmm_table(wilc, vmm_table, vmm_entries_ac);
if (vmm_table_len == 0)
goto out_unlock;
--
2.25.1
Just move the structure down by a few lines so that a later patch can
be understood more easily. No functional change.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/spi.c | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index 2c2ed4b09efd5..5f73b3d2d2112 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -41,17 +41,6 @@ MODULE_PARM_DESC(enable_crc16,
*/
#define WILC_SPI_RSP_HDR_EXTRA_DATA 8
-struct wilc_spi {
- bool isinit; /* true if SPI protocol has been configured */
- bool probing_crc; /* true if we're probing chip's CRC config */
- bool crc7_enabled; /* true if crc7 is currently enabled */
- bool crc16_enabled; /* true if crc16 is currently enabled */
- struct wilc_gpios {
- struct gpio_desc *enable; /* ENABLE GPIO or NULL */
- struct gpio_desc *reset; /* RESET GPIO or NULL */
- } gpios;
-};
-
static const struct wilc_hif_func wilc_hif_spi;
static int wilc_spi_reset(struct wilc *wilc);
@@ -109,6 +98,17 @@ static int wilc_spi_reset(struct wilc *wilc);
#define WILC_SPI_COMMAND_STAT_SUCCESS 0
#define WILC_GET_RESP_HDR_START(h) (((h) >> 4) & 0xf)
+struct wilc_spi {
+ bool isinit; /* true if SPI protocol has been configured */
+ bool probing_crc; /* true if we're probing chip's CRC config */
+ bool crc7_enabled; /* true if crc7 is currently enabled */
+ bool crc16_enabled; /* true if crc16 is currently enabled */
+ struct wilc_gpios {
+ struct gpio_desc *enable; /* ENABLE GPIO or NULL */
+ struct gpio_desc *reset; /* RESET GPIO or NULL */
+ } gpios;
+};
+
struct wilc_spi_cmd {
u8 cmd_type;
union {
--
2.25.1
Rather than peeking at the access-category tx queues, move packets
scheduled for transmission onto the chip queue.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 102 +++++++++---------
1 file changed, 49 insertions(+), 53 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 86b945e5ee076..eefc0d18c1b5c 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -672,74 +672,79 @@ static void set_header(struct wilc *wilc, struct sk_buff *tqe,
}
/**
- * fill_vmm_table() - Fill VMM table with packets to be sent
+ * fill_vmm_table() - fill VMM table with packets to be sent
* @wilc: Pointer to the wilc structure.
* @vmm_table: Pointer to the VMM table to fill.
- * @vmm_entries_ac: Pointer to the queue-number table to fill.
- * For each packet added to the VMM table, this will be filled in
- * with the queue-number (access-category) that the packet is coming
- * from.
*
* Fill VMM table with packets waiting to be sent. The packets are
* added based on access category (priority) but also balanced to
* provide fairness.
*
- * Context: Since this function peeks at the packet queues, the
- * txq_add_to_head_cs mutex must be acquired before calling this
- * function.
- *
* Return:
* The number of VMM entries filled in. The table is 0-terminated
* so the returned number is at most WILC_VMM_TBL_SIZE-1.
*/
-static int fill_vmm_table(const struct wilc *wilc,
- u32 vmm_table[WILC_VMM_TBL_SIZE],
- u8 vmm_entries_ac[WILC_VMM_TBL_SIZE])
+static int fill_vmm_table(struct wilc *wilc,
+ u32 vmm_table[WILC_VMM_TBL_SIZE])
{
int i;
u8 k, ac;
- u32 sum;
static const u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1};
u8 ac_desired_ratio[NQUEUES];
const u8 *num_pkts_to_add;
bool ac_exist = 0;
int vmm_sz = 0;
- struct sk_buff *tqe_q[NQUEUES];
+ struct sk_buff *tqe;
struct wilc_skb_tx_cb *tx_cb;
- for (ac = 0; ac < NQUEUES; ac++)
- tqe_q[ac] = skb_peek(&wilc->txq[ac]);
-
i = 0;
- sum = 0;
+
+ if (unlikely(wilc->chipq_bytes > 0)) {
+ /* fill in packets that are already on the chipq: */
+ skb_queue_walk(&wilc->chipq, tqe) {
+ tx_cb = WILC_SKB_TX_CB(tqe);
+ vmm_sz = tx_hdr_len(tx_cb->type);
+ vmm_sz += tqe->len;
+ vmm_sz = ALIGN(vmm_sz, 4);
+ vmm_table[i++] = vmm_table_entry(tqe, vmm_sz);
+ }
+ }
ac_balance(wilc, ac_desired_ratio);
num_pkts_to_add = ac_desired_ratio;
do {
ac_exist = 0;
for (ac = 0; ac < NQUEUES; ac++) {
- if (!tqe_q[ac])
+ if (skb_queue_len(&wilc->txq[ac]) < 1)
continue;
ac_exist = 1;
- for (k = 0; k < num_pkts_to_add[ac] && tqe_q[ac]; k++) {
+ for (k = 0; k < num_pkts_to_add[ac]; k++) {
if (i >= WILC_VMM_TBL_SIZE - 1)
goto out;
- tx_cb = WILC_SKB_TX_CB(tqe_q[ac]);
+ tqe = skb_dequeue(&wilc->txq[ac]);
+ if (!tqe)
+ continue;
+
+ tx_cb = WILC_SKB_TX_CB(tqe);
vmm_sz = tx_hdr_len(tx_cb->type);
- vmm_sz += tqe_q[ac]->len;
+ vmm_sz += tqe->len;
vmm_sz = ALIGN(vmm_sz, 4);
- if (sum + vmm_sz > WILC_TX_BUFF_SIZE)
+ if (wilc->chipq_bytes + vmm_sz > WILC_TX_BUFF_SIZE) {
+ /* return packet to its queue */
+ skb_queue_head(&wilc->txq[ac], tqe);
goto out;
- vmm_table[i] = vmm_table_entry(tqe_q[ac], vmm_sz);
- vmm_entries_ac[i] = ac;
+ }
+ atomic_dec(&wilc->txq_entries);
+
+ __skb_queue_tail(&wilc->chipq, tqe);
+ wilc->chipq_bytes += tqe->len;
+ vmm_table[i] = vmm_table_entry(tqe, vmm_sz);
i++;
- sum += vmm_sz;
- tqe_q[ac] = skb_peek_next(tqe_q[ac],
- &wilc->txq[ac]);
+
}
}
num_pkts_to_add = ac_preserve_ratio;
@@ -837,14 +842,11 @@ static int send_vmm_table(struct wilc *wilc,
}
/**
- * copy_packets() - Copy packets to the transmit buffer
+ * copy_packets() - copy packets to the transmit buffer
* @wilc: Pointer to the wilc structure.
- * @entries: The number of packets to send from the VMM table.
- * @vmm_table: The VMM table to send.
- * @vmm_entries_ac: Table index i contains the number of the queue to
- * take the i-th packet from.
+ * @entries: The number of packets to copy from the chip queue.
*
- * Copy a set of packets to the transmit buffer.
+ * Copy a number of packets to the transmit buffer.
*
* Context: The txq_add_to_head_cs mutex must still be held when
* calling this function.
@@ -852,8 +854,7 @@ static int send_vmm_table(struct wilc *wilc,
* Return: Number of bytes copied to the transmit buffer (always
* non-negative).
*/
-static int copy_packets(struct wilc *wilc, int entries, u32 *vmm_table,
- u8 *vmm_entries_ac)
+static int copy_packets(struct wilc *wilc, int entries)
{
u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0};
struct wilc_skb_tx_cb *tx_cb;
@@ -867,21 +868,19 @@ static int copy_packets(struct wilc *wilc, int entries, u32 *vmm_table,
struct sk_buff *tqe;
u32 buffer_offset;
- tqe = skb_dequeue(&wilc->txq[vmm_entries_ac[i]]);
- if (!tqe)
+ tqe = __skb_dequeue(&wilc->chipq);
+ if (WARN_ON(!tqe))
break;
+ wilc->chipq_bytes -= tqe->len;
- atomic_dec(&wilc->txq_entries);
- ac_pkt_num_to_chip[vmm_entries_ac[i]]++;
tx_cb = WILC_SKB_TX_CB(tqe);
- if (vmm_table[i] == 0)
- break;
-
- le32_to_cpus(&vmm_table[i]);
- vmm_sz = FIELD_GET(WILC_VMM_BUFFER_SIZE, vmm_table[i]);
- vmm_sz *= 4;
+ ac_pkt_num_to_chip[tx_cb->q_num]++;
buffer_offset = tx_hdr_len(tx_cb->type);
+ vmm_sz = buffer_offset;
+ vmm_sz += tqe->len;
+ vmm_sz = ALIGN(vmm_sz, 4);
+
set_header(wilc, tqe, vmm_sz, txb + offset);
memcpy(&txb[offset + buffer_offset], tqe->data, tqe->len);
offset += vmm_sz;
@@ -916,13 +915,11 @@ static int send_packets(struct wilc *wilc, int len)
return func->hif_block_tx_ext(wilc, 0, wilc->tx_buffer, len);
}
-static int copy_and_send_packets(struct wilc *wilc, int entries,
- u32 vmm_table[WILC_VMM_TBL_SIZE],
- u8 vmm_entries_ac[WILC_VMM_TBL_SIZE])
+static int copy_and_send_packets(struct wilc *wilc, int entries)
{
int len, ret;
- len = copy_packets(wilc, entries, vmm_table, vmm_entries_ac);
+ len = copy_packets(wilc, entries);
if (len <= 0)
return len;
@@ -935,7 +932,6 @@ static int copy_and_send_packets(struct wilc *wilc, int entries,
int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
{
int vmm_table_len, entries;
- u8 vmm_entries_ac[WILC_VMM_TBL_SIZE];
int ret = 0;
u32 vmm_table[WILC_VMM_TBL_SIZE];
int srcu_idx;
@@ -951,7 +947,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev);
srcu_read_unlock(&wilc->srcu, srcu_idx);
- vmm_table_len = fill_vmm_table(wilc, vmm_table, vmm_entries_ac);
+ vmm_table_len = fill_vmm_table(wilc, vmm_table);
if (vmm_table_len == 0)
goto out_unlock;
@@ -966,7 +962,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
if (entries <= 0) {
ret = entries;
} else {
- ret = copy_and_send_packets(wilc, entries, vmm_table, vmm_entries_ac);
+ ret = copy_and_send_packets(wilc, entries);
}
if (ret >= 0 && entries < vmm_table_len)
ret = WILC_VMM_ENTRY_FULL_RETRY;
--
2.25.1
When a packet is moved to the chip queue, push the header and add
necessary padding to the socket-buffer directly.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/netdev.c | 4 ++
.../net/wireless/microchip/wilc1000/wlan.c | 65 +++++++++----------
2 files changed, 33 insertions(+), 36 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c
index 71cb15f042cdd..d9fbff4bfcd30 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.c
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.c
@@ -924,6 +924,10 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
if (!ndev)
return ERR_PTR(-ENOMEM);
+ ndev->needed_headroom = ETH_CONFIG_PKT_HDR_OFFSET;
+ /* we may need up to 3 bytes of padding: */
+ ndev->needed_tailroom = 3;
+
vif = netdev_priv(ndev);
ndev->ieee80211_ptr = &vif->priv.wdev;
strcpy(ndev->name, name);
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index f89ea4839aa61..08f3e96bf72cf 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -626,30 +626,39 @@ static u32 tx_hdr_len(u8 type)
}
}
-static u32 vmm_table_entry(struct sk_buff *tqe, u32 vmm_sz)
+static u32 vmm_table_entry(struct sk_buff *tqe)
{
struct wilc_skb_tx_cb *tx_cb = WILC_SKB_TX_CB(tqe);
u32 entry;
- entry = vmm_sz / 4;
+ entry = tqe->len / 4;
if (tx_cb->type == WILC_CFG_PKT)
entry |= WILC_VMM_CFG_PKT;
return cpu_to_le32(entry);
}
/**
- * set_header() - set WILC-specific header
+ * add_hdr_and_pad() - prepare a packet for the chip queue
* @wilc: Pointer to the wilc structure.
* @tqe: The packet to add to the chip queue.
+ * @hdr_len: The size of the header to add.
* @vmm_sz: The final size of the packet, including VMM header and padding.
- * @hdr: Pointer to the header to set
+ *
+ * Bring a packet into the form required by the chip by adding a
+ * header and padding as needed.
*/
-static void set_header(struct wilc *wilc, struct sk_buff *tqe,
- u32 vmm_sz, void *hdr)
+static void add_hdr_and_pad(struct wilc *wilc, struct sk_buff *tqe,
+ u32 hdr_len, u32 vmm_sz)
{
struct wilc_skb_tx_cb *tx_cb = WILC_SKB_TX_CB(tqe);
u32 mgmt_pkt = 0, vmm_hdr, prio, data_len = tqe->len;
struct wilc_vif *vif;
+ void *hdr;
+
+ /* grow skb with header and pad bytes, all initialized to 0: */
+ hdr = skb_push(tqe, hdr_len);
+ if (vmm_sz > tqe->len)
+ skb_put(tqe, vmm_sz - tqe->len);
/* add the VMM header word: */
if (tx_cb->type == WILC_MGMT_PKT)
@@ -687,8 +696,8 @@ static int schedule_packets(struct wilc *wilc,
static const u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1};
u8 ac_desired_ratio[NQUEUES];
const u8 *num_pkts_to_add;
+ u32 vmm_sz, hdr_len;
bool ac_exist = 0;
- int vmm_sz = 0;
struct sk_buff *tqe;
struct wilc_skb_tx_cb *tx_cb;
@@ -710,8 +719,8 @@ static int schedule_packets(struct wilc *wilc,
continue;
tx_cb = WILC_SKB_TX_CB(tqe);
- vmm_sz = tx_hdr_len(tx_cb->type);
- vmm_sz += tqe->len;
+ hdr_len = tx_hdr_len(tx_cb->type);
+ vmm_sz = hdr_len + tqe->len;
vmm_sz = ALIGN(vmm_sz, 4);
if (wilc->chipq_bytes + vmm_sz > WILC_TX_BUFF_SIZE) {
@@ -721,12 +730,13 @@ static int schedule_packets(struct wilc *wilc,
}
atomic_dec(&wilc->txq_entries);
+ add_hdr_and_pad(wilc, tqe, hdr_len, vmm_sz);
+
__skb_queue_tail(&wilc->chipq, tqe);
wilc->chipq_bytes += tqe->len;
- vmm_table[vmm_table_len] = vmm_table_entry(tqe, vmm_sz);
+ vmm_table[vmm_table_len] = vmm_table_entry(tqe);
vmm_table_len++;
-
}
}
num_pkts_to_add = ac_preserve_ratio;
@@ -747,20 +757,13 @@ static int schedule_packets(struct wilc *wilc,
*/
static int fill_vmm_table(struct wilc *wilc, u32 vmm_table[WILC_VMM_TBL_SIZE])
{
- int vmm_table_len = 0, vmm_sz = 0;
+ int vmm_table_len = 0;
struct sk_buff *tqe;
- struct wilc_skb_tx_cb *tx_cb;
- if (unlikely(wilc->chipq_bytes > 0)) {
+ if (unlikely(wilc->chipq_bytes > 0))
/* fill in packets that are already on the chipq: */
- skb_queue_walk(&wilc->chipq, tqe) {
- tx_cb = WILC_SKB_TX_CB(tqe);
- vmm_sz = tx_hdr_len(tx_cb->type);
- vmm_sz += tqe->len;
- vmm_sz = ALIGN(vmm_sz, 4);
- vmm_table[vmm_table_len++] = vmm_table_entry(tqe, vmm_sz);
- }
- }
+ skb_queue_walk(&wilc->chipq, tqe)
+ vmm_table[vmm_table_len++] = vmm_table_entry(tqe);
vmm_table_len = schedule_packets(wilc, vmm_table_len, vmm_table);
if (vmm_table_len > 0) {
@@ -872,15 +875,12 @@ static int copy_packets(struct wilc *wilc, int entries)
u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0};
struct wilc_skb_tx_cb *tx_cb;
u8 *txb = wilc->tx_buffer;
- int i, vmm_sz;
+ int i;
+ struct sk_buff *tqe;
u32 offset;
offset = 0;
- i = 0;
do {
- struct sk_buff *tqe;
- u32 buffer_offset;
-
tqe = __skb_dequeue(&wilc->chipq);
if (WARN_ON(!tqe))
break;
@@ -889,15 +889,8 @@ static int copy_packets(struct wilc *wilc, int entries)
tx_cb = WILC_SKB_TX_CB(tqe);
ac_pkt_num_to_chip[tx_cb->q_num]++;
- buffer_offset = tx_hdr_len(tx_cb->type);
- vmm_sz = buffer_offset;
- vmm_sz += tqe->len;
- vmm_sz = ALIGN(vmm_sz, 4);
-
- set_header(wilc, tqe, vmm_sz, txb + offset);
- memcpy(&txb[offset + buffer_offset], tqe->data, tqe->len);
- offset += vmm_sz;
- i++;
+ memcpy(&txb[offset], tqe->data, tqe->len);
+ offset += tqe->len;
wilc_wlan_tx_packet_done(tqe, 1);
} while (--entries);
for (i = 0; i < NQUEUES; i++)
--
2.25.1
Setting bit 1 of the WILC_HOST_VMM_CTL register seems to tell the chip
that the VMM table has been updated and is ready for processing.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 3 ++-
drivers/net/wireless/microchip/wilc1000/wlan.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index a4523b0860878..cff70f7d38c89 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -763,7 +763,8 @@ static int send_vmm_table(struct wilc *wilc,
if (ret)
break;
- ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2);
+ ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL,
+ WILC_VMM_TABLE_UPDATED);
if (ret)
break;
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h
index f5d32ec93fdb9..11a54320ffd05 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.h
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.h
@@ -243,6 +243,7 @@
#define WILC_VMM_ENTRY_COUNT GENMASK(8, 3)
#define WILC_VMM_ENTRY_AVAILABLE BIT(2)
+#define WILC_VMM_TABLE_UPDATED BIT(1)
/*******************************************/
/* E0 and later Interrupt flags. */
/*******************************************/
--
2.25.1
Factor two copies of the same calculation into a single instance.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/spi.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index 5f73b3d2d2112..189907580d921 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -658,7 +658,7 @@ static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz)
u8 wb[32], rb[32];
int cmd_len, resp_len;
int retry, ix = 0;
- u8 crc[2];
+ u8 crc[2], *crc7;
struct wilc_spi_cmd *c;
struct wilc_spi_rsp_data *r;
@@ -673,8 +673,6 @@ static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz)
c->u.dma_cmd.size[0] = sz >> 8;
c->u.dma_cmd.size[1] = sz;
cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd.crc);
- if (spi_priv->crc7_enabled)
- c->u.dma_cmd.crc[0] = wilc_get_crc7(wb, cmd_len);
} else if (cmd == CMD_DMA_EXT_WRITE || cmd == CMD_DMA_EXT_READ) {
c->u.dma_cmd_ext.addr[0] = adr >> 16;
c->u.dma_cmd_ext.addr[1] = adr >> 8;
@@ -683,15 +681,16 @@ static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz)
c->u.dma_cmd_ext.size[1] = sz >> 8;
c->u.dma_cmd_ext.size[2] = sz;
cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd_ext.crc);
- if (spi_priv->crc7_enabled)
- c->u.dma_cmd_ext.crc[0] = wilc_get_crc7(wb, cmd_len);
} else {
dev_err(&spi->dev, "dma read write cmd [%x] not supported\n",
cmd);
return -EINVAL;
}
- if (spi_priv->crc7_enabled)
+ if (spi_priv->crc7_enabled) {
+ crc7 = wb + cmd_len;
+ *crc7 = wilc_get_crc7(wb, cmd_len);
cmd_len += 1;
+ }
resp_len = sizeof(*r);
--
2.25.1
Convert the transmit path to use normal socket-buffer operations
rather than driver-specific structures and functions.
This ends up deleting a fair amount of code and otherwise mostly
consists of switching struct txq_entry_t to struct sk_buff.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../wireless/microchip/wilc1000/cfg80211.c | 35 +--
drivers/net/wireless/microchip/wilc1000/mon.c | 36 +--
.../net/wireless/microchip/wilc1000/netdev.c | 26 +-
.../net/wireless/microchip/wilc1000/netdev.h | 7 +-
.../net/wireless/microchip/wilc1000/wlan.c | 281 +++++++-----------
.../net/wireless/microchip/wilc1000/wlan.h | 50 +---
6 files changed, 137 insertions(+), 298 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index be387a8abb6af..d352b7dd03283 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -1038,14 +1038,6 @@ void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
}
-static void wilc_wfi_mgmt_tx_complete(void *priv, int status)
-{
- struct wilc_p2p_mgmt_data *pv_data = priv;
-
- kfree(pv_data->buff);
- kfree(pv_data);
-}
-
static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie)
{
struct wilc_vif *vif = data;
@@ -1124,7 +1116,7 @@ static int mgmt_tx(struct wiphy *wiphy,
const u8 *buf = params->buf;
size_t len = params->len;
const struct ieee80211_mgmt *mgmt;
- struct wilc_p2p_mgmt_data *mgmt_tx;
+ struct sk_buff *skb;
struct wilc_vif *vif = netdev_priv(wdev->netdev);
struct wilc_priv *priv = &vif->priv;
struct host_if_drv *wfi_drv = priv->hif_drv;
@@ -1141,20 +1133,11 @@ static int mgmt_tx(struct wiphy *wiphy,
if (!ieee80211_is_mgmt(mgmt->frame_control))
goto out;
- mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_KERNEL);
- if (!mgmt_tx) {
- ret = -ENOMEM;
- goto out;
- }
-
- mgmt_tx->buff = kmemdup(buf, len, GFP_KERNEL);
- if (!mgmt_tx->buff) {
- ret = -ENOMEM;
- kfree(mgmt_tx);
- goto out;
- }
+ skb = wilc_wlan_alloc_skb(vif, len);
+ if (!skb)
+ return -ENOMEM;
- mgmt_tx->size = len;
+ skb_put_data(skb, buf, len);
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
wilc_set_mac_chnl_num(vif, chan->hw_value);
@@ -1176,7 +1159,7 @@ static int mgmt_tx(struct wiphy *wiphy,
goto out_set_timeout;
vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
- mgmt_tx->buff + ie_offset,
+ skb->data + ie_offset,
len - ie_offset);
if (!vendor_ie)
goto out_set_timeout;
@@ -1189,9 +1172,7 @@ static int mgmt_tx(struct wiphy *wiphy,
out_txq_add_pkt:
- wilc_wlan_txq_add_mgmt_pkt(wdev->netdev, mgmt_tx,
- mgmt_tx->buff, mgmt_tx->size,
- wilc_wfi_mgmt_tx_complete);
+ wilc_wlan_txq_add_mgmt_pkt(wdev->netdev, skb);
out:
@@ -1732,7 +1713,7 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
wl->hif_func = ops;
for (i = 0; i < NQUEUES; i++)
- INIT_LIST_HEAD(&wl->txq[i].txq_head.list);
+ skb_queue_head_init(&wl->txq[i]);
INIT_LIST_HEAD(&wl->rxq_head.list);
INIT_LIST_HEAD(&wl->vif_list);
diff --git a/drivers/net/wireless/microchip/wilc1000/mon.c b/drivers/net/wireless/microchip/wilc1000/mon.c
index 6bd63934c2d84..0b1c4f266cca5 100644
--- a/drivers/net/wireless/microchip/wilc1000/mon.c
+++ b/drivers/net/wireless/microchip/wilc1000/mon.c
@@ -95,45 +95,21 @@ void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size)
netif_rx(skb);
}
-struct tx_complete_mon_data {
- int size;
- void *buff;
-};
-
-static void mgmt_tx_complete(void *priv, int status)
-{
- struct tx_complete_mon_data *pv_data = priv;
- /*
- * in case of fully hosting mode, the freeing will be done
- * in response to the cfg packet
- */
- kfree(pv_data->buff);
-
- kfree(pv_data);
-}
-
static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
{
- struct tx_complete_mon_data *mgmt_tx = NULL;
+ struct wilc_vif *vif = netdev_priv(dev);
+ struct sk_buff *skb;
if (!dev)
return -EFAULT;
netif_stop_queue(dev);
- mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_ATOMIC);
- if (!mgmt_tx)
- return -ENOMEM;
-
- mgmt_tx->buff = kmemdup(buf, len, GFP_ATOMIC);
- if (!mgmt_tx->buff) {
- kfree(mgmt_tx);
+ skb = wilc_wlan_alloc_skb(vif, len);
+ if (!skb)
return -ENOMEM;
- }
-
- mgmt_tx->size = len;
+ skb_put_data(skb, buf, len);
- wilc_wlan_txq_add_mgmt_pkt(dev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size,
- mgmt_tx_complete);
+ wilc_wlan_txq_add_mgmt_pkt(dev, skb);
netif_wake_queue(dev);
return 0;
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c
index 486091a4cb993..999933532c2de 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.c
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.c
@@ -718,19 +718,10 @@ static void wilc_set_multicast_list(struct net_device *dev)
kfree(mc_list);
}
-static void wilc_tx_complete(void *priv, int status)
-{
- struct tx_complete_data *pv_data = priv;
-
- dev_kfree_skb(pv_data->skb);
- kfree(pv_data);
-}
-
netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wilc_vif *vif = netdev_priv(ndev);
struct wilc *wilc = vif->wilc;
- struct tx_complete_data *tx_data = NULL;
int queue_count;
if (skb->dev != ndev) {
@@ -738,22 +729,9 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_OK;
}
- tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC);
- if (!tx_data) {
- dev_kfree_skb(skb);
- netif_wake_queue(ndev);
- return NETDEV_TX_OK;
- }
-
- tx_data->buff = skb->data;
- tx_data->size = skb->len;
- tx_data->skb = skb;
-
vif->netstats.tx_packets++;
- vif->netstats.tx_bytes += tx_data->size;
- queue_count = wilc_wlan_txq_add_net_pkt(ndev, tx_data,
- tx_data->buff, tx_data->size,
- wilc_tx_complete);
+ vif->netstats.tx_bytes += skb->len;
+ queue_count = wilc_wlan_txq_add_net_pkt(ndev, skb);
if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) {
int srcu_idx;
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h
index 60f4871a7d579..650b40961cf98 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.h
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.h
@@ -163,7 +163,7 @@ struct ack_session_info {
struct pending_acks {
u32 ack_num;
u32 session_index;
- struct txq_entry_t *txqe;
+ struct sk_buff *txqe;
};
struct tcp_ack_filter {
@@ -246,15 +246,14 @@ struct wilc {
/* lock to protect issue of wid command to firmware */
struct mutex cfg_cmd_lock;
- struct wilc_cfg_frame cfg_frame;
- u32 cfg_frame_offset;
+ struct sk_buff *cfg_skb;
u8 cfg_seq_no;
u8 *rx_buffer;
u32 rx_buffer_offset;
u8 *tx_buffer;
- struct txq_handle txq[NQUEUES];
+ struct sk_buff_head txq[NQUEUES];
atomic_t txq_entries;
struct txq_fw_recv_queue_stat fw[NQUEUES];
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index c352e939f1901..a970ddf43edf0 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -16,7 +16,7 @@
static const u8 factors[NQUEUES] = {1, 1, 1, 1};
-static void tcp_process(struct net_device *, struct txq_entry_t *);
+static void tcp_process(struct net_device *, struct sk_buff *);
static inline bool is_wilc1000(u32 id)
{
@@ -37,48 +37,19 @@ static inline void release_bus(struct wilc *wilc, enum bus_release release)
mutex_unlock(&wilc->hif_cs);
}
-static void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num,
- struct txq_entry_t *tqe)
-{
- list_del(&tqe->list);
- atomic_dec(&wilc->txq_entries);
- wilc->txq[q_num].count--;
-}
-
-static struct txq_entry_t *
-wilc_wlan_txq_remove_from_head(struct wilc *wilc, u8 q_num)
-{
- struct txq_entry_t *tqe = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&wilc->txq_spinlock, flags);
-
- if (!list_empty(&wilc->txq[q_num].txq_head.list)) {
- tqe = list_first_entry(&wilc->txq[q_num].txq_head.list,
- struct txq_entry_t, list);
- list_del(&tqe->list);
- atomic_dec(&wilc->txq_entries);
- wilc->txq[q_num].count--;
- }
- spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
- return tqe;
-}
-
-static void init_txq_entry(struct txq_entry_t *tqe, struct wilc_vif *vif,
+static void init_txq_entry(struct sk_buff *tqe, struct wilc_vif *vif,
u8 type, enum ip_pkt_priority q_num)
{
struct wilc_skb_tx_cb *tx_cb = WILC_SKB_TX_CB(tqe);
- tqe->vif = vif;
tx_cb->type = type;
tx_cb->q_num = q_num;
tx_cb->ack_idx = NOT_TCP_ACK;
}
static void wilc_wlan_txq_add_to_tail(struct net_device *dev, u8 type, u8 q_num,
- struct txq_entry_t *tqe)
+ struct sk_buff *tqe)
{
- unsigned long flags;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
@@ -86,34 +57,24 @@ static void wilc_wlan_txq_add_to_tail(struct net_device *dev, u8 type, u8 q_num,
if (type == WILC_NET_PKT && vif->ack_filter.enabled)
tcp_process(dev, tqe);
- spin_lock_irqsave(&wilc->txq_spinlock, flags);
-
- list_add_tail(&tqe->list, &wilc->txq[q_num].txq_head.list);
+ skb_queue_tail(&wilc->txq[q_num], tqe);
atomic_inc(&wilc->txq_entries);
- wilc->txq[q_num].count++;
-
- spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
wake_up_interruptible(&wilc->txq_event);
}
static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, u8 type, u8 q_num,
- struct txq_entry_t *tqe)
+ struct sk_buff *tqe)
{
- unsigned long flags;
struct wilc *wilc = vif->wilc;
init_txq_entry(tqe, vif, type, q_num);
mutex_lock(&wilc->txq_add_to_head_cs);
- spin_lock_irqsave(&wilc->txq_spinlock, flags);
-
- list_add(&tqe->list, &wilc->txq[q_num].txq_head.list);
+ skb_queue_head(&wilc->txq[q_num], tqe);
atomic_inc(&wilc->txq_entries);
- wilc->txq[q_num].count++;
- spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
mutex_unlock(&wilc->txq_add_to_head_cs);
wake_up_interruptible(&wilc->txq_event);
}
@@ -143,7 +104,7 @@ static inline void update_tcp_session(struct wilc_vif *vif, u32 index, u32 ack)
static inline void add_tcp_pending_ack(struct wilc_vif *vif, u32 ack,
u32 session_index,
- struct txq_entry_t *txqe)
+ struct sk_buff *txqe)
{
struct wilc_skb_tx_cb *tx_cb = WILC_SKB_TX_CB(txqe);
struct tcp_ack_filter *f = &vif->ack_filter;
@@ -158,9 +119,9 @@ static inline void add_tcp_pending_ack(struct wilc_vif *vif, u32 ack,
}
}
-static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
+static inline void tcp_process(struct net_device *dev, struct sk_buff *tqe)
{
- void *buffer = tqe->buffer;
+ void *buffer = tqe->data;
const struct ethhdr *eth_hdr_ptr = buffer;
int i;
unsigned long flags;
@@ -210,29 +171,30 @@ static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
}
-static void wilc_wlan_tx_packet_done(struct txq_entry_t *tqe, int status)
+static void wilc_wlan_tx_packet_done(struct sk_buff *tqe, int status)
{
- struct wilc_vif *vif = tqe->vif;
+ struct wilc_vif *vif = netdev_priv(tqe->dev);
struct wilc_skb_tx_cb *tx_cb = WILC_SKB_TX_CB(tqe);
int ack_idx = tx_cb->ack_idx;
- tqe->status = status;
- if (tqe->tx_complete_func)
- tqe->tx_complete_func(tqe->priv, tqe->status);
if (ack_idx != NOT_TCP_ACK && ack_idx < MAX_PENDING_ACKS)
vif->ack_filter.pending_acks[ack_idx].txqe = NULL;
- kfree(tqe);
+ if (status)
+ dev_consume_skb_any(tqe);
+ else
+ dev_kfree_skb_any(tqe);
}
-static void wilc_wlan_txq_drop_net_pkt(struct txq_entry_t *tqe)
+static void wilc_wlan_txq_drop_net_pkt(struct sk_buff *tqe)
{
- struct wilc_vif *vif = tqe->vif;
+ struct wilc_vif *vif = netdev_priv(tqe->dev);
struct wilc *wilc = vif->wilc;
struct wilc_skb_tx_cb *tx_cb = WILC_SKB_TX_CB(tqe);
vif->ndev->stats.tx_dropped++;
- wilc_wlan_txq_remove(wilc, tx_cb->q_num, tqe);
+ skb_unlink(tqe, &wilc->txq[tx_cb->q_num]);
+ atomic_dec(&wilc->txq_entries);
wilc_wlan_tx_packet_done(tqe, 1);
}
@@ -261,7 +223,7 @@ static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
bigger_ack_num = f->ack_session_info[index].bigger_ack_num;
if (f->pending_acks[i].ack_num < bigger_ack_num) {
- struct txq_entry_t *tqe;
+ struct sk_buff *tqe;
tqe = f->pending_acks[i].txqe;
if (tqe)
@@ -284,30 +246,17 @@ void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value)
vif->ack_filter.enabled = value;
}
-static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer,
- u32 buffer_size)
+static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, struct sk_buff *tqe)
{
- struct txq_entry_t *tqe;
struct wilc *wilc = vif->wilc;
netdev_dbg(vif->ndev, "Adding config packet ...\n");
if (wilc->quit) {
netdev_dbg(vif->ndev, "Return due to clear function\n");
- complete(&wilc->cfg_event);
- return 0;
- }
-
- tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
- if (!tqe) {
- complete(&wilc->cfg_event);
+ dev_kfree_skb_any(tqe);
return 0;
}
- tqe->buffer = buffer;
- tqe->buffer_size = buffer_size;
- tqe->tx_complete_func = NULL;
- tqe->priv = NULL;
-
wilc_wlan_txq_add_to_head(vif, WILC_CFG_PKT, AC_VO_Q, tqe);
return 1;
@@ -354,7 +303,7 @@ static bool is_ac_q_limit(struct wilc *wl, u8 q_num)
else
q_limit = (q->cnt[q_num] * FLOW_CONTROL_UPPER_THRESHOLD / q->sum) + 1;
- if (wl->txq[q_num].count <= q_limit)
+ if (skb_queue_len(&wl->txq[q_num]) <= q_limit)
ret = true;
spin_unlock_irqrestore(&wl->txq_spinlock, flags);
@@ -442,12 +391,8 @@ static inline u8 ac_change(struct wilc *wilc, u8 *ac)
return 1;
}
-int wilc_wlan_txq_add_net_pkt(struct net_device *dev,
- struct tx_complete_data *tx_data, u8 *buffer,
- u32 buffer_size,
- void (*tx_complete_fn)(void *, int))
+int wilc_wlan_txq_add_net_pkt(struct net_device *dev, struct sk_buff *tqe)
{
- struct txq_entry_t *tqe;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc;
u8 q_num;
@@ -455,109 +400,50 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev,
wilc = vif->wilc;
if (wilc->quit) {
- tx_complete_fn(tx_data, 0);
+ dev_kfree_skb_any(tqe);
return 0;
}
if (!wilc->initialized) {
- tx_complete_fn(tx_data, 0);
+ dev_kfree_skb_any(tqe);
return 0;
}
- tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
-
- if (!tqe) {
- tx_complete_fn(tx_data, 0);
- return 0;
- }
- tqe->buffer = buffer;
- tqe->buffer_size = buffer_size;
- tqe->tx_complete_func = tx_complete_fn;
- tqe->priv = tx_data;
-
- q_num = ac_classify(wilc, tx_data->skb);
+ q_num = ac_classify(wilc, tqe);
if (ac_change(wilc, &q_num)) {
- tx_complete_fn(tx_data, 0);
- kfree(tqe);
+ dev_kfree_skb_any(tqe);
return 0;
}
if (is_ac_q_limit(wilc, q_num)) {
wilc_wlan_txq_add_to_tail(dev, WILC_NET_PKT, q_num, tqe);
} else {
- tx_complete_fn(tx_data, 0);
- kfree(tqe);
+ dev_kfree_skb(tqe);
}
return atomic_read(&wilc->txq_entries);
}
-int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
- u32 buffer_size,
- void (*tx_complete_fn)(void *, int))
+int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, struct sk_buff *tqe)
{
- struct txq_entry_t *tqe;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc;
wilc = vif->wilc;
if (wilc->quit) {
- tx_complete_fn(priv, 0);
+ dev_kfree_skb_any(tqe);
return 0;
}
if (!wilc->initialized) {
- tx_complete_fn(priv, 0);
+ dev_kfree_skb_any(tqe);
return 0;
}
- tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC);
-
- if (!tqe) {
- tx_complete_fn(priv, 0);
- return 0;
- }
- tqe->buffer = buffer;
- tqe->buffer_size = buffer_size;
- tqe->tx_complete_func = tx_complete_fn;
- tqe->priv = priv;
wilc_wlan_txq_add_to_tail(dev, WILC_MGMT_PKT, AC_VO_Q, tqe);
return 1;
}
-static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc, u8 q_num)
-{
- struct txq_entry_t *tqe = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&wilc->txq_spinlock, flags);
-
- if (!list_empty(&wilc->txq[q_num].txq_head.list))
- tqe = list_first_entry(&wilc->txq[q_num].txq_head.list,
- struct txq_entry_t, list);
-
- spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
-
- return tqe;
-}
-
-static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc,
- struct txq_entry_t *tqe,
- u8 q_num)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&wilc->txq_spinlock, flags);
-
- if (!list_is_last(&tqe->list, &wilc->txq[q_num].txq_head.list))
- tqe = list_next_entry(tqe, list);
- else
- tqe = NULL;
- spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
-
- return tqe;
-}
-
static void wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe)
{
if (wilc->quit)
@@ -732,7 +618,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
u32 offset = 0;
bool max_size_over = 0, ac_exist = 0;
int vmm_sz = 0;
- struct txq_entry_t *tqe_q[NQUEUES];
+ struct sk_buff *tqe_q[NQUEUES];
struct wilc_skb_tx_cb *tx_cb;
int ret = 0;
int counter;
@@ -758,7 +644,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
srcu_read_unlock(&wilc->srcu, srcu_idx);
for (ac = 0; ac < NQUEUES; ac++)
- tqe_q[ac] = wilc_wlan_txq_get_first(wilc, ac);
+ tqe_q[ac] = skb_peek(&wilc->txq[ac]);
i = 0;
sum = 0;
@@ -786,7 +672,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
else
vmm_sz = HOST_HDR_OFFSET;
- vmm_sz += tqe_q[ac]->buffer_size;
+ vmm_sz += tqe_q[ac]->len;
vmm_sz = ALIGN(vmm_sz, 4);
if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE) {
@@ -802,9 +688,8 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
i++;
sum += vmm_sz;
- tqe_q[ac] = wilc_wlan_txq_get_next(wilc,
- tqe_q[ac],
- ac);
+ tqe_q[ac] = skb_peek_next(tqe_q[ac],
+ &wilc->txq[ac]);
}
}
num_pkts_to_add = ac_preserve_ratio;
@@ -894,17 +779,18 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
offset = 0;
i = 0;
do {
- struct txq_entry_t *tqe;
+ struct sk_buff *tqe;
u32 header, buffer_offset;
char *bssid;
u8 mgmt_ptk = 0;
- tqe = wilc_wlan_txq_remove_from_head(wilc, vmm_entries_ac[i]);
+ tqe = skb_dequeue(&wilc->txq[vmm_entries_ac[i]]);
if (!tqe)
break;
+ atomic_dec(&wilc->txq_entries);
ac_pkt_num_to_chip[vmm_entries_ac[i]]++;
- vif = tqe->vif;
+ vif = netdev_priv(tqe->dev);
tx_cb = WILC_SKB_TX_CB(tqe);
if (vmm_table[i] == 0)
break;
@@ -918,7 +804,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
header = (FIELD_PREP(WILC_VMM_HDR_TYPE, tx_cb->type) |
FIELD_PREP(WILC_VMM_HDR_MGMT_FIELD, mgmt_ptk) |
- FIELD_PREP(WILC_VMM_HDR_PKT_SIZE, tqe->buffer_size) |
+ FIELD_PREP(WILC_VMM_HDR_PKT_SIZE, tqe->len) |
FIELD_PREP(WILC_VMM_HDR_BUFF_SIZE, vmm_sz));
cpu_to_le32s(&header);
@@ -928,7 +814,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
} else if (tx_cb->type == WILC_NET_PKT) {
int prio = tx_cb->q_num;
- bssid = tqe->vif->bssid;
+ bssid = vif->bssid;
buffer_offset = ETH_ETHERNET_HDR_OFFSET;
memcpy(&txb[offset + 4], &prio, sizeof(prio));
memcpy(&txb[offset + 8], bssid, 6);
@@ -936,8 +822,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
buffer_offset = HOST_HDR_OFFSET;
}
- memcpy(&txb[offset + buffer_offset],
- tqe->buffer, tqe->buffer_size);
+ memcpy(&txb[offset + buffer_offset], tqe->data, tqe->len);
offset += vmm_sz;
i++;
wilc_wlan_tx_packet_done(tqe, 1);
@@ -1251,7 +1136,7 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)
void wilc_wlan_cleanup(struct net_device *dev)
{
- struct txq_entry_t *tqe;
+ struct sk_buff *tqe, *cfg_skb;
struct rxq_entry_t *rqe;
u8 ac;
struct wilc_vif *vif = netdev_priv(dev);
@@ -1259,9 +1144,15 @@ void wilc_wlan_cleanup(struct net_device *dev)
wilc->quit = 1;
for (ac = 0; ac < NQUEUES; ac++) {
- while ((tqe = wilc_wlan_txq_remove_from_head(wilc, ac)))
+ while ((tqe = skb_dequeue(&wilc->txq[ac])))
wilc_wlan_tx_packet_done(tqe, 0);
}
+ atomic_set(&wilc->txq_entries, 0);
+ cfg_skb = wilc->cfg_skb;
+ if (cfg_skb) {
+ wilc->cfg_skb = NULL;
+ dev_kfree_skb_any(cfg_skb);
+ }
while ((rqe = wilc_wlan_rxq_remove(wilc)))
kfree(rqe);
@@ -1273,21 +1164,52 @@ void wilc_wlan_cleanup(struct net_device *dev)
wilc->hif_func->hif_deinit(wilc);
}
+struct sk_buff *wilc_wlan_alloc_skb(struct wilc_vif *vif, size_t len)
+{
+ size_t size, headroom;
+ struct sk_buff *skb;
+
+ headroom = vif->ndev->needed_headroom;
+ size = headroom + len + vif->ndev->needed_tailroom;
+ skb = netdev_alloc_skb(vif->ndev, size);
+ if (!skb) {
+ netdev_err(vif->ndev, "Failed to alloc skb");
+ return NULL;
+ }
+ skb_reserve(skb, headroom);
+ return skb;
+}
+
+static struct sk_buff *alloc_cfg_skb(struct wilc_vif *vif)
+{
+ struct sk_buff *skb;
+
+ skb = wilc_wlan_alloc_skb(vif, (sizeof(struct wilc_cfg_cmd_hdr)
+ + WILC_MAX_CFG_FRAME_SIZE));
+ if (!skb)
+ return NULL;
+ skb_reserve(skb, sizeof(struct wilc_cfg_cmd_hdr));
+ return skb;
+}
+
static int wilc_wlan_cfg_commit(struct wilc_vif *vif, int type,
u32 drv_handler)
{
struct wilc *wilc = vif->wilc;
- struct wilc_cfg_frame *cfg = &wilc->cfg_frame;
- int t_len = wilc->cfg_frame_offset + sizeof(struct wilc_cfg_cmd_hdr);
struct wilc_cfg_cmd_hdr *hdr;
+ struct sk_buff *cfg_skb = wilc->cfg_skb;
- hdr = &cfg->hdr;
+ hdr = skb_push(cfg_skb, sizeof(*hdr));
hdr->cmd_type = (type == WILC_CFG_SET) ? 'W' : 'Q';
hdr->seq_no = wilc->cfg_seq_no;
- hdr->total_len = cpu_to_le16(t_len);
+ hdr->total_len = cpu_to_le16(cfg_skb->len);
hdr->driver_handler = cpu_to_le32(drv_handler);
+ /* We are about to pass ownership of cfg_skb to the tx queue
+ * (or it'll be destroyed, in case the queue is full):
+ */
+ wilc->cfg_skb = NULL;
- if (!wilc_wlan_txq_add_cfg_pkt(vif, (u8 *)&cfg->hdr, t_len))
+ if (!wilc_wlan_txq_add_cfg_pkt(vif, cfg_skb))
return -1;
return 0;
@@ -1316,24 +1238,32 @@ static int wilc_wlan_cfg_apply_wid(struct wilc_vif *vif, int start, u16 wid,
u8 *buffer, u32 buffer_size, int commit,
u32 drv_handler, bool set)
{
- u32 offset;
int ret_size;
struct wilc *wilc = vif->wilc;
mutex_lock(&wilc->cfg_cmd_lock);
- if (start)
- wilc->cfg_frame_offset = 0;
+ if (start) {
+ WARN_ON(wilc->cfg_skb);
+ wilc->cfg_skb = alloc_cfg_skb(vif);
+ if (!wilc->cfg_skb) {
+ netdev_dbg(vif->ndev, "Failed to alloc cfg_skb");
+ mutex_unlock(&wilc->cfg_cmd_lock);
+ return 0;
+ }
+ }
- offset = wilc->cfg_frame_offset;
if (set)
- ret_size = wilc_wlan_cfg_set_wid(wilc->cfg_frame.frame, offset,
+ ret_size = wilc_wlan_cfg_set_wid(skb_tail_pointer(wilc->cfg_skb), 0,
wid, buffer, buffer_size);
else
- ret_size = wilc_wlan_cfg_get_wid(wilc->cfg_frame.frame, offset,
- wid);
- offset += ret_size;
- wilc->cfg_frame_offset = offset;
+ ret_size = wilc_wlan_cfg_get_wid(skb_tail_pointer(wilc->cfg_skb), 0, wid);
+ if (ret_size == 0)
+ netdev_dbg(vif->ndev,
+ "Failed to add WID 0x%x to %s cfg packet\n",
+ wid, set ? "set" : "query");
+
+ skb_put(wilc->cfg_skb, ret_size);
if (!commit) {
mutex_unlock(&wilc->cfg_cmd_lock);
@@ -1353,7 +1283,6 @@ static int wilc_wlan_cfg_apply_wid(struct wilc_vif *vif, int start, u16 wid,
ret_size = 0;
}
- wilc->cfg_frame_offset = 0;
wilc->cfg_seq_no = (wilc->cfg_seq_no + 1) % 256;
mutex_unlock(&wilc->cfg_cmd_lock);
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h
index 295795a8060ac..10618327133ce 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.h
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.h
@@ -320,24 +320,19 @@ enum ip_pkt_priority {
AC_BK_Q = 3
};
-struct txq_entry_t {
- struct list_head list;
- int type;
- u8 q_num;
- int ack_idx;
- u8 *buffer;
- int buffer_size;
- void *priv;
- int status;
- struct wilc_vif *vif;
- void (*tx_complete_func)(void *priv, int status);
+/* When queueing a tx packet, this info is stored in the sk_buff's
+ * control buffer (cb).
+ */
+struct wilc_skb_tx_cb {
+ u8 type; /* one of WILC_*_PKT */
+ enum ip_pkt_priority q_num; /* AC queue this packet is on */
+ int ack_idx; /* TCP ack index */
};
-#define wilc_skb_tx_cb txq_entry_t
-
-static inline struct wilc_skb_tx_cb *WILC_SKB_TX_CB(struct txq_entry_t *tqe)
+static inline struct wilc_skb_tx_cb *WILC_SKB_TX_CB(struct sk_buff *skb)
{
- return (struct wilc_skb_tx_cb *)tqe;
+ BUILD_BUG_ON(sizeof(struct wilc_skb_tx_cb) > sizeof(skb->cb));
+ return (struct wilc_skb_tx_cb *)&skb->cb[0];
}
struct txq_fw_recv_queue_stat {
@@ -345,11 +340,6 @@ struct txq_fw_recv_queue_stat {
u8 count;
};
-struct txq_handle {
- struct txq_entry_t txq_head;
- u16 count;
-};
-
struct rxq_entry_t {
struct list_head list;
u8 *buffer;
@@ -382,12 +372,6 @@ struct wilc_hif_func {
#define WILC_MAX_CFG_FRAME_SIZE 1468
-struct tx_complete_data {
- int size;
- void *buff;
- struct sk_buff *skb;
-};
-
struct wilc_cfg_cmd_hdr {
u8 cmd_type;
u8 seq_no;
@@ -395,11 +379,6 @@ struct wilc_cfg_cmd_hdr {
__le32 driver_handler;
};
-struct wilc_cfg_frame {
- struct wilc_cfg_cmd_hdr hdr;
- u8 frame[WILC_MAX_CFG_FRAME_SIZE];
-};
-
struct wilc_cfg_rsp {
u8 type;
u8 seq_no;
@@ -411,19 +390,16 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
u32 buffer_size);
int wilc_wlan_start(struct wilc *wilc);
int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif);
-int wilc_wlan_txq_add_net_pkt(struct net_device *dev,
- struct tx_complete_data *tx_data, u8 *buffer,
- u32 buffer_size,
- void (*tx_complete_fn)(void *, int));
+int wilc_wlan_txq_add_net_pkt(struct net_device *dev, struct sk_buff *skb);
int wilc_wlan_handle_txq(struct wilc *wl, u32 *txq_count);
void wilc_handle_isr(struct wilc *wilc);
+struct sk_buff *wilc_wlan_alloc_skb(struct wilc_vif *vif, size_t len);
void wilc_wlan_cleanup(struct net_device *dev);
int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,
u32 buffer_size, int commit, u32 drv_handler);
int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,
u32 drv_handler);
-int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
- u32 buffer_size, void (*func)(void *, int));
+int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, struct sk_buff *skb);
void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value);
int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc);
netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev);
--
2.25.1
This restructures the function to make it much clearer how the bus
hand-off works. The patch is unfortunately a bit difficult to read,
but the final code is clearer and eliminates some gotos.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 43 ++++++++-----------
1 file changed, 19 insertions(+), 24 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 64497754a36b1..803d35b18d2e0 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -818,8 +818,8 @@ static int send_vmm_table(struct wilc *wilc,
* Context: The txq_add_to_head_cs mutex must still be held when
* calling this function.
*
- * Return:
- * Negative number on error, 0 on success.
+ * Return: Number of bytes copied to the transmit buffer (always
+ * non-negative).
*/
static int copy_packets(struct wilc *wilc, int entries, u32 *vmm_table,
u8 *vmm_entries_ac)
@@ -908,7 +908,7 @@ static int send_packets(struct wilc *wilc, int len)
int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
{
- int vmm_table_len, entries, len;
+ int vmm_table_len, entries;
u8 vmm_entries_ac[WILC_VMM_TBL_SIZE];
int ret = 0;
u32 vmm_table[WILC_VMM_TBL_SIZE];
@@ -931,29 +931,24 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
- ret = send_vmm_table(wilc, vmm_table_len, vmm_table);
- if (ret <= 0) {
- if (ret == 0)
- /* No VMM space available in firmware. Inform
- * caller to retry later.
- */
- ret = WILC_VMM_ENTRY_FULL_RETRY;
- goto out_release_bus;
- }
-
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
-
- entries = ret;
- len = copy_packets(wilc, entries, vmm_table, vmm_entries_ac);
- if (len <= 0)
- goto out_unlock;
-
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ entries = send_vmm_table(wilc, vmm_table_len, vmm_table);
- ret = send_packets(wilc, len);
+ release_bus(wilc, (entries > 0 ?
+ WILC_BUS_RELEASE_ONLY :
+ WILC_BUS_RELEASE_ALLOW_SLEEP));
-out_release_bus:
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ if (entries <= 0) {
+ ret = entries;
+ } else {
+ ret = copy_packets(wilc, entries, vmm_table, vmm_entries_ac);
+ if (ret > 0) {
+ acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ ret = send_packets(wilc, ret);
+ release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ }
+ }
+ if (ret >= 0 && entries < vmm_table_len)
+ ret = WILC_VMM_ENTRY_FULL_RETRY;
out_unlock:
mutex_unlock(&wilc->txq_add_to_head_cs);
--
2.25.1
Add a helper function to calculate header length instead of using the
same open code twice.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
.../net/wireless/microchip/wilc1000/wlan.c | 43 +++++++++++++------
1 file changed, 30 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 033979cc85b43..1cd9a7761343a 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -602,6 +602,33 @@ void host_sleep_notify(struct wilc *wilc)
}
EXPORT_SYMBOL_GPL(host_sleep_notify);
+/**
+ * tx_hdr_len() - calculate tx packet header length
+ * @type: The packet type for which to return the header length.
+ *
+ * Calculate the total header size for a given packet type. This size
+ * includes the 4 bytes required to hold the VMM header.
+ *
+ * Return: The total size of the header in bytes.
+ */
+static u32 tx_hdr_len(u8 type)
+{
+ switch (type) {
+ case WILC_NET_PKT:
+ return ETH_ETHERNET_HDR_OFFSET;
+
+ case WILC_CFG_PKT:
+ return ETH_CONFIG_PKT_HDR_OFFSET;
+
+ case WILC_MGMT_PKT:
+ return HOST_HDR_OFFSET;
+
+ default:
+ pr_err("%s: Invalid packet type %d.", __func__, type);
+ return 4;
+ }
+}
+
/**
* fill_vmm_table() - Fill VMM table with packets to be sent
* @wilc: Pointer to the wilc structure.
@@ -658,13 +685,7 @@ static int fill_vmm_table(const struct wilc *wilc,
goto out;
tx_cb = WILC_SKB_TX_CB(tqe_q[ac]);
- if (tx_cb->type == WILC_CFG_PKT)
- vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
- else if (tx_cb->type == WILC_NET_PKT)
- vmm_sz = ETH_ETHERNET_HDR_OFFSET;
- else
- vmm_sz = HOST_HDR_OFFSET;
-
+ vmm_sz = tx_hdr_len(tx_cb->type);
vmm_sz += tqe_q[ac]->len;
vmm_sz = ALIGN(vmm_sz, 4);
@@ -834,17 +855,13 @@ static int copy_packets(struct wilc *wilc, int entries, u32 *vmm_table,
cpu_to_le32s(&header);
memcpy(&txb[offset], &header, 4);
- if (tx_cb->type == WILC_CFG_PKT) {
- buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
- } else if (tx_cb->type == WILC_NET_PKT) {
+ buffer_offset = tx_hdr_len(tx_cb->type);
+ if (tx_cb->type == WILC_NET_PKT) {
int prio = tx_cb->q_num;
bssid = vif->bssid;
- buffer_offset = ETH_ETHERNET_HDR_OFFSET;
memcpy(&txb[offset + 4], &prio, sizeof(prio));
memcpy(&txb[offset + 8], bssid, 6);
- } else {
- buffer_offset = HOST_HDR_OFFSET;
}
memcpy(&txb[offset + buffer_offset], tqe->data, tqe->len);
--
2.25.1
Apart from being slightly more efficient, this makes the code easier
to follow.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index dc6608390591c..bdc31a4fd0f6a 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -636,8 +636,8 @@ static int fill_vmm_table(const struct wilc *wilc,
int i;
u8 k, ac;
u32 sum;
- u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1};
- u8 *num_pkts_to_add;
+ static const u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1};
+ const u8 *num_pkts_to_add;
bool ac_exist = 0;
int vmm_sz = 0;
struct sk_buff *tqe_q[NQUEUES];
--
2.25.1
ac_balance() is never going to fail ("ratio" is always non-NULL), so
there is no reason to pretend otherwise.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 5ea9129b36925..287c0843ba152 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -345,21 +345,23 @@ static inline u8 ac_classify(struct wilc *wilc, struct sk_buff *skb)
return q_num;
}
-static inline int ac_balance(struct wilc *wl, u8 *ratio)
+/**
+ * ac_balance() - balance queues by favoring ones with fewer packets pending
+ * @wl: Pointer to the wilc structure.
+ * @ratio: Pointer to array of length NQUEUES in which this function
+ * returns the number of packets that may be scheduled for each
+ * access category.
+ */
+static inline void ac_balance(const struct wilc *wl, u8 *ratio)
{
u8 i, max_count = 0;
- if (!ratio)
- return -EINVAL;
-
for (i = 0; i < NQUEUES; i++)
if (wl->fw[i].count > max_count)
max_count = wl->fw[i].count;
for (i = 0; i < NQUEUES; i++)
ratio[i] = max_count - wl->fw[i].count;
-
- return 0;
}
static inline void ac_update_fw_ac_pkt_info(struct wilc *wl, u32 reg)
@@ -894,8 +896,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
if (wilc->quit)
goto out_update_cnt;
- if (ac_balance(wilc, ac_desired_ratio))
- return -EINVAL;
+ ac_balance(wilc, ac_desired_ratio);
mutex_lock(&wilc->txq_add_to_head_cs);
--
2.25.1
The queue type for management packets was initialized to AC_BE_Q
(best-effort queue) but the packet was then actually added to the
AC_VO_Q queue (voice, or highest-priority queue). This fixes the
inconsistency by setting the type to AC_VO_Q.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 4e59d4c707ea5..1156498e66b81 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -507,7 +507,7 @@ int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
tqe->buffer_size = buffer_size;
tqe->tx_complete_func = tx_complete_fn;
tqe->priv = priv;
- tqe->q_num = AC_BE_Q;
+ tqe->q_num = AC_VO_Q;
tqe->ack_idx = NOT_TCP_ACK;
tqe->vif = vif;
wilc_wlan_txq_add_to_tail(dev, AC_VO_Q, tqe);
--
2.25.1
This patch just adds some helper variables. I suppose they improve
readability, but the real reason for this patch is to make the
forthcoming sk_buff rework patch shorter and more obvious.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 1156498e66b81..77dd91c23faad 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -192,11 +192,14 @@ static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
static void wilc_wlan_tx_packet_done(struct txq_entry_t *tqe, int status)
{
+ struct wilc_vif *vif = tqe->vif;
+ int ack_idx = tqe->ack_idx;
+
tqe->status = status;
if (tqe->tx_complete_func)
tqe->tx_complete_func(tqe->priv, tqe->status);
- if (tqe->ack_idx != NOT_TCP_ACK && tqe->ack_idx < MAX_PENDING_ACKS)
- tqe->vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL;
+ if (ack_idx != NOT_TCP_ACK && ack_idx < MAX_PENDING_ACKS)
+ vif->ack_filter.pending_acks[ack_idx].txqe = NULL;
kfree(tqe);
}
--
2.25.1
This simplifies fill_vmm_table() a bit more and will become even more
useful with the following patches.
Signed-off-by: David Mosberger-Tang <[email protected]>
---
drivers/net/wireless/microchip/wilc1000/wlan.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index cff70f7d38c89..5939ed5b2db68 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -629,6 +629,17 @@ static u32 tx_hdr_len(u8 type)
}
}
+static u32 vmm_table_entry(struct sk_buff *tqe, u32 vmm_sz)
+{
+ struct wilc_skb_tx_cb *tx_cb = WILC_SKB_TX_CB(tqe);
+ u32 entry;
+
+ entry = vmm_sz / 4;
+ if (tx_cb->type == WILC_CFG_PKT)
+ entry |= WILC_VMM_CFG_PKT;
+ return cpu_to_le32(entry);
+}
+
/**
* fill_vmm_table() - Fill VMM table with packets to be sent
* @wilc: Pointer to the wilc structure.
@@ -691,11 +702,7 @@ static int fill_vmm_table(const struct wilc *wilc,
if (sum + vmm_sz > WILC_TX_BUFF_SIZE)
goto out;
- vmm_table[i] = vmm_sz / 4;
- if (tx_cb->type == WILC_CFG_PKT)
- vmm_table[i] |= WILC_VMM_CFG_PKT;
-
- cpu_to_le32s(&vmm_table[i]);
+ vmm_table[i] = vmm_table_entry(tqe_q[ac], vmm_sz);
vmm_entries_ac[i] = ac;
i++;
--
2.25.1
On 23/12/21 06:44, David Mosberger-Tang wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> OK, so I'm nervous about such a large patch series, but it took a lot
> of work to break things down into atomic changes. This should be it
> for the transmit path as far as I'm concerned.
Thanks David for the efforts to break down the changes. I am still
reviewing and testing the previous series and found some inconsistent
results. I am not sure about the cause of the difference. For some
tests, the throughput is improved(~1Mbps) but for some CI tests, the
throughput is less compared(~1Mbps in same range) to the previous.
Though not observed much difference.
Now the new patches are added to the same series so it is difficult to
review them in one go.
I have a request, incase there are new patches please include them in
separate series. Breaking down the patch helps to identify the non
related changes which can go in separate series. The patches(change) may
be related to TX path flow but can go in separate series.
Regards,
Ajay
<[email protected]> writes:
> On 23/12/21 06:44, David Mosberger-Tang wrote:
>> EXTERNAL EMAIL: Do not click links or open attachments unless you
>> know the content is safe
>>
>> OK, so I'm nervous about such a large patch series, but it took a lot
>> of work to break things down into atomic changes. This should be it
>> for the transmit path as far as I'm concerned.
>
>
> Thanks David for the efforts to break down the changes. I am still
> reviewing and testing the previous series and found some inconsistent
> results. I am not sure about the cause of the difference. For some
> tests, the throughput is improved(~1Mbps) but for some CI tests, the
> throughput is less compared(~1Mbps in same range) to the previous.
> Though not observed much difference.
>
> Now the new patches are added to the same series so it is difficult to
> review them in one go.
>
> I have a request, incase there are new patches please include them in
> separate series. Breaking down the patch helps to identify the non
> related changes which can go in separate series. The patches(change) may
> be related to TX path flow but can go in separate series.
Yeah, a thumb of rule is to have around 10-12 patches per patchset. Then
it's still pretty easy to review them and get them accepted. Of course
it's not a hard rule, for smaller patches (like here) having more than
12 is still doable. An also the opposite, with big patches even 10
patches is too much. But 50 patches is just pure pain for the reviewers :)
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
On Thu, 2021-12-23 at 06:16 +0000, [email protected] wrote:
> On 23/12/21 06:44, David Mosberger-Tang wrote:
> > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> >
> > OK, so I'm nervous about such a large patch series, but it took a lot
> > of work to break things down into atomic changes. This should be it
> > for the transmit path as far as I'm concerned.
>
> Thanks David for the efforts to break down the changes. I am still
> reviewing and testing the previous series and found some inconsistent
> results. I am not sure about the cause of the difference. For some
> tests, the throughput is improved(~1Mbps) but for some CI tests, the
> throughput is less compared(~1Mbps in same range) to the previous.
> Though not observed much difference.
There shouldn't be any significant performance regressions. From my
observations, +/-1Mbps in throughput is quite possible due to cache-
effects.
> Now the new patches are added to the same series so it is difficult to
> review them in one go.
Ah, OK, sorry about that. After the automated error reports, I waited
for a day or two and after not seeing any further feedback, I figured
it'd be fine to add to the series.
I take it that as long as a patch shows up in patchworks with a
state==Action required, I should assume the patch is being worked on
(or will be worked on).
> I have a request, incase there are new patches please include them in
> separate series.
I'm not planning on adding more patches.
--david
Hi David,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on kvalo-wireless-drivers-next/master]
[also build test WARNING on kvalo-wireless-drivers/master v5.16-rc7 next-20211224]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/David-Mosberger-Tang/wilc1000-rework-tx-path-to-use-sk_buffs-throughout/20211223-091915
base: https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git master
config: sparc-randconfig-s031-20211228 (https://download.01.org/0day-ci/archive/20211228/[email protected]/config)
compiler: sparc64-linux-gcc (GCC) 11.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.4-dirty
# https://github.com/0day-ci/linux/commit/9339519807fd005c22f3299f859edc615e540d3f
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review David-Mosberger-Tang/wilc1000-rework-tx-path-to-use-sk_buffs-throughout/20211223-091915
git checkout 9339519807fd005c22f3299f859edc615e540d3f
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=sparc SHELL=/bin/bash drivers/net/wireless/microchip/wilc1000/
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>
sparse warnings: (new ones prefixed by >>)
>> drivers/net/wireless/microchip/wilc1000/wlan.c:640:16: sparse: sparse: incorrect type in return expression (different base types) @@ expected unsigned int @@ got restricted __le32 [usertype] @@
drivers/net/wireless/microchip/wilc1000/wlan.c:640:16: sparse: expected unsigned int
drivers/net/wireless/microchip/wilc1000/wlan.c:640:16: sparse: got restricted __le32 [usertype]
vim +640 drivers/net/wireless/microchip/wilc1000/wlan.c
631
632 static u32 vmm_table_entry(struct sk_buff *tqe, u32 vmm_sz)
633 {
634 struct wilc_skb_tx_cb *tx_cb = WILC_SKB_TX_CB(tqe);
635 u32 entry;
636
637 entry = vmm_sz / 4;
638 if (tx_cb->type == WILC_CFG_PKT)
639 entry |= WILC_VMM_CFG_PKT;
> 640 return cpu_to_le32(entry);
641 }
642
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]
Hi David,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on kvalo-wireless-drivers-next/master]
[also build test WARNING on kvalo-wireless-drivers/master v5.16-rc7 next-20211224]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/David-Mosberger-Tang/wilc1000-rework-tx-path-to-use-sk_buffs-throughout/20211223-091915
base: https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git master
config: sparc-randconfig-s031-20211228 (https://download.01.org/0day-ci/archive/20211228/[email protected]/config)
compiler: sparc64-linux-gcc (GCC) 11.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.4-dirty
# https://github.com/0day-ci/linux/commit/65a4186b405c72cc6e1a405db7ed0145a28a372f
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review David-Mosberger-Tang/wilc1000-rework-tx-path-to-use-sk_buffs-throughout/20211223-091915
git checkout 65a4186b405c72cc6e1a405db7ed0145a28a372f
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=sparc SHELL=/bin/bash drivers/net/wireless/microchip/wilc1000/
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>
sparse warnings: (new ones prefixed by >>)
drivers/net/wireless/microchip/wilc1000/wlan.c:640:16: sparse: sparse: incorrect type in return expression (different base types) @@ expected unsigned int @@ got restricted __le32 [usertype] @@
drivers/net/wireless/microchip/wilc1000/wlan.c:640:16: sparse: expected unsigned int
drivers/net/wireless/microchip/wilc1000/wlan.c:640:16: sparse: got restricted __le32 [usertype]
>> drivers/net/wireless/microchip/wilc1000/wlan.c:660:17: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] vmm_hdr @@ got restricted __le32 [usertype] @@
drivers/net/wireless/microchip/wilc1000/wlan.c:660:17: sparse: expected unsigned int [usertype] vmm_hdr
drivers/net/wireless/microchip/wilc1000/wlan.c:660:17: sparse: got restricted __le32 [usertype]
>> drivers/net/wireless/microchip/wilc1000/wlan.c:668:22: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] prio @@ got restricted __le32 [usertype] @@
drivers/net/wireless/microchip/wilc1000/wlan.c:668:22: sparse: expected unsigned int [usertype] prio
drivers/net/wireless/microchip/wilc1000/wlan.c:668:22: sparse: got restricted __le32 [usertype]
vim +660 drivers/net/wireless/microchip/wilc1000/wlan.c
642
643 /**
644 * set_header() - set WILC-specific header
645 * @wilc: Pointer to the wilc structure.
646 * @tqe: The packet to add to the chip queue.
647 * @vmm_sz: The final size of the packet, including VMM header and padding.
648 * @hdr: Pointer to the header to set
649 */
650 static void set_header(struct wilc *wilc, struct sk_buff *tqe,
651 u32 vmm_sz, void *hdr)
652 {
653 struct wilc_skb_tx_cb *tx_cb = WILC_SKB_TX_CB(tqe);
654 u32 mgmt_pkt = 0, vmm_hdr, prio, data_len = tqe->len;
655 struct wilc_vif *vif;
656
657 /* add the VMM header word: */
658 if (tx_cb->type == WILC_MGMT_PKT)
659 mgmt_pkt = FIELD_PREP(WILC_VMM_HDR_MGMT_FIELD, 1);
> 660 vmm_hdr = cpu_to_le32(mgmt_pkt |
661 FIELD_PREP(WILC_VMM_HDR_TYPE, tx_cb->type) |
662 FIELD_PREP(WILC_VMM_HDR_PKT_SIZE, data_len) |
663 FIELD_PREP(WILC_VMM_HDR_BUFF_SIZE, vmm_sz));
664 memcpy(hdr, &vmm_hdr, 4);
665
666 if (tx_cb->type == WILC_NET_PKT) {
667 vif = netdev_priv(tqe->dev);
> 668 prio = cpu_to_le32(tx_cb->q_num);
669 memcpy(hdr + 4, &prio, sizeof(prio));
670 memcpy(hdr + 8, vif->bssid, ETH_ALEN);
671 }
672 }
673
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]