Netdev Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Kari Argillander <kari.argillander@gmail.com>
To: Srinivasan Raju <srini.raju@purelifi.com>
Cc: "mostafa.afgani@purelifi.com Kalle Valo" <kvalo@codeaurora.org>,
	"David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>,
	Johannes Berg <johannes@sipsolutions.net>,
	open list <linux-kernel@vger.kernel.org>,
	"open list:NETWORKING DRIVERS (WIRELESS)" 
	<linux-wireless@vger.kernel.org>,
	"open list:NETWORKING DRIVERS" <netdev@vger.kernel.org>
Subject: Re: [PATCH v20 2/2] wireless: Initial driver submission for pureLiFi STA devices
Date: Wed, 27 Oct 2021 15:38:39 +0300	[thread overview]
Message-ID: <20211027123839.6h3rgxsgk6p4ydg3@kari-VirtualBox> (raw)
In-Reply-To: <20211018100143.7565-3-srini.raju@purelifi.com>

On Mon, Oct 18, 2021 at 11:00:55AM +0100, Srinivasan Raju wrote:
> This driver implementation has been based on the zd1211rw driver
> 
> Driver is based on 802.11 softMAC Architecture and uses
> native 802.11 for configuration and management
> 
> The driver is compiled and tested in ARM, x86 architectures and
> compiled in powerpc architecture

Just small style issues in this review.

> Signed-off-by: Srinivasan Raju <srini.raju@purelifi.com>
> ---
>  MAINTAINERS                                   |   6 +
>  drivers/net/wireless/Kconfig                  |   1 +
>  drivers/net/wireless/Makefile                 |   1 +
>  drivers/net/wireless/purelifi/Kconfig         |  17 +
>  drivers/net/wireless/purelifi/Makefile        |   2 +
>  drivers/net/wireless/purelifi/plfxlc/Kconfig  |  14 +
>  drivers/net/wireless/purelifi/plfxlc/Makefile |   3 +
>  drivers/net/wireless/purelifi/plfxlc/chip.c   |  95 ++
>  drivers/net/wireless/purelifi/plfxlc/chip.h   |  89 ++
>  .../net/wireless/purelifi/plfxlc/firmware.c   | 275 +++++
>  drivers/net/wireless/purelifi/plfxlc/intf.h   |  52 +
>  drivers/net/wireless/purelifi/plfxlc/mac.c    | 770 ++++++++++++++
>  drivers/net/wireless/purelifi/plfxlc/mac.h    | 190 ++++
>  drivers/net/wireless/purelifi/plfxlc/usb.c    | 975 ++++++++++++++++++
>  drivers/net/wireless/purelifi/plfxlc/usb.h    | 196 ++++
>  15 files changed, 2686 insertions(+)
>  create mode 100644 drivers/net/wireless/purelifi/Kconfig
>  create mode 100644 drivers/net/wireless/purelifi/Makefile
>  create mode 100644 drivers/net/wireless/purelifi/plfxlc/Kconfig
>  create mode 100644 drivers/net/wireless/purelifi/plfxlc/Makefile
>  create mode 100644 drivers/net/wireless/purelifi/plfxlc/chip.c
>  create mode 100644 drivers/net/wireless/purelifi/plfxlc/chip.h
>  create mode 100644 drivers/net/wireless/purelifi/plfxlc/firmware.c
>  create mode 100644 drivers/net/wireless/purelifi/plfxlc/intf.h
>  create mode 100644 drivers/net/wireless/purelifi/plfxlc/mac.c
>  create mode 100644 drivers/net/wireless/purelifi/plfxlc/mac.h
>  create mode 100644 drivers/net/wireless/purelifi/plfxlc/usb.c
>  create mode 100644 drivers/net/wireless/purelifi/plfxlc/usb.h


> diff --git a/drivers/net/wireless/purelifi/plfxlc/chip.h b/drivers/net/wireless/purelifi/plfxlc/chip.h
> new file mode 100644
> index 000000000000..167e9b9bd7a7
> --- /dev/null
> +++ b/drivers/net/wireless/purelifi/plfxlc/chip.h
> @@ -0,0 +1,89 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2021 pureLiFi
> + */
> +
> +#ifndef _LF_X_CHIP_H
> +#define _LF_X_CHIP_H
> +
> +#include <net/mac80211.h>
> +
> +#include "usb.h"
> +
> +enum unit_type {
> +	STA = 0,
> +	AP = 1,
> +};
> +
> +enum {
> +	PLFXLC_RADIO_OFF = 0,
> +	PLFXLC_RADIO_ON = 1,
> +};
> +
> +struct purelifi_chip {
> +	struct purelifi_usb usb;
> +	struct mutex mutex; /* lock to protect chip data */
> +	enum unit_type unit_type;
> +	u16 link_led;
> +	u8 beacon_set;
> +	__le16 beacon_interval;

Does seem little wierd that one variable is __le16. You could change
this u16 because there will not be anymore conversion either way.

> +};

> +#endif /* _LF_X_CHIP_H */
> diff --git a/drivers/net/wireless/purelifi/plfxlc/firmware.c b/drivers/net/wireless/purelifi/plfxlc/firmware.c
> new file mode 100644
> index 000000000000..30a8a63e13b6
> --- /dev/null
> +++ b/drivers/net/wireless/purelifi/plfxlc/firmware.c

