]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/benet/be_main.c
be2net: Bug fix in the non-lro path. Size of received packet was not updated in stati...
[karo-tx-linux.git] / drivers / net / benet / be_main.c
index 66bb56874d9bd0bbc99b18284f836f2e6a2535ba..dea3155688bbc570eaa6ba52f94832efe8170f80 100644 (file)
@@ -60,26 +60,6 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q,
        return 0;
 }
 
-static inline void *queue_head_node(struct be_queue_info *q)
-{
-       return q->dma_mem.va + q->head * q->entry_size;
-}
-
-static inline void *queue_tail_node(struct be_queue_info *q)
-{
-       return q->dma_mem.va + q->tail * q->entry_size;
-}
-
-static inline void queue_head_inc(struct be_queue_info *q)
-{
-       index_inc(&q->head, q->len);
-}
-
-static inline void queue_tail_inc(struct be_queue_info *q)
-{
-       index_inc(&q->tail, q->len);
-}
-
 static void be_intr_set(struct be_ctrl_info *ctrl, bool enable)
 {
        u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET;
@@ -127,7 +107,7 @@ static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid,
        iowrite32(val, ctrl->db + DB_EQ_OFFSET);
 }
 
-static void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid,
+void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid,
                bool arm, u16 num_popped)
 {
        u32 val = 0;
@@ -234,28 +214,24 @@ static void netdev_stats_update(struct be_adapter *adapter)
        dev_stats->tx_window_errors = 0;
 }
 
