linux/drivers/staging/octeon/ethernet-mem.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * This file is based on code from OCTEON SDK by Cavium Networks.
   4 *
   5 * Copyright (c) 2003-2010 Cavium Networks
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/netdevice.h>
  10#include <linux/slab.h>
  11
  12#include <asm/octeon/octeon.h>
  13
  14#include "ethernet-mem.h"
  15#include "ethernet-defines.h"
  16
  17#include <asm/octeon/cvmx-fpa.h>
  18
  19/**
  20 * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs
  21 * @pool:     Pool to allocate an skbuff for
  22 * @size:     Size of the buffer needed for the pool
  23 * @elements: Number of buffers to allocate
  24 *
  25 * Returns the actual number of buffers allocated.
  26 */
  27static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
  28{
  29        int freed = elements;
  30
  31        while (freed) {
  32                struct sk_buff *skb = dev_alloc_skb(size + 256);
  33
  34                if (unlikely(!skb))
  35                        break;
  36                skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f));
  37                *(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
  38                cvmx_fpa_free(skb->data, pool, size / 128);
  39                freed--;
  40        }
  41        return elements - freed;
  42}
  43
  44/**
  45 * cvm_oct_free_hw_skbuff- free hardware pool skbuffs
  46 * @pool:     Pool to allocate an skbuff for
  47 * @size:     Size of the buffer needed for the pool
  48 * @elements: Number of buffers to allocate
  49 */
  50static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
  51{
  52        char *memory;
  53
  54        do {
  55                memory = cvmx_fpa_alloc(pool);
  56                if (memory) {
  57                        struct sk_buff *skb =
  58                            *(struct sk_buff **)(memory - sizeof(void *));
  59                        elements--;
  60                        dev_kfree_skb(skb);
  61                }
  62        } while (memory);
  63
  64        if (elements < 0)
  65                pr_warn("Freeing of pool %u had too many skbuffs (%d)\n",
  66                        pool, elements);
  67        else if (elements > 0)
  68                pr_warn("Freeing of pool %u is missing %d skbuffs\n",
  69                        pool, elements);
  70}
  71
  72/**
  73 * cvm_oct_fill_hw_memory - fill a hardware pool with memory.
  74 * @pool:     Pool to populate
  75 * @size:     Size of each buffer in the pool
  76 * @elements: Number of buffers to allocate
  77 *
  78 * Returns the actual number of buffers allocated.
  79 */
  80static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
  81{
  82        char *memory;
  83        char *fpa;
  84        int freed = elements;
  85
  86        while (freed) {
  87                /*
  88                 * FPA memory must be 128 byte aligned.  Since we are
  89                 * aligning we need to save the original pointer so we
  90                 * can feed it to kfree when the memory is returned to
  91                 * the kernel.
  92                 *
  93                 * We allocate an extra 256 bytes to allow for
  94                 * alignment and space for the original pointer saved
  95                 * just before the block.
  96                 */
  97                memory = kmalloc(size + 256, GFP_ATOMIC);
  98                if (unlikely(!memory)) {
  99                        pr_warn("Unable to allocate %u bytes for FPA pool %d\n",
 100                                elements * size, pool);
 101                        break;
 102                }
 103                fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL);
 104                *((char **)fpa - 1) = memory;
 105                cvmx_fpa_free(fpa, pool, 0);
 106                freed--;
 107        }
 108        return elements - freed;
 109}
 110
 111/**
 112 * cvm_oct_free_hw_memory - Free memory allocated by cvm_oct_fill_hw_memory
 113 * @pool:     FPA pool to free
 114 * @size:     Size of each buffer in the pool
 115 * @elements: Number of buffers that should be in the pool
 116 */
 117static void cvm_oct_free_hw_memory(int pool, int size, int elements)
 118{
 119        char *memory;
 120        char *fpa;
 121
 122        do {
 123                fpa = cvmx_fpa_alloc(pool);
 124                if (fpa) {
 125                        elements--;
 126                        fpa = (char *)phys_to_virt(cvmx_ptr_to_phys(fpa));
 127                        memory = *((char **)fpa - 1);
 128                        kfree(memory);
 129                }
 130        } while (fpa);
 131
 132        if (elements < 0)
 133                pr_warn("Freeing of pool %u had too many buffers (%d)\n",
 134                        pool, elements);
 135        else if (elements > 0)
 136                pr_warn("Warning: Freeing of pool %u is missing %d buffers\n",
 137                        pool, elements);
 138}
 139
 140int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
 141{
 142        int freed;
 143
 144        if (pool == CVMX_FPA_PACKET_POOL)
 145                freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
 146        else
 147                freed = cvm_oct_fill_hw_memory(pool, size, elements);
 148        return freed;
 149}
 150
 151void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
 152{
 153        if (pool == CVMX_FPA_PACKET_POOL)
 154                cvm_oct_free_hw_skbuff(pool, size, elements);
 155        else
 156                cvm_oct_free_hw_memory(pool, size, elements);
 157}
 158