> +
> +int download_fpga(struct usb_interface *intf)
> +{
> +	int r, actual_length;
> +	int fw_data_i, blk_tran_len = PLF_BULK_TLEN;
> +	const char *fw_name;
> +	unsigned char *fpga_dmabuff = NULL;
> +	unsigned char *fw_data;
> +	const struct firmware *fw = NULL;
> +	struct usb_device *udev = interface_to_usbdev(intf);

Can you please make something for function variables. They seems totally
random. If I am correct net/ and drivers/net want's reverse christmas
tree format. 

> +int download_xl_firmware(struct usb_interface *intf)
> +{
> +	const struct firmware *fwp = NULL;
> +	struct firmware_file file = {0};
> +	int s, r;
> +	u8 *buf;
> +	u32 i;
> +	const char *fw_pack;
> +	struct usb_device *udev = interface_to_usbdev(intf);
> +
> +	r = send_vendor_command(udev, PLF_VNDR_XL_FW_CMD, NULL, 0);
> +	msleep(PLF_MSLEEP_TIME);
> +
> +	if (r) {
> +		dev_err(&intf->dev, "vendor command failed (%d)\n", r);
> +		return -EINVAL;
> +	}
> +	/* Code for single pack file download */
> +
> +	fw_pack = "plfxlc/lifi-xl.bin";
> +
> +	r = request_firmware(&fwp, fw_pack, &intf->dev);
> +	if (r) {
> +		dev_err(&intf->dev, "Request_firmware failed (%d)\n", r);
> +		return -EINVAL;
> +	}
> +	file.total_files = get_unaligned_le32(&fwp->data[0]);
> +	file.total_size = get_unaligned_le32(&fwp->size);
> +
> +	dev_dbg(&intf->dev, "XL Firmware (%d, %d)\n",
> +		file.total_files, file.total_size);
> +
> +	buf = kzalloc(PLF_XL_BUF_LEN, GFP_KERNEL);
> +	if (!buf) {
> +		release_firmware(fwp);
> +		return -ENOMEM;
> +	}
> +
> +	if (file.total_files > 10) {
> +		dev_err(&intf->dev, "Too many files (%d)\n", file.total_files);
> +		release_firmware(fwp);
> +		kfree(buf);
> +		return -EINVAL;
> +	}
> +
> +	/* Download firmware files in multiple steps */
> +	for (s = 0; s < file.total_files; s++) {
> +		buf[0] = s;
> +		r = send_vendor_command(udev, PLF_VNDR_XL_FILE_CMD, buf,
> +					PLF_XL_BUF_LEN);
> +
> +		if (s < file.total_files - 1)
> +			file.size = get_unaligned_le32(&fwp->data[4 + ((s + 1) * 4)])
> +				    - get_unaligned_le32(&fwp->data[4 + (s) * 4]);
> +		else
> +			file.size = file.total_size -
> +				    get_unaligned_le32(&fwp->data[4 + (s) * 4]);
> +
> +		if (file.size > file.total_size || file.size > 60000) {
> +			dev_err(&intf->dev, "File size is too large (%d)\n", file.size);
> +			break;
> +		}
> +
> +		file.start_addr = get_unaligned_le32(&fwp->data[4 + (s * 4)]);
> +
> +		if (file.size % PLF_XL_BUF_LEN && s < 2)
> +			file.size += PLF_XL_BUF_LEN - file.size % PLF_XL_BUF_LEN;
> +
> +		file.control_packets = file.size / PLF_XL_BUF_LEN;
> +
> +		for (i = 0; i < file.control_packets; i++) {
> +			memcpy(buf,
> +			       &fwp->data[file.start_addr + (i * PLF_XL_BUF_LEN)],
> +			       PLF_XL_BUF_LEN);
> +			r = send_vendor_command(udev, PLF_VNDR_XL_DATA_CMD, buf,
> +						PLF_XL_BUF_LEN);
> +		}
> +		dev_dbg(&intf->dev, "fw-dw step=%d,r=%d size=%d\n", s, r,
> +			file.size);
> +	}
> +	release_firmware(fwp);
> +	kfree(buf);
> +
> +	/* Code for single pack file download ends fw download finish*/

space after finish

> +
> +	r = send_vendor_command(udev, PLF_VNDR_XL_EX_CMD, NULL, 0);
> +	dev_dbg(&intf->dev, "Download fpga (4) (%d)\n", r);
> +
> +	return 0;
> +}

> diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c
> new file mode 100644
> index 000000000000..6e403d5ac84c
> --- /dev/null
> +++ b/drivers/net/wireless/purelifi/plfxlc/mac.c


> +int purelifi_restore_settings(struct purelifi_mac *mac)
> +{
> +	struct sk_buff *beacon;
> +	int beacon_interval, beacon_period;
> +
> +	spin_lock_irq(&mac->lock);
> +	beacon_interval = mac->beacon.interval;
> +	beacon_period = mac->beacon.period;
> +	spin_unlock_irq(&mac->lock);
> +
> +	if (mac->type != NL80211_IFTYPE_ADHOC)
> +		return 0;
> +
> +	if (mac->vif) {
> +		beacon = ieee80211_beacon_get(mac->hw, mac->vif);
> +		if (beacon) {
> +			purelifi_mac_config_beacon(mac->hw, beacon);
> +			kfree_skb(beacon);
> +			/* Returned skb is used only once and lowlevel
> +			 *  driver is responsible for freeing it.

after * there is extre space.

> +			 */
> +		}
> +	}
> +
> +	purelifi_set_beacon_interval(&mac->chip, beacon_interval,
> +				     beacon_period, mac->type);
> +
> +	spin_lock_irq(&mac->lock);
> +	mac->beacon.last_update = jiffies;
> +	spin_unlock_irq(&mac->lock);
> +
> +	return 0;
> +}

> +void purelifi_mac_tx_to_dev(struct sk_buff *skb, int error)
> +{
> +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> +	struct ieee80211_hw *hw = info->rate_driver_data[0];
> +	struct purelifi_mac *mac = purelifi_hw_mac(hw);
> +
> +	ieee80211_tx_info_clear_status(info);
> +	skb_pull(skb, sizeof(struct purelifi_ctrlset));
> +
> +	if (unlikely(error ||
> +		     (info->flags & IEEE80211_TX_CTL_NO_ACK))) {
> +		ieee80211_tx_status_irqsafe(hw, skb);

If this is unlikely make this  return;

> +	} else {

and delete this else so you get lower indention level.

> +		struct sk_buff_head *q = &mac->ack_wait_queue;
> +
> +		skb_queue_tail(q, skb);
> +		while (skb_queue_len(q)/* > PURELIFI_MAC_MAX_ACK_WAITERS*/) {
> +			purelifi_mac_tx_status(hw, skb_dequeue(q),
> +					       mac->ack_pending ?
> +					       mac->ack_signal : 0,
> +					       NULL);
> +			mac->ack_pending = 0;
> +		}
> +	}
> +}
> +
> +static int purelifi_mac_config_beacon(struct ieee80211_hw *hw,
> +				      struct sk_buff *beacon)
> +{
> +	return plf_usb_wreq(beacon->data, beacon->len,
> +			USB_REQ_BEACON_WR);
> +}
> +
> +static int fill_ctrlset(struct purelifi_mac *mac, struct sk_buff *skb)

Should this also have prefix purelifi.

> +{
> +	unsigned int frag_len = skb->len;
> +	unsigned int tmp;
> +	u32 temp_len = 0;
> +	u32 temp_payload_len = 0;
> +	struct purelifi_ctrlset *cs;
> +
> +	if (skb_headroom(skb) < sizeof(struct purelifi_ctrlset)) {
> +		dev_dbg(purelifi_mac_dev(mac), "Not enough hroom(1)\n");
> +		return 1;
> +	}
> +
> +	cs = (void *)skb_push(skb, sizeof(struct purelifi_ctrlset));
> +	temp_payload_len = frag_len;
> +	temp_len = temp_payload_len +
> +		  sizeof(struct purelifi_ctrlset) -
> +		  sizeof(cs->id) - sizeof(cs->len);
> +
> +	/* data packet lengths must be multiple of four bytes
> +	 * and must not be a multiple of 512
> +	 * bytes. First, it is attempted to append the
> +	 * data packet in the tailroom of the skb. In rare
> +	 * ocasions, the tailroom is too small. In this case,
> +	 * the content of the packet is shifted into
> +	 * the headroom of the skb by memcpy. Headroom is allocated
> +	 * at startup (below in this file). Therefore,
> +	 * there will be always enough headroom. The call skb_headroom
> +	 * is an additional safety which might be
> +	 * dropped.
> +	 */

This is not wrapped correctly. Should be like:

	/* Data packet lengths must be multiple of four bytes and must
	 * not be a multiple of 512 bytes. First, it is attempted to
	 * append the data packet in the tailroom of the skb. In rare
	 * ocasions, the tailroom is too small. In this case, the
	 * content of the packet is shifted into the headroom of the skb
	 * by memcpy. Headroom is allocated at startup (below in this
	 * file). Therefore, there will be always enough headroom. The
	 * call skb_headroom is an additional safety which might be
	 * dropped.
 	 */

> +
> +	/* check if 32 bit aligned and align data */
> +	tmp = skb->len & 3;
> +	if (tmp) {
> +		if (skb_tailroom(skb) < (3 - tmp)) {
> +			if (skb_headroom(skb) >= 4 - tmp) {
> +				u8 len;
> +				u8 *src_pt;
> +				u8 *dest_pt;
> +
> +				len = skb->len;
> +				src_pt = skb->data;
> +				dest_pt = skb_push(skb, 4 - tmp);
> +				memmove(dest_pt, src_pt, len);
> +			} else {
> +				return -ENOBUFS;
> +			}
> +		} else {
> +			skb_put(skb, 4 - tmp);
> +		}
> +		temp_len += 4 - tmp;
> +	}
> +
> +	/* check if not multiple of 512 and align data */
> +	tmp = skb->len & 0x1ff;
> +	if (!tmp) {
> +		if (skb_tailroom(skb) < 4) {
> +			if (skb_headroom(skb) >= 4) {
> +				u8 len = skb->len;
> +				u8 *src_pt = skb->data;
> +				u8 *dest_pt = skb_push(skb, 4);
> +
> +				memcpy(dest_pt, src_pt, len);

I notice that Joe has said that you should use memmove in first version.
Just asking if this can overlap. If you are not sure memmove is safer.

> +			} else {
> +				/* should never happen because
> +				 * sufficient headroom was reserved
> +				 */
> +				return -ENOBUFS;
> +			}
> +		} else {
> +			skb_put(skb, 4);
> +		}
> +		temp_len += 4;
> +	}

You use almoust same thing two times row and it is quite long. Maybe
do new inline function.

> +
> +	cs->id = cpu_to_be32(USB_REQ_DATA_TX);
> +	cs->len = cpu_to_be32(temp_len);
> +	cs->payload_len_nw = cpu_to_be32(temp_payload_len);
> +
> +	return 0;
> +}
> +
> +static void plfxlc_op_tx(struct ieee80211_hw *hw,
> +			 struct ieee80211_tx_control *control,
> +			 struct sk_buff *skb)
> +{
> +	struct purelifi_mac *mac = purelifi_hw_mac(hw);
> +	struct purelifi_usb *usb = &mac->chip.usb;
> +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> +	struct purelifi_header *plhdr = (void *)skb->data;
> +	unsigned long flags;
> +	int r;
> +
> +	r = fill_ctrlset(mac, skb);
> +	if (r)
> +		goto fail;
> +
> +	info->rate_driver_data[0] = hw;
> +
> +	if (plhdr->frametype  == IEEE80211_FTYPE_DATA) {
> +		u8 *dst_mac = plhdr->dmac;
> +		u8 sidx;
> +		bool found = false;
> +		struct purelifi_usb_tx *tx = &usb->tx;
> +
> +		for (sidx = 0; sidx < MAX_STA_NUM; sidx++) {
> +			if (!(tx->station[sidx].flag & STATION_CONNECTED_FLAG))
> +				continue;
> +			if (!memcmp(tx->station[sidx].mac, dst_mac, ETH_ALEN)) {
> +				found = true;
> +				break;
> +			}

			if (memcmp(tx->station[sidx].mac, dst_mac, ETH_ALEN))
 				continue;

			found = true;
			break;

> +		}
> +
> +		/* Default to broadcast address for unknown MACs */
> +		if (!found)
> +			sidx = STA_BROADCAST_INDEX;
> +
> +		/* Stop OS from sending packets, if the queue is half full */
> +		if (skb_queue_len(&tx->station[sidx].data_list) > 60)
> +			ieee80211_stop_queues(purelifi_usb_to_hw(usb));
> +
> +		/* Schedule packet for transmission if queue is not full */
> +		if (skb_queue_len(&tx->station[sidx].data_list) < 256) {
> +			skb_queue_tail(&tx->station[sidx].data_list, skb);
> +			purelifi_send_packet_from_data_queue(usb);
> +		} else {
> +			goto fail;
> +		}

Reverse if statment and goto from there. Then no need for else.

> +	} else {
> +		spin_lock_irqsave(&usb->tx.lock, flags);
> +		r = plf_usb_wreq_async(&mac->chip.usb, skb->data, skb->len,
> +				       USB_REQ_DATA_TX, tx_urb_complete, skb);
> +		spin_unlock_irqrestore(&usb->tx.lock, flags);
> +		if (r)
> +			goto fail;
> +	}
> +	return;
> +
> +fail:
> +	dev_kfree_skb(skb);
> +}
> +
> +static int purelifi_filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
> +			       struct ieee80211_rx_status *stats)
> +{
> +	struct purelifi_mac *mac = purelifi_hw_mac(hw);
> +	struct sk_buff *skb;
> +	struct sk_buff_head *q;
> +	unsigned long flags;
> +	bool found = 0;

bool is nicer if used with true/false.

> +	int i, position = 0;
> +
> +	if (!ieee80211_is_ack(rx_hdr->frame_control))
> +		return 0;
> +
> +	dev_dbg(purelifi_mac_dev(mac), "ACK Received\n");
> +
> +	/* code based on zy driver, this logic may need fix */
> +	q = &mac->ack_wait_queue;
> +	spin_lock_irqsave(&q->lock, flags);
> +
> +	skb_queue_walk(q, skb) {
> +		struct ieee80211_hdr *tx_hdr;
> +
> +		position++;
> +
> +		if (mac->ack_pending && skb_queue_is_first(q, skb))
> +			continue;
> +		else if (mac->ack_pending == 0)

if is enogh

> +			break;
> +
> +		tx_hdr = (struct ieee80211_hdr *)skb->data;
> +		if (likely(ether_addr_equal(tx_hdr->addr2, rx_hdr->addr1))) {
> +			found = 1;
> +			break;
> +		}
> +	}
> +
> +	if (found) {
> +		for (i = 1; i < position; i++)
> +			skb = __skb_dequeue(q);
> +		if (i == position) {
> +			purelifi_mac_tx_status(hw, skb,
> +					       mac->ack_pending ?
> +					       mac->ack_signal : 0,
> +					       NULL);
> +			mac->ack_pending = 0;
> +		}
> +
> +		mac->ack_pending = skb_queue_len(q) ? 1 : 0;
> +		mac->ack_signal = stats->signal;
> +	}
> +
> +	spin_unlock_irqrestore(&q->lock, flags);
> +	return 1;
> +}
> +
> +int purelifi_mac_rx(struct ieee80211_hw *hw, const u8 *buffer,
> +		    unsigned int length)
> +{
> +	struct purelifi_mac *mac = purelifi_hw_mac(hw);
> +	struct ieee80211_rx_status stats;
> +	const struct rx_status *status;
> +	struct sk_buff *skb;
> +	int bad_frame = 0;
> +	__le16 fc;
> +	int need_padding;
> +	unsigned int payload_length;
> +	int sidx;
> +	struct purelifi_usb_tx *tx;

Add space

> +	/* Packet blockade during disabled interface. */
> +	if (!mac->vif)
> +		return 0;
> +
> +	memset(&stats, 0, sizeof(stats));
> +	status = (struct rx_status *)buffer;
> +
> +	stats.flag     = 0;
> +	stats.freq     = 2412;
> +	stats.band     = NL80211_BAND_LC;
> +	mac->rssi      = -15 * be16_to_cpu(status->rssi) / 10;
> +
> +	stats.signal   = mac->rssi;
> +
> +	if (status->rate_idx > 7)
> +		stats.rate_idx = 0;
> +	else
> +		stats.rate_idx = status->rate_idx;
> +
> +	mac->crc_errors = be64_to_cpu(status->crc_error_count);
> +
> +	if (!bad_frame &&
> +	    purelifi_filter_ack(hw, (struct ieee80211_hdr *)buffer, &stats) &&
> +	    !mac->pass_ctrl)
> +		return 0;
> +
> +	buffer += sizeof(struct rx_status);
> +	payload_length = get_unaligned_be32(buffer);
> +
> +	/* MTU = 1500, MAC header = 36, CRC = 4, sum = 1540 */

Seems little confusing that you write sum = 1540 and next line you use
1560.

> +	if (payload_length > 1560) {
> +		dev_err(purelifi_mac_dev(mac), " > MTU %u\n", payload_length);
> +		return 0;
> +	}
> +	buffer += sizeof(u32);
> +
> +	fc = get_unaligned((__le16 *)buffer);
> +	need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc);
> +
> +	tx = &mac->chip.usb.tx;
> +
> +	for (sidx = 0; sidx < MAX_STA_NUM - 1; sidx++) {
> +		if (memcmp(&buffer[10], tx->station[sidx].mac, ETH_ALEN))
> +			continue;
> +		if (tx->station[sidx].flag & STATION_CONNECTED_FLAG) {
> +			tx->station[sidx].flag |= STATION_HEARTBEAT_FLAG;
> +			break;
> +		}
> +	}
> +
> +	if (sidx == MAX_STA_NUM - 1) {
> +		for (sidx = 0; sidx < MAX_STA_NUM - 1; sidx++) {
> +			if (tx->station[sidx].flag & STATION_CONNECTED_FLAG)
> +				continue;
> +			memcpy(tx->station[sidx].mac, &buffer[10], ETH_ALEN);
> +			tx->station[sidx].flag |= STATION_CONNECTED_FLAG;
> +			tx->station[sidx].flag |= STATION_HEARTBEAT_FLAG;
> +			break;
> +		}
> +	}
> +
> +	switch (buffer[0]) {
> +	case IEEE80211_STYPE_PROBE_REQ:
> +		dev_dbg(purelifi_mac_dev(mac), "Probe request\n");
> +		break;
> +	case IEEE80211_STYPE_ASSOC_REQ:
> +		dev_dbg(purelifi_mac_dev(mac), "Association request\n");
> +		break;
> +	case IEEE80211_STYPE_AUTH:
> +		dev_dbg(purelifi_mac_dev(mac), "Authentication req\n");
> +		break;
> +	case IEEE80211_FTYPE_DATA:
> +		dev_dbg(purelifi_mac_dev(mac), "802.11 data frame\n");
> +		break;
> +	}
> +
> +	skb = dev_alloc_skb(payload_length + (need_padding ? 2 : 0));
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	if (need_padding)
> +		/* Make sure that the payload data is 4 byte aligned. */
> +		skb_reserve(skb, 2);
> +
> +	skb_put_data(skb, buffer, payload_length);
> +	memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
> +	ieee80211_rx_irqsafe(hw, skb);
> +	return 0;
> +}
> +
> +static int plfxlc_op_add_interface(struct ieee80211_hw *hw,
> +				   struct ieee80211_vif *vif)
> +{
> +	struct purelifi_mac *mac = purelifi_hw_mac(hw);
> +	static const char * const iftype80211[] = {
> +		[NL80211_IFTYPE_STATION]	= "Station",
> +		[NL80211_IFTYPE_ADHOC]		= "Adhoc"
> +	};
> +
> +	if (mac->type != NL80211_IFTYPE_UNSPECIFIED)
> +		return -EOPNOTSUPP;
> +
> +	if (vif->type == NL80211_IFTYPE_ADHOC ||
> +	    vif->type == NL80211_IFTYPE_STATION) {
> +		dev_dbg(purelifi_mac_dev(mac), "%s %s\n", __func__,
> +			iftype80211[vif->type]);
> +		mac->type = vif->type;
> +		mac->vif = vif;
> +	} else {
> +		dev_dbg(purelifi_mac_dev(mac), "unsupported iftype\n");
> +		return -EOPNOTSUPP;
> +	}

Reverse if so no else needed.

> +
> +	return 0;
> +}

