725 lines
18 KiB
C
725 lines
18 KiB
C
|
/*
|
||
|
* vxge-main.c: gPXE driver for Neterion Inc's X3100 Series 10GbE
|
||
|
* PCIe I/O Virtualized Server Adapter.
|
||
|
*
|
||
|
* Copyright(c) 2002-2010 Neterion Inc.
|
||
|
*
|
||
|
* This software may be used and distributed according to the terms of
|
||
|
* the GNU General Public License (GPL), incorporated herein by
|
||
|
* reference. Drivers based on or derived from this code fall under
|
||
|
* the GPL and must retain the authorship, copyright and license
|
||
|
* notice.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
FILE_LICENCE(GPL2_ONLY);
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <gpxe/io.h>
|
||
|
#include <errno.h>
|
||
|
#include <byteswap.h>
|
||
|
#include <gpxe/pci.h>
|
||
|
#include <gpxe/malloc.h>
|
||
|
#include <gpxe/if_ether.h>
|
||
|
#include <gpxe/ethernet.h>
|
||
|
#include <gpxe/iobuf.h>
|
||
|
#include <gpxe/netdevice.h>
|
||
|
#include <gpxe/timer.h>
|
||
|
#include <nic.h>
|
||
|
|
||
|
#include "vxge_main.h"
|
||
|
#include "vxge_reg.h"
|
||
|
|
||
|
/* function modes strings */
|
||
|
static char *vxge_func_mode_names[] = {
|
||
|
"Single Function - 1 func, 17 vpath",
|
||
|
"Multi Function 8 - 8 func, 2 vpath per func",
|
||
|
"SRIOV 17 - 17 VF, 1 vpath per VF",
|
||
|
"WLPEX/SharedIO 17 - 17 VH, 1 vpath/func/hierarchy",
|
||
|
"WLPEX/SharedIO 8 - 8 VH, 2 vpath/func/hierarchy",
|
||
|
"Multi Function 17 - 17 func, 1 vpath per func",
|
||
|
"SRIOV 8 - 1 PF, 7 VF, 2 vpath per VF",
|
||
|
"SRIOV 4 - 1 PF, 3 VF, 4 vpath per VF",
|
||
|
"Multi Function 2 - 2 func, 8 vpath per func",
|
||
|
"Multi Function 4 - 4 func, 4 vpath per func",
|
||
|
"WLPEX/SharedIO 4 - 17 func, 1 vpath per func (PCIe ARI)",
|
||
|
};
|
||
|
|
||
|
static inline int is_vxge_card_up(struct vxgedev *vdev)
|
||
|
{
|
||
|
return test_bit(__VXGE_STATE_CARD_UP, vdev->state);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* vxge_xmit_compl
|
||
|
*
|
||
|
* If an interrupt was raised to indicate DMA complete of the Tx packet,
|
||
|
* this function is called. It identifies the last TxD whose buffer was
|
||
|
* freed and frees all skbs whose data have already DMA'ed into the NICs
|
||
|
* internal memory.
|
||
|
*/
|
||
|
enum vxge_hw_status
|
||
|
vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw,
|
||
|
struct vxge_hw_fifo_txd *txdp, enum vxge_hw_fifo_tcode tcode)
|
||
|
{
|
||
|
struct net_device *netdev;
|
||
|
struct io_buffer *tx_iob = NULL;
|
||
|
|
||
|
vxge_trace();
|
||
|
|
||
|
netdev = fifo_hw->vpathh->hldev->ndev;
|
||
|
|
||
|
tx_iob = (struct io_buffer *)(intptr_t)txdp->host_control;
|
||
|
|
||
|
if (tcode == VXGE_HW_FIFO_T_CODE_OK) {
|
||
|
netdev_tx_complete(netdev, tx_iob);
|
||
|
} else {
|
||
|
netdev_tx_complete_err(netdev, tx_iob, -EINVAL);
|
||
|
vxge_debug(VXGE_ERR, "%s: transmit failed, tcode %d\n",
|
||
|
netdev->name, tcode);
|
||
|
}
|
||
|
|
||
|
memset(txdp, 0, sizeof(struct vxge_hw_fifo_txd));
|
||
|
|
||
|
return VXGE_HW_OK;
|
||
|
}
|
||
|
|
||
|
/* reset vpaths */
|
||
|
enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
|
||
|
{
|
||
|
enum vxge_hw_status status = VXGE_HW_OK;
|
||
|
struct __vxge_hw_virtualpath *vpath;
|
||
|
|
||
|
vxge_trace();
|
||
|
|
||
|
vpath = vdev->vpath.vpathh;
|
||
|
|
||
|
if (vpath) {
|
||
|
if ((status = vxge_hw_vpath_reset(vpath)) == VXGE_HW_OK) {
|
||
|
if (is_vxge_card_up(vdev) &&
|
||
|
(status = vxge_hw_vpath_recover_from_reset(
|
||
|
vpath)) != VXGE_HW_OK) {
|
||
|
vxge_debug(VXGE_ERR, "vxge_hw_vpath_recover_"
|
||
|
"from_reset failed\n");
|
||
|
return status;
|
||
|
} else {
|
||
|
status = __vxge_hw_vpath_reset_check(vpath);
|
||
|
if (status != VXGE_HW_OK) {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"__vxge_hw_vpath_reset_check error\n");
|
||
|
return status;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
vxge_debug(VXGE_ERR, "vxge_hw_vpath_reset failed\n");
|
||
|
return status;
|
||
|
}
|
||
|
}
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/* close vpaths */
|
||
|
void vxge_close_vpaths(struct vxgedev *vdev)
|
||
|
{
|
||
|
|
||
|
if (vdev->vpath.vpathh && vdev->vpath.is_open)
|
||
|
vxge_hw_vpath_close(vdev->vpath.vpathh);
|
||
|
|
||
|
vdev->vpath.is_open = 0;
|
||
|
vdev->vpath.vpathh = NULL;
|
||
|
}
|
||
|
|
||
|
/* open vpaths */
|
||
|
int vxge_open_vpaths(struct vxgedev *vdev)
|
||
|
{
|
||
|
enum vxge_hw_status status;
|
||
|
struct __vxge_hw_device *hldev;
|
||
|
|
||
|
hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
|
||
|
|
||
|
vdev->vpath.vpathh = &hldev->virtual_path;
|
||
|
vdev->vpath.fifo.ndev = vdev->ndev;
|
||
|
vdev->vpath.fifo.pdev = vdev->pdev;
|
||
|
vdev->vpath.fifo.fifoh = &hldev->virtual_path.fifoh;
|
||
|
vdev->vpath.ring.ndev = vdev->ndev;
|
||
|
vdev->vpath.ring.pdev = vdev->pdev;
|
||
|
vdev->vpath.ring.ringh = &hldev->virtual_path.ringh;
|
||
|
|
||
|
status = vxge_hw_vpath_open(vdev->devh, &vdev->vpath);
|
||
|
if (status == VXGE_HW_OK) {
|
||
|
vdev->vpath.is_open = 1;
|
||
|
} else {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"%s: vpath: %d failed to open "
|
||
|
"with status: %d\n",
|
||
|
vdev->ndev->name, vdev->vpath.device_id,
|
||
|
status);
|
||
|
vxge_close_vpaths(vdev);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
hldev->vpaths_deployed |= vxge_mBIT(vdev->vpath.vpathh->vp_id);
|
||
|
|
||
|
return VXGE_HW_OK;
|
||
|
}
|
||
|
|
||
|
/** Functions that implement the gPXE driver API **/
|
||
|
|
||
|
/**
|
||
|
* vxge_xmit
|
||
|
* @skb : the socket buffer containing the Tx data.
|
||
|
* @dev : device pointer.
|
||
|
*
|
||
|
* This function is the Tx entry point of the driver. Neterion NIC supports
|
||
|
* certain protocol assist features on Tx side, namely CSO, S/G, LSO.
|
||
|
*/
|
||
|
static int
|
||
|
vxge_xmit(struct net_device *dev, struct io_buffer *iobuf)
|
||
|
{
|
||
|
struct vxge_fifo *fifo = NULL;
|
||
|
struct vxgedev *vdev = NULL;
|
||
|
struct __vxge_hw_fifo *fifoh;
|
||
|
struct __vxge_hw_device *hldev;
|
||
|
struct vxge_hw_fifo_txd *txdp;
|
||
|
|
||
|
vxge_trace();
|
||
|
|
||
|
vdev = (struct vxgedev *)netdev_priv(dev);
|
||
|
hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
|
||
|
|
||
|
if (!is_vxge_card_up(vdev)) {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"%s: vdev not initialized\n", dev->name);
|
||
|
return -EIO;
|
||
|
}
|
||
|
|
||
|
if (!netdev_link_ok(dev)) {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"%s: Link down, transmit failed\n", dev->name);
|
||
|
return -ENETDOWN;
|
||
|
}
|
||
|
|
||
|
fifo = &vdev->vpath.fifo;
|
||
|
fifoh = fifo->fifoh;
|
||
|
|
||
|
txdp = vxge_hw_fifo_free_txdl_get(fifoh);
|
||
|
if (!txdp) {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"%s: Out of tx descriptors\n", dev->name);
|
||
|
return -ENOBUFS;
|
||
|
}
|
||
|
|
||
|
vxge_debug(VXGE_XMIT, "%s: %s:%d fifoh offset= %d\n",
|
||
|
dev->name, __func__, __LINE__, fifoh->sw_offset);
|
||
|
|
||
|
vxge_hw_fifo_txdl_buffer_set(fifoh, txdp, iobuf);
|
||
|
|
||
|
vxge_hw_fifo_txdl_post(fifoh, txdp);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* vxge_poll
|
||
|
* @ndev: net device pointer
|
||
|
*
|
||
|
* This function acks the interrupt. It polls for rx packets
|
||
|
* and send to upper layer. It also checks for tx completion
|
||
|
* and frees iobs.
|
||
|
*/
|
||
|
static void vxge_poll(struct net_device *ndev)
|
||
|
{
|
||
|
struct __vxge_hw_device *hldev;
|
||
|
struct vxgedev *vdev;
|
||
|
|
||
|
vxge_debug(VXGE_POLL, "%s:%d \n", __func__, __LINE__);
|
||
|
|
||
|
vdev = (struct vxgedev *)netdev_priv(ndev);
|
||
|
hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
|
||
|
|
||
|
if (!is_vxge_card_up(vdev))
|
||
|
return;
|
||
|
|
||
|
/* process alarm and acknowledge the interrupts */
|
||
|
vxge_hw_device_begin_irq(hldev);
|
||
|
|
||
|
vxge_hw_vpath_poll_tx(&hldev->virtual_path.fifoh);
|
||
|
|
||
|
vxge_hw_vpath_poll_rx(&hldev->virtual_path.ringh);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* vxge_irq - enable or Disable interrupts
|
||
|
*
|
||
|
* @netdev netdevice sturcture reference
|
||
|
* @action requested interrupt action
|
||
|
*/
|
||
|
static void vxge_irq(struct net_device *netdev __unused, int action)
|
||
|
{
|
||
|
struct __vxge_hw_device *hldev;
|
||
|
struct vxgedev *vdev;
|
||
|
|
||
|
vxge_debug(VXGE_INFO,
|
||
|
"%s:%d action(%d)\n", __func__, __LINE__, action);
|
||
|
|
||
|
vdev = (struct vxgedev *)netdev_priv(netdev);
|
||
|
hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
|
||
|
|
||
|
switch (action) {
|
||
|
case DISABLE:
|
||
|
vxge_hw_device_mask_all(hldev);
|
||
|
break;
|
||
|
default:
|
||
|
vxge_hw_device_unmask_all(hldev);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* vxge_open
|
||
|
* @dev: pointer to the device structure.
|
||
|
*
|
||
|
* This function is the open entry point of the driver. It mainly calls a
|
||
|
* function to allocate Rx buffers and inserts them into the buffer
|
||
|
* descriptors and then enables the Rx part of the NIC.
|
||
|
* Return value: '0' on success and an appropriate (-)ve integer as
|
||
|
* defined in errno.h file on failure.
|
||
|
*/
|
||
|
int
|
||
|
vxge_open(struct net_device *dev)
|
||
|
{
|
||
|
enum vxge_hw_status status;
|
||
|
struct vxgedev *vdev;
|
||
|
struct __vxge_hw_device *hldev;
|
||
|
int ret = 0;
|
||
|
|
||
|
vxge_debug(VXGE_INFO, "%s: %s:%d\n",
|
||
|
VXGE_DRIVER_NAME, __func__, __LINE__);
|
||
|
|
||
|
vdev = (struct vxgedev *)netdev_priv(dev);
|
||
|
hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
|
||
|
|
||
|
/* make sure you have link off by default every time Nic is
|
||
|
* initialized */
|
||
|
netdev_link_down(dev);
|
||
|
|
||
|
/* Open VPATHs */
|
||
|
status = vxge_open_vpaths(vdev);
|
||
|
if (status != VXGE_HW_OK) {
|
||
|
vxge_debug(VXGE_ERR, "%s: fatal: Vpath open failed\n",
|
||
|
VXGE_DRIVER_NAME);
|
||
|
ret = -EPERM;
|
||
|
goto out0;
|
||
|
}
|
||
|
|
||
|
vdev->mtu = VXGE_HW_DEFAULT_MTU;
|
||
|
/* set initial mtu before enabling the device */
|
||
|
status = vxge_hw_vpath_mtu_set(vdev->vpath.vpathh, vdev->mtu);
|
||
|
if (status != VXGE_HW_OK) {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"%s: fatal: can not set new MTU\n", dev->name);
|
||
|
ret = -EPERM;
|
||
|
goto out2;
|
||
|
}
|
||
|
vxge_debug(VXGE_INFO,
|
||
|
"%s: MTU is %d\n", vdev->ndev->name, vdev->mtu);
|
||
|
|
||
|
set_bit(__VXGE_STATE_CARD_UP, vdev->state);
|
||
|
|
||
|
wmb();
|
||
|
|
||
|
if (vxge_hw_device_link_state_get(vdev->devh) == VXGE_HW_LINK_UP) {
|
||
|
netdev_link_up(vdev->ndev);
|
||
|
vxge_debug(VXGE_INFO, "%s: Link Up\n", vdev->ndev->name);
|
||
|
}
|
||
|
|
||
|
vxge_hw_device_intr_enable(hldev);
|
||
|
|
||
|
vxge_hw_vpath_enable(vdev->vpath.vpathh);
|
||
|
wmb();
|
||
|
vxge_hw_vpath_rx_doorbell_init(vdev->vpath.vpathh);
|
||
|
|
||
|
goto out0;
|
||
|
|
||
|
out2:
|
||
|
vxge_close_vpaths(vdev);
|
||
|
out0:
|
||
|
vxge_debug(VXGE_INFO, "%s: %s:%d Exiting...\n",
|
||
|
dev->name, __func__, __LINE__);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* vxge_close
|
||
|
* @dev: device pointer.
|
||
|
*
|
||
|
* This is the stop entry point of the driver. It needs to undo exactly
|
||
|
* whatever was done by the open entry point, thus it's usually referred to
|
||
|
* as the close function.Among other things this function mainly stops the
|
||
|
* Rx side of the NIC and frees all the Rx buffers in the Rx rings.
|
||
|
* Return value: '0' on success and an appropriate (-)ve integer as
|
||
|
* defined in errno.h file on failure.
|
||
|
*/
|
||
|
static void vxge_close(struct net_device *dev)
|
||
|
{
|
||
|
struct vxgedev *vdev;
|
||
|
struct __vxge_hw_device *hldev;
|
||
|
|
||
|
vxge_debug(VXGE_INFO, "%s: %s:%d\n",
|
||
|
dev->name, __func__, __LINE__);
|
||
|
|
||
|
vdev = (struct vxgedev *)netdev_priv(dev);
|
||
|
hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
|
||
|
|
||
|
if (!is_vxge_card_up(vdev))
|
||
|
return;
|
||
|
|
||
|
clear_bit(__VXGE_STATE_CARD_UP, vdev->state);
|
||
|
|
||
|
vxge_hw_vpath_set_zero_rx_frm_len(hldev);
|
||
|
|
||
|
netdev_link_down(vdev->ndev);
|
||
|
vxge_debug(VXGE_INFO, "%s: Link Down\n", vdev->ndev->name);
|
||
|
|
||
|
/* Note that at this point xmit() is stopped by upper layer */
|
||
|
vxge_hw_device_intr_disable(hldev);
|
||
|
|
||
|
/* Multi function shares INTA, hence we should
|
||
|
* leave it in enabled state
|
||
|
*/
|
||
|
if (is_mf(hldev->hw_info.function_mode))
|
||
|
vxge_hw_device_unmask_all(hldev);
|
||
|
|
||
|
vxge_reset_all_vpaths(vdev);
|
||
|
|
||
|
vxge_close_vpaths(vdev);
|
||
|
|
||
|
vxge_debug(VXGE_INFO,
|
||
|
"%s: %s:%d Exiting...\n", dev->name, __func__, __LINE__);
|
||
|
}
|
||
|
|
||
|
static struct net_device_operations vxge_operations;
|
||
|
|
||
|
int vxge_device_register(struct __vxge_hw_device *hldev,
|
||
|
struct vxgedev **vdev_out)
|
||
|
{
|
||
|
struct net_device *ndev;
|
||
|
struct vxgedev *vdev;
|
||
|
int ret = 0;
|
||
|
|
||
|
*vdev_out = NULL;
|
||
|
|
||
|
ndev = alloc_etherdev(sizeof(struct vxgedev));
|
||
|
if (ndev == NULL) {
|
||
|
vxge_debug(VXGE_ERR, "%s : device allocation failed\n",
|
||
|
__func__);
|
||
|
ret = -ENODEV;
|
||
|
goto _out0;
|
||
|
}
|
||
|
|
||
|
vxge_debug(VXGE_INFO, "%s:%d netdev registering\n",
|
||
|
__func__, __LINE__);
|
||
|
vdev = netdev_priv(ndev);
|
||
|
memset(vdev, 0, sizeof(struct vxgedev));
|
||
|
|
||
|
vdev->ndev = ndev;
|
||
|
vdev->devh = hldev;
|
||
|
vdev->pdev = hldev->pdev;
|
||
|
|
||
|
ndev->dev = &vdev->pdev->dev;
|
||
|
/* Associate vxge-specific network operations operations with
|
||
|
* generic network device layer */
|
||
|
netdev_init(ndev, &vxge_operations);
|
||
|
|
||
|
memcpy(ndev->hw_addr,
|
||
|
(u8 *)hldev->hw_info.mac_addrs[hldev->first_vp_id], ETH_ALEN);
|
||
|
|
||
|
if (register_netdev(ndev)) {
|
||
|
vxge_debug(VXGE_ERR, "%s : device registration failed!\n",
|
||
|
__func__);
|
||
|
ret = -ENODEV;
|
||
|
goto _out2;
|
||
|
}
|
||
|
|
||
|
/* Make Link state as off at this point, when the Link change
|
||
|
* interrupt comes the state will be automatically changed to
|
||
|
* the right state.
|
||
|
*/
|
||
|
netdev_link_down(ndev);
|
||
|
|
||
|
vxge_debug(VXGE_INFO, "%s: Ethernet device registered\n",
|
||
|
VXGE_DRIVER_NAME);
|
||
|
|
||
|
*vdev_out = vdev;
|
||
|
|
||
|
return ret;
|
||
|
_out2:
|
||
|
netdev_put(ndev);
|
||
|
_out0:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* vxge_device_unregister
|
||
|
*
|
||
|
* This function will unregister and free network device
|
||
|
*/
|
||
|
void
|
||
|
vxge_device_unregister(struct __vxge_hw_device *hldev)
|
||
|
{
|
||
|
struct vxgedev *vdev;
|
||
|
struct net_device *ndev;
|
||
|
|
||
|
ndev = hldev->ndev;
|
||
|
vdev = netdev_priv(ndev);
|
||
|
|
||
|
unregister_netdev(ndev);
|
||
|
netdev_nullify(ndev);
|
||
|
netdev_put(ndev);
|
||
|
|
||
|
vxge_debug(VXGE_INFO, "%s: ethernet device unregistered\n",
|
||
|
VXGE_DRIVER_NAME);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* vxge_probe
|
||
|
* @pdev : structure containing the PCI related information of the device.
|
||
|
* @id: List of PCI devices supported by the driver listed in vxge_id_table.
|
||
|
* Description:
|
||
|
* This function is called when a new PCI device gets detected and initializes
|
||
|
* it.
|
||
|
* Return value:
|
||
|
* returns 0 on success and negative on failure.
|
||
|
*
|
||
|
*/
|
||
|
static int
|
||
|
vxge_probe(struct pci_device *pdev, const struct pci_device_id *id __unused)
|
||
|
{
|
||
|
struct __vxge_hw_device *hldev;
|
||
|
enum vxge_hw_status status;
|
||
|
int ret = 0;
|
||
|
u64 vpath_mask = 0;
|
||
|
struct vxgedev *vdev;
|
||
|
int i;
|
||
|
u8 revision, titan1;
|
||
|
u32 host_type;
|
||
|
u32 function_mode;
|
||
|
unsigned long mmio_start, mmio_len;
|
||
|
void *bar0;
|
||
|
struct vxge_hw_device_hw_info hw_info;
|
||
|
struct vxge_hw_device_version *fw_version;
|
||
|
|
||
|
vxge_debug(VXGE_INFO, "vxge_probe for device %02X:%02X.%X\n",
|
||
|
pdev->bus, PCI_SLOT(pdev->devfn),
|
||
|
PCI_FUNC(pdev->devfn));
|
||
|
|
||
|
pci_read_config_byte(pdev, PCI_REVISION_ID, &revision);
|
||
|
titan1 = is_titan1(pdev->device, revision);
|
||
|
|
||
|
mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
|
||
|
mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_0);
|
||
|
vxge_debug(VXGE_INFO, "mmio_start: %#08lx, mmio_len: %#08lx\n",
|
||
|
mmio_start, mmio_len);
|
||
|
|
||
|
/* sets the bus master */
|
||
|
adjust_pci_device(pdev);
|
||
|
|
||
|
bar0 = ioremap(mmio_start, mmio_len);
|
||
|
if (!bar0) {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"%s : cannot remap io memory bar0\n", __func__);
|
||
|
ret = -ENODEV;
|
||
|
goto _exit0;
|
||
|
}
|
||
|
|
||
|
status = vxge_hw_device_hw_info_get(bar0, &hw_info);
|
||
|
if (status != VXGE_HW_OK) {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"%s: Reading of hardware info failed.\n",
|
||
|
VXGE_DRIVER_NAME);
|
||
|
ret = -EINVAL;
|
||
|
goto _exit1;
|
||
|
}
|
||
|
|
||
|
if (hw_info.func_id != 0) {
|
||
|
/* Non zero function, So do not load the driver */
|
||
|
iounmap(bar0);
|
||
|
pci_set_drvdata(pdev, NULL);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
|
||
|
vpath_mask = hw_info.vpath_mask;
|
||
|
if (vpath_mask == 0) {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"%s: No vpaths available in device\n",
|
||
|
VXGE_DRIVER_NAME);
|
||
|
ret = -EINVAL;
|
||
|
goto _exit1;
|
||
|
}
|
||
|
vxge_debug(VXGE_INFO,
|
||
|
"%s:%d Vpath mask = %llx\n", __func__, __LINE__,
|
||
|
(unsigned long long)vpath_mask);
|
||
|
|
||
|
host_type = hw_info.host_type;
|
||
|
fw_version = &hw_info.fw_version;
|
||
|
/* fail the driver loading if firmware is incompatible */
|
||
|
if ((fw_version->major != VXGE_CERT_FW_VER_MAJOR) ||
|
||
|
(fw_version->minor < VXGE_CERT_FW_VER_MINOR)) {
|
||
|
printf("%s: Adapter's current firmware version: %d.%d.%d\n",
|
||
|
VXGE_DRIVER_NAME, fw_version->major,
|
||
|
fw_version->minor, fw_version->build);
|
||
|
|
||
|
printf("%s: Upgrade firmware to version %d.%d.%d\n",
|
||
|
VXGE_DRIVER_NAME, VXGE_CERT_FW_VER_MAJOR,
|
||
|
VXGE_CERT_FW_VER_MINOR, VXGE_CERT_FW_VER_BUILD);
|
||
|
|
||
|
ret = -EACCES;
|
||
|
goto _exit1;
|
||
|
}
|
||
|
|
||
|
status = vxge_hw_device_initialize(&hldev, bar0, pdev, titan1);
|
||
|
if (status != VXGE_HW_OK) {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"Failed to initialize device (%d)\n", status);
|
||
|
ret = -EINVAL;
|
||
|
goto _exit1;
|
||
|
}
|
||
|
memcpy(&hldev->hw_info, &hw_info,
|
||
|
sizeof(struct vxge_hw_device_hw_info));
|
||
|
|
||
|
/* find the vpath id of the first available one */
|
||
|
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
|
||
|
if (vpath_mask & vxge_mBIT(i)) {
|
||
|
hldev->first_vp_id = i;
|
||
|
break;
|
||
|
}
|
||
|
/* if FCS stripping is not disabled in MAC fail driver load */
|
||
|
if (vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask) != VXGE_HW_OK) {
|
||
|
vxge_debug(VXGE_ERR,
|
||
|
"%s: FCS stripping is not disabled in MAC"
|
||
|
" failing driver load\n", VXGE_DRIVER_NAME);
|
||
|
ret = -EINVAL;
|
||
|
goto _exit2;
|
||
|
}
|
||
|
|
||
|
/* Read function mode */
|
||
|
status = vxge_hw_get_func_mode(hldev, &function_mode);
|
||
|
if (status != VXGE_HW_OK)
|
||
|
goto _exit2;
|
||
|
|
||
|
hldev->hw_info.function_mode = function_mode;
|
||
|
|
||
|
/* set private device info */
|
||
|
pci_set_drvdata(pdev, hldev);
|
||
|
|
||
|
if (vxge_device_register(hldev, &vdev)) {
|
||
|
ret = -EINVAL;
|
||
|
goto _exit2;
|
||
|
}
|
||
|
|
||
|
/* set private HW device info */
|
||
|
hldev->ndev = vdev->ndev;
|
||
|
hldev->vdev = vdev;
|
||
|
hldev->pdev = pdev;
|
||
|
vdev->mtu = VXGE_HW_DEFAULT_MTU;
|
||
|
vdev->bar0 = bar0;
|
||
|
vdev->titan1 = titan1;
|
||
|
/* Virtual Path count */
|
||
|
vdev->vpath.device_id = hldev->first_vp_id;
|
||
|
vdev->vpath.vdev = vdev;
|
||
|
memcpy((u8 *)vdev->vpath.macaddr,
|
||
|
(u8 *)hldev->hw_info.mac_addrs[hldev->first_vp_id],
|
||
|
ETH_ALEN);
|
||
|
|
||
|
hldev->hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0';
|
||
|
hldev->hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0';
|
||
|
hldev->hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0';
|
||
|
|
||
|
vxge_debug(VXGE_INFO, "%s: Neterion %s Server Adapter\n",
|
||
|
VXGE_DRIVER_NAME, hldev->hw_info.product_desc);
|
||
|
vxge_debug(VXGE_INFO, "%s: SERIAL NUMBER: %s\n",
|
||
|
VXGE_DRIVER_NAME, hldev->hw_info.serial_number);
|
||
|
vxge_debug(VXGE_INFO, "%s: PART NUMBER: %s\n",
|
||
|
VXGE_DRIVER_NAME, hldev->hw_info.part_number);
|
||
|
vxge_debug(VXGE_INFO, "%s: MAC ADDR: %s\n",
|
||
|
VXGE_DRIVER_NAME, eth_ntoa(vdev->vpath.macaddr));
|
||
|
vxge_debug(VXGE_INFO,
|
||
|
"%s: Firmware version : %s Date : %s\n", VXGE_DRIVER_NAME,
|
||
|
hldev->hw_info.fw_version.version,
|
||
|
hldev->hw_info.fw_date.date);
|
||
|
vxge_debug(VXGE_INFO, "%s: %s Enabled\n",
|
||
|
VXGE_DRIVER_NAME, vxge_func_mode_names[function_mode]);
|
||
|
|
||
|
vxge_debug(VXGE_INFO, "%s: %s:%d Probe Exiting...\n",
|
||
|
VXGE_DRIVER_NAME, __func__, __LINE__);
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
_exit2:
|
||
|
vxge_hw_device_terminate(hldev);
|
||
|
_exit1:
|
||
|
iounmap(bar0);
|
||
|
_exit0:
|
||
|
pci_set_drvdata(pdev, NULL);
|
||
|
printf("%s: WARNING!! Driver loading failed!!\n",
|
||
|
VXGE_DRIVER_NAME);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* vxge_remove - Free the PCI device
|
||
|
* @pdev: structure containing the PCI related information of the device.
|
||
|
* Description: This function is called by the Pci subsystem to release a
|
||
|
* PCI device and free up all resource held up by the device.
|
||
|
*/
|
||
|
static void
|
||
|
vxge_remove(struct pci_device *pdev)
|
||
|
{
|
||
|
struct __vxge_hw_device *hldev;
|
||
|
struct vxgedev *vdev = NULL;
|
||
|
struct net_device *ndev;
|
||
|
|
||
|
vxge_debug(VXGE_INFO,
|
||
|
"%s:%d\n", __func__, __LINE__);
|
||
|
hldev = (struct __vxge_hw_device *) pci_get_drvdata(pdev);
|
||
|
if (hldev == NULL)
|
||
|
return;
|
||
|
|
||
|
ndev = hldev->ndev;
|
||
|
vdev = netdev_priv(ndev);
|
||
|
|
||
|
iounmap(vdev->bar0);
|
||
|
|
||
|
vxge_device_unregister(hldev);
|
||
|
|
||
|
vxge_debug(VXGE_INFO,
|
||
|
"%s:%d Device unregistered\n", __func__, __LINE__);
|
||
|
|
||
|
vxge_hw_device_terminate(hldev);
|
||
|
pci_set_drvdata(pdev, NULL);
|
||
|
}
|
||
|
|
||
|
/* vxge net device operations */
|
||
|
static struct net_device_operations vxge_operations = {
|
||
|
.open = vxge_open,
|
||
|
.close = vxge_close,
|
||
|
.transmit = vxge_xmit,
|
||
|
.poll = vxge_poll,
|
||
|
.irq = vxge_irq,
|
||
|
};
|
||
|
|
||
|
static struct pci_device_id vxge_nics[] = {
|
||
|
PCI_ROM(0x17d5, 0x5833, "vxge-x3100", "Neterion X3100 Series", 0),
|
||
|
};
|
||
|
|
||
|
struct pci_driver vxge_driver __pci_driver = {
|
||
|
.ids = vxge_nics,
|
||
|
.id_count = (sizeof(vxge_nics) / sizeof(vxge_nics[0])),
|
||
|
.probe = vxge_probe,
|
||
|
.remove = vxge_remove,
|
||
|
};
|