be2net: Enable SR-IOV for Lancer
[deliverable/linux.git] / drivers / net / benet / be_main.c
index 7b19931acba17f89ccf76cc81edb36ec7a5388e4..ce6edac007a7ac63cdb4835a2071476ad3351ba6 100644 (file)
@@ -42,6 +42,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
        { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
        { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
        { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)},
+       { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID4)},
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, be_dev_ids);
@@ -245,14 +246,185 @@ netdev_addr:
        return status;
 }
 
+static void populate_be2_stats(struct be_adapter *adapter)
+{
+
+       struct be_drv_stats *drvs = &adapter->drv_stats;
+       struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
+       struct be_port_rxf_stats_v0 *port_stats =
+               be_port_rxf_stats_from_cmd(adapter);
+       struct be_rxf_stats_v0 *rxf_stats =
+               be_rxf_stats_from_cmd(adapter);
+
+       drvs->rx_pause_frames = port_stats->rx_pause_frames;
+       drvs->rx_crc_errors = port_stats->rx_crc_errors;
+       drvs->rx_control_frames = port_stats->rx_control_frames;
+       drvs->rx_in_range_errors = port_stats->rx_in_range_errors;
+       drvs->rx_frame_too_long = port_stats->rx_frame_too_long;
+       drvs->rx_dropped_runt = port_stats->rx_dropped_runt;
+       drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs;
+       drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs;
+       drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs;
+       drvs->rxpp_fifo_overflow_drop = port_stats->rx_fifo_overflow;
+       drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length;
+       drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
+       drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
+       drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
+       drvs->rx_input_fifo_overflow_drop =
+               port_stats->rx_input_fifo_overflow;
+       drvs->rx_dropped_header_too_small =
+               port_stats->rx_dropped_header_too_small;
+       drvs->rx_address_match_errors =
+               port_stats->rx_address_match_errors;
+       drvs->rx_alignment_symbol_errors =
+               port_stats->rx_alignment_symbol_errors;
+
+       drvs->tx_pauseframes = port_stats->tx_pauseframes;
+       drvs->tx_controlframes = port_stats->tx_controlframes;
+
+       if (adapter->port_num)
+               drvs->jabber_events =
+                       rxf_stats->port1_jabber_events;
+       else
+               drvs->jabber_events =
+                       rxf_stats->port0_jabber_events;
+       drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
+       drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
+       drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
+       drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
+       drvs->forwarded_packets = rxf_stats->forwarded_packets;
+       drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
+       drvs->rx_drops_no_tpre_descr =
+               rxf_stats->rx_drops_no_tpre_descr;
+       drvs->rx_drops_too_many_frags =
+               rxf_stats->rx_drops_too_many_frags;
+       adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
+}
+
+static void populate_be3_stats(struct be_adapter *adapter)
+{
+       struct be_drv_stats *drvs = &adapter->drv_stats;
+       struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
+
+       struct be_rxf_stats_v1 *rxf_stats =
+               be_rxf_stats_from_cmd(adapter);
+       struct be_port_rxf_stats_v1 *port_stats =
+               be_port_rxf_stats_from_cmd(adapter);
+
+       drvs->rx_priority_pause_frames = 0;
+       drvs->pmem_fifo_overflow_drop = 0;
+       drvs->rx_pause_frames = port_stats->rx_pause_frames;
+       drvs->rx_crc_errors = port_stats->rx_crc_errors;
+       drvs->rx_control_frames = port_stats->rx_control_frames;
+       drvs->rx_in_range_errors = port_stats->rx_in_range_errors;
+       drvs->rx_frame_too_long = port_stats->rx_frame_too_long;
+       drvs->rx_dropped_runt = port_stats->rx_dropped_runt;
+       drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs;
+       drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs;
+       drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs;
+       drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length;
+       drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
+       drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
+       drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
+       drvs->rx_dropped_header_too_small =
+               port_stats->rx_dropped_header_too_small;
+       drvs->rx_input_fifo_overflow_drop =
+               port_stats->rx_input_fifo_overflow_drop;
+       drvs->rx_address_match_errors =
+               port_stats->rx_address_match_errors;
+       drvs->rx_alignment_symbol_errors =
+               port_stats->rx_alignment_symbol_errors;
+       drvs->rxpp_fifo_overflow_drop =
+               port_stats->rxpp_fifo_overflow_drop;
+       drvs->tx_pauseframes = port_stats->tx_pauseframes;
+       drvs->tx_controlframes = port_stats->tx_controlframes;
+       drvs->jabber_events = port_stats->jabber_events;
+       drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
+       drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
+       drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
+       drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
+       drvs->forwarded_packets = rxf_stats->forwarded_packets;
+       drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
+       drvs->rx_drops_no_tpre_descr =
+               rxf_stats->rx_drops_no_tpre_descr;
+       drvs->rx_drops_too_many_frags =
+               rxf_stats->rx_drops_too_many_frags;
+       adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
+}
+
+static void populate_lancer_stats(struct be_adapter *adapter)
+{
+
+       struct be_drv_stats *drvs = &adapter->drv_stats;
+       struct lancer_cmd_pport_stats *pport_stats = pport_stats_from_cmd
+                                               (adapter);
+       drvs->rx_priority_pause_frames = 0;
+       drvs->pmem_fifo_overflow_drop = 0;
+       drvs->rx_pause_frames =
+               make_64bit_val(pport_stats->rx_pause_frames_lo,
+                                pport_stats->rx_pause_frames_hi);
+       drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi,
+                                               pport_stats->rx_crc_errors_lo);
+       drvs->rx_control_frames =
+                       make_64bit_val(pport_stats->rx_control_frames_hi,
+                       pport_stats->rx_control_frames_lo);
+       drvs->rx_in_range_errors = pport_stats->rx_in_range_errors;
+       drvs->rx_frame_too_long =
+               make_64bit_val(pport_stats->rx_internal_mac_errors_hi,
+                                       pport_stats->rx_frames_too_long_lo);
+       drvs->rx_dropped_runt = pport_stats->rx_dropped_runt;
+       drvs->rx_ip_checksum_errs = pport_stats->rx_ip_checksum_errors;
+       drvs->rx_tcp_checksum_errs = pport_stats->rx_tcp_checksum_errors;
+       drvs->rx_udp_checksum_errs = pport_stats->rx_udp_checksum_errors;
+       drvs->rx_dropped_tcp_length =
+                               pport_stats->rx_dropped_invalid_tcp_length;
+       drvs->rx_dropped_too_small = pport_stats->rx_dropped_too_small;
+       drvs->rx_dropped_too_short = pport_stats->rx_dropped_too_short;
+       drvs->rx_out_range_errors = pport_stats->rx_out_of_range_errors;
+       drvs->rx_dropped_header_too_small =
+                               pport_stats->rx_dropped_header_too_small;
+       drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
+       drvs->rx_address_match_errors = pport_stats->rx_address_match_errors;
+       drvs->rx_alignment_symbol_errors =
+               make_64bit_val(pport_stats->rx_symbol_errors_hi,
+                               pport_stats->rx_symbol_errors_lo);
+       drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
+       drvs->tx_pauseframes = make_64bit_val(pport_stats->tx_pause_frames_hi,
+                                       pport_stats->tx_pause_frames_lo);
+       drvs->tx_controlframes =
+               make_64bit_val(pport_stats->tx_control_frames_hi,
+                               pport_stats->tx_control_frames_lo);
+       drvs->jabber_events = pport_stats->rx_jabbers;
+       drvs->rx_drops_no_pbuf = 0;
+       drvs->rx_drops_no_txpb = 0;
+       drvs->rx_drops_no_erx_descr = 0;
+       drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue;
+       drvs->forwarded_packets = make_64bit_val(pport_stats->num_forwards_hi,
+                                               pport_stats->num_forwards_lo);
+       drvs->rx_drops_mtu = make_64bit_val(pport_stats->rx_drops_mtu_hi,
+                                               pport_stats->rx_drops_mtu_lo);
+       drvs->rx_drops_no_tpre_descr = 0;
+       drvs->rx_drops_too_many_frags =
+               make_64bit_val(pport_stats->rx_drops_too_many_frags_hi,
+                               pport_stats->rx_drops_too_many_frags_lo);
+}
+
+void be_parse_stats(struct be_adapter *adapter)
+{
+       if (adapter->generation == BE_GEN3) {
+               if (lancer_chip(adapter))
+                       populate_lancer_stats(adapter);
+                else
+                       populate_be3_stats(adapter);
+       } else {
+               populate_be2_stats(adapter);
+       }
+}
+
 void netdev_stats_update(struct be_adapter *adapter)
 {
-       struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va);
-       struct be_rxf_stats *rxf_stats = &hw_stats->rxf;
-       struct be_port_rxf_stats *port_stats =
-                       &rxf_stats->port[adapter->port_num];
+       struct be_drv_stats *drvs = &adapter->drv_stats;
        struct net_device_stats *dev_stats = &adapter->netdev->stats;
