iPXE
flexboot_nodnic.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 <stdio.h>
00023 #include <unistd.h>
00024 #include <errno.h>
00025 #include <ipxe/pci.h>
00026 #include <ipxe/malloc.h>
00027 #include <ipxe/umalloc.h>
00028 #include <ipxe/if_ether.h>
00029 #include <ipxe/ethernet.h>
00030 #include <ipxe/vlan.h>
00031 #include <ipxe/io.h>
00032 #include "flexboot_nodnic.h"
00033 #include "mlx_utils/include/public/mlx_types.h"
00034 #include "mlx_utils/include/public/mlx_utils.h"
00035 #include "mlx_utils/include/public/mlx_bail.h"
00036 #include "mlx_nodnic/include/mlx_cmd.h"
00037 #include "mlx_utils/include/public/mlx_memory.h"
00038 #include "mlx_utils/include/public/mlx_pci.h"
00039 #include "mlx_nodnic/include/mlx_device.h"
00040 #include "mlx_nodnic/include/mlx_port.h"
00041 #include <byteswap.h>
00042 #include <usr/ifmgmt.h>
00043 #include "mlx_utils/mlx_lib/mlx_nvconfig/mlx_nvconfig.h"
00044 #include "mlx_utils/mlx_lib/mlx_nvconfig/mlx_nvconfig_defaults.h"
00045 #include "mlx_utils/include/public/mlx_pci_gw.h"
00046 #include "mlx_utils/mlx_lib/mlx_vmac/mlx_vmac.h"
00047 #include "mlx_utils/mlx_lib/mlx_mtu/mlx_mtu.h"
00048 
00049 /***************************************************************************
00050  *
00051  * Completion queue operations
00052  *
00053  ***************************************************************************
00054  */
00055 static int flexboot_nodnic_arm_cq ( struct flexboot_nodnic_port *port ) {
00056 #ifndef DEVICE_CX3
00057         mlx_uint32 val32 = 0;
00058         union arm_cq_uar cq_uar;
00059 
00060 #define ARM_CQ_UAR_CQ_CI_MASK 0xffffff
00061 #define ARM_CQ_UAR_CMDSN_MASK 3
00062 #define ARM_CQ_UAR_CMDSN_OFFSET 28
00063 #define ARM_CQ_UAR_CQ_CI_OFFSET 0x20
00064         if ( port->port_priv.device->device_cap.support_bar_cq_ctrl ) {
00065                 cq_uar.dword[0] = cpu_to_be32((port->eth_cq->next_idx  & ARM_CQ_UAR_CQ_CI_MASK) |
00066                                 ((port->cmdsn++ & ARM_CQ_UAR_CMDSN_MASK) << ARM_CQ_UAR_CMDSN_OFFSET));
00067                 cq_uar.dword[1] = cpu_to_be32(port->eth_cq->cqn);
00068                 wmb();
00069                 writeq(cq_uar.qword, port->port_priv.device->uar.virt + ARM_CQ_UAR_CQ_CI_OFFSET);
00070                 port->port_priv.arm_cq_doorbell_record->dword[0] = cq_uar.dword[1];
00071                 port->port_priv.arm_cq_doorbell_record->dword[1] = cq_uar.dword[0];
00072         } else {
00073                 val32 = ( port->eth_cq->next_idx & 0xffffff );
00074                 if ( nodnic_port_set ( & port->port_priv, nodnic_port_option_arm_cq, val32 ) ) {
00075                         MLX_DEBUG_ERROR( port->port_priv.device, "Failed to arm the CQ\n" );
00076                         return MLX_FAILED;
00077                 }
00078         }
00079 #else
00080         mlx_utils *utils = port->port_priv.device->utils;
00081         nodnic_port_data_flow_gw *ptr = port->port_priv.data_flow_gw;
00082         mlx_uint32 data = 0;
00083         mlx_uint32 val = 0;
00084 
00085         if ( port->port_priv.device->device_cap.crspace_doorbells == 0 ) {
00086                 val = ( port->eth_cq->next_idx & 0xffff );
00087                 if ( nodnic_port_set ( & port->port_priv, nodnic_port_option_arm_cq, val ) ) {
00088                         MLX_DEBUG_ERROR( port->port_priv.device, "Failed to arm the CQ\n" );
00089                         return MLX_FAILED;
00090                 }
00091         } else {
00092                 /* Arming the CQ with CQ CI should be with this format -
00093                  * 16 bit - CQ CI - same endianness as the FW (don't swap bytes)
00094                  * 15 bit - reserved
00095                  *  1 bit - arm CQ - must correct the endianness with the reserved above */
00096                 data = ( ( ( port->eth_cq->next_idx & 0xffff ) << 16 ) | 0x0080 );
00097                 /* Write the new index and update FW that new data was submitted */
00098                 mlx_pci_mem_write ( utils, MlxPciWidthUint32, 0,
00099                                 ( mlx_uintn ) & ( ptr->armcq_cq_ci_dword ), 1, &data );
00100         }
00101 #endif
00102         return 0;
00103 }
00104 
00105 /**
00106  * Create completion queue
00107  *
00108  * @v ibdev             Infiniband device
00109  * @v cq                Completion queue
00110  * @ret rc              Return status code
00111  */
00112 static int flexboot_nodnic_create_cq ( struct ib_device *ibdev ,
00113                               struct ib_completion_queue *cq ) {
00114         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00115         struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
00116         struct flexboot_nodnic_completion_queue *flexboot_nodnic_cq;
00117         mlx_status status = MLX_SUCCESS;
00118         mlx_uint32 cqn;
00119 
00120         flexboot_nodnic_cq = (struct flexboot_nodnic_completion_queue *)
00121                         zalloc(sizeof(*flexboot_nodnic_cq));
00122         if ( flexboot_nodnic_cq == NULL ) {
00123                 status = MLX_OUT_OF_RESOURCES;
00124                 goto qp_alloc_err;
00125         }
00126 
00127         status = nodnic_port_create_cq(&port->port_priv,
00128                         cq->num_cqes *
00129                         flexboot_nodnic->callbacks->get_cqe_size(),
00130                         &flexboot_nodnic_cq->nodnic_completion_queue
00131                         );
00132         MLX_FATAL_CHECK_STATUS(status, create_err,
00133                                 "nodnic_port_create_cq failed");
00134         flexboot_nodnic->callbacks->cqe_set_owner(
00135                         flexboot_nodnic_cq->nodnic_completion_queue->cq_virt,
00136                         cq->num_cqes);
00137         if ( flexboot_nodnic->device_priv.device_cap.support_bar_cq_ctrl ) {
00138                 status = nodnic_port_query(&port->port_priv,
00139                                         nodnic_port_option_cq_n_index,
00140                                         (mlx_uint32 *)&cqn );
00141                 MLX_FATAL_CHECK_STATUS(status, read_cqn_err,
00142                                 "failed to query cqn");
00143                 cq->cqn = cqn;
00144         }
00145 
00146         ib_cq_set_drvdata ( cq, flexboot_nodnic_cq );
00147         return status;
00148 read_cqn_err:
00149 create_err:
00150         free(flexboot_nodnic_cq);
00151 qp_alloc_err:
00152         return status;
00153 }
00154 
00155 /**
00156  * Destroy completion queue
00157  *
00158  * @v ibdev             Infiniband device
00159  * @v cq                Completion queue
00160  */
00161 static void flexboot_nodnic_destroy_cq ( struct ib_device *ibdev ,
00162                                 struct ib_completion_queue *cq ) {
00163         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00164         struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
00165         struct flexboot_nodnic_completion_queue *flexboot_nodnic_cq = ib_cq_get_drvdata ( cq );
00166 
00167         nodnic_port_destroy_cq(&port->port_priv,
00168                         flexboot_nodnic_cq->nodnic_completion_queue);
00169 
00170         free(flexboot_nodnic_cq);
00171 }
00172 
00173 static
00174 struct ib_work_queue * flexboot_nodnic_find_wq ( struct ib_device *ibdev ,
00175                                                         struct ib_completion_queue *cq,
00176                                                         unsigned long qpn, int is_send ) {
00177         struct ib_work_queue *wq;
00178         struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp;
00179         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00180         struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
00181         struct nodnic_ring  *ring;
00182         mlx_uint32 out_qpn;
00183         list_for_each_entry ( wq, &cq->work_queues, list ) {
00184                 flexboot_nodnic_qp = ib_qp_get_drvdata ( wq->qp );
00185                 if( wq->is_send == is_send && wq->is_send == TRUE ) {
00186                         ring = &flexboot_nodnic_qp->nodnic_queue_pair->send.nodnic_ring;
00187                 } else if( wq->is_send == is_send && wq->is_send == FALSE ) {
00188                         ring = &flexboot_nodnic_qp->nodnic_queue_pair->receive.nodnic_ring;
00189                 } else {
00190                         continue;
00191                 }
00192                 nodnic_port_get_qpn(&port->port_priv, ring, &out_qpn);
00193                 if ( out_qpn == qpn )
00194                         return wq;
00195         }
00196         return NULL;
00197 }
00198 
00199 /**
00200  * Handle completion
00201  *
00202  * @v ibdev             Infiniband device
00203  * @v cq                Completion queue
00204  * @v cqe               Hardware completion queue entry
00205  * @ret rc              Return status code
00206  */
00207 static int flexboot_nodnic_complete ( struct ib_device *ibdev,
00208                              struct ib_completion_queue *cq,
00209                                  struct cqe_data *cqe_data ) {
00210         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00211         struct ib_work_queue *wq;
00212         struct ib_queue_pair *qp;
00213         struct io_buffer *iobuf;
00214         struct ib_address_vector recv_dest;
00215         struct ib_address_vector recv_source;
00216         unsigned long qpn;
00217         unsigned long wqe_idx;
00218         unsigned long wqe_idx_mask;
00219         size_t len;
00220         int rc = 0;
00221 
00222         /* Parse completion */
00223         qpn = cqe_data->qpn;
00224 
00225         if ( cqe_data->is_error == TRUE ) {
00226                 DBGC ( flexboot_nodnic, "flexboot_nodnic %p CQN %#lx syndrome %x vendor %x\n",
00227                                 flexboot_nodnic, cq->cqn, cqe_data->syndrome,
00228                                 cqe_data->vendor_err_syndrome );
00229                 rc = -EIO;
00230                 /* Don't return immediately; propagate error to completer */
00231         }
00232 
00233         /* Identify work queue */
00234         wq = flexboot_nodnic_find_wq( ibdev, cq, qpn, cqe_data->is_send );
00235         if ( wq == NULL ) {
00236                 DBGC ( flexboot_nodnic,
00237                                 "flexboot_nodnic %p CQN %#lx unknown %s QPN %#lx\n",
00238                                 flexboot_nodnic, cq->cqn,
00239                                 ( cqe_data->is_send ? "send" : "recv" ), qpn );
00240                 return -EIO;
00241         }
00242         qp = wq->qp;
00243 
00244         /* Identify work queue entry */
00245         wqe_idx = cqe_data->wqe_counter;
00246         wqe_idx_mask = ( wq->num_wqes - 1 );
00247         DBGCP ( flexboot_nodnic,
00248                         "NODNIC %p CQN %#lx QPN %#lx %s WQE %#lx completed:\n",
00249                         flexboot_nodnic, cq->cqn, qp->qpn,
00250                         ( cqe_data->is_send ? "send" : "recv" ),
00251                 wqe_idx );
00252 
00253         /* Identify I/O buffer */
00254         iobuf = wq->iobufs[wqe_idx & wqe_idx_mask];
00255         if ( iobuf == NULL ) {
00256                 DBGC ( flexboot_nodnic,
00257                                 "NODNIC %p CQN %#lx QPN %#lx empty %s WQE %#lx\n",
00258                                 flexboot_nodnic, cq->cqn, qp->qpn,
00259                        ( cqe_data->is_send ? "send" : "recv" ), wqe_idx );
00260                 return -EIO;
00261         }
00262         wq->iobufs[wqe_idx & wqe_idx_mask] = NULL;
00263 
00264         if ( cqe_data->is_send == TRUE ) {
00265                 /* Hand off to completion handler */
00266                 ib_complete_send ( ibdev, qp, iobuf, rc );
00267         } else if ( rc != 0 ) {
00268                 /* Propagate error to receive completion handler */
00269                 ib_complete_recv ( ibdev, qp, NULL, NULL, iobuf, rc );
00270         } else {
00271                 /* Set received length */
00272                 len = cqe_data->byte_cnt;
00273                 assert ( len <= iob_tailroom ( iobuf ) );
00274                 iob_put ( iobuf, len );
00275                 memset ( &recv_dest, 0, sizeof ( recv_dest ) );
00276                 recv_dest.qpn = qpn;
00277                 memset ( &recv_source, 0, sizeof ( recv_source ) );
00278                 switch ( qp->type ) {
00279                 case IB_QPT_SMI:
00280                 case IB_QPT_GSI:
00281                 case IB_QPT_UD:
00282                 case IB_QPT_RC:
00283                         break;
00284                 case IB_QPT_ETH:
00285                         break;
00286                 default:
00287                         assert ( 0 );
00288                         return -EINVAL;
00289                 }
00290                 /* Hand off to completion handler */
00291                 ib_complete_recv ( ibdev, qp, &recv_dest,
00292                                 &recv_source, iobuf, rc );
00293         }
00294 
00295         return rc;
00296 }
00297 /**
00298  * Poll completion queue
00299  *
00300  * @v ibdev             Infiniband device
00301  * @v cq                Completion queues
00302  */
00303 static void flexboot_nodnic_poll_cq ( struct ib_device *ibdev,
00304                              struct ib_completion_queue *cq) {
00305         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00306         struct flexboot_nodnic_completion_queue *flexboot_nodnic_cq = ib_cq_get_drvdata ( cq );
00307         void *cqe;
00308         mlx_size cqe_size;
00309         struct cqe_data cqe_data;
00310         unsigned int cqe_idx_mask;
00311         int rc;
00312 
00313         cqe_size = flexboot_nodnic->callbacks->get_cqe_size();
00314         while ( TRUE ) {
00315                 /* Look for completion entry */
00316                 cqe_idx_mask = ( cq->num_cqes - 1 );
00317                 cqe = ((uint8_t *)flexboot_nodnic_cq->nodnic_completion_queue->cq_virt) +
00318                                 cqe_size * (cq->next_idx & cqe_idx_mask);
00319 
00320                 /* TODO: check fill_completion */
00321                 flexboot_nodnic->callbacks->fill_completion(cqe, &cqe_data);
00322                 if ( cqe_data.owner ^
00323                                 ( ( cq->next_idx & cq->num_cqes ) ? 1 : 0 ) ) {
00324                         /* Entry still owned by hardware; end of poll */
00325                         break;
00326                 }
00327                 /* Handle completion */
00328                 rc = flexboot_nodnic_complete ( ibdev, cq, &cqe_data );
00329                 if ( rc != 0 ) {
00330                         DBGC ( flexboot_nodnic, "flexboot_nodnic %p CQN %#lx failed to complete: %s\n",
00331                                         flexboot_nodnic, cq->cqn, strerror ( rc ) );
00332                         DBGC_HDA ( flexboot_nodnic, virt_to_phys ( cqe ),
00333                                    cqe, sizeof ( *cqe ) );
00334                 }
00335 
00336                 /* Update completion queue's index */
00337                 cq->next_idx++;
00338         }
00339 }
00340 /***************************************************************************
00341  *
00342  * Queue pair operations
00343  *
00344  ***************************************************************************
00345  */
00346 
00347 
00348 /**
00349  * Create queue pair
00350  *
00351  * @v ibdev             Infiniband device
00352  * @v qp                Queue pair
00353  * @ret rc              Return status code
00354  */
00355 static int flexboot_nodnic_create_qp ( struct ib_device *ibdev,
00356                               struct ib_queue_pair *qp ) {
00357         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00358         struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
00359         struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp;
00360         mlx_status status = MLX_SUCCESS;
00361 
00362         flexboot_nodnic_qp = (struct flexboot_nodnic_queue_pair *)zalloc(sizeof(*flexboot_nodnic_qp));
00363         if ( flexboot_nodnic_qp == NULL ) {
00364                 status = MLX_OUT_OF_RESOURCES;
00365                 goto qp_alloc_err;
00366         }
00367 
00368         status = nodnic_port_create_qp(&port->port_priv, qp->type,
00369                         qp->send.num_wqes * sizeof(struct nodnic_send_wqbb),
00370                         qp->send.num_wqes,
00371                         qp->recv.num_wqes * sizeof(struct nodnic_recv_wqe),
00372                         qp->recv.num_wqes,
00373                         &flexboot_nodnic_qp->nodnic_queue_pair);
00374         MLX_FATAL_CHECK_STATUS(status, create_err,
00375                         "nodnic_port_create_qp failed");
00376         ib_qp_set_drvdata ( qp, flexboot_nodnic_qp );
00377         return status;
00378 create_err:
00379         free(flexboot_nodnic_qp);
00380 qp_alloc_err:
00381         return status;
00382 }
00383 
00384 /**
00385  * Modify queue pair
00386  *
00387  * @v ibdev             Infiniband device
00388  * @v qp                Queue pair
00389  * @ret rc              Return status code
00390  */
00391 static int flexboot_nodnic_modify_qp ( struct ib_device *ibdev __unused,
00392                               struct ib_queue_pair *qp __unused) {
00393         /*not needed*/
00394         return 0;
00395 }
00396 
00397 /**
00398  * Destroy queue pair
00399  *
00400  * @v ibdev             Infiniband device
00401  * @v qp                Queue pair
00402  */
00403 static void flexboot_nodnic_destroy_qp ( struct ib_device *ibdev,
00404                                 struct ib_queue_pair *qp ) {
00405         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00406         struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
00407         struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp = ib_qp_get_drvdata ( qp );
00408 
00409         nodnic_port_destroy_qp(&port->port_priv, qp->type,
00410                         flexboot_nodnic_qp->nodnic_queue_pair);
00411 
00412         free(flexboot_nodnic_qp);
00413 }
00414 
00415 /***************************************************************************
00416  *
00417  * Work request operations
00418  *
00419  ***************************************************************************
00420  */
00421 
00422 /**
00423  * Post send work queue entry
00424  *
00425  * @v ibdev             Infiniband device
00426  * @v qp                Queue pair
00427  * @v av                Address vector
00428  * @v iobuf             I/O buffer
00429  * @ret rc              Return status code
00430  */
00431 static int flexboot_nodnic_post_send ( struct ib_device *ibdev,
00432                               struct ib_queue_pair *qp,
00433                               struct ib_address_vector *av,
00434                               struct io_buffer *iobuf) {
00435 
00436         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00437         struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp = ib_qp_get_drvdata ( qp );
00438         struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
00439         struct ib_work_queue *wq = &qp->send;
00440         struct nodnic_send_wqbb *wqbb;
00441         nodnic_qp *nodnic_qp = flexboot_nodnic_qp->nodnic_queue_pair;
00442         struct nodnic_send_ring *send_ring = &nodnic_qp->send;
00443         mlx_status status = MLX_SUCCESS;
00444         unsigned int wqe_idx_mask;
00445         unsigned long wqe_idx;
00446 
00447         if ( ( port->port_priv.dma_state == FALSE ) ||
00448                  ( port->port_priv.port_state & NODNIC_PORT_DISABLING_DMA ) ) {
00449                 DBGC ( flexboot_nodnic, "flexboot_nodnic DMA disabled\n");
00450                 status = -ENETDOWN;
00451                 goto post_send_done;
00452         }
00453 
00454         /* Allocate work queue entry */
00455         wqe_idx = wq->next_idx;
00456         wqe_idx_mask = ( wq->num_wqes - 1 );
00457         if ( wq->iobufs[wqe_idx & wqe_idx_mask] ) {
00458                 DBGC ( flexboot_nodnic, "flexboot_nodnic %p QPN %#lx send queue full\n",
00459                                 flexboot_nodnic, qp->qpn );
00460                 status = -ENOBUFS;
00461                 goto post_send_done;
00462         }
00463         wqbb = &send_ring->wqe_virt[wqe_idx & wqe_idx_mask];
00464         wq->iobufs[wqe_idx & wqe_idx_mask] = iobuf;
00465 
00466         assert ( flexboot_nodnic->callbacks->
00467                         fill_send_wqe[qp->type] != NULL );
00468         status = flexboot_nodnic->callbacks->
00469                         fill_send_wqe[qp->type] ( ibdev, qp, av, iobuf,
00470                                         wqbb, wqe_idx );
00471         if ( status != 0 ) {
00472                 DBGC ( flexboot_nodnic, "flexboot_nodnic %p QPN %#lx fill send wqe failed\n",
00473                                 flexboot_nodnic, qp->qpn );
00474                 goto post_send_done;
00475         }
00476 
00477         wq->next_idx++;
00478 
00479         status = port->port_priv.send_doorbell ( &port->port_priv,
00480                                 &send_ring->nodnic_ring, ( mlx_uint16 ) wq->next_idx );
00481         if ( flexboot_nodnic->callbacks->tx_uar_send_doorbell_fn ) {
00482                 flexboot_nodnic->callbacks->tx_uar_send_doorbell_fn ( ibdev, wqbb );
00483         }
00484         if ( status != 0 ) {
00485                 DBGC ( flexboot_nodnic, "flexboot_nodnic %p ring send doorbell failed\n", flexboot_nodnic );
00486         }
00487 
00488 post_send_done:
00489         return status;
00490 }
00491 
00492 /**
00493  * Post receive work queue entry
00494  *
00495  * @v ibdev             Infiniband device
00496  * @v qp                Queue pair
00497  * @v iobuf             I/O buffer
00498  * @ret rc              Return status code
00499  */
00500 static int flexboot_nodnic_post_recv ( struct ib_device *ibdev,
00501                               struct ib_queue_pair *qp,
00502                               struct io_buffer *iobuf ) {
00503         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00504         struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp = ib_qp_get_drvdata ( qp );
00505         struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
00506         struct ib_work_queue *wq = &qp->recv;
00507         nodnic_qp *nodnic_qp = flexboot_nodnic_qp->nodnic_queue_pair;
00508         struct nodnic_recv_ring *recv_ring = &nodnic_qp->receive;
00509         struct nodnic_recv_wqe *wqe;
00510         unsigned int wqe_idx_mask;
00511         mlx_status status = MLX_SUCCESS;
00512 
00513         /* Allocate work queue entry */
00514         wqe_idx_mask = ( wq->num_wqes - 1 );
00515         if ( wq->iobufs[wq->next_idx & wqe_idx_mask] ) {
00516                 DBGC ( flexboot_nodnic,
00517                                 "flexboot_nodnic %p QPN %#lx receive queue full\n",
00518                                 flexboot_nodnic, qp->qpn );
00519                 status = -ENOBUFS;
00520                 goto post_recv_done;
00521         }
00522         wq->iobufs[wq->next_idx & wqe_idx_mask] = iobuf;
00523         wqe = &((struct nodnic_recv_wqe*)recv_ring->wqe_virt)[wq->next_idx & wqe_idx_mask];
00524 
00525         MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_tailroom ( iobuf ) );
00526         MLX_FILL_1 ( &wqe->data[0], 1, l_key, flexboot_nodnic->device_priv.lkey );
00527         MLX_FILL_H ( &wqe->data[0], 2,
00528                          local_address_h, virt_to_bus ( iobuf->data ) );
00529         MLX_FILL_1 ( &wqe->data[0], 3,
00530                          local_address_l, virt_to_bus ( iobuf->data ) );
00531 
00532         wq->next_idx++;
00533 
00534         status = port->port_priv.recv_doorbell ( &port->port_priv,
00535                                 &recv_ring->nodnic_ring, ( mlx_uint16 ) wq->next_idx );
00536         if ( status != 0 ) {
00537                 DBGC ( flexboot_nodnic, "flexboot_nodnic %p ring receive doorbell failed\n", flexboot_nodnic );
00538         }
00539 post_recv_done:
00540         return status;
00541 }
00542 
00543 /***************************************************************************
00544  *
00545  * Event queues
00546  *
00547  ***************************************************************************
00548  */
00549 
00550 static void flexboot_nodnic_poll_eq ( struct ib_device *ibdev ) {
00551         struct flexboot_nodnic *flexboot_nodnic;
00552         struct flexboot_nodnic_port *port;
00553         struct net_device *netdev;
00554         nodnic_port_state state = 0;
00555         mlx_status status;
00556 
00557         if ( ! ibdev ) {
00558                 DBG ( "%s: ibdev = NULL!!!\n", __FUNCTION__ );
00559                 return;
00560         }
00561 
00562         flexboot_nodnic = ib_get_drvdata ( ibdev );
00563         port = &flexboot_nodnic->port[ibdev->port - 1];
00564         netdev = port->netdev;
00565 
00566         if ( ! netdev_is_open ( netdev ) ) {
00567                 DBG2( "%s: port %d is closed\n", __FUNCTION__, port->ibdev->port );
00568                 return;
00569         }
00570 
00571         /* we don't poll EQ. Just poll link status if it's not active */
00572         if ( ! netdev_link_ok ( netdev ) ) {
00573                 status = nodnic_port_get_state ( &port->port_priv, &state );
00574                 MLX_FATAL_CHECK_STATUS(status, state_err, "nodnic_port_get_state failed");
00575 
00576                 if ( state == nodnic_port_state_active ) {
00577                         DBG( "%s: port %d physical link is up\n", __FUNCTION__,
00578                                         port->ibdev->port );
00579                         port->type->state_change ( flexboot_nodnic, port, 1 );
00580                 }
00581         }
00582 state_err:
00583         return;
00584 }
00585 
00586 /***************************************************************************
00587  *
00588  * Multicast group operations
00589  *
00590  ***************************************************************************
00591  */
00592 static int flexboot_nodnic_mcast_attach ( struct ib_device *ibdev,
00593                                  struct ib_queue_pair *qp,
00594                                  union ib_gid *gid) {
00595         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00596         struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
00597         mlx_mac_address mac;
00598         mlx_status status = MLX_SUCCESS;
00599 
00600         switch (qp->type) {
00601         case IB_QPT_ETH:
00602                 memcpy(&mac, &gid, sizeof(mac));
00603                 status = nodnic_port_add_mac_filter(&port->port_priv, mac);
00604                 MLX_CHECK_STATUS(flexboot_nodnic->device_priv, status, mac_err,
00605                                 "nodnic_port_add_mac_filter failed");
00606                 break;
00607         default:
00608                 break;
00609         }
00610 mac_err:
00611         return status;
00612 }
00613 static void flexboot_nodnic_mcast_detach ( struct ib_device *ibdev,
00614                                   struct ib_queue_pair *qp,
00615                                   union ib_gid *gid ) {
00616         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00617         struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
00618         mlx_mac_address mac;
00619         mlx_status status = MLX_SUCCESS;
00620 
00621         switch (qp->type) {
00622         case IB_QPT_ETH:
00623                 memcpy(&mac, &gid, sizeof(mac));
00624                 status = nodnic_port_remove_mac_filter(&port->port_priv, mac);
00625                 MLX_CHECK_STATUS(flexboot_nodnic->device_priv, status, mac_err,
00626                                 "nodnic_port_remove_mac_filter failed");
00627                 break;
00628         default:
00629                 break;
00630         }
00631 mac_err:
00632         return;
00633 }
00634 /***************************************************************************
00635  *
00636  * Infiniband link-layer operations
00637  *
00638  ***************************************************************************
00639  */
00640 
00641 /**
00642  * Initialise Infiniband link
00643  *
00644  * @v ibdev             Infiniband device
00645  * @ret rc              Return status code
00646  */
00647 static int flexboot_nodnic_ib_open ( struct ib_device *ibdev __unused) {
00648         int rc = 0;
00649 
00650         /*TODO: add implementation*/
00651         return rc;
00652 }
00653 
00654 /**
00655  * Close Infiniband link
00656  *
00657  * @v ibdev             Infiniband device
00658  */
00659 static void flexboot_nodnic_ib_close ( struct ib_device *ibdev __unused) {
00660         /*TODO: add implementation*/
00661 }
00662 
00663 /**
00664  * Inform embedded subnet management agent of a received MAD
00665  *
00666  * @v ibdev             Infiniband device
00667  * @v mad               MAD
00668  * @ret rc              Return status code
00669  */
00670 static int flexboot_nodnic_inform_sma ( struct ib_device *ibdev __unused,
00671                                union ib_mad *mad __unused) {
00672         /*TODO: add implementation*/
00673         return 0;
00674 }
00675 
00676 /** flexboot_nodnic Infiniband operations */
00677 static struct ib_device_operations flexboot_nodnic_ib_operations = {
00678         .create_cq      = flexboot_nodnic_create_cq,
00679         .destroy_cq     = flexboot_nodnic_destroy_cq,
00680         .create_qp      = flexboot_nodnic_create_qp,
00681         .modify_qp      = flexboot_nodnic_modify_qp,
00682         .destroy_qp     = flexboot_nodnic_destroy_qp,
00683         .post_send      = flexboot_nodnic_post_send,
00684         .post_recv      = flexboot_nodnic_post_recv,
00685         .poll_cq        = flexboot_nodnic_poll_cq,
00686         .poll_eq        = flexboot_nodnic_poll_eq,
00687         .open           = flexboot_nodnic_ib_open,
00688         .close          = flexboot_nodnic_ib_close,
00689         .mcast_attach   = flexboot_nodnic_mcast_attach,
00690         .mcast_detach   = flexboot_nodnic_mcast_detach,
00691         .set_port_info  = flexboot_nodnic_inform_sma,
00692         .set_pkey_table = flexboot_nodnic_inform_sma,
00693 };
00694 /***************************************************************************
00695  *
00696  *
00697  *
00698  ***************************************************************************
00699  */
00700 
00701 #define FLEX_NODNIC_TX_POLL_TOUT        500000
00702 #define FLEX_NODNIC_TX_POLL_USLEEP      10
00703 
00704 static void flexboot_nodnic_complete_all_tx ( struct flexboot_nodnic_port *port ) {
00705         struct ib_device *ibdev = port->ibdev;
00706         struct ib_completion_queue *cq;
00707         struct ib_work_queue *wq;
00708         int keep_polling = 0;
00709         int timeout = FLEX_NODNIC_TX_POLL_TOUT;
00710 
00711         list_for_each_entry ( cq, &ibdev->cqs, list ) {
00712                 do {
00713                         ib_poll_cq ( ibdev, cq );
00714                         keep_polling = 0;
00715                         list_for_each_entry ( wq, &cq->work_queues, list ) {
00716                                 if ( wq->is_send )
00717                                         keep_polling += ( wq->fill > 0 );
00718                         }
00719                         udelay ( FLEX_NODNIC_TX_POLL_USLEEP );
00720                 } while ( keep_polling && ( timeout-- > 0 ) );
00721         }
00722 }
00723 
00724 static void flexboot_nodnic_port_disable_dma ( struct flexboot_nodnic_port *port ) {
00725         nodnic_port_priv *port_priv = & ( port->port_priv );
00726         mlx_status status;
00727 
00728         if ( ! ( port_priv->port_state & NODNIC_PORT_OPENED ) )
00729                 return;
00730 
00731         port_priv->port_state |= NODNIC_PORT_DISABLING_DMA;
00732         flexboot_nodnic_complete_all_tx ( port );
00733         if ( ( status = nodnic_port_disable_dma ( port_priv ) ) ) {
00734                 MLX_DEBUG_WARN ( port, "Failed to disable DMA %d\n", status );
00735         }
00736 
00737         port_priv->port_state &= ~NODNIC_PORT_DISABLING_DMA;
00738 }
00739 
00740 /***************************************************************************
00741  *
00742  * Ethernet operation
00743  *
00744  ***************************************************************************
00745  */
00746 
00747 /** Number of flexboot_nodnic Ethernet send work queue entries */
00748 #define FLEXBOOT_NODNIC_ETH_NUM_SEND_WQES 64
00749 
00750 /** Number of flexboot_nodnic Ethernet receive work queue entries */
00751 #define FLEXBOOT_NODNIC_ETH_NUM_RECV_WQES 64
00752 /** flexboot nodnic Ethernet queue pair operations */
00753 static struct ib_queue_pair_operations flexboot_nodnic_eth_qp_op = {
00754         .alloc_iob = alloc_iob,
00755 };
00756 
00757 /**
00758  * Transmit packet via flexboot_nodnic Ethernet device
00759  *
00760  * @v netdev            Network device
00761  * @v iobuf             I/O buffer
00762  * @ret rc              Return status code
00763  */
00764 static int flexboot_nodnic_eth_transmit ( struct net_device *netdev,
00765                                  struct io_buffer *iobuf) {
00766         struct flexboot_nodnic_port *port = netdev->priv;
00767         struct ib_device *ibdev = port->ibdev;
00768         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00769         int rc;
00770 
00771         rc = ib_post_send ( ibdev, port->eth_qp, NULL, iobuf);
00772         /* Transmit packet */
00773         if ( rc != 0) {
00774                 DBGC ( flexboot_nodnic, "NODNIC %p port %d could not transmit: %s\n",
00775                                 flexboot_nodnic, ibdev->port, strerror ( rc ) );
00776                 return rc;
00777         }
00778 
00779         return 0;
00780 }
00781 
00782 /**
00783  * Handle flexboot_nodnic Ethernet device send completion
00784  *
00785  * @v ibdev             Infiniband device
00786  * @v qp                Queue pair
00787  * @v iobuf             I/O buffer
00788  * @v rc                Completion status code
00789  */
00790 static void flexboot_nodnic_eth_complete_send ( struct ib_device *ibdev __unused,
00791                                        struct ib_queue_pair *qp,
00792                                        struct io_buffer *iobuf,
00793                                            int rc) {
00794         struct net_device *netdev = ib_qp_get_ownerdata ( qp );
00795 
00796         netdev_tx_complete_err ( netdev, iobuf, rc );
00797 }
00798 
00799 /**
00800  * Handle flexboot_nodnic Ethernet device receive completion
00801  *
00802  * @v ibdev             Infiniband device
00803  * @v qp                Queue pair
00804  * @v av                Address vector, or NULL
00805  * @v iobuf             I/O buffer
00806  * @v rc                Completion status code
00807  */
00808 static void flexboot_nodnic_eth_complete_recv ( struct ib_device *ibdev __unused,
00809                                 struct ib_queue_pair *qp,
00810                                 struct ib_address_vector *dest __unused,
00811                                 struct ib_address_vector *source,
00812                                  struct io_buffer *iobuf,
00813                                 int rc) {
00814         struct net_device *netdev = ib_qp_get_ownerdata ( qp );
00815 
00816         if ( rc != 0 ) {
00817                 DBG ( "Received packet with error\n" );
00818                 netdev_rx_err ( netdev, iobuf, rc );
00819                 return;
00820         }
00821 
00822         if ( source == NULL ) {
00823                 DBG ( "Received packet without address vector\n" );
00824                 netdev_rx_err ( netdev, iobuf, -ENOTTY );
00825                 return;
00826         }
00827 
00828         netdev_rx ( netdev, iobuf );
00829 }
00830 
00831 /** flexboot_nodnic Ethernet device completion operations */
00832 static struct ib_completion_queue_operations flexboot_nodnic_eth_cq_op = {
00833         .complete_send = flexboot_nodnic_eth_complete_send,
00834         .complete_recv = flexboot_nodnic_eth_complete_recv,
00835 };
00836 
00837 /**
00838  * Poll flexboot_nodnic Ethernet device
00839  *
00840  * @v netdev            Network device
00841  */
00842 static void flexboot_nodnic_eth_poll ( struct net_device *netdev) {
00843         struct flexboot_nodnic_port *port = netdev->priv;
00844         struct ib_device *ibdev = port->ibdev;
00845 
00846         ib_poll_eq ( ibdev );
00847 }
00848 
00849 /**
00850  * Open flexboot_nodnic Ethernet device
00851  *
00852  * @v netdev            Network device
00853  * @ret rc              Return status code
00854  */
00855 static int flexboot_nodnic_eth_open ( struct net_device *netdev ) {
00856         struct flexboot_nodnic_port *port = netdev->priv;
00857         struct ib_device *ibdev = port->ibdev;
00858         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00859         mlx_status status = MLX_SUCCESS;
00860         struct ib_completion_queue *dummy_cq = NULL;
00861         struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp = NULL;
00862         mlx_uint64      cq_size = 0;
00863         mlx_uint32      qpn = 0;
00864         nodnic_port_state state = nodnic_port_state_down;
00865         int rc;
00866 
00867         if ( port->port_priv.port_state & NODNIC_PORT_OPENED ) {
00868                 DBGC ( flexboot_nodnic, "%s: port %d is already opened\n",
00869                                 __FUNCTION__, port->ibdev->port );
00870                 return 0;
00871         }
00872 
00873         port->port_priv.port_state |= NODNIC_PORT_OPENED;
00874 
00875         dummy_cq = zalloc ( sizeof ( struct ib_completion_queue ) );
00876         if ( dummy_cq == NULL ) {
00877                 DBGC ( flexboot_nodnic, "%s: Failed to allocate dummy CQ\n", __FUNCTION__ );
00878                 status = MLX_OUT_OF_RESOURCES;
00879                 goto err_create_dummy_cq;
00880         }
00881         INIT_LIST_HEAD ( &dummy_cq->work_queues );
00882 
00883         if ( ( rc = ib_create_qp ( ibdev, IB_QPT_ETH,
00884                                    FLEXBOOT_NODNIC_ETH_NUM_SEND_WQES, dummy_cq,
00885                                    FLEXBOOT_NODNIC_ETH_NUM_RECV_WQES, dummy_cq,
00886                                    &flexboot_nodnic_eth_qp_op, netdev->name,
00887                                    &port->eth_qp ) ) != 0 ) {
00888                 DBGC ( flexboot_nodnic, "flexboot_nodnic %p port %d could not create queue pair\n",
00889                                  flexboot_nodnic, ibdev->port );
00890                 status = MLX_OUT_OF_RESOURCES;
00891                 goto err_create_qp;
00892         }
00893 
00894         ib_qp_set_ownerdata ( port->eth_qp, netdev );
00895 
00896         status = nodnic_port_get_cq_size(&port->port_priv, &cq_size);
00897         MLX_FATAL_CHECK_STATUS(status, get_cq_size_err,
00898                         "nodnic_port_get_cq_size failed");
00899 
00900         if ( ( rc = ib_create_cq ( ibdev, cq_size, &flexboot_nodnic_eth_cq_op,
00901                                    &port->eth_cq ) ) != 0 ) {
00902                 DBGC ( flexboot_nodnic,
00903                         "flexboot_nodnic %p port %d could not create completion queue\n",
00904                         flexboot_nodnic, ibdev->port );
00905                 status = MLX_OUT_OF_RESOURCES;
00906                 goto err_create_cq;
00907         }
00908         port->eth_qp->send.cq = port->eth_cq;
00909         list_del(&port->eth_qp->send.list);
00910         list_add ( &port->eth_qp->send.list, &port->eth_cq->work_queues );
00911         port->eth_qp->recv.cq = port->eth_cq;
00912         port->cmdsn = 0;
00913         list_del(&port->eth_qp->recv.list);
00914         list_add ( &port->eth_qp->recv.list, &port->eth_cq->work_queues );
00915 
00916         status = nodnic_port_allocate_eq(&port->port_priv,
00917                 flexboot_nodnic->device_priv.device_cap.log_working_buffer_size);
00918         MLX_FATAL_CHECK_STATUS(status, eq_alloc_err,
00919                                 "nodnic_port_allocate_eq failed");
00920 
00921         status = nodnic_port_init(&port->port_priv);
00922         MLX_FATAL_CHECK_STATUS(status, init_err,
00923                                         "nodnic_port_init failed");
00924 
00925         /* update qp - qpn */
00926         flexboot_nodnic_qp = ib_qp_get_drvdata ( port->eth_qp );
00927         status = nodnic_port_get_qpn(&port->port_priv,
00928                         &flexboot_nodnic_qp->nodnic_queue_pair->send.nodnic_ring,
00929                         &qpn);
00930         MLX_FATAL_CHECK_STATUS(status, qpn_err,
00931                                                 "nodnic_port_get_qpn failed");
00932         port->eth_qp->qpn = qpn;
00933 
00934         /* Fill receive rings */
00935         ib_refill_recv ( ibdev, port->eth_qp );
00936 
00937         status = nodnic_port_enable_dma(&port->port_priv);
00938         MLX_FATAL_CHECK_STATUS(status, dma_err,
00939                                         "nodnic_port_enable_dma failed");
00940 
00941         if (flexboot_nodnic->device_priv.device_cap.support_promisc_filter) {
00942                 status = nodnic_port_set_promisc(&port->port_priv, TRUE);
00943                 MLX_FATAL_CHECK_STATUS(status, promisc_err,
00944                                                         "nodnic_port_set_promisc failed");
00945         }
00946 
00947         status = nodnic_port_get_state(&port->port_priv, &state);
00948         MLX_FATAL_CHECK_STATUS(status, state_err,
00949                                                 "nodnic_port_get_state failed");
00950 
00951         port->type->state_change (
00952                         flexboot_nodnic, port, state == nodnic_port_state_active );
00953 
00954         DBGC ( flexboot_nodnic, "%s: port %d opened (link is %s)\n",
00955                         __FUNCTION__, port->ibdev->port,
00956                         ( ( state == nodnic_port_state_active ) ? "Up" : "Down" ) );
00957 
00958         free(dummy_cq);
00959         return 0;
00960 state_err:
00961 promisc_err:
00962 dma_err:
00963 qpn_err:
00964         nodnic_port_close(&port->port_priv);
00965 init_err:
00966         nodnic_port_free_eq(&port->port_priv);
00967 eq_alloc_err:
00968 err_create_cq:
00969 get_cq_size_err:
00970         ib_destroy_qp(ibdev, port->eth_qp );
00971 err_create_qp:
00972         free(dummy_cq);
00973 err_create_dummy_cq:
00974         port->port_priv.port_state &= ~NODNIC_PORT_OPENED;
00975         return status;
00976 }
00977 
00978 /**
00979  * Close flexboot_nodnic Ethernet device
00980  *
00981  * @v netdev            Network device
00982  */
00983 static void flexboot_nodnic_eth_close ( struct net_device *netdev) {
00984         struct flexboot_nodnic_port *port = netdev->priv;
00985         struct ib_device *ibdev = port->ibdev;
00986         struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
00987         mlx_status status = MLX_SUCCESS;
00988 
00989         if ( ! ( port->port_priv.port_state & NODNIC_PORT_OPENED ) ) {
00990                 DBGC ( flexboot_nodnic, "%s: port %d is already closed\n",
00991                                 __FUNCTION__, port->ibdev->port );
00992                 return;
00993         }
00994 
00995         if (flexboot_nodnic->device_priv.device_cap.support_promisc_filter) {
00996                 if ( ( status = nodnic_port_set_promisc( &port->port_priv, FALSE ) ) ) {
00997                         DBGC ( flexboot_nodnic,
00998                                         "nodnic_port_set_promisc failed (status = %d)\n", status );
00999                 }
01000         }
01001 
01002         flexboot_nodnic_port_disable_dma ( port );
01003 
01004         port->port_priv.port_state &= ~NODNIC_PORT_OPENED;
01005 
01006         port->type->state_change ( flexboot_nodnic, port, FALSE );
01007 
01008         /* Close port */
01009         status = nodnic_port_close(&port->port_priv);
01010         if ( status != MLX_SUCCESS ) {
01011                 DBGC ( flexboot_nodnic, "flexboot_nodnic %p port %d could not close port: %s\n",
01012                                 flexboot_nodnic, ibdev->port, strerror ( status ) );
01013                 /* Nothing we can do about this */
01014         }
01015 
01016         ib_destroy_qp ( ibdev, port->eth_qp );
01017         port->eth_qp = NULL;
01018         ib_destroy_cq ( ibdev, port->eth_cq );
01019         port->eth_cq = NULL;
01020 
01021         nodnic_port_free_eq(&port->port_priv);
01022 
01023         DBGC ( flexboot_nodnic, "%s: port %d closed\n", __FUNCTION__, port->ibdev->port );
01024 }
01025 
01026 void flexboot_nodnic_eth_irq ( struct net_device *netdev, int enable ) {
01027         struct flexboot_nodnic_port *port = netdev->priv;
01028 
01029         if ( enable ) {
01030                 if ( ( port->port_priv.port_state & NODNIC_PORT_OPENED ) &&
01031                          ! ( port->port_priv.port_state & NODNIC_PORT_DISABLING_DMA ) ) {
01032                         flexboot_nodnic_arm_cq ( port );
01033                 } else {
01034                         /* do nothing */
01035                 }
01036         } else {
01037                 nodnic_device_clear_int( port->port_priv.device );
01038         }
01039 }
01040 
01041 /** flexboot_nodnic Ethernet network device operations */
01042 static struct net_device_operations flexboot_nodnic_eth_operations = {
01043         .open           = flexboot_nodnic_eth_open,
01044         .close          = flexboot_nodnic_eth_close,
01045         .transmit       = flexboot_nodnic_eth_transmit,
01046         .poll           = flexboot_nodnic_eth_poll,
01047 };
01048 
01049 /**
01050  * Register flexboot_nodnic Ethernet device
01051  */
01052 static int flexboot_nodnic_register_netdev ( struct flexboot_nodnic *flexboot_nodnic,
01053                                     struct flexboot_nodnic_port *port) {
01054         mlx_status status = MLX_SUCCESS;
01055         struct net_device       *netdev;
01056         struct ib_device        *ibdev = port->ibdev;
01057         union {
01058                 uint8_t bytes[8];
01059                 uint32_t dwords[2];
01060         } mac;
01061 
01062         /* Allocate network devices */
01063         netdev = alloc_etherdev ( 0 );
01064         if ( netdev == NULL ) {
01065                 DBGC ( flexboot_nodnic, "flexboot_nodnic %p port %d could not allocate net device\n",
01066                                 flexboot_nodnic, ibdev->port );
01067                 status = MLX_OUT_OF_RESOURCES;
01068                 goto alloc_err;
01069         }
01070         port->netdev = netdev;
01071         netdev_init ( netdev, &flexboot_nodnic_eth_operations );
01072         netdev->dev = ibdev->dev;
01073         netdev->priv = port;
01074 
01075         status = nodnic_port_query(&port->port_priv,
01076                         nodnic_port_option_mac_high,
01077                         &mac.dwords[0]);
01078         MLX_FATAL_CHECK_STATUS(status, mac_err,
01079                         "failed to query mac high");
01080         status = nodnic_port_query(&port->port_priv,
01081                         nodnic_port_option_mac_low,
01082                         &mac.dwords[1]);
01083         MLX_FATAL_CHECK_STATUS(status, mac_err,
01084                                 "failed to query mac low");
01085         mac.dwords[0] = htonl(mac.dwords[0]);
01086         mac.dwords[1] = htonl(mac.dwords[1]);
01087         memcpy ( netdev->hw_addr,
01088                          &mac.bytes[2], ETH_ALEN);
01089         /* Register network device */
01090         status = register_netdev ( netdev );
01091         if ( status != MLX_SUCCESS ) {
01092                 DBGC ( flexboot_nodnic,
01093                         "flexboot_nodnic %p port %d could not register network device: %s\n",
01094                         flexboot_nodnic, ibdev->port, strerror ( status ) );
01095                 goto reg_err;
01096         }
01097         return status;
01098 reg_err:
01099 mac_err:
01100         netdev_put ( netdev );
01101 alloc_err:
01102         return status;
01103 }
01104 
01105 /**
01106  * Handle flexboot_nodnic Ethernet device port state change
01107  */
01108 static void flexboot_nodnic_state_change_netdev ( struct flexboot_nodnic *flexboot_nodnic __unused,
01109                                          struct flexboot_nodnic_port *port,
01110                                          int link_up ) {
01111         struct net_device *netdev = port->netdev;
01112 
01113         if ( link_up )
01114                 netdev_link_up ( netdev );
01115         else
01116                 netdev_link_down ( netdev );
01117 
01118 }
01119 
01120 /**
01121  * Unregister flexboot_nodnic Ethernet device
01122  */
01123 static void flexboot_nodnic_unregister_netdev ( struct flexboot_nodnic *flexboot_nodnic __unused,
01124                                        struct flexboot_nodnic_port *port ) {
01125         struct net_device *netdev = port->netdev;
01126         unregister_netdev ( netdev );
01127         netdev_nullify ( netdev );
01128         netdev_put ( netdev );
01129 }
01130 
01131 /** flexboot_nodnic Ethernet port type */
01132 static struct flexboot_nodnic_port_type flexboot_nodnic_port_type_eth = {
01133         .register_dev = flexboot_nodnic_register_netdev,
01134         .state_change = flexboot_nodnic_state_change_netdev,
01135         .unregister_dev = flexboot_nodnic_unregister_netdev,
01136 };
01137 
01138 /***************************************************************************
01139  *
01140  * PCI interface helper functions
01141  *
01142  ***************************************************************************
01143  */
01144 static
01145 mlx_status
01146 flexboot_nodnic_allocate_infiniband_devices( struct flexboot_nodnic *flexboot_nodnic_priv ) {
01147         mlx_status status = MLX_SUCCESS;
01148         nodnic_device_priv *device_priv = &flexboot_nodnic_priv->device_priv;
01149         struct pci_device *pci = flexboot_nodnic_priv->pci;
01150         struct ib_device *ibdev = NULL;
01151         unsigned int i = 0;
01152 
01153         /* Allocate Infiniband devices */
01154         for (; i < device_priv->device_cap.num_ports; i++) {
01155                 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
01156                         continue;
01157                 ibdev = alloc_ibdev(0);
01158                 if (ibdev == NULL) {
01159                         status = MLX_OUT_OF_RESOURCES;
01160                         goto err_alloc_ibdev;
01161                 }
01162                 flexboot_nodnic_priv->port[i].ibdev = ibdev;
01163                 ibdev->op = &flexboot_nodnic_ib_operations;
01164                 ibdev->dev = &pci->dev;
01165                 ibdev->port = ( FLEXBOOT_NODNIC_PORT_BASE + i);
01166                 ib_set_drvdata(ibdev, flexboot_nodnic_priv);
01167         }
01168         return status;
01169 err_alloc_ibdev:
01170         for ( i-- ; ( signed int ) i >= 0 ; i-- )
01171                 ibdev_put ( flexboot_nodnic_priv->port[i].ibdev );
01172         return status;
01173 }
01174 
01175 static
01176 mlx_status
01177 flexboot_nodnic_thin_init_ports( struct flexboot_nodnic *flexboot_nodnic_priv ) {
01178         mlx_status status = MLX_SUCCESS;
01179         nodnic_device_priv *device_priv = &flexboot_nodnic_priv->device_priv;
01180         nodnic_port_priv *port_priv = NULL;
01181         unsigned int i = 0;
01182 
01183         for ( i = 0; i < device_priv->device_cap.num_ports; i++ ) {
01184                 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
01185                         continue;
01186                 port_priv = &flexboot_nodnic_priv->port[i].port_priv;
01187                 status = nodnic_port_thin_init( device_priv, port_priv, i );
01188                 MLX_FATAL_CHECK_STATUS(status, thin_init_err,
01189                                 "flexboot_nodnic_thin_init_ports failed");
01190         }
01191 thin_init_err:
01192         return status;
01193 }
01194 
01195 
01196 static
01197 mlx_status
01198 flexboot_nodnic_set_ports_type ( struct flexboot_nodnic *flexboot_nodnic_priv ) {
01199         mlx_status status = MLX_SUCCESS;
01200         nodnic_device_priv      *device_priv = &flexboot_nodnic_priv->device_priv;
01201         nodnic_port_priv        *port_priv = NULL;
01202         nodnic_port_type        type = NODNIC_PORT_TYPE_UNKNOWN;
01203         unsigned int i = 0;
01204 
01205         for ( i = 0 ; i < device_priv->device_cap.num_ports ; i++ ) {
01206                 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
01207                         continue;
01208                 port_priv = &flexboot_nodnic_priv->port[i].port_priv;
01209                 status = nodnic_port_get_type(port_priv, &type);
01210                 MLX_FATAL_CHECK_STATUS(status, type_err,
01211                                 "nodnic_port_get_type failed");
01212                 switch ( type ) {
01213                 case NODNIC_PORT_TYPE_ETH:
01214                         DBGC ( flexboot_nodnic_priv, "Port %d type is Ethernet\n", i );
01215                         flexboot_nodnic_priv->port[i].type = &flexboot_nodnic_port_type_eth;
01216                         break;
01217                 case NODNIC_PORT_TYPE_IB:
01218                         DBGC ( flexboot_nodnic_priv, "Port %d type is Infiniband\n", i );
01219                         status = MLX_UNSUPPORTED;
01220                         goto type_err;
01221                 default:
01222                         DBGC ( flexboot_nodnic_priv, "Port %d type is unknown\n", i );
01223                         status = MLX_UNSUPPORTED;
01224                         goto type_err;
01225                 }
01226         }
01227 type_err:
01228         return status;
01229 }
01230 
01231 static
01232 mlx_status
01233 flexboot_nodnic_ports_register_dev( struct flexboot_nodnic *flexboot_nodnic_priv ) {
01234         mlx_status status = MLX_SUCCESS;
01235         nodnic_device_priv *device_priv = &flexboot_nodnic_priv->device_priv;
01236         struct flexboot_nodnic_port *port = NULL;
01237         unsigned int i = 0;
01238 
01239         for (; i < device_priv->device_cap.num_ports; i++) {
01240                 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
01241                         continue;
01242                 port = &flexboot_nodnic_priv->port[i];
01243                 status = port->type->register_dev ( flexboot_nodnic_priv, port );
01244                 MLX_FATAL_CHECK_STATUS(status, reg_err,
01245                                 "port register_dev failed");
01246         }
01247 reg_err:
01248         return status;
01249 }
01250 
01251 static
01252 mlx_status
01253 flexboot_nodnic_ports_unregister_dev ( struct flexboot_nodnic *flexboot_nodnic_priv ) {
01254         struct flexboot_nodnic_port *port;
01255         nodnic_device_priv      *device_priv = &flexboot_nodnic_priv->device_priv;
01256         int i = (device_priv->device_cap.num_ports - 1);
01257 
01258         for (; i >= 0; i--) {
01259                 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
01260                         continue;
01261                 port = &flexboot_nodnic_priv->port[i];
01262                 port->type->unregister_dev(flexboot_nodnic_priv, port);
01263                 ibdev_put(flexboot_nodnic_priv->port[i].ibdev);
01264         }
01265         return MLX_SUCCESS;
01266 }
01267 
01268 /***************************************************************************
01269  *
01270  * flexboot nodnic interface
01271  *
01272  ***************************************************************************
01273  */
01274 __unused static void flexboot_nodnic_enable_dma ( struct flexboot_nodnic *nodnic ) {
01275         nodnic_port_priv *port_priv;
01276         mlx_status status;
01277         int i;
01278 
01279         for ( i = 0; i < nodnic->device_priv.device_cap.num_ports; i++ ) {
01280                 if ( ! ( nodnic->port_mask & ( i + 1 ) ) )
01281                         continue;
01282                 port_priv = & ( nodnic->port[i].port_priv );
01283                 if ( ! ( port_priv->port_state & NODNIC_PORT_OPENED ) )
01284                         continue;
01285 
01286                 if ( ( status = nodnic_port_enable_dma ( port_priv ) ) ) {
01287                         MLX_DEBUG_WARN ( nodnic, "Failed to enable DMA %d\n", status );
01288                 }
01289         }
01290 }
01291 
01292 __unused static void flexboot_nodnic_disable_dma ( struct flexboot_nodnic *nodnic ) {
01293         int i;
01294 
01295         for ( i = 0; i < nodnic->device_priv.device_cap.num_ports; i++ ) {
01296                 if ( ! ( nodnic->port_mask & ( i + 1 ) ) )
01297                         continue;
01298                 flexboot_nodnic_port_disable_dma ( & ( nodnic->port[i] ) );
01299         }
01300 }
01301 
01302 int flexboot_nodnic_is_supported ( struct pci_device *pci ) {
01303         mlx_utils utils;
01304         mlx_pci_gw_buffer buffer;
01305         mlx_status status;
01306         int is_supported = 0;
01307 
01308         DBG ( "%s: start\n", __FUNCTION__ );
01309 
01310         memset ( &utils, 0, sizeof ( utils ) );
01311 
01312         status = mlx_utils_init ( &utils, pci );
01313         MLX_CHECK_STATUS ( pci, status, utils_init_err, "mlx_utils_init failed" );
01314 
01315         status = mlx_pci_gw_init ( &utils );
01316         MLX_CHECK_STATUS ( pci, status, pci_gw_init_err, "mlx_pci_gw_init failed" );
01317 
01318         status = mlx_pci_gw_read ( &utils, PCI_GW_SPACE_NODNIC,
01319                         NODNIC_NIC_INTERFACE_SUPPORTED_OFFSET, &buffer );
01320 
01321         if ( status == MLX_SUCCESS ) {
01322                 buffer >>= NODNIC_NIC_INTERFACE_SUPPORTED_BIT;
01323                 is_supported = ( buffer & 0x1 );
01324         }
01325 
01326         mlx_pci_gw_teardown( &utils );
01327 
01328 pci_gw_init_err:
01329         mlx_utils_teardown(&utils);
01330 utils_init_err:
01331         DBG ( "%s: NODNIC is %s supported (status = %d)\n",
01332                         __FUNCTION__, ( is_supported ? "": "not" ), status );
01333         return is_supported;
01334 }
01335 
01336 
01337 void flexboot_nodnic_copy_mac ( uint8_t mac_addr[], uint32_t low_byte,
01338                 uint16_t high_byte ) {
01339         union mac_addr {
01340                 struct {
01341                         uint32_t low_byte;
01342                         uint16_t high_byte;
01343                 };
01344                 uint8_t mac_addr[ETH_ALEN];
01345         } mac_addr_aux;
01346 
01347         mac_addr_aux.high_byte = high_byte;
01348         mac_addr_aux.low_byte = low_byte;
01349 
01350         mac_addr[0] = mac_addr_aux.mac_addr[5];
01351         mac_addr[1] = mac_addr_aux.mac_addr[4];
01352         mac_addr[2] = mac_addr_aux.mac_addr[3];
01353         mac_addr[3] = mac_addr_aux.mac_addr[2];
01354         mac_addr[4] = mac_addr_aux.mac_addr[1];
01355         mac_addr[5] = mac_addr_aux.mac_addr[0];
01356 }
01357 
01358 static mlx_status flexboot_nodnic_get_factory_mac (
01359                 struct flexboot_nodnic *flexboot_nodnic_priv, uint8_t port __unused ) {
01360         struct mlx_vmac_query_virt_mac virt_mac;
01361         mlx_status status;
01362 
01363         memset ( & virt_mac, 0, sizeof ( virt_mac ) );
01364         status = mlx_vmac_query_virt_mac ( flexboot_nodnic_priv->device_priv.utils,
01365                         &virt_mac );
01366         if ( ! status ) {
01367                 DBGC ( flexboot_nodnic_priv, "NODNIC %p Failed to set the virtual MAC\n"
01368                         ,flexboot_nodnic_priv );
01369         }
01370 
01371         return status;
01372 }
01373 
01374 
01375 /**
01376  * Set port masking
01377  *
01378  * @v flexboot_nodnic           nodnic device
01379  * @ret rc              Return status code
01380  */
01381 static int flexboot_nodnic_set_port_masking ( struct flexboot_nodnic *flexboot_nodnic ) {
01382         unsigned int i;
01383         nodnic_device_priv *device_priv = &flexboot_nodnic->device_priv;
01384 
01385         flexboot_nodnic->port_mask = 0;
01386         for ( i = 0; i < device_priv->device_cap.num_ports; i++ ) {
01387                 flexboot_nodnic->port_mask |= (i + 1);
01388         }
01389 
01390         if ( ! flexboot_nodnic->port_mask ) {
01391                 /* No port was enabled */
01392                 DBGC ( flexboot_nodnic, "NODNIC %p No port was enabled for "
01393                                 "booting\n", flexboot_nodnic );
01394                 return -ENETUNREACH;
01395         }
01396 
01397         return 0;
01398 }
01399 
01400 int init_mlx_utils ( mlx_utils **utils, struct pci_device *pci ) {
01401         int rc = 0;
01402 
01403         *utils = ( mlx_utils * ) zalloc ( sizeof ( mlx_utils ) );
01404         if ( *utils == NULL ) {
01405                 DBGC ( utils, "%s: Failed to allocate utils\n", __FUNCTION__ );
01406                 rc = -1;
01407                 goto err_utils_alloc;
01408         }
01409         if ( mlx_utils_init ( *utils, pci ) ) {
01410                 DBGC ( utils, "%s: mlx_utils_init failed\n", __FUNCTION__ );
01411                 rc = -1;
01412                 goto err_utils_init;
01413         }
01414         if ( mlx_pci_gw_init ( *utils ) ){
01415                 DBGC ( utils, "%s: mlx_pci_gw_init failed\n", __FUNCTION__ );
01416                 rc = -1;
01417                 goto err_cmd_init;
01418         }
01419 
01420         return 0;
01421 
01422         mlx_pci_gw_teardown ( *utils );
01423 err_cmd_init:
01424         mlx_utils_teardown ( *utils );
01425 err_utils_init:
01426         free ( *utils );
01427 err_utils_alloc:
01428         *utils = NULL;
01429 
01430         return rc;
01431 }
01432 
01433 void free_mlx_utils ( mlx_utils **utils ) {
01434 
01435         mlx_pci_gw_teardown ( *utils );
01436         mlx_utils_teardown ( *utils );
01437         free ( *utils );
01438         *utils = NULL;
01439 }
01440 
01441 /**
01442  * Initialise Nodnic PCI parameters
01443  *
01444  * @v hermon            Nodnic device
01445  */
01446 static int flexboot_nodnic_alloc_uar ( struct flexboot_nodnic *flexboot_nodnic ) {
01447         mlx_status status = MLX_SUCCESS;
01448         struct pci_device *pci = flexboot_nodnic->pci;
01449         nodnic_uar *uar = &flexboot_nodnic->port[0].port_priv.device->uar;
01450 
01451         if  ( ! flexboot_nodnic->device_priv.device_cap.support_uar_tx_db ) {
01452                 DBGC ( flexboot_nodnic, "%s: tx db using uar is not supported \n", __FUNCTION__ );
01453                 return -ENOTSUP;
01454         }
01455         /* read uar offset then allocate */
01456         if  ( ( status = nodnic_port_set_send_uar_offset ( &flexboot_nodnic->port[0].port_priv ) ) ) {
01457                 DBGC ( flexboot_nodnic, "%s: nodnic_port_set_send_uar_offset failed,"
01458                                 "status = %d\n", __FUNCTION__, status );
01459                 return -EINVAL;
01460         }
01461         uar->phys = ( pci_bar_start ( pci, FLEXBOOT_NODNIC_HCA_BAR ) + (mlx_uint32)uar->offset );
01462         uar->virt = ( void * )( ioremap ( uar->phys, FLEXBOOT_NODNIC_PAGE_SIZE ) );
01463 
01464         return status;
01465 }
01466 
01467 static int flexboot_nodnic_dealloc_uar ( struct flexboot_nodnic *flexboot_nodnic ) {
01468        nodnic_uar *uar = &flexboot_nodnic->port[0].port_priv.device->uar;
01469 
01470        if ( uar->virt ) {
01471                iounmap( uar->virt );
01472                uar->virt = NULL;
01473        }
01474 
01475        return MLX_SUCCESS;
01476 }
01477 
01478 
01479 int flexboot_nodnic_probe ( struct pci_device *pci,
01480                 struct flexboot_nodnic_callbacks *callbacks,
01481                 void *drv_priv __unused ) {
01482         mlx_status status = MLX_SUCCESS;
01483         struct flexboot_nodnic *flexboot_nodnic_priv = NULL;
01484         nodnic_device_priv *device_priv = NULL;
01485         int i = 0;
01486 
01487         if ( ( pci == NULL ) || ( callbacks == NULL ) ) {
01488                 DBGC ( flexboot_nodnic_priv, "%s: Bad Parameter\n", __FUNCTION__ );
01489                 return -EINVAL;
01490         }
01491 
01492         flexboot_nodnic_priv = zalloc( sizeof ( *flexboot_nodnic_priv ) );
01493         if ( flexboot_nodnic_priv == NULL ) {
01494                 DBGC ( flexboot_nodnic_priv, "%s: Failed to allocate priv data\n", __FUNCTION__ );
01495                 status = MLX_OUT_OF_RESOURCES;
01496                 goto device_err_alloc;
01497         }
01498 
01499         /* Register settings
01500          * Note that pci->priv will be the device private data */
01501         flexboot_nodnic_priv->pci = pci;
01502         flexboot_nodnic_priv->callbacks = callbacks;
01503         pci_set_drvdata ( pci, flexboot_nodnic_priv );
01504 
01505         device_priv = &flexboot_nodnic_priv->device_priv;
01506         /* init mlx utils */
01507         status = init_mlx_utils ( & device_priv->utils, pci );
01508         MLX_FATAL_CHECK_STATUS(status, err_utils_init,
01509                                 "init_mlx_utils failed");
01510 
01511         /* init device */
01512         status = nodnic_device_init( device_priv );
01513         MLX_FATAL_CHECK_STATUS(status, device_init_err,
01514                                 "nodnic_device_init failed");
01515 
01516         status = nodnic_device_get_cap( device_priv );
01517         MLX_FATAL_CHECK_STATUS(status, get_cap_err,
01518                                         "nodnic_device_get_cap failed");
01519 
01520         if ( mlx_set_admin_mtu ( device_priv->utils, 1, EN_DEFAULT_ADMIN_MTU ) ) {
01521                 MLX_DEBUG_ERROR( device_priv->utils, "Failed to set admin mtu\n" );
01522         }
01523 
01524         status =  flexboot_nodnic_set_port_masking ( flexboot_nodnic_priv );
01525         MLX_FATAL_CHECK_STATUS(status, err_set_masking,
01526                                                 "flexboot_nodnic_set_port_masking failed");
01527 
01528         status = flexboot_nodnic_allocate_infiniband_devices( flexboot_nodnic_priv );
01529         MLX_FATAL_CHECK_STATUS(status, err_alloc_ibdev,
01530                                         "flexboot_nodnic_allocate_infiniband_devices failed");
01531 
01532         /* port init */
01533         status = flexboot_nodnic_thin_init_ports( flexboot_nodnic_priv );
01534         MLX_FATAL_CHECK_STATUS(status, err_thin_init_ports,
01535                                                 "flexboot_nodnic_thin_init_ports failed");
01536 
01537         if ( ( status = flexboot_nodnic_alloc_uar ( flexboot_nodnic_priv ) ) ) {
01538                 DBGC(flexboot_nodnic_priv, "%s: flexboot_nodnic_alloc_uar failed"
01539                                 " ( status = %d )\n",__FUNCTION__, status );
01540         }
01541 
01542         /* device reg */
01543         status = flexboot_nodnic_set_ports_type( flexboot_nodnic_priv );
01544         MLX_CHECK_STATUS( flexboot_nodnic_priv, status, err_set_ports_types,
01545                                                 "flexboot_nodnic_set_ports_type failed");
01546 
01547         status = flexboot_nodnic_ports_register_dev( flexboot_nodnic_priv );
01548         MLX_FATAL_CHECK_STATUS(status, reg_err,
01549                                         "flexboot_nodnic_ports_register_dev failed");
01550 
01551         for ( i = 0; i < device_priv->device_cap.num_ports; i++ ) {
01552                 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
01553                         continue;
01554                 flexboot_nodnic_get_factory_mac ( flexboot_nodnic_priv, i );
01555         }
01556 
01557         /* Update ETH operations with IRQ function if supported */
01558         DBGC ( flexboot_nodnic_priv, "%s: %s IRQ function\n",
01559                         __FUNCTION__, ( callbacks->irq ? "Valid" : "No" ) );
01560         flexboot_nodnic_eth_operations.irq = callbacks->irq;
01561         return 0;
01562 
01563         flexboot_nodnic_ports_unregister_dev ( flexboot_nodnic_priv );
01564 reg_err:
01565 err_set_ports_types:
01566         flexboot_nodnic_dealloc_uar ( flexboot_nodnic_priv );
01567 err_thin_init_ports:
01568 err_alloc_ibdev:
01569 err_set_masking:
01570 get_cap_err:
01571         nodnic_device_teardown ( device_priv );
01572 device_init_err:
01573         free_mlx_utils ( & device_priv->utils );
01574 err_utils_init:
01575         free ( flexboot_nodnic_priv );
01576 device_err_alloc:
01577         return status;
01578 }
01579 
01580 void flexboot_nodnic_remove ( struct pci_device *pci )
01581 {
01582         struct flexboot_nodnic *flexboot_nodnic_priv = pci_get_drvdata ( pci );
01583         nodnic_device_priv *device_priv = & ( flexboot_nodnic_priv->device_priv );
01584 
01585         flexboot_nodnic_dealloc_uar ( flexboot_nodnic_priv );
01586         flexboot_nodnic_ports_unregister_dev ( flexboot_nodnic_priv );
01587         nodnic_device_teardown( device_priv );
01588         free_mlx_utils ( & device_priv->utils );
01589         free( flexboot_nodnic_priv );
01590 }