cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ib_ring.c (4915B)


      1/*
      2 * Copyright (c) 2006 Oracle.  All rights reserved.
      3 *
      4 * This software is available to you under a choice of one of two
      5 * licenses.  You may choose to be licensed under the terms of the GNU
      6 * General Public License (GPL) Version 2, available from the file
      7 * COPYING in the main directory of this source tree, or the
      8 * OpenIB.org BSD license below:
      9 *
     10 *     Redistribution and use in source and binary forms, with or
     11 *     without modification, are permitted provided that the following
     12 *     conditions are met:
     13 *
     14 *      - Redistributions of source code must retain the above
     15 *        copyright notice, this list of conditions and the following
     16 *        disclaimer.
     17 *
     18 *      - Redistributions in binary form must reproduce the above
     19 *        copyright notice, this list of conditions and the following
     20 *        disclaimer in the documentation and/or other materials
     21 *        provided with the distribution.
     22 *
     23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     30 * SOFTWARE.
     31 *
     32 */
     33#include <linux/kernel.h>
     34
     35#include "rds.h"
     36#include "ib.h"
     37
     38/*
     39 * Locking for IB rings.
     40 * We assume that allocation is always protected by a mutex
     41 * in the caller (this is a valid assumption for the current
     42 * implementation).
     43 *
     44 * Freeing always happens in an interrupt, and hence only
     45 * races with allocations, but not with other free()s.
     46 *
     47 * The interaction between allocation and freeing is that
     48 * the alloc code has to determine the number of free entries.
     49 * To this end, we maintain two counters; an allocation counter
     50 * and a free counter. Both are allowed to run freely, and wrap
     51 * around.
     52 * The number of used entries is always (alloc_ctr - free_ctr) % NR.
     53 *
     54 * The current implementation makes free_ctr atomic. When the
     55 * caller finds an allocation fails, it should set an "alloc fail"
     56 * bit and retry the allocation. The "alloc fail" bit essentially tells
     57 * the CQ completion handlers to wake it up after freeing some
     58 * more entries.
     59 */
     60
     61/*
     62 * This only happens on shutdown.
     63 */
     64DECLARE_WAIT_QUEUE_HEAD(rds_ib_ring_empty_wait);
     65
     66void rds_ib_ring_init(struct rds_ib_work_ring *ring, u32 nr)
     67{
     68	memset(ring, 0, sizeof(*ring));
     69	ring->w_nr = nr;
     70	rdsdebug("ring %p nr %u\n", ring, ring->w_nr);
     71}
     72
     73static inline u32 __rds_ib_ring_used(struct rds_ib_work_ring *ring)
     74{
     75	u32 diff;
     76
     77	/* This assumes that atomic_t has at least as many bits as u32 */
     78	diff = ring->w_alloc_ctr - (u32) atomic_read(&ring->w_free_ctr);
     79	BUG_ON(diff > ring->w_nr);
     80
     81	return diff;
     82}
     83
     84void rds_ib_ring_resize(struct rds_ib_work_ring *ring, u32 nr)
     85{
     86	/* We only ever get called from the connection setup code,
     87	 * prior to creating the QP. */
     88	BUG_ON(__rds_ib_ring_used(ring));
     89	ring->w_nr = nr;
     90}
     91
     92static int __rds_ib_ring_empty(struct rds_ib_work_ring *ring)
     93{
     94	return __rds_ib_ring_used(ring) == 0;
     95}
     96
     97u32 rds_ib_ring_alloc(struct rds_ib_work_ring *ring, u32 val, u32 *pos)
     98{
     99	u32 ret = 0, avail;
    100
    101	avail = ring->w_nr - __rds_ib_ring_used(ring);
    102
    103	rdsdebug("ring %p val %u next %u free %u\n", ring, val,
    104		 ring->w_alloc_ptr, avail);
    105
    106	if (val && avail) {
    107		ret = min(val, avail);
    108		*pos = ring->w_alloc_ptr;
    109
    110		ring->w_alloc_ptr = (ring->w_alloc_ptr + ret) % ring->w_nr;
    111		ring->w_alloc_ctr += ret;
    112	}
    113
    114	return ret;
    115}
    116
    117void rds_ib_ring_free(struct rds_ib_work_ring *ring, u32 val)
    118{
    119	ring->w_free_ptr = (ring->w_free_ptr + val) % ring->w_nr;
    120	atomic_add(val, &ring->w_free_ctr);
    121
    122	if (__rds_ib_ring_empty(ring) &&
    123	    waitqueue_active(&rds_ib_ring_empty_wait))
    124		wake_up(&rds_ib_ring_empty_wait);
    125}
    126
    127void rds_ib_ring_unalloc(struct rds_ib_work_ring *ring, u32 val)
    128{
    129	ring->w_alloc_ptr = (ring->w_alloc_ptr - val) % ring->w_nr;
    130	ring->w_alloc_ctr -= val;
    131}
    132
    133int rds_ib_ring_empty(struct rds_ib_work_ring *ring)
    134{
    135	return __rds_ib_ring_empty(ring);
    136}
    137
    138int rds_ib_ring_low(struct rds_ib_work_ring *ring)
    139{
    140	return __rds_ib_ring_used(ring) <= (ring->w_nr >> 1);
    141}
    142
    143/*
    144 * returns the oldest allocated ring entry.  This will be the next one
    145 * freed.  This can't be called if there are none allocated.
    146 */
    147u32 rds_ib_ring_oldest(struct rds_ib_work_ring *ring)
    148{
    149	return ring->w_free_ptr;
    150}
    151
    152/*
    153 * returns the number of completed work requests.
    154 */
    155
    156u32 rds_ib_ring_completed(struct rds_ib_work_ring *ring, u32 wr_id, u32 oldest)
    157{
    158	u32 ret;
    159
    160	if (oldest <= (unsigned long long)wr_id)
    161		ret = (unsigned long long)wr_id - oldest + 1;
    162	else
    163		ret = ring->w_nr - oldest + (unsigned long long)wr_id + 1;
    164
    165	rdsdebug("ring %p ret %u wr_id %u oldest %u\n", ring, ret,
    166		 wr_id, oldest);
    167	return ret;
    168}