cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

usb.c (11127B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Marvell NFC-over-USB driver: USB interface related functions
      4 *
      5 * Copyright (C) 2014, Marvell International Ltd.
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/usb.h>
     10#include <linux/nfc.h>
     11#include <net/nfc/nci.h>
     12#include <net/nfc/nci_core.h>
     13#include "nfcmrvl.h"
     14
     15static struct usb_device_id nfcmrvl_table[] = {
     16	{ USB_DEVICE_AND_INTERFACE_INFO(0x1286, 0x2046,
     17					USB_CLASS_VENDOR_SPEC, 4, 1) },
     18	{ }	/* Terminating entry */
     19};
     20
     21MODULE_DEVICE_TABLE(usb, nfcmrvl_table);
     22
     23#define NFCMRVL_USB_BULK_RUNNING	1
     24#define NFCMRVL_USB_SUSPENDING		2
     25
     26struct nfcmrvl_usb_drv_data {
     27	struct usb_device *udev;
     28	struct usb_interface *intf;
     29	unsigned long flags;
     30	struct work_struct waker;
     31	struct usb_anchor tx_anchor;
     32	struct usb_anchor bulk_anchor;
     33	struct usb_anchor deferred;
     34	int tx_in_flight;
     35	/* protects tx_in_flight */
     36	spinlock_t txlock;
     37	struct usb_endpoint_descriptor *bulk_tx_ep;
     38	struct usb_endpoint_descriptor *bulk_rx_ep;
     39	int suspend_count;
     40	struct nfcmrvl_private *priv;
     41};
     42
     43static int nfcmrvl_inc_tx(struct nfcmrvl_usb_drv_data *drv_data)
     44{
     45	unsigned long flags;
     46	int rv;
     47
     48	spin_lock_irqsave(&drv_data->txlock, flags);
     49	rv = test_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
     50	if (!rv)
     51		drv_data->tx_in_flight++;
     52	spin_unlock_irqrestore(&drv_data->txlock, flags);
     53
     54	return rv;
     55}
     56
     57static void nfcmrvl_bulk_complete(struct urb *urb)
     58{
     59	struct nfcmrvl_usb_drv_data *drv_data = urb->context;
     60	int err;
     61
     62	dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d\n",
     63		urb, urb->status, urb->actual_length);
     64
     65	if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
     66		return;
     67
     68	if (!urb->status) {
     69		struct sk_buff *skb;
     70
     71		skb = nci_skb_alloc(drv_data->priv->ndev, urb->actual_length,
     72				    GFP_ATOMIC);
     73		if (!skb) {
     74			nfc_err(&drv_data->udev->dev, "failed to alloc mem\n");
     75		} else {
     76			skb_put_data(skb, urb->transfer_buffer,
     77				     urb->actual_length);
     78			if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0)
     79				nfc_err(&drv_data->udev->dev,
     80					"corrupted Rx packet\n");
     81		}
     82	}
     83
     84	if (!test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags))
     85		return;
     86
     87	usb_anchor_urb(urb, &drv_data->bulk_anchor);
     88	usb_mark_last_busy(drv_data->udev);
     89
     90	err = usb_submit_urb(urb, GFP_ATOMIC);
     91	if (err) {
     92		/* -EPERM: urb is being killed;
     93		 * -ENODEV: device got disconnected
     94		 */
     95		if (err != -EPERM && err != -ENODEV)
     96			nfc_err(&drv_data->udev->dev,
     97				"urb %p failed to resubmit (%d)\n", urb, -err);
     98		usb_unanchor_urb(urb);
     99	}
    100}
    101
    102static int
    103nfcmrvl_submit_bulk_urb(struct nfcmrvl_usb_drv_data *drv_data, gfp_t mem_flags)
    104{
    105	struct urb *urb;
    106	unsigned char *buf;
    107	unsigned int pipe;
    108	int err, size = NFCMRVL_NCI_MAX_EVENT_SIZE;
    109
    110	if (!drv_data->bulk_rx_ep)
    111		return -ENODEV;
    112
    113	urb = usb_alloc_urb(0, mem_flags);
    114	if (!urb)
    115		return -ENOMEM;
    116
    117	buf = kmalloc(size, mem_flags);
    118	if (!buf) {
    119		usb_free_urb(urb);
    120		return -ENOMEM;
    121	}
    122
    123	pipe = usb_rcvbulkpipe(drv_data->udev,
    124			       drv_data->bulk_rx_ep->bEndpointAddress);
    125
    126	usb_fill_bulk_urb(urb, drv_data->udev, pipe, buf, size,
    127			  nfcmrvl_bulk_complete, drv_data);
    128
    129	urb->transfer_flags |= URB_FREE_BUFFER;
    130
    131	usb_mark_last_busy(drv_data->udev);
    132	usb_anchor_urb(urb, &drv_data->bulk_anchor);
    133
    134	err = usb_submit_urb(urb, mem_flags);
    135	if (err) {
    136		if (err != -EPERM && err != -ENODEV)
    137			nfc_err(&drv_data->udev->dev,
    138				"urb %p submission failed (%d)\n", urb, -err);
    139		usb_unanchor_urb(urb);
    140	}
    141
    142	usb_free_urb(urb);
    143
    144	return err;
    145}
    146
    147static void nfcmrvl_tx_complete(struct urb *urb)
    148{
    149	struct sk_buff *skb = urb->context;
    150	struct nci_dev *ndev = (struct nci_dev *)skb->dev;
    151	struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
    152	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
    153	unsigned long flags;
    154
    155	nfc_info(priv->dev, "urb %p status %d count %d\n",
    156		 urb, urb->status, urb->actual_length);
    157
    158	spin_lock_irqsave(&drv_data->txlock, flags);
    159	drv_data->tx_in_flight--;
    160	spin_unlock_irqrestore(&drv_data->txlock, flags);
    161
    162	kfree(urb->setup_packet);
    163	kfree_skb(skb);
    164}
    165
    166static int nfcmrvl_usb_nci_open(struct nfcmrvl_private *priv)
    167{
    168	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
    169	int err;
    170
    171	err = usb_autopm_get_interface(drv_data->intf);
    172	if (err)
    173		return err;
    174
    175	drv_data->intf->needs_remote_wakeup = 1;
    176
    177	err = nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
    178	if (err)
    179		goto failed;
    180
    181	set_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
    182	nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
    183
    184	usb_autopm_put_interface(drv_data->intf);
    185	return 0;
    186
    187failed:
    188	usb_autopm_put_interface(drv_data->intf);
    189	return err;
    190}
    191
    192static void nfcmrvl_usb_stop_traffic(struct nfcmrvl_usb_drv_data *drv_data)
    193{
    194	usb_kill_anchored_urbs(&drv_data->bulk_anchor);
    195}
    196
    197static int nfcmrvl_usb_nci_close(struct nfcmrvl_private *priv)
    198{
    199	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
    200	int err;
    201
    202	cancel_work_sync(&drv_data->waker);
    203
    204	clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
    205
    206	nfcmrvl_usb_stop_traffic(drv_data);
    207	usb_kill_anchored_urbs(&drv_data->tx_anchor);
    208	err = usb_autopm_get_interface(drv_data->intf);
    209	if (err)
    210		goto failed;
    211
    212	drv_data->intf->needs_remote_wakeup = 0;
    213	usb_autopm_put_interface(drv_data->intf);
    214
    215failed:
    216	usb_scuttle_anchored_urbs(&drv_data->deferred);
    217	return 0;
    218}
    219
    220static int nfcmrvl_usb_nci_send(struct nfcmrvl_private *priv,
    221				struct sk_buff *skb)
    222{
    223	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
    224	struct urb *urb;
    225	unsigned int pipe;
    226	int err;
    227
    228	if (!drv_data->bulk_tx_ep)
    229		return -ENODEV;
    230
    231	urb = usb_alloc_urb(0, GFP_ATOMIC);
    232	if (!urb)
    233		return -ENOMEM;
    234
    235	pipe = usb_sndbulkpipe(drv_data->udev,
    236				drv_data->bulk_tx_ep->bEndpointAddress);
    237
    238	usb_fill_bulk_urb(urb, drv_data->udev, pipe, skb->data, skb->len,
    239			  nfcmrvl_tx_complete, skb);
    240
    241	err = nfcmrvl_inc_tx(drv_data);
    242	if (err) {
    243		usb_anchor_urb(urb, &drv_data->deferred);
    244		schedule_work(&drv_data->waker);
    245		err = 0;
    246		goto done;
    247	}
    248
    249	usb_anchor_urb(urb, &drv_data->tx_anchor);
    250
    251	err = usb_submit_urb(urb, GFP_ATOMIC);
    252	if (err) {
    253		if (err != -EPERM && err != -ENODEV)
    254			nfc_err(&drv_data->udev->dev,
    255				"urb %p submission failed (%d)\n", urb, -err);
    256		kfree(urb->setup_packet);
    257		usb_unanchor_urb(urb);
    258	} else {
    259		usb_mark_last_busy(drv_data->udev);
    260	}
    261
    262done:
    263	usb_free_urb(urb);
    264	return err;
    265}
    266
    267static const struct nfcmrvl_if_ops usb_ops = {
    268	.nci_open = nfcmrvl_usb_nci_open,
    269	.nci_close = nfcmrvl_usb_nci_close,
    270	.nci_send = nfcmrvl_usb_nci_send,
    271};
    272
    273static void nfcmrvl_waker(struct work_struct *work)
    274{
    275	struct nfcmrvl_usb_drv_data *drv_data =
    276			container_of(work, struct nfcmrvl_usb_drv_data, waker);
    277	int err;
    278
    279	err = usb_autopm_get_interface(drv_data->intf);
    280	if (err)
    281		return;
    282
    283	usb_autopm_put_interface(drv_data->intf);
    284}
    285
    286static int nfcmrvl_probe(struct usb_interface *intf,
    287			 const struct usb_device_id *id)
    288{
    289	struct nfcmrvl_usb_drv_data *drv_data;
    290	struct nfcmrvl_private *priv;
    291	int i;
    292	struct usb_device *udev = interface_to_usbdev(intf);
    293	struct nfcmrvl_platform_data config;
    294
    295	/* No configuration for USB */
    296	memset(&config, 0, sizeof(config));
    297	config.reset_n_io = -EINVAL;
    298
    299	nfc_info(&udev->dev, "intf %p id %p\n", intf, id);
    300
    301	drv_data = devm_kzalloc(&intf->dev, sizeof(*drv_data), GFP_KERNEL);
    302	if (!drv_data)
    303		return -ENOMEM;
    304
    305	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
    306		struct usb_endpoint_descriptor *ep_desc;
    307
    308		ep_desc = &intf->cur_altsetting->endpoint[i].desc;
    309
    310		if (!drv_data->bulk_tx_ep &&
    311		    usb_endpoint_is_bulk_out(ep_desc)) {
    312			drv_data->bulk_tx_ep = ep_desc;
    313		} else if (!drv_data->bulk_rx_ep &&
    314			   usb_endpoint_is_bulk_in(ep_desc)) {
    315			drv_data->bulk_rx_ep = ep_desc;
    316		}
    317	}
    318
    319	if (!drv_data->bulk_tx_ep || !drv_data->bulk_rx_ep)
    320		return -ENODEV;
    321
    322	drv_data->udev = udev;
    323	drv_data->intf = intf;
    324
    325	INIT_WORK(&drv_data->waker, nfcmrvl_waker);
    326	spin_lock_init(&drv_data->txlock);
    327
    328	init_usb_anchor(&drv_data->tx_anchor);
    329	init_usb_anchor(&drv_data->bulk_anchor);
    330	init_usb_anchor(&drv_data->deferred);
    331
    332	priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_USB, drv_data, &usb_ops,
    333					&intf->dev, &config);
    334	if (IS_ERR(priv))
    335		return PTR_ERR(priv);
    336
    337	drv_data->priv = priv;
    338	drv_data->priv->support_fw_dnld = false;
    339
    340	usb_set_intfdata(intf, drv_data);
    341
    342	return 0;
    343}
    344
    345static void nfcmrvl_disconnect(struct usb_interface *intf)
    346{
    347	struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
    348
    349	if (!drv_data)
    350		return;
    351
    352	nfc_info(&drv_data->udev->dev, "intf %p\n", intf);
    353
    354	nfcmrvl_nci_unregister_dev(drv_data->priv);
    355
    356	usb_set_intfdata(drv_data->intf, NULL);
    357}
    358
    359#ifdef CONFIG_PM
    360static int nfcmrvl_suspend(struct usb_interface *intf, pm_message_t message)
    361{
    362	struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
    363
    364	nfc_info(&drv_data->udev->dev, "intf %p\n", intf);
    365
    366	if (drv_data->suspend_count++)
    367		return 0;
    368
    369	spin_lock_irq(&drv_data->txlock);
    370	if (!(PMSG_IS_AUTO(message) && drv_data->tx_in_flight)) {
    371		set_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
    372		spin_unlock_irq(&drv_data->txlock);
    373	} else {
    374		spin_unlock_irq(&drv_data->txlock);
    375		drv_data->suspend_count--;
    376		return -EBUSY;
    377	}
    378
    379	nfcmrvl_usb_stop_traffic(drv_data);
    380	usb_kill_anchored_urbs(&drv_data->tx_anchor);
    381
    382	return 0;
    383}
    384
    385static void nfcmrvl_play_deferred(struct nfcmrvl_usb_drv_data *drv_data)
    386{
    387	struct urb *urb;
    388	int err;
    389
    390	while ((urb = usb_get_from_anchor(&drv_data->deferred))) {
    391		usb_anchor_urb(urb, &drv_data->tx_anchor);
    392
    393		err = usb_submit_urb(urb, GFP_ATOMIC);
    394		if (err) {
    395			kfree(urb->setup_packet);
    396			usb_unanchor_urb(urb);
    397			usb_free_urb(urb);
    398			break;
    399		}
    400
    401		drv_data->tx_in_flight++;
    402		usb_free_urb(urb);
    403	}
    404
    405	/* Cleanup the rest deferred urbs. */
    406	while ((urb = usb_get_from_anchor(&drv_data->deferred))) {
    407		kfree(urb->setup_packet);
    408		usb_free_urb(urb);
    409	}
    410}
    411
    412static int nfcmrvl_resume(struct usb_interface *intf)
    413{
    414	struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
    415	int err = 0;
    416
    417	nfc_info(&drv_data->udev->dev, "intf %p\n", intf);
    418
    419	if (--drv_data->suspend_count)
    420		return 0;
    421
    422	if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
    423		goto done;
    424
    425	if (test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags)) {
    426		err = nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
    427		if (err) {
    428			clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
    429			goto failed;
    430		}
    431
    432		nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
    433	}
    434
    435	spin_lock_irq(&drv_data->txlock);
    436	nfcmrvl_play_deferred(drv_data);
    437	clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
    438	spin_unlock_irq(&drv_data->txlock);
    439
    440	return 0;
    441
    442failed:
    443	usb_scuttle_anchored_urbs(&drv_data->deferred);
    444done:
    445	spin_lock_irq(&drv_data->txlock);
    446	clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
    447	spin_unlock_irq(&drv_data->txlock);
    448
    449	return err;
    450}
    451#endif
    452
    453static struct usb_driver nfcmrvl_usb_driver = {
    454	.name		= "nfcmrvl",
    455	.probe		= nfcmrvl_probe,
    456	.disconnect	= nfcmrvl_disconnect,
    457#ifdef CONFIG_PM
    458	.suspend	= nfcmrvl_suspend,
    459	.resume		= nfcmrvl_resume,
    460	.reset_resume	= nfcmrvl_resume,
    461#endif
    462	.id_table	= nfcmrvl_table,
    463	.supports_autosuspend = 1,
    464	.disable_hub_initiated_lpm = 1,
    465	.soft_unbind = 1,
    466};
    467module_usb_driver(nfcmrvl_usb_driver);
    468
    469MODULE_AUTHOR("Marvell International Ltd.");
    470MODULE_DESCRIPTION("Marvell NFC-over-USB driver");
    471MODULE_LICENSE("GPL v2");