> +static void plfxlc_op_bss_info_changed(struct ieee80211_hw *hw,
> +				       struct ieee80211_vif *vif,
> +				       struct ieee80211_bss_conf *bss_conf,
> +				       u32 changes)
> +{
> +	struct purelifi_mac *mac = purelifi_hw_mac(hw);
> +	int associated;
> +
> +	dev_dbg(purelifi_mac_dev(mac), "changes: %x\n", changes);
> +
> +	if (mac->type != NL80211_IFTYPE_ADHOC) { /* for STATION */
> +		associated = is_valid_ether_addr(bss_conf->bssid);
> +		goto exit_all;
> +	}
> +	/* for ADHOC */
> +	associated = true;
> +	if (changes & BSS_CHANGED_BEACON) {
> +		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
> +
> +		if (beacon) {
> +			purelifi_mac_config_beacon(hw, beacon);
> +			kfree_skb(beacon);
> +			/*Returned skb is used only once and

space after *

> +			 * low-level driver is
> +			 * responsible for freeing it.
> +			 */
> +		}
> +	}
> +
> +	if (changes & BSS_CHANGED_BEACON_ENABLED) {
> +		u16 interval = 0;
> +		u8 period = 0;
> +
> +		if (bss_conf->enable_beacon) {
> +			period = bss_conf->dtim_period;
> +			interval = bss_conf->beacon_int;
> +		}
> +
> +		spin_lock_irq(&mac->lock);
> +		mac->beacon.period = period;
> +		mac->beacon.interval = interval;
> +		mac->beacon.last_update = jiffies;
> +		spin_unlock_irq(&mac->lock);
> +
> +		purelifi_set_beacon_interval(&mac->chip, interval,
> +					     period, mac->type);
> +	}
> +exit_all:
> +	spin_lock_irq(&mac->lock);
> +	mac->associated = associated;
> +	spin_unlock_irq(&mac->lock);
> +}