-static void be_link_status_update(struct be_adapter *adapter)
+void be_link_status_update(void *ctxt, bool link_up)
 {
-       struct be_link_info *prev = &adapter->link;
-       struct be_link_info now = { 0 };
+       struct be_adapter *adapter = ctxt;
        struct net_device *netdev = adapter->netdev;
 
-       be_cmd_link_status_query(&adapter->ctrl, &now);
-
        /* If link came up or went down */
-       if (now.speed != prev->speed && (now.speed == PHY_LINK_SPEED_ZERO ||
-                       prev->speed == PHY_LINK_SPEED_ZERO)) {
-               if (now.speed == PHY_LINK_SPEED_ZERO) {
-                       netif_stop_queue(netdev);
-                       netif_carrier_off(netdev);
-                       printk(KERN_INFO "%s: Link down\n", netdev->name);
-               } else {
+       if (adapter->link_up != link_up) {
+               if (link_up) {
                        netif_start_queue(netdev);
                        netif_carrier_on(netdev);
                        printk(KERN_INFO "%s: Link up\n", netdev->name);
+               } else {
+                       netif_stop_queue(netdev);
+                       netif_carrier_off(netdev);
+                       printk(KERN_INFO "%s: Link down\n", netdev->name);
                }
+               adapter->link_up = link_up;
        }
-       *prev = now;
 }
 
 /* Update the EQ delay n BE based on the RX frags consumed / sec */
@@ -569,47 +545,32 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
        be_vid_config(netdev);
 }
 
-static void be_set_multicast_filter(struct net_device *netdev)
+static void be_set_multicast_list(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
-       struct dev_mc_list *mc_ptr;
-       u8 mac_addr[32][ETH_ALEN];
-       int i = 0;
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
 
-       if (netdev->flags & IFF_ALLMULTI) {
-               /* set BE in Multicast promiscuous */
-               be_cmd_mcast_mac_set(&adapter->ctrl,
-                                       adapter->if_handle, NULL, 0, true);
-               return;
+       if (netdev->flags & IFF_PROMISC) {
+               be_cmd_promiscuous_config(ctrl, adapter->port_num, 1);
+               adapter->promiscuous = true;
+               goto done;
        }
 
-       for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
-               memcpy(&mac_addr[i][0], mc_ptr->dmi_addr, ETH_ALEN);
-               if (++i >= 32) {
-                       be_cmd_mcast_mac_set(&adapter->ctrl,
-                               adapter->if_handle, &mac_addr[0][0], i, false);
-                       i = 0;
-               }
-
+       /* BE was previously in promiscous mode; disable it */
+       if (adapter->promiscuous) {
+               adapter->promiscuous = false;
+               be_cmd_promiscuous_config(ctrl, adapter->port_num, 0);
        }
 
-       if (i) {
-               /* reset the promiscuous mode also. */
-               be_cmd_mcast_mac_set(&adapter->ctrl,
-                       adapter->if_handle, &mac_addr[0][0], i, false);
+       if (netdev->flags & IFF_ALLMULTI) {
+               be_cmd_multicast_set(ctrl, adapter->if_handle, NULL, 0);
+               goto done;
        }
-}
-
-static void be_set_multicast_list(struct net_device *netdev)
-{
-       struct be_adapter *adapter = netdev_priv(netdev);
 
-       if (netdev->flags & IFF_PROMISC) {
-               be_cmd_promiscuous_config(&adapter->ctrl, adapter->port_num, 1);
-       } else {
-               be_cmd_promiscuous_config(&adapter->ctrl, adapter->port_num, 0);
-               be_set_multicast_filter(netdev);
-       }
+       be_cmd_multicast_set(ctrl, adapter->if_handle, netdev->mc_list,
+               netdev->mc_count);
+done:
+       return;
 }
 
 static void be_rx_rate_update(struct be_adapter *adapter)
@@ -705,8 +666,8 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
 {
        struct be_queue_info *rxq = &adapter->rx_obj.q;
        struct be_rx_page_info *page_info;
-       u16 rxq_idx, i, num_rcvd;
-       u32 pktsize, hdr_len, curr_frag_len;
+       u16 rxq_idx, i, num_rcvd, j;
+       u32 pktsize, hdr_len, curr_frag_len, size;
        u8 *start;
 
        rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
@@ -747,23 +708,34 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
        }
 
        /* More frags present for this completion */
-       pktsize -= curr_frag_len; /* account for above copied frag */
-       for (i = 1; i < num_rcvd; i++) {
+       size = pktsize;
+       for (i = 1, j = 0; i < num_rcvd; i++) {
+               size -= curr_frag_len;
                index_inc(&rxq_idx, rxq->len);
                page_info = get_rx_page_info(adapter, rxq_idx);
 
-               curr_frag_len = min(pktsize, rx_frag_size);
+               curr_frag_len = min(size, rx_frag_size);
+
+               /* Coalesce all frags from the same physical page in one slot */
+               if (page_info->page_offset == 0) {
+                       /* Fresh page */
+                       j++;
+                       skb_shinfo(skb)->frags[j].page = page_info->page;
+                       skb_shinfo(skb)->frags[j].page_offset =
+                                                       page_info->page_offset;
+                       skb_shinfo(skb)->frags[j].size = 0;
+                       skb_shinfo(skb)->nr_frags++;
+               } else {
+                       put_page(page_info->page);
+               }
 
-               skb_shinfo(skb)->frags[i].page = page_info->page;
-               skb_shinfo(skb)->frags[i].page_offset = page_info->page_offset;
-               skb_shinfo(skb)->frags[i].size = curr_frag_len;
+               skb_shinfo(skb)->frags[j].size += curr_frag_len;
                skb->len += curr_frag_len;
                skb->data_len += curr_frag_len;
-               skb_shinfo(skb)->nr_frags++;
-               pktsize -= curr_frag_len;
 
                memset(page_info, 0, sizeof(*page_info));
        }
+       BUG_ON(j > MAX_SKB_FRAGS);
 
 done:
        be_rx_stats_update(adapter, pktsize, num_rcvd);
@@ -825,7 +797,7 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
        struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME];
        struct be_queue_info *rxq = &adapter->rx_obj.q;
        u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
-       u16 i, rxq_idx = 0, vid;
+       u16 i, rxq_idx = 0, vid, j;
 
        num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
        pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
@@ -833,20 +805,28 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
        rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
 
        remaining = pkt_size;
-       for (i = 0; i < num_rcvd; i++) {
+       for (i = 0, j = -1; i < num_rcvd; i++) {
                page_info = get_rx_page_info(adapter, rxq_idx);
 
                curr_frag_len = min(remaining, rx_frag_size);
 
-               rx_frags[i].page = page_info->page;
-               rx_frags[i].page_offset = page_info->page_offset;
-               rx_frags[i].size = curr_frag_len;
-               remaining -= curr_frag_len;
+               /* Coalesce all frags from the same physical page in one slot */
+               if (i == 0 || page_info->page_offset == 0) {
+                       /* First frag or Fresh page */
+                       j++;
+                       rx_frags[j].page = page_info->page;
+                       rx_frags[j].page_offset = page_info->page_offset;
+                       rx_frags[j].size = 0;
+               } else {
+                       put_page(page_info->page);
+               }
+               rx_frags[j].size += curr_frag_len;
 
+               remaining -= curr_frag_len;
                index_inc(&rxq_idx, rxq->len);
-
                memset(page_info, 0, sizeof(*page_info));
        }
+       BUG_ON(j > MAX_SKB_FRAGS);
 
        if (likely(!vlanf)) {
                lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size,
@@ -960,10 +940,8 @@ static void be_post_rx_frags(struct be_adapter *adapter)
        return;
 }
 
-static struct be_eth_tx_compl *
-be_tx_compl_get(struct be_adapter *adapter)
+static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
 {
-       struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
        struct be_eth_tx_compl *txcp = queue_tail_node(tx_cq);
 
        if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0)
@@ -1051,6 +1029,59 @@ static void be_tx_q_clean(struct be_adapter *adapter)
        }
 }
 
+static void be_mcc_queues_destroy(struct be_adapter *adapter)
+{
+       struct be_queue_info *q;
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+
+       q = &ctrl->mcc_obj.q;
+       if (q->created)
+               be_cmd_q_destroy(ctrl, q, QTYPE_MCCQ);
+       be_queue_free(adapter, q);
+
+       q = &ctrl->mcc_obj.cq;
+       if (q->created)
+               be_cmd_q_destroy(ctrl, q, QTYPE_CQ);
+       be_queue_free(adapter, q);
+}
+
+/* Must be called only after TX qs are created as MCC shares TX EQ */
+static int be_mcc_queues_create(struct be_adapter *adapter)
+{
+       struct be_queue_info *q, *cq;
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+
+       /* Alloc MCC compl queue */
+       cq = &ctrl->mcc_obj.cq;
+       if (be_queue_alloc(adapter, cq, MCC_CQ_LEN,
+                       sizeof(struct be_mcc_cq_entry)))
+               goto err;
+
+       /* Ask BE to create MCC compl queue; share TX's eq */
+       if (be_cmd_cq_create(ctrl, cq, &adapter->tx_eq.q, false, true, 0))
+               goto mcc_cq_free;
+
+       /* Alloc MCC queue */
+       q = &ctrl->mcc_obj.q;
+       if (be_queue_alloc(adapter, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb)))
+               goto mcc_cq_destroy;
+
+       /* Ask BE to create MCC queue */
+       if (be_cmd_mccq_create(ctrl, q, cq))
+               goto mcc_q_free;
+
+       return 0;
+
+mcc_q_free:
+       be_queue_free(adapter, q);
+mcc_cq_destroy:
+       be_cmd_q_destroy(ctrl, cq, QTYPE_CQ);
+mcc_cq_free:
+       be_queue_free(adapter, cq);
+err:
+       return -1;
+}
+
 static void be_tx_queues_destroy(struct be_adapter *adapter)
 {
        struct be_queue_info *q;
@@ -1243,15 +1274,17 @@ static irqreturn_t be_intx(int irq, void *dev)
 {
        struct be_adapter *adapter = dev;
        struct be_ctrl_info *ctrl = &adapter->ctrl;
-       int rx, tx;
+        int isr;
 
-       tx = event_handle(ctrl, &adapter->tx_eq);
-       rx = event_handle(ctrl, &adapter->rx_eq);
+       isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET +
+                      ctrl->pci_func * CEV_ISR_SIZE);
+       if (!isr)
+                return IRQ_NONE;
 
-       if (rx || tx)
-               return IRQ_HANDLED;
-       else
-               return IRQ_NONE;
+        event_handle(ctrl, &adapter->tx_eq);
+        event_handle(ctrl, &adapter->rx_eq);
+
+        return IRQ_HANDLED;
 }
 
 static irqreturn_t be_msix_rx(int irq, void *dev)
@@ -1263,7 +1296,7 @@ static irqreturn_t be_msix_rx(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t be_msix_tx(int irq, void *dev)
+static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
 {
        struct be_adapter *adapter = dev;
 
@@ -1324,40 +1357,51 @@ int be_poll_rx(struct napi_struct *napi, int budget)
        return work_done;
 }
 
-/* For TX we don't honour budget; consume everything */
-int be_poll_tx(struct napi_struct *napi, int budget)
+void be_process_tx(struct be_adapter *adapter)
 {
-       struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
-       struct be_adapter *adapter =
-               container_of(tx_eq, struct be_adapter, tx_eq);
-       struct be_tx_obj *tx_obj = &adapter->tx_obj;
-       struct be_queue_info *tx_cq = &tx_obj->cq;
-       struct be_queue_info *txq = &tx_obj->q;
+       struct be_queue_info *txq = &adapter->tx_obj.q;
+       struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
        struct be_eth_tx_compl *txcp;
        u32 num_cmpl = 0;
        u16 end_idx;
 
-       while ((txcp = be_tx_compl_get(adapter))) {
+       while ((txcp = be_tx_compl_get(tx_cq))) {
                end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
                                        wrb_index, txcp);
                be_tx_compl_process(adapter, end_idx);
                num_cmpl++;
        }
 
-       /* As Tx wrbs have been freed up, wake up netdev queue if
-        * it was stopped due to lack of tx wrbs.
-        */
-       if (netif_queue_stopped(adapter->netdev) &&
+       if (num_cmpl) {
+               be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl);
+
+               /* As Tx wrbs have been freed up, wake up netdev queue if
+                * it was stopped due to lack of tx wrbs.
+                */
+               if (netif_queue_stopped(adapter->netdev) &&
                        atomic_read(&txq->used) < txq->len / 2) {
-               netif_wake_queue(adapter->netdev);
+                       netif_wake_queue(adapter->netdev);
+               }
+
+               drvr_stats(adapter)->be_tx_events++;
+               drvr_stats(adapter)->be_tx_compl += num_cmpl;
        }
+}
+
+/* As TX and MCC share the same EQ check for both TX and MCC completions.
+ * For TX/MCC we don't honour budget; consume everything
+ */
+static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
+{
+       struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
+       struct be_adapter *adapter =
+               container_of(tx_eq, struct be_adapter, tx_eq);
 
        napi_complete(napi);
 
-       be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl);
+       be_process_tx(adapter);
 
-       drvr_stats(adapter)->be_tx_events++;
-       drvr_stats(adapter)->be_tx_compl += num_cmpl;
+       be_process_mcc(&adapter->ctrl);
 
        return 1;
 }
@@ -1368,9 +1412,6 @@ static void be_worker(struct work_struct *work)
                container_of(work, struct be_adapter, work.work);
        int status;
 
-       /* Check link */
-       be_link_status_update(adapter);
-
        /* Get Stats */
        status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd);
        if (!status)
