diff options
Diffstat (limited to 'gpxe/src/drivers/net/mtnic.c')
-rw-r--r-- | gpxe/src/drivers/net/mtnic.c | 1853 |
1 files changed, 0 insertions, 1853 deletions
diff --git a/gpxe/src/drivers/net/mtnic.c b/gpxe/src/drivers/net/mtnic.c deleted file mode 100644 index d7ee8d2b..00000000 --- a/gpxe/src/drivers/net/mtnic.c +++ /dev/null @@ -1,1853 +0,0 @@ -/* - * Copyright (c) 2007 Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -FILE_LICENCE ( GPL2_ONLY ); - -#include <strings.h> -#include <errno.h> -#include <gpxe/malloc.h> -#include <gpxe/umalloc.h> -#include <byteswap.h> -#include <unistd.h> -#include <gpxe/io.h> -#include <gpxe/pci.h> -#include <gpxe/ethernet.h> -#include <gpxe/netdevice.h> -#include <gpxe/iobuf.h> -#include "mtnic.h" - - -/* - - - mtnic.c - gPXE driver for Mellanox 10Gig ConnectX EN - - -*/ - - - -/******************************************************************** -* -* MTNIC allocation functions -* -*********************************************************************/ -/** -* mtnic_alloc_aligned -* -* @v unsigned int size size -* @v void **va virtual address -* @v u32 *pa physical address -* @v u32 aligment aligment -* -* Function allocate aligned buffer and put it's virtual address in 'va' -* and it's physical aligned address in 'pa' -*/ -static int -mtnic_alloc_aligned(unsigned int size, void **va, unsigned long *pa, unsigned int alignment) -{ - *va = alloc_memblock(size, alignment); - if (!*va) { - return -EADDRINUSE; - } - *pa = (u32)virt_to_bus(*va); - return 0; -} - - - -/** - * - * mtnic alloc command interface - * - */ -static int -mtnic_alloc_cmdif(struct mtnic *mtnic) -{ - u32 bar = mtnic_pci_dev.dev.bar[0]; - - mtnic->hcr = ioremap(bar + MTNIC_HCR_BASE, MTNIC_HCR_SIZE); - if ( !mtnic->hcr ) { - DBG("Couldn't map command register\n"); - return -EADDRINUSE; - } - mtnic_alloc_aligned(PAGE_SIZE, (void *)&mtnic->cmd.buf, &mtnic->cmd.mapping, PAGE_SIZE); - if ( !mtnic->cmd.buf ) { - DBG("Error in allocating buffer for command interface\n"); - return -EADDRINUSE; - } - return 0; -} - -/** - * Free RX io buffers - */ -static void -mtnic_free_io_buffers(struct mtnic_ring *ring) -{ - int index; - - for (; ring->cons <= ring->prod; ++ring->cons) { - index = ring->cons & ring->size_mask; - if ( ring->iobuf[index] ) { - free_iob(ring->iobuf[index]); - } - } -} - - - -/** - * - * mtnic alloc and attach io buffers - * - */ -static int -mtnic_alloc_iobuf(struct mtnic_port *priv, struct mtnic_ring *ring, - unsigned int size) -{ - struct mtnic_rx_desc *rx_desc_ptr = ring->buf; - u32 index; - - while ((u32)(ring->prod - ring->cons) < UNITS_BUFFER_SIZE) { - index = ring->prod & ring->size_mask; - ring->iobuf[index] = alloc_iob(size); - if (!ring->iobuf[index]) { - if (ring->prod <= (ring->cons + 1)) { - DBG ( "Dropping packet, buffer is full\n" ); - } - break; - } - - /* Attach io_buffer to descriptor */ - rx_desc_ptr = ring->buf + - (sizeof(struct mtnic_rx_desc) * index); - rx_desc_ptr->data.count = cpu_to_be32(size); - rx_desc_ptr->data.mem_type = priv->mtnic->fw.mem_type_snoop_be; - rx_desc_ptr->data.addr_l = cpu_to_be32( - virt_to_bus(ring->iobuf[index]->data)); - - ++ ring->prod; - } - - /* Update RX producer index (PI) */ - ring->db->count = cpu_to_be32(ring->prod & 0xffff); - return 0; -} - - -/** - * mtnic alloc ring - * - * Alloc and configure TX or RX ring - * - */ -static int -mtnic_alloc_ring(struct mtnic_port *priv, struct mtnic_ring *ring, - u32 size, u16 stride, u16 cq, u8 is_rx) -{ - unsigned int i; - int err; - struct mtnic_rx_desc *rx_desc; - struct mtnic_tx_desc *tx_desc; - - ring->size = size; /* Number of descriptors */ - ring->size_mask = size - 1; - ring->stride = stride; /* Size of each entry */ - ring->cq = cq; /* CQ number associated with this ring */ - ring->cons = 0; - ring->prod = 0; - - /* Alloc descriptors buffer */ - ring->buf_size = ring->size * ((is_rx) ? sizeof(struct mtnic_rx_desc) : - sizeof(struct mtnic_tx_desc)); - err = mtnic_alloc_aligned(ring->buf_size, (void *)&ring->buf, - &ring->dma, PAGE_SIZE); - if (err) { - DBG("Failed allocating descriptor ring sizeof %x\n", - ring->buf_size); - return -EADDRINUSE; - } - memset(ring->buf, 0, ring->buf_size); - - DBG("Allocated %s ring (addr:%p) - buf:%p size:%x" - "buf_size:%x dma:%lx\n", - is_rx ? "Rx" : "Tx", ring, ring->buf, ring->size, - ring->buf_size, ring->dma); - - - if (is_rx) { /* RX ring */ - /* Alloc doorbell */ - err = mtnic_alloc_aligned(sizeof(struct mtnic_cq_db_record), - (void *)&ring->db, &ring->db_dma, 32); - if (err) { - DBG("Failed allocating Rx ring doorbell record\n"); - free_memblock(ring->buf, ring->buf_size); - return -EADDRINUSE; - } - - /* ==- Configure Descriptor -== */ - /* Init ctrl seg of rx desc */ - for (i = 0; i < UNITS_BUFFER_SIZE; ++i) { - rx_desc = ring->buf + - (sizeof(struct mtnic_rx_desc) * i); - /* Pre-link descriptor */ - rx_desc->next = cpu_to_be16(i + 1); - } - /*The last ctrl descriptor is '0' and points to the first one*/ - - /* Alloc IO_BUFFERS */ - err = mtnic_alloc_iobuf ( priv, ring, DEF_IOBUF_SIZE ); - if (err) { - DBG("ERROR Allocating io buffer\n"); - free_memblock(ring->buf, ring->buf_size); - return -EADDRINUSE; - } - - } else { /* TX ring */ - /* Set initial ownership of all Tx Desc' to SW (1) */ - for (i = 0; i < ring->size; i++) { - tx_desc = ring->buf + ring->stride * i; - tx_desc->ctrl.op_own = cpu_to_be32(MTNIC_BIT_DESC_OWN); - } - /* DB */ - ring->db_offset = cpu_to_be32( - ((u32) priv->mtnic->fw.tx_offset[priv->port]) << 8); - - /* Map Tx+CQ doorbells */ - DBG("Mapping TxCQ doorbell at offset:0x%x\n", - priv->mtnic->fw.txcq_db_offset); - ring->txcq_db = ioremap(mtnic_pci_dev.dev.bar[2] + - priv->mtnic->fw.txcq_db_offset, PAGE_SIZE); - if (!ring->txcq_db) { - DBG("Couldn't map txcq doorbell, aborting...\n"); - free_memblock(ring->buf, ring->buf_size); - return -EADDRINUSE; - } - } - - return 0; -} - - - -/** - * mtnic alloc CQ - * - * Alloc and configure CQ. - * - */ -static int -mtnic_alloc_cq(struct net_device *dev, int num, struct mtnic_cq *cq, - u8 is_rx, u32 size, u32 offset_ind) -{ - int err ; - unsigned int i; - - cq->num = num; - cq->dev = dev; - cq->size = size; - cq->last = 0; - cq->is_rx = is_rx; - cq->offset_ind = offset_ind; - - /* Alloc doorbell */ - err = mtnic_alloc_aligned(sizeof(struct mtnic_cq_db_record), - (void *)&cq->db, &cq->db_dma, 32); - if (err) { - DBG("Failed allocating CQ doorbell record\n"); - return -EADDRINUSE; - } - memset(cq->db, 0, sizeof(struct mtnic_cq_db_record)); - - /* Alloc CQEs buffer */ - cq->buf_size = size * sizeof(struct mtnic_cqe); - err = mtnic_alloc_aligned(cq->buf_size, - (void *)&cq->buf, &cq->dma, PAGE_SIZE); - if (err) { - DBG("Failed allocating CQ buffer\n"); - free_memblock(cq->db, sizeof(struct mtnic_cq_db_record)); - return -EADDRINUSE; - } - memset(cq->buf, 0, cq->buf_size); - DBG("Allocated CQ (addr:%p) - size:%x buf:%p buf_size:%x " - "dma:%lx db:%p db_dma:%lx\n" - "cqn offset:%x \n", cq, cq->size, cq->buf, - cq->buf_size, cq->dma, cq->db, - cq->db_dma, offset_ind); - - - /* Set ownership of all CQEs to HW */ - DBG("Setting HW ownership for CQ:%d\n", num); - for (i = 0; i < cq->size; i++) { - /* Initial HW ownership is 1 */ - cq->buf[i].op_tr_own = MTNIC_BIT_CQ_OWN; - } - return 0; -} - - - -/** - * mtnic_alloc_resources - * - * Alloc and configure CQs, Tx, Rx - */ -unsigned int -mtnic_alloc_resources(struct net_device *dev) -{ - struct mtnic_port *priv = netdev_priv(dev); - int err; - int cq_ind = 0; - int cq_offset = priv->mtnic->fw.cq_offset; - - /* Alloc 1st CQ */ - err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 1 /* RX */, - UNITS_BUFFER_SIZE, cq_offset + cq_ind); - if (err) { - DBG("Failed allocating Rx CQ\n"); - return -EADDRINUSE; - } - - - /* Alloc RX */ - err = mtnic_alloc_ring(priv, &priv->rx_ring, UNITS_BUFFER_SIZE, - sizeof(struct mtnic_rx_desc), cq_ind, /* RX */1); - if (err) { - DBG("Failed allocating Rx Ring\n"); - goto cq0_error; - } - - - ++cq_ind; - - /* alloc 2nd CQ */ - err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 0 /* TX */, - UNITS_BUFFER_SIZE, cq_offset + cq_ind); - if (err) { - DBG("Failed allocating Tx CQ\n"); - goto rx_error; - } - - /* Alloc TX */ - err = mtnic_alloc_ring(priv, &priv->tx_ring, UNITS_BUFFER_SIZE, - sizeof(struct mtnic_tx_desc), cq_ind, /* TX */ 0); - if (err) { - DBG("Failed allocating Tx ring\n"); - goto cq1_error; - } - - return 0; - -cq1_error: - free_memblock(priv->cq[1].buf, priv->cq[1].buf_size); - free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record)); - -rx_error: - free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size); - free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record)); - mtnic_free_io_buffers(&priv->rx_ring); -cq0_error: - free_memblock(priv->cq[0].buf, priv->cq[0].buf_size); - free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record)); - - return -EADDRINUSE; -} - - -/** - * mtnic alloc_eq - * - * Note: EQ is not used by the driver but must be allocated - */ -static int -mtnic_alloc_eq(struct mtnic *mtnic) -{ - int err; - unsigned int i; - struct mtnic_eqe *eqe_desc = NULL; - - /* Allocating doorbell */ - mtnic->eq_db = ioremap(mtnic_pci_dev.dev.bar[2] + - mtnic->fw.eq_db_offset, sizeof(u32)); - if (!mtnic->eq_db) { - DBG("Couldn't map EQ doorbell, aborting...\n"); - return -EADDRINUSE; - } - - /* Allocating buffer */ - mtnic->eq.size = NUM_EQES; - mtnic->eq.buf_size = mtnic->eq.size * sizeof(struct mtnic_eqe); - err = mtnic_alloc_aligned(mtnic->eq.buf_size, (void *)&mtnic->eq.buf, - &mtnic->eq.dma, PAGE_SIZE); - if (err) { - DBG("Failed allocating EQ buffer\n"); - iounmap(mtnic->eq_db); - return -EADDRINUSE; - } - memset(mtnic->eq.buf, 0, mtnic->eq.buf_size); - - for (i = 0; i < mtnic->eq.size; i++) - eqe_desc = mtnic->eq.buf + (sizeof(struct mtnic_eqe) * i); - eqe_desc->own |= MTNIC_BIT_EQE_OWN; - - mdelay(20); - return 0; -} - - - - - - - - - - - -/******************************************************************** -* -* Mtnic commands functions -* -=-=-=-=-=-=-=-=-=-=-=-= -* -* -* -*********************************************************************/ -static inline int -cmdif_go_bit(struct mtnic *mtnic) -{ - struct mtnic_if_cmd_reg *hcr = mtnic->hcr; - u32 status; - int i; - - for (i = 0; i < TBIT_RETRIES; i++) { - status = be32_to_cpu(readl(&hcr->status_go_opcode)); - if ((status & MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_T_BIT)) == - (mtnic->cmd.tbit << MTNIC_BC_OFF(MTNIC_MASK_CMD_REG_T_BIT))) { - /* Read expected t-bit - now return go-bit value */ - return status & MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_GO_BIT); - } - } - - DBG("Invalid tbit after %d retries!\n", TBIT_RETRIES); - return -EBUSY; /* Return busy... */ -} - -/* Base Command interface */ -static int -mtnic_cmd(struct mtnic *mtnic, void *in_imm, - void *out_imm, u32 in_modifier, u16 op) -{ - - struct mtnic_if_cmd_reg *hcr = mtnic->hcr; - int err = 0; - u32 out_param_h = 0; - u32 out_param_l = 0; - u32 in_param_h = 0; - u32 in_param_l = 0; - - - static u16 token = 0x8000; - u32 status; - unsigned int timeout = 0; - - token++; - - if ( cmdif_go_bit ( mtnic ) ) { - DBG("GO BIT BUSY:%p.\n", hcr + 6); - err = -EBUSY; - goto out; - } - if (in_imm) { - in_param_h = *((u32*)in_imm); - in_param_l = *((u32*)in_imm + 1); - } else { - in_param_l = cpu_to_be32(mtnic->cmd.mapping); - } - out_param_l = cpu_to_be32(mtnic->cmd.mapping); - - /* writing to MCR */ - writel(in_param_h, &hcr->in_param_h); - writel(in_param_l, &hcr->in_param_l); - writel((u32) cpu_to_be32(in_modifier), &hcr->input_modifier); - writel(out_param_h, &hcr->out_param_h); - writel(out_param_l, &hcr->out_param_l); - writel((u32)cpu_to_be32(token << 16), &hcr->token); - wmb(); - - /* flip toggle bit before each write to the HCR */ - mtnic->cmd.tbit = !mtnic->cmd.tbit; - writel( ( u32 ) - cpu_to_be32(MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_GO_BIT) | - ( mtnic->cmd.tbit << MTNIC_BC_OFF ( MTNIC_MASK_CMD_REG_T_BIT ) ) | op ), - &hcr->status_go_opcode); - - while ( cmdif_go_bit ( mtnic ) && ( timeout <= GO_BIT_TIMEOUT ) ) { - mdelay ( 1 ); - ++timeout; - } - - if ( cmdif_go_bit ( mtnic ) ) { - DBG("Command opcode:0x%x token:0x%x TIMEOUT.\n", op, token); - err = -EBUSY; - goto out; - } - - if (out_imm) { - *((u32 *)out_imm) = readl(&hcr->out_param_h); - *((u32 *)out_imm + 1) = readl(&hcr->out_param_l); - } - - status = be32_to_cpu((u32)readl(&hcr->status_go_opcode)) >> 24; - - if (status) { - DBG("Command opcode:0x%x token:0x%x returned:0x%x\n", - op, token, status); - return status; - } - -out: - return err; -} - -/* MAP PAGES wrapper */ -static int -mtnic_map_cmd(struct mtnic *mtnic, u16 op, struct mtnic_pages pages) -{ - unsigned int j; - u32 addr; - unsigned int len; - u32 *page_arr = mtnic->cmd.buf; - int nent = 0; - int err = 0; - - memset(page_arr, 0, PAGE_SIZE); - - len = PAGE_SIZE * pages.num; - pages.buf = (u32 *)umalloc(PAGE_SIZE * (pages.num + 1)); - addr = PAGE_SIZE + ((virt_to_bus(pages.buf) & 0xfffff000) + PAGE_SIZE); - DBG("Mapping pages: size: %x address: %p\n", pages.num, pages.buf); - - if (addr & (PAGE_MASK)) { - DBG("Got FW area not aligned to %d (%llx/%x)\n", - PAGE_SIZE, (u64) addr, len); - return -EADDRINUSE; - } - - /* Function maps each PAGE seperately */ - for (j = 0; j < len; j+= PAGE_SIZE) { - page_arr[nent * 4 + 3] = cpu_to_be32(addr + j); - if (++nent == MTNIC_MAILBOX_SIZE / 16) { - err = mtnic_cmd(mtnic, NULL, NULL, nent, op); - if (err) - return -EIO; - nent = 0; - } - } - - if (nent) { - err = mtnic_cmd(mtnic, NULL, NULL, nent, op); - } - return err; -} - - - -/* - * Query FW - */ -static int -mtnic_QUERY_FW ( struct mtnic *mtnic ) -{ - int err; - struct mtnic_if_query_fw_out_mbox *cmd = mtnic->cmd.buf; - - err = mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_QUERY_FW); - if (err) - return -EIO; - - /* Get FW and interface versions */ - mtnic->fw_ver = ((u64) be16_to_cpu(cmd->rev_maj) << 32) | - ((u64) be16_to_cpu(cmd->rev_min) << 16) | - (u64) be16_to_cpu(cmd->rev_smin); - mtnic->fw.ifc_rev = be16_to_cpu(cmd->ifc_rev); - - /* Get offset for internal error reports (debug) */ - mtnic->fw.err_buf.offset = be64_to_cpu(cmd->err_buf_start); - mtnic->fw.err_buf.size = be32_to_cpu(cmd->err_buf_size); - - DBG("Error buf offset is %llx\n", mtnic->fw.err_buf.offset); - - /* Get number of required FW (4k) pages */ - mtnic->fw.fw_pages.num = be16_to_cpu(cmd->fw_pages); - - return 0; -} - - -static int -mtnic_OPEN_NIC(struct mtnic *mtnic) -{ - struct mtnic_if_open_nic_in_mbox *open_nic = mtnic->cmd.buf; - u32 extra_pages[2] = {0}; - int err; - - memset(open_nic, 0, sizeof *open_nic); - - /* port 1 */ - open_nic->log_rx_p1 = 0; - open_nic->log_cq_p1 = 1; - - open_nic->log_tx_p1 = 0; - open_nic->steer_p1 = MTNIC_IF_STEER_RSS; - /* MAC + VLAN - leave reserved */ - - /* port 2 */ - open_nic->log_rx_p2 = 0; - open_nic->log_cq_p2 = 1; - - open_nic->log_tx_p2 = 0; - open_nic->steer_p2 = MTNIC_IF_STEER_RSS; - /* MAC + VLAN - leave reserved */ - - err = mtnic_cmd(mtnic, NULL, extra_pages, 0, MTNIC_IF_CMD_OPEN_NIC); - - mtnic->fw.extra_pages.num = be32_to_cpu(*(extra_pages+1)); - DBG("Extra pages num is %x\n", mtnic->fw.extra_pages.num); - return err; -} - -static int -mtnic_CONFIG_RX(struct mtnic *mtnic) -{ - struct mtnic_if_config_rx_in_imm config_rx; - - memset(&config_rx, 0, sizeof config_rx); - return mtnic_cmd(mtnic, &config_rx, NULL, 0, MTNIC_IF_CMD_CONFIG_RX); -} - -static int -mtnic_CONFIG_TX(struct mtnic *mtnic) -{ - struct mtnic_if_config_send_in_imm config_tx; - - config_tx.enph_gpf = 0; - return mtnic_cmd(mtnic, &config_tx, NULL, 0, MTNIC_IF_CMD_CONFIG_TX); -} - -static int -mtnic_HEART_BEAT(struct mtnic_port *priv, u32 *link_state) -{ - struct mtnic_if_heart_beat_out_imm heart_beat; - - int err; - u32 flags; - err = mtnic_cmd(priv->mtnic, NULL, &heart_beat, 0, MTNIC_IF_CMD_HEART_BEAT); - if (!err) { - flags = be32_to_cpu(heart_beat.flags); - if (flags & MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR)) { - DBG("Internal error detected\n"); - return -EIO; - } - *link_state = flags & - ~((u32) MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR)); - } - return err; -} - - -/* - * Port commands - */ - -static int -mtnic_SET_PORT_DEFAULT_RING(struct mtnic_port *priv, u8 port, u16 ring) -{ - struct mtnic_if_set_port_default_ring_in_imm def_ring; - - memset(&def_ring, 0, sizeof(def_ring)); - def_ring.ring = ring; - return mtnic_cmd(priv->mtnic, &def_ring, NULL, port + 1, - MTNIC_IF_CMD_SET_PORT_DEFAULT_RING); -} - -static int -mtnic_CONFIG_PORT_RSS_STEER(struct mtnic_port *priv, int port) -{ - memset(priv->mtnic->cmd.buf, 0, PAGE_SIZE); - return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, - MTNIC_IF_CMD_CONFIG_PORT_RSS_STEER); -} - -static int -mtnic_SET_PORT_RSS_INDIRECTION(struct mtnic_port *priv, int port) - -{ - memset(priv->mtnic->cmd.buf, 0, PAGE_SIZE); - return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, - MTNIC_IF_CMD_SET_PORT_RSS_INDIRECTION); -} - - -/* - * Config commands - */ -static int -mtnic_CONFIG_CQ(struct mtnic_port *priv, int port, - u16 cq_ind, struct mtnic_cq *cq) -{ - struct mtnic_if_config_cq_in_mbox *config_cq = priv->mtnic->cmd.buf; - - memset(config_cq, 0, sizeof *config_cq); - config_cq->cq = cq_ind; - config_cq->size = fls(UNITS_BUFFER_SIZE - 1); - config_cq->offset = ((cq->dma) & (PAGE_MASK)) >> 6; - config_cq->db_record_addr_l = cpu_to_be32(cq->db_dma); - config_cq->page_address[1] = cpu_to_be32(cq->dma); - DBG("config cq address: %x dma_address: %lx" - "offset: %d size %d index: %d\n" - , config_cq->page_address[1],cq->dma, - config_cq->offset, config_cq->size, config_cq->cq ); - - return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, - MTNIC_IF_CMD_CONFIG_CQ); -} - - -static int -mtnic_CONFIG_TX_RING(struct mtnic_port *priv, u8 port, - u16 ring_ind, struct mtnic_ring *ring) -{ - struct mtnic_if_config_send_ring_in_mbox *config_tx_ring = priv->mtnic->cmd.buf; - memset(config_tx_ring, 0, sizeof *config_tx_ring); - config_tx_ring->ring = cpu_to_be16(ring_ind); - config_tx_ring->size = fls(UNITS_BUFFER_SIZE - 1); - config_tx_ring->cq = cpu_to_be16(ring->cq); - config_tx_ring->page_address[1] = cpu_to_be32(ring->dma); - - return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, - MTNIC_IF_CMD_CONFIG_TX_RING); -} - -static int -mtnic_CONFIG_RX_RING(struct mtnic_port *priv, u8 port, - u16 ring_ind, struct mtnic_ring *ring) -{ - struct mtnic_if_config_rx_ring_in_mbox *config_rx_ring = priv->mtnic->cmd.buf; - memset(config_rx_ring, 0, sizeof *config_rx_ring); - config_rx_ring->ring = ring_ind; - MTNIC_BC_PUT(config_rx_ring->stride_size, fls(UNITS_BUFFER_SIZE - 1), - MTNIC_MASK_CONFIG_RX_RING_SIZE); - MTNIC_BC_PUT(config_rx_ring->stride_size, 1, - MTNIC_MASK_CONFIG_RX_RING_STRIDE); - config_rx_ring->cq = cpu_to_be16(ring->cq); - config_rx_ring->db_record_addr_l = cpu_to_be32(ring->db_dma); - - DBG("Config RX ring starting at address:%lx\n", ring->dma); - - config_rx_ring->page_address[1] = cpu_to_be32(ring->dma); - - return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, - MTNIC_IF_CMD_CONFIG_RX_RING); -} - -static int -mtnic_CONFIG_EQ(struct mtnic *mtnic) -{ - struct mtnic_if_config_eq_in_mbox *eq = mtnic->cmd.buf; - - if (mtnic->eq.dma & (PAGE_MASK)) { - DBG("misalligned eq buffer:%lx\n", - mtnic->eq.dma); - return -EADDRINUSE; - } - - memset(eq, 0, sizeof *eq); - MTNIC_BC_PUT(eq->offset, mtnic->eq.dma >> 6, MTNIC_MASK_CONFIG_EQ_OFFSET); - MTNIC_BC_PUT(eq->size, fls(mtnic->eq.size - 1) - 1, MTNIC_MASK_CONFIG_EQ_SIZE); - MTNIC_BC_PUT(eq->int_vector, 0, MTNIC_MASK_CONFIG_EQ_INT_VEC); - eq->page_address[1] = cpu_to_be32(mtnic->eq.dma); - - return mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_CONFIG_EQ); -} - - - - -static int -mtnic_SET_RX_RING_ADDR(struct mtnic_port *priv, u8 port, u64* mac) -{ - struct mtnic_if_set_rx_ring_addr_in_imm ring_addr; - u32 modifier = ((u32) port + 1) << 16; - - memset(&ring_addr, 0, sizeof(ring_addr)); - - ring_addr.mac_31_0 = cpu_to_be32(*mac & 0xffffffff); - ring_addr.mac_47_32 = cpu_to_be16((*mac >> 32) & 0xffff); - ring_addr.flags_vlan_id |= cpu_to_be16( - MTNIC_BC_MASK(MTNIC_MASK_SET_RX_RING_ADDR_BY_MAC)); - - return mtnic_cmd(priv->mtnic, &ring_addr, NULL, modifier, MTNIC_IF_CMD_SET_RX_RING_ADDR); -} - -static int -mtnic_SET_PORT_STATE(struct mtnic_port *priv, u8 port, u8 state) -{ - struct mtnic_if_set_port_state_in_imm port_state; - - port_state.state = state ? cpu_to_be32( - MTNIC_BC_MASK(MTNIC_MASK_CONFIG_PORT_STATE)) : 0; - port_state.reserved = 0; - return mtnic_cmd(priv->mtnic, &port_state, NULL, port + 1, - MTNIC_IF_CMD_SET_PORT_STATE); -} - -static int -mtnic_SET_PORT_MTU(struct mtnic_port *priv, u8 port, u16 mtu) -{ - struct mtnic_if_set_port_mtu_in_imm set_mtu; - - memset(&set_mtu, 0, sizeof(set_mtu)); - set_mtu.mtu = cpu_to_be16(mtu); - return mtnic_cmd(priv->mtnic, &set_mtu, NULL, port + 1, - MTNIC_IF_CMD_SET_PORT_MTU); -} - -/* -static int -mtnic_CONFIG_PORT_VLAN_FILTER(struct mtnic_port *priv, int port) -{ - struct mtnic_if_config_port_vlan_filter_in_mbox *vlan_filter = priv->mtnic->cmd.buf; - - // When no vlans are configured we disable the filter - // (i.e., pass all vlans) because we ignore them anyhow - memset(vlan_filter, 0xff, sizeof(*vlan_filter)); - return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, - MTNIC_IF_CMD_CONFIG_PORT_VLAN_FILTER); -} -*/ - - -static int -mtnic_RELEASE_RESOURCE(struct mtnic_port *priv, u8 port, u8 type, u8 index) -{ - struct mtnic_if_release_resource_in_imm rel; - memset(&rel, 0, sizeof rel); - rel.index = index; - rel.type = type; - return mtnic_cmd ( priv->mtnic, - &rel, NULL, ( type == MTNIC_IF_RESOURCE_TYPE_EQ ) ? - 0 : port + 1, MTNIC_IF_CMD_RELEASE_RESOURCE ); -} - - -static int -mtnic_QUERY_CAP(struct mtnic *mtnic, u8 index, u8 mod, u64 *result) -{ - struct mtnic_if_query_cap_in_imm cap; - u32 out_imm[2]; - int err; - - memset(&cap, 0, sizeof cap); - cap.cap_index = index; - cap.cap_modifier = mod; - err = mtnic_cmd(mtnic, &cap, &out_imm, 0, MTNIC_IF_CMD_QUERY_CAP); - - *((u32*)result) = be32_to_cpu(*(out_imm+1)); - *((u32*)result + 1) = be32_to_cpu(*out_imm); - - DBG("Called Query cap with index:0x%x mod:%d result:0x%llx" - " error:%d\n", index, mod, *result, err); - return err; -} - - -#define DO_QUERY_CAP(cap, mod, var) \ - err = mtnic_QUERY_CAP(mtnic, cap, mod, &result);\ - if (err) \ - return err; \ - (var) = result - -static int -mtnic_query_num_ports(struct mtnic *mtnic) -{ - int err = 0; - u64 result; - - DO_QUERY_CAP(MTNIC_IF_CAP_NUM_PORTS, 0, mtnic->fw.num_ports); - - return 0; -} - -static int -mtnic_query_mac(struct mtnic *mtnic) -{ - int err = 0; - int i; - u64 result; - - for (i = 0; i < mtnic->fw.num_ports; i++) { - DO_QUERY_CAP(MTNIC_IF_CAP_DEFAULT_MAC, i + 1, mtnic->fw.mac[i]); - } - - return 0; -} - -static int -mtnic_query_offsets(struct mtnic *mtnic) -{ - int err; - int i; - u64 result; - - DO_QUERY_CAP(MTNIC_IF_CAP_MEM_KEY, - MTNIC_IF_MEM_TYPE_SNOOP, - mtnic->fw.mem_type_snoop_be); - mtnic->fw.mem_type_snoop_be = cpu_to_be32(mtnic->fw.mem_type_snoop_be); - DO_QUERY_CAP(MTNIC_IF_CAP_TX_CQ_DB_OFFSET, 0, mtnic->fw.txcq_db_offset); - DO_QUERY_CAP(MTNIC_IF_CAP_EQ_DB_OFFSET, 0, mtnic->fw.eq_db_offset); - - for (i = 0; i < mtnic->fw.num_ports; i++) { - DO_QUERY_CAP(MTNIC_IF_CAP_CQ_OFFSET, i + 1, mtnic->fw.cq_offset); - DO_QUERY_CAP(MTNIC_IF_CAP_TX_OFFSET, i + 1, mtnic->fw.tx_offset[i]); - DO_QUERY_CAP(MTNIC_IF_CAP_RX_OFFSET, i + 1, mtnic->fw.rx_offset[i]); - DBG("--> Port %d CQ offset:0x%x\n", i, mtnic->fw.cq_offset); - DBG("--> Port %d Tx offset:0x%x\n", i, mtnic->fw.tx_offset[i]); - DBG("--> Port %d Rx offset:0x%x\n", i, mtnic->fw.rx_offset[i]); - } - - mdelay(20); - return 0; -} - - - - - - - - - - - -/******************************************************************** -* -* MTNIC initalization functions -* -* -* -* -*********************************************************************/ - -/** - * Reset device - */ -void -mtnic_reset ( void ) -{ - void *reset = ioremap ( mtnic_pci_dev.dev.bar[0] + MTNIC_RESET_OFFSET, - 4 ); - writel ( cpu_to_be32 ( 1 ), reset ); - iounmap ( reset ); -} - - -/** - * Restore PCI config - */ -static int -restore_config(void) -{ - int i; - int rc; - - for (i = 0; i < 64; ++i) { - if (i != 22 && i != 23) { - rc = pci_write_config_dword(mtnic_pci_dev.dev.dev, - i << 2, - mtnic_pci_dev.dev. - dev_config_space[i]); - if (rc) - return rc; - } - } - return 0; -} - - - -/** - * Init PCI configuration - */ -static int -mtnic_init_pci(struct pci_device *dev) -{ - int i; - int err; - - /* save bars */ - DBG("bus=%d devfn=0x%x\n", dev->bus, dev->devfn); - for (i = 0; i < 6; ++i) { - mtnic_pci_dev.dev.bar[i] = - pci_bar_start(dev, PCI_BASE_ADDRESS_0 + (i << 2)); - DBG("bar[%d]= 0x%08lx \n", i, mtnic_pci_dev.dev.bar[i]); - } - - /* save config space */ - for (i = 0; i < 64; ++i) { - err = pci_read_config_dword(dev, i << 2, - &mtnic_pci_dev.dev. - dev_config_space[i]); - if (err) { - DBG("Can not save configuration space"); - return err; - } - } - - mtnic_pci_dev.dev.dev = dev; - - return 0; -} - -/** - * Initial hardware - */ -static inline -int mtnic_init_card(struct mtnic *mtnic) -{ - int err = 0; - - - /* Alloc command interface */ - err = mtnic_alloc_cmdif ( mtnic ); - if (err) { - DBG("Failed to init command interface, aborting\n"); - return -EADDRINUSE; - } - - - /** - * Bring up HW - */ - err = mtnic_QUERY_FW ( mtnic ); - if (err) { - DBG("QUERY_FW command failed, aborting\n"); - goto cmd_error; - } - DBG("Command interface revision:%d\n", mtnic->fw.ifc_rev); - - /* Allocate memory for FW and start it */ - err = mtnic_map_cmd(mtnic, MTNIC_IF_CMD_MAP_FW, mtnic->fw.fw_pages); - if (err) { - DBG("Eror In MAP_FW\n"); - if (mtnic->fw.fw_pages.buf) - ufree((intptr_t)mtnic->fw.fw_pages.buf); - goto cmd_error; - } - - /* Run firmware */ - err = mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_RUN_FW); - if (err) { - DBG("Eror In RUN FW\n"); - goto map_fw_error; - } - - DBG("FW version:%d.%d.%d\n", - (u16) (mtnic->fw_ver >> 32), - (u16) ((mtnic->fw_ver >> 16) & 0xffff), - (u16) (mtnic->fw_ver & 0xffff)); - - - /* Query num ports */ - err = mtnic_query_num_ports(mtnic); - if (err) { - DBG("Insufficient resources, aborting\n"); - goto map_fw_error; - } - - /* Open NIC */ - err = mtnic_OPEN_NIC(mtnic); - if (err) { - DBG("Failed opening NIC, aborting\n"); - goto map_fw_error; - } - - /* Allocate and map pages worksace */ - err = mtnic_map_cmd(mtnic, MTNIC_IF_CMD_MAP_PAGES, mtnic->fw.extra_pages); - if (err) { - DBG("Couldn't allocate %x FW extra pages, aborting\n", - mtnic->fw.extra_pages.num); - if (mtnic->fw.extra_pages.buf) - ufree((intptr_t)mtnic->fw.extra_pages.buf); - goto map_fw_error; - } - - - /* Get device information */ - err = mtnic_query_mac(mtnic); - if (err) { - DBG("Insufficient resources in quesry mac, aborting\n"); - goto map_fw_error; - } - - /* Get device offsets */ - err = mtnic_query_offsets(mtnic); - if (err) { - DBG("Failed retrieving resource offests, aborting\n"); - ufree((intptr_t)mtnic->fw.extra_pages.buf); - goto map_extra_error; - } - - - /* Alloc EQ */ - err = mtnic_alloc_eq(mtnic); - if (err) { - DBG("Failed init shared resources. error: %d\n", err); - goto map_extra_error; - } - - /* Configure HW */ - err = mtnic_CONFIG_EQ(mtnic); - if (err) { - DBG("Failed configuring EQ\n"); - goto eq_error; - } - err = mtnic_CONFIG_RX(mtnic); - if (err) { - DBG("Failed Rx configuration\n"); - goto eq_error; - } - err = mtnic_CONFIG_TX(mtnic); - if (err) { - DBG("Failed Tx configuration\n"); - goto eq_error; - } - - - return 0; - - -eq_error: - iounmap(mtnic->eq_db); - free_memblock(mtnic->eq.buf, mtnic->eq.buf_size); -map_extra_error: - ufree((intptr_t)mtnic->fw.extra_pages.buf); -map_fw_error: - ufree((intptr_t)mtnic->fw.fw_pages.buf); - -cmd_error: - iounmap(mtnic->hcr); - free_memblock(mtnic->cmd.buf, PAGE_SIZE); - - return -EADDRINUSE; -} - - - - - - - - - - -/******************************************************************* -* -* Process functions -* -* process compliations of TX and RX -* -* -********************************************************************/ -void mtnic_process_tx_cq(struct mtnic_port *priv, struct net_device *dev, - struct mtnic_cq *cq) -{ - struct mtnic_cqe *cqe = cq->buf; - struct mtnic_ring *ring = &priv->tx_ring; - u16 index; - - - index = cq->last & (cq->size-1); - cqe = &cq->buf[index]; - - /* Owner bit changes every round */ - while (XNOR(cqe->op_tr_own & MTNIC_BIT_CQ_OWN, cq->last & cq->size)) { - netdev_tx_complete (dev, ring->iobuf[index]); - ++cq->last; - index = cq->last & (cq->size-1); - cqe = &cq->buf[index]; - } - - /* Update consumer index */ - cq->db->update_ci = cpu_to_be32(cq->last & 0xffffff); - wmb(); /* ensure HW sees CQ consumer before we post new buffers */ - ring->cons = cq->last; -} - - -int mtnic_process_rx_cq(struct mtnic_port *priv, - struct net_device *dev, - struct mtnic_cq *cq) -{ - struct mtnic_cqe *cqe; - struct mtnic_ring *ring = &priv->rx_ring; - int index; - int err; - struct io_buffer *rx_iob; - unsigned int length; - - - /* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx - * descriptor offset can be deduced from the CQE index instead of - * reading 'cqe->index' */ - index = cq->last & (cq->size-1); - cqe = &cq->buf[index]; - - /* Process all completed CQEs */ - while (XNOR(cqe->op_tr_own & MTNIC_BIT_CQ_OWN, cq->last & cq->size)) { - /* Drop packet on bad receive or bad checksum */ - if ((cqe->op_tr_own & 0x1f) == MTNIC_OPCODE_ERROR) { - DBG("CQE completed with error - vendor \n"); - free_iob(ring->iobuf[index]); - goto next; - } - if (cqe->enc_bf & MTNIC_BIT_BAD_FCS) { - DBG("Accepted packet with bad FCS\n"); - free_iob(ring->iobuf[index]); - goto next; - } - - /* - * Packet is OK - process it. - */ - length = be32_to_cpu(cqe->byte_cnt); - rx_iob = ring->iobuf[index]; - iob_put(rx_iob, length); - - /* Add this packet to the receive queue. */ - netdev_rx(dev, rx_iob); - ring->iobuf[index] = NULL; - -next: - ++cq->last; - index = cq->last & (cq->size-1); - cqe = &cq->buf[index]; - - - - } - - /* Update consumer index */ - cq->db->update_ci = cpu_to_be32(cq->last & 0xffffff); - wmb(); /* ensure HW sees CQ consumer before we post new buffers */ - ring->cons = cq->last; - - if (ring->prod - ring->cons < (MAX_GAP_PROD_CONS)) { - err = mtnic_alloc_iobuf(priv, &priv->rx_ring, DEF_IOBUF_SIZE); - if (err) { - DBG("ERROR Allocating io buffer"); - return -EADDRINUSE; - } - } - - return 0; -} - - - - - - - - - - - - - - - - -/******************************************************************** -* -* net_device functions -* -* -* open, poll, close, probe, disable, irq -* -*********************************************************************/ -static int -mtnic_open(struct net_device *dev) -{ - struct mtnic_port *priv = netdev_priv(dev); - - int err = 0; - struct mtnic_ring *ring; - struct mtnic_cq *cq; - int cq_ind = 0; - u32 dev_link_state; - int link_check; - - DBG("starting port:%d, MAC Address: 0x%12llx\n", - priv->port, priv->mtnic->fw.mac[priv->port]); - - /* Alloc and configure CQs, TX, RX */ - err = mtnic_alloc_resources ( dev ); - if (err) { - DBG("Error allocating resources\n"); - return -EADDRINUSE; - } - - /* Pass CQs configuration to HW */ - for (cq_ind = 0; cq_ind < NUM_CQS; ++cq_ind) { - cq = &priv->cq[cq_ind]; - err = mtnic_CONFIG_CQ(priv, priv->port, cq_ind, cq); - if (err) { - DBG("Failed configuring CQ:%d error %d\n", - cq_ind, err); - if (cq_ind) - goto cq_error; - else - goto allocation_error; - } - /* Update consumer index */ - cq->db->update_ci = cpu_to_be32(cq->last & 0xffffff); - } - - - - /* Pass Tx configuration to HW */ - ring = &priv->tx_ring; - err = mtnic_CONFIG_TX_RING(priv, priv->port, 0, ring); - if (err) { - DBG("Failed configuring Tx ring:0\n"); - goto cq_error; - } - - /* Pass RX configuration to HW */ - ring = &priv->rx_ring; - err = mtnic_CONFIG_RX_RING(priv, priv->port, 0, ring); - if (err) { - DBG("Failed configuring Rx ring:0\n"); - goto tx_error; - } - - /* Configure Rx steering */ - err = mtnic_CONFIG_PORT_RSS_STEER(priv, priv->port); - if (!err) - err = mtnic_SET_PORT_RSS_INDIRECTION(priv, priv->port); - if (err) { - DBG("Failed configuring RSS steering\n"); - goto rx_error; - } - - - /* Set the port default ring to ring 0 */ - err = mtnic_SET_PORT_DEFAULT_RING(priv, priv->port, 0); - if (err) { - DBG("Failed setting default ring\n"); - goto rx_error; - } - - /* Set Mac address */ - err = mtnic_SET_RX_RING_ADDR(priv, priv->port, &priv->mtnic->fw.mac[priv->port]); - if (err) { - DBG("Failed setting default MAC address\n"); - goto rx_error; - } - - /* Set MTU */ - err = mtnic_SET_PORT_MTU(priv, priv->port, DEF_MTU); - if (err) { - DBG("Failed setting MTU\n"); - goto rx_error; - } - - /* Configure VLAN filter */ - /* By adding this function, The second port won't accept packets - err = mtnic_CONFIG_PORT_VLAN_FILTER(priv, priv->port); - if (err) { - DBG("Failed configuring VLAN filter\n"); - goto rx_error; - } - */ - - - /* Bring up physical link */ - err = mtnic_SET_PORT_STATE(priv, priv->port, 1); - if (err) { - DBG("Failed bringing up port\n"); - goto rx_error; - } - - /* PORT IS UP */ - priv->state = CARD_UP; - - - /* Checking Link is up */ - DBG ( "Checking if link is up\n" ); - - - for ( link_check = 0; link_check < CHECK_LINK_TIMES; link_check ++ ) { - /* Let link state stabilize if cable was connected */ - mdelay ( DELAY_LINK_CHECK ); - - err = mtnic_HEART_BEAT(priv, &dev_link_state); - if (err) { - DBG("Failed getting device link state\n"); - return -ENETDOWN; - } - - if ( dev_link_state & priv->port ) { - /* Link is up */ - break; - } - } - - - if ( ! ( dev_link_state & 0x3 ) ) { - DBG("Link down, check cables and restart\n"); - netdev_link_down ( dev ); - return -ENETDOWN; - } - - DBG ( "Link is up!\n" ); - - /* Mark as link up */ - netdev_link_up ( dev ); - - return 0; - -rx_error: - err = mtnic_RELEASE_RESOURCE(priv, priv->port, - MTNIC_IF_RESOURCE_TYPE_RX_RING, 0); -tx_error: - err |= mtnic_RELEASE_RESOURCE(priv, priv->port, - MTNIC_IF_RESOURCE_TYPE_TX_RING, 0); - -cq_error: - while (cq_ind) { - err |= mtnic_RELEASE_RESOURCE(priv, priv->port, - MTNIC_IF_RESOURCE_TYPE_CQ, --cq_ind); - } - if (err) - DBG("Eror Releasing resources\n"); - -allocation_error: - - free_memblock(priv->tx_ring.buf, priv->tx_ring.buf_size); - iounmap(priv->tx_ring.txcq_db); - free_memblock(priv->cq[1].buf, priv->cq[1].buf_size); - free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record)); - free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size); - free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record)); - free_memblock(priv->cq[0].buf, priv->cq[0].buf_size); - free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record)); - - mtnic_free_io_buffers(&priv->rx_ring); - - return -ENETDOWN; -} - - - - -/** Check if we got completion for receive and transmit and - * check the line with heart_bit command */ -static void -mtnic_poll ( struct net_device *dev ) -{ - struct mtnic_port *priv = netdev_priv(dev); - struct mtnic_cq *cq; - u32 dev_link_state; - int err; - unsigned int i; - - /* In case of an old error then return */ - if (priv->state != CARD_UP) - return; - - /* We do not check the device every call _poll call, - since it will slow it down */ - if ((priv->poll_counter % ROUND_TO_CHECK) == 0) { - /* Check device */ - err = mtnic_HEART_BEAT(priv, &dev_link_state); - if (err) { - DBG("Device has internal error\n"); - priv->state = CARD_LINK_DOWN; - return; - } - if (!(dev_link_state & 0x3)) { - DBG("Link down, check cables and restart\n"); - priv->state = CARD_LINK_DOWN; - return; - } - } - /* Polling CQ */ - for (i = 0; i < NUM_CQS; i++) { - cq = &priv->cq[i]; //Passing on the 2 cqs. - - if (cq->is_rx) { - err = mtnic_process_rx_cq(priv, cq->dev, cq); - if (err) { - priv->state = CARD_LINK_DOWN; - DBG(" Error allocating RX buffers\n"); - return; - } - } else { - mtnic_process_tx_cq(priv, cq->dev, cq); - } - } - ++ priv->poll_counter; -} - - - -static int -mtnic_transmit( struct net_device *dev, struct io_buffer *iobuf ) -{ - - struct mtnic_port *priv = netdev_priv(dev); - struct mtnic_ring *ring; - struct mtnic_tx_desc *tx_desc; - struct mtnic_data_seg *data; - u32 index; - - /* In case of an error then return */ - if (priv->state != CARD_UP) - return -ENETDOWN; - - ring = &priv->tx_ring; - - index = ring->prod & ring->size_mask; - if ((ring->prod - ring->cons) >= ring->size) { - DBG("No space left for descriptors!!! cons: %x prod: %x\n", - ring->cons, ring->prod); - mdelay(5); - return -EAGAIN;/* no space left */ - } - - /* get current descriptor */ - tx_desc = ring->buf + (index * sizeof(struct mtnic_tx_desc)); - - /* Prepare Data Seg */ - data = &tx_desc->data; - data->addr_l = cpu_to_be32((u32)virt_to_bus(iobuf->data)); - data->count = cpu_to_be32(iob_len(iobuf)); - data->mem_type = priv->mtnic->fw.mem_type_snoop_be; - - /* Prepare ctrl segement */ - tx_desc->ctrl.size_vlan = cpu_to_be32(2); - tx_desc->ctrl.flags = cpu_to_be32(MTNIC_BIT_TX_COMP | - MTNIC_BIT_NO_ICRC); - tx_desc->ctrl.op_own = cpu_to_be32(MTNIC_OPCODE_SEND) | - ((ring->prod & ring->size) ? - cpu_to_be32(MTNIC_BIT_DESC_OWN) : 0); - - /* Attach io_buffer */ - ring->iobuf[index] = iobuf; - - /* Update producer index */ - ++ring->prod; - - /* Ring doorbell! */ - wmb(); - writel((u32) ring->db_offset, &ring->txcq_db->send_db); - - return 0; -} - - -static void -mtnic_close(struct net_device *dev) -{ - struct mtnic_port *priv = netdev_priv(dev); - int err = 0; - DBG("Close called for port:%d\n", priv->port); - - if ( ( priv->state == CARD_UP ) || - ( priv->state == CARD_LINK_DOWN ) ) { - - /* Disable port */ - err |= mtnic_SET_PORT_STATE(priv, priv->port, 0); - /* - * Stop HW associated with this port - */ - mdelay(5); - - /* Stop RX */ - err |= mtnic_RELEASE_RESOURCE(priv, priv->port, - MTNIC_IF_RESOURCE_TYPE_RX_RING, 0); - - /* Stop TX */ - err |= mtnic_RELEASE_RESOURCE(priv, priv->port, - MTNIC_IF_RESOURCE_TYPE_TX_RING, 0); - - /* Stop CQs */ - err |= mtnic_RELEASE_RESOURCE(priv, priv->port, - MTNIC_IF_RESOURCE_TYPE_CQ, 0); - err |= mtnic_RELEASE_RESOURCE(priv, priv->port, - MTNIC_IF_RESOURCE_TYPE_CQ, 1); - if (err) { - DBG("Close reported error %d\n", err); - } - - mdelay ( 10 ); - - /* free memory */ - free_memblock(priv->tx_ring.buf, priv->tx_ring.buf_size); - iounmap(priv->tx_ring.txcq_db); - free_memblock(priv->cq[1].buf, priv->cq[1].buf_size); - free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record)); - free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size); - free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record)); - free_memblock(priv->cq[0].buf, priv->cq[0].buf_size); - free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record)); - - /* Free RX buffers */ - mtnic_free_io_buffers(&priv->rx_ring); - - - - } - - priv->state = CARD_INITIALIZED; - -} - - -static void -mtnic_disable(struct pci_device *pci) -{ - - int err; - int i; - struct mtnic *mtnic = pci_get_drvdata(pci); - - - struct net_device *dev; - struct mtnic_port *priv; - - for ( i = ( mtnic->fw.num_ports - 1 ); i >= 0; i-- ) { - - dev = mtnic->netdev[i]; - - priv = netdev_priv(dev); - - /* Just in case */ - if ( ( priv->state == CARD_UP ) || - ( priv->state == CARD_LINK_DOWN ) ) - mtnic_close ( dev ); - } - - /* Releasing EQ */ - priv = netdev_priv ( mtnic->netdev[0] ); - err = mtnic_RELEASE_RESOURCE(priv, 1, - MTNIC_IF_RESOURCE_TYPE_EQ, 0); - - DBG("Calling MTNIC_CLOSE command\n"); - err |= mtnic_cmd(mtnic, NULL, NULL, 0, - MTNIC_IF_CMD_CLOSE_NIC); - if (err) { - DBG("Error Releasing resources %d\n", err); - } - - free_memblock(mtnic->cmd.buf, PAGE_SIZE); - iounmap(mtnic->hcr); - ufree((intptr_t)mtnic->fw.fw_pages.buf); - ufree((intptr_t)mtnic->fw.extra_pages.buf); - free_memblock(mtnic->eq.buf, mtnic->eq.buf_size); - iounmap(mtnic->eq_db); - - - for ( i = ( mtnic->fw.num_ports - 1 ); i >= 0; i-- ) { - dev = mtnic->netdev[i]; - unregister_netdev ( dev ); - netdev_nullify ( dev ); - netdev_put ( dev ); - } - - free ( mtnic ); - - - mtnic_reset (); - mdelay ( 1000 ); - /* Restore config, if we would like to retry booting */ - restore_config (); - - -} - - - -static void -mtnic_irq(struct net_device *netdev __unused, int enable __unused) -{ - /* Not implemented */ -} - - - -/** mtnic net device operations */ -static struct net_device_operations mtnic_operations = { - .open = mtnic_open, - .close = mtnic_close, - .transmit = mtnic_transmit, - .poll = mtnic_poll, - .irq = mtnic_irq, -}; - - - - - - - -static int -mtnic_probe(struct pci_device *pci, - const struct pci_device_id *id __unused) -{ - struct mtnic_port *priv; - struct mtnic *mtnic; - int err; - u64 mac; - int port_index; - - - adjust_pci_device(pci); - - err = mtnic_init_pci(pci); - if (err) { - DBG("Error in pci_init\n"); - return -EIO; - } - - mtnic_reset(); - mdelay(1000); - - err = restore_config(); - if (err) { - DBG("Error in restoring config\n"); - return err; - } - - mtnic = zalloc ( sizeof ( *mtnic ) ); - if ( ! mtnic ) { - DBG ( "Error Allocating mtnic buffer\n" ); - return -EADDRINUSE; - } - - pci_set_drvdata(pci, mtnic); - - mtnic->pdev = pci; - - - /* Initialize hardware */ - err = mtnic_init_card ( mtnic ); - if (err) { - DBG("Error in init_card\n"); - goto err_init_card; - } - - for ( port_index = 0; port_index < mtnic->fw.num_ports; port_index ++ ) { - /* Initializing net device */ - mtnic->netdev[port_index] = alloc_etherdev( sizeof ( struct mtnic_port ) ); - if ( mtnic->netdev[port_index] == NULL ) { - DBG("Net device allocation failed\n"); - goto err_alloc_mtnic; - } - - /* - * Initialize driver private data - */ - - mtnic->netdev[port_index]->dev = &pci->dev; - priv = netdev_priv ( mtnic->netdev[port_index] ); - memset ( priv, 0, sizeof ( struct mtnic_port ) ); - priv->mtnic = mtnic; - priv->netdev = mtnic->netdev[port_index]; - - /* Attach pci device */ - netdev_init(mtnic->netdev[port_index], &mtnic_operations); - - /* Set port number */ - priv->port = port_index; - - /* Set state */ - priv->state = CARD_DOWN; - } - - - int mac_idx; - for ( port_index = 0; port_index < mtnic->fw.num_ports; port_index ++ ) { - priv = netdev_priv ( mtnic->netdev[port_index] ); - /* Program the MAC address */ - mac = priv->mtnic->fw.mac[port_index]; - for (mac_idx = 0; mac_idx < MAC_ADDRESS_SIZE; ++mac_idx) { - mtnic->netdev[port_index]->hw_addr[MAC_ADDRESS_SIZE - mac_idx - 1] = mac & 0xFF; - mac = mac >> 8; - } - - if ( register_netdev ( mtnic->netdev[port_index] ) ) { - DBG("Netdev registration failed\n"); - priv->state = CARD_INITIALIZED; - goto err_alloc_mtnic; - } - } - - - return 0; - -err_alloc_mtnic: - free ( mtnic ); -err_init_card: - return -EIO; -} - - - - -static struct pci_device_id mtnic_nics[] = { - PCI_ROM ( 0x15b3, 0x6368, "mt25448", "Mellanox ConnectX EN driver", 0 ), - PCI_ROM ( 0x15b3, 0x6372, "mt25458", "Mellanox ConnectX ENt driver", 0 ), - PCI_ROM ( 0x15b3, 0x6750, "mt26448", "Mellanox ConnectX EN GEN2 driver", 0 ), - PCI_ROM ( 0x15b3, 0x675a, "mt26458", "Mellanox ConnectX ENt GEN2 driver", 0 ), -}; - -struct pci_driver mtnic_driver __pci_driver = { - .ids = mtnic_nics, - .id_count = sizeof(mtnic_nics) / sizeof(mtnic_nics[0]), - .probe = mtnic_probe, - .remove = mtnic_disable, -}; - |