> +static const struct ieee80211_ops plfxlc_ops = {
> +	.tx                 = plfxlc_op_tx,
> +	.start              = plfxlc_op_start,
> +	.stop               = plfxlc_op_stop,
> +	.add_interface      = plfxlc_op_add_interface,
> +	.remove_interface   = plfxlc_op_remove_interface,
> +	.set_rts_threshold  = purelifi_set_rts_threshold,
> +	.config             = plfxlc_op_config,
> +	.configure_filter   = plfxlc_op_configure_filter,
> +	.bss_info_changed   = plfxlc_op_bss_info_changed,
> +	.get_stats          = purelifi_get_stats,
> +	.get_et_sset_count  = purelifi_get_et_sset_count,
> +	.get_et_stats       = purelifi_get_et_stats,
> +	.get_et_strings     = purelifi_get_et_strings,
> +};

Just asking why some prefixes are purelifi and some are plfxlc?

> diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.h b/drivers/net/wireless/purelifi/plfxlc/mac.h
> new file mode 100644
> index 000000000000..3852d7343a40
> --- /dev/null
> +++ b/drivers/net/wireless/purelifi/plfxlc/mac.h
> @@ -0,0 +1,190 @@

> +struct purelifi_mac {
> +	struct purelifi_chip chip;
> +	spinlock_t lock; /* lock for mac data */
> +	struct ieee80211_hw *hw;
> +	struct ieee80211_vif *vif;
> +	struct beacon beacon;
> +	struct work_struct set_rts_cts_work;
> +	struct work_struct process_intr;
> +	struct purelifi_mc_hash multicast_hash;
> +	u8 intr_buffer[USB_MAX_EP_INT_BUFFER];
> +	u8 regdomain;
> +	u8 default_regdomain;
> +	u8 channel;
> +	int type;
> +	int associated;
> +	unsigned long flags;
> +	struct sk_buff_head ack_wait_queue;
> +	struct ieee80211_channel channels[14];
> +	struct ieee80211_rate rates[12];
> +	struct ieee80211_supported_band band;

Maybe move these below other ieee8011_* structs. Will be muh more
readable. Right now this struct is just big mess to read.

> +
> +	/* whether to pass frames with CRC errors to stack */
> +	bool pass_failed_fcs;
> +
> +	/* whether to pass control frames to stack */
> +	bool pass_ctrl;
> +
> +	/* whether we have received a 802.11 ACK that is pending */
> +	bool ack_pending;
> +
> +	/* signal strength of the last 802.11 ACK received */
> +	int ack_signal;
> +
> +	unsigned char hw_address[ETH_ALEN];
> +	char serial_number[PURELIFI_SERIAL_LEN];
> +	u64 crc_errors;
> +	u64 rssi;
> +};

