brintos

brintos / linux-shallow public Read only

0
0
Text · 20.5 KiB · 1bcaf52 Raw
599 lines · c
1/*2 * This file is provided under a dual BSD/GPLv2 license.  When using or3 * redistributing this file, you may do so under either license.4 *5 * GPL LICENSE SUMMARY6 *7 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.8 *9 * This program is free software; you can redistribute it and/or modify10 * it under the terms of version 2 of the GNU General Public License as11 * published by the Free Software Foundation.12 *13 * This program is distributed in the hope that it will be useful, but14 * WITHOUT ANY WARRANTY; without even the implied warranty of15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU16 * General Public License for more details.17 *18 * You should have received a copy of the GNU General Public License19 * along with this program; if not, write to the Free Software20 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.21 * The full GNU General Public License is included in this distribution22 * in the file called LICENSE.GPL.23 *24 * BSD LICENSE25 *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 without30 * modification, are permitted provided that the following conditions31 * are met:32 *33 *   * Redistributions of source code must retain the above copyright34 *     notice, this list of conditions and the following disclaimer.35 *   * Redistributions in binary form must reproduce the above copyright36 *     notice, this list of conditions and the following disclaimer in37 *     the documentation and/or other materials provided with the38 *     distribution.39 *   * Neither the name of Intel Corporation nor the names of its40 *     contributors may be used to endorse or promote products derived41 *     from this software without specific prior written permission.42 *43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.54 */55 56/*57 * This file contains the implementation of the SCIC_SDS_REMOTE_NODE_TABLE58 *    public, protected, and private methods.59 */60#include "remote_node_table.h"61#include "remote_node_context.h"62 63/**64 * sci_remote_node_table_get_group_index()65 * @remote_node_table: This is the remote node index table from which the66 *    selection will be made.67 * @group_table_index: This is the index to the group table from which to68 *    search for an available selection.69 *70 * This routine will find the bit position in absolute bit terms of the next 3271 * + bit position.  If there are available bits in the first u32 then it is72 * just bit position. u32 This is the absolute bit position for an available73 * group.74 */75static u32 sci_remote_node_table_get_group_index(76	struct sci_remote_node_table *remote_node_table,77	u32 group_table_index)78{79	u32 dword_index;80	u32 *group_table;81	u32 bit_index;82 83	group_table = remote_node_table->remote_node_groups[group_table_index];84 85	for (dword_index = 0; dword_index < remote_node_table->group_array_size; dword_index++) {86		if (group_table[dword_index] != 0) {87			for (bit_index = 0; bit_index < 32; bit_index++) {88				if ((group_table[dword_index] & (1 << bit_index)) != 0) {89					return (dword_index * 32) + bit_index;90				}91			}92		}93	}94 95	return SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX;96}97 98/**99 * sci_remote_node_table_clear_group_index()100 * @remote_node_table: This the remote node table in which to clear the101 *    selector.102 * @group_table_index: This is the remote node selector in which the change will be103 *    made.104 * @group_index: This is the bit index in the table to be modified.105 *106 * This method will clear the group index entry in the specified group index107 * table. none108 */109static void sci_remote_node_table_clear_group_index(110	struct sci_remote_node_table *remote_node_table,111	u32 group_table_index,112	u32 group_index)113{114	u32 dword_index;115	u32 bit_index;116	u32 *group_table;117 118	BUG_ON(group_table_index >= SCU_STP_REMOTE_NODE_COUNT);119	BUG_ON(group_index >= (u32)(remote_node_table->group_array_size * 32));120 121	dword_index = group_index / 32;122	bit_index   = group_index % 32;123	group_table = remote_node_table->remote_node_groups[group_table_index];124 125	group_table[dword_index] = group_table[dword_index] & ~(1 << bit_index);126}127 128/**129 * sci_remote_node_table_set_group_index()130 * @remote_node_table: This the remote node table in which to set the131 *    selector.132 * @group_table_index: This is the remote node selector in which the change133 *    will be made.134 * @group_index: This is the bit position in the table to be modified.135 *136 * This method will set the group index bit entry in the specified gropu index137 * table. none138 */139static void sci_remote_node_table_set_group_index(140	struct sci_remote_node_table *remote_node_table,141	u32 group_table_index,142	u32 group_index)143{144	u32 dword_index;145	u32 bit_index;146	u32 *group_table;147 148	BUG_ON(group_table_index >= SCU_STP_REMOTE_NODE_COUNT);149	BUG_ON(group_index >= (u32)(remote_node_table->group_array_size * 32));150 151	dword_index = group_index / 32;152	bit_index   = group_index % 32;153	group_table = remote_node_table->remote_node_groups[group_table_index];154 155	group_table[dword_index] = group_table[dword_index] | (1 << bit_index);156}157 158/**159 * sci_remote_node_table_set_node_index()160 * @remote_node_table: This is the remote node table in which to modify161 *    the remote node availability.162 * @remote_node_index: This is the remote node index that is being returned to163 *    the table.164 *165 * This method will set the remote to available in the remote node allocation166 * table. none167 */168static void sci_remote_node_table_set_node_index(169	struct sci_remote_node_table *remote_node_table,170	u32 remote_node_index)171{172	u32 dword_location;173	u32 dword_remainder;174	u32 slot_normalized;175	u32 slot_position;176 177	BUG_ON(178		(remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD)179		<= (remote_node_index / SCU_STP_REMOTE_NODE_COUNT)180		);181 182	dword_location  = remote_node_index / SCIC_SDS_REMOTE_NODES_PER_DWORD;183	dword_remainder = remote_node_index % SCIC_SDS_REMOTE_NODES_PER_DWORD;184	slot_normalized = (dword_remainder / SCU_STP_REMOTE_NODE_COUNT) * sizeof(u32);185	slot_position   = remote_node_index % SCU_STP_REMOTE_NODE_COUNT;186 187	remote_node_table->available_remote_nodes[dword_location] |=188		1 << (slot_normalized + slot_position);189}190 191/**192 * sci_remote_node_table_clear_node_index()193 * @remote_node_table: This is the remote node table from which to clear194 *    the available remote node bit.195 * @remote_node_index: This is the remote node index which is to be cleared196 *    from the table.197 *198 * This method clears the remote node index from the table of available remote199 * nodes. none200 */201static void sci_remote_node_table_clear_node_index(202	struct sci_remote_node_table *remote_node_table,203	u32 remote_node_index)204{205	u32 dword_location;206	u32 dword_remainder;207	u32 slot_position;208	u32 slot_normalized;209 210	BUG_ON(211		(remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD)212		<= (remote_node_index / SCU_STP_REMOTE_NODE_COUNT)213		);214 215	dword_location  = remote_node_index / SCIC_SDS_REMOTE_NODES_PER_DWORD;216	dword_remainder = remote_node_index % SCIC_SDS_REMOTE_NODES_PER_DWORD;217	slot_normalized = (dword_remainder / SCU_STP_REMOTE_NODE_COUNT) * sizeof(u32);218	slot_position   = remote_node_index % SCU_STP_REMOTE_NODE_COUNT;219 220	remote_node_table->available_remote_nodes[dword_location] &=221		~(1 << (slot_normalized + slot_position));222}223 224/**225 * sci_remote_node_table_clear_group()226 * @remote_node_table: The remote node table from which the slot will be227 *    cleared.228 * @group_index: The index for the slot that is to be cleared.229 *230 * This method clears the entire table slot at the specified slot index. none231 */232static void sci_remote_node_table_clear_group(233	struct sci_remote_node_table *remote_node_table,234	u32 group_index)235{236	u32 dword_location;237	u32 dword_remainder;238	u32 dword_value;239 240	BUG_ON(241		(remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD)242		<= (group_index / SCU_STP_REMOTE_NODE_COUNT)243		);244 245	dword_location  = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;246	dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;247 248	dword_value = remote_node_table->available_remote_nodes[dword_location];249	dword_value &= ~(SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4));250	remote_node_table->available_remote_nodes[dword_location] = dword_value;251}252 253/*254 * sci_remote_node_table_set_group()255 *256 * THis method sets an entire remote node group in the remote node table.257 */258static void sci_remote_node_table_set_group(259	struct sci_remote_node_table *remote_node_table,260	u32 group_index)261{262	u32 dword_location;263	u32 dword_remainder;264	u32 dword_value;265 266	BUG_ON(267		(remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD)268		<= (group_index / SCU_STP_REMOTE_NODE_COUNT)269		);270 271	dword_location  = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;272	dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;273 274	dword_value = remote_node_table->available_remote_nodes[dword_location];275	dword_value |= (SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4));276	remote_node_table->available_remote_nodes[dword_location] = dword_value;277}278 279/**280 * sci_remote_node_table_get_group_value()281 * @remote_node_table: This is the remote node table that for which the group282 *    value is to be returned.283 * @group_index: This is the group index to use to find the group value.284 *285 * This method will return the group value for the specified group index. The286 * bit values at the specified remote node group index.287 */288static u8 sci_remote_node_table_get_group_value(289	struct sci_remote_node_table *remote_node_table,290	u32 group_index)291{292	u32 dword_location;293	u32 dword_remainder;294	u32 dword_value;295 296	dword_location  = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;297	dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD;298 299	dword_value = remote_node_table->available_remote_nodes[dword_location];300	dword_value &= (SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4));301	dword_value = dword_value >> (dword_remainder * 4);302 303	return (u8)dword_value;304}305 306/**307 * sci_remote_node_table_initialize()308 * @remote_node_table: The remote that which is to be initialized.309 * @remote_node_entries: The number of entries to put in the table.310 *311 * This method will initialize the remote node table for use. none312 */313void sci_remote_node_table_initialize(314	struct sci_remote_node_table *remote_node_table,315	u32 remote_node_entries)316{317	u32 index;318 319	/*320	 * Initialize the raw data we could improve the speed by only initializing321	 * those entries that we are actually going to be used */322	memset(323		remote_node_table->available_remote_nodes,324		0x00,325		sizeof(remote_node_table->available_remote_nodes)326		);327 328	memset(329		remote_node_table->remote_node_groups,330		0x00,331		sizeof(remote_node_table->remote_node_groups)332		);333 334	/* Initialize the available remote node sets */335	remote_node_table->available_nodes_array_size = (u16)336							(remote_node_entries / SCIC_SDS_REMOTE_NODES_PER_DWORD)337							+ ((remote_node_entries % SCIC_SDS_REMOTE_NODES_PER_DWORD) != 0);338 339 340	/* Initialize each full DWORD to a FULL SET of remote nodes */341	for (index = 0; index < remote_node_entries; index++) {342		sci_remote_node_table_set_node_index(remote_node_table, index);343	}344 345	remote_node_table->group_array_size = (u16)346					      (remote_node_entries / (SCU_STP_REMOTE_NODE_COUNT * 32))347					      + ((remote_node_entries % (SCU_STP_REMOTE_NODE_COUNT * 32)) != 0);348 349	for (index = 0; index < (remote_node_entries / SCU_STP_REMOTE_NODE_COUNT); index++) {350		/*351		 * These are all guaranteed to be full slot values so fill them in the352		 * available sets of 3 remote nodes */353		sci_remote_node_table_set_group_index(remote_node_table, 2, index);354	}355 356	/* Now fill in any remainders that we may find */357	if ((remote_node_entries % SCU_STP_REMOTE_NODE_COUNT) == 2) {358		sci_remote_node_table_set_group_index(remote_node_table, 1, index);359	} else if ((remote_node_entries % SCU_STP_REMOTE_NODE_COUNT) == 1) {360		sci_remote_node_table_set_group_index(remote_node_table, 0, index);361	}362}363 364/**365 * sci_remote_node_table_allocate_single_remote_node()366 * @remote_node_table: The remote node table from which to allocate a367 *    remote node.368 * @group_table_index: The group index that is to be used for the search.369 *370 * This method will allocate a single RNi from the remote node table.  The371 * table index will determine from which remote node group table to search.372 * This search may fail and another group node table can be specified.  The373 * function is designed to allow a serach of the available single remote node374 * group up to the triple remote node group.  If an entry is found in the375 * specified table the remote node is removed and the remote node groups are376 * updated. The RNi value or an invalid remote node context if an RNi can not377 * be found.378 */379static u16 sci_remote_node_table_allocate_single_remote_node(380	struct sci_remote_node_table *remote_node_table,381	u32 group_table_index)382{383	u8 index;384	u8 group_value;385	u32 group_index;386	u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX;387 388	group_index = sci_remote_node_table_get_group_index(389		remote_node_table, group_table_index);390 391	/* We could not find an available slot in the table selector 0 */392	if (group_index != SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX) {393		group_value = sci_remote_node_table_get_group_value(394			remote_node_table, group_index);395 396		for (index = 0; index < SCU_STP_REMOTE_NODE_COUNT; index++) {397			if (((1 << index) & group_value) != 0) {398				/* We have selected a bit now clear it */399				remote_node_index = (u16)(group_index * SCU_STP_REMOTE_NODE_COUNT400							  + index);401 402				sci_remote_node_table_clear_group_index(403					remote_node_table, group_table_index, group_index404					);405 406				sci_remote_node_table_clear_node_index(407					remote_node_table, remote_node_index408					);409 410				if (group_table_index > 0) {411					sci_remote_node_table_set_group_index(412						remote_node_table, group_table_index - 1, group_index413						);414				}415 416				break;417			}418		}419	}420 421	return remote_node_index;422}423 424/**425 * sci_remote_node_table_allocate_triple_remote_node()426 * @remote_node_table: This is the remote node table from which to allocate the427 *    remote node entries.428 * @group_table_index: This is the group table index which must equal two (2)429 *    for this operation.430 *431 * This method will allocate three consecutive remote node context entries. If432 * there are no remaining triple entries the function will return a failure.433 * The remote node index that represents three consecutive remote node entries434 * or an invalid remote node context if none can be found.435 */436static u16 sci_remote_node_table_allocate_triple_remote_node(437	struct sci_remote_node_table *remote_node_table,438	u32 group_table_index)439{440	u32 group_index;441	u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX;442 443	group_index = sci_remote_node_table_get_group_index(444		remote_node_table, group_table_index);445 446	if (group_index != SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX) {447		remote_node_index = (u16)group_index * SCU_STP_REMOTE_NODE_COUNT;448 449		sci_remote_node_table_clear_group_index(450			remote_node_table, group_table_index, group_index451			);452 453		sci_remote_node_table_clear_group(454			remote_node_table, group_index455			);456	}457 458	return remote_node_index;459}460 461/**462 * sci_remote_node_table_allocate_remote_node()463 * @remote_node_table: This is the remote node table from which the remote node464 *    allocation is to take place.465 * @remote_node_count: This is ther remote node count which is one of466 *    SCU_SSP_REMOTE_NODE_COUNT(1) or SCU_STP_REMOTE_NODE_COUNT(3).467 *468 * This method will allocate a remote node that mataches the remote node count469 * specified by the caller.  Valid values for remote node count is470 * SCU_SSP_REMOTE_NODE_COUNT(1) or SCU_STP_REMOTE_NODE_COUNT(3). u16 This is471 * the remote node index that is returned or an invalid remote node context.472 */473u16 sci_remote_node_table_allocate_remote_node(474	struct sci_remote_node_table *remote_node_table,475	u32 remote_node_count)476{477	u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX;478 479	if (remote_node_count == SCU_SSP_REMOTE_NODE_COUNT) {480		remote_node_index =481			sci_remote_node_table_allocate_single_remote_node(482				remote_node_table, 0);483 484		if (remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {485			remote_node_index =486				sci_remote_node_table_allocate_single_remote_node(487					remote_node_table, 1);488		}489 490		if (remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) {491			remote_node_index =492				sci_remote_node_table_allocate_single_remote_node(493					remote_node_table, 2);494		}495	} else if (remote_node_count == SCU_STP_REMOTE_NODE_COUNT) {496		remote_node_index =497			sci_remote_node_table_allocate_triple_remote_node(498				remote_node_table, 2);499	}500 501	return remote_node_index;502}503 504/**505 * sci_remote_node_table_release_single_remote_node()506 * @remote_node_table: This is the remote node table from which the remote node507 *    release is to take place.508 * @remote_node_index: This is the remote node index that is being released.509 * This method will free a single remote node index back to the remote node510 * table.  This routine will update the remote node groups511 */512static void sci_remote_node_table_release_single_remote_node(513	struct sci_remote_node_table *remote_node_table,514	u16 remote_node_index)515{516	u32 group_index;517	u8 group_value;518 519	group_index = remote_node_index / SCU_STP_REMOTE_NODE_COUNT;520 521	group_value = sci_remote_node_table_get_group_value(remote_node_table, group_index);522 523	/*524	 * Assert that we are not trying to add an entry to a slot that is already525	 * full. */526	BUG_ON(group_value == SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE);527 528	if (group_value == 0x00) {529		/*530		 * There are no entries in this slot so it must be added to the single531		 * slot table. */532		sci_remote_node_table_set_group_index(remote_node_table, 0, group_index);533	} else if ((group_value & (group_value - 1)) == 0) {534		/*535		 * There is only one entry in this slot so it must be moved from the536		 * single slot table to the dual slot table */537		sci_remote_node_table_clear_group_index(remote_node_table, 0, group_index);538		sci_remote_node_table_set_group_index(remote_node_table, 1, group_index);539	} else {540		/*541		 * There are two entries in the slot so it must be moved from the dual542		 * slot table to the tripple slot table. */543		sci_remote_node_table_clear_group_index(remote_node_table, 1, group_index);544		sci_remote_node_table_set_group_index(remote_node_table, 2, group_index);545	}546 547	sci_remote_node_table_set_node_index(remote_node_table, remote_node_index);548}549 550/**551 * sci_remote_node_table_release_triple_remote_node()552 * @remote_node_table: This is the remote node table to which the remote node553 *    index is to be freed.554 * @remote_node_index: This is the remote node index that is being released.555 *556 * This method will release a group of three consecutive remote nodes back to557 * the free remote nodes.558 */559static void sci_remote_node_table_release_triple_remote_node(560	struct sci_remote_node_table *remote_node_table,561	u16 remote_node_index)562{563	u32 group_index;564 565	group_index = remote_node_index / SCU_STP_REMOTE_NODE_COUNT;566 567	sci_remote_node_table_set_group_index(568		remote_node_table, 2, group_index569		);570 571	sci_remote_node_table_set_group(remote_node_table, group_index);572}573 574/**575 * sci_remote_node_table_release_remote_node_index()576 * @remote_node_table: The remote node table to which the remote node index is577 *    to be freed.578 * @remote_node_count: This is the count of consecutive remote nodes that are579 *    to be freed.580 * @remote_node_index: This is the remote node index that is being released.581 *582 * This method will release the remote node index back into the remote node583 * table free pool.584 */585void sci_remote_node_table_release_remote_node_index(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 599