Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
remote_node_table.c
Go to the documentation of this file.
1 /*
2  * This file is provided under a dual BSD/GPLv2 license. When using or
3  * redistributing this file, you may do so under either license.
4  *
5  * GPL LICENSE SUMMARY
6  *
7  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of version 2 of the GNU General Public License as
11  * published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21  * The full GNU General Public License is included in this distribution
22  * in the file called LICENSE.GPL.
23  *
24  * BSD LICENSE
25  *
26  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27  * All rights reserved.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions
31  * are met:
32  *
33  * * Redistributions of source code must retain the above copyright
34  * notice, this list of conditions and the following disclaimer.
35  * * Redistributions in binary form must reproduce the above copyright
36  * notice, this list of conditions and the following disclaimer in
37  * the documentation and/or other materials provided with the
38  * distribution.
39  * * Neither the name of Intel Corporation nor the names of its
40  * contributors may be used to endorse or promote products derived
41  * from this software without specific prior written permission.
42  *
43  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54  */
55 
62 #include "remote_node_table.h"
63 #include "remote_node_context.h"
64 
77 static u32 sci_remote_node_table_get_group_index(
78  struct sci_remote_node_table *remote_node_table,
79  u32 group_table_index)
80 {
81  u32 dword_index;
82  u32 *group_table;
83  u32 bit_index;
84 
85  group_table = remote_node_table->remote_node_groups[group_table_index];
86 
87  for (dword_index = 0; dword_index < remote_node_table->group_array_size; dword_index++) {
88  if (group_table[dword_index] != 0) {
89  for (bit_index = 0; bit_index < 32; bit_index++) {
90  if ((group_table[dword_index] & (1 << bit_index)) != 0) {
91  return (dword_index * 32) + bit_index;
92  }
93  }
94  }
95  }
96 
98 }
99 
111 static void sci_remote_node_table_clear_group_index(
112  struct sci_remote_node_table *remote_node_table,
113  u32 group_table_index,
114  u32 group_index)
115 {
116  u32 dword_index;
117  u32 bit_index;
118  u32 *group_table;
119 
120  BUG_ON(group_table_index >= SCU_STP_REMOTE_NODE_COUNT);
121  BUG_ON(group_index >= (u32)(remote_node_table->group_array_size * 32));
122 
123  dword_index = group_index / 32;
124  bit_index = group_index % 32;
125  group_table = remote_node_table->remote_node_groups[group_table_index];
126 
127  group_table[dword_index] = group_table[dword_index] & ~(1 << bit_index);
128 }
129 
141 static void sci_remote_node_table_set_group_index(
142  struct sci_remote_node_table *remote_node_table,
143  u32 group_table_index,
144  u32 group_index)
145 {
146  u32 dword_index;
147  u32 bit_index;
148  u32 *group_table;
149 
150  BUG_ON(group_table_index >= SCU_STP_REMOTE_NODE_COUNT);
151  BUG_ON(group_index >= (u32)(remote_node_table->group_array_size * 32));
152 
153  dword_index = group_index / 32;
154  bit_index = group_index % 32;
155  group_table = remote_node_table->remote_node_groups[group_table_index];
156 
157  group_table[dword_index] = group_table[dword_index] | (1 << bit_index);
158 }
159 
170 static void sci_remote_node_table_set_node_index(
171  struct sci_remote_node_table *remote_node_table,
172  u32 remote_node_index)
173 {
174  u32 dword_location;
175  u32 dword_remainder;
176  u32 slot_normalized;
177  u32 slot_position;
178 
179  BUG_ON(
181  <= (remote_node_index / SCU_STP_REMOTE_NODE_COUNT)
182  );
183 
184  dword_location = remote_node_index / SCIC_SDS_REMOTE_NODES_PER_DWORD;
185  dword_remainder = remote_node_index % SCIC_SDS_REMOTE_NODES_PER_DWORD;
186  slot_normalized = (dword_remainder / SCU_STP_REMOTE_NODE_COUNT) * sizeof(u32);
187  slot_position = remote_node_index % SCU_STP_REMOTE_NODE_COUNT;
188 
189  remote_node_table->available_remote_nodes[dword_location] |=
190  1 << (slot_normalized + slot_position);
191 }
192 
203 static void sci_remote_node_table_clear_node_index(
204  struct sci_remote_node_table *remote_node_table,
205  u32 remote_node_index)
206 {
207  u32 dword_location;
208  u32 dword_remainder;
209  u32 slot_position;
210  u32 slot_normalized;
211 
212  BUG_ON(
214  <= (remote_node_index / SCU_STP_REMOTE_NODE_COUNT)
215  );
216 
217  dword_location = remote_node_index / SCIC_SDS_REMOTE_NODES_PER_DWORD;
218  dword_remainder = remote_node_index % SCIC_SDS_REMOTE_NODES_PER_DWORD;
219  slot_normalized = (dword_remainder / SCU_STP_REMOTE_NODE_COUNT) * sizeof(u32);
220  slot_position = remote_node_index % SCU_STP_REMOTE_NODE_COUNT;
221 
222  remote_node_table->available_remote_nodes[dword_location] &=
223  ~(1 << (slot_normalized + slot_position));
224 }
225 
234 static void sci_remote_node_table_clear_group(
235  struct sci_remote_node_table *remote_node_table,
236  u32 group_index)
237 {
238  u32 dword_location;
239  u32 dword_remainder;
240  u32 dword_value;
241 
242  BUG_ON(
244  <= (group_index / SCU_STP_REMOTE_NODE_COUNT)
245  );
246 
247  dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
248  dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
249 
250  dword_value = remote_node_table->available_remote_nodes[dword_location];
251  dword_value &= ~(SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4));
252  remote_node_table->available_remote_nodes[dword_location] = dword_value;
253 }
254 
261 static void sci_remote_node_table_set_group(
262  struct sci_remote_node_table *remote_node_table,
263  u32 group_index)
264 {
265  u32 dword_location;
266  u32 dword_remainder;
267  u32 dword_value;
268 
269  BUG_ON(
271  <= (group_index / SCU_STP_REMOTE_NODE_COUNT)
272  );
273 
274  dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
275  dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
276 
277  dword_value = remote_node_table->available_remote_nodes[dword_location];
278  dword_value |= (SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4));
279  remote_node_table->available_remote_nodes[dword_location] = dword_value;
280 }
281 
291 static u8 sci_remote_node_table_get_group_value(
292  struct sci_remote_node_table *remote_node_table,
293  u32 group_index)
294 {
295  u32 dword_location;
296  u32 dword_remainder;
297  u32 dword_value;
298 
299  dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
300  dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;
301 
302  dword_value = remote_node_table->available_remote_nodes[dword_location];
303  dword_value &= (SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4));
304  dword_value = dword_value >> (dword_remainder * 4);
305 
306  return (u8)dword_value;
307 }
308 
317  struct sci_remote_node_table *remote_node_table,
318  u32 remote_node_entries)
319 {
320  u32 index;
321 
322  /*
323  * Initialize the raw data we could improve the speed by only initializing
324  * those entries that we are actually going to be used */
325  memset(
326  remote_node_table->available_remote_nodes,
327  0x00,
328  sizeof(remote_node_table->available_remote_nodes)
329  );
330 
331  memset(
332  remote_node_table->remote_node_groups,
333  0x00,
334  sizeof(remote_node_table->remote_node_groups)
335  );
336 
337  /* Initialize the available remote node sets */
338  remote_node_table->available_nodes_array_size = (u16)
339  (remote_node_entries / SCIC_SDS_REMOTE_NODES_PER_DWORD)
340  + ((remote_node_entries % SCIC_SDS_REMOTE_NODES_PER_DWORD) != 0);
341 
342 
343  /* Initialize each full DWORD to a FULL SET of remote nodes */
344  for (index = 0; index < remote_node_entries; index++) {
345  sci_remote_node_table_set_node_index(remote_node_table, index);
346  }
347 
348  remote_node_table->group_array_size = (u16)
349  (remote_node_entries / (SCU_STP_REMOTE_NODE_COUNT * 32))
350  + ((remote_node_entries % (SCU_STP_REMOTE_NODE_COUNT * 32)) != 0);
351 
352  for (index = 0; index < (remote_node_entries / SCU_STP_REMOTE_NODE_COUNT); index++) {
353  /*
354  * These are all guaranteed to be full slot values so fill them in the
355  * available sets of 3 remote nodes */
356  sci_remote_node_table_set_group_index(remote_node_table, 2, index);
357  }
358 
359  /* Now fill in any remainders that we may find */
360  if ((remote_node_entries % SCU_STP_REMOTE_NODE_COUNT) == 2) {
361  sci_remote_node_table_set_group_index(remote_node_table, 1, index);
362  } else if ((remote_node_entries % SCU_STP_REMOTE_NODE_COUNT) == 1) {
363  sci_remote_node_table_set_group_index(remote_node_table, 0, index);
364  }
365 }
366 
382 static u16 sci_remote_node_table_allocate_single_remote_node(
383  struct sci_remote_node_table *remote_node_table,
384  u32 group_table_index)
385 {
386  u8 index;
387  u8 group_value;
388  u32 group_index;
390 
391  group_index = sci_remote_node_table_get_group_index(
392  remote_node_table, group_table_index);
393 
394  /* We could not find an available slot in the table selector 0 */
395  if (group_index != SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX) {
396  group_value = sci_remote_node_table_get_group_value(
397  remote_node_table, group_index);
398 
399  for (index = 0; index < SCU_STP_REMOTE_NODE_COUNT; index++) {
400  if (((1 << index) & group_value) != 0) {
401  /* We have selected a bit now clear it */
402  remote_node_index = (u16)(group_index * SCU_STP_REMOTE_NODE_COUNT
403  + index);
404 
405  sci_remote_node_table_clear_group_index(
406  remote_node_table, group_table_index, group_index
407  );
408 
409  sci_remote_node_table_clear_node_index(
410  remote_node_table, remote_node_index
411  );
412 
413  if (group_table_index > 0) {
414  sci_remote_node_table_set_group_index(
415  remote_node_table, group_table_index - 1, group_index
416  );
417  }
418 
419  break;
420  }
421  }
422  }
423 
424  return remote_node_index;
425 }
426 
439 static u16 sci_remote_node_table_allocate_triple_remote_node(
440  struct sci_remote_node_table *remote_node_table,
441  u32 group_table_index)
442 {
443  u32 group_index;
445 
446  group_index = sci_remote_node_table_get_group_index(
447  remote_node_table, group_table_index);
448 
449  if (group_index != SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX) {
450  remote_node_index = (u16)group_index * SCU_STP_REMOTE_NODE_COUNT;
451 
452  sci_remote_node_table_clear_group_index(
453  remote_node_table, group_table_index, group_index
454  );
455 
456  sci_remote_node_table_clear_group(
457  remote_node_table, group_index
458  );
459  }
460 
461  return remote_node_index;
462 }
463 
477  struct sci_remote_node_table *remote_node_table,
478  u32 remote_node_count)
479 {
481 
482  if (remote_node_count == SCU_SSP_REMOTE_NODE_COUNT) {
483  remote_node_index =
484  sci_remote_node_table_allocate_single_remote_node(
485  remote_node_table, 0);
486 
487  if (remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
488  remote_node_index =
489  sci_remote_node_table_allocate_single_remote_node(
490  remote_node_table, 1);
491  }
492 
493  if (remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {
494  remote_node_index =
495  sci_remote_node_table_allocate_single_remote_node(
496  remote_node_table, 2);
497  }
498  } else if (remote_node_count == SCU_STP_REMOTE_NODE_COUNT) {
499  remote_node_index =
500  sci_remote_node_table_allocate_triple_remote_node(
501  remote_node_table, 2);
502  }
503 
504  return remote_node_index;
505 }
506 
514 static void sci_remote_node_table_release_single_remote_node(
515  struct sci_remote_node_table *remote_node_table,
516  u16 remote_node_index)
517 {
518  u32 group_index;
519  u8 group_value;
520 
521  group_index = remote_node_index / SCU_STP_REMOTE_NODE_COUNT;
522 
523  group_value = sci_remote_node_table_get_group_value(remote_node_table, group_index);
524 
525  /*
526  * Assert that we are not trying to add an entry to a slot that is already
527  * full. */
529 
530  if (group_value == 0x00) {
531  /*
532  * There are no entries in this slot so it must be added to the single
533  * slot table. */
534  sci_remote_node_table_set_group_index(remote_node_table, 0, group_index);
535  } else if ((group_value & (group_value - 1)) == 0) {
536  /*
537  * There is only one entry in this slot so it must be moved from the
538  * single slot table to the dual slot table */
539  sci_remote_node_table_clear_group_index(remote_node_table, 0, group_index);
540  sci_remote_node_table_set_group_index(remote_node_table, 1, group_index);
541  } else {
542  /*
543  * There are two entries in the slot so it must be moved from the dual
544  * slot table to the tripple slot table. */
545  sci_remote_node_table_clear_group_index(remote_node_table, 1, group_index);
546  sci_remote_node_table_set_group_index(remote_node_table, 2, group_index);
547  }
548 
549  sci_remote_node_table_set_node_index(remote_node_table, remote_node_index);
550 }
551 
560 static void sci_remote_node_table_release_triple_remote_node(
561  struct sci_remote_node_table *remote_node_table,
562  u16 remote_node_index)
563 {
564  u32 group_index;
565 
566  group_index = remote_node_index / SCU_STP_REMOTE_NODE_COUNT;
567 
568  sci_remote_node_table_set_group_index(
569  remote_node_table, 2, group_index
570  );
571 
572  sci_remote_node_table_set_group(remote_node_table, group_index);
573 }
574 
586  struct sci_remote_node_table *remote_node_table,
587  u32 remote_node_count,
588  u16 remote_node_index)
589 {
590  if (remote_node_count == SCU_SSP_REMOTE_NODE_COUNT) {
591  sci_remote_node_table_release_single_remote_node(
592  remote_node_table, remote_node_index);
593  } else if (remote_node_count == SCU_STP_REMOTE_NODE_COUNT) {
594  sci_remote_node_table_release_triple_remote_node(
595  remote_node_table, remote_node_index);
596  }
597 }
598