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

ohci-sm501.c (6835B)


      1// SPDX-License-Identifier: GPL-1.0+
      2/*
      3 * OHCI HCD (Host Controller Driver) for USB.
      4 *
      5 * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
      6 * (C) Copyright 2000-2005 David Brownell
      7 * (C) Copyright 2002 Hewlett-Packard Company
      8 * (C) Copyright 2008 Magnus Damm
      9 *
     10 * SM501 Bus Glue - based on ohci-omap.c
     11 *
     12 * This file is licenced under the GPL.
     13 */
     14
     15#include <linux/interrupt.h>
     16#include <linux/jiffies.h>
     17#include <linux/platform_device.h>
     18#include <linux/dma-mapping.h>
     19#include <linux/sm501.h>
     20#include <linux/sm501-regs.h>
     21
     22static int ohci_sm501_init(struct usb_hcd *hcd)
     23{
     24	return ohci_init(hcd_to_ohci(hcd));
     25}
     26
     27static int ohci_sm501_start(struct usb_hcd *hcd)
     28{
     29	struct device *dev = hcd->self.controller;
     30	int ret;
     31
     32	ret = ohci_run(hcd_to_ohci(hcd));
     33	if (ret < 0) {
     34		dev_err(dev, "can't start %s", hcd->self.bus_name);
     35		ohci_stop(hcd);
     36	}
     37
     38	return ret;
     39}
     40
     41/*-------------------------------------------------------------------------*/
     42
     43static const struct hc_driver ohci_sm501_hc_driver = {
     44	.description =		hcd_name,
     45	.product_desc =		"SM501 OHCI",
     46	.hcd_priv_size =	sizeof(struct ohci_hcd),
     47
     48	/*
     49	 * generic hardware linkage
     50	 */
     51	.irq =			ohci_irq,
     52	.flags =		HCD_USB11 | HCD_MEMORY,
     53
     54	/*
     55	 * basic lifecycle operations
     56	 */
     57	.reset =		ohci_sm501_init,
     58	.start =		ohci_sm501_start,
     59	.stop =			ohci_stop,
     60	.shutdown =		ohci_shutdown,
     61
     62	/*
     63	 * managing i/o requests and associated device resources
     64	 */
     65	.urb_enqueue =		ohci_urb_enqueue,
     66	.urb_dequeue =		ohci_urb_dequeue,
     67	.endpoint_disable =	ohci_endpoint_disable,
     68
     69	/*
     70	 * scheduling support
     71	 */
     72	.get_frame_number =	ohci_get_frame,
     73
     74	/*
     75	 * root hub support
     76	 */
     77	.hub_status_data =	ohci_hub_status_data,
     78	.hub_control =		ohci_hub_control,
     79#ifdef	CONFIG_PM
     80	.bus_suspend =		ohci_bus_suspend,
     81	.bus_resume =		ohci_bus_resume,
     82#endif
     83	.start_port_reset =	ohci_start_port_reset,
     84};
     85
     86/*-------------------------------------------------------------------------*/
     87
     88static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
     89{
     90	const struct hc_driver *driver = &ohci_sm501_hc_driver;
     91	struct device *dev = &pdev->dev;
     92	struct resource	*res, *mem;
     93	int retval, irq;
     94	struct usb_hcd *hcd = NULL;
     95
     96	irq = retval = platform_get_irq(pdev, 0);
     97	if (retval < 0)
     98		goto err0;
     99
    100	mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
    101	if (mem == NULL) {
    102		dev_err(dev, "no resource definition for memory\n");
    103		retval = -ENOENT;
    104		goto err0;
    105	}
    106
    107	if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
    108		dev_err(dev, "request_mem_region failed\n");
    109		retval = -EBUSY;
    110		goto err0;
    111	}
    112
    113	/* allocate, reserve and remap resources for registers */
    114	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    115	if (res == NULL) {
    116		dev_err(dev, "no resource definition for registers\n");
    117		retval = -ENOENT;
    118		goto err1;
    119	}
    120
    121	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
    122	if (!hcd) {
    123		retval = -ENOMEM;
    124		goto err1;
    125	}
    126
    127	hcd->rsrc_start = res->start;
    128	hcd->rsrc_len = resource_size(res);
    129
    130	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,	pdev->name)) {
    131		dev_err(dev, "request_mem_region failed\n");
    132		retval = -EBUSY;
    133		goto err3;
    134	}
    135
    136	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
    137	if (hcd->regs == NULL) {
    138		dev_err(dev, "cannot remap registers\n");
    139		retval = -ENXIO;
    140		goto err4;
    141	}
    142
    143	ohci_hcd_init(hcd_to_ohci(hcd));
    144
    145	/* The sm501 chip is equipped with local memory that may be used
    146	 * by on-chip devices such as the video controller and the usb host.
    147	 * This driver uses genalloc so that usb allocations with
    148	 * gen_pool_dma_alloc() allocate from this local memory. The dma_handle
    149	 * returned by gen_pool_dma_alloc() will be an offset starting from 0
    150	 * for the first local memory byte.
    151	 *
    152	 * So as long as data is allocated using gen_pool_dma_alloc() all is
    153	 * fine. This is however not always the case - buffers may be allocated
    154	 * using kmalloc() - so the usb core needs to be told that it must copy
    155	 * data into our local memory if the buffers happen to be placed in
    156	 * regular memory. A non-null hcd->localmem_pool initialized by the
    157	 * the call to usb_hcd_setup_local_mem() below does just that.
    158	 */
    159
    160	retval = usb_hcd_setup_local_mem(hcd, mem->start,
    161					 mem->start - mem->parent->start,
    162					 resource_size(mem));
    163	if (retval < 0)
    164		goto err5;
    165	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
    166	if (retval)
    167		goto err5;
    168	device_wakeup_enable(hcd->self.controller);
    169
    170	/* enable power and unmask interrupts */
    171
    172	sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
    173	sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0);
    174
    175	return 0;
    176err5:
    177	iounmap(hcd->regs);
    178err4:
    179	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
    180err3:
    181	usb_put_hcd(hcd);
    182err1:
    183	release_mem_region(mem->start, resource_size(mem));
    184err0:
    185	return retval;
    186}
    187
    188static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)
    189{
    190	struct usb_hcd *hcd = platform_get_drvdata(pdev);
    191	struct resource	*mem;
    192
    193	usb_remove_hcd(hcd);
    194	iounmap(hcd->regs);
    195	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
    196	usb_put_hcd(hcd);
    197	mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
    198	if (mem)
    199		release_mem_region(mem->start, resource_size(mem));
    200
    201	/* mask interrupts and disable power */
    202
    203	sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6);
    204	sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0);
    205
    206	return 0;
    207}
    208
    209/*-------------------------------------------------------------------------*/
    210
    211#ifdef CONFIG_PM
    212static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg)
    213{
    214	struct device *dev = &pdev->dev;
    215	struct usb_hcd  *hcd = platform_get_drvdata(pdev);
    216	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
    217	bool do_wakeup = device_may_wakeup(dev);
    218	int ret;
    219
    220	if (time_before(jiffies, ohci->next_statechange))
    221		msleep(5);
    222	ohci->next_statechange = jiffies;
    223
    224	ret = ohci_suspend(hcd, do_wakeup);
    225	if (ret)
    226		return ret;
    227
    228	sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0);
    229	return ret;
    230}
    231
    232static int ohci_sm501_resume(struct platform_device *pdev)
    233{
    234	struct device *dev = &pdev->dev;
    235	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
    236	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
    237
    238	if (time_before(jiffies, ohci->next_statechange))
    239		msleep(5);
    240	ohci->next_statechange = jiffies;
    241
    242	sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
    243	ohci_resume(hcd, false);
    244	return 0;
    245}
    246#else
    247#define ohci_sm501_suspend NULL
    248#define ohci_sm501_resume NULL
    249#endif
    250
    251/*-------------------------------------------------------------------------*/
    252
    253/*
    254 * Driver definition to register with the SM501 bus
    255 */
    256static struct platform_driver ohci_hcd_sm501_driver = {
    257	.probe		= ohci_hcd_sm501_drv_probe,
    258	.remove		= ohci_hcd_sm501_drv_remove,
    259	.shutdown	= usb_hcd_platform_shutdown,
    260	.suspend	= ohci_sm501_suspend,
    261	.resume		= ohci_sm501_resume,
    262	.driver		= {
    263		.name	= "sm501-usb",
    264	},
    265};
    266MODULE_ALIAS("platform:sm501-usb");