> diff --git a/drivers/net/wireless/purelifi/plfxlc/usb.c b/drivers/net/wireless/purelifi/plfxlc/usb.c
> new file mode 100644
> index 000000000000..8cd9f223025e
> --- /dev/null
> +++ b/drivers/net/wireless/purelifi/plfxlc/usb.c

> +void purelifi_send_packet_from_data_queue(struct purelifi_usb *usb)
> +{
> +	struct sk_buff *skb = NULL;
> +	unsigned long flags;
> +	static u8 sidx;

Static here, but I might already tell that in preview message, but here
for safety.

> +	u8 last_served_sidx;
> +	struct purelifi_usb_tx *tx = &usb->tx;
> +
> +	spin_lock_irqsave(&tx->lock, flags);
> +	last_served_sidx = sidx;
> +	do {
> +		sidx = (sidx + 1) % MAX_STA_NUM;
> +		if (!tx->station[sidx].flag & STATION_CONNECTED_FLAG)
> +			continue;
> +		if (!(tx->station[sidx].flag & STATION_FIFO_FULL_FLAG))
> +			skb = skb_peek(&tx->station[sidx].data_list);
> +	} while ((sidx != last_served_sidx) && (!skb));
> +
> +	if (skb) {
> +		skb = skb_dequeue(&tx->station[sidx].data_list);
> +		plf_usb_wreq_async(usb, skb->data, skb->len, USB_REQ_DATA_TX,
> +				   tx_urb_complete, skb);
> +		if (skb_queue_len(&tx->station[sidx].data_list) <= 60)
> +			ieee80211_wake_queues(purelifi_usb_to_hw(usb));
> +	}
> +	spin_unlock_irqrestore(&tx->lock, flags);
> +}