-       struct be_erx_stats *erx_stats = &hw_stats->erx;
        struct be_rx_obj *rxo;
        int i;
 
@@ -262,43 +434,54 @@ void netdev_stats_update(struct be_adapter *adapter)
                dev_stats->rx_bytes += rx_stats(rxo)->rx_bytes;
                dev_stats->multicast += rx_stats(rxo)->rx_mcast_pkts;
                /*  no space in linux buffers: best possible approximation */
-               dev_stats->rx_dropped +=
-                       erx_stats->rx_drops_no_fragments[rxo->q.id];
+               if (adapter->generation == BE_GEN3) {
+                       if (!(lancer_chip(adapter))) {
+                               struct be_erx_stats_v1 *erx_stats =
+                                       be_erx_stats_from_cmd(adapter);
+                               dev_stats->rx_dropped +=
+                               erx_stats->rx_drops_no_fragments[rxo->q.id];
+                       }
+               } else {
+                       struct be_erx_stats_v0 *erx_stats =
+                                       be_erx_stats_from_cmd(adapter);
+                       dev_stats->rx_dropped +=
+                               erx_stats->rx_drops_no_fragments[rxo->q.id];
+               }
        }
 
        dev_stats->tx_packets = tx_stats(adapter)->be_tx_pkts;
        dev_stats->tx_bytes = tx_stats(adapter)->be_tx_bytes;
 
        /* bad pkts received */