@@ -1419,7 +1460,7 @@ static int be_msix_register(struct be_adapter *adapter)
 
        sprintf(tx_eq->desc, "%s-tx", netdev->name);
        vec = be_msix_vec_get(adapter, tx_eq->q.id);
-       status = request_irq(vec, be_msix_tx, 0, tx_eq->desc, adapter);
+       status = request_irq(vec, be_msix_tx_mcc, 0, tx_eq->desc, adapter);
        if (status)
                goto err;
 
@@ -1495,6 +1536,39 @@ static int be_open(struct net_device *netdev)
        struct be_ctrl_info *ctrl = &adapter->ctrl;
        struct be_eq_obj *rx_eq = &adapter->rx_eq;
        struct be_eq_obj *tx_eq = &adapter->tx_eq;
+       bool link_up;
+       int status;
+
+       /* First time posting */
+       be_post_rx_frags(adapter);
+
+       napi_enable(&rx_eq->napi);
+       napi_enable(&tx_eq->napi);
+
+       be_irq_register(adapter);
+
+       be_intr_set(ctrl, true);
+
+       /* The evt queues are created in unarmed state; arm them */
+       be_eq_notify(ctrl, rx_eq->q.id, true, false, 0);
+       be_eq_notify(ctrl, tx_eq->q.id, true, false, 0);
+
+       /* Rx compl queue may be in unarmed state; rearm it */
+       be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0);
+
+       status = be_cmd_link_status_query(ctrl, &link_up);
+       if (status)
+               return status;
+       be_link_status_update(adapter, link_up);
+
+       schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
+       return 0;
+}
+
+static int be_setup(struct be_adapter *adapter)
+{
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+       struct net_device *netdev = adapter->netdev;
        u32 if_flags;
        int status;
 
@@ -1521,29 +1595,14 @@ static int be_open(struct net_device *netdev)
        if (status != 0)
                goto tx_qs_destroy;
 
-       /* First time posting */
-       be_post_rx_frags(adapter);
-
-       napi_enable(&rx_eq->napi);
-       napi_enable(&tx_eq->napi);
-
-       be_irq_register(adapter);
-
-       be_intr_set(ctrl, true);
-
-       /* The evt queues are created in the unarmed state; arm them */
-       be_eq_notify(ctrl, rx_eq->q.id, true, false, 0);
-       be_eq_notify(ctrl, tx_eq->q.id, true, false, 0);
-
-       /* The compl queues are created in the unarmed state; arm them */
-       be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0);
-       be_cq_notify(ctrl, adapter->tx_obj.cq.id, true, 0);
-
-       be_link_status_update(adapter);
+       status = be_mcc_queues_create(adapter);
+       if (status != 0)
+               goto rx_qs_destroy;
 
