xref: /openbmc/linux/drivers/net/wireless/purelifi/plfxlc/usb.c (revision 1188f7f111c61394ec56beb8e30322305a8220b6)
168d57a07SSrinivasan Raju // SPDX-License-Identifier: GPL-2.0-only
268d57a07SSrinivasan Raju /*
368d57a07SSrinivasan Raju  * Copyright (c) 2021 pureLiFi
468d57a07SSrinivasan Raju  */
568d57a07SSrinivasan Raju 
668d57a07SSrinivasan Raju #include <linux/kernel.h>
768d57a07SSrinivasan Raju #include <linux/init.h>
868d57a07SSrinivasan Raju #include <linux/device.h>
968d57a07SSrinivasan Raju #include <linux/errno.h>
1068d57a07SSrinivasan Raju #include <linux/slab.h>
1168d57a07SSrinivasan Raju #include <linux/skbuff.h>
1268d57a07SSrinivasan Raju #include <linux/usb.h>
1368d57a07SSrinivasan Raju #include <linux/workqueue.h>
1468d57a07SSrinivasan Raju #include <linux/proc_fs.h>
1568d57a07SSrinivasan Raju #include <linux/fs.h>
1668d57a07SSrinivasan Raju #include <linux/string.h>
1768d57a07SSrinivasan Raju #include <linux/module.h>
1868d57a07SSrinivasan Raju #include <net/mac80211.h>
1968d57a07SSrinivasan Raju #include <asm/unaligned.h>
2068d57a07SSrinivasan Raju #include <linux/sysfs.h>
2168d57a07SSrinivasan Raju 
2268d57a07SSrinivasan Raju #include "mac.h"
2368d57a07SSrinivasan Raju #include "usb.h"
2468d57a07SSrinivasan Raju #include "chip.h"
2568d57a07SSrinivasan Raju 
2668d57a07SSrinivasan Raju static const struct usb_device_id usb_ids[] = {
2768d57a07SSrinivasan Raju 	{ USB_DEVICE(PURELIFI_X_VENDOR_ID_0, PURELIFI_X_PRODUCT_ID_0),
2868d57a07SSrinivasan Raju 	  .driver_info = DEVICE_LIFI_X },
2968d57a07SSrinivasan Raju 	{ USB_DEVICE(PURELIFI_XC_VENDOR_ID_0, PURELIFI_XC_PRODUCT_ID_0),
3068d57a07SSrinivasan Raju 	  .driver_info = DEVICE_LIFI_XC },
3168d57a07SSrinivasan Raju 	{ USB_DEVICE(PURELIFI_XL_VENDOR_ID_0, PURELIFI_XL_PRODUCT_ID_0),
3268d57a07SSrinivasan Raju 	  .driver_info = DEVICE_LIFI_XL },
3368d57a07SSrinivasan Raju 	{}
3468d57a07SSrinivasan Raju };
3568d57a07SSrinivasan Raju 
plfxlc_send_packet_from_data_queue(struct plfxlc_usb * usb)3668d57a07SSrinivasan Raju void plfxlc_send_packet_from_data_queue(struct plfxlc_usb *usb)
3768d57a07SSrinivasan Raju {
3868d57a07SSrinivasan Raju 	struct plfxlc_usb_tx *tx = &usb->tx;
3968d57a07SSrinivasan Raju 	struct sk_buff *skb = NULL;
4068d57a07SSrinivasan Raju 	unsigned long flags;
4168d57a07SSrinivasan Raju 	u8 last_served_sidx;
4268d57a07SSrinivasan Raju 
4368d57a07SSrinivasan Raju 	spin_lock_irqsave(&tx->lock, flags);
4468d57a07SSrinivasan Raju 	last_served_sidx = usb->sidx;
4568d57a07SSrinivasan Raju 	do {
4668d57a07SSrinivasan Raju 		usb->sidx = (usb->sidx + 1) % MAX_STA_NUM;
4768d57a07SSrinivasan Raju 		if (!(tx->station[usb->sidx].flag & STATION_CONNECTED_FLAG))
4868d57a07SSrinivasan Raju 			continue;
4968d57a07SSrinivasan Raju 		if (!(tx->station[usb->sidx].flag & STATION_FIFO_FULL_FLAG))
5068d57a07SSrinivasan Raju 			skb = skb_peek(&tx->station[usb->sidx].data_list);
5168d57a07SSrinivasan Raju 	} while ((usb->sidx != last_served_sidx) && (!skb));
5268d57a07SSrinivasan Raju 
5368d57a07SSrinivasan Raju 	if (skb) {
5468d57a07SSrinivasan Raju 		skb = skb_dequeue(&tx->station[usb->sidx].data_list);
5568d57a07SSrinivasan Raju 		plfxlc_usb_wreq_async(usb, skb->data, skb->len, USB_REQ_DATA_TX,
5668d57a07SSrinivasan Raju 				      plfxlc_tx_urb_complete, skb);
5768d57a07SSrinivasan Raju 		if (skb_queue_len(&tx->station[usb->sidx].data_list) <= 60)
5868d57a07SSrinivasan Raju 			ieee80211_wake_queues(plfxlc_usb_to_hw(usb));
5968d57a07SSrinivasan Raju 	}
6068d57a07SSrinivasan Raju 	spin_unlock_irqrestore(&tx->lock, flags);
6168d57a07SSrinivasan Raju }
6268d57a07SSrinivasan Raju 
handle_rx_packet(struct plfxlc_usb * usb,const u8 * buffer,unsigned int length)6368d57a07SSrinivasan Raju static void handle_rx_packet(struct plfxlc_usb *usb, const u8 *buffer,
6468d57a07SSrinivasan Raju 			     unsigned int length)
6568d57a07SSrinivasan Raju {
6668d57a07SSrinivasan Raju 	plfxlc_mac_rx(plfxlc_usb_to_hw(usb), buffer, length);
6768d57a07SSrinivasan Raju }
6868d57a07SSrinivasan Raju 
rx_urb_complete(struct urb * urb)6968d57a07SSrinivasan Raju static void rx_urb_complete(struct urb *urb)
7068d57a07SSrinivasan Raju {
7168d57a07SSrinivasan Raju 	struct plfxlc_usb_tx *tx;
7268d57a07SSrinivasan Raju 	struct plfxlc_usb *usb;
7368d57a07SSrinivasan Raju 	unsigned int length;
7468d57a07SSrinivasan Raju 	const u8 *buffer;
7568d57a07SSrinivasan Raju 	u16 status;
7668d57a07SSrinivasan Raju 	u8 sidx;
7768d57a07SSrinivasan Raju 	int r;
7868d57a07SSrinivasan Raju 
7968d57a07SSrinivasan Raju 	if (!urb) {
8068d57a07SSrinivasan Raju 		pr_err("urb is NULL\n");
8168d57a07SSrinivasan Raju 		return;
8268d57a07SSrinivasan Raju 	}
8368d57a07SSrinivasan Raju 	if (!urb->context) {
8468d57a07SSrinivasan Raju 		pr_err("urb ctx is NULL\n");
8568d57a07SSrinivasan Raju 		return;
8668d57a07SSrinivasan Raju 	}
8768d57a07SSrinivasan Raju 	usb = urb->context;
8868d57a07SSrinivasan Raju 
8968d57a07SSrinivasan Raju 	if (usb->initialized != 1) {
9068d57a07SSrinivasan Raju 		pr_err("usb is not initialized\n");
9168d57a07SSrinivasan Raju 		return;
9268d57a07SSrinivasan Raju 	}
9368d57a07SSrinivasan Raju 
9468d57a07SSrinivasan Raju 	tx = &usb->tx;
9568d57a07SSrinivasan Raju 	switch (urb->status) {
9668d57a07SSrinivasan Raju 	case 0:
9768d57a07SSrinivasan Raju 		break;
9868d57a07SSrinivasan Raju 	case -ESHUTDOWN:
9968d57a07SSrinivasan Raju 	case -EINVAL:
10068d57a07SSrinivasan Raju 	case -ENODEV:
10168d57a07SSrinivasan Raju 	case -ENOENT:
10268d57a07SSrinivasan Raju 	case -ECONNRESET:
10368d57a07SSrinivasan Raju 	case -EPIPE:
10468d57a07SSrinivasan Raju 		dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status);
10568d57a07SSrinivasan Raju 		return;
10668d57a07SSrinivasan Raju 	default:
10768d57a07SSrinivasan Raju 		dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status);
10868d57a07SSrinivasan Raju 		if (tx->submitted_urbs++ < PURELIFI_URB_RETRY_MAX) {
10968d57a07SSrinivasan Raju 			dev_dbg(plfxlc_urb_dev(urb), "urb %p resubmit %d", urb,
11068d57a07SSrinivasan Raju 				tx->submitted_urbs++);
11168d57a07SSrinivasan Raju 			goto resubmit;
11268d57a07SSrinivasan Raju 		} else {
11368d57a07SSrinivasan Raju 			dev_dbg(plfxlc_urb_dev(urb), "urb %p  max resubmits reached", urb);
11468d57a07SSrinivasan Raju 			tx->submitted_urbs = 0;
11568d57a07SSrinivasan Raju 			return;
11668d57a07SSrinivasan Raju 		}
11768d57a07SSrinivasan Raju 	}
11868d57a07SSrinivasan Raju 
11968d57a07SSrinivasan Raju 	buffer = urb->transfer_buffer;
12068d57a07SSrinivasan Raju 	length = le32_to_cpu(*(__le32 *)(buffer + sizeof(struct rx_status)))
12168d57a07SSrinivasan Raju 		 + sizeof(u32);
12268d57a07SSrinivasan Raju 
12368d57a07SSrinivasan Raju 	if (urb->actual_length != (PLF_MSG_STATUS_OFFSET + 1)) {
12468d57a07SSrinivasan Raju 		if (usb->initialized && usb->link_up)
12568d57a07SSrinivasan Raju 			handle_rx_packet(usb, buffer, length);
12668d57a07SSrinivasan Raju 		goto resubmit;
12768d57a07SSrinivasan Raju 	}
12868d57a07SSrinivasan Raju 
12968d57a07SSrinivasan Raju 	status = buffer[PLF_MSG_STATUS_OFFSET];
13068d57a07SSrinivasan Raju 
13168d57a07SSrinivasan Raju 	switch (status) {
13268d57a07SSrinivasan Raju 	case STATION_FIFO_ALMOST_FULL_NOT_MESSAGE:
13368d57a07SSrinivasan Raju 		dev_dbg(&usb->intf->dev,
13468d57a07SSrinivasan Raju 			"FIFO full not packet receipt\n");
13568d57a07SSrinivasan Raju 		tx->mac_fifo_full = 1;
13668d57a07SSrinivasan Raju 		for (sidx = 0; sidx < MAX_STA_NUM; sidx++)
13768d57a07SSrinivasan Raju 			tx->station[sidx].flag |= STATION_FIFO_FULL_FLAG;
13868d57a07SSrinivasan Raju 		break;
13968d57a07SSrinivasan Raju 	case STATION_FIFO_ALMOST_FULL_MESSAGE:
14068d57a07SSrinivasan Raju 		dev_dbg(&usb->intf->dev, "FIFO full packet receipt\n");
14168d57a07SSrinivasan Raju 
14268d57a07SSrinivasan Raju 		for (sidx = 0; sidx < MAX_STA_NUM; sidx++)
14368d57a07SSrinivasan Raju 			tx->station[sidx].flag &= STATION_ACTIVE_FLAG;
14468d57a07SSrinivasan Raju 
14568d57a07SSrinivasan Raju 		plfxlc_send_packet_from_data_queue(usb);
14668d57a07SSrinivasan Raju 		break;
14768d57a07SSrinivasan Raju 	case STATION_CONNECT_MESSAGE:
14868d57a07SSrinivasan Raju 		usb->link_up = 1;
14968d57a07SSrinivasan Raju 		dev_dbg(&usb->intf->dev, "ST_CONNECT_MSG packet receipt\n");
15068d57a07SSrinivasan Raju 		break;
15168d57a07SSrinivasan Raju 	case STATION_DISCONNECT_MESSAGE:
15268d57a07SSrinivasan Raju 		usb->link_up = 0;
15368d57a07SSrinivasan Raju 		dev_dbg(&usb->intf->dev, "ST_DISCONN_MSG packet receipt\n");
15468d57a07SSrinivasan Raju 		break;
15568d57a07SSrinivasan Raju 	default:
15668d57a07SSrinivasan Raju 		dev_dbg(&usb->intf->dev, "Unknown packet receipt\n");
15768d57a07SSrinivasan Raju 		break;
15868d57a07SSrinivasan Raju 	}
15968d57a07SSrinivasan Raju 
16068d57a07SSrinivasan Raju resubmit:
16168d57a07SSrinivasan Raju 	r = usb_submit_urb(urb, GFP_ATOMIC);
16268d57a07SSrinivasan Raju 	if (r)
16368d57a07SSrinivasan Raju 		dev_dbg(plfxlc_urb_dev(urb), "urb %p resubmit fail (%d)\n", urb, r);
16468d57a07SSrinivasan Raju }
16568d57a07SSrinivasan Raju 
alloc_rx_urb(struct plfxlc_usb * usb)16668d57a07SSrinivasan Raju static struct urb *alloc_rx_urb(struct plfxlc_usb *usb)
16768d57a07SSrinivasan Raju {
16868d57a07SSrinivasan Raju 	struct usb_device *udev = plfxlc_usb_to_usbdev(usb);
16968d57a07SSrinivasan Raju 	struct urb *urb;
17068d57a07SSrinivasan Raju 	void *buffer;
17168d57a07SSrinivasan Raju 
17268d57a07SSrinivasan Raju 	urb = usb_alloc_urb(0, GFP_KERNEL);
17368d57a07SSrinivasan Raju 	if (!urb)
17468d57a07SSrinivasan Raju 		return NULL;
17568d57a07SSrinivasan Raju 
17668d57a07SSrinivasan Raju 	buffer = usb_alloc_coherent(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
17768d57a07SSrinivasan Raju 				    &urb->transfer_dma);
17868d57a07SSrinivasan Raju 	if (!buffer) {
17968d57a07SSrinivasan Raju 		usb_free_urb(urb);
18068d57a07SSrinivasan Raju 		return NULL;
18168d57a07SSrinivasan Raju 	}
18268d57a07SSrinivasan Raju 
18368d57a07SSrinivasan Raju 	usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN),
18468d57a07SSrinivasan Raju 			  buffer, USB_MAX_RX_SIZE,
18568d57a07SSrinivasan Raju 			  rx_urb_complete, usb);
18668d57a07SSrinivasan Raju 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
18768d57a07SSrinivasan Raju 
18868d57a07SSrinivasan Raju 	return urb;
18968d57a07SSrinivasan Raju }
19068d57a07SSrinivasan Raju 
free_rx_urb(struct urb * urb)19168d57a07SSrinivasan Raju static void free_rx_urb(struct urb *urb)
19268d57a07SSrinivasan Raju {
19368d57a07SSrinivasan Raju 	if (!urb)
19468d57a07SSrinivasan Raju 		return;
19568d57a07SSrinivasan Raju 	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
19668d57a07SSrinivasan Raju 			  urb->transfer_buffer, urb->transfer_dma);
19768d57a07SSrinivasan Raju 	usb_free_urb(urb);
19868d57a07SSrinivasan Raju }
19968d57a07SSrinivasan Raju 
__lf_x_usb_enable_rx(struct plfxlc_usb * usb)20068d57a07SSrinivasan Raju static int __lf_x_usb_enable_rx(struct plfxlc_usb *usb)
20168d57a07SSrinivasan Raju {
20268d57a07SSrinivasan Raju 	struct plfxlc_usb_rx *rx = &usb->rx;
20368d57a07SSrinivasan Raju 	struct urb **urbs;
20468d57a07SSrinivasan Raju 	int i, r;
20568d57a07SSrinivasan Raju 
20668d57a07SSrinivasan Raju 	r = -ENOMEM;
20768d57a07SSrinivasan Raju 	urbs = kcalloc(RX_URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
20868d57a07SSrinivasan Raju 	if (!urbs)
20968d57a07SSrinivasan Raju 		goto error;
21068d57a07SSrinivasan Raju 
21168d57a07SSrinivasan Raju 	for (i = 0; i < RX_URBS_COUNT; i++) {
21268d57a07SSrinivasan Raju 		urbs[i] = alloc_rx_urb(usb);
21368d57a07SSrinivasan Raju 		if (!urbs[i])
21468d57a07SSrinivasan Raju 			goto error;
21568d57a07SSrinivasan Raju 	}
21668d57a07SSrinivasan Raju 
21768d57a07SSrinivasan Raju 	spin_lock_irq(&rx->lock);
21868d57a07SSrinivasan Raju 
21968d57a07SSrinivasan Raju 	dev_dbg(plfxlc_usb_dev(usb), "irq_disabled %d\n", irqs_disabled());
22068d57a07SSrinivasan Raju 
22168d57a07SSrinivasan Raju 	if (rx->urbs) {
22268d57a07SSrinivasan Raju 		spin_unlock_irq(&rx->lock);
22368d57a07SSrinivasan Raju 		r = 0;
22468d57a07SSrinivasan Raju 		goto error;
22568d57a07SSrinivasan Raju 	}
22668d57a07SSrinivasan Raju 	rx->urbs = urbs;
22768d57a07SSrinivasan Raju 	rx->urbs_count = RX_URBS_COUNT;
22868d57a07SSrinivasan Raju 	spin_unlock_irq(&rx->lock);
22968d57a07SSrinivasan Raju 
23068d57a07SSrinivasan Raju 	for (i = 0; i < RX_URBS_COUNT; i++) {
23168d57a07SSrinivasan Raju 		r = usb_submit_urb(urbs[i], GFP_KERNEL);
23268d57a07SSrinivasan Raju 		if (r)
23368d57a07SSrinivasan Raju 			goto error_submit;
23468d57a07SSrinivasan Raju 	}
23568d57a07SSrinivasan Raju 
23668d57a07SSrinivasan Raju 	return 0;
23768d57a07SSrinivasan Raju 
23868d57a07SSrinivasan Raju error_submit:
23968d57a07SSrinivasan Raju 	for (i = 0; i < RX_URBS_COUNT; i++)
24068d57a07SSrinivasan Raju 		usb_kill_urb(urbs[i]);
24168d57a07SSrinivasan Raju 	spin_lock_irq(&rx->lock);
24268d57a07SSrinivasan Raju 	rx->urbs = NULL;
24368d57a07SSrinivasan Raju 	rx->urbs_count = 0;
24468d57a07SSrinivasan Raju 	spin_unlock_irq(&rx->lock);
24568d57a07SSrinivasan Raju error:
24668d57a07SSrinivasan Raju 	if (urbs) {
24768d57a07SSrinivasan Raju 		for (i = 0; i < RX_URBS_COUNT; i++)
24868d57a07SSrinivasan Raju 			free_rx_urb(urbs[i]);
24968d57a07SSrinivasan Raju 	}
250895b3b06SZiyang Xuan 	kfree(urbs);
25168d57a07SSrinivasan Raju 	return r;
25268d57a07SSrinivasan Raju }
25368d57a07SSrinivasan Raju 
plfxlc_usb_enable_rx(struct plfxlc_usb * usb)25468d57a07SSrinivasan Raju int plfxlc_usb_enable_rx(struct plfxlc_usb *usb)
25568d57a07SSrinivasan Raju {
25668d57a07SSrinivasan Raju 	struct plfxlc_usb_rx *rx = &usb->rx;
25768d57a07SSrinivasan Raju 	int r;
25868d57a07SSrinivasan Raju 
25968d57a07SSrinivasan Raju 	mutex_lock(&rx->setup_mutex);
26068d57a07SSrinivasan Raju 	r = __lf_x_usb_enable_rx(usb);
26168d57a07SSrinivasan Raju 	if (!r)
26268d57a07SSrinivasan Raju 		usb->rx_usb_enabled = 1;
26368d57a07SSrinivasan Raju 
26468d57a07SSrinivasan Raju 	mutex_unlock(&rx->setup_mutex);
26568d57a07SSrinivasan Raju 
26668d57a07SSrinivasan Raju 	return r;
26768d57a07SSrinivasan Raju }
26868d57a07SSrinivasan Raju 
__lf_x_usb_disable_rx(struct plfxlc_usb * usb)26968d57a07SSrinivasan Raju static void __lf_x_usb_disable_rx(struct plfxlc_usb *usb)
27068d57a07SSrinivasan Raju {
27168d57a07SSrinivasan Raju 	struct plfxlc_usb_rx *rx = &usb->rx;
27268d57a07SSrinivasan Raju 	unsigned long flags;
27368d57a07SSrinivasan Raju 	unsigned int count;
27468d57a07SSrinivasan Raju 	struct urb **urbs;
27568d57a07SSrinivasan Raju 	int i;
27668d57a07SSrinivasan Raju 
27768d57a07SSrinivasan Raju 	spin_lock_irqsave(&rx->lock, flags);
27868d57a07SSrinivasan Raju 	urbs = rx->urbs;
27968d57a07SSrinivasan Raju 	count = rx->urbs_count;
28068d57a07SSrinivasan Raju 	spin_unlock_irqrestore(&rx->lock, flags);
28168d57a07SSrinivasan Raju 
28268d57a07SSrinivasan Raju 	if (!urbs)
28368d57a07SSrinivasan Raju 		return;
28468d57a07SSrinivasan Raju 
28568d57a07SSrinivasan Raju 	for (i = 0; i < count; i++) {
28668d57a07SSrinivasan Raju 		usb_kill_urb(urbs[i]);
28768d57a07SSrinivasan Raju 		free_rx_urb(urbs[i]);
28868d57a07SSrinivasan Raju 	}
28968d57a07SSrinivasan Raju 	kfree(urbs);
29068d57a07SSrinivasan Raju 	rx->urbs = NULL;
29168d57a07SSrinivasan Raju 	rx->urbs_count = 0;
29268d57a07SSrinivasan Raju }
29368d57a07SSrinivasan Raju 
plfxlc_usb_disable_rx(struct plfxlc_usb * usb)29468d57a07SSrinivasan Raju void plfxlc_usb_disable_rx(struct plfxlc_usb *usb)
29568d57a07SSrinivasan Raju {
29668d57a07SSrinivasan Raju 	struct plfxlc_usb_rx *rx = &usb->rx;
29768d57a07SSrinivasan Raju 
29868d57a07SSrinivasan Raju 	mutex_lock(&rx->setup_mutex);
29968d57a07SSrinivasan Raju 	__lf_x_usb_disable_rx(usb);
30068d57a07SSrinivasan Raju 	usb->rx_usb_enabled = 0;
30168d57a07SSrinivasan Raju 	mutex_unlock(&rx->setup_mutex);
30268d57a07SSrinivasan Raju }
30368d57a07SSrinivasan Raju 
plfxlc_usb_disable_tx(struct plfxlc_usb * usb)30468d57a07SSrinivasan Raju void plfxlc_usb_disable_tx(struct plfxlc_usb *usb)
30568d57a07SSrinivasan Raju {
30668d57a07SSrinivasan Raju 	struct plfxlc_usb_tx *tx = &usb->tx;
30768d57a07SSrinivasan Raju 	unsigned long flags;
30868d57a07SSrinivasan Raju 
30968d57a07SSrinivasan Raju 	clear_bit(PLF_BIT_ENABLED, &tx->enabled);
31068d57a07SSrinivasan Raju 
31168d57a07SSrinivasan Raju 	/* kill all submitted tx-urbs */
31268d57a07SSrinivasan Raju 	usb_kill_anchored_urbs(&tx->submitted);
31368d57a07SSrinivasan Raju 
31468d57a07SSrinivasan Raju 	spin_lock_irqsave(&tx->lock, flags);
31568d57a07SSrinivasan Raju 	WARN_ON(!skb_queue_empty(&tx->submitted_skbs));
31668d57a07SSrinivasan Raju 	WARN_ON(tx->submitted_urbs != 0);
31768d57a07SSrinivasan Raju 	tx->submitted_urbs = 0;
31868d57a07SSrinivasan Raju 	spin_unlock_irqrestore(&tx->lock, flags);
31968d57a07SSrinivasan Raju 
32068d57a07SSrinivasan Raju 	/* The stopped state is ignored, relying on ieee80211_wake_queues()
32168d57a07SSrinivasan Raju 	 * in a potentionally following plfxlc_usb_enable_tx().
32268d57a07SSrinivasan Raju 	 */
32368d57a07SSrinivasan Raju }
32468d57a07SSrinivasan Raju 
plfxlc_usb_enable_tx(struct plfxlc_usb * usb)32568d57a07SSrinivasan Raju void plfxlc_usb_enable_tx(struct plfxlc_usb *usb)
32668d57a07SSrinivasan Raju {
32768d57a07SSrinivasan Raju 	struct plfxlc_usb_tx *tx = &usb->tx;
32868d57a07SSrinivasan Raju 	unsigned long flags;
32968d57a07SSrinivasan Raju 
33068d57a07SSrinivasan Raju 	spin_lock_irqsave(&tx->lock, flags);
33168d57a07SSrinivasan Raju 	set_bit(PLF_BIT_ENABLED, &tx->enabled);
33268d57a07SSrinivasan Raju 	tx->submitted_urbs = 0;
33368d57a07SSrinivasan Raju 	ieee80211_wake_queues(plfxlc_usb_to_hw(usb));
33468d57a07SSrinivasan Raju 	tx->stopped = 0;
33568d57a07SSrinivasan Raju 	spin_unlock_irqrestore(&tx->lock, flags);
33668d57a07SSrinivasan Raju }
33768d57a07SSrinivasan Raju 
plfxlc_tx_urb_complete(struct urb * urb)33868d57a07SSrinivasan Raju void plfxlc_tx_urb_complete(struct urb *urb)
33968d57a07SSrinivasan Raju {
34068d57a07SSrinivasan Raju 	struct ieee80211_tx_info *info;
34168d57a07SSrinivasan Raju 	struct plfxlc_usb *usb;
34268d57a07SSrinivasan Raju 	struct sk_buff *skb;
34368d57a07SSrinivasan Raju 
34468d57a07SSrinivasan Raju 	skb = urb->context;
34568d57a07SSrinivasan Raju 	info = IEEE80211_SKB_CB(skb);
34668d57a07SSrinivasan Raju 	/* grab 'usb' pointer before handing off the skb (since
34768d57a07SSrinivasan Raju 	 * it might be freed by plfxlc_mac_tx_to_dev or mac80211)
34868d57a07SSrinivasan Raju 	 */
34968d57a07SSrinivasan Raju 	usb = &plfxlc_hw_mac(info->rate_driver_data[0])->chip.usb;
35068d57a07SSrinivasan Raju 
35168d57a07SSrinivasan Raju 	switch (urb->status) {
35268d57a07SSrinivasan Raju 	case 0:
35368d57a07SSrinivasan Raju 		break;
35468d57a07SSrinivasan Raju 	case -ESHUTDOWN:
35568d57a07SSrinivasan Raju 	case -EINVAL:
35668d57a07SSrinivasan Raju 	case -ENODEV:
35768d57a07SSrinivasan Raju 	case -ENOENT:
35868d57a07SSrinivasan Raju 	case -ECONNRESET:
35968d57a07SSrinivasan Raju 	case -EPIPE:
36068d57a07SSrinivasan Raju 		dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status);
36168d57a07SSrinivasan Raju 		break;
36268d57a07SSrinivasan Raju 	default:
36368d57a07SSrinivasan Raju 		dev_dbg(plfxlc_urb_dev(urb), "urb %p error %d\n", urb, urb->status);
36468d57a07SSrinivasan Raju 		return;
36568d57a07SSrinivasan Raju 	}
36668d57a07SSrinivasan Raju 
36768d57a07SSrinivasan Raju 	plfxlc_mac_tx_to_dev(skb, urb->status);
36868d57a07SSrinivasan Raju 	plfxlc_send_packet_from_data_queue(usb);
36968d57a07SSrinivasan Raju 	usb_free_urb(urb);
37068d57a07SSrinivasan Raju }
37168d57a07SSrinivasan Raju 
init_usb_rx(struct plfxlc_usb * usb)37268d57a07SSrinivasan Raju static inline void init_usb_rx(struct plfxlc_usb *usb)
37368d57a07SSrinivasan Raju {
37468d57a07SSrinivasan Raju 	struct plfxlc_usb_rx *rx = &usb->rx;
37568d57a07SSrinivasan Raju 
37668d57a07SSrinivasan Raju 	spin_lock_init(&rx->lock);
37768d57a07SSrinivasan Raju 	mutex_init(&rx->setup_mutex);
37868d57a07SSrinivasan Raju 
37968d57a07SSrinivasan Raju 	if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH)
38068d57a07SSrinivasan Raju 		rx->usb_packet_size = 512;
38168d57a07SSrinivasan Raju 	else
38268d57a07SSrinivasan Raju 		rx->usb_packet_size = 64;
38368d57a07SSrinivasan Raju 
38468d57a07SSrinivasan Raju 	if (rx->fragment_length != 0)
38568d57a07SSrinivasan Raju 		dev_dbg(plfxlc_usb_dev(usb), "fragment_length error\n");
38668d57a07SSrinivasan Raju }
38768d57a07SSrinivasan Raju 
init_usb_tx(struct plfxlc_usb * usb)38868d57a07SSrinivasan Raju static inline void init_usb_tx(struct plfxlc_usb *usb)
38968d57a07SSrinivasan Raju {
39068d57a07SSrinivasan Raju 	struct plfxlc_usb_tx *tx = &usb->tx;
39168d57a07SSrinivasan Raju 
39268d57a07SSrinivasan Raju 	spin_lock_init(&tx->lock);
39368d57a07SSrinivasan Raju 	clear_bit(PLF_BIT_ENABLED, &tx->enabled);
39468d57a07SSrinivasan Raju 	tx->stopped = 0;
39568d57a07SSrinivasan Raju 	skb_queue_head_init(&tx->submitted_skbs);
39668d57a07SSrinivasan Raju 	init_usb_anchor(&tx->submitted);
39768d57a07SSrinivasan Raju }
39868d57a07SSrinivasan Raju 
plfxlc_usb_init(struct plfxlc_usb * usb,struct ieee80211_hw * hw,struct usb_interface * intf)39968d57a07SSrinivasan Raju void plfxlc_usb_init(struct plfxlc_usb *usb, struct ieee80211_hw *hw,
40068d57a07SSrinivasan Raju 		     struct usb_interface *intf)
40168d57a07SSrinivasan Raju {
40268d57a07SSrinivasan Raju 	memset(usb, 0, sizeof(*usb));
40368d57a07SSrinivasan Raju 	usb->intf = usb_get_intf(intf);
40468d57a07SSrinivasan Raju 	usb_set_intfdata(usb->intf, hw);
40568d57a07SSrinivasan Raju 	init_usb_tx(usb);
40668d57a07SSrinivasan Raju 	init_usb_rx(usb);
40768d57a07SSrinivasan Raju }
40868d57a07SSrinivasan Raju 
plfxlc_usb_release(struct plfxlc_usb * usb)40968d57a07SSrinivasan Raju void plfxlc_usb_release(struct plfxlc_usb *usb)
41068d57a07SSrinivasan Raju {
41168d57a07SSrinivasan Raju 	plfxlc_op_stop(plfxlc_usb_to_hw(usb));
41268d57a07SSrinivasan Raju 	plfxlc_usb_disable_tx(usb);
41368d57a07SSrinivasan Raju 	plfxlc_usb_disable_rx(usb);
41468d57a07SSrinivasan Raju 	usb_set_intfdata(usb->intf, NULL);
41568d57a07SSrinivasan Raju 	usb_put_intf(usb->intf);
41668d57a07SSrinivasan Raju }
41768d57a07SSrinivasan Raju 
plfxlc_speed(enum usb_device_speed speed)41868d57a07SSrinivasan Raju const char *plfxlc_speed(enum usb_device_speed speed)
41968d57a07SSrinivasan Raju {
42068d57a07SSrinivasan Raju 	switch (speed) {
42168d57a07SSrinivasan Raju 	case USB_SPEED_LOW:
42268d57a07SSrinivasan Raju 		return "low";
42368d57a07SSrinivasan Raju 	case USB_SPEED_FULL:
42468d57a07SSrinivasan Raju 		return "full";
42568d57a07SSrinivasan Raju 	case USB_SPEED_HIGH:
42668d57a07SSrinivasan Raju 		return "high";
42768d57a07SSrinivasan Raju 	default:
42868d57a07SSrinivasan Raju 		return "unknown";
42968d57a07SSrinivasan Raju 	}
43068d57a07SSrinivasan Raju }
43168d57a07SSrinivasan Raju 
plfxlc_usb_init_hw(struct plfxlc_usb * usb)43268d57a07SSrinivasan Raju int plfxlc_usb_init_hw(struct plfxlc_usb *usb)
43368d57a07SSrinivasan Raju {
43468d57a07SSrinivasan Raju 	int r;
43568d57a07SSrinivasan Raju 
43668d57a07SSrinivasan Raju 	r = usb_reset_configuration(plfxlc_usb_to_usbdev(usb));
43768d57a07SSrinivasan Raju 	if (r) {
43868d57a07SSrinivasan Raju 		dev_err(plfxlc_usb_dev(usb), "cfg reset failed (%d)\n", r);
43968d57a07SSrinivasan Raju 		return r;
44068d57a07SSrinivasan Raju 	}
44168d57a07SSrinivasan Raju 	return 0;
44268d57a07SSrinivasan Raju }
44368d57a07SSrinivasan Raju 
get_usb_req(struct usb_device * udev,void * buffer,u32 buffer_len,enum plf_usb_req_enum usb_req_id,struct plf_usb_req * usb_req)44468d57a07SSrinivasan Raju static void get_usb_req(struct usb_device *udev, void *buffer,
44568d57a07SSrinivasan Raju 			u32 buffer_len, enum plf_usb_req_enum usb_req_id,
44668d57a07SSrinivasan Raju 			struct plf_usb_req *usb_req)
44768d57a07SSrinivasan Raju {
44868d57a07SSrinivasan Raju 	__be32 payload_len_nw = cpu_to_be32(buffer_len + FCS_LEN);
44968d57a07SSrinivasan Raju 	const u8 *buffer_src_p = buffer;
45068d57a07SSrinivasan Raju 	u8 *buffer_dst = usb_req->buf;
45168d57a07SSrinivasan Raju 	u32 temp_usb_len = 0;
45268d57a07SSrinivasan Raju 
45368d57a07SSrinivasan Raju 	usb_req->id = cpu_to_be32(usb_req_id);
45468d57a07SSrinivasan Raju 	usb_req->len  = cpu_to_be32(0);
45568d57a07SSrinivasan Raju 
45668d57a07SSrinivasan Raju 	/* Copy buffer length into the transmitted buffer, as it is important
45768d57a07SSrinivasan Raju 	 * for the Rx MAC to know its exact length.
45868d57a07SSrinivasan Raju 	 */
45968d57a07SSrinivasan Raju 	if (usb_req->id == cpu_to_be32(USB_REQ_BEACON_WR)) {
46068d57a07SSrinivasan Raju 		memcpy(buffer_dst, &payload_len_nw, sizeof(payload_len_nw));
46168d57a07SSrinivasan Raju 		buffer_dst += sizeof(payload_len_nw);
46268d57a07SSrinivasan Raju 		temp_usb_len += sizeof(payload_len_nw);
46368d57a07SSrinivasan Raju 	}
46468d57a07SSrinivasan Raju 
46568d57a07SSrinivasan Raju 	memcpy(buffer_dst, buffer_src_p, buffer_len);
46668d57a07SSrinivasan Raju 	buffer_dst += buffer_len;
46768d57a07SSrinivasan Raju 	buffer_src_p += buffer_len;
46868d57a07SSrinivasan Raju 	temp_usb_len +=  buffer_len;
46968d57a07SSrinivasan Raju 
47068d57a07SSrinivasan Raju 	/* Set the FCS_LEN (4) bytes as 0 for CRC checking. */
47168d57a07SSrinivasan Raju 	memset(buffer_dst, 0, FCS_LEN);
47268d57a07SSrinivasan Raju 	buffer_dst += FCS_LEN;
47368d57a07SSrinivasan Raju 	temp_usb_len += FCS_LEN;
47468d57a07SSrinivasan Raju 
47568d57a07SSrinivasan Raju 	/* Round the packet to be transmitted to 4 bytes. */
47668d57a07SSrinivasan Raju 	if (temp_usb_len % PURELIFI_BYTE_NUM_ALIGNMENT) {
47768d57a07SSrinivasan Raju 		memset(buffer_dst, 0, PURELIFI_BYTE_NUM_ALIGNMENT -
47868d57a07SSrinivasan Raju 		       (temp_usb_len %
47968d57a07SSrinivasan Raju 			PURELIFI_BYTE_NUM_ALIGNMENT));
48068d57a07SSrinivasan Raju 		buffer_dst += PURELIFI_BYTE_NUM_ALIGNMENT -
48168d57a07SSrinivasan Raju 				(temp_usb_len %
48268d57a07SSrinivasan Raju 				PURELIFI_BYTE_NUM_ALIGNMENT);
48368d57a07SSrinivasan Raju 		temp_usb_len += PURELIFI_BYTE_NUM_ALIGNMENT -
48468d57a07SSrinivasan Raju 				(temp_usb_len % PURELIFI_BYTE_NUM_ALIGNMENT);
48568d57a07SSrinivasan Raju 	}
48668d57a07SSrinivasan Raju 
48768d57a07SSrinivasan Raju 	usb_req->len = cpu_to_be32(temp_usb_len);
48868d57a07SSrinivasan Raju }
48968d57a07SSrinivasan Raju 
plfxlc_usb_wreq_async(struct plfxlc_usb * usb,const u8 * buffer,int buffer_len,enum plf_usb_req_enum usb_req_id,usb_complete_t complete_fn,void * context)49068d57a07SSrinivasan Raju int plfxlc_usb_wreq_async(struct plfxlc_usb *usb, const u8 *buffer,
49168d57a07SSrinivasan Raju 			  int buffer_len, enum plf_usb_req_enum usb_req_id,
49268d57a07SSrinivasan Raju 			  usb_complete_t complete_fn,
49368d57a07SSrinivasan Raju 			  void *context)
49468d57a07SSrinivasan Raju {
49568d57a07SSrinivasan Raju 	struct usb_device *udev = interface_to_usbdev(usb->ez_usb);
496*2ed15a3aSDan Carpenter 	struct urb *urb;
49768d57a07SSrinivasan Raju 	int r;
49868d57a07SSrinivasan Raju 
499*2ed15a3aSDan Carpenter 	urb = usb_alloc_urb(0, GFP_ATOMIC);
500*2ed15a3aSDan Carpenter 	if (!urb)
501*2ed15a3aSDan Carpenter 		return -ENOMEM;
50268d57a07SSrinivasan Raju 	usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
50368d57a07SSrinivasan Raju 			  (void *)buffer, buffer_len, complete_fn, context);
50468d57a07SSrinivasan Raju 
50568d57a07SSrinivasan Raju 	r = usb_submit_urb(urb, GFP_ATOMIC);
50668d57a07SSrinivasan Raju 	if (r)
50768d57a07SSrinivasan Raju 		dev_err(&udev->dev, "Async write submit failed (%d)\n", r);
50868d57a07SSrinivasan Raju 
50968d57a07SSrinivasan Raju 	return r;
51068d57a07SSrinivasan Raju }
51168d57a07SSrinivasan Raju 
plfxlc_usb_wreq(struct usb_interface * ez_usb,void * buffer,int buffer_len,enum plf_usb_req_enum usb_req_id)51268d57a07SSrinivasan Raju int plfxlc_usb_wreq(struct usb_interface *ez_usb, void *buffer, int buffer_len,
51368d57a07SSrinivasan Raju 		    enum plf_usb_req_enum usb_req_id)
51468d57a07SSrinivasan Raju {
51568d57a07SSrinivasan Raju 	struct usb_device *udev = interface_to_usbdev(ez_usb);
51668d57a07SSrinivasan Raju 	unsigned char *dma_buffer = NULL;
51768d57a07SSrinivasan Raju 	struct plf_usb_req usb_req;
51868d57a07SSrinivasan Raju 	int usb_bulk_msg_len;
51968d57a07SSrinivasan Raju 	int actual_length;
52068d57a07SSrinivasan Raju 	int r;
52168d57a07SSrinivasan Raju 
52268d57a07SSrinivasan Raju 	get_usb_req(udev, buffer, buffer_len, usb_req_id, &usb_req);
52368d57a07SSrinivasan Raju 	usb_bulk_msg_len = sizeof(__le32) + sizeof(__le32) +
52468d57a07SSrinivasan Raju 			   be32_to_cpu(usb_req.len);
52568d57a07SSrinivasan Raju 
52668d57a07SSrinivasan Raju 	dma_buffer = kmemdup(&usb_req, usb_bulk_msg_len, GFP_KERNEL);
52768d57a07SSrinivasan Raju 
52868d57a07SSrinivasan Raju 	if (!dma_buffer) {
52968d57a07SSrinivasan Raju 		r = -ENOMEM;
53068d57a07SSrinivasan Raju 		goto error;
53168d57a07SSrinivasan Raju 	}
53268d57a07SSrinivasan Raju 
53368d57a07SSrinivasan Raju 	r = usb_bulk_msg(udev,
53468d57a07SSrinivasan Raju 			 usb_sndbulkpipe(udev, EP_DATA_OUT),
53568d57a07SSrinivasan Raju 			 dma_buffer, usb_bulk_msg_len,
53668d57a07SSrinivasan Raju 			 &actual_length, USB_BULK_MSG_TIMEOUT_MS);
53768d57a07SSrinivasan Raju 	kfree(dma_buffer);
53868d57a07SSrinivasan Raju error:
53968d57a07SSrinivasan Raju 	if (r) {
54068d57a07SSrinivasan Raju 		r = -ENOMEM;
54168d57a07SSrinivasan Raju 		dev_err(&udev->dev, "usb_bulk_msg failed (%d)\n", r);
54268d57a07SSrinivasan Raju 	}
54368d57a07SSrinivasan Raju 
54468d57a07SSrinivasan Raju 	return r;
54568d57a07SSrinivasan Raju }
54668d57a07SSrinivasan Raju 
slif_data_plane_sap_timer_callb(struct timer_list * t)54768d57a07SSrinivasan Raju static void slif_data_plane_sap_timer_callb(struct timer_list *t)
54868d57a07SSrinivasan Raju {
54968d57a07SSrinivasan Raju 	struct plfxlc_usb *usb = from_timer(usb, t, tx.tx_retry_timer);
55068d57a07SSrinivasan Raju 
55168d57a07SSrinivasan Raju 	plfxlc_send_packet_from_data_queue(usb);
55268d57a07SSrinivasan Raju 	timer_setup(&usb->tx.tx_retry_timer,
55368d57a07SSrinivasan Raju 		    slif_data_plane_sap_timer_callb, 0);
55468d57a07SSrinivasan Raju 	mod_timer(&usb->tx.tx_retry_timer, jiffies + TX_RETRY_BACKOFF_JIFF);
55568d57a07SSrinivasan Raju }
55668d57a07SSrinivasan Raju 
sta_queue_cleanup_timer_callb(struct timer_list * t)55768d57a07SSrinivasan Raju static void sta_queue_cleanup_timer_callb(struct timer_list *t)
55868d57a07SSrinivasan Raju {
55968d57a07SSrinivasan Raju 	struct plfxlc_usb *usb = from_timer(usb, t, sta_queue_cleanup);
56068d57a07SSrinivasan Raju 	struct plfxlc_usb_tx *tx = &usb->tx;
56168d57a07SSrinivasan Raju 	int sidx;
56268d57a07SSrinivasan Raju 
56368d57a07SSrinivasan Raju 	for (sidx = 0; sidx < MAX_STA_NUM - 1; sidx++) {
56468d57a07SSrinivasan Raju 		if (!(tx->station[sidx].flag & STATION_CONNECTED_FLAG))
56568d57a07SSrinivasan Raju 			continue;
56668d57a07SSrinivasan Raju 		if (tx->station[sidx].flag & STATION_HEARTBEAT_FLAG) {
56768d57a07SSrinivasan Raju 			tx->station[sidx].flag ^= STATION_HEARTBEAT_FLAG;
56868d57a07SSrinivasan Raju 		} else {
56970c898d4SXu Qiang 			eth_zero_addr(tx->station[sidx].mac);
57068d57a07SSrinivasan Raju 			tx->station[sidx].flag = 0;
57168d57a07SSrinivasan Raju 		}
57268d57a07SSrinivasan Raju 	}
57368d57a07SSrinivasan Raju 	timer_setup(&usb->sta_queue_cleanup,
57468d57a07SSrinivasan Raju 		    sta_queue_cleanup_timer_callb, 0);
57568d57a07SSrinivasan Raju 	mod_timer(&usb->sta_queue_cleanup, jiffies + STA_QUEUE_CLEANUP_JIFF);
57668d57a07SSrinivasan Raju }
57768d57a07SSrinivasan Raju 
probe(struct usb_interface * intf,const struct usb_device_id * id)57868d57a07SSrinivasan Raju static int probe(struct usb_interface *intf,
57968d57a07SSrinivasan Raju 		 const struct usb_device_id *id)
58068d57a07SSrinivasan Raju {
58168d57a07SSrinivasan Raju 	u8 serial_number[PURELIFI_SERIAL_LEN];
58268d57a07SSrinivasan Raju 	struct ieee80211_hw *hw = NULL;
58368d57a07SSrinivasan Raju 	struct plfxlc_usb_tx *tx;
58468d57a07SSrinivasan Raju 	struct plfxlc_chip *chip;
58568d57a07SSrinivasan Raju 	struct plfxlc_usb *usb;
58668d57a07SSrinivasan Raju 	u8 hw_address[ETH_ALEN];
58768d57a07SSrinivasan Raju 	unsigned int i;
58868d57a07SSrinivasan Raju 	int r = 0;
58968d57a07SSrinivasan Raju 
59068d57a07SSrinivasan Raju 	hw = plfxlc_mac_alloc_hw(intf);
59168d57a07SSrinivasan Raju 
59268d57a07SSrinivasan Raju 	if (!hw) {
59368d57a07SSrinivasan Raju 		r = -ENOMEM;
59468d57a07SSrinivasan Raju 		goto error;
59568d57a07SSrinivasan Raju 	}
59668d57a07SSrinivasan Raju 
59768d57a07SSrinivasan Raju 	chip = &plfxlc_hw_mac(hw)->chip;
59868d57a07SSrinivasan Raju 	usb = &chip->usb;
59968d57a07SSrinivasan Raju 	usb->ez_usb = intf;
60068d57a07SSrinivasan Raju 	tx = &usb->tx;
60168d57a07SSrinivasan Raju 
60268d57a07SSrinivasan Raju 	r = plfxlc_upload_mac_and_serial(intf, hw_address, serial_number);
60368d57a07SSrinivasan Raju 	if (r) {
60468d57a07SSrinivasan Raju 		dev_err(&intf->dev, "MAC and Serial upload failed (%d)\n", r);
60568d57a07SSrinivasan Raju 		goto error;
60668d57a07SSrinivasan Raju 	}
60768d57a07SSrinivasan Raju 
60868d57a07SSrinivasan Raju 	chip->unit_type = STA;
60968d57a07SSrinivasan Raju 	dev_err(&intf->dev, "Unit type is station");
61068d57a07SSrinivasan Raju 
61168d57a07SSrinivasan Raju 	r = plfxlc_mac_preinit_hw(hw, hw_address);
61268d57a07SSrinivasan Raju 	if (r) {
61368d57a07SSrinivasan Raju 		dev_err(&intf->dev, "Init mac failed (%d)\n", r);
61468d57a07SSrinivasan Raju 		goto error;
61568d57a07SSrinivasan Raju 	}
61668d57a07SSrinivasan Raju 
61768d57a07SSrinivasan Raju 	r = ieee80211_register_hw(hw);
61868d57a07SSrinivasan Raju 	if (r) {
61968d57a07SSrinivasan Raju 		dev_err(&intf->dev, "Register device failed (%d)\n", r);
62068d57a07SSrinivasan Raju 		goto error;
62168d57a07SSrinivasan Raju 	}
62268d57a07SSrinivasan Raju 
62368d57a07SSrinivasan Raju 	if ((le16_to_cpu(interface_to_usbdev(intf)->descriptor.idVendor) ==
62468d57a07SSrinivasan Raju 				PURELIFI_XL_VENDOR_ID_0) &&
62568d57a07SSrinivasan Raju 	    (le16_to_cpu(interface_to_usbdev(intf)->descriptor.idProduct) ==
62668d57a07SSrinivasan Raju 				PURELIFI_XL_PRODUCT_ID_0)) {
62768d57a07SSrinivasan Raju 		r = plfxlc_download_xl_firmware(intf);
62868d57a07SSrinivasan Raju 	} else {
62968d57a07SSrinivasan Raju 		r = plfxlc_download_fpga(intf);
63068d57a07SSrinivasan Raju 	}
63168d57a07SSrinivasan Raju 	if (r != 0) {
63268d57a07SSrinivasan Raju 		dev_err(&intf->dev, "FPGA download failed (%d)\n", r);
63368d57a07SSrinivasan Raju 		goto error;
63468d57a07SSrinivasan Raju 	}
63568d57a07SSrinivasan Raju 
63668d57a07SSrinivasan Raju 	tx->mac_fifo_full = 0;
63768d57a07SSrinivasan Raju 	spin_lock_init(&tx->lock);
63868d57a07SSrinivasan Raju 
63968d57a07SSrinivasan Raju 	msleep(PLF_MSLEEP_TIME);
64068d57a07SSrinivasan Raju 	r = plfxlc_usb_init_hw(usb);
64168d57a07SSrinivasan Raju 	if (r < 0) {
64268d57a07SSrinivasan Raju 		dev_err(&intf->dev, "usb_init_hw failed (%d)\n", r);
64368d57a07SSrinivasan Raju 		goto error;
64468d57a07SSrinivasan Raju 	}
64568d57a07SSrinivasan Raju 
64668d57a07SSrinivasan Raju 	msleep(PLF_MSLEEP_TIME);
64768d57a07SSrinivasan Raju 	r = plfxlc_chip_switch_radio(chip, PLFXLC_RADIO_ON);
64868d57a07SSrinivasan Raju 	if (r < 0) {
64968d57a07SSrinivasan Raju 		dev_dbg(&intf->dev, "chip_switch_radio_on failed (%d)\n", r);
65068d57a07SSrinivasan Raju 		goto error;
65168d57a07SSrinivasan Raju 	}
65268d57a07SSrinivasan Raju 
65368d57a07SSrinivasan Raju 	msleep(PLF_MSLEEP_TIME);
65468d57a07SSrinivasan Raju 	r = plfxlc_chip_set_rate(chip, 8);
65568d57a07SSrinivasan Raju 	if (r < 0) {
65668d57a07SSrinivasan Raju 		dev_dbg(&intf->dev, "chip_set_rate failed (%d)\n", r);
65768d57a07SSrinivasan Raju 		goto error;
65868d57a07SSrinivasan Raju 	}
65968d57a07SSrinivasan Raju 
66068d57a07SSrinivasan Raju 	msleep(PLF_MSLEEP_TIME);
66168d57a07SSrinivasan Raju 	r = plfxlc_usb_wreq(usb->ez_usb,
66268d57a07SSrinivasan Raju 			    hw_address, ETH_ALEN, USB_REQ_MAC_WR);
66368d57a07SSrinivasan Raju 	if (r < 0) {
66468d57a07SSrinivasan Raju 		dev_dbg(&intf->dev, "MAC_WR failure (%d)\n", r);
66568d57a07SSrinivasan Raju 		goto error;
66668d57a07SSrinivasan Raju 	}
66768d57a07SSrinivasan Raju 
66868d57a07SSrinivasan Raju 	plfxlc_chip_enable_rxtx(chip);
66968d57a07SSrinivasan Raju 
67068d57a07SSrinivasan Raju 	/* Initialise the data plane Tx queue */
67168d57a07SSrinivasan Raju 	for (i = 0; i < MAX_STA_NUM; i++) {
67268d57a07SSrinivasan Raju 		skb_queue_head_init(&tx->station[i].data_list);
67368d57a07SSrinivasan Raju 		tx->station[i].flag = 0;
67468d57a07SSrinivasan Raju 	}
67568d57a07SSrinivasan Raju 
67668d57a07SSrinivasan Raju 	tx->station[STA_BROADCAST_INDEX].flag |= STATION_CONNECTED_FLAG;
67768d57a07SSrinivasan Raju 	for (i = 0; i < ETH_ALEN; i++)
67868d57a07SSrinivasan Raju 		tx->station[STA_BROADCAST_INDEX].mac[i] = 0xFF;
67968d57a07SSrinivasan Raju 
68068d57a07SSrinivasan Raju 	timer_setup(&tx->tx_retry_timer, slif_data_plane_sap_timer_callb, 0);
68168d57a07SSrinivasan Raju 	tx->tx_retry_timer.expires = jiffies + TX_RETRY_BACKOFF_JIFF;
68268d57a07SSrinivasan Raju 	add_timer(&tx->tx_retry_timer);
68368d57a07SSrinivasan Raju 
68468d57a07SSrinivasan Raju 	timer_setup(&usb->sta_queue_cleanup,
68568d57a07SSrinivasan Raju 		    sta_queue_cleanup_timer_callb, 0);
68668d57a07SSrinivasan Raju 	usb->sta_queue_cleanup.expires = jiffies + STA_QUEUE_CLEANUP_JIFF;
68768d57a07SSrinivasan Raju 	add_timer(&usb->sta_queue_cleanup);
68868d57a07SSrinivasan Raju 
68968d57a07SSrinivasan Raju 	plfxlc_mac_init_hw(hw);
69068d57a07SSrinivasan Raju 	usb->initialized = true;
69168d57a07SSrinivasan Raju 	return 0;
69268d57a07SSrinivasan Raju error:
69368d57a07SSrinivasan Raju 	if (hw) {
69468d57a07SSrinivasan Raju 		plfxlc_mac_release(plfxlc_hw_mac(hw));
69568d57a07SSrinivasan Raju 		ieee80211_unregister_hw(hw);
69668d57a07SSrinivasan Raju 		ieee80211_free_hw(hw);
69768d57a07SSrinivasan Raju 	}
69868d57a07SSrinivasan Raju 	dev_err(&intf->dev, "pureLifi:Device error");
69968d57a07SSrinivasan Raju 	return r;
70068d57a07SSrinivasan Raju }
70168d57a07SSrinivasan Raju 
disconnect(struct usb_interface * intf)70268d57a07SSrinivasan Raju static void disconnect(struct usb_interface *intf)
70368d57a07SSrinivasan Raju {
70468d57a07SSrinivasan Raju 	struct ieee80211_hw *hw = plfxlc_intf_to_hw(intf);
70568d57a07SSrinivasan Raju 	struct plfxlc_mac *mac;
70668d57a07SSrinivasan Raju 	struct plfxlc_usb *usb;
70768d57a07SSrinivasan Raju 
70868d57a07SSrinivasan Raju 	/* Either something really bad happened, or
70968d57a07SSrinivasan Raju 	 * we're just dealing with a DEVICE_INSTALLER.
71068d57a07SSrinivasan Raju 	 */
71168d57a07SSrinivasan Raju 	if (!hw)
71268d57a07SSrinivasan Raju 		return;
71368d57a07SSrinivasan Raju 
71468d57a07SSrinivasan Raju 	mac = plfxlc_hw_mac(hw);
71568d57a07SSrinivasan Raju 	usb = &mac->chip.usb;
71668d57a07SSrinivasan Raju 
71768d57a07SSrinivasan Raju 	del_timer_sync(&usb->tx.tx_retry_timer);
71868d57a07SSrinivasan Raju 	del_timer_sync(&usb->sta_queue_cleanup);
71968d57a07SSrinivasan Raju 
72068d57a07SSrinivasan Raju 	ieee80211_unregister_hw(hw);
72168d57a07SSrinivasan Raju 
72268d57a07SSrinivasan Raju 	plfxlc_chip_disable_rxtx(&mac->chip);
72368d57a07SSrinivasan Raju 
72468d57a07SSrinivasan Raju 	/* If the disconnect has been caused by a removal of the
72568d57a07SSrinivasan Raju 	 * driver module, the reset allows reloading of the driver. If the
72668d57a07SSrinivasan Raju 	 * reset will not be executed here, the upload of the firmware in the
72768d57a07SSrinivasan Raju 	 * probe function caused by the reloading of the driver will fail.
72868d57a07SSrinivasan Raju 	 */
72968d57a07SSrinivasan Raju 	usb_reset_device(interface_to_usbdev(intf));
73068d57a07SSrinivasan Raju 
73168d57a07SSrinivasan Raju 	plfxlc_mac_release(mac);
73268d57a07SSrinivasan Raju 	ieee80211_free_hw(hw);
73368d57a07SSrinivasan Raju }
73468d57a07SSrinivasan Raju 
plfxlc_usb_resume(struct plfxlc_usb * usb)73568d57a07SSrinivasan Raju static void plfxlc_usb_resume(struct plfxlc_usb *usb)
73668d57a07SSrinivasan Raju {
73768d57a07SSrinivasan Raju 	struct plfxlc_mac *mac = plfxlc_usb_to_mac(usb);
73868d57a07SSrinivasan Raju 	int r;
73968d57a07SSrinivasan Raju 
74068d57a07SSrinivasan Raju 	r = plfxlc_op_start(plfxlc_usb_to_hw(usb));
74168d57a07SSrinivasan Raju 	if (r < 0) {
74268d57a07SSrinivasan Raju 		dev_warn(plfxlc_usb_dev(usb),
74368d57a07SSrinivasan Raju 			 "Device resume failed (%d)\n", r);
74468d57a07SSrinivasan Raju 
74568d57a07SSrinivasan Raju 		if (usb->was_running)
74668d57a07SSrinivasan Raju 			set_bit(PURELIFI_DEVICE_RUNNING, &mac->flags);
74768d57a07SSrinivasan Raju 
74868d57a07SSrinivasan Raju 		usb_queue_reset_device(usb->intf);
74968d57a07SSrinivasan Raju 		return;
75068d57a07SSrinivasan Raju 	}
75168d57a07SSrinivasan Raju 
75268d57a07SSrinivasan Raju 	if (mac->type != NL80211_IFTYPE_UNSPECIFIED) {
75368d57a07SSrinivasan Raju 		r = plfxlc_restore_settings(mac);
75468d57a07SSrinivasan Raju 		if (r < 0) {
75568d57a07SSrinivasan Raju 			dev_dbg(plfxlc_usb_dev(usb),
75668d57a07SSrinivasan Raju 				"Restore failed (%d)\n", r);
75768d57a07SSrinivasan Raju 			return;
75868d57a07SSrinivasan Raju 		}
75968d57a07SSrinivasan Raju 	}
76068d57a07SSrinivasan Raju }
76168d57a07SSrinivasan Raju 
plfxlc_usb_stop(struct plfxlc_usb * usb)76268d57a07SSrinivasan Raju static void plfxlc_usb_stop(struct plfxlc_usb *usb)
76368d57a07SSrinivasan Raju {
76468d57a07SSrinivasan Raju 	plfxlc_op_stop(plfxlc_usb_to_hw(usb));
76568d57a07SSrinivasan Raju 	plfxlc_usb_disable_tx(usb);
76668d57a07SSrinivasan Raju 	plfxlc_usb_disable_rx(usb);
76768d57a07SSrinivasan Raju 
76868d57a07SSrinivasan Raju 	usb->initialized = false;
76968d57a07SSrinivasan Raju }
77068d57a07SSrinivasan Raju 
pre_reset(struct usb_interface * intf)77168d57a07SSrinivasan Raju static int pre_reset(struct usb_interface *intf)
77268d57a07SSrinivasan Raju {
77368d57a07SSrinivasan Raju 	struct ieee80211_hw *hw = usb_get_intfdata(intf);
77468d57a07SSrinivasan Raju 	struct plfxlc_mac *mac;
77568d57a07SSrinivasan Raju 	struct plfxlc_usb *usb;
77668d57a07SSrinivasan Raju 
77768d57a07SSrinivasan Raju 	if (!hw || intf->condition != USB_INTERFACE_BOUND)
77868d57a07SSrinivasan Raju 		return 0;
77968d57a07SSrinivasan Raju 
78068d57a07SSrinivasan Raju 	mac = plfxlc_hw_mac(hw);
78168d57a07SSrinivasan Raju 	usb = &mac->chip.usb;
78268d57a07SSrinivasan Raju 
78368d57a07SSrinivasan Raju 	usb->was_running = test_bit(PURELIFI_DEVICE_RUNNING, &mac->flags);
78468d57a07SSrinivasan Raju 
78568d57a07SSrinivasan Raju 	plfxlc_usb_stop(usb);
78668d57a07SSrinivasan Raju 
78768d57a07SSrinivasan Raju 	return 0;
78868d57a07SSrinivasan Raju }
78968d57a07SSrinivasan Raju 
post_reset(struct usb_interface * intf)79068d57a07SSrinivasan Raju static int post_reset(struct usb_interface *intf)
79168d57a07SSrinivasan Raju {
79268d57a07SSrinivasan Raju 	struct ieee80211_hw *hw = usb_get_intfdata(intf);
79368d57a07SSrinivasan Raju 	struct plfxlc_mac *mac;
79468d57a07SSrinivasan Raju 	struct plfxlc_usb *usb;
79568d57a07SSrinivasan Raju 
79668d57a07SSrinivasan Raju 	if (!hw || intf->condition != USB_INTERFACE_BOUND)
79768d57a07SSrinivasan Raju 		return 0;
79868d57a07SSrinivasan Raju 
79968d57a07SSrinivasan Raju 	mac = plfxlc_hw_mac(hw);
80068d57a07SSrinivasan Raju 	usb = &mac->chip.usb;
80168d57a07SSrinivasan Raju 
80268d57a07SSrinivasan Raju 	if (usb->was_running)
80368d57a07SSrinivasan Raju 		plfxlc_usb_resume(usb);
80468d57a07SSrinivasan Raju 
80568d57a07SSrinivasan Raju 	return 0;
80668d57a07SSrinivasan Raju }
80768d57a07SSrinivasan Raju 
80868d57a07SSrinivasan Raju #ifdef CONFIG_PM
80968d57a07SSrinivasan Raju 
get_plfxlc_usb(struct usb_interface * intf)81068d57a07SSrinivasan Raju static struct plfxlc_usb *get_plfxlc_usb(struct usb_interface *intf)
81168d57a07SSrinivasan Raju {
81268d57a07SSrinivasan Raju 	struct ieee80211_hw *hw = plfxlc_intf_to_hw(intf);
81368d57a07SSrinivasan Raju 	struct plfxlc_mac *mac;
81468d57a07SSrinivasan Raju 
81568d57a07SSrinivasan Raju 	/* Either something really bad happened, or
81668d57a07SSrinivasan Raju 	 * we're just dealing with a DEVICE_INSTALLER.
81768d57a07SSrinivasan Raju 	 */
81868d57a07SSrinivasan Raju 	if (!hw)
81968d57a07SSrinivasan Raju 		return NULL;
82068d57a07SSrinivasan Raju 
82168d57a07SSrinivasan Raju 	mac = plfxlc_hw_mac(hw);
82268d57a07SSrinivasan Raju 	return &mac->chip.usb;
82368d57a07SSrinivasan Raju }
82468d57a07SSrinivasan Raju 
suspend(struct usb_interface * interface,pm_message_t message)82568d57a07SSrinivasan Raju static int suspend(struct usb_interface *interface,
82668d57a07SSrinivasan Raju 		   pm_message_t message)
82768d57a07SSrinivasan Raju {
82868d57a07SSrinivasan Raju 	struct plfxlc_usb *pl = get_plfxlc_usb(interface);
82968d57a07SSrinivasan Raju 	struct plfxlc_mac *mac = plfxlc_usb_to_mac(pl);
83068d57a07SSrinivasan Raju 
8310c7ab953SJakub Kicinski 	if (!pl)
83268d57a07SSrinivasan Raju 		return -ENODEV;
83368d57a07SSrinivasan Raju 	if (pl->initialized == 0)
83468d57a07SSrinivasan Raju 		return 0;
83568d57a07SSrinivasan Raju 	pl->was_running = test_bit(PURELIFI_DEVICE_RUNNING, &mac->flags);
83668d57a07SSrinivasan Raju 	plfxlc_usb_stop(pl);
83768d57a07SSrinivasan Raju 	return 0;
83868d57a07SSrinivasan Raju }
83968d57a07SSrinivasan Raju 
resume(struct usb_interface * interface)84068d57a07SSrinivasan Raju static int resume(struct usb_interface *interface)
84168d57a07SSrinivasan Raju {
84268d57a07SSrinivasan Raju 	struct plfxlc_usb *pl = get_plfxlc_usb(interface);
84368d57a07SSrinivasan Raju 
8440c7ab953SJakub Kicinski 	if (!pl)
84568d57a07SSrinivasan Raju 		return -ENODEV;
84668d57a07SSrinivasan Raju 	if (pl->was_running)
84768d57a07SSrinivasan Raju 		plfxlc_usb_resume(pl);
84868d57a07SSrinivasan Raju 	return 0;
84968d57a07SSrinivasan Raju }
85068d57a07SSrinivasan Raju 
85168d57a07SSrinivasan Raju #endif
85268d57a07SSrinivasan Raju 
85368d57a07SSrinivasan Raju static struct usb_driver driver = {
85468d57a07SSrinivasan Raju 	.name = KBUILD_MODNAME,
85568d57a07SSrinivasan Raju 	.id_table = usb_ids,
85668d57a07SSrinivasan Raju 	.probe = probe,
85768d57a07SSrinivasan Raju 	.disconnect = disconnect,
85868d57a07SSrinivasan Raju 	.pre_reset = pre_reset,
85968d57a07SSrinivasan Raju 	.post_reset = post_reset,
86068d57a07SSrinivasan Raju #ifdef CONFIG_PM
86168d57a07SSrinivasan Raju 	.suspend = suspend,
86268d57a07SSrinivasan Raju 	.resume = resume,
86368d57a07SSrinivasan Raju #endif
86468d57a07SSrinivasan Raju 	.disable_hub_initiated_lpm = 1,
86568d57a07SSrinivasan Raju };
86668d57a07SSrinivasan Raju 
usb_init(void)86768d57a07SSrinivasan Raju static int __init usb_init(void)
86868d57a07SSrinivasan Raju {
86968d57a07SSrinivasan Raju 	int r;
87068d57a07SSrinivasan Raju 
87168d57a07SSrinivasan Raju 	r = usb_register(&driver);
87268d57a07SSrinivasan Raju 	if (r) {
87368d57a07SSrinivasan Raju 		pr_err("%s usb_register() failed %d\n", driver.name, r);
87468d57a07SSrinivasan Raju 		return r;
87568d57a07SSrinivasan Raju 	}
87668d57a07SSrinivasan Raju 
87768d57a07SSrinivasan Raju 	pr_debug("Driver initialized :%s\n", driver.name);
87868d57a07SSrinivasan Raju 	return 0;
87968d57a07SSrinivasan Raju }
88068d57a07SSrinivasan Raju 
usb_exit(void)88168d57a07SSrinivasan Raju static void __exit usb_exit(void)
88268d57a07SSrinivasan Raju {
88368d57a07SSrinivasan Raju 	usb_deregister(&driver);
88468d57a07SSrinivasan Raju 	pr_debug("%s %s\n", driver.name, __func__);
88568d57a07SSrinivasan Raju }
88668d57a07SSrinivasan Raju 
88768d57a07SSrinivasan Raju MODULE_LICENSE("GPL");
88868d57a07SSrinivasan Raju MODULE_DESCRIPTION("USB driver for pureLiFi devices");
88968d57a07SSrinivasan Raju MODULE_AUTHOR("pureLiFi");
89068d57a07SSrinivasan Raju MODULE_VERSION("1.0");
89168d57a07SSrinivasan Raju MODULE_FIRMWARE("plfxlc/lifi-x.bin");
89268d57a07SSrinivasan Raju MODULE_DEVICE_TABLE(usb, usb_ids);
89368d57a07SSrinivasan Raju 
89468d57a07SSrinivasan Raju module_init(usb_init);
89568d57a07SSrinivasan Raju module_exit(usb_exit);
896