-       dev_stats->rx_errors = port_stats->rx_crc_errors +
-               port_stats->rx_alignment_symbol_errors +
-               port_stats->rx_in_range_errors +
-               port_stats->rx_out_range_errors +
-               port_stats->rx_frame_too_long +
-               port_stats->rx_dropped_too_small +
-               port_stats->rx_dropped_too_short +
-               port_stats->rx_dropped_header_too_small +
-               port_stats->rx_dropped_tcp_length +
-               port_stats->rx_dropped_runt +
-               port_stats->rx_tcp_checksum_errs +
-               port_stats->rx_ip_checksum_errs +
-               port_stats->rx_udp_checksum_errs;
+       dev_stats->rx_errors = drvs->rx_crc_errors +
+               drvs->rx_alignment_symbol_errors +
+               drvs->rx_in_range_errors +
+               drvs->rx_out_range_errors +
+               drvs->rx_frame_too_long +
+               drvs->rx_dropped_too_small +
+               drvs->rx_dropped_too_short +
+               drvs->rx_dropped_header_too_small +
+               drvs->rx_dropped_tcp_length +
+               drvs->rx_dropped_runt +
+               drvs->rx_tcp_checksum_errs +
+               drvs->rx_ip_checksum_errs +
+               drvs->rx_udp_checksum_errs;
 
        /* detailed rx errors */
-       dev_stats->rx_length_errors = port_stats->rx_in_range_errors +
-               port_stats->rx_out_range_errors +
-               port_stats->rx_frame_too_long;
+       dev_stats->rx_length_errors = drvs->rx_in_range_errors +
+               drvs->rx_out_range_errors +
+               drvs->rx_frame_too_long;
 
-       dev_stats->rx_crc_errors = port_stats->rx_crc_errors;
+       dev_stats->rx_crc_errors = drvs->rx_crc_errors;
 
        /* frame alignment errors */
-       dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors;
+       dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors;
 
        /* receiver fifo overrun */
        /* drops_no_pbuf is no per i/f, it's per BE card */
-       dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow +
-                                       port_stats->rx_input_fifo_overflow +
-                                       rxf_stats->rx_drops_no_pbuf;
+       dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop +
+                               drvs->rx_input_fifo_overflow_drop +
+                               drvs->rx_drops_no_pbuf;
 }
 
 void be_link_status_update(struct be_adapter *adapter, bool link_up)
@@ -698,7 +881,7 @@ 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, adapter->port_num, 1);
+               be_cmd_promiscuous_config(adapter, true);
                adapter->promiscuous = true;
                goto done;
        }
@@ -706,7 +889,7 @@ static void be_set_multicast_list(struct net_device *netdev)
        /* BE was previously in promiscuous mode; disable it */
        if (adapter->promiscuous) {
                adapter->promiscuous = false;
-               be_cmd_promiscuous_config(adapter, adapter->port_num, 0);
+               be_cmd_promiscuous_config(adapter, false);
        }
 
        /* Enable multicast promisc if num configured exceeds what we support */
