diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-06-08 01:50:55 (GMT) |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 11:04:51 (GMT) |
commit | ac668c69709c7d927015c5cf3d9e87bf4eaaf57d (patch) | |
tree | 16a42117d260a86b8217d266ab65b25438c48e06 | |
parent | 9b917987fd16d0687afe550a02f68099419f5d43 (diff) | |
download | linux-ac668c69709c7d927015c5cf3d9e87bf4eaaf57d.tar.xz |
isci: cleanup/optimize pool implementation
The circ_buf macros are ~6% faster, as measured by perf, because they take
advantage of power-of-two math assumptions i.e. no test and branch for
rollover. Their semantics are clearer than the hidden side effects in pool.h
(like sci_pool_get() which hides an assignment).
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | drivers/scsi/isci/host.c | 75 | ||||
-rw-r--r-- | drivers/scsi/isci/host.h | 12 | ||||
-rw-r--r-- | drivers/scsi/isci/isci.h | 1 | ||||
-rw-r--r-- | drivers/scsi/isci/pool.h | 199 |
4 files changed, 56 insertions, 231 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 41a7c50..343655b 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -52,6 +52,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <linux/circ_buf.h> #include <linux/device.h> #include <scsi/sas.h> #include "host.h" @@ -1054,6 +1055,33 @@ done: spin_unlock_irqrestore(&ihost->scic_lock, flags); } +static void isci_tci_free(struct isci_host *ihost, u16 tci) +{ + u16 tail = ihost->tci_tail & (SCI_MAX_IO_REQUESTS-1); + + ihost->tci_pool[tail] = tci; + ihost->tci_tail = tail + 1; +} + +static u16 isci_tci_alloc(struct isci_host *ihost) +{ + u16 head = ihost->tci_head & (SCI_MAX_IO_REQUESTS-1); + u16 tci = ihost->tci_pool[head]; + + ihost->tci_head = head + 1; + return tci; +} + +static u16 isci_tci_active(struct isci_host *ihost) +{ + return CIRC_CNT(ihost->tci_head, ihost->tci_tail, SCI_MAX_IO_REQUESTS); +} + +static u16 isci_tci_space(struct isci_host *ihost) +{ + return CIRC_SPACE(ihost->tci_head, ihost->tci_tail, SCI_MAX_IO_REQUESTS); +} + static enum sci_status scic_controller_start(struct scic_sds_controller *scic, u32 timeout) { @@ -1069,9 +1097,11 @@ static enum sci_status scic_controller_start(struct scic_sds_controller *scic, } /* Build the TCi free pool */ - sci_pool_initialize(scic->tci_pool); + BUILD_BUG_ON(SCI_MAX_IO_REQUESTS > 1 << sizeof(ihost->tci_pool[0]) * 8); + ihost->tci_head = 0; + ihost->tci_tail = 0; for (index = 0; index < scic->task_context_entries; index++) - sci_pool_put(scic->tci_pool, index); + isci_tci_free(ihost, index); /* Build the RNi free pool */ scic_sds_remote_node_table_initialize( @@ -3063,18 +3093,17 @@ enum sci_task_status scic_controller_start_task( * currently available tags to be allocated. All return other values indicate a * legitimate tag. */ -u16 scic_controller_allocate_io_tag( - struct scic_sds_controller *scic) +u16 scic_controller_allocate_io_tag(struct scic_sds_controller *scic) { - u16 task_context; - u16 sequence_count; - - if (!sci_pool_empty(scic->tci_pool)) { - sci_pool_get(scic->tci_pool, task_context); + struct isci_host *ihost = scic_to_ihost(scic); + u16 tci; + u16 seq; - sequence_count = scic->io_request_sequence[task_context]; + if (isci_tci_space(ihost)) { + tci = isci_tci_alloc(ihost); + seq = scic->io_request_sequence[tci]; - return scic_sds_io_tag_construct(sequence_count, task_context); + return scic_sds_io_tag_construct(seq, tci); } return SCI_CONTROLLER_INVALID_IO_TAG; @@ -3105,10 +3134,10 @@ u16 scic_controller_allocate_io_tag( * tags. SCI_FAILURE_INVALID_IO_TAG This value is returned if the supplied tag * is not a valid IO tag value. */ -enum sci_status scic_controller_free_io_tag( - struct scic_sds_controller *scic, - u16 io_tag) +enum sci_status scic_controller_free_io_tag(struct scic_sds_controller *scic, + u16 io_tag) { + struct isci_host *ihost = scic_to_ihost(scic); u16 sequence; u16 index; @@ -3117,18 +3146,16 @@ enum sci_status scic_controller_free_io_tag( sequence = scic_sds_io_tag_get_sequence(io_tag); index = scic_sds_io_tag_get_index(io_tag); - if (!sci_pool_full(scic->tci_pool)) { - if (sequence == scic->io_request_sequence[index]) { - scic_sds_io_sequence_increment( - scic->io_request_sequence[index]); + /* prevent tail from passing head */ + if (isci_tci_active(ihost) == 0) + return SCI_FAILURE_INVALID_IO_TAG; - sci_pool_put(scic->tci_pool, index); + if (sequence == scic->io_request_sequence[index]) { + scic_sds_io_sequence_increment(scic->io_request_sequence[index]); - return SCI_SUCCESS; - } - } + isci_tci_free(ihost, index); + return SCI_SUCCESS; + } return SCI_FAILURE_INVALID_IO_TAG; } - - diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 74035004..c61a9fa 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h @@ -57,7 +57,6 @@ #include "remote_device.h" #include "phy.h" -#include "pool.h" #include "isci.h" #include "remote_node_table.h" #include "registers.h" @@ -180,11 +179,6 @@ struct scic_sds_controller { struct scic_remote_node_table available_remote_nodes; /** - * This field is the TCi pool used to manage the task context index. - */ - SCI_POOL_CREATE(tci_pool, u16, SCI_MAX_IO_REQUESTS); - - /** * This filed is the struct scic_power_control data used to controll when direct * attached devices can consume power. */ @@ -310,6 +304,10 @@ struct scic_sds_controller { struct isci_host { struct scic_sds_controller sci; + u16 tci_head; + u16 tci_tail; + u16 tci_pool[SCI_MAX_IO_REQUESTS]; + union scic_oem_parameters oem_parameters; int id; /* unique within a given pci device */ @@ -423,8 +421,6 @@ enum scic_sds_controller_states { SCIC_FAILED, }; - - /** * struct isci_pci_info - This class represents the pci function containing the * controllers. Depending on PCI SKU, there could be up to 2 controllers in diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h index 714ed92..84ba533 100644 --- a/drivers/scsi/isci/isci.h +++ b/drivers/scsi/isci/isci.h @@ -112,6 +112,7 @@ static inline void check_sizes(void) BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_UNSOLICITED_FRAMES); BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_COMPLETION_QUEUE_ENTRIES); BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES > SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES); + BUILD_BUG_ON_NOT_POWER_OF_2(SCI_MAX_IO_REQUESTS); } /** diff --git a/drivers/scsi/isci/pool.h b/drivers/scsi/isci/pool.h deleted file mode 100644 index 016ec83..0000000 --- a/drivers/scsi/isci/pool.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * This file contains the interface to the pool class. This class allows two - * different two different priority tasks to insert and remove items from - * the free pool. The user of the pool is expected to evaluate the pool - * condition empty before a get operation and pool condition full before a - * put operation. Methods Provided: - sci_pool_create() - - * sci_pool_initialize() - sci_pool_empty() - sci_pool_full() - - * sci_pool_get() - sci_pool_put() - * - * - */ - -#ifndef _SCI_POOL_H_ -#define _SCI_POOL_H_ - -/** - * SCI_POOL_INCREMENT() - - * - * Private operation for the pool - */ -#define SCI_POOL_INCREMENT(pool, index) \ - (((index) + 1) == (pool).size ? 0 : (index) + 1) - -/** - * SCI_POOL_CREATE() - - * - * This creates a pool structure of pool_name. The members in the pool are of - * type with number of elements equal to size. - */ -#define SCI_POOL_CREATE(pool_name, type, pool_size) \ - struct \ - { \ - u32 size; \ - u32 get; \ - u32 put; \ - type array[(pool_size) + 1]; \ - } pool_name - - -/** - * sci_pool_empty() - - * - * This macro evaluates the pool and returns true if the pool is empty. If the - * pool is empty the user should not perform any get operation on the pool. - */ -#define sci_pool_empty(pool) \ - ((pool).get == (pool).put) - -/** - * sci_pool_full() - - * - * This macro evaluates the pool and returns true if the pool is full. If the - * pool is full the user should not perform any put operation. - */ -#define sci_pool_full(pool) \ - (SCI_POOL_INCREMENT(pool, (pool).put) == (pool).get) - -/** - * sci_pool_size() - - * - * This macro returns the size of the pool created. The internal size of the - * pool is actually 1 larger then necessary in order to ensure get and put - * pointers can be written simultaneously by different users. As a result, - * this macro subtracts 1 from the internal size - */ -#define sci_pool_size(pool) \ - ((pool).size - 1) - -/** - * sci_pool_count() - - * - * This macro indicates the number of elements currently contained in the pool. - */ -#define sci_pool_count(pool) \ - (\ - sci_pool_empty((pool)) \ - ? 0 \ - : (\ - sci_pool_full((pool)) \ - ? sci_pool_size((pool)) \ - : (\ - (pool).get > (pool).put \ - ? ((pool).size - (pool).get + (pool).put) \ - : ((pool).put - (pool).get) \ - ) \ - ) \ - ) - -/** - * sci_pool_initialize() - - * - * This macro initializes the pool to an empty condition. - */ -#define sci_pool_initialize(pool) \ - { \ - (pool).size = (sizeof((pool).array) / sizeof((pool).array[0])); \ - (pool).get = 0; \ - (pool).put = 0; \ - } - -/** - * sci_pool_get() - - * - * This macro will get the next free element from the pool. This should only be - * called if the pool is not empty. - */ -#define sci_pool_get(pool, my_value) \ - { \ - (my_value) = (pool).array[(pool).get]; \ - (pool).get = SCI_POOL_INCREMENT((pool), (pool).get); \ - } - -/** - * sci_pool_put() - - * - * This macro will put the value into the pool. This should only be called if - * the pool is not full. - */ -#define sci_pool_put(pool, value) \ - { \ - (pool).array[(pool).put] = (value); \ - (pool).put = SCI_POOL_INCREMENT((pool), (pool).put); \ - } - -/** - * sci_pool_erase() - - * - * This macro will search the pool and remove any elements in the pool matching - * the supplied value. This method can only be utilized on pools - */ -#define sci_pool_erase(pool, type, value) \ - { \ - type tmp_value; \ - u32 index; \ - u32 element_count = sci_pool_count((pool)); \ - \ - for (index = 0; index < element_count; index++) { \ - sci_pool_get((pool), tmp_value); \ - if (tmp_value != (value)) \ - sci_pool_put((pool), tmp_value); \ - } \ - } - -#endif /* _SCI_POOL_H_ */ |