#include "bnx2x.h"
#include "bnx2x_init.h"
- #define DRV_MODULE_VERSION "1.45.24"
- #define DRV_MODULE_RELDATE "2009/01/14"
+ #define DRV_MODULE_VERSION "1.45.26"
+ #define DRV_MODULE_RELDATE "2009/01/26"
#define BNX2X_BC_VER 0x040200
/* Time in jiffies before concluding the transmitter is hung */
/* Tell compiler that status block fields can change */
barrier();
tx_cons_sb = le16_to_cpu(*fp->tx_cons_sb);
- return ((fp->tx_pkt_prod != tx_cons_sb) ||
- (fp->tx_pkt_prod != fp->tx_pkt_cons));
+ return (fp->tx_pkt_cons != tx_cons_sb);
+ }
+
+ static inline int bnx2x_has_tx_work_unload(struct bnx2x_fastpath *fp)
+ {
+ /* Tell compiler that consumer and producer can change */
+ barrier();
+ return (fp->tx_pkt_prod != fp->tx_pkt_cons);
+
}
/* free skb in the packet ring at pos idx
prefetch(&fp->status_blk->c_status_block.status_block_index);
prefetch(&fp->status_blk->u_status_block.status_block_index);
- netif_rx_schedule(&bnx2x_fp(bp, index, napi));
+ napi_schedule(&bnx2x_fp(bp, index, napi));
return IRQ_HANDLED;
}
prefetch(&fp->status_blk->c_status_block.status_block_index);
prefetch(&fp->status_blk->u_status_block.status_block_index);
- netif_rx_schedule(&bnx2x_fp(bp, 0, napi));
+ napi_schedule(&bnx2x_fp(bp, 0, napi));
status &= ~mask;
}
}
+ static void bnx2x_reset_common(struct bnx2x *bp)
+ {
+ /* reset_common */
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
+ 0xd3ffff7f);
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403);
+ }
+
static int bnx2x_init_common(struct bnx2x *bp)
{
u32 val, i;
DP(BNX2X_MSG_MCP, "starting common init func %d\n", BP_FUNC(bp));
+ bnx2x_reset_common(bp);
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff);
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, 0xfffc);
static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
{
bnx2x_int_disable_sync(bp, disable_hw);
+ bnx2x_napi_disable(bp);
if (netif_running(bp->dev)) {
- bnx2x_napi_disable(bp);
netif_tx_disable(bp->dev);
bp->dev->trans_start = jiffies; /* prevent tx timeout */
}
static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
{
u32 load_code;
- int i, rc;
+ int i, rc = 0;
#ifdef BNX2X_STOP_ON_ERROR
if (unlikely(bp->panic))
return -EPERM;
bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
- /* Send LOAD_REQUEST command to MCP
- Returns the type of LOAD command:
- if it is the first port to be initialized
- common blocks should be initialized, otherwise - not
- */
- if (!BP_NOMCP(bp)) {
- load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
- if (!load_code) {
- BNX2X_ERR("MCP response failure, aborting\n");
- return -EBUSY;
- }
- if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED)
- return -EBUSY; /* other port in diagnostic mode */
-
- } else {
- int port = BP_PORT(bp);
-
- DP(NETIF_MSG_IFUP, "NO MCP load counts before us %d, %d, %d\n",
- load_count[0], load_count[1], load_count[2]);
- load_count[0]++;
- load_count[1 + port]++;
- DP(NETIF_MSG_IFUP, "NO MCP new load counts %d, %d, %d\n",
- load_count[0], load_count[1], load_count[2]);
- if (load_count[0] == 1)
- load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
- else if (load_count[1 + port] == 1)
- load_code = FW_MSG_CODE_DRV_LOAD_PORT;
- else
- load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
- }
-
- if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
- (load_code == FW_MSG_CODE_DRV_LOAD_PORT))
- bp->port.pmf = 1;
- else
- bp->port.pmf = 0;
- DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
-
- /* if we can't use MSI-X we only need one fp,
- * so try to enable MSI-X with the requested number of fp's
- * and fallback to inta with one fp
- */
if (use_inta) {
bp->num_queues = 1;
else
bp->num_queues = 1;
- if (bnx2x_enable_msix(bp)) {
+ DP(NETIF_MSG_IFUP,
+ "set number of queues to %d\n", bp->num_queues);
+
+ /* if we can't use MSI-X we only need one fp,
+ * so try to enable MSI-X with the requested number of fp's
+ * and fallback to MSI or legacy INTx with one fp
+ */
+ rc = bnx2x_enable_msix(bp);
+ if (rc) {
/* failed to enable MSI-X */
bp->num_queues = 1;
if (use_multi)
" to enable MSI-X\n");
}
}
- DP(NETIF_MSG_IFUP,
- "set number of queues to %d\n", bp->num_queues);
if (bnx2x_alloc_mem(bp))
return -ENOMEM;
bnx2x_fp(bp, i, disable_tpa) =
((bp->flags & TPA_ENABLE_FLAG) == 0);
+ for_each_queue(bp, i)
+ netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
+ bnx2x_poll, 128);
+
+ #ifdef BNX2X_STOP_ON_ERROR
+ for_each_queue(bp, i) {
+ struct bnx2x_fastpath *fp = &bp->fp[i];
+
+ fp->poll_no_work = 0;
+ fp->poll_calls = 0;
+ fp->poll_max_calls = 0;
+ fp->poll_complete = 0;
+ fp->poll_exit = 0;
+ }
+ #endif
+ bnx2x_napi_enable(bp);
+
if (bp->flags & USING_MSIX_FLAG) {
rc = bnx2x_req_msix_irqs(bp);
if (rc) {
pci_disable_msix(bp->pdev);
- goto load_error;
+ goto load_error1;
}
+ printk(KERN_INFO PFX "%s: using MSI-X\n", bp->dev->name);
} else {
bnx2x_ack_int(bp);
rc = bnx2x_req_irq(bp);
if (rc) {
- BNX2X_ERR("IRQ request failed, aborting\n");
- goto load_error;
+ BNX2X_ERR("IRQ request failed rc %d, aborting\n", rc);
+ goto load_error1;
}
}
- for_each_queue(bp, i)
- netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
- bnx2x_poll, 128);
+ /* Send LOAD_REQUEST command to MCP
+ Returns the type of LOAD command:
+ if it is the first port to be initialized
+ common blocks should be initialized, otherwise - not
+ */
+ if (!BP_NOMCP(bp)) {
+ load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
+ if (!load_code) {
+ BNX2X_ERR("MCP response failure, aborting\n");
+ rc = -EBUSY;
+ goto load_error2;
+ }
+ if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
+ rc = -EBUSY; /* other port in diagnostic mode */
+ goto load_error2;
+ }
+
+ } else {
+ int port = BP_PORT(bp);
+
+ DP(NETIF_MSG_IFUP, "NO MCP load counts before us %d, %d, %d\n",
+ load_count[0], load_count[1], load_count[2]);
+ load_count[0]++;
+ load_count[1 + port]++;
+ DP(NETIF_MSG_IFUP, "NO MCP new load counts %d, %d, %d\n",
+ load_count[0], load_count[1], load_count[2]);
+ if (load_count[0] == 1)
+ load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
+ else if (load_count[1 + port] == 1)
+ load_code = FW_MSG_CODE_DRV_LOAD_PORT;
+ else
+ load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
+ }
+
+ if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+ (load_code == FW_MSG_CODE_DRV_LOAD_PORT))
+ bp->port.pmf = 1;
+ else
+ bp->port.pmf = 0;
+ DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
/* Initialize HW */
rc = bnx2x_init_hw(bp, load_code);
if (rc) {
BNX2X_ERR("HW init failed, aborting\n");
- goto load_int_disable;
+ goto load_error2;
}
/* Setup NIC internals and enable interrupts */
if (!load_code) {
BNX2X_ERR("MCP response failure, aborting\n");
rc = -EBUSY;
- goto load_rings_free;
+ goto load_error3;
}
}
rc = bnx2x_setup_leading(bp);
if (rc) {
BNX2X_ERR("Setup leading failed!\n");
- goto load_netif_stop;
+ goto load_error3;
}
if (CHIP_IS_E1H(bp))
for_each_nondefault_queue(bp, i) {
rc = bnx2x_setup_multi(bp, i);
if (rc)
- goto load_netif_stop;
+ goto load_error3;
}
if (CHIP_IS_E1(bp))
case LOAD_NORMAL:
/* Tx queue should be only reenabled */
netif_wake_queue(bp->dev);
+ /* Initialize the receive filter. */
bnx2x_set_rx_mode(bp->dev);
break;
case LOAD_OPEN:
netif_start_queue(bp->dev);
+ /* Initialize the receive filter. */
bnx2x_set_rx_mode(bp->dev);
- if (bp->flags & USING_MSIX_FLAG)
- printk(KERN_INFO PFX "%s: using MSI-X\n",
- bp->dev->name);
break;
case LOAD_DIAG:
+ /* Initialize the receive filter. */
bnx2x_set_rx_mode(bp->dev);
bp->state = BNX2X_STATE_DIAG;
break;
return 0;
- load_netif_stop:
- bnx2x_napi_disable(bp);
- load_rings_free:
+ load_error3:
+ bnx2x_int_disable_sync(bp, 1);
+ if (!BP_NOMCP(bp)) {
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
+ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+ }
+ bp->port.pmf = 0;
/* Free SKBs, SGEs, TPA pool and driver internals */
bnx2x_free_skbs(bp);
for_each_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
- load_int_disable:
- bnx2x_int_disable_sync(bp, 1);
+ load_error2:
/* Release IRQs */
bnx2x_free_irq(bp);
- load_error:
+ load_error1:
+ bnx2x_napi_disable(bp);
+ for_each_queue(bp, i)
+ netif_napi_del(&bnx2x_fp(bp, i, napi));
bnx2x_free_mem(bp);
- bp->port.pmf = 0;
/* TBD we really need to reset the chip
if we want to recover from this */
}
cnt--;
msleep(1);
+ rmb(); /* Refresh the dsb_sp_prod */
}
bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD;
bp->fp[0].state = BNX2X_FP_STATE_CLOSED;
/* TODO: Close Doorbell port? */
}
- static void bnx2x_reset_common(struct bnx2x *bp)
- {
- /* reset_common */
- REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
- 0xd3ffff7f);
- REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403);
- }
-
static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code)
{
DP(BNX2X_MSG_MCP, "function %d reset_code %x\n",
bnx2x_set_storm_rx_mode(bp);
bnx2x_netif_stop(bp, 1);
- if (!netif_running(bp->dev))
- bnx2x_napi_disable(bp);
+
del_timer_sync(&bp->timer);
SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb,
(DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq));
cnt = 1000;
smp_rmb();
- while (bnx2x_has_tx_work(fp)) {
+ while (bnx2x_has_tx_work_unload(fp)) {
bnx2x_tx_int(fp, 1000);
if (!cnt) {
bnx2x_free_skbs(bp);
for_each_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
+ for_each_queue(bp, i)
+ netif_napi_del(&bnx2x_fp(bp, i, napi));
bnx2x_free_mem(bp);
bp->state = BNX2X_STATE_CLOSED;
if (loopback_mode == BNX2X_MAC_LOOPBACK) {
bp->link_params.loopback_mode = LOOPBACK_BMAC;
- bnx2x_acquire_phy_lock(bp);
bnx2x_phy_init(&bp->link_params, &bp->link_vars);
- bnx2x_release_phy_lock(bp);
} else if (loopback_mode == BNX2X_PHY_LOOPBACK) {
+ u16 cnt = 1000;
bp->link_params.loopback_mode = LOOPBACK_XGXS_10;
- bnx2x_acquire_phy_lock(bp);
bnx2x_phy_init(&bp->link_params, &bp->link_vars);
- bnx2x_release_phy_lock(bp);
/* wait until link state is restored */
- bnx2x_wait_for_link(bp, link_up);
-
+ if (link_up)
+ while (cnt-- && bnx2x_test_link(&bp->link_params,
+ &bp->link_vars))
+ msleep(10);
} else
return -EINVAL;
return BNX2X_LOOPBACK_FAILED;
bnx2x_netif_stop(bp, 1);
+ bnx2x_acquire_phy_lock(bp);
if (bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up)) {
DP(NETIF_MSG_PROBE, "MAC loopback failed\n");
rc |= BNX2X_PHY_LOOPBACK_FAILED;
}
+ bnx2x_release_phy_lock(bp);
bnx2x_netif_start(bp);
return rc;
#ifdef BNX2X_STOP_ON_ERROR
poll_panic:
#endif
- netif_rx_complete(napi);
+ napi_complete(napi);
bnx2x_ack_sb(bp, FP_SB_ID(fp), USTORM_ID,
le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1);
{
struct bnx2x *bp = netdev_priv(dev);
+ netif_carrier_off(dev);
+
bnx2x_set_power_state(bp, PCI_D0);
return bnx2x_nic_load(bp, LOAD_OPEN);
goto init_one_exit;
}
- netif_carrier_off(dev);
-
bp->common.name = board_info[ent->driver_data].name;
printk(KERN_INFO "%s: %s (%c%d) PCI-E x%d %s found at mem %lx,"
" IRQ %d, ", dev->name, bp->common.name,
bnx2x_free_skbs(bp);
for_each_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
+ for_each_queue(bp, i)
+ netif_napi_del(&bnx2x_fp(bp, i, napi));
bnx2x_free_mem(bp);
bp->state = BNX2X_STATE_CLOSED;
#include <linux/virtio.h>
#include <linux/virtio_net.h>
#include <linux/scatterlist.h>
+ #include <linux/if_vlan.h>
static int napi_weight = 128;
module_param(napi_weight, int, 0444);
module_param(gso, bool, 0444);
/* FIXME: MTU in config. */
- #define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN)
+ #define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
#define GOOD_COPY_LEN 128
struct virtnet_info
struct virtqueue *rvq, *svq;
struct net_device *dev;
struct napi_struct napi;
+ unsigned int status;
/* The skb we couldn't send because buffers were full. */
struct sk_buff *last_xmit_skb;
{
struct virtnet_info *vi = rvq->vdev->priv;
/* Schedule NAPI, Suppress further interrupts if successful. */
- if (netif_rx_schedule_prep(&vi->napi)) {
+ if (napi_schedule_prep(&vi->napi)) {
rvq->vq_ops->disable_cb(rvq);
- __netif_rx_schedule(&vi->napi);
+ __napi_schedule(&vi->napi);
}
}
/* Out of packets? */
if (received < budget) {
- netif_rx_complete(napi);
+ napi_complete(napi);
if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq))
&& napi_schedule_prep(napi)) {
vi->rvq->vq_ops->disable_cb(vi->rvq);
- __netif_rx_schedule(napi);
+ __napi_schedule(napi);
goto again;
}
}
* won't get another interrupt, so process any outstanding packets
* now. virtnet_poll wants re-enable the queue, so we disable here.
* We synchronize against interrupts via NAPI_STATE_SCHED */
- if (netif_rx_schedule_prep(&vi->napi)) {
+ if (napi_schedule_prep(&vi->napi)) {
vi->rvq->vq_ops->disable_cb(vi->rvq);
- __netif_rx_schedule(&vi->napi);
+ __napi_schedule(&vi->napi);
}
return 0;
}
.set_tx_csum = virtnet_set_tx_csum,
.set_sg = ethtool_op_set_sg,
.set_tso = ethtool_op_set_tso,
+ .get_link = ethtool_op_get_link,
};
#define MIN_MTU 68
#endif
};
+static void virtnet_update_status(struct virtnet_info *vi)
+{
+ u16 v;
+
+ if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS))
+ return;
+
+ vi->vdev->config->get(vi->vdev,
+ offsetof(struct virtio_net_config, status),
+ &v, sizeof(v));
+
+ /* Ignore unknown (future) status bits */
+ v &= VIRTIO_NET_S_LINK_UP;
+
+ if (vi->status == v)
+ return;
+
+ vi->status = v;
+
+ if (vi->status & VIRTIO_NET_S_LINK_UP) {
+ netif_carrier_on(vi->dev);
+ netif_wake_queue(vi->dev);
+ } else {
+ netif_carrier_off(vi->dev);
+ netif_stop_queue(vi->dev);
+ }
+}
+
+static void virtnet_config_changed(struct virtio_device *vdev)
+{
+ struct virtnet_info *vi = vdev->priv;
+
+ virtnet_update_status(vi);
+}
+
static int virtnet_probe(struct virtio_device *vdev)
{
int err;
goto unregister;
}
+ vi->status = VIRTIO_NET_S_LINK_UP;
+ virtnet_update_status(vi);
+
pr_debug("virtnet: registered device %s\n", dev->name);
return 0;
VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */
- VIRTIO_NET_F_MRG_RXBUF,
+ VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS,
VIRTIO_F_NOTIFY_ON_EMPTY,
};
.id_table = id_table,
.probe = virtnet_probe,
.remove = __devexit_p(virtnet_remove),
+ .config_changed = virtnet_config_changed,
};
static int __init init(void)
static void lcs_tasklet(unsigned long);
static void lcs_start_kernel_thread(struct work_struct *);
static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *);
+ #ifdef CONFIG_IP_MULTICAST
static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *);
+ #endif /* CONFIG_IP_MULTICAST */
static int lcs_recovery(void *ptr);
/**
lcs_clear_thread_running_bit(card, LCS_SET_MC_THREAD);
return 0;
}
+ #endif /* CONFIG_IP_MULTICAST */
+
/**
* function called by net device to
* handle multicast address relevant things
static void
lcs_set_multicast_list(struct net_device *dev)
{
+ #ifdef CONFIG_IP_MULTICAST
struct lcs_card *card;
LCS_DBF_TEXT(4, trace, "setmulti");
if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD))
schedule_work(&card->kernel_thread_starter);
- }
-
#endif /* CONFIG_IP_MULTICAST */
+ }
static long
lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb)
/**
* lcs_new_device will be called by setting the group device online.
*/
+static const struct net_device_ops lcs_netdev_ops = {
+ .ndo_open = lcs_open_device,
+ .ndo_stop = lcs_stop_device,
+ .ndo_get_stats = lcs_getstats,
+ .ndo_start_xmit = lcs_start_xmit,
+};
+
+static const struct net_device_ops lcs_mc_netdev_ops = {
+ .ndo_open = lcs_open_device,
+ .ndo_stop = lcs_stop_device,
+ .ndo_get_stats = lcs_getstats,
+ .ndo_start_xmit = lcs_start_xmit,
+ .ndo_set_multicast_list = lcs_set_multicast_list,
+};
static int
lcs_new_device(struct ccwgroup_device *ccwgdev)
goto out;
card->dev = dev;
card->dev->ml_priv = card;
- card->dev->open = lcs_open_device;
- card->dev->stop = lcs_stop_device;
- card->dev->hard_start_xmit = lcs_start_xmit;
- card->dev->get_stats = lcs_getstats;
+ card->dev->netdev_ops = &lcs_netdev_ops;
memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
#ifdef CONFIG_IP_MULTICAST
if (!lcs_check_multicast_support(card))
- card->dev->set_multicast_list = lcs_set_multicast_list;
+ card->dev->netdev_ops = &lcs_mc_netdev_ops;
#endif
netdev_out:
lcs_set_allowed_threads(card,0xffffffff);