iPXE
mlx_device.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/mlx_device.h"
00023 #include "../include/mlx_cmd.h"
00024 #include "../../mlx_utils/include/public/mlx_bail.h"
00025 #include "../../mlx_utils/include/public/mlx_pci.h"
00026 #include "../../mlx_utils/include/public/mlx_memory.h"
00027 #include "../../mlx_utils/include/public/mlx_logging.h"
00028 
00029 #define CHECK_BIT(field, offset)        (((field) & ((mlx_uint32)1 << (offset))) != 0)
00030 
00031 static
00032 mlx_status
00033 check_nodnic_interface_supported(
00034                                                         IN nodnic_device_priv* device_priv,
00035                                                         OUT mlx_boolean *out
00036                                                         )
00037 {
00038         mlx_status status = MLX_SUCCESS;
00039         mlx_uint32      output = 0;
00040         status = nodnic_cmd_read(device_priv, NODNIC_NIC_INTERFACE_SUPPORTED_OFFSET,
00041                         &output);
00042         MLX_FATAL_CHECK_STATUS(status, read_error, "failed to read nic_interface_supported");
00043         *out = CHECK_BIT(output, NODNIC_NIC_INTERFACE_SUPPORTED_BIT);
00044 read_error:
00045         return status;
00046 }
00047 
00048 static
00049 mlx_status
00050 wait_for_device_initialization(
00051                                                         IN nodnic_device_priv* device_priv
00052                                                         )
00053 {
00054         mlx_status status = MLX_SUCCESS;
00055         mlx_uint8 try = 0;
00056         mlx_uint32                      buffer = 0;
00057 
00058 #define CHECK_DEVICE_INIT_TRIES 10
00059         for( ; try < CHECK_DEVICE_INIT_TRIES ; try++){
00060                 status = nodnic_cmd_read(device_priv, NODNIC_INITIALIZING_OFFSET, &buffer);
00061                 MLX_CHECK_STATUS(device_priv, status, read_error, "failed to read initializing");
00062                 if( !CHECK_BIT(buffer, NODNIC_INITIALIZING_BIT)){
00063                         goto init_done;
00064                 }
00065                 mlx_utils_delay_in_ms(100);
00066         }
00067         status = MLX_FAILED;
00068 read_error:
00069 init_done:
00070         return status;
00071 }
00072 
00073 static
00074 mlx_status
00075 disable_nodnic_inteface(
00076                                                 IN nodnic_device_priv *device_priv
00077                                                 )
00078 {
00079         mlx_status                      status = MLX_SUCCESS;
00080         mlx_uint32                      buffer = 0;
00081 
00082         buffer = (1 << NODNIC_DISABLE_INTERFACE_BIT);
00083         status = nodnic_cmd_write(device_priv, NODNIC_CMDQ_PHY_ADDR_LOW_OFFSET, buffer);
00084         MLX_FATAL_CHECK_STATUS(status, write_err, "failed to write cmdq_phy_addr + nic_interface");
00085 
00086         status = wait_for_device_initialization(device_priv);
00087         MLX_FATAL_CHECK_STATUS(status, init_err, "failed to initialize device");
00088 init_err:
00089 write_err:
00090         return status;
00091 }
00092 static
00093 mlx_status
00094 nodnic_device_start_nodnic(
00095                                 IN nodnic_device_priv *device_priv
00096                                 )
00097 {
00098         mlx_status                      status = MLX_SUCCESS;
00099         mlx_uint32                      buffer = 0;
00100         mlx_boolean                     nodnic_supported = 0;
00101 
00102         status = wait_for_device_initialization(device_priv);
00103         MLX_FATAL_CHECK_STATUS(status, wait_for_fw_err, "failed to initialize device");
00104 
00105         status = check_nodnic_interface_supported(device_priv, &nodnic_supported);
00106         MLX_FATAL_CHECK_STATUS(status, read_err,"failed to check nic_interface_supported");
00107 
00108         if(     nodnic_supported == 0 ){
00109                 status = MLX_UNSUPPORTED;
00110                 goto nodnic_unsupported;
00111         }
00112         buffer =  (1 << NODNIC_NIC_INTERFACE_BIT);
00113         status = nodnic_cmd_write(device_priv, NODNIC_NIC_INTERFACE_OFFSET, buffer);
00114         MLX_FATAL_CHECK_STATUS(status, write_err, "failed to write cmdq_phy_addr + nic_interface");
00115 
00116         status = wait_for_device_initialization(device_priv);
00117         MLX_FATAL_CHECK_STATUS(status, init_err, "failed to initialize device");
00118 init_err:
00119 read_err:
00120 write_err:
00121 nodnic_unsupported:
00122 wait_for_fw_err:
00123         return status;
00124 }
00125 
00126 static
00127 mlx_status
00128 nodnic_device_get_nodnic_data(
00129                                 IN nodnic_device_priv *device_priv
00130                                 )
00131 {
00132         mlx_status                      status = MLX_SUCCESS;
00133         mlx_uint32                      buffer = 0;
00134 
00135         status = nodnic_cmd_read(device_priv, NODNIC_LOCATION_OFFSET, &device_priv->device_offset);
00136         MLX_FATAL_CHECK_STATUS(status, nodnic_offset_read_err, "failed to read nodnic offset");
00137 
00138         status = nodnic_cmd_read(device_priv,
00139                         device_priv->device_offset + NODNIC_REVISION_OFFSET, &buffer);
00140         MLX_FATAL_CHECK_STATUS(status, nodnic_revision_read_err, "failed to read nodnic revision");
00141 
00142         device_priv->nodnic_revision = (buffer >> 24) & 0xFF;
00143         if( device_priv->nodnic_revision != NODIC_SUPPORTED_REVISION ){
00144                 MLX_DEBUG_ERROR(device_priv, "nodnic revision not supported\n");
00145                 status = MLX_UNSUPPORTED;
00146                 goto unsupported_revision;
00147         }
00148 
00149         status = nodnic_cmd_read(device_priv,
00150                         device_priv->device_offset + NODNIC_HARDWARE_FORMAT_OFFSET, &buffer);
00151         MLX_FATAL_CHECK_STATUS(status, nodnic_hardware_format_read_err, "failed to read nodnic revision");
00152         device_priv->hardware_format = (buffer >> 16) & 0xFF;
00153 
00154         return status;
00155 
00156 unsupported_revision:
00157 nodnic_hardware_format_read_err:
00158 nodnic_offset_read_err:
00159 nodnic_revision_read_err:
00160         disable_nodnic_inteface(device_priv);
00161         return status;
00162 }
00163 
00164 mlx_status
00165 nodnic_device_clear_int (
00166                                 IN nodnic_device_priv *device_priv
00167                                 )
00168 {
00169         mlx_status                      status = MLX_SUCCESS;
00170         mlx_uint32                      disable = 1;
00171 #ifndef DEVICE_CX3
00172         status = nodnic_cmd_write(device_priv, NODNIC_NIC_DISABLE_INT_OFFSET, disable);
00173         MLX_CHECK_STATUS(device_priv, status, clear_int_done, "failed writing to disable_bit");
00174 #else
00175         mlx_utils *utils = device_priv->utils;
00176         mlx_uint64 clear_int = (mlx_uintn)(device_priv->crspace_clear_int);
00177         mlx_uint32 swapped = 0;
00178 
00179         if (device_priv->device_cap.crspace_doorbells == 0) {
00180                 status = nodnic_cmd_write(device_priv, NODNIC_NIC_DISABLE_INT_OFFSET, disable);
00181                 MLX_CHECK_STATUS(device_priv, status, clear_int_done, "failed writing to disable_bit");
00182         } else {
00183                 /* Write the new index and update FW that new data was submitted */
00184                 disable = 0x80000000;
00185                 mlx_memory_cpu_to_be32(utils, disable, &swapped);
00186                 mlx_pci_mem_write (utils, MlxPciWidthUint32, 0, clear_int, 1, &swapped);
00187                 mlx_pci_mem_read (utils, MlxPciWidthUint32, 0, clear_int, 1, &swapped);
00188         }
00189 #endif
00190 clear_int_done:
00191         return status;
00192 }
00193 
00194 mlx_status
00195 nodnic_device_init(
00196                                 IN nodnic_device_priv *device_priv
00197                                 )
00198 {
00199         mlx_status                      status = MLX_SUCCESS;
00200 
00201         if( device_priv == NULL ){
00202                 status = MLX_INVALID_PARAMETER;
00203                 goto parm_err;
00204         }
00205         status = nodnic_device_start_nodnic(device_priv);
00206         MLX_FATAL_CHECK_STATUS(status, start_nodnic_err, "nodnic_device_start_nodnic failed");
00207 
00208         status = nodnic_device_get_nodnic_data(device_priv);
00209         MLX_FATAL_CHECK_STATUS(status, data_err, "nodnic_device_get_nodnic_data failed");
00210         return status;
00211 data_err:
00212 start_nodnic_err:
00213 parm_err:
00214         return status;
00215 }
00216 
00217 mlx_status
00218 nodnic_device_teardown(
00219                                 IN nodnic_device_priv *device_priv
00220                                 )
00221 {
00222         mlx_status                      status = MLX_SUCCESS;
00223         status = disable_nodnic_inteface(device_priv);
00224         MLX_FATAL_CHECK_STATUS(status, disable_failed, "failed to disable nodnic interface");
00225 disable_failed:
00226         return status;
00227 }
00228 
00229 mlx_status
00230 nodnic_device_get_cap(
00231                                 IN nodnic_device_priv *device_priv
00232                                 )
00233 {
00234         mlx_status                                      status = MLX_SUCCESS;
00235         nodnic_device_capabilites       *device_cap = NULL;
00236         mlx_uint32                                      buffer = 0;
00237         mlx_uint64                                      guid_l = 0;
00238         mlx_uint64                                      guid_h = 0;
00239         if( device_priv == NULL ){
00240                 status = MLX_INVALID_PARAMETER;
00241                 goto parm_err;
00242         }
00243 
00244         device_cap = &device_priv->device_cap;
00245 
00246         //get device capabilities
00247         status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x0, &buffer);
00248         MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic first dword");
00249 
00250 #define NODNIC_DEVICE_SUPPORT_MAC_FILTERS_OFFSET 15
00251 #define NODNIC_DEVICE_SUPPORT_PROMISC_FILTER_OFFSET 14
00252 #define NODNIC_DEVICE_SUPPORT_PROMISC_MULT_FILTER_OFFSET 13
00253 #define NODNIC_DEVICE_LOG_WORKING_BUFFER_SIZE_OFFSET 8
00254 #define NODNIC_DEVICE_LOG_WORKING_BUFFER_SIZE_MASK 0x7
00255 #define NODNIC_DEVICE_LOG_PKEY_TABLE_SIZE_OFFSET 4
00256 #define NODNIC_DEVICE_LOG_PKEY_TABLE_SIZE_MASK 0xF
00257 #define NODNIC_DEVICE_NUM_PORTS_OFFSET 0
00258         device_cap->support_mac_filters = CHECK_BIT(buffer, NODNIC_DEVICE_SUPPORT_MAC_FILTERS_OFFSET);
00259 
00260         device_cap->support_promisc_filter = CHECK_BIT(buffer, NODNIC_DEVICE_SUPPORT_PROMISC_FILTER_OFFSET);
00261 
00262         device_cap->support_promisc_multicast_filter = CHECK_BIT(buffer, NODNIC_DEVICE_SUPPORT_PROMISC_MULT_FILTER_OFFSET);
00263 
00264         device_cap->log_working_buffer_size =
00265                         (buffer >> NODNIC_DEVICE_LOG_WORKING_BUFFER_SIZE_OFFSET) & NODNIC_DEVICE_LOG_WORKING_BUFFER_SIZE_MASK;
00266 
00267         device_cap->log_pkey_table_size =
00268                         (buffer >> NODNIC_DEVICE_LOG_PKEY_TABLE_SIZE_OFFSET) & NODNIC_DEVICE_LOG_PKEY_TABLE_SIZE_MASK;
00269 
00270         device_cap->num_ports = CHECK_BIT(buffer, NODNIC_DEVICE_NUM_PORTS_OFFSET) + 1;
00271 
00272 #ifdef DEVICE_CX3
00273 #define NODNIC_DEVICE_CRSPACE_DB_OFFSET 12
00274         device_cap->crspace_doorbells = CHECK_BIT(buffer, NODNIC_DEVICE_CRSPACE_DB_OFFSET);
00275 #endif
00276 
00277         status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x4, &buffer);
00278         MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic second dword");
00279 
00280 #define NODNIC_DEVICE_LOG_MAX_RING_SIZE_OFFSET 24
00281 #define NODNIC_DEVICE_LOG_MAX_RING_SIZE_MASK 0x3F
00282 #define NODNIC_DEVICE_PD_MASK 0xFFFFFF
00283         device_cap->log_max_ring_size =
00284                         (buffer >> NODNIC_DEVICE_LOG_MAX_RING_SIZE_OFFSET) & NODNIC_DEVICE_LOG_MAX_RING_SIZE_MASK;
00285 
00286         //get device magic numbers
00287         device_priv->pd = buffer & NODNIC_DEVICE_PD_MASK;
00288 
00289         status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x8, &buffer);
00290         MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic third dword");
00291         device_priv->lkey = buffer;
00292 
00293 #ifdef DEVICE_CX3
00294         if ( device_cap->crspace_doorbells ) {
00295                 status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x18, &buffer);
00296                 MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic_crspace_clear_int address");
00297                 device_priv->crspace_clear_int = device_priv->utils->config + buffer;
00298         }
00299 #endif
00300 
00301         status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x10, (mlx_uint32*)&guid_h);
00302         MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic guid_h");
00303         status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x14, (mlx_uint32*)&guid_l);
00304         MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic guid_l");
00305         device_priv->device_guid = guid_l | (guid_h << 32);
00306 
00307 #define NODNIC_DEVICE_SUPPORT_RX_PI_DMA_OFFSET 31
00308 #define NODNIC_DEVICE_SUPPORT_RX_PI_DMA_MASK 0x1
00309 #define NODNIC_DEVICE_SUPPORT_UAR_TRX_DB_OFFSET 29
00310 #define NODNIC_DEVICE_SUPPORT_UAR_TRX_DB_MASK 0x1
00311 #define NODNIC_DEVICE_SUPPORT_BAR_CQ_CONTROL_OFFSET 27
00312 #define NODNIC_DEVICE_SUPPORT_BAR_CQ_CONTROL_MASK 0x1
00313         status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x1c, &buffer);
00314         MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic support_rx_pi_dma");
00315         if ( sizeof ( mlx_uintn ) == sizeof ( mlx_uint32 ) ) {
00316                 device_cap->support_rx_pi_dma = FALSE;
00317                 device_cap->support_uar_tx_db = FALSE;
00318                 device_cap->support_bar_cq_ctrl = FALSE;
00319         } else {
00320                 device_cap->support_rx_pi_dma = CHECK_BIT(buffer, NODNIC_DEVICE_SUPPORT_RX_PI_DMA_OFFSET);
00321                 device_cap->support_uar_tx_db = CHECK_BIT(buffer, NODNIC_DEVICE_SUPPORT_UAR_TRX_DB_OFFSET);
00322                 device_cap->support_bar_cq_ctrl = CHECK_BIT(buffer, NODNIC_DEVICE_SUPPORT_BAR_CQ_CONTROL_OFFSET);
00323         }
00324 
00325 #define NODNIC_DEVICE_LOG_UAR_PAGE_SIZE_OFFSET 0
00326 #define NODNIC_DEVICE_LOG_UAR_PAGE_SIZE_MASK 0xFF
00327         status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x20, &buffer);
00328         MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic log_uar_page_size");
00329         device_cap->log_uar_page_size = ( buffer >> NODNIC_DEVICE_LOG_UAR_PAGE_SIZE_OFFSET) & NODNIC_DEVICE_LOG_UAR_PAGE_SIZE_MASK;
00330 read_err:
00331 parm_err:
00332         return status;
00333 }
00334 
00335 mlx_status
00336 nodnic_device_get_fw_version(
00337                                 IN nodnic_device_priv *device_priv,
00338                                 OUT mlx_uint16          *fw_ver_minor,
00339                                 OUT mlx_uint16          *fw_ver_sub_minor,
00340                                 OUT mlx_uint16          *fw_ver_major
00341                                 ){
00342         mlx_status              status = MLX_SUCCESS;
00343         mlx_uint32              buffer = 0;
00344 
00345         if( device_priv == NULL ){
00346                 status = MLX_INVALID_PARAMETER;
00347                 goto parm_err;
00348         }
00349 
00350         status = nodnic_cmd_read(device_priv, 0x0, &buffer);
00351         MLX_CHECK_STATUS(device_priv, status, read_err, "failed to read fw revision major and minor");
00352 
00353         *fw_ver_minor = (mlx_uint16)(buffer >> 16);
00354         *fw_ver_major = (mlx_uint16)buffer;
00355 
00356         status = nodnic_cmd_read(device_priv, 0x4, &buffer);
00357         MLX_CHECK_STATUS(device_priv, status, read_err, "failed to read fw revision sub minor");
00358 
00359         *fw_ver_sub_minor = (mlx_uint16)buffer;
00360 read_err:
00361 parm_err:
00362         return status;
00363 }