iPXE
mlx_icmd.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 
00021 FILE_LICENCE ( GPL2_OR_LATER );
00022 
00023 #include "../../include/public/mlx_bail.h"
00024 #include "../../include/public/mlx_icmd.h"
00025 #include "../../include/public/mlx_pci_gw.h"
00026 #include "../../include/public/mlx_utils.h"
00027 
00028 static
00029 mlx_status
00030 mlx_icmd_get_semaphore(
00031                                 IN mlx_utils *utils
00032                                 )
00033 {
00034         mlx_status status = MLX_SUCCESS;
00035         mlx_uint32 retries = 0;
00036         mlx_uint32 semaphore_id;
00037         mlx_uint32 buffer;
00038         if (utils == NULL) {
00039                 status = MLX_INVALID_PARAMETER;
00040                 goto invalid_param;
00041         }
00042 
00043         status = mlx_utils_rand(utils, &semaphore_id);
00044         MLX_CHECK_STATUS(utils, status, rand_err, "failed to get random number");
00045 #define ICMD_GET_SEMAPHORE_TRIES 2560
00046         for (retries = 0 ; retries < ICMD_GET_SEMAPHORE_TRIES ; retries++) {
00047                 status = mlx_pci_gw_read( utils, PCI_GW_SPACE_SEMAPHORE,
00048                                         MLX_ICMD_SEMAPHORE_ADDR, &buffer);
00049                 MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd semaphore");
00050                 if (buffer != 0) {
00051                         mlx_utils_delay_in_ms(10);
00052                         continue;
00053                 }
00054                 mlx_pci_gw_write( utils, PCI_GW_SPACE_SEMAPHORE,
00055                                                         MLX_ICMD_SEMAPHORE_ADDR, semaphore_id);
00056                 MLX_CHECK_STATUS(utils, status, set_err, "failed to set icmd semaphore");
00057                 status = mlx_pci_gw_read( utils, PCI_GW_SPACE_SEMAPHORE,
00058                                                         MLX_ICMD_SEMAPHORE_ADDR, &buffer);
00059                 MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd semaphore");
00060                 if (semaphore_id == buffer) {
00061                         status = MLX_SUCCESS;
00062                         utils->icmd.took_semaphore = TRUE;
00063                         break;
00064                 }
00065                 mlx_utils_delay_in_ms(10);
00066         }
00067         if (semaphore_id != buffer) {
00068                 status = MLX_FAILED;
00069         }
00070 read_err:
00071 set_err:
00072 rand_err:
00073 invalid_param:
00074         return status;
00075 }
00076 static
00077 mlx_status
00078 mlx_icmd_clear_semaphore(
00079                                 IN mlx_utils *utils
00080                                 )
00081 {
00082         mlx_status status = MLX_SUCCESS;
00083 
00084         if (utils == NULL) {
00085                 status = MLX_INVALID_PARAMETER;
00086                 goto invalid_param;
00087         }
00088 
00089         if (utils->icmd.took_semaphore == FALSE) {
00090                 goto semaphore_not_taken;
00091         }
00092         status = mlx_pci_gw_write( utils, PCI_GW_SPACE_SEMAPHORE,
00093                         MLX_ICMD_SEMAPHORE_ADDR, 0);
00094         MLX_CHECK_STATUS(utils, status, read_err, "failed to clear icmd semaphore");
00095 
00096         utils->icmd.took_semaphore = FALSE;
00097 read_err:
00098 semaphore_not_taken:
00099 invalid_param:
00100         return status;
00101 }
00102 
00103 static
00104 mlx_status
00105 mlx_icmd_init(
00106                                 IN mlx_utils *utils
00107                                 )
00108 {
00109         mlx_status status = MLX_SUCCESS;
00110 
00111         if (utils == NULL) {
00112                 status = MLX_INVALID_PARAMETER;
00113                 goto invalid_param;
00114         }
00115         if (utils->icmd.icmd_opened == TRUE) {
00116                 goto already_opened;
00117         }
00118 
00119         utils->icmd.took_semaphore = FALSE;
00120 
00121         status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
00122                         MLX_ICMD_MB_SIZE_ADDR, &utils->icmd.max_cmd_size);
00123         MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd mail box size");
00124 
00125         utils->icmd.icmd_opened = TRUE;
00126 read_err:
00127 already_opened:
00128 invalid_param:
00129         return status;
00130 }
00131 
00132 static
00133 mlx_status
00134 mlx_icmd_set_opcode(
00135                                 IN mlx_utils *utils,
00136                                 IN mlx_uint16 opcode
00137                                 )
00138 {
00139         mlx_status status = MLX_SUCCESS;
00140         mlx_uint32 buffer;
00141 
00142         if (utils == NULL) {
00143                 status = MLX_INVALID_PARAMETER;
00144                 goto invalid_param;
00145         }
00146 
00147         status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
00148                                 MLX_ICMD_CTRL_ADDR, &buffer);
00149         MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd ctrl");
00150 
00151 #define MLX_ICMD_OPCODE_ALIGN 16
00152 #define MLX_ICMD_OPCODE_MASK 0xffff
00153 
00154         buffer = buffer & ~(MLX_ICMD_OPCODE_MASK << MLX_ICMD_OPCODE_ALIGN);
00155         buffer = buffer | (opcode << MLX_ICMD_OPCODE_ALIGN);
00156 
00157         status = mlx_pci_gw_write( utils, PCI_GW_SPACE_ALL_ICMD,
00158                                         MLX_ICMD_CTRL_ADDR, buffer);
00159         MLX_CHECK_STATUS(utils, status, write_err, "failed to write icmd ctrl");
00160 write_err:
00161 read_err:
00162 invalid_param:
00163         return status;
00164 }
00165 
00166 static
00167 mlx_status
00168 mlx_icmd_go(
00169                         IN mlx_utils *utils
00170                         )
00171 {
00172         mlx_status status = MLX_SUCCESS;
00173         mlx_uint32 buffer;
00174         mlx_uint32 busy;
00175         mlx_uint32 wait_iteration = 0;
00176 
00177         if (utils == NULL) {
00178                 status = MLX_INVALID_PARAMETER;
00179                 goto invalid_param;
00180         }
00181 
00182         status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
00183                                 MLX_ICMD_CTRL_ADDR, &buffer);
00184         MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd ctrl");
00185 
00186 #define MLX_ICMD_BUSY_ALIGN 0
00187 #define MLX_ICMD_BUSY_MASK 0x1
00188 
00189         busy = (buffer >> MLX_ICMD_BUSY_ALIGN) & MLX_ICMD_BUSY_MASK;
00190         if (busy != 0) {
00191                 status = MLX_FAILED;
00192                 goto already_busy;
00193         }
00194 
00195         buffer = buffer | (1 << MLX_ICMD_BUSY_ALIGN);
00196 
00197         status = mlx_pci_gw_write( utils, PCI_GW_SPACE_ALL_ICMD,
00198                                         MLX_ICMD_CTRL_ADDR, buffer);
00199         MLX_CHECK_STATUS(utils, status, write_err, "failed to write icmd ctrl");
00200 
00201 #define MLX_ICMD_BUSY_MAX_ITERATIONS 1024
00202         do {
00203                 if (++wait_iteration > MLX_ICMD_BUSY_MAX_ITERATIONS) {
00204                         status = MLX_FAILED;
00205                         MLX_DEBUG_ERROR(utils, "ICMD time out");
00206                         goto busy_timeout;
00207                 }
00208 
00209                 mlx_utils_delay_in_ms(10);
00210                 status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
00211                                         MLX_ICMD_CTRL_ADDR, &buffer);
00212                 MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd ctrl");
00213                 busy = (buffer >> MLX_ICMD_BUSY_ALIGN) & MLX_ICMD_BUSY_MASK;
00214         } while (busy != 0);
00215 
00216 busy_timeout:
00217 write_err:
00218 already_busy:
00219 read_err:
00220 invalid_param:
00221         return status;
00222 }
00223 
00224 static
00225 mlx_status
00226 mlx_icmd_get_status(
00227                         IN mlx_utils *utils,
00228                         OUT mlx_uint32 *out_status
00229                         )
00230 {
00231         mlx_status status = MLX_SUCCESS;
00232         mlx_uint32 buffer;
00233 
00234         if (utils == NULL || out_status == NULL) {
00235                 status = MLX_INVALID_PARAMETER;
00236                 goto invalid_param;
00237         }
00238 
00239         status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
00240                                 MLX_ICMD_CTRL_ADDR, &buffer);
00241         MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd ctrl");
00242 
00243 #define MLX_ICMD_STATUS_ALIGN 8
00244 #define MLX_ICMD_STATUS_MASK 0xff
00245 
00246         *out_status = (buffer >> MLX_ICMD_STATUS_ALIGN) & MLX_ICMD_STATUS_MASK;
00247 
00248 read_err:
00249 invalid_param:
00250         return status;
00251 }
00252 
00253 static
00254 mlx_status
00255 mlx_icmd_write_buffer(
00256                 IN mlx_utils *utils,
00257                 IN mlx_void* data,
00258                 IN mlx_uint32 data_size
00259                 )
00260 {
00261         mlx_status status = MLX_SUCCESS;
00262         mlx_uint32 data_offset = 0;
00263         mlx_size dword_size = sizeof(mlx_uint32);
00264 
00265         if (utils == NULL || data == NULL) {
00266                 status = MLX_INVALID_PARAMETER;
00267                 goto invalid_param;
00268         }
00269 
00270         for (data_offset = 0 ; data_offset*dword_size < data_size ; data_offset++) {
00271                 status = mlx_pci_gw_write( utils, PCI_GW_SPACE_ALL_ICMD,
00272                                                         MLX_ICMD_MB_ADDR + data_offset*dword_size,
00273                                                         ((mlx_uint32*)data)[data_offset]);
00274                 MLX_CHECK_STATUS(utils, status, write_err, "failed to write icmd MB");
00275         }
00276 write_err:
00277 invalid_param:
00278         return status;
00279 }
00280 
00281 
00282 static
00283 mlx_status
00284 mlx_icmd_read_buffer(
00285                 IN mlx_utils *utils,
00286                 OUT mlx_void* data,
00287                 IN mlx_uint32 data_size
00288                 )
00289 {
00290         mlx_status status = MLX_SUCCESS;
00291         mlx_uint32 data_offset = 0;
00292         mlx_size dword_size = sizeof(mlx_uint32);
00293 
00294         if (utils == NULL || data == NULL) {
00295                 status = MLX_INVALID_PARAMETER;
00296                 goto invalid_param;
00297         }
00298 
00299         for (data_offset = 0 ; data_offset*dword_size < data_size ; data_offset++) {
00300                 status = mlx_pci_gw_read( utils, PCI_GW_SPACE_ALL_ICMD,
00301                                                         MLX_ICMD_MB_ADDR + data_offset*dword_size,
00302                                                         (mlx_uint32*)data + data_offset);
00303                 MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd MB");
00304         }
00305 read_err:
00306 invalid_param:
00307         return status;
00308 }
00309 mlx_status
00310 mlx_icmd_send_command(
00311                                 IN mlx_utils *utils,
00312                                 IN  mlx_uint16 opcode,
00313                                 IN OUT mlx_void* data,
00314                                 IN mlx_uint32 write_data_size,
00315                                 IN mlx_uint32 read_data_size
00316                                 )
00317 {
00318         mlx_status status = MLX_SUCCESS;
00319         mlx_uint32 icmd_status = 0;
00320 
00321         if (utils == NULL || data == NULL) {
00322                 status = MLX_INVALID_PARAMETER;
00323                 goto invalid_param;
00324         }
00325         status = mlx_icmd_init(utils);
00326         MLX_CHECK_STATUS(utils, status, open_err, "failed to open icmd");
00327 
00328         if (write_data_size > utils->icmd.max_cmd_size ||
00329                         read_data_size > utils->icmd.max_cmd_size) {
00330                 status = MLX_INVALID_PARAMETER;
00331                 goto size_err;
00332         }
00333 
00334         status = mlx_icmd_get_semaphore(utils);
00335         MLX_CHECK_STATUS(utils, status, semaphore_err, "failed to get icmd semaphore");
00336 
00337         status = mlx_icmd_set_opcode(utils, opcode);
00338         MLX_CHECK_STATUS(utils, status, opcode_err, "failed to set icmd opcode");
00339 
00340         if (write_data_size != 0) {
00341                 status = mlx_icmd_write_buffer(utils, data, write_data_size);
00342                 MLX_CHECK_STATUS(utils, status, opcode_err, "failed to write icmd MB");
00343         }
00344 
00345         status = mlx_icmd_go(utils);
00346         MLX_CHECK_STATUS(utils, status, go_err, "failed to activate icmd");
00347 
00348         status = mlx_icmd_get_status(utils, &icmd_status);
00349         MLX_CHECK_STATUS(utils, status, get_status_err, "failed to set icmd opcode");
00350 
00351         if (icmd_status != 0) {
00352                 MLX_DEBUG_ERROR(utils, "icmd failed with status = %d\n", icmd_status);
00353                 status = MLX_FAILED;
00354                 goto icmd_failed;
00355         }
00356         if (read_data_size != 0) {
00357                 status = mlx_icmd_read_buffer(utils, data, read_data_size);
00358                 MLX_CHECK_STATUS(utils, status, read_err, "failed to read icmd MB");
00359         }
00360 read_err:
00361 icmd_failed:
00362 get_status_err:
00363 go_err:
00364 opcode_err:
00365         mlx_icmd_clear_semaphore(utils);
00366 semaphore_err:
00367 size_err:
00368 open_err:
00369 invalid_param:
00370         return status;
00371 }