18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* QLogic qed NIC Driver 38c2ecf20Sopenharmony_ci * Copyright (c) 2015-2017 QLogic Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2019-2020 Marvell International Ltd. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 98c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 108c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/pci.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/stddef.h> 158c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 168c2ecf20Sopenharmony_ci#include <net/ipv6.h> 178c2ecf20Sopenharmony_ci#include <linux/bitops.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/errno.h> 208c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci#include <linux/list.h> 238c2ecf20Sopenharmony_ci#include <linux/mutex.h> 248c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 258c2ecf20Sopenharmony_ci#include <linux/string.h> 268c2ecf20Sopenharmony_ci#include <linux/qed/qed_ll2_if.h> 278c2ecf20Sopenharmony_ci#include "qed.h" 288c2ecf20Sopenharmony_ci#include "qed_cxt.h" 298c2ecf20Sopenharmony_ci#include "qed_dev_api.h" 308c2ecf20Sopenharmony_ci#include "qed_hsi.h" 318c2ecf20Sopenharmony_ci#include "qed_hw.h" 328c2ecf20Sopenharmony_ci#include "qed_int.h" 338c2ecf20Sopenharmony_ci#include "qed_ll2.h" 348c2ecf20Sopenharmony_ci#include "qed_mcp.h" 358c2ecf20Sopenharmony_ci#include "qed_ooo.h" 368c2ecf20Sopenharmony_ci#include "qed_reg_addr.h" 378c2ecf20Sopenharmony_ci#include "qed_sp.h" 388c2ecf20Sopenharmony_ci#include "qed_rdma.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define QED_LL2_RX_REGISTERED(ll2) ((ll2)->rx_queue.b_cb_registered) 418c2ecf20Sopenharmony_ci#define QED_LL2_TX_REGISTERED(ll2) ((ll2)->tx_queue.b_cb_registered) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define QED_LL2_TX_SIZE (256) 448c2ecf20Sopenharmony_ci#define QED_LL2_RX_SIZE (4096) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistruct qed_cb_ll2_info { 478c2ecf20Sopenharmony_ci int rx_cnt; 488c2ecf20Sopenharmony_ci u32 rx_size; 498c2ecf20Sopenharmony_ci u8 handle; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* Lock protecting LL2 buffer lists in sleepless context */ 528c2ecf20Sopenharmony_ci spinlock_t lock; 538c2ecf20Sopenharmony_ci struct list_head list; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci const struct qed_ll2_cb_ops *cbs; 568c2ecf20Sopenharmony_ci void *cb_cookie; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct qed_ll2_buffer { 608c2ecf20Sopenharmony_ci struct list_head list; 618c2ecf20Sopenharmony_ci void *data; 628c2ecf20Sopenharmony_ci dma_addr_t phys_addr; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void qed_ll2b_complete_tx_packet(void *cxt, 668c2ecf20Sopenharmony_ci u8 connection_handle, 678c2ecf20Sopenharmony_ci void *cookie, 688c2ecf20Sopenharmony_ci dma_addr_t first_frag_addr, 698c2ecf20Sopenharmony_ci bool b_last_fragment, 708c2ecf20Sopenharmony_ci bool b_last_packet) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 738c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 748c2ecf20Sopenharmony_ci struct sk_buff *skb = cookie; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* All we need to do is release the mapping */ 778c2ecf20Sopenharmony_ci dma_unmap_single(&p_hwfn->cdev->pdev->dev, first_frag_addr, 788c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (cdev->ll2->cbs && cdev->ll2->cbs->tx_cb) 818c2ecf20Sopenharmony_ci cdev->ll2->cbs->tx_cb(cdev->ll2->cb_cookie, skb, 828c2ecf20Sopenharmony_ci b_last_fragment); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int qed_ll2_alloc_buffer(struct qed_dev *cdev, 888c2ecf20Sopenharmony_ci u8 **data, dma_addr_t *phys_addr) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci size_t size = cdev->ll2->rx_size + NET_SKB_PAD + 918c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci *data = kmalloc(size, GFP_ATOMIC); 948c2ecf20Sopenharmony_ci if (!(*data)) { 958c2ecf20Sopenharmony_ci DP_INFO(cdev, "Failed to allocate LL2 buffer data\n"); 968c2ecf20Sopenharmony_ci return -ENOMEM; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci *phys_addr = dma_map_single(&cdev->pdev->dev, 1008c2ecf20Sopenharmony_ci ((*data) + NET_SKB_PAD), 1018c2ecf20Sopenharmony_ci cdev->ll2->rx_size, DMA_FROM_DEVICE); 1028c2ecf20Sopenharmony_ci if (dma_mapping_error(&cdev->pdev->dev, *phys_addr)) { 1038c2ecf20Sopenharmony_ci DP_INFO(cdev, "Failed to map LL2 buffer data\n"); 1048c2ecf20Sopenharmony_ci kfree((*data)); 1058c2ecf20Sopenharmony_ci return -ENOMEM; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int qed_ll2_dealloc_buffer(struct qed_dev *cdev, 1128c2ecf20Sopenharmony_ci struct qed_ll2_buffer *buffer) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci spin_lock_bh(&cdev->ll2->lock); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci dma_unmap_single(&cdev->pdev->dev, buffer->phys_addr, 1178c2ecf20Sopenharmony_ci cdev->ll2->rx_size, DMA_FROM_DEVICE); 1188c2ecf20Sopenharmony_ci kfree(buffer->data); 1198c2ecf20Sopenharmony_ci list_del(&buffer->list); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci cdev->ll2->rx_cnt--; 1228c2ecf20Sopenharmony_ci if (!cdev->ll2->rx_cnt) 1238c2ecf20Sopenharmony_ci DP_INFO(cdev, "All LL2 entries were removed\n"); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci spin_unlock_bh(&cdev->ll2->lock); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return 0; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic void qed_ll2_kill_buffers(struct qed_dev *cdev) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct qed_ll2_buffer *buffer, *tmp_buffer; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci list_for_each_entry_safe(buffer, tmp_buffer, &cdev->ll2->list, list) 1358c2ecf20Sopenharmony_ci qed_ll2_dealloc_buffer(cdev, buffer); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void qed_ll2b_complete_rx_packet(void *cxt, 1398c2ecf20Sopenharmony_ci struct qed_ll2_comp_rx_data *data) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 1428c2ecf20Sopenharmony_ci struct qed_ll2_buffer *buffer = data->cookie; 1438c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 1448c2ecf20Sopenharmony_ci dma_addr_t new_phys_addr; 1458c2ecf20Sopenharmony_ci struct sk_buff *skb; 1468c2ecf20Sopenharmony_ci bool reuse = false; 1478c2ecf20Sopenharmony_ci int rc = -EINVAL; 1488c2ecf20Sopenharmony_ci u8 *new_data; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 1518c2ecf20Sopenharmony_ci (NETIF_MSG_RX_STATUS | QED_MSG_STORAGE | NETIF_MSG_PKTDATA), 1528c2ecf20Sopenharmony_ci "Got an LL2 Rx completion: [Buffer at phys 0x%llx, offset 0x%02x] Length 0x%04x Parse_flags 0x%04x vlan 0x%04x Opaque data [0x%08x:0x%08x]\n", 1538c2ecf20Sopenharmony_ci (u64)data->rx_buf_addr, 1548c2ecf20Sopenharmony_ci data->u.placement_offset, 1558c2ecf20Sopenharmony_ci data->length.packet_length, 1568c2ecf20Sopenharmony_ci data->parse_flags, 1578c2ecf20Sopenharmony_ci data->vlan, data->opaque_data_0, data->opaque_data_1); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if ((cdev->dp_module & NETIF_MSG_PKTDATA) && buffer->data) { 1608c2ecf20Sopenharmony_ci print_hex_dump(KERN_INFO, "", 1618c2ecf20Sopenharmony_ci DUMP_PREFIX_OFFSET, 16, 1, 1628c2ecf20Sopenharmony_ci buffer->data, data->length.packet_length, false); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Determine if data is valid */ 1668c2ecf20Sopenharmony_ci if (data->length.packet_length < ETH_HLEN) 1678c2ecf20Sopenharmony_ci reuse = true; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* Allocate a replacement for buffer; Reuse upon failure */ 1708c2ecf20Sopenharmony_ci if (!reuse) 1718c2ecf20Sopenharmony_ci rc = qed_ll2_alloc_buffer(p_hwfn->cdev, &new_data, 1728c2ecf20Sopenharmony_ci &new_phys_addr); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* If need to reuse or there's no replacement buffer, repost this */ 1758c2ecf20Sopenharmony_ci if (rc) 1768c2ecf20Sopenharmony_ci goto out_post; 1778c2ecf20Sopenharmony_ci dma_unmap_single(&cdev->pdev->dev, buffer->phys_addr, 1788c2ecf20Sopenharmony_ci cdev->ll2->rx_size, DMA_FROM_DEVICE); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci skb = build_skb(buffer->data, 0); 1818c2ecf20Sopenharmony_ci if (!skb) { 1828c2ecf20Sopenharmony_ci DP_INFO(cdev, "Failed to build SKB\n"); 1838c2ecf20Sopenharmony_ci kfree(buffer->data); 1848c2ecf20Sopenharmony_ci goto out_post1; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci data->u.placement_offset += NET_SKB_PAD; 1888c2ecf20Sopenharmony_ci skb_reserve(skb, data->u.placement_offset); 1898c2ecf20Sopenharmony_ci skb_put(skb, data->length.packet_length); 1908c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Get parital ethernet information instead of eth_type_trans(), 1938c2ecf20Sopenharmony_ci * Since we don't have an associated net_device. 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 1968c2ecf20Sopenharmony_ci skb->protocol = eth_hdr(skb)->h_proto; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* Pass SKB onward */ 1998c2ecf20Sopenharmony_ci if (cdev->ll2->cbs && cdev->ll2->cbs->rx_cb) { 2008c2ecf20Sopenharmony_ci if (data->vlan) 2018c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 2028c2ecf20Sopenharmony_ci data->vlan); 2038c2ecf20Sopenharmony_ci cdev->ll2->cbs->rx_cb(cdev->ll2->cb_cookie, skb, 2048c2ecf20Sopenharmony_ci data->opaque_data_0, 2058c2ecf20Sopenharmony_ci data->opaque_data_1); 2068c2ecf20Sopenharmony_ci } else { 2078c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, (NETIF_MSG_RX_STATUS | NETIF_MSG_PKTDATA | 2088c2ecf20Sopenharmony_ci QED_MSG_LL2 | QED_MSG_STORAGE), 2098c2ecf20Sopenharmony_ci "Dropping the packet\n"); 2108c2ecf20Sopenharmony_ci kfree(buffer->data); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ciout_post1: 2148c2ecf20Sopenharmony_ci /* Update Buffer information and update FW producer */ 2158c2ecf20Sopenharmony_ci buffer->data = new_data; 2168c2ecf20Sopenharmony_ci buffer->phys_addr = new_phys_addr; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ciout_post: 2198c2ecf20Sopenharmony_ci rc = qed_ll2_post_rx_buffer(p_hwfn, cdev->ll2->handle, 2208c2ecf20Sopenharmony_ci buffer->phys_addr, 0, buffer, 1); 2218c2ecf20Sopenharmony_ci if (rc) 2228c2ecf20Sopenharmony_ci qed_ll2_dealloc_buffer(cdev, buffer); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic struct qed_ll2_info *__qed_ll2_handle_sanity(struct qed_hwfn *p_hwfn, 2268c2ecf20Sopenharmony_ci u8 connection_handle, 2278c2ecf20Sopenharmony_ci bool b_lock, 2288c2ecf20Sopenharmony_ci bool b_only_active) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn, *p_ret = NULL; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (connection_handle >= QED_MAX_NUM_OF_LL2_CONNECTIONS) 2338c2ecf20Sopenharmony_ci return NULL; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!p_hwfn->p_ll2_info) 2368c2ecf20Sopenharmony_ci return NULL; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci p_ll2_conn = &p_hwfn->p_ll2_info[connection_handle]; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (b_only_active) { 2418c2ecf20Sopenharmony_ci if (b_lock) 2428c2ecf20Sopenharmony_ci mutex_lock(&p_ll2_conn->mutex); 2438c2ecf20Sopenharmony_ci if (p_ll2_conn->b_active) 2448c2ecf20Sopenharmony_ci p_ret = p_ll2_conn; 2458c2ecf20Sopenharmony_ci if (b_lock) 2468c2ecf20Sopenharmony_ci mutex_unlock(&p_ll2_conn->mutex); 2478c2ecf20Sopenharmony_ci } else { 2488c2ecf20Sopenharmony_ci p_ret = p_ll2_conn; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return p_ret; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic struct qed_ll2_info *qed_ll2_handle_sanity(struct qed_hwfn *p_hwfn, 2558c2ecf20Sopenharmony_ci u8 connection_handle) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci return __qed_ll2_handle_sanity(p_hwfn, connection_handle, false, true); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic struct qed_ll2_info *qed_ll2_handle_sanity_lock(struct qed_hwfn *p_hwfn, 2618c2ecf20Sopenharmony_ci u8 connection_handle) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci return __qed_ll2_handle_sanity(p_hwfn, connection_handle, true, true); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic struct qed_ll2_info *qed_ll2_handle_sanity_inactive(struct qed_hwfn 2678c2ecf20Sopenharmony_ci *p_hwfn, 2688c2ecf20Sopenharmony_ci u8 connection_handle) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci return __qed_ll2_handle_sanity(p_hwfn, connection_handle, false, false); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci bool b_last_packet = false, b_last_frag = false; 2768c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet *p_pkt = NULL; 2778c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn; 2788c2ecf20Sopenharmony_ci struct qed_ll2_tx_queue *p_tx; 2798c2ecf20Sopenharmony_ci unsigned long flags = 0; 2808c2ecf20Sopenharmony_ci dma_addr_t tx_frag; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci p_ll2_conn = qed_ll2_handle_sanity_inactive(p_hwfn, connection_handle); 2838c2ecf20Sopenharmony_ci if (!p_ll2_conn) 2848c2ecf20Sopenharmony_ci return; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci p_tx = &p_ll2_conn->tx_queue; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_tx->lock, flags); 2898c2ecf20Sopenharmony_ci while (!list_empty(&p_tx->active_descq)) { 2908c2ecf20Sopenharmony_ci p_pkt = list_first_entry(&p_tx->active_descq, 2918c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet, list_entry); 2928c2ecf20Sopenharmony_ci if (!p_pkt) 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci list_del(&p_pkt->list_entry); 2968c2ecf20Sopenharmony_ci b_last_packet = list_empty(&p_tx->active_descq); 2978c2ecf20Sopenharmony_ci list_add_tail(&p_pkt->list_entry, &p_tx->free_descq); 2988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_tx->lock, flags); 2998c2ecf20Sopenharmony_ci if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) { 3008c2ecf20Sopenharmony_ci struct qed_ooo_buffer *p_buffer; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie; 3038c2ecf20Sopenharmony_ci qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info, 3048c2ecf20Sopenharmony_ci p_buffer); 3058c2ecf20Sopenharmony_ci } else { 3068c2ecf20Sopenharmony_ci p_tx->cur_completing_packet = *p_pkt; 3078c2ecf20Sopenharmony_ci p_tx->cur_completing_bd_idx = 1; 3088c2ecf20Sopenharmony_ci b_last_frag = 3098c2ecf20Sopenharmony_ci p_tx->cur_completing_bd_idx == p_pkt->bd_used; 3108c2ecf20Sopenharmony_ci tx_frag = p_pkt->bds_set[0].tx_frag; 3118c2ecf20Sopenharmony_ci p_ll2_conn->cbs.tx_release_cb(p_ll2_conn->cbs.cookie, 3128c2ecf20Sopenharmony_ci p_ll2_conn->my_id, 3138c2ecf20Sopenharmony_ci p_pkt->cookie, 3148c2ecf20Sopenharmony_ci tx_frag, 3158c2ecf20Sopenharmony_ci b_last_frag, 3168c2ecf20Sopenharmony_ci b_last_packet); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_tx->lock, flags); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_tx->lock, flags); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn = p_cookie; 3268c2ecf20Sopenharmony_ci struct qed_ll2_tx_queue *p_tx = &p_ll2_conn->tx_queue; 3278c2ecf20Sopenharmony_ci u16 new_idx = 0, num_bds = 0, num_bds_in_packet = 0; 3288c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet *p_pkt; 3298c2ecf20Sopenharmony_ci bool b_last_frag = false; 3308c2ecf20Sopenharmony_ci unsigned long flags; 3318c2ecf20Sopenharmony_ci int rc = -EINVAL; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (!p_ll2_conn) 3348c2ecf20Sopenharmony_ci return rc; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_tx->lock, flags); 3378c2ecf20Sopenharmony_ci if (p_tx->b_completing_packet) { 3388c2ecf20Sopenharmony_ci rc = -EBUSY; 3398c2ecf20Sopenharmony_ci goto out; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci new_idx = le16_to_cpu(*p_tx->p_fw_cons); 3438c2ecf20Sopenharmony_ci num_bds = ((s16)new_idx - (s16)p_tx->bds_idx); 3448c2ecf20Sopenharmony_ci while (num_bds) { 3458c2ecf20Sopenharmony_ci if (list_empty(&p_tx->active_descq)) 3468c2ecf20Sopenharmony_ci goto out; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci p_pkt = list_first_entry(&p_tx->active_descq, 3498c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet, list_entry); 3508c2ecf20Sopenharmony_ci if (!p_pkt) 3518c2ecf20Sopenharmony_ci goto out; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci p_tx->b_completing_packet = true; 3548c2ecf20Sopenharmony_ci p_tx->cur_completing_packet = *p_pkt; 3558c2ecf20Sopenharmony_ci num_bds_in_packet = p_pkt->bd_used; 3568c2ecf20Sopenharmony_ci list_del(&p_pkt->list_entry); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (num_bds < num_bds_in_packet) { 3598c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 3608c2ecf20Sopenharmony_ci "Rest of BDs does not cover whole packet\n"); 3618c2ecf20Sopenharmony_ci goto out; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci num_bds -= num_bds_in_packet; 3658c2ecf20Sopenharmony_ci p_tx->bds_idx += num_bds_in_packet; 3668c2ecf20Sopenharmony_ci while (num_bds_in_packet--) 3678c2ecf20Sopenharmony_ci qed_chain_consume(&p_tx->txq_chain); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci p_tx->cur_completing_bd_idx = 1; 3708c2ecf20Sopenharmony_ci b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used; 3718c2ecf20Sopenharmony_ci list_add_tail(&p_pkt->list_entry, &p_tx->free_descq); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_tx->lock, flags); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci p_ll2_conn->cbs.tx_comp_cb(p_ll2_conn->cbs.cookie, 3768c2ecf20Sopenharmony_ci p_ll2_conn->my_id, 3778c2ecf20Sopenharmony_ci p_pkt->cookie, 3788c2ecf20Sopenharmony_ci p_pkt->bds_set[0].tx_frag, 3798c2ecf20Sopenharmony_ci b_last_frag, !num_bds); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_tx->lock, flags); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci p_tx->b_completing_packet = false; 3858c2ecf20Sopenharmony_ci rc = 0; 3868c2ecf20Sopenharmony_ciout: 3878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_tx->lock, flags); 3888c2ecf20Sopenharmony_ci return rc; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic void qed_ll2_rxq_parse_gsi(struct qed_hwfn *p_hwfn, 3928c2ecf20Sopenharmony_ci union core_rx_cqe_union *p_cqe, 3938c2ecf20Sopenharmony_ci struct qed_ll2_comp_rx_data *data) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci data->parse_flags = le16_to_cpu(p_cqe->rx_cqe_gsi.parse_flags.flags); 3968c2ecf20Sopenharmony_ci data->length.data_length = le16_to_cpu(p_cqe->rx_cqe_gsi.data_length); 3978c2ecf20Sopenharmony_ci data->vlan = le16_to_cpu(p_cqe->rx_cqe_gsi.vlan); 3988c2ecf20Sopenharmony_ci data->opaque_data_0 = le32_to_cpu(p_cqe->rx_cqe_gsi.src_mac_addrhi); 3998c2ecf20Sopenharmony_ci data->opaque_data_1 = le16_to_cpu(p_cqe->rx_cqe_gsi.src_mac_addrlo); 4008c2ecf20Sopenharmony_ci data->u.data_length_error = p_cqe->rx_cqe_gsi.data_length_error; 4018c2ecf20Sopenharmony_ci data->qp_id = le16_to_cpu(p_cqe->rx_cqe_gsi.qp_id); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci data->src_qp = le32_to_cpu(p_cqe->rx_cqe_gsi.src_qp); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic void qed_ll2_rxq_parse_reg(struct qed_hwfn *p_hwfn, 4078c2ecf20Sopenharmony_ci union core_rx_cqe_union *p_cqe, 4088c2ecf20Sopenharmony_ci struct qed_ll2_comp_rx_data *data) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci data->parse_flags = le16_to_cpu(p_cqe->rx_cqe_fp.parse_flags.flags); 4118c2ecf20Sopenharmony_ci data->err_flags = le16_to_cpu(p_cqe->rx_cqe_fp.err_flags.flags); 4128c2ecf20Sopenharmony_ci data->length.packet_length = 4138c2ecf20Sopenharmony_ci le16_to_cpu(p_cqe->rx_cqe_fp.packet_length); 4148c2ecf20Sopenharmony_ci data->vlan = le16_to_cpu(p_cqe->rx_cqe_fp.vlan); 4158c2ecf20Sopenharmony_ci data->opaque_data_0 = le32_to_cpu(p_cqe->rx_cqe_fp.opaque_data.data[0]); 4168c2ecf20Sopenharmony_ci data->opaque_data_1 = le32_to_cpu(p_cqe->rx_cqe_fp.opaque_data.data[1]); 4178c2ecf20Sopenharmony_ci data->u.placement_offset = p_cqe->rx_cqe_fp.placement_offset; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic int 4218c2ecf20Sopenharmony_ciqed_ll2_handle_slowpath(struct qed_hwfn *p_hwfn, 4228c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn, 4238c2ecf20Sopenharmony_ci union core_rx_cqe_union *p_cqe, 4248c2ecf20Sopenharmony_ci unsigned long *p_lock_flags) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue; 4278c2ecf20Sopenharmony_ci struct core_rx_slow_path_cqe *sp_cqe; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci sp_cqe = &p_cqe->rx_cqe_sp; 4308c2ecf20Sopenharmony_ci if (sp_cqe->ramrod_cmd_id != CORE_RAMROD_RX_QUEUE_FLUSH) { 4318c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 4328c2ecf20Sopenharmony_ci "LL2 - unexpected Rx CQE slowpath ramrod_cmd_id:%d\n", 4338c2ecf20Sopenharmony_ci sp_cqe->ramrod_cmd_id); 4348c2ecf20Sopenharmony_ci return -EINVAL; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (!p_ll2_conn->cbs.slowpath_cb) { 4388c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 4398c2ecf20Sopenharmony_ci "LL2 - received RX_QUEUE_FLUSH but no callback was provided\n"); 4408c2ecf20Sopenharmony_ci return -EINVAL; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_rx->lock, *p_lock_flags); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci p_ll2_conn->cbs.slowpath_cb(p_ll2_conn->cbs.cookie, 4468c2ecf20Sopenharmony_ci p_ll2_conn->my_id, 4478c2ecf20Sopenharmony_ci le32_to_cpu(sp_cqe->opaque_data.data[0]), 4488c2ecf20Sopenharmony_ci le32_to_cpu(sp_cqe->opaque_data.data[1])); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_rx->lock, *p_lock_flags); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic int 4568c2ecf20Sopenharmony_ciqed_ll2_rxq_handle_completion(struct qed_hwfn *p_hwfn, 4578c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn, 4588c2ecf20Sopenharmony_ci union core_rx_cqe_union *p_cqe, 4598c2ecf20Sopenharmony_ci unsigned long *p_lock_flags, bool b_last_cqe) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue; 4628c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet *p_pkt = NULL; 4638c2ecf20Sopenharmony_ci struct qed_ll2_comp_rx_data data; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (!list_empty(&p_rx->active_descq)) 4668c2ecf20Sopenharmony_ci p_pkt = list_first_entry(&p_rx->active_descq, 4678c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet, list_entry); 4688c2ecf20Sopenharmony_ci if (!p_pkt) { 4698c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 4708c2ecf20Sopenharmony_ci "[%d] LL2 Rx completion but active_descq is empty\n", 4718c2ecf20Sopenharmony_ci p_ll2_conn->input.conn_type); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return -EIO; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci list_del(&p_pkt->list_entry); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (p_cqe->rx_cqe_sp.type == CORE_RX_CQE_TYPE_REGULAR) 4788c2ecf20Sopenharmony_ci qed_ll2_rxq_parse_reg(p_hwfn, p_cqe, &data); 4798c2ecf20Sopenharmony_ci else 4808c2ecf20Sopenharmony_ci qed_ll2_rxq_parse_gsi(p_hwfn, p_cqe, &data); 4818c2ecf20Sopenharmony_ci if (qed_chain_consume(&p_rx->rxq_chain) != p_pkt->rxq_bd) 4828c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 4838c2ecf20Sopenharmony_ci "Mismatch between active_descq and the LL2 Rx chain\n"); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci list_add_tail(&p_pkt->list_entry, &p_rx->free_descq); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci data.connection_handle = p_ll2_conn->my_id; 4888c2ecf20Sopenharmony_ci data.cookie = p_pkt->cookie; 4898c2ecf20Sopenharmony_ci data.rx_buf_addr = p_pkt->rx_buf_addr; 4908c2ecf20Sopenharmony_ci data.b_last_packet = b_last_cqe; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_rx->lock, *p_lock_flags); 4938c2ecf20Sopenharmony_ci p_ll2_conn->cbs.rx_comp_cb(p_ll2_conn->cbs.cookie, &data); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_rx->lock, *p_lock_flags); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, void *cookie) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn = (struct qed_ll2_info *)cookie; 5038c2ecf20Sopenharmony_ci struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue; 5048c2ecf20Sopenharmony_ci union core_rx_cqe_union *cqe = NULL; 5058c2ecf20Sopenharmony_ci u16 cq_new_idx = 0, cq_old_idx = 0; 5068c2ecf20Sopenharmony_ci unsigned long flags = 0; 5078c2ecf20Sopenharmony_ci int rc = 0; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (!p_ll2_conn) 5108c2ecf20Sopenharmony_ci return rc; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_rx->lock, flags); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (!QED_LL2_RX_REGISTERED(p_ll2_conn)) { 5158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_rx->lock, flags); 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci cq_new_idx = le16_to_cpu(*p_rx->p_fw_cons); 5208c2ecf20Sopenharmony_ci cq_old_idx = qed_chain_get_cons_idx(&p_rx->rcq_chain); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci while (cq_new_idx != cq_old_idx) { 5238c2ecf20Sopenharmony_ci bool b_last_cqe = (cq_new_idx == cq_old_idx); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci cqe = 5268c2ecf20Sopenharmony_ci (union core_rx_cqe_union *) 5278c2ecf20Sopenharmony_ci qed_chain_consume(&p_rx->rcq_chain); 5288c2ecf20Sopenharmony_ci cq_old_idx = qed_chain_get_cons_idx(&p_rx->rcq_chain); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 5318c2ecf20Sopenharmony_ci QED_MSG_LL2, 5328c2ecf20Sopenharmony_ci "LL2 [sw. cons %04x, fw. at %04x] - Got Packet of type %02x\n", 5338c2ecf20Sopenharmony_ci cq_old_idx, cq_new_idx, cqe->rx_cqe_sp.type); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci switch (cqe->rx_cqe_sp.type) { 5368c2ecf20Sopenharmony_ci case CORE_RX_CQE_TYPE_SLOW_PATH: 5378c2ecf20Sopenharmony_ci rc = qed_ll2_handle_slowpath(p_hwfn, p_ll2_conn, 5388c2ecf20Sopenharmony_ci cqe, &flags); 5398c2ecf20Sopenharmony_ci break; 5408c2ecf20Sopenharmony_ci case CORE_RX_CQE_TYPE_GSI_OFFLOAD: 5418c2ecf20Sopenharmony_ci case CORE_RX_CQE_TYPE_REGULAR: 5428c2ecf20Sopenharmony_ci rc = qed_ll2_rxq_handle_completion(p_hwfn, p_ll2_conn, 5438c2ecf20Sopenharmony_ci cqe, &flags, 5448c2ecf20Sopenharmony_ci b_last_cqe); 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci default: 5478c2ecf20Sopenharmony_ci rc = -EIO; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_rx->lock, flags); 5528c2ecf20Sopenharmony_ci return rc; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn = NULL; 5588c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet *p_pkt = NULL; 5598c2ecf20Sopenharmony_ci struct qed_ll2_rx_queue *p_rx; 5608c2ecf20Sopenharmony_ci unsigned long flags = 0; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci p_ll2_conn = qed_ll2_handle_sanity_inactive(p_hwfn, connection_handle); 5638c2ecf20Sopenharmony_ci if (!p_ll2_conn) 5648c2ecf20Sopenharmony_ci return; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci p_rx = &p_ll2_conn->rx_queue; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_rx->lock, flags); 5698c2ecf20Sopenharmony_ci while (!list_empty(&p_rx->active_descq)) { 5708c2ecf20Sopenharmony_ci p_pkt = list_first_entry(&p_rx->active_descq, 5718c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet, list_entry); 5728c2ecf20Sopenharmony_ci if (!p_pkt) 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci list_move_tail(&p_pkt->list_entry, &p_rx->free_descq); 5758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_rx->lock, flags); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) { 5788c2ecf20Sopenharmony_ci struct qed_ooo_buffer *p_buffer; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie; 5818c2ecf20Sopenharmony_ci qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info, 5828c2ecf20Sopenharmony_ci p_buffer); 5838c2ecf20Sopenharmony_ci } else { 5848c2ecf20Sopenharmony_ci dma_addr_t rx_buf_addr = p_pkt->rx_buf_addr; 5858c2ecf20Sopenharmony_ci void *cookie = p_pkt->cookie; 5868c2ecf20Sopenharmony_ci bool b_last; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci b_last = list_empty(&p_rx->active_descq); 5898c2ecf20Sopenharmony_ci p_ll2_conn->cbs.rx_release_cb(p_ll2_conn->cbs.cookie, 5908c2ecf20Sopenharmony_ci p_ll2_conn->my_id, 5918c2ecf20Sopenharmony_ci cookie, 5928c2ecf20Sopenharmony_ci rx_buf_addr, b_last); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_rx->lock, flags); 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_rx->lock, flags); 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic bool 6008c2ecf20Sopenharmony_ciqed_ll2_lb_rxq_handler_slowpath(struct qed_hwfn *p_hwfn, 6018c2ecf20Sopenharmony_ci struct core_rx_slow_path_cqe *p_cqe) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci struct ooo_opaque *iscsi_ooo; 6048c2ecf20Sopenharmony_ci u32 cid; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (p_cqe->ramrod_cmd_id != CORE_RAMROD_RX_QUEUE_FLUSH) 6078c2ecf20Sopenharmony_ci return false; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci iscsi_ooo = (struct ooo_opaque *)&p_cqe->opaque_data; 6108c2ecf20Sopenharmony_ci if (iscsi_ooo->ooo_opcode != TCP_EVENT_DELETE_ISLES) 6118c2ecf20Sopenharmony_ci return false; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* Need to make a flush */ 6148c2ecf20Sopenharmony_ci cid = le32_to_cpu(iscsi_ooo->cid); 6158c2ecf20Sopenharmony_ci qed_ooo_release_connection_isles(p_hwfn, p_hwfn->p_ooo_info, cid); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci return true; 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic int qed_ll2_lb_rxq_handler(struct qed_hwfn *p_hwfn, 6218c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue; 6248c2ecf20Sopenharmony_ci u16 packet_length = 0, parse_flags = 0, vlan = 0; 6258c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet *p_pkt = NULL; 6268c2ecf20Sopenharmony_ci u32 num_ooo_add_to_peninsula = 0, cid; 6278c2ecf20Sopenharmony_ci union core_rx_cqe_union *cqe = NULL; 6288c2ecf20Sopenharmony_ci u16 cq_new_idx = 0, cq_old_idx = 0; 6298c2ecf20Sopenharmony_ci struct qed_ooo_buffer *p_buffer; 6308c2ecf20Sopenharmony_ci struct ooo_opaque *iscsi_ooo; 6318c2ecf20Sopenharmony_ci u8 placement_offset = 0; 6328c2ecf20Sopenharmony_ci u8 cqe_type; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci cq_new_idx = le16_to_cpu(*p_rx->p_fw_cons); 6358c2ecf20Sopenharmony_ci cq_old_idx = qed_chain_get_cons_idx(&p_rx->rcq_chain); 6368c2ecf20Sopenharmony_ci if (cq_new_idx == cq_old_idx) 6378c2ecf20Sopenharmony_ci return 0; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci while (cq_new_idx != cq_old_idx) { 6408c2ecf20Sopenharmony_ci struct core_rx_fast_path_cqe *p_cqe_fp; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci cqe = qed_chain_consume(&p_rx->rcq_chain); 6438c2ecf20Sopenharmony_ci cq_old_idx = qed_chain_get_cons_idx(&p_rx->rcq_chain); 6448c2ecf20Sopenharmony_ci cqe_type = cqe->rx_cqe_sp.type; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (cqe_type == CORE_RX_CQE_TYPE_SLOW_PATH) 6478c2ecf20Sopenharmony_ci if (qed_ll2_lb_rxq_handler_slowpath(p_hwfn, 6488c2ecf20Sopenharmony_ci &cqe->rx_cqe_sp)) 6498c2ecf20Sopenharmony_ci continue; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (cqe_type != CORE_RX_CQE_TYPE_REGULAR) { 6528c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 6538c2ecf20Sopenharmony_ci "Got a non-regular LB LL2 completion [type 0x%02x]\n", 6548c2ecf20Sopenharmony_ci cqe_type); 6558c2ecf20Sopenharmony_ci return -EINVAL; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci p_cqe_fp = &cqe->rx_cqe_fp; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci placement_offset = p_cqe_fp->placement_offset; 6608c2ecf20Sopenharmony_ci parse_flags = le16_to_cpu(p_cqe_fp->parse_flags.flags); 6618c2ecf20Sopenharmony_ci packet_length = le16_to_cpu(p_cqe_fp->packet_length); 6628c2ecf20Sopenharmony_ci vlan = le16_to_cpu(p_cqe_fp->vlan); 6638c2ecf20Sopenharmony_ci iscsi_ooo = (struct ooo_opaque *)&p_cqe_fp->opaque_data; 6648c2ecf20Sopenharmony_ci qed_ooo_save_history_entry(p_hwfn, p_hwfn->p_ooo_info, 6658c2ecf20Sopenharmony_ci iscsi_ooo); 6668c2ecf20Sopenharmony_ci cid = le32_to_cpu(iscsi_ooo->cid); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* Process delete isle first */ 6698c2ecf20Sopenharmony_ci if (iscsi_ooo->drop_size) 6708c2ecf20Sopenharmony_ci qed_ooo_delete_isles(p_hwfn, p_hwfn->p_ooo_info, cid, 6718c2ecf20Sopenharmony_ci iscsi_ooo->drop_isle, 6728c2ecf20Sopenharmony_ci iscsi_ooo->drop_size); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (iscsi_ooo->ooo_opcode == TCP_EVENT_NOP) 6758c2ecf20Sopenharmony_ci continue; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* Now process create/add/join isles */ 6788c2ecf20Sopenharmony_ci if (list_empty(&p_rx->active_descq)) { 6798c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 6808c2ecf20Sopenharmony_ci "LL2 OOO RX chain has no submitted buffers\n" 6818c2ecf20Sopenharmony_ci ); 6828c2ecf20Sopenharmony_ci return -EIO; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci p_pkt = list_first_entry(&p_rx->active_descq, 6868c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet, list_entry); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if ((iscsi_ooo->ooo_opcode == TCP_EVENT_ADD_NEW_ISLE) || 6898c2ecf20Sopenharmony_ci (iscsi_ooo->ooo_opcode == TCP_EVENT_ADD_ISLE_RIGHT) || 6908c2ecf20Sopenharmony_ci (iscsi_ooo->ooo_opcode == TCP_EVENT_ADD_ISLE_LEFT) || 6918c2ecf20Sopenharmony_ci (iscsi_ooo->ooo_opcode == TCP_EVENT_ADD_PEN) || 6928c2ecf20Sopenharmony_ci (iscsi_ooo->ooo_opcode == TCP_EVENT_JOIN)) { 6938c2ecf20Sopenharmony_ci if (!p_pkt) { 6948c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 6958c2ecf20Sopenharmony_ci "LL2 OOO RX packet is not valid\n"); 6968c2ecf20Sopenharmony_ci return -EIO; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci list_del(&p_pkt->list_entry); 6998c2ecf20Sopenharmony_ci p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie; 7008c2ecf20Sopenharmony_ci p_buffer->packet_length = packet_length; 7018c2ecf20Sopenharmony_ci p_buffer->parse_flags = parse_flags; 7028c2ecf20Sopenharmony_ci p_buffer->vlan = vlan; 7038c2ecf20Sopenharmony_ci p_buffer->placement_offset = placement_offset; 7048c2ecf20Sopenharmony_ci qed_chain_consume(&p_rx->rxq_chain); 7058c2ecf20Sopenharmony_ci list_add_tail(&p_pkt->list_entry, &p_rx->free_descq); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci switch (iscsi_ooo->ooo_opcode) { 7088c2ecf20Sopenharmony_ci case TCP_EVENT_ADD_NEW_ISLE: 7098c2ecf20Sopenharmony_ci qed_ooo_add_new_isle(p_hwfn, 7108c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info, 7118c2ecf20Sopenharmony_ci cid, 7128c2ecf20Sopenharmony_ci iscsi_ooo->ooo_isle, 7138c2ecf20Sopenharmony_ci p_buffer); 7148c2ecf20Sopenharmony_ci break; 7158c2ecf20Sopenharmony_ci case TCP_EVENT_ADD_ISLE_RIGHT: 7168c2ecf20Sopenharmony_ci qed_ooo_add_new_buffer(p_hwfn, 7178c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info, 7188c2ecf20Sopenharmony_ci cid, 7198c2ecf20Sopenharmony_ci iscsi_ooo->ooo_isle, 7208c2ecf20Sopenharmony_ci p_buffer, 7218c2ecf20Sopenharmony_ci QED_OOO_RIGHT_BUF); 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci case TCP_EVENT_ADD_ISLE_LEFT: 7248c2ecf20Sopenharmony_ci qed_ooo_add_new_buffer(p_hwfn, 7258c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info, 7268c2ecf20Sopenharmony_ci cid, 7278c2ecf20Sopenharmony_ci iscsi_ooo->ooo_isle, 7288c2ecf20Sopenharmony_ci p_buffer, 7298c2ecf20Sopenharmony_ci QED_OOO_LEFT_BUF); 7308c2ecf20Sopenharmony_ci break; 7318c2ecf20Sopenharmony_ci case TCP_EVENT_JOIN: 7328c2ecf20Sopenharmony_ci qed_ooo_add_new_buffer(p_hwfn, 7338c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info, 7348c2ecf20Sopenharmony_ci cid, 7358c2ecf20Sopenharmony_ci iscsi_ooo->ooo_isle + 7368c2ecf20Sopenharmony_ci 1, 7378c2ecf20Sopenharmony_ci p_buffer, 7388c2ecf20Sopenharmony_ci QED_OOO_LEFT_BUF); 7398c2ecf20Sopenharmony_ci qed_ooo_join_isles(p_hwfn, 7408c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info, 7418c2ecf20Sopenharmony_ci cid, iscsi_ooo->ooo_isle); 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci case TCP_EVENT_ADD_PEN: 7448c2ecf20Sopenharmony_ci num_ooo_add_to_peninsula++; 7458c2ecf20Sopenharmony_ci qed_ooo_put_ready_buffer(p_hwfn, 7468c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info, 7478c2ecf20Sopenharmony_ci p_buffer, true); 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci } else { 7518c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 7528c2ecf20Sopenharmony_ci "Unexpected event (%d) TX OOO completion\n", 7538c2ecf20Sopenharmony_ci iscsi_ooo->ooo_opcode); 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci return 0; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic void 7618c2ecf20Sopenharmony_ciqed_ooo_submit_tx_buffers(struct qed_hwfn *p_hwfn, 7628c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci struct qed_ll2_tx_pkt_info tx_pkt; 7658c2ecf20Sopenharmony_ci struct qed_ooo_buffer *p_buffer; 7668c2ecf20Sopenharmony_ci u16 l4_hdr_offset_w; 7678c2ecf20Sopenharmony_ci dma_addr_t first_frag; 7688c2ecf20Sopenharmony_ci u8 bd_flags; 7698c2ecf20Sopenharmony_ci int rc; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci /* Submit Tx buffers here */ 7728c2ecf20Sopenharmony_ci while ((p_buffer = qed_ooo_get_ready_buffer(p_hwfn, 7738c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info))) { 7748c2ecf20Sopenharmony_ci l4_hdr_offset_w = 0; 7758c2ecf20Sopenharmony_ci bd_flags = 0; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci first_frag = p_buffer->rx_buffer_phys_addr + 7788c2ecf20Sopenharmony_ci p_buffer->placement_offset; 7798c2ecf20Sopenharmony_ci SET_FIELD(bd_flags, CORE_TX_BD_DATA_FORCE_VLAN_MODE, 1); 7808c2ecf20Sopenharmony_ci SET_FIELD(bd_flags, CORE_TX_BD_DATA_L4_PROTOCOL, 1); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci memset(&tx_pkt, 0, sizeof(tx_pkt)); 7838c2ecf20Sopenharmony_ci tx_pkt.num_of_bds = 1; 7848c2ecf20Sopenharmony_ci tx_pkt.vlan = p_buffer->vlan; 7858c2ecf20Sopenharmony_ci tx_pkt.bd_flags = bd_flags; 7868c2ecf20Sopenharmony_ci tx_pkt.l4_hdr_offset_w = l4_hdr_offset_w; 7878c2ecf20Sopenharmony_ci switch (p_ll2_conn->tx_dest) { 7888c2ecf20Sopenharmony_ci case CORE_TX_DEST_NW: 7898c2ecf20Sopenharmony_ci tx_pkt.tx_dest = QED_LL2_TX_DEST_NW; 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci case CORE_TX_DEST_LB: 7928c2ecf20Sopenharmony_ci tx_pkt.tx_dest = QED_LL2_TX_DEST_LB; 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci case CORE_TX_DEST_DROP: 7958c2ecf20Sopenharmony_ci default: 7968c2ecf20Sopenharmony_ci tx_pkt.tx_dest = QED_LL2_TX_DEST_DROP; 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci tx_pkt.first_frag = first_frag; 8008c2ecf20Sopenharmony_ci tx_pkt.first_frag_len = p_buffer->packet_length; 8018c2ecf20Sopenharmony_ci tx_pkt.cookie = p_buffer; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci rc = qed_ll2_prepare_tx_packet(p_hwfn, p_ll2_conn->my_id, 8048c2ecf20Sopenharmony_ci &tx_pkt, true); 8058c2ecf20Sopenharmony_ci if (rc) { 8068c2ecf20Sopenharmony_ci qed_ooo_put_ready_buffer(p_hwfn, p_hwfn->p_ooo_info, 8078c2ecf20Sopenharmony_ci p_buffer, false); 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic void 8148c2ecf20Sopenharmony_ciqed_ooo_submit_rx_buffers(struct qed_hwfn *p_hwfn, 8158c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct qed_ooo_buffer *p_buffer; 8188c2ecf20Sopenharmony_ci int rc; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci while ((p_buffer = qed_ooo_get_free_buffer(p_hwfn, 8218c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info))) { 8228c2ecf20Sopenharmony_ci rc = qed_ll2_post_rx_buffer(p_hwfn, 8238c2ecf20Sopenharmony_ci p_ll2_conn->my_id, 8248c2ecf20Sopenharmony_ci p_buffer->rx_buffer_phys_addr, 8258c2ecf20Sopenharmony_ci 0, p_buffer, true); 8268c2ecf20Sopenharmony_ci if (rc) { 8278c2ecf20Sopenharmony_ci qed_ooo_put_free_buffer(p_hwfn, 8288c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info, p_buffer); 8298c2ecf20Sopenharmony_ci break; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic int qed_ll2_lb_rxq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn = (struct qed_ll2_info *)p_cookie; 8378c2ecf20Sopenharmony_ci int rc; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci if (!p_ll2_conn) 8408c2ecf20Sopenharmony_ci return 0; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (!QED_LL2_RX_REGISTERED(p_ll2_conn)) 8438c2ecf20Sopenharmony_ci return 0; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci rc = qed_ll2_lb_rxq_handler(p_hwfn, p_ll2_conn); 8468c2ecf20Sopenharmony_ci if (rc) 8478c2ecf20Sopenharmony_ci return rc; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci qed_ooo_submit_rx_buffers(p_hwfn, p_ll2_conn); 8508c2ecf20Sopenharmony_ci qed_ooo_submit_tx_buffers(p_hwfn, p_ll2_conn); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci return 0; 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cistatic int qed_ll2_lb_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn = (struct qed_ll2_info *)p_cookie; 8588c2ecf20Sopenharmony_ci struct qed_ll2_tx_queue *p_tx = &p_ll2_conn->tx_queue; 8598c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet *p_pkt = NULL; 8608c2ecf20Sopenharmony_ci struct qed_ooo_buffer *p_buffer; 8618c2ecf20Sopenharmony_ci bool b_dont_submit_rx = false; 8628c2ecf20Sopenharmony_ci u16 new_idx = 0, num_bds = 0; 8638c2ecf20Sopenharmony_ci int rc; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (!p_ll2_conn) 8668c2ecf20Sopenharmony_ci return 0; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (!QED_LL2_TX_REGISTERED(p_ll2_conn)) 8698c2ecf20Sopenharmony_ci return 0; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci new_idx = le16_to_cpu(*p_tx->p_fw_cons); 8728c2ecf20Sopenharmony_ci num_bds = ((s16)new_idx - (s16)p_tx->bds_idx); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (!num_bds) 8758c2ecf20Sopenharmony_ci return 0; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci while (num_bds) { 8788c2ecf20Sopenharmony_ci if (list_empty(&p_tx->active_descq)) 8798c2ecf20Sopenharmony_ci return -EINVAL; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci p_pkt = list_first_entry(&p_tx->active_descq, 8828c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet, list_entry); 8838c2ecf20Sopenharmony_ci if (!p_pkt) 8848c2ecf20Sopenharmony_ci return -EINVAL; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (p_pkt->bd_used != 1) { 8878c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 8888c2ecf20Sopenharmony_ci "Unexpectedly many BDs(%d) in TX OOO completion\n", 8898c2ecf20Sopenharmony_ci p_pkt->bd_used); 8908c2ecf20Sopenharmony_ci return -EINVAL; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci list_del(&p_pkt->list_entry); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci num_bds--; 8968c2ecf20Sopenharmony_ci p_tx->bds_idx++; 8978c2ecf20Sopenharmony_ci qed_chain_consume(&p_tx->txq_chain); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie; 9008c2ecf20Sopenharmony_ci list_add_tail(&p_pkt->list_entry, &p_tx->free_descq); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (b_dont_submit_rx) { 9038c2ecf20Sopenharmony_ci qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info, 9048c2ecf20Sopenharmony_ci p_buffer); 9058c2ecf20Sopenharmony_ci continue; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci rc = qed_ll2_post_rx_buffer(p_hwfn, p_ll2_conn->my_id, 9098c2ecf20Sopenharmony_ci p_buffer->rx_buffer_phys_addr, 0, 9108c2ecf20Sopenharmony_ci p_buffer, true); 9118c2ecf20Sopenharmony_ci if (rc != 0) { 9128c2ecf20Sopenharmony_ci qed_ooo_put_free_buffer(p_hwfn, 9138c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info, p_buffer); 9148c2ecf20Sopenharmony_ci b_dont_submit_rx = true; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci qed_ooo_submit_tx_buffers(p_hwfn, p_ll2_conn); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci return 0; 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_cistatic void qed_ll2_stop_ooo(struct qed_hwfn *p_hwfn) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci u8 *handle = &p_hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, (QED_MSG_STORAGE | QED_MSG_LL2), 9288c2ecf20Sopenharmony_ci "Stopping LL2 OOO queue [%02x]\n", *handle); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci qed_ll2_terminate_connection(p_hwfn, *handle); 9318c2ecf20Sopenharmony_ci qed_ll2_release_connection(p_hwfn, *handle); 9328c2ecf20Sopenharmony_ci *handle = QED_LL2_UNUSED_HANDLE; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn, 9368c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn, 9378c2ecf20Sopenharmony_ci u8 action_on_error) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci enum qed_ll2_conn_type conn_type = p_ll2_conn->input.conn_type; 9408c2ecf20Sopenharmony_ci struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue; 9418c2ecf20Sopenharmony_ci struct core_rx_start_ramrod_data *p_ramrod = NULL; 9428c2ecf20Sopenharmony_ci struct qed_spq_entry *p_ent = NULL; 9438c2ecf20Sopenharmony_ci struct qed_sp_init_data init_data; 9448c2ecf20Sopenharmony_ci u16 cqe_pbl_size; 9458c2ecf20Sopenharmony_ci int rc = 0; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* Get SPQ entry */ 9488c2ecf20Sopenharmony_ci memset(&init_data, 0, sizeof(init_data)); 9498c2ecf20Sopenharmony_ci init_data.cid = p_ll2_conn->cid; 9508c2ecf20Sopenharmony_ci init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; 9518c2ecf20Sopenharmony_ci init_data.comp_mode = QED_SPQ_MODE_EBLOCK; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci rc = qed_sp_init_request(p_hwfn, &p_ent, 9548c2ecf20Sopenharmony_ci CORE_RAMROD_RX_QUEUE_START, 9558c2ecf20Sopenharmony_ci PROTOCOLID_CORE, &init_data); 9568c2ecf20Sopenharmony_ci if (rc) 9578c2ecf20Sopenharmony_ci return rc; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci p_ramrod = &p_ent->ramrod.core_rx_queue_start; 9608c2ecf20Sopenharmony_ci memset(p_ramrod, 0, sizeof(*p_ramrod)); 9618c2ecf20Sopenharmony_ci p_ramrod->sb_id = cpu_to_le16(qed_int_get_sp_sb_id(p_hwfn)); 9628c2ecf20Sopenharmony_ci p_ramrod->sb_index = p_rx->rx_sb_index; 9638c2ecf20Sopenharmony_ci p_ramrod->complete_event_flg = 1; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci p_ramrod->mtu = cpu_to_le16(p_ll2_conn->input.mtu); 9668c2ecf20Sopenharmony_ci DMA_REGPAIR_LE(p_ramrod->bd_base, p_rx->rxq_chain.p_phys_addr); 9678c2ecf20Sopenharmony_ci cqe_pbl_size = (u16)qed_chain_get_page_cnt(&p_rx->rcq_chain); 9688c2ecf20Sopenharmony_ci p_ramrod->num_of_pbl_pages = cpu_to_le16(cqe_pbl_size); 9698c2ecf20Sopenharmony_ci DMA_REGPAIR_LE(p_ramrod->cqe_pbl_addr, 9708c2ecf20Sopenharmony_ci qed_chain_get_pbl_phys(&p_rx->rcq_chain)); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci p_ramrod->drop_ttl0_flg = p_ll2_conn->input.rx_drop_ttl0_flg; 9738c2ecf20Sopenharmony_ci p_ramrod->inner_vlan_stripping_en = 9748c2ecf20Sopenharmony_ci p_ll2_conn->input.rx_vlan_removal_en; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits) && 9778c2ecf20Sopenharmony_ci p_ll2_conn->input.conn_type == QED_LL2_TYPE_FCOE) 9788c2ecf20Sopenharmony_ci p_ramrod->report_outer_vlan = 1; 9798c2ecf20Sopenharmony_ci p_ramrod->queue_id = p_ll2_conn->queue_id; 9808c2ecf20Sopenharmony_ci p_ramrod->main_func_queue = p_ll2_conn->main_func_queue ? 1 : 0; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (test_bit(QED_MF_LL2_NON_UNICAST, &p_hwfn->cdev->mf_bits) && 9838c2ecf20Sopenharmony_ci p_ramrod->main_func_queue && conn_type != QED_LL2_TYPE_ROCE && 9848c2ecf20Sopenharmony_ci conn_type != QED_LL2_TYPE_IWARP) { 9858c2ecf20Sopenharmony_ci p_ramrod->mf_si_bcast_accept_all = 1; 9868c2ecf20Sopenharmony_ci p_ramrod->mf_si_mcast_accept_all = 1; 9878c2ecf20Sopenharmony_ci } else { 9888c2ecf20Sopenharmony_ci p_ramrod->mf_si_bcast_accept_all = 0; 9898c2ecf20Sopenharmony_ci p_ramrod->mf_si_mcast_accept_all = 0; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci p_ramrod->action_on_error.error_type = action_on_error; 9938c2ecf20Sopenharmony_ci p_ramrod->gsi_offload_flag = p_ll2_conn->input.gsi_enable; 9948c2ecf20Sopenharmony_ci p_ramrod->zero_prod_flg = 1; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci return qed_spq_post(p_hwfn, p_ent, NULL); 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, 10008c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci enum qed_ll2_conn_type conn_type = p_ll2_conn->input.conn_type; 10038c2ecf20Sopenharmony_ci struct qed_ll2_tx_queue *p_tx = &p_ll2_conn->tx_queue; 10048c2ecf20Sopenharmony_ci struct core_tx_start_ramrod_data *p_ramrod = NULL; 10058c2ecf20Sopenharmony_ci struct qed_spq_entry *p_ent = NULL; 10068c2ecf20Sopenharmony_ci struct qed_sp_init_data init_data; 10078c2ecf20Sopenharmony_ci u16 pq_id = 0, pbl_size; 10088c2ecf20Sopenharmony_ci int rc = -EINVAL; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci if (!QED_LL2_TX_REGISTERED(p_ll2_conn)) 10118c2ecf20Sopenharmony_ci return 0; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) 10148c2ecf20Sopenharmony_ci p_ll2_conn->tx_stats_en = 0; 10158c2ecf20Sopenharmony_ci else 10168c2ecf20Sopenharmony_ci p_ll2_conn->tx_stats_en = 1; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci /* Get SPQ entry */ 10198c2ecf20Sopenharmony_ci memset(&init_data, 0, sizeof(init_data)); 10208c2ecf20Sopenharmony_ci init_data.cid = p_ll2_conn->cid; 10218c2ecf20Sopenharmony_ci init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; 10228c2ecf20Sopenharmony_ci init_data.comp_mode = QED_SPQ_MODE_EBLOCK; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci rc = qed_sp_init_request(p_hwfn, &p_ent, 10258c2ecf20Sopenharmony_ci CORE_RAMROD_TX_QUEUE_START, 10268c2ecf20Sopenharmony_ci PROTOCOLID_CORE, &init_data); 10278c2ecf20Sopenharmony_ci if (rc) 10288c2ecf20Sopenharmony_ci return rc; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci p_ramrod = &p_ent->ramrod.core_tx_queue_start; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci p_ramrod->sb_id = cpu_to_le16(qed_int_get_sp_sb_id(p_hwfn)); 10338c2ecf20Sopenharmony_ci p_ramrod->sb_index = p_tx->tx_sb_index; 10348c2ecf20Sopenharmony_ci p_ramrod->mtu = cpu_to_le16(p_ll2_conn->input.mtu); 10358c2ecf20Sopenharmony_ci p_ramrod->stats_en = p_ll2_conn->tx_stats_en; 10368c2ecf20Sopenharmony_ci p_ramrod->stats_id = p_ll2_conn->tx_stats_id; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci DMA_REGPAIR_LE(p_ramrod->pbl_base_addr, 10398c2ecf20Sopenharmony_ci qed_chain_get_pbl_phys(&p_tx->txq_chain)); 10408c2ecf20Sopenharmony_ci pbl_size = qed_chain_get_page_cnt(&p_tx->txq_chain); 10418c2ecf20Sopenharmony_ci p_ramrod->pbl_size = cpu_to_le16(pbl_size); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci switch (p_ll2_conn->input.tx_tc) { 10448c2ecf20Sopenharmony_ci case PURE_LB_TC: 10458c2ecf20Sopenharmony_ci pq_id = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_LB); 10468c2ecf20Sopenharmony_ci break; 10478c2ecf20Sopenharmony_ci case PKT_LB_TC: 10488c2ecf20Sopenharmony_ci pq_id = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OOO); 10498c2ecf20Sopenharmony_ci break; 10508c2ecf20Sopenharmony_ci default: 10518c2ecf20Sopenharmony_ci pq_id = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD); 10528c2ecf20Sopenharmony_ci break; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci p_ramrod->qm_pq_id = cpu_to_le16(pq_id); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci switch (conn_type) { 10588c2ecf20Sopenharmony_ci case QED_LL2_TYPE_FCOE: 10598c2ecf20Sopenharmony_ci p_ramrod->conn_type = PROTOCOLID_FCOE; 10608c2ecf20Sopenharmony_ci break; 10618c2ecf20Sopenharmony_ci case QED_LL2_TYPE_ISCSI: 10628c2ecf20Sopenharmony_ci p_ramrod->conn_type = PROTOCOLID_ISCSI; 10638c2ecf20Sopenharmony_ci break; 10648c2ecf20Sopenharmony_ci case QED_LL2_TYPE_ROCE: 10658c2ecf20Sopenharmony_ci p_ramrod->conn_type = PROTOCOLID_ROCE; 10668c2ecf20Sopenharmony_ci break; 10678c2ecf20Sopenharmony_ci case QED_LL2_TYPE_IWARP: 10688c2ecf20Sopenharmony_ci p_ramrod->conn_type = PROTOCOLID_IWARP; 10698c2ecf20Sopenharmony_ci break; 10708c2ecf20Sopenharmony_ci case QED_LL2_TYPE_OOO: 10718c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) 10728c2ecf20Sopenharmony_ci p_ramrod->conn_type = PROTOCOLID_ISCSI; 10738c2ecf20Sopenharmony_ci else 10748c2ecf20Sopenharmony_ci p_ramrod->conn_type = PROTOCOLID_IWARP; 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci default: 10778c2ecf20Sopenharmony_ci p_ramrod->conn_type = PROTOCOLID_ETH; 10788c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Unknown connection type: %d\n", conn_type); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci p_ramrod->gsi_offload_flag = p_ll2_conn->input.gsi_enable; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci rc = qed_spq_post(p_hwfn, p_ent, NULL); 10848c2ecf20Sopenharmony_ci if (rc) 10858c2ecf20Sopenharmony_ci return rc; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci rc = qed_db_recovery_add(p_hwfn->cdev, p_tx->doorbell_addr, 10888c2ecf20Sopenharmony_ci &p_tx->db_msg, DB_REC_WIDTH_32B, 10898c2ecf20Sopenharmony_ci DB_REC_KERNEL); 10908c2ecf20Sopenharmony_ci return rc; 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cistatic int qed_sp_ll2_rx_queue_stop(struct qed_hwfn *p_hwfn, 10948c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn) 10958c2ecf20Sopenharmony_ci{ 10968c2ecf20Sopenharmony_ci struct core_rx_stop_ramrod_data *p_ramrod = NULL; 10978c2ecf20Sopenharmony_ci struct qed_spq_entry *p_ent = NULL; 10988c2ecf20Sopenharmony_ci struct qed_sp_init_data init_data; 10998c2ecf20Sopenharmony_ci int rc = -EINVAL; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* Get SPQ entry */ 11028c2ecf20Sopenharmony_ci memset(&init_data, 0, sizeof(init_data)); 11038c2ecf20Sopenharmony_ci init_data.cid = p_ll2_conn->cid; 11048c2ecf20Sopenharmony_ci init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; 11058c2ecf20Sopenharmony_ci init_data.comp_mode = QED_SPQ_MODE_EBLOCK; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci rc = qed_sp_init_request(p_hwfn, &p_ent, 11088c2ecf20Sopenharmony_ci CORE_RAMROD_RX_QUEUE_STOP, 11098c2ecf20Sopenharmony_ci PROTOCOLID_CORE, &init_data); 11108c2ecf20Sopenharmony_ci if (rc) 11118c2ecf20Sopenharmony_ci return rc; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci p_ramrod = &p_ent->ramrod.core_rx_queue_stop; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci p_ramrod->complete_event_flg = 1; 11168c2ecf20Sopenharmony_ci p_ramrod->queue_id = p_ll2_conn->queue_id; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci return qed_spq_post(p_hwfn, p_ent, NULL); 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic int qed_sp_ll2_tx_queue_stop(struct qed_hwfn *p_hwfn, 11228c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci struct qed_ll2_tx_queue *p_tx = &p_ll2_conn->tx_queue; 11258c2ecf20Sopenharmony_ci struct qed_spq_entry *p_ent = NULL; 11268c2ecf20Sopenharmony_ci struct qed_sp_init_data init_data; 11278c2ecf20Sopenharmony_ci int rc = -EINVAL; 11288c2ecf20Sopenharmony_ci qed_db_recovery_del(p_hwfn->cdev, p_tx->doorbell_addr, &p_tx->db_msg); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* Get SPQ entry */ 11318c2ecf20Sopenharmony_ci memset(&init_data, 0, sizeof(init_data)); 11328c2ecf20Sopenharmony_ci init_data.cid = p_ll2_conn->cid; 11338c2ecf20Sopenharmony_ci init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; 11348c2ecf20Sopenharmony_ci init_data.comp_mode = QED_SPQ_MODE_EBLOCK; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci rc = qed_sp_init_request(p_hwfn, &p_ent, 11378c2ecf20Sopenharmony_ci CORE_RAMROD_TX_QUEUE_STOP, 11388c2ecf20Sopenharmony_ci PROTOCOLID_CORE, &init_data); 11398c2ecf20Sopenharmony_ci if (rc) 11408c2ecf20Sopenharmony_ci return rc; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci return qed_spq_post(p_hwfn, p_ent, NULL); 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic int 11468c2ecf20Sopenharmony_ciqed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn, 11478c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_info) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct qed_chain_init_params params = { 11508c2ecf20Sopenharmony_ci .intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE, 11518c2ecf20Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U16, 11528c2ecf20Sopenharmony_ci .num_elems = p_ll2_info->input.rx_num_desc, 11538c2ecf20Sopenharmony_ci }; 11548c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 11558c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet *p_descq; 11568c2ecf20Sopenharmony_ci u32 capacity; 11578c2ecf20Sopenharmony_ci int rc = 0; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (!p_ll2_info->input.rx_num_desc) 11608c2ecf20Sopenharmony_ci goto out; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci params.mode = QED_CHAIN_MODE_NEXT_PTR; 11638c2ecf20Sopenharmony_ci params.elem_size = sizeof(struct core_rx_bd); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci rc = qed_chain_alloc(cdev, &p_ll2_info->rx_queue.rxq_chain, ¶ms); 11668c2ecf20Sopenharmony_ci if (rc) { 11678c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to allocate ll2 rxq chain\n"); 11688c2ecf20Sopenharmony_ci goto out; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci capacity = qed_chain_get_capacity(&p_ll2_info->rx_queue.rxq_chain); 11728c2ecf20Sopenharmony_ci p_descq = kcalloc(capacity, sizeof(struct qed_ll2_rx_packet), 11738c2ecf20Sopenharmony_ci GFP_KERNEL); 11748c2ecf20Sopenharmony_ci if (!p_descq) { 11758c2ecf20Sopenharmony_ci rc = -ENOMEM; 11768c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to allocate ll2 Rx desc\n"); 11778c2ecf20Sopenharmony_ci goto out; 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci p_ll2_info->rx_queue.descq_array = p_descq; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci params.mode = QED_CHAIN_MODE_PBL; 11828c2ecf20Sopenharmony_ci params.elem_size = sizeof(struct core_rx_fast_path_cqe); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci rc = qed_chain_alloc(cdev, &p_ll2_info->rx_queue.rcq_chain, ¶ms); 11858c2ecf20Sopenharmony_ci if (rc) { 11868c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to allocate ll2 rcq chain\n"); 11878c2ecf20Sopenharmony_ci goto out; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_LL2, 11918c2ecf20Sopenharmony_ci "Allocated LL2 Rxq [Type %08x] with 0x%08x buffers\n", 11928c2ecf20Sopenharmony_ci p_ll2_info->input.conn_type, p_ll2_info->input.rx_num_desc); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ciout: 11958c2ecf20Sopenharmony_ci return rc; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic int qed_ll2_acquire_connection_tx(struct qed_hwfn *p_hwfn, 11998c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_info) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci struct qed_chain_init_params params = { 12028c2ecf20Sopenharmony_ci .mode = QED_CHAIN_MODE_PBL, 12038c2ecf20Sopenharmony_ci .intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE, 12048c2ecf20Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U16, 12058c2ecf20Sopenharmony_ci .num_elems = p_ll2_info->input.tx_num_desc, 12068c2ecf20Sopenharmony_ci .elem_size = sizeof(struct core_tx_bd), 12078c2ecf20Sopenharmony_ci }; 12088c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet *p_descq; 12098c2ecf20Sopenharmony_ci size_t desc_size; 12108c2ecf20Sopenharmony_ci u32 capacity; 12118c2ecf20Sopenharmony_ci int rc = 0; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci if (!p_ll2_info->input.tx_num_desc) 12148c2ecf20Sopenharmony_ci goto out; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci rc = qed_chain_alloc(p_hwfn->cdev, &p_ll2_info->tx_queue.txq_chain, 12178c2ecf20Sopenharmony_ci ¶ms); 12188c2ecf20Sopenharmony_ci if (rc) 12198c2ecf20Sopenharmony_ci goto out; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci capacity = qed_chain_get_capacity(&p_ll2_info->tx_queue.txq_chain); 12228c2ecf20Sopenharmony_ci /* All bds_set elements are flexibily added. */ 12238c2ecf20Sopenharmony_ci desc_size = struct_size(p_descq, bds_set, 12248c2ecf20Sopenharmony_ci p_ll2_info->input.tx_max_bds_per_packet); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci p_descq = kcalloc(capacity, desc_size, GFP_KERNEL); 12278c2ecf20Sopenharmony_ci if (!p_descq) { 12288c2ecf20Sopenharmony_ci rc = -ENOMEM; 12298c2ecf20Sopenharmony_ci goto out; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci p_ll2_info->tx_queue.descq_mem = p_descq; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_LL2, 12348c2ecf20Sopenharmony_ci "Allocated LL2 Txq [Type %08x] with 0x%08x buffers\n", 12358c2ecf20Sopenharmony_ci p_ll2_info->input.conn_type, p_ll2_info->input.tx_num_desc); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ciout: 12388c2ecf20Sopenharmony_ci if (rc) 12398c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 12408c2ecf20Sopenharmony_ci "Can't allocate memory for Tx LL2 with 0x%08x buffers\n", 12418c2ecf20Sopenharmony_ci p_ll2_info->input.tx_num_desc); 12428c2ecf20Sopenharmony_ci return rc; 12438c2ecf20Sopenharmony_ci} 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_cistatic int 12468c2ecf20Sopenharmony_ciqed_ll2_acquire_connection_ooo(struct qed_hwfn *p_hwfn, 12478c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_info, u16 mtu) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci struct qed_ooo_buffer *p_buf = NULL; 12508c2ecf20Sopenharmony_ci void *p_virt; 12518c2ecf20Sopenharmony_ci u16 buf_idx; 12528c2ecf20Sopenharmony_ci int rc = 0; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (p_ll2_info->input.conn_type != QED_LL2_TYPE_OOO) 12558c2ecf20Sopenharmony_ci return rc; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci /* Correct number of requested OOO buffers if needed */ 12588c2ecf20Sopenharmony_ci if (!p_ll2_info->input.rx_num_ooo_buffers) { 12598c2ecf20Sopenharmony_ci u16 num_desc = p_ll2_info->input.rx_num_desc; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (!num_desc) 12628c2ecf20Sopenharmony_ci return -EINVAL; 12638c2ecf20Sopenharmony_ci p_ll2_info->input.rx_num_ooo_buffers = num_desc * 2; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci for (buf_idx = 0; buf_idx < p_ll2_info->input.rx_num_ooo_buffers; 12678c2ecf20Sopenharmony_ci buf_idx++) { 12688c2ecf20Sopenharmony_ci p_buf = kzalloc(sizeof(*p_buf), GFP_KERNEL); 12698c2ecf20Sopenharmony_ci if (!p_buf) { 12708c2ecf20Sopenharmony_ci rc = -ENOMEM; 12718c2ecf20Sopenharmony_ci goto out; 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci p_buf->rx_buffer_size = mtu + 26 + ETH_CACHE_LINE_SIZE; 12758c2ecf20Sopenharmony_ci p_buf->rx_buffer_size = (p_buf->rx_buffer_size + 12768c2ecf20Sopenharmony_ci ETH_CACHE_LINE_SIZE - 1) & 12778c2ecf20Sopenharmony_ci ~(ETH_CACHE_LINE_SIZE - 1); 12788c2ecf20Sopenharmony_ci p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 12798c2ecf20Sopenharmony_ci p_buf->rx_buffer_size, 12808c2ecf20Sopenharmony_ci &p_buf->rx_buffer_phys_addr, 12818c2ecf20Sopenharmony_ci GFP_KERNEL); 12828c2ecf20Sopenharmony_ci if (!p_virt) { 12838c2ecf20Sopenharmony_ci kfree(p_buf); 12848c2ecf20Sopenharmony_ci rc = -ENOMEM; 12858c2ecf20Sopenharmony_ci goto out; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci p_buf->rx_buffer_virt_addr = p_virt; 12898c2ecf20Sopenharmony_ci qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info, p_buf); 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_LL2, 12938c2ecf20Sopenharmony_ci "Allocated [%04x] LL2 OOO buffers [each of size 0x%08x]\n", 12948c2ecf20Sopenharmony_ci p_ll2_info->input.rx_num_ooo_buffers, p_buf->rx_buffer_size); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ciout: 12978c2ecf20Sopenharmony_ci return rc; 12988c2ecf20Sopenharmony_ci} 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_cistatic int 13018c2ecf20Sopenharmony_ciqed_ll2_set_cbs(struct qed_ll2_info *p_ll2_info, const struct qed_ll2_cbs *cbs) 13028c2ecf20Sopenharmony_ci{ 13038c2ecf20Sopenharmony_ci if (!cbs || (!cbs->rx_comp_cb || 13048c2ecf20Sopenharmony_ci !cbs->rx_release_cb || 13058c2ecf20Sopenharmony_ci !cbs->tx_comp_cb || !cbs->tx_release_cb || !cbs->cookie)) 13068c2ecf20Sopenharmony_ci return -EINVAL; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci p_ll2_info->cbs.rx_comp_cb = cbs->rx_comp_cb; 13098c2ecf20Sopenharmony_ci p_ll2_info->cbs.rx_release_cb = cbs->rx_release_cb; 13108c2ecf20Sopenharmony_ci p_ll2_info->cbs.tx_comp_cb = cbs->tx_comp_cb; 13118c2ecf20Sopenharmony_ci p_ll2_info->cbs.tx_release_cb = cbs->tx_release_cb; 13128c2ecf20Sopenharmony_ci p_ll2_info->cbs.slowpath_cb = cbs->slowpath_cb; 13138c2ecf20Sopenharmony_ci p_ll2_info->cbs.cookie = cbs->cookie; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci return 0; 13168c2ecf20Sopenharmony_ci} 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic void _qed_ll2_calc_allowed_conns(struct qed_hwfn *p_hwfn, 13198c2ecf20Sopenharmony_ci struct qed_ll2_acquire_data *data, 13208c2ecf20Sopenharmony_ci u8 *start_idx, u8 *last_idx) 13218c2ecf20Sopenharmony_ci{ 13228c2ecf20Sopenharmony_ci /* LL2 queues handles will be split as follows: 13238c2ecf20Sopenharmony_ci * First will be the legacy queues, and then the ctx based. 13248c2ecf20Sopenharmony_ci */ 13258c2ecf20Sopenharmony_ci if (data->input.rx_conn_type == QED_LL2_RX_TYPE_LEGACY) { 13268c2ecf20Sopenharmony_ci *start_idx = QED_LL2_LEGACY_CONN_BASE_PF; 13278c2ecf20Sopenharmony_ci *last_idx = *start_idx + 13288c2ecf20Sopenharmony_ci QED_MAX_NUM_OF_LEGACY_LL2_CONNS_PF; 13298c2ecf20Sopenharmony_ci } else { 13308c2ecf20Sopenharmony_ci /* QED_LL2_RX_TYPE_CTX */ 13318c2ecf20Sopenharmony_ci *start_idx = QED_LL2_CTX_CONN_BASE_PF; 13328c2ecf20Sopenharmony_ci *last_idx = *start_idx + 13338c2ecf20Sopenharmony_ci QED_MAX_NUM_OF_CTX_LL2_CONNS_PF; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic enum core_error_handle 13388c2ecf20Sopenharmony_ciqed_ll2_get_error_choice(enum qed_ll2_error_handle err) 13398c2ecf20Sopenharmony_ci{ 13408c2ecf20Sopenharmony_ci switch (err) { 13418c2ecf20Sopenharmony_ci case QED_LL2_DROP_PACKET: 13428c2ecf20Sopenharmony_ci return LL2_DROP_PACKET; 13438c2ecf20Sopenharmony_ci case QED_LL2_DO_NOTHING: 13448c2ecf20Sopenharmony_ci return LL2_DO_NOTHING; 13458c2ecf20Sopenharmony_ci case QED_LL2_ASSERT: 13468c2ecf20Sopenharmony_ci return LL2_ASSERT; 13478c2ecf20Sopenharmony_ci default: 13488c2ecf20Sopenharmony_ci return LL2_DO_NOTHING; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci} 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ciint qed_ll2_acquire_connection(void *cxt, struct qed_ll2_acquire_data *data) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 13558c2ecf20Sopenharmony_ci qed_int_comp_cb_t comp_rx_cb, comp_tx_cb; 13568c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_info = NULL; 13578c2ecf20Sopenharmony_ci u8 i, first_idx, last_idx, *p_tx_max; 13588c2ecf20Sopenharmony_ci int rc; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci if (!data->p_connection_handle || !p_hwfn->p_ll2_info) 13618c2ecf20Sopenharmony_ci return -EINVAL; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci _qed_ll2_calc_allowed_conns(p_hwfn, data, &first_idx, &last_idx); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* Find a free connection to be used */ 13668c2ecf20Sopenharmony_ci for (i = first_idx; i < last_idx; i++) { 13678c2ecf20Sopenharmony_ci mutex_lock(&p_hwfn->p_ll2_info[i].mutex); 13688c2ecf20Sopenharmony_ci if (p_hwfn->p_ll2_info[i].b_active) { 13698c2ecf20Sopenharmony_ci mutex_unlock(&p_hwfn->p_ll2_info[i].mutex); 13708c2ecf20Sopenharmony_ci continue; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci p_hwfn->p_ll2_info[i].b_active = true; 13748c2ecf20Sopenharmony_ci p_ll2_info = &p_hwfn->p_ll2_info[i]; 13758c2ecf20Sopenharmony_ci mutex_unlock(&p_hwfn->p_ll2_info[i].mutex); 13768c2ecf20Sopenharmony_ci break; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci if (!p_ll2_info) 13798c2ecf20Sopenharmony_ci return -EBUSY; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci memcpy(&p_ll2_info->input, &data->input, sizeof(p_ll2_info->input)); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci switch (data->input.tx_dest) { 13848c2ecf20Sopenharmony_ci case QED_LL2_TX_DEST_NW: 13858c2ecf20Sopenharmony_ci p_ll2_info->tx_dest = CORE_TX_DEST_NW; 13868c2ecf20Sopenharmony_ci break; 13878c2ecf20Sopenharmony_ci case QED_LL2_TX_DEST_LB: 13888c2ecf20Sopenharmony_ci p_ll2_info->tx_dest = CORE_TX_DEST_LB; 13898c2ecf20Sopenharmony_ci break; 13908c2ecf20Sopenharmony_ci case QED_LL2_TX_DEST_DROP: 13918c2ecf20Sopenharmony_ci p_ll2_info->tx_dest = CORE_TX_DEST_DROP; 13928c2ecf20Sopenharmony_ci break; 13938c2ecf20Sopenharmony_ci default: 13948c2ecf20Sopenharmony_ci return -EINVAL; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (data->input.conn_type == QED_LL2_TYPE_OOO || 13988c2ecf20Sopenharmony_ci data->input.secondary_queue) 13998c2ecf20Sopenharmony_ci p_ll2_info->main_func_queue = false; 14008c2ecf20Sopenharmony_ci else 14018c2ecf20Sopenharmony_ci p_ll2_info->main_func_queue = true; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci /* Correct maximum number of Tx BDs */ 14048c2ecf20Sopenharmony_ci p_tx_max = &p_ll2_info->input.tx_max_bds_per_packet; 14058c2ecf20Sopenharmony_ci if (*p_tx_max == 0) 14068c2ecf20Sopenharmony_ci *p_tx_max = CORE_LL2_TX_MAX_BDS_PER_PACKET; 14078c2ecf20Sopenharmony_ci else 14088c2ecf20Sopenharmony_ci *p_tx_max = min_t(u8, *p_tx_max, 14098c2ecf20Sopenharmony_ci CORE_LL2_TX_MAX_BDS_PER_PACKET); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci rc = qed_ll2_set_cbs(p_ll2_info, data->cbs); 14128c2ecf20Sopenharmony_ci if (rc) { 14138c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Invalid callback functions\n"); 14148c2ecf20Sopenharmony_ci goto q_allocate_fail; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci rc = qed_ll2_acquire_connection_rx(p_hwfn, p_ll2_info); 14188c2ecf20Sopenharmony_ci if (rc) 14198c2ecf20Sopenharmony_ci goto q_allocate_fail; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci rc = qed_ll2_acquire_connection_tx(p_hwfn, p_ll2_info); 14228c2ecf20Sopenharmony_ci if (rc) 14238c2ecf20Sopenharmony_ci goto q_allocate_fail; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci rc = qed_ll2_acquire_connection_ooo(p_hwfn, p_ll2_info, 14268c2ecf20Sopenharmony_ci data->input.mtu); 14278c2ecf20Sopenharmony_ci if (rc) 14288c2ecf20Sopenharmony_ci goto q_allocate_fail; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci /* Register callbacks for the Rx/Tx queues */ 14318c2ecf20Sopenharmony_ci if (data->input.conn_type == QED_LL2_TYPE_OOO) { 14328c2ecf20Sopenharmony_ci comp_rx_cb = qed_ll2_lb_rxq_completion; 14338c2ecf20Sopenharmony_ci comp_tx_cb = qed_ll2_lb_txq_completion; 14348c2ecf20Sopenharmony_ci } else { 14358c2ecf20Sopenharmony_ci comp_rx_cb = qed_ll2_rxq_completion; 14368c2ecf20Sopenharmony_ci comp_tx_cb = qed_ll2_txq_completion; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if (data->input.rx_num_desc) { 14408c2ecf20Sopenharmony_ci qed_int_register_cb(p_hwfn, comp_rx_cb, 14418c2ecf20Sopenharmony_ci &p_hwfn->p_ll2_info[i], 14428c2ecf20Sopenharmony_ci &p_ll2_info->rx_queue.rx_sb_index, 14438c2ecf20Sopenharmony_ci &p_ll2_info->rx_queue.p_fw_cons); 14448c2ecf20Sopenharmony_ci p_ll2_info->rx_queue.b_cb_registered = true; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (data->input.tx_num_desc) { 14488c2ecf20Sopenharmony_ci qed_int_register_cb(p_hwfn, 14498c2ecf20Sopenharmony_ci comp_tx_cb, 14508c2ecf20Sopenharmony_ci &p_hwfn->p_ll2_info[i], 14518c2ecf20Sopenharmony_ci &p_ll2_info->tx_queue.tx_sb_index, 14528c2ecf20Sopenharmony_ci &p_ll2_info->tx_queue.p_fw_cons); 14538c2ecf20Sopenharmony_ci p_ll2_info->tx_queue.b_cb_registered = true; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci *data->p_connection_handle = i; 14578c2ecf20Sopenharmony_ci return rc; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ciq_allocate_fail: 14608c2ecf20Sopenharmony_ci qed_ll2_release_connection(p_hwfn, i); 14618c2ecf20Sopenharmony_ci return -ENOMEM; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic int qed_ll2_establish_connection_rx(struct qed_hwfn *p_hwfn, 14658c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci enum qed_ll2_error_handle error_input; 14688c2ecf20Sopenharmony_ci enum core_error_handle error_mode; 14698c2ecf20Sopenharmony_ci u8 action_on_error = 0; 14708c2ecf20Sopenharmony_ci int rc; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if (!QED_LL2_RX_REGISTERED(p_ll2_conn)) 14738c2ecf20Sopenharmony_ci return 0; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci DIRECT_REG_WR(p_ll2_conn->rx_queue.set_prod_addr, 0x0); 14768c2ecf20Sopenharmony_ci error_input = p_ll2_conn->input.ai_err_packet_too_big; 14778c2ecf20Sopenharmony_ci error_mode = qed_ll2_get_error_choice(error_input); 14788c2ecf20Sopenharmony_ci SET_FIELD(action_on_error, 14798c2ecf20Sopenharmony_ci CORE_RX_ACTION_ON_ERROR_PACKET_TOO_BIG, error_mode); 14808c2ecf20Sopenharmony_ci error_input = p_ll2_conn->input.ai_err_no_buf; 14818c2ecf20Sopenharmony_ci error_mode = qed_ll2_get_error_choice(error_input); 14828c2ecf20Sopenharmony_ci SET_FIELD(action_on_error, CORE_RX_ACTION_ON_ERROR_NO_BUFF, error_mode); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci rc = qed_sp_ll2_rx_queue_start(p_hwfn, p_ll2_conn, action_on_error); 14858c2ecf20Sopenharmony_ci if (rc) 14868c2ecf20Sopenharmony_ci return rc; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci if (p_ll2_conn->rx_queue.ctx_based) { 14898c2ecf20Sopenharmony_ci rc = qed_db_recovery_add(p_hwfn->cdev, 14908c2ecf20Sopenharmony_ci p_ll2_conn->rx_queue.set_prod_addr, 14918c2ecf20Sopenharmony_ci &p_ll2_conn->rx_queue.db_data, 14928c2ecf20Sopenharmony_ci DB_REC_WIDTH_64B, DB_REC_KERNEL); 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci return rc; 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_cistatic void 14998c2ecf20Sopenharmony_ciqed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn, 15008c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_OOO) 15038c2ecf20Sopenharmony_ci return; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); 15068c2ecf20Sopenharmony_ci qed_ooo_submit_rx_buffers(p_hwfn, p_ll2_conn); 15078c2ecf20Sopenharmony_ci} 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_cistatic inline u8 qed_ll2_handle_to_queue_id(struct qed_hwfn *p_hwfn, 15108c2ecf20Sopenharmony_ci u8 handle, 15118c2ecf20Sopenharmony_ci u8 ll2_queue_type) 15128c2ecf20Sopenharmony_ci{ 15138c2ecf20Sopenharmony_ci u8 qid; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci if (ll2_queue_type == QED_LL2_RX_TYPE_LEGACY) 15168c2ecf20Sopenharmony_ci return p_hwfn->hw_info.resc_start[QED_LL2_RAM_QUEUE] + handle; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci /* QED_LL2_RX_TYPE_CTX 15198c2ecf20Sopenharmony_ci * FW distinguishes between the legacy queues (ram based) and the 15208c2ecf20Sopenharmony_ci * ctx based queues by the queue_id. 15218c2ecf20Sopenharmony_ci * The first MAX_NUM_LL2_RX_RAM_QUEUES queues are legacy 15228c2ecf20Sopenharmony_ci * and the queue ids above that are ctx base. 15238c2ecf20Sopenharmony_ci */ 15248c2ecf20Sopenharmony_ci qid = p_hwfn->hw_info.resc_start[QED_LL2_CTX_QUEUE] + 15258c2ecf20Sopenharmony_ci MAX_NUM_LL2_RX_RAM_QUEUES; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci /* See comment on the acquire connection for how the ll2 15288c2ecf20Sopenharmony_ci * queues handles are divided. 15298c2ecf20Sopenharmony_ci */ 15308c2ecf20Sopenharmony_ci qid += (handle - QED_MAX_NUM_OF_LEGACY_LL2_CONNS_PF); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci return qid; 15338c2ecf20Sopenharmony_ci} 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ciint qed_ll2_establish_connection(void *cxt, u8 connection_handle) 15368c2ecf20Sopenharmony_ci{ 15378c2ecf20Sopenharmony_ci struct e4_core_conn_context *p_cxt; 15388c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet *p_pkt; 15398c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn; 15408c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 15418c2ecf20Sopenharmony_ci struct qed_ll2_rx_queue *p_rx; 15428c2ecf20Sopenharmony_ci struct qed_ll2_tx_queue *p_tx; 15438c2ecf20Sopenharmony_ci struct qed_cxt_info cxt_info; 15448c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 15458c2ecf20Sopenharmony_ci int rc = -EINVAL; 15468c2ecf20Sopenharmony_ci u32 i, capacity; 15478c2ecf20Sopenharmony_ci size_t desc_size; 15488c2ecf20Sopenharmony_ci u8 qid; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 15518c2ecf20Sopenharmony_ci if (!p_ptt) 15528c2ecf20Sopenharmony_ci return -EAGAIN; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci p_ll2_conn = qed_ll2_handle_sanity_lock(p_hwfn, connection_handle); 15558c2ecf20Sopenharmony_ci if (!p_ll2_conn) { 15568c2ecf20Sopenharmony_ci rc = -EINVAL; 15578c2ecf20Sopenharmony_ci goto out; 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci p_rx = &p_ll2_conn->rx_queue; 15618c2ecf20Sopenharmony_ci p_tx = &p_ll2_conn->tx_queue; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci qed_chain_reset(&p_rx->rxq_chain); 15648c2ecf20Sopenharmony_ci qed_chain_reset(&p_rx->rcq_chain); 15658c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p_rx->active_descq); 15668c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p_rx->free_descq); 15678c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p_rx->posting_descq); 15688c2ecf20Sopenharmony_ci spin_lock_init(&p_rx->lock); 15698c2ecf20Sopenharmony_ci capacity = qed_chain_get_capacity(&p_rx->rxq_chain); 15708c2ecf20Sopenharmony_ci for (i = 0; i < capacity; i++) 15718c2ecf20Sopenharmony_ci list_add_tail(&p_rx->descq_array[i].list_entry, 15728c2ecf20Sopenharmony_ci &p_rx->free_descq); 15738c2ecf20Sopenharmony_ci *p_rx->p_fw_cons = 0; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci qed_chain_reset(&p_tx->txq_chain); 15768c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p_tx->active_descq); 15778c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p_tx->free_descq); 15788c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p_tx->sending_descq); 15798c2ecf20Sopenharmony_ci spin_lock_init(&p_tx->lock); 15808c2ecf20Sopenharmony_ci capacity = qed_chain_get_capacity(&p_tx->txq_chain); 15818c2ecf20Sopenharmony_ci /* All bds_set elements are flexibily added. */ 15828c2ecf20Sopenharmony_ci desc_size = struct_size(p_pkt, bds_set, 15838c2ecf20Sopenharmony_ci p_ll2_conn->input.tx_max_bds_per_packet); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci for (i = 0; i < capacity; i++) { 15868c2ecf20Sopenharmony_ci p_pkt = p_tx->descq_mem + desc_size * i; 15878c2ecf20Sopenharmony_ci list_add_tail(&p_pkt->list_entry, &p_tx->free_descq); 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ci p_tx->cur_completing_bd_idx = 0; 15908c2ecf20Sopenharmony_ci p_tx->bds_idx = 0; 15918c2ecf20Sopenharmony_ci p_tx->b_completing_packet = false; 15928c2ecf20Sopenharmony_ci p_tx->cur_send_packet = NULL; 15938c2ecf20Sopenharmony_ci p_tx->cur_send_frag_num = 0; 15948c2ecf20Sopenharmony_ci p_tx->cur_completing_frag_num = 0; 15958c2ecf20Sopenharmony_ci *p_tx->p_fw_cons = 0; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_CORE, &p_ll2_conn->cid); 15988c2ecf20Sopenharmony_ci if (rc) 15998c2ecf20Sopenharmony_ci goto out; 16008c2ecf20Sopenharmony_ci cxt_info.iid = p_ll2_conn->cid; 16018c2ecf20Sopenharmony_ci rc = qed_cxt_get_cid_info(p_hwfn, &cxt_info); 16028c2ecf20Sopenharmony_ci if (rc) { 16038c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Cannot find context info for cid=%d\n", 16048c2ecf20Sopenharmony_ci p_ll2_conn->cid); 16058c2ecf20Sopenharmony_ci goto out; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci p_cxt = cxt_info.p_cxt; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci memset(p_cxt, 0, sizeof(*p_cxt)); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci qid = qed_ll2_handle_to_queue_id(p_hwfn, connection_handle, 16138c2ecf20Sopenharmony_ci p_ll2_conn->input.rx_conn_type); 16148c2ecf20Sopenharmony_ci p_ll2_conn->queue_id = qid; 16158c2ecf20Sopenharmony_ci p_ll2_conn->tx_stats_id = qid; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_LL2, 16188c2ecf20Sopenharmony_ci "Establishing ll2 queue. PF %d ctx_based=%d abs qid=%d\n", 16198c2ecf20Sopenharmony_ci p_hwfn->rel_pf_id, p_ll2_conn->input.rx_conn_type, qid); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (p_ll2_conn->input.rx_conn_type == QED_LL2_RX_TYPE_LEGACY) { 16228c2ecf20Sopenharmony_ci p_rx->set_prod_addr = p_hwfn->regview + 16238c2ecf20Sopenharmony_ci GTT_BAR0_MAP_REG_TSDM_RAM + TSTORM_LL2_RX_PRODS_OFFSET(qid); 16248c2ecf20Sopenharmony_ci } else { 16258c2ecf20Sopenharmony_ci /* QED_LL2_RX_TYPE_CTX - using doorbell */ 16268c2ecf20Sopenharmony_ci p_rx->ctx_based = 1; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci p_rx->set_prod_addr = p_hwfn->doorbells + 16298c2ecf20Sopenharmony_ci p_hwfn->dpi_start_offset + 16308c2ecf20Sopenharmony_ci DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_LL2_PROD_UPDATE); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci /* prepare db data */ 16338c2ecf20Sopenharmony_ci p_rx->db_data.icid = cpu_to_le16((u16)p_ll2_conn->cid); 16348c2ecf20Sopenharmony_ci SET_FIELD(p_rx->db_data.params, 16358c2ecf20Sopenharmony_ci CORE_PWM_PROD_UPDATE_DATA_AGG_CMD, DB_AGG_CMD_SET); 16368c2ecf20Sopenharmony_ci SET_FIELD(p_rx->db_data.params, 16378c2ecf20Sopenharmony_ci CORE_PWM_PROD_UPDATE_DATA_RESERVED1, 0); 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci p_tx->doorbell_addr = (u8 __iomem *)p_hwfn->doorbells + 16418c2ecf20Sopenharmony_ci qed_db_addr(p_ll2_conn->cid, 16428c2ecf20Sopenharmony_ci DQ_DEMS_LEGACY); 16438c2ecf20Sopenharmony_ci /* prepare db data */ 16448c2ecf20Sopenharmony_ci SET_FIELD(p_tx->db_msg.params, CORE_DB_DATA_DEST, DB_DEST_XCM); 16458c2ecf20Sopenharmony_ci SET_FIELD(p_tx->db_msg.params, CORE_DB_DATA_AGG_CMD, DB_AGG_CMD_SET); 16468c2ecf20Sopenharmony_ci SET_FIELD(p_tx->db_msg.params, CORE_DB_DATA_AGG_VAL_SEL, 16478c2ecf20Sopenharmony_ci DQ_XCM_CORE_TX_BD_PROD_CMD); 16488c2ecf20Sopenharmony_ci p_tx->db_msg.agg_flags = DQ_XCM_CORE_DQ_CF_CMD; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci rc = qed_ll2_establish_connection_rx(p_hwfn, p_ll2_conn); 16518c2ecf20Sopenharmony_ci if (rc) 16528c2ecf20Sopenharmony_ci goto out; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci rc = qed_sp_ll2_tx_queue_start(p_hwfn, p_ll2_conn); 16558c2ecf20Sopenharmony_ci if (rc) 16568c2ecf20Sopenharmony_ci goto out; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (!QED_IS_RDMA_PERSONALITY(p_hwfn)) 16598c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_USE_LIGHT_L2, 1); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci qed_ll2_establish_connection_ooo(p_hwfn, p_ll2_conn); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_FCOE) { 16648c2ecf20Sopenharmony_ci if (!test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits)) 16658c2ecf20Sopenharmony_ci qed_llh_add_protocol_filter(p_hwfn->cdev, 0, 16668c2ecf20Sopenharmony_ci QED_LLH_FILTER_ETHERTYPE, 16678c2ecf20Sopenharmony_ci ETH_P_FCOE, 0); 16688c2ecf20Sopenharmony_ci qed_llh_add_protocol_filter(p_hwfn->cdev, 0, 16698c2ecf20Sopenharmony_ci QED_LLH_FILTER_ETHERTYPE, 16708c2ecf20Sopenharmony_ci ETH_P_FIP, 0); 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ciout: 16748c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 16758c2ecf20Sopenharmony_ci return rc; 16768c2ecf20Sopenharmony_ci} 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_cistatic void qed_ll2_post_rx_buffer_notify_fw(struct qed_hwfn *p_hwfn, 16798c2ecf20Sopenharmony_ci struct qed_ll2_rx_queue *p_rx, 16808c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet *p_curp) 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet *p_posting_packet = NULL; 16838c2ecf20Sopenharmony_ci struct core_ll2_rx_prod rx_prod = { 0, 0 }; 16848c2ecf20Sopenharmony_ci bool b_notify_fw = false; 16858c2ecf20Sopenharmony_ci u16 bd_prod, cq_prod; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci /* This handles the flushing of already posted buffers */ 16888c2ecf20Sopenharmony_ci while (!list_empty(&p_rx->posting_descq)) { 16898c2ecf20Sopenharmony_ci p_posting_packet = list_first_entry(&p_rx->posting_descq, 16908c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet, 16918c2ecf20Sopenharmony_ci list_entry); 16928c2ecf20Sopenharmony_ci list_move_tail(&p_posting_packet->list_entry, 16938c2ecf20Sopenharmony_ci &p_rx->active_descq); 16948c2ecf20Sopenharmony_ci b_notify_fw = true; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci /* This handles the supplied packet [if there is one] */ 16988c2ecf20Sopenharmony_ci if (p_curp) { 16998c2ecf20Sopenharmony_ci list_add_tail(&p_curp->list_entry, &p_rx->active_descq); 17008c2ecf20Sopenharmony_ci b_notify_fw = true; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci if (!b_notify_fw) 17048c2ecf20Sopenharmony_ci return; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci bd_prod = qed_chain_get_prod_idx(&p_rx->rxq_chain); 17078c2ecf20Sopenharmony_ci cq_prod = qed_chain_get_prod_idx(&p_rx->rcq_chain); 17088c2ecf20Sopenharmony_ci if (p_rx->ctx_based) { 17098c2ecf20Sopenharmony_ci /* update producer by giving a doorbell */ 17108c2ecf20Sopenharmony_ci p_rx->db_data.prod.bd_prod = cpu_to_le16(bd_prod); 17118c2ecf20Sopenharmony_ci p_rx->db_data.prod.cqe_prod = cpu_to_le16(cq_prod); 17128c2ecf20Sopenharmony_ci /* Make sure chain element is updated before ringing the 17138c2ecf20Sopenharmony_ci * doorbell 17148c2ecf20Sopenharmony_ci */ 17158c2ecf20Sopenharmony_ci dma_wmb(); 17168c2ecf20Sopenharmony_ci DIRECT_REG_WR64(p_rx->set_prod_addr, 17178c2ecf20Sopenharmony_ci *((u64 *)&p_rx->db_data)); 17188c2ecf20Sopenharmony_ci } else { 17198c2ecf20Sopenharmony_ci rx_prod.bd_prod = cpu_to_le16(bd_prod); 17208c2ecf20Sopenharmony_ci rx_prod.cqe_prod = cpu_to_le16(cq_prod); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci /* Make sure chain element is updated before ringing the 17238c2ecf20Sopenharmony_ci * doorbell 17248c2ecf20Sopenharmony_ci */ 17258c2ecf20Sopenharmony_ci dma_wmb(); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci DIRECT_REG_WR(p_rx->set_prod_addr, *((u32 *)&rx_prod)); 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci} 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ciint qed_ll2_post_rx_buffer(void *cxt, 17328c2ecf20Sopenharmony_ci u8 connection_handle, 17338c2ecf20Sopenharmony_ci dma_addr_t addr, 17348c2ecf20Sopenharmony_ci u16 buf_len, void *cookie, u8 notify_fw) 17358c2ecf20Sopenharmony_ci{ 17368c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 17378c2ecf20Sopenharmony_ci struct core_rx_bd_with_buff_len *p_curb = NULL; 17388c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet *p_curp = NULL; 17398c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn; 17408c2ecf20Sopenharmony_ci struct qed_ll2_rx_queue *p_rx; 17418c2ecf20Sopenharmony_ci unsigned long flags; 17428c2ecf20Sopenharmony_ci void *p_data; 17438c2ecf20Sopenharmony_ci int rc = 0; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci p_ll2_conn = qed_ll2_handle_sanity(p_hwfn, connection_handle); 17468c2ecf20Sopenharmony_ci if (!p_ll2_conn) 17478c2ecf20Sopenharmony_ci return -EINVAL; 17488c2ecf20Sopenharmony_ci p_rx = &p_ll2_conn->rx_queue; 17498c2ecf20Sopenharmony_ci if (!p_rx->set_prod_addr) 17508c2ecf20Sopenharmony_ci return -EIO; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_rx->lock, flags); 17538c2ecf20Sopenharmony_ci if (!list_empty(&p_rx->free_descq)) 17548c2ecf20Sopenharmony_ci p_curp = list_first_entry(&p_rx->free_descq, 17558c2ecf20Sopenharmony_ci struct qed_ll2_rx_packet, list_entry); 17568c2ecf20Sopenharmony_ci if (p_curp) { 17578c2ecf20Sopenharmony_ci if (qed_chain_get_elem_left(&p_rx->rxq_chain) && 17588c2ecf20Sopenharmony_ci qed_chain_get_elem_left(&p_rx->rcq_chain)) { 17598c2ecf20Sopenharmony_ci p_data = qed_chain_produce(&p_rx->rxq_chain); 17608c2ecf20Sopenharmony_ci p_curb = (struct core_rx_bd_with_buff_len *)p_data; 17618c2ecf20Sopenharmony_ci qed_chain_produce(&p_rx->rcq_chain); 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci /* If we're lacking entires, let's try to flush buffers to FW */ 17668c2ecf20Sopenharmony_ci if (!p_curp || !p_curb) { 17678c2ecf20Sopenharmony_ci rc = -EBUSY; 17688c2ecf20Sopenharmony_ci p_curp = NULL; 17698c2ecf20Sopenharmony_ci goto out_notify; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci /* We have an Rx packet we can fill */ 17738c2ecf20Sopenharmony_ci DMA_REGPAIR_LE(p_curb->addr, addr); 17748c2ecf20Sopenharmony_ci p_curb->buff_length = cpu_to_le16(buf_len); 17758c2ecf20Sopenharmony_ci p_curp->rx_buf_addr = addr; 17768c2ecf20Sopenharmony_ci p_curp->cookie = cookie; 17778c2ecf20Sopenharmony_ci p_curp->rxq_bd = p_curb; 17788c2ecf20Sopenharmony_ci p_curp->buf_length = buf_len; 17798c2ecf20Sopenharmony_ci list_del(&p_curp->list_entry); 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci /* Check if we only want to enqueue this packet without informing FW */ 17828c2ecf20Sopenharmony_ci if (!notify_fw) { 17838c2ecf20Sopenharmony_ci list_add_tail(&p_curp->list_entry, &p_rx->posting_descq); 17848c2ecf20Sopenharmony_ci goto out; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ciout_notify: 17888c2ecf20Sopenharmony_ci qed_ll2_post_rx_buffer_notify_fw(p_hwfn, p_rx, p_curp); 17898c2ecf20Sopenharmony_ciout: 17908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_rx->lock, flags); 17918c2ecf20Sopenharmony_ci return rc; 17928c2ecf20Sopenharmony_ci} 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_cistatic void qed_ll2_prepare_tx_packet_set(struct qed_hwfn *p_hwfn, 17958c2ecf20Sopenharmony_ci struct qed_ll2_tx_queue *p_tx, 17968c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet *p_curp, 17978c2ecf20Sopenharmony_ci struct qed_ll2_tx_pkt_info *pkt, 17988c2ecf20Sopenharmony_ci u8 notify_fw) 17998c2ecf20Sopenharmony_ci{ 18008c2ecf20Sopenharmony_ci list_del(&p_curp->list_entry); 18018c2ecf20Sopenharmony_ci p_curp->cookie = pkt->cookie; 18028c2ecf20Sopenharmony_ci p_curp->bd_used = pkt->num_of_bds; 18038c2ecf20Sopenharmony_ci p_curp->notify_fw = notify_fw; 18048c2ecf20Sopenharmony_ci p_tx->cur_send_packet = p_curp; 18058c2ecf20Sopenharmony_ci p_tx->cur_send_frag_num = 0; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci p_curp->bds_set[p_tx->cur_send_frag_num].tx_frag = pkt->first_frag; 18088c2ecf20Sopenharmony_ci p_curp->bds_set[p_tx->cur_send_frag_num].frag_len = pkt->first_frag_len; 18098c2ecf20Sopenharmony_ci p_tx->cur_send_frag_num++; 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_cistatic void 18138c2ecf20Sopenharmony_ciqed_ll2_prepare_tx_packet_set_bd(struct qed_hwfn *p_hwfn, 18148c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2, 18158c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet *p_curp, 18168c2ecf20Sopenharmony_ci struct qed_ll2_tx_pkt_info *pkt) 18178c2ecf20Sopenharmony_ci{ 18188c2ecf20Sopenharmony_ci struct qed_chain *p_tx_chain = &p_ll2->tx_queue.txq_chain; 18198c2ecf20Sopenharmony_ci u16 prod_idx = qed_chain_get_prod_idx(p_tx_chain); 18208c2ecf20Sopenharmony_ci struct core_tx_bd *start_bd = NULL; 18218c2ecf20Sopenharmony_ci enum core_roce_flavor_type roce_flavor; 18228c2ecf20Sopenharmony_ci enum core_tx_dest tx_dest; 18238c2ecf20Sopenharmony_ci u16 bd_data = 0, frag_idx; 18248c2ecf20Sopenharmony_ci u16 bitfield1; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci roce_flavor = (pkt->qed_roce_flavor == QED_LL2_ROCE) ? CORE_ROCE 18278c2ecf20Sopenharmony_ci : CORE_RROCE; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci switch (pkt->tx_dest) { 18308c2ecf20Sopenharmony_ci case QED_LL2_TX_DEST_NW: 18318c2ecf20Sopenharmony_ci tx_dest = CORE_TX_DEST_NW; 18328c2ecf20Sopenharmony_ci break; 18338c2ecf20Sopenharmony_ci case QED_LL2_TX_DEST_LB: 18348c2ecf20Sopenharmony_ci tx_dest = CORE_TX_DEST_LB; 18358c2ecf20Sopenharmony_ci break; 18368c2ecf20Sopenharmony_ci case QED_LL2_TX_DEST_DROP: 18378c2ecf20Sopenharmony_ci tx_dest = CORE_TX_DEST_DROP; 18388c2ecf20Sopenharmony_ci break; 18398c2ecf20Sopenharmony_ci default: 18408c2ecf20Sopenharmony_ci tx_dest = CORE_TX_DEST_LB; 18418c2ecf20Sopenharmony_ci break; 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci start_bd = (struct core_tx_bd *)qed_chain_produce(p_tx_chain); 18458c2ecf20Sopenharmony_ci if (QED_IS_IWARP_PERSONALITY(p_hwfn) && 18468c2ecf20Sopenharmony_ci p_ll2->input.conn_type == QED_LL2_TYPE_OOO) { 18478c2ecf20Sopenharmony_ci start_bd->nw_vlan_or_lb_echo = 18488c2ecf20Sopenharmony_ci cpu_to_le16(IWARP_LL2_IN_ORDER_TX_QUEUE); 18498c2ecf20Sopenharmony_ci } else { 18508c2ecf20Sopenharmony_ci start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan); 18518c2ecf20Sopenharmony_ci if (test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits) && 18528c2ecf20Sopenharmony_ci p_ll2->input.conn_type == QED_LL2_TYPE_FCOE) 18538c2ecf20Sopenharmony_ci pkt->remove_stag = true; 18548c2ecf20Sopenharmony_ci } 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci bitfield1 = le16_to_cpu(start_bd->bitfield1); 18578c2ecf20Sopenharmony_ci SET_FIELD(bitfield1, CORE_TX_BD_L4_HDR_OFFSET_W, pkt->l4_hdr_offset_w); 18588c2ecf20Sopenharmony_ci SET_FIELD(bitfield1, CORE_TX_BD_TX_DST, tx_dest); 18598c2ecf20Sopenharmony_ci start_bd->bitfield1 = cpu_to_le16(bitfield1); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci bd_data |= pkt->bd_flags; 18628c2ecf20Sopenharmony_ci SET_FIELD(bd_data, CORE_TX_BD_DATA_START_BD, 0x1); 18638c2ecf20Sopenharmony_ci SET_FIELD(bd_data, CORE_TX_BD_DATA_NBDS, pkt->num_of_bds); 18648c2ecf20Sopenharmony_ci SET_FIELD(bd_data, CORE_TX_BD_DATA_ROCE_FLAV, roce_flavor); 18658c2ecf20Sopenharmony_ci SET_FIELD(bd_data, CORE_TX_BD_DATA_IP_CSUM, !!(pkt->enable_ip_cksum)); 18668c2ecf20Sopenharmony_ci SET_FIELD(bd_data, CORE_TX_BD_DATA_L4_CSUM, !!(pkt->enable_l4_cksum)); 18678c2ecf20Sopenharmony_ci SET_FIELD(bd_data, CORE_TX_BD_DATA_IP_LEN, !!(pkt->calc_ip_len)); 18688c2ecf20Sopenharmony_ci SET_FIELD(bd_data, CORE_TX_BD_DATA_DISABLE_STAG_INSERTION, 18698c2ecf20Sopenharmony_ci !!(pkt->remove_stag)); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci start_bd->bd_data.as_bitfield = cpu_to_le16(bd_data); 18728c2ecf20Sopenharmony_ci DMA_REGPAIR_LE(start_bd->addr, pkt->first_frag); 18738c2ecf20Sopenharmony_ci start_bd->nbytes = cpu_to_le16(pkt->first_frag_len); 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 18768c2ecf20Sopenharmony_ci (NETIF_MSG_TX_QUEUED | QED_MSG_LL2), 18778c2ecf20Sopenharmony_ci "LL2 [q 0x%02x cid 0x%08x type 0x%08x] Tx Producer at [0x%04x] - set with a %04x bytes %02x BDs buffer at %08x:%08x\n", 18788c2ecf20Sopenharmony_ci p_ll2->queue_id, 18798c2ecf20Sopenharmony_ci p_ll2->cid, 18808c2ecf20Sopenharmony_ci p_ll2->input.conn_type, 18818c2ecf20Sopenharmony_ci prod_idx, 18828c2ecf20Sopenharmony_ci pkt->first_frag_len, 18838c2ecf20Sopenharmony_ci pkt->num_of_bds, 18848c2ecf20Sopenharmony_ci le32_to_cpu(start_bd->addr.hi), 18858c2ecf20Sopenharmony_ci le32_to_cpu(start_bd->addr.lo)); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci if (p_ll2->tx_queue.cur_send_frag_num == pkt->num_of_bds) 18888c2ecf20Sopenharmony_ci return; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci /* Need to provide the packet with additional BDs for frags */ 18918c2ecf20Sopenharmony_ci for (frag_idx = p_ll2->tx_queue.cur_send_frag_num; 18928c2ecf20Sopenharmony_ci frag_idx < pkt->num_of_bds; frag_idx++) { 18938c2ecf20Sopenharmony_ci struct core_tx_bd **p_bd = &p_curp->bds_set[frag_idx].txq_bd; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci *p_bd = (struct core_tx_bd *)qed_chain_produce(p_tx_chain); 18968c2ecf20Sopenharmony_ci (*p_bd)->bd_data.as_bitfield = 0; 18978c2ecf20Sopenharmony_ci (*p_bd)->bitfield1 = 0; 18988c2ecf20Sopenharmony_ci p_curp->bds_set[frag_idx].tx_frag = 0; 18998c2ecf20Sopenharmony_ci p_curp->bds_set[frag_idx].frag_len = 0; 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci} 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci/* This should be called while the Txq spinlock is being held */ 19048c2ecf20Sopenharmony_cistatic void qed_ll2_tx_packet_notify(struct qed_hwfn *p_hwfn, 19058c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci bool b_notify = p_ll2_conn->tx_queue.cur_send_packet->notify_fw; 19088c2ecf20Sopenharmony_ci struct qed_ll2_tx_queue *p_tx = &p_ll2_conn->tx_queue; 19098c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet *p_pkt = NULL; 19108c2ecf20Sopenharmony_ci u16 bd_prod; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci /* If there are missing BDs, don't do anything now */ 19138c2ecf20Sopenharmony_ci if (p_ll2_conn->tx_queue.cur_send_frag_num != 19148c2ecf20Sopenharmony_ci p_ll2_conn->tx_queue.cur_send_packet->bd_used) 19158c2ecf20Sopenharmony_ci return; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci /* Push the current packet to the list and clean after it */ 19188c2ecf20Sopenharmony_ci list_add_tail(&p_ll2_conn->tx_queue.cur_send_packet->list_entry, 19198c2ecf20Sopenharmony_ci &p_ll2_conn->tx_queue.sending_descq); 19208c2ecf20Sopenharmony_ci p_ll2_conn->tx_queue.cur_send_packet = NULL; 19218c2ecf20Sopenharmony_ci p_ll2_conn->tx_queue.cur_send_frag_num = 0; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci /* Notify FW of packet only if requested to */ 19248c2ecf20Sopenharmony_ci if (!b_notify) 19258c2ecf20Sopenharmony_ci return; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci bd_prod = qed_chain_get_prod_idx(&p_ll2_conn->tx_queue.txq_chain); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci while (!list_empty(&p_tx->sending_descq)) { 19308c2ecf20Sopenharmony_ci p_pkt = list_first_entry(&p_tx->sending_descq, 19318c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet, list_entry); 19328c2ecf20Sopenharmony_ci if (!p_pkt) 19338c2ecf20Sopenharmony_ci break; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci list_move_tail(&p_pkt->list_entry, &p_tx->active_descq); 19368c2ecf20Sopenharmony_ci } 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci p_tx->db_msg.spq_prod = cpu_to_le16(bd_prod); 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci /* Make sure the BDs data is updated before ringing the doorbell */ 19418c2ecf20Sopenharmony_ci wmb(); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci DIRECT_REG_WR(p_tx->doorbell_addr, *((u32 *)&p_tx->db_msg)); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 19468c2ecf20Sopenharmony_ci (NETIF_MSG_TX_QUEUED | QED_MSG_LL2), 19478c2ecf20Sopenharmony_ci "LL2 [q 0x%02x cid 0x%08x type 0x%08x] Doorbelled [producer 0x%04x]\n", 19488c2ecf20Sopenharmony_ci p_ll2_conn->queue_id, 19498c2ecf20Sopenharmony_ci p_ll2_conn->cid, 19508c2ecf20Sopenharmony_ci p_ll2_conn->input.conn_type, p_tx->db_msg.spq_prod); 19518c2ecf20Sopenharmony_ci} 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ciint qed_ll2_prepare_tx_packet(void *cxt, 19548c2ecf20Sopenharmony_ci u8 connection_handle, 19558c2ecf20Sopenharmony_ci struct qed_ll2_tx_pkt_info *pkt, 19568c2ecf20Sopenharmony_ci bool notify_fw) 19578c2ecf20Sopenharmony_ci{ 19588c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 19598c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet *p_curp = NULL; 19608c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn = NULL; 19618c2ecf20Sopenharmony_ci struct qed_ll2_tx_queue *p_tx; 19628c2ecf20Sopenharmony_ci struct qed_chain *p_tx_chain; 19638c2ecf20Sopenharmony_ci unsigned long flags; 19648c2ecf20Sopenharmony_ci int rc = 0; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci p_ll2_conn = qed_ll2_handle_sanity(p_hwfn, connection_handle); 19678c2ecf20Sopenharmony_ci if (!p_ll2_conn) 19688c2ecf20Sopenharmony_ci return -EINVAL; 19698c2ecf20Sopenharmony_ci p_tx = &p_ll2_conn->tx_queue; 19708c2ecf20Sopenharmony_ci p_tx_chain = &p_tx->txq_chain; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci if (pkt->num_of_bds > p_ll2_conn->input.tx_max_bds_per_packet) 19738c2ecf20Sopenharmony_ci return -EIO; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_tx->lock, flags); 19768c2ecf20Sopenharmony_ci if (p_tx->cur_send_packet) { 19778c2ecf20Sopenharmony_ci rc = -EEXIST; 19788c2ecf20Sopenharmony_ci goto out; 19798c2ecf20Sopenharmony_ci } 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci /* Get entry, but only if we have tx elements for it */ 19828c2ecf20Sopenharmony_ci if (!list_empty(&p_tx->free_descq)) 19838c2ecf20Sopenharmony_ci p_curp = list_first_entry(&p_tx->free_descq, 19848c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet, list_entry); 19858c2ecf20Sopenharmony_ci if (p_curp && qed_chain_get_elem_left(p_tx_chain) < pkt->num_of_bds) 19868c2ecf20Sopenharmony_ci p_curp = NULL; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci if (!p_curp) { 19898c2ecf20Sopenharmony_ci rc = -EBUSY; 19908c2ecf20Sopenharmony_ci goto out; 19918c2ecf20Sopenharmony_ci } 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci /* Prepare packet and BD, and perhaps send a doorbell to FW */ 19948c2ecf20Sopenharmony_ci qed_ll2_prepare_tx_packet_set(p_hwfn, p_tx, p_curp, pkt, notify_fw); 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci qed_ll2_prepare_tx_packet_set_bd(p_hwfn, p_ll2_conn, p_curp, pkt); 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci qed_ll2_tx_packet_notify(p_hwfn, p_ll2_conn); 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ciout: 20018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_tx->lock, flags); 20028c2ecf20Sopenharmony_ci return rc; 20038c2ecf20Sopenharmony_ci} 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ciint qed_ll2_set_fragment_of_tx_packet(void *cxt, 20068c2ecf20Sopenharmony_ci u8 connection_handle, 20078c2ecf20Sopenharmony_ci dma_addr_t addr, u16 nbytes) 20088c2ecf20Sopenharmony_ci{ 20098c2ecf20Sopenharmony_ci struct qed_ll2_tx_packet *p_cur_send_packet = NULL; 20108c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 20118c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn = NULL; 20128c2ecf20Sopenharmony_ci u16 cur_send_frag_num = 0; 20138c2ecf20Sopenharmony_ci struct core_tx_bd *p_bd; 20148c2ecf20Sopenharmony_ci unsigned long flags; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci p_ll2_conn = qed_ll2_handle_sanity(p_hwfn, connection_handle); 20178c2ecf20Sopenharmony_ci if (!p_ll2_conn) 20188c2ecf20Sopenharmony_ci return -EINVAL; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (!p_ll2_conn->tx_queue.cur_send_packet) 20218c2ecf20Sopenharmony_ci return -EINVAL; 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci p_cur_send_packet = p_ll2_conn->tx_queue.cur_send_packet; 20248c2ecf20Sopenharmony_ci cur_send_frag_num = p_ll2_conn->tx_queue.cur_send_frag_num; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci if (cur_send_frag_num >= p_cur_send_packet->bd_used) 20278c2ecf20Sopenharmony_ci return -EINVAL; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci /* Fill the BD information, and possibly notify FW */ 20308c2ecf20Sopenharmony_ci p_bd = p_cur_send_packet->bds_set[cur_send_frag_num].txq_bd; 20318c2ecf20Sopenharmony_ci DMA_REGPAIR_LE(p_bd->addr, addr); 20328c2ecf20Sopenharmony_ci p_bd->nbytes = cpu_to_le16(nbytes); 20338c2ecf20Sopenharmony_ci p_cur_send_packet->bds_set[cur_send_frag_num].tx_frag = addr; 20348c2ecf20Sopenharmony_ci p_cur_send_packet->bds_set[cur_send_frag_num].frag_len = nbytes; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci p_ll2_conn->tx_queue.cur_send_frag_num++; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci spin_lock_irqsave(&p_ll2_conn->tx_queue.lock, flags); 20398c2ecf20Sopenharmony_ci qed_ll2_tx_packet_notify(p_hwfn, p_ll2_conn); 20408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p_ll2_conn->tx_queue.lock, flags); 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci return 0; 20438c2ecf20Sopenharmony_ci} 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ciint qed_ll2_terminate_connection(void *cxt, u8 connection_handle) 20468c2ecf20Sopenharmony_ci{ 20478c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 20488c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn = NULL; 20498c2ecf20Sopenharmony_ci int rc = -EINVAL; 20508c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 20538c2ecf20Sopenharmony_ci if (!p_ptt) 20548c2ecf20Sopenharmony_ci return -EAGAIN; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci p_ll2_conn = qed_ll2_handle_sanity_lock(p_hwfn, connection_handle); 20578c2ecf20Sopenharmony_ci if (!p_ll2_conn) { 20588c2ecf20Sopenharmony_ci rc = -EINVAL; 20598c2ecf20Sopenharmony_ci goto out; 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci /* Stop Tx & Rx of connection, if needed */ 20638c2ecf20Sopenharmony_ci if (QED_LL2_TX_REGISTERED(p_ll2_conn)) { 20648c2ecf20Sopenharmony_ci p_ll2_conn->tx_queue.b_cb_registered = false; 20658c2ecf20Sopenharmony_ci smp_wmb(); /* Make sure this is seen by ll2_lb_rxq_completion */ 20668c2ecf20Sopenharmony_ci rc = qed_sp_ll2_tx_queue_stop(p_hwfn, p_ll2_conn); 20678c2ecf20Sopenharmony_ci if (rc) 20688c2ecf20Sopenharmony_ci goto out; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci qed_ll2_txq_flush(p_hwfn, connection_handle); 20718c2ecf20Sopenharmony_ci qed_int_unregister_cb(p_hwfn, p_ll2_conn->tx_queue.tx_sb_index); 20728c2ecf20Sopenharmony_ci } 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci if (QED_LL2_RX_REGISTERED(p_ll2_conn)) { 20758c2ecf20Sopenharmony_ci p_ll2_conn->rx_queue.b_cb_registered = false; 20768c2ecf20Sopenharmony_ci smp_wmb(); /* Make sure this is seen by ll2_lb_rxq_completion */ 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci if (p_ll2_conn->rx_queue.ctx_based) 20798c2ecf20Sopenharmony_ci qed_db_recovery_del(p_hwfn->cdev, 20808c2ecf20Sopenharmony_ci p_ll2_conn->rx_queue.set_prod_addr, 20818c2ecf20Sopenharmony_ci &p_ll2_conn->rx_queue.db_data); 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci rc = qed_sp_ll2_rx_queue_stop(p_hwfn, p_ll2_conn); 20848c2ecf20Sopenharmony_ci if (rc) 20858c2ecf20Sopenharmony_ci goto out; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci qed_ll2_rxq_flush(p_hwfn, connection_handle); 20888c2ecf20Sopenharmony_ci qed_int_unregister_cb(p_hwfn, p_ll2_conn->rx_queue.rx_sb_index); 20898c2ecf20Sopenharmony_ci } 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) 20928c2ecf20Sopenharmony_ci qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_FCOE) { 20958c2ecf20Sopenharmony_ci if (!test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits)) 20968c2ecf20Sopenharmony_ci qed_llh_remove_protocol_filter(p_hwfn->cdev, 0, 20978c2ecf20Sopenharmony_ci QED_LLH_FILTER_ETHERTYPE, 20988c2ecf20Sopenharmony_ci ETH_P_FCOE, 0); 20998c2ecf20Sopenharmony_ci qed_llh_remove_protocol_filter(p_hwfn->cdev, 0, 21008c2ecf20Sopenharmony_ci QED_LLH_FILTER_ETHERTYPE, 21018c2ecf20Sopenharmony_ci ETH_P_FIP, 0); 21028c2ecf20Sopenharmony_ci } 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ciout: 21058c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 21068c2ecf20Sopenharmony_ci return rc; 21078c2ecf20Sopenharmony_ci} 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_cistatic void qed_ll2_release_connection_ooo(struct qed_hwfn *p_hwfn, 21108c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn) 21118c2ecf20Sopenharmony_ci{ 21128c2ecf20Sopenharmony_ci struct qed_ooo_buffer *p_buffer; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_OOO) 21158c2ecf20Sopenharmony_ci return; 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); 21188c2ecf20Sopenharmony_ci while ((p_buffer = qed_ooo_get_free_buffer(p_hwfn, 21198c2ecf20Sopenharmony_ci p_hwfn->p_ooo_info))) { 21208c2ecf20Sopenharmony_ci dma_free_coherent(&p_hwfn->cdev->pdev->dev, 21218c2ecf20Sopenharmony_ci p_buffer->rx_buffer_size, 21228c2ecf20Sopenharmony_ci p_buffer->rx_buffer_virt_addr, 21238c2ecf20Sopenharmony_ci p_buffer->rx_buffer_phys_addr); 21248c2ecf20Sopenharmony_ci kfree(p_buffer); 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci} 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_civoid qed_ll2_release_connection(void *cxt, u8 connection_handle) 21298c2ecf20Sopenharmony_ci{ 21308c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 21318c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn = NULL; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci p_ll2_conn = qed_ll2_handle_sanity(p_hwfn, connection_handle); 21348c2ecf20Sopenharmony_ci if (!p_ll2_conn) 21358c2ecf20Sopenharmony_ci return; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci kfree(p_ll2_conn->tx_queue.descq_mem); 21388c2ecf20Sopenharmony_ci qed_chain_free(p_hwfn->cdev, &p_ll2_conn->tx_queue.txq_chain); 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci kfree(p_ll2_conn->rx_queue.descq_array); 21418c2ecf20Sopenharmony_ci qed_chain_free(p_hwfn->cdev, &p_ll2_conn->rx_queue.rxq_chain); 21428c2ecf20Sopenharmony_ci qed_chain_free(p_hwfn->cdev, &p_ll2_conn->rx_queue.rcq_chain); 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci qed_cxt_release_cid(p_hwfn, p_ll2_conn->cid); 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci qed_ll2_release_connection_ooo(p_hwfn, p_ll2_conn); 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci mutex_lock(&p_ll2_conn->mutex); 21498c2ecf20Sopenharmony_ci p_ll2_conn->b_active = false; 21508c2ecf20Sopenharmony_ci mutex_unlock(&p_ll2_conn->mutex); 21518c2ecf20Sopenharmony_ci} 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ciint qed_ll2_alloc(struct qed_hwfn *p_hwfn) 21548c2ecf20Sopenharmony_ci{ 21558c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_connections; 21568c2ecf20Sopenharmony_ci u8 i; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci /* Allocate LL2's set struct */ 21598c2ecf20Sopenharmony_ci p_ll2_connections = kcalloc(QED_MAX_NUM_OF_LL2_CONNECTIONS, 21608c2ecf20Sopenharmony_ci sizeof(struct qed_ll2_info), GFP_KERNEL); 21618c2ecf20Sopenharmony_ci if (!p_ll2_connections) { 21628c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_ll2'\n"); 21638c2ecf20Sopenharmony_ci return -ENOMEM; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci for (i = 0; i < QED_MAX_NUM_OF_LL2_CONNECTIONS; i++) 21678c2ecf20Sopenharmony_ci p_ll2_connections[i].my_id = i; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci p_hwfn->p_ll2_info = p_ll2_connections; 21708c2ecf20Sopenharmony_ci return 0; 21718c2ecf20Sopenharmony_ci} 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_civoid qed_ll2_setup(struct qed_hwfn *p_hwfn) 21748c2ecf20Sopenharmony_ci{ 21758c2ecf20Sopenharmony_ci int i; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci for (i = 0; i < QED_MAX_NUM_OF_LL2_CONNECTIONS; i++) 21788c2ecf20Sopenharmony_ci mutex_init(&p_hwfn->p_ll2_info[i].mutex); 21798c2ecf20Sopenharmony_ci} 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_civoid qed_ll2_free(struct qed_hwfn *p_hwfn) 21828c2ecf20Sopenharmony_ci{ 21838c2ecf20Sopenharmony_ci if (!p_hwfn->p_ll2_info) 21848c2ecf20Sopenharmony_ci return; 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci kfree(p_hwfn->p_ll2_info); 21878c2ecf20Sopenharmony_ci p_hwfn->p_ll2_info = NULL; 21888c2ecf20Sopenharmony_ci} 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_cistatic void _qed_ll2_get_port_stats(struct qed_hwfn *p_hwfn, 21918c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 21928c2ecf20Sopenharmony_ci struct qed_ll2_stats *p_stats) 21938c2ecf20Sopenharmony_ci{ 21948c2ecf20Sopenharmony_ci struct core_ll2_port_stats port_stats; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci memset(&port_stats, 0, sizeof(port_stats)); 21978c2ecf20Sopenharmony_ci qed_memcpy_from(p_hwfn, p_ptt, &port_stats, 21988c2ecf20Sopenharmony_ci BAR0_MAP_REG_TSDM_RAM + 21998c2ecf20Sopenharmony_ci TSTORM_LL2_PORT_STAT_OFFSET(MFW_PORT(p_hwfn)), 22008c2ecf20Sopenharmony_ci sizeof(port_stats)); 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci p_stats->gsi_invalid_hdr += HILO_64_REGPAIR(port_stats.gsi_invalid_hdr); 22038c2ecf20Sopenharmony_ci p_stats->gsi_invalid_pkt_length += 22048c2ecf20Sopenharmony_ci HILO_64_REGPAIR(port_stats.gsi_invalid_pkt_length); 22058c2ecf20Sopenharmony_ci p_stats->gsi_unsupported_pkt_typ += 22068c2ecf20Sopenharmony_ci HILO_64_REGPAIR(port_stats.gsi_unsupported_pkt_typ); 22078c2ecf20Sopenharmony_ci p_stats->gsi_crcchksm_error += 22088c2ecf20Sopenharmony_ci HILO_64_REGPAIR(port_stats.gsi_crcchksm_error); 22098c2ecf20Sopenharmony_ci} 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_cistatic void _qed_ll2_get_tstats(struct qed_hwfn *p_hwfn, 22128c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 22138c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn, 22148c2ecf20Sopenharmony_ci struct qed_ll2_stats *p_stats) 22158c2ecf20Sopenharmony_ci{ 22168c2ecf20Sopenharmony_ci struct core_ll2_tstorm_per_queue_stat tstats; 22178c2ecf20Sopenharmony_ci u8 qid = p_ll2_conn->queue_id; 22188c2ecf20Sopenharmony_ci u32 tstats_addr; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci memset(&tstats, 0, sizeof(tstats)); 22218c2ecf20Sopenharmony_ci tstats_addr = BAR0_MAP_REG_TSDM_RAM + 22228c2ecf20Sopenharmony_ci CORE_LL2_TSTORM_PER_QUEUE_STAT_OFFSET(qid); 22238c2ecf20Sopenharmony_ci qed_memcpy_from(p_hwfn, p_ptt, &tstats, tstats_addr, sizeof(tstats)); 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci p_stats->packet_too_big_discard += 22268c2ecf20Sopenharmony_ci HILO_64_REGPAIR(tstats.packet_too_big_discard); 22278c2ecf20Sopenharmony_ci p_stats->no_buff_discard += HILO_64_REGPAIR(tstats.no_buff_discard); 22288c2ecf20Sopenharmony_ci} 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_cistatic void _qed_ll2_get_ustats(struct qed_hwfn *p_hwfn, 22318c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 22328c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn, 22338c2ecf20Sopenharmony_ci struct qed_ll2_stats *p_stats) 22348c2ecf20Sopenharmony_ci{ 22358c2ecf20Sopenharmony_ci struct core_ll2_ustorm_per_queue_stat ustats; 22368c2ecf20Sopenharmony_ci u8 qid = p_ll2_conn->queue_id; 22378c2ecf20Sopenharmony_ci u32 ustats_addr; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci memset(&ustats, 0, sizeof(ustats)); 22408c2ecf20Sopenharmony_ci ustats_addr = BAR0_MAP_REG_USDM_RAM + 22418c2ecf20Sopenharmony_ci CORE_LL2_USTORM_PER_QUEUE_STAT_OFFSET(qid); 22428c2ecf20Sopenharmony_ci qed_memcpy_from(p_hwfn, p_ptt, &ustats, ustats_addr, sizeof(ustats)); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci p_stats->rcv_ucast_bytes += HILO_64_REGPAIR(ustats.rcv_ucast_bytes); 22458c2ecf20Sopenharmony_ci p_stats->rcv_mcast_bytes += HILO_64_REGPAIR(ustats.rcv_mcast_bytes); 22468c2ecf20Sopenharmony_ci p_stats->rcv_bcast_bytes += HILO_64_REGPAIR(ustats.rcv_bcast_bytes); 22478c2ecf20Sopenharmony_ci p_stats->rcv_ucast_pkts += HILO_64_REGPAIR(ustats.rcv_ucast_pkts); 22488c2ecf20Sopenharmony_ci p_stats->rcv_mcast_pkts += HILO_64_REGPAIR(ustats.rcv_mcast_pkts); 22498c2ecf20Sopenharmony_ci p_stats->rcv_bcast_pkts += HILO_64_REGPAIR(ustats.rcv_bcast_pkts); 22508c2ecf20Sopenharmony_ci} 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_cistatic void _qed_ll2_get_pstats(struct qed_hwfn *p_hwfn, 22538c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 22548c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn, 22558c2ecf20Sopenharmony_ci struct qed_ll2_stats *p_stats) 22568c2ecf20Sopenharmony_ci{ 22578c2ecf20Sopenharmony_ci struct core_ll2_pstorm_per_queue_stat pstats; 22588c2ecf20Sopenharmony_ci u8 stats_id = p_ll2_conn->tx_stats_id; 22598c2ecf20Sopenharmony_ci u32 pstats_addr; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci memset(&pstats, 0, sizeof(pstats)); 22628c2ecf20Sopenharmony_ci pstats_addr = BAR0_MAP_REG_PSDM_RAM + 22638c2ecf20Sopenharmony_ci CORE_LL2_PSTORM_PER_QUEUE_STAT_OFFSET(stats_id); 22648c2ecf20Sopenharmony_ci qed_memcpy_from(p_hwfn, p_ptt, &pstats, pstats_addr, sizeof(pstats)); 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci p_stats->sent_ucast_bytes += HILO_64_REGPAIR(pstats.sent_ucast_bytes); 22678c2ecf20Sopenharmony_ci p_stats->sent_mcast_bytes += HILO_64_REGPAIR(pstats.sent_mcast_bytes); 22688c2ecf20Sopenharmony_ci p_stats->sent_bcast_bytes += HILO_64_REGPAIR(pstats.sent_bcast_bytes); 22698c2ecf20Sopenharmony_ci p_stats->sent_ucast_pkts += HILO_64_REGPAIR(pstats.sent_ucast_pkts); 22708c2ecf20Sopenharmony_ci p_stats->sent_mcast_pkts += HILO_64_REGPAIR(pstats.sent_mcast_pkts); 22718c2ecf20Sopenharmony_ci p_stats->sent_bcast_pkts += HILO_64_REGPAIR(pstats.sent_bcast_pkts); 22728c2ecf20Sopenharmony_ci} 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_cistatic int __qed_ll2_get_stats(void *cxt, u8 connection_handle, 22758c2ecf20Sopenharmony_ci struct qed_ll2_stats *p_stats) 22768c2ecf20Sopenharmony_ci{ 22778c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 22788c2ecf20Sopenharmony_ci struct qed_ll2_info *p_ll2_conn = NULL; 22798c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci if ((connection_handle >= QED_MAX_NUM_OF_LL2_CONNECTIONS) || 22828c2ecf20Sopenharmony_ci !p_hwfn->p_ll2_info) 22838c2ecf20Sopenharmony_ci return -EINVAL; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci p_ll2_conn = &p_hwfn->p_ll2_info[connection_handle]; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 22888c2ecf20Sopenharmony_ci if (!p_ptt) { 22898c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Failed to acquire ptt\n"); 22908c2ecf20Sopenharmony_ci return -EINVAL; 22918c2ecf20Sopenharmony_ci } 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci if (p_ll2_conn->input.gsi_enable) 22948c2ecf20Sopenharmony_ci _qed_ll2_get_port_stats(p_hwfn, p_ptt, p_stats); 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci _qed_ll2_get_tstats(p_hwfn, p_ptt, p_ll2_conn, p_stats); 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci _qed_ll2_get_ustats(p_hwfn, p_ptt, p_ll2_conn, p_stats); 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci if (p_ll2_conn->tx_stats_en) 23018c2ecf20Sopenharmony_ci _qed_ll2_get_pstats(p_hwfn, p_ptt, p_ll2_conn, p_stats); 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci return 0; 23068c2ecf20Sopenharmony_ci} 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ciint qed_ll2_get_stats(void *cxt, 23098c2ecf20Sopenharmony_ci u8 connection_handle, struct qed_ll2_stats *p_stats) 23108c2ecf20Sopenharmony_ci{ 23118c2ecf20Sopenharmony_ci memset(p_stats, 0, sizeof(*p_stats)); 23128c2ecf20Sopenharmony_ci return __qed_ll2_get_stats(cxt, connection_handle, p_stats); 23138c2ecf20Sopenharmony_ci} 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_cistatic void qed_ll2b_release_rx_packet(void *cxt, 23168c2ecf20Sopenharmony_ci u8 connection_handle, 23178c2ecf20Sopenharmony_ci void *cookie, 23188c2ecf20Sopenharmony_ci dma_addr_t rx_buf_addr, 23198c2ecf20Sopenharmony_ci bool b_last_packet) 23208c2ecf20Sopenharmony_ci{ 23218c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = cxt; 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci qed_ll2_dealloc_buffer(p_hwfn->cdev, cookie); 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_cistatic void qed_ll2_register_cb_ops(struct qed_dev *cdev, 23278c2ecf20Sopenharmony_ci const struct qed_ll2_cb_ops *ops, 23288c2ecf20Sopenharmony_ci void *cookie) 23298c2ecf20Sopenharmony_ci{ 23308c2ecf20Sopenharmony_ci cdev->ll2->cbs = ops; 23318c2ecf20Sopenharmony_ci cdev->ll2->cb_cookie = cookie; 23328c2ecf20Sopenharmony_ci} 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_cistatic struct qed_ll2_cbs ll2_cbs = { 23358c2ecf20Sopenharmony_ci .rx_comp_cb = &qed_ll2b_complete_rx_packet, 23368c2ecf20Sopenharmony_ci .rx_release_cb = &qed_ll2b_release_rx_packet, 23378c2ecf20Sopenharmony_ci .tx_comp_cb = &qed_ll2b_complete_tx_packet, 23388c2ecf20Sopenharmony_ci .tx_release_cb = &qed_ll2b_complete_tx_packet, 23398c2ecf20Sopenharmony_ci}; 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_cistatic void qed_ll2_set_conn_data(struct qed_hwfn *p_hwfn, 23428c2ecf20Sopenharmony_ci struct qed_ll2_acquire_data *data, 23438c2ecf20Sopenharmony_ci struct qed_ll2_params *params, 23448c2ecf20Sopenharmony_ci enum qed_ll2_conn_type conn_type, 23458c2ecf20Sopenharmony_ci u8 *handle, bool lb) 23468c2ecf20Sopenharmony_ci{ 23478c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci data->input.conn_type = conn_type; 23508c2ecf20Sopenharmony_ci data->input.mtu = params->mtu; 23518c2ecf20Sopenharmony_ci data->input.rx_num_desc = QED_LL2_RX_SIZE; 23528c2ecf20Sopenharmony_ci data->input.rx_drop_ttl0_flg = params->drop_ttl0_packets; 23538c2ecf20Sopenharmony_ci data->input.rx_vlan_removal_en = params->rx_vlan_stripping; 23548c2ecf20Sopenharmony_ci data->input.tx_num_desc = QED_LL2_TX_SIZE; 23558c2ecf20Sopenharmony_ci data->p_connection_handle = handle; 23568c2ecf20Sopenharmony_ci data->cbs = &ll2_cbs; 23578c2ecf20Sopenharmony_ci ll2_cbs.cookie = p_hwfn; 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci if (lb) { 23608c2ecf20Sopenharmony_ci data->input.tx_tc = PKT_LB_TC; 23618c2ecf20Sopenharmony_ci data->input.tx_dest = QED_LL2_TX_DEST_LB; 23628c2ecf20Sopenharmony_ci } else { 23638c2ecf20Sopenharmony_ci data->input.tx_tc = 0; 23648c2ecf20Sopenharmony_ci data->input.tx_dest = QED_LL2_TX_DEST_NW; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci} 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_cistatic int qed_ll2_start_ooo(struct qed_hwfn *p_hwfn, 23698c2ecf20Sopenharmony_ci struct qed_ll2_params *params) 23708c2ecf20Sopenharmony_ci{ 23718c2ecf20Sopenharmony_ci u8 *handle = &p_hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id; 23728c2ecf20Sopenharmony_ci struct qed_ll2_acquire_data data; 23738c2ecf20Sopenharmony_ci int rc; 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci qed_ll2_set_conn_data(p_hwfn, &data, params, 23768c2ecf20Sopenharmony_ci QED_LL2_TYPE_OOO, handle, true); 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci rc = qed_ll2_acquire_connection(p_hwfn, &data); 23798c2ecf20Sopenharmony_ci if (rc) { 23808c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Failed to acquire LL2 OOO connection\n"); 23818c2ecf20Sopenharmony_ci goto out; 23828c2ecf20Sopenharmony_ci } 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci rc = qed_ll2_establish_connection(p_hwfn, *handle); 23858c2ecf20Sopenharmony_ci if (rc) { 23868c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Failed to establish LL2 OOO connection\n"); 23878c2ecf20Sopenharmony_ci goto fail; 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci return 0; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_cifail: 23938c2ecf20Sopenharmony_ci qed_ll2_release_connection(p_hwfn, *handle); 23948c2ecf20Sopenharmony_ciout: 23958c2ecf20Sopenharmony_ci *handle = QED_LL2_UNUSED_HANDLE; 23968c2ecf20Sopenharmony_ci return rc; 23978c2ecf20Sopenharmony_ci} 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_cistatic bool qed_ll2_is_storage_eng1(struct qed_dev *cdev) 24008c2ecf20Sopenharmony_ci{ 24018c2ecf20Sopenharmony_ci return (QED_IS_FCOE_PERSONALITY(QED_LEADING_HWFN(cdev)) || 24028c2ecf20Sopenharmony_ci QED_IS_ISCSI_PERSONALITY(QED_LEADING_HWFN(cdev))) && 24038c2ecf20Sopenharmony_ci (QED_AFFIN_HWFN(cdev) != QED_LEADING_HWFN(cdev)); 24048c2ecf20Sopenharmony_ci} 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_cistatic int __qed_ll2_stop(struct qed_hwfn *p_hwfn) 24078c2ecf20Sopenharmony_ci{ 24088c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 24098c2ecf20Sopenharmony_ci int rc; 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci rc = qed_ll2_terminate_connection(p_hwfn, cdev->ll2->handle); 24128c2ecf20Sopenharmony_ci if (rc) 24138c2ecf20Sopenharmony_ci DP_INFO(cdev, "Failed to terminate LL2 connection\n"); 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci qed_ll2_release_connection(p_hwfn, cdev->ll2->handle); 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci return rc; 24188c2ecf20Sopenharmony_ci} 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_cistatic int qed_ll2_stop(struct qed_dev *cdev) 24218c2ecf20Sopenharmony_ci{ 24228c2ecf20Sopenharmony_ci bool b_is_storage_eng1 = qed_ll2_is_storage_eng1(cdev); 24238c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_AFFIN_HWFN(cdev); 24248c2ecf20Sopenharmony_ci int rc = 0, rc2 = 0; 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci if (cdev->ll2->handle == QED_LL2_UNUSED_HANDLE) 24278c2ecf20Sopenharmony_ci return 0; 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci qed_llh_remove_mac_filter(cdev, 0, cdev->ll2_mac_address); 24308c2ecf20Sopenharmony_ci eth_zero_addr(cdev->ll2_mac_address); 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci if (QED_IS_ISCSI_PERSONALITY(p_hwfn)) 24338c2ecf20Sopenharmony_ci qed_ll2_stop_ooo(p_hwfn); 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci /* In CMT mode, LL2 is always started on engine 0 for a storage PF */ 24368c2ecf20Sopenharmony_ci if (b_is_storage_eng1) { 24378c2ecf20Sopenharmony_ci rc2 = __qed_ll2_stop(QED_LEADING_HWFN(cdev)); 24388c2ecf20Sopenharmony_ci if (rc2) 24398c2ecf20Sopenharmony_ci DP_NOTICE(QED_LEADING_HWFN(cdev), 24408c2ecf20Sopenharmony_ci "Failed to stop LL2 on engine 0\n"); 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci rc = __qed_ll2_stop(p_hwfn); 24448c2ecf20Sopenharmony_ci if (rc) 24458c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to stop LL2\n"); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci qed_ll2_kill_buffers(cdev); 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci cdev->ll2->handle = QED_LL2_UNUSED_HANDLE; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci return rc | rc2; 24528c2ecf20Sopenharmony_ci} 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_cistatic int __qed_ll2_start(struct qed_hwfn *p_hwfn, 24558c2ecf20Sopenharmony_ci struct qed_ll2_params *params) 24568c2ecf20Sopenharmony_ci{ 24578c2ecf20Sopenharmony_ci struct qed_ll2_buffer *buffer, *tmp_buffer; 24588c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 24598c2ecf20Sopenharmony_ci enum qed_ll2_conn_type conn_type; 24608c2ecf20Sopenharmony_ci struct qed_ll2_acquire_data data; 24618c2ecf20Sopenharmony_ci int rc, rx_cnt; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci switch (p_hwfn->hw_info.personality) { 24648c2ecf20Sopenharmony_ci case QED_PCI_FCOE: 24658c2ecf20Sopenharmony_ci conn_type = QED_LL2_TYPE_FCOE; 24668c2ecf20Sopenharmony_ci break; 24678c2ecf20Sopenharmony_ci case QED_PCI_ISCSI: 24688c2ecf20Sopenharmony_ci conn_type = QED_LL2_TYPE_ISCSI; 24698c2ecf20Sopenharmony_ci break; 24708c2ecf20Sopenharmony_ci case QED_PCI_ETH_ROCE: 24718c2ecf20Sopenharmony_ci conn_type = QED_LL2_TYPE_ROCE; 24728c2ecf20Sopenharmony_ci break; 24738c2ecf20Sopenharmony_ci default: 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci conn_type = QED_LL2_TYPE_TEST; 24768c2ecf20Sopenharmony_ci } 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci qed_ll2_set_conn_data(p_hwfn, &data, params, conn_type, 24798c2ecf20Sopenharmony_ci &cdev->ll2->handle, false); 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci rc = qed_ll2_acquire_connection(p_hwfn, &data); 24828c2ecf20Sopenharmony_ci if (rc) { 24838c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Failed to acquire LL2 connection\n"); 24848c2ecf20Sopenharmony_ci return rc; 24858c2ecf20Sopenharmony_ci } 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci rc = qed_ll2_establish_connection(p_hwfn, cdev->ll2->handle); 24888c2ecf20Sopenharmony_ci if (rc) { 24898c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Failed to establish LL2 connection\n"); 24908c2ecf20Sopenharmony_ci goto release_conn; 24918c2ecf20Sopenharmony_ci } 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci /* Post all Rx buffers to FW */ 24948c2ecf20Sopenharmony_ci spin_lock_bh(&cdev->ll2->lock); 24958c2ecf20Sopenharmony_ci rx_cnt = cdev->ll2->rx_cnt; 24968c2ecf20Sopenharmony_ci list_for_each_entry_safe(buffer, tmp_buffer, &cdev->ll2->list, list) { 24978c2ecf20Sopenharmony_ci rc = qed_ll2_post_rx_buffer(p_hwfn, 24988c2ecf20Sopenharmony_ci cdev->ll2->handle, 24998c2ecf20Sopenharmony_ci buffer->phys_addr, 0, buffer, 1); 25008c2ecf20Sopenharmony_ci if (rc) { 25018c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 25028c2ecf20Sopenharmony_ci "Failed to post an Rx buffer; Deleting it\n"); 25038c2ecf20Sopenharmony_ci dma_unmap_single(&cdev->pdev->dev, buffer->phys_addr, 25048c2ecf20Sopenharmony_ci cdev->ll2->rx_size, DMA_FROM_DEVICE); 25058c2ecf20Sopenharmony_ci kfree(buffer->data); 25068c2ecf20Sopenharmony_ci list_del(&buffer->list); 25078c2ecf20Sopenharmony_ci kfree(buffer); 25088c2ecf20Sopenharmony_ci } else { 25098c2ecf20Sopenharmony_ci rx_cnt++; 25108c2ecf20Sopenharmony_ci } 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci spin_unlock_bh(&cdev->ll2->lock); 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_ci if (rx_cnt == cdev->ll2->rx_cnt) { 25158c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed passing even a single Rx buffer\n"); 25168c2ecf20Sopenharmony_ci goto terminate_conn; 25178c2ecf20Sopenharmony_ci } 25188c2ecf20Sopenharmony_ci cdev->ll2->rx_cnt = rx_cnt; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci return 0; 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_citerminate_conn: 25238c2ecf20Sopenharmony_ci qed_ll2_terminate_connection(p_hwfn, cdev->ll2->handle); 25248c2ecf20Sopenharmony_cirelease_conn: 25258c2ecf20Sopenharmony_ci qed_ll2_release_connection(p_hwfn, cdev->ll2->handle); 25268c2ecf20Sopenharmony_ci return rc; 25278c2ecf20Sopenharmony_ci} 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_cistatic int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) 25308c2ecf20Sopenharmony_ci{ 25318c2ecf20Sopenharmony_ci bool b_is_storage_eng1 = qed_ll2_is_storage_eng1(cdev); 25328c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_AFFIN_HWFN(cdev); 25338c2ecf20Sopenharmony_ci struct qed_ll2_buffer *buffer; 25348c2ecf20Sopenharmony_ci int rx_num_desc, i, rc; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(params->ll2_mac_address)) { 25378c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Invalid Ethernet address\n"); 25388c2ecf20Sopenharmony_ci return -EINVAL; 25398c2ecf20Sopenharmony_ci } 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci WARN_ON(!cdev->ll2->cbs); 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci /* Initialize LL2 locks & lists */ 25448c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cdev->ll2->list); 25458c2ecf20Sopenharmony_ci spin_lock_init(&cdev->ll2->lock); 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci cdev->ll2->rx_size = PRM_DMA_PAD_BYTES_NUM + ETH_HLEN + 25488c2ecf20Sopenharmony_ci L1_CACHE_BYTES + params->mtu; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci /* Allocate memory for LL2. 25518c2ecf20Sopenharmony_ci * In CMT mode, in case of a storage PF which is affintized to engine 1, 25528c2ecf20Sopenharmony_ci * LL2 is started also on engine 0 and thus we need twofold buffers. 25538c2ecf20Sopenharmony_ci */ 25548c2ecf20Sopenharmony_ci rx_num_desc = QED_LL2_RX_SIZE * (b_is_storage_eng1 ? 2 : 1); 25558c2ecf20Sopenharmony_ci DP_INFO(cdev, "Allocating %d LL2 buffers of size %08x bytes\n", 25568c2ecf20Sopenharmony_ci rx_num_desc, cdev->ll2->rx_size); 25578c2ecf20Sopenharmony_ci for (i = 0; i < rx_num_desc; i++) { 25588c2ecf20Sopenharmony_ci buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); 25598c2ecf20Sopenharmony_ci if (!buffer) { 25608c2ecf20Sopenharmony_ci DP_INFO(cdev, "Failed to allocate LL2 buffers\n"); 25618c2ecf20Sopenharmony_ci rc = -ENOMEM; 25628c2ecf20Sopenharmony_ci goto err0; 25638c2ecf20Sopenharmony_ci } 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci rc = qed_ll2_alloc_buffer(cdev, (u8 **)&buffer->data, 25668c2ecf20Sopenharmony_ci &buffer->phys_addr); 25678c2ecf20Sopenharmony_ci if (rc) { 25688c2ecf20Sopenharmony_ci kfree(buffer); 25698c2ecf20Sopenharmony_ci goto err0; 25708c2ecf20Sopenharmony_ci } 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci list_add_tail(&buffer->list, &cdev->ll2->list); 25738c2ecf20Sopenharmony_ci } 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci rc = __qed_ll2_start(p_hwfn, params); 25768c2ecf20Sopenharmony_ci if (rc) { 25778c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Failed to start LL2\n"); 25788c2ecf20Sopenharmony_ci goto err0; 25798c2ecf20Sopenharmony_ci } 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci /* In CMT mode, always need to start LL2 on engine 0 for a storage PF, 25828c2ecf20Sopenharmony_ci * since broadcast/mutlicast packets are routed to engine 0. 25838c2ecf20Sopenharmony_ci */ 25848c2ecf20Sopenharmony_ci if (b_is_storage_eng1) { 25858c2ecf20Sopenharmony_ci rc = __qed_ll2_start(QED_LEADING_HWFN(cdev), params); 25868c2ecf20Sopenharmony_ci if (rc) { 25878c2ecf20Sopenharmony_ci DP_NOTICE(QED_LEADING_HWFN(cdev), 25888c2ecf20Sopenharmony_ci "Failed to start LL2 on engine 0\n"); 25898c2ecf20Sopenharmony_ci goto err1; 25908c2ecf20Sopenharmony_ci } 25918c2ecf20Sopenharmony_ci } 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci if (QED_IS_ISCSI_PERSONALITY(p_hwfn)) { 25948c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_STORAGE, "Starting OOO LL2 queue\n"); 25958c2ecf20Sopenharmony_ci rc = qed_ll2_start_ooo(p_hwfn, params); 25968c2ecf20Sopenharmony_ci if (rc) { 25978c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Failed to start OOO LL2\n"); 25988c2ecf20Sopenharmony_ci goto err2; 25998c2ecf20Sopenharmony_ci } 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci rc = qed_llh_add_mac_filter(cdev, 0, params->ll2_mac_address); 26038c2ecf20Sopenharmony_ci if (rc) { 26048c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Failed to add an LLH filter\n"); 26058c2ecf20Sopenharmony_ci goto err3; 26068c2ecf20Sopenharmony_ci } 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci ether_addr_copy(cdev->ll2_mac_address, params->ll2_mac_address); 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci return 0; 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_cierr3: 26138c2ecf20Sopenharmony_ci if (QED_IS_ISCSI_PERSONALITY(p_hwfn)) 26148c2ecf20Sopenharmony_ci qed_ll2_stop_ooo(p_hwfn); 26158c2ecf20Sopenharmony_cierr2: 26168c2ecf20Sopenharmony_ci if (b_is_storage_eng1) 26178c2ecf20Sopenharmony_ci __qed_ll2_stop(QED_LEADING_HWFN(cdev)); 26188c2ecf20Sopenharmony_cierr1: 26198c2ecf20Sopenharmony_ci __qed_ll2_stop(p_hwfn); 26208c2ecf20Sopenharmony_cierr0: 26218c2ecf20Sopenharmony_ci qed_ll2_kill_buffers(cdev); 26228c2ecf20Sopenharmony_ci cdev->ll2->handle = QED_LL2_UNUSED_HANDLE; 26238c2ecf20Sopenharmony_ci return rc; 26248c2ecf20Sopenharmony_ci} 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_cistatic int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb, 26278c2ecf20Sopenharmony_ci unsigned long xmit_flags) 26288c2ecf20Sopenharmony_ci{ 26298c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_AFFIN_HWFN(cdev); 26308c2ecf20Sopenharmony_ci struct qed_ll2_tx_pkt_info pkt; 26318c2ecf20Sopenharmony_ci const skb_frag_t *frag; 26328c2ecf20Sopenharmony_ci u8 flags = 0, nr_frags; 26338c2ecf20Sopenharmony_ci int rc = -EINVAL, i; 26348c2ecf20Sopenharmony_ci dma_addr_t mapping; 26358c2ecf20Sopenharmony_ci u16 vlan = 0; 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci if (unlikely(skb->ip_summed != CHECKSUM_NONE)) { 26388c2ecf20Sopenharmony_ci DP_INFO(cdev, "Cannot transmit a checksummed packet\n"); 26398c2ecf20Sopenharmony_ci return -EINVAL; 26408c2ecf20Sopenharmony_ci } 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci /* Cache number of fragments from SKB since SKB may be freed by 26438c2ecf20Sopenharmony_ci * the completion routine after calling qed_ll2_prepare_tx_packet() 26448c2ecf20Sopenharmony_ci */ 26458c2ecf20Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci if (1 + nr_frags > CORE_LL2_TX_MAX_BDS_PER_PACKET) { 26488c2ecf20Sopenharmony_ci DP_ERR(cdev, "Cannot transmit a packet with %d fragments\n", 26498c2ecf20Sopenharmony_ci 1 + nr_frags); 26508c2ecf20Sopenharmony_ci return -EINVAL; 26518c2ecf20Sopenharmony_ci } 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci mapping = dma_map_single(&cdev->pdev->dev, skb->data, 26548c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 26558c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&cdev->pdev->dev, mapping))) { 26568c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "SKB mapping failed\n"); 26578c2ecf20Sopenharmony_ci return -EINVAL; 26588c2ecf20Sopenharmony_ci } 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci /* Request HW to calculate IP csum */ 26618c2ecf20Sopenharmony_ci if (!((vlan_get_protocol(skb) == htons(ETH_P_IPV6)) && 26628c2ecf20Sopenharmony_ci ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6)) 26638c2ecf20Sopenharmony_ci flags |= BIT(CORE_TX_BD_DATA_IP_CSUM_SHIFT); 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 26668c2ecf20Sopenharmony_ci vlan = skb_vlan_tag_get(skb); 26678c2ecf20Sopenharmony_ci flags |= BIT(CORE_TX_BD_DATA_VLAN_INSERTION_SHIFT); 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci memset(&pkt, 0, sizeof(pkt)); 26718c2ecf20Sopenharmony_ci pkt.num_of_bds = 1 + nr_frags; 26728c2ecf20Sopenharmony_ci pkt.vlan = vlan; 26738c2ecf20Sopenharmony_ci pkt.bd_flags = flags; 26748c2ecf20Sopenharmony_ci pkt.tx_dest = QED_LL2_TX_DEST_NW; 26758c2ecf20Sopenharmony_ci pkt.first_frag = mapping; 26768c2ecf20Sopenharmony_ci pkt.first_frag_len = skb->len; 26778c2ecf20Sopenharmony_ci pkt.cookie = skb; 26788c2ecf20Sopenharmony_ci if (test_bit(QED_MF_UFP_SPECIFIC, &cdev->mf_bits) && 26798c2ecf20Sopenharmony_ci test_bit(QED_LL2_XMIT_FLAGS_FIP_DISCOVERY, &xmit_flags)) 26808c2ecf20Sopenharmony_ci pkt.remove_stag = true; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci /* qed_ll2_prepare_tx_packet() may actually send the packet if 26838c2ecf20Sopenharmony_ci * there are no fragments in the skb and subsequently the completion 26848c2ecf20Sopenharmony_ci * routine may run and free the SKB, so no dereferencing the SKB 26858c2ecf20Sopenharmony_ci * beyond this point unless skb has any fragments. 26868c2ecf20Sopenharmony_ci */ 26878c2ecf20Sopenharmony_ci rc = qed_ll2_prepare_tx_packet(p_hwfn, cdev->ll2->handle, 26888c2ecf20Sopenharmony_ci &pkt, 1); 26898c2ecf20Sopenharmony_ci if (rc) 26908c2ecf20Sopenharmony_ci goto err; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci for (i = 0; i < nr_frags; i++) { 26938c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[i]; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci mapping = skb_frag_dma_map(&cdev->pdev->dev, frag, 0, 26968c2ecf20Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&cdev->pdev->dev, mapping))) { 26998c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 27008c2ecf20Sopenharmony_ci "Unable to map frag - dropping packet\n"); 27018c2ecf20Sopenharmony_ci rc = -ENOMEM; 27028c2ecf20Sopenharmony_ci goto err; 27038c2ecf20Sopenharmony_ci } 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci rc = qed_ll2_set_fragment_of_tx_packet(p_hwfn, 27068c2ecf20Sopenharmony_ci cdev->ll2->handle, 27078c2ecf20Sopenharmony_ci mapping, 27088c2ecf20Sopenharmony_ci skb_frag_size(frag)); 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci /* if failed not much to do here, partial packet has been posted 27118c2ecf20Sopenharmony_ci * we can't free memory, will need to wait for completion 27128c2ecf20Sopenharmony_ci */ 27138c2ecf20Sopenharmony_ci if (rc) 27148c2ecf20Sopenharmony_ci goto err2; 27158c2ecf20Sopenharmony_ci } 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci return 0; 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_cierr: 27208c2ecf20Sopenharmony_ci dma_unmap_single(&cdev->pdev->dev, mapping, skb->len, DMA_TO_DEVICE); 27218c2ecf20Sopenharmony_cierr2: 27228c2ecf20Sopenharmony_ci return rc; 27238c2ecf20Sopenharmony_ci} 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_cistatic int qed_ll2_stats(struct qed_dev *cdev, struct qed_ll2_stats *stats) 27268c2ecf20Sopenharmony_ci{ 27278c2ecf20Sopenharmony_ci bool b_is_storage_eng1 = qed_ll2_is_storage_eng1(cdev); 27288c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_AFFIN_HWFN(cdev); 27298c2ecf20Sopenharmony_ci int rc; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci if (!cdev->ll2) 27328c2ecf20Sopenharmony_ci return -EINVAL; 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci rc = qed_ll2_get_stats(p_hwfn, cdev->ll2->handle, stats); 27358c2ecf20Sopenharmony_ci if (rc) { 27368c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to get LL2 stats\n"); 27378c2ecf20Sopenharmony_ci return rc; 27388c2ecf20Sopenharmony_ci } 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci /* In CMT mode, LL2 is always started on engine 0 for a storage PF */ 27418c2ecf20Sopenharmony_ci if (b_is_storage_eng1) { 27428c2ecf20Sopenharmony_ci rc = __qed_ll2_get_stats(QED_LEADING_HWFN(cdev), 27438c2ecf20Sopenharmony_ci cdev->ll2->handle, stats); 27448c2ecf20Sopenharmony_ci if (rc) { 27458c2ecf20Sopenharmony_ci DP_NOTICE(QED_LEADING_HWFN(cdev), 27468c2ecf20Sopenharmony_ci "Failed to get LL2 stats on engine 0\n"); 27478c2ecf20Sopenharmony_ci return rc; 27488c2ecf20Sopenharmony_ci } 27498c2ecf20Sopenharmony_ci } 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_ci return 0; 27528c2ecf20Sopenharmony_ci} 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ciconst struct qed_ll2_ops qed_ll2_ops_pass = { 27558c2ecf20Sopenharmony_ci .start = &qed_ll2_start, 27568c2ecf20Sopenharmony_ci .stop = &qed_ll2_stop, 27578c2ecf20Sopenharmony_ci .start_xmit = &qed_ll2_start_xmit, 27588c2ecf20Sopenharmony_ci .register_cb_ops = &qed_ll2_register_cb_ops, 27598c2ecf20Sopenharmony_ci .get_stats = &qed_ll2_stats, 27608c2ecf20Sopenharmony_ci}; 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ciint qed_ll2_alloc_if(struct qed_dev *cdev) 27638c2ecf20Sopenharmony_ci{ 27648c2ecf20Sopenharmony_ci cdev->ll2 = kzalloc(sizeof(*cdev->ll2), GFP_KERNEL); 27658c2ecf20Sopenharmony_ci return cdev->ll2 ? 0 : -ENOMEM; 27668c2ecf20Sopenharmony_ci} 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_civoid qed_ll2_dealloc_if(struct qed_dev *cdev) 27698c2ecf20Sopenharmony_ci{ 27708c2ecf20Sopenharmony_ci kfree(cdev->ll2); 27718c2ecf20Sopenharmony_ci cdev->ll2 = NULL; 27728c2ecf20Sopenharmony_ci} 2773