diff options
author | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-05-13 00:37:27 -0700 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-08-11 02:33:55 -0700 |
commit | 9aebddd11be42366f89b0296590770c02797aa98 (patch) | |
tree | bca16cd2c06a513096e930ab6337bd6f9d9ac674 /drivers/net/benet/be_main.c | |
parent | 874aeea5d01cac55c160a4e503e3ddb4db030de7 (diff) |
be2net: Move the Emulex driver
Moves the Emulex driver into drivers/net/ethernet/emulex/ and
make the necessary Kconfig and Makefile changes.
CC: Sathya Perla <sathya.perla@emulex.com>
CC: Subbu Seetharaman <subbu.seetharaman@emulex.com>
CC: Ajit Khaparde <ajit.khaparde@emulex.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/benet/be_main.c')
-rw-r--r-- | drivers/net/benet/be_main.c | 3633 |
1 files changed, 0 insertions, 3633 deletions
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c deleted file mode 100644 index 1a3accab3d1..00000000000 --- a/drivers/net/benet/be_main.c +++ /dev/null @@ -1,3633 +0,0 @@ -/* - * Copyright (C) 2005 - 2011 Emulex - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * - * Contact Information: - * linux-drivers@emulex.com - * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 - */ - -#include <linux/prefetch.h> -#include "be.h" -#include "be_cmds.h" -#include <asm/div64.h> - -MODULE_VERSION(DRV_VER); -MODULE_DEVICE_TABLE(pci, be_dev_ids); -MODULE_DESCRIPTION(DRV_DESC " " DRV_VER); -MODULE_AUTHOR("ServerEngines Corporation"); -MODULE_LICENSE("GPL"); - -static ushort rx_frag_size = 2048; -static unsigned int num_vfs; -module_param(rx_frag_size, ushort, S_IRUGO); -module_param(num_vfs, uint, S_IRUGO); -MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); -MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize"); - -static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { - { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, - { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, - { 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); -/* UE Status Low CSR */ -static const char * const ue_status_low_desc[] = { - "CEV", - "CTX", - "DBUF", - "ERX", - "Host", - "MPU", - "NDMA", - "PTC ", - "RDMA ", - "RXF ", - "RXIPS ", - "RXULP0 ", - "RXULP1 ", - "RXULP2 ", - "TIM ", - "TPOST ", - "TPRE ", - "TXIPS ", - "TXULP0 ", - "TXULP1 ", - "UC ", - "WDMA ", - "TXULP2 ", - "HOST1 ", - "P0_OB_LINK ", - "P1_OB_LINK ", - "HOST_GPIO ", - "MBOX ", - "AXGMAC0", - "AXGMAC1", - "JTAG", - "MPU_INTPEND" -}; -/* UE Status High CSR */ -static const char * const ue_status_hi_desc[] = { - "LPCMEMHOST", - "MGMT_MAC", - "PCS0ONLINE", - "MPU_IRAM", - "PCS1ONLINE", - "PCTL0", - "PCTL1", - "PMEM", - "RR", - "TXPB", - "RXPP", - "XAUI", - "TXP", - "ARM", - "IPC", - "HOST2", - "HOST3", - "HOST4", - "HOST5", - "HOST6", - "HOST7", - "HOST8", - "HOST9", - "NETC", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown" -}; - -static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) -{ - struct be_dma_mem *mem = &q->dma_mem; - if (mem->va) - dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va, - mem->dma); -} - -static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, - u16 len, u16 entry_size) -{ - struct be_dma_mem *mem = &q->dma_mem; - - memset(q, 0, sizeof(*q)); - q->len = len; - q->entry_size = entry_size; - mem->size = len * entry_size; - mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size, &mem->dma, - GFP_KERNEL); - if (!mem->va) - return -1; - memset(mem->va, 0, mem->size); - return 0; -} - -static void be_intr_set(struct be_adapter *adapter, bool enable) -{ - u8 __iomem *addr = adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; - u32 reg = ioread32(addr); - u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - - if (adapter->eeh_err) - return; - - if (!enabled && enable) - reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - else if (enabled && !enable) - reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - else - return; - - iowrite32(reg, addr); -} - -static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted) -{ - u32 val = 0; - val |= qid & DB_RQ_RING_ID_MASK; - val |= posted << DB_RQ_NUM_POSTED_SHIFT; - - wmb(); - iowrite32(val, adapter->db + DB_RQ_OFFSET); -} - -static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted) -{ - u32 val = 0; - val |= qid & DB_TXULP_RING_ID_MASK; - val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT; - - wmb(); - iowrite32(val, adapter->db + DB_TXULP1_OFFSET); -} - -static void be_eq_notify(struct be_adapter *adapter, u16 qid, - bool arm, bool clear_int, u16 num_popped) -{ - u32 val = 0; - val |= qid & DB_EQ_RING_ID_MASK; - val |= ((qid & DB_EQ_RING_ID_EXT_MASK) << - DB_EQ_RING_ID_EXT_MASK_SHIFT); - - if (adapter->eeh_err) - return; - - if (arm) - val |= 1 << DB_EQ_REARM_SHIFT; - if (clear_int) - val |= 1 << DB_EQ_CLR_SHIFT; - val |= 1 << DB_EQ_EVNT_SHIFT; - val |= num_popped << DB_EQ_NUM_POPPED_SHIFT; - iowrite32(val, adapter->db + DB_EQ_OFFSET); -} - -void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped) -{ - u32 val = 0; - val |= qid & DB_CQ_RING_ID_MASK; - val |= ((qid & DB_CQ_RING_ID_EXT_MASK) << - DB_CQ_RING_ID_EXT_MASK_SHIFT); - - if (adapter->eeh_err) - return; - - if (arm) - val |= 1 << DB_CQ_REARM_SHIFT; - val |= num_popped << DB_CQ_NUM_POPPED_SHIFT; - iowrite32(val, adapter->db + DB_CQ_OFFSET); -} - -static int be_mac_addr_set(struct net_device *netdev, void *p) -{ - struct be_adapter *adapter = netdev_priv(netdev); - struct sockaddr *addr = p; - int status = 0; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - /* MAC addr configuration will be done in hardware for VFs - * by their corresponding PFs. Just copy to netdev addr here - */ - if (!be_physfn(adapter)) - goto netdev_addr; - - status = be_cmd_pmac_del(adapter, adapter->if_handle, - adapter->pmac_id, 0); - if (status) - return status; - - status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, - adapter->if_handle, &adapter->pmac_id, 0); -netdev_addr: - if (!status) - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - - return status; -} - -static void populate_be2_stats(struct be_adapter *adapter) -{ - struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); - struct be_pmem_stats *pmem_sts = &hw_stats->pmem; - struct be_rxf_stats_v0 *rxf_stats = &hw_stats->rxf; - struct be_port_rxf_stats_v0 *port_stats = - &rxf_stats->port[adapter->port_num]; - struct be_drv_stats *drvs = &adapter->drv_stats; - - be_dws_le_to_cpu(hw_stats, sizeof(*hw_stats)); - 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_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); - struct be_pmem_stats *pmem_sts = &hw_stats->pmem; - struct be_rxf_stats_v1 *rxf_stats = &hw_stats->rxf; - struct be_port_rxf_stats_v1 *port_stats = - &rxf_stats->port[adapter->port_num]; - struct be_drv_stats *drvs = &adapter->drv_stats; - - be_dws_le_to_cpu(hw_stats, sizeof(*hw_stats)); - 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_pport_stats *pport_stats = - pport_stats_from_cmd(adapter); - - be_dws_le_to_cpu(pport_stats, sizeof(*pport_stats)); - drvs->rx_pause_frames = pport_stats->rx_pause_frames_lo; - drvs->rx_crc_errors = pport_stats->rx_crc_errors_lo; - drvs->rx_control_frames = pport_stats->rx_control_frames_lo; - drvs->rx_in_range_errors = pport_stats->rx_in_range_errors; - drvs->rx_frame_too_long = 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 = pport_stats->rx_symbol_errors_lo; - drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow; - drvs->tx_pauseframes = pport_stats->tx_pause_frames_lo; - drvs->tx_controlframes = pport_stats->tx_control_frames_lo; - drvs->jabber_events = pport_stats->rx_jabbers; - drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue; - drvs->forwarded_packets = pport_stats->num_forwards_lo; - drvs->rx_drops_mtu = pport_stats->rx_drops_mtu_lo; - drvs->rx_drops_too_many_frags = - pport_stats->rx_drops_too_many_frags_lo; -} - -void be_parse_stats(struct be_adapter *adapter) -{ - struct be_erx_stats_v1 *erx = be_erx_stats_from_cmd(adapter); - struct be_rx_obj *rxo; - int i; - - if (adapter->generation == BE_GEN3) { - if (lancer_chip(adapter)) - populate_lancer_stats(adapter); - else - populate_be3_stats(adapter); - } else { - populate_be2_stats(adapter); - } - - /* as erx_v1 is longer than v0, ok to use v1 defn for v0 access */ - for_all_rx_queues(adapter, rxo, i) - rx_stats(rxo)->rx_drops_no_frags = - erx->rx_drops_no_fragments[rxo->q.id]; -} - -static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev, - struct rtnl_link_stats64 *stats) -{ - struct be_adapter *adapter = netdev_priv(netdev); - struct be_drv_stats *drvs = &adapter->drv_stats; - struct be_rx_obj *rxo; - struct be_tx_obj *txo; - u64 pkts, bytes; - unsigned int start; - int i; - - for_all_rx_queues(adapter, rxo, i) { - const struct be_rx_stats *rx_stats = rx_stats(rxo); - do { - start = u64_stats_fetch_begin_bh(&rx_stats->sync); - pkts = rx_stats(rxo)->rx_pkts; - bytes = rx_stats(rxo)->rx_bytes; - } while (u64_stats_fetch_retry_bh(&rx_stats->sync, start)); - stats->rx_packets += pkts; - stats->rx_bytes += bytes; - stats->multicast += rx_stats(rxo)->rx_mcast_pkts; - stats->rx_dropped += rx_stats(rxo)->rx_drops_no_skbs + - rx_stats(rxo)->rx_drops_no_frags; - } - - for_all_tx_queues(adapter, txo, i) { - const struct be_tx_stats *tx_stats = tx_stats(txo); - do { - start = u64_stats_fetch_begin_bh(&tx_stats->sync); - pkts = tx_stats(txo)->tx_pkts; - bytes = tx_stats(txo)->tx_bytes; - } while (u64_stats_fetch_retry_bh(&tx_stats->sync, start)); - stats->tx_packets += pkts; - stats->tx_bytes += bytes; - } - - /* bad pkts received */ - 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; - - /* detailed rx errors */ - stats->rx_length_errors = drvs->rx_in_range_errors + - drvs->rx_out_range_errors + - drvs->rx_frame_too_long; - - stats->rx_crc_errors = drvs->rx_crc_errors; - - /* frame alignment errors */ - 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 */ - stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop + - drvs->rx_input_fifo_overflow_drop + - drvs->rx_drops_no_pbuf; - return stats; -} - -void be_link_status_update(struct be_adapter *adapter, u32 link_status) -{ - struct net_device *netdev = adapter->netdev; - - /* when link status changes, link speed must be re-queried from card */ - adapter->link_speed = -1; - if ((link_status & LINK_STATUS_MASK) == LINK_UP) { - netif_carrier_on(netdev); - dev_info(&adapter->pdev->dev, "%s: Link up\n", netdev->name); - } else { - netif_carrier_off(netdev); - dev_info(&adapter->pdev->dev, "%s: Link down\n", netdev->name); - } -} - -static void be_tx_stats_update(struct be_tx_obj *txo, - u32 wrb_cnt, u32 copied, u32 gso_segs, bool stopped) -{ - struct be_tx_stats *stats = tx_stats(txo); - - u64_stats_update_begin(&stats->sync); - stats->tx_reqs++; - stats->tx_wrbs += wrb_cnt; - stats->tx_bytes += copied; - stats->tx_pkts += (gso_segs ? gso_segs : 1); - if (stopped) - stats->tx_stops++; - u64_stats_update_end(&stats->sync); -} - -/* Determine number of WRB entries needed to xmit data in an skb */ -static u32 wrb_cnt_for_skb(struct be_adapter *adapter, struct sk_buff *skb, - bool *dummy) -{ - int cnt = (skb->len > skb->data_len); - - cnt += skb_shinfo(skb)->nr_frags; - - /* to account for hdr wrb */ - cnt++; - if (lancer_chip(adapter) || !(cnt & 1)) { - *dummy = false; - } else { - /* add a dummy to make it an even num */ - cnt++; - *dummy = true; - } - BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT); - return cnt; -} - -static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len) -{ - wrb->frag_pa_hi = upper_32_bits(addr); - wrb->frag_pa_lo = addr & 0xFFFFFFFF; - wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK; -} - -static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, - struct sk_buff *skb, u32 wrb_cnt, u32 len) -{ - u8 vlan_prio = 0; - u16 vlan_tag = 0; - - memset(hdr, 0, sizeof(*hdr)); - - AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1); - - if (skb_is_gso(skb)) { - AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1); - AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss, - hdr, skb_shinfo(skb)->gso_size); - if (skb_is_gso_v6(skb) && !lancer_chip(adapter)) - AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1); - if (lancer_chip(adapter) && adapter->sli_family == - LANCER_A0_SLI_FAMILY) { - AMAP_SET_BITS(struct amap_eth_hdr_wrb, ipcs, hdr, 1); - if (is_tcp_pkt(skb)) - AMAP_SET_BITS(struct amap_eth_hdr_wrb, - tcpcs, hdr, 1); - else if (is_udp_pkt(skb)) - AMAP_SET_BITS(struct amap_eth_hdr_wrb, - udpcs, hdr, 1); - } - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (is_tcp_pkt(skb)) - AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1); - else if (is_udp_pkt(skb)) - AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1); - } - - if (vlan_tx_tag_present(skb)) { - AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1); - vlan_tag = vlan_tx_tag_get(skb); - vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; - /* If vlan priority provided by OS is NOT in available bmap */ - if (!(adapter->vlan_prio_bmap & (1 << vlan_prio))) - vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) | - adapter->recommended_prio; - AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag); - } - - AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1); - AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, 1); - AMAP_SET_BITS(struct amap_eth_hdr_wrb, num_wrb, hdr, wrb_cnt); - AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len); -} - -static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, - bool unmap_single) -{ - dma_addr_t dma; - - be_dws_le_to_cpu(wrb, sizeof(*wrb)); - - dma = (u64)wrb->frag_pa_hi << 32 | (u64)wrb->frag_pa_lo; - if (wrb->frag_len) { - if (unmap_single) - dma_unmap_single(dev, dma, wrb->frag_len, - DMA_TO_DEVICE); - else - dma_unmap_page(dev, dma, wrb->frag_len, DMA_TO_DEVICE); - } -} - -static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, - struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb) -{ - dma_addr_t busaddr; - int i, copied = 0; - struct device *dev = &adapter->pdev->dev; - struct sk_buff *first_skb = skb; - struct be_eth_wrb *wrb; - struct be_eth_hdr_wrb *hdr; - bool map_single = false; - u16 map_head; - - hdr = queue_head_node(txq); - queue_head_inc(txq); - map_head = txq->head; - - if (skb->len > skb->data_len) { - int len = skb_headlen(skb); - busaddr = dma_map_single(dev, skb->data, len, DMA_TO_DEVICE); - if (dma_mapping_error(dev, busaddr)) - goto dma_err; - map_single = true; - wrb = queue_head_node(txq); - wrb_fill(wrb, busaddr, len); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - copied += len; - } - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - struct skb_frag_struct *frag = - &skb_shinfo(skb)->frags[i]; - busaddr = dma_map_page(dev, frag->page, frag->page_offset, - frag->size, DMA_TO_DEVICE); - if (dma_mapping_error(dev, busaddr)) - goto dma_err; - wrb = queue_head_node(txq); - wrb_fill(wrb, busaddr, frag->size); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - copied += frag->size; - } - - if (dummy_wrb) { - wrb = queue_head_node(txq); - wrb_fill(wrb, 0, 0); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - } - - wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied); - be_dws_cpu_to_le(hdr, sizeof(*hdr)); - - return copied; -dma_err: - txq->head = map_head; - while (copied) { - wrb = queue_head_node(txq); - unmap_tx_frag(dev, wrb, map_single); - map_single = false; - copied -= wrb->frag_len; - queue_head_inc(txq); - } - return 0; -} - -static netdev_tx_t be_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ - struct be_adapter *adapter = netdev_priv(netdev); - struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)]; - struct be_queue_info *txq = &txo->q; - u32 wrb_cnt = 0, copied = 0; - u32 start = txq->head; - bool dummy_wrb, stopped = false; - - wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); - - copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); - if (copied) { - /* record the sent skb in the sent_skb table */ - BUG_ON(txo->sent_skb_list[start]); - txo->sent_skb_list[start] = skb; - - /* Ensure txq has space for the next skb; Else stop the queue - * *BEFORE* ringing the tx doorbell, so that we serialze the - * tx compls of the current transmit which'll wake up the queue - */ - atomic_add(wrb_cnt, &txq->used); - if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= - txq->len) { - netif_stop_subqueue(netdev, skb_get_queue_mapping(skb)); - stopped = true; - } - - be_txq_notify(adapter, txq->id, wrb_cnt); - - be_tx_stats_update(txo, wrb_cnt, copied, - skb_shinfo(skb)->gso_segs, stopped); - } else { - txq->head = start; - dev_kfree_skb_any(skb); - } - return NETDEV_TX_OK; -} - -static int be_change_mtu(struct net_device *netdev, int new_mtu) -{ - struct be_adapter *adapter = netdev_priv(netdev); - if (new_mtu < BE_MIN_MTU || - new_mtu > (BE_MAX_JUMBO_FRAME_SIZE - - (ETH_HLEN + ETH_FCS_LEN))) { - dev_info(&adapter->pdev->dev, - "MTU must be between %d and %d bytes\n", - BE_MIN_MTU, - (BE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN))); - return -EINVAL; - } - dev_info(&adapter->pdev->dev, "MTU changed from %d to %d bytes\n", - netdev->mtu, new_mtu); - netdev->mtu = new_mtu; - return 0; -} - -/* - * A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE. - * If the user configures more, place BE in vlan promiscuous mode. - */ -static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) -{ - u16 vtag[BE_NUM_VLANS_SUPPORTED]; - u16 ntags = 0, i; - int status = 0; - u32 if_handle; - - if (vf) { - if_handle = adapter->vf_cfg[vf_num].vf_if_handle; - vtag[0] = cpu_to_le16(adapter->vf_cfg[vf_num].vf_vlan_tag); - status = be_cmd_vlan_config(adapter, if_handle, vtag, 1, 1, 0); - } - - /* No need to further configure vids if in promiscuous mode */ - if (adapter->promiscuous) - return 0; - - if (adapter->vlans_added <= adapter->max_vlans) { - /* Construct VLAN Table to give to HW */ - for (i = 0; i < VLAN_N_VID; i++) { - if (adapter->vlan_tag[i]) { - vtag[ntags] = cpu_to_le16(i); - ntags++; - } - } - status = be_cmd_vlan_config(adapter, adapter->if_handle, - vtag, ntags, 1, 0); - } else { - status = be_cmd_vlan_config(adapter, adapter->if_handle, - NULL, 0, 1, 1); - } - - return status; -} - -static void be_vlan_add_vid(struct net_device *netdev, u16 vid) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - adapter->vlans_added++; - if (!be_physfn(adapter)) - return; - - adapter->vlan_tag[vid] = 1; - if (adapter->vlans_added <= (adapter->max_vlans + 1)) - be_vid_config(adapter, false, 0); -} - -static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - adapter->vlans_added--; - - if (!be_physfn(adapter)) - return; - - adapter->vlan_tag[vid] = 0; - if (adapter->vlans_added <= adapter->max_vlans) - be_vid_config(adapter, false, 0); -} - -static void be_set_multicast_list(struct net_device *netdev) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - if (netdev->flags & IFF_PROMISC) { - be_cmd_rx_filter(adapter, IFF_PROMISC, ON); - adapter->promiscuous = true; - goto done; - } - - /* BE was previously in promiscuous mode; disable it */ - if (adapter->promiscuous) { - adapter->promiscuous = false; - be_cmd_rx_filter(adapter, IFF_PROMISC, OFF); - - if (adapter->vlans_added) - be_vid_config(adapter, false, 0); - } - - /* Enable multicast promisc if num configured exceeds what we support */ - if (netdev->flags & IFF_ALLMULTI || - netdev_mc_count(netdev) > BE_MAX_MC) { - be_cmd_rx_filter(adapter, IFF_ALLMULTI, ON); - goto done; - } - - be_cmd_rx_filter(adapter, IFF_MULTICAST, ON); -done: - return; -} - -static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) -{ - struct be_adapter *adapter = netdev_priv(netdev); - int status; - - if (!adapter->sriov_enabled) - return -EPERM; - - if (!is_valid_ether_addr(mac) || (vf >= num_vfs)) - return -EINVAL; - - if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID) - status = be_cmd_pmac_del(adapter, - adapter->vf_cfg[vf].vf_if_handle, - adapter->vf_cfg[vf].vf_pmac_id, vf + 1); - - status = be_cmd_pmac_add(adapter, mac, - adapter->vf_cfg[vf].vf_if_handle, - &adapter->vf_cfg[vf].vf_pmac_id, vf + 1); - - if (status) - dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n", - mac, vf); - else - memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN); - - return status; -} - -static int be_get_vf_config(struct net_device *netdev, int vf, - struct ifla_vf_info *vi) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - if (!adapter->sriov_enabled) - return -EPERM; - - if (vf >= num_vfs) - return -EINVAL; - - vi->vf = vf; - vi->tx_rate = adapter->vf_cfg[vf].vf_tx_rate; - vi->vlan = adapter->vf_cfg[vf].vf_vlan_tag; - vi->qos = 0; - memcpy(&vi->mac, adapter->vf_cfg[vf].vf_mac_addr, ETH_ALEN); - - return 0; -} - -static int be_set_vf_vlan(struct net_device *netdev, - int vf, u16 vlan, u8 qos) -{ - struct be_adapter *adapter = netdev_priv(netdev); - int status = 0; - - if (!adapter->sriov_enabled) - return -EPERM; - - if ((vf >= num_vfs) || (vlan > 4095)) - return -EINVAL; - - if (vlan) { - adapter->vf_cfg[vf].vf_vlan_tag = vlan; - adapter->vlans_added++; - } else { - adapter->vf_cfg[vf].vf_vlan_tag = 0; - adapter->vlans_added--; - } - - status = be_vid_config(adapter, true, vf); - - if (status) - dev_info(&adapter->pdev->dev, - "VLAN %d config on VF %d failed\n", vlan, vf); - return status; -} - -static int be_set_vf_tx_rate(struct net_device *netdev, - int vf, int rate) -{ - struct be_adapter *adapter = netdev_priv(netdev); - int status = 0; - - if (!adapter->sriov_enabled) - return -EPERM; - - if ((vf >= num_vfs) || (rate < 0)) - return -EINVAL; - - if (rate > 10000) - rate = 10000; - - adapter->vf_cfg[vf].vf_tx_rate = rate; - status = be_cmd_set_qos(adapter, rate / 10, vf + 1); - - if (status) - dev_info(&adapter->pdev->dev, - "tx rate %d on VF %d failed\n", rate, vf); - return status; -} - -static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo) -{ - struct be_eq_obj *rx_eq = &rxo->rx_eq; - struct be_rx_stats *stats = rx_stats(rxo); - ulong now = jiffies; - ulong delta = now - stats->rx_jiffies; - u64 pkts; - unsigned int start, eqd; - - if (!rx_eq->enable_aic) - return; - - /* Wrapped around */ - if (time_before(now, stats->rx_jiffies)) { - stats->rx_jiffies = now; - return; - } - - /* Update once a second */ - if (delta < HZ) - return; - - do { - start = u64_stats_fetch_begin_bh(&stats->sync); - pkts = stats->rx_pkts; - } while (u64_stats_fetch_retry_bh(&stats->sync, start)); - - stats->rx_pps = (pkts - stats->rx_pkts_prev) / (delta / HZ); - stats->rx_pkts_prev = pkts; - stats->rx_jiffies = now; - eqd = stats->rx_pps / 110000; - eqd = eqd << 3; - if (eqd > rx_eq->max_eqd) - eqd = rx_eq->max_eqd; - if (eqd < rx_eq->min_eqd) - eqd = rx_eq->min_eqd; - if (eqd < 10) - eqd = 0; - if (eqd != rx_eq->cur_eqd) { - be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd); - rx_eq->cur_eqd = eqd; - } -} - -static void be_rx_stats_update(struct be_rx_obj *rxo, - struct be_rx_compl_info *rxcp) -{ - struct be_rx_stats *stats = rx_stats(rxo); - - u64_stats_update_begin(&stats->sync); - stats->rx_compl++; - stats->rx_bytes += rxcp->pkt_size; - stats->rx_pkts++; - if (rxcp->pkt_type == BE_MULTICAST_PACKET) - stats->rx_mcast_pkts++; - if (rxcp->err) - stats->rx_compl_err++; - u64_stats_update_end(&stats->sync); -} - -static inline bool csum_passed(struct be_rx_compl_info *rxcp) -{ - /* L4 checksum is not reliable for non TCP/UDP packets. - * Also ignore ipcksm for ipv6 pkts */ - return (rxcp->tcpf || rxcp->udpf) && rxcp->l4_csum && - (rxcp->ip_csum || rxcp->ipv6); -} - -static struct be_rx_page_info * -get_rx_page_info(struct be_adapter *adapter, - struct be_rx_obj *rxo, - u16 frag_idx) -{ - struct be_rx_page_info *rx_page_info; - struct be_queue_info *rxq = &rxo->q; - - rx_page_info = &rxo->page_info_tbl[frag_idx]; - BUG_ON(!rx_page_info->page); - - if (rx_page_info->last_page_user) { - dma_unmap_page(&adapter->pdev->dev, - dma_unmap_addr(rx_page_info, bus), - adapter->big_page_size, DMA_FROM_DEVICE); - rx_page_info->last_page_user = false; - } - - atomic_dec(&rxq->used); - return rx_page_info; -} - -/* Throwaway the data in the Rx completion */ -static void be_rx_compl_discard(struct be_adapter *adapter, - struct be_rx_obj *rxo, - struct be_rx_compl_info *rxcp) -{ - struct be_queue_info *rxq = &rxo->q; - struct be_rx_page_info *page_info; - u16 i, num_rcvd = rxcp->num_rcvd; - - for (i = 0; i < num_rcvd; i++) { - page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); - put_page(page_info->page); - memset(page_info, 0, sizeof(*page_info)); - index_inc(&rxcp->rxq_idx, rxq->len); - } -} - -/* - * skb_fill_rx_data forms a complete skb for an ether frame - * indicated by rxcp. - */ -static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo, - struct sk_buff *skb, struct be_rx_compl_info *rxcp) -{ - struct be_queue_info *rxq = &rxo->q; - struct be_rx_page_info *page_info; - u16 i, j; - u16 hdr_len, curr_frag_len, remaining; - u8 *start; - - page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); - start = page_address(page_info->page) + page_info->page_offset; - prefetch(start); - - /* Copy data in the first descriptor of this completion */ - curr_frag_len = min(rxcp->pkt_size, rx_frag_size); - - /* Copy the header portion into skb_data */ - hdr_len = min(BE_HDR_LEN, curr_frag_len); - memcpy(skb->data, start, hdr_len); - skb->len = curr_frag_len; - if (curr_frag_len <= BE_HDR_LEN) { /* tiny packet */ - /* Complete packet has now been moved to data */ - put_page(page_info->page); - skb->data_len = 0; - skb->tail += curr_frag_len; - } else { - skb_shinfo(skb)->nr_frags = 1; - skb_shinfo(skb)->frags[0].page = page_info->page; - skb_shinfo(skb)->frags[0].page_offset = - page_info->page_offset + hdr_len; - skb_shinfo(skb)->frags[0].size = curr_frag_len - hdr_len; - skb->data_len = curr_frag_len - hdr_len; - skb->tail += hdr_len; - } - page_info->page = NULL; - - if (rxcp->pkt_size <= rx_frag_size) { - BUG_ON(rxcp->num_rcvd != 1); - return; - } - - /* More frags present for this completion */ - index_inc(&rxcp->rxq_idx, rxq->len); - remaining = rxcp->pkt_size - curr_frag_len; - for (i = 1, j = 0; i < rxcp->num_rcvd; i++) { - page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); - curr_frag_len = min(remaining, 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[j].size += curr_frag_len; - skb->len += curr_frag_len; - skb->data_len += curr_frag_len; - - remaining -= curr_frag_len; - index_inc(&rxcp->rxq_idx, rxq->len); - page_info->page = NULL; - } - BUG_ON(j > |