iPXE
mlx_pci_gw.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2015 Mellanox Technologies Ltd.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  */
00019 
00020 FILE_LICENCE ( GPL2_OR_LATER );
00021 
00022 #include "../../include/public/mlx_pci_gw.h"
00023 #include "../../include/public/mlx_bail.h"
00024 #include "../../include/public/mlx_pci.h"
00025 #include "../../include/public/mlx_logging.h"
00026 
00027 /* Lock/unlock GW on each VSEC access */
00028 #undef VSEC_DEBUG
00029 
00030 static
00031 mlx_status
00032 mlx_pci_gw_check_capability_id(
00033                                                         IN mlx_utils *utils,
00034                                                         IN mlx_uint8 cap_pointer,
00035                                                         OUT mlx_boolean *bool
00036                                                         )
00037 {
00038         mlx_status              status = MLX_SUCCESS;
00039         mlx_uint8               offset = cap_pointer + PCI_GW_CAPABILITY_ID_OFFSET;
00040         mlx_uint8               id = 0;
00041         status = mlx_pci_read(utils, MlxPciWidthUint8, offset,
00042                                 1, &id);
00043         MLX_CHECK_STATUS(utils, status, read_err,"failed to read capability id");
00044         *bool = ( id == PCI_GW_CAPABILITY_ID );
00045 read_err:
00046         return status;
00047 }
00048 
00049 static
00050 mlx_status
00051 mlx_pci_gw_get_ownership(
00052                                                 IN mlx_utils *utils
00053                                                 )
00054 {
00055         mlx_status                      status = MLX_SUCCESS;
00056         mlx_uint32                      cap_offset = utils->pci_gw.pci_cmd_offset;
00057         mlx_uint32                      semaphore = 0;
00058         mlx_uint32                      counter = 0;
00059         mlx_uint32                      get_semaphore_try = 0;
00060         mlx_uint32                      get_ownership_try = 0;
00061 
00062         for( ; get_ownership_try < PCI_GW_GET_OWNERSHIP_TRIES; get_ownership_try ++){
00063                 for( ; get_semaphore_try <= PCI_GW_SEMPHORE_TRIES ; get_semaphore_try++){
00064                         status = mlx_pci_read(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_SEMAPHORE_OFFSET,
00065                                         1, &semaphore);
00066                         MLX_CHECK_STATUS(utils, status, read_err,"failed to read semaphore");
00067                         if( semaphore == 0 ){
00068                                 break;
00069                         }
00070                         mlx_utils_delay_in_us(10);
00071                 }
00072                 if( semaphore != 0 ){
00073                         status = MLX_FAILED;
00074                         goto semaphore_err;
00075                 }
00076 
00077                 status = mlx_pci_read(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_COUNTER_OFFSET,
00078                                                 1, &counter);
00079                 MLX_CHECK_STATUS(utils, status, read_err, "failed to read counter");
00080 
00081                 status = mlx_pci_write(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_SEMAPHORE_OFFSET,
00082                                                 1, &counter);
00083                 MLX_CHECK_STATUS(utils, status, write_err,"failed to write semaphore");
00084 
00085                 status = mlx_pci_read(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_SEMAPHORE_OFFSET,
00086                                                 1, &semaphore);
00087                 MLX_CHECK_STATUS(utils, status, read_err,"failed to read semaphore");
00088                 if( counter == semaphore ){
00089                         break;
00090                 }
00091         }
00092         if( counter != semaphore ){
00093                 status = MLX_FAILED;
00094         }
00095 write_err:
00096 read_err:
00097 semaphore_err:
00098         return status;
00099 }
00100 
00101 static
00102 mlx_status
00103 mlx_pci_gw_free_ownership(
00104                                                 IN mlx_utils *utils
00105                                                 )
00106 {
00107         mlx_status              status = MLX_SUCCESS;
00108         mlx_uint32              cap_offset = utils->pci_gw.pci_cmd_offset;
00109         mlx_uint32              value = 0;
00110 
00111         status = mlx_pci_write(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_SEMAPHORE_OFFSET,
00112                                         1, &value);
00113         MLX_CHECK_STATUS(utils, status, write_err,"failed to write semaphore");
00114 write_err:
00115         return status;
00116 }
00117 
00118 static
00119 mlx_status
00120 mlx_pci_gw_set_space(
00121                                         IN mlx_utils *utils,
00122                                         IN mlx_pci_gw_space space
00123                                         )
00124 {
00125         mlx_status              status = MLX_SUCCESS;
00126         mlx_uint32              cap_offset = utils->pci_gw.pci_cmd_offset;;
00127         mlx_uint8               space_status = 0;
00128 
00129         /* set nodnic*/
00130         status = mlx_pci_write(utils, MlxPciWidthUint16, cap_offset + PCI_GW_CAPABILITY_SPACE_OFFSET, 1, &space);
00131         MLX_CHECK_STATUS(utils, status, read_error,"failed to write capability space");
00132 
00133         status = mlx_pci_read(utils, MlxPciWidthUint8, cap_offset + PCI_GW_CAPABILITY_STATUS_OFFSET, 1, &space_status);
00134         MLX_CHECK_STATUS(utils, status, read_error,"failed to read capability status");
00135         if( (space_status & 0x20) == 0){
00136                 status = MLX_FAILED;
00137                 goto space_unsupported;
00138         }
00139 read_error:
00140 space_unsupported:
00141         return status;
00142 }
00143 
00144 static
00145 mlx_status
00146 mlx_pci_gw_wait_for_flag_value(
00147                                                         IN mlx_utils *utils,
00148                                                         IN mlx_boolean value
00149                                                         )
00150 {
00151         mlx_status              status = MLX_SUCCESS;
00152         mlx_uint32              try = 0;
00153         mlx_uint32              cap_offset = utils->pci_gw.pci_cmd_offset;
00154         mlx_uint32              flag = 0;
00155 
00156         for(; try < PCI_GW_READ_FLAG_TRIES ; try ++ ) {
00157                 status = mlx_pci_read(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_FLAG_OFFSET, 1, &flag);
00158                 MLX_CHECK_STATUS(utils, status, read_error, "failed to read capability flag");
00159                 if( ((flag & 0x80000000) != 0) == value ){
00160                         goto flag_valid;
00161                 }
00162                 mlx_utils_delay_in_us(10);
00163         }
00164         status = MLX_FAILED;
00165 flag_valid:
00166 read_error:
00167         return status;
00168 }
00169 static
00170 mlx_status
00171 mlx_pci_gw_search_capability(
00172                                 IN mlx_utils *utils,
00173                                 OUT mlx_uint32  *cap_offset
00174                                 )
00175 {
00176         mlx_status              status = MLX_SUCCESS;
00177         mlx_uint8               cap_pointer = 0;
00178         mlx_boolean             is_capability = FALSE;
00179 
00180         if( cap_offset == NULL || utils == NULL){
00181                 status = MLX_INVALID_PARAMETER;
00182                 goto bad_param;
00183         }
00184 
00185         //get first capability pointer
00186         status = mlx_pci_read(utils, MlxPciWidthUint8, PCI_GW_FIRST_CAPABILITY_POINTER_OFFSET,
00187                         1, &cap_pointer);
00188         MLX_CHECK_STATUS(utils, status, read_err,
00189                         "failed to read capability pointer");
00190 
00191         //search the right capability
00192         while( cap_pointer != 0 ){
00193                 status = mlx_pci_gw_check_capability_id(utils, cap_pointer, &is_capability);
00194                 MLX_CHECK_STATUS(utils, status, check_err
00195                                 ,"failed to check capability id");
00196 
00197                 if( is_capability == TRUE ){
00198                         *cap_offset = cap_pointer;
00199                         break;
00200                 }
00201 
00202                 status = mlx_pci_read(utils, MlxPciWidthUint8, cap_pointer +
00203                                 PCI_GW_CAPABILITY_NEXT_POINTER_OFFSET ,
00204                                 1, &cap_pointer);
00205                 MLX_CHECK_STATUS(utils, status, read_err,
00206                                 "failed to read capability pointer");
00207         }
00208         if( is_capability != TRUE ){
00209                 status = MLX_NOT_FOUND;
00210         }
00211 check_err:
00212 read_err:
00213 bad_param:
00214         return status;
00215 }
00216 
00217 mlx_status
00218 mlx_pci_gw_init(
00219                         IN mlx_utils *utils
00220                         )
00221 {
00222         mlx_status              status = MLX_SUCCESS;
00223         mlx_pci_gw *pci_gw = NULL;
00224 
00225         if( utils == NULL){
00226                 status = MLX_INVALID_PARAMETER;
00227                 goto bad_param;
00228         }
00229 
00230         pci_gw = &utils->pci_gw;
00231 
00232         status = mlx_pci_gw_search_capability(utils, &pci_gw->pci_cmd_offset);
00233         MLX_CHECK_STATUS(utils, status, cap_err,
00234                                         "mlx_pci_gw_search_capability failed");
00235 
00236 #if ! defined ( VSEC_DEBUG )
00237         status = mlx_pci_gw_get_ownership(utils);
00238         MLX_CHECK_STATUS(utils, status, ownership_err,"failed to get ownership");
00239 ownership_err:
00240 #endif
00241 cap_err:
00242 bad_param:
00243         return status;
00244 }
00245 
00246 mlx_status
00247 mlx_pci_gw_teardown(
00248                 IN mlx_utils *utils __attribute__ ((unused))
00249                 )
00250 {
00251 #if ! defined ( VSEC_DEBUG )
00252         mlx_pci_gw_free_ownership(utils);
00253 #endif
00254         return MLX_SUCCESS;
00255 }
00256 
00257 mlx_status
00258 mlx_pci_gw_read(
00259                 IN mlx_utils *utils,
00260                 IN mlx_pci_gw_space space,
00261                 IN mlx_uint32 address,
00262                 OUT mlx_pci_gw_buffer *buffer
00263                 )
00264 {
00265         mlx_status              status = MLX_SUCCESS;
00266         mlx_pci_gw              *pci_gw = NULL;
00267         mlx_uint32              cap_offset = 0;
00268 
00269         if (utils == NULL || buffer == NULL || utils->pci_gw.pci_cmd_offset == 0) {
00270                 status = MLX_INVALID_PARAMETER;
00271                 goto bad_param;
00272         }
00273 
00274         mlx_utils_acquire_lock(utils);
00275 
00276         pci_gw = &utils->pci_gw;
00277         cap_offset = pci_gw->pci_cmd_offset;
00278 
00279 #if ! defined ( VSEC_DEBUG )
00280         if (pci_gw->space != space) {
00281                    status = mlx_pci_gw_set_space(utils, space);
00282                    MLX_CHECK_STATUS(utils, status, space_error,"failed to set space");
00283                    pci_gw->space = space;
00284         }
00285 #else
00286         status = mlx_pci_gw_get_ownership(utils);
00287         MLX_CHECK_STATUS(utils, status, ownership_err,"failed to get ownership");
00288 
00289         status = mlx_pci_gw_set_space(utils, space);
00290         MLX_CHECK_STATUS(utils, status, space_error,"failed to set space");
00291         pci_gw->space = space;
00292 #endif
00293 
00294         status = mlx_pci_write(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_ADDRESS_OFFSET, 1, &address);
00295         MLX_CHECK_STATUS(utils, status, read_error,"failed to write capability address");
00296 
00297 #if defined ( DEVICE_CX3 )
00298         /* WA for PCI issue (race) */
00299         mlx_utils_delay_in_us ( 10 );
00300 #endif
00301 
00302         status = mlx_pci_gw_wait_for_flag_value(utils, TRUE);
00303         MLX_CHECK_STATUS(utils, status, read_error, "flag failed to change");
00304 
00305         status = mlx_pci_read(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_DATA_OFFSET, 1, buffer);
00306         MLX_CHECK_STATUS(utils, status, read_error,"failed to read capability data");
00307 
00308 #if defined ( VSEC_DEBUG )
00309         status = mlx_pci_gw_free_ownership(utils);
00310         MLX_CHECK_STATUS(utils, status, free_err,
00311                                                 "mlx_pci_gw_free_ownership failed");
00312 free_err:
00313         mlx_utils_release_lock(utils);
00314         return status;
00315 #endif
00316 read_error:
00317 space_error:
00318 #if defined ( VSEC_DEBUG )
00319         mlx_pci_gw_free_ownership(utils);
00320 ownership_err:
00321 #endif
00322 mlx_utils_release_lock(utils);
00323 bad_param:
00324         return status;
00325 }
00326 
00327 mlx_status
00328 mlx_pci_gw_write(
00329                                 IN mlx_utils *utils,
00330                                 IN mlx_pci_gw_space space,
00331                                 IN mlx_uint32 address,
00332                                 IN mlx_pci_gw_buffer buffer
00333                                 )
00334 {
00335         mlx_status              status = MLX_SUCCESS;
00336         mlx_pci_gw              *pci_gw = NULL;
00337         mlx_uint32              cap_offset = 0;
00338         mlx_uint32              fixed_address = address | PCI_GW_WRITE_FLAG;
00339 
00340         if (utils == NULL || utils->pci_gw.pci_cmd_offset == 0) {
00341                 status = MLX_INVALID_PARAMETER;
00342                 goto bad_param;
00343         }
00344 
00345         mlx_utils_acquire_lock(utils);
00346 
00347         pci_gw = &utils->pci_gw;
00348         cap_offset = pci_gw->pci_cmd_offset;
00349 
00350 #if ! defined ( VSEC_DEBUG )
00351         if (pci_gw->space != space) {
00352                    status = mlx_pci_gw_set_space(utils, space);
00353                    MLX_CHECK_STATUS(utils, status, space_error,"failed to set space");
00354                    pci_gw->space = space;
00355         }
00356 #else
00357         status = mlx_pci_gw_get_ownership(utils);
00358         MLX_CHECK_STATUS(utils, status, ownership_err,"failed to get ownership");
00359 
00360         status = mlx_pci_gw_set_space(utils, space);
00361         MLX_CHECK_STATUS(utils, status, space_error,"failed to set space");
00362         pci_gw->space = space;
00363 #endif
00364         status = mlx_pci_write(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_DATA_OFFSET, 1, &buffer);
00365         MLX_CHECK_STATUS(utils, status, read_error,"failed to write capability data");
00366 
00367         status = mlx_pci_write(utils, MlxPciWidthUint32, cap_offset + PCI_GW_CAPABILITY_ADDRESS_OFFSET, 1, &fixed_address);
00368         MLX_CHECK_STATUS(utils, status, read_error,"failed to write capability address");
00369 
00370         status = mlx_pci_gw_wait_for_flag_value(utils, FALSE);
00371         MLX_CHECK_STATUS(utils, status, read_error, "flag failed to change");
00372 #if defined ( VSEC_DEBUG )
00373         status = mlx_pci_gw_free_ownership(utils);
00374         MLX_CHECK_STATUS(utils, status, free_err,
00375                                                 "mlx_pci_gw_free_ownership failed");
00376 free_err:
00377 mlx_utils_release_lock(utils);
00378         return status;
00379 #endif
00380 read_error:
00381 space_error:
00382 #if defined ( VSEC_DEBUG )
00383         mlx_pci_gw_free_ownership(utils);
00384 ownership_err:
00385 #endif
00386 mlx_utils_release_lock(utils);
00387 bad_param:
00388         return status;
00389 }
00390 
00391 
00392