> +static void rx_urb_complete(struct urb *urb)
> +{
> +	int r;
> +	struct purelifi_usb *usb;
> +	struct purelifi_usb_tx *tx;
> +	const u8 *buffer;
> +	unsigned int length;
> +	u16 status;
> +	u8 sidx;
> +
> +	if (!urb) {
> +		pr_err("urb is NULL\n");
> +		return;
> +	} else if (!urb->context) {

Another if is as good as this.

> +		pr_err("urb ctx is NULL\n");
> +		return;
> +	}

> +int purelifi_usb_enable_rx(struct purelifi_usb *usb)
> +{
> +	int r;
> +	struct purelifi_usb_rx *rx = &usb->rx;
> +
> +	mutex_lock(&rx->setup_mutex);
> +	r = __lf_x_usb_enable_rx(usb);
> +	if (!r)
> +		usb->rx_usb_enabled = 1;

Use true.

> +
> +	mutex_unlock(&rx->setup_mutex);
> +
> +	return r;
> +}

> +int purelifi_usb_tx(struct purelifi_usb *usb, struct sk_buff *skb)
> +{
> +	int r;
> +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> +	struct usb_device *udev = purelifi_usb_to_usbdev(usb);
> +	struct urb *urb;
> +	struct purelifi_usb_tx *tx = &usb->tx;
> +
> +	if (!test_bit(PLF_BIT_ENABLED, &tx->enabled)) {
> +		r = -ENOENT;
> +		goto out;
> +	}
> +
> +	urb = usb_alloc_urb(0, GFP_ATOMIC);
> +	if (!urb) {
> +		r = -ENOMEM;
> +		goto out;
> +	}
> +
> +	usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
> +			  skb->data, skb->len, tx_urb_complete, skb);
> +
> +	info->rate_driver_data[1] = (void *)jiffies;
> +	skb_queue_tail(&tx->submitted_skbs, skb);
> +	usb_anchor_urb(urb, &tx->submitted);
> +
> +	r = usb_submit_urb(urb, GFP_ATOMIC);
> +	if (r) {
> +		dev_dbg(purelifi_usb_dev(usb), "urb %p submit failed (%d)\n",
> +			urb, r);
> +		usb_unanchor_urb(urb);
> +		skb_unlink(skb, &tx->submitted_skbs);
> +		goto error;
> +	}
> +	return 0;
> +error:
> +	usb_free_urb(urb);
> +out:
> +	return r;

Do need to error paths in this function. Just return when goto out and
you use error just in one place.

> +}

> +int plf_usb_wreq_async(struct purelifi_usb *usb, const u8 *buffer,
> +		       int buffer_len, enum plf_usb_req_enum usb_req_id,
> +		       usb_complete_t complete_fn,
> +		       void *context)
> +{
> +	int r;
> +	struct usb_device *udev = interface_to_usbdev(ez_usb_interface);
> +	struct urb *urb = usb_alloc_urb(0, GFP_ATOMIC);
> +
> +	usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
> +			  (void *)buffer, buffer_len, complete_fn, context);
> +
> +	r = usb_submit_urb(urb, GFP_ATOMIC);
> +

Remove newline.

> +	if (r)
> +		dev_err(&udev->dev, "Async write submit failed (%d)\n", r);
> +
> +	return r;
> +}
> +
> +int plf_usb_wreq(void *buffer, int buffer_len,
> +		 enum plf_usb_req_enum usb_req_id)
> +{
> +	int r;
> +	int actual_length;
> +	int usb_bulk_msg_len;
> +	unsigned char *dma_buffer = NULL;
> +	struct usb_device *udev = interface_to_usbdev(ez_usb_interface);
> +	struct plf_usb_req usb_req;
> +
> +	get_usb_req(udev, buffer, buffer_len, usb_req_id, &usb_req);
> +	usb_bulk_msg_len = sizeof(__le32) + sizeof(__le32) +
> +			   be32_to_cpu(usb_req.len);
> +
> +	dma_buffer = kmemdup(&usb_req, usb_bulk_msg_len, GFP_KERNEL);
> +
> +	if (!dma_buffer) {
> +		r = -ENOMEM;
> +		goto error;
> +	}
> +
> +	r = usb_bulk_msg(udev,
> +			 usb_sndbulkpipe(udev, EP_DATA_OUT),
> +			 dma_buffer, usb_bulk_msg_len,
> +			 &actual_length, USB_BULK_MSG_TIMEOUT_MS);
> +	kfree(dma_buffer);
> +error:
> +	if (r)
> +		dev_err(&udev->dev, "usb_bulk_msg failed (%d)\n", r);

Can also be enomem. So maybe return -ENOMEM in upper.

> +
> +	return r;
> +}

