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