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

buffer.c (3760B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * DMA memory management for framework level HCD code (hc_driver)
      4 *
      5 * This implementation plugs in through generic "usb_bus" level methods,
      6 * and should work with all USB controllers, regardless of bus type.
      7 *
      8 * Released under the GPLv2 only.
      9 */
     10
     11#include <linux/module.h>
     12#include <linux/kernel.h>
     13#include <linux/slab.h>
     14#include <linux/device.h>
     15#include <linux/mm.h>
     16#include <linux/io.h>
     17#include <linux/dma-mapping.h>
     18#include <linux/dmapool.h>
     19#include <linux/genalloc.h>
     20#include <linux/usb.h>
     21#include <linux/usb/hcd.h>
     22
     23
     24/*
     25 * DMA-Coherent Buffers
     26 */
     27
     28/* FIXME tune these based on pool statistics ... */
     29static size_t pool_max[HCD_BUFFER_POOLS] = {
     30	32, 128, 512, 2048,
     31};
     32
     33void __init usb_init_pool_max(void)
     34{
     35	/*
     36	 * The pool_max values must never be smaller than
     37	 * ARCH_KMALLOC_MINALIGN.
     38	 */
     39	if (ARCH_KMALLOC_MINALIGN <= 32)
     40		;			/* Original value is okay */
     41	else if (ARCH_KMALLOC_MINALIGN <= 64)
     42		pool_max[0] = 64;
     43	else if (ARCH_KMALLOC_MINALIGN <= 128)
     44		pool_max[0] = 0;	/* Don't use this pool */
     45	else
     46		BUILD_BUG();		/* We don't allow this */
     47}
     48
     49/* SETUP primitives */
     50
     51/**
     52 * hcd_buffer_create - initialize buffer pools
     53 * @hcd: the bus whose buffer pools are to be initialized
     54 *
     55 * Context: task context, might sleep
     56 *
     57 * Call this as part of initializing a host controller that uses the dma
     58 * memory allocators.  It initializes some pools of dma-coherent memory that
     59 * will be shared by all drivers using that controller.
     60 *
     61 * Call hcd_buffer_destroy() to clean up after using those pools.
     62 *
     63 * Return: 0 if successful. A negative errno value otherwise.
     64 */
     65int hcd_buffer_create(struct usb_hcd *hcd)
     66{
     67	char		name[16];
     68	int		i, size;
     69
     70	if (hcd->localmem_pool || !hcd_uses_dma(hcd))
     71		return 0;
     72
     73	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
     74		size = pool_max[i];
     75		if (!size)
     76			continue;
     77		snprintf(name, sizeof(name), "buffer-%d", size);
     78		hcd->pool[i] = dma_pool_create(name, hcd->self.sysdev,
     79				size, size, 0);
     80		if (!hcd->pool[i]) {
     81			hcd_buffer_destroy(hcd);
     82			return -ENOMEM;
     83		}
     84	}
     85	return 0;
     86}
     87
     88
     89/**
     90 * hcd_buffer_destroy - deallocate buffer pools
     91 * @hcd: the bus whose buffer pools are to be destroyed
     92 *
     93 * Context: task context, might sleep
     94 *
     95 * This frees the buffer pools created by hcd_buffer_create().
     96 */
     97void hcd_buffer_destroy(struct usb_hcd *hcd)
     98{
     99	int i;
    100
    101	if (!IS_ENABLED(CONFIG_HAS_DMA))
    102		return;
    103
    104	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
    105		dma_pool_destroy(hcd->pool[i]);
    106		hcd->pool[i] = NULL;
    107	}
    108}
    109
    110
    111/* sometimes alloc/free could use kmalloc with GFP_DMA, for
    112 * better sharing and to leverage mm/slab.c intelligence.
    113 */
    114
    115void *hcd_buffer_alloc(
    116	struct usb_bus		*bus,
    117	size_t			size,
    118	gfp_t			mem_flags,
    119	dma_addr_t		*dma
    120)
    121{
    122	struct usb_hcd		*hcd = bus_to_hcd(bus);
    123	int			i;
    124
    125	if (size == 0)
    126		return NULL;
    127
    128	if (hcd->localmem_pool)
    129		return gen_pool_dma_alloc(hcd->localmem_pool, size, dma);
    130
    131	/* some USB hosts just use PIO */
    132	if (!hcd_uses_dma(hcd)) {
    133		*dma = ~(dma_addr_t) 0;
    134		return kmalloc(size, mem_flags);
    135	}
    136
    137	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
    138		if (size <= pool_max[i])
    139			return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
    140	}
    141	return dma_alloc_coherent(hcd->self.sysdev, size, dma, mem_flags);
    142}
    143
    144void hcd_buffer_free(
    145	struct usb_bus		*bus,
    146	size_t			size,
    147	void			*addr,
    148	dma_addr_t		dma
    149)
    150{
    151	struct usb_hcd		*hcd = bus_to_hcd(bus);
    152	int			i;
    153
    154	if (!addr)
    155		return;
    156
    157	if (hcd->localmem_pool) {
    158		gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size);
    159		return;
    160	}
    161
    162	if (!hcd_uses_dma(hcd)) {
    163		kfree(addr);
    164		return;
    165	}
    166
    167	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
    168		if (size <= pool_max[i]) {
    169			dma_pool_free(hcd->pool[i], addr, dma);
    170			return;
    171		}
    172	}
    173	dma_free_coherent(hcd->self.sysdev, size, addr, dma);
    174}