162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QLogic qlcnic NIC Driver 462306a36Sopenharmony_ci * Copyright (c) 2009-2013 QLogic Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/netdevice.h> 862306a36Sopenharmony_ci#include <linux/if_vlan.h> 962306a36Sopenharmony_ci#include <net/ip.h> 1062306a36Sopenharmony_ci#include <linux/ipv6.h> 1162306a36Sopenharmony_ci#include <net/checksum.h> 1262306a36Sopenharmony_ci#include <linux/printk.h> 1362306a36Sopenharmony_ci#include <linux/jiffies.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "qlcnic.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define QLCNIC_TX_ETHER_PKT 0x01 1862306a36Sopenharmony_ci#define QLCNIC_TX_TCP_PKT 0x02 1962306a36Sopenharmony_ci#define QLCNIC_TX_UDP_PKT 0x03 2062306a36Sopenharmony_ci#define QLCNIC_TX_IP_PKT 0x04 2162306a36Sopenharmony_ci#define QLCNIC_TX_TCP_LSO 0x05 2262306a36Sopenharmony_ci#define QLCNIC_TX_TCP_LSO6 0x06 2362306a36Sopenharmony_ci#define QLCNIC_TX_ENCAP_PKT 0x07 2462306a36Sopenharmony_ci#define QLCNIC_TX_ENCAP_LSO 0x08 2562306a36Sopenharmony_ci#define QLCNIC_TX_TCPV6_PKT 0x0b 2662306a36Sopenharmony_ci#define QLCNIC_TX_UDPV6_PKT 0x0c 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define QLCNIC_FLAGS_VLAN_TAGGED 0x10 2962306a36Sopenharmony_ci#define QLCNIC_FLAGS_VLAN_OOB 0x40 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define qlcnic_set_tx_vlan_tci(cmd_desc, v) \ 3262306a36Sopenharmony_ci (cmd_desc)->vlan_TCI = cpu_to_le16(v); 3362306a36Sopenharmony_ci#define qlcnic_set_cmd_desc_port(cmd_desc, var) \ 3462306a36Sopenharmony_ci ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) 3562306a36Sopenharmony_ci#define qlcnic_set_cmd_desc_ctxid(cmd_desc, var) \ 3662306a36Sopenharmony_ci ((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0)) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define qlcnic_set_tx_port(_desc, _port) \ 3962306a36Sopenharmony_ci ((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0)) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define qlcnic_set_tx_flags_opcode(_desc, _flags, _opcode) \ 4262306a36Sopenharmony_ci ((_desc)->flags_opcode |= \ 4362306a36Sopenharmony_ci cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7))) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define qlcnic_set_tx_frags_len(_desc, _frags, _len) \ 4662306a36Sopenharmony_ci ((_desc)->nfrags__length = \ 4762306a36Sopenharmony_ci cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8))) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* owner bits of status_desc */ 5062306a36Sopenharmony_ci#define STATUS_OWNER_HOST (0x1ULL << 56) 5162306a36Sopenharmony_ci#define STATUS_OWNER_PHANTOM (0x2ULL << 56) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* Status descriptor: 5462306a36Sopenharmony_ci 0-3 port, 4-7 status, 8-11 type, 12-27 total_length 5562306a36Sopenharmony_ci 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset 5662306a36Sopenharmony_ci 53-55 desc_cnt, 56-57 owner, 58-63 opcode 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci#define qlcnic_get_sts_port(sts_data) \ 5962306a36Sopenharmony_ci ((sts_data) & 0x0F) 6062306a36Sopenharmony_ci#define qlcnic_get_sts_status(sts_data) \ 6162306a36Sopenharmony_ci (((sts_data) >> 4) & 0x0F) 6262306a36Sopenharmony_ci#define qlcnic_get_sts_type(sts_data) \ 6362306a36Sopenharmony_ci (((sts_data) >> 8) & 0x0F) 6462306a36Sopenharmony_ci#define qlcnic_get_sts_totallength(sts_data) \ 6562306a36Sopenharmony_ci (((sts_data) >> 12) & 0xFFFF) 6662306a36Sopenharmony_ci#define qlcnic_get_sts_refhandle(sts_data) \ 6762306a36Sopenharmony_ci (((sts_data) >> 28) & 0xFFFF) 6862306a36Sopenharmony_ci#define qlcnic_get_sts_prot(sts_data) \ 6962306a36Sopenharmony_ci (((sts_data) >> 44) & 0x0F) 7062306a36Sopenharmony_ci#define qlcnic_get_sts_pkt_offset(sts_data) \ 7162306a36Sopenharmony_ci (((sts_data) >> 48) & 0x1F) 7262306a36Sopenharmony_ci#define qlcnic_get_sts_desc_cnt(sts_data) \ 7362306a36Sopenharmony_ci (((sts_data) >> 53) & 0x7) 7462306a36Sopenharmony_ci#define qlcnic_get_sts_opcode(sts_data) \ 7562306a36Sopenharmony_ci (((sts_data) >> 58) & 0x03F) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define qlcnic_get_lro_sts_refhandle(sts_data) \ 7862306a36Sopenharmony_ci ((sts_data) & 0x07FFF) 7962306a36Sopenharmony_ci#define qlcnic_get_lro_sts_length(sts_data) \ 8062306a36Sopenharmony_ci (((sts_data) >> 16) & 0x0FFFF) 8162306a36Sopenharmony_ci#define qlcnic_get_lro_sts_l2_hdr_offset(sts_data) \ 8262306a36Sopenharmony_ci (((sts_data) >> 32) & 0x0FF) 8362306a36Sopenharmony_ci#define qlcnic_get_lro_sts_l4_hdr_offset(sts_data) \ 8462306a36Sopenharmony_ci (((sts_data) >> 40) & 0x0FF) 8562306a36Sopenharmony_ci#define qlcnic_get_lro_sts_timestamp(sts_data) \ 8662306a36Sopenharmony_ci (((sts_data) >> 48) & 0x1) 8762306a36Sopenharmony_ci#define qlcnic_get_lro_sts_type(sts_data) \ 8862306a36Sopenharmony_ci (((sts_data) >> 49) & 0x7) 8962306a36Sopenharmony_ci#define qlcnic_get_lro_sts_push_flag(sts_data) \ 9062306a36Sopenharmony_ci (((sts_data) >> 52) & 0x1) 9162306a36Sopenharmony_ci#define qlcnic_get_lro_sts_seq_number(sts_data) \ 9262306a36Sopenharmony_ci ((sts_data) & 0x0FFFFFFFF) 9362306a36Sopenharmony_ci#define qlcnic_get_lro_sts_mss(sts_data1) \ 9462306a36Sopenharmony_ci ((sts_data1 >> 32) & 0x0FFFF) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define qlcnic_83xx_get_lro_sts_mss(sts) ((sts) & 0xffff) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* opcode field in status_desc */ 9962306a36Sopenharmony_ci#define QLCNIC_SYN_OFFLOAD 0x03 10062306a36Sopenharmony_ci#define QLCNIC_RXPKT_DESC 0x04 10162306a36Sopenharmony_ci#define QLCNIC_OLD_RXPKT_DESC 0x3f 10262306a36Sopenharmony_ci#define QLCNIC_RESPONSE_DESC 0x05 10362306a36Sopenharmony_ci#define QLCNIC_LRO_DESC 0x12 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define QLCNIC_TCP_HDR_SIZE 20 10662306a36Sopenharmony_ci#define QLCNIC_TCP_TS_OPTION_SIZE 12 10762306a36Sopenharmony_ci#define QLCNIC_FETCH_RING_ID(handle) ((handle) >> 63) 10862306a36Sopenharmony_ci#define QLCNIC_DESC_OWNER_FW cpu_to_le64(STATUS_OWNER_PHANTOM) 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci#define QLCNIC_TCP_TS_HDR_SIZE (QLCNIC_TCP_HDR_SIZE + QLCNIC_TCP_TS_OPTION_SIZE) 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* for status field in status_desc */ 11362306a36Sopenharmony_ci#define STATUS_CKSUM_LOOP 0 11462306a36Sopenharmony_ci#define STATUS_CKSUM_OK 2 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#define qlcnic_83xx_pktln(sts) ((sts >> 32) & 0x3FFF) 11762306a36Sopenharmony_ci#define qlcnic_83xx_hndl(sts) ((sts >> 48) & 0x7FFF) 11862306a36Sopenharmony_ci#define qlcnic_83xx_csum_status(sts) ((sts >> 39) & 7) 11962306a36Sopenharmony_ci#define qlcnic_83xx_opcode(sts) ((sts >> 42) & 0xF) 12062306a36Sopenharmony_ci#define qlcnic_83xx_vlan_tag(sts) (((sts) >> 48) & 0xFFFF) 12162306a36Sopenharmony_ci#define qlcnic_83xx_lro_pktln(sts) (((sts) >> 32) & 0x3FFF) 12262306a36Sopenharmony_ci#define qlcnic_83xx_l2_hdr_off(sts) (((sts) >> 16) & 0xFF) 12362306a36Sopenharmony_ci#define qlcnic_83xx_l4_hdr_off(sts) (((sts) >> 24) & 0xFF) 12462306a36Sopenharmony_ci#define qlcnic_83xx_pkt_cnt(sts) (((sts) >> 16) & 0x7) 12562306a36Sopenharmony_ci#define qlcnic_83xx_is_tstamp(sts) (((sts) >> 40) & 1) 12662306a36Sopenharmony_ci#define qlcnic_83xx_is_psh_bit(sts) (((sts) >> 41) & 1) 12762306a36Sopenharmony_ci#define qlcnic_83xx_is_ip_align(sts) (((sts) >> 46) & 1) 12862306a36Sopenharmony_ci#define qlcnic_83xx_has_vlan_tag(sts) (((sts) >> 47) & 1) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, 13162306a36Sopenharmony_ci int max); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *, 13462306a36Sopenharmony_ci struct qlcnic_host_rds_ring *, 13562306a36Sopenharmony_ci u16, u16); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic inline u8 qlcnic_mac_hash(u64 mac, u16 vlan) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff) ^ (vlan & 0xff)); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter, 14362306a36Sopenharmony_ci u16 handle, u8 ring_id) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 14662306a36Sopenharmony_ci return handle | (ring_id << 15); 14762306a36Sopenharmony_ci else 14862306a36Sopenharmony_ci return handle; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic inline int qlcnic_82xx_is_lb_pkt(u64 sts_data) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void qlcnic_delete_rx_list_mac(struct qlcnic_adapter *adapter, 15762306a36Sopenharmony_ci struct qlcnic_filter *fil, 15862306a36Sopenharmony_ci void *addr, u16 vlan_id) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci int ret; 16162306a36Sopenharmony_ci u8 op; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD; 16462306a36Sopenharmony_ci ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op); 16562306a36Sopenharmony_ci if (ret) 16662306a36Sopenharmony_ci return; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL; 16962306a36Sopenharmony_ci ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op); 17062306a36Sopenharmony_ci if (!ret) { 17162306a36Sopenharmony_ci hlist_del(&fil->fnode); 17262306a36Sopenharmony_ci adapter->rx_fhash.fnum--; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head, 17762306a36Sopenharmony_ci void *addr, u16 vlan_id) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct qlcnic_filter *tmp_fil = NULL; 18062306a36Sopenharmony_ci struct hlist_node *n; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { 18362306a36Sopenharmony_ci if (ether_addr_equal(tmp_fil->faddr, addr) && 18462306a36Sopenharmony_ci tmp_fil->vlan_id == vlan_id) 18562306a36Sopenharmony_ci return tmp_fil; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return NULL; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, 19262306a36Sopenharmony_ci struct sk_buff *skb, int loopback_pkt, u16 vlan_id) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct ethhdr *phdr = (struct ethhdr *)(skb->data); 19562306a36Sopenharmony_ci struct qlcnic_filter *fil, *tmp_fil; 19662306a36Sopenharmony_ci struct hlist_head *head; 19762306a36Sopenharmony_ci unsigned long time; 19862306a36Sopenharmony_ci u64 src_addr = 0; 19962306a36Sopenharmony_ci u8 hindex, op; 20062306a36Sopenharmony_ci int ret; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (!qlcnic_sriov_pf_check(adapter) || (vlan_id == 0xffff)) 20362306a36Sopenharmony_ci vlan_id = 0; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci memcpy(&src_addr, phdr->h_source, ETH_ALEN); 20662306a36Sopenharmony_ci hindex = qlcnic_mac_hash(src_addr, vlan_id) & 20762306a36Sopenharmony_ci (adapter->fhash.fbucket_size - 1); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (loopback_pkt) { 21062306a36Sopenharmony_ci if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax) 21162306a36Sopenharmony_ci return; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci head = &(adapter->rx_fhash.fhead[hindex]); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id); 21662306a36Sopenharmony_ci if (tmp_fil) { 21762306a36Sopenharmony_ci time = tmp_fil->ftime; 21862306a36Sopenharmony_ci if (time_after(jiffies, QLCNIC_READD_AGE * HZ + time)) 21962306a36Sopenharmony_ci tmp_fil->ftime = jiffies; 22062306a36Sopenharmony_ci return; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC); 22462306a36Sopenharmony_ci if (!fil) 22562306a36Sopenharmony_ci return; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci fil->ftime = jiffies; 22862306a36Sopenharmony_ci memcpy(fil->faddr, &src_addr, ETH_ALEN); 22962306a36Sopenharmony_ci fil->vlan_id = vlan_id; 23062306a36Sopenharmony_ci spin_lock(&adapter->rx_mac_learn_lock); 23162306a36Sopenharmony_ci hlist_add_head(&(fil->fnode), head); 23262306a36Sopenharmony_ci adapter->rx_fhash.fnum++; 23362306a36Sopenharmony_ci spin_unlock(&adapter->rx_mac_learn_lock); 23462306a36Sopenharmony_ci } else { 23562306a36Sopenharmony_ci head = &adapter->fhash.fhead[hindex]; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci spin_lock(&adapter->mac_learn_lock); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id); 24062306a36Sopenharmony_ci if (tmp_fil) { 24162306a36Sopenharmony_ci op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL; 24262306a36Sopenharmony_ci ret = qlcnic_sre_macaddr_change(adapter, 24362306a36Sopenharmony_ci (u8 *)&src_addr, 24462306a36Sopenharmony_ci vlan_id, op); 24562306a36Sopenharmony_ci if (!ret) { 24662306a36Sopenharmony_ci hlist_del(&tmp_fil->fnode); 24762306a36Sopenharmony_ci adapter->fhash.fnum--; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci spin_unlock(&adapter->mac_learn_lock); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci spin_unlock(&adapter->mac_learn_lock); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci head = &adapter->rx_fhash.fhead[hindex]; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci spin_lock(&adapter->rx_mac_learn_lock); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id); 26262306a36Sopenharmony_ci if (tmp_fil) 26362306a36Sopenharmony_ci qlcnic_delete_rx_list_mac(adapter, tmp_fil, &src_addr, 26462306a36Sopenharmony_ci vlan_id); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci spin_unlock(&adapter->rx_mac_learn_lock); 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_civoid qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, 27162306a36Sopenharmony_ci u16 vlan_id, struct qlcnic_host_tx_ring *tx_ring) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct cmd_desc_type0 *hwdesc; 27462306a36Sopenharmony_ci struct qlcnic_nic_req *req; 27562306a36Sopenharmony_ci struct qlcnic_mac_req *mac_req; 27662306a36Sopenharmony_ci struct qlcnic_vlan_req *vlan_req; 27762306a36Sopenharmony_ci u32 producer; 27862306a36Sopenharmony_ci u64 word; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci producer = tx_ring->producer; 28162306a36Sopenharmony_ci hwdesc = &tx_ring->desc_head[tx_ring->producer]; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci req = (struct qlcnic_nic_req *)hwdesc; 28462306a36Sopenharmony_ci memset(req, 0, sizeof(struct qlcnic_nic_req)); 28562306a36Sopenharmony_ci req->qhdr = cpu_to_le64(QLCNIC_REQUEST << 23); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci word = QLCNIC_MAC_EVENT | ((u64)(adapter->portnum) << 16); 28862306a36Sopenharmony_ci req->req_hdr = cpu_to_le64(word); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci mac_req = (struct qlcnic_mac_req *)&(req->words[0]); 29162306a36Sopenharmony_ci mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD; 29262306a36Sopenharmony_ci memcpy(mac_req->mac_addr, uaddr, ETH_ALEN); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci vlan_req = (struct qlcnic_vlan_req *)&req->words[1]; 29562306a36Sopenharmony_ci vlan_req->vlan_id = cpu_to_le16(vlan_id); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci tx_ring->producer = get_next_index(producer, tx_ring->num_desc); 29862306a36Sopenharmony_ci smp_mb(); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void qlcnic_send_filter(struct qlcnic_adapter *adapter, 30262306a36Sopenharmony_ci struct cmd_desc_type0 *first_desc, 30362306a36Sopenharmony_ci struct sk_buff *skb, 30462306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data); 30762306a36Sopenharmony_ci struct ethhdr *phdr = (struct ethhdr *)(skb->data); 30862306a36Sopenharmony_ci u16 protocol = ntohs(skb->protocol); 30962306a36Sopenharmony_ci struct qlcnic_filter *fil, *tmp_fil; 31062306a36Sopenharmony_ci struct hlist_head *head; 31162306a36Sopenharmony_ci struct hlist_node *n; 31262306a36Sopenharmony_ci u64 src_addr = 0; 31362306a36Sopenharmony_ci u16 vlan_id = 0; 31462306a36Sopenharmony_ci u8 hindex, hval; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) 31762306a36Sopenharmony_ci return; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (adapter->flags & QLCNIC_VLAN_FILTERING) { 32062306a36Sopenharmony_ci if (protocol == ETH_P_8021Q) { 32162306a36Sopenharmony_ci vh = skb_vlan_eth_hdr(skb); 32262306a36Sopenharmony_ci vlan_id = ntohs(vh->h_vlan_TCI); 32362306a36Sopenharmony_ci } else if (skb_vlan_tag_present(skb)) { 32462306a36Sopenharmony_ci vlan_id = skb_vlan_tag_get(skb); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci memcpy(&src_addr, phdr->h_source, ETH_ALEN); 32962306a36Sopenharmony_ci hval = qlcnic_mac_hash(src_addr, vlan_id); 33062306a36Sopenharmony_ci hindex = hval & (adapter->fhash.fbucket_size - 1); 33162306a36Sopenharmony_ci head = &(adapter->fhash.fhead[hindex]); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { 33462306a36Sopenharmony_ci if (ether_addr_equal(tmp_fil->faddr, (u8 *)&src_addr) && 33562306a36Sopenharmony_ci tmp_fil->vlan_id == vlan_id) { 33662306a36Sopenharmony_ci if (time_is_before_jiffies(QLCNIC_READD_AGE * HZ + tmp_fil->ftime)) 33762306a36Sopenharmony_ci qlcnic_change_filter(adapter, &src_addr, 33862306a36Sopenharmony_ci vlan_id, tx_ring); 33962306a36Sopenharmony_ci tmp_fil->ftime = jiffies; 34062306a36Sopenharmony_ci return; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (unlikely(adapter->fhash.fnum >= adapter->fhash.fmax)) { 34562306a36Sopenharmony_ci adapter->stats.mac_filter_limit_overrun++; 34662306a36Sopenharmony_ci return; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC); 35062306a36Sopenharmony_ci if (!fil) 35162306a36Sopenharmony_ci return; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci qlcnic_change_filter(adapter, &src_addr, vlan_id, tx_ring); 35462306a36Sopenharmony_ci fil->ftime = jiffies; 35562306a36Sopenharmony_ci fil->vlan_id = vlan_id; 35662306a36Sopenharmony_ci memcpy(fil->faddr, &src_addr, ETH_ALEN); 35762306a36Sopenharmony_ci spin_lock(&adapter->mac_learn_lock); 35862306a36Sopenharmony_ci hlist_add_head(&(fil->fnode), head); 35962306a36Sopenharmony_ci adapter->fhash.fnum++; 36062306a36Sopenharmony_ci spin_unlock(&adapter->mac_learn_lock); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci#define QLCNIC_ENCAP_VXLAN_PKT BIT_0 36462306a36Sopenharmony_ci#define QLCNIC_ENCAP_OUTER_L3_IP6 BIT_1 36562306a36Sopenharmony_ci#define QLCNIC_ENCAP_INNER_L3_IP6 BIT_2 36662306a36Sopenharmony_ci#define QLCNIC_ENCAP_INNER_L4_UDP BIT_3 36762306a36Sopenharmony_ci#define QLCNIC_ENCAP_DO_L3_CSUM BIT_4 36862306a36Sopenharmony_ci#define QLCNIC_ENCAP_DO_L4_CSUM BIT_5 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic int qlcnic_tx_encap_pkt(struct qlcnic_adapter *adapter, 37162306a36Sopenharmony_ci struct cmd_desc_type0 *first_desc, 37262306a36Sopenharmony_ci struct sk_buff *skb, 37362306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci u8 opcode = 0, inner_hdr_len = 0, outer_hdr_len = 0, total_hdr_len = 0; 37662306a36Sopenharmony_ci int copied, copy_len, descr_size; 37762306a36Sopenharmony_ci u32 producer = tx_ring->producer; 37862306a36Sopenharmony_ci struct cmd_desc_type0 *hwdesc; 37962306a36Sopenharmony_ci u16 flags = 0, encap_descr = 0; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci opcode = QLCNIC_TX_ETHER_PKT; 38262306a36Sopenharmony_ci encap_descr = QLCNIC_ENCAP_VXLAN_PKT; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (skb_is_gso(skb)) { 38562306a36Sopenharmony_ci inner_hdr_len = skb_inner_transport_header(skb) + 38662306a36Sopenharmony_ci inner_tcp_hdrlen(skb) - 38762306a36Sopenharmony_ci skb_inner_mac_header(skb); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* VXLAN header size = 8 */ 39062306a36Sopenharmony_ci outer_hdr_len = skb_transport_offset(skb) + 8 + 39162306a36Sopenharmony_ci sizeof(struct udphdr); 39262306a36Sopenharmony_ci first_desc->outer_hdr_length = outer_hdr_len; 39362306a36Sopenharmony_ci total_hdr_len = inner_hdr_len + outer_hdr_len; 39462306a36Sopenharmony_ci encap_descr |= QLCNIC_ENCAP_DO_L3_CSUM | 39562306a36Sopenharmony_ci QLCNIC_ENCAP_DO_L4_CSUM; 39662306a36Sopenharmony_ci first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); 39762306a36Sopenharmony_ci first_desc->hdr_length = inner_hdr_len; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Copy inner and outer headers in Tx descriptor(s) 40062306a36Sopenharmony_ci * If total_hdr_len > cmd_desc_type0, use multiple 40162306a36Sopenharmony_ci * descriptors 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_ci copied = 0; 40462306a36Sopenharmony_ci descr_size = (int)sizeof(struct cmd_desc_type0); 40562306a36Sopenharmony_ci while (copied < total_hdr_len) { 40662306a36Sopenharmony_ci copy_len = min(descr_size, (total_hdr_len - copied)); 40762306a36Sopenharmony_ci hwdesc = &tx_ring->desc_head[producer]; 40862306a36Sopenharmony_ci tx_ring->cmd_buf_arr[producer].skb = NULL; 40962306a36Sopenharmony_ci skb_copy_from_linear_data_offset(skb, copied, 41062306a36Sopenharmony_ci (char *)hwdesc, 41162306a36Sopenharmony_ci copy_len); 41262306a36Sopenharmony_ci copied += copy_len; 41362306a36Sopenharmony_ci producer = get_next_index(producer, tx_ring->num_desc); 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci tx_ring->producer = producer; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* Make sure updated tx_ring->producer is visible 41962306a36Sopenharmony_ci * for qlcnic_tx_avail() 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ci smp_mb(); 42262306a36Sopenharmony_ci adapter->stats.encap_lso_frames++; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci opcode = QLCNIC_TX_ENCAP_LSO; 42562306a36Sopenharmony_ci } else if (skb->ip_summed == CHECKSUM_PARTIAL) { 42662306a36Sopenharmony_ci if (inner_ip_hdr(skb)->version == 6) { 42762306a36Sopenharmony_ci if (inner_ipv6_hdr(skb)->nexthdr == IPPROTO_UDP) 42862306a36Sopenharmony_ci encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP; 42962306a36Sopenharmony_ci } else { 43062306a36Sopenharmony_ci if (inner_ip_hdr(skb)->protocol == IPPROTO_UDP) 43162306a36Sopenharmony_ci encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci adapter->stats.encap_tx_csummed++; 43562306a36Sopenharmony_ci opcode = QLCNIC_TX_ENCAP_PKT; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Prepare first 16 bits of byte offset 16 of Tx descriptor */ 43962306a36Sopenharmony_ci if (ip_hdr(skb)->version == 6) 44062306a36Sopenharmony_ci encap_descr |= QLCNIC_ENCAP_OUTER_L3_IP6; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* outer IP header's size in 32bit words size*/ 44362306a36Sopenharmony_ci encap_descr |= (skb_network_header_len(skb) >> 2) << 6; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* outer IP header offset */ 44662306a36Sopenharmony_ci encap_descr |= skb_network_offset(skb) << 10; 44762306a36Sopenharmony_ci first_desc->encap_descr = cpu_to_le16(encap_descr); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci first_desc->tcp_hdr_offset = skb_inner_transport_header(skb) - 45062306a36Sopenharmony_ci skb->data; 45162306a36Sopenharmony_ci first_desc->ip_hdr_offset = skb_inner_network_offset(skb); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int qlcnic_tx_pkt(struct qlcnic_adapter *adapter, 45962306a36Sopenharmony_ci struct cmd_desc_type0 *first_desc, struct sk_buff *skb, 46062306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci u8 l4proto, opcode = 0, hdr_len = 0, tag_vlan = 0; 46362306a36Sopenharmony_ci u16 flags = 0, vlan_tci = 0; 46462306a36Sopenharmony_ci int copied, offset, copy_len, size; 46562306a36Sopenharmony_ci struct cmd_desc_type0 *hwdesc; 46662306a36Sopenharmony_ci struct vlan_ethhdr *vh; 46762306a36Sopenharmony_ci u16 protocol = ntohs(skb->protocol); 46862306a36Sopenharmony_ci u32 producer = tx_ring->producer; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (protocol == ETH_P_8021Q) { 47162306a36Sopenharmony_ci vh = skb_vlan_eth_hdr(skb); 47262306a36Sopenharmony_ci flags = QLCNIC_FLAGS_VLAN_TAGGED; 47362306a36Sopenharmony_ci vlan_tci = ntohs(vh->h_vlan_TCI); 47462306a36Sopenharmony_ci protocol = ntohs(vh->h_vlan_encapsulated_proto); 47562306a36Sopenharmony_ci tag_vlan = 1; 47662306a36Sopenharmony_ci } else if (skb_vlan_tag_present(skb)) { 47762306a36Sopenharmony_ci flags = QLCNIC_FLAGS_VLAN_OOB; 47862306a36Sopenharmony_ci vlan_tci = skb_vlan_tag_get(skb); 47962306a36Sopenharmony_ci tag_vlan = 1; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci if (unlikely(adapter->tx_pvid)) { 48262306a36Sopenharmony_ci if (tag_vlan && !(adapter->flags & QLCNIC_TAGGING_ENABLED)) 48362306a36Sopenharmony_ci return -EIO; 48462306a36Sopenharmony_ci if (tag_vlan && (adapter->flags & QLCNIC_TAGGING_ENABLED)) 48562306a36Sopenharmony_ci goto set_flags; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci flags = QLCNIC_FLAGS_VLAN_OOB; 48862306a36Sopenharmony_ci vlan_tci = adapter->tx_pvid; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ciset_flags: 49162306a36Sopenharmony_ci qlcnic_set_tx_vlan_tci(first_desc, vlan_tci); 49262306a36Sopenharmony_ci qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (*(skb->data) & BIT_0) { 49562306a36Sopenharmony_ci flags |= BIT_0; 49662306a36Sopenharmony_ci memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci opcode = QLCNIC_TX_ETHER_PKT; 49962306a36Sopenharmony_ci if (skb_is_gso(skb)) { 50062306a36Sopenharmony_ci hdr_len = skb_tcp_all_headers(skb); 50162306a36Sopenharmony_ci first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); 50262306a36Sopenharmony_ci first_desc->hdr_length = hdr_len; 50362306a36Sopenharmony_ci opcode = (protocol == ETH_P_IPV6) ? QLCNIC_TX_TCP_LSO6 : 50462306a36Sopenharmony_ci QLCNIC_TX_TCP_LSO; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* For LSO, we need to copy the MAC/IP/TCP headers into 50762306a36Sopenharmony_ci * the descriptor ring */ 50862306a36Sopenharmony_ci copied = 0; 50962306a36Sopenharmony_ci offset = 2; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (flags & QLCNIC_FLAGS_VLAN_OOB) { 51262306a36Sopenharmony_ci first_desc->hdr_length += VLAN_HLEN; 51362306a36Sopenharmony_ci first_desc->tcp_hdr_offset = VLAN_HLEN; 51462306a36Sopenharmony_ci first_desc->ip_hdr_offset = VLAN_HLEN; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Only in case of TSO on vlan device */ 51762306a36Sopenharmony_ci flags |= QLCNIC_FLAGS_VLAN_TAGGED; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* Create a TSO vlan header template for firmware */ 52062306a36Sopenharmony_ci hwdesc = &tx_ring->desc_head[producer]; 52162306a36Sopenharmony_ci tx_ring->cmd_buf_arr[producer].skb = NULL; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci copy_len = min((int)sizeof(struct cmd_desc_type0) - 52462306a36Sopenharmony_ci offset, hdr_len + VLAN_HLEN); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci vh = (struct vlan_ethhdr *)((char *) hwdesc + 2); 52762306a36Sopenharmony_ci skb_copy_from_linear_data(skb, vh, 12); 52862306a36Sopenharmony_ci vh->h_vlan_proto = htons(ETH_P_8021Q); 52962306a36Sopenharmony_ci vh->h_vlan_TCI = htons(vlan_tci); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci skb_copy_from_linear_data_offset(skb, 12, 53262306a36Sopenharmony_ci (char *)vh + 16, 53362306a36Sopenharmony_ci copy_len - 16); 53462306a36Sopenharmony_ci copied = copy_len - VLAN_HLEN; 53562306a36Sopenharmony_ci offset = 0; 53662306a36Sopenharmony_ci producer = get_next_index(producer, tx_ring->num_desc); 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci while (copied < hdr_len) { 54062306a36Sopenharmony_ci size = (int)sizeof(struct cmd_desc_type0) - offset; 54162306a36Sopenharmony_ci copy_len = min(size, (hdr_len - copied)); 54262306a36Sopenharmony_ci hwdesc = &tx_ring->desc_head[producer]; 54362306a36Sopenharmony_ci tx_ring->cmd_buf_arr[producer].skb = NULL; 54462306a36Sopenharmony_ci skb_copy_from_linear_data_offset(skb, copied, 54562306a36Sopenharmony_ci (char *)hwdesc + 54662306a36Sopenharmony_ci offset, copy_len); 54762306a36Sopenharmony_ci copied += copy_len; 54862306a36Sopenharmony_ci offset = 0; 54962306a36Sopenharmony_ci producer = get_next_index(producer, tx_ring->num_desc); 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci tx_ring->producer = producer; 55362306a36Sopenharmony_ci smp_mb(); 55462306a36Sopenharmony_ci adapter->stats.lso_frames++; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci } else if (skb->ip_summed == CHECKSUM_PARTIAL) { 55762306a36Sopenharmony_ci if (protocol == ETH_P_IP) { 55862306a36Sopenharmony_ci l4proto = ip_hdr(skb)->protocol; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (l4proto == IPPROTO_TCP) 56162306a36Sopenharmony_ci opcode = QLCNIC_TX_TCP_PKT; 56262306a36Sopenharmony_ci else if (l4proto == IPPROTO_UDP) 56362306a36Sopenharmony_ci opcode = QLCNIC_TX_UDP_PKT; 56462306a36Sopenharmony_ci } else if (protocol == ETH_P_IPV6) { 56562306a36Sopenharmony_ci l4proto = ipv6_hdr(skb)->nexthdr; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (l4proto == IPPROTO_TCP) 56862306a36Sopenharmony_ci opcode = QLCNIC_TX_TCPV6_PKT; 56962306a36Sopenharmony_ci else if (l4proto == IPPROTO_UDP) 57062306a36Sopenharmony_ci opcode = QLCNIC_TX_UDPV6_PKT; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci first_desc->tcp_hdr_offset += skb_transport_offset(skb); 57462306a36Sopenharmony_ci first_desc->ip_hdr_offset += skb_network_offset(skb); 57562306a36Sopenharmony_ci qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic int qlcnic_map_tx_skb(struct pci_dev *pdev, struct sk_buff *skb, 58162306a36Sopenharmony_ci struct qlcnic_cmd_buffer *pbuf) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct qlcnic_skb_frag *nf; 58462306a36Sopenharmony_ci skb_frag_t *frag; 58562306a36Sopenharmony_ci int i, nr_frags; 58662306a36Sopenharmony_ci dma_addr_t map; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 58962306a36Sopenharmony_ci nf = &pbuf->frag_array[0]; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci map = dma_map_single(&pdev->dev, skb->data, skb_headlen(skb), 59262306a36Sopenharmony_ci DMA_TO_DEVICE); 59362306a36Sopenharmony_ci if (dma_mapping_error(&pdev->dev, map)) 59462306a36Sopenharmony_ci goto out_err; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci nf->dma = map; 59762306a36Sopenharmony_ci nf->length = skb_headlen(skb); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci for (i = 0; i < nr_frags; i++) { 60062306a36Sopenharmony_ci frag = &skb_shinfo(skb)->frags[i]; 60162306a36Sopenharmony_ci nf = &pbuf->frag_array[i+1]; 60262306a36Sopenharmony_ci map = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag), 60362306a36Sopenharmony_ci DMA_TO_DEVICE); 60462306a36Sopenharmony_ci if (dma_mapping_error(&pdev->dev, map)) 60562306a36Sopenharmony_ci goto unwind; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci nf->dma = map; 60862306a36Sopenharmony_ci nf->length = skb_frag_size(frag); 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci return 0; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ciunwind: 61462306a36Sopenharmony_ci while (--i >= 0) { 61562306a36Sopenharmony_ci nf = &pbuf->frag_array[i+1]; 61662306a36Sopenharmony_ci dma_unmap_page(&pdev->dev, nf->dma, nf->length, DMA_TO_DEVICE); 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci nf = &pbuf->frag_array[0]; 62062306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, nf->dma, skb_headlen(skb), DMA_TO_DEVICE); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ciout_err: 62362306a36Sopenharmony_ci return -ENOMEM; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic void qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb, 62762306a36Sopenharmony_ci struct qlcnic_cmd_buffer *pbuf) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct qlcnic_skb_frag *nf = &pbuf->frag_array[0]; 63062306a36Sopenharmony_ci int i, nr_frags = skb_shinfo(skb)->nr_frags; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci for (i = 0; i < nr_frags; i++) { 63362306a36Sopenharmony_ci nf = &pbuf->frag_array[i+1]; 63462306a36Sopenharmony_ci dma_unmap_page(&pdev->dev, nf->dma, nf->length, DMA_TO_DEVICE); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci nf = &pbuf->frag_array[0]; 63862306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, nf->dma, skb_headlen(skb), DMA_TO_DEVICE); 63962306a36Sopenharmony_ci pbuf->skb = NULL; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic inline void qlcnic_clear_cmddesc(u64 *desc) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci desc[0] = 0ULL; 64562306a36Sopenharmony_ci desc[2] = 0ULL; 64662306a36Sopenharmony_ci desc[7] = 0ULL; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cinetdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 65262306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 65362306a36Sopenharmony_ci struct qlcnic_cmd_buffer *pbuf; 65462306a36Sopenharmony_ci struct qlcnic_skb_frag *buffrag; 65562306a36Sopenharmony_ci struct cmd_desc_type0 *hwdesc, *first_desc; 65662306a36Sopenharmony_ci struct pci_dev *pdev; 65762306a36Sopenharmony_ci struct ethhdr *phdr; 65862306a36Sopenharmony_ci int i, k, frag_count, delta = 0; 65962306a36Sopenharmony_ci u32 producer, num_txd; 66062306a36Sopenharmony_ci u16 protocol; 66162306a36Sopenharmony_ci bool l4_is_udp = false; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { 66462306a36Sopenharmony_ci netif_tx_stop_all_queues(netdev); 66562306a36Sopenharmony_ci return NETDEV_TX_BUSY; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (adapter->flags & QLCNIC_MACSPOOF) { 66962306a36Sopenharmony_ci phdr = (struct ethhdr *)skb->data; 67062306a36Sopenharmony_ci if (!ether_addr_equal(phdr->h_source, adapter->mac_addr)) 67162306a36Sopenharmony_ci goto drop_packet; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci tx_ring = &adapter->tx_ring[skb_get_queue_mapping(skb)]; 67562306a36Sopenharmony_ci num_txd = tx_ring->num_desc; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci frag_count = skb_shinfo(skb)->nr_frags + 1; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* 14 frags supported for normal packet and 68062306a36Sopenharmony_ci * 32 frags supported for TSO packet 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) { 68362306a36Sopenharmony_ci for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++) 68462306a36Sopenharmony_ci delta += skb_frag_size(&skb_shinfo(skb)->frags[i]); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (!__pskb_pull_tail(skb, delta)) 68762306a36Sopenharmony_ci goto drop_packet; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci frag_count = 1 + skb_shinfo(skb)->nr_frags; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) { 69362306a36Sopenharmony_ci netif_tx_stop_queue(tx_ring->txq); 69462306a36Sopenharmony_ci if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) { 69562306a36Sopenharmony_ci netif_tx_start_queue(tx_ring->txq); 69662306a36Sopenharmony_ci } else { 69762306a36Sopenharmony_ci tx_ring->tx_stats.xmit_off++; 69862306a36Sopenharmony_ci return NETDEV_TX_BUSY; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci producer = tx_ring->producer; 70362306a36Sopenharmony_ci pbuf = &tx_ring->cmd_buf_arr[producer]; 70462306a36Sopenharmony_ci pdev = adapter->pdev; 70562306a36Sopenharmony_ci first_desc = &tx_ring->desc_head[producer]; 70662306a36Sopenharmony_ci hwdesc = &tx_ring->desc_head[producer]; 70762306a36Sopenharmony_ci qlcnic_clear_cmddesc((u64 *)hwdesc); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (qlcnic_map_tx_skb(pdev, skb, pbuf)) { 71062306a36Sopenharmony_ci adapter->stats.tx_dma_map_error++; 71162306a36Sopenharmony_ci goto drop_packet; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci pbuf->skb = skb; 71562306a36Sopenharmony_ci pbuf->frag_count = frag_count; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len); 71862306a36Sopenharmony_ci qlcnic_set_tx_port(first_desc, adapter->portnum); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci for (i = 0; i < frag_count; i++) { 72162306a36Sopenharmony_ci k = i % 4; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if ((k == 0) && (i > 0)) { 72462306a36Sopenharmony_ci /* move to next desc.*/ 72562306a36Sopenharmony_ci producer = get_next_index(producer, num_txd); 72662306a36Sopenharmony_ci hwdesc = &tx_ring->desc_head[producer]; 72762306a36Sopenharmony_ci qlcnic_clear_cmddesc((u64 *)hwdesc); 72862306a36Sopenharmony_ci tx_ring->cmd_buf_arr[producer].skb = NULL; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci buffrag = &pbuf->frag_array[i]; 73262306a36Sopenharmony_ci hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length); 73362306a36Sopenharmony_ci switch (k) { 73462306a36Sopenharmony_ci case 0: 73562306a36Sopenharmony_ci hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci case 1: 73862306a36Sopenharmony_ci hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma); 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci case 2: 74162306a36Sopenharmony_ci hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma); 74262306a36Sopenharmony_ci break; 74362306a36Sopenharmony_ci case 3: 74462306a36Sopenharmony_ci hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma); 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci tx_ring->producer = get_next_index(producer, num_txd); 75062306a36Sopenharmony_ci smp_mb(); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci protocol = ntohs(skb->protocol); 75362306a36Sopenharmony_ci if (protocol == ETH_P_IP) 75462306a36Sopenharmony_ci l4_is_udp = ip_hdr(skb)->protocol == IPPROTO_UDP; 75562306a36Sopenharmony_ci else if (protocol == ETH_P_IPV6) 75662306a36Sopenharmony_ci l4_is_udp = ipv6_hdr(skb)->nexthdr == IPPROTO_UDP; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* Check if it is a VXLAN packet */ 75962306a36Sopenharmony_ci if (!skb->encapsulation || !l4_is_udp || 76062306a36Sopenharmony_ci !qlcnic_encap_tx_offload(adapter)) { 76162306a36Sopenharmony_ci if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb, 76262306a36Sopenharmony_ci tx_ring))) 76362306a36Sopenharmony_ci goto unwind_buff; 76462306a36Sopenharmony_ci } else { 76562306a36Sopenharmony_ci if (unlikely(qlcnic_tx_encap_pkt(adapter, first_desc, 76662306a36Sopenharmony_ci skb, tx_ring))) 76762306a36Sopenharmony_ci goto unwind_buff; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (adapter->drv_mac_learn) 77162306a36Sopenharmony_ci qlcnic_send_filter(adapter, first_desc, skb, tx_ring); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci tx_ring->tx_stats.tx_bytes += skb->len; 77462306a36Sopenharmony_ci tx_ring->tx_stats.xmit_called++; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* Ensure writes are complete before HW fetches Tx descriptors */ 77762306a36Sopenharmony_ci wmb(); 77862306a36Sopenharmony_ci qlcnic_update_cmd_producer(tx_ring); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci return NETDEV_TX_OK; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ciunwind_buff: 78362306a36Sopenharmony_ci qlcnic_unmap_buffers(pdev, skb, pbuf); 78462306a36Sopenharmony_cidrop_packet: 78562306a36Sopenharmony_ci adapter->stats.txdropped++; 78662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 78762306a36Sopenharmony_ci return NETDEV_TX_OK; 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_civoid qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (adapter->ahw->linkup && !linkup) { 79562306a36Sopenharmony_ci netdev_info(netdev, "NIC Link is down\n"); 79662306a36Sopenharmony_ci adapter->ahw->linkup = 0; 79762306a36Sopenharmony_ci netif_carrier_off(netdev); 79862306a36Sopenharmony_ci } else if (!adapter->ahw->linkup && linkup) { 79962306a36Sopenharmony_ci adapter->ahw->linkup = 1; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci /* Do not advertise Link up to the stack if device 80262306a36Sopenharmony_ci * is in loopback mode 80362306a36Sopenharmony_ci */ 80462306a36Sopenharmony_ci if (qlcnic_83xx_check(adapter) && adapter->ahw->lb_mode) { 80562306a36Sopenharmony_ci netdev_info(netdev, "NIC Link is up for loopback test\n"); 80662306a36Sopenharmony_ci return; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci netdev_info(netdev, "NIC Link is up\n"); 81062306a36Sopenharmony_ci netif_carrier_on(netdev); 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter, 81562306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring, 81662306a36Sopenharmony_ci struct qlcnic_rx_buffer *buffer) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct sk_buff *skb; 81962306a36Sopenharmony_ci dma_addr_t dma; 82062306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci skb = netdev_alloc_skb(adapter->netdev, rds_ring->skb_size); 82362306a36Sopenharmony_ci if (!skb) { 82462306a36Sopenharmony_ci adapter->stats.skb_alloc_failure++; 82562306a36Sopenharmony_ci return -ENOMEM; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci skb_reserve(skb, NET_IP_ALIGN); 82962306a36Sopenharmony_ci dma = dma_map_single(&pdev->dev, skb->data, rds_ring->dma_size, 83062306a36Sopenharmony_ci DMA_FROM_DEVICE); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (dma_mapping_error(&pdev->dev, dma)) { 83362306a36Sopenharmony_ci adapter->stats.rx_dma_map_error++; 83462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 83562306a36Sopenharmony_ci return -ENOMEM; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci buffer->skb = skb; 83962306a36Sopenharmony_ci buffer->dma = dma; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci return 0; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, 84562306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring, 84662306a36Sopenharmony_ci u8 ring_id) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct rcv_desc *pdesc; 84962306a36Sopenharmony_ci struct qlcnic_rx_buffer *buffer; 85062306a36Sopenharmony_ci int count = 0; 85162306a36Sopenharmony_ci uint32_t producer, handle; 85262306a36Sopenharmony_ci struct list_head *head; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (!spin_trylock(&rds_ring->lock)) 85562306a36Sopenharmony_ci return; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci producer = rds_ring->producer; 85862306a36Sopenharmony_ci head = &rds_ring->free_list; 85962306a36Sopenharmony_ci while (!list_empty(head)) { 86062306a36Sopenharmony_ci buffer = list_entry(head->next, struct qlcnic_rx_buffer, list); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (!buffer->skb) { 86362306a36Sopenharmony_ci if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer)) 86462306a36Sopenharmony_ci break; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci count++; 86762306a36Sopenharmony_ci list_del(&buffer->list); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci /* make a rcv descriptor */ 87062306a36Sopenharmony_ci pdesc = &rds_ring->desc_head[producer]; 87162306a36Sopenharmony_ci handle = qlcnic_get_ref_handle(adapter, 87262306a36Sopenharmony_ci buffer->ref_handle, ring_id); 87362306a36Sopenharmony_ci pdesc->reference_handle = cpu_to_le16(handle); 87462306a36Sopenharmony_ci pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size); 87562306a36Sopenharmony_ci pdesc->addr_buffer = cpu_to_le64(buffer->dma); 87662306a36Sopenharmony_ci producer = get_next_index(producer, rds_ring->num_desc); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci if (count) { 87962306a36Sopenharmony_ci rds_ring->producer = producer; 88062306a36Sopenharmony_ci writel((producer - 1) & (rds_ring->num_desc - 1), 88162306a36Sopenharmony_ci rds_ring->crb_rcv_producer); 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci spin_unlock(&rds_ring->lock); 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_cistatic int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter, 88762306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring, 88862306a36Sopenharmony_ci int budget) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci u32 sw_consumer, hw_consumer; 89162306a36Sopenharmony_ci int i, done, count = 0; 89262306a36Sopenharmony_ci struct qlcnic_cmd_buffer *buffer; 89362306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 89462306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 89562306a36Sopenharmony_ci struct qlcnic_skb_frag *frag; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (!spin_trylock(&tx_ring->tx_clean_lock)) 89862306a36Sopenharmony_ci return 1; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci sw_consumer = tx_ring->sw_consumer; 90162306a36Sopenharmony_ci hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci while (sw_consumer != hw_consumer) { 90462306a36Sopenharmony_ci buffer = &tx_ring->cmd_buf_arr[sw_consumer]; 90562306a36Sopenharmony_ci if (buffer->skb) { 90662306a36Sopenharmony_ci frag = &buffer->frag_array[0]; 90762306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, frag->dma, frag->length, 90862306a36Sopenharmony_ci DMA_TO_DEVICE); 90962306a36Sopenharmony_ci frag->dma = 0ULL; 91062306a36Sopenharmony_ci for (i = 1; i < buffer->frag_count; i++) { 91162306a36Sopenharmony_ci frag++; 91262306a36Sopenharmony_ci dma_unmap_page(&pdev->dev, frag->dma, 91362306a36Sopenharmony_ci frag->length, DMA_TO_DEVICE); 91462306a36Sopenharmony_ci frag->dma = 0ULL; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci tx_ring->tx_stats.xmit_finished++; 91762306a36Sopenharmony_ci dev_kfree_skb_any(buffer->skb); 91862306a36Sopenharmony_ci buffer->skb = NULL; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc); 92262306a36Sopenharmony_ci if (++count >= budget) 92362306a36Sopenharmony_ci break; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci tx_ring->sw_consumer = sw_consumer; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (count && netif_running(netdev)) { 92962306a36Sopenharmony_ci smp_mb(); 93062306a36Sopenharmony_ci if (netif_tx_queue_stopped(tx_ring->txq) && 93162306a36Sopenharmony_ci netif_carrier_ok(netdev)) { 93262306a36Sopenharmony_ci if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) { 93362306a36Sopenharmony_ci netif_tx_wake_queue(tx_ring->txq); 93462306a36Sopenharmony_ci tx_ring->tx_stats.xmit_on++; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci adapter->tx_timeo_cnt = 0; 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci /* 94062306a36Sopenharmony_ci * If everything is freed up to consumer then check if the ring is full 94162306a36Sopenharmony_ci * If the ring is full then check if more needs to be freed and 94262306a36Sopenharmony_ci * schedule the call back again. 94362306a36Sopenharmony_ci * 94462306a36Sopenharmony_ci * This happens when there are 2 CPUs. One could be freeing and the 94562306a36Sopenharmony_ci * other filling it. If the ring is full when we get out of here and 94662306a36Sopenharmony_ci * the card has already interrupted the host then the host can miss the 94762306a36Sopenharmony_ci * interrupt. 94862306a36Sopenharmony_ci * 94962306a36Sopenharmony_ci * There is still a possible race condition and the host could miss an 95062306a36Sopenharmony_ci * interrupt. The card has to take care of this. 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_ci hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); 95362306a36Sopenharmony_ci done = (sw_consumer == hw_consumer); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci spin_unlock(&tx_ring->tx_clean_lock); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return done; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic int qlcnic_poll(struct napi_struct *napi, int budget) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci int tx_complete, work_done; 96362306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 96462306a36Sopenharmony_ci struct qlcnic_adapter *adapter; 96562306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi); 96862306a36Sopenharmony_ci adapter = sds_ring->adapter; 96962306a36Sopenharmony_ci tx_ring = sds_ring->tx_ring; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, 97262306a36Sopenharmony_ci budget); 97362306a36Sopenharmony_ci work_done = qlcnic_process_rcv_ring(sds_ring, budget); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci /* Check if we need a repoll */ 97662306a36Sopenharmony_ci if (!tx_complete) 97762306a36Sopenharmony_ci work_done = budget; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (work_done < budget) { 98062306a36Sopenharmony_ci napi_complete_done(&sds_ring->napi, work_done); 98162306a36Sopenharmony_ci if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { 98262306a36Sopenharmony_ci qlcnic_enable_sds_intr(adapter, sds_ring); 98362306a36Sopenharmony_ci qlcnic_enable_tx_intr(adapter, tx_ring); 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci return work_done; 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic int qlcnic_tx_poll(struct napi_struct *napi, int budget) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 99362306a36Sopenharmony_ci struct qlcnic_adapter *adapter; 99462306a36Sopenharmony_ci int work_done; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci tx_ring = container_of(napi, struct qlcnic_host_tx_ring, napi); 99762306a36Sopenharmony_ci adapter = tx_ring->adapter; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci work_done = qlcnic_process_cmd_ring(adapter, tx_ring, budget); 100062306a36Sopenharmony_ci if (work_done) { 100162306a36Sopenharmony_ci napi_complete(&tx_ring->napi); 100262306a36Sopenharmony_ci if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) 100362306a36Sopenharmony_ci qlcnic_enable_tx_intr(adapter, tx_ring); 100462306a36Sopenharmony_ci } else { 100562306a36Sopenharmony_ci /* As qlcnic_process_cmd_ring() returned 0, we need a repoll*/ 100662306a36Sopenharmony_ci work_done = budget; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci return work_done; 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cistatic int qlcnic_rx_poll(struct napi_struct *napi, int budget) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 101562306a36Sopenharmony_ci struct qlcnic_adapter *adapter; 101662306a36Sopenharmony_ci int work_done; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi); 101962306a36Sopenharmony_ci adapter = sds_ring->adapter; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci work_done = qlcnic_process_rcv_ring(sds_ring, budget); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (work_done < budget) { 102462306a36Sopenharmony_ci napi_complete_done(&sds_ring->napi, work_done); 102562306a36Sopenharmony_ci if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) 102662306a36Sopenharmony_ci qlcnic_enable_sds_intr(adapter, sds_ring); 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci return work_done; 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic void qlcnic_handle_linkevent(struct qlcnic_adapter *adapter, 103362306a36Sopenharmony_ci struct qlcnic_fw_msg *msg) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci u32 cable_OUI; 103662306a36Sopenharmony_ci u16 cable_len, link_speed; 103762306a36Sopenharmony_ci u8 link_status, module, duplex, autoneg, lb_status = 0; 103862306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci adapter->ahw->has_link_events = 1; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci cable_OUI = msg->body[1] & 0xffffffff; 104362306a36Sopenharmony_ci cable_len = (msg->body[1] >> 32) & 0xffff; 104462306a36Sopenharmony_ci link_speed = (msg->body[1] >> 48) & 0xffff; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci link_status = msg->body[2] & 0xff; 104762306a36Sopenharmony_ci duplex = (msg->body[2] >> 16) & 0xff; 104862306a36Sopenharmony_ci autoneg = (msg->body[2] >> 24) & 0xff; 104962306a36Sopenharmony_ci lb_status = (msg->body[2] >> 32) & 0x3; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci module = (msg->body[2] >> 8) & 0xff; 105262306a36Sopenharmony_ci if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE) 105362306a36Sopenharmony_ci dev_info(&netdev->dev, 105462306a36Sopenharmony_ci "unsupported cable: OUI 0x%x, length %d\n", 105562306a36Sopenharmony_ci cable_OUI, cable_len); 105662306a36Sopenharmony_ci else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN) 105762306a36Sopenharmony_ci dev_info(&netdev->dev, "unsupported cable length %d\n", 105862306a36Sopenharmony_ci cable_len); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (!link_status && (lb_status == QLCNIC_ILB_MODE || 106162306a36Sopenharmony_ci lb_status == QLCNIC_ELB_MODE)) 106262306a36Sopenharmony_ci adapter->ahw->loopback_state |= QLCNIC_LINKEVENT; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci qlcnic_advert_link_change(adapter, link_status); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (duplex == LINKEVENT_FULL_DUPLEX) 106762306a36Sopenharmony_ci adapter->ahw->link_duplex = DUPLEX_FULL; 106862306a36Sopenharmony_ci else 106962306a36Sopenharmony_ci adapter->ahw->link_duplex = DUPLEX_HALF; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci adapter->ahw->module_type = module; 107262306a36Sopenharmony_ci adapter->ahw->link_autoneg = autoneg; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (link_status) { 107562306a36Sopenharmony_ci adapter->ahw->link_speed = link_speed; 107662306a36Sopenharmony_ci } else { 107762306a36Sopenharmony_ci adapter->ahw->link_speed = SPEED_UNKNOWN; 107862306a36Sopenharmony_ci adapter->ahw->link_duplex = DUPLEX_UNKNOWN; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistatic void qlcnic_handle_fw_message(int desc_cnt, int index, 108362306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci struct qlcnic_fw_msg msg; 108662306a36Sopenharmony_ci struct status_desc *desc; 108762306a36Sopenharmony_ci struct qlcnic_adapter *adapter; 108862306a36Sopenharmony_ci struct device *dev; 108962306a36Sopenharmony_ci int i = 0, opcode, ret; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci while (desc_cnt > 0 && i < 8) { 109262306a36Sopenharmony_ci desc = &sds_ring->desc_head[index]; 109362306a36Sopenharmony_ci msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]); 109462306a36Sopenharmony_ci msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci index = get_next_index(index, sds_ring->num_desc); 109762306a36Sopenharmony_ci desc_cnt--; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci adapter = sds_ring->adapter; 110162306a36Sopenharmony_ci dev = &adapter->pdev->dev; 110262306a36Sopenharmony_ci opcode = qlcnic_get_nic_msg_opcode(msg.body[0]); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci switch (opcode) { 110562306a36Sopenharmony_ci case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE: 110662306a36Sopenharmony_ci qlcnic_handle_linkevent(adapter, &msg); 110762306a36Sopenharmony_ci break; 110862306a36Sopenharmony_ci case QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK: 110962306a36Sopenharmony_ci ret = (u32)(msg.body[1]); 111062306a36Sopenharmony_ci switch (ret) { 111162306a36Sopenharmony_ci case 0: 111262306a36Sopenharmony_ci adapter->ahw->loopback_state |= QLCNIC_LB_RESPONSE; 111362306a36Sopenharmony_ci break; 111462306a36Sopenharmony_ci case 1: 111562306a36Sopenharmony_ci dev_info(dev, "loopback already in progress\n"); 111662306a36Sopenharmony_ci adapter->ahw->diag_cnt = -EINPROGRESS; 111762306a36Sopenharmony_ci break; 111862306a36Sopenharmony_ci case 2: 111962306a36Sopenharmony_ci dev_info(dev, "loopback cable is not connected\n"); 112062306a36Sopenharmony_ci adapter->ahw->diag_cnt = -ENODEV; 112162306a36Sopenharmony_ci break; 112262306a36Sopenharmony_ci default: 112362306a36Sopenharmony_ci dev_info(dev, 112462306a36Sopenharmony_ci "loopback configure request failed, err %x\n", 112562306a36Sopenharmony_ci ret); 112662306a36Sopenharmony_ci adapter->ahw->diag_cnt = -EIO; 112762306a36Sopenharmony_ci break; 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci break; 113062306a36Sopenharmony_ci case QLCNIC_C2H_OPCODE_GET_DCB_AEN: 113162306a36Sopenharmony_ci qlcnic_dcb_aen_handler(adapter->dcb, (void *)&msg); 113262306a36Sopenharmony_ci break; 113362306a36Sopenharmony_ci default: 113462306a36Sopenharmony_ci break; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, 113962306a36Sopenharmony_ci struct qlcnic_host_rds_ring *ring, 114062306a36Sopenharmony_ci u16 index, u16 cksum) 114162306a36Sopenharmony_ci{ 114262306a36Sopenharmony_ci struct qlcnic_rx_buffer *buffer; 114362306a36Sopenharmony_ci struct sk_buff *skb; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci buffer = &ring->rx_buf_arr[index]; 114662306a36Sopenharmony_ci if (unlikely(buffer->skb == NULL)) { 114762306a36Sopenharmony_ci WARN_ON(1); 114862306a36Sopenharmony_ci return NULL; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci dma_unmap_single(&adapter->pdev->dev, buffer->dma, ring->dma_size, 115262306a36Sopenharmony_ci DMA_FROM_DEVICE); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci skb = buffer->skb; 115562306a36Sopenharmony_ci if (likely((adapter->netdev->features & NETIF_F_RXCSUM) && 115662306a36Sopenharmony_ci (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) { 115762306a36Sopenharmony_ci adapter->stats.csummed++; 115862306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 115962306a36Sopenharmony_ci } else { 116062306a36Sopenharmony_ci skb_checksum_none_assert(skb); 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci buffer->skb = NULL; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci return skb; 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cistatic inline int qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, 117062306a36Sopenharmony_ci struct sk_buff *skb, u16 *vlan_tag) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct ethhdr *eth_hdr; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci if (!__vlan_get_tag(skb, vlan_tag)) { 117562306a36Sopenharmony_ci eth_hdr = (struct ethhdr *)skb->data; 117662306a36Sopenharmony_ci memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2); 117762306a36Sopenharmony_ci skb_pull(skb, VLAN_HLEN); 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci if (!adapter->rx_pvid) 118062306a36Sopenharmony_ci return 0; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (*vlan_tag == adapter->rx_pvid) { 118362306a36Sopenharmony_ci /* Outer vlan tag. Packet should follow non-vlan path */ 118462306a36Sopenharmony_ci *vlan_tag = 0xffff; 118562306a36Sopenharmony_ci return 0; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci if (adapter->flags & QLCNIC_TAGGING_ENABLED) 118862306a36Sopenharmony_ci return 0; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci return -EINVAL; 119162306a36Sopenharmony_ci} 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_cistatic struct qlcnic_rx_buffer * 119462306a36Sopenharmony_ciqlcnic_process_rcv(struct qlcnic_adapter *adapter, 119562306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring, int ring, 119662306a36Sopenharmony_ci u64 sts_data0) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 119962306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 120062306a36Sopenharmony_ci struct qlcnic_rx_buffer *buffer; 120162306a36Sopenharmony_ci struct sk_buff *skb; 120262306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 120362306a36Sopenharmony_ci int index, length, cksum, pkt_offset, is_lb_pkt; 120462306a36Sopenharmony_ci u16 vid = 0xffff, t_vid; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci if (unlikely(ring >= adapter->max_rds_rings)) 120762306a36Sopenharmony_ci return NULL; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci rds_ring = &recv_ctx->rds_rings[ring]; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci index = qlcnic_get_sts_refhandle(sts_data0); 121262306a36Sopenharmony_ci if (unlikely(index >= rds_ring->num_desc)) 121362306a36Sopenharmony_ci return NULL; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci buffer = &rds_ring->rx_buf_arr[index]; 121662306a36Sopenharmony_ci length = qlcnic_get_sts_totallength(sts_data0); 121762306a36Sopenharmony_ci cksum = qlcnic_get_sts_status(sts_data0); 121862306a36Sopenharmony_ci pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum); 122162306a36Sopenharmony_ci if (!skb) 122262306a36Sopenharmony_ci return buffer; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if (adapter->rx_mac_learn) { 122562306a36Sopenharmony_ci t_vid = 0; 122662306a36Sopenharmony_ci is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0); 122762306a36Sopenharmony_ci qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if (length > rds_ring->skb_size) 123162306a36Sopenharmony_ci skb_put(skb, rds_ring->skb_size); 123262306a36Sopenharmony_ci else 123362306a36Sopenharmony_ci skb_put(skb, length); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (pkt_offset) 123662306a36Sopenharmony_ci skb_pull(skb, pkt_offset); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { 123962306a36Sopenharmony_ci adapter->stats.rxdropped++; 124062306a36Sopenharmony_ci dev_kfree_skb(skb); 124162306a36Sopenharmony_ci return buffer; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, netdev); 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci if (vid != 0xffff) 124762306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci napi_gro_receive(&sds_ring->napi, skb); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci adapter->stats.rx_pkts++; 125262306a36Sopenharmony_ci adapter->stats.rxbytes += length; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci return buffer; 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci#define QLC_TCP_HDR_SIZE 20 125862306a36Sopenharmony_ci#define QLC_TCP_TS_OPTION_SIZE 12 125962306a36Sopenharmony_ci#define QLC_TCP_TS_HDR_SIZE (QLC_TCP_HDR_SIZE + QLC_TCP_TS_OPTION_SIZE) 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_cistatic struct qlcnic_rx_buffer * 126262306a36Sopenharmony_ciqlcnic_process_lro(struct qlcnic_adapter *adapter, 126362306a36Sopenharmony_ci int ring, u64 sts_data0, u64 sts_data1) 126462306a36Sopenharmony_ci{ 126562306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 126662306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 126762306a36Sopenharmony_ci struct qlcnic_rx_buffer *buffer; 126862306a36Sopenharmony_ci struct sk_buff *skb; 126962306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 127062306a36Sopenharmony_ci struct iphdr *iph; 127162306a36Sopenharmony_ci struct ipv6hdr *ipv6h; 127262306a36Sopenharmony_ci struct tcphdr *th; 127362306a36Sopenharmony_ci bool push, timestamp; 127462306a36Sopenharmony_ci int index, l2_hdr_offset, l4_hdr_offset, is_lb_pkt; 127562306a36Sopenharmony_ci u16 lro_length, length, data_offset, t_vid, vid = 0xffff; 127662306a36Sopenharmony_ci u32 seq_number; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (unlikely(ring >= adapter->max_rds_rings)) 127962306a36Sopenharmony_ci return NULL; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci rds_ring = &recv_ctx->rds_rings[ring]; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci index = qlcnic_get_lro_sts_refhandle(sts_data0); 128462306a36Sopenharmony_ci if (unlikely(index >= rds_ring->num_desc)) 128562306a36Sopenharmony_ci return NULL; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci buffer = &rds_ring->rx_buf_arr[index]; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci timestamp = qlcnic_get_lro_sts_timestamp(sts_data0); 129062306a36Sopenharmony_ci lro_length = qlcnic_get_lro_sts_length(sts_data0); 129162306a36Sopenharmony_ci l2_hdr_offset = qlcnic_get_lro_sts_l2_hdr_offset(sts_data0); 129262306a36Sopenharmony_ci l4_hdr_offset = qlcnic_get_lro_sts_l4_hdr_offset(sts_data0); 129362306a36Sopenharmony_ci push = qlcnic_get_lro_sts_push_flag(sts_data0); 129462306a36Sopenharmony_ci seq_number = qlcnic_get_lro_sts_seq_number(sts_data1); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK); 129762306a36Sopenharmony_ci if (!skb) 129862306a36Sopenharmony_ci return buffer; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci if (adapter->rx_mac_learn) { 130162306a36Sopenharmony_ci t_vid = 0; 130262306a36Sopenharmony_ci is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0); 130362306a36Sopenharmony_ci qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (timestamp) 130762306a36Sopenharmony_ci data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE; 130862306a36Sopenharmony_ci else 130962306a36Sopenharmony_ci data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci skb_put(skb, lro_length + data_offset); 131262306a36Sopenharmony_ci skb_pull(skb, l2_hdr_offset); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { 131562306a36Sopenharmony_ci adapter->stats.rxdropped++; 131662306a36Sopenharmony_ci dev_kfree_skb(skb); 131762306a36Sopenharmony_ci return buffer; 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, netdev); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (ntohs(skb->protocol) == ETH_P_IPV6) { 132362306a36Sopenharmony_ci ipv6h = (struct ipv6hdr *)skb->data; 132462306a36Sopenharmony_ci th = (struct tcphdr *)(skb->data + sizeof(struct ipv6hdr)); 132562306a36Sopenharmony_ci length = (th->doff << 2) + lro_length; 132662306a36Sopenharmony_ci ipv6h->payload_len = htons(length); 132762306a36Sopenharmony_ci } else { 132862306a36Sopenharmony_ci iph = (struct iphdr *)skb->data; 132962306a36Sopenharmony_ci th = (struct tcphdr *)(skb->data + (iph->ihl << 2)); 133062306a36Sopenharmony_ci length = (iph->ihl << 2) + (th->doff << 2) + lro_length; 133162306a36Sopenharmony_ci csum_replace2(&iph->check, iph->tot_len, htons(length)); 133262306a36Sopenharmony_ci iph->tot_len = htons(length); 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci th->psh = push; 133662306a36Sopenharmony_ci th->seq = htonl(seq_number); 133762306a36Sopenharmony_ci length = skb->len; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) { 134062306a36Sopenharmony_ci skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1); 134162306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IPV6)) 134262306a36Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; 134362306a36Sopenharmony_ci else 134462306a36Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci if (vid != 0xffff) 134862306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); 134962306a36Sopenharmony_ci netif_receive_skb(skb); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci adapter->stats.lro_pkts++; 135262306a36Sopenharmony_ci adapter->stats.lrobytes += length; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci return buffer; 135562306a36Sopenharmony_ci} 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_cistatic int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 136062306a36Sopenharmony_ci struct qlcnic_adapter *adapter = sds_ring->adapter; 136162306a36Sopenharmony_ci struct list_head *cur; 136262306a36Sopenharmony_ci struct status_desc *desc; 136362306a36Sopenharmony_ci struct qlcnic_rx_buffer *rxbuf; 136462306a36Sopenharmony_ci int opcode, desc_cnt, count = 0; 136562306a36Sopenharmony_ci u64 sts_data0, sts_data1; 136662306a36Sopenharmony_ci u8 ring; 136762306a36Sopenharmony_ci u32 consumer = sds_ring->consumer; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci while (count < max) { 137062306a36Sopenharmony_ci desc = &sds_ring->desc_head[consumer]; 137162306a36Sopenharmony_ci sts_data0 = le64_to_cpu(desc->status_desc_data[0]); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (!(sts_data0 & STATUS_OWNER_HOST)) 137462306a36Sopenharmony_ci break; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0); 137762306a36Sopenharmony_ci opcode = qlcnic_get_sts_opcode(sts_data0); 137862306a36Sopenharmony_ci switch (opcode) { 137962306a36Sopenharmony_ci case QLCNIC_RXPKT_DESC: 138062306a36Sopenharmony_ci case QLCNIC_OLD_RXPKT_DESC: 138162306a36Sopenharmony_ci case QLCNIC_SYN_OFFLOAD: 138262306a36Sopenharmony_ci ring = qlcnic_get_sts_type(sts_data0); 138362306a36Sopenharmony_ci rxbuf = qlcnic_process_rcv(adapter, sds_ring, ring, 138462306a36Sopenharmony_ci sts_data0); 138562306a36Sopenharmony_ci break; 138662306a36Sopenharmony_ci case QLCNIC_LRO_DESC: 138762306a36Sopenharmony_ci ring = qlcnic_get_lro_sts_type(sts_data0); 138862306a36Sopenharmony_ci sts_data1 = le64_to_cpu(desc->status_desc_data[1]); 138962306a36Sopenharmony_ci rxbuf = qlcnic_process_lro(adapter, ring, sts_data0, 139062306a36Sopenharmony_ci sts_data1); 139162306a36Sopenharmony_ci break; 139262306a36Sopenharmony_ci case QLCNIC_RESPONSE_DESC: 139362306a36Sopenharmony_ci qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring); 139462306a36Sopenharmony_ci goto skip; 139562306a36Sopenharmony_ci default: 139662306a36Sopenharmony_ci goto skip; 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci WARN_ON(desc_cnt > 1); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (likely(rxbuf)) 140162306a36Sopenharmony_ci list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); 140262306a36Sopenharmony_ci else 140362306a36Sopenharmony_ci adapter->stats.null_rxbuf++; 140462306a36Sopenharmony_ciskip: 140562306a36Sopenharmony_ci for (; desc_cnt > 0; desc_cnt--) { 140662306a36Sopenharmony_ci desc = &sds_ring->desc_head[consumer]; 140762306a36Sopenharmony_ci desc->status_desc_data[0] = QLCNIC_DESC_OWNER_FW; 140862306a36Sopenharmony_ci consumer = get_next_index(consumer, sds_ring->num_desc); 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci count++; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci for (ring = 0; ring < adapter->max_rds_rings; ring++) { 141462306a36Sopenharmony_ci rds_ring = &adapter->recv_ctx->rds_rings[ring]; 141562306a36Sopenharmony_ci if (!list_empty(&sds_ring->free_list[ring])) { 141662306a36Sopenharmony_ci list_for_each(cur, &sds_ring->free_list[ring]) { 141762306a36Sopenharmony_ci rxbuf = list_entry(cur, struct qlcnic_rx_buffer, 141862306a36Sopenharmony_ci list); 141962306a36Sopenharmony_ci qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf); 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci spin_lock(&rds_ring->lock); 142262306a36Sopenharmony_ci list_splice_tail_init(&sds_ring->free_list[ring], 142362306a36Sopenharmony_ci &rds_ring->free_list); 142462306a36Sopenharmony_ci spin_unlock(&rds_ring->lock); 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci qlcnic_post_rx_buffers_nodb(adapter, rds_ring, ring); 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci if (count) { 143162306a36Sopenharmony_ci sds_ring->consumer = consumer; 143262306a36Sopenharmony_ci writel(consumer, sds_ring->crb_sts_consumer); 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci return count; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_civoid qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, 143962306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring, u8 ring_id) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci struct rcv_desc *pdesc; 144262306a36Sopenharmony_ci struct qlcnic_rx_buffer *buffer; 144362306a36Sopenharmony_ci int count = 0; 144462306a36Sopenharmony_ci u32 producer, handle; 144562306a36Sopenharmony_ci struct list_head *head; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci producer = rds_ring->producer; 144862306a36Sopenharmony_ci head = &rds_ring->free_list; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci while (!list_empty(head)) { 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci buffer = list_entry(head->next, struct qlcnic_rx_buffer, list); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci if (!buffer->skb) { 145562306a36Sopenharmony_ci if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer)) 145662306a36Sopenharmony_ci break; 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci count++; 146062306a36Sopenharmony_ci list_del(&buffer->list); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci /* make a rcv descriptor */ 146362306a36Sopenharmony_ci pdesc = &rds_ring->desc_head[producer]; 146462306a36Sopenharmony_ci pdesc->addr_buffer = cpu_to_le64(buffer->dma); 146562306a36Sopenharmony_ci handle = qlcnic_get_ref_handle(adapter, buffer->ref_handle, 146662306a36Sopenharmony_ci ring_id); 146762306a36Sopenharmony_ci pdesc->reference_handle = cpu_to_le16(handle); 146862306a36Sopenharmony_ci pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size); 146962306a36Sopenharmony_ci producer = get_next_index(producer, rds_ring->num_desc); 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (count) { 147362306a36Sopenharmony_ci rds_ring->producer = producer; 147462306a36Sopenharmony_ci writel((producer-1) & (rds_ring->num_desc-1), 147562306a36Sopenharmony_ci rds_ring->crb_rcv_producer); 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci} 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_cistatic void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter) 148062306a36Sopenharmony_ci{ 148162306a36Sopenharmony_ci if (adapter->ahw->msg_enable & NETIF_MSG_DRV) { 148262306a36Sopenharmony_ci char prefix[30]; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci scnprintf(prefix, sizeof(prefix), "%s: %s: ", 148562306a36Sopenharmony_ci dev_name(&adapter->pdev->dev), __func__); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci print_hex_dump_debug(prefix, DUMP_PREFIX_NONE, 16, 1, 148862306a36Sopenharmony_ci skb->data, skb->len, true); 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci} 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_cistatic void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, int ring, 149362306a36Sopenharmony_ci u64 sts_data0) 149462306a36Sopenharmony_ci{ 149562306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 149662306a36Sopenharmony_ci struct sk_buff *skb; 149762306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 149862306a36Sopenharmony_ci int index, length, cksum, pkt_offset; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (unlikely(ring >= adapter->max_rds_rings)) 150162306a36Sopenharmony_ci return; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci rds_ring = &recv_ctx->rds_rings[ring]; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci index = qlcnic_get_sts_refhandle(sts_data0); 150662306a36Sopenharmony_ci length = qlcnic_get_sts_totallength(sts_data0); 150762306a36Sopenharmony_ci if (unlikely(index >= rds_ring->num_desc)) 150862306a36Sopenharmony_ci return; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci cksum = qlcnic_get_sts_status(sts_data0); 151162306a36Sopenharmony_ci pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum); 151462306a36Sopenharmony_ci if (!skb) 151562306a36Sopenharmony_ci return; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (length > rds_ring->skb_size) 151862306a36Sopenharmony_ci skb_put(skb, rds_ring->skb_size); 151962306a36Sopenharmony_ci else 152062306a36Sopenharmony_ci skb_put(skb, length); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci if (pkt_offset) 152362306a36Sopenharmony_ci skb_pull(skb, pkt_offset); 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr)) 152662306a36Sopenharmony_ci adapter->ahw->diag_cnt++; 152762306a36Sopenharmony_ci else 152862306a36Sopenharmony_ci dump_skb(skb, adapter); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci dev_kfree_skb_any(skb); 153162306a36Sopenharmony_ci adapter->stats.rx_pkts++; 153262306a36Sopenharmony_ci adapter->stats.rxbytes += length; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci return; 153562306a36Sopenharmony_ci} 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_civoid qlcnic_82xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci struct qlcnic_adapter *adapter = sds_ring->adapter; 154062306a36Sopenharmony_ci struct status_desc *desc; 154162306a36Sopenharmony_ci u64 sts_data0; 154262306a36Sopenharmony_ci int ring, opcode, desc_cnt; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci u32 consumer = sds_ring->consumer; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci desc = &sds_ring->desc_head[consumer]; 154762306a36Sopenharmony_ci sts_data0 = le64_to_cpu(desc->status_desc_data[0]); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci if (!(sts_data0 & STATUS_OWNER_HOST)) 155062306a36Sopenharmony_ci return; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0); 155362306a36Sopenharmony_ci opcode = qlcnic_get_sts_opcode(sts_data0); 155462306a36Sopenharmony_ci switch (opcode) { 155562306a36Sopenharmony_ci case QLCNIC_RESPONSE_DESC: 155662306a36Sopenharmony_ci qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring); 155762306a36Sopenharmony_ci break; 155862306a36Sopenharmony_ci default: 155962306a36Sopenharmony_ci ring = qlcnic_get_sts_type(sts_data0); 156062306a36Sopenharmony_ci qlcnic_process_rcv_diag(adapter, ring, sts_data0); 156162306a36Sopenharmony_ci break; 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci for (; desc_cnt > 0; desc_cnt--) { 156562306a36Sopenharmony_ci desc = &sds_ring->desc_head[consumer]; 156662306a36Sopenharmony_ci desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM); 156762306a36Sopenharmony_ci consumer = get_next_index(consumer, sds_ring->num_desc); 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci sds_ring->consumer = consumer; 157162306a36Sopenharmony_ci writel(consumer, sds_ring->crb_sts_consumer); 157262306a36Sopenharmony_ci} 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ciint qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter, 157562306a36Sopenharmony_ci struct net_device *netdev) 157662306a36Sopenharmony_ci{ 157762306a36Sopenharmony_ci int ring; 157862306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 157962306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 158062306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci if (qlcnic_alloc_sds_rings(recv_ctx, adapter->drv_sds_rings)) 158362306a36Sopenharmony_ci return -ENOMEM; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 158662306a36Sopenharmony_ci sds_ring = &recv_ctx->sds_rings[ring]; 158762306a36Sopenharmony_ci if (qlcnic_check_multi_tx(adapter) && 158862306a36Sopenharmony_ci !adapter->ahw->diag_test) { 158962306a36Sopenharmony_ci netif_napi_add(netdev, &sds_ring->napi, 159062306a36Sopenharmony_ci qlcnic_rx_poll); 159162306a36Sopenharmony_ci } else { 159262306a36Sopenharmony_ci if (ring == (adapter->drv_sds_rings - 1)) 159362306a36Sopenharmony_ci netif_napi_add(netdev, &sds_ring->napi, 159462306a36Sopenharmony_ci qlcnic_poll); 159562306a36Sopenharmony_ci else 159662306a36Sopenharmony_ci netif_napi_add(netdev, &sds_ring->napi, 159762306a36Sopenharmony_ci qlcnic_rx_poll); 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (qlcnic_alloc_tx_rings(adapter, netdev)) { 160262306a36Sopenharmony_ci qlcnic_free_sds_rings(recv_ctx); 160362306a36Sopenharmony_ci return -ENOMEM; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test) { 160762306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 160862306a36Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 160962306a36Sopenharmony_ci netif_napi_add_tx(netdev, &tx_ring->napi, 161062306a36Sopenharmony_ci qlcnic_tx_poll); 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci return 0; 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_civoid qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter) 161862306a36Sopenharmony_ci{ 161962306a36Sopenharmony_ci int ring; 162062306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 162162306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 162262306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 162562306a36Sopenharmony_ci sds_ring = &recv_ctx->sds_rings[ring]; 162662306a36Sopenharmony_ci netif_napi_del(&sds_ring->napi); 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci qlcnic_free_sds_rings(adapter->recv_ctx); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test) { 163262306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 163362306a36Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 163462306a36Sopenharmony_ci netif_napi_del(&tx_ring->napi); 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci qlcnic_free_tx_rings(adapter); 163962306a36Sopenharmony_ci} 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_civoid qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter) 164262306a36Sopenharmony_ci{ 164362306a36Sopenharmony_ci int ring; 164462306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 164562306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 164662306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) 164962306a36Sopenharmony_ci return; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 165262306a36Sopenharmony_ci sds_ring = &recv_ctx->sds_rings[ring]; 165362306a36Sopenharmony_ci napi_enable(&sds_ring->napi); 165462306a36Sopenharmony_ci qlcnic_enable_sds_intr(adapter, sds_ring); 165562306a36Sopenharmony_ci } 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci if (qlcnic_check_multi_tx(adapter) && 165862306a36Sopenharmony_ci (adapter->flags & QLCNIC_MSIX_ENABLED) && 165962306a36Sopenharmony_ci !adapter->ahw->diag_test) { 166062306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 166162306a36Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 166262306a36Sopenharmony_ci napi_enable(&tx_ring->napi); 166362306a36Sopenharmony_ci qlcnic_enable_tx_intr(adapter, tx_ring); 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci} 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_civoid qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter) 166962306a36Sopenharmony_ci{ 167062306a36Sopenharmony_ci int ring; 167162306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 167262306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 167362306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) 167662306a36Sopenharmony_ci return; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 167962306a36Sopenharmony_ci sds_ring = &recv_ctx->sds_rings[ring]; 168062306a36Sopenharmony_ci qlcnic_disable_sds_intr(adapter, sds_ring); 168162306a36Sopenharmony_ci napi_synchronize(&sds_ring->napi); 168262306a36Sopenharmony_ci napi_disable(&sds_ring->napi); 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci if ((adapter->flags & QLCNIC_MSIX_ENABLED) && 168662306a36Sopenharmony_ci !adapter->ahw->diag_test && 168762306a36Sopenharmony_ci qlcnic_check_multi_tx(adapter)) { 168862306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 168962306a36Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 169062306a36Sopenharmony_ci qlcnic_disable_tx_intr(adapter, tx_ring); 169162306a36Sopenharmony_ci napi_synchronize(&tx_ring->napi); 169262306a36Sopenharmony_ci napi_disable(&tx_ring->napi); 169362306a36Sopenharmony_ci } 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci} 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci#define QLC_83XX_NORMAL_LB_PKT (1ULL << 36) 169862306a36Sopenharmony_ci#define QLC_83XX_LRO_LB_PKT (1ULL << 46) 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_cistatic inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt) 170162306a36Sopenharmony_ci{ 170262306a36Sopenharmony_ci if (lro_pkt) 170362306a36Sopenharmony_ci return (sts_data & QLC_83XX_LRO_LB_PKT) ? 1 : 0; 170462306a36Sopenharmony_ci else 170562306a36Sopenharmony_ci return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0; 170662306a36Sopenharmony_ci} 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci#define QLCNIC_ENCAP_LENGTH_MASK 0x7f 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_cistatic inline u8 qlcnic_encap_length(u64 sts_data) 171162306a36Sopenharmony_ci{ 171262306a36Sopenharmony_ci return sts_data & QLCNIC_ENCAP_LENGTH_MASK; 171362306a36Sopenharmony_ci} 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_cistatic struct qlcnic_rx_buffer * 171662306a36Sopenharmony_ciqlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, 171762306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring, 171862306a36Sopenharmony_ci u8 ring, u64 sts_data[]) 171962306a36Sopenharmony_ci{ 172062306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 172162306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 172262306a36Sopenharmony_ci struct qlcnic_rx_buffer *buffer; 172362306a36Sopenharmony_ci struct sk_buff *skb; 172462306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 172562306a36Sopenharmony_ci int index, length, cksum, is_lb_pkt; 172662306a36Sopenharmony_ci u16 vid = 0xffff; 172762306a36Sopenharmony_ci int err; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci if (unlikely(ring >= adapter->max_rds_rings)) 173062306a36Sopenharmony_ci return NULL; 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci rds_ring = &recv_ctx->rds_rings[ring]; 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci index = qlcnic_83xx_hndl(sts_data[0]); 173562306a36Sopenharmony_ci if (unlikely(index >= rds_ring->num_desc)) 173662306a36Sopenharmony_ci return NULL; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci buffer = &rds_ring->rx_buf_arr[index]; 173962306a36Sopenharmony_ci length = qlcnic_83xx_pktln(sts_data[0]); 174062306a36Sopenharmony_ci cksum = qlcnic_83xx_csum_status(sts_data[1]); 174162306a36Sopenharmony_ci skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum); 174262306a36Sopenharmony_ci if (!skb) 174362306a36Sopenharmony_ci return buffer; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci if (length > rds_ring->skb_size) 174662306a36Sopenharmony_ci skb_put(skb, rds_ring->skb_size); 174762306a36Sopenharmony_ci else 174862306a36Sopenharmony_ci skb_put(skb, length); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci err = qlcnic_check_rx_tagging(adapter, skb, &vid); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (adapter->rx_mac_learn) { 175362306a36Sopenharmony_ci is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); 175462306a36Sopenharmony_ci qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci if (unlikely(err)) { 175862306a36Sopenharmony_ci adapter->stats.rxdropped++; 175962306a36Sopenharmony_ci dev_kfree_skb(skb); 176062306a36Sopenharmony_ci return buffer; 176162306a36Sopenharmony_ci } 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, netdev); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci if (qlcnic_encap_length(sts_data[1]) && 176662306a36Sopenharmony_ci skb->ip_summed == CHECKSUM_UNNECESSARY) { 176762306a36Sopenharmony_ci skb->csum_level = 1; 176862306a36Sopenharmony_ci adapter->stats.encap_rx_csummed++; 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci if (vid != 0xffff) 177262306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci napi_gro_receive(&sds_ring->napi, skb); 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci adapter->stats.rx_pkts++; 177762306a36Sopenharmony_ci adapter->stats.rxbytes += length; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci return buffer; 178062306a36Sopenharmony_ci} 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_cistatic struct qlcnic_rx_buffer * 178362306a36Sopenharmony_ciqlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, 178462306a36Sopenharmony_ci u8 ring, u64 sts_data[]) 178562306a36Sopenharmony_ci{ 178662306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 178762306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 178862306a36Sopenharmony_ci struct qlcnic_rx_buffer *buffer; 178962306a36Sopenharmony_ci struct sk_buff *skb; 179062306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 179162306a36Sopenharmony_ci struct iphdr *iph; 179262306a36Sopenharmony_ci struct ipv6hdr *ipv6h; 179362306a36Sopenharmony_ci struct tcphdr *th; 179462306a36Sopenharmony_ci bool push; 179562306a36Sopenharmony_ci int l2_hdr_offset, l4_hdr_offset; 179662306a36Sopenharmony_ci int index, is_lb_pkt; 179762306a36Sopenharmony_ci u16 lro_length, length, data_offset, gso_size; 179862306a36Sopenharmony_ci u16 vid = 0xffff; 179962306a36Sopenharmony_ci int err; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci if (unlikely(ring >= adapter->max_rds_rings)) 180262306a36Sopenharmony_ci return NULL; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci rds_ring = &recv_ctx->rds_rings[ring]; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci index = qlcnic_83xx_hndl(sts_data[0]); 180762306a36Sopenharmony_ci if (unlikely(index >= rds_ring->num_desc)) 180862306a36Sopenharmony_ci return NULL; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci buffer = &rds_ring->rx_buf_arr[index]; 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci lro_length = qlcnic_83xx_lro_pktln(sts_data[0]); 181362306a36Sopenharmony_ci l2_hdr_offset = qlcnic_83xx_l2_hdr_off(sts_data[1]); 181462306a36Sopenharmony_ci l4_hdr_offset = qlcnic_83xx_l4_hdr_off(sts_data[1]); 181562306a36Sopenharmony_ci push = qlcnic_83xx_is_psh_bit(sts_data[1]); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK); 181862306a36Sopenharmony_ci if (!skb) 181962306a36Sopenharmony_ci return buffer; 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci if (qlcnic_83xx_is_tstamp(sts_data[1])) 182262306a36Sopenharmony_ci data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE; 182362306a36Sopenharmony_ci else 182462306a36Sopenharmony_ci data_offset = l4_hdr_offset + QLCNIC_TCP_HDR_SIZE; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci skb_put(skb, lro_length + data_offset); 182762306a36Sopenharmony_ci skb_pull(skb, l2_hdr_offset); 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci err = qlcnic_check_rx_tagging(adapter, skb, &vid); 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci if (adapter->rx_mac_learn) { 183262306a36Sopenharmony_ci is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); 183362306a36Sopenharmony_ci qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); 183462306a36Sopenharmony_ci } 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci if (unlikely(err)) { 183762306a36Sopenharmony_ci adapter->stats.rxdropped++; 183862306a36Sopenharmony_ci dev_kfree_skb(skb); 183962306a36Sopenharmony_ci return buffer; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, netdev); 184362306a36Sopenharmony_ci if (ntohs(skb->protocol) == ETH_P_IPV6) { 184462306a36Sopenharmony_ci ipv6h = (struct ipv6hdr *)skb->data; 184562306a36Sopenharmony_ci th = (struct tcphdr *)(skb->data + sizeof(struct ipv6hdr)); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci length = (th->doff << 2) + lro_length; 184862306a36Sopenharmony_ci ipv6h->payload_len = htons(length); 184962306a36Sopenharmony_ci } else { 185062306a36Sopenharmony_ci iph = (struct iphdr *)skb->data; 185162306a36Sopenharmony_ci th = (struct tcphdr *)(skb->data + (iph->ihl << 2)); 185262306a36Sopenharmony_ci length = (iph->ihl << 2) + (th->doff << 2) + lro_length; 185362306a36Sopenharmony_ci csum_replace2(&iph->check, iph->tot_len, htons(length)); 185462306a36Sopenharmony_ci iph->tot_len = htons(length); 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci th->psh = push; 185862306a36Sopenharmony_ci length = skb->len; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) { 186162306a36Sopenharmony_ci gso_size = qlcnic_83xx_get_lro_sts_mss(sts_data[0]); 186262306a36Sopenharmony_ci skb_shinfo(skb)->gso_size = gso_size; 186362306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IPV6)) 186462306a36Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; 186562306a36Sopenharmony_ci else 186662306a36Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci if (vid != 0xffff) 187062306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci netif_receive_skb(skb); 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci adapter->stats.lro_pkts++; 187562306a36Sopenharmony_ci adapter->stats.lrobytes += length; 187662306a36Sopenharmony_ci return buffer; 187762306a36Sopenharmony_ci} 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_cistatic int qlcnic_83xx_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, 188062306a36Sopenharmony_ci int max) 188162306a36Sopenharmony_ci{ 188262306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 188362306a36Sopenharmony_ci struct qlcnic_adapter *adapter = sds_ring->adapter; 188462306a36Sopenharmony_ci struct list_head *cur; 188562306a36Sopenharmony_ci struct status_desc *desc; 188662306a36Sopenharmony_ci struct qlcnic_rx_buffer *rxbuf = NULL; 188762306a36Sopenharmony_ci u8 ring; 188862306a36Sopenharmony_ci u64 sts_data[2]; 188962306a36Sopenharmony_ci int count = 0, opcode; 189062306a36Sopenharmony_ci u32 consumer = sds_ring->consumer; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci while (count < max) { 189362306a36Sopenharmony_ci desc = &sds_ring->desc_head[consumer]; 189462306a36Sopenharmony_ci sts_data[1] = le64_to_cpu(desc->status_desc_data[1]); 189562306a36Sopenharmony_ci opcode = qlcnic_83xx_opcode(sts_data[1]); 189662306a36Sopenharmony_ci if (!opcode) 189762306a36Sopenharmony_ci break; 189862306a36Sopenharmony_ci sts_data[0] = le64_to_cpu(desc->status_desc_data[0]); 189962306a36Sopenharmony_ci ring = QLCNIC_FETCH_RING_ID(sts_data[0]); 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci switch (opcode) { 190262306a36Sopenharmony_ci case QLC_83XX_REG_DESC: 190362306a36Sopenharmony_ci rxbuf = qlcnic_83xx_process_rcv(adapter, sds_ring, 190462306a36Sopenharmony_ci ring, sts_data); 190562306a36Sopenharmony_ci break; 190662306a36Sopenharmony_ci case QLC_83XX_LRO_DESC: 190762306a36Sopenharmony_ci rxbuf = qlcnic_83xx_process_lro(adapter, ring, 190862306a36Sopenharmony_ci sts_data); 190962306a36Sopenharmony_ci break; 191062306a36Sopenharmony_ci default: 191162306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, 191262306a36Sopenharmony_ci "Unknown opcode: 0x%x\n", opcode); 191362306a36Sopenharmony_ci goto skip; 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci if (likely(rxbuf)) 191762306a36Sopenharmony_ci list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); 191862306a36Sopenharmony_ci else 191962306a36Sopenharmony_ci adapter->stats.null_rxbuf++; 192062306a36Sopenharmony_ciskip: 192162306a36Sopenharmony_ci desc = &sds_ring->desc_head[consumer]; 192262306a36Sopenharmony_ci /* Reset the descriptor */ 192362306a36Sopenharmony_ci desc->status_desc_data[1] = 0; 192462306a36Sopenharmony_ci consumer = get_next_index(consumer, sds_ring->num_desc); 192562306a36Sopenharmony_ci count++; 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci for (ring = 0; ring < adapter->max_rds_rings; ring++) { 192862306a36Sopenharmony_ci rds_ring = &adapter->recv_ctx->rds_rings[ring]; 192962306a36Sopenharmony_ci if (!list_empty(&sds_ring->free_list[ring])) { 193062306a36Sopenharmony_ci list_for_each(cur, &sds_ring->free_list[ring]) { 193162306a36Sopenharmony_ci rxbuf = list_entry(cur, struct qlcnic_rx_buffer, 193262306a36Sopenharmony_ci list); 193362306a36Sopenharmony_ci qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf); 193462306a36Sopenharmony_ci } 193562306a36Sopenharmony_ci spin_lock(&rds_ring->lock); 193662306a36Sopenharmony_ci list_splice_tail_init(&sds_ring->free_list[ring], 193762306a36Sopenharmony_ci &rds_ring->free_list); 193862306a36Sopenharmony_ci spin_unlock(&rds_ring->lock); 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci qlcnic_post_rx_buffers_nodb(adapter, rds_ring, ring); 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci if (count) { 194362306a36Sopenharmony_ci sds_ring->consumer = consumer; 194462306a36Sopenharmony_ci writel(consumer, sds_ring->crb_sts_consumer); 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci return count; 194762306a36Sopenharmony_ci} 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_cistatic int qlcnic_83xx_msix_sriov_vf_poll(struct napi_struct *napi, int budget) 195062306a36Sopenharmony_ci{ 195162306a36Sopenharmony_ci int tx_complete; 195262306a36Sopenharmony_ci int work_done; 195362306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 195462306a36Sopenharmony_ci struct qlcnic_adapter *adapter; 195562306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi); 195862306a36Sopenharmony_ci adapter = sds_ring->adapter; 195962306a36Sopenharmony_ci /* tx ring count = 1 */ 196062306a36Sopenharmony_ci tx_ring = adapter->tx_ring; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget); 196362306a36Sopenharmony_ci work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci /* Check if we need a repoll */ 196662306a36Sopenharmony_ci if (!tx_complete) 196762306a36Sopenharmony_ci work_done = budget; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci if (work_done < budget) { 197062306a36Sopenharmony_ci napi_complete_done(&sds_ring->napi, work_done); 197162306a36Sopenharmony_ci qlcnic_enable_sds_intr(adapter, sds_ring); 197262306a36Sopenharmony_ci } 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci return work_done; 197562306a36Sopenharmony_ci} 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_cistatic int qlcnic_83xx_poll(struct napi_struct *napi, int budget) 197862306a36Sopenharmony_ci{ 197962306a36Sopenharmony_ci int tx_complete; 198062306a36Sopenharmony_ci int work_done; 198162306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 198262306a36Sopenharmony_ci struct qlcnic_adapter *adapter; 198362306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi); 198662306a36Sopenharmony_ci adapter = sds_ring->adapter; 198762306a36Sopenharmony_ci /* tx ring count = 1 */ 198862306a36Sopenharmony_ci tx_ring = adapter->tx_ring; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget); 199162306a36Sopenharmony_ci work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci /* Check if we need a repoll */ 199462306a36Sopenharmony_ci if (!tx_complete) 199562306a36Sopenharmony_ci work_done = budget; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci if (work_done < budget) { 199862306a36Sopenharmony_ci napi_complete_done(&sds_ring->napi, work_done); 199962306a36Sopenharmony_ci qlcnic_enable_sds_intr(adapter, sds_ring); 200062306a36Sopenharmony_ci } 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci return work_done; 200362306a36Sopenharmony_ci} 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_cistatic int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget) 200662306a36Sopenharmony_ci{ 200762306a36Sopenharmony_ci int work_done; 200862306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 200962306a36Sopenharmony_ci struct qlcnic_adapter *adapter; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci tx_ring = container_of(napi, struct qlcnic_host_tx_ring, napi); 201262306a36Sopenharmony_ci adapter = tx_ring->adapter; 201362306a36Sopenharmony_ci work_done = qlcnic_process_cmd_ring(adapter, tx_ring, budget); 201462306a36Sopenharmony_ci if (work_done) { 201562306a36Sopenharmony_ci napi_complete(&tx_ring->napi); 201662306a36Sopenharmony_ci if (test_bit(__QLCNIC_DEV_UP , &adapter->state)) 201762306a36Sopenharmony_ci qlcnic_enable_tx_intr(adapter, tx_ring); 201862306a36Sopenharmony_ci } else { 201962306a36Sopenharmony_ci /* need a repoll */ 202062306a36Sopenharmony_ci work_done = budget; 202162306a36Sopenharmony_ci } 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci return work_done; 202462306a36Sopenharmony_ci} 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_cistatic int qlcnic_83xx_rx_poll(struct napi_struct *napi, int budget) 202762306a36Sopenharmony_ci{ 202862306a36Sopenharmony_ci int work_done; 202962306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 203062306a36Sopenharmony_ci struct qlcnic_adapter *adapter; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi); 203362306a36Sopenharmony_ci adapter = sds_ring->adapter; 203462306a36Sopenharmony_ci work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget); 203562306a36Sopenharmony_ci if (work_done < budget) { 203662306a36Sopenharmony_ci napi_complete_done(&sds_ring->napi, work_done); 203762306a36Sopenharmony_ci if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) 203862306a36Sopenharmony_ci qlcnic_enable_sds_intr(adapter, sds_ring); 203962306a36Sopenharmony_ci } 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci return work_done; 204262306a36Sopenharmony_ci} 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_civoid qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter) 204562306a36Sopenharmony_ci{ 204662306a36Sopenharmony_ci int ring; 204762306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 204862306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 204962306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) 205262306a36Sopenharmony_ci return; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 205562306a36Sopenharmony_ci sds_ring = &recv_ctx->sds_rings[ring]; 205662306a36Sopenharmony_ci napi_enable(&sds_ring->napi); 205762306a36Sopenharmony_ci if (adapter->flags & QLCNIC_MSIX_ENABLED) 205862306a36Sopenharmony_ci qlcnic_enable_sds_intr(adapter, sds_ring); 205962306a36Sopenharmony_ci } 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci if ((adapter->flags & QLCNIC_MSIX_ENABLED) && 206262306a36Sopenharmony_ci !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { 206362306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 206462306a36Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 206562306a36Sopenharmony_ci napi_enable(&tx_ring->napi); 206662306a36Sopenharmony_ci qlcnic_enable_tx_intr(adapter, tx_ring); 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci } 206962306a36Sopenharmony_ci} 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_civoid qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter) 207262306a36Sopenharmony_ci{ 207362306a36Sopenharmony_ci int ring; 207462306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 207562306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 207662306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) 207962306a36Sopenharmony_ci return; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 208262306a36Sopenharmony_ci sds_ring = &recv_ctx->sds_rings[ring]; 208362306a36Sopenharmony_ci if (adapter->flags & QLCNIC_MSIX_ENABLED) 208462306a36Sopenharmony_ci qlcnic_disable_sds_intr(adapter, sds_ring); 208562306a36Sopenharmony_ci napi_synchronize(&sds_ring->napi); 208662306a36Sopenharmony_ci napi_disable(&sds_ring->napi); 208762306a36Sopenharmony_ci } 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci if ((adapter->flags & QLCNIC_MSIX_ENABLED) && 209062306a36Sopenharmony_ci !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { 209162306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 209262306a36Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 209362306a36Sopenharmony_ci qlcnic_disable_tx_intr(adapter, tx_ring); 209462306a36Sopenharmony_ci napi_synchronize(&tx_ring->napi); 209562306a36Sopenharmony_ci napi_disable(&tx_ring->napi); 209662306a36Sopenharmony_ci } 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci} 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ciint qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter, 210162306a36Sopenharmony_ci struct net_device *netdev) 210262306a36Sopenharmony_ci{ 210362306a36Sopenharmony_ci int ring; 210462306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 210562306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 210662306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci if (qlcnic_alloc_sds_rings(recv_ctx, adapter->drv_sds_rings)) 210962306a36Sopenharmony_ci return -ENOMEM; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 211262306a36Sopenharmony_ci sds_ring = &recv_ctx->sds_rings[ring]; 211362306a36Sopenharmony_ci if (adapter->flags & QLCNIC_MSIX_ENABLED) { 211462306a36Sopenharmony_ci if (!(adapter->flags & QLCNIC_TX_INTR_SHARED)) 211562306a36Sopenharmony_ci netif_napi_add(netdev, &sds_ring->napi, 211662306a36Sopenharmony_ci qlcnic_83xx_rx_poll); 211762306a36Sopenharmony_ci else 211862306a36Sopenharmony_ci netif_napi_add(netdev, &sds_ring->napi, 211962306a36Sopenharmony_ci qlcnic_83xx_msix_sriov_vf_poll); 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci } else { 212262306a36Sopenharmony_ci netif_napi_add(netdev, &sds_ring->napi, 212362306a36Sopenharmony_ci qlcnic_83xx_poll); 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci } 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci if (qlcnic_alloc_tx_rings(adapter, netdev)) { 212862306a36Sopenharmony_ci qlcnic_free_sds_rings(recv_ctx); 212962306a36Sopenharmony_ci return -ENOMEM; 213062306a36Sopenharmony_ci } 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci if ((adapter->flags & QLCNIC_MSIX_ENABLED) && 213362306a36Sopenharmony_ci !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { 213462306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 213562306a36Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 213662306a36Sopenharmony_ci netif_napi_add_tx(netdev, &tx_ring->napi, 213762306a36Sopenharmony_ci qlcnic_83xx_msix_tx_poll); 213862306a36Sopenharmony_ci } 213962306a36Sopenharmony_ci } 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci return 0; 214262306a36Sopenharmony_ci} 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_civoid qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter) 214562306a36Sopenharmony_ci{ 214662306a36Sopenharmony_ci int ring; 214762306a36Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 214862306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 214962306a36Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 215262306a36Sopenharmony_ci sds_ring = &recv_ctx->sds_rings[ring]; 215362306a36Sopenharmony_ci netif_napi_del(&sds_ring->napi); 215462306a36Sopenharmony_ci } 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci qlcnic_free_sds_rings(adapter->recv_ctx); 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci if ((adapter->flags & QLCNIC_MSIX_ENABLED) && 215962306a36Sopenharmony_ci !(adapter->flags & QLCNIC_TX_INTR_SHARED)) { 216062306a36Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 216162306a36Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 216262306a36Sopenharmony_ci netif_napi_del(&tx_ring->napi); 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci } 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci qlcnic_free_tx_rings(adapter); 216762306a36Sopenharmony_ci} 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_cistatic void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter, 217062306a36Sopenharmony_ci int ring, u64 sts_data[]) 217162306a36Sopenharmony_ci{ 217262306a36Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 217362306a36Sopenharmony_ci struct sk_buff *skb; 217462306a36Sopenharmony_ci struct qlcnic_host_rds_ring *rds_ring; 217562306a36Sopenharmony_ci int index, length; 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci if (unlikely(ring >= adapter->max_rds_rings)) 217862306a36Sopenharmony_ci return; 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci rds_ring = &recv_ctx->rds_rings[ring]; 218162306a36Sopenharmony_ci index = qlcnic_83xx_hndl(sts_data[0]); 218262306a36Sopenharmony_ci if (unlikely(index >= rds_ring->num_desc)) 218362306a36Sopenharmony_ci return; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci length = qlcnic_83xx_pktln(sts_data[0]); 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK); 218862306a36Sopenharmony_ci if (!skb) 218962306a36Sopenharmony_ci return; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci if (length > rds_ring->skb_size) 219262306a36Sopenharmony_ci skb_put(skb, rds_ring->skb_size); 219362306a36Sopenharmony_ci else 219462306a36Sopenharmony_ci skb_put(skb, length); 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr)) 219762306a36Sopenharmony_ci adapter->ahw->diag_cnt++; 219862306a36Sopenharmony_ci else 219962306a36Sopenharmony_ci dump_skb(skb, adapter); 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 220262306a36Sopenharmony_ci return; 220362306a36Sopenharmony_ci} 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_civoid qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring) 220662306a36Sopenharmony_ci{ 220762306a36Sopenharmony_ci struct qlcnic_adapter *adapter = sds_ring->adapter; 220862306a36Sopenharmony_ci struct status_desc *desc; 220962306a36Sopenharmony_ci u64 sts_data[2]; 221062306a36Sopenharmony_ci int ring, opcode; 221162306a36Sopenharmony_ci u32 consumer = sds_ring->consumer; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci desc = &sds_ring->desc_head[consumer]; 221462306a36Sopenharmony_ci sts_data[0] = le64_to_cpu(desc->status_desc_data[0]); 221562306a36Sopenharmony_ci sts_data[1] = le64_to_cpu(desc->status_desc_data[1]); 221662306a36Sopenharmony_ci opcode = qlcnic_83xx_opcode(sts_data[1]); 221762306a36Sopenharmony_ci if (!opcode) 221862306a36Sopenharmony_ci return; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci ring = QLCNIC_FETCH_RING_ID(sts_data[0]); 222162306a36Sopenharmony_ci qlcnic_83xx_process_rcv_diag(adapter, ring, sts_data); 222262306a36Sopenharmony_ci desc = &sds_ring->desc_head[consumer]; 222362306a36Sopenharmony_ci desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM); 222462306a36Sopenharmony_ci consumer = get_next_index(consumer, sds_ring->num_desc); 222562306a36Sopenharmony_ci sds_ring->consumer = consumer; 222662306a36Sopenharmony_ci writel(consumer, sds_ring->crb_sts_consumer); 222762306a36Sopenharmony_ci} 2228