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/io.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/mutex.h> 158c2ecf20Sopenharmony_ci#include <linux/pci.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 198c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 208c2ecf20Sopenharmony_ci#include <linux/qed/qed_chain.h> 218c2ecf20Sopenharmony_ci#include <linux/qed/qed_if.h> 228c2ecf20Sopenharmony_ci#include "qed.h" 238c2ecf20Sopenharmony_ci#include "qed_cxt.h" 248c2ecf20Sopenharmony_ci#include "qed_dcbx.h" 258c2ecf20Sopenharmony_ci#include "qed_dev_api.h" 268c2ecf20Sopenharmony_ci#include "qed_fcoe.h" 278c2ecf20Sopenharmony_ci#include "qed_hsi.h" 288c2ecf20Sopenharmony_ci#include "qed_hw.h" 298c2ecf20Sopenharmony_ci#include "qed_init_ops.h" 308c2ecf20Sopenharmony_ci#include "qed_int.h" 318c2ecf20Sopenharmony_ci#include "qed_iscsi.h" 328c2ecf20Sopenharmony_ci#include "qed_ll2.h" 338c2ecf20Sopenharmony_ci#include "qed_mcp.h" 348c2ecf20Sopenharmony_ci#include "qed_ooo.h" 358c2ecf20Sopenharmony_ci#include "qed_reg_addr.h" 368c2ecf20Sopenharmony_ci#include "qed_sp.h" 378c2ecf20Sopenharmony_ci#include "qed_sriov.h" 388c2ecf20Sopenharmony_ci#include "qed_vf.h" 398c2ecf20Sopenharmony_ci#include "qed_rdma.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(qm_lock); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/******************** Doorbell Recovery *******************/ 448c2ecf20Sopenharmony_ci/* The doorbell recovery mechanism consists of a list of entries which represent 458c2ecf20Sopenharmony_ci * doorbelling entities (l2 queues, roce sq/rq/cqs, the slowpath spq, etc). Each 468c2ecf20Sopenharmony_ci * entity needs to register with the mechanism and provide the parameters 478c2ecf20Sopenharmony_ci * describing it's doorbell, including a location where last used doorbell data 488c2ecf20Sopenharmony_ci * can be found. The doorbell execute function will traverse the list and 498c2ecf20Sopenharmony_ci * doorbell all of the registered entries. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistruct qed_db_recovery_entry { 528c2ecf20Sopenharmony_ci struct list_head list_entry; 538c2ecf20Sopenharmony_ci void __iomem *db_addr; 548c2ecf20Sopenharmony_ci void *db_data; 558c2ecf20Sopenharmony_ci enum qed_db_rec_width db_width; 568c2ecf20Sopenharmony_ci enum qed_db_rec_space db_space; 578c2ecf20Sopenharmony_ci u8 hwfn_idx; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* Display a single doorbell recovery entry */ 618c2ecf20Sopenharmony_cistatic void qed_db_recovery_dp_entry(struct qed_hwfn *p_hwfn, 628c2ecf20Sopenharmony_ci struct qed_db_recovery_entry *db_entry, 638c2ecf20Sopenharmony_ci char *action) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 668c2ecf20Sopenharmony_ci QED_MSG_SPQ, 678c2ecf20Sopenharmony_ci "(%s: db_entry %p, addr %p, data %p, width %s, %s space, hwfn %d)\n", 688c2ecf20Sopenharmony_ci action, 698c2ecf20Sopenharmony_ci db_entry, 708c2ecf20Sopenharmony_ci db_entry->db_addr, 718c2ecf20Sopenharmony_ci db_entry->db_data, 728c2ecf20Sopenharmony_ci db_entry->db_width == DB_REC_WIDTH_32B ? "32b" : "64b", 738c2ecf20Sopenharmony_ci db_entry->db_space == DB_REC_USER ? "user" : "kernel", 748c2ecf20Sopenharmony_ci db_entry->hwfn_idx); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Doorbell address sanity (address within doorbell bar range) */ 788c2ecf20Sopenharmony_cistatic bool qed_db_rec_sanity(struct qed_dev *cdev, 798c2ecf20Sopenharmony_ci void __iomem *db_addr, 808c2ecf20Sopenharmony_ci enum qed_db_rec_width db_width, 818c2ecf20Sopenharmony_ci void *db_data) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci u32 width = (db_width == DB_REC_WIDTH_32B) ? 32 : 64; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* Make sure doorbell address is within the doorbell bar */ 868c2ecf20Sopenharmony_ci if (db_addr < cdev->doorbells || 878c2ecf20Sopenharmony_ci (u8 __iomem *)db_addr + width > 888c2ecf20Sopenharmony_ci (u8 __iomem *)cdev->doorbells + cdev->db_size) { 898c2ecf20Sopenharmony_ci WARN(true, 908c2ecf20Sopenharmony_ci "Illegal doorbell address: %p. Legal range for doorbell addresses is [%p..%p]\n", 918c2ecf20Sopenharmony_ci db_addr, 928c2ecf20Sopenharmony_ci cdev->doorbells, 938c2ecf20Sopenharmony_ci (u8 __iomem *)cdev->doorbells + cdev->db_size); 948c2ecf20Sopenharmony_ci return false; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* ake sure doorbell data pointer is not null */ 988c2ecf20Sopenharmony_ci if (!db_data) { 998c2ecf20Sopenharmony_ci WARN(true, "Illegal doorbell data pointer: %p", db_data); 1008c2ecf20Sopenharmony_ci return false; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return true; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Find hwfn according to the doorbell address */ 1078c2ecf20Sopenharmony_cistatic struct qed_hwfn *qed_db_rec_find_hwfn(struct qed_dev *cdev, 1088c2ecf20Sopenharmony_ci void __iomem *db_addr) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* In CMT doorbell bar is split down the middle between engine 0 and enigne 1 */ 1138c2ecf20Sopenharmony_ci if (cdev->num_hwfns > 1) 1148c2ecf20Sopenharmony_ci p_hwfn = db_addr < cdev->hwfns[1].doorbells ? 1158c2ecf20Sopenharmony_ci &cdev->hwfns[0] : &cdev->hwfns[1]; 1168c2ecf20Sopenharmony_ci else 1178c2ecf20Sopenharmony_ci p_hwfn = QED_LEADING_HWFN(cdev); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return p_hwfn; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* Add a new entry to the doorbell recovery mechanism */ 1238c2ecf20Sopenharmony_ciint qed_db_recovery_add(struct qed_dev *cdev, 1248c2ecf20Sopenharmony_ci void __iomem *db_addr, 1258c2ecf20Sopenharmony_ci void *db_data, 1268c2ecf20Sopenharmony_ci enum qed_db_rec_width db_width, 1278c2ecf20Sopenharmony_ci enum qed_db_rec_space db_space) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct qed_db_recovery_entry *db_entry; 1308c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Shortcircuit VFs, for now */ 1338c2ecf20Sopenharmony_ci if (IS_VF(cdev)) { 1348c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 1358c2ecf20Sopenharmony_ci QED_MSG_IOV, "db recovery - skipping VF doorbell\n"); 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* Sanitize doorbell address */ 1408c2ecf20Sopenharmony_ci if (!qed_db_rec_sanity(cdev, db_addr, db_width, db_data)) 1418c2ecf20Sopenharmony_ci return -EINVAL; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* Obtain hwfn from doorbell address */ 1448c2ecf20Sopenharmony_ci p_hwfn = qed_db_rec_find_hwfn(cdev, db_addr); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* Create entry */ 1478c2ecf20Sopenharmony_ci db_entry = kzalloc(sizeof(*db_entry), GFP_KERNEL); 1488c2ecf20Sopenharmony_ci if (!db_entry) { 1498c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Failed to allocate a db recovery entry\n"); 1508c2ecf20Sopenharmony_ci return -ENOMEM; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* Populate entry */ 1548c2ecf20Sopenharmony_ci db_entry->db_addr = db_addr; 1558c2ecf20Sopenharmony_ci db_entry->db_data = db_data; 1568c2ecf20Sopenharmony_ci db_entry->db_width = db_width; 1578c2ecf20Sopenharmony_ci db_entry->db_space = db_space; 1588c2ecf20Sopenharmony_ci db_entry->hwfn_idx = p_hwfn->my_id; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Display */ 1618c2ecf20Sopenharmony_ci qed_db_recovery_dp_entry(p_hwfn, db_entry, "Adding"); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* Protect the list */ 1648c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->db_recovery_info.lock); 1658c2ecf20Sopenharmony_ci list_add_tail(&db_entry->list_entry, &p_hwfn->db_recovery_info.list); 1668c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->db_recovery_info.lock); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* Remove an entry from the doorbell recovery mechanism */ 1728c2ecf20Sopenharmony_ciint qed_db_recovery_del(struct qed_dev *cdev, 1738c2ecf20Sopenharmony_ci void __iomem *db_addr, void *db_data) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct qed_db_recovery_entry *db_entry = NULL; 1768c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn; 1778c2ecf20Sopenharmony_ci int rc = -EINVAL; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Shortcircuit VFs, for now */ 1808c2ecf20Sopenharmony_ci if (IS_VF(cdev)) { 1818c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 1828c2ecf20Sopenharmony_ci QED_MSG_IOV, "db recovery - skipping VF doorbell\n"); 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Obtain hwfn from doorbell address */ 1878c2ecf20Sopenharmony_ci p_hwfn = qed_db_rec_find_hwfn(cdev, db_addr); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Protect the list */ 1908c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->db_recovery_info.lock); 1918c2ecf20Sopenharmony_ci list_for_each_entry(db_entry, 1928c2ecf20Sopenharmony_ci &p_hwfn->db_recovery_info.list, list_entry) { 1938c2ecf20Sopenharmony_ci /* search according to db_data addr since db_addr is not unique (roce) */ 1948c2ecf20Sopenharmony_ci if (db_entry->db_data == db_data) { 1958c2ecf20Sopenharmony_ci qed_db_recovery_dp_entry(p_hwfn, db_entry, "Deleting"); 1968c2ecf20Sopenharmony_ci list_del(&db_entry->list_entry); 1978c2ecf20Sopenharmony_ci rc = 0; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->db_recovery_info.lock); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (rc == -EINVAL) 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 2078c2ecf20Sopenharmony_ci "Failed to find element in list. Key (db_data addr) was %p. db_addr was %p\n", 2088c2ecf20Sopenharmony_ci db_data, db_addr); 2098c2ecf20Sopenharmony_ci else 2108c2ecf20Sopenharmony_ci kfree(db_entry); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return rc; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* Initialize the doorbell recovery mechanism */ 2168c2ecf20Sopenharmony_cistatic int qed_db_recovery_setup(struct qed_hwfn *p_hwfn) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SPQ, "Setting up db recovery\n"); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* Make sure db_size was set in cdev */ 2218c2ecf20Sopenharmony_ci if (!p_hwfn->cdev->db_size) { 2228c2ecf20Sopenharmony_ci DP_ERR(p_hwfn->cdev, "db_size not set\n"); 2238c2ecf20Sopenharmony_ci return -EINVAL; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p_hwfn->db_recovery_info.list); 2278c2ecf20Sopenharmony_ci spin_lock_init(&p_hwfn->db_recovery_info.lock); 2288c2ecf20Sopenharmony_ci p_hwfn->db_recovery_info.db_recovery_counter = 0; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/* Destroy the doorbell recovery mechanism */ 2348c2ecf20Sopenharmony_cistatic void qed_db_recovery_teardown(struct qed_hwfn *p_hwfn) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct qed_db_recovery_entry *db_entry = NULL; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SPQ, "Tearing down db recovery\n"); 2398c2ecf20Sopenharmony_ci if (!list_empty(&p_hwfn->db_recovery_info.list)) { 2408c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 2418c2ecf20Sopenharmony_ci QED_MSG_SPQ, 2428c2ecf20Sopenharmony_ci "Doorbell Recovery teardown found the doorbell recovery list was not empty (Expected in disorderly driver unload (e.g. recovery) otherwise this probably means some flow forgot to db_recovery_del). Prepare to purge doorbell recovery list...\n"); 2438c2ecf20Sopenharmony_ci while (!list_empty(&p_hwfn->db_recovery_info.list)) { 2448c2ecf20Sopenharmony_ci db_entry = 2458c2ecf20Sopenharmony_ci list_first_entry(&p_hwfn->db_recovery_info.list, 2468c2ecf20Sopenharmony_ci struct qed_db_recovery_entry, 2478c2ecf20Sopenharmony_ci list_entry); 2488c2ecf20Sopenharmony_ci qed_db_recovery_dp_entry(p_hwfn, db_entry, "Purging"); 2498c2ecf20Sopenharmony_ci list_del(&db_entry->list_entry); 2508c2ecf20Sopenharmony_ci kfree(db_entry); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci p_hwfn->db_recovery_info.db_recovery_counter = 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/* Print the content of the doorbell recovery mechanism */ 2578c2ecf20Sopenharmony_civoid qed_db_recovery_dp(struct qed_hwfn *p_hwfn) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct qed_db_recovery_entry *db_entry = NULL; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 2628c2ecf20Sopenharmony_ci "Displaying doorbell recovery database. Counter was %d\n", 2638c2ecf20Sopenharmony_ci p_hwfn->db_recovery_info.db_recovery_counter); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Protect the list */ 2668c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->db_recovery_info.lock); 2678c2ecf20Sopenharmony_ci list_for_each_entry(db_entry, 2688c2ecf20Sopenharmony_ci &p_hwfn->db_recovery_info.list, list_entry) { 2698c2ecf20Sopenharmony_ci qed_db_recovery_dp_entry(p_hwfn, db_entry, "Printing"); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->db_recovery_info.lock); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/* Ring the doorbell of a single doorbell recovery entry */ 2768c2ecf20Sopenharmony_cistatic void qed_db_recovery_ring(struct qed_hwfn *p_hwfn, 2778c2ecf20Sopenharmony_ci struct qed_db_recovery_entry *db_entry) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci /* Print according to width */ 2808c2ecf20Sopenharmony_ci if (db_entry->db_width == DB_REC_WIDTH_32B) { 2818c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SPQ, 2828c2ecf20Sopenharmony_ci "ringing doorbell address %p data %x\n", 2838c2ecf20Sopenharmony_ci db_entry->db_addr, 2848c2ecf20Sopenharmony_ci *(u32 *)db_entry->db_data); 2858c2ecf20Sopenharmony_ci } else { 2868c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SPQ, 2878c2ecf20Sopenharmony_ci "ringing doorbell address %p data %llx\n", 2888c2ecf20Sopenharmony_ci db_entry->db_addr, 2898c2ecf20Sopenharmony_ci *(u64 *)(db_entry->db_data)); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Sanity */ 2938c2ecf20Sopenharmony_ci if (!qed_db_rec_sanity(p_hwfn->cdev, db_entry->db_addr, 2948c2ecf20Sopenharmony_ci db_entry->db_width, db_entry->db_data)) 2958c2ecf20Sopenharmony_ci return; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Flush the write combined buffer. Since there are multiple doorbelling 2988c2ecf20Sopenharmony_ci * entities using the same address, if we don't flush, a transaction 2998c2ecf20Sopenharmony_ci * could be lost. 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_ci wmb(); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Ring the doorbell */ 3048c2ecf20Sopenharmony_ci if (db_entry->db_width == DB_REC_WIDTH_32B) 3058c2ecf20Sopenharmony_ci DIRECT_REG_WR(db_entry->db_addr, 3068c2ecf20Sopenharmony_ci *(u32 *)(db_entry->db_data)); 3078c2ecf20Sopenharmony_ci else 3088c2ecf20Sopenharmony_ci DIRECT_REG_WR64(db_entry->db_addr, 3098c2ecf20Sopenharmony_ci *(u64 *)(db_entry->db_data)); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Flush the write combined buffer. Next doorbell may come from a 3128c2ecf20Sopenharmony_ci * different entity to the same address... 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_ci wmb(); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* Traverse the doorbell recovery entry list and ring all the doorbells */ 3188c2ecf20Sopenharmony_civoid qed_db_recovery_execute(struct qed_hwfn *p_hwfn) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct qed_db_recovery_entry *db_entry = NULL; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Executing doorbell recovery. Counter was %d\n", 3238c2ecf20Sopenharmony_ci p_hwfn->db_recovery_info.db_recovery_counter); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* Track amount of times recovery was executed */ 3268c2ecf20Sopenharmony_ci p_hwfn->db_recovery_info.db_recovery_counter++; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* Protect the list */ 3298c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->db_recovery_info.lock); 3308c2ecf20Sopenharmony_ci list_for_each_entry(db_entry, 3318c2ecf20Sopenharmony_ci &p_hwfn->db_recovery_info.list, list_entry) 3328c2ecf20Sopenharmony_ci qed_db_recovery_ring(p_hwfn, db_entry); 3338c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->db_recovery_info.lock); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/******************** Doorbell Recovery end ****************/ 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci/********************************** NIG LLH ***********************************/ 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cienum qed_llh_filter_type { 3418c2ecf20Sopenharmony_ci QED_LLH_FILTER_TYPE_MAC, 3428c2ecf20Sopenharmony_ci QED_LLH_FILTER_TYPE_PROTOCOL, 3438c2ecf20Sopenharmony_ci}; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistruct qed_llh_mac_filter { 3468c2ecf20Sopenharmony_ci u8 addr[ETH_ALEN]; 3478c2ecf20Sopenharmony_ci}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistruct qed_llh_protocol_filter { 3508c2ecf20Sopenharmony_ci enum qed_llh_prot_filter_type_t type; 3518c2ecf20Sopenharmony_ci u16 source_port_or_eth_type; 3528c2ecf20Sopenharmony_ci u16 dest_port; 3538c2ecf20Sopenharmony_ci}; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ciunion qed_llh_filter { 3568c2ecf20Sopenharmony_ci struct qed_llh_mac_filter mac; 3578c2ecf20Sopenharmony_ci struct qed_llh_protocol_filter protocol; 3588c2ecf20Sopenharmony_ci}; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistruct qed_llh_filter_info { 3618c2ecf20Sopenharmony_ci bool b_enabled; 3628c2ecf20Sopenharmony_ci u32 ref_cnt; 3638c2ecf20Sopenharmony_ci enum qed_llh_filter_type type; 3648c2ecf20Sopenharmony_ci union qed_llh_filter filter; 3658c2ecf20Sopenharmony_ci}; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistruct qed_llh_info { 3688c2ecf20Sopenharmony_ci /* Number of LLH filters banks */ 3698c2ecf20Sopenharmony_ci u8 num_ppfid; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci#define MAX_NUM_PPFID 8 3728c2ecf20Sopenharmony_ci u8 ppfid_array[MAX_NUM_PPFID]; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Array of filters arrays: 3758c2ecf20Sopenharmony_ci * "num_ppfid" elements of filters banks, where each is an array of 3768c2ecf20Sopenharmony_ci * "NIG_REG_LLH_FUNC_FILTER_EN_SIZE" filters. 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci struct qed_llh_filter_info **pp_filters; 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic void qed_llh_free(struct qed_dev *cdev) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct qed_llh_info *p_llh_info = cdev->p_llh_info; 3848c2ecf20Sopenharmony_ci u32 i; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (p_llh_info) { 3878c2ecf20Sopenharmony_ci if (p_llh_info->pp_filters) 3888c2ecf20Sopenharmony_ci for (i = 0; i < p_llh_info->num_ppfid; i++) 3898c2ecf20Sopenharmony_ci kfree(p_llh_info->pp_filters[i]); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci kfree(p_llh_info->pp_filters); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci kfree(p_llh_info); 3958c2ecf20Sopenharmony_ci cdev->p_llh_info = NULL; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int qed_llh_alloc(struct qed_dev *cdev) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct qed_llh_info *p_llh_info; 4018c2ecf20Sopenharmony_ci u32 size, i; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci p_llh_info = kzalloc(sizeof(*p_llh_info), GFP_KERNEL); 4048c2ecf20Sopenharmony_ci if (!p_llh_info) 4058c2ecf20Sopenharmony_ci return -ENOMEM; 4068c2ecf20Sopenharmony_ci cdev->p_llh_info = p_llh_info; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NUM_PPFID; i++) { 4098c2ecf20Sopenharmony_ci if (!(cdev->ppfid_bitmap & (0x1 << i))) 4108c2ecf20Sopenharmony_ci continue; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci p_llh_info->ppfid_array[p_llh_info->num_ppfid] = i; 4138c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_SP, "ppfid_array[%d] = %hhd\n", 4148c2ecf20Sopenharmony_ci p_llh_info->num_ppfid, i); 4158c2ecf20Sopenharmony_ci p_llh_info->num_ppfid++; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci size = p_llh_info->num_ppfid * sizeof(*p_llh_info->pp_filters); 4198c2ecf20Sopenharmony_ci p_llh_info->pp_filters = kzalloc(size, GFP_KERNEL); 4208c2ecf20Sopenharmony_ci if (!p_llh_info->pp_filters) 4218c2ecf20Sopenharmony_ci return -ENOMEM; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci size = NIG_REG_LLH_FUNC_FILTER_EN_SIZE * 4248c2ecf20Sopenharmony_ci sizeof(**p_llh_info->pp_filters); 4258c2ecf20Sopenharmony_ci for (i = 0; i < p_llh_info->num_ppfid; i++) { 4268c2ecf20Sopenharmony_ci p_llh_info->pp_filters[i] = kzalloc(size, GFP_KERNEL); 4278c2ecf20Sopenharmony_ci if (!p_llh_info->pp_filters[i]) 4288c2ecf20Sopenharmony_ci return -ENOMEM; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return 0; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic int qed_llh_shadow_sanity(struct qed_dev *cdev, 4358c2ecf20Sopenharmony_ci u8 ppfid, u8 filter_idx, const char *action) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci struct qed_llh_info *p_llh_info = cdev->p_llh_info; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (ppfid >= p_llh_info->num_ppfid) { 4408c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 4418c2ecf20Sopenharmony_ci "LLH shadow [%s]: using ppfid %d while only %d ppfids are available\n", 4428c2ecf20Sopenharmony_ci action, ppfid, p_llh_info->num_ppfid); 4438c2ecf20Sopenharmony_ci return -EINVAL; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (filter_idx >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE) { 4478c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 4488c2ecf20Sopenharmony_ci "LLH shadow [%s]: using filter_idx %d while only %d filters are available\n", 4498c2ecf20Sopenharmony_ci action, filter_idx, NIG_REG_LLH_FUNC_FILTER_EN_SIZE); 4508c2ecf20Sopenharmony_ci return -EINVAL; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci#define QED_LLH_INVALID_FILTER_IDX 0xff 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int 4598c2ecf20Sopenharmony_ciqed_llh_shadow_search_filter(struct qed_dev *cdev, 4608c2ecf20Sopenharmony_ci u8 ppfid, 4618c2ecf20Sopenharmony_ci union qed_llh_filter *p_filter, u8 *p_filter_idx) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct qed_llh_info *p_llh_info = cdev->p_llh_info; 4648c2ecf20Sopenharmony_ci struct qed_llh_filter_info *p_filters; 4658c2ecf20Sopenharmony_ci int rc; 4668c2ecf20Sopenharmony_ci u8 i; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci rc = qed_llh_shadow_sanity(cdev, ppfid, 0, "search"); 4698c2ecf20Sopenharmony_ci if (rc) 4708c2ecf20Sopenharmony_ci return rc; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci *p_filter_idx = QED_LLH_INVALID_FILTER_IDX; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci p_filters = p_llh_info->pp_filters[ppfid]; 4758c2ecf20Sopenharmony_ci for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) { 4768c2ecf20Sopenharmony_ci if (!memcmp(p_filter, &p_filters[i].filter, 4778c2ecf20Sopenharmony_ci sizeof(*p_filter))) { 4788c2ecf20Sopenharmony_ci *p_filter_idx = i; 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return 0; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int 4878c2ecf20Sopenharmony_ciqed_llh_shadow_get_free_idx(struct qed_dev *cdev, u8 ppfid, u8 *p_filter_idx) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct qed_llh_info *p_llh_info = cdev->p_llh_info; 4908c2ecf20Sopenharmony_ci struct qed_llh_filter_info *p_filters; 4918c2ecf20Sopenharmony_ci int rc; 4928c2ecf20Sopenharmony_ci u8 i; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci rc = qed_llh_shadow_sanity(cdev, ppfid, 0, "get_free_idx"); 4958c2ecf20Sopenharmony_ci if (rc) 4968c2ecf20Sopenharmony_ci return rc; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci *p_filter_idx = QED_LLH_INVALID_FILTER_IDX; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci p_filters = p_llh_info->pp_filters[ppfid]; 5018c2ecf20Sopenharmony_ci for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) { 5028c2ecf20Sopenharmony_ci if (!p_filters[i].b_enabled) { 5038c2ecf20Sopenharmony_ci *p_filter_idx = i; 5048c2ecf20Sopenharmony_ci break; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic int 5128c2ecf20Sopenharmony_ci__qed_llh_shadow_add_filter(struct qed_dev *cdev, 5138c2ecf20Sopenharmony_ci u8 ppfid, 5148c2ecf20Sopenharmony_ci u8 filter_idx, 5158c2ecf20Sopenharmony_ci enum qed_llh_filter_type type, 5168c2ecf20Sopenharmony_ci union qed_llh_filter *p_filter, u32 *p_ref_cnt) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct qed_llh_info *p_llh_info = cdev->p_llh_info; 5198c2ecf20Sopenharmony_ci struct qed_llh_filter_info *p_filters; 5208c2ecf20Sopenharmony_ci int rc; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci rc = qed_llh_shadow_sanity(cdev, ppfid, filter_idx, "add"); 5238c2ecf20Sopenharmony_ci if (rc) 5248c2ecf20Sopenharmony_ci return rc; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci p_filters = p_llh_info->pp_filters[ppfid]; 5278c2ecf20Sopenharmony_ci if (!p_filters[filter_idx].ref_cnt) { 5288c2ecf20Sopenharmony_ci p_filters[filter_idx].b_enabled = true; 5298c2ecf20Sopenharmony_ci p_filters[filter_idx].type = type; 5308c2ecf20Sopenharmony_ci memcpy(&p_filters[filter_idx].filter, p_filter, 5318c2ecf20Sopenharmony_ci sizeof(p_filters[filter_idx].filter)); 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci *p_ref_cnt = ++p_filters[filter_idx].ref_cnt; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic int 5408c2ecf20Sopenharmony_ciqed_llh_shadow_add_filter(struct qed_dev *cdev, 5418c2ecf20Sopenharmony_ci u8 ppfid, 5428c2ecf20Sopenharmony_ci enum qed_llh_filter_type type, 5438c2ecf20Sopenharmony_ci union qed_llh_filter *p_filter, 5448c2ecf20Sopenharmony_ci u8 *p_filter_idx, u32 *p_ref_cnt) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci int rc; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* Check if the same filter already exist */ 5498c2ecf20Sopenharmony_ci rc = qed_llh_shadow_search_filter(cdev, ppfid, p_filter, p_filter_idx); 5508c2ecf20Sopenharmony_ci if (rc) 5518c2ecf20Sopenharmony_ci return rc; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* Find a new entry in case of a new filter */ 5548c2ecf20Sopenharmony_ci if (*p_filter_idx == QED_LLH_INVALID_FILTER_IDX) { 5558c2ecf20Sopenharmony_ci rc = qed_llh_shadow_get_free_idx(cdev, ppfid, p_filter_idx); 5568c2ecf20Sopenharmony_ci if (rc) 5578c2ecf20Sopenharmony_ci return rc; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* No free entry was found */ 5618c2ecf20Sopenharmony_ci if (*p_filter_idx == QED_LLH_INVALID_FILTER_IDX) { 5628c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 5638c2ecf20Sopenharmony_ci "Failed to find an empty LLH filter to utilize [ppfid %d]\n", 5648c2ecf20Sopenharmony_ci ppfid); 5658c2ecf20Sopenharmony_ci return -EINVAL; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return __qed_llh_shadow_add_filter(cdev, ppfid, *p_filter_idx, type, 5698c2ecf20Sopenharmony_ci p_filter, p_ref_cnt); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int 5738c2ecf20Sopenharmony_ci__qed_llh_shadow_remove_filter(struct qed_dev *cdev, 5748c2ecf20Sopenharmony_ci u8 ppfid, u8 filter_idx, u32 *p_ref_cnt) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct qed_llh_info *p_llh_info = cdev->p_llh_info; 5778c2ecf20Sopenharmony_ci struct qed_llh_filter_info *p_filters; 5788c2ecf20Sopenharmony_ci int rc; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci rc = qed_llh_shadow_sanity(cdev, ppfid, filter_idx, "remove"); 5818c2ecf20Sopenharmony_ci if (rc) 5828c2ecf20Sopenharmony_ci return rc; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci p_filters = p_llh_info->pp_filters[ppfid]; 5858c2ecf20Sopenharmony_ci if (!p_filters[filter_idx].ref_cnt) { 5868c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 5878c2ecf20Sopenharmony_ci "LLH shadow: trying to remove a filter with ref_cnt=0\n"); 5888c2ecf20Sopenharmony_ci return -EINVAL; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci *p_ref_cnt = --p_filters[filter_idx].ref_cnt; 5928c2ecf20Sopenharmony_ci if (!p_filters[filter_idx].ref_cnt) 5938c2ecf20Sopenharmony_ci memset(&p_filters[filter_idx], 5948c2ecf20Sopenharmony_ci 0, sizeof(p_filters[filter_idx])); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic int 6008c2ecf20Sopenharmony_ciqed_llh_shadow_remove_filter(struct qed_dev *cdev, 6018c2ecf20Sopenharmony_ci u8 ppfid, 6028c2ecf20Sopenharmony_ci union qed_llh_filter *p_filter, 6038c2ecf20Sopenharmony_ci u8 *p_filter_idx, u32 *p_ref_cnt) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci int rc; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci rc = qed_llh_shadow_search_filter(cdev, ppfid, p_filter, p_filter_idx); 6088c2ecf20Sopenharmony_ci if (rc) 6098c2ecf20Sopenharmony_ci return rc; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* No matching filter was found */ 6128c2ecf20Sopenharmony_ci if (*p_filter_idx == QED_LLH_INVALID_FILTER_IDX) { 6138c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Failed to find a filter in the LLH shadow\n"); 6148c2ecf20Sopenharmony_ci return -EINVAL; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci return __qed_llh_shadow_remove_filter(cdev, ppfid, *p_filter_idx, 6188c2ecf20Sopenharmony_ci p_ref_cnt); 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int qed_llh_abs_ppfid(struct qed_dev *cdev, u8 ppfid, u8 *p_abs_ppfid) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct qed_llh_info *p_llh_info = cdev->p_llh_info; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (ppfid >= p_llh_info->num_ppfid) { 6268c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 6278c2ecf20Sopenharmony_ci "ppfid %d is not valid, available indices are 0..%hhd\n", 6288c2ecf20Sopenharmony_ci ppfid, p_llh_info->num_ppfid - 1); 6298c2ecf20Sopenharmony_ci *p_abs_ppfid = 0; 6308c2ecf20Sopenharmony_ci return -EINVAL; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci *p_abs_ppfid = p_llh_info->ppfid_array[ppfid]; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return 0; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic int 6398c2ecf20Sopenharmony_ciqed_llh_set_engine_affin(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 6428c2ecf20Sopenharmony_ci enum qed_eng eng; 6438c2ecf20Sopenharmony_ci u8 ppfid; 6448c2ecf20Sopenharmony_ci int rc; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci rc = qed_mcp_get_engine_config(p_hwfn, p_ptt); 6478c2ecf20Sopenharmony_ci if (rc != 0 && rc != -EOPNOTSUPP) { 6488c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 6498c2ecf20Sopenharmony_ci "Failed to get the engine affinity configuration\n"); 6508c2ecf20Sopenharmony_ci return rc; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* RoCE PF is bound to a single engine */ 6548c2ecf20Sopenharmony_ci if (QED_IS_ROCE_PERSONALITY(p_hwfn)) { 6558c2ecf20Sopenharmony_ci eng = cdev->fir_affin ? QED_ENG1 : QED_ENG0; 6568c2ecf20Sopenharmony_ci rc = qed_llh_set_roce_affinity(cdev, eng); 6578c2ecf20Sopenharmony_ci if (rc) { 6588c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 6598c2ecf20Sopenharmony_ci "Failed to set the RoCE engine affinity\n"); 6608c2ecf20Sopenharmony_ci return rc; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 6648c2ecf20Sopenharmony_ci QED_MSG_SP, 6658c2ecf20Sopenharmony_ci "LLH: Set the engine affinity of RoCE packets as %d\n", 6668c2ecf20Sopenharmony_ci eng); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* Storage PF is bound to a single engine while L2 PF uses both */ 6708c2ecf20Sopenharmony_ci if (QED_IS_FCOE_PERSONALITY(p_hwfn) || QED_IS_ISCSI_PERSONALITY(p_hwfn)) 6718c2ecf20Sopenharmony_ci eng = cdev->fir_affin ? QED_ENG1 : QED_ENG0; 6728c2ecf20Sopenharmony_ci else /* L2_PERSONALITY */ 6738c2ecf20Sopenharmony_ci eng = QED_BOTH_ENG; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) { 6768c2ecf20Sopenharmony_ci rc = qed_llh_set_ppfid_affinity(cdev, ppfid, eng); 6778c2ecf20Sopenharmony_ci if (rc) { 6788c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 6798c2ecf20Sopenharmony_ci "Failed to set the engine affinity of ppfid %d\n", 6808c2ecf20Sopenharmony_ci ppfid); 6818c2ecf20Sopenharmony_ci return rc; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, QED_MSG_SP, 6868c2ecf20Sopenharmony_ci "LLH: Set the engine affinity of non-RoCE packets as %d\n", 6878c2ecf20Sopenharmony_ci eng); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic int qed_llh_hw_init_pf(struct qed_hwfn *p_hwfn, 6938c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 6968c2ecf20Sopenharmony_ci u8 ppfid, abs_ppfid; 6978c2ecf20Sopenharmony_ci int rc; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) { 7008c2ecf20Sopenharmony_ci u32 addr; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid); 7038c2ecf20Sopenharmony_ci if (rc) 7048c2ecf20Sopenharmony_ci return rc; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci addr = NIG_REG_LLH_PPFID2PFID_TBL_0 + abs_ppfid * 0x4; 7078c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, addr, p_hwfn->rel_pf_id); 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits) && 7118c2ecf20Sopenharmony_ci !QED_IS_FCOE_PERSONALITY(p_hwfn)) { 7128c2ecf20Sopenharmony_ci rc = qed_llh_add_mac_filter(cdev, 0, 7138c2ecf20Sopenharmony_ci p_hwfn->hw_info.hw_mac_addr); 7148c2ecf20Sopenharmony_ci if (rc) 7158c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 7168c2ecf20Sopenharmony_ci "Failed to add an LLH filter with the primary MAC\n"); 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (QED_IS_CMT(cdev)) { 7208c2ecf20Sopenharmony_ci rc = qed_llh_set_engine_affin(p_hwfn, p_ptt); 7218c2ecf20Sopenharmony_ci if (rc) 7228c2ecf20Sopenharmony_ci return rc; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ciu8 qed_llh_get_num_ppfid(struct qed_dev *cdev) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci return cdev->p_llh_info->num_ppfid; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci#define NIG_REG_PPF_TO_ENGINE_SEL_ROCE_MASK 0x3 7348c2ecf20Sopenharmony_ci#define NIG_REG_PPF_TO_ENGINE_SEL_ROCE_SHIFT 0 7358c2ecf20Sopenharmony_ci#define NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE_MASK 0x3 7368c2ecf20Sopenharmony_ci#define NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE_SHIFT 2 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ciint qed_llh_set_ppfid_affinity(struct qed_dev *cdev, u8 ppfid, enum qed_eng eng) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 7418c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn); 7428c2ecf20Sopenharmony_ci u32 addr, val, eng_sel; 7438c2ecf20Sopenharmony_ci u8 abs_ppfid; 7448c2ecf20Sopenharmony_ci int rc = 0; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (!p_ptt) 7478c2ecf20Sopenharmony_ci return -EAGAIN; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (!QED_IS_CMT(cdev)) 7508c2ecf20Sopenharmony_ci goto out; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid); 7538c2ecf20Sopenharmony_ci if (rc) 7548c2ecf20Sopenharmony_ci goto out; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci switch (eng) { 7578c2ecf20Sopenharmony_ci case QED_ENG0: 7588c2ecf20Sopenharmony_ci eng_sel = 0; 7598c2ecf20Sopenharmony_ci break; 7608c2ecf20Sopenharmony_ci case QED_ENG1: 7618c2ecf20Sopenharmony_ci eng_sel = 1; 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci case QED_BOTH_ENG: 7648c2ecf20Sopenharmony_ci eng_sel = 2; 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci default: 7678c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Invalid affinity value for ppfid [%d]\n", eng); 7688c2ecf20Sopenharmony_ci rc = -EINVAL; 7698c2ecf20Sopenharmony_ci goto out; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4; 7738c2ecf20Sopenharmony_ci val = qed_rd(p_hwfn, p_ptt, addr); 7748c2ecf20Sopenharmony_ci SET_FIELD(val, NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE, eng_sel); 7758c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, addr, val); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* The iWARP affinity is set as the affinity of ppfid 0 */ 7788c2ecf20Sopenharmony_ci if (!ppfid && QED_IS_IWARP_PERSONALITY(p_hwfn)) 7798c2ecf20Sopenharmony_ci cdev->iwarp_affin = (eng == QED_ENG1) ? 1 : 0; 7808c2ecf20Sopenharmony_ciout: 7818c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci return rc; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ciint qed_llh_set_roce_affinity(struct qed_dev *cdev, enum qed_eng eng) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 7898c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn); 7908c2ecf20Sopenharmony_ci u32 addr, val, eng_sel; 7918c2ecf20Sopenharmony_ci u8 ppfid, abs_ppfid; 7928c2ecf20Sopenharmony_ci int rc = 0; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (!p_ptt) 7958c2ecf20Sopenharmony_ci return -EAGAIN; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (!QED_IS_CMT(cdev)) 7988c2ecf20Sopenharmony_ci goto out; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci switch (eng) { 8018c2ecf20Sopenharmony_ci case QED_ENG0: 8028c2ecf20Sopenharmony_ci eng_sel = 0; 8038c2ecf20Sopenharmony_ci break; 8048c2ecf20Sopenharmony_ci case QED_ENG1: 8058c2ecf20Sopenharmony_ci eng_sel = 1; 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci case QED_BOTH_ENG: 8088c2ecf20Sopenharmony_ci eng_sel = 2; 8098c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_ENG_CLS_ROCE_QP_SEL, 8108c2ecf20Sopenharmony_ci 0xf); /* QP bit 15 */ 8118c2ecf20Sopenharmony_ci break; 8128c2ecf20Sopenharmony_ci default: 8138c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "Invalid affinity value for RoCE [%d]\n", eng); 8148c2ecf20Sopenharmony_ci rc = -EINVAL; 8158c2ecf20Sopenharmony_ci goto out; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++) { 8198c2ecf20Sopenharmony_ci rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid); 8208c2ecf20Sopenharmony_ci if (rc) 8218c2ecf20Sopenharmony_ci goto out; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4; 8248c2ecf20Sopenharmony_ci val = qed_rd(p_hwfn, p_ptt, addr); 8258c2ecf20Sopenharmony_ci SET_FIELD(val, NIG_REG_PPF_TO_ENGINE_SEL_ROCE, eng_sel); 8268c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, addr, val); 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ciout: 8298c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci return rc; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistruct qed_llh_filter_details { 8358c2ecf20Sopenharmony_ci u64 value; 8368c2ecf20Sopenharmony_ci u32 mode; 8378c2ecf20Sopenharmony_ci u32 protocol_type; 8388c2ecf20Sopenharmony_ci u32 hdr_sel; 8398c2ecf20Sopenharmony_ci u32 enable; 8408c2ecf20Sopenharmony_ci}; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic int 8438c2ecf20Sopenharmony_ciqed_llh_access_filter(struct qed_hwfn *p_hwfn, 8448c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 8458c2ecf20Sopenharmony_ci u8 abs_ppfid, 8468c2ecf20Sopenharmony_ci u8 filter_idx, 8478c2ecf20Sopenharmony_ci struct qed_llh_filter_details *p_details) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct qed_dmae_params params = {0}; 8508c2ecf20Sopenharmony_ci u32 addr; 8518c2ecf20Sopenharmony_ci u8 pfid; 8528c2ecf20Sopenharmony_ci int rc; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* The NIG/LLH registers that are accessed in this function have only 16 8558c2ecf20Sopenharmony_ci * rows which are exposed to a PF. I.e. only the 16 filters of its 8568c2ecf20Sopenharmony_ci * default ppfid. Accessing filters of other ppfids requires pretending 8578c2ecf20Sopenharmony_ci * to another PFs. 8588c2ecf20Sopenharmony_ci * The calculation of PPFID->PFID in AH is based on the relative index 8598c2ecf20Sopenharmony_ci * of a PF on its port. 8608c2ecf20Sopenharmony_ci * For BB the pfid is actually the abs_ppfid. 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_ci if (QED_IS_BB(p_hwfn->cdev)) 8638c2ecf20Sopenharmony_ci pfid = abs_ppfid; 8648c2ecf20Sopenharmony_ci else 8658c2ecf20Sopenharmony_ci pfid = abs_ppfid * p_hwfn->cdev->num_ports_in_engine + 8668c2ecf20Sopenharmony_ci MFW_PORT(p_hwfn); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* Filter enable - should be done first when removing a filter */ 8698c2ecf20Sopenharmony_ci if (!p_details->enable) { 8708c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, 8718c2ecf20Sopenharmony_ci pfid << PXP_PRETEND_CONCRETE_FID_PFID_SHIFT); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci addr = NIG_REG_LLH_FUNC_FILTER_EN + filter_idx * 0x4; 8748c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, addr, p_details->enable); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, 8778c2ecf20Sopenharmony_ci p_hwfn->rel_pf_id << 8788c2ecf20Sopenharmony_ci PXP_PRETEND_CONCRETE_FID_PFID_SHIFT); 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* Filter value */ 8828c2ecf20Sopenharmony_ci addr = NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * filter_idx * 0x4; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci SET_FIELD(params.flags, QED_DMAE_PARAMS_DST_PF_VALID, 0x1); 8858c2ecf20Sopenharmony_ci params.dst_pfid = pfid; 8868c2ecf20Sopenharmony_ci rc = qed_dmae_host2grc(p_hwfn, 8878c2ecf20Sopenharmony_ci p_ptt, 8888c2ecf20Sopenharmony_ci (u64)(uintptr_t)&p_details->value, 8898c2ecf20Sopenharmony_ci addr, 2 /* size_in_dwords */, 8908c2ecf20Sopenharmony_ci ¶ms); 8918c2ecf20Sopenharmony_ci if (rc) 8928c2ecf20Sopenharmony_ci return rc; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, 8958c2ecf20Sopenharmony_ci pfid << PXP_PRETEND_CONCRETE_FID_PFID_SHIFT); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* Filter mode */ 8988c2ecf20Sopenharmony_ci addr = NIG_REG_LLH_FUNC_FILTER_MODE + filter_idx * 0x4; 8998c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, addr, p_details->mode); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* Filter protocol type */ 9028c2ecf20Sopenharmony_ci addr = NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE + filter_idx * 0x4; 9038c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, addr, p_details->protocol_type); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* Filter header select */ 9068c2ecf20Sopenharmony_ci addr = NIG_REG_LLH_FUNC_FILTER_HDR_SEL + filter_idx * 0x4; 9078c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, addr, p_details->hdr_sel); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* Filter enable - should be done last when adding a filter */ 9108c2ecf20Sopenharmony_ci if (p_details->enable) { 9118c2ecf20Sopenharmony_ci addr = NIG_REG_LLH_FUNC_FILTER_EN + filter_idx * 0x4; 9128c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, addr, p_details->enable); 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, 9168c2ecf20Sopenharmony_ci p_hwfn->rel_pf_id << 9178c2ecf20Sopenharmony_ci PXP_PRETEND_CONCRETE_FID_PFID_SHIFT); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci return 0; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic int 9238c2ecf20Sopenharmony_ciqed_llh_add_filter(struct qed_hwfn *p_hwfn, 9248c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 9258c2ecf20Sopenharmony_ci u8 abs_ppfid, 9268c2ecf20Sopenharmony_ci u8 filter_idx, u8 filter_prot_type, u32 high, u32 low) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci struct qed_llh_filter_details filter_details; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci filter_details.enable = 1; 9318c2ecf20Sopenharmony_ci filter_details.value = ((u64)high << 32) | low; 9328c2ecf20Sopenharmony_ci filter_details.hdr_sel = 0; 9338c2ecf20Sopenharmony_ci filter_details.protocol_type = filter_prot_type; 9348c2ecf20Sopenharmony_ci /* Mode: 0: MAC-address classification 1: protocol classification */ 9358c2ecf20Sopenharmony_ci filter_details.mode = filter_prot_type ? 1 : 0; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci return qed_llh_access_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx, 9388c2ecf20Sopenharmony_ci &filter_details); 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic int 9428c2ecf20Sopenharmony_ciqed_llh_remove_filter(struct qed_hwfn *p_hwfn, 9438c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u8 abs_ppfid, u8 filter_idx) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci struct qed_llh_filter_details filter_details = {0}; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return qed_llh_access_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx, 9488c2ecf20Sopenharmony_ci &filter_details); 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ciint qed_llh_add_mac_filter(struct qed_dev *cdev, 9528c2ecf20Sopenharmony_ci u8 ppfid, u8 mac_addr[ETH_ALEN]) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 9558c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn); 9568c2ecf20Sopenharmony_ci union qed_llh_filter filter = {}; 9578c2ecf20Sopenharmony_ci u8 filter_idx, abs_ppfid = 0; 9588c2ecf20Sopenharmony_ci u32 high, low, ref_cnt; 9598c2ecf20Sopenharmony_ci int rc = 0; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (!p_ptt) 9628c2ecf20Sopenharmony_ci return -EAGAIN; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (!test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits)) 9658c2ecf20Sopenharmony_ci goto out; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci memcpy(filter.mac.addr, mac_addr, ETH_ALEN); 9688c2ecf20Sopenharmony_ci rc = qed_llh_shadow_add_filter(cdev, ppfid, 9698c2ecf20Sopenharmony_ci QED_LLH_FILTER_TYPE_MAC, 9708c2ecf20Sopenharmony_ci &filter, &filter_idx, &ref_cnt); 9718c2ecf20Sopenharmony_ci if (rc) 9728c2ecf20Sopenharmony_ci goto err; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* Configure the LLH only in case of a new the filter */ 9758c2ecf20Sopenharmony_ci if (ref_cnt == 1) { 9768c2ecf20Sopenharmony_ci rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid); 9778c2ecf20Sopenharmony_ci if (rc) 9788c2ecf20Sopenharmony_ci goto err; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci high = mac_addr[1] | (mac_addr[0] << 8); 9818c2ecf20Sopenharmony_ci low = mac_addr[5] | (mac_addr[4] << 8) | (mac_addr[3] << 16) | 9828c2ecf20Sopenharmony_ci (mac_addr[2] << 24); 9838c2ecf20Sopenharmony_ci rc = qed_llh_add_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx, 9848c2ecf20Sopenharmony_ci 0, high, low); 9858c2ecf20Sopenharmony_ci if (rc) 9868c2ecf20Sopenharmony_ci goto err; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 9908c2ecf20Sopenharmony_ci QED_MSG_SP, 9918c2ecf20Sopenharmony_ci "LLH: Added MAC filter [%pM] to ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n", 9928c2ecf20Sopenharmony_ci mac_addr, ppfid, abs_ppfid, filter_idx, ref_cnt); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci goto out; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cierr: DP_NOTICE(cdev, 9978c2ecf20Sopenharmony_ci "LLH: Failed to add MAC filter [%pM] to ppfid %hhd\n", 9988c2ecf20Sopenharmony_ci mac_addr, ppfid); 9998c2ecf20Sopenharmony_ciout: 10008c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return rc; 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic int 10068c2ecf20Sopenharmony_ciqed_llh_protocol_filter_stringify(struct qed_dev *cdev, 10078c2ecf20Sopenharmony_ci enum qed_llh_prot_filter_type_t type, 10088c2ecf20Sopenharmony_ci u16 source_port_or_eth_type, 10098c2ecf20Sopenharmony_ci u16 dest_port, u8 *str, size_t str_len) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci switch (type) { 10128c2ecf20Sopenharmony_ci case QED_LLH_FILTER_ETHERTYPE: 10138c2ecf20Sopenharmony_ci snprintf(str, str_len, "Ethertype 0x%04x", 10148c2ecf20Sopenharmony_ci source_port_or_eth_type); 10158c2ecf20Sopenharmony_ci break; 10168c2ecf20Sopenharmony_ci case QED_LLH_FILTER_TCP_SRC_PORT: 10178c2ecf20Sopenharmony_ci snprintf(str, str_len, "TCP src port 0x%04x", 10188c2ecf20Sopenharmony_ci source_port_or_eth_type); 10198c2ecf20Sopenharmony_ci break; 10208c2ecf20Sopenharmony_ci case QED_LLH_FILTER_UDP_SRC_PORT: 10218c2ecf20Sopenharmony_ci snprintf(str, str_len, "UDP src port 0x%04x", 10228c2ecf20Sopenharmony_ci source_port_or_eth_type); 10238c2ecf20Sopenharmony_ci break; 10248c2ecf20Sopenharmony_ci case QED_LLH_FILTER_TCP_DEST_PORT: 10258c2ecf20Sopenharmony_ci snprintf(str, str_len, "TCP dst port 0x%04x", dest_port); 10268c2ecf20Sopenharmony_ci break; 10278c2ecf20Sopenharmony_ci case QED_LLH_FILTER_UDP_DEST_PORT: 10288c2ecf20Sopenharmony_ci snprintf(str, str_len, "UDP dst port 0x%04x", dest_port); 10298c2ecf20Sopenharmony_ci break; 10308c2ecf20Sopenharmony_ci case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT: 10318c2ecf20Sopenharmony_ci snprintf(str, str_len, "TCP src/dst ports 0x%04x/0x%04x", 10328c2ecf20Sopenharmony_ci source_port_or_eth_type, dest_port); 10338c2ecf20Sopenharmony_ci break; 10348c2ecf20Sopenharmony_ci case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT: 10358c2ecf20Sopenharmony_ci snprintf(str, str_len, "UDP src/dst ports 0x%04x/0x%04x", 10368c2ecf20Sopenharmony_ci source_port_or_eth_type, dest_port); 10378c2ecf20Sopenharmony_ci break; 10388c2ecf20Sopenharmony_ci default: 10398c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 10408c2ecf20Sopenharmony_ci "Non valid LLH protocol filter type %d\n", type); 10418c2ecf20Sopenharmony_ci return -EINVAL; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci return 0; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic int 10488c2ecf20Sopenharmony_ciqed_llh_protocol_filter_to_hilo(struct qed_dev *cdev, 10498c2ecf20Sopenharmony_ci enum qed_llh_prot_filter_type_t type, 10508c2ecf20Sopenharmony_ci u16 source_port_or_eth_type, 10518c2ecf20Sopenharmony_ci u16 dest_port, u32 *p_high, u32 *p_low) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci *p_high = 0; 10548c2ecf20Sopenharmony_ci *p_low = 0; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci switch (type) { 10578c2ecf20Sopenharmony_ci case QED_LLH_FILTER_ETHERTYPE: 10588c2ecf20Sopenharmony_ci *p_high = source_port_or_eth_type; 10598c2ecf20Sopenharmony_ci break; 10608c2ecf20Sopenharmony_ci case QED_LLH_FILTER_TCP_SRC_PORT: 10618c2ecf20Sopenharmony_ci case QED_LLH_FILTER_UDP_SRC_PORT: 10628c2ecf20Sopenharmony_ci *p_low = source_port_or_eth_type << 16; 10638c2ecf20Sopenharmony_ci break; 10648c2ecf20Sopenharmony_ci case QED_LLH_FILTER_TCP_DEST_PORT: 10658c2ecf20Sopenharmony_ci case QED_LLH_FILTER_UDP_DEST_PORT: 10668c2ecf20Sopenharmony_ci *p_low = dest_port; 10678c2ecf20Sopenharmony_ci break; 10688c2ecf20Sopenharmony_ci case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT: 10698c2ecf20Sopenharmony_ci case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT: 10708c2ecf20Sopenharmony_ci *p_low = (source_port_or_eth_type << 16) | dest_port; 10718c2ecf20Sopenharmony_ci break; 10728c2ecf20Sopenharmony_ci default: 10738c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 10748c2ecf20Sopenharmony_ci "Non valid LLH protocol filter type %d\n", type); 10758c2ecf20Sopenharmony_ci return -EINVAL; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci return 0; 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ciint 10828c2ecf20Sopenharmony_ciqed_llh_add_protocol_filter(struct qed_dev *cdev, 10838c2ecf20Sopenharmony_ci u8 ppfid, 10848c2ecf20Sopenharmony_ci enum qed_llh_prot_filter_type_t type, 10858c2ecf20Sopenharmony_ci u16 source_port_or_eth_type, u16 dest_port) 10868c2ecf20Sopenharmony_ci{ 10878c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 10888c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn); 10898c2ecf20Sopenharmony_ci u8 filter_idx, abs_ppfid, str[32], type_bitmap; 10908c2ecf20Sopenharmony_ci union qed_llh_filter filter = {}; 10918c2ecf20Sopenharmony_ci u32 high, low, ref_cnt; 10928c2ecf20Sopenharmony_ci int rc = 0; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (!p_ptt) 10958c2ecf20Sopenharmony_ci return -EAGAIN; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (!test_bit(QED_MF_LLH_PROTO_CLSS, &cdev->mf_bits)) 10988c2ecf20Sopenharmony_ci goto out; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci rc = qed_llh_protocol_filter_stringify(cdev, type, 11018c2ecf20Sopenharmony_ci source_port_or_eth_type, 11028c2ecf20Sopenharmony_ci dest_port, str, sizeof(str)); 11038c2ecf20Sopenharmony_ci if (rc) 11048c2ecf20Sopenharmony_ci goto err; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci filter.protocol.type = type; 11078c2ecf20Sopenharmony_ci filter.protocol.source_port_or_eth_type = source_port_or_eth_type; 11088c2ecf20Sopenharmony_ci filter.protocol.dest_port = dest_port; 11098c2ecf20Sopenharmony_ci rc = qed_llh_shadow_add_filter(cdev, 11108c2ecf20Sopenharmony_ci ppfid, 11118c2ecf20Sopenharmony_ci QED_LLH_FILTER_TYPE_PROTOCOL, 11128c2ecf20Sopenharmony_ci &filter, &filter_idx, &ref_cnt); 11138c2ecf20Sopenharmony_ci if (rc) 11148c2ecf20Sopenharmony_ci goto err; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid); 11178c2ecf20Sopenharmony_ci if (rc) 11188c2ecf20Sopenharmony_ci goto err; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci /* Configure the LLH only in case of a new the filter */ 11218c2ecf20Sopenharmony_ci if (ref_cnt == 1) { 11228c2ecf20Sopenharmony_ci rc = qed_llh_protocol_filter_to_hilo(cdev, type, 11238c2ecf20Sopenharmony_ci source_port_or_eth_type, 11248c2ecf20Sopenharmony_ci dest_port, &high, &low); 11258c2ecf20Sopenharmony_ci if (rc) 11268c2ecf20Sopenharmony_ci goto err; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci type_bitmap = 0x1 << type; 11298c2ecf20Sopenharmony_ci rc = qed_llh_add_filter(p_hwfn, p_ptt, abs_ppfid, 11308c2ecf20Sopenharmony_ci filter_idx, type_bitmap, high, low); 11318c2ecf20Sopenharmony_ci if (rc) 11328c2ecf20Sopenharmony_ci goto err; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 11368c2ecf20Sopenharmony_ci QED_MSG_SP, 11378c2ecf20Sopenharmony_ci "LLH: Added protocol filter [%s] to ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n", 11388c2ecf20Sopenharmony_ci str, ppfid, abs_ppfid, filter_idx, ref_cnt); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci goto out; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_cierr: DP_NOTICE(p_hwfn, 11438c2ecf20Sopenharmony_ci "LLH: Failed to add protocol filter [%s] to ppfid %hhd\n", 11448c2ecf20Sopenharmony_ci str, ppfid); 11458c2ecf20Sopenharmony_ciout: 11468c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci return rc; 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_civoid qed_llh_remove_mac_filter(struct qed_dev *cdev, 11528c2ecf20Sopenharmony_ci u8 ppfid, u8 mac_addr[ETH_ALEN]) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 11558c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn); 11568c2ecf20Sopenharmony_ci union qed_llh_filter filter = {}; 11578c2ecf20Sopenharmony_ci u8 filter_idx, abs_ppfid; 11588c2ecf20Sopenharmony_ci int rc = 0; 11598c2ecf20Sopenharmony_ci u32 ref_cnt; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (!p_ptt) 11628c2ecf20Sopenharmony_ci return; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (!test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits)) 11658c2ecf20Sopenharmony_ci goto out; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci ether_addr_copy(filter.mac.addr, mac_addr); 11688c2ecf20Sopenharmony_ci rc = qed_llh_shadow_remove_filter(cdev, ppfid, &filter, &filter_idx, 11698c2ecf20Sopenharmony_ci &ref_cnt); 11708c2ecf20Sopenharmony_ci if (rc) 11718c2ecf20Sopenharmony_ci goto err; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid); 11748c2ecf20Sopenharmony_ci if (rc) 11758c2ecf20Sopenharmony_ci goto err; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci /* Remove from the LLH in case the filter is not in use */ 11788c2ecf20Sopenharmony_ci if (!ref_cnt) { 11798c2ecf20Sopenharmony_ci rc = qed_llh_remove_filter(p_hwfn, p_ptt, abs_ppfid, 11808c2ecf20Sopenharmony_ci filter_idx); 11818c2ecf20Sopenharmony_ci if (rc) 11828c2ecf20Sopenharmony_ci goto err; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 11868c2ecf20Sopenharmony_ci QED_MSG_SP, 11878c2ecf20Sopenharmony_ci "LLH: Removed MAC filter [%pM] from ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n", 11888c2ecf20Sopenharmony_ci mac_addr, ppfid, abs_ppfid, filter_idx, ref_cnt); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci goto out; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cierr: DP_NOTICE(cdev, 11938c2ecf20Sopenharmony_ci "LLH: Failed to remove MAC filter [%pM] from ppfid %hhd\n", 11948c2ecf20Sopenharmony_ci mac_addr, ppfid); 11958c2ecf20Sopenharmony_ciout: 11968c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_civoid qed_llh_remove_protocol_filter(struct qed_dev *cdev, 12008c2ecf20Sopenharmony_ci u8 ppfid, 12018c2ecf20Sopenharmony_ci enum qed_llh_prot_filter_type_t type, 12028c2ecf20Sopenharmony_ci u16 source_port_or_eth_type, u16 dest_port) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 12058c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn); 12068c2ecf20Sopenharmony_ci u8 filter_idx, abs_ppfid, str[32]; 12078c2ecf20Sopenharmony_ci union qed_llh_filter filter = {}; 12088c2ecf20Sopenharmony_ci int rc = 0; 12098c2ecf20Sopenharmony_ci u32 ref_cnt; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci if (!p_ptt) 12128c2ecf20Sopenharmony_ci return; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (!test_bit(QED_MF_LLH_PROTO_CLSS, &cdev->mf_bits)) 12158c2ecf20Sopenharmony_ci goto out; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci rc = qed_llh_protocol_filter_stringify(cdev, type, 12188c2ecf20Sopenharmony_ci source_port_or_eth_type, 12198c2ecf20Sopenharmony_ci dest_port, str, sizeof(str)); 12208c2ecf20Sopenharmony_ci if (rc) 12218c2ecf20Sopenharmony_ci goto err; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci filter.protocol.type = type; 12248c2ecf20Sopenharmony_ci filter.protocol.source_port_or_eth_type = source_port_or_eth_type; 12258c2ecf20Sopenharmony_ci filter.protocol.dest_port = dest_port; 12268c2ecf20Sopenharmony_ci rc = qed_llh_shadow_remove_filter(cdev, ppfid, &filter, &filter_idx, 12278c2ecf20Sopenharmony_ci &ref_cnt); 12288c2ecf20Sopenharmony_ci if (rc) 12298c2ecf20Sopenharmony_ci goto err; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid); 12328c2ecf20Sopenharmony_ci if (rc) 12338c2ecf20Sopenharmony_ci goto err; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci /* Remove from the LLH in case the filter is not in use */ 12368c2ecf20Sopenharmony_ci if (!ref_cnt) { 12378c2ecf20Sopenharmony_ci rc = qed_llh_remove_filter(p_hwfn, p_ptt, abs_ppfid, 12388c2ecf20Sopenharmony_ci filter_idx); 12398c2ecf20Sopenharmony_ci if (rc) 12408c2ecf20Sopenharmony_ci goto err; 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 12448c2ecf20Sopenharmony_ci QED_MSG_SP, 12458c2ecf20Sopenharmony_ci "LLH: Removed protocol filter [%s] from ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n", 12468c2ecf20Sopenharmony_ci str, ppfid, abs_ppfid, filter_idx, ref_cnt); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci goto out; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cierr: DP_NOTICE(cdev, 12518c2ecf20Sopenharmony_ci "LLH: Failed to remove protocol filter [%s] from ppfid %hhd\n", 12528c2ecf20Sopenharmony_ci str, ppfid); 12538c2ecf20Sopenharmony_ciout: 12548c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci/******************************* NIG LLH - End ********************************/ 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci#define QED_MIN_DPIS (4) 12608c2ecf20Sopenharmony_ci#define QED_MIN_PWM_REGION (QED_WID_SIZE * QED_MIN_DPIS) 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_cistatic u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn, 12638c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, enum BAR_ID bar_id) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci u32 bar_reg = (bar_id == BAR_ID_0 ? 12668c2ecf20Sopenharmony_ci PGLUE_B_REG_PF_BAR0_SIZE : PGLUE_B_REG_PF_BAR1_SIZE); 12678c2ecf20Sopenharmony_ci u32 val; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 12708c2ecf20Sopenharmony_ci return qed_vf_hw_bar_size(p_hwfn, bar_id); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci val = qed_rd(p_hwfn, p_ptt, bar_reg); 12738c2ecf20Sopenharmony_ci if (val) 12748c2ecf20Sopenharmony_ci return 1 << (val + 15); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci /* Old MFW initialized above registered only conditionally */ 12778c2ecf20Sopenharmony_ci if (p_hwfn->cdev->num_hwfns > 1) { 12788c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 12798c2ecf20Sopenharmony_ci "BAR size not configured. Assuming BAR size of 256kB for GRC and 512kB for DB\n"); 12808c2ecf20Sopenharmony_ci return BAR_ID_0 ? 256 * 1024 : 512 * 1024; 12818c2ecf20Sopenharmony_ci } else { 12828c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 12838c2ecf20Sopenharmony_ci "BAR size not configured. Assuming BAR size of 512kB for GRC and 512kB for DB\n"); 12848c2ecf20Sopenharmony_ci return 512 * 1024; 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_civoid qed_init_dp(struct qed_dev *cdev, u32 dp_module, u8 dp_level) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci u32 i; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci cdev->dp_level = dp_level; 12938c2ecf20Sopenharmony_ci cdev->dp_module = dp_module; 12948c2ecf20Sopenharmony_ci for (i = 0; i < MAX_HWFNS_PER_DEVICE; i++) { 12958c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci p_hwfn->dp_level = dp_level; 12988c2ecf20Sopenharmony_ci p_hwfn->dp_module = dp_module; 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci} 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_civoid qed_init_struct(struct qed_dev *cdev) 13038c2ecf20Sopenharmony_ci{ 13048c2ecf20Sopenharmony_ci u8 i; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci for (i = 0; i < MAX_HWFNS_PER_DEVICE; i++) { 13078c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci p_hwfn->cdev = cdev; 13108c2ecf20Sopenharmony_ci p_hwfn->my_id = i; 13118c2ecf20Sopenharmony_ci p_hwfn->b_active = false; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci mutex_init(&p_hwfn->dmae_info.mutex); 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci /* hwfn 0 is always active */ 13178c2ecf20Sopenharmony_ci cdev->hwfns[0].b_active = true; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci /* set the default cache alignment to 128 */ 13208c2ecf20Sopenharmony_ci cdev->cache_shift = 7; 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cistatic void qed_qm_info_free(struct qed_hwfn *p_hwfn) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci kfree(qm_info->qm_pq_params); 13288c2ecf20Sopenharmony_ci qm_info->qm_pq_params = NULL; 13298c2ecf20Sopenharmony_ci kfree(qm_info->qm_vport_params); 13308c2ecf20Sopenharmony_ci qm_info->qm_vport_params = NULL; 13318c2ecf20Sopenharmony_ci kfree(qm_info->qm_port_params); 13328c2ecf20Sopenharmony_ci qm_info->qm_port_params = NULL; 13338c2ecf20Sopenharmony_ci kfree(qm_info->wfq_data); 13348c2ecf20Sopenharmony_ci qm_info->wfq_data = NULL; 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic void qed_dbg_user_data_free(struct qed_hwfn *p_hwfn) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci kfree(p_hwfn->dbg_user_info); 13408c2ecf20Sopenharmony_ci p_hwfn->dbg_user_info = NULL; 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_civoid qed_resc_free(struct qed_dev *cdev) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci struct qed_rdma_info *rdma_info; 13468c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn; 13478c2ecf20Sopenharmony_ci int i; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci if (IS_VF(cdev)) { 13508c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) 13518c2ecf20Sopenharmony_ci qed_l2_free(&cdev->hwfns[i]); 13528c2ecf20Sopenharmony_ci return; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci kfree(cdev->fw_data); 13568c2ecf20Sopenharmony_ci cdev->fw_data = NULL; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci kfree(cdev->reset_stats); 13598c2ecf20Sopenharmony_ci cdev->reset_stats = NULL; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci qed_llh_free(cdev); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 13648c2ecf20Sopenharmony_ci p_hwfn = cdev->hwfns + i; 13658c2ecf20Sopenharmony_ci rdma_info = p_hwfn->p_rdma_info; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci qed_cxt_mngr_free(p_hwfn); 13688c2ecf20Sopenharmony_ci qed_qm_info_free(p_hwfn); 13698c2ecf20Sopenharmony_ci qed_spq_free(p_hwfn); 13708c2ecf20Sopenharmony_ci qed_eq_free(p_hwfn); 13718c2ecf20Sopenharmony_ci qed_consq_free(p_hwfn); 13728c2ecf20Sopenharmony_ci qed_int_free(p_hwfn); 13738c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_LL2 13748c2ecf20Sopenharmony_ci qed_ll2_free(p_hwfn); 13758c2ecf20Sopenharmony_ci#endif 13768c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.personality == QED_PCI_FCOE) 13778c2ecf20Sopenharmony_ci qed_fcoe_free(p_hwfn); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { 13808c2ecf20Sopenharmony_ci qed_iscsi_free(p_hwfn); 13818c2ecf20Sopenharmony_ci qed_ooo_free(p_hwfn); 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci if (QED_IS_RDMA_PERSONALITY(p_hwfn) && rdma_info) { 13858c2ecf20Sopenharmony_ci qed_spq_unregister_async_cb(p_hwfn, rdma_info->proto); 13868c2ecf20Sopenharmony_ci qed_rdma_info_free(p_hwfn); 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci qed_iov_free(p_hwfn); 13908c2ecf20Sopenharmony_ci qed_l2_free(p_hwfn); 13918c2ecf20Sopenharmony_ci qed_dmae_info_free(p_hwfn); 13928c2ecf20Sopenharmony_ci qed_dcbx_info_free(p_hwfn); 13938c2ecf20Sopenharmony_ci qed_dbg_user_data_free(p_hwfn); 13948c2ecf20Sopenharmony_ci qed_fw_overlay_mem_free(p_hwfn, p_hwfn->fw_overlay_mem); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* Destroy doorbell recovery mechanism */ 13978c2ecf20Sopenharmony_ci qed_db_recovery_teardown(p_hwfn); 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci} 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci/******************** QM initialization *******************/ 14028c2ecf20Sopenharmony_ci#define ACTIVE_TCS_BMAP 0x9f 14038c2ecf20Sopenharmony_ci#define ACTIVE_TCS_BMAP_4PORT_K2 0xf 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci/* determines the physical queue flags for a given PF. */ 14068c2ecf20Sopenharmony_cistatic u32 qed_get_pq_flags(struct qed_hwfn *p_hwfn) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci u32 flags; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci /* common flags */ 14118c2ecf20Sopenharmony_ci flags = PQ_FLAGS_LB; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci /* feature flags */ 14148c2ecf20Sopenharmony_ci if (IS_QED_SRIOV(p_hwfn->cdev)) 14158c2ecf20Sopenharmony_ci flags |= PQ_FLAGS_VFS; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci /* protocol flags */ 14188c2ecf20Sopenharmony_ci switch (p_hwfn->hw_info.personality) { 14198c2ecf20Sopenharmony_ci case QED_PCI_ETH: 14208c2ecf20Sopenharmony_ci flags |= PQ_FLAGS_MCOS; 14218c2ecf20Sopenharmony_ci break; 14228c2ecf20Sopenharmony_ci case QED_PCI_FCOE: 14238c2ecf20Sopenharmony_ci flags |= PQ_FLAGS_OFLD; 14248c2ecf20Sopenharmony_ci break; 14258c2ecf20Sopenharmony_ci case QED_PCI_ISCSI: 14268c2ecf20Sopenharmony_ci flags |= PQ_FLAGS_ACK | PQ_FLAGS_OOO | PQ_FLAGS_OFLD; 14278c2ecf20Sopenharmony_ci break; 14288c2ecf20Sopenharmony_ci case QED_PCI_ETH_ROCE: 14298c2ecf20Sopenharmony_ci flags |= PQ_FLAGS_MCOS | PQ_FLAGS_OFLD | PQ_FLAGS_LLT; 14308c2ecf20Sopenharmony_ci if (IS_QED_MULTI_TC_ROCE(p_hwfn)) 14318c2ecf20Sopenharmony_ci flags |= PQ_FLAGS_MTC; 14328c2ecf20Sopenharmony_ci break; 14338c2ecf20Sopenharmony_ci case QED_PCI_ETH_IWARP: 14348c2ecf20Sopenharmony_ci flags |= PQ_FLAGS_MCOS | PQ_FLAGS_ACK | PQ_FLAGS_OOO | 14358c2ecf20Sopenharmony_ci PQ_FLAGS_OFLD; 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci default: 14388c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 14398c2ecf20Sopenharmony_ci "unknown personality %d\n", p_hwfn->hw_info.personality); 14408c2ecf20Sopenharmony_ci return 0; 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci return flags; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci/* Getters for resource amounts necessary for qm initialization */ 14478c2ecf20Sopenharmony_cistatic u8 qed_init_qm_get_num_tcs(struct qed_hwfn *p_hwfn) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci return p_hwfn->hw_info.num_hw_tc; 14508c2ecf20Sopenharmony_ci} 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_cistatic u16 qed_init_qm_get_num_vfs(struct qed_hwfn *p_hwfn) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci return IS_QED_SRIOV(p_hwfn->cdev) ? 14558c2ecf20Sopenharmony_ci p_hwfn->cdev->p_iov_info->total_vfs : 0; 14568c2ecf20Sopenharmony_ci} 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cistatic u8 qed_init_qm_get_num_mtc_tcs(struct qed_hwfn *p_hwfn) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci u32 pq_flags = qed_get_pq_flags(p_hwfn); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci if (!(PQ_FLAGS_MTC & pq_flags)) 14638c2ecf20Sopenharmony_ci return 1; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci return qed_init_qm_get_num_tcs(p_hwfn); 14668c2ecf20Sopenharmony_ci} 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci#define NUM_DEFAULT_RLS 1 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_cistatic u16 qed_init_qm_get_num_pf_rls(struct qed_hwfn *p_hwfn) 14718c2ecf20Sopenharmony_ci{ 14728c2ecf20Sopenharmony_ci u16 num_pf_rls, num_vfs = qed_init_qm_get_num_vfs(p_hwfn); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci /* num RLs can't exceed resource amount of rls or vports */ 14758c2ecf20Sopenharmony_ci num_pf_rls = (u16) min_t(u32, RESC_NUM(p_hwfn, QED_RL), 14768c2ecf20Sopenharmony_ci RESC_NUM(p_hwfn, QED_VPORT)); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* Make sure after we reserve there's something left */ 14798c2ecf20Sopenharmony_ci if (num_pf_rls < num_vfs + NUM_DEFAULT_RLS) 14808c2ecf20Sopenharmony_ci return 0; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci /* subtract rls necessary for VFs and one default one for the PF */ 14838c2ecf20Sopenharmony_ci num_pf_rls -= num_vfs + NUM_DEFAULT_RLS; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci return num_pf_rls; 14868c2ecf20Sopenharmony_ci} 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_cistatic u16 qed_init_qm_get_num_vports(struct qed_hwfn *p_hwfn) 14898c2ecf20Sopenharmony_ci{ 14908c2ecf20Sopenharmony_ci u32 pq_flags = qed_get_pq_flags(p_hwfn); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci /* all pqs share the same vport, except for vfs and pf_rl pqs */ 14938c2ecf20Sopenharmony_ci return (!!(PQ_FLAGS_RLS & pq_flags)) * 14948c2ecf20Sopenharmony_ci qed_init_qm_get_num_pf_rls(p_hwfn) + 14958c2ecf20Sopenharmony_ci (!!(PQ_FLAGS_VFS & pq_flags)) * 14968c2ecf20Sopenharmony_ci qed_init_qm_get_num_vfs(p_hwfn) + 1; 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci/* calc amount of PQs according to the requested flags */ 15008c2ecf20Sopenharmony_cistatic u16 qed_init_qm_get_num_pqs(struct qed_hwfn *p_hwfn) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci u32 pq_flags = qed_get_pq_flags(p_hwfn); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return (!!(PQ_FLAGS_RLS & pq_flags)) * 15058c2ecf20Sopenharmony_ci qed_init_qm_get_num_pf_rls(p_hwfn) + 15068c2ecf20Sopenharmony_ci (!!(PQ_FLAGS_MCOS & pq_flags)) * 15078c2ecf20Sopenharmony_ci qed_init_qm_get_num_tcs(p_hwfn) + 15088c2ecf20Sopenharmony_ci (!!(PQ_FLAGS_LB & pq_flags)) + (!!(PQ_FLAGS_OOO & pq_flags)) + 15098c2ecf20Sopenharmony_ci (!!(PQ_FLAGS_ACK & pq_flags)) + 15108c2ecf20Sopenharmony_ci (!!(PQ_FLAGS_OFLD & pq_flags)) * 15118c2ecf20Sopenharmony_ci qed_init_qm_get_num_mtc_tcs(p_hwfn) + 15128c2ecf20Sopenharmony_ci (!!(PQ_FLAGS_LLT & pq_flags)) * 15138c2ecf20Sopenharmony_ci qed_init_qm_get_num_mtc_tcs(p_hwfn) + 15148c2ecf20Sopenharmony_ci (!!(PQ_FLAGS_VFS & pq_flags)) * qed_init_qm_get_num_vfs(p_hwfn); 15158c2ecf20Sopenharmony_ci} 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci/* initialize the top level QM params */ 15188c2ecf20Sopenharmony_cistatic void qed_init_qm_params(struct qed_hwfn *p_hwfn) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 15218c2ecf20Sopenharmony_ci bool four_port; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci /* pq and vport bases for this PF */ 15248c2ecf20Sopenharmony_ci qm_info->start_pq = (u16) RESC_START(p_hwfn, QED_PQ); 15258c2ecf20Sopenharmony_ci qm_info->start_vport = (u8) RESC_START(p_hwfn, QED_VPORT); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci /* rate limiting and weighted fair queueing are always enabled */ 15288c2ecf20Sopenharmony_ci qm_info->vport_rl_en = true; 15298c2ecf20Sopenharmony_ci qm_info->vport_wfq_en = true; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* TC config is different for AH 4 port */ 15328c2ecf20Sopenharmony_ci four_port = p_hwfn->cdev->num_ports_in_engine == MAX_NUM_PORTS_K2; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci /* in AH 4 port we have fewer TCs per port */ 15358c2ecf20Sopenharmony_ci qm_info->max_phys_tcs_per_port = four_port ? NUM_PHYS_TCS_4PORT_K2 : 15368c2ecf20Sopenharmony_ci NUM_OF_PHYS_TCS; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci /* unless MFW indicated otherwise, ooo_tc == 3 for 15398c2ecf20Sopenharmony_ci * AH 4-port and 4 otherwise. 15408c2ecf20Sopenharmony_ci */ 15418c2ecf20Sopenharmony_ci if (!qm_info->ooo_tc) 15428c2ecf20Sopenharmony_ci qm_info->ooo_tc = four_port ? DCBX_TCP_OOO_K2_4PORT_TC : 15438c2ecf20Sopenharmony_ci DCBX_TCP_OOO_TC; 15448c2ecf20Sopenharmony_ci} 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci/* initialize qm vport params */ 15478c2ecf20Sopenharmony_cistatic void qed_init_qm_vport_params(struct qed_hwfn *p_hwfn) 15488c2ecf20Sopenharmony_ci{ 15498c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 15508c2ecf20Sopenharmony_ci u8 i; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci /* all vports participate in weighted fair queueing */ 15538c2ecf20Sopenharmony_ci for (i = 0; i < qed_init_qm_get_num_vports(p_hwfn); i++) 15548c2ecf20Sopenharmony_ci qm_info->qm_vport_params[i].wfq = 1; 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci/* initialize qm port params */ 15588c2ecf20Sopenharmony_cistatic void qed_init_qm_port_params(struct qed_hwfn *p_hwfn) 15598c2ecf20Sopenharmony_ci{ 15608c2ecf20Sopenharmony_ci /* Initialize qm port parameters */ 15618c2ecf20Sopenharmony_ci u8 i, active_phys_tcs, num_ports = p_hwfn->cdev->num_ports_in_engine; 15628c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci /* indicate how ooo and high pri traffic is dealt with */ 15658c2ecf20Sopenharmony_ci active_phys_tcs = num_ports == MAX_NUM_PORTS_K2 ? 15668c2ecf20Sopenharmony_ci ACTIVE_TCS_BMAP_4PORT_K2 : 15678c2ecf20Sopenharmony_ci ACTIVE_TCS_BMAP; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci for (i = 0; i < num_ports; i++) { 15708c2ecf20Sopenharmony_ci struct init_qm_port_params *p_qm_port = 15718c2ecf20Sopenharmony_ci &p_hwfn->qm_info.qm_port_params[i]; 15728c2ecf20Sopenharmony_ci u16 pbf_max_cmd_lines; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci p_qm_port->active = 1; 15758c2ecf20Sopenharmony_ci p_qm_port->active_phys_tcs = active_phys_tcs; 15768c2ecf20Sopenharmony_ci pbf_max_cmd_lines = (u16)NUM_OF_PBF_CMD_LINES(cdev); 15778c2ecf20Sopenharmony_ci p_qm_port->num_pbf_cmd_lines = pbf_max_cmd_lines / num_ports; 15788c2ecf20Sopenharmony_ci p_qm_port->num_btb_blocks = NUM_OF_BTB_BLOCKS(cdev) / num_ports; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci} 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci/* Reset the params which must be reset for qm init. QM init may be called as 15838c2ecf20Sopenharmony_ci * a result of flows other than driver load (e.g. dcbx renegotiation). Other 15848c2ecf20Sopenharmony_ci * params may be affected by the init but would simply recalculate to the same 15858c2ecf20Sopenharmony_ci * values. The allocations made for QM init, ports, vports, pqs and vfqs are not 15868c2ecf20Sopenharmony_ci * affected as these amounts stay the same. 15878c2ecf20Sopenharmony_ci */ 15888c2ecf20Sopenharmony_cistatic void qed_init_qm_reset_params(struct qed_hwfn *p_hwfn) 15898c2ecf20Sopenharmony_ci{ 15908c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci qm_info->num_pqs = 0; 15938c2ecf20Sopenharmony_ci qm_info->num_vports = 0; 15948c2ecf20Sopenharmony_ci qm_info->num_pf_rls = 0; 15958c2ecf20Sopenharmony_ci qm_info->num_vf_pqs = 0; 15968c2ecf20Sopenharmony_ci qm_info->first_vf_pq = 0; 15978c2ecf20Sopenharmony_ci qm_info->first_mcos_pq = 0; 15988c2ecf20Sopenharmony_ci qm_info->first_rl_pq = 0; 15998c2ecf20Sopenharmony_ci} 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_cistatic void qed_init_qm_advance_vport(struct qed_hwfn *p_hwfn) 16028c2ecf20Sopenharmony_ci{ 16038c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci qm_info->num_vports++; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (qm_info->num_vports > qed_init_qm_get_num_vports(p_hwfn)) 16088c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 16098c2ecf20Sopenharmony_ci "vport overflow! qm_info->num_vports %d, qm_init_get_num_vports() %d\n", 16108c2ecf20Sopenharmony_ci qm_info->num_vports, qed_init_qm_get_num_vports(p_hwfn)); 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci/* initialize a single pq and manage qm_info resources accounting. 16148c2ecf20Sopenharmony_ci * The pq_init_flags param determines whether the PQ is rate limited 16158c2ecf20Sopenharmony_ci * (for VF or PF) and whether a new vport is allocated to the pq or not 16168c2ecf20Sopenharmony_ci * (i.e. vport will be shared). 16178c2ecf20Sopenharmony_ci */ 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci/* flags for pq init */ 16208c2ecf20Sopenharmony_ci#define PQ_INIT_SHARE_VPORT (1 << 0) 16218c2ecf20Sopenharmony_ci#define PQ_INIT_PF_RL (1 << 1) 16228c2ecf20Sopenharmony_ci#define PQ_INIT_VF_RL (1 << 2) 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci/* defines for pq init */ 16258c2ecf20Sopenharmony_ci#define PQ_INIT_DEFAULT_WRR_GROUP 1 16268c2ecf20Sopenharmony_ci#define PQ_INIT_DEFAULT_TC 0 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_civoid qed_hw_info_set_offload_tc(struct qed_hw_info *p_info, u8 tc) 16298c2ecf20Sopenharmony_ci{ 16308c2ecf20Sopenharmony_ci p_info->offload_tc = tc; 16318c2ecf20Sopenharmony_ci p_info->offload_tc_set = true; 16328c2ecf20Sopenharmony_ci} 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_cistatic bool qed_is_offload_tc_set(struct qed_hwfn *p_hwfn) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci return p_hwfn->hw_info.offload_tc_set; 16378c2ecf20Sopenharmony_ci} 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cistatic u32 qed_get_offload_tc(struct qed_hwfn *p_hwfn) 16408c2ecf20Sopenharmony_ci{ 16418c2ecf20Sopenharmony_ci if (qed_is_offload_tc_set(p_hwfn)) 16428c2ecf20Sopenharmony_ci return p_hwfn->hw_info.offload_tc; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci return PQ_INIT_DEFAULT_TC; 16458c2ecf20Sopenharmony_ci} 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_cistatic void qed_init_qm_pq(struct qed_hwfn *p_hwfn, 16488c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info, 16498c2ecf20Sopenharmony_ci u8 tc, u32 pq_init_flags) 16508c2ecf20Sopenharmony_ci{ 16518c2ecf20Sopenharmony_ci u16 pq_idx = qm_info->num_pqs, max_pq = qed_init_qm_get_num_pqs(p_hwfn); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci if (pq_idx > max_pq) 16548c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 16558c2ecf20Sopenharmony_ci "pq overflow! pq %d, max pq %d\n", pq_idx, max_pq); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci /* init pq params */ 16588c2ecf20Sopenharmony_ci qm_info->qm_pq_params[pq_idx].port_id = p_hwfn->port_id; 16598c2ecf20Sopenharmony_ci qm_info->qm_pq_params[pq_idx].vport_id = qm_info->start_vport + 16608c2ecf20Sopenharmony_ci qm_info->num_vports; 16618c2ecf20Sopenharmony_ci qm_info->qm_pq_params[pq_idx].tc_id = tc; 16628c2ecf20Sopenharmony_ci qm_info->qm_pq_params[pq_idx].wrr_group = PQ_INIT_DEFAULT_WRR_GROUP; 16638c2ecf20Sopenharmony_ci qm_info->qm_pq_params[pq_idx].rl_valid = 16648c2ecf20Sopenharmony_ci (pq_init_flags & PQ_INIT_PF_RL || pq_init_flags & PQ_INIT_VF_RL); 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci /* qm params accounting */ 16678c2ecf20Sopenharmony_ci qm_info->num_pqs++; 16688c2ecf20Sopenharmony_ci if (!(pq_init_flags & PQ_INIT_SHARE_VPORT)) 16698c2ecf20Sopenharmony_ci qm_info->num_vports++; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (pq_init_flags & PQ_INIT_PF_RL) 16728c2ecf20Sopenharmony_ci qm_info->num_pf_rls++; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci if (qm_info->num_vports > qed_init_qm_get_num_vports(p_hwfn)) 16758c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 16768c2ecf20Sopenharmony_ci "vport overflow! qm_info->num_vports %d, qm_init_get_num_vports() %d\n", 16778c2ecf20Sopenharmony_ci qm_info->num_vports, qed_init_qm_get_num_vports(p_hwfn)); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci if (qm_info->num_pf_rls > qed_init_qm_get_num_pf_rls(p_hwfn)) 16808c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 16818c2ecf20Sopenharmony_ci "rl overflow! qm_info->num_pf_rls %d, qm_init_get_num_pf_rls() %d\n", 16828c2ecf20Sopenharmony_ci qm_info->num_pf_rls, qed_init_qm_get_num_pf_rls(p_hwfn)); 16838c2ecf20Sopenharmony_ci} 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci/* get pq index according to PQ_FLAGS */ 16868c2ecf20Sopenharmony_cistatic u16 *qed_init_qm_get_idx_from_flags(struct qed_hwfn *p_hwfn, 16878c2ecf20Sopenharmony_ci unsigned long pq_flags) 16888c2ecf20Sopenharmony_ci{ 16898c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci /* Can't have multiple flags set here */ 16928c2ecf20Sopenharmony_ci if (bitmap_weight(&pq_flags, 16938c2ecf20Sopenharmony_ci sizeof(pq_flags) * BITS_PER_BYTE) > 1) { 16948c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "requested multiple pq flags 0x%lx\n", pq_flags); 16958c2ecf20Sopenharmony_ci goto err; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci if (!(qed_get_pq_flags(p_hwfn) & pq_flags)) { 16998c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "pq flag 0x%lx is not set\n", pq_flags); 17008c2ecf20Sopenharmony_ci goto err; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci switch (pq_flags) { 17048c2ecf20Sopenharmony_ci case PQ_FLAGS_RLS: 17058c2ecf20Sopenharmony_ci return &qm_info->first_rl_pq; 17068c2ecf20Sopenharmony_ci case PQ_FLAGS_MCOS: 17078c2ecf20Sopenharmony_ci return &qm_info->first_mcos_pq; 17088c2ecf20Sopenharmony_ci case PQ_FLAGS_LB: 17098c2ecf20Sopenharmony_ci return &qm_info->pure_lb_pq; 17108c2ecf20Sopenharmony_ci case PQ_FLAGS_OOO: 17118c2ecf20Sopenharmony_ci return &qm_info->ooo_pq; 17128c2ecf20Sopenharmony_ci case PQ_FLAGS_ACK: 17138c2ecf20Sopenharmony_ci return &qm_info->pure_ack_pq; 17148c2ecf20Sopenharmony_ci case PQ_FLAGS_OFLD: 17158c2ecf20Sopenharmony_ci return &qm_info->first_ofld_pq; 17168c2ecf20Sopenharmony_ci case PQ_FLAGS_LLT: 17178c2ecf20Sopenharmony_ci return &qm_info->first_llt_pq; 17188c2ecf20Sopenharmony_ci case PQ_FLAGS_VFS: 17198c2ecf20Sopenharmony_ci return &qm_info->first_vf_pq; 17208c2ecf20Sopenharmony_ci default: 17218c2ecf20Sopenharmony_ci goto err; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_cierr: 17258c2ecf20Sopenharmony_ci return &qm_info->start_pq; 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci/* save pq index in qm info */ 17298c2ecf20Sopenharmony_cistatic void qed_init_qm_set_idx(struct qed_hwfn *p_hwfn, 17308c2ecf20Sopenharmony_ci u32 pq_flags, u16 pq_val) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci u16 *base_pq_idx = qed_init_qm_get_idx_from_flags(p_hwfn, pq_flags); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci *base_pq_idx = p_hwfn->qm_info.start_pq + pq_val; 17358c2ecf20Sopenharmony_ci} 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci/* get tx pq index, with the PQ TX base already set (ready for context init) */ 17388c2ecf20Sopenharmony_ciu16 qed_get_cm_pq_idx(struct qed_hwfn *p_hwfn, u32 pq_flags) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci u16 *base_pq_idx = qed_init_qm_get_idx_from_flags(p_hwfn, pq_flags); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci return *base_pq_idx + CM_TX_PQ_BASE; 17438c2ecf20Sopenharmony_ci} 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ciu16 qed_get_cm_pq_idx_mcos(struct qed_hwfn *p_hwfn, u8 tc) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci u8 max_tc = qed_init_qm_get_num_tcs(p_hwfn); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (max_tc == 0) { 17508c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "pq with flag 0x%lx do not exist\n", 17518c2ecf20Sopenharmony_ci PQ_FLAGS_MCOS); 17528c2ecf20Sopenharmony_ci return p_hwfn->qm_info.start_pq; 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci if (tc > max_tc) 17568c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "tc %d must be smaller than %d\n", tc, max_tc); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci return qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_MCOS) + (tc % max_tc); 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ciu16 qed_get_cm_pq_idx_vf(struct qed_hwfn *p_hwfn, u16 vf) 17628c2ecf20Sopenharmony_ci{ 17638c2ecf20Sopenharmony_ci u16 max_vf = qed_init_qm_get_num_vfs(p_hwfn); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if (max_vf == 0) { 17668c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "pq with flag 0x%lx do not exist\n", 17678c2ecf20Sopenharmony_ci PQ_FLAGS_VFS); 17688c2ecf20Sopenharmony_ci return p_hwfn->qm_info.start_pq; 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci if (vf > max_vf) 17728c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "vf %d must be smaller than %d\n", vf, max_vf); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci return qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_VFS) + (vf % max_vf); 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ciu16 qed_get_cm_pq_idx_ofld_mtc(struct qed_hwfn *p_hwfn, u8 tc) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci u16 first_ofld_pq, pq_offset; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci first_ofld_pq = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD); 17828c2ecf20Sopenharmony_ci pq_offset = (tc < qed_init_qm_get_num_mtc_tcs(p_hwfn)) ? 17838c2ecf20Sopenharmony_ci tc : PQ_INIT_DEFAULT_TC; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci return first_ofld_pq + pq_offset; 17868c2ecf20Sopenharmony_ci} 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ciu16 qed_get_cm_pq_idx_llt_mtc(struct qed_hwfn *p_hwfn, u8 tc) 17898c2ecf20Sopenharmony_ci{ 17908c2ecf20Sopenharmony_ci u16 first_llt_pq, pq_offset; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci first_llt_pq = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_LLT); 17938c2ecf20Sopenharmony_ci pq_offset = (tc < qed_init_qm_get_num_mtc_tcs(p_hwfn)) ? 17948c2ecf20Sopenharmony_ci tc : PQ_INIT_DEFAULT_TC; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci return first_llt_pq + pq_offset; 17978c2ecf20Sopenharmony_ci} 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci/* Functions for creating specific types of pqs */ 18008c2ecf20Sopenharmony_cistatic void qed_init_qm_lb_pq(struct qed_hwfn *p_hwfn) 18018c2ecf20Sopenharmony_ci{ 18028c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_LB)) 18058c2ecf20Sopenharmony_ci return; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_LB, qm_info->num_pqs); 18088c2ecf20Sopenharmony_ci qed_init_qm_pq(p_hwfn, qm_info, PURE_LB_TC, PQ_INIT_SHARE_VPORT); 18098c2ecf20Sopenharmony_ci} 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_cistatic void qed_init_qm_ooo_pq(struct qed_hwfn *p_hwfn) 18128c2ecf20Sopenharmony_ci{ 18138c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_OOO)) 18168c2ecf20Sopenharmony_ci return; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_OOO, qm_info->num_pqs); 18198c2ecf20Sopenharmony_ci qed_init_qm_pq(p_hwfn, qm_info, qm_info->ooo_tc, PQ_INIT_SHARE_VPORT); 18208c2ecf20Sopenharmony_ci} 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_cistatic void qed_init_qm_pure_ack_pq(struct qed_hwfn *p_hwfn) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_ACK)) 18278c2ecf20Sopenharmony_ci return; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_ACK, qm_info->num_pqs); 18308c2ecf20Sopenharmony_ci qed_init_qm_pq(p_hwfn, qm_info, qed_get_offload_tc(p_hwfn), 18318c2ecf20Sopenharmony_ci PQ_INIT_SHARE_VPORT); 18328c2ecf20Sopenharmony_ci} 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_cistatic void qed_init_qm_mtc_pqs(struct qed_hwfn *p_hwfn) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci u8 num_tcs = qed_init_qm_get_num_mtc_tcs(p_hwfn); 18378c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 18388c2ecf20Sopenharmony_ci u8 tc; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci /* override pq's TC if offload TC is set */ 18418c2ecf20Sopenharmony_ci for (tc = 0; tc < num_tcs; tc++) 18428c2ecf20Sopenharmony_ci qed_init_qm_pq(p_hwfn, qm_info, 18438c2ecf20Sopenharmony_ci qed_is_offload_tc_set(p_hwfn) ? 18448c2ecf20Sopenharmony_ci p_hwfn->hw_info.offload_tc : tc, 18458c2ecf20Sopenharmony_ci PQ_INIT_SHARE_VPORT); 18468c2ecf20Sopenharmony_ci} 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_cistatic void qed_init_qm_offload_pq(struct qed_hwfn *p_hwfn) 18498c2ecf20Sopenharmony_ci{ 18508c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_OFLD)) 18538c2ecf20Sopenharmony_ci return; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_OFLD, qm_info->num_pqs); 18568c2ecf20Sopenharmony_ci qed_init_qm_mtc_pqs(p_hwfn); 18578c2ecf20Sopenharmony_ci} 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_cistatic void qed_init_qm_low_latency_pq(struct qed_hwfn *p_hwfn) 18608c2ecf20Sopenharmony_ci{ 18618c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_LLT)) 18648c2ecf20Sopenharmony_ci return; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_LLT, qm_info->num_pqs); 18678c2ecf20Sopenharmony_ci qed_init_qm_mtc_pqs(p_hwfn); 18688c2ecf20Sopenharmony_ci} 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cistatic void qed_init_qm_mcos_pqs(struct qed_hwfn *p_hwfn) 18718c2ecf20Sopenharmony_ci{ 18728c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 18738c2ecf20Sopenharmony_ci u8 tc_idx; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_MCOS)) 18768c2ecf20Sopenharmony_ci return; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_MCOS, qm_info->num_pqs); 18798c2ecf20Sopenharmony_ci for (tc_idx = 0; tc_idx < qed_init_qm_get_num_tcs(p_hwfn); tc_idx++) 18808c2ecf20Sopenharmony_ci qed_init_qm_pq(p_hwfn, qm_info, tc_idx, PQ_INIT_SHARE_VPORT); 18818c2ecf20Sopenharmony_ci} 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_cistatic void qed_init_qm_vf_pqs(struct qed_hwfn *p_hwfn) 18848c2ecf20Sopenharmony_ci{ 18858c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 18868c2ecf20Sopenharmony_ci u16 vf_idx, num_vfs = qed_init_qm_get_num_vfs(p_hwfn); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_VFS)) 18898c2ecf20Sopenharmony_ci return; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_VFS, qm_info->num_pqs); 18928c2ecf20Sopenharmony_ci qm_info->num_vf_pqs = num_vfs; 18938c2ecf20Sopenharmony_ci for (vf_idx = 0; vf_idx < num_vfs; vf_idx++) 18948c2ecf20Sopenharmony_ci qed_init_qm_pq(p_hwfn, 18958c2ecf20Sopenharmony_ci qm_info, PQ_INIT_DEFAULT_TC, PQ_INIT_VF_RL); 18968c2ecf20Sopenharmony_ci} 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_cistatic void qed_init_qm_rl_pqs(struct qed_hwfn *p_hwfn) 18998c2ecf20Sopenharmony_ci{ 19008c2ecf20Sopenharmony_ci u16 pf_rls_idx, num_pf_rls = qed_init_qm_get_num_pf_rls(p_hwfn); 19018c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci if (!(qed_get_pq_flags(p_hwfn) & PQ_FLAGS_RLS)) 19048c2ecf20Sopenharmony_ci return; 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci qed_init_qm_set_idx(p_hwfn, PQ_FLAGS_RLS, qm_info->num_pqs); 19078c2ecf20Sopenharmony_ci for (pf_rls_idx = 0; pf_rls_idx < num_pf_rls; pf_rls_idx++) 19088c2ecf20Sopenharmony_ci qed_init_qm_pq(p_hwfn, qm_info, qed_get_offload_tc(p_hwfn), 19098c2ecf20Sopenharmony_ci PQ_INIT_PF_RL); 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_cistatic void qed_init_qm_pq_params(struct qed_hwfn *p_hwfn) 19138c2ecf20Sopenharmony_ci{ 19148c2ecf20Sopenharmony_ci /* rate limited pqs, must come first (FW assumption) */ 19158c2ecf20Sopenharmony_ci qed_init_qm_rl_pqs(p_hwfn); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci /* pqs for multi cos */ 19188c2ecf20Sopenharmony_ci qed_init_qm_mcos_pqs(p_hwfn); 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci /* pure loopback pq */ 19218c2ecf20Sopenharmony_ci qed_init_qm_lb_pq(p_hwfn); 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci /* out of order pq */ 19248c2ecf20Sopenharmony_ci qed_init_qm_ooo_pq(p_hwfn); 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci /* pure ack pq */ 19278c2ecf20Sopenharmony_ci qed_init_qm_pure_ack_pq(p_hwfn); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci /* pq for offloaded protocol */ 19308c2ecf20Sopenharmony_ci qed_init_qm_offload_pq(p_hwfn); 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci /* low latency pq */ 19338c2ecf20Sopenharmony_ci qed_init_qm_low_latency_pq(p_hwfn); 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci /* done sharing vports */ 19368c2ecf20Sopenharmony_ci qed_init_qm_advance_vport(p_hwfn); 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci /* pqs for vfs */ 19398c2ecf20Sopenharmony_ci qed_init_qm_vf_pqs(p_hwfn); 19408c2ecf20Sopenharmony_ci} 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci/* compare values of getters against resources amounts */ 19438c2ecf20Sopenharmony_cistatic int qed_init_qm_sanity(struct qed_hwfn *p_hwfn) 19448c2ecf20Sopenharmony_ci{ 19458c2ecf20Sopenharmony_ci if (qed_init_qm_get_num_vports(p_hwfn) > RESC_NUM(p_hwfn, QED_VPORT)) { 19468c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "requested amount of vports exceeds resource\n"); 19478c2ecf20Sopenharmony_ci return -EINVAL; 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci if (qed_init_qm_get_num_pqs(p_hwfn) <= RESC_NUM(p_hwfn, QED_PQ)) 19518c2ecf20Sopenharmony_ci return 0; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci if (QED_IS_ROCE_PERSONALITY(p_hwfn)) { 19548c2ecf20Sopenharmony_ci p_hwfn->hw_info.multi_tc_roce_en = false; 19558c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 19568c2ecf20Sopenharmony_ci "multi-tc roce was disabled to reduce requested amount of pqs\n"); 19578c2ecf20Sopenharmony_ci if (qed_init_qm_get_num_pqs(p_hwfn) <= RESC_NUM(p_hwfn, QED_PQ)) 19588c2ecf20Sopenharmony_ci return 0; 19598c2ecf20Sopenharmony_ci } 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "requested amount of pqs exceeds resource\n"); 19628c2ecf20Sopenharmony_ci return -EINVAL; 19638c2ecf20Sopenharmony_ci} 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_cistatic void qed_dp_init_qm_params(struct qed_hwfn *p_hwfn) 19668c2ecf20Sopenharmony_ci{ 19678c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 19688c2ecf20Sopenharmony_ci struct init_qm_vport_params *vport; 19698c2ecf20Sopenharmony_ci struct init_qm_port_params *port; 19708c2ecf20Sopenharmony_ci struct init_qm_pq_params *pq; 19718c2ecf20Sopenharmony_ci int i, tc; 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci /* top level params */ 19748c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 19758c2ecf20Sopenharmony_ci NETIF_MSG_HW, 19768c2ecf20Sopenharmony_ci "qm init top level params: start_pq %d, start_vport %d, pure_lb_pq %d, offload_pq %d, llt_pq %d, pure_ack_pq %d\n", 19778c2ecf20Sopenharmony_ci qm_info->start_pq, 19788c2ecf20Sopenharmony_ci qm_info->start_vport, 19798c2ecf20Sopenharmony_ci qm_info->pure_lb_pq, 19808c2ecf20Sopenharmony_ci qm_info->first_ofld_pq, 19818c2ecf20Sopenharmony_ci qm_info->first_llt_pq, 19828c2ecf20Sopenharmony_ci qm_info->pure_ack_pq); 19838c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 19848c2ecf20Sopenharmony_ci NETIF_MSG_HW, 19858c2ecf20Sopenharmony_ci "ooo_pq %d, first_vf_pq %d, num_pqs %d, num_vf_pqs %d, num_vports %d, max_phys_tcs_per_port %d\n", 19868c2ecf20Sopenharmony_ci qm_info->ooo_pq, 19878c2ecf20Sopenharmony_ci qm_info->first_vf_pq, 19888c2ecf20Sopenharmony_ci qm_info->num_pqs, 19898c2ecf20Sopenharmony_ci qm_info->num_vf_pqs, 19908c2ecf20Sopenharmony_ci qm_info->num_vports, qm_info->max_phys_tcs_per_port); 19918c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 19928c2ecf20Sopenharmony_ci NETIF_MSG_HW, 19938c2ecf20Sopenharmony_ci "pf_rl_en %d, pf_wfq_en %d, vport_rl_en %d, vport_wfq_en %d, pf_wfq %d, pf_rl %d, num_pf_rls %d, pq_flags %x\n", 19948c2ecf20Sopenharmony_ci qm_info->pf_rl_en, 19958c2ecf20Sopenharmony_ci qm_info->pf_wfq_en, 19968c2ecf20Sopenharmony_ci qm_info->vport_rl_en, 19978c2ecf20Sopenharmony_ci qm_info->vport_wfq_en, 19988c2ecf20Sopenharmony_ci qm_info->pf_wfq, 19998c2ecf20Sopenharmony_ci qm_info->pf_rl, 20008c2ecf20Sopenharmony_ci qm_info->num_pf_rls, qed_get_pq_flags(p_hwfn)); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci /* port table */ 20038c2ecf20Sopenharmony_ci for (i = 0; i < p_hwfn->cdev->num_ports_in_engine; i++) { 20048c2ecf20Sopenharmony_ci port = &(qm_info->qm_port_params[i]); 20058c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 20068c2ecf20Sopenharmony_ci NETIF_MSG_HW, 20078c2ecf20Sopenharmony_ci "port idx %d, active %d, active_phys_tcs %d, num_pbf_cmd_lines %d, num_btb_blocks %d, reserved %d\n", 20088c2ecf20Sopenharmony_ci i, 20098c2ecf20Sopenharmony_ci port->active, 20108c2ecf20Sopenharmony_ci port->active_phys_tcs, 20118c2ecf20Sopenharmony_ci port->num_pbf_cmd_lines, 20128c2ecf20Sopenharmony_ci port->num_btb_blocks, port->reserved); 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci /* vport table */ 20168c2ecf20Sopenharmony_ci for (i = 0; i < qm_info->num_vports; i++) { 20178c2ecf20Sopenharmony_ci vport = &(qm_info->qm_vport_params[i]); 20188c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 20198c2ecf20Sopenharmony_ci NETIF_MSG_HW, 20208c2ecf20Sopenharmony_ci "vport idx %d, wfq %d, first_tx_pq_id [ ", 20218c2ecf20Sopenharmony_ci qm_info->start_vport + i, vport->wfq); 20228c2ecf20Sopenharmony_ci for (tc = 0; tc < NUM_OF_TCS; tc++) 20238c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 20248c2ecf20Sopenharmony_ci NETIF_MSG_HW, 20258c2ecf20Sopenharmony_ci "%d ", vport->first_tx_pq_id[tc]); 20268c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_HW, "]\n"); 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci /* pq table */ 20308c2ecf20Sopenharmony_ci for (i = 0; i < qm_info->num_pqs; i++) { 20318c2ecf20Sopenharmony_ci pq = &(qm_info->qm_pq_params[i]); 20328c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 20338c2ecf20Sopenharmony_ci NETIF_MSG_HW, 20348c2ecf20Sopenharmony_ci "pq idx %d, port %d, vport_id %d, tc %d, wrr_grp %d, rl_valid %d rl_id %d\n", 20358c2ecf20Sopenharmony_ci qm_info->start_pq + i, 20368c2ecf20Sopenharmony_ci pq->port_id, 20378c2ecf20Sopenharmony_ci pq->vport_id, 20388c2ecf20Sopenharmony_ci pq->tc_id, pq->wrr_group, pq->rl_valid, pq->rl_id); 20398c2ecf20Sopenharmony_ci } 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistatic void qed_init_qm_info(struct qed_hwfn *p_hwfn) 20438c2ecf20Sopenharmony_ci{ 20448c2ecf20Sopenharmony_ci /* reset params required for init run */ 20458c2ecf20Sopenharmony_ci qed_init_qm_reset_params(p_hwfn); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci /* init QM top level params */ 20488c2ecf20Sopenharmony_ci qed_init_qm_params(p_hwfn); 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci /* init QM port params */ 20518c2ecf20Sopenharmony_ci qed_init_qm_port_params(p_hwfn); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci /* init QM vport params */ 20548c2ecf20Sopenharmony_ci qed_init_qm_vport_params(p_hwfn); 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci /* init QM physical queue params */ 20578c2ecf20Sopenharmony_ci qed_init_qm_pq_params(p_hwfn); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci /* display all that init */ 20608c2ecf20Sopenharmony_ci qed_dp_init_qm_params(p_hwfn); 20618c2ecf20Sopenharmony_ci} 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci/* This function reconfigures the QM pf on the fly. 20648c2ecf20Sopenharmony_ci * For this purpose we: 20658c2ecf20Sopenharmony_ci * 1. reconfigure the QM database 20668c2ecf20Sopenharmony_ci * 2. set new values to runtime array 20678c2ecf20Sopenharmony_ci * 3. send an sdm_qm_cmd through the rbc interface to stop the QM 20688c2ecf20Sopenharmony_ci * 4. activate init tool in QM_PF stage 20698c2ecf20Sopenharmony_ci * 5. send an sdm_qm_cmd through rbc interface to release the QM 20708c2ecf20Sopenharmony_ci */ 20718c2ecf20Sopenharmony_ciint qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 20728c2ecf20Sopenharmony_ci{ 20738c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 20748c2ecf20Sopenharmony_ci bool b_rc; 20758c2ecf20Sopenharmony_ci int rc; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci /* initialize qed's qm data structure */ 20788c2ecf20Sopenharmony_ci qed_init_qm_info(p_hwfn); 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci /* stop PF's qm queues */ 20818c2ecf20Sopenharmony_ci spin_lock_bh(&qm_lock); 20828c2ecf20Sopenharmony_ci b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, false, true, 20838c2ecf20Sopenharmony_ci qm_info->start_pq, qm_info->num_pqs); 20848c2ecf20Sopenharmony_ci spin_unlock_bh(&qm_lock); 20858c2ecf20Sopenharmony_ci if (!b_rc) 20868c2ecf20Sopenharmony_ci return -EINVAL; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci /* prepare QM portion of runtime array */ 20898c2ecf20Sopenharmony_ci qed_qm_init_pf(p_hwfn, p_ptt, false); 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci /* activate init tool on runtime array */ 20928c2ecf20Sopenharmony_ci rc = qed_init_run(p_hwfn, p_ptt, PHASE_QM_PF, p_hwfn->rel_pf_id, 20938c2ecf20Sopenharmony_ci p_hwfn->hw_info.hw_mode); 20948c2ecf20Sopenharmony_ci if (rc) 20958c2ecf20Sopenharmony_ci return rc; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci /* start PF's qm queues */ 20988c2ecf20Sopenharmony_ci spin_lock_bh(&qm_lock); 20998c2ecf20Sopenharmony_ci b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, true, true, 21008c2ecf20Sopenharmony_ci qm_info->start_pq, qm_info->num_pqs); 21018c2ecf20Sopenharmony_ci spin_unlock_bh(&qm_lock); 21028c2ecf20Sopenharmony_ci if (!b_rc) 21038c2ecf20Sopenharmony_ci return -EINVAL; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci return 0; 21068c2ecf20Sopenharmony_ci} 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_cistatic int qed_alloc_qm_data(struct qed_hwfn *p_hwfn) 21098c2ecf20Sopenharmony_ci{ 21108c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 21118c2ecf20Sopenharmony_ci int rc; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci rc = qed_init_qm_sanity(p_hwfn); 21148c2ecf20Sopenharmony_ci if (rc) 21158c2ecf20Sopenharmony_ci goto alloc_err; 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci qm_info->qm_pq_params = kcalloc(qed_init_qm_get_num_pqs(p_hwfn), 21188c2ecf20Sopenharmony_ci sizeof(*qm_info->qm_pq_params), 21198c2ecf20Sopenharmony_ci GFP_KERNEL); 21208c2ecf20Sopenharmony_ci if (!qm_info->qm_pq_params) 21218c2ecf20Sopenharmony_ci goto alloc_err; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci qm_info->qm_vport_params = kcalloc(qed_init_qm_get_num_vports(p_hwfn), 21248c2ecf20Sopenharmony_ci sizeof(*qm_info->qm_vport_params), 21258c2ecf20Sopenharmony_ci GFP_KERNEL); 21268c2ecf20Sopenharmony_ci if (!qm_info->qm_vport_params) 21278c2ecf20Sopenharmony_ci goto alloc_err; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci qm_info->qm_port_params = kcalloc(p_hwfn->cdev->num_ports_in_engine, 21308c2ecf20Sopenharmony_ci sizeof(*qm_info->qm_port_params), 21318c2ecf20Sopenharmony_ci GFP_KERNEL); 21328c2ecf20Sopenharmony_ci if (!qm_info->qm_port_params) 21338c2ecf20Sopenharmony_ci goto alloc_err; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci qm_info->wfq_data = kcalloc(qed_init_qm_get_num_vports(p_hwfn), 21368c2ecf20Sopenharmony_ci sizeof(*qm_info->wfq_data), 21378c2ecf20Sopenharmony_ci GFP_KERNEL); 21388c2ecf20Sopenharmony_ci if (!qm_info->wfq_data) 21398c2ecf20Sopenharmony_ci goto alloc_err; 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci return 0; 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_cialloc_err: 21448c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to allocate memory for QM params\n"); 21458c2ecf20Sopenharmony_ci qed_qm_info_free(p_hwfn); 21468c2ecf20Sopenharmony_ci return -ENOMEM; 21478c2ecf20Sopenharmony_ci} 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ciint qed_resc_alloc(struct qed_dev *cdev) 21508c2ecf20Sopenharmony_ci{ 21518c2ecf20Sopenharmony_ci u32 rdma_tasks, excess_tasks; 21528c2ecf20Sopenharmony_ci u32 line_count; 21538c2ecf20Sopenharmony_ci int i, rc = 0; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci if (IS_VF(cdev)) { 21568c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 21578c2ecf20Sopenharmony_ci rc = qed_l2_alloc(&cdev->hwfns[i]); 21588c2ecf20Sopenharmony_ci if (rc) 21598c2ecf20Sopenharmony_ci return rc; 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci return rc; 21628c2ecf20Sopenharmony_ci } 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci cdev->fw_data = kzalloc(sizeof(*cdev->fw_data), GFP_KERNEL); 21658c2ecf20Sopenharmony_ci if (!cdev->fw_data) 21668c2ecf20Sopenharmony_ci return -ENOMEM; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 21698c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 21708c2ecf20Sopenharmony_ci u32 n_eqes, num_cons; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci /* Initialize the doorbell recovery mechanism */ 21738c2ecf20Sopenharmony_ci rc = qed_db_recovery_setup(p_hwfn); 21748c2ecf20Sopenharmony_ci if (rc) 21758c2ecf20Sopenharmony_ci goto alloc_err; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci /* First allocate the context manager structure */ 21788c2ecf20Sopenharmony_ci rc = qed_cxt_mngr_alloc(p_hwfn); 21798c2ecf20Sopenharmony_ci if (rc) 21808c2ecf20Sopenharmony_ci goto alloc_err; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci /* Set the HW cid/tid numbers (in the contest manager) 21838c2ecf20Sopenharmony_ci * Must be done prior to any further computations. 21848c2ecf20Sopenharmony_ci */ 21858c2ecf20Sopenharmony_ci rc = qed_cxt_set_pf_params(p_hwfn, RDMA_MAX_TIDS); 21868c2ecf20Sopenharmony_ci if (rc) 21878c2ecf20Sopenharmony_ci goto alloc_err; 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci rc = qed_alloc_qm_data(p_hwfn); 21908c2ecf20Sopenharmony_ci if (rc) 21918c2ecf20Sopenharmony_ci goto alloc_err; 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci /* init qm info */ 21948c2ecf20Sopenharmony_ci qed_init_qm_info(p_hwfn); 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci /* Compute the ILT client partition */ 21978c2ecf20Sopenharmony_ci rc = qed_cxt_cfg_ilt_compute(p_hwfn, &line_count); 21988c2ecf20Sopenharmony_ci if (rc) { 21998c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 22008c2ecf20Sopenharmony_ci "too many ILT lines; re-computing with less lines\n"); 22018c2ecf20Sopenharmony_ci /* In case there are not enough ILT lines we reduce the 22028c2ecf20Sopenharmony_ci * number of RDMA tasks and re-compute. 22038c2ecf20Sopenharmony_ci */ 22048c2ecf20Sopenharmony_ci excess_tasks = 22058c2ecf20Sopenharmony_ci qed_cxt_cfg_ilt_compute_excess(p_hwfn, line_count); 22068c2ecf20Sopenharmony_ci if (!excess_tasks) 22078c2ecf20Sopenharmony_ci goto alloc_err; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci rdma_tasks = RDMA_MAX_TIDS - excess_tasks; 22108c2ecf20Sopenharmony_ci rc = qed_cxt_set_pf_params(p_hwfn, rdma_tasks); 22118c2ecf20Sopenharmony_ci if (rc) 22128c2ecf20Sopenharmony_ci goto alloc_err; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci rc = qed_cxt_cfg_ilt_compute(p_hwfn, &line_count); 22158c2ecf20Sopenharmony_ci if (rc) { 22168c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 22178c2ecf20Sopenharmony_ci "failed ILT compute. Requested too many lines: %u\n", 22188c2ecf20Sopenharmony_ci line_count); 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci goto alloc_err; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci } 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci /* CID map / ILT shadow table / T2 22258c2ecf20Sopenharmony_ci * The talbes sizes are determined by the computations above 22268c2ecf20Sopenharmony_ci */ 22278c2ecf20Sopenharmony_ci rc = qed_cxt_tables_alloc(p_hwfn); 22288c2ecf20Sopenharmony_ci if (rc) 22298c2ecf20Sopenharmony_ci goto alloc_err; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci /* SPQ, must follow ILT because initializes SPQ context */ 22328c2ecf20Sopenharmony_ci rc = qed_spq_alloc(p_hwfn); 22338c2ecf20Sopenharmony_ci if (rc) 22348c2ecf20Sopenharmony_ci goto alloc_err; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci /* SP status block allocation */ 22378c2ecf20Sopenharmony_ci p_hwfn->p_dpc_ptt = qed_get_reserved_ptt(p_hwfn, 22388c2ecf20Sopenharmony_ci RESERVED_PTT_DPC); 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci rc = qed_int_alloc(p_hwfn, p_hwfn->p_main_ptt); 22418c2ecf20Sopenharmony_ci if (rc) 22428c2ecf20Sopenharmony_ci goto alloc_err; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci rc = qed_iov_alloc(p_hwfn); 22458c2ecf20Sopenharmony_ci if (rc) 22468c2ecf20Sopenharmony_ci goto alloc_err; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci /* EQ */ 22498c2ecf20Sopenharmony_ci n_eqes = qed_chain_get_capacity(&p_hwfn->p_spq->chain); 22508c2ecf20Sopenharmony_ci if (QED_IS_RDMA_PERSONALITY(p_hwfn)) { 22518c2ecf20Sopenharmony_ci u32 n_srq = qed_cxt_get_total_srq_count(p_hwfn); 22528c2ecf20Sopenharmony_ci enum protocol_type rdma_proto; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci if (QED_IS_ROCE_PERSONALITY(p_hwfn)) 22558c2ecf20Sopenharmony_ci rdma_proto = PROTOCOLID_ROCE; 22568c2ecf20Sopenharmony_ci else 22578c2ecf20Sopenharmony_ci rdma_proto = PROTOCOLID_IWARP; 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci num_cons = qed_cxt_get_proto_cid_count(p_hwfn, 22608c2ecf20Sopenharmony_ci rdma_proto, 22618c2ecf20Sopenharmony_ci NULL) * 2; 22628c2ecf20Sopenharmony_ci /* EQ should be able to get events from all SRQ's 22638c2ecf20Sopenharmony_ci * at the same time 22648c2ecf20Sopenharmony_ci */ 22658c2ecf20Sopenharmony_ci n_eqes += num_cons + 2 * MAX_NUM_VFS_BB + n_srq; 22668c2ecf20Sopenharmony_ci } else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { 22678c2ecf20Sopenharmony_ci num_cons = 22688c2ecf20Sopenharmony_ci qed_cxt_get_proto_cid_count(p_hwfn, 22698c2ecf20Sopenharmony_ci PROTOCOLID_ISCSI, 22708c2ecf20Sopenharmony_ci NULL); 22718c2ecf20Sopenharmony_ci n_eqes += 2 * num_cons; 22728c2ecf20Sopenharmony_ci } 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci if (n_eqes > 0xFFFF) { 22758c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 22768c2ecf20Sopenharmony_ci "Cannot allocate 0x%x EQ elements. The maximum of a u16 chain is 0x%x\n", 22778c2ecf20Sopenharmony_ci n_eqes, 0xFFFF); 22788c2ecf20Sopenharmony_ci goto alloc_no_mem; 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci rc = qed_eq_alloc(p_hwfn, (u16) n_eqes); 22828c2ecf20Sopenharmony_ci if (rc) 22838c2ecf20Sopenharmony_ci goto alloc_err; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci rc = qed_consq_alloc(p_hwfn); 22868c2ecf20Sopenharmony_ci if (rc) 22878c2ecf20Sopenharmony_ci goto alloc_err; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci rc = qed_l2_alloc(p_hwfn); 22908c2ecf20Sopenharmony_ci if (rc) 22918c2ecf20Sopenharmony_ci goto alloc_err; 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_LL2 22948c2ecf20Sopenharmony_ci if (p_hwfn->using_ll2) { 22958c2ecf20Sopenharmony_ci rc = qed_ll2_alloc(p_hwfn); 22968c2ecf20Sopenharmony_ci if (rc) 22978c2ecf20Sopenharmony_ci goto alloc_err; 22988c2ecf20Sopenharmony_ci } 22998c2ecf20Sopenharmony_ci#endif 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.personality == QED_PCI_FCOE) { 23028c2ecf20Sopenharmony_ci rc = qed_fcoe_alloc(p_hwfn); 23038c2ecf20Sopenharmony_ci if (rc) 23048c2ecf20Sopenharmony_ci goto alloc_err; 23058c2ecf20Sopenharmony_ci } 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { 23088c2ecf20Sopenharmony_ci rc = qed_iscsi_alloc(p_hwfn); 23098c2ecf20Sopenharmony_ci if (rc) 23108c2ecf20Sopenharmony_ci goto alloc_err; 23118c2ecf20Sopenharmony_ci rc = qed_ooo_alloc(p_hwfn); 23128c2ecf20Sopenharmony_ci if (rc) 23138c2ecf20Sopenharmony_ci goto alloc_err; 23148c2ecf20Sopenharmony_ci } 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci if (QED_IS_RDMA_PERSONALITY(p_hwfn)) { 23178c2ecf20Sopenharmony_ci rc = qed_rdma_info_alloc(p_hwfn); 23188c2ecf20Sopenharmony_ci if (rc) 23198c2ecf20Sopenharmony_ci goto alloc_err; 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci /* DMA info initialization */ 23238c2ecf20Sopenharmony_ci rc = qed_dmae_info_alloc(p_hwfn); 23248c2ecf20Sopenharmony_ci if (rc) 23258c2ecf20Sopenharmony_ci goto alloc_err; 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci /* DCBX initialization */ 23288c2ecf20Sopenharmony_ci rc = qed_dcbx_info_alloc(p_hwfn); 23298c2ecf20Sopenharmony_ci if (rc) 23308c2ecf20Sopenharmony_ci goto alloc_err; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci rc = qed_dbg_alloc_user_data(p_hwfn, &p_hwfn->dbg_user_info); 23338c2ecf20Sopenharmony_ci if (rc) 23348c2ecf20Sopenharmony_ci goto alloc_err; 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci rc = qed_llh_alloc(cdev); 23388c2ecf20Sopenharmony_ci if (rc) { 23398c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 23408c2ecf20Sopenharmony_ci "Failed to allocate memory for the llh_info structure\n"); 23418c2ecf20Sopenharmony_ci goto alloc_err; 23428c2ecf20Sopenharmony_ci } 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL); 23458c2ecf20Sopenharmony_ci if (!cdev->reset_stats) 23468c2ecf20Sopenharmony_ci goto alloc_no_mem; 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci return 0; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_cialloc_no_mem: 23518c2ecf20Sopenharmony_ci rc = -ENOMEM; 23528c2ecf20Sopenharmony_cialloc_err: 23538c2ecf20Sopenharmony_ci qed_resc_free(cdev); 23548c2ecf20Sopenharmony_ci return rc; 23558c2ecf20Sopenharmony_ci} 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_civoid qed_resc_setup(struct qed_dev *cdev) 23588c2ecf20Sopenharmony_ci{ 23598c2ecf20Sopenharmony_ci int i; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci if (IS_VF(cdev)) { 23628c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) 23638c2ecf20Sopenharmony_ci qed_l2_setup(&cdev->hwfns[i]); 23648c2ecf20Sopenharmony_ci return; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 23688c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci qed_cxt_mngr_setup(p_hwfn); 23718c2ecf20Sopenharmony_ci qed_spq_setup(p_hwfn); 23728c2ecf20Sopenharmony_ci qed_eq_setup(p_hwfn); 23738c2ecf20Sopenharmony_ci qed_consq_setup(p_hwfn); 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci /* Read shadow of current MFW mailbox */ 23768c2ecf20Sopenharmony_ci qed_mcp_read_mb(p_hwfn, p_hwfn->p_main_ptt); 23778c2ecf20Sopenharmony_ci memcpy(p_hwfn->mcp_info->mfw_mb_shadow, 23788c2ecf20Sopenharmony_ci p_hwfn->mcp_info->mfw_mb_cur, 23798c2ecf20Sopenharmony_ci p_hwfn->mcp_info->mfw_mb_length); 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci qed_int_setup(p_hwfn, p_hwfn->p_main_ptt); 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci qed_l2_setup(p_hwfn); 23848c2ecf20Sopenharmony_ci qed_iov_setup(p_hwfn); 23858c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_LL2 23868c2ecf20Sopenharmony_ci if (p_hwfn->using_ll2) 23878c2ecf20Sopenharmony_ci qed_ll2_setup(p_hwfn); 23888c2ecf20Sopenharmony_ci#endif 23898c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.personality == QED_PCI_FCOE) 23908c2ecf20Sopenharmony_ci qed_fcoe_setup(p_hwfn); 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { 23938c2ecf20Sopenharmony_ci qed_iscsi_setup(p_hwfn); 23948c2ecf20Sopenharmony_ci qed_ooo_setup(p_hwfn); 23958c2ecf20Sopenharmony_ci } 23968c2ecf20Sopenharmony_ci } 23978c2ecf20Sopenharmony_ci} 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci#define FINAL_CLEANUP_POLL_CNT (100) 24008c2ecf20Sopenharmony_ci#define FINAL_CLEANUP_POLL_TIME (10) 24018c2ecf20Sopenharmony_ciint qed_final_cleanup(struct qed_hwfn *p_hwfn, 24028c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u16 id, bool is_vf) 24038c2ecf20Sopenharmony_ci{ 24048c2ecf20Sopenharmony_ci u32 command = 0, addr, count = FINAL_CLEANUP_POLL_CNT; 24058c2ecf20Sopenharmony_ci int rc = -EBUSY; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci addr = GTT_BAR0_MAP_REG_USDM_RAM + 24088c2ecf20Sopenharmony_ci USTORM_FLR_FINAL_ACK_OFFSET(p_hwfn->rel_pf_id); 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci if (is_vf) 24118c2ecf20Sopenharmony_ci id += 0x10; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci command |= X_FINAL_CLEANUP_AGG_INT << 24148c2ecf20Sopenharmony_ci SDM_AGG_INT_COMP_PARAMS_AGG_INT_INDEX_SHIFT; 24158c2ecf20Sopenharmony_ci command |= 1 << SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_ENABLE_SHIFT; 24168c2ecf20Sopenharmony_ci command |= id << SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_BIT_SHIFT; 24178c2ecf20Sopenharmony_ci command |= SDM_COMP_TYPE_AGG_INT << SDM_OP_GEN_COMP_TYPE_SHIFT; 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci /* Make sure notification is not set before initiating final cleanup */ 24208c2ecf20Sopenharmony_ci if (REG_RD(p_hwfn, addr)) { 24218c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 24228c2ecf20Sopenharmony_ci "Unexpected; Found final cleanup notification before initiating final cleanup\n"); 24238c2ecf20Sopenharmony_ci REG_WR(p_hwfn, addr, 0); 24248c2ecf20Sopenharmony_ci } 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 24278c2ecf20Sopenharmony_ci "Sending final cleanup for PFVF[%d] [Command %08x]\n", 24288c2ecf20Sopenharmony_ci id, command); 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, XSDM_REG_OPERATION_GEN, command); 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci /* Poll until completion */ 24338c2ecf20Sopenharmony_ci while (!REG_RD(p_hwfn, addr) && count--) 24348c2ecf20Sopenharmony_ci msleep(FINAL_CLEANUP_POLL_TIME); 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci if (REG_RD(p_hwfn, addr)) 24378c2ecf20Sopenharmony_ci rc = 0; 24388c2ecf20Sopenharmony_ci else 24398c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 24408c2ecf20Sopenharmony_ci "Failed to receive FW final cleanup notification\n"); 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci /* Cleanup afterwards */ 24438c2ecf20Sopenharmony_ci REG_WR(p_hwfn, addr, 0); 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci return rc; 24468c2ecf20Sopenharmony_ci} 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_cistatic int qed_calc_hw_mode(struct qed_hwfn *p_hwfn) 24498c2ecf20Sopenharmony_ci{ 24508c2ecf20Sopenharmony_ci int hw_mode = 0; 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci if (QED_IS_BB_B0(p_hwfn->cdev)) { 24538c2ecf20Sopenharmony_ci hw_mode |= 1 << MODE_BB; 24548c2ecf20Sopenharmony_ci } else if (QED_IS_AH(p_hwfn->cdev)) { 24558c2ecf20Sopenharmony_ci hw_mode |= 1 << MODE_K2; 24568c2ecf20Sopenharmony_ci } else { 24578c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Unknown chip type %#x\n", 24588c2ecf20Sopenharmony_ci p_hwfn->cdev->type); 24598c2ecf20Sopenharmony_ci return -EINVAL; 24608c2ecf20Sopenharmony_ci } 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci switch (p_hwfn->cdev->num_ports_in_engine) { 24638c2ecf20Sopenharmony_ci case 1: 24648c2ecf20Sopenharmony_ci hw_mode |= 1 << MODE_PORTS_PER_ENG_1; 24658c2ecf20Sopenharmony_ci break; 24668c2ecf20Sopenharmony_ci case 2: 24678c2ecf20Sopenharmony_ci hw_mode |= 1 << MODE_PORTS_PER_ENG_2; 24688c2ecf20Sopenharmony_ci break; 24698c2ecf20Sopenharmony_ci case 4: 24708c2ecf20Sopenharmony_ci hw_mode |= 1 << MODE_PORTS_PER_ENG_4; 24718c2ecf20Sopenharmony_ci break; 24728c2ecf20Sopenharmony_ci default: 24738c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "num_ports_in_engine = %d not supported\n", 24748c2ecf20Sopenharmony_ci p_hwfn->cdev->num_ports_in_engine); 24758c2ecf20Sopenharmony_ci return -EINVAL; 24768c2ecf20Sopenharmony_ci } 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci if (test_bit(QED_MF_OVLAN_CLSS, &p_hwfn->cdev->mf_bits)) 24798c2ecf20Sopenharmony_ci hw_mode |= 1 << MODE_MF_SD; 24808c2ecf20Sopenharmony_ci else 24818c2ecf20Sopenharmony_ci hw_mode |= 1 << MODE_MF_SI; 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci hw_mode |= 1 << MODE_ASIC; 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci if (p_hwfn->cdev->num_hwfns > 1) 24868c2ecf20Sopenharmony_ci hw_mode |= 1 << MODE_100G; 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci p_hwfn->hw_info.hw_mode = hw_mode; 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, (NETIF_MSG_PROBE | NETIF_MSG_IFUP), 24918c2ecf20Sopenharmony_ci "Configuring function for hw_mode: 0x%08x\n", 24928c2ecf20Sopenharmony_ci p_hwfn->hw_info.hw_mode); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci return 0; 24958c2ecf20Sopenharmony_ci} 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci/* Init run time data for all PFs on an engine. */ 24988c2ecf20Sopenharmony_cistatic void qed_init_cau_rt_data(struct qed_dev *cdev) 24998c2ecf20Sopenharmony_ci{ 25008c2ecf20Sopenharmony_ci u32 offset = CAU_REG_SB_VAR_MEMORY_RT_OFFSET; 25018c2ecf20Sopenharmony_ci int i, igu_sb_id; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 25048c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 25058c2ecf20Sopenharmony_ci struct qed_igu_info *p_igu_info; 25068c2ecf20Sopenharmony_ci struct qed_igu_block *p_block; 25078c2ecf20Sopenharmony_ci struct cau_sb_entry sb_entry; 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci p_igu_info = p_hwfn->hw_info.p_igu_info; 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci for (igu_sb_id = 0; 25128c2ecf20Sopenharmony_ci igu_sb_id < QED_MAPPING_MEMORY_SIZE(cdev); igu_sb_id++) { 25138c2ecf20Sopenharmony_ci p_block = &p_igu_info->entry[igu_sb_id]; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci if (!p_block->is_pf) 25168c2ecf20Sopenharmony_ci continue; 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci qed_init_cau_sb_entry(p_hwfn, &sb_entry, 25198c2ecf20Sopenharmony_ci p_block->function_id, 0, 0); 25208c2ecf20Sopenharmony_ci STORE_RT_REG_AGG(p_hwfn, offset + igu_sb_id * 2, 25218c2ecf20Sopenharmony_ci sb_entry); 25228c2ecf20Sopenharmony_ci } 25238c2ecf20Sopenharmony_ci } 25248c2ecf20Sopenharmony_ci} 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_cistatic void qed_init_cache_line_size(struct qed_hwfn *p_hwfn, 25278c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 25288c2ecf20Sopenharmony_ci{ 25298c2ecf20Sopenharmony_ci u32 val, wr_mbs, cache_line_size; 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci val = qed_rd(p_hwfn, p_ptt, PSWRQ2_REG_WR_MBS0); 25328c2ecf20Sopenharmony_ci switch (val) { 25338c2ecf20Sopenharmony_ci case 0: 25348c2ecf20Sopenharmony_ci wr_mbs = 128; 25358c2ecf20Sopenharmony_ci break; 25368c2ecf20Sopenharmony_ci case 1: 25378c2ecf20Sopenharmony_ci wr_mbs = 256; 25388c2ecf20Sopenharmony_ci break; 25398c2ecf20Sopenharmony_ci case 2: 25408c2ecf20Sopenharmony_ci wr_mbs = 512; 25418c2ecf20Sopenharmony_ci break; 25428c2ecf20Sopenharmony_ci default: 25438c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 25448c2ecf20Sopenharmony_ci "Unexpected value of PSWRQ2_REG_WR_MBS0 [0x%x]. Avoid configuring PGLUE_B_REG_CACHE_LINE_SIZE.\n", 25458c2ecf20Sopenharmony_ci val); 25468c2ecf20Sopenharmony_ci return; 25478c2ecf20Sopenharmony_ci } 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci cache_line_size = min_t(u32, L1_CACHE_BYTES, wr_mbs); 25508c2ecf20Sopenharmony_ci switch (cache_line_size) { 25518c2ecf20Sopenharmony_ci case 32: 25528c2ecf20Sopenharmony_ci val = 0; 25538c2ecf20Sopenharmony_ci break; 25548c2ecf20Sopenharmony_ci case 64: 25558c2ecf20Sopenharmony_ci val = 1; 25568c2ecf20Sopenharmony_ci break; 25578c2ecf20Sopenharmony_ci case 128: 25588c2ecf20Sopenharmony_ci val = 2; 25598c2ecf20Sopenharmony_ci break; 25608c2ecf20Sopenharmony_ci case 256: 25618c2ecf20Sopenharmony_ci val = 3; 25628c2ecf20Sopenharmony_ci break; 25638c2ecf20Sopenharmony_ci default: 25648c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 25658c2ecf20Sopenharmony_ci "Unexpected value of cache line size [0x%x]. Avoid configuring PGLUE_B_REG_CACHE_LINE_SIZE.\n", 25668c2ecf20Sopenharmony_ci cache_line_size); 25678c2ecf20Sopenharmony_ci } 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci if (L1_CACHE_BYTES > wr_mbs) 25708c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 25718c2ecf20Sopenharmony_ci "The cache line size for padding is suboptimal for performance [OS cache line size 0x%x, wr mbs 0x%x]\n", 25728c2ecf20Sopenharmony_ci L1_CACHE_BYTES, wr_mbs); 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET, val); 25758c2ecf20Sopenharmony_ci if (val > 0) { 25768c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET, val); 25778c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET, val); 25788c2ecf20Sopenharmony_ci } 25798c2ecf20Sopenharmony_ci} 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_cistatic int qed_hw_init_common(struct qed_hwfn *p_hwfn, 25828c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, int hw_mode) 25838c2ecf20Sopenharmony_ci{ 25848c2ecf20Sopenharmony_ci struct qed_qm_info *qm_info = &p_hwfn->qm_info; 25858c2ecf20Sopenharmony_ci struct qed_qm_common_rt_init_params params; 25868c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 25878c2ecf20Sopenharmony_ci u8 vf_id, max_num_vfs; 25888c2ecf20Sopenharmony_ci u16 num_pfs, pf_id; 25898c2ecf20Sopenharmony_ci u32 concrete_fid; 25908c2ecf20Sopenharmony_ci int rc = 0; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci qed_init_cau_rt_data(cdev); 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci /* Program GTT windows */ 25958c2ecf20Sopenharmony_ci qed_gtt_init(p_hwfn); 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info) { 25988c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->func_info.bandwidth_max) 25998c2ecf20Sopenharmony_ci qm_info->pf_rl_en = true; 26008c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->func_info.bandwidth_min) 26018c2ecf20Sopenharmony_ci qm_info->pf_wfq_en = true; 26028c2ecf20Sopenharmony_ci } 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 26058c2ecf20Sopenharmony_ci params.max_ports_per_engine = p_hwfn->cdev->num_ports_in_engine; 26068c2ecf20Sopenharmony_ci params.max_phys_tcs_per_port = qm_info->max_phys_tcs_per_port; 26078c2ecf20Sopenharmony_ci params.pf_rl_en = qm_info->pf_rl_en; 26088c2ecf20Sopenharmony_ci params.pf_wfq_en = qm_info->pf_wfq_en; 26098c2ecf20Sopenharmony_ci params.global_rl_en = qm_info->vport_rl_en; 26108c2ecf20Sopenharmony_ci params.vport_wfq_en = qm_info->vport_wfq_en; 26118c2ecf20Sopenharmony_ci params.port_params = qm_info->qm_port_params; 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci qed_qm_common_rt_init(p_hwfn, ¶ms); 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci qed_cxt_hw_init_common(p_hwfn); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci qed_init_cache_line_size(p_hwfn, p_ptt); 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci rc = qed_init_run(p_hwfn, p_ptt, PHASE_ENGINE, ANY_PHASE_ID, hw_mode); 26208c2ecf20Sopenharmony_ci if (rc) 26218c2ecf20Sopenharmony_ci return rc; 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PSWRQ2_REG_L2P_VALIDATE_VFID, 0); 26248c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_USE_CLIENTID_IN_TAG, 1); 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci if (QED_IS_BB(p_hwfn->cdev)) { 26278c2ecf20Sopenharmony_ci num_pfs = NUM_OF_ENG_PFS(p_hwfn->cdev); 26288c2ecf20Sopenharmony_ci for (pf_id = 0; pf_id < num_pfs; pf_id++) { 26298c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, pf_id); 26308c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0); 26318c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0); 26328c2ecf20Sopenharmony_ci } 26338c2ecf20Sopenharmony_ci /* pretend to original PF */ 26348c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, p_hwfn->rel_pf_id); 26358c2ecf20Sopenharmony_ci } 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci max_num_vfs = QED_IS_AH(cdev) ? MAX_NUM_VFS_K2 : MAX_NUM_VFS_BB; 26388c2ecf20Sopenharmony_ci for (vf_id = 0; vf_id < max_num_vfs; vf_id++) { 26398c2ecf20Sopenharmony_ci concrete_fid = qed_vfid_to_concrete(p_hwfn, vf_id); 26408c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, (u16) concrete_fid); 26418c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, CCFC_REG_STRONG_ENABLE_VF, 0x1); 26428c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, CCFC_REG_WEAK_ENABLE_VF, 0x0); 26438c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, TCFC_REG_STRONG_ENABLE_VF, 0x1); 26448c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, TCFC_REG_WEAK_ENABLE_VF, 0x0); 26458c2ecf20Sopenharmony_ci } 26468c2ecf20Sopenharmony_ci /* pretend to original PF */ 26478c2ecf20Sopenharmony_ci qed_fid_pretend(p_hwfn, p_ptt, p_hwfn->rel_pf_id); 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci return rc; 26508c2ecf20Sopenharmony_ci} 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_cistatic int 26538c2ecf20Sopenharmony_ciqed_hw_init_dpi_size(struct qed_hwfn *p_hwfn, 26548c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u32 pwm_region_size, u32 n_cpus) 26558c2ecf20Sopenharmony_ci{ 26568c2ecf20Sopenharmony_ci u32 dpi_bit_shift, dpi_count, dpi_page_size; 26578c2ecf20Sopenharmony_ci u32 min_dpis; 26588c2ecf20Sopenharmony_ci u32 n_wids; 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci /* Calculate DPI size */ 26618c2ecf20Sopenharmony_ci n_wids = max_t(u32, QED_MIN_WIDS, n_cpus); 26628c2ecf20Sopenharmony_ci dpi_page_size = QED_WID_SIZE * roundup_pow_of_two(n_wids); 26638c2ecf20Sopenharmony_ci dpi_page_size = (dpi_page_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); 26648c2ecf20Sopenharmony_ci dpi_bit_shift = ilog2(dpi_page_size / 4096); 26658c2ecf20Sopenharmony_ci dpi_count = pwm_region_size / dpi_page_size; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci min_dpis = p_hwfn->pf_params.rdma_pf_params.min_dpis; 26688c2ecf20Sopenharmony_ci min_dpis = max_t(u32, QED_MIN_DPIS, min_dpis); 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci p_hwfn->dpi_size = dpi_page_size; 26718c2ecf20Sopenharmony_ci p_hwfn->dpi_count = dpi_count; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DPI_BIT_SHIFT, dpi_bit_shift); 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci if (dpi_count < min_dpis) 26768c2ecf20Sopenharmony_ci return -EINVAL; 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ci return 0; 26798c2ecf20Sopenharmony_ci} 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_cienum QED_ROCE_EDPM_MODE { 26828c2ecf20Sopenharmony_ci QED_ROCE_EDPM_MODE_ENABLE = 0, 26838c2ecf20Sopenharmony_ci QED_ROCE_EDPM_MODE_FORCE_ON = 1, 26848c2ecf20Sopenharmony_ci QED_ROCE_EDPM_MODE_DISABLE = 2, 26858c2ecf20Sopenharmony_ci}; 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_cibool qed_edpm_enabled(struct qed_hwfn *p_hwfn) 26888c2ecf20Sopenharmony_ci{ 26898c2ecf20Sopenharmony_ci if (p_hwfn->dcbx_no_edpm || p_hwfn->db_bar_no_edpm) 26908c2ecf20Sopenharmony_ci return false; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci return true; 26938c2ecf20Sopenharmony_ci} 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_cistatic int 26968c2ecf20Sopenharmony_ciqed_hw_init_pf_doorbell_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 26978c2ecf20Sopenharmony_ci{ 26988c2ecf20Sopenharmony_ci u32 pwm_regsize, norm_regsize; 26998c2ecf20Sopenharmony_ci u32 non_pwm_conn, min_addr_reg1; 27008c2ecf20Sopenharmony_ci u32 db_bar_size, n_cpus = 1; 27018c2ecf20Sopenharmony_ci u32 roce_edpm_mode; 27028c2ecf20Sopenharmony_ci u32 pf_dems_shift; 27038c2ecf20Sopenharmony_ci int rc = 0; 27048c2ecf20Sopenharmony_ci u8 cond; 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci db_bar_size = qed_hw_bar_size(p_hwfn, p_ptt, BAR_ID_1); 27078c2ecf20Sopenharmony_ci if (p_hwfn->cdev->num_hwfns > 1) 27088c2ecf20Sopenharmony_ci db_bar_size /= 2; 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci /* Calculate doorbell regions */ 27118c2ecf20Sopenharmony_ci non_pwm_conn = qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_CORE) + 27128c2ecf20Sopenharmony_ci qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_CORE, 27138c2ecf20Sopenharmony_ci NULL) + 27148c2ecf20Sopenharmony_ci qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH, 27158c2ecf20Sopenharmony_ci NULL); 27168c2ecf20Sopenharmony_ci norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, PAGE_SIZE); 27178c2ecf20Sopenharmony_ci min_addr_reg1 = norm_regsize / 4096; 27188c2ecf20Sopenharmony_ci pwm_regsize = db_bar_size - norm_regsize; 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ci /* Check that the normal and PWM sizes are valid */ 27218c2ecf20Sopenharmony_ci if (db_bar_size < norm_regsize) { 27228c2ecf20Sopenharmony_ci DP_ERR(p_hwfn->cdev, 27238c2ecf20Sopenharmony_ci "Doorbell BAR size 0x%x is too small (normal region is 0x%0x )\n", 27248c2ecf20Sopenharmony_ci db_bar_size, norm_regsize); 27258c2ecf20Sopenharmony_ci return -EINVAL; 27268c2ecf20Sopenharmony_ci } 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci if (pwm_regsize < QED_MIN_PWM_REGION) { 27298c2ecf20Sopenharmony_ci DP_ERR(p_hwfn->cdev, 27308c2ecf20Sopenharmony_ci "PWM region size 0x%0x is too small. Should be at least 0x%0x (Doorbell BAR size is 0x%x and normal region size is 0x%0x)\n", 27318c2ecf20Sopenharmony_ci pwm_regsize, 27328c2ecf20Sopenharmony_ci QED_MIN_PWM_REGION, db_bar_size, norm_regsize); 27338c2ecf20Sopenharmony_ci return -EINVAL; 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci /* Calculate number of DPIs */ 27378c2ecf20Sopenharmony_ci roce_edpm_mode = p_hwfn->pf_params.rdma_pf_params.roce_edpm_mode; 27388c2ecf20Sopenharmony_ci if ((roce_edpm_mode == QED_ROCE_EDPM_MODE_ENABLE) || 27398c2ecf20Sopenharmony_ci ((roce_edpm_mode == QED_ROCE_EDPM_MODE_FORCE_ON))) { 27408c2ecf20Sopenharmony_ci /* Either EDPM is mandatory, or we are attempting to allocate a 27418c2ecf20Sopenharmony_ci * WID per CPU. 27428c2ecf20Sopenharmony_ci */ 27438c2ecf20Sopenharmony_ci n_cpus = num_present_cpus(); 27448c2ecf20Sopenharmony_ci rc = qed_hw_init_dpi_size(p_hwfn, p_ptt, pwm_regsize, n_cpus); 27458c2ecf20Sopenharmony_ci } 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci cond = (rc && (roce_edpm_mode == QED_ROCE_EDPM_MODE_ENABLE)) || 27488c2ecf20Sopenharmony_ci (roce_edpm_mode == QED_ROCE_EDPM_MODE_DISABLE); 27498c2ecf20Sopenharmony_ci if (cond || p_hwfn->dcbx_no_edpm) { 27508c2ecf20Sopenharmony_ci /* Either EDPM is disabled from user configuration, or it is 27518c2ecf20Sopenharmony_ci * disabled via DCBx, or it is not mandatory and we failed to 27528c2ecf20Sopenharmony_ci * allocated a WID per CPU. 27538c2ecf20Sopenharmony_ci */ 27548c2ecf20Sopenharmony_ci n_cpus = 1; 27558c2ecf20Sopenharmony_ci rc = qed_hw_init_dpi_size(p_hwfn, p_ptt, pwm_regsize, n_cpus); 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci if (cond) 27588c2ecf20Sopenharmony_ci qed_rdma_dpm_bar(p_hwfn, p_ptt); 27598c2ecf20Sopenharmony_ci } 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci p_hwfn->wid_count = (u16) n_cpus; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 27648c2ecf20Sopenharmony_ci "doorbell bar: normal_region_size=%d, pwm_region_size=%d, dpi_size=%d, dpi_count=%d, roce_edpm=%s, page_size=%lu\n", 27658c2ecf20Sopenharmony_ci norm_regsize, 27668c2ecf20Sopenharmony_ci pwm_regsize, 27678c2ecf20Sopenharmony_ci p_hwfn->dpi_size, 27688c2ecf20Sopenharmony_ci p_hwfn->dpi_count, 27698c2ecf20Sopenharmony_ci (!qed_edpm_enabled(p_hwfn)) ? 27708c2ecf20Sopenharmony_ci "disabled" : "enabled", PAGE_SIZE); 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci if (rc) { 27738c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 27748c2ecf20Sopenharmony_ci "Failed to allocate enough DPIs. Allocated %d but the current minimum is %d.\n", 27758c2ecf20Sopenharmony_ci p_hwfn->dpi_count, 27768c2ecf20Sopenharmony_ci p_hwfn->pf_params.rdma_pf_params.min_dpis); 27778c2ecf20Sopenharmony_ci return -EINVAL; 27788c2ecf20Sopenharmony_ci } 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci p_hwfn->dpi_start_offset = norm_regsize; 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci /* DEMS size is configured log2 of DWORDs, hence the division by 4 */ 27838c2ecf20Sopenharmony_ci pf_dems_shift = ilog2(QED_PF_DEMS_SIZE / 4); 27848c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_ICID_BIT_SHIFT_NORM, pf_dems_shift); 27858c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_MIN_ADDR_REG1, min_addr_reg1); 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci return 0; 27888c2ecf20Sopenharmony_ci} 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_cistatic int qed_hw_init_port(struct qed_hwfn *p_hwfn, 27918c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, int hw_mode) 27928c2ecf20Sopenharmony_ci{ 27938c2ecf20Sopenharmony_ci int rc = 0; 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci /* In CMT the gate should be cleared by the 2nd hwfn */ 27968c2ecf20Sopenharmony_ci if (!QED_IS_CMT(p_hwfn->cdev) || !IS_LEAD_HWFN(p_hwfn)) 27978c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, NIG_REG_BRB_GATE_DNTFWD_PORT_RT_OFFSET, 0); 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci rc = qed_init_run(p_hwfn, p_ptt, PHASE_PORT, p_hwfn->port_id, hw_mode); 28008c2ecf20Sopenharmony_ci if (rc) 28018c2ecf20Sopenharmony_ci return rc; 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_MASTER_WRITE_PAD_ENABLE, 0); 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci return 0; 28068c2ecf20Sopenharmony_ci} 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_cistatic int qed_hw_init_pf(struct qed_hwfn *p_hwfn, 28098c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 28108c2ecf20Sopenharmony_ci struct qed_tunnel_info *p_tunn, 28118c2ecf20Sopenharmony_ci int hw_mode, 28128c2ecf20Sopenharmony_ci bool b_hw_start, 28138c2ecf20Sopenharmony_ci enum qed_int_mode int_mode, 28148c2ecf20Sopenharmony_ci bool allow_npar_tx_switch) 28158c2ecf20Sopenharmony_ci{ 28168c2ecf20Sopenharmony_ci u8 rel_pf_id = p_hwfn->rel_pf_id; 28178c2ecf20Sopenharmony_ci int rc = 0; 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info) { 28208c2ecf20Sopenharmony_ci struct qed_mcp_function_info *p_info; 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci p_info = &p_hwfn->mcp_info->func_info; 28238c2ecf20Sopenharmony_ci if (p_info->bandwidth_min) 28248c2ecf20Sopenharmony_ci p_hwfn->qm_info.pf_wfq = p_info->bandwidth_min; 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci /* Update rate limit once we'll actually have a link */ 28278c2ecf20Sopenharmony_ci p_hwfn->qm_info.pf_rl = 100000; 28288c2ecf20Sopenharmony_ci } 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci qed_cxt_hw_init_pf(p_hwfn, p_ptt); 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci qed_int_igu_init_rt(p_hwfn); 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci /* Set VLAN in NIG if needed */ 28358c2ecf20Sopenharmony_ci if (hw_mode & BIT(MODE_MF_SD)) { 28368c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_HW, "Configuring LLH_FUNC_TAG\n"); 28378c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET, 1); 28388c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET, 28398c2ecf20Sopenharmony_ci p_hwfn->hw_info.ovlan); 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_HW, 28428c2ecf20Sopenharmony_ci "Configuring LLH_FUNC_FILTER_HDR_SEL\n"); 28438c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET, 28448c2ecf20Sopenharmony_ci 1); 28458c2ecf20Sopenharmony_ci } 28468c2ecf20Sopenharmony_ci 28478c2ecf20Sopenharmony_ci /* Enable classification by MAC if needed */ 28488c2ecf20Sopenharmony_ci if (hw_mode & BIT(MODE_MF_SI)) { 28498c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_HW, 28508c2ecf20Sopenharmony_ci "Configuring TAGMAC_CLS_TYPE\n"); 28518c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, 28528c2ecf20Sopenharmony_ci NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET, 1); 28538c2ecf20Sopenharmony_ci } 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci /* Protocol Configuration */ 28568c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_TCP_RT_OFFSET, 28578c2ecf20Sopenharmony_ci (p_hwfn->hw_info.personality == QED_PCI_ISCSI) ? 1 : 0); 28588c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_FCOE_RT_OFFSET, 28598c2ecf20Sopenharmony_ci (p_hwfn->hw_info.personality == QED_PCI_FCOE) ? 1 : 0); 28608c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0); 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ci /* Sanity check before the PF init sequence that uses DMAE */ 28638c2ecf20Sopenharmony_ci rc = qed_dmae_sanity(p_hwfn, p_ptt, "pf_phase"); 28648c2ecf20Sopenharmony_ci if (rc) 28658c2ecf20Sopenharmony_ci return rc; 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci /* PF Init sequence */ 28688c2ecf20Sopenharmony_ci rc = qed_init_run(p_hwfn, p_ptt, PHASE_PF, rel_pf_id, hw_mode); 28698c2ecf20Sopenharmony_ci if (rc) 28708c2ecf20Sopenharmony_ci return rc; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci /* QM_PF Init sequence (may be invoked separately e.g. for DCB) */ 28738c2ecf20Sopenharmony_ci rc = qed_init_run(p_hwfn, p_ptt, PHASE_QM_PF, rel_pf_id, hw_mode); 28748c2ecf20Sopenharmony_ci if (rc) 28758c2ecf20Sopenharmony_ci return rc; 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci qed_fw_overlay_init_ram(p_hwfn, p_ptt, p_hwfn->fw_overlay_mem); 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci /* Pure runtime initializations - directly to the HW */ 28808c2ecf20Sopenharmony_ci qed_int_igu_init_pure_rt(p_hwfn, p_ptt, true, true); 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci rc = qed_hw_init_pf_doorbell_bar(p_hwfn, p_ptt); 28838c2ecf20Sopenharmony_ci if (rc) 28848c2ecf20Sopenharmony_ci return rc; 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci /* Use the leading hwfn since in CMT only NIG #0 is operational */ 28878c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn)) { 28888c2ecf20Sopenharmony_ci rc = qed_llh_hw_init_pf(p_hwfn, p_ptt); 28898c2ecf20Sopenharmony_ci if (rc) 28908c2ecf20Sopenharmony_ci return rc; 28918c2ecf20Sopenharmony_ci } 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci if (b_hw_start) { 28948c2ecf20Sopenharmony_ci /* enable interrupts */ 28958c2ecf20Sopenharmony_ci qed_int_igu_enable(p_hwfn, p_ptt, int_mode); 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci /* send function start command */ 28988c2ecf20Sopenharmony_ci rc = qed_sp_pf_start(p_hwfn, p_ptt, p_tunn, 28998c2ecf20Sopenharmony_ci allow_npar_tx_switch); 29008c2ecf20Sopenharmony_ci if (rc) { 29018c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Function start ramrod failed\n"); 29028c2ecf20Sopenharmony_ci return rc; 29038c2ecf20Sopenharmony_ci } 29048c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.personality == QED_PCI_FCOE) { 29058c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TAG1, BIT(2)); 29068c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, 29078c2ecf20Sopenharmony_ci PRS_REG_PKT_LEN_STAT_TAGS_NOT_COUNTED_FIRST, 29088c2ecf20Sopenharmony_ci 0x100); 29098c2ecf20Sopenharmony_ci } 29108c2ecf20Sopenharmony_ci } 29118c2ecf20Sopenharmony_ci return rc; 29128c2ecf20Sopenharmony_ci} 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ciint qed_pglueb_set_pfid_enable(struct qed_hwfn *p_hwfn, 29158c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, bool b_enable) 29168c2ecf20Sopenharmony_ci{ 29178c2ecf20Sopenharmony_ci u32 delay_idx = 0, val, set_val = b_enable ? 1 : 0; 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci /* Configure the PF's internal FID_enable for master transactions */ 29208c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, set_val); 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci /* Wait until value is set - try for 1 second every 50us */ 29238c2ecf20Sopenharmony_ci for (delay_idx = 0; delay_idx < 20000; delay_idx++) { 29248c2ecf20Sopenharmony_ci val = qed_rd(p_hwfn, p_ptt, 29258c2ecf20Sopenharmony_ci PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER); 29268c2ecf20Sopenharmony_ci if (val == set_val) 29278c2ecf20Sopenharmony_ci break; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci usleep_range(50, 60); 29308c2ecf20Sopenharmony_ci } 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci if (val != set_val) { 29338c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 29348c2ecf20Sopenharmony_ci "PFID_ENABLE_MASTER wasn't changed after a second\n"); 29358c2ecf20Sopenharmony_ci return -EAGAIN; 29368c2ecf20Sopenharmony_ci } 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci return 0; 29398c2ecf20Sopenharmony_ci} 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_cistatic void qed_reset_mb_shadow(struct qed_hwfn *p_hwfn, 29428c2ecf20Sopenharmony_ci struct qed_ptt *p_main_ptt) 29438c2ecf20Sopenharmony_ci{ 29448c2ecf20Sopenharmony_ci /* Read shadow of current MFW mailbox */ 29458c2ecf20Sopenharmony_ci qed_mcp_read_mb(p_hwfn, p_main_ptt); 29468c2ecf20Sopenharmony_ci memcpy(p_hwfn->mcp_info->mfw_mb_shadow, 29478c2ecf20Sopenharmony_ci p_hwfn->mcp_info->mfw_mb_cur, p_hwfn->mcp_info->mfw_mb_length); 29488c2ecf20Sopenharmony_ci} 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_cistatic void 29518c2ecf20Sopenharmony_ciqed_fill_load_req_params(struct qed_load_req_params *p_load_req, 29528c2ecf20Sopenharmony_ci struct qed_drv_load_params *p_drv_load) 29538c2ecf20Sopenharmony_ci{ 29548c2ecf20Sopenharmony_ci memset(p_load_req, 0, sizeof(*p_load_req)); 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci p_load_req->drv_role = p_drv_load->is_crash_kernel ? 29578c2ecf20Sopenharmony_ci QED_DRV_ROLE_KDUMP : QED_DRV_ROLE_OS; 29588c2ecf20Sopenharmony_ci p_load_req->timeout_val = p_drv_load->mfw_timeout_val; 29598c2ecf20Sopenharmony_ci p_load_req->avoid_eng_reset = p_drv_load->avoid_eng_reset; 29608c2ecf20Sopenharmony_ci p_load_req->override_force_load = p_drv_load->override_force_load; 29618c2ecf20Sopenharmony_ci} 29628c2ecf20Sopenharmony_ci 29638c2ecf20Sopenharmony_cistatic int qed_vf_start(struct qed_hwfn *p_hwfn, 29648c2ecf20Sopenharmony_ci struct qed_hw_init_params *p_params) 29658c2ecf20Sopenharmony_ci{ 29668c2ecf20Sopenharmony_ci if (p_params->p_tunn) { 29678c2ecf20Sopenharmony_ci qed_vf_set_vf_start_tunn_update_param(p_params->p_tunn); 29688c2ecf20Sopenharmony_ci qed_vf_pf_tunnel_param_update(p_hwfn, p_params->p_tunn); 29698c2ecf20Sopenharmony_ci } 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci p_hwfn->b_int_enabled = true; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci return 0; 29748c2ecf20Sopenharmony_ci} 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_cistatic void qed_pglueb_clear_err(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 29778c2ecf20Sopenharmony_ci{ 29788c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR, 29798c2ecf20Sopenharmony_ci BIT(p_hwfn->abs_pf_id)); 29808c2ecf20Sopenharmony_ci} 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ciint qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) 29838c2ecf20Sopenharmony_ci{ 29848c2ecf20Sopenharmony_ci struct qed_load_req_params load_req_params; 29858c2ecf20Sopenharmony_ci u32 load_code, resp, param, drv_mb_param; 29868c2ecf20Sopenharmony_ci bool b_default_mtu = true; 29878c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn; 29888c2ecf20Sopenharmony_ci const u32 *fw_overlays; 29898c2ecf20Sopenharmony_ci u32 fw_overlays_len; 29908c2ecf20Sopenharmony_ci u16 ether_type; 29918c2ecf20Sopenharmony_ci int rc = 0, i; 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci if ((p_params->int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { 29948c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n"); 29958c2ecf20Sopenharmony_ci return -EINVAL; 29968c2ecf20Sopenharmony_ci } 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 29998c2ecf20Sopenharmony_ci rc = qed_init_fw_data(cdev, p_params->bin_fw_data); 30008c2ecf20Sopenharmony_ci if (rc) 30018c2ecf20Sopenharmony_ci return rc; 30028c2ecf20Sopenharmony_ci } 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 30058c2ecf20Sopenharmony_ci p_hwfn = &cdev->hwfns[i]; 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_ci /* If management didn't provide a default, set one of our own */ 30088c2ecf20Sopenharmony_ci if (!p_hwfn->hw_info.mtu) { 30098c2ecf20Sopenharmony_ci p_hwfn->hw_info.mtu = 1500; 30108c2ecf20Sopenharmony_ci b_default_mtu = false; 30118c2ecf20Sopenharmony_ci } 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci if (IS_VF(cdev)) { 30148c2ecf20Sopenharmony_ci qed_vf_start(p_hwfn, p_params); 30158c2ecf20Sopenharmony_ci continue; 30168c2ecf20Sopenharmony_ci } 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci rc = qed_calc_hw_mode(p_hwfn); 30198c2ecf20Sopenharmony_ci if (rc) 30208c2ecf20Sopenharmony_ci return rc; 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci if (IS_PF(cdev) && (test_bit(QED_MF_8021Q_TAGGING, 30238c2ecf20Sopenharmony_ci &cdev->mf_bits) || 30248c2ecf20Sopenharmony_ci test_bit(QED_MF_8021AD_TAGGING, 30258c2ecf20Sopenharmony_ci &cdev->mf_bits))) { 30268c2ecf20Sopenharmony_ci if (test_bit(QED_MF_8021Q_TAGGING, &cdev->mf_bits)) 30278c2ecf20Sopenharmony_ci ether_type = ETH_P_8021Q; 30288c2ecf20Sopenharmony_ci else 30298c2ecf20Sopenharmony_ci ether_type = ETH_P_8021AD; 30308c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, PRS_REG_TAG_ETHERTYPE_0_RT_OFFSET, 30318c2ecf20Sopenharmony_ci ether_type); 30328c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, NIG_REG_TAG_ETHERTYPE_0_RT_OFFSET, 30338c2ecf20Sopenharmony_ci ether_type); 30348c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, PBF_REG_TAG_ETHERTYPE_0_RT_OFFSET, 30358c2ecf20Sopenharmony_ci ether_type); 30368c2ecf20Sopenharmony_ci STORE_RT_REG(p_hwfn, DORQ_REG_TAG1_ETHERTYPE_RT_OFFSET, 30378c2ecf20Sopenharmony_ci ether_type); 30388c2ecf20Sopenharmony_ci } 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ci qed_fill_load_req_params(&load_req_params, 30418c2ecf20Sopenharmony_ci p_params->p_drv_load_params); 30428c2ecf20Sopenharmony_ci rc = qed_mcp_load_req(p_hwfn, p_hwfn->p_main_ptt, 30438c2ecf20Sopenharmony_ci &load_req_params); 30448c2ecf20Sopenharmony_ci if (rc) { 30458c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed sending a LOAD_REQ command\n"); 30468c2ecf20Sopenharmony_ci return rc; 30478c2ecf20Sopenharmony_ci } 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci load_code = load_req_params.load_code; 30508c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 30518c2ecf20Sopenharmony_ci "Load request was sent. Load code: 0x%x\n", 30528c2ecf20Sopenharmony_ci load_code); 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci /* Only relevant for recovery: 30558c2ecf20Sopenharmony_ci * Clear the indication after LOAD_REQ is responded by the MFW. 30568c2ecf20Sopenharmony_ci */ 30578c2ecf20Sopenharmony_ci cdev->recov_in_prog = false; 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci qed_mcp_set_capabilities(p_hwfn, p_hwfn->p_main_ptt); 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci qed_reset_mb_shadow(p_hwfn, p_hwfn->p_main_ptt); 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci /* Clean up chip from previous driver if such remains exist. 30648c2ecf20Sopenharmony_ci * This is not needed when the PF is the first one on the 30658c2ecf20Sopenharmony_ci * engine, since afterwards we are going to init the FW. 30668c2ecf20Sopenharmony_ci */ 30678c2ecf20Sopenharmony_ci if (load_code != FW_MSG_CODE_DRV_LOAD_ENGINE) { 30688c2ecf20Sopenharmony_ci rc = qed_final_cleanup(p_hwfn, p_hwfn->p_main_ptt, 30698c2ecf20Sopenharmony_ci p_hwfn->rel_pf_id, false); 30708c2ecf20Sopenharmony_ci if (rc) { 30718c2ecf20Sopenharmony_ci qed_hw_err_notify(p_hwfn, p_hwfn->p_main_ptt, 30728c2ecf20Sopenharmony_ci QED_HW_ERR_RAMROD_FAIL, 30738c2ecf20Sopenharmony_ci "Final cleanup failed\n"); 30748c2ecf20Sopenharmony_ci goto load_err; 30758c2ecf20Sopenharmony_ci } 30768c2ecf20Sopenharmony_ci } 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci /* Log and clear previous pglue_b errors if such exist */ 30798c2ecf20Sopenharmony_ci qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_main_ptt, true); 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci /* Enable the PF's internal FID_enable in the PXP */ 30828c2ecf20Sopenharmony_ci rc = qed_pglueb_set_pfid_enable(p_hwfn, p_hwfn->p_main_ptt, 30838c2ecf20Sopenharmony_ci true); 30848c2ecf20Sopenharmony_ci if (rc) 30858c2ecf20Sopenharmony_ci goto load_err; 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci /* Clear the pglue_b was_error indication. 30888c2ecf20Sopenharmony_ci * In E4 it must be done after the BME and the internal 30898c2ecf20Sopenharmony_ci * FID_enable for the PF are set, since VDMs may cause the 30908c2ecf20Sopenharmony_ci * indication to be set again. 30918c2ecf20Sopenharmony_ci */ 30928c2ecf20Sopenharmony_ci qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt); 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci fw_overlays = cdev->fw_data->fw_overlays; 30958c2ecf20Sopenharmony_ci fw_overlays_len = cdev->fw_data->fw_overlays_len; 30968c2ecf20Sopenharmony_ci p_hwfn->fw_overlay_mem = 30978c2ecf20Sopenharmony_ci qed_fw_overlay_mem_alloc(p_hwfn, fw_overlays, 30988c2ecf20Sopenharmony_ci fw_overlays_len); 30998c2ecf20Sopenharmony_ci if (!p_hwfn->fw_overlay_mem) { 31008c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 31018c2ecf20Sopenharmony_ci "Failed to allocate fw overlay memory\n"); 31028c2ecf20Sopenharmony_ci rc = -ENOMEM; 31038c2ecf20Sopenharmony_ci goto load_err; 31048c2ecf20Sopenharmony_ci } 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci switch (load_code) { 31078c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_LOAD_ENGINE: 31088c2ecf20Sopenharmony_ci rc = qed_hw_init_common(p_hwfn, p_hwfn->p_main_ptt, 31098c2ecf20Sopenharmony_ci p_hwfn->hw_info.hw_mode); 31108c2ecf20Sopenharmony_ci if (rc) 31118c2ecf20Sopenharmony_ci break; 31128c2ecf20Sopenharmony_ci fallthrough; 31138c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_LOAD_PORT: 31148c2ecf20Sopenharmony_ci rc = qed_hw_init_port(p_hwfn, p_hwfn->p_main_ptt, 31158c2ecf20Sopenharmony_ci p_hwfn->hw_info.hw_mode); 31168c2ecf20Sopenharmony_ci if (rc) 31178c2ecf20Sopenharmony_ci break; 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci fallthrough; 31208c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_LOAD_FUNCTION: 31218c2ecf20Sopenharmony_ci rc = qed_hw_init_pf(p_hwfn, p_hwfn->p_main_ptt, 31228c2ecf20Sopenharmony_ci p_params->p_tunn, 31238c2ecf20Sopenharmony_ci p_hwfn->hw_info.hw_mode, 31248c2ecf20Sopenharmony_ci p_params->b_hw_start, 31258c2ecf20Sopenharmony_ci p_params->int_mode, 31268c2ecf20Sopenharmony_ci p_params->allow_npar_tx_switch); 31278c2ecf20Sopenharmony_ci break; 31288c2ecf20Sopenharmony_ci default: 31298c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 31308c2ecf20Sopenharmony_ci "Unexpected load code [0x%08x]", load_code); 31318c2ecf20Sopenharmony_ci rc = -EINVAL; 31328c2ecf20Sopenharmony_ci break; 31338c2ecf20Sopenharmony_ci } 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci if (rc) { 31368c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 31378c2ecf20Sopenharmony_ci "init phase failed for loadcode 0x%x (rc %d)\n", 31388c2ecf20Sopenharmony_ci load_code, rc); 31398c2ecf20Sopenharmony_ci goto load_err; 31408c2ecf20Sopenharmony_ci } 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci rc = qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt); 31438c2ecf20Sopenharmony_ci if (rc) 31448c2ecf20Sopenharmony_ci return rc; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci /* send DCBX attention request command */ 31478c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 31488c2ecf20Sopenharmony_ci QED_MSG_DCB, 31498c2ecf20Sopenharmony_ci "sending phony dcbx set command to trigger DCBx attention handling\n"); 31508c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, 31518c2ecf20Sopenharmony_ci DRV_MSG_CODE_SET_DCBX, 31528c2ecf20Sopenharmony_ci 1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT, 31538c2ecf20Sopenharmony_ci &resp, ¶m); 31548c2ecf20Sopenharmony_ci if (rc) { 31558c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 31568c2ecf20Sopenharmony_ci "Failed to send DCBX attention request\n"); 31578c2ecf20Sopenharmony_ci return rc; 31588c2ecf20Sopenharmony_ci } 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_ci p_hwfn->hw_init_done = true; 31618c2ecf20Sopenharmony_ci } 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 31648c2ecf20Sopenharmony_ci p_hwfn = QED_LEADING_HWFN(cdev); 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci /* Get pre-negotiated values for stag, bandwidth etc. */ 31678c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 31688c2ecf20Sopenharmony_ci QED_MSG_SPQ, 31698c2ecf20Sopenharmony_ci "Sending GET_OEM_UPDATES command to trigger stag/bandwidth attention handling\n"); 31708c2ecf20Sopenharmony_ci drv_mb_param = 1 << DRV_MB_PARAM_DUMMY_OEM_UPDATES_OFFSET; 31718c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, 31728c2ecf20Sopenharmony_ci DRV_MSG_CODE_GET_OEM_UPDATES, 31738c2ecf20Sopenharmony_ci drv_mb_param, &resp, ¶m); 31748c2ecf20Sopenharmony_ci if (rc) 31758c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 31768c2ecf20Sopenharmony_ci "Failed to send GET_OEM_UPDATES attention request\n"); 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci drv_mb_param = STORM_FW_VERSION; 31798c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, 31808c2ecf20Sopenharmony_ci DRV_MSG_CODE_OV_UPDATE_STORM_FW_VER, 31818c2ecf20Sopenharmony_ci drv_mb_param, &load_code, ¶m); 31828c2ecf20Sopenharmony_ci if (rc) 31838c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Failed to update firmware version\n"); 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_ci if (!b_default_mtu) { 31868c2ecf20Sopenharmony_ci rc = qed_mcp_ov_update_mtu(p_hwfn, p_hwfn->p_main_ptt, 31878c2ecf20Sopenharmony_ci p_hwfn->hw_info.mtu); 31888c2ecf20Sopenharmony_ci if (rc) 31898c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 31908c2ecf20Sopenharmony_ci "Failed to update default mtu\n"); 31918c2ecf20Sopenharmony_ci } 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci rc = qed_mcp_ov_update_driver_state(p_hwfn, 31948c2ecf20Sopenharmony_ci p_hwfn->p_main_ptt, 31958c2ecf20Sopenharmony_ci QED_OV_DRIVER_STATE_DISABLED); 31968c2ecf20Sopenharmony_ci if (rc) 31978c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Failed to update driver state\n"); 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci rc = qed_mcp_ov_update_eswitch(p_hwfn, p_hwfn->p_main_ptt, 32008c2ecf20Sopenharmony_ci QED_OV_ESWITCH_NONE); 32018c2ecf20Sopenharmony_ci if (rc) 32028c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Failed to update eswitch mode\n"); 32038c2ecf20Sopenharmony_ci } 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci return 0; 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ciload_err: 32088c2ecf20Sopenharmony_ci /* The MFW load lock should be released also when initialization fails. 32098c2ecf20Sopenharmony_ci */ 32108c2ecf20Sopenharmony_ci qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt); 32118c2ecf20Sopenharmony_ci return rc; 32128c2ecf20Sopenharmony_ci} 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci#define QED_HW_STOP_RETRY_LIMIT (10) 32158c2ecf20Sopenharmony_cistatic void qed_hw_timers_stop(struct qed_dev *cdev, 32168c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 32178c2ecf20Sopenharmony_ci{ 32188c2ecf20Sopenharmony_ci int i; 32198c2ecf20Sopenharmony_ci 32208c2ecf20Sopenharmony_ci /* close timers */ 32218c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0); 32228c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0); 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci if (cdev->recov_in_prog) 32258c2ecf20Sopenharmony_ci return; 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) { 32288c2ecf20Sopenharmony_ci if ((!qed_rd(p_hwfn, p_ptt, 32298c2ecf20Sopenharmony_ci TM_REG_PF_SCAN_ACTIVE_CONN)) && 32308c2ecf20Sopenharmony_ci (!qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_TASK))) 32318c2ecf20Sopenharmony_ci break; 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci /* Dependent on number of connection/tasks, possibly 32348c2ecf20Sopenharmony_ci * 1ms sleep is required between polls 32358c2ecf20Sopenharmony_ci */ 32368c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 32378c2ecf20Sopenharmony_ci } 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci if (i < QED_HW_STOP_RETRY_LIMIT) 32408c2ecf20Sopenharmony_ci return; 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 32438c2ecf20Sopenharmony_ci "Timers linear scans are not over [Connection %02x Tasks %02x]\n", 32448c2ecf20Sopenharmony_ci (u8)qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_CONN), 32458c2ecf20Sopenharmony_ci (u8)qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_TASK)); 32468c2ecf20Sopenharmony_ci} 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_civoid qed_hw_timers_stop_all(struct qed_dev *cdev) 32498c2ecf20Sopenharmony_ci{ 32508c2ecf20Sopenharmony_ci int j; 32518c2ecf20Sopenharmony_ci 32528c2ecf20Sopenharmony_ci for_each_hwfn(cdev, j) { 32538c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[j]; 32548c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt = p_hwfn->p_main_ptt; 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_ci qed_hw_timers_stop(cdev, p_hwfn, p_ptt); 32578c2ecf20Sopenharmony_ci } 32588c2ecf20Sopenharmony_ci} 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ciint qed_hw_stop(struct qed_dev *cdev) 32618c2ecf20Sopenharmony_ci{ 32628c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn; 32638c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 32648c2ecf20Sopenharmony_ci int rc, rc2 = 0; 32658c2ecf20Sopenharmony_ci int j; 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_ci for_each_hwfn(cdev, j) { 32688c2ecf20Sopenharmony_ci p_hwfn = &cdev->hwfns[j]; 32698c2ecf20Sopenharmony_ci p_ptt = p_hwfn->p_main_ptt; 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_IFDOWN, "Stopping hw/fw\n"); 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci if (IS_VF(cdev)) { 32748c2ecf20Sopenharmony_ci qed_vf_pf_int_cleanup(p_hwfn); 32758c2ecf20Sopenharmony_ci rc = qed_vf_pf_reset(p_hwfn); 32768c2ecf20Sopenharmony_ci if (rc) { 32778c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 32788c2ecf20Sopenharmony_ci "qed_vf_pf_reset failed. rc = %d.\n", 32798c2ecf20Sopenharmony_ci rc); 32808c2ecf20Sopenharmony_ci rc2 = -EINVAL; 32818c2ecf20Sopenharmony_ci } 32828c2ecf20Sopenharmony_ci continue; 32838c2ecf20Sopenharmony_ci } 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_ci /* mark the hw as uninitialized... */ 32868c2ecf20Sopenharmony_ci p_hwfn->hw_init_done = false; 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci /* Send unload command to MCP */ 32898c2ecf20Sopenharmony_ci if (!cdev->recov_in_prog) { 32908c2ecf20Sopenharmony_ci rc = qed_mcp_unload_req(p_hwfn, p_ptt); 32918c2ecf20Sopenharmony_ci if (rc) { 32928c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 32938c2ecf20Sopenharmony_ci "Failed sending a UNLOAD_REQ command. rc = %d.\n", 32948c2ecf20Sopenharmony_ci rc); 32958c2ecf20Sopenharmony_ci rc2 = -EINVAL; 32968c2ecf20Sopenharmony_ci } 32978c2ecf20Sopenharmony_ci } 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci qed_slowpath_irq_sync(p_hwfn); 33008c2ecf20Sopenharmony_ci 33018c2ecf20Sopenharmony_ci /* After this point no MFW attentions are expected, e.g. prevent 33028c2ecf20Sopenharmony_ci * race between pf stop and dcbx pf update. 33038c2ecf20Sopenharmony_ci */ 33048c2ecf20Sopenharmony_ci rc = qed_sp_pf_stop(p_hwfn); 33058c2ecf20Sopenharmony_ci if (rc) { 33068c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 33078c2ecf20Sopenharmony_ci "Failed to close PF against FW [rc = %d]. Continue to stop HW to prevent illegal host access by the device.\n", 33088c2ecf20Sopenharmony_ci rc); 33098c2ecf20Sopenharmony_ci rc2 = -EINVAL; 33108c2ecf20Sopenharmony_ci } 33118c2ecf20Sopenharmony_ci 33128c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, 33138c2ecf20Sopenharmony_ci NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x1); 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0); 33168c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_UDP, 0x0); 33178c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_FCOE, 0x0); 33188c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0); 33198c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0); 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci qed_hw_timers_stop(cdev, p_hwfn, p_ptt); 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci /* Disable Attention Generation */ 33248c2ecf20Sopenharmony_ci qed_int_igu_disable_int(p_hwfn, p_ptt); 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, IGU_REG_LEADING_EDGE_LATCH, 0); 33278c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, IGU_REG_TRAILING_EDGE_LATCH, 0); 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci qed_int_igu_init_pure_rt(p_hwfn, p_ptt, false, true); 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci /* Need to wait 1ms to guarantee SBs are cleared */ 33328c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci /* Disable PF in HW blocks */ 33358c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DB_ENABLE, 0); 33368c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, QM_REG_PF_EN, 0); 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn) && 33398c2ecf20Sopenharmony_ci test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits) && 33408c2ecf20Sopenharmony_ci !QED_IS_FCOE_PERSONALITY(p_hwfn)) 33418c2ecf20Sopenharmony_ci qed_llh_remove_mac_filter(cdev, 0, 33428c2ecf20Sopenharmony_ci p_hwfn->hw_info.hw_mac_addr); 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci if (!cdev->recov_in_prog) { 33458c2ecf20Sopenharmony_ci rc = qed_mcp_unload_done(p_hwfn, p_ptt); 33468c2ecf20Sopenharmony_ci if (rc) { 33478c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 33488c2ecf20Sopenharmony_ci "Failed sending a UNLOAD_DONE command. rc = %d.\n", 33498c2ecf20Sopenharmony_ci rc); 33508c2ecf20Sopenharmony_ci rc2 = -EINVAL; 33518c2ecf20Sopenharmony_ci } 33528c2ecf20Sopenharmony_ci } 33538c2ecf20Sopenharmony_ci } 33548c2ecf20Sopenharmony_ci 33558c2ecf20Sopenharmony_ci if (IS_PF(cdev) && !cdev->recov_in_prog) { 33568c2ecf20Sopenharmony_ci p_hwfn = QED_LEADING_HWFN(cdev); 33578c2ecf20Sopenharmony_ci p_ptt = QED_LEADING_HWFN(cdev)->p_main_ptt; 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci /* Clear the PF's internal FID_enable in the PXP. 33608c2ecf20Sopenharmony_ci * In CMT this should only be done for first hw-function, and 33618c2ecf20Sopenharmony_ci * only after all transactions have stopped for all active 33628c2ecf20Sopenharmony_ci * hw-functions. 33638c2ecf20Sopenharmony_ci */ 33648c2ecf20Sopenharmony_ci rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false); 33658c2ecf20Sopenharmony_ci if (rc) { 33668c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 33678c2ecf20Sopenharmony_ci "qed_pglueb_set_pfid_enable() failed. rc = %d.\n", 33688c2ecf20Sopenharmony_ci rc); 33698c2ecf20Sopenharmony_ci rc2 = -EINVAL; 33708c2ecf20Sopenharmony_ci } 33718c2ecf20Sopenharmony_ci } 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci return rc2; 33748c2ecf20Sopenharmony_ci} 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ciint qed_hw_stop_fastpath(struct qed_dev *cdev) 33778c2ecf20Sopenharmony_ci{ 33788c2ecf20Sopenharmony_ci int j; 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ci for_each_hwfn(cdev, j) { 33818c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[j]; 33828c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 33838c2ecf20Sopenharmony_ci 33848c2ecf20Sopenharmony_ci if (IS_VF(cdev)) { 33858c2ecf20Sopenharmony_ci qed_vf_pf_int_cleanup(p_hwfn); 33868c2ecf20Sopenharmony_ci continue; 33878c2ecf20Sopenharmony_ci } 33888c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 33898c2ecf20Sopenharmony_ci if (!p_ptt) 33908c2ecf20Sopenharmony_ci return -EAGAIN; 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 33938c2ecf20Sopenharmony_ci NETIF_MSG_IFDOWN, "Shutting down the fastpath\n"); 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, 33968c2ecf20Sopenharmony_ci NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x1); 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TCP, 0x0); 33998c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_UDP, 0x0); 34008c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_FCOE, 0x0); 34018c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0); 34028c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0); 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ci qed_int_igu_init_pure_rt(p_hwfn, p_ptt, false, false); 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ci /* Need to wait 1ms to guarantee SBs are cleared */ 34078c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 34088c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 34098c2ecf20Sopenharmony_ci } 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ci return 0; 34128c2ecf20Sopenharmony_ci} 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ciint qed_hw_start_fastpath(struct qed_hwfn *p_hwfn) 34158c2ecf20Sopenharmony_ci{ 34168c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 34198c2ecf20Sopenharmony_ci return 0; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 34228c2ecf20Sopenharmony_ci if (!p_ptt) 34238c2ecf20Sopenharmony_ci return -EAGAIN; 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ci if (p_hwfn->p_rdma_info && 34268c2ecf20Sopenharmony_ci p_hwfn->p_rdma_info->active && p_hwfn->b_rdma_enabled_in_prs) 34278c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, p_hwfn->rdma_prs_search_reg, 0x1); 34288c2ecf20Sopenharmony_ci 34298c2ecf20Sopenharmony_ci /* Re-open incoming traffic */ 34308c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x0); 34318c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci return 0; 34348c2ecf20Sopenharmony_ci} 34358c2ecf20Sopenharmony_ci 34368c2ecf20Sopenharmony_ci/* Free hwfn memory and resources acquired in hw_hwfn_prepare */ 34378c2ecf20Sopenharmony_cistatic void qed_hw_hwfn_free(struct qed_hwfn *p_hwfn) 34388c2ecf20Sopenharmony_ci{ 34398c2ecf20Sopenharmony_ci qed_ptt_pool_free(p_hwfn); 34408c2ecf20Sopenharmony_ci kfree(p_hwfn->hw_info.p_igu_info); 34418c2ecf20Sopenharmony_ci p_hwfn->hw_info.p_igu_info = NULL; 34428c2ecf20Sopenharmony_ci} 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ci/* Setup bar access */ 34458c2ecf20Sopenharmony_cistatic void qed_hw_hwfn_prepare(struct qed_hwfn *p_hwfn) 34468c2ecf20Sopenharmony_ci{ 34478c2ecf20Sopenharmony_ci /* clear indirect access */ 34488c2ecf20Sopenharmony_ci if (QED_IS_AH(p_hwfn->cdev)) { 34498c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_hwfn->p_main_ptt, 34508c2ecf20Sopenharmony_ci PGLUE_B_REG_PGL_ADDR_E8_F0_K2, 0); 34518c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_hwfn->p_main_ptt, 34528c2ecf20Sopenharmony_ci PGLUE_B_REG_PGL_ADDR_EC_F0_K2, 0); 34538c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_hwfn->p_main_ptt, 34548c2ecf20Sopenharmony_ci PGLUE_B_REG_PGL_ADDR_F0_F0_K2, 0); 34558c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_hwfn->p_main_ptt, 34568c2ecf20Sopenharmony_ci PGLUE_B_REG_PGL_ADDR_F4_F0_K2, 0); 34578c2ecf20Sopenharmony_ci } else { 34588c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_hwfn->p_main_ptt, 34598c2ecf20Sopenharmony_ci PGLUE_B_REG_PGL_ADDR_88_F0_BB, 0); 34608c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_hwfn->p_main_ptt, 34618c2ecf20Sopenharmony_ci PGLUE_B_REG_PGL_ADDR_8C_F0_BB, 0); 34628c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_hwfn->p_main_ptt, 34638c2ecf20Sopenharmony_ci PGLUE_B_REG_PGL_ADDR_90_F0_BB, 0); 34648c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_hwfn->p_main_ptt, 34658c2ecf20Sopenharmony_ci PGLUE_B_REG_PGL_ADDR_94_F0_BB, 0); 34668c2ecf20Sopenharmony_ci } 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci /* Clean previous pglue_b errors if such exist */ 34698c2ecf20Sopenharmony_ci qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt); 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci /* enable internal target-read */ 34728c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_hwfn->p_main_ptt, 34738c2ecf20Sopenharmony_ci PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1); 34748c2ecf20Sopenharmony_ci} 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_cistatic void get_function_id(struct qed_hwfn *p_hwfn) 34778c2ecf20Sopenharmony_ci{ 34788c2ecf20Sopenharmony_ci /* ME Register */ 34798c2ecf20Sopenharmony_ci p_hwfn->hw_info.opaque_fid = (u16) REG_RD(p_hwfn, 34808c2ecf20Sopenharmony_ci PXP_PF_ME_OPAQUE_ADDR); 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_ci p_hwfn->hw_info.concrete_fid = REG_RD(p_hwfn, PXP_PF_ME_CONCRETE_ADDR); 34838c2ecf20Sopenharmony_ci 34848c2ecf20Sopenharmony_ci p_hwfn->abs_pf_id = (p_hwfn->hw_info.concrete_fid >> 16) & 0xf; 34858c2ecf20Sopenharmony_ci p_hwfn->rel_pf_id = GET_FIELD(p_hwfn->hw_info.concrete_fid, 34868c2ecf20Sopenharmony_ci PXP_CONCRETE_FID_PFID); 34878c2ecf20Sopenharmony_ci p_hwfn->port_id = GET_FIELD(p_hwfn->hw_info.concrete_fid, 34888c2ecf20Sopenharmony_ci PXP_CONCRETE_FID_PORT); 34898c2ecf20Sopenharmony_ci 34908c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_PROBE, 34918c2ecf20Sopenharmony_ci "Read ME register: Concrete 0x%08x Opaque 0x%04x\n", 34928c2ecf20Sopenharmony_ci p_hwfn->hw_info.concrete_fid, p_hwfn->hw_info.opaque_fid); 34938c2ecf20Sopenharmony_ci} 34948c2ecf20Sopenharmony_ci 34958c2ecf20Sopenharmony_cistatic void qed_hw_set_feat(struct qed_hwfn *p_hwfn) 34968c2ecf20Sopenharmony_ci{ 34978c2ecf20Sopenharmony_ci u32 *feat_num = p_hwfn->hw_info.feat_num; 34988c2ecf20Sopenharmony_ci struct qed_sb_cnt_info sb_cnt; 34998c2ecf20Sopenharmony_ci u32 non_l2_sbs = 0; 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci memset(&sb_cnt, 0, sizeof(sb_cnt)); 35028c2ecf20Sopenharmony_ci qed_int_get_num_sbs(p_hwfn, &sb_cnt); 35038c2ecf20Sopenharmony_ci 35048c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_QED_RDMA) && 35058c2ecf20Sopenharmony_ci QED_IS_RDMA_PERSONALITY(p_hwfn)) { 35068c2ecf20Sopenharmony_ci /* Roce CNQ each requires: 1 status block + 1 CNQ. We divide 35078c2ecf20Sopenharmony_ci * the status blocks equally between L2 / RoCE but with 35088c2ecf20Sopenharmony_ci * consideration as to how many l2 queues / cnqs we have. 35098c2ecf20Sopenharmony_ci */ 35108c2ecf20Sopenharmony_ci feat_num[QED_RDMA_CNQ] = 35118c2ecf20Sopenharmony_ci min_t(u32, sb_cnt.cnt / 2, 35128c2ecf20Sopenharmony_ci RESC_NUM(p_hwfn, QED_RDMA_CNQ_RAM)); 35138c2ecf20Sopenharmony_ci 35148c2ecf20Sopenharmony_ci non_l2_sbs = feat_num[QED_RDMA_CNQ]; 35158c2ecf20Sopenharmony_ci } 35168c2ecf20Sopenharmony_ci if (QED_IS_L2_PERSONALITY(p_hwfn)) { 35178c2ecf20Sopenharmony_ci /* Start by allocating VF queues, then PF's */ 35188c2ecf20Sopenharmony_ci feat_num[QED_VF_L2_QUE] = min_t(u32, 35198c2ecf20Sopenharmony_ci RESC_NUM(p_hwfn, QED_L2_QUEUE), 35208c2ecf20Sopenharmony_ci sb_cnt.iov_cnt); 35218c2ecf20Sopenharmony_ci feat_num[QED_PF_L2_QUE] = min_t(u32, 35228c2ecf20Sopenharmony_ci sb_cnt.cnt - non_l2_sbs, 35238c2ecf20Sopenharmony_ci RESC_NUM(p_hwfn, 35248c2ecf20Sopenharmony_ci QED_L2_QUEUE) - 35258c2ecf20Sopenharmony_ci FEAT_NUM(p_hwfn, 35268c2ecf20Sopenharmony_ci QED_VF_L2_QUE)); 35278c2ecf20Sopenharmony_ci } 35288c2ecf20Sopenharmony_ci 35298c2ecf20Sopenharmony_ci if (QED_IS_FCOE_PERSONALITY(p_hwfn)) 35308c2ecf20Sopenharmony_ci feat_num[QED_FCOE_CQ] = min_t(u32, sb_cnt.cnt, 35318c2ecf20Sopenharmony_ci RESC_NUM(p_hwfn, 35328c2ecf20Sopenharmony_ci QED_CMDQS_CQS)); 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci if (QED_IS_ISCSI_PERSONALITY(p_hwfn)) 35358c2ecf20Sopenharmony_ci feat_num[QED_ISCSI_CQ] = min_t(u32, sb_cnt.cnt, 35368c2ecf20Sopenharmony_ci RESC_NUM(p_hwfn, 35378c2ecf20Sopenharmony_ci QED_CMDQS_CQS)); 35388c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 35398c2ecf20Sopenharmony_ci NETIF_MSG_PROBE, 35408c2ecf20Sopenharmony_ci "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d FCOE_CQ=%d ISCSI_CQ=%d #SBS=%d\n", 35418c2ecf20Sopenharmony_ci (int)FEAT_NUM(p_hwfn, QED_PF_L2_QUE), 35428c2ecf20Sopenharmony_ci (int)FEAT_NUM(p_hwfn, QED_VF_L2_QUE), 35438c2ecf20Sopenharmony_ci (int)FEAT_NUM(p_hwfn, QED_RDMA_CNQ), 35448c2ecf20Sopenharmony_ci (int)FEAT_NUM(p_hwfn, QED_FCOE_CQ), 35458c2ecf20Sopenharmony_ci (int)FEAT_NUM(p_hwfn, QED_ISCSI_CQ), 35468c2ecf20Sopenharmony_ci (int)sb_cnt.cnt); 35478c2ecf20Sopenharmony_ci} 35488c2ecf20Sopenharmony_ci 35498c2ecf20Sopenharmony_ciconst char *qed_hw_get_resc_name(enum qed_resources res_id) 35508c2ecf20Sopenharmony_ci{ 35518c2ecf20Sopenharmony_ci switch (res_id) { 35528c2ecf20Sopenharmony_ci case QED_L2_QUEUE: 35538c2ecf20Sopenharmony_ci return "L2_QUEUE"; 35548c2ecf20Sopenharmony_ci case QED_VPORT: 35558c2ecf20Sopenharmony_ci return "VPORT"; 35568c2ecf20Sopenharmony_ci case QED_RSS_ENG: 35578c2ecf20Sopenharmony_ci return "RSS_ENG"; 35588c2ecf20Sopenharmony_ci case QED_PQ: 35598c2ecf20Sopenharmony_ci return "PQ"; 35608c2ecf20Sopenharmony_ci case QED_RL: 35618c2ecf20Sopenharmony_ci return "RL"; 35628c2ecf20Sopenharmony_ci case QED_MAC: 35638c2ecf20Sopenharmony_ci return "MAC"; 35648c2ecf20Sopenharmony_ci case QED_VLAN: 35658c2ecf20Sopenharmony_ci return "VLAN"; 35668c2ecf20Sopenharmony_ci case QED_RDMA_CNQ_RAM: 35678c2ecf20Sopenharmony_ci return "RDMA_CNQ_RAM"; 35688c2ecf20Sopenharmony_ci case QED_ILT: 35698c2ecf20Sopenharmony_ci return "ILT"; 35708c2ecf20Sopenharmony_ci case QED_LL2_RAM_QUEUE: 35718c2ecf20Sopenharmony_ci return "LL2_RAM_QUEUE"; 35728c2ecf20Sopenharmony_ci case QED_LL2_CTX_QUEUE: 35738c2ecf20Sopenharmony_ci return "LL2_CTX_QUEUE"; 35748c2ecf20Sopenharmony_ci case QED_CMDQS_CQS: 35758c2ecf20Sopenharmony_ci return "CMDQS_CQS"; 35768c2ecf20Sopenharmony_ci case QED_RDMA_STATS_QUEUE: 35778c2ecf20Sopenharmony_ci return "RDMA_STATS_QUEUE"; 35788c2ecf20Sopenharmony_ci case QED_BDQ: 35798c2ecf20Sopenharmony_ci return "BDQ"; 35808c2ecf20Sopenharmony_ci case QED_SB: 35818c2ecf20Sopenharmony_ci return "SB"; 35828c2ecf20Sopenharmony_ci default: 35838c2ecf20Sopenharmony_ci return "UNKNOWN_RESOURCE"; 35848c2ecf20Sopenharmony_ci } 35858c2ecf20Sopenharmony_ci} 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_cistatic int 35888c2ecf20Sopenharmony_ci__qed_hw_set_soft_resc_size(struct qed_hwfn *p_hwfn, 35898c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 35908c2ecf20Sopenharmony_ci enum qed_resources res_id, 35918c2ecf20Sopenharmony_ci u32 resc_max_val, u32 *p_mcp_resp) 35928c2ecf20Sopenharmony_ci{ 35938c2ecf20Sopenharmony_ci int rc; 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci rc = qed_mcp_set_resc_max_val(p_hwfn, p_ptt, res_id, 35968c2ecf20Sopenharmony_ci resc_max_val, p_mcp_resp); 35978c2ecf20Sopenharmony_ci if (rc) { 35988c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 35998c2ecf20Sopenharmony_ci "MFW response failure for a max value setting of resource %d [%s]\n", 36008c2ecf20Sopenharmony_ci res_id, qed_hw_get_resc_name(res_id)); 36018c2ecf20Sopenharmony_ci return rc; 36028c2ecf20Sopenharmony_ci } 36038c2ecf20Sopenharmony_ci 36048c2ecf20Sopenharmony_ci if (*p_mcp_resp != FW_MSG_CODE_RESOURCE_ALLOC_OK) 36058c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 36068c2ecf20Sopenharmony_ci "Failed to set the max value of resource %d [%s]. mcp_resp = 0x%08x.\n", 36078c2ecf20Sopenharmony_ci res_id, qed_hw_get_resc_name(res_id), *p_mcp_resp); 36088c2ecf20Sopenharmony_ci 36098c2ecf20Sopenharmony_ci return 0; 36108c2ecf20Sopenharmony_ci} 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_cistatic u32 qed_hsi_def_val[][MAX_CHIP_IDS] = { 36138c2ecf20Sopenharmony_ci {MAX_NUM_VFS_BB, MAX_NUM_VFS_K2}, 36148c2ecf20Sopenharmony_ci {MAX_NUM_L2_QUEUES_BB, MAX_NUM_L2_QUEUES_K2}, 36158c2ecf20Sopenharmony_ci {MAX_NUM_PORTS_BB, MAX_NUM_PORTS_K2}, 36168c2ecf20Sopenharmony_ci {MAX_SB_PER_PATH_BB, MAX_SB_PER_PATH_K2,}, 36178c2ecf20Sopenharmony_ci {MAX_NUM_PFS_BB, MAX_NUM_PFS_K2}, 36188c2ecf20Sopenharmony_ci {MAX_NUM_VPORTS_BB, MAX_NUM_VPORTS_K2}, 36198c2ecf20Sopenharmony_ci {ETH_RSS_ENGINE_NUM_BB, ETH_RSS_ENGINE_NUM_K2}, 36208c2ecf20Sopenharmony_ci {MAX_QM_TX_QUEUES_BB, MAX_QM_TX_QUEUES_K2}, 36218c2ecf20Sopenharmony_ci {PXP_NUM_ILT_RECORDS_BB, PXP_NUM_ILT_RECORDS_K2}, 36228c2ecf20Sopenharmony_ci {RDMA_NUM_STATISTIC_COUNTERS_BB, RDMA_NUM_STATISTIC_COUNTERS_K2}, 36238c2ecf20Sopenharmony_ci {MAX_QM_GLOBAL_RLS, MAX_QM_GLOBAL_RLS}, 36248c2ecf20Sopenharmony_ci {PBF_MAX_CMD_LINES, PBF_MAX_CMD_LINES}, 36258c2ecf20Sopenharmony_ci {BTB_MAX_BLOCKS_BB, BTB_MAX_BLOCKS_K2}, 36268c2ecf20Sopenharmony_ci}; 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_ciu32 qed_get_hsi_def_val(struct qed_dev *cdev, enum qed_hsi_def_type type) 36298c2ecf20Sopenharmony_ci{ 36308c2ecf20Sopenharmony_ci enum chip_ids chip_id = QED_IS_BB(cdev) ? CHIP_BB : CHIP_K2; 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci if (type >= QED_NUM_HSI_DEFS) { 36338c2ecf20Sopenharmony_ci DP_ERR(cdev, "Unexpected HSI definition type [%d]\n", type); 36348c2ecf20Sopenharmony_ci return 0; 36358c2ecf20Sopenharmony_ci } 36368c2ecf20Sopenharmony_ci 36378c2ecf20Sopenharmony_ci return qed_hsi_def_val[type][chip_id]; 36388c2ecf20Sopenharmony_ci} 36398c2ecf20Sopenharmony_cistatic int 36408c2ecf20Sopenharmony_ciqed_hw_set_soft_resc_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 36418c2ecf20Sopenharmony_ci{ 36428c2ecf20Sopenharmony_ci u32 resc_max_val, mcp_resp; 36438c2ecf20Sopenharmony_ci u8 res_id; 36448c2ecf20Sopenharmony_ci int rc; 36458c2ecf20Sopenharmony_ci for (res_id = 0; res_id < QED_MAX_RESC; res_id++) { 36468c2ecf20Sopenharmony_ci switch (res_id) { 36478c2ecf20Sopenharmony_ci case QED_LL2_RAM_QUEUE: 36488c2ecf20Sopenharmony_ci resc_max_val = MAX_NUM_LL2_RX_RAM_QUEUES; 36498c2ecf20Sopenharmony_ci break; 36508c2ecf20Sopenharmony_ci case QED_LL2_CTX_QUEUE: 36518c2ecf20Sopenharmony_ci resc_max_val = MAX_NUM_LL2_RX_CTX_QUEUES; 36528c2ecf20Sopenharmony_ci break; 36538c2ecf20Sopenharmony_ci case QED_RDMA_CNQ_RAM: 36548c2ecf20Sopenharmony_ci /* No need for a case for QED_CMDQS_CQS since 36558c2ecf20Sopenharmony_ci * CNQ/CMDQS are the same resource. 36568c2ecf20Sopenharmony_ci */ 36578c2ecf20Sopenharmony_ci resc_max_val = NUM_OF_GLOBAL_QUEUES; 36588c2ecf20Sopenharmony_ci break; 36598c2ecf20Sopenharmony_ci case QED_RDMA_STATS_QUEUE: 36608c2ecf20Sopenharmony_ci resc_max_val = 36618c2ecf20Sopenharmony_ci NUM_OF_RDMA_STATISTIC_COUNTERS(p_hwfn->cdev); 36628c2ecf20Sopenharmony_ci break; 36638c2ecf20Sopenharmony_ci case QED_BDQ: 36648c2ecf20Sopenharmony_ci resc_max_val = BDQ_NUM_RESOURCES; 36658c2ecf20Sopenharmony_ci break; 36668c2ecf20Sopenharmony_ci default: 36678c2ecf20Sopenharmony_ci continue; 36688c2ecf20Sopenharmony_ci } 36698c2ecf20Sopenharmony_ci 36708c2ecf20Sopenharmony_ci rc = __qed_hw_set_soft_resc_size(p_hwfn, p_ptt, res_id, 36718c2ecf20Sopenharmony_ci resc_max_val, &mcp_resp); 36728c2ecf20Sopenharmony_ci if (rc) 36738c2ecf20Sopenharmony_ci return rc; 36748c2ecf20Sopenharmony_ci 36758c2ecf20Sopenharmony_ci /* There's no point to continue to the next resource if the 36768c2ecf20Sopenharmony_ci * command is not supported by the MFW. 36778c2ecf20Sopenharmony_ci * We do continue if the command is supported but the resource 36788c2ecf20Sopenharmony_ci * is unknown to the MFW. Such a resource will be later 36798c2ecf20Sopenharmony_ci * configured with the default allocation values. 36808c2ecf20Sopenharmony_ci */ 36818c2ecf20Sopenharmony_ci if (mcp_resp == FW_MSG_CODE_UNSUPPORTED) 36828c2ecf20Sopenharmony_ci return -EINVAL; 36838c2ecf20Sopenharmony_ci } 36848c2ecf20Sopenharmony_ci 36858c2ecf20Sopenharmony_ci return 0; 36868c2ecf20Sopenharmony_ci} 36878c2ecf20Sopenharmony_ci 36888c2ecf20Sopenharmony_cistatic 36898c2ecf20Sopenharmony_ciint qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn, 36908c2ecf20Sopenharmony_ci enum qed_resources res_id, 36918c2ecf20Sopenharmony_ci u32 *p_resc_num, u32 *p_resc_start) 36928c2ecf20Sopenharmony_ci{ 36938c2ecf20Sopenharmony_ci u8 num_funcs = p_hwfn->num_funcs_on_engine; 36948c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 36958c2ecf20Sopenharmony_ci 36968c2ecf20Sopenharmony_ci switch (res_id) { 36978c2ecf20Sopenharmony_ci case QED_L2_QUEUE: 36988c2ecf20Sopenharmony_ci *p_resc_num = NUM_OF_L2_QUEUES(cdev) / num_funcs; 36998c2ecf20Sopenharmony_ci break; 37008c2ecf20Sopenharmony_ci case QED_VPORT: 37018c2ecf20Sopenharmony_ci *p_resc_num = NUM_OF_VPORTS(cdev) / num_funcs; 37028c2ecf20Sopenharmony_ci break; 37038c2ecf20Sopenharmony_ci case QED_RSS_ENG: 37048c2ecf20Sopenharmony_ci *p_resc_num = NUM_OF_RSS_ENGINES(cdev) / num_funcs; 37058c2ecf20Sopenharmony_ci break; 37068c2ecf20Sopenharmony_ci case QED_PQ: 37078c2ecf20Sopenharmony_ci *p_resc_num = NUM_OF_QM_TX_QUEUES(cdev) / num_funcs; 37088c2ecf20Sopenharmony_ci *p_resc_num &= ~0x7; /* The granularity of the PQs is 8 */ 37098c2ecf20Sopenharmony_ci break; 37108c2ecf20Sopenharmony_ci case QED_RL: 37118c2ecf20Sopenharmony_ci *p_resc_num = NUM_OF_QM_GLOBAL_RLS(cdev) / num_funcs; 37128c2ecf20Sopenharmony_ci break; 37138c2ecf20Sopenharmony_ci case QED_MAC: 37148c2ecf20Sopenharmony_ci case QED_VLAN: 37158c2ecf20Sopenharmony_ci /* Each VFC resource can accommodate both a MAC and a VLAN */ 37168c2ecf20Sopenharmony_ci *p_resc_num = ETH_NUM_MAC_FILTERS / num_funcs; 37178c2ecf20Sopenharmony_ci break; 37188c2ecf20Sopenharmony_ci case QED_ILT: 37198c2ecf20Sopenharmony_ci *p_resc_num = NUM_OF_PXP_ILT_RECORDS(cdev) / num_funcs; 37208c2ecf20Sopenharmony_ci break; 37218c2ecf20Sopenharmony_ci case QED_LL2_RAM_QUEUE: 37228c2ecf20Sopenharmony_ci *p_resc_num = MAX_NUM_LL2_RX_RAM_QUEUES / num_funcs; 37238c2ecf20Sopenharmony_ci break; 37248c2ecf20Sopenharmony_ci case QED_LL2_CTX_QUEUE: 37258c2ecf20Sopenharmony_ci *p_resc_num = MAX_NUM_LL2_RX_CTX_QUEUES / num_funcs; 37268c2ecf20Sopenharmony_ci break; 37278c2ecf20Sopenharmony_ci case QED_RDMA_CNQ_RAM: 37288c2ecf20Sopenharmony_ci case QED_CMDQS_CQS: 37298c2ecf20Sopenharmony_ci /* CNQ/CMDQS are the same resource */ 37308c2ecf20Sopenharmony_ci *p_resc_num = NUM_OF_GLOBAL_QUEUES / num_funcs; 37318c2ecf20Sopenharmony_ci break; 37328c2ecf20Sopenharmony_ci case QED_RDMA_STATS_QUEUE: 37338c2ecf20Sopenharmony_ci *p_resc_num = NUM_OF_RDMA_STATISTIC_COUNTERS(cdev) / num_funcs; 37348c2ecf20Sopenharmony_ci break; 37358c2ecf20Sopenharmony_ci case QED_BDQ: 37368c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.personality != QED_PCI_ISCSI && 37378c2ecf20Sopenharmony_ci p_hwfn->hw_info.personality != QED_PCI_FCOE) 37388c2ecf20Sopenharmony_ci *p_resc_num = 0; 37398c2ecf20Sopenharmony_ci else 37408c2ecf20Sopenharmony_ci *p_resc_num = 1; 37418c2ecf20Sopenharmony_ci break; 37428c2ecf20Sopenharmony_ci case QED_SB: 37438c2ecf20Sopenharmony_ci /* Since we want its value to reflect whether MFW supports 37448c2ecf20Sopenharmony_ci * the new scheme, have a default of 0. 37458c2ecf20Sopenharmony_ci */ 37468c2ecf20Sopenharmony_ci *p_resc_num = 0; 37478c2ecf20Sopenharmony_ci break; 37488c2ecf20Sopenharmony_ci default: 37498c2ecf20Sopenharmony_ci return -EINVAL; 37508c2ecf20Sopenharmony_ci } 37518c2ecf20Sopenharmony_ci 37528c2ecf20Sopenharmony_ci switch (res_id) { 37538c2ecf20Sopenharmony_ci case QED_BDQ: 37548c2ecf20Sopenharmony_ci if (!*p_resc_num) 37558c2ecf20Sopenharmony_ci *p_resc_start = 0; 37568c2ecf20Sopenharmony_ci else if (p_hwfn->cdev->num_ports_in_engine == 4) 37578c2ecf20Sopenharmony_ci *p_resc_start = p_hwfn->port_id; 37588c2ecf20Sopenharmony_ci else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) 37598c2ecf20Sopenharmony_ci *p_resc_start = p_hwfn->port_id; 37608c2ecf20Sopenharmony_ci else if (p_hwfn->hw_info.personality == QED_PCI_FCOE) 37618c2ecf20Sopenharmony_ci *p_resc_start = p_hwfn->port_id + 2; 37628c2ecf20Sopenharmony_ci break; 37638c2ecf20Sopenharmony_ci default: 37648c2ecf20Sopenharmony_ci *p_resc_start = *p_resc_num * p_hwfn->enabled_func_idx; 37658c2ecf20Sopenharmony_ci break; 37668c2ecf20Sopenharmony_ci } 37678c2ecf20Sopenharmony_ci 37688c2ecf20Sopenharmony_ci return 0; 37698c2ecf20Sopenharmony_ci} 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_cistatic int __qed_hw_set_resc_info(struct qed_hwfn *p_hwfn, 37728c2ecf20Sopenharmony_ci enum qed_resources res_id) 37738c2ecf20Sopenharmony_ci{ 37748c2ecf20Sopenharmony_ci u32 dflt_resc_num = 0, dflt_resc_start = 0; 37758c2ecf20Sopenharmony_ci u32 mcp_resp, *p_resc_num, *p_resc_start; 37768c2ecf20Sopenharmony_ci int rc; 37778c2ecf20Sopenharmony_ci 37788c2ecf20Sopenharmony_ci p_resc_num = &RESC_NUM(p_hwfn, res_id); 37798c2ecf20Sopenharmony_ci p_resc_start = &RESC_START(p_hwfn, res_id); 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ci rc = qed_hw_get_dflt_resc(p_hwfn, res_id, &dflt_resc_num, 37828c2ecf20Sopenharmony_ci &dflt_resc_start); 37838c2ecf20Sopenharmony_ci if (rc) { 37848c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 37858c2ecf20Sopenharmony_ci "Failed to get default amount for resource %d [%s]\n", 37868c2ecf20Sopenharmony_ci res_id, qed_hw_get_resc_name(res_id)); 37878c2ecf20Sopenharmony_ci return rc; 37888c2ecf20Sopenharmony_ci } 37898c2ecf20Sopenharmony_ci 37908c2ecf20Sopenharmony_ci rc = qed_mcp_get_resc_info(p_hwfn, p_hwfn->p_main_ptt, res_id, 37918c2ecf20Sopenharmony_ci &mcp_resp, p_resc_num, p_resc_start); 37928c2ecf20Sopenharmony_ci if (rc) { 37938c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 37948c2ecf20Sopenharmony_ci "MFW response failure for an allocation request for resource %d [%s]\n", 37958c2ecf20Sopenharmony_ci res_id, qed_hw_get_resc_name(res_id)); 37968c2ecf20Sopenharmony_ci return rc; 37978c2ecf20Sopenharmony_ci } 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci /* Default driver values are applied in the following cases: 38008c2ecf20Sopenharmony_ci * - The resource allocation MB command is not supported by the MFW 38018c2ecf20Sopenharmony_ci * - There is an internal error in the MFW while processing the request 38028c2ecf20Sopenharmony_ci * - The resource ID is unknown to the MFW 38038c2ecf20Sopenharmony_ci */ 38048c2ecf20Sopenharmony_ci if (mcp_resp != FW_MSG_CODE_RESOURCE_ALLOC_OK) { 38058c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 38068c2ecf20Sopenharmony_ci "Failed to receive allocation info for resource %d [%s]. mcp_resp = 0x%x. Applying default values [%d,%d].\n", 38078c2ecf20Sopenharmony_ci res_id, 38088c2ecf20Sopenharmony_ci qed_hw_get_resc_name(res_id), 38098c2ecf20Sopenharmony_ci mcp_resp, dflt_resc_num, dflt_resc_start); 38108c2ecf20Sopenharmony_ci *p_resc_num = dflt_resc_num; 38118c2ecf20Sopenharmony_ci *p_resc_start = dflt_resc_start; 38128c2ecf20Sopenharmony_ci goto out; 38138c2ecf20Sopenharmony_ci } 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ciout: 38168c2ecf20Sopenharmony_ci /* PQs have to divide by 8 [that's the HW granularity]. 38178c2ecf20Sopenharmony_ci * Reduce number so it would fit. 38188c2ecf20Sopenharmony_ci */ 38198c2ecf20Sopenharmony_ci if ((res_id == QED_PQ) && ((*p_resc_num % 8) || (*p_resc_start % 8))) { 38208c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 38218c2ecf20Sopenharmony_ci "PQs need to align by 8; Number %08x --> %08x, Start %08x --> %08x\n", 38228c2ecf20Sopenharmony_ci *p_resc_num, 38238c2ecf20Sopenharmony_ci (*p_resc_num) & ~0x7, 38248c2ecf20Sopenharmony_ci *p_resc_start, (*p_resc_start) & ~0x7); 38258c2ecf20Sopenharmony_ci *p_resc_num &= ~0x7; 38268c2ecf20Sopenharmony_ci *p_resc_start &= ~0x7; 38278c2ecf20Sopenharmony_ci } 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci return 0; 38308c2ecf20Sopenharmony_ci} 38318c2ecf20Sopenharmony_ci 38328c2ecf20Sopenharmony_cistatic int qed_hw_set_resc_info(struct qed_hwfn *p_hwfn) 38338c2ecf20Sopenharmony_ci{ 38348c2ecf20Sopenharmony_ci int rc; 38358c2ecf20Sopenharmony_ci u8 res_id; 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci for (res_id = 0; res_id < QED_MAX_RESC; res_id++) { 38388c2ecf20Sopenharmony_ci rc = __qed_hw_set_resc_info(p_hwfn, res_id); 38398c2ecf20Sopenharmony_ci if (rc) 38408c2ecf20Sopenharmony_ci return rc; 38418c2ecf20Sopenharmony_ci } 38428c2ecf20Sopenharmony_ci 38438c2ecf20Sopenharmony_ci return 0; 38448c2ecf20Sopenharmony_ci} 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_cistatic int qed_hw_get_ppfid_bitmap(struct qed_hwfn *p_hwfn, 38478c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 38488c2ecf20Sopenharmony_ci{ 38498c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 38508c2ecf20Sopenharmony_ci u8 native_ppfid_idx; 38518c2ecf20Sopenharmony_ci int rc; 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_ci /* Calculation of BB/AH is different for native_ppfid_idx */ 38548c2ecf20Sopenharmony_ci if (QED_IS_BB(cdev)) 38558c2ecf20Sopenharmony_ci native_ppfid_idx = p_hwfn->rel_pf_id; 38568c2ecf20Sopenharmony_ci else 38578c2ecf20Sopenharmony_ci native_ppfid_idx = p_hwfn->rel_pf_id / 38588c2ecf20Sopenharmony_ci cdev->num_ports_in_engine; 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci rc = qed_mcp_get_ppfid_bitmap(p_hwfn, p_ptt); 38618c2ecf20Sopenharmony_ci if (rc != 0 && rc != -EOPNOTSUPP) 38628c2ecf20Sopenharmony_ci return rc; 38638c2ecf20Sopenharmony_ci else if (rc == -EOPNOTSUPP) 38648c2ecf20Sopenharmony_ci cdev->ppfid_bitmap = 0x1 << native_ppfid_idx; 38658c2ecf20Sopenharmony_ci 38668c2ecf20Sopenharmony_ci if (!(cdev->ppfid_bitmap & (0x1 << native_ppfid_idx))) { 38678c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 38688c2ecf20Sopenharmony_ci "Fix the PPFID bitmap to include the native PPFID [native_ppfid_idx %hhd, orig_bitmap 0x%hhx]\n", 38698c2ecf20Sopenharmony_ci native_ppfid_idx, cdev->ppfid_bitmap); 38708c2ecf20Sopenharmony_ci cdev->ppfid_bitmap = 0x1 << native_ppfid_idx; 38718c2ecf20Sopenharmony_ci } 38728c2ecf20Sopenharmony_ci 38738c2ecf20Sopenharmony_ci return 0; 38748c2ecf20Sopenharmony_ci} 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_cistatic int qed_hw_get_resc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 38778c2ecf20Sopenharmony_ci{ 38788c2ecf20Sopenharmony_ci struct qed_resc_unlock_params resc_unlock_params; 38798c2ecf20Sopenharmony_ci struct qed_resc_lock_params resc_lock_params; 38808c2ecf20Sopenharmony_ci bool b_ah = QED_IS_AH(p_hwfn->cdev); 38818c2ecf20Sopenharmony_ci u8 res_id; 38828c2ecf20Sopenharmony_ci int rc; 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci /* Setting the max values of the soft resources and the following 38858c2ecf20Sopenharmony_ci * resources allocation queries should be atomic. Since several PFs can 38868c2ecf20Sopenharmony_ci * run in parallel - a resource lock is needed. 38878c2ecf20Sopenharmony_ci * If either the resource lock or resource set value commands are not 38888c2ecf20Sopenharmony_ci * supported - skip the the max values setting, release the lock if 38898c2ecf20Sopenharmony_ci * needed, and proceed to the queries. Other failures, including a 38908c2ecf20Sopenharmony_ci * failure to acquire the lock, will cause this function to fail. 38918c2ecf20Sopenharmony_ci */ 38928c2ecf20Sopenharmony_ci qed_mcp_resc_lock_default_init(&resc_lock_params, &resc_unlock_params, 38938c2ecf20Sopenharmony_ci QED_RESC_LOCK_RESC_ALLOC, false); 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci rc = qed_mcp_resc_lock(p_hwfn, p_ptt, &resc_lock_params); 38968c2ecf20Sopenharmony_ci if (rc && rc != -EINVAL) { 38978c2ecf20Sopenharmony_ci return rc; 38988c2ecf20Sopenharmony_ci } else if (rc == -EINVAL) { 38998c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 39008c2ecf20Sopenharmony_ci "Skip the max values setting of the soft resources since the resource lock is not supported by the MFW\n"); 39018c2ecf20Sopenharmony_ci } else if (!rc && !resc_lock_params.b_granted) { 39028c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 39038c2ecf20Sopenharmony_ci "Failed to acquire the resource lock for the resource allocation commands\n"); 39048c2ecf20Sopenharmony_ci return -EBUSY; 39058c2ecf20Sopenharmony_ci } else { 39068c2ecf20Sopenharmony_ci rc = qed_hw_set_soft_resc_size(p_hwfn, p_ptt); 39078c2ecf20Sopenharmony_ci if (rc && rc != -EINVAL) { 39088c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 39098c2ecf20Sopenharmony_ci "Failed to set the max values of the soft resources\n"); 39108c2ecf20Sopenharmony_ci goto unlock_and_exit; 39118c2ecf20Sopenharmony_ci } else if (rc == -EINVAL) { 39128c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 39138c2ecf20Sopenharmony_ci "Skip the max values setting of the soft resources since it is not supported by the MFW\n"); 39148c2ecf20Sopenharmony_ci rc = qed_mcp_resc_unlock(p_hwfn, p_ptt, 39158c2ecf20Sopenharmony_ci &resc_unlock_params); 39168c2ecf20Sopenharmony_ci if (rc) 39178c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 39188c2ecf20Sopenharmony_ci "Failed to release the resource lock for the resource allocation commands\n"); 39198c2ecf20Sopenharmony_ci } 39208c2ecf20Sopenharmony_ci } 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ci rc = qed_hw_set_resc_info(p_hwfn); 39238c2ecf20Sopenharmony_ci if (rc) 39248c2ecf20Sopenharmony_ci goto unlock_and_exit; 39258c2ecf20Sopenharmony_ci 39268c2ecf20Sopenharmony_ci if (resc_lock_params.b_granted && !resc_unlock_params.b_released) { 39278c2ecf20Sopenharmony_ci rc = qed_mcp_resc_unlock(p_hwfn, p_ptt, &resc_unlock_params); 39288c2ecf20Sopenharmony_ci if (rc) 39298c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 39308c2ecf20Sopenharmony_ci "Failed to release the resource lock for the resource allocation commands\n"); 39318c2ecf20Sopenharmony_ci } 39328c2ecf20Sopenharmony_ci 39338c2ecf20Sopenharmony_ci /* PPFID bitmap */ 39348c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn)) { 39358c2ecf20Sopenharmony_ci rc = qed_hw_get_ppfid_bitmap(p_hwfn, p_ptt); 39368c2ecf20Sopenharmony_ci if (rc) 39378c2ecf20Sopenharmony_ci return rc; 39388c2ecf20Sopenharmony_ci } 39398c2ecf20Sopenharmony_ci 39408c2ecf20Sopenharmony_ci /* Sanity for ILT */ 39418c2ecf20Sopenharmony_ci if ((b_ah && (RESC_END(p_hwfn, QED_ILT) > PXP_NUM_ILT_RECORDS_K2)) || 39428c2ecf20Sopenharmony_ci (!b_ah && (RESC_END(p_hwfn, QED_ILT) > PXP_NUM_ILT_RECORDS_BB))) { 39438c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Can't assign ILT pages [%08x,...,%08x]\n", 39448c2ecf20Sopenharmony_ci RESC_START(p_hwfn, QED_ILT), 39458c2ecf20Sopenharmony_ci RESC_END(p_hwfn, QED_ILT) - 1); 39468c2ecf20Sopenharmony_ci return -EINVAL; 39478c2ecf20Sopenharmony_ci } 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci /* This will also learn the number of SBs from MFW */ 39508c2ecf20Sopenharmony_ci if (qed_int_igu_reset_cam(p_hwfn, p_ptt)) 39518c2ecf20Sopenharmony_ci return -EINVAL; 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci qed_hw_set_feat(p_hwfn); 39548c2ecf20Sopenharmony_ci 39558c2ecf20Sopenharmony_ci for (res_id = 0; res_id < QED_MAX_RESC; res_id++) 39568c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_PROBE, "%s = %d start = %d\n", 39578c2ecf20Sopenharmony_ci qed_hw_get_resc_name(res_id), 39588c2ecf20Sopenharmony_ci RESC_NUM(p_hwfn, res_id), 39598c2ecf20Sopenharmony_ci RESC_START(p_hwfn, res_id)); 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ci return 0; 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ciunlock_and_exit: 39648c2ecf20Sopenharmony_ci if (resc_lock_params.b_granted && !resc_unlock_params.b_released) 39658c2ecf20Sopenharmony_ci qed_mcp_resc_unlock(p_hwfn, p_ptt, &resc_unlock_params); 39668c2ecf20Sopenharmony_ci return rc; 39678c2ecf20Sopenharmony_ci} 39688c2ecf20Sopenharmony_ci 39698c2ecf20Sopenharmony_cistatic int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 39708c2ecf20Sopenharmony_ci{ 39718c2ecf20Sopenharmony_ci u32 port_cfg_addr, link_temp, nvm_cfg_addr, device_capabilities, fld; 39728c2ecf20Sopenharmony_ci u32 nvm_cfg1_offset, mf_mode, addr, generic_cont0, core_cfg; 39738c2ecf20Sopenharmony_ci struct qed_mcp_link_speed_params *ext_speed; 39748c2ecf20Sopenharmony_ci struct qed_mcp_link_capabilities *p_caps; 39758c2ecf20Sopenharmony_ci struct qed_mcp_link_params *link; 39768c2ecf20Sopenharmony_ci int i; 39778c2ecf20Sopenharmony_ci 39788c2ecf20Sopenharmony_ci /* Read global nvm_cfg address */ 39798c2ecf20Sopenharmony_ci nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci /* Verify MCP has initialized it */ 39828c2ecf20Sopenharmony_ci if (!nvm_cfg_addr) { 39838c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Shared memory not initialized\n"); 39848c2ecf20Sopenharmony_ci return -EINVAL; 39858c2ecf20Sopenharmony_ci } 39868c2ecf20Sopenharmony_ci 39878c2ecf20Sopenharmony_ci /* Read nvm_cfg1 (Notice this is just offset, and not offsize (TBD) */ 39888c2ecf20Sopenharmony_ci nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 39918c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1, glob) + 39928c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_glob, core_cfg); 39938c2ecf20Sopenharmony_ci 39948c2ecf20Sopenharmony_ci core_cfg = qed_rd(p_hwfn, p_ptt, addr); 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci switch ((core_cfg & NVM_CFG1_GLOB_NETWORK_PORT_MODE_MASK) >> 39978c2ecf20Sopenharmony_ci NVM_CFG1_GLOB_NETWORK_PORT_MODE_OFFSET) { 39988c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_2X40G: 39998c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X50G: 40008c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_1X100G: 40018c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X10G_F: 40028c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X10G_E: 40038c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X20G: 40048c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X40G: 40058c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X25G: 40068c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X10G: 40078c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X25G: 40088c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X25G: 40098c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_AHP_2X50G_R1: 40108c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_AHP_4X50G_R1: 40118c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_AHP_1X100G_R2: 40128c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_AHP_2X100G_R2: 40138c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_NETWORK_PORT_MODE_AHP_1X100G_R4: 40148c2ecf20Sopenharmony_ci break; 40158c2ecf20Sopenharmony_ci default: 40168c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Unknown port mode in 0x%08x\n", core_cfg); 40178c2ecf20Sopenharmony_ci break; 40188c2ecf20Sopenharmony_ci } 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci /* Read default link configuration */ 40218c2ecf20Sopenharmony_ci link = &p_hwfn->mcp_info->link_input; 40228c2ecf20Sopenharmony_ci p_caps = &p_hwfn->mcp_info->link_capabilities; 40238c2ecf20Sopenharmony_ci port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 40248c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]); 40258c2ecf20Sopenharmony_ci link_temp = qed_rd(p_hwfn, p_ptt, 40268c2ecf20Sopenharmony_ci port_cfg_addr + 40278c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_port, speed_cap_mask)); 40288c2ecf20Sopenharmony_ci link_temp &= NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_MASK; 40298c2ecf20Sopenharmony_ci link->speed.advertised_speeds = link_temp; 40308c2ecf20Sopenharmony_ci 40318c2ecf20Sopenharmony_ci p_caps->speed_capabilities = link->speed.advertised_speeds; 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci link_temp = qed_rd(p_hwfn, p_ptt, 40348c2ecf20Sopenharmony_ci port_cfg_addr + 40358c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_port, link_settings)); 40368c2ecf20Sopenharmony_ci switch ((link_temp & NVM_CFG1_PORT_DRV_LINK_SPEED_MASK) >> 40378c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_LINK_SPEED_OFFSET) { 40388c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_DRV_LINK_SPEED_AUTONEG: 40398c2ecf20Sopenharmony_ci link->speed.autoneg = true; 40408c2ecf20Sopenharmony_ci break; 40418c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_DRV_LINK_SPEED_1G: 40428c2ecf20Sopenharmony_ci link->speed.forced_speed = 1000; 40438c2ecf20Sopenharmony_ci break; 40448c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_DRV_LINK_SPEED_10G: 40458c2ecf20Sopenharmony_ci link->speed.forced_speed = 10000; 40468c2ecf20Sopenharmony_ci break; 40478c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_DRV_LINK_SPEED_20G: 40488c2ecf20Sopenharmony_ci link->speed.forced_speed = 20000; 40498c2ecf20Sopenharmony_ci break; 40508c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_DRV_LINK_SPEED_25G: 40518c2ecf20Sopenharmony_ci link->speed.forced_speed = 25000; 40528c2ecf20Sopenharmony_ci break; 40538c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_DRV_LINK_SPEED_40G: 40548c2ecf20Sopenharmony_ci link->speed.forced_speed = 40000; 40558c2ecf20Sopenharmony_ci break; 40568c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_DRV_LINK_SPEED_50G: 40578c2ecf20Sopenharmony_ci link->speed.forced_speed = 50000; 40588c2ecf20Sopenharmony_ci break; 40598c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_DRV_LINK_SPEED_BB_100G: 40608c2ecf20Sopenharmony_ci link->speed.forced_speed = 100000; 40618c2ecf20Sopenharmony_ci break; 40628c2ecf20Sopenharmony_ci default: 40638c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Unknown Speed in 0x%08x\n", link_temp); 40648c2ecf20Sopenharmony_ci } 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ci p_caps->default_speed_autoneg = link->speed.autoneg; 40678c2ecf20Sopenharmony_ci 40688c2ecf20Sopenharmony_ci fld = GET_MFW_FIELD(link_temp, NVM_CFG1_PORT_DRV_FLOW_CONTROL); 40698c2ecf20Sopenharmony_ci link->pause.autoneg = !!(fld & NVM_CFG1_PORT_DRV_FLOW_CONTROL_AUTONEG); 40708c2ecf20Sopenharmony_ci link->pause.forced_rx = !!(fld & NVM_CFG1_PORT_DRV_FLOW_CONTROL_RX); 40718c2ecf20Sopenharmony_ci link->pause.forced_tx = !!(fld & NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX); 40728c2ecf20Sopenharmony_ci link->loopback_mode = 0; 40738c2ecf20Sopenharmony_ci 40748c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->capabilities & 40758c2ecf20Sopenharmony_ci FW_MB_PARAM_FEATURE_SUPPORT_FEC_CONTROL) { 40768c2ecf20Sopenharmony_ci switch (GET_MFW_FIELD(link_temp, 40778c2ecf20Sopenharmony_ci NVM_CFG1_PORT_FEC_FORCE_MODE)) { 40788c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_FEC_FORCE_MODE_NONE: 40798c2ecf20Sopenharmony_ci p_caps->fec_default |= QED_FEC_MODE_NONE; 40808c2ecf20Sopenharmony_ci break; 40818c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_FEC_FORCE_MODE_FIRECODE: 40828c2ecf20Sopenharmony_ci p_caps->fec_default |= QED_FEC_MODE_FIRECODE; 40838c2ecf20Sopenharmony_ci break; 40848c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_FEC_FORCE_MODE_RS: 40858c2ecf20Sopenharmony_ci p_caps->fec_default |= QED_FEC_MODE_RS; 40868c2ecf20Sopenharmony_ci break; 40878c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_FEC_FORCE_MODE_AUTO: 40888c2ecf20Sopenharmony_ci p_caps->fec_default |= QED_FEC_MODE_AUTO; 40898c2ecf20Sopenharmony_ci break; 40908c2ecf20Sopenharmony_ci default: 40918c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 40928c2ecf20Sopenharmony_ci "unknown FEC mode in 0x%08x\n", link_temp); 40938c2ecf20Sopenharmony_ci } 40948c2ecf20Sopenharmony_ci } else { 40958c2ecf20Sopenharmony_ci p_caps->fec_default = QED_FEC_MODE_UNSUPPORTED; 40968c2ecf20Sopenharmony_ci } 40978c2ecf20Sopenharmony_ci 40988c2ecf20Sopenharmony_ci link->fec = p_caps->fec_default; 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) { 41018c2ecf20Sopenharmony_ci link_temp = qed_rd(p_hwfn, p_ptt, port_cfg_addr + 41028c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_port, ext_phy)); 41038c2ecf20Sopenharmony_ci link_temp &= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_MASK; 41048c2ecf20Sopenharmony_ci link_temp >>= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_OFFSET; 41058c2ecf20Sopenharmony_ci p_caps->default_eee = QED_MCP_EEE_ENABLED; 41068c2ecf20Sopenharmony_ci link->eee.enable = true; 41078c2ecf20Sopenharmony_ci switch (link_temp) { 41088c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_DISABLED: 41098c2ecf20Sopenharmony_ci p_caps->default_eee = QED_MCP_EEE_DISABLED; 41108c2ecf20Sopenharmony_ci link->eee.enable = false; 41118c2ecf20Sopenharmony_ci break; 41128c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_BALANCED: 41138c2ecf20Sopenharmony_ci p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_BALANCED_TIME; 41148c2ecf20Sopenharmony_ci break; 41158c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_AGGRESSIVE: 41168c2ecf20Sopenharmony_ci p_caps->eee_lpi_timer = 41178c2ecf20Sopenharmony_ci EEE_TX_TIMER_USEC_AGGRESSIVE_TIME; 41188c2ecf20Sopenharmony_ci break; 41198c2ecf20Sopenharmony_ci case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_LOW_LATENCY: 41208c2ecf20Sopenharmony_ci p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_LATENCY_TIME; 41218c2ecf20Sopenharmony_ci break; 41228c2ecf20Sopenharmony_ci } 41238c2ecf20Sopenharmony_ci 41248c2ecf20Sopenharmony_ci link->eee.tx_lpi_timer = p_caps->eee_lpi_timer; 41258c2ecf20Sopenharmony_ci link->eee.tx_lpi_enable = link->eee.enable; 41268c2ecf20Sopenharmony_ci link->eee.adv_caps = QED_EEE_1G_ADV | QED_EEE_10G_ADV; 41278c2ecf20Sopenharmony_ci } else { 41288c2ecf20Sopenharmony_ci p_caps->default_eee = QED_MCP_EEE_UNSUPPORTED; 41298c2ecf20Sopenharmony_ci } 41308c2ecf20Sopenharmony_ci 41318c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->capabilities & 41328c2ecf20Sopenharmony_ci FW_MB_PARAM_FEATURE_SUPPORT_EXT_SPEED_FEC_CONTROL) { 41338c2ecf20Sopenharmony_ci ext_speed = &link->ext_speed; 41348c2ecf20Sopenharmony_ci 41358c2ecf20Sopenharmony_ci link_temp = qed_rd(p_hwfn, p_ptt, 41368c2ecf20Sopenharmony_ci port_cfg_addr + 41378c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_port, 41388c2ecf20Sopenharmony_ci extended_speed)); 41398c2ecf20Sopenharmony_ci 41408c2ecf20Sopenharmony_ci fld = GET_MFW_FIELD(link_temp, NVM_CFG1_PORT_EXTENDED_SPEED); 41418c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_AN) 41428c2ecf20Sopenharmony_ci ext_speed->autoneg = true; 41438c2ecf20Sopenharmony_ci 41448c2ecf20Sopenharmony_ci ext_speed->forced_speed = 0; 41458c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_1G) 41468c2ecf20Sopenharmony_ci ext_speed->forced_speed |= QED_EXT_SPEED_1G; 41478c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_10G) 41488c2ecf20Sopenharmony_ci ext_speed->forced_speed |= QED_EXT_SPEED_10G; 41498c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_20G) 41508c2ecf20Sopenharmony_ci ext_speed->forced_speed |= QED_EXT_SPEED_20G; 41518c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_25G) 41528c2ecf20Sopenharmony_ci ext_speed->forced_speed |= QED_EXT_SPEED_25G; 41538c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_40G) 41548c2ecf20Sopenharmony_ci ext_speed->forced_speed |= QED_EXT_SPEED_40G; 41558c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_50G_R) 41568c2ecf20Sopenharmony_ci ext_speed->forced_speed |= QED_EXT_SPEED_50G_R; 41578c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_50G_R2) 41588c2ecf20Sopenharmony_ci ext_speed->forced_speed |= QED_EXT_SPEED_50G_R2; 41598c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_100G_R2) 41608c2ecf20Sopenharmony_ci ext_speed->forced_speed |= QED_EXT_SPEED_100G_R2; 41618c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_100G_R4) 41628c2ecf20Sopenharmony_ci ext_speed->forced_speed |= QED_EXT_SPEED_100G_R4; 41638c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_EXTND_SPD_100G_P4) 41648c2ecf20Sopenharmony_ci ext_speed->forced_speed |= QED_EXT_SPEED_100G_P4; 41658c2ecf20Sopenharmony_ci 41668c2ecf20Sopenharmony_ci fld = GET_MFW_FIELD(link_temp, 41678c2ecf20Sopenharmony_ci NVM_CFG1_PORT_EXTENDED_SPEED_CAP); 41688c2ecf20Sopenharmony_ci 41698c2ecf20Sopenharmony_ci ext_speed->advertised_speeds = 0; 41708c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_RESERVED) 41718c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= QED_EXT_SPEED_MASK_RES; 41728c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_1G) 41738c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= QED_EXT_SPEED_MASK_1G; 41748c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_10G) 41758c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= QED_EXT_SPEED_MASK_10G; 41768c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_20G) 41778c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= QED_EXT_SPEED_MASK_20G; 41788c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_25G) 41798c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= QED_EXT_SPEED_MASK_25G; 41808c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_40G) 41818c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= QED_EXT_SPEED_MASK_40G; 41828c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_50G_R) 41838c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= 41848c2ecf20Sopenharmony_ci QED_EXT_SPEED_MASK_50G_R; 41858c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_50G_R2) 41868c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= 41878c2ecf20Sopenharmony_ci QED_EXT_SPEED_MASK_50G_R2; 41888c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_100G_R2) 41898c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= 41908c2ecf20Sopenharmony_ci QED_EXT_SPEED_MASK_100G_R2; 41918c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_100G_R4) 41928c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= 41938c2ecf20Sopenharmony_ci QED_EXT_SPEED_MASK_100G_R4; 41948c2ecf20Sopenharmony_ci if (fld & NVM_CFG1_PORT_EXTENDED_SPEED_CAP_EXTND_SPD_100G_P4) 41958c2ecf20Sopenharmony_ci ext_speed->advertised_speeds |= 41968c2ecf20Sopenharmony_ci QED_EXT_SPEED_MASK_100G_P4; 41978c2ecf20Sopenharmony_ci 41988c2ecf20Sopenharmony_ci link_temp = qed_rd(p_hwfn, p_ptt, 41998c2ecf20Sopenharmony_ci port_cfg_addr + 42008c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_port, 42018c2ecf20Sopenharmony_ci extended_fec_mode)); 42028c2ecf20Sopenharmony_ci link->ext_fec_mode = link_temp; 42038c2ecf20Sopenharmony_ci 42048c2ecf20Sopenharmony_ci p_caps->default_ext_speed_caps = ext_speed->advertised_speeds; 42058c2ecf20Sopenharmony_ci p_caps->default_ext_speed = ext_speed->forced_speed; 42068c2ecf20Sopenharmony_ci p_caps->default_ext_autoneg = ext_speed->autoneg; 42078c2ecf20Sopenharmony_ci p_caps->default_ext_fec = link->ext_fec_mode; 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 42108c2ecf20Sopenharmony_ci "Read default extended link config: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, FEC: 0x%02x\n", 42118c2ecf20Sopenharmony_ci ext_speed->forced_speed, 42128c2ecf20Sopenharmony_ci ext_speed->advertised_speeds, ext_speed->autoneg, 42138c2ecf20Sopenharmony_ci p_caps->default_ext_fec); 42148c2ecf20Sopenharmony_ci } 42158c2ecf20Sopenharmony_ci 42168c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 42178c2ecf20Sopenharmony_ci "Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x, EEE: 0x%02x [0x%08x usec], FEC: 0x%02x\n", 42188c2ecf20Sopenharmony_ci link->speed.forced_speed, link->speed.advertised_speeds, 42198c2ecf20Sopenharmony_ci link->speed.autoneg, link->pause.autoneg, 42208c2ecf20Sopenharmony_ci p_caps->default_eee, p_caps->eee_lpi_timer, 42218c2ecf20Sopenharmony_ci p_caps->fec_default); 42228c2ecf20Sopenharmony_ci 42238c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn)) { 42248c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci /* Read Multi-function information from shmem */ 42278c2ecf20Sopenharmony_ci addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 42288c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1, glob) + 42298c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_glob, generic_cont0); 42308c2ecf20Sopenharmony_ci 42318c2ecf20Sopenharmony_ci generic_cont0 = qed_rd(p_hwfn, p_ptt, addr); 42328c2ecf20Sopenharmony_ci 42338c2ecf20Sopenharmony_ci mf_mode = (generic_cont0 & NVM_CFG1_GLOB_MF_MODE_MASK) >> 42348c2ecf20Sopenharmony_ci NVM_CFG1_GLOB_MF_MODE_OFFSET; 42358c2ecf20Sopenharmony_ci 42368c2ecf20Sopenharmony_ci switch (mf_mode) { 42378c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_MF_MODE_MF_ALLOWED: 42388c2ecf20Sopenharmony_ci cdev->mf_bits = BIT(QED_MF_OVLAN_CLSS); 42398c2ecf20Sopenharmony_ci break; 42408c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_MF_MODE_UFP: 42418c2ecf20Sopenharmony_ci cdev->mf_bits = BIT(QED_MF_OVLAN_CLSS) | 42428c2ecf20Sopenharmony_ci BIT(QED_MF_LLH_PROTO_CLSS) | 42438c2ecf20Sopenharmony_ci BIT(QED_MF_UFP_SPECIFIC) | 42448c2ecf20Sopenharmony_ci BIT(QED_MF_8021Q_TAGGING) | 42458c2ecf20Sopenharmony_ci BIT(QED_MF_DONT_ADD_VLAN0_TAG); 42468c2ecf20Sopenharmony_ci break; 42478c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_MF_MODE_BD: 42488c2ecf20Sopenharmony_ci cdev->mf_bits = BIT(QED_MF_OVLAN_CLSS) | 42498c2ecf20Sopenharmony_ci BIT(QED_MF_LLH_PROTO_CLSS) | 42508c2ecf20Sopenharmony_ci BIT(QED_MF_8021AD_TAGGING) | 42518c2ecf20Sopenharmony_ci BIT(QED_MF_DONT_ADD_VLAN0_TAG); 42528c2ecf20Sopenharmony_ci break; 42538c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_MF_MODE_NPAR1_0: 42548c2ecf20Sopenharmony_ci cdev->mf_bits = BIT(QED_MF_LLH_MAC_CLSS) | 42558c2ecf20Sopenharmony_ci BIT(QED_MF_LLH_PROTO_CLSS) | 42568c2ecf20Sopenharmony_ci BIT(QED_MF_LL2_NON_UNICAST) | 42578c2ecf20Sopenharmony_ci BIT(QED_MF_INTER_PF_SWITCH) | 42588c2ecf20Sopenharmony_ci BIT(QED_MF_DISABLE_ARFS); 42598c2ecf20Sopenharmony_ci break; 42608c2ecf20Sopenharmony_ci case NVM_CFG1_GLOB_MF_MODE_DEFAULT: 42618c2ecf20Sopenharmony_ci cdev->mf_bits = BIT(QED_MF_LLH_MAC_CLSS) | 42628c2ecf20Sopenharmony_ci BIT(QED_MF_LLH_PROTO_CLSS) | 42638c2ecf20Sopenharmony_ci BIT(QED_MF_LL2_NON_UNICAST); 42648c2ecf20Sopenharmony_ci if (QED_IS_BB(p_hwfn->cdev)) 42658c2ecf20Sopenharmony_ci cdev->mf_bits |= BIT(QED_MF_NEED_DEF_PF); 42668c2ecf20Sopenharmony_ci break; 42678c2ecf20Sopenharmony_ci } 42688c2ecf20Sopenharmony_ci 42698c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Multi function mode is 0x%lx\n", 42708c2ecf20Sopenharmony_ci cdev->mf_bits); 42718c2ecf20Sopenharmony_ci 42728c2ecf20Sopenharmony_ci /* In CMT the PF is unknown when the GFS block processes the 42738c2ecf20Sopenharmony_ci * packet. Therefore cannot use searcher as it has a per PF 42748c2ecf20Sopenharmony_ci * database, and thus ARFS must be disabled. 42758c2ecf20Sopenharmony_ci * 42768c2ecf20Sopenharmony_ci */ 42778c2ecf20Sopenharmony_ci if (QED_IS_CMT(cdev)) 42788c2ecf20Sopenharmony_ci cdev->mf_bits |= BIT(QED_MF_DISABLE_ARFS); 42798c2ecf20Sopenharmony_ci } 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Multi function mode is 0x%lx\n", 42828c2ecf20Sopenharmony_ci p_hwfn->cdev->mf_bits); 42838c2ecf20Sopenharmony_ci 42848c2ecf20Sopenharmony_ci /* Read device capabilities information from shmem */ 42858c2ecf20Sopenharmony_ci addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 42868c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1, glob) + 42878c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_glob, device_capabilities); 42888c2ecf20Sopenharmony_ci 42898c2ecf20Sopenharmony_ci device_capabilities = qed_rd(p_hwfn, p_ptt, addr); 42908c2ecf20Sopenharmony_ci if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET) 42918c2ecf20Sopenharmony_ci __set_bit(QED_DEV_CAP_ETH, 42928c2ecf20Sopenharmony_ci &p_hwfn->hw_info.device_capabilities); 42938c2ecf20Sopenharmony_ci if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_FCOE) 42948c2ecf20Sopenharmony_ci __set_bit(QED_DEV_CAP_FCOE, 42958c2ecf20Sopenharmony_ci &p_hwfn->hw_info.device_capabilities); 42968c2ecf20Sopenharmony_ci if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ISCSI) 42978c2ecf20Sopenharmony_ci __set_bit(QED_DEV_CAP_ISCSI, 42988c2ecf20Sopenharmony_ci &p_hwfn->hw_info.device_capabilities); 42998c2ecf20Sopenharmony_ci if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ROCE) 43008c2ecf20Sopenharmony_ci __set_bit(QED_DEV_CAP_ROCE, 43018c2ecf20Sopenharmony_ci &p_hwfn->hw_info.device_capabilities); 43028c2ecf20Sopenharmony_ci 43038c2ecf20Sopenharmony_ci /* Read device serial number information from shmem */ 43048c2ecf20Sopenharmony_ci addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 43058c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1, glob) + 43068c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_glob, serial_number); 43078c2ecf20Sopenharmony_ci 43088c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 43098c2ecf20Sopenharmony_ci p_hwfn->hw_info.part_num[i] = qed_rd(p_hwfn, p_ptt, addr + i * 4); 43108c2ecf20Sopenharmony_ci 43118c2ecf20Sopenharmony_ci return qed_mcp_fill_shmem_func_info(p_hwfn, p_ptt); 43128c2ecf20Sopenharmony_ci} 43138c2ecf20Sopenharmony_ci 43148c2ecf20Sopenharmony_cistatic void qed_get_num_funcs(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 43158c2ecf20Sopenharmony_ci{ 43168c2ecf20Sopenharmony_ci u8 num_funcs, enabled_func_idx = p_hwfn->rel_pf_id; 43178c2ecf20Sopenharmony_ci u32 reg_function_hide, tmp, eng_mask, low_pfs_mask; 43188c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 43198c2ecf20Sopenharmony_ci 43208c2ecf20Sopenharmony_ci num_funcs = QED_IS_AH(cdev) ? MAX_NUM_PFS_K2 : MAX_NUM_PFS_BB; 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_ci /* Bit 0 of MISCS_REG_FUNCTION_HIDE indicates whether the bypass values 43238c2ecf20Sopenharmony_ci * in the other bits are selected. 43248c2ecf20Sopenharmony_ci * Bits 1-15 are for functions 1-15, respectively, and their value is 43258c2ecf20Sopenharmony_ci * '0' only for enabled functions (function 0 always exists and 43268c2ecf20Sopenharmony_ci * enabled). 43278c2ecf20Sopenharmony_ci * In case of CMT, only the "even" functions are enabled, and thus the 43288c2ecf20Sopenharmony_ci * number of functions for both hwfns is learnt from the same bits. 43298c2ecf20Sopenharmony_ci */ 43308c2ecf20Sopenharmony_ci reg_function_hide = qed_rd(p_hwfn, p_ptt, MISCS_REG_FUNCTION_HIDE); 43318c2ecf20Sopenharmony_ci 43328c2ecf20Sopenharmony_ci if (reg_function_hide & 0x1) { 43338c2ecf20Sopenharmony_ci if (QED_IS_BB(cdev)) { 43348c2ecf20Sopenharmony_ci if (QED_PATH_ID(p_hwfn) && cdev->num_hwfns == 1) { 43358c2ecf20Sopenharmony_ci num_funcs = 0; 43368c2ecf20Sopenharmony_ci eng_mask = 0xaaaa; 43378c2ecf20Sopenharmony_ci } else { 43388c2ecf20Sopenharmony_ci num_funcs = 1; 43398c2ecf20Sopenharmony_ci eng_mask = 0x5554; 43408c2ecf20Sopenharmony_ci } 43418c2ecf20Sopenharmony_ci } else { 43428c2ecf20Sopenharmony_ci num_funcs = 1; 43438c2ecf20Sopenharmony_ci eng_mask = 0xfffe; 43448c2ecf20Sopenharmony_ci } 43458c2ecf20Sopenharmony_ci 43468c2ecf20Sopenharmony_ci /* Get the number of the enabled functions on the engine */ 43478c2ecf20Sopenharmony_ci tmp = (reg_function_hide ^ 0xffffffff) & eng_mask; 43488c2ecf20Sopenharmony_ci while (tmp) { 43498c2ecf20Sopenharmony_ci if (tmp & 0x1) 43508c2ecf20Sopenharmony_ci num_funcs++; 43518c2ecf20Sopenharmony_ci tmp >>= 0x1; 43528c2ecf20Sopenharmony_ci } 43538c2ecf20Sopenharmony_ci 43548c2ecf20Sopenharmony_ci /* Get the PF index within the enabled functions */ 43558c2ecf20Sopenharmony_ci low_pfs_mask = (0x1 << p_hwfn->abs_pf_id) - 1; 43568c2ecf20Sopenharmony_ci tmp = reg_function_hide & eng_mask & low_pfs_mask; 43578c2ecf20Sopenharmony_ci while (tmp) { 43588c2ecf20Sopenharmony_ci if (tmp & 0x1) 43598c2ecf20Sopenharmony_ci enabled_func_idx--; 43608c2ecf20Sopenharmony_ci tmp >>= 0x1; 43618c2ecf20Sopenharmony_ci } 43628c2ecf20Sopenharmony_ci } 43638c2ecf20Sopenharmony_ci 43648c2ecf20Sopenharmony_ci p_hwfn->num_funcs_on_engine = num_funcs; 43658c2ecf20Sopenharmony_ci p_hwfn->enabled_func_idx = enabled_func_idx; 43668c2ecf20Sopenharmony_ci 43678c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 43688c2ecf20Sopenharmony_ci NETIF_MSG_PROBE, 43698c2ecf20Sopenharmony_ci "PF [rel_id %d, abs_id %d] occupies index %d within the %d enabled functions on the engine\n", 43708c2ecf20Sopenharmony_ci p_hwfn->rel_pf_id, 43718c2ecf20Sopenharmony_ci p_hwfn->abs_pf_id, 43728c2ecf20Sopenharmony_ci p_hwfn->enabled_func_idx, p_hwfn->num_funcs_on_engine); 43738c2ecf20Sopenharmony_ci} 43748c2ecf20Sopenharmony_ci 43758c2ecf20Sopenharmony_cistatic void qed_hw_info_port_num(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 43768c2ecf20Sopenharmony_ci{ 43778c2ecf20Sopenharmony_ci u32 addr, global_offsize, global_addr, port_mode; 43788c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 43798c2ecf20Sopenharmony_ci 43808c2ecf20Sopenharmony_ci /* In CMT there is always only one port */ 43818c2ecf20Sopenharmony_ci if (cdev->num_hwfns > 1) { 43828c2ecf20Sopenharmony_ci cdev->num_ports_in_engine = 1; 43838c2ecf20Sopenharmony_ci cdev->num_ports = 1; 43848c2ecf20Sopenharmony_ci return; 43858c2ecf20Sopenharmony_ci } 43868c2ecf20Sopenharmony_ci 43878c2ecf20Sopenharmony_ci /* Determine the number of ports per engine */ 43888c2ecf20Sopenharmony_ci port_mode = qed_rd(p_hwfn, p_ptt, MISC_REG_PORT_MODE); 43898c2ecf20Sopenharmony_ci switch (port_mode) { 43908c2ecf20Sopenharmony_ci case 0x0: 43918c2ecf20Sopenharmony_ci cdev->num_ports_in_engine = 1; 43928c2ecf20Sopenharmony_ci break; 43938c2ecf20Sopenharmony_ci case 0x1: 43948c2ecf20Sopenharmony_ci cdev->num_ports_in_engine = 2; 43958c2ecf20Sopenharmony_ci break; 43968c2ecf20Sopenharmony_ci case 0x2: 43978c2ecf20Sopenharmony_ci cdev->num_ports_in_engine = 4; 43988c2ecf20Sopenharmony_ci break; 43998c2ecf20Sopenharmony_ci default: 44008c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Unknown port mode 0x%08x\n", port_mode); 44018c2ecf20Sopenharmony_ci cdev->num_ports_in_engine = 1; /* Default to something */ 44028c2ecf20Sopenharmony_ci break; 44038c2ecf20Sopenharmony_ci } 44048c2ecf20Sopenharmony_ci 44058c2ecf20Sopenharmony_ci /* Get the total number of ports of the device */ 44068c2ecf20Sopenharmony_ci addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 44078c2ecf20Sopenharmony_ci PUBLIC_GLOBAL); 44088c2ecf20Sopenharmony_ci global_offsize = qed_rd(p_hwfn, p_ptt, addr); 44098c2ecf20Sopenharmony_ci global_addr = SECTION_ADDR(global_offsize, 0); 44108c2ecf20Sopenharmony_ci addr = global_addr + offsetof(struct public_global, max_ports); 44118c2ecf20Sopenharmony_ci cdev->num_ports = (u8)qed_rd(p_hwfn, p_ptt, addr); 44128c2ecf20Sopenharmony_ci} 44138c2ecf20Sopenharmony_ci 44148c2ecf20Sopenharmony_cistatic void qed_get_eee_caps(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 44158c2ecf20Sopenharmony_ci{ 44168c2ecf20Sopenharmony_ci struct qed_mcp_link_capabilities *p_caps; 44178c2ecf20Sopenharmony_ci u32 eee_status; 44188c2ecf20Sopenharmony_ci 44198c2ecf20Sopenharmony_ci p_caps = &p_hwfn->mcp_info->link_capabilities; 44208c2ecf20Sopenharmony_ci if (p_caps->default_eee == QED_MCP_EEE_UNSUPPORTED) 44218c2ecf20Sopenharmony_ci return; 44228c2ecf20Sopenharmony_ci 44238c2ecf20Sopenharmony_ci p_caps->eee_speed_caps = 0; 44248c2ecf20Sopenharmony_ci eee_status = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 44258c2ecf20Sopenharmony_ci offsetof(struct public_port, eee_status)); 44268c2ecf20Sopenharmony_ci eee_status = (eee_status & EEE_SUPPORTED_SPEED_MASK) >> 44278c2ecf20Sopenharmony_ci EEE_SUPPORTED_SPEED_OFFSET; 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ci if (eee_status & EEE_1G_SUPPORTED) 44308c2ecf20Sopenharmony_ci p_caps->eee_speed_caps |= QED_EEE_1G_ADV; 44318c2ecf20Sopenharmony_ci if (eee_status & EEE_10G_ADV) 44328c2ecf20Sopenharmony_ci p_caps->eee_speed_caps |= QED_EEE_10G_ADV; 44338c2ecf20Sopenharmony_ci} 44348c2ecf20Sopenharmony_ci 44358c2ecf20Sopenharmony_cistatic int 44368c2ecf20Sopenharmony_ciqed_get_hw_info(struct qed_hwfn *p_hwfn, 44378c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 44388c2ecf20Sopenharmony_ci enum qed_pci_personality personality) 44398c2ecf20Sopenharmony_ci{ 44408c2ecf20Sopenharmony_ci int rc; 44418c2ecf20Sopenharmony_ci 44428c2ecf20Sopenharmony_ci /* Since all information is common, only first hwfns should do this */ 44438c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn)) { 44448c2ecf20Sopenharmony_ci rc = qed_iov_hw_info(p_hwfn); 44458c2ecf20Sopenharmony_ci if (rc) 44468c2ecf20Sopenharmony_ci return rc; 44478c2ecf20Sopenharmony_ci } 44488c2ecf20Sopenharmony_ci 44498c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn)) 44508c2ecf20Sopenharmony_ci qed_hw_info_port_num(p_hwfn, p_ptt); 44518c2ecf20Sopenharmony_ci 44528c2ecf20Sopenharmony_ci qed_mcp_get_capabilities(p_hwfn, p_ptt); 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_ci qed_hw_get_nvm_info(p_hwfn, p_ptt); 44558c2ecf20Sopenharmony_ci 44568c2ecf20Sopenharmony_ci rc = qed_int_igu_read_cam(p_hwfn, p_ptt); 44578c2ecf20Sopenharmony_ci if (rc) 44588c2ecf20Sopenharmony_ci return rc; 44598c2ecf20Sopenharmony_ci 44608c2ecf20Sopenharmony_ci if (qed_mcp_is_init(p_hwfn)) 44618c2ecf20Sopenharmony_ci ether_addr_copy(p_hwfn->hw_info.hw_mac_addr, 44628c2ecf20Sopenharmony_ci p_hwfn->mcp_info->func_info.mac); 44638c2ecf20Sopenharmony_ci else 44648c2ecf20Sopenharmony_ci eth_random_addr(p_hwfn->hw_info.hw_mac_addr); 44658c2ecf20Sopenharmony_ci 44668c2ecf20Sopenharmony_ci if (qed_mcp_is_init(p_hwfn)) { 44678c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->func_info.ovlan != QED_MCP_VLAN_UNSET) 44688c2ecf20Sopenharmony_ci p_hwfn->hw_info.ovlan = 44698c2ecf20Sopenharmony_ci p_hwfn->mcp_info->func_info.ovlan; 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci qed_mcp_cmd_port_init(p_hwfn, p_ptt); 44728c2ecf20Sopenharmony_ci 44738c2ecf20Sopenharmony_ci qed_get_eee_caps(p_hwfn, p_ptt); 44748c2ecf20Sopenharmony_ci 44758c2ecf20Sopenharmony_ci qed_mcp_read_ufp_config(p_hwfn, p_ptt); 44768c2ecf20Sopenharmony_ci } 44778c2ecf20Sopenharmony_ci 44788c2ecf20Sopenharmony_ci if (qed_mcp_is_init(p_hwfn)) { 44798c2ecf20Sopenharmony_ci enum qed_pci_personality protocol; 44808c2ecf20Sopenharmony_ci 44818c2ecf20Sopenharmony_ci protocol = p_hwfn->mcp_info->func_info.protocol; 44828c2ecf20Sopenharmony_ci p_hwfn->hw_info.personality = protocol; 44838c2ecf20Sopenharmony_ci } 44848c2ecf20Sopenharmony_ci 44858c2ecf20Sopenharmony_ci if (QED_IS_ROCE_PERSONALITY(p_hwfn)) 44868c2ecf20Sopenharmony_ci p_hwfn->hw_info.multi_tc_roce_en = true; 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_ci p_hwfn->hw_info.num_hw_tc = NUM_PHYS_TCS_4PORT_K2; 44898c2ecf20Sopenharmony_ci p_hwfn->hw_info.num_active_tc = 1; 44908c2ecf20Sopenharmony_ci 44918c2ecf20Sopenharmony_ci qed_get_num_funcs(p_hwfn, p_ptt); 44928c2ecf20Sopenharmony_ci 44938c2ecf20Sopenharmony_ci if (qed_mcp_is_init(p_hwfn)) 44948c2ecf20Sopenharmony_ci p_hwfn->hw_info.mtu = p_hwfn->mcp_info->func_info.mtu; 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ci return qed_hw_get_resc(p_hwfn, p_ptt); 44978c2ecf20Sopenharmony_ci} 44988c2ecf20Sopenharmony_ci 44998c2ecf20Sopenharmony_cistatic int qed_get_dev_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 45008c2ecf20Sopenharmony_ci{ 45018c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 45028c2ecf20Sopenharmony_ci u16 device_id_mask; 45038c2ecf20Sopenharmony_ci u32 tmp; 45048c2ecf20Sopenharmony_ci 45058c2ecf20Sopenharmony_ci /* Read Vendor Id / Device Id */ 45068c2ecf20Sopenharmony_ci pci_read_config_word(cdev->pdev, PCI_VENDOR_ID, &cdev->vendor_id); 45078c2ecf20Sopenharmony_ci pci_read_config_word(cdev->pdev, PCI_DEVICE_ID, &cdev->device_id); 45088c2ecf20Sopenharmony_ci 45098c2ecf20Sopenharmony_ci /* Determine type */ 45108c2ecf20Sopenharmony_ci device_id_mask = cdev->device_id & QED_DEV_ID_MASK; 45118c2ecf20Sopenharmony_ci switch (device_id_mask) { 45128c2ecf20Sopenharmony_ci case QED_DEV_ID_MASK_BB: 45138c2ecf20Sopenharmony_ci cdev->type = QED_DEV_TYPE_BB; 45148c2ecf20Sopenharmony_ci break; 45158c2ecf20Sopenharmony_ci case QED_DEV_ID_MASK_AH: 45168c2ecf20Sopenharmony_ci cdev->type = QED_DEV_TYPE_AH; 45178c2ecf20Sopenharmony_ci break; 45188c2ecf20Sopenharmony_ci default: 45198c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Unknown device id 0x%x\n", cdev->device_id); 45208c2ecf20Sopenharmony_ci return -EBUSY; 45218c2ecf20Sopenharmony_ci } 45228c2ecf20Sopenharmony_ci 45238c2ecf20Sopenharmony_ci cdev->chip_num = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_NUM); 45248c2ecf20Sopenharmony_ci cdev->chip_rev = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_REV); 45258c2ecf20Sopenharmony_ci 45268c2ecf20Sopenharmony_ci MASK_FIELD(CHIP_REV, cdev->chip_rev); 45278c2ecf20Sopenharmony_ci 45288c2ecf20Sopenharmony_ci /* Learn number of HW-functions */ 45298c2ecf20Sopenharmony_ci tmp = qed_rd(p_hwfn, p_ptt, MISCS_REG_CMT_ENABLED_FOR_PAIR); 45308c2ecf20Sopenharmony_ci 45318c2ecf20Sopenharmony_ci if (tmp & (1 << p_hwfn->rel_pf_id)) { 45328c2ecf20Sopenharmony_ci DP_NOTICE(cdev->hwfns, "device in CMT mode\n"); 45338c2ecf20Sopenharmony_ci cdev->num_hwfns = 2; 45348c2ecf20Sopenharmony_ci } else { 45358c2ecf20Sopenharmony_ci cdev->num_hwfns = 1; 45368c2ecf20Sopenharmony_ci } 45378c2ecf20Sopenharmony_ci 45388c2ecf20Sopenharmony_ci cdev->chip_bond_id = qed_rd(p_hwfn, p_ptt, 45398c2ecf20Sopenharmony_ci MISCS_REG_CHIP_TEST_REG) >> 4; 45408c2ecf20Sopenharmony_ci MASK_FIELD(CHIP_BOND_ID, cdev->chip_bond_id); 45418c2ecf20Sopenharmony_ci cdev->chip_metal = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_METAL); 45428c2ecf20Sopenharmony_ci MASK_FIELD(CHIP_METAL, cdev->chip_metal); 45438c2ecf20Sopenharmony_ci 45448c2ecf20Sopenharmony_ci DP_INFO(cdev->hwfns, 45458c2ecf20Sopenharmony_ci "Chip details - %s %c%d, Num: %04x Rev: %04x Bond id: %04x Metal: %04x\n", 45468c2ecf20Sopenharmony_ci QED_IS_BB(cdev) ? "BB" : "AH", 45478c2ecf20Sopenharmony_ci 'A' + cdev->chip_rev, 45488c2ecf20Sopenharmony_ci (int)cdev->chip_metal, 45498c2ecf20Sopenharmony_ci cdev->chip_num, cdev->chip_rev, 45508c2ecf20Sopenharmony_ci cdev->chip_bond_id, cdev->chip_metal); 45518c2ecf20Sopenharmony_ci 45528c2ecf20Sopenharmony_ci return 0; 45538c2ecf20Sopenharmony_ci} 45548c2ecf20Sopenharmony_ci 45558c2ecf20Sopenharmony_cistatic int qed_hw_prepare_single(struct qed_hwfn *p_hwfn, 45568c2ecf20Sopenharmony_ci void __iomem *p_regview, 45578c2ecf20Sopenharmony_ci void __iomem *p_doorbells, 45588c2ecf20Sopenharmony_ci u64 db_phys_addr, 45598c2ecf20Sopenharmony_ci enum qed_pci_personality personality) 45608c2ecf20Sopenharmony_ci{ 45618c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 45628c2ecf20Sopenharmony_ci int rc = 0; 45638c2ecf20Sopenharmony_ci 45648c2ecf20Sopenharmony_ci /* Split PCI bars evenly between hwfns */ 45658c2ecf20Sopenharmony_ci p_hwfn->regview = p_regview; 45668c2ecf20Sopenharmony_ci p_hwfn->doorbells = p_doorbells; 45678c2ecf20Sopenharmony_ci p_hwfn->db_phys_addr = db_phys_addr; 45688c2ecf20Sopenharmony_ci 45698c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 45708c2ecf20Sopenharmony_ci return qed_vf_hw_prepare(p_hwfn); 45718c2ecf20Sopenharmony_ci 45728c2ecf20Sopenharmony_ci /* Validate that chip access is feasible */ 45738c2ecf20Sopenharmony_ci if (REG_RD(p_hwfn, PXP_PF_ME_OPAQUE_ADDR) == 0xffffffff) { 45748c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 45758c2ecf20Sopenharmony_ci "Reading the ME register returns all Fs; Preventing further chip access\n"); 45768c2ecf20Sopenharmony_ci return -EINVAL; 45778c2ecf20Sopenharmony_ci } 45788c2ecf20Sopenharmony_ci 45798c2ecf20Sopenharmony_ci get_function_id(p_hwfn); 45808c2ecf20Sopenharmony_ci 45818c2ecf20Sopenharmony_ci /* Allocate PTT pool */ 45828c2ecf20Sopenharmony_ci rc = qed_ptt_pool_alloc(p_hwfn); 45838c2ecf20Sopenharmony_ci if (rc) 45848c2ecf20Sopenharmony_ci goto err0; 45858c2ecf20Sopenharmony_ci 45868c2ecf20Sopenharmony_ci /* Allocate the main PTT */ 45878c2ecf20Sopenharmony_ci p_hwfn->p_main_ptt = qed_get_reserved_ptt(p_hwfn, RESERVED_PTT_MAIN); 45888c2ecf20Sopenharmony_ci 45898c2ecf20Sopenharmony_ci /* First hwfn learns basic information, e.g., number of hwfns */ 45908c2ecf20Sopenharmony_ci if (!p_hwfn->my_id) { 45918c2ecf20Sopenharmony_ci rc = qed_get_dev_info(p_hwfn, p_hwfn->p_main_ptt); 45928c2ecf20Sopenharmony_ci if (rc) 45938c2ecf20Sopenharmony_ci goto err1; 45948c2ecf20Sopenharmony_ci } 45958c2ecf20Sopenharmony_ci 45968c2ecf20Sopenharmony_ci qed_hw_hwfn_prepare(p_hwfn); 45978c2ecf20Sopenharmony_ci 45988c2ecf20Sopenharmony_ci /* Initialize MCP structure */ 45998c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_init(p_hwfn, p_hwfn->p_main_ptt); 46008c2ecf20Sopenharmony_ci if (rc) { 46018c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed initializing mcp command\n"); 46028c2ecf20Sopenharmony_ci goto err1; 46038c2ecf20Sopenharmony_ci } 46048c2ecf20Sopenharmony_ci 46058c2ecf20Sopenharmony_ci /* Read the device configuration information from the HW and SHMEM */ 46068c2ecf20Sopenharmony_ci rc = qed_get_hw_info(p_hwfn, p_hwfn->p_main_ptt, personality); 46078c2ecf20Sopenharmony_ci if (rc) { 46088c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to get HW information\n"); 46098c2ecf20Sopenharmony_ci goto err2; 46108c2ecf20Sopenharmony_ci } 46118c2ecf20Sopenharmony_ci 46128c2ecf20Sopenharmony_ci /* Sending a mailbox to the MFW should be done after qed_get_hw_info() 46138c2ecf20Sopenharmony_ci * is called as it sets the ports number in an engine. 46148c2ecf20Sopenharmony_ci */ 46158c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn) && !cdev->recov_in_prog) { 46168c2ecf20Sopenharmony_ci rc = qed_mcp_initiate_pf_flr(p_hwfn, p_hwfn->p_main_ptt); 46178c2ecf20Sopenharmony_ci if (rc) 46188c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to initiate PF FLR\n"); 46198c2ecf20Sopenharmony_ci } 46208c2ecf20Sopenharmony_ci 46218c2ecf20Sopenharmony_ci /* NVRAM info initialization and population */ 46228c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn)) { 46238c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_info_populate(p_hwfn); 46248c2ecf20Sopenharmony_ci if (rc) { 46258c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 46268c2ecf20Sopenharmony_ci "Failed to populate nvm info shadow\n"); 46278c2ecf20Sopenharmony_ci goto err2; 46288c2ecf20Sopenharmony_ci } 46298c2ecf20Sopenharmony_ci } 46308c2ecf20Sopenharmony_ci 46318c2ecf20Sopenharmony_ci /* Allocate the init RT array and initialize the init-ops engine */ 46328c2ecf20Sopenharmony_ci rc = qed_init_alloc(p_hwfn); 46338c2ecf20Sopenharmony_ci if (rc) 46348c2ecf20Sopenharmony_ci goto err3; 46358c2ecf20Sopenharmony_ci 46368c2ecf20Sopenharmony_ci return rc; 46378c2ecf20Sopenharmony_cierr3: 46388c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn)) 46398c2ecf20Sopenharmony_ci qed_mcp_nvm_info_free(p_hwfn); 46408c2ecf20Sopenharmony_cierr2: 46418c2ecf20Sopenharmony_ci if (IS_LEAD_HWFN(p_hwfn)) 46428c2ecf20Sopenharmony_ci qed_iov_free_hw_info(p_hwfn->cdev); 46438c2ecf20Sopenharmony_ci qed_mcp_free(p_hwfn); 46448c2ecf20Sopenharmony_cierr1: 46458c2ecf20Sopenharmony_ci qed_hw_hwfn_free(p_hwfn); 46468c2ecf20Sopenharmony_cierr0: 46478c2ecf20Sopenharmony_ci return rc; 46488c2ecf20Sopenharmony_ci} 46498c2ecf20Sopenharmony_ci 46508c2ecf20Sopenharmony_ciint qed_hw_prepare(struct qed_dev *cdev, 46518c2ecf20Sopenharmony_ci int personality) 46528c2ecf20Sopenharmony_ci{ 46538c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 46548c2ecf20Sopenharmony_ci int rc; 46558c2ecf20Sopenharmony_ci 46568c2ecf20Sopenharmony_ci /* Store the precompiled init data ptrs */ 46578c2ecf20Sopenharmony_ci if (IS_PF(cdev)) 46588c2ecf20Sopenharmony_ci qed_init_iro_array(cdev); 46598c2ecf20Sopenharmony_ci 46608c2ecf20Sopenharmony_ci /* Initialize the first hwfn - will learn number of hwfns */ 46618c2ecf20Sopenharmony_ci rc = qed_hw_prepare_single(p_hwfn, 46628c2ecf20Sopenharmony_ci cdev->regview, 46638c2ecf20Sopenharmony_ci cdev->doorbells, 46648c2ecf20Sopenharmony_ci cdev->db_phys_addr, 46658c2ecf20Sopenharmony_ci personality); 46668c2ecf20Sopenharmony_ci if (rc) 46678c2ecf20Sopenharmony_ci return rc; 46688c2ecf20Sopenharmony_ci 46698c2ecf20Sopenharmony_ci personality = p_hwfn->hw_info.personality; 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_ci /* Initialize the rest of the hwfns */ 46728c2ecf20Sopenharmony_ci if (cdev->num_hwfns > 1) { 46738c2ecf20Sopenharmony_ci void __iomem *p_regview, *p_doorbell; 46748c2ecf20Sopenharmony_ci u64 db_phys_addr; 46758c2ecf20Sopenharmony_ci u32 offset; 46768c2ecf20Sopenharmony_ci 46778c2ecf20Sopenharmony_ci /* adjust bar offset for second engine */ 46788c2ecf20Sopenharmony_ci offset = qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt, 46798c2ecf20Sopenharmony_ci BAR_ID_0) / 2; 46808c2ecf20Sopenharmony_ci p_regview = cdev->regview + offset; 46818c2ecf20Sopenharmony_ci 46828c2ecf20Sopenharmony_ci offset = qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt, 46838c2ecf20Sopenharmony_ci BAR_ID_1) / 2; 46848c2ecf20Sopenharmony_ci 46858c2ecf20Sopenharmony_ci p_doorbell = cdev->doorbells + offset; 46868c2ecf20Sopenharmony_ci 46878c2ecf20Sopenharmony_ci db_phys_addr = cdev->db_phys_addr + offset; 46888c2ecf20Sopenharmony_ci 46898c2ecf20Sopenharmony_ci /* prepare second hw function */ 46908c2ecf20Sopenharmony_ci rc = qed_hw_prepare_single(&cdev->hwfns[1], p_regview, 46918c2ecf20Sopenharmony_ci p_doorbell, db_phys_addr, 46928c2ecf20Sopenharmony_ci personality); 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_ci /* in case of error, need to free the previously 46958c2ecf20Sopenharmony_ci * initiliazed hwfn 0. 46968c2ecf20Sopenharmony_ci */ 46978c2ecf20Sopenharmony_ci if (rc) { 46988c2ecf20Sopenharmony_ci if (IS_PF(cdev)) { 46998c2ecf20Sopenharmony_ci qed_init_free(p_hwfn); 47008c2ecf20Sopenharmony_ci qed_mcp_nvm_info_free(p_hwfn); 47018c2ecf20Sopenharmony_ci qed_mcp_free(p_hwfn); 47028c2ecf20Sopenharmony_ci qed_hw_hwfn_free(p_hwfn); 47038c2ecf20Sopenharmony_ci } 47048c2ecf20Sopenharmony_ci } 47058c2ecf20Sopenharmony_ci } 47068c2ecf20Sopenharmony_ci 47078c2ecf20Sopenharmony_ci return rc; 47088c2ecf20Sopenharmony_ci} 47098c2ecf20Sopenharmony_ci 47108c2ecf20Sopenharmony_civoid qed_hw_remove(struct qed_dev *cdev) 47118c2ecf20Sopenharmony_ci{ 47128c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 47138c2ecf20Sopenharmony_ci int i; 47148c2ecf20Sopenharmony_ci 47158c2ecf20Sopenharmony_ci if (IS_PF(cdev)) 47168c2ecf20Sopenharmony_ci qed_mcp_ov_update_driver_state(p_hwfn, p_hwfn->p_main_ptt, 47178c2ecf20Sopenharmony_ci QED_OV_DRIVER_STATE_NOT_LOADED); 47188c2ecf20Sopenharmony_ci 47198c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 47208c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 47218c2ecf20Sopenharmony_ci 47228c2ecf20Sopenharmony_ci if (IS_VF(cdev)) { 47238c2ecf20Sopenharmony_ci qed_vf_pf_release(p_hwfn); 47248c2ecf20Sopenharmony_ci continue; 47258c2ecf20Sopenharmony_ci } 47268c2ecf20Sopenharmony_ci 47278c2ecf20Sopenharmony_ci qed_init_free(p_hwfn); 47288c2ecf20Sopenharmony_ci qed_hw_hwfn_free(p_hwfn); 47298c2ecf20Sopenharmony_ci qed_mcp_free(p_hwfn); 47308c2ecf20Sopenharmony_ci } 47318c2ecf20Sopenharmony_ci 47328c2ecf20Sopenharmony_ci qed_iov_free_hw_info(cdev); 47338c2ecf20Sopenharmony_ci 47348c2ecf20Sopenharmony_ci qed_mcp_nvm_info_free(p_hwfn); 47358c2ecf20Sopenharmony_ci} 47368c2ecf20Sopenharmony_ci 47378c2ecf20Sopenharmony_ciint qed_fw_l2_queue(struct qed_hwfn *p_hwfn, u16 src_id, u16 *dst_id) 47388c2ecf20Sopenharmony_ci{ 47398c2ecf20Sopenharmony_ci if (src_id >= RESC_NUM(p_hwfn, QED_L2_QUEUE)) { 47408c2ecf20Sopenharmony_ci u16 min, max; 47418c2ecf20Sopenharmony_ci 47428c2ecf20Sopenharmony_ci min = (u16) RESC_START(p_hwfn, QED_L2_QUEUE); 47438c2ecf20Sopenharmony_ci max = min + RESC_NUM(p_hwfn, QED_L2_QUEUE); 47448c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 47458c2ecf20Sopenharmony_ci "l2_queue id [%d] is not valid, available indices [%d - %d]\n", 47468c2ecf20Sopenharmony_ci src_id, min, max); 47478c2ecf20Sopenharmony_ci 47488c2ecf20Sopenharmony_ci return -EINVAL; 47498c2ecf20Sopenharmony_ci } 47508c2ecf20Sopenharmony_ci 47518c2ecf20Sopenharmony_ci *dst_id = RESC_START(p_hwfn, QED_L2_QUEUE) + src_id; 47528c2ecf20Sopenharmony_ci 47538c2ecf20Sopenharmony_ci return 0; 47548c2ecf20Sopenharmony_ci} 47558c2ecf20Sopenharmony_ci 47568c2ecf20Sopenharmony_ciint qed_fw_vport(struct qed_hwfn *p_hwfn, u8 src_id, u8 *dst_id) 47578c2ecf20Sopenharmony_ci{ 47588c2ecf20Sopenharmony_ci if (src_id >= RESC_NUM(p_hwfn, QED_VPORT)) { 47598c2ecf20Sopenharmony_ci u8 min, max; 47608c2ecf20Sopenharmony_ci 47618c2ecf20Sopenharmony_ci min = (u8)RESC_START(p_hwfn, QED_VPORT); 47628c2ecf20Sopenharmony_ci max = min + RESC_NUM(p_hwfn, QED_VPORT); 47638c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 47648c2ecf20Sopenharmony_ci "vport id [%d] is not valid, available indices [%d - %d]\n", 47658c2ecf20Sopenharmony_ci src_id, min, max); 47668c2ecf20Sopenharmony_ci 47678c2ecf20Sopenharmony_ci return -EINVAL; 47688c2ecf20Sopenharmony_ci } 47698c2ecf20Sopenharmony_ci 47708c2ecf20Sopenharmony_ci *dst_id = RESC_START(p_hwfn, QED_VPORT) + src_id; 47718c2ecf20Sopenharmony_ci 47728c2ecf20Sopenharmony_ci return 0; 47738c2ecf20Sopenharmony_ci} 47748c2ecf20Sopenharmony_ci 47758c2ecf20Sopenharmony_ciint qed_fw_rss_eng(struct qed_hwfn *p_hwfn, u8 src_id, u8 *dst_id) 47768c2ecf20Sopenharmony_ci{ 47778c2ecf20Sopenharmony_ci if (src_id >= RESC_NUM(p_hwfn, QED_RSS_ENG)) { 47788c2ecf20Sopenharmony_ci u8 min, max; 47798c2ecf20Sopenharmony_ci 47808c2ecf20Sopenharmony_ci min = (u8)RESC_START(p_hwfn, QED_RSS_ENG); 47818c2ecf20Sopenharmony_ci max = min + RESC_NUM(p_hwfn, QED_RSS_ENG); 47828c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 47838c2ecf20Sopenharmony_ci "rss_eng id [%d] is not valid, available indices [%d - %d]\n", 47848c2ecf20Sopenharmony_ci src_id, min, max); 47858c2ecf20Sopenharmony_ci 47868c2ecf20Sopenharmony_ci return -EINVAL; 47878c2ecf20Sopenharmony_ci } 47888c2ecf20Sopenharmony_ci 47898c2ecf20Sopenharmony_ci *dst_id = RESC_START(p_hwfn, QED_RSS_ENG) + src_id; 47908c2ecf20Sopenharmony_ci 47918c2ecf20Sopenharmony_ci return 0; 47928c2ecf20Sopenharmony_ci} 47938c2ecf20Sopenharmony_ci 47948c2ecf20Sopenharmony_cistatic int qed_set_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 47958c2ecf20Sopenharmony_ci u32 hw_addr, void *p_eth_qzone, 47968c2ecf20Sopenharmony_ci size_t eth_qzone_size, u8 timeset) 47978c2ecf20Sopenharmony_ci{ 47988c2ecf20Sopenharmony_ci struct coalescing_timeset *p_coal_timeset; 47998c2ecf20Sopenharmony_ci 48008c2ecf20Sopenharmony_ci if (p_hwfn->cdev->int_coalescing_mode != QED_COAL_MODE_ENABLE) { 48018c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Coalescing configuration not enabled\n"); 48028c2ecf20Sopenharmony_ci return -EINVAL; 48038c2ecf20Sopenharmony_ci } 48048c2ecf20Sopenharmony_ci 48058c2ecf20Sopenharmony_ci p_coal_timeset = p_eth_qzone; 48068c2ecf20Sopenharmony_ci memset(p_eth_qzone, 0, eth_qzone_size); 48078c2ecf20Sopenharmony_ci SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_TIMESET, timeset); 48088c2ecf20Sopenharmony_ci SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_VALID, 1); 48098c2ecf20Sopenharmony_ci qed_memcpy_to(p_hwfn, p_ptt, hw_addr, p_eth_qzone, eth_qzone_size); 48108c2ecf20Sopenharmony_ci 48118c2ecf20Sopenharmony_ci return 0; 48128c2ecf20Sopenharmony_ci} 48138c2ecf20Sopenharmony_ci 48148c2ecf20Sopenharmony_ciint qed_set_queue_coalesce(u16 rx_coal, u16 tx_coal, void *p_handle) 48158c2ecf20Sopenharmony_ci{ 48168c2ecf20Sopenharmony_ci struct qed_queue_cid *p_cid = p_handle; 48178c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn; 48188c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 48198c2ecf20Sopenharmony_ci int rc = 0; 48208c2ecf20Sopenharmony_ci 48218c2ecf20Sopenharmony_ci p_hwfn = p_cid->p_owner; 48228c2ecf20Sopenharmony_ci 48238c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 48248c2ecf20Sopenharmony_ci return qed_vf_pf_set_coalesce(p_hwfn, rx_coal, tx_coal, p_cid); 48258c2ecf20Sopenharmony_ci 48268c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 48278c2ecf20Sopenharmony_ci if (!p_ptt) 48288c2ecf20Sopenharmony_ci return -EAGAIN; 48298c2ecf20Sopenharmony_ci 48308c2ecf20Sopenharmony_ci if (rx_coal) { 48318c2ecf20Sopenharmony_ci rc = qed_set_rxq_coalesce(p_hwfn, p_ptt, rx_coal, p_cid); 48328c2ecf20Sopenharmony_ci if (rc) 48338c2ecf20Sopenharmony_ci goto out; 48348c2ecf20Sopenharmony_ci p_hwfn->cdev->rx_coalesce_usecs = rx_coal; 48358c2ecf20Sopenharmony_ci } 48368c2ecf20Sopenharmony_ci 48378c2ecf20Sopenharmony_ci if (tx_coal) { 48388c2ecf20Sopenharmony_ci rc = qed_set_txq_coalesce(p_hwfn, p_ptt, tx_coal, p_cid); 48398c2ecf20Sopenharmony_ci if (rc) 48408c2ecf20Sopenharmony_ci goto out; 48418c2ecf20Sopenharmony_ci p_hwfn->cdev->tx_coalesce_usecs = tx_coal; 48428c2ecf20Sopenharmony_ci } 48438c2ecf20Sopenharmony_ciout: 48448c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 48458c2ecf20Sopenharmony_ci return rc; 48468c2ecf20Sopenharmony_ci} 48478c2ecf20Sopenharmony_ci 48488c2ecf20Sopenharmony_ciint qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn, 48498c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 48508c2ecf20Sopenharmony_ci u16 coalesce, struct qed_queue_cid *p_cid) 48518c2ecf20Sopenharmony_ci{ 48528c2ecf20Sopenharmony_ci struct ustorm_eth_queue_zone eth_qzone; 48538c2ecf20Sopenharmony_ci u8 timeset, timer_res; 48548c2ecf20Sopenharmony_ci u32 address; 48558c2ecf20Sopenharmony_ci int rc; 48568c2ecf20Sopenharmony_ci 48578c2ecf20Sopenharmony_ci /* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */ 48588c2ecf20Sopenharmony_ci if (coalesce <= 0x7F) { 48598c2ecf20Sopenharmony_ci timer_res = 0; 48608c2ecf20Sopenharmony_ci } else if (coalesce <= 0xFF) { 48618c2ecf20Sopenharmony_ci timer_res = 1; 48628c2ecf20Sopenharmony_ci } else if (coalesce <= 0x1FF) { 48638c2ecf20Sopenharmony_ci timer_res = 2; 48648c2ecf20Sopenharmony_ci } else { 48658c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce); 48668c2ecf20Sopenharmony_ci return -EINVAL; 48678c2ecf20Sopenharmony_ci } 48688c2ecf20Sopenharmony_ci timeset = (u8)(coalesce >> timer_res); 48698c2ecf20Sopenharmony_ci 48708c2ecf20Sopenharmony_ci rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res, 48718c2ecf20Sopenharmony_ci p_cid->sb_igu_id, false); 48728c2ecf20Sopenharmony_ci if (rc) 48738c2ecf20Sopenharmony_ci goto out; 48748c2ecf20Sopenharmony_ci 48758c2ecf20Sopenharmony_ci address = BAR0_MAP_REG_USDM_RAM + 48768c2ecf20Sopenharmony_ci USTORM_ETH_QUEUE_ZONE_OFFSET(p_cid->abs.queue_id); 48778c2ecf20Sopenharmony_ci 48788c2ecf20Sopenharmony_ci rc = qed_set_coalesce(p_hwfn, p_ptt, address, ð_qzone, 48798c2ecf20Sopenharmony_ci sizeof(struct ustorm_eth_queue_zone), timeset); 48808c2ecf20Sopenharmony_ci if (rc) 48818c2ecf20Sopenharmony_ci goto out; 48828c2ecf20Sopenharmony_ci 48838c2ecf20Sopenharmony_ciout: 48848c2ecf20Sopenharmony_ci return rc; 48858c2ecf20Sopenharmony_ci} 48868c2ecf20Sopenharmony_ci 48878c2ecf20Sopenharmony_ciint qed_set_txq_coalesce(struct qed_hwfn *p_hwfn, 48888c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 48898c2ecf20Sopenharmony_ci u16 coalesce, struct qed_queue_cid *p_cid) 48908c2ecf20Sopenharmony_ci{ 48918c2ecf20Sopenharmony_ci struct xstorm_eth_queue_zone eth_qzone; 48928c2ecf20Sopenharmony_ci u8 timeset, timer_res; 48938c2ecf20Sopenharmony_ci u32 address; 48948c2ecf20Sopenharmony_ci int rc; 48958c2ecf20Sopenharmony_ci 48968c2ecf20Sopenharmony_ci /* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */ 48978c2ecf20Sopenharmony_ci if (coalesce <= 0x7F) { 48988c2ecf20Sopenharmony_ci timer_res = 0; 48998c2ecf20Sopenharmony_ci } else if (coalesce <= 0xFF) { 49008c2ecf20Sopenharmony_ci timer_res = 1; 49018c2ecf20Sopenharmony_ci } else if (coalesce <= 0x1FF) { 49028c2ecf20Sopenharmony_ci timer_res = 2; 49038c2ecf20Sopenharmony_ci } else { 49048c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce); 49058c2ecf20Sopenharmony_ci return -EINVAL; 49068c2ecf20Sopenharmony_ci } 49078c2ecf20Sopenharmony_ci timeset = (u8)(coalesce >> timer_res); 49088c2ecf20Sopenharmony_ci 49098c2ecf20Sopenharmony_ci rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res, 49108c2ecf20Sopenharmony_ci p_cid->sb_igu_id, true); 49118c2ecf20Sopenharmony_ci if (rc) 49128c2ecf20Sopenharmony_ci goto out; 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_ci address = BAR0_MAP_REG_XSDM_RAM + 49158c2ecf20Sopenharmony_ci XSTORM_ETH_QUEUE_ZONE_OFFSET(p_cid->abs.queue_id); 49168c2ecf20Sopenharmony_ci 49178c2ecf20Sopenharmony_ci rc = qed_set_coalesce(p_hwfn, p_ptt, address, ð_qzone, 49188c2ecf20Sopenharmony_ci sizeof(struct xstorm_eth_queue_zone), timeset); 49198c2ecf20Sopenharmony_ciout: 49208c2ecf20Sopenharmony_ci return rc; 49218c2ecf20Sopenharmony_ci} 49228c2ecf20Sopenharmony_ci 49238c2ecf20Sopenharmony_ci/* Calculate final WFQ values for all vports and configure them. 49248c2ecf20Sopenharmony_ci * After this configuration each vport will have 49258c2ecf20Sopenharmony_ci * approx min rate = min_pf_rate * (vport_wfq / QED_WFQ_UNIT) 49268c2ecf20Sopenharmony_ci */ 49278c2ecf20Sopenharmony_cistatic void qed_configure_wfq_for_all_vports(struct qed_hwfn *p_hwfn, 49288c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 49298c2ecf20Sopenharmony_ci u32 min_pf_rate) 49308c2ecf20Sopenharmony_ci{ 49318c2ecf20Sopenharmony_ci struct init_qm_vport_params *vport_params; 49328c2ecf20Sopenharmony_ci int i; 49338c2ecf20Sopenharmony_ci 49348c2ecf20Sopenharmony_ci vport_params = p_hwfn->qm_info.qm_vport_params; 49358c2ecf20Sopenharmony_ci 49368c2ecf20Sopenharmony_ci for (i = 0; i < p_hwfn->qm_info.num_vports; i++) { 49378c2ecf20Sopenharmony_ci u32 wfq_speed = p_hwfn->qm_info.wfq_data[i].min_speed; 49388c2ecf20Sopenharmony_ci 49398c2ecf20Sopenharmony_ci vport_params[i].wfq = (wfq_speed * QED_WFQ_UNIT) / 49408c2ecf20Sopenharmony_ci min_pf_rate; 49418c2ecf20Sopenharmony_ci qed_init_vport_wfq(p_hwfn, p_ptt, 49428c2ecf20Sopenharmony_ci vport_params[i].first_tx_pq_id, 49438c2ecf20Sopenharmony_ci vport_params[i].wfq); 49448c2ecf20Sopenharmony_ci } 49458c2ecf20Sopenharmony_ci} 49468c2ecf20Sopenharmony_ci 49478c2ecf20Sopenharmony_cistatic void qed_init_wfq_default_param(struct qed_hwfn *p_hwfn, 49488c2ecf20Sopenharmony_ci u32 min_pf_rate) 49498c2ecf20Sopenharmony_ci 49508c2ecf20Sopenharmony_ci{ 49518c2ecf20Sopenharmony_ci int i; 49528c2ecf20Sopenharmony_ci 49538c2ecf20Sopenharmony_ci for (i = 0; i < p_hwfn->qm_info.num_vports; i++) 49548c2ecf20Sopenharmony_ci p_hwfn->qm_info.qm_vport_params[i].wfq = 1; 49558c2ecf20Sopenharmony_ci} 49568c2ecf20Sopenharmony_ci 49578c2ecf20Sopenharmony_cistatic void qed_disable_wfq_for_all_vports(struct qed_hwfn *p_hwfn, 49588c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 49598c2ecf20Sopenharmony_ci u32 min_pf_rate) 49608c2ecf20Sopenharmony_ci{ 49618c2ecf20Sopenharmony_ci struct init_qm_vport_params *vport_params; 49628c2ecf20Sopenharmony_ci int i; 49638c2ecf20Sopenharmony_ci 49648c2ecf20Sopenharmony_ci vport_params = p_hwfn->qm_info.qm_vport_params; 49658c2ecf20Sopenharmony_ci 49668c2ecf20Sopenharmony_ci for (i = 0; i < p_hwfn->qm_info.num_vports; i++) { 49678c2ecf20Sopenharmony_ci qed_init_wfq_default_param(p_hwfn, min_pf_rate); 49688c2ecf20Sopenharmony_ci qed_init_vport_wfq(p_hwfn, p_ptt, 49698c2ecf20Sopenharmony_ci vport_params[i].first_tx_pq_id, 49708c2ecf20Sopenharmony_ci vport_params[i].wfq); 49718c2ecf20Sopenharmony_ci } 49728c2ecf20Sopenharmony_ci} 49738c2ecf20Sopenharmony_ci 49748c2ecf20Sopenharmony_ci/* This function performs several validations for WFQ 49758c2ecf20Sopenharmony_ci * configuration and required min rate for a given vport 49768c2ecf20Sopenharmony_ci * 1. req_rate must be greater than one percent of min_pf_rate. 49778c2ecf20Sopenharmony_ci * 2. req_rate should not cause other vports [not configured for WFQ explicitly] 49788c2ecf20Sopenharmony_ci * rates to get less than one percent of min_pf_rate. 49798c2ecf20Sopenharmony_ci * 3. total_req_min_rate [all vports min rate sum] shouldn't exceed min_pf_rate. 49808c2ecf20Sopenharmony_ci */ 49818c2ecf20Sopenharmony_cistatic int qed_init_wfq_param(struct qed_hwfn *p_hwfn, 49828c2ecf20Sopenharmony_ci u16 vport_id, u32 req_rate, u32 min_pf_rate) 49838c2ecf20Sopenharmony_ci{ 49848c2ecf20Sopenharmony_ci u32 total_req_min_rate = 0, total_left_rate = 0, left_rate_per_vp = 0; 49858c2ecf20Sopenharmony_ci int non_requested_count = 0, req_count = 0, i, num_vports; 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_ci num_vports = p_hwfn->qm_info.num_vports; 49888c2ecf20Sopenharmony_ci 49898c2ecf20Sopenharmony_ci if (num_vports < 2) { 49908c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Unexpected num_vports: %d\n", num_vports); 49918c2ecf20Sopenharmony_ci return -EINVAL; 49928c2ecf20Sopenharmony_ci } 49938c2ecf20Sopenharmony_ci 49948c2ecf20Sopenharmony_ci /* Accounting for the vports which are configured for WFQ explicitly */ 49958c2ecf20Sopenharmony_ci for (i = 0; i < num_vports; i++) { 49968c2ecf20Sopenharmony_ci u32 tmp_speed; 49978c2ecf20Sopenharmony_ci 49988c2ecf20Sopenharmony_ci if ((i != vport_id) && 49998c2ecf20Sopenharmony_ci p_hwfn->qm_info.wfq_data[i].configured) { 50008c2ecf20Sopenharmony_ci req_count++; 50018c2ecf20Sopenharmony_ci tmp_speed = p_hwfn->qm_info.wfq_data[i].min_speed; 50028c2ecf20Sopenharmony_ci total_req_min_rate += tmp_speed; 50038c2ecf20Sopenharmony_ci } 50048c2ecf20Sopenharmony_ci } 50058c2ecf20Sopenharmony_ci 50068c2ecf20Sopenharmony_ci /* Include current vport data as well */ 50078c2ecf20Sopenharmony_ci req_count++; 50088c2ecf20Sopenharmony_ci total_req_min_rate += req_rate; 50098c2ecf20Sopenharmony_ci non_requested_count = num_vports - req_count; 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_ci if (req_rate < min_pf_rate / QED_WFQ_UNIT) { 50128c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 50138c2ecf20Sopenharmony_ci "Vport [%d] - Requested rate[%d Mbps] is less than one percent of configured PF min rate[%d Mbps]\n", 50148c2ecf20Sopenharmony_ci vport_id, req_rate, min_pf_rate); 50158c2ecf20Sopenharmony_ci return -EINVAL; 50168c2ecf20Sopenharmony_ci } 50178c2ecf20Sopenharmony_ci 50188c2ecf20Sopenharmony_ci if (num_vports > QED_WFQ_UNIT) { 50198c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 50208c2ecf20Sopenharmony_ci "Number of vports is greater than %d\n", 50218c2ecf20Sopenharmony_ci QED_WFQ_UNIT); 50228c2ecf20Sopenharmony_ci return -EINVAL; 50238c2ecf20Sopenharmony_ci } 50248c2ecf20Sopenharmony_ci 50258c2ecf20Sopenharmony_ci if (total_req_min_rate > min_pf_rate) { 50268c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 50278c2ecf20Sopenharmony_ci "Total requested min rate for all vports[%d Mbps] is greater than configured PF min rate[%d Mbps]\n", 50288c2ecf20Sopenharmony_ci total_req_min_rate, min_pf_rate); 50298c2ecf20Sopenharmony_ci return -EINVAL; 50308c2ecf20Sopenharmony_ci } 50318c2ecf20Sopenharmony_ci 50328c2ecf20Sopenharmony_ci total_left_rate = min_pf_rate - total_req_min_rate; 50338c2ecf20Sopenharmony_ci 50348c2ecf20Sopenharmony_ci left_rate_per_vp = total_left_rate / non_requested_count; 50358c2ecf20Sopenharmony_ci if (left_rate_per_vp < min_pf_rate / QED_WFQ_UNIT) { 50368c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 50378c2ecf20Sopenharmony_ci "Non WFQ configured vports rate [%d Mbps] is less than one percent of configured PF min rate[%d Mbps]\n", 50388c2ecf20Sopenharmony_ci left_rate_per_vp, min_pf_rate); 50398c2ecf20Sopenharmony_ci return -EINVAL; 50408c2ecf20Sopenharmony_ci } 50418c2ecf20Sopenharmony_ci 50428c2ecf20Sopenharmony_ci p_hwfn->qm_info.wfq_data[vport_id].min_speed = req_rate; 50438c2ecf20Sopenharmony_ci p_hwfn->qm_info.wfq_data[vport_id].configured = true; 50448c2ecf20Sopenharmony_ci 50458c2ecf20Sopenharmony_ci for (i = 0; i < num_vports; i++) { 50468c2ecf20Sopenharmony_ci if (p_hwfn->qm_info.wfq_data[i].configured) 50478c2ecf20Sopenharmony_ci continue; 50488c2ecf20Sopenharmony_ci 50498c2ecf20Sopenharmony_ci p_hwfn->qm_info.wfq_data[i].min_speed = left_rate_per_vp; 50508c2ecf20Sopenharmony_ci } 50518c2ecf20Sopenharmony_ci 50528c2ecf20Sopenharmony_ci return 0; 50538c2ecf20Sopenharmony_ci} 50548c2ecf20Sopenharmony_ci 50558c2ecf20Sopenharmony_cistatic int __qed_configure_vport_wfq(struct qed_hwfn *p_hwfn, 50568c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u16 vp_id, u32 rate) 50578c2ecf20Sopenharmony_ci{ 50588c2ecf20Sopenharmony_ci struct qed_mcp_link_state *p_link; 50598c2ecf20Sopenharmony_ci int rc = 0; 50608c2ecf20Sopenharmony_ci 50618c2ecf20Sopenharmony_ci p_link = &p_hwfn->cdev->hwfns[0].mcp_info->link_output; 50628c2ecf20Sopenharmony_ci 50638c2ecf20Sopenharmony_ci if (!p_link->min_pf_rate) { 50648c2ecf20Sopenharmony_ci p_hwfn->qm_info.wfq_data[vp_id].min_speed = rate; 50658c2ecf20Sopenharmony_ci p_hwfn->qm_info.wfq_data[vp_id].configured = true; 50668c2ecf20Sopenharmony_ci return rc; 50678c2ecf20Sopenharmony_ci } 50688c2ecf20Sopenharmony_ci 50698c2ecf20Sopenharmony_ci rc = qed_init_wfq_param(p_hwfn, vp_id, rate, p_link->min_pf_rate); 50708c2ecf20Sopenharmony_ci 50718c2ecf20Sopenharmony_ci if (!rc) 50728c2ecf20Sopenharmony_ci qed_configure_wfq_for_all_vports(p_hwfn, p_ptt, 50738c2ecf20Sopenharmony_ci p_link->min_pf_rate); 50748c2ecf20Sopenharmony_ci else 50758c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 50768c2ecf20Sopenharmony_ci "Validation failed while configuring min rate\n"); 50778c2ecf20Sopenharmony_ci 50788c2ecf20Sopenharmony_ci return rc; 50798c2ecf20Sopenharmony_ci} 50808c2ecf20Sopenharmony_ci 50818c2ecf20Sopenharmony_cistatic int __qed_configure_vp_wfq_on_link_change(struct qed_hwfn *p_hwfn, 50828c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 50838c2ecf20Sopenharmony_ci u32 min_pf_rate) 50848c2ecf20Sopenharmony_ci{ 50858c2ecf20Sopenharmony_ci bool use_wfq = false; 50868c2ecf20Sopenharmony_ci int rc = 0; 50878c2ecf20Sopenharmony_ci u16 i; 50888c2ecf20Sopenharmony_ci 50898c2ecf20Sopenharmony_ci /* Validate all pre configured vports for wfq */ 50908c2ecf20Sopenharmony_ci for (i = 0; i < p_hwfn->qm_info.num_vports; i++) { 50918c2ecf20Sopenharmony_ci u32 rate; 50928c2ecf20Sopenharmony_ci 50938c2ecf20Sopenharmony_ci if (!p_hwfn->qm_info.wfq_data[i].configured) 50948c2ecf20Sopenharmony_ci continue; 50958c2ecf20Sopenharmony_ci 50968c2ecf20Sopenharmony_ci rate = p_hwfn->qm_info.wfq_data[i].min_speed; 50978c2ecf20Sopenharmony_ci use_wfq = true; 50988c2ecf20Sopenharmony_ci 50998c2ecf20Sopenharmony_ci rc = qed_init_wfq_param(p_hwfn, i, rate, min_pf_rate); 51008c2ecf20Sopenharmony_ci if (rc) { 51018c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 51028c2ecf20Sopenharmony_ci "WFQ validation failed while configuring min rate\n"); 51038c2ecf20Sopenharmony_ci break; 51048c2ecf20Sopenharmony_ci } 51058c2ecf20Sopenharmony_ci } 51068c2ecf20Sopenharmony_ci 51078c2ecf20Sopenharmony_ci if (!rc && use_wfq) 51088c2ecf20Sopenharmony_ci qed_configure_wfq_for_all_vports(p_hwfn, p_ptt, min_pf_rate); 51098c2ecf20Sopenharmony_ci else 51108c2ecf20Sopenharmony_ci qed_disable_wfq_for_all_vports(p_hwfn, p_ptt, min_pf_rate); 51118c2ecf20Sopenharmony_ci 51128c2ecf20Sopenharmony_ci return rc; 51138c2ecf20Sopenharmony_ci} 51148c2ecf20Sopenharmony_ci 51158c2ecf20Sopenharmony_ci/* Main API for qed clients to configure vport min rate. 51168c2ecf20Sopenharmony_ci * vp_id - vport id in PF Range[0 - (total_num_vports_per_pf - 1)] 51178c2ecf20Sopenharmony_ci * rate - Speed in Mbps needs to be assigned to a given vport. 51188c2ecf20Sopenharmony_ci */ 51198c2ecf20Sopenharmony_ciint qed_configure_vport_wfq(struct qed_dev *cdev, u16 vp_id, u32 rate) 51208c2ecf20Sopenharmony_ci{ 51218c2ecf20Sopenharmony_ci int i, rc = -EINVAL; 51228c2ecf20Sopenharmony_ci 51238c2ecf20Sopenharmony_ci /* Currently not supported; Might change in future */ 51248c2ecf20Sopenharmony_ci if (cdev->num_hwfns > 1) { 51258c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 51268c2ecf20Sopenharmony_ci "WFQ configuration is not supported for this device\n"); 51278c2ecf20Sopenharmony_ci return rc; 51288c2ecf20Sopenharmony_ci } 51298c2ecf20Sopenharmony_ci 51308c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 51318c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 51328c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 51338c2ecf20Sopenharmony_ci 51348c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 51358c2ecf20Sopenharmony_ci if (!p_ptt) 51368c2ecf20Sopenharmony_ci return -EBUSY; 51378c2ecf20Sopenharmony_ci 51388c2ecf20Sopenharmony_ci rc = __qed_configure_vport_wfq(p_hwfn, p_ptt, vp_id, rate); 51398c2ecf20Sopenharmony_ci 51408c2ecf20Sopenharmony_ci if (rc) { 51418c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 51428c2ecf20Sopenharmony_ci return rc; 51438c2ecf20Sopenharmony_ci } 51448c2ecf20Sopenharmony_ci 51458c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 51468c2ecf20Sopenharmony_ci } 51478c2ecf20Sopenharmony_ci 51488c2ecf20Sopenharmony_ci return rc; 51498c2ecf20Sopenharmony_ci} 51508c2ecf20Sopenharmony_ci 51518c2ecf20Sopenharmony_ci/* API to configure WFQ from mcp link change */ 51528c2ecf20Sopenharmony_civoid qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev, 51538c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u32 min_pf_rate) 51548c2ecf20Sopenharmony_ci{ 51558c2ecf20Sopenharmony_ci int i; 51568c2ecf20Sopenharmony_ci 51578c2ecf20Sopenharmony_ci if (cdev->num_hwfns > 1) { 51588c2ecf20Sopenharmony_ci DP_VERBOSE(cdev, 51598c2ecf20Sopenharmony_ci NETIF_MSG_LINK, 51608c2ecf20Sopenharmony_ci "WFQ configuration is not supported for this device\n"); 51618c2ecf20Sopenharmony_ci return; 51628c2ecf20Sopenharmony_ci } 51638c2ecf20Sopenharmony_ci 51648c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 51658c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 51668c2ecf20Sopenharmony_ci 51678c2ecf20Sopenharmony_ci __qed_configure_vp_wfq_on_link_change(p_hwfn, p_ptt, 51688c2ecf20Sopenharmony_ci min_pf_rate); 51698c2ecf20Sopenharmony_ci } 51708c2ecf20Sopenharmony_ci} 51718c2ecf20Sopenharmony_ci 51728c2ecf20Sopenharmony_ciint __qed_configure_pf_max_bandwidth(struct qed_hwfn *p_hwfn, 51738c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 51748c2ecf20Sopenharmony_ci struct qed_mcp_link_state *p_link, 51758c2ecf20Sopenharmony_ci u8 max_bw) 51768c2ecf20Sopenharmony_ci{ 51778c2ecf20Sopenharmony_ci int rc = 0; 51788c2ecf20Sopenharmony_ci 51798c2ecf20Sopenharmony_ci p_hwfn->mcp_info->func_info.bandwidth_max = max_bw; 51808c2ecf20Sopenharmony_ci 51818c2ecf20Sopenharmony_ci if (!p_link->line_speed && (max_bw != 100)) 51828c2ecf20Sopenharmony_ci return rc; 51838c2ecf20Sopenharmony_ci 51848c2ecf20Sopenharmony_ci p_link->speed = (p_link->line_speed * max_bw) / 100; 51858c2ecf20Sopenharmony_ci p_hwfn->qm_info.pf_rl = p_link->speed; 51868c2ecf20Sopenharmony_ci 51878c2ecf20Sopenharmony_ci /* Since the limiter also affects Tx-switched traffic, we don't want it 51888c2ecf20Sopenharmony_ci * to limit such traffic in case there's no actual limit. 51898c2ecf20Sopenharmony_ci * In that case, set limit to imaginary high boundary. 51908c2ecf20Sopenharmony_ci */ 51918c2ecf20Sopenharmony_ci if (max_bw == 100) 51928c2ecf20Sopenharmony_ci p_hwfn->qm_info.pf_rl = 100000; 51938c2ecf20Sopenharmony_ci 51948c2ecf20Sopenharmony_ci rc = qed_init_pf_rl(p_hwfn, p_ptt, p_hwfn->rel_pf_id, 51958c2ecf20Sopenharmony_ci p_hwfn->qm_info.pf_rl); 51968c2ecf20Sopenharmony_ci 51978c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 51988c2ecf20Sopenharmony_ci "Configured MAX bandwidth to be %08x Mb/sec\n", 51998c2ecf20Sopenharmony_ci p_link->speed); 52008c2ecf20Sopenharmony_ci 52018c2ecf20Sopenharmony_ci return rc; 52028c2ecf20Sopenharmony_ci} 52038c2ecf20Sopenharmony_ci 52048c2ecf20Sopenharmony_ci/* Main API to configure PF max bandwidth where bw range is [1 - 100] */ 52058c2ecf20Sopenharmony_ciint qed_configure_pf_max_bandwidth(struct qed_dev *cdev, u8 max_bw) 52068c2ecf20Sopenharmony_ci{ 52078c2ecf20Sopenharmony_ci int i, rc = -EINVAL; 52088c2ecf20Sopenharmony_ci 52098c2ecf20Sopenharmony_ci if (max_bw < 1 || max_bw > 100) { 52108c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "PF max bw valid range is [1-100]\n"); 52118c2ecf20Sopenharmony_ci return rc; 52128c2ecf20Sopenharmony_ci } 52138c2ecf20Sopenharmony_ci 52148c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 52158c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 52168c2ecf20Sopenharmony_ci struct qed_hwfn *p_lead = QED_LEADING_HWFN(cdev); 52178c2ecf20Sopenharmony_ci struct qed_mcp_link_state *p_link; 52188c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 52198c2ecf20Sopenharmony_ci 52208c2ecf20Sopenharmony_ci p_link = &p_lead->mcp_info->link_output; 52218c2ecf20Sopenharmony_ci 52228c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 52238c2ecf20Sopenharmony_ci if (!p_ptt) 52248c2ecf20Sopenharmony_ci return -EBUSY; 52258c2ecf20Sopenharmony_ci 52268c2ecf20Sopenharmony_ci rc = __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt, 52278c2ecf20Sopenharmony_ci p_link, max_bw); 52288c2ecf20Sopenharmony_ci 52298c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 52308c2ecf20Sopenharmony_ci 52318c2ecf20Sopenharmony_ci if (rc) 52328c2ecf20Sopenharmony_ci break; 52338c2ecf20Sopenharmony_ci } 52348c2ecf20Sopenharmony_ci 52358c2ecf20Sopenharmony_ci return rc; 52368c2ecf20Sopenharmony_ci} 52378c2ecf20Sopenharmony_ci 52388c2ecf20Sopenharmony_ciint __qed_configure_pf_min_bandwidth(struct qed_hwfn *p_hwfn, 52398c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 52408c2ecf20Sopenharmony_ci struct qed_mcp_link_state *p_link, 52418c2ecf20Sopenharmony_ci u8 min_bw) 52428c2ecf20Sopenharmony_ci{ 52438c2ecf20Sopenharmony_ci int rc = 0; 52448c2ecf20Sopenharmony_ci 52458c2ecf20Sopenharmony_ci p_hwfn->mcp_info->func_info.bandwidth_min = min_bw; 52468c2ecf20Sopenharmony_ci p_hwfn->qm_info.pf_wfq = min_bw; 52478c2ecf20Sopenharmony_ci 52488c2ecf20Sopenharmony_ci if (!p_link->line_speed) 52498c2ecf20Sopenharmony_ci return rc; 52508c2ecf20Sopenharmony_ci 52518c2ecf20Sopenharmony_ci p_link->min_pf_rate = (p_link->line_speed * min_bw) / 100; 52528c2ecf20Sopenharmony_ci 52538c2ecf20Sopenharmony_ci rc = qed_init_pf_wfq(p_hwfn, p_ptt, p_hwfn->rel_pf_id, min_bw); 52548c2ecf20Sopenharmony_ci 52558c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 52568c2ecf20Sopenharmony_ci "Configured MIN bandwidth to be %d Mb/sec\n", 52578c2ecf20Sopenharmony_ci p_link->min_pf_rate); 52588c2ecf20Sopenharmony_ci 52598c2ecf20Sopenharmony_ci return rc; 52608c2ecf20Sopenharmony_ci} 52618c2ecf20Sopenharmony_ci 52628c2ecf20Sopenharmony_ci/* Main API to configure PF min bandwidth where bw range is [1-100] */ 52638c2ecf20Sopenharmony_ciint qed_configure_pf_min_bandwidth(struct qed_dev *cdev, u8 min_bw) 52648c2ecf20Sopenharmony_ci{ 52658c2ecf20Sopenharmony_ci int i, rc = -EINVAL; 52668c2ecf20Sopenharmony_ci 52678c2ecf20Sopenharmony_ci if (min_bw < 1 || min_bw > 100) { 52688c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "PF min bw valid range is [1-100]\n"); 52698c2ecf20Sopenharmony_ci return rc; 52708c2ecf20Sopenharmony_ci } 52718c2ecf20Sopenharmony_ci 52728c2ecf20Sopenharmony_ci for_each_hwfn(cdev, i) { 52738c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; 52748c2ecf20Sopenharmony_ci struct qed_hwfn *p_lead = QED_LEADING_HWFN(cdev); 52758c2ecf20Sopenharmony_ci struct qed_mcp_link_state *p_link; 52768c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 52778c2ecf20Sopenharmony_ci 52788c2ecf20Sopenharmony_ci p_link = &p_lead->mcp_info->link_output; 52798c2ecf20Sopenharmony_ci 52808c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 52818c2ecf20Sopenharmony_ci if (!p_ptt) 52828c2ecf20Sopenharmony_ci return -EBUSY; 52838c2ecf20Sopenharmony_ci 52848c2ecf20Sopenharmony_ci rc = __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt, 52858c2ecf20Sopenharmony_ci p_link, min_bw); 52868c2ecf20Sopenharmony_ci if (rc) { 52878c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 52888c2ecf20Sopenharmony_ci return rc; 52898c2ecf20Sopenharmony_ci } 52908c2ecf20Sopenharmony_ci 52918c2ecf20Sopenharmony_ci if (p_link->min_pf_rate) { 52928c2ecf20Sopenharmony_ci u32 min_rate = p_link->min_pf_rate; 52938c2ecf20Sopenharmony_ci 52948c2ecf20Sopenharmony_ci rc = __qed_configure_vp_wfq_on_link_change(p_hwfn, 52958c2ecf20Sopenharmony_ci p_ptt, 52968c2ecf20Sopenharmony_ci min_rate); 52978c2ecf20Sopenharmony_ci } 52988c2ecf20Sopenharmony_ci 52998c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 53008c2ecf20Sopenharmony_ci } 53018c2ecf20Sopenharmony_ci 53028c2ecf20Sopenharmony_ci return rc; 53038c2ecf20Sopenharmony_ci} 53048c2ecf20Sopenharmony_ci 53058c2ecf20Sopenharmony_civoid qed_clean_wfq_db(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 53068c2ecf20Sopenharmony_ci{ 53078c2ecf20Sopenharmony_ci struct qed_mcp_link_state *p_link; 53088c2ecf20Sopenharmony_ci 53098c2ecf20Sopenharmony_ci p_link = &p_hwfn->mcp_info->link_output; 53108c2ecf20Sopenharmony_ci 53118c2ecf20Sopenharmony_ci if (p_link->min_pf_rate) 53128c2ecf20Sopenharmony_ci qed_disable_wfq_for_all_vports(p_hwfn, p_ptt, 53138c2ecf20Sopenharmony_ci p_link->min_pf_rate); 53148c2ecf20Sopenharmony_ci 53158c2ecf20Sopenharmony_ci memset(p_hwfn->qm_info.wfq_data, 0, 53168c2ecf20Sopenharmony_ci sizeof(*p_hwfn->qm_info.wfq_data) * p_hwfn->qm_info.num_vports); 53178c2ecf20Sopenharmony_ci} 53188c2ecf20Sopenharmony_ci 53198c2ecf20Sopenharmony_ciint qed_device_num_ports(struct qed_dev *cdev) 53208c2ecf20Sopenharmony_ci{ 53218c2ecf20Sopenharmony_ci return cdev->num_ports; 53228c2ecf20Sopenharmony_ci} 53238c2ecf20Sopenharmony_ci 53248c2ecf20Sopenharmony_civoid qed_set_fw_mac_addr(__le16 *fw_msb, 53258c2ecf20Sopenharmony_ci __le16 *fw_mid, __le16 *fw_lsb, u8 *mac) 53268c2ecf20Sopenharmony_ci{ 53278c2ecf20Sopenharmony_ci ((u8 *)fw_msb)[0] = mac[1]; 53288c2ecf20Sopenharmony_ci ((u8 *)fw_msb)[1] = mac[0]; 53298c2ecf20Sopenharmony_ci ((u8 *)fw_mid)[0] = mac[3]; 53308c2ecf20Sopenharmony_ci ((u8 *)fw_mid)[1] = mac[2]; 53318c2ecf20Sopenharmony_ci ((u8 *)fw_lsb)[0] = mac[5]; 53328c2ecf20Sopenharmony_ci ((u8 *)fw_lsb)[1] = mac[4]; 53338c2ecf20Sopenharmony_ci} 5334