@@ -1017,7 +1200,8 @@ static void be_rx_compl_process(struct be_adapter *adapter,
                        kfree_skb(skb);
                        return;
                }
-               vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rxcp->vid);
+               vlan_hwaccel_receive_skb(skb, adapter->vlan_grp,
+                                       rxcp->vlan_tag);
        } else {
                netif_receive_skb(skb);
        }
@@ -1077,7 +1261,8 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
        if (likely(!rxcp->vlanf))
                napi_gro_frags(&eq_obj->napi);
        else
-               vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, rxcp->vid);
+               vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp,
+                               rxcp->vlan_tag);
 }
 
 static void be_parse_rx_compl_v1(struct be_adapter *adapter,
@@ -1106,9 +1291,9 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter,
                AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp);
        if (rxcp->vlanf) {
                rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm,
-                               compl);
-               rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
-                               compl);
+                                         compl);
+               rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
+                                              compl);
        }
 }
 
@@ -1138,9 +1323,9 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter,
                AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp);
        if (rxcp->vlanf) {
                rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm,
-                               compl);
-               rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
-                               compl);
+                                         compl);
+               rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
+                                              compl);
        }
 }
 
@@ -1170,10 +1355,11 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
                        rxcp->vlanf = 0;
 
                if (!lancer_chip(adapter))
-                       rxcp->vid = swab16(rxcp->vid);
+                       rxcp->vlan_tag = swab16(rxcp->vlan_tag);
 
-               if ((adapter->pvid == rxcp->vid) &&
-                       !adapter->vlan_tag[rxcp->vid])
+               if (((adapter->pvid & VLAN_VID_MASK) ==
+                    (rxcp->vlan_tag & VLAN_VID_MASK)) &&
+                   !adapter->vlan_tag[rxcp->vlan_tag])
                        rxcp->vlanf = 0;
        }
 
@@ -1272,7 +1458,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
        return txcp;
 }
 
-static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
+static u16 be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
 {
        struct be_queue_info *txq = &adapter->tx_obj.q;
        struct be_eth_wrb *wrb;
@@ -1299,9 +1485,8 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
                queue_tail_inc(txq);
        } while (cur_index != last_index);
 
-       atomic_sub(num_wrbs, &txq->used);
-
        kfree_skb(sent_skb);
+       return num_wrbs;
 }
 
 static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj)
@@ -1384,7 +1569,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
        struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
        struct be_queue_info *txq = &adapter->tx_obj.q;
        struct be_eth_tx_compl *txcp;
-       u16 end_idx, cmpl = 0, timeo = 0;
+       u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0;
        struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
        struct sk_buff *sent_skb;
        bool dummy_wrb;
@@ -1394,12 +1579,14 @@ static void be_tx_compl_clean(struct be_adapter *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_wrbs += be_tx_compl_process(adapter, end_idx);
                        cmpl++;
                }
                if (cmpl) {
                        be_cq_notify(adapter, tx_cq->id, false, cmpl);
+                       atomic_sub(num_wrbs, &txq->used);
                        cmpl = 0;
+                       num_wrbs = 0;
                }
 
                if (atomic_read(&txq->used) == 0 || ++timeo > 200)
@@ -1419,7 +1606,8 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
                index_adv(&end_idx,
                        wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1,
                        txq->len);
-               be_tx_compl_process(adapter, end_idx);
+               num_wrbs = be_tx_compl_process(adapter, end_idx);
+               atomic_sub(num_wrbs, &txq->used);
        }
 }
 
@@ -1754,12 +1942,15 @@ static int be_poll_rx(struct napi_struct *napi, int budget)
                        break;
 
                /* Ignore flush completions */
-               if (rxcp->num_rcvd) {
+               if (rxcp->num_rcvd && rxcp->pkt_size) {
                        if (do_gro(rxcp))
                                be_rx_compl_process_gro(adapter, rxo, rxcp);
                        else
                                be_rx_compl_process(adapter, rxo, rxcp);
+               } else if (rxcp->pkt_size == 0) {
+                       be_rx_compl_discard(adapter, rxo, rxcp);
                }
+
                be_rx_stats_update(rxo, rxcp);
        }
 
@@ -1790,12 +1981,12 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
        struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
        struct be_eth_tx_compl *txcp;
        int tx_compl = 0, mcc_compl, status = 0;
-       u16 end_idx;
+       u16 end_idx, num_wrbs = 0;
 
        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_wrbs += be_tx_compl_process(adapter, end_idx);
                tx_compl++;
        }
 
