Updated `README.md` with instructions for building/using the kernel module.
[xeon-phi-kernel-module] / micscif / micscif_va_node.c
CommitLineData
800f879a
AT
1/*
2 * Copyright 2010-2017 Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * Disclaimer: The codes contained in these modules may be specific to
14 * the Intel Software Development Platform codenamed Knights Ferry,
15 * and the Intel product codenamed Knights Corner, and are not backward
16 * compatible with other Intel products. Additionally, Intel will NOT
17 * support the codes or instruction set in future products.
18 *
19 * Intel offers no warranty of any kind regarding the code. This code is
20 * licensed on an "AS IS" basis and Intel is not obligated to provide
21 * any support, assistance, installation, training, or other services
22 * of any kind. Intel is also not obligated to provide any updates,
23 * enhancements or extensions. Intel specifically disclaims any warranty
24 * of merchantability, non-infringement, fitness for any particular
25 * purpose, and any other warranty.
26 *
27 * Further, Intel disclaims all liability of any kind, including but
28 * not limited to liability for infringement of any proprietary rights,
29 * relating to the use of the code, even if Intel is notified of the
30 * possibility of such liability. Except as expressly stated in an Intel
31 * license agreement provided with this code and agreed upon with Intel,
32 * no license, express or implied, by estoppel or otherwise, to any
33 * intellectual property rights is granted herein.
34 */
35
36/***************************************************************************\
37manage available nodes for VaGenAddress
38\***************************************************************************/
39#include "mic/micscif.h"
40
41/***************************************************************************\
42FUNCTION: va_node_init
43
44DESCRIPTION: constructor for allocator for GfxGenAddress
45\***************************************************************************/
46void va_node_init(struct va_node_allocator *node)
47{
48 node->pp_slab_directory = 0;
49 node->slab_shift = 7; /* 2^7 -> 128 nodes in the slab */
50 node->nodes_in_slab = 1<<node->slab_shift;
51 node->slab_mask = (node->nodes_in_slab-1);
52 node->num_slabs = 0;
53 node->num_free_slabs = 0;
54 node->free_list = invalid_va_node_index;
55}
56
57int va_node_is_valid(uint32_t index)
58{
59 return invalid_va_node_index != index;
60}
61
62/************************************************************************** *\
63FUNCTION: va_node_destroy
64
65DESCRIPTION: destructor for allocator for GfxGenAddress
66\************************************************************************** */
67void va_node_destroy(struct va_node_allocator *node)
68{
69 uint32_t i;
70 if (node->pp_slab_directory) {
71 for (i = 0; i < node->num_slabs; i++) {
72 kfree(node->pp_slab_directory[i]);
73 node->pp_slab_directory[i] = NULL;
74 }
75 kfree(node->pp_slab_directory);
76 node->pp_slab_directory = NULL;
77 }
78}
79
80/* ************************************************************************* *\
81FUNCTION: va_node_realloc
82
83DESCRIPTION: va_node_realloc to add more node arrays
84\* ************************************************************************* */
85static int va_node_realloc(struct va_node_allocator *node)
86{
87 uint32_t growSlabs = 2 * (node->num_slabs) + 1;
88 struct va_node **ppGrowDirectory =
89 kzalloc(sizeof(struct va_node *) * growSlabs, GFP_KERNEL);
90 uint32_t i;
91
92 if (!ppGrowDirectory)
93 return -ENOMEM;
94
95 if (node->num_slabs) {
96 for (i = 0; i < node->num_slabs; i++)
97 ppGrowDirectory[i] = node->pp_slab_directory[i];
98 kfree(node->pp_slab_directory);
99 node->pp_slab_directory = NULL;
100 }
101 node->pp_slab_directory = ppGrowDirectory;
102 node->num_free_slabs = growSlabs - node->num_slabs;
103 return 0;
104}
105
106/* ************************************************************************* *\
107FUNCTION: va_node_grow
108
109DESCRIPTION: add a node array
110\* ************************************************************************* */
111static int va_node_grow(struct va_node_allocator *node)
112{
113 struct va_node *pNewSlab;
114 uint32_t i, start;
115 int ret;
116
117 if (!node->num_free_slabs)
118 if ((ret = va_node_realloc(node)) < 0)
119 return ret;
120
121 pNewSlab = kzalloc(sizeof(struct va_node) *
122 node->nodes_in_slab, GFP_KERNEL);
123 if (pNewSlab)
124 node->pp_slab_directory[node->num_slabs] = pNewSlab;
125 else
126 return -ENOMEM;
127
128 /*--------------------------------------------------------
129 * add new nodes to free list
130 * slightly better than just calling free() for each index
131 */
132 start = node->num_slabs * node->nodes_in_slab;
133 for (i = 0; i < (node->nodes_in_slab-1); i++)
134 /* we could optimize this, but why bother? */
135 pNewSlab[i].next = start + i + 1;
136 /* add new allocations to start of list */
137 pNewSlab[node->nodes_in_slab-1].next = node->free_list;
138 node->free_list = start;
139 /*-------------------------------------------------------*/
140
141 /* update bookkeeping for array of arrays */
142 node->num_slabs++;
143 node->num_free_slabs--;
144 return 0;
145}
146
147/* ************************************************************************* *\
148FUNCTION: va_node_get
149
150DESCRIPTION: return a node reference from index
151\* ************************************************************************* */
152struct va_node *va_node_get(struct va_node_allocator *node, uint32_t index)
153{
154 uint32_t slabIndex = index >> node->slab_shift;
155 uint32_t nodeIndex = index & node->slab_mask;
156
157 return &node->pp_slab_directory[slabIndex][nodeIndex];
158}
159
160/* ************************************************************************* *\
161FUNCTION: va_node_alloc
162
163DESCRIPTION: return 0 on success with valid index in out_alloc or errno on failure.
164\* ************************************************************************* */
165int va_node_alloc(struct va_node_allocator *node, uint32_t *out_alloc)
166{
167 int ret;
168
169 if (!va_node_is_valid(node->free_list))
170 if ((ret = va_node_grow(node)) < 0)
171 return ret;
172 *out_alloc = node->free_list;
173 node->free_list = (va_node_get(node, *out_alloc))->next;
174 return 0;
175}
176
177/* ************************************************************************* *\
178FUNCTION: va_node_free
179
180DESCRIPTION: make a node available
181\* ************************************************************************* */
182void va_node_free(struct va_node_allocator *node, uint32_t index)
183{
184 struct va_node *tmp = va_node_get(node, index);
185 tmp->next = node->free_list;
186 node->free_list = index;
187}