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

cdnsp-pci.c (5710B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Cadence PCI Glue driver.
      4 *
      5 * Copyright (C) 2019 Cadence.
      6 *
      7 * Author: Pawel Laszczak <pawell@cadence.com>
      8 *
      9 */
     10
     11#include <linux/platform_device.h>
     12#include <linux/dma-mapping.h>
     13#include <linux/kernel.h>
     14#include <linux/module.h>
     15#include <linux/slab.h>
     16#include <linux/pci.h>
     17
     18#include "core.h"
     19#include "gadget-export.h"
     20
     21#define PCI_BAR_HOST		0
     22#define PCI_BAR_OTG		0
     23#define PCI_BAR_DEV		2
     24
     25#define PCI_DEV_FN_HOST_DEVICE	0
     26#define PCI_DEV_FN_OTG		1
     27
     28#define PCI_DRIVER_NAME		"cdns-pci-usbssp"
     29#define PLAT_DRIVER_NAME	"cdns-usbssp"
     30
     31#define CDNS_VENDOR_ID		0x17cd
     32#define CDNS_DEVICE_ID		0x0100
     33#define CDNS_DRD_IF		(PCI_CLASS_SERIAL_USB << 8 | 0x80)
     34
     35static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
     36{
     37	struct pci_dev *func;
     38
     39	/*
     40	 * Gets the second function.
     41	 * It's little tricky, but this platform has two function.
     42	 * The fist keeps resources for Host/Device while the second
     43	 * keeps resources for DRD/OTG.
     44	 */
     45	func = pci_get_device(pdev->vendor, pdev->device, NULL);
     46	if (!func)
     47		return NULL;
     48
     49	if (func->devfn == pdev->devfn) {
     50		func = pci_get_device(pdev->vendor, pdev->device, func);
     51		if (!func)
     52			return NULL;
     53	}
     54
     55	return func;
     56}
     57
     58static int cdnsp_pci_probe(struct pci_dev *pdev,
     59			   const struct pci_device_id *id)
     60{
     61	struct device *dev = &pdev->dev;
     62	struct pci_dev *func;
     63	struct resource *res;
     64	struct cdns *cdnsp;
     65	int ret;
     66
     67	/*
     68	 * For GADGET/HOST PCI (devfn) function number is 0,
     69	 * for OTG PCI (devfn) function number is 1.
     70	 */
     71	if (!id || (pdev->devfn != PCI_DEV_FN_HOST_DEVICE &&
     72		    pdev->devfn != PCI_DEV_FN_OTG))
     73		return -EINVAL;
     74
     75	func = cdnsp_get_second_fun(pdev);
     76	if (!func)
     77		return -EINVAL;
     78
     79	if (func->class == PCI_CLASS_SERIAL_USB_XHCI ||
     80	    pdev->class == PCI_CLASS_SERIAL_USB_XHCI) {
     81		ret = -EINVAL;
     82		goto put_pci;
     83	}
     84
     85	ret = pcim_enable_device(pdev);
     86	if (ret) {
     87		dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", ret);
     88		goto put_pci;
     89	}
     90
     91	pci_set_master(pdev);
     92	if (pci_is_enabled(func)) {
     93		cdnsp = pci_get_drvdata(func);
     94	} else {
     95		cdnsp = kzalloc(sizeof(*cdnsp), GFP_KERNEL);
     96		if (!cdnsp) {
     97			ret = -ENOMEM;
     98			goto disable_pci;
     99		}
    100	}
    101
    102	/* For GADGET device function number is 0. */
    103	if (pdev->devfn == 0) {
    104		resource_size_t rsrc_start, rsrc_len;
    105
    106		/* Function 0: host(BAR_0) + device(BAR_1).*/
    107		dev_dbg(dev, "Initialize resources\n");
    108		rsrc_start = pci_resource_start(pdev, PCI_BAR_DEV);
    109		rsrc_len = pci_resource_len(pdev, PCI_BAR_DEV);
    110		res = devm_request_mem_region(dev, rsrc_start, rsrc_len, "dev");
    111		if (!res) {
    112			dev_dbg(dev, "controller already in use\n");
    113			ret = -EBUSY;
    114			goto free_cdnsp;
    115		}
    116
    117		cdnsp->dev_regs = devm_ioremap(dev, rsrc_start, rsrc_len);
    118		if (!cdnsp->dev_regs) {
    119			dev_dbg(dev, "error mapping memory\n");
    120			ret = -EFAULT;
    121			goto free_cdnsp;
    122		}
    123
    124		cdnsp->dev_irq = pdev->irq;
    125		dev_dbg(dev, "USBSS-DEV physical base addr: %pa\n",
    126			&rsrc_start);
    127
    128		res = &cdnsp->xhci_res[0];
    129		res->start = pci_resource_start(pdev, PCI_BAR_HOST);
    130		res->end = pci_resource_end(pdev, PCI_BAR_HOST);
    131		res->name = "xhci";
    132		res->flags = IORESOURCE_MEM;
    133		dev_dbg(dev, "USBSS-XHCI physical base addr: %pa\n",
    134			&res->start);
    135
    136		/* Interrupt for XHCI, */
    137		res = &cdnsp->xhci_res[1];
    138		res->start = pdev->irq;
    139		res->name = "host";
    140		res->flags = IORESOURCE_IRQ;
    141	} else {
    142		res = &cdnsp->otg_res;
    143		res->start = pci_resource_start(pdev, PCI_BAR_OTG);
    144		res->end =   pci_resource_end(pdev, PCI_BAR_OTG);
    145		res->name = "otg";
    146		res->flags = IORESOURCE_MEM;
    147		dev_dbg(dev, "CDNSP-DRD physical base addr: %pa\n",
    148			&res->start);
    149
    150		/* Interrupt for OTG/DRD. */
    151		cdnsp->otg_irq = pdev->irq;
    152	}
    153
    154	if (pci_is_enabled(func)) {
    155		cdnsp->dev = dev;
    156		cdnsp->gadget_init = cdnsp_gadget_init;
    157
    158		ret = cdns_init(cdnsp);
    159		if (ret)
    160			goto free_cdnsp;
    161	}
    162
    163	pci_set_drvdata(pdev, cdnsp);
    164
    165	device_wakeup_enable(&pdev->dev);
    166	if (pci_dev_run_wake(pdev))
    167		pm_runtime_put_noidle(&pdev->dev);
    168
    169	return 0;
    170
    171free_cdnsp:
    172	if (!pci_is_enabled(func))
    173		kfree(cdnsp);
    174
    175disable_pci:
    176	pci_disable_device(pdev);
    177
    178put_pci:
    179	pci_dev_put(func);
    180
    181	return ret;
    182}
    183
    184static void cdnsp_pci_remove(struct pci_dev *pdev)
    185{
    186	struct cdns *cdnsp;
    187	struct pci_dev *func;
    188
    189	func = cdnsp_get_second_fun(pdev);
    190	cdnsp = (struct cdns *)pci_get_drvdata(pdev);
    191
    192	if (pci_dev_run_wake(pdev))
    193		pm_runtime_get_noresume(&pdev->dev);
    194
    195	if (!pci_is_enabled(func)) {
    196		kfree(cdnsp);
    197		goto pci_put;
    198	}
    199
    200	cdns_remove(cdnsp);
    201
    202pci_put:
    203	pci_dev_put(func);
    204}
    205
    206static int __maybe_unused cdnsp_pci_suspend(struct device *dev)
    207{
    208	struct cdns *cdns = dev_get_drvdata(dev);
    209
    210	return cdns_suspend(cdns);
    211}
    212
    213static int __maybe_unused cdnsp_pci_resume(struct device *dev)
    214{
    215	struct cdns *cdns = dev_get_drvdata(dev);
    216	unsigned long flags;
    217	int ret;
    218
    219	spin_lock_irqsave(&cdns->lock, flags);
    220	ret = cdns_resume(cdns, 1);
    221	spin_unlock_irqrestore(&cdns->lock, flags);
    222
    223	return ret;
    224}
    225
    226static const struct dev_pm_ops cdnsp_pci_pm_ops = {
    227	SET_SYSTEM_SLEEP_PM_OPS(cdnsp_pci_suspend, cdnsp_pci_resume)
    228};
    229
    230static const struct pci_device_id cdnsp_pci_ids[] = {
    231	{ PCI_VENDOR_ID_CDNS, CDNS_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
    232	  PCI_CLASS_SERIAL_USB_DEVICE, PCI_ANY_ID },
    233	{ PCI_VENDOR_ID_CDNS, CDNS_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
    234	  CDNS_DRD_IF, PCI_ANY_ID },
    235	{ 0, }
    236};
    237
    238static struct pci_driver cdnsp_pci_driver = {
    239	.name = "cdnsp-pci",
    240	.id_table = &cdnsp_pci_ids[0],
    241	.probe = cdnsp_pci_probe,
    242	.remove = cdnsp_pci_remove,
    243	.driver = {
    244		.pm = &cdnsp_pci_pm_ops,
    245	}
    246};
    247
    248module_pci_driver(cdnsp_pci_driver);
    249MODULE_DEVICE_TABLE(pci, cdnsp_pci_ids);
    250
    251MODULE_ALIAS("pci:cdnsp");
    252MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
    253MODULE_LICENSE("GPL v2");
    254MODULE_DESCRIPTION("Cadence CDNSP PCI driver");