sonic-buildimage/platform/broadcom/saibcm-modules/sdklt/linux/bde/ngbde_dma.c
vmittal-msft 04b9ce8e32
[BCMSAI] Update BCMSAI debian to 6.0.0.10 with 6.5.23 SDK, and opennsl module to 6.5.23 (#9046)
Manual verification on switch (TH3 device)
admin@str2-xxxxx-01:~$ bcmcmd bsv
bsv
BRCM SAI ver: [6.0.0.10], OCP SAI ver: [1.9.1], SDK ver: [sdk-6.5.23]
drivshell>

admin@str2-xxxxx-01:~$ bcmcmd version
version
Broadcom Command Monitor: Copyright (c) 1998-2021 Broadcom
Release: sdk-6.5.23 built 20211020 (Wed Oct 20 06:52:58 2021)
From root@fedbbfdbee81:/__w/2/s/output/x86-xgsall-deb/hsdk
Platform: X86
OS: Unix (Posix)
Chips:
BCM56640_A0,
BCM56850_A0,
BCM56340_A0,
BCM56960_A0, BCM56860_A0,

   BCM56970_A0, BCM56870_A0,
   BCM56980_A0, BCM56980_B0,
  
   BCM56370_A0, BCM56275_A0, BCM56770_A0,
Chips:
BCM56780_A0, BCM56782_A0, BCM56784_A0, BCM56785_A0,
BCM56786_A0, BCM56787_A0, BCM56788_A0, BCM56789_A0,
BCM56880_A0, BCM56880_B0, BCM56881_A0, BCM56881_B0,
BCM56883_A0, BCM56883_B0, BCM56990_A0, BCM56990_B0,
BCM56991_B0, BCM56992_B0, BCM56996_A0, BCM56996_B0,
BCM56997_A0, BCM56997_B0

Variant drivers:
BCM56780_A0_CNA_1_2_10, BCM56780_A0_DNA_2_7_6_0, BCM56880_A0_CNA_1_2_9, BCM56880_A0_DNA_4_9_5_0
PHYs: BCM5400, BCM54182, BCM54185, BCM54180,
BCM54140, BCM54192, BCM54195, BCM54190,
BCM54194, BCM54210, BCM54220, BCM54280,
BCM54282, BCM54240, BCM54285, BCM5428X,
BCM54290, BCM54292, BCM54294, BCM54295,
BCM54296, BCM56160-GPHY, BCM53540-GPHY, BCM56275-GPHY,
BCM8750, BCM8752, BCM8754, BCM84740,
BCM84164, BCM84758, BCM84780, BCM84784,
BCM84318, BCM84328, Sesto, BCM82780,
copper sfp

drivshell>
2021-10-28 00:12:32 -07:00

341 lines
9.2 KiB
C

/*! \file ngbde_dma.c
*
* This module handles allocation of DMA memory pools.
*
*/
/*
* $Copyright: Copyright 2018-2021 Broadcom. All rights reserved.
* The term 'Broadcom' refers to Broadcom Inc. and/or its subsidiaries.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A copy of the GNU General Public License version 2 (GPLv2) can
* be found in the LICENSES folder.$
*/
#include <ngbde.h>
/*! \cond */
static int dma_debug = 0;
module_param(dma_debug, int, 0);
MODULE_PARM_DESC(dma_debug,
"DMA debug output enable (default 0).");
/*! \endcond */
/*! Default size of of DMA memory pools (in MB). */
#define DMAPOOL_SIZE_DEFAULT 16
/*! Default number of DMA memory pools per device. */
#define NUM_DMAPOOL_DEFAULT 1
/*! \cond */
static int dma_size = DMAPOOL_SIZE_DEFAULT;
module_param(dma_size, int, 0);
MODULE_PARM_DESC(dma_size,
"Size of of DMA memory pools in MB (default 16 MB).");
/*! \endcond */
/*! \cond */
static char *dma_alloc;
module_param(dma_alloc, charp, 0);
MODULE_PARM_DESC(dma_alloc,
"DMA allocation method auto|kapi|pgmem (default auto)");
/*! \endcond */
/*! \cond */
static int dma_pools = NUM_DMAPOOL_DEFAULT;
module_param(dma_pools, int, 0);
MODULE_PARM_DESC(dma_pools,
"Number of DMA memory pools to pre-allocate per device (default 1).");
/*! \endcond */
/*!
* \brief Allocate DMA memory via kernel API.
*
* \param [in] dmactrl DMA allocation control.
* \param [out] dmamem DMA allocation result.
*
* \return Nothing.
*/
static void
ngbde_dmamem_kapi_alloc(ngbde_dmactrl_t *dmactrl, ngbde_dmamem_t *dmamem)
{
void *vaddr;
dma_addr_t baddr;
vaddr = dma_alloc_coherent(dmactrl->dev, dmactrl->size, &baddr,
dmactrl->flags);
if (vaddr) {
/* Store allocation information in dmamem structure */
dmamem->vaddr = vaddr;
dmamem->paddr = virt_to_phys(vaddr);
dmamem->dev = dmactrl->dev;
dmamem->size = dmactrl->size;
dmamem->type = NGBDE_DMA_T_KAPI;
dmamem->baddr = baddr;
/* Write small signature for debug purposes */
strcpy((char *)vaddr, "DMA_KAPI");
if (dma_debug) {
printk("DMA: Allocated %d KB of KAPI memory at 0x%08lx\n",
(int)(dmamem->size / ONE_KB),
(unsigned long)dmamem->paddr);
}
} else {
if (dma_debug) {
printk("DMA: Failed to allocate KAPI memory\n");
}
}
}
/*!
* \brief Allocate DMA memory via page allocator.
*
* \param [in] dmactrl DMA allocation control.
* \param [out] dmamem DMA allocation result.
*
* \return Nothing.
*/
static void
ngbde_dmamem_pgmem_alloc(ngbde_dmactrl_t *dmactrl, ngbde_dmamem_t *dmamem)
{
void *vaddr;
vaddr = ngbde_pgmem_alloc(dmactrl->size, dmactrl->flags);
if (vaddr) {
/* Store allocation information in dmamem structure */
dmamem->vaddr = vaddr;
dmamem->paddr = virt_to_phys(vaddr);
dmamem->dev = dmactrl->dev;
dmamem->size = dmactrl->size;
dmamem->type = NGBDE_DMA_T_PGMEM;
dmamem->baddr = dma_map_single(dmamem->dev, dmamem->vaddr,
dmamem->size, DMA_BIDIRECTIONAL);
if (dma_mapping_error(dmactrl->dev, dmamem->baddr)) {
dmamem->baddr = 0;
if (dma_debug) {
printk("DMA: Failed to map PGMEM memory\n");
}
}
/* Write small signature for debug purposes */
strcpy((char *)vaddr, "DMA_PGMEM");
if (dma_debug) {
printk("DMA: Allocated %d KB of PGMEM memory at 0x%08lx\n",
(int)(dmamem->size / ONE_KB),
(unsigned long)dmamem->paddr);
}
} else {
if (dma_debug) {
printk("DMA: Failed to allocate PGMEM memory\n");
}
}
}
/*!
* \brief Allocate DMA memory.
*
* Depending on the DMA allocation control parameters, we select one
* of several DMA memory allocation methods.
*
* \param [in] dmactrl DMA allocation control.
* \param [out] dmamem DMA allocation result.
*
* \return Nothing.
*/
static int
ngbde_dmamem_alloc(ngbde_dmactrl_t *dmactrl, ngbde_dmamem_t *dmamem)
{
int kapi = 0;
if (dmamem->vaddr) {
/* Already allocated */
return 0;
}
#ifdef CONFIG_CMA
/* Always allow KAPI when CMA is available */
kapi = 1;
#else
if (dmactrl->size <= (1 << (MAX_ORDER - 1 + PAGE_SHIFT))) {
kapi = 1;
}
#endif
/* Allocation via kernel DMA API (if allowed) */
if (kapi) {
switch (dmactrl->pref_type) {
case NGBDE_DMA_T_AUTO:
case NGBDE_DMA_T_KAPI:
ngbde_dmamem_kapi_alloc(dmactrl, dmamem);
break;
default:
break;
}
}
/* Allocation via private page allocator */
if (dmamem->vaddr == NULL) {
switch (dmactrl->pref_type) {
case NGBDE_DMA_T_AUTO:
case NGBDE_DMA_T_PGMEM:
ngbde_dmamem_pgmem_alloc(dmactrl, dmamem);
break;
default:
break;
}
}
if (dmamem->vaddr == NULL) {
printk(KERN_WARNING "%s: Failed to allocate DMA memory\n",
MOD_NAME);
return -1;
}
return 0;
}
/*!
* \brief Free DMA memory.
*
* Free DMA memory allocated via \ref ngbde_dmamem_alloc.
*
* \param [in] dmamem DMA allocation result from \ref ngbde_dmamem_alloc.
*
* \return Nothing.
*/
static int
ngbde_dmamem_free(ngbde_dmamem_t *dmamem)
{
switch (dmamem->type) {
case NGBDE_DMA_T_KAPI:
if (dma_debug) {
printk("DMA: Freeing %d KB of KAPI memory\n",
(int)(dmamem->size / ONE_KB));
}
dma_free_coherent(dmamem->dev, dmamem->size,
dmamem->vaddr, dmamem->paddr);
memset(dmamem, 0, sizeof(*dmamem));
break;
case NGBDE_DMA_T_PGMEM:
if (dma_debug) {
printk("DMA: Freeing %d KB of PGMEM memory\n",
(int)(dmamem->size / ONE_KB));
}
if (dmamem->baddr) {
if (dma_debug) {
printk("DMA: Unmapping PGMEM memory at 0x%08lx\n",
(unsigned long)dmamem->baddr);
}
dma_unmap_single(dmamem->dev, dmamem->baddr,
dmamem->size, DMA_BIDIRECTIONAL);
}
ngbde_pgmem_free(dmamem->vaddr);
memset(dmamem, 0, sizeof(*dmamem));
break;
case NGBDE_DMA_T_NONE:
/* Nothing to free */
break;
default:
printk(KERN_WARNING "%s: Unable to free unknown DMA memory type\n",
MOD_NAME);
break;
}
return 0;
}
/*!
* \brief Free all DMA memory pools for all devices.
*
* \return Nothing.
*/
void
ngbde_dma_cleanup(void)
{
struct ngbde_dev_s *swdev;
unsigned int num_swdev, idx;
unsigned int pool;
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
for (pool = 0; pool < NGBDE_NUM_DMAPOOL_MAX; pool++) {
if (swdev[idx].inactive) {
ngbde_dmamem_free(&swdev[idx].dmapool[pool].dmamem);
}
}
}
}
/*!
* \brief Allocate DMA memory pools for all devices.
*
* \return Nothing.
*/
int
ngbde_dma_init(void)
{
int rv;
struct ngbde_dev_s *swdev;
unsigned int num_swdev, idx;
int dma_type = NGBDE_DMA_T_AUTO;
struct ngbde_dmapool_s *dmapool;
unsigned int pool;
/* Default DMA memory size per device */
if (dma_size < 0) {
dma_size = DMAPOOL_SIZE_DEFAULT;
}
/* Check for forced DMA allocation method */
if (dma_alloc) {
if (strcmp(dma_alloc, "kapi") == 0) {
dma_type = NGBDE_DMA_T_KAPI;
} else if (strcmp(dma_alloc, "pgmem") == 0) {
dma_type = NGBDE_DMA_T_PGMEM;
} else {
printk(KERN_WARNING "%s: Unknown DMA type: %s\n",
MOD_NAME, dma_alloc);
}
}
/* Number of DMA memory pools per device */
if ((unsigned int)dma_pools >= NGBDE_NUM_DMAPOOL_MAX) {
dma_pools = NUM_DMAPOOL_DEFAULT;
}
ngbde_swdev_get_all(&swdev, &num_swdev);
for (idx = 0; idx < num_swdev; idx++) {
/* Set DMA allocation parameters */
for (pool = 0; pool < NGBDE_NUM_DMAPOOL_MAX; pool++) {
dmapool = &swdev[idx].dmapool[pool];
dmapool->dmactrl.dev = swdev[idx].dma_dev;
dmapool->dmactrl.size = dma_size * ONE_MB;
dmapool->dmactrl.pref_type = dma_type;
dmapool->dmactrl.flags = GFP_KERNEL | GFP_DMA32;
}
/* Allocate DMA pools */
for (pool = 0; pool < dma_pools; pool++) {
dmapool = &swdev[idx].dmapool[pool];
rv = ngbde_dmamem_alloc(&dmapool->dmactrl, &dmapool->dmamem);
if (rv < 0) {
printk(KERN_WARNING "%s: Unable to allocate DMA pool %d %d\n",
MOD_NAME, idx, pool);
}
}
}
return 0;
}