s2io_driver

17 篇文章 0 订阅

static struct pci_driver s2io_driver = {
    .name = "S2IO",
    .id_table = s2io_tbl,
    .probe = s2io_init_nic,
    .remove = s2io_rem_nic,
    .err_handler = &s2io_err_handler,
};

##############################################################


/**
 *  s2io_init_nic - Initialization of the adapter .
 *  @pdev : structure containing the PCI related information of the device.
 *  @pre: List of PCI devices supported by the driver listed in s2io_tbl.
 *  Description:
 *  The function initializes an adapter identified by the pci_dec structure.
 *  All OS related initialization including memory and device structure and
 *  initlaization of the device private variable is done. Also the swapper
 *  control register is initialized to enable read and write into the I/O
 *  registers of the device.
 *  Return value:
 *  returns 0 on success and negative on failure.
 */

static int
s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
{
    struct s2io_nic *sp;
    struct net_device *dev;
    int i, j, ret;
    int dma_flag = false;
    u32 mac_up, mac_down;
    u64 val64 = 0, tmp64 = 0;
    struct XENA_dev_config __iomem *bar0 = NULL;
    u16 subid;
    struct config_param *config;
    struct mac_info *mac_control;
    int mode;
    u8 dev_intr_type = intr_type;
    u8 dev_multiq = 0;

    ret = s2io_verify_parm(pdev, &dev_intr_type, &dev_multiq);
    if (ret)
        return ret;

    ret = pci_enable_device(pdev);
    if (ret) {
        DBG_PRINT(ERR_DBG,
              "%s: pci_enable_device failed\n", __func__);
        return ret;
    }

    if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
        DBG_PRINT(INIT_DBG, "%s: Using 64bit DMA\n", __func__);
        dma_flag = true;
        if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
            DBG_PRINT(ERR_DBG,
                  "Unable to obtain 64bit DMA "
                  "for consistent allocations\n");
            pci_disable_device(pdev);
            return -ENOMEM;
        }
    } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
        DBG_PRINT(INIT_DBG, "%s: Using 32bit DMA\n", __func__);
    } else {
        pci_disable_device(pdev);
        return -ENOMEM;
    }
    ret = pci_request_regions(pdev, s2io_driver_name);
    if (ret) {
        DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x\n",
              __func__, ret);
        pci_disable_device(pdev);
        return -ENODEV;
    }
    if (dev_multiq)
        dev = alloc_etherdev_mq(sizeof(struct s2io_nic), tx_fifo_num);
    else
        dev = alloc_etherdev(sizeof(struct s2io_nic));
    if (dev == NULL) {
        pci_disable_device(pdev);
        pci_release_regions(pdev);
        return -ENODEV;
    }

    pci_set_master(pdev);
    pci_set_drvdata(pdev, dev);
    SET_NETDEV_DEV(dev, &pdev->dev);

    /*  Private member variable initialized to s2io NIC structure */
    sp = netdev_priv(dev);
    sp->dev = dev;
    sp->pdev = pdev;
    sp->high_dma_flag = dma_flag;
    sp->device_enabled_once = false;
    if (rx_ring_mode == 1)
        sp->rxd_mode = RXD_MODE_1;
    if (rx_ring_mode == 2)
        sp->rxd_mode = RXD_MODE_3B;

    sp->config.intr_type = dev_intr_type;

    if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
        (pdev->device == PCI_DEVICE_ID_HERC_UNI))
        sp->device_type = XFRAME_II_DEVICE;
    else
        sp->device_type = XFRAME_I_DEVICE;


    /* Initialize some PCI/PCI-X fields of the NIC. */
    s2io_init_pci(sp);

    /*
     * Setting the device configuration parameters.
     * Most of these parameters can be specified by the user during
     * module insertion as they are module loadable parameters. If
     * these parameters are not not specified during load time, they
     * are initialized with default values.
     */
    config = &sp->config;
    mac_control = &sp->mac_control;

    config->napi = napi;
    config->tx_steering_type = tx_steering_type;

    /* Tx side parameters. */
    if (config->tx_steering_type == TX_PRIORITY_STEERING)
        config->tx_fifo_num = MAX_TX_FIFOS;
    else
        config->tx_fifo_num = tx_fifo_num;

    /* Initialize the fifos used for tx steering */
    if (config->tx_fifo_num < 5) {
        if (config->tx_fifo_num  == 1)
            sp->total_tcp_fifos = 1;
        else
            sp->total_tcp_fifos = config->tx_fifo_num - 1;
        sp->udp_fifo_idx = config->tx_fifo_num - 1;
        sp->total_udp_fifos = 1;
        sp->other_fifo_idx = sp->total_tcp_fifos - 1;
    } else {
        sp->total_tcp_fifos = (tx_fifo_num - FIFO_UDP_MAX_NUM -
                       FIFO_OTHER_MAX_NUM);
        sp->udp_fifo_idx = sp->total_tcp_fifos;
        sp->total_udp_fifos = FIFO_UDP_MAX_NUM;
        sp->other_fifo_idx = sp->udp_fifo_idx + FIFO_UDP_MAX_NUM;
    }

    config->multiq = dev_multiq;
    for (i = 0; i < config->tx_fifo_num; i++) {
        struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];

        tx_cfg->fifo_len = tx_fifo_len[i];
        tx_cfg->fifo_priority = i;
    }

    /* mapping the QoS priority to the configured fifos */
    for (i = 0; i < MAX_TX_FIFOS; i++)
        config->fifo_mapping[i] = fifo_map[config->tx_fifo_num - 1][i];

    /* map the hashing selector table to the configured fifos */
    for (i = 0; i < config->tx_fifo_num; i++)
        sp->fifo_selector[i] = fifo_selector[i];


    config->tx_intr_type = TXD_INT_TYPE_UTILZ;
    for (i = 0; i < config->tx_fifo_num; i++) {
        struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];

        tx_cfg->f_no_snoop = (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER);
        if (tx_cfg->fifo_len < 65) {
            config->tx_intr_type = TXD_INT_TYPE_PER_LIST;
            break;
        }
    }
    /* + 2 because one Txd for skb->data and one Txd for UFO */
    config->max_txds = MAX_SKB_FRAGS + 2;

    /* Rx side parameters. */
    config->rx_ring_num = rx_ring_num;
    for (i = 0; i < config->rx_ring_num; i++) {
        struct rx_ring_config *rx_cfg = &config->rx_cfg[i];
        struct ring_info *ring = &mac_control->rings[i];

        rx_cfg->num_rxd = rx_ring_sz[i] * (rxd_count[sp->rxd_mode] + 1);
        rx_cfg->ring_priority = i;
        ring->rx_bufs_left = 0;
        ring->rxd_mode = sp->rxd_mode;
        ring->rxd_count = rxd_count[sp->rxd_mode];
        ring->pdev = sp->pdev;
        ring->dev = sp->dev;
    }

    for (i = 0; i < rx_ring_num; i++) {
        struct rx_ring_config *rx_cfg = &config->rx_cfg[i];

        rx_cfg->ring_org = RING_ORG_BUFF1;
        rx_cfg->f_no_snoop = (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER);
    }

    /*  Setting Mac Control parameters */
    mac_control->rmac_pause_time = rmac_pause_time;
    mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
    mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;


    /*  initialize the shared memory used by the NIC and the host */
    if (init_shared_mem(sp)) {
        DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", dev->name);
        ret = -ENOMEM;
        goto mem_alloc_failed;
    }

    sp->bar0 = pci_ioremap_bar(pdev, 0);
    if (!sp->bar0) {
        DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
              dev->name);
        ret = -ENOMEM;
        goto bar0_remap_failed;
    }

    sp->bar1 = pci_ioremap_bar(pdev, 2);
    if (!sp->bar1) {
        DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
              dev->name);
        ret = -ENOMEM;
        goto bar1_remap_failed;
    }

    /* Initializing the BAR1 address as the start of the FIFO pointer. */
    for (j = 0; j < MAX_TX_FIFOS; j++) {
        mac_control->tx_FIFO_start[j] = sp->bar1 + (j * 0x00020000);
    }

    /*  Driver entry points */
    dev->netdev_ops = &s2io_netdev_ops;
    dev->ethtool_ops = &netdev_ethtool_ops;
    dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
        NETIF_F_TSO | NETIF_F_TSO6 |
        NETIF_F_RXCSUM | NETIF_F_LRO;
    dev->features |= dev->hw_features |
        NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
    if (sp->device_type & XFRAME_II_DEVICE) {
        dev->hw_features |= NETIF_F_UFO;
        if (ufo)
            dev->features |= NETIF_F_UFO;
    }
    if (sp->high_dma_flag == true)
        dev->features |= NETIF_F_HIGHDMA;
    dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
    INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
    INIT_WORK(&sp->set_link_task, s2io_set_link);

    pci_save_state(sp->pdev);

    /* Setting swapper control on the NIC, for proper reset operation */
    if (s2io_set_swapper(sp)) {
        DBG_PRINT(ERR_DBG, "%s: swapper settings are wrong\n",
              dev->name);
        ret = -EAGAIN;
        goto set_swap_failed;
    }

    /* Verify if the Herc works on the slot its placed into */
    if (sp->device_type & XFRAME_II_DEVICE) {
        mode = s2io_verify_pci_mode(sp);
        if (mode < 0) {
            DBG_PRINT(ERR_DBG, "%s: Unsupported PCI bus mode\n",
                  __func__);
            ret = -EBADSLT;
            goto set_swap_failed;
        }
    }

    if (sp->config.intr_type == MSI_X) {
        sp->num_entries = config->rx_ring_num + 1;
        ret = s2io_enable_msi_x(sp);

        if (!ret) {
            ret = s2io_test_msi(sp);
            /* rollback MSI-X, will re-enable during add_isr() */
            remove_msix_isr(sp);
        }
        if (ret) {

            DBG_PRINT(ERR_DBG,
                  "MSI-X requested but failed to enable\n");
            sp->config.intr_type = INTA;
        }
    }

    if (config->intr_type ==  MSI_X) {
        for (i = 0; i < config->rx_ring_num ; i++) {
            struct ring_info *ring = &mac_control->rings[i];

            netif_napi_add(dev, &ring->napi, s2io_poll_msix, 64);
        }
    } else {
        netif_napi_add(dev, &sp->napi, s2io_poll_inta, 64);
    }

    /* Not needed for Herc */
    if (sp->device_type & XFRAME_I_DEVICE) {
        /*
         * Fix for all "FFs" MAC address problems observed on
         * Alpha platforms
         */
        fix_mac_address(sp);
        s2io_reset(sp);
    }

    /*
     * MAC address initialization.
     * For now only one mac address will be read and used.
     */
    bar0 = sp->bar0;
    val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
        RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET);
    writeq(val64, &bar0->rmac_addr_cmd_mem);
    wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
                  RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
                  S2IO_BIT_RESET);
    tmp64 = readq(&bar0->rmac_addr_data0_mem);
    mac_down = (u32)tmp64;
    mac_up = (u32) (tmp64 >> 32);

    sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
    sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
    sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
    sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24);
    sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16);
    sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24);

    /*  Set the factory defined MAC address initially   */
    dev->addr_len = ETH_ALEN;
    memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);

    /* initialize number of multicast & unicast MAC entries variables */
    if (sp->device_type == XFRAME_I_DEVICE) {
        config->max_mc_addr = S2IO_XENA_MAX_MC_ADDRESSES;
        config->max_mac_addr = S2IO_XENA_MAX_MAC_ADDRESSES;
        config->mc_start_offset = S2IO_XENA_MC_ADDR_START_OFFSET;
    } else if (sp->device_type == XFRAME_II_DEVICE) {
        config->max_mc_addr = S2IO_HERC_MAX_MC_ADDRESSES;
        config->max_mac_addr = S2IO_HERC_MAX_MAC_ADDRESSES;
        config->mc_start_offset = S2IO_HERC_MC_ADDR_START_OFFSET;
    }

    /* store mac addresses from CAM to s2io_nic structure */
    do_s2io_store_unicast_mc(sp);

    /* Configure MSIX vector for number of rings configured plus one */
    if ((sp->device_type == XFRAME_II_DEVICE) &&
        (config->intr_type == MSI_X))
        sp->num_entries = config->rx_ring_num + 1;

    /* Store the values of the MSIX table in the s2io_nic structure */
    store_xmsi_data(sp);
    /* reset Nic and bring it to known state */
    s2io_reset(sp);

    /*
     * Initialize link state flags
     * and the card state parameter
     */
    sp->state = 0;

    /* Initialize spinlocks */
    for (i = 0; i < sp->config.tx_fifo_num; i++) {
        struct fifo_info *fifo = &mac_control->fifos[i];

        spin_lock_init(&fifo->tx_lock);
    }

    /*
     * SXE-002: Configure link and activity LED to init state
     * on driver load.
     */
    subid = sp->pdev->subsystem_device;
    if ((subid & 0xFF) >= 0x07) {
        val64 = readq(&bar0->gpio_control);
        val64 |= 0x0000800000000000ULL;
        writeq(val64, &bar0->gpio_control);
        val64 = 0x0411040400000000ULL;
        writeq(val64, (void __iomem *)bar0 + 0x2700);
        val64 = readq(&bar0->gpio_control);
    }

    sp->rx_csum = 1;    /* Rx chksum verify enabled by default */

    if (register_netdev(dev)) {
        DBG_PRINT(ERR_DBG, "Device registration failed\n");
        ret = -ENODEV;
        goto register_failed;
    }
    s2io_vpd_read(sp);
    DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2010 Exar Corp.\n");
    DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n", dev->name,
          sp->product_name, pdev->revision);
    DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
          s2io_driver_version);
    DBG_PRINT(ERR_DBG, "%s: MAC Address: %pM\n", dev->name, dev->dev_addr);
    DBG_PRINT(ERR_DBG, "Serial number: %s\n", sp->serial_num);
    if (sp->device_type & XFRAME_II_DEVICE) {
        mode = s2io_print_pci_mode(sp);
        if (mode < 0) {
            ret = -EBADSLT;
            unregister_netdev(dev);
            goto set_swap_failed;
        }
    }
    switch (sp->rxd_mode) {
    case RXD_MODE_1:
        DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n",
              dev->name);
        break;
    case RXD_MODE_3B:
        DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
              dev->name);
        break;
    }

    switch (sp->config.napi) {
    case 0:
        DBG_PRINT(ERR_DBG, "%s: NAPI disabled\n", dev->name);
        break;
    case 1:
        DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
        break;
    }

    DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name,
          sp->config.tx_fifo_num);

    DBG_PRINT(ERR_DBG, "%s: Using %d Rx ring(s)\n", dev->name,
          sp->config.rx_ring_num);

    switch (sp->config.intr_type) {
    case INTA:
        DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
        break;
    case MSI_X:
        DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
        break;
    }
    if (sp->config.multiq) {
        for (i = 0; i < sp->config.tx_fifo_num; i++) {
            struct fifo_info *fifo = &mac_control->fifos[i];

            fifo->multiq = config->multiq;
        }
        DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n",
              dev->name);
    } else
        DBG_PRINT(ERR_DBG, "%s: Multiqueue support disabled\n",
              dev->name);

    switch (sp->config.tx_steering_type) {
    case NO_STEERING:
        DBG_PRINT(ERR_DBG, "%s: No steering enabled for transmit\n",
              dev->name);
        break;
    case TX_PRIORITY_STEERING:
        DBG_PRINT(ERR_DBG,
              "%s: Priority steering enabled for transmit\n",
              dev->name);
        break;
    case TX_DEFAULT_STEERING:
        DBG_PRINT(ERR_DBG,
              "%s: Default steering enabled for transmit\n",
              dev->name);
    }

    DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
          dev->name);
    if (ufo)
        DBG_PRINT(ERR_DBG,
              "%s: UDP Fragmentation Offload(UFO) enabled\n",
              dev->name);
    /* Initialize device name */
    snprintf(sp->name, sizeof(sp->name), "%s Neterion %s", dev->name,
         sp->product_name);

    if (vlan_tag_strip)
        sp->vlan_strip_flag = 1;
    else
        sp->vlan_strip_flag = 0;

    /*
     * Make Link state as off at this point, when the Link change
     * interrupt comes the state will be automatically changed to
     * the right state.
     */
    netif_carrier_off(dev);

    return 0;

register_failed:
set_swap_failed:
    iounmap(sp->bar1);
bar1_remap_failed:
    iounmap(sp->bar0);
bar0_remap_failed:
mem_alloc_failed:
    free_shared_mem(sp);
    pci_disable_device(pdev);
    pci_release_regions(pdev);
    free_netdev(dev);

    return ret;
}


##########################################################################

static const struct net_device_ops s2io_netdev_ops = {
    .ndo_open            = s2io_open,
    .ndo_stop            = s2io_close,
    .ndo_get_stats            = s2io_get_stats,
    .ndo_start_xmit        = s2io_xmit,
    .ndo_validate_addr    = eth_validate_addr,
    .ndo_set_rx_mode    = s2io_set_multicast,
    .ndo_do_ioctl           = s2io_ioctl,
    .ndo_set_mac_address    = s2io_set_mac_addr,
    .ndo_change_mtu           = s2io_change_mtu,
    .ndo_set_features    = s2io_set_features,
    .ndo_tx_timeout           = s2io_tx_watchdog,
#ifdef CONFIG_NET_POLL_CONTROLLER
    .ndo_poll_controller    = s2io_netpoll,
#endif
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值