@@ -1811,6 +2002,8 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
        if (tx_compl) {
                be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl);
 
+               atomic_sub(num_wrbs, &txq->used);
+
                /* As Tx wrbs have been freed up, wake up netdev queue if
                 * it was stopped due to lack of tx wrbs.
                 */
@@ -1891,9 +2084,13 @@ static void be_worker(struct work_struct *work)
                goto reschedule;
        }
 
-       if (!adapter->stats_cmd_sent)
-               be_cmd_get_stats(adapter, &adapter->stats_cmd);
-
+       if (!adapter->stats_cmd_sent) {
+               if (lancer_chip(adapter))
+                       lancer_cmd_get_pport_stats(adapter,
+                                               &adapter->stats_cmd);
+               else
+                       be_cmd_get_stats(adapter, &adapter->stats_cmd);
+       }
        be_tx_rate_update(adapter);
 
        for_all_rx_queues(adapter, rxo, i) {
@@ -2516,7 +2713,6 @@ static int be_flash_data(struct be_adapter *adapter,
                                        "cmd to write to flash rom failed.\n");
                                return -1;
                        }
-                       yield();
                }
        }
        return 0;
@@ -2534,32 +2730,98 @@ static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr)
                return 0;
 }
 
-int be_load_fw(struct be_adapter *adapter, u8 *func)
+static int lancer_fw_download(struct be_adapter *adapter,
+                               const struct firmware *fw)
 {
-       char fw_file[ETHTOOL_FLASH_MAX_FILENAME];
-       const struct firmware *fw;
-       struct flash_file_hdr_g2 *fhdr;
-       struct flash_file_hdr_g3 *fhdr3;
-       struct image_hdr *img_hdr_ptr = NULL;
+#define LANCER_FW_DOWNLOAD_CHUNK      (32 * 1024)
+#define LANCER_FW_DOWNLOAD_LOCATION   "/prg"
        struct be_dma_mem flash_cmd;
-       int status, i = 0, num_imgs = 0;
-       const u8 *p;
+       struct lancer_cmd_req_write_object *req;
+       const u8 *data_ptr = NULL;
+       u8 *dest_image_ptr = NULL;
+       size_t image_size = 0;
+       u32 chunk_size = 0;
+       u32 data_written = 0;
+       u32 offset = 0;
+       int status = 0;
+       u8 add_status = 0;
 
-       if (!netif_running(adapter->netdev)) {
+       if (!IS_ALIGNED(fw->size, sizeof(u32))) {
                dev_err(&adapter->pdev->dev,
-                       "Firmware load not allowed (interface is down)\n");
-               return -EPERM;
+                       "FW Image not properly aligned. "
+                       "Length must be 4 byte aligned.\n");
+               status = -EINVAL;
+               goto lancer_fw_exit;
+       }
+
+       flash_cmd.size = sizeof(struct lancer_cmd_req_write_object)
+                               + LANCER_FW_DOWNLOAD_CHUNK;
+       flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
+                                               &flash_cmd.dma, GFP_KERNEL);
+       if (!flash_cmd.va) {
+               status = -ENOMEM;
+               dev_err(&adapter->pdev->dev,
+                       "Memory allocation failure while flashing\n");
+               goto lancer_fw_exit;
        }
 
-       strcpy(fw_file, func);
+       req = flash_cmd.va;
+       dest_image_ptr = flash_cmd.va +
+                               sizeof(struct lancer_cmd_req_write_object);
+       image_size = fw->size;
+       data_ptr = fw->data;
 
