diff options
Diffstat (limited to 'drivers/net/enic')
-rw-r--r-- | drivers/net/enic/cq_desc.h | 5 | ||||
-rw-r--r-- | drivers/net/enic/enic.h | 2 | ||||
-rw-r--r-- | drivers/net/enic/enic_main.c | 86 | ||||
-rw-r--r-- | drivers/net/enic/enic_res.c | 7 | ||||
-rw-r--r-- | drivers/net/enic/enic_res.h | 4 | ||||
-rw-r--r-- | drivers/net/enic/vnic_dev.c | 70 | ||||
-rw-r--r-- | drivers/net/enic/vnic_devcmd.h | 19 | ||||
-rw-r--r-- | drivers/net/enic/vnic_intr.h | 2 | ||||
-rw-r--r-- | drivers/net/enic/vnic_resource.h | 2 | ||||
-rw-r--r-- | drivers/net/enic/vnic_rq.h | 9 | ||||
-rw-r--r-- | drivers/net/enic/vnic_rss.h | 13 | ||||
-rw-r--r-- | drivers/net/enic/vnic_wq.h | 9 |
12 files changed, 146 insertions, 82 deletions
diff --git a/drivers/net/enic/cq_desc.h b/drivers/net/enic/cq_desc.h index c036a8bfd04..1eb289f773b 100644 --- a/drivers/net/enic/cq_desc.h +++ b/drivers/net/enic/cq_desc.h @@ -44,9 +44,10 @@ struct cq_desc { u8 type_color; }; -#define CQ_DESC_TYPE_BITS 7 +#define CQ_DESC_TYPE_BITS 4 #define CQ_DESC_TYPE_MASK ((1 << CQ_DESC_TYPE_BITS) - 1) #define CQ_DESC_COLOR_MASK 1 +#define CQ_DESC_COLOR_SHIFT 7 #define CQ_DESC_Q_NUM_BITS 10 #define CQ_DESC_Q_NUM_MASK ((1 << CQ_DESC_Q_NUM_BITS) - 1) #define CQ_DESC_COMP_NDX_BITS 12 @@ -58,7 +59,7 @@ static inline void cq_desc_dec(const struct cq_desc *desc_arg, const struct cq_desc *desc = desc_arg; const u8 type_color = desc->type_color; - *color = (type_color >> CQ_DESC_TYPE_BITS) & CQ_DESC_COLOR_MASK; + *color = (type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK; /* * Make sure color bit is read from desc *before* other fields diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 7f677e89a78..a832cc5d6a1 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -33,7 +33,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco 10G Ethernet Driver" -#define DRV_VERSION "0.0.1-18163.472-k1" +#define DRV_VERSION "1.0.0.648" #define DRV_COPYRIGHT "Copyright 2008 Cisco Systems, Inc" #define PFX DRV_NAME ": " diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 180e968dc54..d039e16f276 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -273,6 +273,8 @@ static struct ethtool_ops enic_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, .set_tso = enic_set_tso, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, }; static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) @@ -409,8 +411,8 @@ static irqreturn_t enic_isr_legacy(int irq, void *data) } if (ENIC_TEST_INTR(pba, ENIC_INTX_WQ_RQ)) { - if (netif_rx_schedule_prep(netdev, &enic->napi)) - __netif_rx_schedule(netdev, &enic->napi); + if (netif_rx_schedule_prep(&enic->napi)) + __netif_rx_schedule(&enic->napi); } else { vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]); } @@ -438,7 +440,7 @@ static irqreturn_t enic_isr_msi(int irq, void *data) * writes). */ - netif_rx_schedule(enic->netdev, &enic->napi); + netif_rx_schedule(&enic->napi); return IRQ_HANDLED; } @@ -448,7 +450,7 @@ static irqreturn_t enic_isr_msix_rq(int irq, void *data) struct enic *enic = data; /* schedule NAPI polling for RQ cleanup */ - netif_rx_schedule(enic->netdev, &enic->napi); + netif_rx_schedule(&enic->napi); return IRQ_HANDLED; } @@ -895,6 +897,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, int skipped, void *opaque) { struct enic *enic = vnic_dev_priv(rq->vdev); + struct net_device *netdev = enic->netdev; struct sk_buff *skb; u8 type, color, eop, sop, ingress_port, vlan_stripped; @@ -929,7 +932,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, if (net_ratelimit()) printk(KERN_ERR PFX "%s: packet error: bad FCS\n", - enic->netdev->name); + netdev->name); } dev_kfree_skb_any(skb); @@ -943,19 +946,18 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, */ skb_put(skb, bytes_written); - skb->protocol = eth_type_trans(skb, enic->netdev); + skb->protocol = eth_type_trans(skb, netdev); if (enic->csum_rx_enabled && !csum_not_calc) { skb->csum = htons(checksum); skb->ip_summed = CHECKSUM_COMPLETE; } - skb->dev = enic->netdev; - enic->netdev->last_rx = jiffies; + skb->dev = netdev; if (enic->vlan_group && vlan_stripped) { - if (ENIC_SETTING(enic, LRO) && ipv4) + if ((netdev->features & NETIF_F_LRO) && ipv4) lro_vlan_hwaccel_receive_skb(&enic->lro_mgr, skb, enic->vlan_group, vlan, cq_desc); @@ -965,7 +967,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, } else { - if (ENIC_SETTING(enic, LRO) && ipv4) + if ((netdev->features & NETIF_F_LRO) && ipv4) lro_receive_skb(&enic->lro_mgr, skb, cq_desc); else netif_receive_skb(skb); @@ -1063,10 +1065,10 @@ static int enic_poll(struct napi_struct *napi, int budget) /* If no work done, flush all LROs and exit polling */ - if (ENIC_SETTING(enic, LRO)) + if (netdev->features & NETIF_F_LRO) lro_flush_all(&enic->lro_mgr); - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]); } @@ -1107,10 +1109,10 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) /* If no work done, flush all LROs and exit polling */ - if (ENIC_SETTING(enic, LRO)) + if (netdev->features & NETIF_F_LRO) lro_flush_all(&enic->lro_mgr); - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]); } @@ -1591,6 +1593,23 @@ static void enic_iounmap(struct enic *enic) iounmap(enic->bar0.vaddr); } +static const struct net_device_ops enic_netdev_ops = { + .ndo_open = enic_open, + .ndo_stop = enic_stop, + .ndo_start_xmit = enic_hard_start_xmit, + .ndo_get_stats = enic_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = enic_set_multicast_list, + .ndo_change_mtu = enic_change_mtu, + .ndo_vlan_rx_register = enic_vlan_rx_register, + .ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = enic_vlan_rx_kill_vid, + .ndo_tx_timeout = enic_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = enic_poll_controller, +#endif +}; + static int __devinit enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1746,13 +1765,13 @@ static int __devinit enic_probe(struct pci_dev *pdev, } /* Get available resource counts - */ + */ enic_get_res_counts(enic); /* Set interrupt mode based on resource counts and system * capabilities - */ + */ err = enic_set_intr_mode(enic); if (err) { @@ -1814,21 +1833,9 @@ static int __devinit enic_probe(struct pci_dev *pdev, goto err_out_free_vnic_resources; } - netdev->open = enic_open; - netdev->stop = enic_stop; - netdev->hard_start_xmit = enic_hard_start_xmit; - netdev->get_stats = enic_get_stats; - netdev->set_multicast_list = enic_set_multicast_list; - netdev->change_mtu = enic_change_mtu; - netdev->vlan_rx_register = enic_vlan_rx_register; - netdev->vlan_rx_add_vid = enic_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = enic_vlan_rx_kill_vid; - netdev->tx_timeout = enic_tx_timeout; + netdev->netdev_ops = &enic_netdev_ops; netdev->watchdog_timeo = 2 * HZ; netdev->ethtool_ops = &enic_ethtool_ops; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = enic_poll_controller; -#endif switch (vnic_dev_get_intr_mode(enic->vdev)) { default: @@ -1845,22 +1852,23 @@ static int __devinit enic_probe(struct pci_dev *pdev, if (ENIC_SETTING(enic, TSO)) netdev->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN; + if (ENIC_SETTING(enic, LRO)) + netdev->features |= NETIF_F_LRO; if (using_dac) netdev->features |= NETIF_F_HIGHDMA; enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM); - if (ENIC_SETTING(enic, LRO)) { - enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR; - enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC; - enic->lro_mgr.lro_arr = enic->lro_desc; - enic->lro_mgr.get_skb_header = enic_get_skb_header; - enic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; - enic->lro_mgr.dev = netdev; - enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE; - enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; - } + enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR; + enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC; + enic->lro_mgr.lro_arr = enic->lro_desc; + enic->lro_mgr.get_skb_header = enic_get_skb_header; + enic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + enic->lro_mgr.dev = netdev; + enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE; + enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; + err = register_netdev(netdev); if (err) { diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index 95184b9108e..e5fc9384f8f 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -90,11 +90,8 @@ int enic_get_vnic_config(struct enic *enic) c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); - printk(KERN_INFO PFX "vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x " - "wq/rq %d/%d\n", - enic->mac_addr[0], enic->mac_addr[1], enic->mac_addr[2], - enic->mac_addr[3], enic->mac_addr[4], enic->mac_addr[5], - c->wq_desc_count, c->rq_desc_count); + printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n", + enic->mac_addr, c->wq_desc_count, c->rq_desc_count); printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d " "intr timer %d\n", c->mtu, ENIC_SETTING(enic, TXCSUM), diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h index 68534a29b7a..7bf272fa859 100644 --- a/drivers/net/enic/enic_res.h +++ b/drivers/net/enic/enic_res.h @@ -58,8 +58,6 @@ static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq, (u16)vlan_tag, 0 /* loopback */); - wmb(); - vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop); } @@ -127,8 +125,6 @@ static inline void enic_queue_rq_desc(struct vnic_rq *rq, (u64)dma_addr | VNIC_PADDR_TARGET, type, (u16)len); - wmb(); - vnic_rq_post(rq, os_buf, os_buf_index, dma_addr, len); } diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index 4d104f5c30f..11708579b6c 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -43,6 +43,7 @@ struct vnic_dev { struct vnic_devcmd_notify *notify; struct vnic_devcmd_notify notify_copy; dma_addr_t notify_pa; + u32 notify_sz; u32 *linkstatus; dma_addr_t linkstatus_pa; struct vnic_stats *stats; @@ -235,14 +236,6 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, struct vnic_devcmd __iomem *devcmd = vdev->devcmd; int delay; u32 status; - int dev_cmd_err[] = { - /* convert from fw's version of error.h to host's version */ - 0, /* ERR_SUCCESS */ - EINVAL, /* ERR_EINVAL */ - EFAULT, /* ERR_EFAULT */ - EPERM, /* ERR_EPERM */ - EBUSY, /* ERR_EBUSY */ - }; int err; status = ioread32(&devcmd->status); @@ -270,10 +263,12 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, if (!(status & STAT_BUSY)) { if (status & STAT_ERROR) { - err = dev_cmd_err[(int)readq(&devcmd->args[0])]; - printk(KERN_ERR "Error %d devcmd %d\n", - err, _CMD_N(cmd)); - return -err; + err = (int)readq(&devcmd->args[0]); + if (err != ERR_ECMDUNKNOWN || + cmd != CMD_CAPABILITY) + printk(KERN_ERR "Error %d devcmd %d\n", + err, _CMD_N(cmd)); + return err; } if (_CMD_DIR(cmd) & _CMD_DIR_READ) { @@ -290,6 +285,17 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, return -ETIMEDOUT; } +static int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd) +{ + u64 a0 = (u32)cmd, a1 = 0; + int wait = 1000; + int err; + + err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); + + return !(err || a0); +} + int vnic_dev_fw_info(struct vnic_dev *vdev, struct vnic_devcmd_fw_info **fw_info) { @@ -489,10 +495,7 @@ void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); if (err) - printk(KERN_ERR - "Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], - err); + printk(KERN_ERR "Can't add addr [%pM], %d\n", addr, err); } void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) @@ -507,16 +510,14 @@ void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); if (err) - printk(KERN_ERR - "Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], - err); + printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err); } int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) { u64 a0, a1; int wait = 1000; + int r; if (!vdev->notify) { vdev->notify = pci_alloc_consistent(vdev->pdev, @@ -524,13 +525,16 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) &vdev->notify_pa); if (!vdev->notify) return -ENOMEM; + memset(vdev->notify, 0, sizeof(struct vnic_devcmd_notify)); } a0 = vdev->notify_pa; a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL; a1 += sizeof(struct vnic_devcmd_notify); - return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); + r = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); + vdev->notify_sz = (r == 0) ? (u32)a1 : 0; + return r; } void vnic_dev_notify_unset(struct vnic_dev *vdev) @@ -543,22 +547,22 @@ void vnic_dev_notify_unset(struct vnic_dev *vdev) a1 += sizeof(struct vnic_devcmd_notify); vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); + vdev->notify_sz = 0; } static int vnic_dev_notify_ready(struct vnic_dev *vdev) { u32 *words; - unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4; + unsigned int nwords = vdev->notify_sz / 4; unsigned int i; u32 csum; - if (!vdev->notify) + if (!vdev->notify || !vdev->notify_sz) return 0; do { csum = 0; - memcpy(&vdev->notify_copy, vdev->notify, - sizeof(struct vnic_devcmd_notify)); + memcpy(&vdev->notify_copy, vdev->notify, vdev->notify_sz); words = (u32 *)&vdev->notify_copy; for (i = 1; i < nwords; i++) csum += words[i]; @@ -571,7 +575,20 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg) { u64 a0 = (u32)arg, a1 = 0; int wait = 1000; - return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); + int r = 0; + + if (vnic_dev_capable(vdev, CMD_INIT)) + r = vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); + else { + vnic_dev_cmd(vdev, CMD_INIT_v1, &a0, &a1, wait); + if (a0 & CMD_INITF_DEFAULT_MAC) { + // Emulate these for old CMD_INIT_v1 which + // didn't pass a0 so no CMD_INITF_*. + vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait); + vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); + } + } + return r; } int vnic_dev_link_status(struct vnic_dev *vdev) @@ -672,3 +689,4 @@ err_out: return NULL; } + diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h index d8617a3373b..8062c75154e 100644 --- a/drivers/net/enic/vnic_devcmd.h +++ b/drivers/net/enic/vnic_devcmd.h @@ -168,7 +168,8 @@ enum vnic_devcmd_cmd { CMD_CLOSE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25), /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ - CMD_INIT = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), +/***** Replaced by CMD_INIT *****/ + CMD_INIT_v1 = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), /* variant of CMD_INIT, with provisioning info * (u64)a0=paddr of vnic_devcmd_provinfo @@ -198,6 +199,14 @@ enum vnic_devcmd_cmd { /* undo initialize of virtual link */ CMD_DEINIT = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34), + + /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ + CMD_INIT = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 35), + + /* check fw capability of a cmd: + * in: (u32)a0=cmd + * out: (u32)a0=errno, 0:valid cmd, a1=supported VNIC_STF_* bits */ + CMD_CAPABILITY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 36), }; /* flags for CMD_OPEN */ @@ -249,8 +258,16 @@ struct vnic_devcmd_notify { u32 uif; /* uplink interface */ u32 status; /* status bits (see VNIC_STF_*) */ u32 error; /* error code (see ERR_*) for first ERR */ + u32 link_down_cnt; /* running count of link down transitions */ }; #define VNIC_STF_FATAL_ERR 0x0001 /* fatal fw error */ +#define VNIC_STF_STD_PAUSE 0x0002 /* standard link-level pause on */ +#define VNIC_STF_PFC_PAUSE 0x0004 /* priority flow control pause on */ +/* all supported status flags */ +#define VNIC_STF_ALL (VNIC_STF_FATAL_ERR |\ + VNIC_STF_STD_PAUSE |\ + VNIC_STF_PFC_PAUSE |\ + 0) struct vnic_devcmd_provinfo { u8 oui[3]; diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h index ccc408116af..ce633a5a7e3 100644 --- a/drivers/net/enic/vnic_intr.h +++ b/drivers/net/enic/vnic_intr.h @@ -78,7 +78,7 @@ static inline void vnic_intr_return_credits(struct vnic_intr *intr, static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba) { - /* get and ack interrupt in one read (clear-and-ack-on-read) */ + /* read PBA without clearing */ return ioread32(legacy_pba); } diff --git a/drivers/net/enic/vnic_resource.h b/drivers/net/enic/vnic_resource.h index 144d2812f08..b61c22aec41 100644 --- a/drivers/net/enic/vnic_resource.h +++ b/drivers/net/enic/vnic_resource.h @@ -38,7 +38,7 @@ enum vnic_res_type { RES_TYPE_INTR_CTRL, /* Interrupt ctrl table */ RES_TYPE_INTR_TABLE, /* MSI/MSI-X Interrupt table */ RES_TYPE_INTR_PBA, /* MSI/MSI-X PBA table */ - RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status, r2c */ + RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status */ RES_TYPE_RSVD6, RES_TYPE_RSVD7, RES_TYPE_DEVCMD, /* Device command region */ diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h index 82bfca67cc4..fd0ef66d2e9 100644 --- a/drivers/net/enic/vnic_rq.h +++ b/drivers/net/enic/vnic_rq.h @@ -132,8 +132,15 @@ static inline void vnic_rq_post(struct vnic_rq *rq, #define VNIC_RQ_RETURN_RATE 0xf /* keep 2^n - 1 */ #endif - if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) + if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) { + /* Adding write memory barrier prevents compiler and/or CPU + * reordering, thus avoiding descriptor posting before + * descriptor is initialized. Otherwise, hardware can read + * stale descriptor fields. + */ + wmb(); iowrite32(buf->index, &rq->ctrl->posted_index); + } } static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) diff --git a/drivers/net/enic/vnic_rss.h b/drivers/net/enic/vnic_rss.h index e325d65d7c3..5fbb3c923bc 100644 --- a/drivers/net/enic/vnic_rss.h +++ b/drivers/net/enic/vnic_rss.h @@ -1,6 +1,19 @@ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. */ #ifndef _VNIC_RSS_H_ diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h index 7081828d8a4..c826137dc65 100644 --- a/drivers/net/enic/vnic_wq.h +++ b/drivers/net/enic/vnic_wq.h @@ -108,8 +108,15 @@ static inline void vnic_wq_post(struct vnic_wq *wq, buf->len = len; buf = buf->next; - if (eop) + if (eop) { + /* Adding write memory barrier prevents compiler and/or CPU + * reordering, thus avoiding descriptor posting before + * descriptor is initialized. Otherwise, hardware can read + * stale descriptor fields. + */ + wmb(); iowrite32(buf->index, &wq->ctrl->posted_index); + } wq->to_use = buf; wq->ring.desc_avail--; |