Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/usb/core/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 4 kB image not shown  

Quelle  buffer.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * DMA memory management for framework level HCD code (hc_driver)
 *
 * This implementation plugs in through generic "usb_bus" level methods,
 * and should work with all USB controllers, regardless of bus type.
 *
 * Released under the GPLv2 only.
 */


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/genalloc.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>


/*
 * DMA-Coherent Buffers
 */


/* FIXME tune these based on pool statistics ... */
static size_t pool_max[HCD_BUFFER_POOLS] = {
 32, 128, 512, 2048,
};

void __init usb_init_pool_max(void)
{
 /*
 * The pool_max values must never be smaller than
 * ARCH_DMA_MINALIGN.
 */

 if (ARCH_DMA_MINALIGN <= 32)
  ;   /* Original value is okay */
 else if (ARCH_DMA_MINALIGN <= 64)
  pool_max[0] = 64;
 else if (ARCH_DMA_MINALIGN <= 128)
  pool_max[0] = 0; /* Don't use this pool */
 else
  BUILD_BUG();  /* We don't allow this */
}

/* SETUP primitives */

/**
 * hcd_buffer_create - initialize buffer pools
 * @hcd: the bus whose buffer pools are to be initialized
 *
 * Context: task context, might sleep
 *
 * Call this as part of initializing a host controller that uses the dma
 * memory allocators.  It initializes some pools of dma-coherent memory that
 * will be shared by all drivers using that controller.
 *
 * Call hcd_buffer_destroy() to clean up after using those pools.
 *
 * Return: 0 if successful. A negative errno value otherwise.
 */

int hcd_buffer_create(struct usb_hcd *hcd)
{
 char  name[16];
 int  i, size;

 if (hcd->localmem_pool || !hcd_uses_dma(hcd))
  return 0;

 for (i = 0; i < HCD_BUFFER_POOLS; i++) {
  size = pool_max[i];
  if (!size)
   continue;
  snprintf(name, sizeof(name), "buffer-%d", size);
  hcd->pool[i] = dma_pool_create(name, hcd->self.sysdev,
    size, size, 0);
  if (!hcd->pool[i]) {
   hcd_buffer_destroy(hcd);
   return -ENOMEM;
  }
 }
 return 0;
}


/**
 * hcd_buffer_destroy - deallocate buffer pools
 * @hcd: the bus whose buffer pools are to be destroyed
 *
 * Context: task context, might sleep
 *
 * This frees the buffer pools created by hcd_buffer_create().
 */

void hcd_buffer_destroy(struct usb_hcd *hcd)
{
 int i;

 if (!IS_ENABLED(CONFIG_HAS_DMA))
  return;

 for (i = 0; i < HCD_BUFFER_POOLS; i++) {
  dma_pool_destroy(hcd->pool[i]);
  hcd->pool[i] = NULL;
 }
}


/* sometimes alloc/free could use kmalloc with GFP_DMA, for
 * better sharing and to leverage mm/slab.c intelligence.
 */


void *hcd_buffer_alloc(
 struct usb_bus  *bus,
 size_t   size,
 gfp_t   mem_flags,
 dma_addr_t  *dma
)
{
 struct usb_hcd  *hcd = bus_to_hcd(bus);
 int   i;

 if (size == 0)
  return NULL;

 if (hcd->localmem_pool)
  return gen_pool_dma_alloc(hcd->localmem_pool, size, dma);

 /* some USB hosts just use PIO */
 if (!hcd_uses_dma(hcd)) {
  *dma = ~(dma_addr_t) 0;
  return kmalloc(size, mem_flags);
 }

 for (i = 0; i < HCD_BUFFER_POOLS; i++) {
  if (size <= pool_max[i])
   return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
 }
 return dma_alloc_coherent(hcd->self.sysdev, size, dma, mem_flags);
}

void hcd_buffer_free(
 struct usb_bus  *bus,
 size_t   size,
 void   *addr,
 dma_addr_t  dma
)
{
 struct usb_hcd  *hcd = bus_to_hcd(bus);
 int   i;

 if (!addr)
  return;

 if (hcd->localmem_pool) {
  gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size);
  return;
 }

 if (!hcd_uses_dma(hcd)) {
  kfree(addr);
  return;
 }

 for (i = 0; i < HCD_BUFFER_POOLS; i++) {
  if (size <= pool_max[i]) {
   dma_pool_free(hcd->pool[i], addr, dma);
   return;
  }
 }
 dma_free_coherent(hcd->self.sysdev, size, addr, dma);
}

void *hcd_buffer_alloc_pages(struct usb_hcd *hcd,
  size_t size, gfp_t mem_flags, dma_addr_t *dma)
{
 if (size == 0)
  return NULL;

 if (hcd->localmem_pool)
  return gen_pool_dma_alloc_align(hcd->localmem_pool,
    size, dma, PAGE_SIZE);

 /* some USB hosts just use PIO */
 if (!hcd_uses_dma(hcd)) {
  *dma = DMA_MAPPING_ERROR;
  return (void *)__get_free_pages(mem_flags,
    get_order(size));
 }

 return dma_alloc_coherent(hcd->self.sysdev,
   size, dma, mem_flags);
}

void hcd_buffer_free_pages(struct usb_hcd *hcd,
  size_t size, void *addr, dma_addr_t dma)
{
 if (!addr)
  return;

 if (hcd->localmem_pool) {
  gen_pool_free(hcd->localmem_pool,
    (unsigned long)addr, size);
  return;
 }

 if (!hcd_uses_dma(hcd)) {
  free_pages((unsigned long)addr, get_order(size));
  return;
 }

 dma_free_coherent(hcd->self.sysdev, size, addr, dma);
}

Messung V0.5
C=96 H=95 G=95

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.