id_table.c revision 303975
138774Snsouch/* 238774Snsouch * Copyright (c) 2011-2013 Chelsio Communications. All rights reserved. 338774Snsouch * 438774Snsouch * This software is available to you under a choice of one of two 538774Snsouch * licenses. You may choose to be licensed under the terms of the GNU 638774Snsouch * General Public License (GPL) Version 2, available from the file 738774Snsouch * COPYING in the main directory of this source tree, or the 838774Snsouch * OpenIB.org BSD license below: 938774Snsouch * 1038774Snsouch * Redistribution and use in source and binary forms, with or 1138774Snsouch * without modification, are permitted provided that the following 1238774Snsouch * conditions are met: 1338774Snsouch * 1438774Snsouch * - Redistributions of source code must retain the above 1538774Snsouch * copyright notice, this list of conditions and the following 1638774Snsouch * disclaimer. 1738774Snsouch * 1838774Snsouch * - Redistributions in binary form must reproduce the above 1938774Snsouch * copyright notice, this list of conditions and the following 2038774Snsouch * disclaimer in the documentation and/or other materials 2138774Snsouch * provided with the distribution. 2238774Snsouch * 2338774Snsouch * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2438774Snsouch * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2538774Snsouch * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2640782Snsouch * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2738774Snsouch * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2838774Snsouch * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2938774Snsouch * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3038774Snsouch * SOFTWARE. 3138774Snsouch */ 3238774Snsouch#include <sys/cdefs.h> 3338774Snsouch__FBSDID("$FreeBSD: releng/11.0/sys/dev/cxgbe/iw_cxgbe/id_table.c 256694 2013-10-17 18:37:25Z np $"); 3438774Snsouch 3538774Snsouch#include "opt_inet.h" 3638774Snsouch 3738774Snsouch#ifdef TCP_OFFLOAD 3838774Snsouch#include <sys/libkern.h> 3938774Snsouch#include "iw_cxgbe.h" 4038774Snsouch 4138774Snsouch#define RANDOM_SKIP 16 4238774Snsouch 4338774Snsouch/* 4438774Snsouch * Trivial bitmap-based allocator. If the random flag is set, the 4538774Snsouch * allocator is designed to: 4638774Snsouch * - pseudo-randomize the id returned such that it is not trivially predictable. 4738774Snsouch * - avoid reuse of recently used id (at the expense of predictability) 4838774Snsouch */ 4938774Snsouchu32 c4iw_id_alloc(struct c4iw_id_table *alloc) 5038774Snsouch{ 5138774Snsouch unsigned long flags; 5238774Snsouch u32 obj; 5338774Snsouch 5438774Snsouch spin_lock_irqsave(&alloc->lock, flags); 5538774Snsouch 5638774Snsouch obj = find_next_zero_bit(alloc->table, alloc->max, alloc->last); 5738774Snsouch if (obj >= alloc->max) 5838774Snsouch obj = find_first_zero_bit(alloc->table, alloc->max); 5938774Snsouch 6038774Snsouch if (obj < alloc->max) { 6138774Snsouch if (alloc->flags & C4IW_ID_TABLE_F_RANDOM) 6240782Snsouch alloc->last += arc4random() % RANDOM_SKIP; 6340782Snsouch else 6438774Snsouch alloc->last = obj + 1; 6540782Snsouch if (alloc->last >= alloc->max) 6640782Snsouch alloc->last = 0; 6740782Snsouch set_bit(obj, alloc->table); 6840782Snsouch obj += alloc->start; 6940782Snsouch } else 7040782Snsouch obj = -1; 7138774Snsouch 7238774Snsouch spin_unlock_irqrestore(&alloc->lock, flags); 7338774Snsouch return obj; 7438774Snsouch} 7538774Snsouch 7638774Snsouchvoid c4iw_id_free(struct c4iw_id_table *alloc, u32 obj) 7738774Snsouch{ 7838774Snsouch unsigned long flags; 7938774Snsouch 8038774Snsouch obj -= alloc->start; 8138774Snsouch BUG_ON((int)obj < 0); 8238774Snsouch 8338774Snsouch spin_lock_irqsave(&alloc->lock, flags); 8438774Snsouch clear_bit(obj, alloc->table); 8538774Snsouch spin_unlock_irqrestore(&alloc->lock, flags); 8638774Snsouch} 8738774Snsouch 8838774Snsouchint c4iw_id_table_alloc(struct c4iw_id_table *alloc, u32 start, u32 num, 8938774Snsouch u32 reserved, u32 flags) 9038774Snsouch{ 9138774Snsouch int i; 9240782Snsouch 9340782Snsouch alloc->start = start; 9438774Snsouch alloc->flags = flags; 9538774Snsouch if (flags & C4IW_ID_TABLE_F_RANDOM) 9638774Snsouch alloc->last = arc4random() % RANDOM_SKIP; 9738774Snsouch else 9838774Snsouch alloc->last = 0; 9938774Snsouch alloc->max = num; 10038774Snsouch spin_lock_init(&alloc->lock); 10138774Snsouch alloc->table = kmalloc(BITS_TO_LONGS(num) * sizeof(long), 10238774Snsouch GFP_KERNEL); 10338774Snsouch if (!alloc->table) 10438774Snsouch return -ENOMEM; 10538774Snsouch 10640782Snsouch bitmap_zero(alloc->table, num); 10740782Snsouch if (!(alloc->flags & C4IW_ID_TABLE_F_EMPTY)) 10840782Snsouch for (i = 0; i < reserved; ++i) 10940782Snsouch set_bit(i, alloc->table); 11040782Snsouch 11140782Snsouch return 0; 11240782Snsouch} 11338774Snsouch 11438774Snsouchvoid c4iw_id_table_free(struct c4iw_id_table *alloc) 11540782Snsouch{ 11640782Snsouch kfree(alloc->table); 11740782Snsouch} 11840782Snsouch#endif 11940782Snsouch