Signed-off-by: Hal Rosenstock <h...@mellanox.com>
---
 include/opensm/osm_pkey.h |   35 +++++++++++++++++++
 opensm/osm_pkey.c         |   19 ++++++++++
 opensm/osm_pkey_mgr.c     |   81 +++++++++++++++++++++++++++++++++++---------
 3 files changed, 118 insertions(+), 17 deletions(-)

diff --git a/include/opensm/osm_pkey.h b/include/opensm/osm_pkey.h
index 53e9657..33de7e7 100644
--- a/include/opensm/osm_pkey.h
+++ b/include/opensm/osm_pkey.h
@@ -82,15 +82,21 @@ struct osm_physp;
 * SYNOPSIS
 */
 typedef struct osm_pkeybl {
+       cl_ptr_vector_t accum_pkeys;
        cl_ptr_vector_t blocks;
        cl_ptr_vector_t new_blocks;
        cl_map_t keys;
        cl_qlist_t pending;
+       uint16_t last_pkey_idx;
        uint16_t used_blocks;
        uint16_t max_blocks;
 } osm_pkey_tbl_t;
 /*
 * FIELDS
+*      accum_pkeys
+*              Accumulated pkeys with pkey index. Used to
+*              preserve pkey index.
+*
 *      blocks
 *              The IBA defined blocks of pkey values, updated from the subnet
 *
@@ -288,6 +294,35 @@ static inline ib_pkey_table_t 
*osm_pkey_tbl_new_block_get(const osm_pkey_tbl_t *
                &p_pkey_tbl->new_blocks, block) : NULL);
 };
 
+/****f* OpenSM: osm_pkey_tbl_set_accum_pkeys
+* NAME
+*  osm_pkey_tbl_set_accum_pkeys
+*
+* DESCRIPTION
+*   Stores the given pkey in the "accum_pkeys" array and update
+*   update the "map"
+*
+* SYNOPSIS
+*/
+cl_status_t
+osm_pkey_tbl_set_accum_pkeys(IN osm_pkey_tbl_t * p_pkey_tbl,
+                            IN uint16_t pkey, IN uint16_t pkey_idx);
+/*
+* p_pkey_tbl
+*   [in] Pointer to the PKey table
+*
+* pkey
+*   [in] PKey to store
+*
+* pkey_idx
+*   [in] The overall index
+*
+* RETURN VALUES
+*   CL_SUCCESS if OK
+*   CL_INSUFFICIENT_MEMORY if failed
+*
+*********/
+
 /****f* OpenSM: osm_pkey_tbl_set_new_entry
 * NAME
 *  osm_pkey_tbl_set_new_entry
diff --git a/opensm/osm_pkey.c b/opensm/osm_pkey.c
index 6abc8ed..02b7c59 100644
--- a/opensm/osm_pkey.c
+++ b/opensm/osm_pkey.c
@@ -56,6 +56,7 @@
 
 void osm_pkey_tbl_construct(IN osm_pkey_tbl_t * p_pkey_tbl)
 {
+       cl_ptr_vector_construct(&p_pkey_tbl->accum_pkeys);
        cl_ptr_vector_construct(&p_pkey_tbl->blocks);
        cl_ptr_vector_construct(&p_pkey_tbl->new_blocks);
        cl_map_construct(&p_pkey_tbl->keys);
@@ -79,16 +80,20 @@ void osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl)
                        free(p_block);
        cl_ptr_vector_destroy(&p_pkey_tbl->new_blocks);
 
+       cl_ptr_vector_destroy(&p_pkey_tbl->accum_pkeys);
+
        cl_map_remove_all(&p_pkey_tbl->keys);
        cl_map_destroy(&p_pkey_tbl->keys);
 }
 
 ib_api_status_t osm_pkey_tbl_init(IN osm_pkey_tbl_t * p_pkey_tbl)
 {
+       cl_ptr_vector_init(&p_pkey_tbl->accum_pkeys, 0, 1);
        cl_ptr_vector_init(&p_pkey_tbl->blocks, 0, 1);
        cl_ptr_vector_init(&p_pkey_tbl->new_blocks, 0, 1);
        cl_map_init(&p_pkey_tbl->keys, 1);
        cl_qlist_init(&p_pkey_tbl->pending);
+       p_pkey_tbl->last_pkey_idx = 0;
        p_pkey_tbl->used_blocks = 0;
        p_pkey_tbl->max_blocks = 0;
        return IB_SUCCESS;
@@ -173,6 +178,20 @@ ib_api_status_t osm_pkey_tbl_set(IN osm_pkey_tbl_t * 
p_pkey_tbl,
 }
 
 /*
+  Store the given pkey (along with it's overall index) in the accum_pkeys 
array.
+*/
+cl_status_t osm_pkey_tbl_set_accum_pkeys(IN osm_pkey_tbl_t * p_pkey_tbl,
+                                        IN uint16_t pkey,
+                                        IN uint16_t pkey_idx)
+{
+       uintptr_t ptr = pkey_idx + 1; /* 0 means not found so bias by 1 */
+
+       if (pkey_idx > p_pkey_tbl->last_pkey_idx)
+               p_pkey_tbl->last_pkey_idx = pkey_idx;
+       return cl_ptr_vector_set(&p_pkey_tbl->accum_pkeys, pkey, (void *)ptr);
+}
+
+/*
   Store the given pkey in the "new" blocks array.
   Also, make sure the regular block exists.
 */
