linux/drivers/infiniband/sw/rxe/rxe_queue.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
   2/*
   3 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
   4 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
   5 */
   6
   7#ifndef RXE_QUEUE_H
   8#define RXE_QUEUE_H
   9
  10/* for definition of shared struct rxe_queue_buf */
  11#include <uapi/rdma/rdma_user_rxe.h>
  12
  13/* implements a simple circular buffer that can optionally be
  14 * shared between user space and the kernel and can be resized
  15 * the requested element size is rounded up to a power of 2
  16 * and the number of elements in the buffer is also rounded
  17 * up to a power of 2. Since the queue is empty when the
  18 * producer and consumer indices match the maximum capacity
  19 * of the queue is one less than the number of element slots
  20 *
  21 * Notes:
  22 *   - Kernel space indices are always masked off to q->index_mask
  23 *   before storing so do not need to be checked on reads.
  24 *   - User space indices may be out of range and must be
  25 *   masked before use when read.
  26 *   - The kernel indices for shared queues must not be written
  27 *   by user space so a local copy is used and a shared copy is
  28 *   stored when the local copy changes.
  29 *   - By passing the type in the parameter list separate from q
  30 *   the compiler can eliminate the switch statement when the
  31 *   actual queue type is known when the function is called.
  32 *   In the performance path this is done. In less critical
  33 *   paths just q->type is passed.
  34 */
  35
  36/* type of queue */
  37enum queue_type {
  38        QUEUE_TYPE_KERNEL,
  39        QUEUE_TYPE_TO_USER,
  40        QUEUE_TYPE_FROM_USER,
  41};
  42
  43struct rxe_queue {
  44        struct rxe_dev          *rxe;
  45        struct rxe_queue_buf    *buf;
  46        struct rxe_mmap_info    *ip;
  47        size_t                  buf_size;
  48        size_t                  elem_size;
  49        unsigned int            log2_elem_size;
  50        u32                     index_mask;
  51        enum queue_type         type;
  52        /* private copy of index for shared queues between
  53         * kernel space and user space. Kernel reads and writes
  54         * this copy and then replicates to rxe_queue_buf
  55         * for read access by user space.
  56         */
  57        u32                     index;
  58};
  59
  60int do_mmap_info(struct rxe_dev *rxe, struct mminfo __user *outbuf,
  61                 struct ib_udata *udata, struct rxe_queue_buf *buf,
  62                 size_t buf_size, struct rxe_mmap_info **ip_p);
  63
  64void rxe_queue_reset(struct rxe_queue *q);
  65
  66struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe, int *num_elem,
  67                        unsigned int elem_size, enum queue_type type);
  68
  69int rxe_queue_resize(struct rxe_queue *q, unsigned int *num_elem_p,
  70                     unsigned int elem_size, struct ib_udata *udata,
  71                     struct mminfo __user *outbuf,
  72                     /* Protect producers while resizing queue */
  73                     spinlock_t *producer_lock,
  74                     /* Protect consumers while resizing queue */
  75                     spinlock_t *consumer_lock);
  76
  77void rxe_queue_cleanup(struct rxe_queue *queue);
  78
  79static inline int next_index(struct rxe_queue *q, int index)
  80{
  81        return (index + 1) & q->buf->index_mask;
  82}
  83
  84static inline int queue_empty(struct rxe_queue *q, enum queue_type type)
  85{
  86        u32 prod;
  87        u32 cons;
  88
  89        switch (type) {
  90        case QUEUE_TYPE_FROM_USER:
  91                /* protect user space index */
  92                prod = smp_load_acquire(&q->buf->producer_index);
  93                cons = q->index;
  94                break;
  95        case QUEUE_TYPE_TO_USER:
  96                prod = q->index;
  97                /* protect user space index */
  98                cons = smp_load_acquire(&q->buf->consumer_index);
  99                break;
 100        case QUEUE_TYPE_KERNEL:
 101                prod = q->buf->producer_index;
 102                cons = q->buf->consumer_index;
 103                break;
 104        }
 105
 106        return ((prod - cons) & q->index_mask) == 0;
 107}
 108
 109static inline int queue_full(struct rxe_queue *q, enum queue_type type)
 110{
 111        u32 prod;
 112        u32 cons;
 113
 114        switch (type) {
 115        case QUEUE_TYPE_FROM_USER:
 116                /* protect user space index */
 117                prod = smp_load_acquire(&q->buf->producer_index);
 118                cons = q->index;
 119                break;
 120        case QUEUE_TYPE_TO_USER:
 121                prod = q->index;
 122                /* protect user space index */
 123                cons = smp_load_acquire(&q->buf->consumer_index);
 124                break;
 125        case QUEUE_TYPE_KERNEL:
 126                prod = q->buf->producer_index;
 127                cons = q->buf->consumer_index;
 128                break;
 129        }
 130
 131        return ((prod + 1 - cons) & q->index_mask) == 0;
 132}
 133
 134static inline unsigned int queue_count(const struct rxe_queue *q,
 135                                        enum queue_type type)
 136{
 137        u32 prod;
 138        u32 cons;
 139
 140        switch (type) {
 141        case QUEUE_TYPE_FROM_USER:
 142                /* protect user space index */
 143                prod = smp_load_acquire(&q->buf->producer_index);
 144                cons = q->index;
 145                break;
 146        case QUEUE_TYPE_TO_USER:
 147                prod = q->index;
 148                /* protect user space index */
 149                cons = smp_load_acquire(&q->buf->consumer_index);
 150                break;
 151        case QUEUE_TYPE_KERNEL:
 152                prod = q->buf->producer_index;
 153                cons = q->buf->consumer_index;
 154                break;
 155        }
 156
 157        return (prod - cons) & q->index_mask;
 158}
 159
 160static inline void advance_producer(struct rxe_queue *q, enum queue_type type)
 161{
 162        u32 prod;
 163
 164        switch (type) {
 165        case QUEUE_TYPE_FROM_USER:
 166                pr_warn_once("Normally kernel should not write user space index\n");
 167                /* protect user space index */
 168                prod = smp_load_acquire(&q->buf->producer_index);
 169                prod = (prod + 1) & q->index_mask;
 170                /* same */
 171                smp_store_release(&q->buf->producer_index, prod);
 172                break;
 173        case QUEUE_TYPE_TO_USER:
 174                prod = q->index;
 175                q->index = (prod + 1) & q->index_mask;
 176                q->buf->producer_index = q->index;
 177                break;
 178        case QUEUE_TYPE_KERNEL:
 179                prod = q->buf->producer_index;
 180                q->buf->producer_index = (prod + 1) & q->index_mask;
 181                break;
 182        }
 183}
 184
 185static inline void advance_consumer(struct rxe_queue *q, enum queue_type type)
 186{
 187        u32 cons;
 188
 189        switch (type) {
 190        case QUEUE_TYPE_FROM_USER:
 191                cons = q->index;
 192                q->index = (cons + 1) & q->index_mask;
 193                q->buf->consumer_index = q->index;
 194                break;
 195        case QUEUE_TYPE_TO_USER:
 196                pr_warn_once("Normally kernel should not write user space index\n");
 197                /* protect user space index */
 198                cons = smp_load_acquire(&q->buf->consumer_index);
 199                cons = (cons + 1) & q->index_mask;
 200                /* same */
 201                smp_store_release(&q->buf->consumer_index, cons);
 202                break;
 203        case QUEUE_TYPE_KERNEL:
 204                cons = q->buf->consumer_index;
 205                q->buf->consumer_index = (cons + 1) & q->index_mask;
 206                break;
 207        }
 208}
 209
 210static inline void *producer_addr(struct rxe_queue *q, enum queue_type type)
 211{
 212        u32 prod;
 213
 214        switch (type) {
 215        case QUEUE_TYPE_FROM_USER:
 216                /* protect user space index */
 217                prod = smp_load_acquire(&q->buf->producer_index);
 218                prod &= q->index_mask;
 219                break;
 220        case QUEUE_TYPE_TO_USER:
 221                prod = q->index;
 222                break;
 223        case QUEUE_TYPE_KERNEL:
 224                prod = q->buf->producer_index;
 225                break;
 226        }
 227
 228        return q->buf->data + (prod << q->log2_elem_size);
 229}
 230
 231static inline void *consumer_addr(struct rxe_queue *q, enum queue_type type)
 232{
 233        u32 cons;
 234
 235        switch (type) {
 236        case QUEUE_TYPE_FROM_USER:
 237                cons = q->index;
 238                break;
 239        case QUEUE_TYPE_TO_USER:
 240                /* protect user space index */
 241                cons = smp_load_acquire(&q->buf->consumer_index);
 242                cons &= q->index_mask;
 243                break;
 244        case QUEUE_TYPE_KERNEL:
 245                cons = q->buf->consumer_index;
 246                break;
 247        }
 248
 249        return q->buf->data + (cons << q->log2_elem_size);
 250}
 251
 252static inline unsigned int producer_index(struct rxe_queue *q,
 253                                                enum queue_type type)
 254{
 255        u32 prod;
 256
 257        switch (type) {
 258        case QUEUE_TYPE_FROM_USER:
 259                /* protect user space index */
 260                prod = smp_load_acquire(&q->buf->producer_index);
 261                prod &= q->index_mask;
 262                break;
 263        case QUEUE_TYPE_TO_USER:
 264                prod = q->index;
 265                break;
 266        case QUEUE_TYPE_KERNEL:
 267                prod = q->buf->producer_index;
 268                break;
 269        }
 270
 271        return prod;
 272}
 273
 274static inline unsigned int consumer_index(struct rxe_queue *q,
 275                                                enum queue_type type)
 276{
 277        u32 cons;
 278
 279        switch (type) {
 280        case QUEUE_TYPE_FROM_USER:
 281                cons = q->index;
 282                break;
 283        case QUEUE_TYPE_TO_USER:
 284                /* protect user space index */
 285                cons = smp_load_acquire(&q->buf->consumer_index);
 286                cons &= q->index_mask;
 287                break;
 288        case QUEUE_TYPE_KERNEL:
 289                cons = q->buf->consumer_index;
 290                break;
 291        }
 292
 293        return cons;
 294}
 295
 296static inline void *addr_from_index(struct rxe_queue *q,
 297                                unsigned int index)
 298{
 299        return q->buf->data + ((index & q->index_mask)
 300                                << q->buf->log2_elem_size);
 301}
 302
 303static inline unsigned int index_from_addr(const struct rxe_queue *q,
 304                                const void *addr)
 305{
 306        return (((u8 *)addr - q->buf->data) >> q->log2_elem_size)
 307                                & q->index_mask;
 308}
 309
 310static inline void *queue_head(struct rxe_queue *q, enum queue_type type)
 311{
 312        return queue_empty(q, type) ? NULL : consumer_addr(q, type);
 313}
 314
 315#endif /* RXE_QUEUE_H */
 316