-       schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
        return 0;
 
+rx_qs_destroy:
+       be_rx_queues_destroy(adapter);
 tx_qs_destroy:
        be_tx_queues_destroy(adapter);
 if_destroy:
@@ -1552,6 +1611,19 @@ do_none:
        return status;
 }
 
+static int be_clear(struct be_adapter *adapter)
+{
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+
+       be_rx_queues_destroy(adapter);
+       be_tx_queues_destroy(adapter);
+
+       be_cmd_if_destroy(ctrl, adapter->if_handle);
+
+       be_mcc_queues_destroy(adapter);
+       return 0;
+}
+
 static int be_close(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -1564,7 +1636,7 @@ static int be_close(struct net_device *netdev)
 
        netif_stop_queue(netdev);
        netif_carrier_off(netdev);
-       adapter->link.speed = PHY_LINK_SPEED_ZERO;
+       adapter->link_up = false;
 
        be_intr_set(ctrl, false);
 
@@ -1581,10 +1653,6 @@ static int be_close(struct net_device *netdev)
        napi_disable(&rx_eq->napi);
        napi_disable(&tx_eq->napi);
 
-       be_rx_queues_destroy(adapter);
-       be_tx_queues_destroy(adapter);
-
-       be_cmd_if_destroy(ctrl, adapter->if_handle);
        return 0;
 }
 
