david/ipxe
Archived
1
0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/src/drivers/net/vxge/vxge_main.c
Michael Brown 8406115834 [build] Rename gPXE to iPXE
Access to the gpxe.org and etherboot.org domains and associated
resources has been revoked by the registrant of the domain.  Work
around this problem by renaming project from gPXE to iPXE, and
updating URLs to match.

Also update README, LOG and COPYRIGHTS to remove obsolete information.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2010-04-19 23:43:39 +01:00

726 lines
18 KiB
C

/*
* vxge-main.c: iPXE 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 <ipxe/io.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/pci.h>
#include <ipxe/malloc.h>
#include <ipxe/if_ether.h>
#include <ipxe/ethernet.h>
#include <ipxe/iobuf.h>
#include <ipxe/netdevice.h>
#include <ipxe/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 iPXE 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_main_nics[] = {
/* If you change this, also adjust vxge_nics[] in vxge.c */
PCI_ID(0x17d5, 0x5833, "vxge-x3100", "Neterion X3100 Series", 0),
};
struct pci_driver vxge_driver __pci_driver = {
.ids = vxge_main_nics,
.id_count = (sizeof(vxge_main_nics) / sizeof(vxge_main_nics[0])),
.probe = vxge_probe,
.remove = vxge_remove,
};