18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet 38c2ecf20Sopenharmony_ci * driver for Linux. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 88c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 98c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 108c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 118c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 148c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 158c2ecf20Sopenharmony_ci * conditions are met: 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 188c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 198c2ecf20Sopenharmony_ci * disclaimer. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 228c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 238c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 248c2ecf20Sopenharmony_ci * provided with the distribution. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 278c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 288c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 298c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 308c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 318c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 328c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 338c2ecf20Sopenharmony_ci * SOFTWARE. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/pci.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "t4vf_common.h" 398c2ecf20Sopenharmony_ci#include "t4vf_defs.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include "../cxgb4/t4_regs.h" 428c2ecf20Sopenharmony_ci#include "../cxgb4/t4_values.h" 438c2ecf20Sopenharmony_ci#include "../cxgb4/t4fw_api.h" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Wait for the device to become ready (signified by our "who am I" register 478c2ecf20Sopenharmony_ci * returning a value other than all 1's). Return an error if it doesn't 488c2ecf20Sopenharmony_ci * become ready ... 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ciint t4vf_wait_dev_ready(struct adapter *adapter) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci const u32 whoami = T4VF_PL_BASE_ADDR + PL_VF_WHOAMI; 538c2ecf20Sopenharmony_ci const u32 notready1 = 0xffffffff; 548c2ecf20Sopenharmony_ci const u32 notready2 = 0xeeeeeeee; 558c2ecf20Sopenharmony_ci u32 val; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci val = t4_read_reg(adapter, whoami); 588c2ecf20Sopenharmony_ci if (val != notready1 && val != notready2) 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci msleep(500); 618c2ecf20Sopenharmony_ci val = t4_read_reg(adapter, whoami); 628c2ecf20Sopenharmony_ci if (val != notready1 && val != notready2) 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci else 658c2ecf20Sopenharmony_ci return -EIO; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci * Get the reply to a mailbox command and store it in @rpl in big-endian order 708c2ecf20Sopenharmony_ci * (since the firmware data structures are specified in a big-endian layout). 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_cistatic void get_mbox_rpl(struct adapter *adapter, __be64 *rpl, int size, 738c2ecf20Sopenharmony_ci u32 mbox_data) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci for ( ; size; size -= 8, mbox_data += 8) 768c2ecf20Sopenharmony_ci *rpl++ = cpu_to_be64(t4_read_reg64(adapter, mbox_data)); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/** 808c2ecf20Sopenharmony_ci * t4vf_record_mbox - record a Firmware Mailbox Command/Reply in the log 818c2ecf20Sopenharmony_ci * @adapter: the adapter 828c2ecf20Sopenharmony_ci * @cmd: the Firmware Mailbox Command or Reply 838c2ecf20Sopenharmony_ci * @size: command length in bytes 848c2ecf20Sopenharmony_ci * @access: the time (ms) needed to access the Firmware Mailbox 858c2ecf20Sopenharmony_ci * @execute: the time (ms) the command spent being executed 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic void t4vf_record_mbox(struct adapter *adapter, const __be64 *cmd, 888c2ecf20Sopenharmony_ci int size, int access, int execute) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct mbox_cmd_log *log = adapter->mbox_log; 918c2ecf20Sopenharmony_ci struct mbox_cmd *entry; 928c2ecf20Sopenharmony_ci int i; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci entry = mbox_cmd_log_entry(log, log->cursor++); 958c2ecf20Sopenharmony_ci if (log->cursor == log->size) 968c2ecf20Sopenharmony_ci log->cursor = 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci for (i = 0; i < size / 8; i++) 998c2ecf20Sopenharmony_ci entry->cmd[i] = be64_to_cpu(cmd[i]); 1008c2ecf20Sopenharmony_ci while (i < MBOX_LEN / 8) 1018c2ecf20Sopenharmony_ci entry->cmd[i++] = 0; 1028c2ecf20Sopenharmony_ci entry->timestamp = jiffies; 1038c2ecf20Sopenharmony_ci entry->seqno = log->seqno++; 1048c2ecf20Sopenharmony_ci entry->access = access; 1058c2ecf20Sopenharmony_ci entry->execute = execute; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/** 1098c2ecf20Sopenharmony_ci * t4vf_wr_mbox_core - send a command to FW through the mailbox 1108c2ecf20Sopenharmony_ci * @adapter: the adapter 1118c2ecf20Sopenharmony_ci * @cmd: the command to write 1128c2ecf20Sopenharmony_ci * @size: command length in bytes 1138c2ecf20Sopenharmony_ci * @rpl: where to optionally store the reply 1148c2ecf20Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 1158c2ecf20Sopenharmony_ci * 1168c2ecf20Sopenharmony_ci * Sends the given command to FW through the mailbox and waits for the 1178c2ecf20Sopenharmony_ci * FW to execute the command. If @rpl is not %NULL it is used to store 1188c2ecf20Sopenharmony_ci * the FW's reply to the command. The command and its optional reply 1198c2ecf20Sopenharmony_ci * are of the same length. FW can take up to 500 ms to respond. 1208c2ecf20Sopenharmony_ci * @sleep_ok determines whether we may sleep while awaiting the response. 1218c2ecf20Sopenharmony_ci * If sleeping is allowed we use progressive backoff otherwise we spin. 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * The return value is 0 on success or a negative errno on failure. A 1248c2ecf20Sopenharmony_ci * failure can happen either because we are not able to execute the 1258c2ecf20Sopenharmony_ci * command or FW executes it but signals an error. In the latter case 1268c2ecf20Sopenharmony_ci * the return value is the error code indicated by FW (negated). 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ciint t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, 1298c2ecf20Sopenharmony_ci void *rpl, bool sleep_ok) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci static const int delay[] = { 1328c2ecf20Sopenharmony_ci 1, 1, 3, 5, 10, 10, 20, 50, 100 1338c2ecf20Sopenharmony_ci }; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci u16 access = 0, execute = 0; 1368c2ecf20Sopenharmony_ci u32 v, mbox_data; 1378c2ecf20Sopenharmony_ci int i, ms, delay_idx, ret; 1388c2ecf20Sopenharmony_ci const __be64 *p; 1398c2ecf20Sopenharmony_ci u32 mbox_ctl = T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL; 1408c2ecf20Sopenharmony_ci u32 cmd_op = FW_CMD_OP_G(be32_to_cpu(((struct fw_cmd_hdr *)cmd)->hi)); 1418c2ecf20Sopenharmony_ci __be64 cmd_rpl[MBOX_LEN / 8]; 1428c2ecf20Sopenharmony_ci struct mbox_list entry; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* In T6, mailbox size is changed to 128 bytes to avoid 1458c2ecf20Sopenharmony_ci * invalidating the entire prefetch buffer. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) 1488c2ecf20Sopenharmony_ci mbox_data = T4VF_MBDATA_BASE_ADDR; 1498c2ecf20Sopenharmony_ci else 1508c2ecf20Sopenharmony_ci mbox_data = T6VF_MBDATA_BASE_ADDR; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* 1538c2ecf20Sopenharmony_ci * Commands must be multiples of 16 bytes in length and may not be 1548c2ecf20Sopenharmony_ci * larger than the size of the Mailbox Data register array. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci if ((size % 16) != 0 || 1578c2ecf20Sopenharmony_ci size > NUM_CIM_VF_MAILBOX_DATA_INSTANCES * 4) 1588c2ecf20Sopenharmony_ci return -EINVAL; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Queue ourselves onto the mailbox access list. When our entry is at 1618c2ecf20Sopenharmony_ci * the front of the list, we have rights to access the mailbox. So we 1628c2ecf20Sopenharmony_ci * wait [for a while] till we're at the front [or bail out with an 1638c2ecf20Sopenharmony_ci * EBUSY] ... 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci spin_lock(&adapter->mbox_lock); 1668c2ecf20Sopenharmony_ci list_add_tail(&entry.list, &adapter->mlist.list); 1678c2ecf20Sopenharmony_ci spin_unlock(&adapter->mbox_lock); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci delay_idx = 0; 1708c2ecf20Sopenharmony_ci ms = delay[0]; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci for (i = 0; ; i += ms) { 1738c2ecf20Sopenharmony_ci /* If we've waited too long, return a busy indication. This 1748c2ecf20Sopenharmony_ci * really ought to be based on our initial position in the 1758c2ecf20Sopenharmony_ci * mailbox access list but this is a start. We very rearely 1768c2ecf20Sopenharmony_ci * contend on access to the mailbox ... 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci if (i > FW_CMD_MAX_TIMEOUT) { 1798c2ecf20Sopenharmony_ci spin_lock(&adapter->mbox_lock); 1808c2ecf20Sopenharmony_ci list_del(&entry.list); 1818c2ecf20Sopenharmony_ci spin_unlock(&adapter->mbox_lock); 1828c2ecf20Sopenharmony_ci ret = -EBUSY; 1838c2ecf20Sopenharmony_ci t4vf_record_mbox(adapter, cmd, size, access, ret); 1848c2ecf20Sopenharmony_ci return ret; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* If we're at the head, break out and start the mailbox 1888c2ecf20Sopenharmony_ci * protocol. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci if (list_first_entry(&adapter->mlist.list, struct mbox_list, 1918c2ecf20Sopenharmony_ci list) == &entry) 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* Delay for a bit before checking again ... */ 1958c2ecf20Sopenharmony_ci if (sleep_ok) { 1968c2ecf20Sopenharmony_ci ms = delay[delay_idx]; /* last element may repeat */ 1978c2ecf20Sopenharmony_ci if (delay_idx < ARRAY_SIZE(delay) - 1) 1988c2ecf20Sopenharmony_ci delay_idx++; 1998c2ecf20Sopenharmony_ci msleep(ms); 2008c2ecf20Sopenharmony_ci } else { 2018c2ecf20Sopenharmony_ci mdelay(ms); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* 2068c2ecf20Sopenharmony_ci * Loop trying to get ownership of the mailbox. Return an error 2078c2ecf20Sopenharmony_ci * if we can't gain ownership. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl)); 2108c2ecf20Sopenharmony_ci for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) 2118c2ecf20Sopenharmony_ci v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl)); 2128c2ecf20Sopenharmony_ci if (v != MBOX_OWNER_DRV) { 2138c2ecf20Sopenharmony_ci spin_lock(&adapter->mbox_lock); 2148c2ecf20Sopenharmony_ci list_del(&entry.list); 2158c2ecf20Sopenharmony_ci spin_unlock(&adapter->mbox_lock); 2168c2ecf20Sopenharmony_ci ret = (v == MBOX_OWNER_FW) ? -EBUSY : -ETIMEDOUT; 2178c2ecf20Sopenharmony_ci t4vf_record_mbox(adapter, cmd, size, access, ret); 2188c2ecf20Sopenharmony_ci return ret; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * Write the command array into the Mailbox Data register array and 2238c2ecf20Sopenharmony_ci * transfer ownership of the mailbox to the firmware. 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * For the VFs, the Mailbox Data "registers" are actually backed by 2268c2ecf20Sopenharmony_ci * T4's "MA" interface rather than PL Registers (as is the case for 2278c2ecf20Sopenharmony_ci * the PFs). Because these are in different coherency domains, the 2288c2ecf20Sopenharmony_ci * write to the VF's PL-register-backed Mailbox Control can race in 2298c2ecf20Sopenharmony_ci * front of the writes to the MA-backed VF Mailbox Data "registers". 2308c2ecf20Sopenharmony_ci * So we need to do a read-back on at least one byte of the VF Mailbox 2318c2ecf20Sopenharmony_ci * Data registers before doing the write to the VF Mailbox Control 2328c2ecf20Sopenharmony_ci * register. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci if (cmd_op != FW_VI_STATS_CMD) 2358c2ecf20Sopenharmony_ci t4vf_record_mbox(adapter, cmd, size, access, 0); 2368c2ecf20Sopenharmony_ci for (i = 0, p = cmd; i < size; i += 8) 2378c2ecf20Sopenharmony_ci t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++)); 2388c2ecf20Sopenharmony_ci t4_read_reg(adapter, mbox_data); /* flush write */ 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci t4_write_reg(adapter, mbox_ctl, 2418c2ecf20Sopenharmony_ci MBMSGVALID_F | MBOWNER_V(MBOX_OWNER_FW)); 2428c2ecf20Sopenharmony_ci t4_read_reg(adapter, mbox_ctl); /* flush write */ 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* 2458c2ecf20Sopenharmony_ci * Spin waiting for firmware to acknowledge processing our command. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci delay_idx = 0; 2488c2ecf20Sopenharmony_ci ms = delay[0]; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { 2518c2ecf20Sopenharmony_ci if (sleep_ok) { 2528c2ecf20Sopenharmony_ci ms = delay[delay_idx]; 2538c2ecf20Sopenharmony_ci if (delay_idx < ARRAY_SIZE(delay) - 1) 2548c2ecf20Sopenharmony_ci delay_idx++; 2558c2ecf20Sopenharmony_ci msleep(ms); 2568c2ecf20Sopenharmony_ci } else 2578c2ecf20Sopenharmony_ci mdelay(ms); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* 2608c2ecf20Sopenharmony_ci * If we're the owner, see if this is the reply we wanted. 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_ci v = t4_read_reg(adapter, mbox_ctl); 2638c2ecf20Sopenharmony_ci if (MBOWNER_G(v) == MBOX_OWNER_DRV) { 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * If the Message Valid bit isn't on, revoke ownership 2668c2ecf20Sopenharmony_ci * of the mailbox and continue waiting for our reply. 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ci if ((v & MBMSGVALID_F) == 0) { 2698c2ecf20Sopenharmony_ci t4_write_reg(adapter, mbox_ctl, 2708c2ecf20Sopenharmony_ci MBOWNER_V(MBOX_OWNER_NONE)); 2718c2ecf20Sopenharmony_ci continue; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* 2758c2ecf20Sopenharmony_ci * We now have our reply. Extract the command return 2768c2ecf20Sopenharmony_ci * value, copy the reply back to our caller's buffer 2778c2ecf20Sopenharmony_ci * (if specified) and revoke ownership of the mailbox. 2788c2ecf20Sopenharmony_ci * We return the (negated) firmware command return 2798c2ecf20Sopenharmony_ci * code (this depends on FW_SUCCESS == 0). 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci get_mbox_rpl(adapter, cmd_rpl, size, mbox_data); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* return value in low-order little-endian word */ 2848c2ecf20Sopenharmony_ci v = be64_to_cpu(cmd_rpl[0]); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (rpl) { 2878c2ecf20Sopenharmony_ci /* request bit in high-order BE word */ 2888c2ecf20Sopenharmony_ci WARN_ON((be32_to_cpu(*(const __be32 *)cmd) 2898c2ecf20Sopenharmony_ci & FW_CMD_REQUEST_F) == 0); 2908c2ecf20Sopenharmony_ci memcpy(rpl, cmd_rpl, size); 2918c2ecf20Sopenharmony_ci WARN_ON((be32_to_cpu(*(__be32 *)rpl) 2928c2ecf20Sopenharmony_ci & FW_CMD_REQUEST_F) != 0); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci t4_write_reg(adapter, mbox_ctl, 2958c2ecf20Sopenharmony_ci MBOWNER_V(MBOX_OWNER_NONE)); 2968c2ecf20Sopenharmony_ci execute = i + ms; 2978c2ecf20Sopenharmony_ci if (cmd_op != FW_VI_STATS_CMD) 2988c2ecf20Sopenharmony_ci t4vf_record_mbox(adapter, cmd_rpl, size, access, 2998c2ecf20Sopenharmony_ci execute); 3008c2ecf20Sopenharmony_ci spin_lock(&adapter->mbox_lock); 3018c2ecf20Sopenharmony_ci list_del(&entry.list); 3028c2ecf20Sopenharmony_ci spin_unlock(&adapter->mbox_lock); 3038c2ecf20Sopenharmony_ci return -FW_CMD_RETVAL_G(v); 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* We timed out. Return the error ... */ 3088c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 3098c2ecf20Sopenharmony_ci t4vf_record_mbox(adapter, cmd, size, access, ret); 3108c2ecf20Sopenharmony_ci spin_lock(&adapter->mbox_lock); 3118c2ecf20Sopenharmony_ci list_del(&entry.list); 3128c2ecf20Sopenharmony_ci spin_unlock(&adapter->mbox_lock); 3138c2ecf20Sopenharmony_ci return ret; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/* In the Physical Function Driver Common Code, the ADVERT_MASK is used to 3178c2ecf20Sopenharmony_ci * mask out bits in the Advertised Port Capabilities which are managed via 3188c2ecf20Sopenharmony_ci * separate controls, like Pause Frames and Forward Error Correction. In the 3198c2ecf20Sopenharmony_ci * Virtual Function Common Code, since we never perform L1 Configuration on 3208c2ecf20Sopenharmony_ci * the Link, the only things we really need to filter out are things which 3218c2ecf20Sopenharmony_ci * we decode and report separately like Speed. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci#define ADVERT_MASK (FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) | \ 3248c2ecf20Sopenharmony_ci FW_PORT_CAP32_802_3_PAUSE | \ 3258c2ecf20Sopenharmony_ci FW_PORT_CAP32_802_3_ASM_DIR | \ 3268c2ecf20Sopenharmony_ci FW_PORT_CAP32_FEC_V(FW_PORT_CAP32_FEC_M) | \ 3278c2ecf20Sopenharmony_ci FW_PORT_CAP32_ANEG) 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/** 3308c2ecf20Sopenharmony_ci * fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits 3318c2ecf20Sopenharmony_ci * @caps16: a 16-bit Port Capabilities value 3328c2ecf20Sopenharmony_ci * 3338c2ecf20Sopenharmony_ci * Returns the equivalent 32-bit Port Capabilities value. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_cistatic fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci fw_port_cap32_t caps32 = 0; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci #define CAP16_TO_CAP32(__cap) \ 3408c2ecf20Sopenharmony_ci do { \ 3418c2ecf20Sopenharmony_ci if (caps16 & FW_PORT_CAP_##__cap) \ 3428c2ecf20Sopenharmony_ci caps32 |= FW_PORT_CAP32_##__cap; \ 3438c2ecf20Sopenharmony_ci } while (0) 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci CAP16_TO_CAP32(SPEED_100M); 3468c2ecf20Sopenharmony_ci CAP16_TO_CAP32(SPEED_1G); 3478c2ecf20Sopenharmony_ci CAP16_TO_CAP32(SPEED_25G); 3488c2ecf20Sopenharmony_ci CAP16_TO_CAP32(SPEED_10G); 3498c2ecf20Sopenharmony_ci CAP16_TO_CAP32(SPEED_40G); 3508c2ecf20Sopenharmony_ci CAP16_TO_CAP32(SPEED_100G); 3518c2ecf20Sopenharmony_ci CAP16_TO_CAP32(FC_RX); 3528c2ecf20Sopenharmony_ci CAP16_TO_CAP32(FC_TX); 3538c2ecf20Sopenharmony_ci CAP16_TO_CAP32(ANEG); 3548c2ecf20Sopenharmony_ci CAP16_TO_CAP32(MDIAUTO); 3558c2ecf20Sopenharmony_ci CAP16_TO_CAP32(MDISTRAIGHT); 3568c2ecf20Sopenharmony_ci CAP16_TO_CAP32(FEC_RS); 3578c2ecf20Sopenharmony_ci CAP16_TO_CAP32(FEC_BASER_RS); 3588c2ecf20Sopenharmony_ci CAP16_TO_CAP32(802_3_PAUSE); 3598c2ecf20Sopenharmony_ci CAP16_TO_CAP32(802_3_ASM_DIR); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci #undef CAP16_TO_CAP32 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return caps32; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* Translate Firmware Pause specification to Common Code */ 3678c2ecf20Sopenharmony_cistatic inline enum cc_pause fwcap_to_cc_pause(fw_port_cap32_t fw_pause) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci enum cc_pause cc_pause = 0; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (fw_pause & FW_PORT_CAP32_FC_RX) 3728c2ecf20Sopenharmony_ci cc_pause |= PAUSE_RX; 3738c2ecf20Sopenharmony_ci if (fw_pause & FW_PORT_CAP32_FC_TX) 3748c2ecf20Sopenharmony_ci cc_pause |= PAUSE_TX; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return cc_pause; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/* Translate Firmware Forward Error Correction specification to Common Code */ 3808c2ecf20Sopenharmony_cistatic inline enum cc_fec fwcap_to_cc_fec(fw_port_cap32_t fw_fec) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci enum cc_fec cc_fec = 0; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (fw_fec & FW_PORT_CAP32_FEC_RS) 3858c2ecf20Sopenharmony_ci cc_fec |= FEC_RS; 3868c2ecf20Sopenharmony_ci if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS) 3878c2ecf20Sopenharmony_ci cc_fec |= FEC_BASER_RS; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return cc_fec; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/* Return the highest speed set in the port capabilities, in Mb/s. */ 3938c2ecf20Sopenharmony_cistatic unsigned int fwcap_to_speed(fw_port_cap32_t caps) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci #define TEST_SPEED_RETURN(__caps_speed, __speed) \ 3968c2ecf20Sopenharmony_ci do { \ 3978c2ecf20Sopenharmony_ci if (caps & FW_PORT_CAP32_SPEED_##__caps_speed) \ 3988c2ecf20Sopenharmony_ci return __speed; \ 3998c2ecf20Sopenharmony_ci } while (0) 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(400G, 400000); 4028c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(200G, 200000); 4038c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(100G, 100000); 4048c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(50G, 50000); 4058c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(40G, 40000); 4068c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(25G, 25000); 4078c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(10G, 10000); 4088c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(1G, 1000); 4098c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(100M, 100); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci #undef TEST_SPEED_RETURN 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/** 4178c2ecf20Sopenharmony_ci * fwcap_to_fwspeed - return highest speed in Port Capabilities 4188c2ecf20Sopenharmony_ci * @acaps: advertised Port Capabilities 4198c2ecf20Sopenharmony_ci * 4208c2ecf20Sopenharmony_ci * Get the highest speed for the port from the advertised Port 4218c2ecf20Sopenharmony_ci * Capabilities. It will be either the highest speed from the list of 4228c2ecf20Sopenharmony_ci * speeds or whatever user has set using ethtool. 4238c2ecf20Sopenharmony_ci */ 4248c2ecf20Sopenharmony_cistatic fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci #define TEST_SPEED_RETURN(__caps_speed) \ 4278c2ecf20Sopenharmony_ci do { \ 4288c2ecf20Sopenharmony_ci if (acaps & FW_PORT_CAP32_SPEED_##__caps_speed) \ 4298c2ecf20Sopenharmony_ci return FW_PORT_CAP32_SPEED_##__caps_speed; \ 4308c2ecf20Sopenharmony_ci } while (0) 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(400G); 4338c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(200G); 4348c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(100G); 4358c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(50G); 4368c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(40G); 4378c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(25G); 4388c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(10G); 4398c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(1G); 4408c2ecf20Sopenharmony_ci TEST_SPEED_RETURN(100M); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci #undef TEST_SPEED_RETURN 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* 4478c2ecf20Sopenharmony_ci * init_link_config - initialize a link's SW state 4488c2ecf20Sopenharmony_ci * @lc: structure holding the link state 4498c2ecf20Sopenharmony_ci * @pcaps: link Port Capabilities 4508c2ecf20Sopenharmony_ci * @acaps: link current Advertised Port Capabilities 4518c2ecf20Sopenharmony_ci * 4528c2ecf20Sopenharmony_ci * Initializes the SW state maintained for each link, including the link's 4538c2ecf20Sopenharmony_ci * capabilities and default speed/flow-control/autonegotiation settings. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_cistatic void init_link_config(struct link_config *lc, 4568c2ecf20Sopenharmony_ci fw_port_cap32_t pcaps, 4578c2ecf20Sopenharmony_ci fw_port_cap32_t acaps) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci lc->pcaps = pcaps; 4608c2ecf20Sopenharmony_ci lc->lpacaps = 0; 4618c2ecf20Sopenharmony_ci lc->speed_caps = 0; 4628c2ecf20Sopenharmony_ci lc->speed = 0; 4638c2ecf20Sopenharmony_ci lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* For Forward Error Control, we default to whatever the Firmware 4668c2ecf20Sopenharmony_ci * tells us the Link is currently advertising. 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci lc->auto_fec = fwcap_to_cc_fec(acaps); 4698c2ecf20Sopenharmony_ci lc->requested_fec = FEC_AUTO; 4708c2ecf20Sopenharmony_ci lc->fec = lc->auto_fec; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* If the Port is capable of Auto-Negtotiation, initialize it as 4738c2ecf20Sopenharmony_ci * "enabled" and copy over all of the Physical Port Capabilities 4748c2ecf20Sopenharmony_ci * to the Advertised Port Capabilities. Otherwise mark it as 4758c2ecf20Sopenharmony_ci * Auto-Negotiate disabled and select the highest supported speed 4768c2ecf20Sopenharmony_ci * for the link. Note parallel structure in t4_link_l1cfg_core() 4778c2ecf20Sopenharmony_ci * and t4_handle_get_port_info(). 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci if (lc->pcaps & FW_PORT_CAP32_ANEG) { 4808c2ecf20Sopenharmony_ci lc->acaps = acaps & ADVERT_MASK; 4818c2ecf20Sopenharmony_ci lc->autoneg = AUTONEG_ENABLE; 4828c2ecf20Sopenharmony_ci lc->requested_fc |= PAUSE_AUTONEG; 4838c2ecf20Sopenharmony_ci } else { 4848c2ecf20Sopenharmony_ci lc->acaps = 0; 4858c2ecf20Sopenharmony_ci lc->autoneg = AUTONEG_DISABLE; 4868c2ecf20Sopenharmony_ci lc->speed_caps = fwcap_to_fwspeed(acaps); 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/** 4918c2ecf20Sopenharmony_ci * t4vf_port_init - initialize port hardware/software state 4928c2ecf20Sopenharmony_ci * @adapter: the adapter 4938c2ecf20Sopenharmony_ci * @pidx: the adapter port index 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_ciint t4vf_port_init(struct adapter *adapter, int pidx) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci struct port_info *pi = adap2pinfo(adapter, pidx); 4988c2ecf20Sopenharmony_ci unsigned int fw_caps = adapter->params.fw_caps_support; 4998c2ecf20Sopenharmony_ci struct fw_vi_cmd vi_cmd, vi_rpl; 5008c2ecf20Sopenharmony_ci struct fw_port_cmd port_cmd, port_rpl; 5018c2ecf20Sopenharmony_ci enum fw_port_type port_type; 5028c2ecf20Sopenharmony_ci int mdio_addr; 5038c2ecf20Sopenharmony_ci fw_port_cap32_t pcaps, acaps; 5048c2ecf20Sopenharmony_ci int ret; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* If we haven't yet determined whether we're talking to Firmware 5078c2ecf20Sopenharmony_ci * which knows the new 32-bit Port Capabilities, it's time to find 5088c2ecf20Sopenharmony_ci * out now. This will also tell new Firmware to send us Port Status 5098c2ecf20Sopenharmony_ci * Updates using the new 32-bit Port Capabilities version of the 5108c2ecf20Sopenharmony_ci * Port Information message. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_ci if (fw_caps == FW_CAPS_UNKNOWN) { 5138c2ecf20Sopenharmony_ci u32 param, val; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | 5168c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_PORT_CAPS32)); 5178c2ecf20Sopenharmony_ci val = 1; 5188c2ecf20Sopenharmony_ci ret = t4vf_set_params(adapter, 1, ¶m, &val); 5198c2ecf20Sopenharmony_ci fw_caps = (ret == 0 ? FW_CAPS32 : FW_CAPS16); 5208c2ecf20Sopenharmony_ci adapter->params.fw_caps_support = fw_caps; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* 5248c2ecf20Sopenharmony_ci * Execute a VI Read command to get our Virtual Interface information 5258c2ecf20Sopenharmony_ci * like MAC address, etc. 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_ci memset(&vi_cmd, 0, sizeof(vi_cmd)); 5288c2ecf20Sopenharmony_ci vi_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) | 5298c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 5308c2ecf20Sopenharmony_ci FW_CMD_READ_F); 5318c2ecf20Sopenharmony_ci vi_cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(vi_cmd)); 5328c2ecf20Sopenharmony_ci vi_cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID_V(pi->viid)); 5338c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox(adapter, &vi_cmd, sizeof(vi_cmd), &vi_rpl); 5348c2ecf20Sopenharmony_ci if (ret != FW_SUCCESS) 5358c2ecf20Sopenharmony_ci return ret; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci BUG_ON(pi->port_id != FW_VI_CMD_PORTID_G(vi_rpl.portid_pkd)); 5388c2ecf20Sopenharmony_ci pi->rss_size = FW_VI_CMD_RSSSIZE_G(be16_to_cpu(vi_rpl.rsssize_pkd)); 5398c2ecf20Sopenharmony_ci t4_os_set_hw_addr(adapter, pidx, vi_rpl.mac); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* 5428c2ecf20Sopenharmony_ci * If we don't have read access to our port information, we're done 5438c2ecf20Sopenharmony_ci * now. Otherwise, execute a PORT Read command to get it ... 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_ci if (!(adapter->params.vfres.r_caps & FW_CMD_CAP_PORT)) 5468c2ecf20Sopenharmony_ci return 0; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci memset(&port_cmd, 0, sizeof(port_cmd)); 5498c2ecf20Sopenharmony_ci port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | 5508c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 5518c2ecf20Sopenharmony_ci FW_CMD_READ_F | 5528c2ecf20Sopenharmony_ci FW_PORT_CMD_PORTID_V(pi->port_id)); 5538c2ecf20Sopenharmony_ci port_cmd.action_to_len16 = cpu_to_be32( 5548c2ecf20Sopenharmony_ci FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16 5558c2ecf20Sopenharmony_ci ? FW_PORT_ACTION_GET_PORT_INFO 5568c2ecf20Sopenharmony_ci : FW_PORT_ACTION_GET_PORT_INFO32) | 5578c2ecf20Sopenharmony_ci FW_LEN16(port_cmd)); 5588c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox(adapter, &port_cmd, sizeof(port_cmd), &port_rpl); 5598c2ecf20Sopenharmony_ci if (ret != FW_SUCCESS) 5608c2ecf20Sopenharmony_ci return ret; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Extract the various fields from the Port Information message. */ 5638c2ecf20Sopenharmony_ci if (fw_caps == FW_CAPS16) { 5648c2ecf20Sopenharmony_ci u32 lstatus = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci port_type = FW_PORT_CMD_PTYPE_G(lstatus); 5678c2ecf20Sopenharmony_ci mdio_addr = ((lstatus & FW_PORT_CMD_MDIOCAP_F) 5688c2ecf20Sopenharmony_ci ? FW_PORT_CMD_MDIOADDR_G(lstatus) 5698c2ecf20Sopenharmony_ci : -1); 5708c2ecf20Sopenharmony_ci pcaps = fwcaps16_to_caps32(be16_to_cpu(port_rpl.u.info.pcap)); 5718c2ecf20Sopenharmony_ci acaps = fwcaps16_to_caps32(be16_to_cpu(port_rpl.u.info.acap)); 5728c2ecf20Sopenharmony_ci } else { 5738c2ecf20Sopenharmony_ci u32 lstatus32 = 5748c2ecf20Sopenharmony_ci be32_to_cpu(port_rpl.u.info32.lstatus32_to_cbllen32); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci port_type = FW_PORT_CMD_PORTTYPE32_G(lstatus32); 5778c2ecf20Sopenharmony_ci mdio_addr = ((lstatus32 & FW_PORT_CMD_MDIOCAP32_F) 5788c2ecf20Sopenharmony_ci ? FW_PORT_CMD_MDIOADDR32_G(lstatus32) 5798c2ecf20Sopenharmony_ci : -1); 5808c2ecf20Sopenharmony_ci pcaps = be32_to_cpu(port_rpl.u.info32.pcaps32); 5818c2ecf20Sopenharmony_ci acaps = be32_to_cpu(port_rpl.u.info32.acaps32); 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci pi->port_type = port_type; 5858c2ecf20Sopenharmony_ci pi->mdio_addr = mdio_addr; 5868c2ecf20Sopenharmony_ci pi->mod_type = FW_PORT_MOD_TYPE_NA; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci init_link_config(&pi->link_cfg, pcaps, acaps); 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/** 5938c2ecf20Sopenharmony_ci * t4vf_fw_reset - issue a reset to FW 5948c2ecf20Sopenharmony_ci * @adapter: the adapter 5958c2ecf20Sopenharmony_ci * 5968c2ecf20Sopenharmony_ci * Issues a reset command to FW. For a Physical Function this would 5978c2ecf20Sopenharmony_ci * result in the Firmware resetting all of its state. For a Virtual 5988c2ecf20Sopenharmony_ci * Function this just resets the state associated with the VF. 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ciint t4vf_fw_reset(struct adapter *adapter) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci struct fw_reset_cmd cmd; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 6058c2ecf20Sopenharmony_ci cmd.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_RESET_CMD) | 6068c2ecf20Sopenharmony_ci FW_CMD_WRITE_F); 6078c2ecf20Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 6088c2ecf20Sopenharmony_ci return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/** 6128c2ecf20Sopenharmony_ci * t4vf_query_params - query FW or device parameters 6138c2ecf20Sopenharmony_ci * @adapter: the adapter 6148c2ecf20Sopenharmony_ci * @nparams: the number of parameters 6158c2ecf20Sopenharmony_ci * @params: the parameter names 6168c2ecf20Sopenharmony_ci * @vals: the parameter values 6178c2ecf20Sopenharmony_ci * 6188c2ecf20Sopenharmony_ci * Reads the values of firmware or device parameters. Up to 7 parameters 6198c2ecf20Sopenharmony_ci * can be queried at once. 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_cistatic int t4vf_query_params(struct adapter *adapter, unsigned int nparams, 6228c2ecf20Sopenharmony_ci const u32 *params, u32 *vals) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci int i, ret; 6258c2ecf20Sopenharmony_ci struct fw_params_cmd cmd, rpl; 6268c2ecf20Sopenharmony_ci struct fw_params_param *p; 6278c2ecf20Sopenharmony_ci size_t len16; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (nparams > 7) 6308c2ecf20Sopenharmony_ci return -EINVAL; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 6338c2ecf20Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) | 6348c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 6358c2ecf20Sopenharmony_ci FW_CMD_READ_F); 6368c2ecf20Sopenharmony_ci len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd, 6378c2ecf20Sopenharmony_ci param[nparams].mnem), 16); 6388c2ecf20Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16)); 6398c2ecf20Sopenharmony_ci for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++) 6408c2ecf20Sopenharmony_ci p->mnem = htonl(*params++); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); 6438c2ecf20Sopenharmony_ci if (ret == 0) 6448c2ecf20Sopenharmony_ci for (i = 0, p = &rpl.param[0]; i < nparams; i++, p++) 6458c2ecf20Sopenharmony_ci *vals++ = be32_to_cpu(p->val); 6468c2ecf20Sopenharmony_ci return ret; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci/** 6508c2ecf20Sopenharmony_ci * t4vf_set_params - sets FW or device parameters 6518c2ecf20Sopenharmony_ci * @adapter: the adapter 6528c2ecf20Sopenharmony_ci * @nparams: the number of parameters 6538c2ecf20Sopenharmony_ci * @params: the parameter names 6548c2ecf20Sopenharmony_ci * @vals: the parameter values 6558c2ecf20Sopenharmony_ci * 6568c2ecf20Sopenharmony_ci * Sets the values of firmware or device parameters. Up to 7 parameters 6578c2ecf20Sopenharmony_ci * can be specified at once. 6588c2ecf20Sopenharmony_ci */ 6598c2ecf20Sopenharmony_ciint t4vf_set_params(struct adapter *adapter, unsigned int nparams, 6608c2ecf20Sopenharmony_ci const u32 *params, const u32 *vals) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci int i; 6638c2ecf20Sopenharmony_ci struct fw_params_cmd cmd; 6648c2ecf20Sopenharmony_ci struct fw_params_param *p; 6658c2ecf20Sopenharmony_ci size_t len16; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (nparams > 7) 6688c2ecf20Sopenharmony_ci return -EINVAL; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 6718c2ecf20Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) | 6728c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 6738c2ecf20Sopenharmony_ci FW_CMD_WRITE_F); 6748c2ecf20Sopenharmony_ci len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd, 6758c2ecf20Sopenharmony_ci param[nparams]), 16); 6768c2ecf20Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16)); 6778c2ecf20Sopenharmony_ci for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++) { 6788c2ecf20Sopenharmony_ci p->mnem = cpu_to_be32(*params++); 6798c2ecf20Sopenharmony_ci p->val = cpu_to_be32(*vals++); 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci/** 6868c2ecf20Sopenharmony_ci * t4vf_fl_pkt_align - return the fl packet alignment 6878c2ecf20Sopenharmony_ci * @adapter: the adapter 6888c2ecf20Sopenharmony_ci * 6898c2ecf20Sopenharmony_ci * T4 has a single field to specify the packing and padding boundary. 6908c2ecf20Sopenharmony_ci * T5 onwards has separate fields for this and hence the alignment for 6918c2ecf20Sopenharmony_ci * next packet offset is maximum of these two. And T6 changes the 6928c2ecf20Sopenharmony_ci * Ingress Padding Boundary Shift, so it's all a mess and it's best 6938c2ecf20Sopenharmony_ci * if we put this in low-level Common Code ... 6948c2ecf20Sopenharmony_ci * 6958c2ecf20Sopenharmony_ci */ 6968c2ecf20Sopenharmony_ciint t4vf_fl_pkt_align(struct adapter *adapter) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci u32 sge_control, sge_control2; 6998c2ecf20Sopenharmony_ci unsigned int ingpadboundary, ingpackboundary, fl_align, ingpad_shift; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci sge_control = adapter->params.sge.sge_control; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci /* T4 uses a single control field to specify both the PCIe Padding and 7048c2ecf20Sopenharmony_ci * Packing Boundary. T5 introduced the ability to specify these 7058c2ecf20Sopenharmony_ci * separately. The actual Ingress Packet Data alignment boundary 7068c2ecf20Sopenharmony_ci * within Packed Buffer Mode is the maximum of these two 7078c2ecf20Sopenharmony_ci * specifications. (Note that it makes no real practical sense to 7088c2ecf20Sopenharmony_ci * have the Pading Boudary be larger than the Packing Boundary but you 7098c2ecf20Sopenharmony_ci * could set the chip up that way and, in fact, legacy T4 code would 7108c2ecf20Sopenharmony_ci * end doing this because it would initialize the Padding Boundary and 7118c2ecf20Sopenharmony_ci * leave the Packing Boundary initialized to 0 (16 bytes).) 7128c2ecf20Sopenharmony_ci * Padding Boundary values in T6 starts from 8B, 7138c2ecf20Sopenharmony_ci * where as it is 32B for T4 and T5. 7148c2ecf20Sopenharmony_ci */ 7158c2ecf20Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) 7168c2ecf20Sopenharmony_ci ingpad_shift = INGPADBOUNDARY_SHIFT_X; 7178c2ecf20Sopenharmony_ci else 7188c2ecf20Sopenharmony_ci ingpad_shift = T6_INGPADBOUNDARY_SHIFT_X; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_control) + ingpad_shift); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci fl_align = ingpadboundary; 7238c2ecf20Sopenharmony_ci if (!is_t4(adapter->params.chip)) { 7248c2ecf20Sopenharmony_ci /* T5 has a different interpretation of one of the PCIe Packing 7258c2ecf20Sopenharmony_ci * Boundary values. 7268c2ecf20Sopenharmony_ci */ 7278c2ecf20Sopenharmony_ci sge_control2 = adapter->params.sge.sge_control2; 7288c2ecf20Sopenharmony_ci ingpackboundary = INGPACKBOUNDARY_G(sge_control2); 7298c2ecf20Sopenharmony_ci if (ingpackboundary == INGPACKBOUNDARY_16B_X) 7308c2ecf20Sopenharmony_ci ingpackboundary = 16; 7318c2ecf20Sopenharmony_ci else 7328c2ecf20Sopenharmony_ci ingpackboundary = 1 << (ingpackboundary + 7338c2ecf20Sopenharmony_ci INGPACKBOUNDARY_SHIFT_X); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci fl_align = max(ingpadboundary, ingpackboundary); 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci return fl_align; 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci/** 7418c2ecf20Sopenharmony_ci * t4vf_bar2_sge_qregs - return BAR2 SGE Queue register information 7428c2ecf20Sopenharmony_ci * @adapter: the adapter 7438c2ecf20Sopenharmony_ci * @qid: the Queue ID 7448c2ecf20Sopenharmony_ci * @qtype: the Ingress or Egress type for @qid 7458c2ecf20Sopenharmony_ci * @pbar2_qoffset: BAR2 Queue Offset 7468c2ecf20Sopenharmony_ci * @pbar2_qid: BAR2 Queue ID or 0 for Queue ID inferred SGE Queues 7478c2ecf20Sopenharmony_ci * 7488c2ecf20Sopenharmony_ci * Returns the BAR2 SGE Queue Registers information associated with the 7498c2ecf20Sopenharmony_ci * indicated Absolute Queue ID. These are passed back in return value 7508c2ecf20Sopenharmony_ci * pointers. @qtype should be T4_BAR2_QTYPE_EGRESS for Egress Queue 7518c2ecf20Sopenharmony_ci * and T4_BAR2_QTYPE_INGRESS for Ingress Queues. 7528c2ecf20Sopenharmony_ci * 7538c2ecf20Sopenharmony_ci * This may return an error which indicates that BAR2 SGE Queue 7548c2ecf20Sopenharmony_ci * registers aren't available. If an error is not returned, then the 7558c2ecf20Sopenharmony_ci * following values are returned: 7568c2ecf20Sopenharmony_ci * 7578c2ecf20Sopenharmony_ci * *@pbar2_qoffset: the BAR2 Offset of the @qid Registers 7588c2ecf20Sopenharmony_ci * *@pbar2_qid: the BAR2 SGE Queue ID or 0 of @qid 7598c2ecf20Sopenharmony_ci * 7608c2ecf20Sopenharmony_ci * If the returned BAR2 Queue ID is 0, then BAR2 SGE registers which 7618c2ecf20Sopenharmony_ci * require the "Inferred Queue ID" ability may be used. E.g. the 7628c2ecf20Sopenharmony_ci * Write Combining Doorbell Buffer. If the BAR2 Queue ID is not 0, 7638c2ecf20Sopenharmony_ci * then these "Inferred Queue ID" register may not be used. 7648c2ecf20Sopenharmony_ci */ 7658c2ecf20Sopenharmony_ciint t4vf_bar2_sge_qregs(struct adapter *adapter, 7668c2ecf20Sopenharmony_ci unsigned int qid, 7678c2ecf20Sopenharmony_ci enum t4_bar2_qtype qtype, 7688c2ecf20Sopenharmony_ci u64 *pbar2_qoffset, 7698c2ecf20Sopenharmony_ci unsigned int *pbar2_qid) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci unsigned int page_shift, page_size, qpp_shift, qpp_mask; 7728c2ecf20Sopenharmony_ci u64 bar2_page_offset, bar2_qoffset; 7738c2ecf20Sopenharmony_ci unsigned int bar2_qid, bar2_qid_offset, bar2_qinferred; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci /* T4 doesn't support BAR2 SGE Queue registers. 7768c2ecf20Sopenharmony_ci */ 7778c2ecf20Sopenharmony_ci if (is_t4(adapter->params.chip)) 7788c2ecf20Sopenharmony_ci return -EINVAL; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* Get our SGE Page Size parameters. 7818c2ecf20Sopenharmony_ci */ 7828c2ecf20Sopenharmony_ci page_shift = adapter->params.sge.sge_vf_hps + 10; 7838c2ecf20Sopenharmony_ci page_size = 1 << page_shift; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* Get the right Queues per Page parameters for our Queue. 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_ci qpp_shift = (qtype == T4_BAR2_QTYPE_EGRESS 7888c2ecf20Sopenharmony_ci ? adapter->params.sge.sge_vf_eq_qpp 7898c2ecf20Sopenharmony_ci : adapter->params.sge.sge_vf_iq_qpp); 7908c2ecf20Sopenharmony_ci qpp_mask = (1 << qpp_shift) - 1; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* Calculate the basics of the BAR2 SGE Queue register area: 7938c2ecf20Sopenharmony_ci * o The BAR2 page the Queue registers will be in. 7948c2ecf20Sopenharmony_ci * o The BAR2 Queue ID. 7958c2ecf20Sopenharmony_ci * o The BAR2 Queue ID Offset into the BAR2 page. 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_ci bar2_page_offset = ((u64)(qid >> qpp_shift) << page_shift); 7988c2ecf20Sopenharmony_ci bar2_qid = qid & qpp_mask; 7998c2ecf20Sopenharmony_ci bar2_qid_offset = bar2_qid * SGE_UDB_SIZE; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci /* If the BAR2 Queue ID Offset is less than the Page Size, then the 8028c2ecf20Sopenharmony_ci * hardware will infer the Absolute Queue ID simply from the writes to 8038c2ecf20Sopenharmony_ci * the BAR2 Queue ID Offset within the BAR2 Page (and we need to use a 8048c2ecf20Sopenharmony_ci * BAR2 Queue ID of 0 for those writes). Otherwise, we'll simply 8058c2ecf20Sopenharmony_ci * write to the first BAR2 SGE Queue Area within the BAR2 Page with 8068c2ecf20Sopenharmony_ci * the BAR2 Queue ID and the hardware will infer the Absolute Queue ID 8078c2ecf20Sopenharmony_ci * from the BAR2 Page and BAR2 Queue ID. 8088c2ecf20Sopenharmony_ci * 8098c2ecf20Sopenharmony_ci * One important censequence of this is that some BAR2 SGE registers 8108c2ecf20Sopenharmony_ci * have a "Queue ID" field and we can write the BAR2 SGE Queue ID 8118c2ecf20Sopenharmony_ci * there. But other registers synthesize the SGE Queue ID purely 8128c2ecf20Sopenharmony_ci * from the writes to the registers -- the Write Combined Doorbell 8138c2ecf20Sopenharmony_ci * Buffer is a good example. These BAR2 SGE Registers are only 8148c2ecf20Sopenharmony_ci * available for those BAR2 SGE Register areas where the SGE Absolute 8158c2ecf20Sopenharmony_ci * Queue ID can be inferred from simple writes. 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci bar2_qoffset = bar2_page_offset; 8188c2ecf20Sopenharmony_ci bar2_qinferred = (bar2_qid_offset < page_size); 8198c2ecf20Sopenharmony_ci if (bar2_qinferred) { 8208c2ecf20Sopenharmony_ci bar2_qoffset += bar2_qid_offset; 8218c2ecf20Sopenharmony_ci bar2_qid = 0; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci *pbar2_qoffset = bar2_qoffset; 8258c2ecf20Sopenharmony_ci *pbar2_qid = bar2_qid; 8268c2ecf20Sopenharmony_ci return 0; 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ciunsigned int t4vf_get_pf_from_vf(struct adapter *adapter) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci u32 whoami; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci whoami = t4_read_reg(adapter, T4VF_PL_BASE_ADDR + PL_VF_WHOAMI_A); 8348c2ecf20Sopenharmony_ci return (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ? 8358c2ecf20Sopenharmony_ci SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami)); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci/** 8398c2ecf20Sopenharmony_ci * t4vf_get_sge_params - retrieve adapter Scatter gather Engine parameters 8408c2ecf20Sopenharmony_ci * @adapter: the adapter 8418c2ecf20Sopenharmony_ci * 8428c2ecf20Sopenharmony_ci * Retrieves various core SGE parameters in the form of hardware SGE 8438c2ecf20Sopenharmony_ci * register values. The caller is responsible for decoding these as 8448c2ecf20Sopenharmony_ci * needed. The SGE parameters are stored in @adapter->params.sge. 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_ciint t4vf_get_sge_params(struct adapter *adapter) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct sge_params *sge_params = &adapter->params.sge; 8498c2ecf20Sopenharmony_ci u32 params[7], vals[7]; 8508c2ecf20Sopenharmony_ci int v; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 8538c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V(SGE_CONTROL_A)); 8548c2ecf20Sopenharmony_ci params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 8558c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V(SGE_HOST_PAGE_SIZE_A)); 8568c2ecf20Sopenharmony_ci params[2] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 8578c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE0_A)); 8588c2ecf20Sopenharmony_ci params[3] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 8598c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE1_A)); 8608c2ecf20Sopenharmony_ci params[4] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 8618c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_0_AND_1_A)); 8628c2ecf20Sopenharmony_ci params[5] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 8638c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_2_AND_3_A)); 8648c2ecf20Sopenharmony_ci params[6] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 8658c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_4_AND_5_A)); 8668c2ecf20Sopenharmony_ci v = t4vf_query_params(adapter, 7, params, vals); 8678c2ecf20Sopenharmony_ci if (v) 8688c2ecf20Sopenharmony_ci return v; 8698c2ecf20Sopenharmony_ci sge_params->sge_control = vals[0]; 8708c2ecf20Sopenharmony_ci sge_params->sge_host_page_size = vals[1]; 8718c2ecf20Sopenharmony_ci sge_params->sge_fl_buffer_size[0] = vals[2]; 8728c2ecf20Sopenharmony_ci sge_params->sge_fl_buffer_size[1] = vals[3]; 8738c2ecf20Sopenharmony_ci sge_params->sge_timer_value_0_and_1 = vals[4]; 8748c2ecf20Sopenharmony_ci sge_params->sge_timer_value_2_and_3 = vals[5]; 8758c2ecf20Sopenharmony_ci sge_params->sge_timer_value_4_and_5 = vals[6]; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* T4 uses a single control field to specify both the PCIe Padding and 8788c2ecf20Sopenharmony_ci * Packing Boundary. T5 introduced the ability to specify these 8798c2ecf20Sopenharmony_ci * separately with the Padding Boundary in SGE_CONTROL and and Packing 8808c2ecf20Sopenharmony_ci * Boundary in SGE_CONTROL2. So for T5 and later we need to grab 8818c2ecf20Sopenharmony_ci * SGE_CONTROL in order to determine how ingress packet data will be 8828c2ecf20Sopenharmony_ci * laid out in Packed Buffer Mode. Unfortunately, older versions of 8838c2ecf20Sopenharmony_ci * the firmware won't let us retrieve SGE_CONTROL2 so if we get a 8848c2ecf20Sopenharmony_ci * failure grabbing it we throw an error since we can't figure out the 8858c2ecf20Sopenharmony_ci * right value. 8868c2ecf20Sopenharmony_ci */ 8878c2ecf20Sopenharmony_ci if (!is_t4(adapter->params.chip)) { 8888c2ecf20Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 8898c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V(SGE_CONTROL2_A)); 8908c2ecf20Sopenharmony_ci v = t4vf_query_params(adapter, 1, params, vals); 8918c2ecf20Sopenharmony_ci if (v != FW_SUCCESS) { 8928c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 8938c2ecf20Sopenharmony_ci "Unable to get SGE Control2; " 8948c2ecf20Sopenharmony_ci "probably old firmware.\n"); 8958c2ecf20Sopenharmony_ci return v; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci sge_params->sge_control2 = vals[0]; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 9018c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V(SGE_INGRESS_RX_THRESHOLD_A)); 9028c2ecf20Sopenharmony_ci params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 9038c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V(SGE_CONM_CTRL_A)); 9048c2ecf20Sopenharmony_ci v = t4vf_query_params(adapter, 2, params, vals); 9058c2ecf20Sopenharmony_ci if (v) 9068c2ecf20Sopenharmony_ci return v; 9078c2ecf20Sopenharmony_ci sge_params->sge_ingress_rx_threshold = vals[0]; 9088c2ecf20Sopenharmony_ci sge_params->sge_congestion_control = vals[1]; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* For T5 and later we want to use the new BAR2 Doorbells. 9118c2ecf20Sopenharmony_ci * Unfortunately, older firmware didn't allow the this register to be 9128c2ecf20Sopenharmony_ci * read. 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_ci if (!is_t4(adapter->params.chip)) { 9158c2ecf20Sopenharmony_ci unsigned int pf, s_hps, s_qpp; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 9188c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V( 9198c2ecf20Sopenharmony_ci SGE_EGRESS_QUEUES_PER_PAGE_VF_A)); 9208c2ecf20Sopenharmony_ci params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | 9218c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_XYZ_V( 9228c2ecf20Sopenharmony_ci SGE_INGRESS_QUEUES_PER_PAGE_VF_A)); 9238c2ecf20Sopenharmony_ci v = t4vf_query_params(adapter, 2, params, vals); 9248c2ecf20Sopenharmony_ci if (v != FW_SUCCESS) { 9258c2ecf20Sopenharmony_ci dev_warn(adapter->pdev_dev, 9268c2ecf20Sopenharmony_ci "Unable to get VF SGE Queues/Page; " 9278c2ecf20Sopenharmony_ci "probably old firmware.\n"); 9288c2ecf20Sopenharmony_ci return v; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci sge_params->sge_egress_queues_per_page = vals[0]; 9318c2ecf20Sopenharmony_ci sge_params->sge_ingress_queues_per_page = vals[1]; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* We need the Queues/Page for our VF. This is based on the 9348c2ecf20Sopenharmony_ci * PF from which we're instantiated and is indexed in the 9358c2ecf20Sopenharmony_ci * register we just read. Do it once here so other code in 9368c2ecf20Sopenharmony_ci * the driver can just use it. 9378c2ecf20Sopenharmony_ci */ 9388c2ecf20Sopenharmony_ci pf = t4vf_get_pf_from_vf(adapter); 9398c2ecf20Sopenharmony_ci s_hps = (HOSTPAGESIZEPF0_S + 9408c2ecf20Sopenharmony_ci (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * pf); 9418c2ecf20Sopenharmony_ci sge_params->sge_vf_hps = 9428c2ecf20Sopenharmony_ci ((sge_params->sge_host_page_size >> s_hps) 9438c2ecf20Sopenharmony_ci & HOSTPAGESIZEPF0_M); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci s_qpp = (QUEUESPERPAGEPF0_S + 9468c2ecf20Sopenharmony_ci (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * pf); 9478c2ecf20Sopenharmony_ci sge_params->sge_vf_eq_qpp = 9488c2ecf20Sopenharmony_ci ((sge_params->sge_egress_queues_per_page >> s_qpp) 9498c2ecf20Sopenharmony_ci & QUEUESPERPAGEPF0_M); 9508c2ecf20Sopenharmony_ci sge_params->sge_vf_iq_qpp = 9518c2ecf20Sopenharmony_ci ((sge_params->sge_ingress_queues_per_page >> s_qpp) 9528c2ecf20Sopenharmony_ci & QUEUESPERPAGEPF0_M); 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci/** 9598c2ecf20Sopenharmony_ci * t4vf_get_vpd_params - retrieve device VPD paremeters 9608c2ecf20Sopenharmony_ci * @adapter: the adapter 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * Retrives various device Vital Product Data parameters. The parameters 9638c2ecf20Sopenharmony_ci * are stored in @adapter->params.vpd. 9648c2ecf20Sopenharmony_ci */ 9658c2ecf20Sopenharmony_ciint t4vf_get_vpd_params(struct adapter *adapter) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci struct vpd_params *vpd_params = &adapter->params.vpd; 9688c2ecf20Sopenharmony_ci u32 params[7], vals[7]; 9698c2ecf20Sopenharmony_ci int v; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 9728c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CCLK)); 9738c2ecf20Sopenharmony_ci v = t4vf_query_params(adapter, 1, params, vals); 9748c2ecf20Sopenharmony_ci if (v) 9758c2ecf20Sopenharmony_ci return v; 9768c2ecf20Sopenharmony_ci vpd_params->cclk = vals[0]; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci return 0; 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci/** 9828c2ecf20Sopenharmony_ci * t4vf_get_dev_params - retrieve device paremeters 9838c2ecf20Sopenharmony_ci * @adapter: the adapter 9848c2ecf20Sopenharmony_ci * 9858c2ecf20Sopenharmony_ci * Retrives various device parameters. The parameters are stored in 9868c2ecf20Sopenharmony_ci * @adapter->params.dev. 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_ciint t4vf_get_dev_params(struct adapter *adapter) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct dev_params *dev_params = &adapter->params.dev; 9918c2ecf20Sopenharmony_ci u32 params[7], vals[7]; 9928c2ecf20Sopenharmony_ci int v; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 9958c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FWREV)); 9968c2ecf20Sopenharmony_ci params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 9978c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_TPREV)); 9988c2ecf20Sopenharmony_ci v = t4vf_query_params(adapter, 2, params, vals); 9998c2ecf20Sopenharmony_ci if (v) 10008c2ecf20Sopenharmony_ci return v; 10018c2ecf20Sopenharmony_ci dev_params->fwrev = vals[0]; 10028c2ecf20Sopenharmony_ci dev_params->tprev = vals[1]; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci return 0; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci/** 10088c2ecf20Sopenharmony_ci * t4vf_get_rss_glb_config - retrieve adapter RSS Global Configuration 10098c2ecf20Sopenharmony_ci * @adapter: the adapter 10108c2ecf20Sopenharmony_ci * 10118c2ecf20Sopenharmony_ci * Retrieves global RSS mode and parameters with which we have to live 10128c2ecf20Sopenharmony_ci * and stores them in the @adapter's RSS parameters. 10138c2ecf20Sopenharmony_ci */ 10148c2ecf20Sopenharmony_ciint t4vf_get_rss_glb_config(struct adapter *adapter) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci struct rss_params *rss = &adapter->params.rss; 10178c2ecf20Sopenharmony_ci struct fw_rss_glb_config_cmd cmd, rpl; 10188c2ecf20Sopenharmony_ci int v; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci /* 10218c2ecf20Sopenharmony_ci * Execute an RSS Global Configuration read command to retrieve 10228c2ecf20Sopenharmony_ci * our RSS configuration. 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 10258c2ecf20Sopenharmony_ci cmd.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_RSS_GLB_CONFIG_CMD) | 10268c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 10278c2ecf20Sopenharmony_ci FW_CMD_READ_F); 10288c2ecf20Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 10298c2ecf20Sopenharmony_ci v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); 10308c2ecf20Sopenharmony_ci if (v) 10318c2ecf20Sopenharmony_ci return v; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci /* 10348c2ecf20Sopenharmony_ci * Transate the big-endian RSS Global Configuration into our 10358c2ecf20Sopenharmony_ci * cpu-endian format based on the RSS mode. We also do first level 10368c2ecf20Sopenharmony_ci * filtering at this point to weed out modes which don't support 10378c2ecf20Sopenharmony_ci * VF Drivers ... 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_ci rss->mode = FW_RSS_GLB_CONFIG_CMD_MODE_G( 10408c2ecf20Sopenharmony_ci be32_to_cpu(rpl.u.manual.mode_pkd)); 10418c2ecf20Sopenharmony_ci switch (rss->mode) { 10428c2ecf20Sopenharmony_ci case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: { 10438c2ecf20Sopenharmony_ci u32 word = be32_to_cpu( 10448c2ecf20Sopenharmony_ci rpl.u.basicvirtual.synmapen_to_hashtoeplitz); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci rss->u.basicvirtual.synmapen = 10478c2ecf20Sopenharmony_ci ((word & FW_RSS_GLB_CONFIG_CMD_SYNMAPEN_F) != 0); 10488c2ecf20Sopenharmony_ci rss->u.basicvirtual.syn4tupenipv6 = 10498c2ecf20Sopenharmony_ci ((word & FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV6_F) != 0); 10508c2ecf20Sopenharmony_ci rss->u.basicvirtual.syn2tupenipv6 = 10518c2ecf20Sopenharmony_ci ((word & FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV6_F) != 0); 10528c2ecf20Sopenharmony_ci rss->u.basicvirtual.syn4tupenipv4 = 10538c2ecf20Sopenharmony_ci ((word & FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV4_F) != 0); 10548c2ecf20Sopenharmony_ci rss->u.basicvirtual.syn2tupenipv4 = 10558c2ecf20Sopenharmony_ci ((word & FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV4_F) != 0); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci rss->u.basicvirtual.ofdmapen = 10588c2ecf20Sopenharmony_ci ((word & FW_RSS_GLB_CONFIG_CMD_OFDMAPEN_F) != 0); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci rss->u.basicvirtual.tnlmapen = 10618c2ecf20Sopenharmony_ci ((word & FW_RSS_GLB_CONFIG_CMD_TNLMAPEN_F) != 0); 10628c2ecf20Sopenharmony_ci rss->u.basicvirtual.tnlalllookup = 10638c2ecf20Sopenharmony_ci ((word & FW_RSS_GLB_CONFIG_CMD_TNLALLLKP_F) != 0); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci rss->u.basicvirtual.hashtoeplitz = 10668c2ecf20Sopenharmony_ci ((word & FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ_F) != 0); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* we need at least Tunnel Map Enable to be set */ 10698c2ecf20Sopenharmony_ci if (!rss->u.basicvirtual.tnlmapen) 10708c2ecf20Sopenharmony_ci return -EINVAL; 10718c2ecf20Sopenharmony_ci break; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci default: 10758c2ecf20Sopenharmony_ci /* all unknown/unsupported RSS modes result in an error */ 10768c2ecf20Sopenharmony_ci return -EINVAL; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci return 0; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci/** 10838c2ecf20Sopenharmony_ci * t4vf_get_vfres - retrieve VF resource limits 10848c2ecf20Sopenharmony_ci * @adapter: the adapter 10858c2ecf20Sopenharmony_ci * 10868c2ecf20Sopenharmony_ci * Retrieves configured resource limits and capabilities for a virtual 10878c2ecf20Sopenharmony_ci * function. The results are stored in @adapter->vfres. 10888c2ecf20Sopenharmony_ci */ 10898c2ecf20Sopenharmony_ciint t4vf_get_vfres(struct adapter *adapter) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci struct vf_resources *vfres = &adapter->params.vfres; 10928c2ecf20Sopenharmony_ci struct fw_pfvf_cmd cmd, rpl; 10938c2ecf20Sopenharmony_ci int v; 10948c2ecf20Sopenharmony_ci u32 word; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* 10978c2ecf20Sopenharmony_ci * Execute PFVF Read command to get VF resource limits; bail out early 10988c2ecf20Sopenharmony_ci * with error on command failure. 10998c2ecf20Sopenharmony_ci */ 11008c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 11018c2ecf20Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PFVF_CMD) | 11028c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 11038c2ecf20Sopenharmony_ci FW_CMD_READ_F); 11048c2ecf20Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 11058c2ecf20Sopenharmony_ci v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); 11068c2ecf20Sopenharmony_ci if (v) 11078c2ecf20Sopenharmony_ci return v; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci /* 11108c2ecf20Sopenharmony_ci * Extract VF resource limits and return success. 11118c2ecf20Sopenharmony_ci */ 11128c2ecf20Sopenharmony_ci word = be32_to_cpu(rpl.niqflint_niq); 11138c2ecf20Sopenharmony_ci vfres->niqflint = FW_PFVF_CMD_NIQFLINT_G(word); 11148c2ecf20Sopenharmony_ci vfres->niq = FW_PFVF_CMD_NIQ_G(word); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci word = be32_to_cpu(rpl.type_to_neq); 11178c2ecf20Sopenharmony_ci vfres->neq = FW_PFVF_CMD_NEQ_G(word); 11188c2ecf20Sopenharmony_ci vfres->pmask = FW_PFVF_CMD_PMASK_G(word); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci word = be32_to_cpu(rpl.tc_to_nexactf); 11218c2ecf20Sopenharmony_ci vfres->tc = FW_PFVF_CMD_TC_G(word); 11228c2ecf20Sopenharmony_ci vfres->nvi = FW_PFVF_CMD_NVI_G(word); 11238c2ecf20Sopenharmony_ci vfres->nexactf = FW_PFVF_CMD_NEXACTF_G(word); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci word = be32_to_cpu(rpl.r_caps_to_nethctrl); 11268c2ecf20Sopenharmony_ci vfres->r_caps = FW_PFVF_CMD_R_CAPS_G(word); 11278c2ecf20Sopenharmony_ci vfres->wx_caps = FW_PFVF_CMD_WX_CAPS_G(word); 11288c2ecf20Sopenharmony_ci vfres->nethctrl = FW_PFVF_CMD_NETHCTRL_G(word); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci return 0; 11318c2ecf20Sopenharmony_ci} 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci/** 11348c2ecf20Sopenharmony_ci * t4vf_read_rss_vi_config - read a VI's RSS configuration 11358c2ecf20Sopenharmony_ci * @adapter: the adapter 11368c2ecf20Sopenharmony_ci * @viid: Virtual Interface ID 11378c2ecf20Sopenharmony_ci * @config: pointer to host-native VI RSS Configuration buffer 11388c2ecf20Sopenharmony_ci * 11398c2ecf20Sopenharmony_ci * Reads the Virtual Interface's RSS configuration information and 11408c2ecf20Sopenharmony_ci * translates it into CPU-native format. 11418c2ecf20Sopenharmony_ci */ 11428c2ecf20Sopenharmony_ciint t4vf_read_rss_vi_config(struct adapter *adapter, unsigned int viid, 11438c2ecf20Sopenharmony_ci union rss_vi_config *config) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci struct fw_rss_vi_config_cmd cmd, rpl; 11468c2ecf20Sopenharmony_ci int v; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 11498c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) | 11508c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 11518c2ecf20Sopenharmony_ci FW_CMD_READ_F | 11528c2ecf20Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_VIID(viid)); 11538c2ecf20Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 11548c2ecf20Sopenharmony_ci v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); 11558c2ecf20Sopenharmony_ci if (v) 11568c2ecf20Sopenharmony_ci return v; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci switch (adapter->params.rss.mode) { 11598c2ecf20Sopenharmony_ci case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: { 11608c2ecf20Sopenharmony_ci u32 word = be32_to_cpu(rpl.u.basicvirtual.defaultq_to_udpen); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci config->basicvirtual.ip6fourtupen = 11638c2ecf20Sopenharmony_ci ((word & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) != 0); 11648c2ecf20Sopenharmony_ci config->basicvirtual.ip6twotupen = 11658c2ecf20Sopenharmony_ci ((word & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) != 0); 11668c2ecf20Sopenharmony_ci config->basicvirtual.ip4fourtupen = 11678c2ecf20Sopenharmony_ci ((word & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) != 0); 11688c2ecf20Sopenharmony_ci config->basicvirtual.ip4twotupen = 11698c2ecf20Sopenharmony_ci ((word & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) != 0); 11708c2ecf20Sopenharmony_ci config->basicvirtual.udpen = 11718c2ecf20Sopenharmony_ci ((word & FW_RSS_VI_CONFIG_CMD_UDPEN_F) != 0); 11728c2ecf20Sopenharmony_ci config->basicvirtual.defaultq = 11738c2ecf20Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_DEFAULTQ_G(word); 11748c2ecf20Sopenharmony_ci break; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci default: 11788c2ecf20Sopenharmony_ci return -EINVAL; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci return 0; 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci/** 11858c2ecf20Sopenharmony_ci * t4vf_write_rss_vi_config - write a VI's RSS configuration 11868c2ecf20Sopenharmony_ci * @adapter: the adapter 11878c2ecf20Sopenharmony_ci * @viid: Virtual Interface ID 11888c2ecf20Sopenharmony_ci * @config: pointer to host-native VI RSS Configuration buffer 11898c2ecf20Sopenharmony_ci * 11908c2ecf20Sopenharmony_ci * Write the Virtual Interface's RSS configuration information 11918c2ecf20Sopenharmony_ci * (translating it into firmware-native format before writing). 11928c2ecf20Sopenharmony_ci */ 11938c2ecf20Sopenharmony_ciint t4vf_write_rss_vi_config(struct adapter *adapter, unsigned int viid, 11948c2ecf20Sopenharmony_ci union rss_vi_config *config) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci struct fw_rss_vi_config_cmd cmd, rpl; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 11998c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) | 12008c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 12018c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 12028c2ecf20Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_VIID(viid)); 12038c2ecf20Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 12048c2ecf20Sopenharmony_ci switch (adapter->params.rss.mode) { 12058c2ecf20Sopenharmony_ci case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: { 12068c2ecf20Sopenharmony_ci u32 word = 0; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (config->basicvirtual.ip6fourtupen) 12098c2ecf20Sopenharmony_ci word |= FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F; 12108c2ecf20Sopenharmony_ci if (config->basicvirtual.ip6twotupen) 12118c2ecf20Sopenharmony_ci word |= FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F; 12128c2ecf20Sopenharmony_ci if (config->basicvirtual.ip4fourtupen) 12138c2ecf20Sopenharmony_ci word |= FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F; 12148c2ecf20Sopenharmony_ci if (config->basicvirtual.ip4twotupen) 12158c2ecf20Sopenharmony_ci word |= FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F; 12168c2ecf20Sopenharmony_ci if (config->basicvirtual.udpen) 12178c2ecf20Sopenharmony_ci word |= FW_RSS_VI_CONFIG_CMD_UDPEN_F; 12188c2ecf20Sopenharmony_ci word |= FW_RSS_VI_CONFIG_CMD_DEFAULTQ_V( 12198c2ecf20Sopenharmony_ci config->basicvirtual.defaultq); 12208c2ecf20Sopenharmony_ci cmd.u.basicvirtual.defaultq_to_udpen = cpu_to_be32(word); 12218c2ecf20Sopenharmony_ci break; 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci default: 12258c2ecf20Sopenharmony_ci return -EINVAL; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci/** 12328c2ecf20Sopenharmony_ci * t4vf_config_rss_range - configure a portion of the RSS mapping table 12338c2ecf20Sopenharmony_ci * @adapter: the adapter 12348c2ecf20Sopenharmony_ci * @viid: Virtual Interface of RSS Table Slice 12358c2ecf20Sopenharmony_ci * @start: starting entry in the table to write 12368c2ecf20Sopenharmony_ci * @n: how many table entries to write 12378c2ecf20Sopenharmony_ci * @rspq: values for the "Response Queue" (Ingress Queue) lookup table 12388c2ecf20Sopenharmony_ci * @nrspq: number of values in @rspq 12398c2ecf20Sopenharmony_ci * 12408c2ecf20Sopenharmony_ci * Programs the selected part of the VI's RSS mapping table with the 12418c2ecf20Sopenharmony_ci * provided values. If @nrspq < @n the supplied values are used repeatedly 12428c2ecf20Sopenharmony_ci * until the full table range is populated. 12438c2ecf20Sopenharmony_ci * 12448c2ecf20Sopenharmony_ci * The caller must ensure the values in @rspq are in the range 0..1023. 12458c2ecf20Sopenharmony_ci */ 12468c2ecf20Sopenharmony_ciint t4vf_config_rss_range(struct adapter *adapter, unsigned int viid, 12478c2ecf20Sopenharmony_ci int start, int n, const u16 *rspq, int nrspq) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci const u16 *rsp = rspq; 12508c2ecf20Sopenharmony_ci const u16 *rsp_end = rspq+nrspq; 12518c2ecf20Sopenharmony_ci struct fw_rss_ind_tbl_cmd cmd; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci /* 12548c2ecf20Sopenharmony_ci * Initialize firmware command template to write the RSS table. 12558c2ecf20Sopenharmony_ci */ 12568c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 12578c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_IND_TBL_CMD) | 12588c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 12598c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 12608c2ecf20Sopenharmony_ci FW_RSS_IND_TBL_CMD_VIID_V(viid)); 12618c2ecf20Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* 12648c2ecf20Sopenharmony_ci * Each firmware RSS command can accommodate up to 32 RSS Ingress 12658c2ecf20Sopenharmony_ci * Queue Identifiers. These Ingress Queue IDs are packed three to 12668c2ecf20Sopenharmony_ci * a 32-bit word as 10-bit values with the upper remaining 2 bits 12678c2ecf20Sopenharmony_ci * reserved. 12688c2ecf20Sopenharmony_ci */ 12698c2ecf20Sopenharmony_ci while (n > 0) { 12708c2ecf20Sopenharmony_ci __be32 *qp = &cmd.iq0_to_iq2; 12718c2ecf20Sopenharmony_ci int nq = min(n, 32); 12728c2ecf20Sopenharmony_ci int ret; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci /* 12758c2ecf20Sopenharmony_ci * Set up the firmware RSS command header to send the next 12768c2ecf20Sopenharmony_ci * "nq" Ingress Queue IDs to the firmware. 12778c2ecf20Sopenharmony_ci */ 12788c2ecf20Sopenharmony_ci cmd.niqid = cpu_to_be16(nq); 12798c2ecf20Sopenharmony_ci cmd.startidx = cpu_to_be16(start); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* 12828c2ecf20Sopenharmony_ci * "nq" more done for the start of the next loop. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_ci start += nq; 12858c2ecf20Sopenharmony_ci n -= nq; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci /* 12888c2ecf20Sopenharmony_ci * While there are still Ingress Queue IDs to stuff into the 12898c2ecf20Sopenharmony_ci * current firmware RSS command, retrieve them from the 12908c2ecf20Sopenharmony_ci * Ingress Queue ID array and insert them into the command. 12918c2ecf20Sopenharmony_ci */ 12928c2ecf20Sopenharmony_ci while (nq > 0) { 12938c2ecf20Sopenharmony_ci /* 12948c2ecf20Sopenharmony_ci * Grab up to the next 3 Ingress Queue IDs (wrapping 12958c2ecf20Sopenharmony_ci * around the Ingress Queue ID array if necessary) and 12968c2ecf20Sopenharmony_ci * insert them into the firmware RSS command at the 12978c2ecf20Sopenharmony_ci * current 3-tuple position within the commad. 12988c2ecf20Sopenharmony_ci */ 12998c2ecf20Sopenharmony_ci u16 qbuf[3]; 13008c2ecf20Sopenharmony_ci u16 *qbp = qbuf; 13018c2ecf20Sopenharmony_ci int nqbuf = min(3, nq); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci nq -= nqbuf; 13048c2ecf20Sopenharmony_ci qbuf[0] = qbuf[1] = qbuf[2] = 0; 13058c2ecf20Sopenharmony_ci while (nqbuf) { 13068c2ecf20Sopenharmony_ci nqbuf--; 13078c2ecf20Sopenharmony_ci *qbp++ = *rsp++; 13088c2ecf20Sopenharmony_ci if (rsp >= rsp_end) 13098c2ecf20Sopenharmony_ci rsp = rspq; 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci *qp++ = cpu_to_be32(FW_RSS_IND_TBL_CMD_IQ0_V(qbuf[0]) | 13128c2ecf20Sopenharmony_ci FW_RSS_IND_TBL_CMD_IQ1_V(qbuf[1]) | 13138c2ecf20Sopenharmony_ci FW_RSS_IND_TBL_CMD_IQ2_V(qbuf[2])); 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci /* 13178c2ecf20Sopenharmony_ci * Send this portion of the RRS table update to the firmware; 13188c2ecf20Sopenharmony_ci * bail out on any errors. 13198c2ecf20Sopenharmony_ci */ 13208c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); 13218c2ecf20Sopenharmony_ci if (ret) 13228c2ecf20Sopenharmony_ci return ret; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci return 0; 13258c2ecf20Sopenharmony_ci} 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci/** 13288c2ecf20Sopenharmony_ci * t4vf_alloc_vi - allocate a virtual interface on a port 13298c2ecf20Sopenharmony_ci * @adapter: the adapter 13308c2ecf20Sopenharmony_ci * @port_id: physical port associated with the VI 13318c2ecf20Sopenharmony_ci * 13328c2ecf20Sopenharmony_ci * Allocate a new Virtual Interface and bind it to the indicated 13338c2ecf20Sopenharmony_ci * physical port. Return the new Virtual Interface Identifier on 13348c2ecf20Sopenharmony_ci * success, or a [negative] error number on failure. 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_ciint t4vf_alloc_vi(struct adapter *adapter, int port_id) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci struct fw_vi_cmd cmd, rpl; 13398c2ecf20Sopenharmony_ci int v; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci /* 13428c2ecf20Sopenharmony_ci * Execute a VI command to allocate Virtual Interface and return its 13438c2ecf20Sopenharmony_ci * VIID. 13448c2ecf20Sopenharmony_ci */ 13458c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 13468c2ecf20Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) | 13478c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 13488c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 13498c2ecf20Sopenharmony_ci FW_CMD_EXEC_F); 13508c2ecf20Sopenharmony_ci cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) | 13518c2ecf20Sopenharmony_ci FW_VI_CMD_ALLOC_F); 13528c2ecf20Sopenharmony_ci cmd.portid_pkd = FW_VI_CMD_PORTID_V(port_id); 13538c2ecf20Sopenharmony_ci v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); 13548c2ecf20Sopenharmony_ci if (v) 13558c2ecf20Sopenharmony_ci return v; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci return FW_VI_CMD_VIID_G(be16_to_cpu(rpl.type_viid)); 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci/** 13618c2ecf20Sopenharmony_ci * t4vf_free_vi -- free a virtual interface 13628c2ecf20Sopenharmony_ci * @adapter: the adapter 13638c2ecf20Sopenharmony_ci * @viid: the virtual interface identifier 13648c2ecf20Sopenharmony_ci * 13658c2ecf20Sopenharmony_ci * Free a previously allocated Virtual Interface. Return an error on 13668c2ecf20Sopenharmony_ci * failure. 13678c2ecf20Sopenharmony_ci */ 13688c2ecf20Sopenharmony_ciint t4vf_free_vi(struct adapter *adapter, int viid) 13698c2ecf20Sopenharmony_ci{ 13708c2ecf20Sopenharmony_ci struct fw_vi_cmd cmd; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci /* 13738c2ecf20Sopenharmony_ci * Execute a VI command to free the Virtual Interface. 13748c2ecf20Sopenharmony_ci */ 13758c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 13768c2ecf20Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) | 13778c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 13788c2ecf20Sopenharmony_ci FW_CMD_EXEC_F); 13798c2ecf20Sopenharmony_ci cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) | 13808c2ecf20Sopenharmony_ci FW_VI_CMD_FREE_F); 13818c2ecf20Sopenharmony_ci cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID_V(viid)); 13828c2ecf20Sopenharmony_ci return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci/** 13868c2ecf20Sopenharmony_ci * t4vf_enable_vi - enable/disable a virtual interface 13878c2ecf20Sopenharmony_ci * @adapter: the adapter 13888c2ecf20Sopenharmony_ci * @viid: the Virtual Interface ID 13898c2ecf20Sopenharmony_ci * @rx_en: 1=enable Rx, 0=disable Rx 13908c2ecf20Sopenharmony_ci * @tx_en: 1=enable Tx, 0=disable Tx 13918c2ecf20Sopenharmony_ci * 13928c2ecf20Sopenharmony_ci * Enables/disables a virtual interface. 13938c2ecf20Sopenharmony_ci */ 13948c2ecf20Sopenharmony_ciint t4vf_enable_vi(struct adapter *adapter, unsigned int viid, 13958c2ecf20Sopenharmony_ci bool rx_en, bool tx_en) 13968c2ecf20Sopenharmony_ci{ 13978c2ecf20Sopenharmony_ci struct fw_vi_enable_cmd cmd; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 14008c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_ENABLE_CMD) | 14018c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 14028c2ecf20Sopenharmony_ci FW_CMD_EXEC_F | 14038c2ecf20Sopenharmony_ci FW_VI_ENABLE_CMD_VIID_V(viid)); 14048c2ecf20Sopenharmony_ci cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_IEN_V(rx_en) | 14058c2ecf20Sopenharmony_ci FW_VI_ENABLE_CMD_EEN_V(tx_en) | 14068c2ecf20Sopenharmony_ci FW_LEN16(cmd)); 14078c2ecf20Sopenharmony_ci return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci/** 14118c2ecf20Sopenharmony_ci * t4vf_enable_pi - enable/disable a Port's virtual interface 14128c2ecf20Sopenharmony_ci * @adapter: the adapter 14138c2ecf20Sopenharmony_ci * @pi: the Port Information structure 14148c2ecf20Sopenharmony_ci * @rx_en: 1=enable Rx, 0=disable Rx 14158c2ecf20Sopenharmony_ci * @tx_en: 1=enable Tx, 0=disable Tx 14168c2ecf20Sopenharmony_ci * 14178c2ecf20Sopenharmony_ci * Enables/disables a Port's virtual interface. If the Virtual 14188c2ecf20Sopenharmony_ci * Interface enable/disable operation is successful, we notify the 14198c2ecf20Sopenharmony_ci * OS-specific code of a potential Link Status change via the OS Contract 14208c2ecf20Sopenharmony_ci * API t4vf_os_link_changed(). 14218c2ecf20Sopenharmony_ci */ 14228c2ecf20Sopenharmony_ciint t4vf_enable_pi(struct adapter *adapter, struct port_info *pi, 14238c2ecf20Sopenharmony_ci bool rx_en, bool tx_en) 14248c2ecf20Sopenharmony_ci{ 14258c2ecf20Sopenharmony_ci int ret = t4vf_enable_vi(adapter, pi->viid, rx_en, tx_en); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (ret) 14288c2ecf20Sopenharmony_ci return ret; 14298c2ecf20Sopenharmony_ci t4vf_os_link_changed(adapter, pi->pidx, 14308c2ecf20Sopenharmony_ci rx_en && tx_en && pi->link_cfg.link_ok); 14318c2ecf20Sopenharmony_ci return 0; 14328c2ecf20Sopenharmony_ci} 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci/** 14358c2ecf20Sopenharmony_ci * t4vf_identify_port - identify a VI's port by blinking its LED 14368c2ecf20Sopenharmony_ci * @adapter: the adapter 14378c2ecf20Sopenharmony_ci * @viid: the Virtual Interface ID 14388c2ecf20Sopenharmony_ci * @nblinks: how many times to blink LED at 2.5 Hz 14398c2ecf20Sopenharmony_ci * 14408c2ecf20Sopenharmony_ci * Identifies a VI's port by blinking its LED. 14418c2ecf20Sopenharmony_ci */ 14428c2ecf20Sopenharmony_ciint t4vf_identify_port(struct adapter *adapter, unsigned int viid, 14438c2ecf20Sopenharmony_ci unsigned int nblinks) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci struct fw_vi_enable_cmd cmd; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 14488c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_ENABLE_CMD) | 14498c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 14508c2ecf20Sopenharmony_ci FW_CMD_EXEC_F | 14518c2ecf20Sopenharmony_ci FW_VI_ENABLE_CMD_VIID_V(viid)); 14528c2ecf20Sopenharmony_ci cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_LED_F | 14538c2ecf20Sopenharmony_ci FW_LEN16(cmd)); 14548c2ecf20Sopenharmony_ci cmd.blinkdur = cpu_to_be16(nblinks); 14558c2ecf20Sopenharmony_ci return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); 14568c2ecf20Sopenharmony_ci} 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci/** 14598c2ecf20Sopenharmony_ci * t4vf_set_rxmode - set Rx properties of a virtual interface 14608c2ecf20Sopenharmony_ci * @adapter: the adapter 14618c2ecf20Sopenharmony_ci * @viid: the VI id 14628c2ecf20Sopenharmony_ci * @mtu: the new MTU or -1 for no change 14638c2ecf20Sopenharmony_ci * @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change 14648c2ecf20Sopenharmony_ci * @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change 14658c2ecf20Sopenharmony_ci * @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change 14668c2ecf20Sopenharmony_ci * @vlanex: 1 to enable hardware VLAN Tag extraction, 0 to disable it, 14678c2ecf20Sopenharmony_ci * -1 no change 14688c2ecf20Sopenharmony_ci * @sleep_ok: call is allowed to sleep 14698c2ecf20Sopenharmony_ci * 14708c2ecf20Sopenharmony_ci * Sets Rx properties of a virtual interface. 14718c2ecf20Sopenharmony_ci */ 14728c2ecf20Sopenharmony_ciint t4vf_set_rxmode(struct adapter *adapter, unsigned int viid, 14738c2ecf20Sopenharmony_ci int mtu, int promisc, int all_multi, int bcast, int vlanex, 14748c2ecf20Sopenharmony_ci bool sleep_ok) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci struct fw_vi_rxmode_cmd cmd; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* convert to FW values */ 14798c2ecf20Sopenharmony_ci if (mtu < 0) 14808c2ecf20Sopenharmony_ci mtu = FW_VI_RXMODE_CMD_MTU_M; 14818c2ecf20Sopenharmony_ci if (promisc < 0) 14828c2ecf20Sopenharmony_ci promisc = FW_VI_RXMODE_CMD_PROMISCEN_M; 14838c2ecf20Sopenharmony_ci if (all_multi < 0) 14848c2ecf20Sopenharmony_ci all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_M; 14858c2ecf20Sopenharmony_ci if (bcast < 0) 14868c2ecf20Sopenharmony_ci bcast = FW_VI_RXMODE_CMD_BROADCASTEN_M; 14878c2ecf20Sopenharmony_ci if (vlanex < 0) 14888c2ecf20Sopenharmony_ci vlanex = FW_VI_RXMODE_CMD_VLANEXEN_M; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 14918c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_RXMODE_CMD) | 14928c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 14938c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 14948c2ecf20Sopenharmony_ci FW_VI_RXMODE_CMD_VIID_V(viid)); 14958c2ecf20Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 14968c2ecf20Sopenharmony_ci cmd.mtu_to_vlanexen = 14978c2ecf20Sopenharmony_ci cpu_to_be32(FW_VI_RXMODE_CMD_MTU_V(mtu) | 14988c2ecf20Sopenharmony_ci FW_VI_RXMODE_CMD_PROMISCEN_V(promisc) | 14998c2ecf20Sopenharmony_ci FW_VI_RXMODE_CMD_ALLMULTIEN_V(all_multi) | 15008c2ecf20Sopenharmony_ci FW_VI_RXMODE_CMD_BROADCASTEN_V(bcast) | 15018c2ecf20Sopenharmony_ci FW_VI_RXMODE_CMD_VLANEXEN_V(vlanex)); 15028c2ecf20Sopenharmony_ci return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok); 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci/** 15068c2ecf20Sopenharmony_ci * t4vf_alloc_mac_filt - allocates exact-match filters for MAC addresses 15078c2ecf20Sopenharmony_ci * @adapter: the adapter 15088c2ecf20Sopenharmony_ci * @viid: the Virtual Interface Identifier 15098c2ecf20Sopenharmony_ci * @free: if true any existing filters for this VI id are first removed 15108c2ecf20Sopenharmony_ci * @naddr: the number of MAC addresses to allocate filters for (up to 7) 15118c2ecf20Sopenharmony_ci * @addr: the MAC address(es) 15128c2ecf20Sopenharmony_ci * @idx: where to store the index of each allocated filter 15138c2ecf20Sopenharmony_ci * @hash: pointer to hash address filter bitmap 15148c2ecf20Sopenharmony_ci * @sleep_ok: call is allowed to sleep 15158c2ecf20Sopenharmony_ci * 15168c2ecf20Sopenharmony_ci * Allocates an exact-match filter for each of the supplied addresses and 15178c2ecf20Sopenharmony_ci * sets it to the corresponding address. If @idx is not %NULL it should 15188c2ecf20Sopenharmony_ci * have at least @naddr entries, each of which will be set to the index of 15198c2ecf20Sopenharmony_ci * the filter allocated for the corresponding MAC address. If a filter 15208c2ecf20Sopenharmony_ci * could not be allocated for an address its index is set to 0xffff. 15218c2ecf20Sopenharmony_ci * If @hash is not %NULL addresses that fail to allocate an exact filter 15228c2ecf20Sopenharmony_ci * are hashed and update the hash filter bitmap pointed at by @hash. 15238c2ecf20Sopenharmony_ci * 15248c2ecf20Sopenharmony_ci * Returns a negative error number or the number of filters allocated. 15258c2ecf20Sopenharmony_ci */ 15268c2ecf20Sopenharmony_ciint t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free, 15278c2ecf20Sopenharmony_ci unsigned int naddr, const u8 **addr, u16 *idx, 15288c2ecf20Sopenharmony_ci u64 *hash, bool sleep_ok) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci int offset, ret = 0; 15318c2ecf20Sopenharmony_ci unsigned nfilters = 0; 15328c2ecf20Sopenharmony_ci unsigned int rem = naddr; 15338c2ecf20Sopenharmony_ci struct fw_vi_mac_cmd cmd, rpl; 15348c2ecf20Sopenharmony_ci unsigned int max_naddr = adapter->params.arch.mps_tcam_size; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci if (naddr > max_naddr) 15378c2ecf20Sopenharmony_ci return -EINVAL; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci for (offset = 0; offset < naddr; /**/) { 15408c2ecf20Sopenharmony_ci unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact) 15418c2ecf20Sopenharmony_ci ? rem 15428c2ecf20Sopenharmony_ci : ARRAY_SIZE(cmd.u.exact)); 15438c2ecf20Sopenharmony_ci size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, 15448c2ecf20Sopenharmony_ci u.exact[fw_naddr]), 16); 15458c2ecf20Sopenharmony_ci struct fw_vi_mac_exact *p; 15468c2ecf20Sopenharmony_ci int i; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 15498c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 15508c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 15518c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 15528c2ecf20Sopenharmony_ci (free ? FW_CMD_EXEC_F : 0) | 15538c2ecf20Sopenharmony_ci FW_VI_MAC_CMD_VIID_V(viid)); 15548c2ecf20Sopenharmony_ci cmd.freemacs_to_len16 = 15558c2ecf20Sopenharmony_ci cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(free) | 15568c2ecf20Sopenharmony_ci FW_CMD_LEN16_V(len16)); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) { 15598c2ecf20Sopenharmony_ci p->valid_to_idx = cpu_to_be16( 15608c2ecf20Sopenharmony_ci FW_VI_MAC_CMD_VALID_F | 15618c2ecf20Sopenharmony_ci FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_ADD_MAC)); 15628c2ecf20Sopenharmony_ci memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, 15678c2ecf20Sopenharmony_ci sleep_ok); 15688c2ecf20Sopenharmony_ci if (ret && ret != -ENOMEM) 15698c2ecf20Sopenharmony_ci break; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci for (i = 0, p = rpl.u.exact; i < fw_naddr; i++, p++) { 15728c2ecf20Sopenharmony_ci u16 index = FW_VI_MAC_CMD_IDX_G( 15738c2ecf20Sopenharmony_ci be16_to_cpu(p->valid_to_idx)); 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci if (idx) 15768c2ecf20Sopenharmony_ci idx[offset+i] = 15778c2ecf20Sopenharmony_ci (index >= max_naddr 15788c2ecf20Sopenharmony_ci ? 0xffff 15798c2ecf20Sopenharmony_ci : index); 15808c2ecf20Sopenharmony_ci if (index < max_naddr) 15818c2ecf20Sopenharmony_ci nfilters++; 15828c2ecf20Sopenharmony_ci else if (hash) 15838c2ecf20Sopenharmony_ci *hash |= (1ULL << hash_mac_addr(addr[offset+i])); 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci free = false; 15878c2ecf20Sopenharmony_ci offset += fw_naddr; 15888c2ecf20Sopenharmony_ci rem -= fw_naddr; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci /* 15928c2ecf20Sopenharmony_ci * If there were no errors or we merely ran out of room in our MAC 15938c2ecf20Sopenharmony_ci * address arena, return the number of filters actually written. 15948c2ecf20Sopenharmony_ci */ 15958c2ecf20Sopenharmony_ci if (ret == 0 || ret == -ENOMEM) 15968c2ecf20Sopenharmony_ci ret = nfilters; 15978c2ecf20Sopenharmony_ci return ret; 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci/** 16018c2ecf20Sopenharmony_ci * t4vf_free_mac_filt - frees exact-match filters of given MAC addresses 16028c2ecf20Sopenharmony_ci * @adapter: the adapter 16038c2ecf20Sopenharmony_ci * @viid: the VI id 16048c2ecf20Sopenharmony_ci * @naddr: the number of MAC addresses to allocate filters for (up to 7) 16058c2ecf20Sopenharmony_ci * @addr: the MAC address(es) 16068c2ecf20Sopenharmony_ci * @sleep_ok: call is allowed to sleep 16078c2ecf20Sopenharmony_ci * 16088c2ecf20Sopenharmony_ci * Frees the exact-match filter for each of the supplied addresses 16098c2ecf20Sopenharmony_ci * 16108c2ecf20Sopenharmony_ci * Returns a negative error number or the number of filters freed. 16118c2ecf20Sopenharmony_ci */ 16128c2ecf20Sopenharmony_ciint t4vf_free_mac_filt(struct adapter *adapter, unsigned int viid, 16138c2ecf20Sopenharmony_ci unsigned int naddr, const u8 **addr, bool sleep_ok) 16148c2ecf20Sopenharmony_ci{ 16158c2ecf20Sopenharmony_ci int offset, ret = 0; 16168c2ecf20Sopenharmony_ci struct fw_vi_mac_cmd cmd; 16178c2ecf20Sopenharmony_ci unsigned int nfilters = 0; 16188c2ecf20Sopenharmony_ci unsigned int max_naddr = adapter->params.arch.mps_tcam_size; 16198c2ecf20Sopenharmony_ci unsigned int rem = naddr; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (naddr > max_naddr) 16228c2ecf20Sopenharmony_ci return -EINVAL; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci for (offset = 0; offset < (int)naddr ; /**/) { 16258c2ecf20Sopenharmony_ci unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact) ? 16268c2ecf20Sopenharmony_ci rem : ARRAY_SIZE(cmd.u.exact)); 16278c2ecf20Sopenharmony_ci size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, 16288c2ecf20Sopenharmony_ci u.exact[fw_naddr]), 16); 16298c2ecf20Sopenharmony_ci struct fw_vi_mac_exact *p; 16308c2ecf20Sopenharmony_ci int i; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 16338c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 16348c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 16358c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 16368c2ecf20Sopenharmony_ci FW_CMD_EXEC_V(0) | 16378c2ecf20Sopenharmony_ci FW_VI_MAC_CMD_VIID_V(viid)); 16388c2ecf20Sopenharmony_ci cmd.freemacs_to_len16 = 16398c2ecf20Sopenharmony_ci cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(0) | 16408c2ecf20Sopenharmony_ci FW_CMD_LEN16_V(len16)); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci for (i = 0, p = cmd.u.exact; i < (int)fw_naddr; i++, p++) { 16438c2ecf20Sopenharmony_ci p->valid_to_idx = cpu_to_be16( 16448c2ecf20Sopenharmony_ci FW_VI_MAC_CMD_VALID_F | 16458c2ecf20Sopenharmony_ci FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_MAC_BASED_FREE)); 16468c2ecf20Sopenharmony_ci memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &cmd, 16508c2ecf20Sopenharmony_ci sleep_ok); 16518c2ecf20Sopenharmony_ci if (ret) 16528c2ecf20Sopenharmony_ci break; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) { 16558c2ecf20Sopenharmony_ci u16 index = FW_VI_MAC_CMD_IDX_G( 16568c2ecf20Sopenharmony_ci be16_to_cpu(p->valid_to_idx)); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (index < max_naddr) 16598c2ecf20Sopenharmony_ci nfilters++; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci offset += fw_naddr; 16638c2ecf20Sopenharmony_ci rem -= fw_naddr; 16648c2ecf20Sopenharmony_ci } 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci if (ret == 0) 16678c2ecf20Sopenharmony_ci ret = nfilters; 16688c2ecf20Sopenharmony_ci return ret; 16698c2ecf20Sopenharmony_ci} 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci/** 16728c2ecf20Sopenharmony_ci * t4vf_change_mac - modifies the exact-match filter for a MAC address 16738c2ecf20Sopenharmony_ci * @adapter: the adapter 16748c2ecf20Sopenharmony_ci * @viid: the Virtual Interface ID 16758c2ecf20Sopenharmony_ci * @idx: index of existing filter for old value of MAC address, or -1 16768c2ecf20Sopenharmony_ci * @addr: the new MAC address value 16778c2ecf20Sopenharmony_ci * @persist: if idx < 0, the new MAC allocation should be persistent 16788c2ecf20Sopenharmony_ci * 16798c2ecf20Sopenharmony_ci * Modifies an exact-match filter and sets it to the new MAC address. 16808c2ecf20Sopenharmony_ci * Note that in general it is not possible to modify the value of a given 16818c2ecf20Sopenharmony_ci * filter so the generic way to modify an address filter is to free the 16828c2ecf20Sopenharmony_ci * one being used by the old address value and allocate a new filter for 16838c2ecf20Sopenharmony_ci * the new address value. @idx can be -1 if the address is a new 16848c2ecf20Sopenharmony_ci * addition. 16858c2ecf20Sopenharmony_ci * 16868c2ecf20Sopenharmony_ci * Returns a negative error number or the index of the filter with the new 16878c2ecf20Sopenharmony_ci * MAC value. 16888c2ecf20Sopenharmony_ci */ 16898c2ecf20Sopenharmony_ciint t4vf_change_mac(struct adapter *adapter, unsigned int viid, 16908c2ecf20Sopenharmony_ci int idx, const u8 *addr, bool persist) 16918c2ecf20Sopenharmony_ci{ 16928c2ecf20Sopenharmony_ci int ret; 16938c2ecf20Sopenharmony_ci struct fw_vi_mac_cmd cmd, rpl; 16948c2ecf20Sopenharmony_ci struct fw_vi_mac_exact *p = &cmd.u.exact[0]; 16958c2ecf20Sopenharmony_ci size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, 16968c2ecf20Sopenharmony_ci u.exact[1]), 16); 16978c2ecf20Sopenharmony_ci unsigned int max_mac_addr = adapter->params.arch.mps_tcam_size; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci /* 17008c2ecf20Sopenharmony_ci * If this is a new allocation, determine whether it should be 17018c2ecf20Sopenharmony_ci * persistent (across a "freemacs" operation) or not. 17028c2ecf20Sopenharmony_ci */ 17038c2ecf20Sopenharmony_ci if (idx < 0) 17048c2ecf20Sopenharmony_ci idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 17078c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 17088c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 17098c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 17108c2ecf20Sopenharmony_ci FW_VI_MAC_CMD_VIID_V(viid)); 17118c2ecf20Sopenharmony_ci cmd.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16)); 17128c2ecf20Sopenharmony_ci p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID_F | 17138c2ecf20Sopenharmony_ci FW_VI_MAC_CMD_IDX_V(idx)); 17148c2ecf20Sopenharmony_ci memcpy(p->macaddr, addr, sizeof(p->macaddr)); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); 17178c2ecf20Sopenharmony_ci if (ret == 0) { 17188c2ecf20Sopenharmony_ci p = &rpl.u.exact[0]; 17198c2ecf20Sopenharmony_ci ret = FW_VI_MAC_CMD_IDX_G(be16_to_cpu(p->valid_to_idx)); 17208c2ecf20Sopenharmony_ci if (ret >= max_mac_addr) 17218c2ecf20Sopenharmony_ci ret = -ENOMEM; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci return ret; 17248c2ecf20Sopenharmony_ci} 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci/** 17278c2ecf20Sopenharmony_ci * t4vf_set_addr_hash - program the MAC inexact-match hash filter 17288c2ecf20Sopenharmony_ci * @adapter: the adapter 17298c2ecf20Sopenharmony_ci * @viid: the Virtual Interface Identifier 17308c2ecf20Sopenharmony_ci * @ucast: whether the hash filter should also match unicast addresses 17318c2ecf20Sopenharmony_ci * @vec: the value to be written to the hash filter 17328c2ecf20Sopenharmony_ci * @sleep_ok: call is allowed to sleep 17338c2ecf20Sopenharmony_ci * 17348c2ecf20Sopenharmony_ci * Sets the 64-bit inexact-match hash filter for a virtual interface. 17358c2ecf20Sopenharmony_ci */ 17368c2ecf20Sopenharmony_ciint t4vf_set_addr_hash(struct adapter *adapter, unsigned int viid, 17378c2ecf20Sopenharmony_ci bool ucast, u64 vec, bool sleep_ok) 17388c2ecf20Sopenharmony_ci{ 17398c2ecf20Sopenharmony_ci struct fw_vi_mac_cmd cmd; 17408c2ecf20Sopenharmony_ci size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, 17418c2ecf20Sopenharmony_ci u.exact[0]), 16); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 17448c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 17458c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 17468c2ecf20Sopenharmony_ci FW_CMD_WRITE_F | 17478c2ecf20Sopenharmony_ci FW_VI_ENABLE_CMD_VIID_V(viid)); 17488c2ecf20Sopenharmony_ci cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_HASHVECEN_F | 17498c2ecf20Sopenharmony_ci FW_VI_MAC_CMD_HASHUNIEN_V(ucast) | 17508c2ecf20Sopenharmony_ci FW_CMD_LEN16_V(len16)); 17518c2ecf20Sopenharmony_ci cmd.u.hash.hashvec = cpu_to_be64(vec); 17528c2ecf20Sopenharmony_ci return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok); 17538c2ecf20Sopenharmony_ci} 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci/** 17568c2ecf20Sopenharmony_ci * t4vf_get_port_stats - collect "port" statistics 17578c2ecf20Sopenharmony_ci * @adapter: the adapter 17588c2ecf20Sopenharmony_ci * @pidx: the port index 17598c2ecf20Sopenharmony_ci * @s: the stats structure to fill 17608c2ecf20Sopenharmony_ci * 17618c2ecf20Sopenharmony_ci * Collect statistics for the "port"'s Virtual Interface. 17628c2ecf20Sopenharmony_ci */ 17638c2ecf20Sopenharmony_ciint t4vf_get_port_stats(struct adapter *adapter, int pidx, 17648c2ecf20Sopenharmony_ci struct t4vf_port_stats *s) 17658c2ecf20Sopenharmony_ci{ 17668c2ecf20Sopenharmony_ci struct port_info *pi = adap2pinfo(adapter, pidx); 17678c2ecf20Sopenharmony_ci struct fw_vi_stats_vf fwstats; 17688c2ecf20Sopenharmony_ci unsigned int rem = VI_VF_NUM_STATS; 17698c2ecf20Sopenharmony_ci __be64 *fwsp = (__be64 *)&fwstats; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci /* 17728c2ecf20Sopenharmony_ci * Grab the Virtual Interface statistics a chunk at a time via mailbox 17738c2ecf20Sopenharmony_ci * commands. We could use a Work Request and get all of them at once 17748c2ecf20Sopenharmony_ci * but that's an asynchronous interface which is awkward to use. 17758c2ecf20Sopenharmony_ci */ 17768c2ecf20Sopenharmony_ci while (rem) { 17778c2ecf20Sopenharmony_ci unsigned int ix = VI_VF_NUM_STATS - rem; 17788c2ecf20Sopenharmony_ci unsigned int nstats = min(6U, rem); 17798c2ecf20Sopenharmony_ci struct fw_vi_stats_cmd cmd, rpl; 17808c2ecf20Sopenharmony_ci size_t len = (offsetof(struct fw_vi_stats_cmd, u) + 17818c2ecf20Sopenharmony_ci sizeof(struct fw_vi_stats_ctl)); 17828c2ecf20Sopenharmony_ci size_t len16 = DIV_ROUND_UP(len, 16); 17838c2ecf20Sopenharmony_ci int ret; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 17868c2ecf20Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_STATS_CMD) | 17878c2ecf20Sopenharmony_ci FW_VI_STATS_CMD_VIID_V(pi->viid) | 17888c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 17898c2ecf20Sopenharmony_ci FW_CMD_READ_F); 17908c2ecf20Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16)); 17918c2ecf20Sopenharmony_ci cmd.u.ctl.nstats_ix = 17928c2ecf20Sopenharmony_ci cpu_to_be16(FW_VI_STATS_CMD_IX_V(ix) | 17938c2ecf20Sopenharmony_ci FW_VI_STATS_CMD_NSTATS_V(nstats)); 17948c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox_ns(adapter, &cmd, len, &rpl); 17958c2ecf20Sopenharmony_ci if (ret) 17968c2ecf20Sopenharmony_ci return ret; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci memcpy(fwsp, &rpl.u.ctl.stat0, sizeof(__be64) * nstats); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci rem -= nstats; 18018c2ecf20Sopenharmony_ci fwsp += nstats; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci /* 18058c2ecf20Sopenharmony_ci * Translate firmware statistics into host native statistics. 18068c2ecf20Sopenharmony_ci */ 18078c2ecf20Sopenharmony_ci s->tx_bcast_bytes = be64_to_cpu(fwstats.tx_bcast_bytes); 18088c2ecf20Sopenharmony_ci s->tx_bcast_frames = be64_to_cpu(fwstats.tx_bcast_frames); 18098c2ecf20Sopenharmony_ci s->tx_mcast_bytes = be64_to_cpu(fwstats.tx_mcast_bytes); 18108c2ecf20Sopenharmony_ci s->tx_mcast_frames = be64_to_cpu(fwstats.tx_mcast_frames); 18118c2ecf20Sopenharmony_ci s->tx_ucast_bytes = be64_to_cpu(fwstats.tx_ucast_bytes); 18128c2ecf20Sopenharmony_ci s->tx_ucast_frames = be64_to_cpu(fwstats.tx_ucast_frames); 18138c2ecf20Sopenharmony_ci s->tx_drop_frames = be64_to_cpu(fwstats.tx_drop_frames); 18148c2ecf20Sopenharmony_ci s->tx_offload_bytes = be64_to_cpu(fwstats.tx_offload_bytes); 18158c2ecf20Sopenharmony_ci s->tx_offload_frames = be64_to_cpu(fwstats.tx_offload_frames); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci s->rx_bcast_bytes = be64_to_cpu(fwstats.rx_bcast_bytes); 18188c2ecf20Sopenharmony_ci s->rx_bcast_frames = be64_to_cpu(fwstats.rx_bcast_frames); 18198c2ecf20Sopenharmony_ci s->rx_mcast_bytes = be64_to_cpu(fwstats.rx_mcast_bytes); 18208c2ecf20Sopenharmony_ci s->rx_mcast_frames = be64_to_cpu(fwstats.rx_mcast_frames); 18218c2ecf20Sopenharmony_ci s->rx_ucast_bytes = be64_to_cpu(fwstats.rx_ucast_bytes); 18228c2ecf20Sopenharmony_ci s->rx_ucast_frames = be64_to_cpu(fwstats.rx_ucast_frames); 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci s->rx_err_frames = be64_to_cpu(fwstats.rx_err_frames); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci return 0; 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci/** 18308c2ecf20Sopenharmony_ci * t4vf_iq_free - free an ingress queue and its free lists 18318c2ecf20Sopenharmony_ci * @adapter: the adapter 18328c2ecf20Sopenharmony_ci * @iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.) 18338c2ecf20Sopenharmony_ci * @iqid: ingress queue ID 18348c2ecf20Sopenharmony_ci * @fl0id: FL0 queue ID or 0xffff if no attached FL0 18358c2ecf20Sopenharmony_ci * @fl1id: FL1 queue ID or 0xffff if no attached FL1 18368c2ecf20Sopenharmony_ci * 18378c2ecf20Sopenharmony_ci * Frees an ingress queue and its associated free lists, if any. 18388c2ecf20Sopenharmony_ci */ 18398c2ecf20Sopenharmony_ciint t4vf_iq_free(struct adapter *adapter, unsigned int iqtype, 18408c2ecf20Sopenharmony_ci unsigned int iqid, unsigned int fl0id, unsigned int fl1id) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci struct fw_iq_cmd cmd; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 18458c2ecf20Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_IQ_CMD) | 18468c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 18478c2ecf20Sopenharmony_ci FW_CMD_EXEC_F); 18488c2ecf20Sopenharmony_ci cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_FREE_F | 18498c2ecf20Sopenharmony_ci FW_LEN16(cmd)); 18508c2ecf20Sopenharmony_ci cmd.type_to_iqandstindex = 18518c2ecf20Sopenharmony_ci cpu_to_be32(FW_IQ_CMD_TYPE_V(iqtype)); 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci cmd.iqid = cpu_to_be16(iqid); 18548c2ecf20Sopenharmony_ci cmd.fl0id = cpu_to_be16(fl0id); 18558c2ecf20Sopenharmony_ci cmd.fl1id = cpu_to_be16(fl1id); 18568c2ecf20Sopenharmony_ci return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); 18578c2ecf20Sopenharmony_ci} 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci/** 18608c2ecf20Sopenharmony_ci * t4vf_eth_eq_free - free an Ethernet egress queue 18618c2ecf20Sopenharmony_ci * @adapter: the adapter 18628c2ecf20Sopenharmony_ci * @eqid: egress queue ID 18638c2ecf20Sopenharmony_ci * 18648c2ecf20Sopenharmony_ci * Frees an Ethernet egress queue. 18658c2ecf20Sopenharmony_ci */ 18668c2ecf20Sopenharmony_ciint t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid) 18678c2ecf20Sopenharmony_ci{ 18688c2ecf20Sopenharmony_ci struct fw_eq_eth_cmd cmd; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 18718c2ecf20Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_ETH_CMD) | 18728c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 18738c2ecf20Sopenharmony_ci FW_CMD_EXEC_F); 18748c2ecf20Sopenharmony_ci cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_FREE_F | 18758c2ecf20Sopenharmony_ci FW_LEN16(cmd)); 18768c2ecf20Sopenharmony_ci cmd.eqid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_EQID_V(eqid)); 18778c2ecf20Sopenharmony_ci return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); 18788c2ecf20Sopenharmony_ci} 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci/** 18818c2ecf20Sopenharmony_ci * t4vf_link_down_rc_str - return a string for a Link Down Reason Code 18828c2ecf20Sopenharmony_ci * @link_down_rc: Link Down Reason Code 18838c2ecf20Sopenharmony_ci * 18848c2ecf20Sopenharmony_ci * Returns a string representation of the Link Down Reason Code. 18858c2ecf20Sopenharmony_ci */ 18868c2ecf20Sopenharmony_cistatic const char *t4vf_link_down_rc_str(unsigned char link_down_rc) 18878c2ecf20Sopenharmony_ci{ 18888c2ecf20Sopenharmony_ci static const char * const reason[] = { 18898c2ecf20Sopenharmony_ci "Link Down", 18908c2ecf20Sopenharmony_ci "Remote Fault", 18918c2ecf20Sopenharmony_ci "Auto-negotiation Failure", 18928c2ecf20Sopenharmony_ci "Reserved", 18938c2ecf20Sopenharmony_ci "Insufficient Airflow", 18948c2ecf20Sopenharmony_ci "Unable To Determine Reason", 18958c2ecf20Sopenharmony_ci "No RX Signal Detected", 18968c2ecf20Sopenharmony_ci "Reserved", 18978c2ecf20Sopenharmony_ci }; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci if (link_down_rc >= ARRAY_SIZE(reason)) 19008c2ecf20Sopenharmony_ci return "Bad Reason Code"; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci return reason[link_down_rc]; 19038c2ecf20Sopenharmony_ci} 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci/** 19068c2ecf20Sopenharmony_ci * t4vf_handle_get_port_info - process a FW reply message 19078c2ecf20Sopenharmony_ci * @pi: the port info 19088c2ecf20Sopenharmony_ci * @cmd: start of the FW message 19098c2ecf20Sopenharmony_ci * 19108c2ecf20Sopenharmony_ci * Processes a GET_PORT_INFO FW reply message. 19118c2ecf20Sopenharmony_ci */ 19128c2ecf20Sopenharmony_cistatic void t4vf_handle_get_port_info(struct port_info *pi, 19138c2ecf20Sopenharmony_ci const struct fw_port_cmd *cmd) 19148c2ecf20Sopenharmony_ci{ 19158c2ecf20Sopenharmony_ci fw_port_cap32_t pcaps, acaps, lpacaps, linkattr; 19168c2ecf20Sopenharmony_ci struct link_config *lc = &pi->link_cfg; 19178c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 19188c2ecf20Sopenharmony_ci unsigned int speed, fc, fec, adv_fc; 19198c2ecf20Sopenharmony_ci enum fw_port_module_type mod_type; 19208c2ecf20Sopenharmony_ci int action, link_ok, linkdnrc; 19218c2ecf20Sopenharmony_ci enum fw_port_type port_type; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci /* Extract the various fields from the Port Information message. */ 19248c2ecf20Sopenharmony_ci action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16)); 19258c2ecf20Sopenharmony_ci switch (action) { 19268c2ecf20Sopenharmony_ci case FW_PORT_ACTION_GET_PORT_INFO: { 19278c2ecf20Sopenharmony_ci u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci link_ok = (lstatus & FW_PORT_CMD_LSTATUS_F) != 0; 19308c2ecf20Sopenharmony_ci linkdnrc = FW_PORT_CMD_LINKDNRC_G(lstatus); 19318c2ecf20Sopenharmony_ci port_type = FW_PORT_CMD_PTYPE_G(lstatus); 19328c2ecf20Sopenharmony_ci mod_type = FW_PORT_CMD_MODTYPE_G(lstatus); 19338c2ecf20Sopenharmony_ci pcaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.pcap)); 19348c2ecf20Sopenharmony_ci acaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.acap)); 19358c2ecf20Sopenharmony_ci lpacaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.lpacap)); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci /* Unfortunately the format of the Link Status in the old 19388c2ecf20Sopenharmony_ci * 16-bit Port Information message isn't the same as the 19398c2ecf20Sopenharmony_ci * 16-bit Port Capabilities bitfield used everywhere else ... 19408c2ecf20Sopenharmony_ci */ 19418c2ecf20Sopenharmony_ci linkattr = 0; 19428c2ecf20Sopenharmony_ci if (lstatus & FW_PORT_CMD_RXPAUSE_F) 19438c2ecf20Sopenharmony_ci linkattr |= FW_PORT_CAP32_FC_RX; 19448c2ecf20Sopenharmony_ci if (lstatus & FW_PORT_CMD_TXPAUSE_F) 19458c2ecf20Sopenharmony_ci linkattr |= FW_PORT_CAP32_FC_TX; 19468c2ecf20Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) 19478c2ecf20Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_100M; 19488c2ecf20Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) 19498c2ecf20Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_1G; 19508c2ecf20Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) 19518c2ecf20Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_10G; 19528c2ecf20Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G)) 19538c2ecf20Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_25G; 19548c2ecf20Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) 19558c2ecf20Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_40G; 19568c2ecf20Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G)) 19578c2ecf20Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_100G; 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci break; 19608c2ecf20Sopenharmony_ci } 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci case FW_PORT_ACTION_GET_PORT_INFO32: { 19638c2ecf20Sopenharmony_ci u32 lstatus32; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci lstatus32 = be32_to_cpu(cmd->u.info32.lstatus32_to_cbllen32); 19668c2ecf20Sopenharmony_ci link_ok = (lstatus32 & FW_PORT_CMD_LSTATUS32_F) != 0; 19678c2ecf20Sopenharmony_ci linkdnrc = FW_PORT_CMD_LINKDNRC32_G(lstatus32); 19688c2ecf20Sopenharmony_ci port_type = FW_PORT_CMD_PORTTYPE32_G(lstatus32); 19698c2ecf20Sopenharmony_ci mod_type = FW_PORT_CMD_MODTYPE32_G(lstatus32); 19708c2ecf20Sopenharmony_ci pcaps = be32_to_cpu(cmd->u.info32.pcaps32); 19718c2ecf20Sopenharmony_ci acaps = be32_to_cpu(cmd->u.info32.acaps32); 19728c2ecf20Sopenharmony_ci lpacaps = be32_to_cpu(cmd->u.info32.lpacaps32); 19738c2ecf20Sopenharmony_ci linkattr = be32_to_cpu(cmd->u.info32.linkattr32); 19748c2ecf20Sopenharmony_ci break; 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci default: 19788c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, "Handle Port Information: Bad Command/Action %#x\n", 19798c2ecf20Sopenharmony_ci be32_to_cpu(cmd->action_to_len16)); 19808c2ecf20Sopenharmony_ci return; 19818c2ecf20Sopenharmony_ci } 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci fec = fwcap_to_cc_fec(acaps); 19848c2ecf20Sopenharmony_ci adv_fc = fwcap_to_cc_pause(acaps); 19858c2ecf20Sopenharmony_ci fc = fwcap_to_cc_pause(linkattr); 19868c2ecf20Sopenharmony_ci speed = fwcap_to_speed(linkattr); 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci if (mod_type != pi->mod_type) { 19898c2ecf20Sopenharmony_ci /* When a new Transceiver Module is inserted, the Firmware 19908c2ecf20Sopenharmony_ci * will examine any Forward Error Correction parameters 19918c2ecf20Sopenharmony_ci * present in the Transceiver Module i2c EPROM and determine 19928c2ecf20Sopenharmony_ci * the supported and recommended FEC settings from those 19938c2ecf20Sopenharmony_ci * based on IEEE 802.3 standards. We always record the 19948c2ecf20Sopenharmony_ci * IEEE 802.3 recommended "automatic" settings. 19958c2ecf20Sopenharmony_ci */ 19968c2ecf20Sopenharmony_ci lc->auto_fec = fec; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci /* Some versions of the early T6 Firmware "cheated" when 19998c2ecf20Sopenharmony_ci * handling different Transceiver Modules by changing the 20008c2ecf20Sopenharmony_ci * underlaying Port Type reported to the Host Drivers. As 20018c2ecf20Sopenharmony_ci * such we need to capture whatever Port Type the Firmware 20028c2ecf20Sopenharmony_ci * sends us and record it in case it's different from what we 20038c2ecf20Sopenharmony_ci * were told earlier. Unfortunately, since Firmware is 20048c2ecf20Sopenharmony_ci * forever, we'll need to keep this code here forever, but in 20058c2ecf20Sopenharmony_ci * later T6 Firmware it should just be an assignment of the 20068c2ecf20Sopenharmony_ci * same value already recorded. 20078c2ecf20Sopenharmony_ci */ 20088c2ecf20Sopenharmony_ci pi->port_type = port_type; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci pi->mod_type = mod_type; 20118c2ecf20Sopenharmony_ci t4vf_os_portmod_changed(adapter, pi->pidx); 20128c2ecf20Sopenharmony_ci } 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci if (link_ok != lc->link_ok || speed != lc->speed || 20158c2ecf20Sopenharmony_ci fc != lc->fc || adv_fc != lc->advertised_fc || 20168c2ecf20Sopenharmony_ci fec != lc->fec) { 20178c2ecf20Sopenharmony_ci /* something changed */ 20188c2ecf20Sopenharmony_ci if (!link_ok && lc->link_ok) { 20198c2ecf20Sopenharmony_ci lc->link_down_rc = linkdnrc; 20208c2ecf20Sopenharmony_ci dev_warn_ratelimited(adapter->pdev_dev, 20218c2ecf20Sopenharmony_ci "Port %d link down, reason: %s\n", 20228c2ecf20Sopenharmony_ci pi->port_id, 20238c2ecf20Sopenharmony_ci t4vf_link_down_rc_str(linkdnrc)); 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci lc->link_ok = link_ok; 20268c2ecf20Sopenharmony_ci lc->speed = speed; 20278c2ecf20Sopenharmony_ci lc->advertised_fc = adv_fc; 20288c2ecf20Sopenharmony_ci lc->fc = fc; 20298c2ecf20Sopenharmony_ci lc->fec = fec; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci lc->pcaps = pcaps; 20328c2ecf20Sopenharmony_ci lc->lpacaps = lpacaps; 20338c2ecf20Sopenharmony_ci lc->acaps = acaps & ADVERT_MASK; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci /* If we're not physically capable of Auto-Negotiation, note 20368c2ecf20Sopenharmony_ci * this as Auto-Negotiation disabled. Otherwise, we track 20378c2ecf20Sopenharmony_ci * what Auto-Negotiation settings we have. Note parallel 20388c2ecf20Sopenharmony_ci * structure in init_link_config(). 20398c2ecf20Sopenharmony_ci */ 20408c2ecf20Sopenharmony_ci if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) { 20418c2ecf20Sopenharmony_ci lc->autoneg = AUTONEG_DISABLE; 20428c2ecf20Sopenharmony_ci } else if (lc->acaps & FW_PORT_CAP32_ANEG) { 20438c2ecf20Sopenharmony_ci lc->autoneg = AUTONEG_ENABLE; 20448c2ecf20Sopenharmony_ci } else { 20458c2ecf20Sopenharmony_ci /* When Autoneg is disabled, user needs to set 20468c2ecf20Sopenharmony_ci * single speed. 20478c2ecf20Sopenharmony_ci * Similar to cxgb4_ethtool.c: set_link_ksettings 20488c2ecf20Sopenharmony_ci */ 20498c2ecf20Sopenharmony_ci lc->acaps = 0; 20508c2ecf20Sopenharmony_ci lc->speed_caps = fwcap_to_speed(acaps); 20518c2ecf20Sopenharmony_ci lc->autoneg = AUTONEG_DISABLE; 20528c2ecf20Sopenharmony_ci } 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci t4vf_os_link_changed(adapter, pi->pidx, link_ok); 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci} 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci/** 20598c2ecf20Sopenharmony_ci * t4vf_update_port_info - retrieve and update port information if changed 20608c2ecf20Sopenharmony_ci * @pi: the port_info 20618c2ecf20Sopenharmony_ci * 20628c2ecf20Sopenharmony_ci * We issue a Get Port Information Command to the Firmware and, if 20638c2ecf20Sopenharmony_ci * successful, we check to see if anything is different from what we 20648c2ecf20Sopenharmony_ci * last recorded and update things accordingly. 20658c2ecf20Sopenharmony_ci */ 20668c2ecf20Sopenharmony_ciint t4vf_update_port_info(struct port_info *pi) 20678c2ecf20Sopenharmony_ci{ 20688c2ecf20Sopenharmony_ci unsigned int fw_caps = pi->adapter->params.fw_caps_support; 20698c2ecf20Sopenharmony_ci struct fw_port_cmd port_cmd; 20708c2ecf20Sopenharmony_ci int ret; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci memset(&port_cmd, 0, sizeof(port_cmd)); 20738c2ecf20Sopenharmony_ci port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | 20748c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F | 20758c2ecf20Sopenharmony_ci FW_PORT_CMD_PORTID_V(pi->port_id)); 20768c2ecf20Sopenharmony_ci port_cmd.action_to_len16 = cpu_to_be32( 20778c2ecf20Sopenharmony_ci FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16 20788c2ecf20Sopenharmony_ci ? FW_PORT_ACTION_GET_PORT_INFO 20798c2ecf20Sopenharmony_ci : FW_PORT_ACTION_GET_PORT_INFO32) | 20808c2ecf20Sopenharmony_ci FW_LEN16(port_cmd)); 20818c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox(pi->adapter, &port_cmd, sizeof(port_cmd), 20828c2ecf20Sopenharmony_ci &port_cmd); 20838c2ecf20Sopenharmony_ci if (ret) 20848c2ecf20Sopenharmony_ci return ret; 20858c2ecf20Sopenharmony_ci t4vf_handle_get_port_info(pi, &port_cmd); 20868c2ecf20Sopenharmony_ci return 0; 20878c2ecf20Sopenharmony_ci} 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci/** 20908c2ecf20Sopenharmony_ci * t4vf_handle_fw_rpl - process a firmware reply message 20918c2ecf20Sopenharmony_ci * @adapter: the adapter 20928c2ecf20Sopenharmony_ci * @rpl: start of the firmware message 20938c2ecf20Sopenharmony_ci * 20948c2ecf20Sopenharmony_ci * Processes a firmware message, such as link state change messages. 20958c2ecf20Sopenharmony_ci */ 20968c2ecf20Sopenharmony_ciint t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) 20978c2ecf20Sopenharmony_ci{ 20988c2ecf20Sopenharmony_ci const struct fw_cmd_hdr *cmd_hdr = (const struct fw_cmd_hdr *)rpl; 20998c2ecf20Sopenharmony_ci u8 opcode = FW_CMD_OP_G(be32_to_cpu(cmd_hdr->hi)); 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci switch (opcode) { 21028c2ecf20Sopenharmony_ci case FW_PORT_CMD: { 21038c2ecf20Sopenharmony_ci /* 21048c2ecf20Sopenharmony_ci * Link/module state change message. 21058c2ecf20Sopenharmony_ci */ 21068c2ecf20Sopenharmony_ci const struct fw_port_cmd *port_cmd = 21078c2ecf20Sopenharmony_ci (const struct fw_port_cmd *)rpl; 21088c2ecf20Sopenharmony_ci int action = FW_PORT_CMD_ACTION_G( 21098c2ecf20Sopenharmony_ci be32_to_cpu(port_cmd->action_to_len16)); 21108c2ecf20Sopenharmony_ci int port_id, pidx; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci if (action != FW_PORT_ACTION_GET_PORT_INFO && 21138c2ecf20Sopenharmony_ci action != FW_PORT_ACTION_GET_PORT_INFO32) { 21148c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 21158c2ecf20Sopenharmony_ci "Unknown firmware PORT reply action %x\n", 21168c2ecf20Sopenharmony_ci action); 21178c2ecf20Sopenharmony_ci break; 21188c2ecf20Sopenharmony_ci } 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci port_id = FW_PORT_CMD_PORTID_G( 21218c2ecf20Sopenharmony_ci be32_to_cpu(port_cmd->op_to_portid)); 21228c2ecf20Sopenharmony_ci for_each_port(adapter, pidx) { 21238c2ecf20Sopenharmony_ci struct port_info *pi = adap2pinfo(adapter, pidx); 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci if (pi->port_id != port_id) 21268c2ecf20Sopenharmony_ci continue; 21278c2ecf20Sopenharmony_ci t4vf_handle_get_port_info(pi, port_cmd); 21288c2ecf20Sopenharmony_ci } 21298c2ecf20Sopenharmony_ci break; 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci default: 21338c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, "Unknown firmware reply %X\n", 21348c2ecf20Sopenharmony_ci opcode); 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci return 0; 21378c2ecf20Sopenharmony_ci} 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ciint t4vf_prep_adapter(struct adapter *adapter) 21408c2ecf20Sopenharmony_ci{ 21418c2ecf20Sopenharmony_ci int err; 21428c2ecf20Sopenharmony_ci unsigned int chipid; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci /* Wait for the device to become ready before proceeding ... 21458c2ecf20Sopenharmony_ci */ 21468c2ecf20Sopenharmony_ci err = t4vf_wait_dev_ready(adapter); 21478c2ecf20Sopenharmony_ci if (err) 21488c2ecf20Sopenharmony_ci return err; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci /* Default port and clock for debugging in case we can't reach 21518c2ecf20Sopenharmony_ci * firmware. 21528c2ecf20Sopenharmony_ci */ 21538c2ecf20Sopenharmony_ci adapter->params.nports = 1; 21548c2ecf20Sopenharmony_ci adapter->params.vfres.pmask = 1; 21558c2ecf20Sopenharmony_ci adapter->params.vpd.cclk = 50000; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci adapter->params.chip = 0; 21588c2ecf20Sopenharmony_ci switch (CHELSIO_PCI_ID_VER(adapter->pdev->device)) { 21598c2ecf20Sopenharmony_ci case CHELSIO_T4: 21608c2ecf20Sopenharmony_ci adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T4, 0); 21618c2ecf20Sopenharmony_ci adapter->params.arch.sge_fl_db = DBPRIO_F; 21628c2ecf20Sopenharmony_ci adapter->params.arch.mps_tcam_size = 21638c2ecf20Sopenharmony_ci NUM_MPS_CLS_SRAM_L_INSTANCES; 21648c2ecf20Sopenharmony_ci break; 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci case CHELSIO_T5: 21678c2ecf20Sopenharmony_ci chipid = REV_G(t4_read_reg(adapter, PL_VF_REV_A)); 21688c2ecf20Sopenharmony_ci adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T5, chipid); 21698c2ecf20Sopenharmony_ci adapter->params.arch.sge_fl_db = DBPRIO_F | DBTYPE_F; 21708c2ecf20Sopenharmony_ci adapter->params.arch.mps_tcam_size = 21718c2ecf20Sopenharmony_ci NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 21728c2ecf20Sopenharmony_ci break; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci case CHELSIO_T6: 21758c2ecf20Sopenharmony_ci chipid = REV_G(t4_read_reg(adapter, PL_VF_REV_A)); 21768c2ecf20Sopenharmony_ci adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T6, chipid); 21778c2ecf20Sopenharmony_ci adapter->params.arch.sge_fl_db = 0; 21788c2ecf20Sopenharmony_ci adapter->params.arch.mps_tcam_size = 21798c2ecf20Sopenharmony_ci NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 21808c2ecf20Sopenharmony_ci break; 21818c2ecf20Sopenharmony_ci } 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci return 0; 21848c2ecf20Sopenharmony_ci} 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci/** 21878c2ecf20Sopenharmony_ci * t4vf_get_vf_mac_acl - Get the MAC address to be set to 21888c2ecf20Sopenharmony_ci * the VI of this VF. 21898c2ecf20Sopenharmony_ci * @adapter: The adapter 21908c2ecf20Sopenharmony_ci * @port: The port associated with vf 21918c2ecf20Sopenharmony_ci * @naddr: the number of ACL MAC addresses returned in addr 21928c2ecf20Sopenharmony_ci * @addr: Placeholder for MAC addresses 21938c2ecf20Sopenharmony_ci * 21948c2ecf20Sopenharmony_ci * Find the MAC address to be set to the VF's VI. The requested MAC address 21958c2ecf20Sopenharmony_ci * is from the host OS via callback in the PF driver. 21968c2ecf20Sopenharmony_ci */ 21978c2ecf20Sopenharmony_ciint t4vf_get_vf_mac_acl(struct adapter *adapter, unsigned int port, 21988c2ecf20Sopenharmony_ci unsigned int *naddr, u8 *addr) 21998c2ecf20Sopenharmony_ci{ 22008c2ecf20Sopenharmony_ci struct fw_acl_mac_cmd cmd; 22018c2ecf20Sopenharmony_ci int ret; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 22048c2ecf20Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_ACL_MAC_CMD) | 22058c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 22068c2ecf20Sopenharmony_ci FW_CMD_READ_F); 22078c2ecf20Sopenharmony_ci cmd.en_to_len16 = cpu_to_be32((unsigned int)FW_LEN16(cmd)); 22088c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &cmd); 22098c2ecf20Sopenharmony_ci if (ret) 22108c2ecf20Sopenharmony_ci return ret; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci if (cmd.nmac < *naddr) 22138c2ecf20Sopenharmony_ci *naddr = cmd.nmac; 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci switch (port) { 22168c2ecf20Sopenharmony_ci case 3: 22178c2ecf20Sopenharmony_ci memcpy(addr, cmd.macaddr3, sizeof(cmd.macaddr3)); 22188c2ecf20Sopenharmony_ci break; 22198c2ecf20Sopenharmony_ci case 2: 22208c2ecf20Sopenharmony_ci memcpy(addr, cmd.macaddr2, sizeof(cmd.macaddr2)); 22218c2ecf20Sopenharmony_ci break; 22228c2ecf20Sopenharmony_ci case 1: 22238c2ecf20Sopenharmony_ci memcpy(addr, cmd.macaddr1, sizeof(cmd.macaddr1)); 22248c2ecf20Sopenharmony_ci break; 22258c2ecf20Sopenharmony_ci case 0: 22268c2ecf20Sopenharmony_ci memcpy(addr, cmd.macaddr0, sizeof(cmd.macaddr0)); 22278c2ecf20Sopenharmony_ci break; 22288c2ecf20Sopenharmony_ci } 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci return ret; 22318c2ecf20Sopenharmony_ci} 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci/** 22348c2ecf20Sopenharmony_ci * t4vf_get_vf_vlan_acl - Get the VLAN ID to be set to 22358c2ecf20Sopenharmony_ci * the VI of this VF. 22368c2ecf20Sopenharmony_ci * @adapter: The adapter 22378c2ecf20Sopenharmony_ci * 22388c2ecf20Sopenharmony_ci * Find the VLAN ID to be set to the VF's VI. The requested VLAN ID 22398c2ecf20Sopenharmony_ci * is from the host OS via callback in the PF driver. 22408c2ecf20Sopenharmony_ci */ 22418c2ecf20Sopenharmony_ciint t4vf_get_vf_vlan_acl(struct adapter *adapter) 22428c2ecf20Sopenharmony_ci{ 22438c2ecf20Sopenharmony_ci struct fw_acl_vlan_cmd cmd; 22448c2ecf20Sopenharmony_ci int vlan = 0; 22458c2ecf20Sopenharmony_ci int ret = 0; 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci cmd.op_to_vfn = htonl(FW_CMD_OP_V(FW_ACL_VLAN_CMD) | 22488c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F); 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci /* Note: Do not enable the ACL */ 22518c2ecf20Sopenharmony_ci cmd.en_to_len16 = cpu_to_be32((unsigned int)FW_LEN16(cmd)); 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &cmd); 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci if (!ret) 22568c2ecf20Sopenharmony_ci vlan = be16_to_cpu(cmd.vlanid[0]); 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci return vlan; 22598c2ecf20Sopenharmony_ci} 2260