1*29c8d9ebSAdit Ranadive /* 2*29c8d9ebSAdit Ranadive * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. 3*29c8d9ebSAdit Ranadive * 4*29c8d9ebSAdit Ranadive * This program is free software; you can redistribute it and/or 5*29c8d9ebSAdit Ranadive * modify it under the terms of EITHER the GNU General Public License 6*29c8d9ebSAdit Ranadive * version 2 as published by the Free Software Foundation or the BSD 7*29c8d9ebSAdit Ranadive * 2-Clause License. This program is distributed in the hope that it 8*29c8d9ebSAdit Ranadive * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED 9*29c8d9ebSAdit Ranadive * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 10*29c8d9ebSAdit Ranadive * See the GNU General Public License version 2 for more details at 11*29c8d9ebSAdit Ranadive * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. 12*29c8d9ebSAdit Ranadive * 13*29c8d9ebSAdit Ranadive * You should have received a copy of the GNU General Public License 14*29c8d9ebSAdit Ranadive * along with this program available in the file COPYING in the main 15*29c8d9ebSAdit Ranadive * directory of this source tree. 16*29c8d9ebSAdit Ranadive * 17*29c8d9ebSAdit Ranadive * The BSD 2-Clause License 18*29c8d9ebSAdit Ranadive * 19*29c8d9ebSAdit Ranadive * Redistribution and use in source and binary forms, with or 20*29c8d9ebSAdit Ranadive * without modification, are permitted provided that the following 21*29c8d9ebSAdit Ranadive * conditions are met: 22*29c8d9ebSAdit Ranadive * 23*29c8d9ebSAdit Ranadive * - Redistributions of source code must retain the above 24*29c8d9ebSAdit Ranadive * copyright notice, this list of conditions and the following 25*29c8d9ebSAdit Ranadive * disclaimer. 26*29c8d9ebSAdit Ranadive * 27*29c8d9ebSAdit Ranadive * - Redistributions in binary form must reproduce the above 28*29c8d9ebSAdit Ranadive * copyright notice, this list of conditions and the following 29*29c8d9ebSAdit Ranadive * disclaimer in the documentation and/or other materials 30*29c8d9ebSAdit Ranadive * provided with the distribution. 31*29c8d9ebSAdit Ranadive * 32*29c8d9ebSAdit Ranadive * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33*29c8d9ebSAdit Ranadive * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34*29c8d9ebSAdit Ranadive * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 35*29c8d9ebSAdit Ranadive * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 36*29c8d9ebSAdit Ranadive * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 37*29c8d9ebSAdit Ranadive * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 38*29c8d9ebSAdit Ranadive * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 39*29c8d9ebSAdit Ranadive * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40*29c8d9ebSAdit Ranadive * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 41*29c8d9ebSAdit Ranadive * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 42*29c8d9ebSAdit Ranadive * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 43*29c8d9ebSAdit Ranadive * OF THE POSSIBILITY OF SUCH DAMAGE. 44*29c8d9ebSAdit Ranadive */ 45*29c8d9ebSAdit Ranadive 46*29c8d9ebSAdit Ranadive #ifndef __PVRDMA_RING_H__ 47*29c8d9ebSAdit Ranadive #define __PVRDMA_RING_H__ 48*29c8d9ebSAdit Ranadive 49*29c8d9ebSAdit Ranadive #include <linux/types.h> 50*29c8d9ebSAdit Ranadive 51*29c8d9ebSAdit Ranadive #define PVRDMA_INVALID_IDX -1 /* Invalid index. */ 52*29c8d9ebSAdit Ranadive 53*29c8d9ebSAdit Ranadive struct pvrdma_ring { 54*29c8d9ebSAdit Ranadive atomic_t prod_tail; /* Producer tail. */ 55*29c8d9ebSAdit Ranadive atomic_t cons_head; /* Consumer head. */ 56*29c8d9ebSAdit Ranadive }; 57*29c8d9ebSAdit Ranadive 58*29c8d9ebSAdit Ranadive struct pvrdma_ring_state { 59*29c8d9ebSAdit Ranadive struct pvrdma_ring tx; /* Tx ring. */ 60*29c8d9ebSAdit Ranadive struct pvrdma_ring rx; /* Rx ring. */ 61*29c8d9ebSAdit Ranadive }; 62*29c8d9ebSAdit Ranadive 63*29c8d9ebSAdit Ranadive static inline int pvrdma_idx_valid(__u32 idx, __u32 max_elems) 64*29c8d9ebSAdit Ranadive { 65*29c8d9ebSAdit Ranadive /* Generates fewer instructions than a less-than. */ 66*29c8d9ebSAdit Ranadive return (idx & ~((max_elems << 1) - 1)) == 0; 67*29c8d9ebSAdit Ranadive } 68*29c8d9ebSAdit Ranadive 69*29c8d9ebSAdit Ranadive static inline __s32 pvrdma_idx(atomic_t *var, __u32 max_elems) 70*29c8d9ebSAdit Ranadive { 71*29c8d9ebSAdit Ranadive const unsigned int idx = atomic_read(var); 72*29c8d9ebSAdit Ranadive 73*29c8d9ebSAdit Ranadive if (pvrdma_idx_valid(idx, max_elems)) 74*29c8d9ebSAdit Ranadive return idx & (max_elems - 1); 75*29c8d9ebSAdit Ranadive return PVRDMA_INVALID_IDX; 76*29c8d9ebSAdit Ranadive } 77*29c8d9ebSAdit Ranadive 78*29c8d9ebSAdit Ranadive static inline void pvrdma_idx_ring_inc(atomic_t *var, __u32 max_elems) 79*29c8d9ebSAdit Ranadive { 80*29c8d9ebSAdit Ranadive __u32 idx = atomic_read(var) + 1; /* Increment. */ 81*29c8d9ebSAdit Ranadive 82*29c8d9ebSAdit Ranadive idx &= (max_elems << 1) - 1; /* Modulo size, flip gen. */ 83*29c8d9ebSAdit Ranadive atomic_set(var, idx); 84*29c8d9ebSAdit Ranadive } 85*29c8d9ebSAdit Ranadive 86*29c8d9ebSAdit Ranadive static inline __s32 pvrdma_idx_ring_has_space(const struct pvrdma_ring *r, 87*29c8d9ebSAdit Ranadive __u32 max_elems, __u32 *out_tail) 88*29c8d9ebSAdit Ranadive { 89*29c8d9ebSAdit Ranadive const __u32 tail = atomic_read(&r->prod_tail); 90*29c8d9ebSAdit Ranadive const __u32 head = atomic_read(&r->cons_head); 91*29c8d9ebSAdit Ranadive 92*29c8d9ebSAdit Ranadive if (pvrdma_idx_valid(tail, max_elems) && 93*29c8d9ebSAdit Ranadive pvrdma_idx_valid(head, max_elems)) { 94*29c8d9ebSAdit Ranadive *out_tail = tail & (max_elems - 1); 95*29c8d9ebSAdit Ranadive return tail != (head ^ max_elems); 96*29c8d9ebSAdit Ranadive } 97*29c8d9ebSAdit Ranadive return PVRDMA_INVALID_IDX; 98*29c8d9ebSAdit Ranadive } 99*29c8d9ebSAdit Ranadive 100*29c8d9ebSAdit Ranadive static inline __s32 pvrdma_idx_ring_has_data(const struct pvrdma_ring *r, 101*29c8d9ebSAdit Ranadive __u32 max_elems, __u32 *out_head) 102*29c8d9ebSAdit Ranadive { 103*29c8d9ebSAdit Ranadive const __u32 tail = atomic_read(&r->prod_tail); 104*29c8d9ebSAdit Ranadive const __u32 head = atomic_read(&r->cons_head); 105*29c8d9ebSAdit Ranadive 106*29c8d9ebSAdit Ranadive if (pvrdma_idx_valid(tail, max_elems) && 107*29c8d9ebSAdit Ranadive pvrdma_idx_valid(head, max_elems)) { 108*29c8d9ebSAdit Ranadive *out_head = head & (max_elems - 1); 109*29c8d9ebSAdit Ranadive return tail != head; 110*29c8d9ebSAdit Ranadive } 111*29c8d9ebSAdit Ranadive return PVRDMA_INVALID_IDX; 112*29c8d9ebSAdit Ranadive } 113*29c8d9ebSAdit Ranadive 114*29c8d9ebSAdit Ranadive #endif /* __PVRDMA_RING_H__ */ 115