root/drivers/misc/mei/dma-ring.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mei_dmam_dscr_alloc
  2. mei_dmam_dscr_free
  3. mei_dmam_ring_free
  4. mei_dmam_ring_alloc
  5. mei_dma_ring_is_allocated
  6. mei_dma_ring_ctrl
  7. mei_dma_ring_reset
  8. mei_dma_copy_from
  9. mei_dma_copy_to
  10. mei_dma_ring_read
  11. mei_dma_ring_hbuf_depth
  12. mei_dma_ring_empty_slots
  13. mei_dma_ring_write

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright(c) 2016-2018 Intel Corporation. All rights reserved.
   4  */
   5 #include <linux/dma-mapping.h>
   6 #include <linux/mei.h>
   7 
   8 #include "mei_dev.h"
   9 
  10 /**
  11  * mei_dmam_dscr_alloc() - allocate a managed coherent buffer
  12  *     for the dma descriptor
  13  * @dev: mei_device
  14  * @dscr: dma descriptor
  15  *
  16  * Return:
  17  * * 0       - on success or zero allocation request
  18  * * -EINVAL - if size is not power of 2
  19  * * -ENOMEM - of allocation has failed
  20  */
  21 static int mei_dmam_dscr_alloc(struct mei_device *dev,
  22                                struct mei_dma_dscr *dscr)
  23 {
  24         if (!dscr->size)
  25                 return 0;
  26 
  27         if (WARN_ON(!is_power_of_2(dscr->size)))
  28                 return -EINVAL;
  29 
  30         if (dscr->vaddr)
  31                 return 0;
  32 
  33         dscr->vaddr = dmam_alloc_coherent(dev->dev, dscr->size, &dscr->daddr,
  34                                           GFP_KERNEL);
  35         if (!dscr->vaddr)
  36                 return -ENOMEM;
  37 
  38         return 0;
  39 }
  40 
  41 /**
  42  * mei_dmam_dscr_free() - free a managed coherent buffer
  43  *     from the dma descriptor
  44  * @dev: mei_device
  45  * @dscr: dma descriptor
  46  */
  47 static void mei_dmam_dscr_free(struct mei_device *dev,
  48                                struct mei_dma_dscr *dscr)
  49 {
  50         if (!dscr->vaddr)
  51                 return;
  52 
  53         dmam_free_coherent(dev->dev, dscr->size, dscr->vaddr, dscr->daddr);
  54         dscr->vaddr = NULL;
  55 }
  56 
  57 /**
  58  * mei_dmam_ring_free() - free dma ring buffers
  59  * @dev: mei device
  60  */
  61 void mei_dmam_ring_free(struct mei_device *dev)
  62 {
  63         int i;
  64 
  65         for (i = 0; i < DMA_DSCR_NUM; i++)
  66                 mei_dmam_dscr_free(dev, &dev->dr_dscr[i]);
  67 }
  68 
  69 /**
  70  * mei_dmam_ring_alloc() - allocate dma ring buffers
  71  * @dev: mei device
  72  *
  73  * Return: -ENOMEM on allocation failure 0 otherwise
  74  */
  75 int mei_dmam_ring_alloc(struct mei_device *dev)
  76 {
  77         int i;
  78 
  79         for (i = 0; i < DMA_DSCR_NUM; i++)
  80                 if (mei_dmam_dscr_alloc(dev, &dev->dr_dscr[i]))
  81                         goto err;
  82 
  83         return 0;
  84 
  85 err:
  86         mei_dmam_ring_free(dev);
  87         return -ENOMEM;
  88 }
  89 
  90 /**
  91  * mei_dma_ring_is_allocated() - check if dma ring is allocated
  92  * @dev: mei device
  93  *
  94  * Return: true if dma ring is allocated
  95  */
  96 bool mei_dma_ring_is_allocated(struct mei_device *dev)
  97 {
  98         return !!dev->dr_dscr[DMA_DSCR_HOST].vaddr;
  99 }
 100 
 101 static inline
 102 struct hbm_dma_ring_ctrl *mei_dma_ring_ctrl(struct mei_device *dev)
 103 {
 104         return (struct hbm_dma_ring_ctrl *)dev->dr_dscr[DMA_DSCR_CTRL].vaddr;
 105 }
 106 
 107 /**
 108  * mei_dma_ring_reset() - reset the dma control block
 109  * @dev: mei device
 110  */
 111 void mei_dma_ring_reset(struct mei_device *dev)
 112 {
 113         struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev);
 114 
 115         if (!ctrl)
 116                 return;
 117 
 118         memset(ctrl, 0, sizeof(*ctrl));
 119 }
 120 
 121 /**
 122  * mei_dma_copy_from() - copy from dma ring into buffer
 123  * @dev: mei device
 124  * @buf: data buffer
 125  * @offset: offset in slots.
 126  * @n: number of slots to copy.
 127  */
 128 static size_t mei_dma_copy_from(struct mei_device *dev, unsigned char *buf,
 129                                 u32 offset, u32 n)
 130 {
 131         unsigned char *dbuf = dev->dr_dscr[DMA_DSCR_DEVICE].vaddr;
 132 
 133         size_t b_offset = offset << 2;
 134         size_t b_n = n << 2;
 135 
 136         memcpy(buf, dbuf + b_offset, b_n);
 137 
 138         return b_n;
 139 }
 140 
 141 /**
 142  * mei_dma_copy_to() - copy to a buffer to the dma ring
 143  * @dev: mei device
 144  * @buf: data buffer
 145  * @offset: offset in slots.
 146  * @n: number of slots to copy.
 147  */
 148 static size_t mei_dma_copy_to(struct mei_device *dev, unsigned char *buf,
 149                               u32 offset, u32 n)
 150 {
 151         unsigned char *hbuf = dev->dr_dscr[DMA_DSCR_HOST].vaddr;
 152 
 153         size_t b_offset = offset << 2;
 154         size_t b_n = n << 2;
 155 
 156         memcpy(hbuf + b_offset, buf, b_n);
 157 
 158         return b_n;
 159 }
 160 
 161 /**
 162  * mei_dma_ring_read() - read data from the ring
 163  * @dev: mei device
 164  * @buf: buffer to read into: may be NULL in case of droping the data.
 165  * @len: length to read.
 166  */
 167 void mei_dma_ring_read(struct mei_device *dev, unsigned char *buf, u32 len)
 168 {
 169         struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev);
 170         u32 dbuf_depth;
 171         u32 rd_idx, rem, slots;
 172 
 173         if (WARN_ON(!ctrl))
 174                 return;
 175 
 176         dev_dbg(dev->dev, "reading from dma %u bytes\n", len);
 177 
 178         if (!len)
 179                 return;
 180 
 181         dbuf_depth = dev->dr_dscr[DMA_DSCR_DEVICE].size >> 2;
 182         rd_idx = READ_ONCE(ctrl->dbuf_rd_idx) & (dbuf_depth - 1);
 183         slots = mei_data2slots(len);
 184 
 185         /* if buf is NULL we drop the packet by advancing the pointer.*/
 186         if (!buf)
 187                 goto out;
 188 
 189         if (rd_idx + slots > dbuf_depth) {
 190                 buf += mei_dma_copy_from(dev, buf, rd_idx, dbuf_depth - rd_idx);
 191                 rem = slots - (dbuf_depth - rd_idx);
 192                 rd_idx = 0;
 193         } else {
 194                 rem = slots;
 195         }
 196 
 197         mei_dma_copy_from(dev, buf, rd_idx, rem);
 198 out:
 199         WRITE_ONCE(ctrl->dbuf_rd_idx, ctrl->dbuf_rd_idx + slots);
 200 }
 201 
 202 static inline u32 mei_dma_ring_hbuf_depth(struct mei_device *dev)
 203 {
 204         return dev->dr_dscr[DMA_DSCR_HOST].size >> 2;
 205 }
 206 
 207 /**
 208  * mei_dma_ring_empty_slots() - calaculate number of empty slots in dma ring
 209  * @dev: mei_device
 210  *
 211  * Return: number of empty slots
 212  */
 213 u32 mei_dma_ring_empty_slots(struct mei_device *dev)
 214 {
 215         struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev);
 216         u32 wr_idx, rd_idx, hbuf_depth, empty;
 217 
 218         if (!mei_dma_ring_is_allocated(dev))
 219                 return 0;
 220 
 221         if (WARN_ON(!ctrl))
 222                 return 0;
 223 
 224         /* easier to work in slots */
 225         hbuf_depth = mei_dma_ring_hbuf_depth(dev);
 226         rd_idx = READ_ONCE(ctrl->hbuf_rd_idx);
 227         wr_idx = READ_ONCE(ctrl->hbuf_wr_idx);
 228 
 229         if (rd_idx > wr_idx)
 230                 empty = rd_idx - wr_idx;
 231         else
 232                 empty = hbuf_depth - (wr_idx - rd_idx);
 233 
 234         return empty;
 235 }
 236 
 237 /**
 238  * mei_dma_ring_write - write data to dma ring host buffer
 239  *
 240  * @dev: mei_device
 241  * @buf: data will be written
 242  * @len: data length
 243  */
 244 void mei_dma_ring_write(struct mei_device *dev, unsigned char *buf, u32 len)
 245 {
 246         struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev);
 247         u32 hbuf_depth;
 248         u32 wr_idx, rem, slots;
 249 
 250         if (WARN_ON(!ctrl))
 251                 return;
 252 
 253         dev_dbg(dev->dev, "writing to dma %u bytes\n", len);
 254         hbuf_depth = mei_dma_ring_hbuf_depth(dev);
 255         wr_idx = READ_ONCE(ctrl->hbuf_wr_idx) & (hbuf_depth - 1);
 256         slots = mei_data2slots(len);
 257 
 258         if (wr_idx + slots > hbuf_depth) {
 259                 buf += mei_dma_copy_to(dev, buf, wr_idx, hbuf_depth - wr_idx);
 260                 rem = slots - (hbuf_depth - wr_idx);
 261                 wr_idx = 0;
 262         } else {
 263                 rem = slots;
 264         }
 265 
 266         mei_dma_copy_to(dev, buf, wr_idx, rem);
 267 
 268         WRITE_ONCE(ctrl->hbuf_wr_idx, ctrl->hbuf_wr_idx + slots);
 269 }

/* [<][>][^][v][top][bottom][index][help] */