162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2006 Oracle. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci#include <linux/kernel.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include "rds.h" 3662306a36Sopenharmony_ci#include "ib.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * Locking for IB rings. 4062306a36Sopenharmony_ci * We assume that allocation is always protected by a mutex 4162306a36Sopenharmony_ci * in the caller (this is a valid assumption for the current 4262306a36Sopenharmony_ci * implementation). 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * Freeing always happens in an interrupt, and hence only 4562306a36Sopenharmony_ci * races with allocations, but not with other free()s. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * The interaction between allocation and freeing is that 4862306a36Sopenharmony_ci * the alloc code has to determine the number of free entries. 4962306a36Sopenharmony_ci * To this end, we maintain two counters; an allocation counter 5062306a36Sopenharmony_ci * and a free counter. Both are allowed to run freely, and wrap 5162306a36Sopenharmony_ci * around. 5262306a36Sopenharmony_ci * The number of used entries is always (alloc_ctr - free_ctr) % NR. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * The current implementation makes free_ctr atomic. When the 5562306a36Sopenharmony_ci * caller finds an allocation fails, it should set an "alloc fail" 5662306a36Sopenharmony_ci * bit and retry the allocation. The "alloc fail" bit essentially tells 5762306a36Sopenharmony_ci * the CQ completion handlers to wake it up after freeing some 5862306a36Sopenharmony_ci * more entries. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * This only happens on shutdown. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ciDECLARE_WAIT_QUEUE_HEAD(rds_ib_ring_empty_wait); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_civoid rds_ib_ring_init(struct rds_ib_work_ring *ring, u32 nr) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci memset(ring, 0, sizeof(*ring)); 6962306a36Sopenharmony_ci ring->w_nr = nr; 7062306a36Sopenharmony_ci rdsdebug("ring %p nr %u\n", ring, ring->w_nr); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic inline u32 __rds_ib_ring_used(struct rds_ib_work_ring *ring) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci u32 diff; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* This assumes that atomic_t has at least as many bits as u32 */ 7862306a36Sopenharmony_ci diff = ring->w_alloc_ctr - (u32) atomic_read(&ring->w_free_ctr); 7962306a36Sopenharmony_ci BUG_ON(diff > ring->w_nr); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return diff; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_civoid rds_ib_ring_resize(struct rds_ib_work_ring *ring, u32 nr) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci /* We only ever get called from the connection setup code, 8762306a36Sopenharmony_ci * prior to creating the QP. */ 8862306a36Sopenharmony_ci BUG_ON(__rds_ib_ring_used(ring)); 8962306a36Sopenharmony_ci ring->w_nr = nr; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int __rds_ib_ring_empty(struct rds_ib_work_ring *ring) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci return __rds_ib_ring_used(ring) == 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciu32 rds_ib_ring_alloc(struct rds_ib_work_ring *ring, u32 val, u32 *pos) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci u32 ret = 0, avail; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci avail = ring->w_nr - __rds_ib_ring_used(ring); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci rdsdebug("ring %p val %u next %u free %u\n", ring, val, 10462306a36Sopenharmony_ci ring->w_alloc_ptr, avail); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (val && avail) { 10762306a36Sopenharmony_ci ret = min(val, avail); 10862306a36Sopenharmony_ci *pos = ring->w_alloc_ptr; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci ring->w_alloc_ptr = (ring->w_alloc_ptr + ret) % ring->w_nr; 11162306a36Sopenharmony_ci ring->w_alloc_ctr += ret; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return ret; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_civoid rds_ib_ring_free(struct rds_ib_work_ring *ring, u32 val) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci ring->w_free_ptr = (ring->w_free_ptr + val) % ring->w_nr; 12062306a36Sopenharmony_ci atomic_add(val, &ring->w_free_ctr); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (__rds_ib_ring_empty(ring) && 12362306a36Sopenharmony_ci waitqueue_active(&rds_ib_ring_empty_wait)) 12462306a36Sopenharmony_ci wake_up(&rds_ib_ring_empty_wait); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_civoid rds_ib_ring_unalloc(struct rds_ib_work_ring *ring, u32 val) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci ring->w_alloc_ptr = (ring->w_alloc_ptr - val) % ring->w_nr; 13062306a36Sopenharmony_ci ring->w_alloc_ctr -= val; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ciint rds_ib_ring_empty(struct rds_ib_work_ring *ring) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci return __rds_ib_ring_empty(ring); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciint rds_ib_ring_low(struct rds_ib_work_ring *ring) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci return __rds_ib_ring_used(ring) <= (ring->w_nr >> 1); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * returns the oldest allocated ring entry. This will be the next one 14562306a36Sopenharmony_ci * freed. This can't be called if there are none allocated. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ciu32 rds_ib_ring_oldest(struct rds_ib_work_ring *ring) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci return ring->w_free_ptr; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* 15362306a36Sopenharmony_ci * returns the number of completed work requests. 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ciu32 rds_ib_ring_completed(struct rds_ib_work_ring *ring, u32 wr_id, u32 oldest) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci u32 ret; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (oldest <= (unsigned long long)wr_id) 16162306a36Sopenharmony_ci ret = (unsigned long long)wr_id - oldest + 1; 16262306a36Sopenharmony_ci else 16362306a36Sopenharmony_ci ret = ring->w_nr - oldest + (unsigned long long)wr_id + 1; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci rdsdebug("ring %p ret %u wr_id %u oldest %u\n", ring, ret, 16662306a36Sopenharmony_ci wr_id, oldest); 16762306a36Sopenharmony_ci return ret; 16862306a36Sopenharmony_ci} 169