-       status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
-       if (status)
-               goto fw_exit;
+       while (image_size) {
+               chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK);
+
+               /* Copy the image chunk content. */
+               memcpy(dest_image_ptr, data_ptr, chunk_size);
+
+               status = lancer_cmd_write_object(adapter, &flash_cmd,
+                               chunk_size, offset, LANCER_FW_DOWNLOAD_LOCATION,
+                               &data_written, &add_status);
+
+               if (status)
+                       break;
+
+               offset += data_written;
+               data_ptr += data_written;
+               image_size -= data_written;
+       }
+
+       if (!status) {
+               /* Commit the FW written */
+               status = lancer_cmd_write_object(adapter, &flash_cmd,
+                                       0, offset, LANCER_FW_DOWNLOAD_LOCATION,
+                                       &data_written, &add_status);
+       }
+
+       dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va,
+                               flash_cmd.dma);
+       if (status) {
+               dev_err(&adapter->pdev->dev,
+                       "Firmware load error. "
+                       "Status code: 0x%x Additional Status: 0x%x\n",
+                       status, add_status);
+               goto lancer_fw_exit;
+       }
+
+       dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
+lancer_fw_exit:
+       return status;
+}
+
+static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw)
+{
+       struct flash_file_hdr_g2 *fhdr;
+       struct flash_file_hdr_g3 *fhdr3;
+       struct image_hdr *img_hdr_ptr = NULL;
+       struct be_dma_mem flash_cmd;
+       const u8 *p;
+       int status = 0, i = 0, num_imgs = 0;
 
        p = fw->data;
        fhdr = (struct flash_file_hdr_g2 *) p;
-       dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
 
        flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024;
        flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
@@ -2568,7 +2830,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
                status = -ENOMEM;
                dev_err(&adapter->pdev->dev,
                        "Memory allocation failure while flashing\n");
-               goto fw_exit;
+               goto be_fw_exit;
        }
 
        if ((adapter->generation == BE_GEN3) &&
@@ -2596,11 +2858,37 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
                          flash_cmd.dma);
        if (status) {
                dev_err(&adapter->pdev->dev, "Firmware load error\n");
-               goto fw_exit;
+               goto be_fw_exit;
        }
 
        dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
 
+be_fw_exit:
+       return status;
+}
+
+int be_load_fw(struct be_adapter *adapter, u8 *fw_file)
+{
+       const struct firmware *fw;
+       int status;
+
+       if (!netif_running(adapter->netdev)) {
+               dev_err(&adapter->pdev->dev,
+                       "Firmware load not allowed (interface is down)\n");
+               return -1;
+       }
+
+       status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
+       if (status)
+               goto fw_exit;
+
+       dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
+
+       if (lancer_chip(adapter))
+               status = lancer_fw_download(adapter, fw);
+       else
+               status = be_fw_download(adapter, fw);
+
 fw_exit:
        release_firmware(fw);
        return status;
@@ -2813,7 +3101,14 @@ static int be_stats_init(struct be_adapter *adapter)
 {
        struct be_dma_mem *cmd = &adapter->stats_cmd;
 
-       cmd->size = sizeof(struct be_cmd_req_get_stats);
+       if (adapter->generation == BE_GEN2) {
+               cmd->size = sizeof(struct be_cmd_req_get_stats_v0);
+       } else {
+               if (lancer_chip(adapter))
+                       cmd->size = sizeof(struct lancer_cmd_req_pport_stats);
+               else
+                       cmd->size = sizeof(struct be_cmd_req_get_stats_v1);
+       }
        cmd->va = dma_alloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma,
                                     GFP_KERNEL);
        if (cmd->va == NULL)
@@ -2867,7 +3162,8 @@ static int be_get_config(struct be_adapter *adapter)
 
        memset(mac, 0, ETH_ALEN);
 
-       if (be_physfn(adapter)) {
+       /* A default permanent address is given to each VF for Lancer*/
+       if (be_physfn(adapter) || lancer_chip(adapter)) {
                status = be_cmd_mac_addr_query(adapter, mac,
                        MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0);
 
@@ -2909,6 +3205,7 @@ static int be_dev_family_check(struct be_adapter *adapter)
                adapter->generation = BE_GEN3;
                break;
        case OC_DEVICE_ID3:
+       case OC_DEVICE_ID4:
                pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);
                if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>
                                                SLI_INTF_IF_TYPE_SHIFT;
@@ -2918,10 +3215,6 @@ static int be_dev_family_check(struct be_adapter *adapter)
                        dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");
                        return -EINVAL;
                }
-               if (num_vfs > 0) {
-                       dev_err(&pdev->dev, "VFs not supported\n");
-                       return -EINVAL;
-               }
                adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >>
                                         SLI_INTF_FAMILY_SHIFT);
                adapter->generation = BE_GEN3;
@@ -3087,9 +3380,11 @@ static int __devinit be_probe(struct pci_dev *pdev,
                bool link_up;
                u16 vf, lnk_speed;
 
-               status = be_vf_eth_addr_config(adapter);
-               if (status)
-                       goto unreg_netdev;
+               if (!lancer_chip(adapter)) {
+                       status = be_vf_eth_addr_config(adapter);
+                       if (status)
+                               goto unreg_netdev;
+               }
 
                for (vf = 0; vf < num_vfs; vf++) {
                        status = be_cmd_link_status_query(adapter, &link_up,
This page took 0.036086 seconds and 5 git commands to generate.