> +static int probe(struct usb_interface *intf,
> +		 const struct usb_device_id *id)
> +{
> +	int r = 0;
> +	struct purelifi_chip *chip;
> +	struct purelifi_usb *usb;
> +	struct purelifi_usb_tx *tx;
> +	struct ieee80211_hw *hw = NULL;
> +	u8 hw_address[ETH_ALEN];
> +	u8 serial_number[PURELIFI_SERIAL_LEN];
> +	unsigned int i;
> +
> +	ez_usb_interface = intf;
> +
> +	hw = purelifi_mac_alloc_hw(intf);
> +

Remove newline

> +	if (!hw) {
> +		r = -ENOMEM;
> +		goto error;

Just return straight away. This should not need message.

> +	}
> +
> +	chip = &purelifi_hw_mac(hw)->chip;
> +	usb = &chip->usb;
> +	tx = &usb->tx;
> +
> +	r = upload_mac_and_serial(intf, hw_address, serial_number);
> +

Remove newline.

<snip>

> +	timer_setup(&usb->sta_queue_cleanup,
> +		    sta_queue_cleanup_timer_callb, 0);
> +	usb->sta_queue_cleanup.expires = jiffies + STA_QUEUE_CLEANUP_JIFF;
> +	add_timer(&usb->sta_queue_cleanup);
> +
> +	usb->initialized = 1;

true

> +	return 0;
> +error:
> +	if (hw) {
> +		purelifi_mac_release(purelifi_hw_mac(hw));
> +		ieee80211_unregister_hw(hw);
> +		ieee80211_free_hw(hw);
> +	}
> +	dev_err(&intf->dev, "pureLifi:Device error");
> +	return r;
> +}
> +
> +static void disconnect(struct usb_interface *intf)
> +{
> +	struct ieee80211_hw *hw = purelifi_intf_to_hw(intf);
> +	struct purelifi_mac *mac;
> +	struct purelifi_usb *usb;
> +
> +	/* Either something really bad happened, or
> +	 * we're just dealing with
> +	 * a DEVICE_INSTALLER.
> +	 */

wrapping

> +	if (!hw)
> +		return;
> +
> +	mac = purelifi_hw_mac(hw);
> +	usb = &mac->chip.usb;
> +
> +	del_timer_sync(&usb->tx.tx_retry_timer);
> +	del_timer_sync(&usb->sta_queue_cleanup);
> +
> +	ieee80211_unregister_hw(hw);
> +
> +	purelifi_usb_disable_tx(usb);
> +	purelifi_usb_disable_rx(usb);
> +
> +	/* If the disconnect has been caused by a removal of the
> +	 * driver module, the reset allows reloading of the driver. If the
> +	 * reset will not be executed here,
> +	 * the upload of the firmware in the
> +	 * probe function caused by the reloading of the driver will fail.
> +	 */

ditto

> +	usb_reset_device(interface_to_usbdev(intf));
> +
> +	purelifi_mac_release(mac);
> +	ieee80211_free_hw(hw);
> +}

