LCOV - code coverage report
Current view: top level - drivers/usb/core - buffer.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 17 40 42.5 %
Date: 2020-09-30 20:25:40 Functions: 3 5 60.0 %
Branches: 11 34 32.4 %

           Branch data     Line data    Source code
       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 ... */
      29                 :            : static size_t pool_max[HCD_BUFFER_POOLS] = {
      30                 :            :         32, 128, 512, 2048,
      31                 :            : };
      32                 :            : 
      33                 :        207 : void __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                 :        207 :                 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                 :        207 : }
      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                 :            :  * Context: !in_interrupt()
      55                 :            :  *
      56                 :            :  * Call this as part of initializing a host controller that uses the dma
      57                 :            :  * memory allocators.  It initializes some pools of dma-coherent memory that
      58                 :            :  * will be shared by all drivers using that controller.
      59                 :            :  *
      60                 :            :  * Call hcd_buffer_destroy() to clean up after using those pools.
      61                 :            :  *
      62                 :            :  * Return: 0 if successful. A negative errno value otherwise.
      63                 :            :  */
      64                 :        207 : int hcd_buffer_create(struct usb_hcd *hcd)
      65                 :            : {
      66                 :            :         char            name[16];
      67                 :            :         int             i, size;
      68                 :            : 
      69   [ +  -  +  - ]:        414 :         if (hcd->localmem_pool || !hcd_uses_dma(hcd))
      70                 :            :                 return 0;
      71                 :            : 
      72         [ +  + ]:        828 :         for (i = 0; i < HCD_BUFFER_POOLS; i++) {
      73                 :        828 :                 size = pool_max[i];
      74         [ -  + ]:        828 :                 if (!size)
      75                 :          0 :                         continue;
      76                 :        828 :                 snprintf(name, sizeof(name), "buffer-%d", size);
      77                 :        828 :                 hcd->pool[i] = dma_pool_create(name, hcd->self.sysdev,
      78                 :            :                                 size, size, 0);
      79         [ -  + ]:        828 :                 if (!hcd->pool[i]) {
      80                 :            :                         hcd_buffer_destroy(hcd);
      81                 :            :                         return -ENOMEM;
      82                 :            :                 }
      83                 :            :         }
      84                 :            :         return 0;
      85                 :            : }
      86                 :            : 
      87                 :            : 
      88                 :            : /**
      89                 :            :  * hcd_buffer_destroy - deallocate buffer pools
      90                 :            :  * @hcd: the bus whose buffer pools are to be destroyed
      91                 :            :  * Context: !in_interrupt()
      92                 :            :  *
      93                 :            :  * This frees the buffer pools created by hcd_buffer_create().
      94                 :            :  */
      95                 :          0 : void hcd_buffer_destroy(struct usb_hcd *hcd)
      96                 :            : {
      97                 :            :         int i;
      98                 :            : 
      99                 :            :         if (!IS_ENABLED(CONFIG_HAS_DMA))
     100                 :          0 :                 return;
     101                 :            : 
     102   [ #  #  #  # ]:          0 :         for (i = 0; i < HCD_BUFFER_POOLS; i++) {
     103                 :          0 :                 dma_pool_destroy(hcd->pool[i]);
     104                 :          0 :                 hcd->pool[i] = NULL;
     105                 :            :         }
     106                 :            : }
     107                 :            : 
     108                 :            : 
     109                 :            : /* sometimes alloc/free could use kmalloc with GFP_DMA, for
     110                 :            :  * better sharing and to leverage mm/slab.c intelligence.
     111                 :            :  */
     112                 :            : 
     113                 :       1863 : void *hcd_buffer_alloc(
     114                 :            :         struct usb_bus          *bus,
     115                 :            :         size_t                  size,
     116                 :            :         gfp_t                   mem_flags,
     117                 :            :         dma_addr_t              *dma
     118                 :            : )
     119                 :            : {
     120                 :            :         struct usb_hcd          *hcd = bus_to_hcd(bus);
     121                 :            :         int                     i;
     122                 :            : 
     123         [ +  - ]:       1863 :         if (size == 0)
     124                 :            :                 return NULL;
     125                 :            : 
     126         [ -  + ]:       1863 :         if (hcd->localmem_pool)
     127                 :          0 :                 return gen_pool_dma_alloc(hcd->localmem_pool, size, dma);
     128                 :            : 
     129                 :            :         /* some USB hosts just use PIO */
     130         [ +  - ]:       1863 :         if (!hcd_uses_dma(hcd)) {
     131                 :          0 :                 *dma = ~(dma_addr_t) 0;
     132                 :          0 :                 return kmalloc(size, mem_flags);
     133                 :            :         }
     134                 :            : 
     135         [ +  - ]:          0 :         for (i = 0; i < HCD_BUFFER_POOLS; i++) {
     136         [ +  - ]:       1863 :                 if (size <= pool_max[i])
     137                 :       1863 :                         return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
     138                 :            :         }
     139                 :          0 :         return dma_alloc_coherent(hcd->self.sysdev, size, dma, mem_flags);
     140                 :            : }
     141                 :            : 
     142                 :          0 : void hcd_buffer_free(
     143                 :            :         struct usb_bus          *bus,
     144                 :            :         size_t                  size,
     145                 :            :         void                    *addr,
     146                 :            :         dma_addr_t              dma
     147                 :            : )
     148                 :            : {
     149                 :            :         struct usb_hcd          *hcd = bus_to_hcd(bus);
     150                 :            :         int                     i;
     151                 :            : 
     152         [ #  # ]:          0 :         if (!addr)
     153                 :            :                 return;
     154                 :            : 
     155         [ #  # ]:          0 :         if (hcd->localmem_pool) {
     156                 :          0 :                 gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size);
     157                 :            :                 return;
     158                 :            :         }
     159                 :            : 
     160         [ #  # ]:          0 :         if (!hcd_uses_dma(hcd)) {
     161                 :          0 :                 kfree(addr);
     162                 :          0 :                 return;
     163                 :            :         }
     164                 :            : 
     165         [ #  # ]:          0 :         for (i = 0; i < HCD_BUFFER_POOLS; i++) {
     166         [ #  # ]:          0 :                 if (size <= pool_max[i]) {
     167                 :          0 :                         dma_pool_free(hcd->pool[i], addr, dma);
     168                 :          0 :                         return;
     169                 :            :                 }
     170                 :            :         }
     171                 :          0 :         dma_free_coherent(hcd->self.sysdev, size, addr, dma);
     172                 :            : }

Generated by: LCOV version 1.14