@@ -1673,7 +1741,7 @@ static void be_netdev_init(struct net_device *netdev)
 
        netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx,
                BE_NAPI_WEIGHT);
-       netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx,
+       netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
                BE_NAPI_WEIGHT);
 
        netif_carrier_off(netdev);
@@ -1755,7 +1823,12 @@ static int be_ctrl_init(struct be_adapter *adapter)
        mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
        mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
        memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
-       spin_lock_init(&ctrl->cmd_lock);
+       spin_lock_init(&ctrl->mbox_lock);
+       spin_lock_init(&ctrl->mcc_lock);
+       spin_lock_init(&ctrl->mcc_cq_lock);
+
+       ctrl->async_cb = be_link_status_update;
+       ctrl->adapter_ctxt = adapter;
 
        val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET);
        ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) &
@@ -1793,6 +1866,8 @@ static void __devexit be_remove(struct pci_dev *pdev)
 
        unregister_netdev(adapter->netdev);
 
+       be_clear(adapter);
+
        be_stats_cleanup(adapter);
 
        be_ctrl_cleanup(adapter);
@@ -1890,13 +1965,18 @@ static int __devinit be_probe(struct pci_dev *pdev,
        be_netdev_init(netdev);
        SET_NETDEV_DEV(netdev, &adapter->pdev->dev);
 
+       status = be_setup(adapter);
+       if (status)
+               goto stats_clean;
        status = register_netdev(netdev);
        if (status != 0)
-               goto stats_clean;
+               goto unsetup;
 
        dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num);
        return 0;
 
+unsetup:
+       be_clear(adapter);
 stats_clean:
        be_stats_cleanup(adapter);
 ctrl_clean:
@@ -1921,6 +2001,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
        if (netif_running(netdev)) {
                rtnl_lock();
                be_close(netdev);
+               be_clear(adapter);
                rtnl_unlock();
        }
 
@@ -1947,6 +2028,7 @@ static int be_resume(struct pci_dev *pdev)
 
        if (netif_running(netdev)) {
                rtnl_lock();
+               be_setup(adapter);
                be_open(netdev);
                rtnl_unlock();
        }