> +static struct purelifi_usb *get_purelifi_usb(struct usb_interface *intf)
> +{
> +	struct ieee80211_hw *hw = purelifi_intf_to_hw(intf);
> +	struct purelifi_mac *mac;
> +
> +	/* Either something really bad happened, or
> +	 * we're just dealing with
> +	 * a DEVICE_INSTALLER.
> +	 */

wrapping

  Argillander

  parent reply	other threads:[~2021-10-27 12:38 UTC|newest]

Thread overview: 102+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20200924151910.21693-1-srini.raju@purelifi.com>
2020-09-28 10:19 ` [PATCH] [v2] wireless: Initial driver submission for pureLiFi devices Srinivasan Raju
2020-09-28 12:07   ` Joe Perches
2020-09-28 12:53     ` Srinivasan Raju
2020-09-30  5:16   ` Leon Romanovsky
2020-09-30  5:29     ` Srinivasan Raju
2020-09-30  8:01     ` Kalle Valo
2020-09-30  9:55       ` Leon Romanovsky
2020-09-30 10:11         ` Johannes Berg
2020-09-30 10:44           ` Leon Romanovsky
2020-10-16  8:23             ` Kalle Valo
2020-09-30  8:05     ` Kalle Valo
2020-09-30 10:04       ` Leon Romanovsky
2020-10-14  6:19   ` [PATCH] [PATCH] [v3] wireless: Initial driver submission for pureLiFi STA devices Srinivasan Raju
2020-10-15 22:35     ` Joe Perches
2020-10-16  6:36       ` Srinivasan Raju
2020-10-16  6:34   ` [PATCH] [v4] " Srinivasan Raju
2020-10-16  8:58     ` Joe Perches
2020-10-16 10:13       ` Srinivasan Raju
2020-10-19  3:17     ` [PATCH] [v5] " Srinivasan Raju
2020-10-19  4:55       ` Joe Perches
2020-10-19  6:05         ` Srinivasan Raju
2020-10-19  8:38       ` [PATCH] [v6] " Srinivasan Raju
2020-10-19 16:07         ` Krishna Chaitanya
2020-10-19 16:40           ` Srinivasan Raju
2020-10-19 16:54             ` Joe Perches
2020-10-19 17:05               ` Srinivasan Raju
2020-11-16  9:22     ` [PATCH] [v7] " Srinivasan Raju
2020-11-16 20:45       ` Joe Perches
2020-11-18  3:24         ` Srinivasan Raju
2020-11-24 14:44       ` Kalle Valo
     [not found]       ` <20201124144448.4E95EC43460@smtp.codeaurora.org>
2020-11-26  5:01         ` Srinivasan Raju
2020-12-03  4:43           ` Srinivasan Raju
2020-12-03 15:58             ` Kalle Valo
2020-12-03 16:50               ` Srinivasan Raju
2020-12-19 13:15                 ` Kalle Valo
2020-12-03  4:38   ` [PATCH] [v8] " Srinivasan Raju
2020-12-03  5:09   ` [PATCH] [v9] " Srinivasan Raju
2020-12-03  7:53     ` Joe Perches
2020-12-08  5:53   ` [PATCH] [v10] " Srinivasan Raju
2020-12-08 11:57   ` [PATCH] [v11] " Srinivasan Raju
2020-12-08 14:37     ` Kalle Valo
2020-12-19 12:51     ` Kalle Valo
2020-12-19 13:06     ` Kalle Valo
2020-12-19 13:14     ` Kalle Valo
2020-12-21  5:52       ` Srinivasan Raju
2020-12-21  5:57         ` Kalle Valo
2021-01-15 12:13           ` Srinivasan Raju
2021-01-05 13:19   ` [PATCH] [PATCH] [v12] " Srinivasan Raju
2021-02-12 11:49   ` [PATCH] [v13] " Srinivasan Raju
2021-02-12 13:44     ` Johannes Berg
2021-02-17 10:05       ` Kalle Valo
2021-02-19  5:15       ` Srinivasan Raju
2021-02-19  8:25         ` Johannes Berg
2021-02-24 10:41           ` Srinivasan Raju
2021-02-17 10:02     ` Kalle Valo
2021-02-17 10:13       ` Kalle Valo
2021-02-17 10:16         ` Srinivasan Raju
2021-02-17 10:09     ` Kalle Valo
2021-02-17 10:19     ` Kalle Valo
2021-02-24 10:44       ` Srinivasan Raju
2021-02-26 13:07   ` [PATCH] [v14] " Srinivasan Raju
2021-04-19 11:52     ` Srinivasan Raju
2021-08-10 13:02       ` Srinivasan Raju
2021-08-21 13:42         ` Kalle Valo
2021-08-18 14:13     ` [PATCH] [v15] " Srinivasan Raju
2021-09-20 13:05       ` Kalle Valo
     [not found]         ` <CWLP265MB3217BB5AA5F102629A3AD204E0A19@CWLP265MB3217.GBRP265.PROD.OUTLOOK.COM>
2021-09-21 12:30           ` [EXTERNAL] " Kalle Valo
2021-09-22  7:33             ` Johannes Berg
2021-09-24 13:27               ` [EXTERNAL] " Srinivasan Raju
2021-09-20 14:11       ` Kalle Valo
2021-09-24 11:11       ` Kalle Valo
2021-09-24 13:26   ` [PATCH] [v16] wireless: Initial driver submission for pureLiFi LiFi Station Srinivasan Raju
2021-09-24 13:40     ` Kalle Valo
2021-10-05 11:22   ` [PATCH] [v17] wireless: Initial driver submission for pureLiFi STA devices Srinivasan Raju
2021-10-05 11:26     ` Johannes Berg
2021-10-05 12:30   ` [PATCH] [v18 1/2] nl80211: Add LC placeholder band definition to enum nl80211_band Srinivasan Raju
2021-10-05 12:31   ` [PATCH] [v18 2/2] wireless: Initial driver submission for pureLiFi STA devices Srinivasan Raju
2021-10-05 22:09     ` Jeff Johnson
2021-10-06 10:04   ` [PATCH] [v19 " Srinivasan Raju
2021-10-11  6:16     ` Kalle Valo
2021-10-12 12:50   ` [PATCH 0/2] wireless: New Driver " Srinivasan Raju
2021-10-12 12:50     ` [PATCH 1/2] [v19 1/2] nl80211: Add LC placeholder band definition to enum nl80211_band Srinivasan Raju
2021-10-12 12:50     ` [PATCH 2/2] [v19 2/2] wireless: Initial driver submission for pureLiFi STA devices Srinivasan Raju
2021-10-18 10:00   ` [PATCH v20 0/2] wireless: New Driver " Srinivasan Raju
2021-10-18 10:00     ` [PATCH v20 1/2] nl80211: Add LC placeholder band definition to nl80211_band Srinivasan Raju
2021-10-18 10:00     ` [PATCH v20 2/2] wireless: Initial driver submission for pureLiFi STA devices Srinivasan Raju
2021-10-25  9:59       ` Kari Argillander
     [not found]         ` <CWLP265MB321780AB502EF147F6AAF197E0839@CWLP265MB3217.GBRP265.PROD.OUTLOOK.COM>
2021-10-25 12:17           ` [EXTERNAL] " Kalle Valo
2021-10-27 12:38       ` Kari Argillander [this message]
2021-10-28  7:24         ` Kalle Valo
2021-10-31 13:10   ` [PATCH v21 0/2] wireless: New Driver " Srinivasan Raju
2021-10-31 13:10     ` [PATCH 1/2] nl80211: Add LC placeholder band definition to nl80211_band Srinivasan Raju
2021-10-31 13:10     ` [PATCH 2/2] wireless: Initial driver submission for pureLiFi STA devices Srinivasan Raju
2021-12-20 19:13       ` Kalle Valo
2022-02-24 15:35       ` Kalle Valo
2022-02-24 18:20   ` [PATCH v22 0/2] wireless: New Driver " Srinivasan Raju
2022-02-24 18:20     ` [PATCH v22 1/2] nl80211: Add LC placeholder band definition to nl80211_band Srinivasan Raju
2022-02-25  9:52       ` Kalle Valo
2022-02-24 18:20     ` [PATCH v22 1/2] wireless: Initial driver submission for pureLiFi STA devices Srinivasan Raju
2022-04-25 13:06       ` Kalle Valo
     [not found]         ` <CWLP265MB32173F6188304F6B2CB90C79E0F89@CWLP265MB3217.GBRP265.PROD.OUTLOOK.COM>
2022-04-26  4:17           ` [EXTERNAL] " Kalle Valo
2022-04-27  4:55       ` Kalle Valo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211027123839.6h3rgxsgk6p4ydg3@kari-VirtualBox \
    --to=kari.argillander@gmail.com \
    --cc=davem@davemloft.net \
    --cc=johannes@sipsolutions.net \
    --cc=kuba@kernel.org \
    --cc=kvalo@codeaurora.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=srini.raju@purelifi.com \
    --subject='Re: [PATCH v20 2/2] wireless: Initial driver submission for pureLiFi STA devices' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).