diff --git a/opensm/osm_pkey_mgr.c b/opensm/osm_pkey_mgr.c
index 609d753..4c92c05 100644
--- a/opensm/osm_pkey_mgr.c
+++ b/opensm/osm_pkey_mgr.c
@@ -54,12 +54,12 @@
 #include <opensm/osm_opensm.h>
 
 /*
-  The max number of pkey blocks for a physical port is located in
-  a different place for switch external ports (SwitchInfo) and the
+  The max number of pkeys/pkey blocks for a physical port is located
+  in a different place for switch external ports (SwitchInfo) and the
   rest of the ports (NodeInfo).
 */
 static uint16_t
-pkey_mgr_get_physp_max_blocks(IN const osm_physp_t * p_physp)
+pkey_mgr_get_physp_max_pkeys(IN const osm_physp_t * p_physp)
 {
        osm_node_t *p_node = osm_physp_get_node_ptr(p_physp);
        uint16_t num_pkeys = 0;
@@ -68,7 +68,13 @@ pkey_mgr_get_physp_max_blocks(IN const osm_physp_t * p_physp)
                num_pkeys = cl_ntoh16(p_node->node_info.partition_cap);
        else
                num_pkeys = cl_ntoh16(p_node->sw->switch_info.enforce_cap);
-       return ((num_pkeys + 31) / 32);
+       return num_pkeys;
+}
+
+static uint16_t
+pkey_mgr_get_physp_max_blocks(IN const osm_physp_t * p_physp)
+{
+       return ((pkey_mgr_get_physp_max_pkeys(p_physp) + 31) / 32);
 }
 
 /*
@@ -244,6 +250,14 @@ pkey_mgr_enforce_partition(IN osm_log_t * p_log, osm_sm_t 
* sm,
        return status;
 }
 
+static void last_accum_pkey_index(osm_pkey_tbl_t * p_pkey_tbl,
+                                 uint16_t * p_block_idx,
+                                 uint8_t * p_pkey_idx)
+{
+       *p_block_idx = p_pkey_tbl->last_pkey_idx / 
IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
+       *p_pkey_idx = p_pkey_tbl->last_pkey_idx % IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
+}
+
 static int pkey_mgr_update_port(osm_log_t * p_log, osm_sm_t * sm,
                                const osm_port_t * const p_port)
 {
@@ -262,6 +276,9 @@ static int pkey_mgr_update_port(osm_log_t * p_log, osm_sm_t 
* sm,
        boolean_t found;
        ib_pkey_table_t empty_block;
        int ret = 0;
+       void *ptr;
+       uintptr_t pkey_idx_ptr;
+       uint16_t pkey_idx;
 
        p_physp = p_port->p_physp;
        if (!p_physp)
@@ -295,26 +312,50 @@ static int pkey_mgr_update_port(osm_log_t * p_log, 
osm_sm_t * sm,
            (osm_pending_pkey_t *) cl_qlist_remove_head(&p_pkey_tbl->pending);
        while (p_pending !=
               (osm_pending_pkey_t *) cl_qlist_end(&p_pkey_tbl->pending)) {
+
+               found = FALSE;
+               ptr = NULL;
+
                if (p_pending->is_new == FALSE) {
                        block_index = p_pending->block;
                        pkey_index = p_pending->index;
                        found = TRUE;
                } else {
-                       found = osm_pkey_find_next_free_entry(p_pkey_tbl,
-                                                             
&last_free_block_index,
-                                                             
&last_free_pkey_index);
+                       if (cl_ntoh16(p_pending->pkey) < 
cl_ptr_vector_get_size(&p_pkey_tbl->accum_pkeys)) {
+                               ptr = 
cl_ptr_vector_get(&p_pkey_tbl->accum_pkeys,
+                                                       p_pending->pkey);
+                               if (ptr != NULL) {
+                                       pkey_idx_ptr = (uintptr_t) ptr;
+                                       pkey_idx = pkey_idx_ptr;
+                                       pkey_idx--; /* adjust pkey index for 
bias */
+                                       block_index = pkey_idx / 
IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
+                                       pkey_index = pkey_idx % 
IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
+                                       found = TRUE;
+                               }
+                       }
+
                        if (!found) {
-                               OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0504: "
-                                       "Failed to find empty space for new 
pkey 0x%04x "
-                                       "for node 0x%016" PRIx64 " port %u 
(%s)\n",
-                                       cl_ntoh16(p_pending->pkey),
-                                       cl_ntoh64(osm_node_get_node_guid
-                                                 (p_node)),
-                                       osm_physp_get_port_num(p_physp),
-                                       p_physp->p_node->print_desc);
-                       } else {
+                               last_accum_pkey_index(p_pkey_tbl,
+                                                     &last_free_block_index,
+                                                     &last_free_pkey_index);
                                block_index = last_free_block_index;
-                               pkey_index = last_free_pkey_index++;
+                               pkey_index = last_free_pkey_index + 1;
+                               if (pkey_index >= 
IB_NUM_PKEY_ELEMENTS_IN_BLOCK) {
+                                       block_index++;
+                                       pkey_index -= 
IB_NUM_PKEY_ELEMENTS_IN_BLOCK;
+                                       if (block_index * 
IB_NUM_PKEY_ELEMENTS_IN_BLOCK + pkey_index >= 
pkey_mgr_get_physp_max_pkeys(p_physp)) {
+                                               OSM_LOG(p_log, OSM_LOG_ERROR,
+                                                       "ERR 0512: "
+                                                       "Failed to set PKey 
0x%04x since Pkey table is full "
+                                                       "for node 0x%016" 
PRIx64 " port %u (%s)\n",
+
+                                                       
cl_ntoh16(p_pending->pkey),
+                                                       
cl_ntoh64(osm_node_get_node_guid(p_node)),
+                                                       
osm_physp_get_port_num(p_physp),
+                                                       
p_physp->p_node->print_desc);
+                                       }
+                               } else
+                                       found = TRUE;
                        }
                }
 
@@ -333,6 +374,12 @@ static int pkey_mgr_update_port(osm_log_t * p_log, 
osm_sm_t * sm,
                                        osm_physp_get_port_num(p_physp),
                                        p_physp->p_node->print_desc);
                        }
+                       if (ptr == NULL &&
+                           CL_SUCCESS !=
+                           osm_pkey_tbl_set_accum_pkeys(p_pkey_tbl,
+                                                        p_pending->pkey,
+                                                        block_index * 
IB_NUM_PKEY_ELEMENTS_IN_BLOCK + pkey_index)) {
+                       }
                }
 
                free(p_pending);
-- 
1.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to